AWS Elastic Beanstalk, работает cronjob

Я хотел бы знать, есть ли способ настроить cronjob / task для выполнения каждую минуту. В настоящее время любой из моих экземпляров должен иметь возможность запускать эту задачу.

Это то, что я пытался сделать в конфигурационных файлах без успеха:

container_commands: 01cronjobs: command: echo "*/1 * * * * root php /etc/httpd/myscript.php" 

Я не уверен, что это правильный способ сделать это

Есть идеи?

Вот как я добавил работу cron в Elastic Beanstalk:

Создайте папку в корне вашего приложения с именем .ebextensions, если она еще не существует. Затем создайте файл конфигурации внутри папки .ebextensions. Я буду использовать example.config для иллюстрации. Затем добавьте это в example.config

 container_commands: 01_some_cron_job: command: "cat .ebextensions/some_cron_job.txt > /etc/cron.d/some_cron_job && chmod 644 /etc/cron.d/some_cron_job" leader_only: true 

Это файл конфигурации YAML для Elastic Beanstalk. Убедитесь, что при копировании в текстовый редактор ваш текстовый редактор использует пробелы вместо вкладок. В противном случае вы получите ошибку YAML, когда вы нажмете это на EB.

Итак, что это такое, создайте команду под названием 01_some_cron_job. Команды запускаются в алфавитном порядке, так что 01 гарантирует, что он запускается как первая команда.

Затем команда берет содержимое файла с именем some_cron_job.txt и добавляет его в файл с именем some_cron_job в /etc/cron.d.

Затем команда изменяет разрешения в файле /etc/cron.d/some_cron_job.

Ключ leader_only гарантирует, что команда запускается только на экземпляр ec2, который считается лидером. Вместо запуска на каждом экземпляре ec2 вы можете запустить.

Затем создайте файл с именем some_cron_job.txt внутри папки .ebextensions. Вы разместите свои задания cron в этом файле.

Так, например:

 # The newline at the end of this file is extremely important. Cron won't run without it. * * * * * root /usr/bin/php some-php-script-here > /dev/null 

Таким образом, это задание cron будет выполняться каждую минуту каждого часа каждого дня в качестве пользователя root и отбрасывать вывод в / dev / null. / usr / bin / php – это путь к php. Затем замените некоторый-php-скрипт здесь на путь к вашему php-файлу. Очевидно, это предполагает, что ваше задание cron должно запускать файл PHP.

Кроме того, убедитесь, что файл some_cron_job.txt имеет новую строку в конце файла, как говорит комментарий. В противном случае cron не будет работать.

Обновление: есть проблема с этим решением, когда Elastic Beanstalk расширяет ваши экземпляры. Например, скажем, у вас есть один экземпляр с запущенным заданием cron. Вы получаете увеличение трафика, так что эластичный beanstalk весит вас до двух экземпляров. Lead_only гарантирует, что у вас есть только одно задание cron между двумя экземплярами. Ваш трафик уменьшается, а эластичный бобовый штанги сводит вас к одному экземпляру. Но вместо того, чтобы завершать второй экземпляр, Elastic Beanstalk завершает первый экземпляр, который был лидером. Теперь у вас нет заданий cron, поскольку они выполнялись только в первом экземпляре, который был завершен. См. Комментарии ниже.

Обновление 2: просто сделайте это ясно из комментариев ниже: AWS теперь имеет защиту от автоматического завершения экземпляра. Просто включите его на примере вашего лидера, и вы хорошо пойдете. – Nicolás Arévalo Oct 28 ’16 в 9:23

Это официальный способ сделать это сейчас (2015+). Сначала попробуйте это, это самый простой способ, ansible в настоящее время и самый надежный.

Согласно текущим документам, каждый может выполнять периодические задачи на так называемом рабочем уровне .

Ссылаясь на документацию:

AWS Elastic Beanstalk поддерживает периодические задачи для уровней рабочей среды в средах с предопределенной конфигурацией с стеком решений, который содержит «v1.2.0» в имени контейнера. Вы должны создать новую среду.

Также интересна часть о cron.yaml :

Чтобы вызывать периодические задачи, ваш источник источника приложения должен содержать файл cron.yaml на корневом уровне. Файл должен содержать информацию о периодических задачах, которые вы хотите запланировать. Укажите эту информацию, используя стандартный синтаксис crontab.

Обновление: мы смогли получить эту работу. Вот некоторые важные проблемы из нашего опыта (платформа Node.js):

  • При использовании файла cron.yaml убедитесь, что у вас есть последний awsebcli , потому что более старые версии не будут работать должным образом.
  • Также важно создать новую среду (по крайней мере, в нашем случае это было), а не просто клонировать старый.
  • Если вы хотите убедиться, что CRON поддерживается на вашем экземпляре Worker Tier EC2, ssh в него ( eb ssh ) и запустите cat /var/log/aws-sqsd/default.log . Он должен сообщать как aws-sqsd 2.0 (2015-02-18) . Если у вас нет версии 2.0, что-то пошло не так, создавая среду, и вам нужно создать новую, как указано выше.

Что касается ответа jamieb, и, как упоминается в alrdinleal, вы можете использовать свойство «leader_only», чтобы гарантировать, что только один экземпляр EC2 запускает задание cron.

Цитата взята из http://docs.amazonwebservices.com/elasticbeanstalk/latest/dg/customize-containers-ec2.html :

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

Я пытаюсь достичь подобной вещи на моем eb, поэтому обновит свой пост, если решит его.

ОБНОВИТЬ:

Итак, теперь у меня есть рабочие cronjobs, используя следующую конфигурацию eb:

 files: "/tmp/cronjob" : mode: "000777" owner: ec2-user group: ec2-user content: | # clear expired baskets */10 * * * * /usr/bin/wget -o /dev/null http://blah.elasticbeanstalk.com/basket/purge > $HOME/basket_purge.log 2>&1 # clean up files created by above cronjob 30 23 * * * rm $HOME/purge* encoding: plain container_commands: purge_basket: command: crontab /tmp/cronjob leader_only: true commands: delete_cronjob_file: command: rm /tmp/cronjob 

По существу, я создаю временный файл с cronjobs, а затем устанавливаю crontab для чтения из временного файла, а затем удаляю временный файл. Надеюсь это поможет.

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

Я провел некоторое исследование, а затем поговорил с нашим специалистом по учетным записям AWS, чтобы поднять идеи и обосновать решение, которое я придумал. Вы можете выполнить это с помощью OpsWorks , хотя это похоже на использование дома, чтобы убить муху. Также возможно использовать Data Pipeline с Task Runner , но это имеет ограниченные возможности в сценариях, которые он может выполнить, и мне нужно было иметь возможность запускать PHP-скрипты с доступом ко всей базе кода. Вы также можете выделить экземпляр EC2 вне кластера ElasticBeanstalk, но тогда у вас нет сбоя снова.

Итак, вот что я придумал, что, по-видимому, нетрадиционное (как комментировал представитель AWS), и его можно считать взломом, но он работает и прочен с ошибкой. Я выбрал решение для кодирования с использованием SDK, которое я покажу на PHP, хотя вы можете сделать тот же метод на любом предпочитаемом вами языке.

 // contains the values for variables used (key, secret, env) require_once('cron_config.inc'); // Load the AWS PHP SDK to connection to ElasticBeanstalk use Aws\ElasticBeanstalk\ElasticBeanstalkClient; $client = ElasticBeanstalkClient::factory(array( 'key' => AWS_KEY, 'secret' => AWS_SECRET, 'profile' => 'your_profile', 'region' => 'us-east-1' )); $result = $client->describeEnvironmentResources(array( 'EnvironmentName' => AWS_ENV )); if (php_uname('n') != $result['EnvironmentResources']['Instances'][0]['Id']) { die("Not the primary EC2 instance\n"); } 

Итак, пройдя через это и как он работает … Вы называете скрипты crontab, как обычно, на каждом экземпляре EC2. Каждый сценарий включает это в начале (или включает в себя один файл для каждого, как я его использую), который устанавливает объект ElasticBeanstalk и извлекает список всех экземпляров. Он использует только первый сервер в списке и проверяет, совпадает ли он с самим собой, и если он его продолжает, в противном случае он умирает и закрывается. Я проверил, и возвращаемый список кажется последовательным, и технически он должен быть согласован в течение минуты или около того, поскольку каждый экземпляр выполняет запланированный cron. Если он изменится, это не имеет значения, поскольку снова это относится только к этому маленькому окну.

Это не изящно ни в коем случае, но подходит для наших конкретных потребностей – что не должно увеличивать стоимость с помощью дополнительной услуги или иметь специальный экземпляр EC2 и будет иметь отказ в случае сбоя. Наши скрипты cron запускают сценарии обслуживания, которые помещаются в SQS, и каждый сервер в кластере помогает выполнить. По крайней мере, это может дать вам альтернативный вариант, если он соответствует вашим потребностям.

-Davey

Если вы используете Rails, вы можете использовать gem every-elasticbeanstalk . Он позволяет запускать задания cron либо во всех экземплярах, либо только в одном. Он проверяет каждую минуту, чтобы убедиться, что существует только один экземпляр «лидера» и автоматически будет продвигать один сервер к «лидеру», если его нет. Это необходимо, так как Elastic Beanstalk имеет только концепцию лидера во время развертывания и может закрывать любой экземпляр в любое время при масштабировании.

ОБНОВЛЕНИЕ Я переключился на использование AWS OpsWorks и больше не поддерживаю этот gem. Если вам нужно больше функциональности, чем доступно в основах Elastic Beanstalk, я настоятельно рекомендую переключиться на OpsWorks.

Я поговорил с агентом поддержки AWS, и именно так мы получили это, чтобы работать на меня. 2015:

Создайте файл в каталоге .ebextensions с вашим_файл_имя.config. В ввод файла конфигурации:

  файлы:
   "/etc/cron.d/cron_example":
     режим: "000644"
     владелец: root
     группа: корень
     содержание: |
       * * * * * root /usr/local/bin/cron_example.sh

   "/usr/local/bin/cron_example.sh":
     режим: "000755"
     владелец: root
     группа: корень
     содержание: |
       #! / Bin / Баш

       /usr/local/bin/test_cron.sh ||  Выход
       echo "Cron running at" `date` >> /tmp/cron_example.log
       # Теперь выполняйте задачи, которые должны выполняться только в одном экземпляре ...

   "/usr/local/bin/test_cron.sh":
     режим: "000755"
     владелец: root
     группа: корень
     содержание: |
       #! / Bin / Баш

       METADATA = / Opt / AWS / bin / ec2-метаданные
       INSTANCE_ID = `$ METADATA -i |  awk '{print $ 2}' `
       REGION = `$ METADATA -z |  awk '{print substr ($ 2, 0, length ($ 2) -1)}' `

       # Найдите имя автомасштабируемой группы.
       ASG = `aws ec2 description-tags -filters" Name = resource-id, Values ​​= $ INSTANCE_ID "\
         --region $ REGION --outout текст |  awk '/ aws: autoscaling: groupName / {print $ 5}' `

       # Найти первый экземпляр в группе
       FIRST = `aws autoscaling describe-auto-scaling-groups -auto-scaling-group-names $ ASG \
         --region $ REGION --outout текст |  awk '/ InService $ / {print $ 4}' |  сортировать |  head -1`

       # Проверьте, совпадают ли они.
       ["$ FIRST" = "$ INSTANCE_ID"]

 команды:
   rm_old_cron:
     команда: "rm * .bak"
     cwd: "/etc/cron.d"
     ignoreErrors: true

Это решение имеет два недостатка:

  1. При последующих развертываниях Beanstalk переименовывает существующий cron-скрипт как .bak, но cron все равно будет его запускать. Ваш Cron теперь выполняется дважды на одном компьютере.
  2. Если ваша среда масштабируется, вы получаете несколько экземпляров, все из которых запускают ваш скрипт cron. Это означает, что ваши почтовые снимки повторяются, или ваши архивы базы данных дублируются

Временное решение:

  1. Убедитесь, что любой скрипт .ebextensions, который создает cron, также удаляет файлы .bak при последующих развертываниях.
  2. Имейте вспомогательный скрипт, который выполняет следующие действия: – Получает текущий идентификатор экземпляра из метаданных; – получает текущее имя автоматической масштабирующей группы из тегов EC2; – получает список экземпляров EC2 в этой группе, отсортированных по алфавиту. – Принимает первый экземпляр из этого списка. – Сравнивает идентификатор экземпляра с шага 1 с первым идентификатором экземпляра с шага 4. Затем ваши cron-скрипты могут использовать этот вспомогательный скрипт, чтобы определить, должны ли они выполняться.

Предостережение:

  • Роль IAM, используемая для экземпляров Beanstalk, требует ec2: DescribeTags и автомасштабирование: Разрешения DescribeAutoScalingGroups
  • Выбранными экземплярами являются те, которые показаны как InService путем автоматического масштабирования. Это не обязательно означает, что они полностью загружены и готовы запустить ваш cron.

Вам не нужно будет устанавливать роли IAM, если вы используете роль beanstalk по умолчанию.

Вы действительно не хотите выполнять задания cron на Elastic Beanstalk. Поскольку у вас будет несколько экземпляров приложений, это может привести к условиям гонки и другим нечетным проблемам. Я на самом деле недавно писал об этом (4-й или 5-й отзыв вниз по странице). Краткая версия. В зависимости от приложения используйте очередь заданий, такую ​​как SQS или стороннее решение, такое как iron.io.

Более читаемое решение, использующее files вместо container_commands :

 файлы:
   "/etc/cron.d/my_cron":
     режим: "000644"
     владелец: root
     группа: корень
     содержание: |
       # переопределить адрес электронной почты по умолчанию
       MAILTO = "[email protected]"
       # запускать команду Symfony каждые пять минут (как ec2-пользователь)
       * / 10 * * * * ec2-user / usr / bin / php / var / app / current / app / console делают: что-то
     кодирование: plain
 команды:
   # удалить файл резервной копии, созданный Elastic Beanstalk
   clear_cron_backup:
     команда: rm -f /etc/cron.d/watson.bak

Обратите внимание, что формат отличается от обычного формата crontab тем, что он задает пользователю выполнение команды as.

Кто-то задавался вопросом о проблемах с автоматическим масштабированием лидера, когда возникают новые лидеры. Я не могу понять, как ответить на их комментарии, но посмотрите эту ссылку: http://blog.paulopoiati.com/2013/08/25/running-cron-in-elastic-beanstalk-auto-scaling- Окружающая среда/

Чтобы контролировать, может ли Auto Scaling завершать конкретный экземпляр при масштабировании, используйте защиту экземпляра. Вы можете включить настройку защиты экземпляра в группе автоматического масштабирования или отдельном экземпляре Auto Scaling. Когда Auto Scaling запускает экземпляр, экземпляр наследует настройку защиты экземпляра группы Auto Scaling. Вы можете изменить настройку защиты экземпляра для группы автоматического масштабирования или экземпляра автоматического масштабирования в любое время.

http://docs.aws.amazon.com/autoscaling/latest/userguide/as-instance-termination.html#instance-protection

У меня было другое решение для этого, если php-файл должен быть запущен через cron, и если вы установили какие-либо экземпляры NAT, вы можете поместить cronjob в экземпляр NAT и запустить php-файл через wget.

2017: Если вы используете Laravel5 +

Для его настройки требуется всего 2 минуты:

  • создать рабочий уровень
  • установить laravel-aws-worker

    composer require dusterio/laravel-aws-worker

  • добавьте cron.yaml в корневую папку:

Добавьте cron.yaml в корневую папку вашего приложения (это может быть частью вашего репо или вы можете добавить этот файл прямо перед развертыванием в EB – важно то, что этот файл присутствует во время развертывания):

 version: 1 cron: - name: "schedule" url: "/worker/schedule" schedule: "* * * * *" 

Это оно!

Теперь все ваши задачи в App\Console\Kernel будут выполнены

Подробные инструкции и объяснения: https://github.com/dusterio/laravel-aws-worker

Как написать задачи внутри Laravel: https://laravel.com/docs/5.4/scheduling

Таким образом, мы боролись с этим некоторое время, и после некоторого обсуждения с представителем AWS я наконец придумал то, что считаю лучшим решением.

Использование рабочего уровня с cron.yaml – это, безусловно, самое простое исправление. Однако то, что документация не дает понять, заключается в том, что это положит задание в конце очереди SQS, которую вы используете, чтобы фактически выполнять ваши задания. Если ваши задания cron являются чувствительными к времени (как многие из них), это неприемлемо, поскольку это будет зависеть от размера очереди. Один из вариантов – использовать совершенно отдельную среду, чтобы запускать задания cron, но я думаю, что это слишком много.

Некоторые из других вариантов, например проверка того, являетесь ли вы первым экземпляром в списке, также не идеальны. Что делать, если текущий первый экземпляр находится в процессе закрытия?

Защита экземпляра также может возникнуть с проблемами – что, если этот экземпляр заблокирован / заморожен?

Важно понимать, как AWS управляет функциональностью cron.yaml. Существует демон SQS, который использует таблицу Dynamo для обработки «выборов лидеров». Он часто пишет эту таблицу, и если текущий лидер не за короткое время написал, следующий экземпляр возьмет на себя лидера. Именно так демона решает, какой экземпляр должен запустить задание в очередь SQS.

Мы можем перепрофилировать существующую функциональность, а не пытаться переписать ее самостоятельно. Вы можете увидеть полное решение здесь: https://gist.github.com/dorner/4517fe2b8c79ccb3971084ec28267f27

Это в Ruby, но вы можете легко адаптировать его к любому другому языку, на котором есть AWS SDK. По существу, он проверяет текущего лидера, затем проверяет состояние, чтобы убедиться, что он в хорошем состоянии. Он будет зацикливаться до тех пор, пока не будет текущий лидер в хорошем состоянии, и если текущий экземпляр является лидером, выполните задание.

вот исправление, которое вы хотите сделать в PHP. Вам просто нужно cronjob.config в вашей папке .ebextensions, чтобы заставить его работать так.

 files: "/etc/cron.d/my_cron": mode: "000644" owner: root group: root content: | empty stuff encoding: plain commands: 01_clear_cron_backup: command: "rm -f /etc/cron.d/*.bak" 02_remove_content: command: "sudo sed -i 's/empty stuff//g' /etc/cron.d/my_cron" container_commands: adding_cron: command: "echo '* * * * * ec2-user . /opt/elasticbeanstalk/support/envvars && /usr/bin/php /var/app/current/index.php cron sendemail > /tmp/sendemail.log 2>&1' > /etc/cron.d/my_cron" leader_only: true 

envvars получает переменные окружения для файлов. Вы можете отлаживать вывод на tmp / sendemail.log, как указано выше.

Надеюсь, это помогает кому-то, поскольку это, безусловно, помогло нам!

Мой 1 цент взноса за 2018 год

Вот правильный способ сделать это (используя приложение django/python и django_crontab ):

внутри папки .ebextensions создайте файл, подобный этому 98_cron.config :

 files: "/tmp/98_create_cron.sh": mode: "000755" owner: root group: root content: | #!/bin/sh cd / sudo /opt/python/run/venv/bin/python /opt/python/current/app/manage.py crontab remove > /home/ec2-user/remove11.txt sudo /opt/python/run/venv/bin/python /opt/python/current/app/manage.py crontab add > /home/ec2-user/add11.txt container_commands: 98crontab: command: "mv /tmp/98_create_cron.sh /opt/elasticbeanstalk/hooks/appdeploy/post && chmod 774 /opt/elasticbeanstalk/hooks/appdeploy/post/98_create_cron.sh" leader_only: true 

Он должен быть commands container_commands вместо commands

Interesting Posts
Давайте будем гением компьютера.