АРМ эластичный бобовый стебель, работает в процентах


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

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

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

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

какие идеи?

16 79

16 ответов:

вот как я добавил задание cron в Elastic Beanstalk:

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

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 для эластичного бобового стебля. Убедитесь, что при копировании в текстовый редактор используются пробелы вместо вкладок. В противном случае вы получите ошибку 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. Затем замените some-php-script-here путем к вашему php-файлу. Это, очевидно, предполагает, что ваша работа cron должна запускать PHP-файл.

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

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

обновление 2: Просто делая это ясно из комментариев ниже: AWS теперь имеет защиту от автоматического завершения инстанса. Просто включите его на вашем экземпляре лидера, и вы хорошо идти. - Николас Аревало 28 '16 октября в 9:23

Это официальный способ сделать это сейчас (2015+). Пожалуйста, попробуйте это во-первых, это на сегодняшний день самый простой способ, доступный и самый надежный.

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

со ссылкой на документы:

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

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

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

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

  • при использовании cron.и YAML файл, убедитесь, что у вас есть последние awsebcli, потому что старые версии не будут работать должным образом.
  • кроме того, крайне важно создать новую среду (по крайней мере в нашем случае было), а не просто клонировать старый.
  • если вы хотите, чтобы убедиться, CRON поддерживается на вашем экземпляре рабочего уровня 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 для чтения из временного файла, а затем удаляю временный файл. Надеюсь, это поможет.

Я провел некоторое исследование, а затем поговорил с нашим специалистом по аккаунтам AWS, чтобы отбросить идеи и подтвердить решение, которое я придумал. Вы можете сделать это с помощью OpsWorks, хотя это немного похоже на использование дома, чтобы убить муху. Также можно использовать конвейер данных с задачей 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

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

обновление Я переключился на использование AWS OpsWorks и больше не поддерживаю этот драгоценный камень. Если вам нужно больше функциональности, чем доступно в основах Elastic Beanstalk, я настоятельно рекомендую переключиться на OpsWorks.

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

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

files:
  "/etc/cron.d/cron_example":
    mode: "000644"
    owner: root
    group: root
    content: |
      * * * * * root /usr/local/bin/cron_example.sh

  "/usr/local/bin/cron_example.sh":
    mode: "000755"
    owner: root
    group: root
    content: |
      #!/bin/bash

      /usr/local/bin/test_cron.sh || exit
      echo "Cron running at " `date` >> /tmp/cron_example.log
      # Now do tasks that should only run on 1 instance ...

  "/usr/local/bin/test_cron.sh":
    mode: "000755"
    owner: root
    group: root
    content: |
      #!/bin/bash

      METADATA=/opt/aws/bin/ec2-metadata
      INSTANCE_ID=`$METADATA -i | awk '{print }'`
      REGION=`$METADATA -z | awk '{print substr(, 0, length()-1)}'`

      # Find our Auto Scaling Group name.
      ASG=`aws ec2 describe-tags --filters "Name=resource-id,Values=$INSTANCE_ID" \
        --region $REGION --output text | awk '/aws:autoscaling:groupName/ {print }'`

      # Find the first instance in the Group
      FIRST=`aws autoscaling describe-auto-scaling-groups --auto-scaling-group-names $ASG \
        --region $REGION --output text | awk '/InService$/ {print }' | sort | head -1`

      # Test if they're the same.
      [ "$FIRST" = "$INSTANCE_ID" ]

commands:
  rm_old_cron:
    command: "rm *.bak"
    cwd: "/etc/cron.d"
    ignoreErrors: true

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

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

решение:

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

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

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

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

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

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

files:
  "/etc/cron.d/my_cron":
    mode: "000644"
    owner: root
    group: root
    content: |
      # override default email address
      MAILTO="example@gmail.com"
      # run a Symfony command every five minutes (as ec2-user)
      */10 * * * * ec2-user /usr/bin/php /var/app/current/app/console do:something
    encoding: plain
commands:
  # delete backup file created by Elastic Beanstalk
  clear_cron_backup:
    command: rm -f /etc/cron.d/watson.bak

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

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

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

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.ямл в корневую папку:

добавить 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.функциональность ямл. Существует демон SQS, который использует динамическую таблицу для обработки "выборов лидера". Он часто записывает в эту таблицу, и если текущий лидер не написал в течение короткого времени, следующий экземпляр возьмет на себя роль лидера. Именно так демон решает, какой экземпляр запустить задание в очередь SQS.

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

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

вот исправление, если вы хотите сделать это в PHP. Тебе просто нужна дружба.конфиг в вашем .папка 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 получает переменные среды для файлов. Вы можете отлаживать выход на ТМП/отправка электронных писем отключена.войти, как указано выше.

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

Мой 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

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