Поиск по сайту:

Как использовать Cron с контейнерами Docker


Запуск фоновых задач по расписанию — стандартное требование серверных служб. Раньше настройка была простой — вы определяли свои задачи в crontab вашего сервера и заканчивали работу. Давайте посмотрим, как вы можете использовать cron при использовании Docker для развертывания.

Контейнеризация ваших сервисов повышает производительность разработчиков. В то же время это может заставить вас задуматься о том, как традиционные задачи системного администратора соотносятся с концепциями Docker. У вас есть несколько вариантов использования cron с контейнерами Docker, и мы рассмотрим их ниже в порядке пригодности. Прежде чем продолжить, убедитесь, что вы установили Docker и создали Docker-образ своего приложения.

Использование Crontab хоста

По сути, вы всегда можете использовать установку cron хоста, на котором работает ваш Docker Engine. Убедитесь, что cron установлен, а затем отредактируйте системный crontab как обычно.

Вы можете использовать docker exec для запуска команды в существующем контейнере:

*/5 * * * * docker exec example_app_container /example-scheduled-task.sh

Это будет работать только в том случае, если вы можете быть уверены в имени контейнера заранее. Обычно лучше создать новый контейнер, который существует исключительно для запуска задачи:

*/5 * * * * docker run --rm example_app_image:latest /example-scheduled-task.sh

Каждые пять минут установка cron вашей системы будет создавать новый контейнер Docker, используя образ вашего приложения. Docker выполнит скрипт /example-scheduled-task.sh внутри контейнера. Контейнер будет уничтожен (--rm) после выхода скрипта.

Использование Cron в ваших контейнерах

Использование crontab хоста нарушает контейнеризацию Docker, поскольку запланированные задачи требуют ручной настройки в вашей системе. Вам необходимо убедиться, что cron установлен на каждом хосте, на который вы выполняете развертывание. Хотя это может быть полезно при разработке, по возможности следует интегрировать cron в свои службы Dockerized.

Большинство популярных базовых образов Docker по умолчанию не включают демон cron. Вы можете установить его в свой Dockerfile, а затем зарегистрировать crontab своего приложения.

Сначала создайте новый файл crontab в своей кодовой базе:

*/5 * * * * /usr/bin/sh /example-scheduled-task.sh

Затем измените свой Dockerfile, чтобы установить cron и зарегистрируйте свой crontab — вот как вы можете сделать это с образом на основе Debian:

RUN apt-get update && apt-get install -y cron
COPY example-crontab /etc/cron.d/example-crontab
RUN chmod 0644 /etc/cron.d/example-crontab &&
    crontab /etc/cron.d/example-crontab

Мы устанавливаем cron и копируем crontab нашей кодовой базы в каталог /etc/cron.d. Затем нам нужно изменить разрешения для нашего crontab, чтобы убедиться, что он доступен для cron. Наконец, используйте команду crontab, чтобы сделать файл известным демону cron.

Чтобы завершить эту настройку, вам нужно изменить команду или точку входа вашего образа, чтобы запустить демон cron при запуске контейнеров. Вы не можете добиться этого с помощью этапа RUN в вашем Dockerfile, потому что это временные шаги, которые не сохраняются после этапа сборки образа. Служба будет запущена в эфемерном контейнере, используемом для создания слоя, а не в конечных контейнерах, в которых запущен готовый образ.

Если единственной задачей вашего контейнера является запуск cron, о чем мы поговорим ниже, вы можете добавить ENTRYPOINT [\cron\, \-f\] в свой Dockerfile, чтобы запустить его как процесс переднего плана. Если вам нужно, чтобы другой процесс, например веб-сервер, оставался на переднем плане, вам следует создать специальный сценарий точки входа (например, ENTRYPOINT [\bash\, \init.sh\]). и добавьте service cron start в качестве команды в этот файл.

Отделение Cron от сервисов вашего приложения

Реализация настройки, описанной в предыдущем разделе, обеспечивает более надежное решение, чем использование crontab хоста. Добавление демона cron в контейнеры, которые обслуживают ваше приложение, гарантирует, что любой, кто использует ваш образ Docker, автоматически настроит запланированные задачи.

Это по-прежнему приводит к смешению проблем. В конечном итоге ваши контейнеры выполняют две обязанности: во-первых, обеспечивать функциональность приложения, а во-вторых, поддерживать работоспособность cron и выполнять запланированные задачи. В идеале каждый контейнер должен предоставлять одну конкретную единицу функциональности.

По возможности вам следует запускать задачи cron в отдельном контейнере вашего приложения. Если вы создаете веб-бэкенд, это будет означать, что один контейнер будет предоставлять ваш веб-сервер, а другой запускает cron на переднем плане.

Без этого разделения вы не сможете использовать оркестратор, такой как Docker Swarm или Kubernetes, для запуска нескольких реплик вашего приложения. В каждом контейнере будет запускаться собственный демон cron, в результате чего запланированные задачи будут выполняться несколько раз. Этого можно избежать, используя файлы блокировки, привязанные к общему тому Docker. Тем не менее, проще решить корневую проблему и ввести специальный контейнер для демона cron.

Как правило, вы хотите, чтобы оба контейнера основывались на образе Docker вашего приложения. Каждому из них потребуются подключения к томам и сетям Docker вашего сервиса. Это гарантирует, что контейнер cron имеет ту же среду, что и контейнер приложения, с той лишь разницей, что процесс переднего плана.

Это не жесткое правило — в некоторых проектах ваши запланированные задачи могут быть тривиальными сценариями, которые работают независимо от вашей кодовой базы. В этом случае контейнер cron может использовать минимальный базовый образ и избавиться от подключений к ненужным периферийным ресурсам.

Один из способов настроить отдельный контейнер cron — использовать docker-compose. Вы бы определили контейнер cron как дополнительный сервис. Вы можете использовать базовый образ вашего приложения, переопределив команду точки входа для запуска демона cron. Использование docker-compose также упрощает подключение контейнера к любым требуемым общим томам и сетям.

version: "3"
 
services:
  app:
    image: demo-image:latest
    volumes:
      - data:/app-data
  cron:
    image: demo-image:latest
    entrypoint: /bin/bash
    command: ["cron", "-f"]
    volumes:
      - data:/app-data
 
volumes:
  data:

Используя приведенный выше пример, один контейнер обслуживает наше приложение, используя точку входа по умолчанию в образе. Убедитесь, что это не запускает демон cron! Второй контейнер переопределяет точку входа изображения для запуска cron. Пока в образе установлен cron и настроен ваш crontab, вы можете использовать docker-compose up для запуска своего приложения.

Использование заданий Kubernetes Cron

Наконец, давайте рассмотрим простой пример запуска запланированных задач в Kubernetes. Kubernetes поставляется с собственным ресурсом CronJob, который вы можете использовать в своих манифестах.

Вам не нужно устанавливать cron в свой образ или настраивать специализированные контейнеры, если вы используете Kubernetes. Имейте в виду, что CronJob — это бета-ресурс, который может измениться в будущих выпусках Kubernetes.

apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: my-cron
  namespace: my-namespace
spec:
  schedule: "*/5 * * * *"
  concurrencyPolicy: Forbid
  jobTemplate:
    spec:
      template:
        spec:
          containers:
            - name: my-container
              image: my-image:latest
              command: ["/bin/bash", "/my-cron-script.sh"]
          restartPolicy: OnFailure

Примените приведенный выше манифест к своему кластеру, чтобы создать новое задание cron, которое будет запускать /my-cron-script.sh в вашем контейнере каждые пять минут. Частота задается как обычное определение cron для ключа schedule в spec ресурса.

Вы можете настроить ConcurrencyPolicy, чтобы контролировать, разрешает ли Kubernetes перекрытие ваших заданий. По умолчанию используется значение Разрешить, но его можно изменить на Запретить (предотвратить запуск новых заданий, пока одно уже существует) или Заменить (завершить существующее задание как как только начнется новый).

Использование встроенного ресурса Kubernetes — это рекомендуемый способ управления запланированными задачами в ваших кластерах. Вы можете легко получить доступ к журналам заданий, и вам не нужно беспокоиться о подготовке ваших контейнеров для использования с cron. Вам просто нужно создать образ Docker, содержащий все, что нужно для запуска ваших задач. Kubernetes будет создавать и уничтожать экземпляры контейнеров по указанному вами расписанию.




Все права защищены. © Linux-Console.net • 2019-2024