AWS Elastic Beanstalk, ejecutando un cronjob


Me gustaría saber si hay una manera de configurar un cronjob/tarea para ejecutar cada minuto. Actualmente cualquiera de mis instancias debería poder ejecutar esta tarea.

Esto es lo que he intentado hacer en los archivos de configuración sin éxito:

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

No estoy muy seguro de si esta es la forma correcta de hacerlo

¿Alguna idea?

Author: Onema, 2012-12-29

16 answers

Así es como agregué un trabajo cron a Elastic Beanstalk:

Cree una carpeta en la raíz de su aplicación llamada .ebextensions si no existe ya. A continuación, crear un archivo de configuración dentro de la .carpeta ebextensions. Usaré el ejemplo.configuración con fines ilustrativos. Luego agregue esto al ejemplo.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

Este es un archivo de configuración YAML para Elastic Beanstalk. Asegúrese de que cuando copia esto en su editor de texto que su editor de texto utiliza espacios en lugar de pestañas. De lo contrario, obtendrás un error YAML cuando envíes esto a EB.

Entonces lo que esto hace es crear un comando llamado 01_some_cron_job. Los comandos se ejecutan en orden alfabético por lo que el 01 se asegura de que se ejecute como el primer comando.

El comando entonces toma el contenido de un archivo llamado some_cron_job.txt y lo añade a un archivo llamado some_cron_job en /etc / cron.d.

El comando entonces cambia los permisos en el /etc/cron.d / archivo some_cron_job.

La clave leader_only asegura el comando solo se ejecuta en la instancia ec2 que se considera líder. En lugar de ejecutar en todas las instancias de ec2 que puede tener en ejecución.

Luego crea un archivo llamado some_cron_job.txt dentro de la .carpeta ebextensions. Usted colocará sus trabajos cron en este archivo.

Por ejemplo:

# 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

Así que este trabajo cron ejecutará cada minuto de cada hora de cada día como usuario root y descartará la salida a /dev/null. /usr / bin / php es la ruta a php. Luego reemplace algunos-php-script-aquí con la ruta a su archivo php. Esto es obviamente asumiendo que su trabajo cron necesita ejecutar un archivo PHP.

También, asegúrese de que el some_cron_job.el archivo txt tiene una nueva línea al final del archivo como dice el comentario. De lo contrario Cron no huirá.

Actualización: Hay un problema con esta solución cuando Elastic Beanstalk escala sus instancias. Por ejemplo, digamos que tiene una instancia con el trabajo cron en ejecución. Usted consigue un aumento en el tráfico tan elástico Beanstalk lo escala hasta dos instancias. El leader_only se asegurará de que solo tenga un trabajo cron ejecutándose entre las dos instancias. Su tráfico disminuye y Elastic Beanstalk lo escala a una instancia. Pero en lugar de terminar la segunda instancia, Elastic Beanstalk termina la primera instancia que fue el líder. Ahora no tiene ningún trabajo cron en ejecución, ya que solo se ejecutaban en la primera instancia que se terminó. Ver los comentarios debajo.

Actualización 2: Simplemente dejando esto claro en los comentarios a continuación: AWS ahora tiene protección contra la terminación automática de instancias. Solo habilítalo en tu instancia de líder y estarás listo. - Nicolás Arévalo Oct 28 ' 16 at 9: 23

 81
Author: Anarchtica,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-01-09 17:15:37

Esta es la forma oficial de hacerlo ahora (2015+). Por favor, intente esto primero, es por mucho el método más fácil actualmente disponible y más confiable también.

De acuerdo con los documentos actuales, uno es capaz de ejecutar tareas periódicas en su llamado nivel de trabajo .

Citando la documentación:

AWS Elastic Beanstalk admite tareas periódicas para niveles de entorno de trabajo en entornos que ejecutan una configuración predefinida con una pila de soluciones que contiene "v1. 2.0" en el nombre del contenedor. Debes crear un nuevo entorno.

También es interesante la parte sobre cron.yaml :

Para invocar tareas periódicas, el paquete fuente de la aplicación debe incluir un cron.archivo yaml en el nivel raíz. El archivo debe contener información sobre las tareas periódicas que desea programar. Especifique esta información utilizando la sintaxis estándar de crontab.

Actualización: Pudimos obtener este trabajo. Aquí están algunos conclusiones importantes de nuestra experiencia (Node.js platform):

  • Cuando se usa cron.archivo yaml , asegúrese de tener la última awsebcli, porque las versiones anteriores no funcionarán correctamente.
  • También es vital crear un nuevo entorno (al menos en nuestro caso lo fue), no solo clonar uno antiguo.
  • Si desea asegurarse de que CRON es compatible con su instancia de nivel de trabajo de EC2, introduzca ssh (eb ssh) y ejecute cat /var/log/aws-sqsd/default.log. Debe informar como aws-sqsd 2.0 (2015-02-18). Si no tienes 2.0 versión, algo salió mal al crear su entorno y necesita crear uno nuevo como se indicó anteriormente.
 53
Author: xaralis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-04-16 09:08:08

Con respecto a la respuesta de jamieb, y como alrdinleal menciona, puede usar la propiedad 'leader_only' para asegurarse de que solo una instancia EC2 ejecute el trabajo cron.

Cita tomada de http://docs.amazonwebservices.com/elasticbeanstalk/latest/dg/customize-containers-ec2.html:

Puedes usar leader_only. Se elige una instancia para ser el líder en un grupo de Auto Scaling. Si el valor leader_only se establece en true, el comando se ejecuta solo en la instancia que está marcada como lider.

Estoy tratando de lograr algo similar en mi eb, por lo que actualizaré mi publicación si lo resuelvo.

ACTUALIZACIÓN:

Ok, ahora tengo cronjobs trabajando usando la siguiente configuración de 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

Esencialmente, creo un archivo temporal con el cronjobs y luego establezco el crontab para leer desde el archivo temporal, luego elimino el archivo temporal después. Espero que esto ayude.

 31
Author: beterthanlife,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-01-01 18:18:41

Como se mencionó anteriormente, el defecto fundamental al establecer cualquier configuración de crontab es que solo sucede en el despliegue. Como el clúster recibe auto-escala, y luego hacia abajo, es el favorito a ser también el primer servidor apagado. Además no habría ningún fallo, que para mí era crítico.

Investigué un poco, luego hablé con nuestro especialista en cuentas de AWS para intercambiar ideas y validar la solución que se me ocurrió. Puede lograr esto con OpsWorks , aunque es un poco como usar una casa para matar una mosca. También es posible usar Data Pipeline con Task Runner, pero esto tiene una capacidad limitada en los scripts que puede ejecutar, y necesitaba poder ejecutar scripts PHP, con acceso a toda la base de código. También puede dedicar una instancia EC2 fuera del clúster de ElasticBeanstalk, pero entonces no tendrá que volver a realizar fail-over.

Así que esto es lo que se me ocurrió, que aparentemente no es convencional (como comentó el representante de AWS) y puede ser considerado un hack, pero funciona y es sólido con fail-over. Elegí una solución de codificación usando el SDK, que mostraré en PHP, aunque podría hacer el mismo método en cualquier idioma que prefiera.

// 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");
}

Así que caminar a través de esto y cómo funciona... Llama a scripts desde crontab como lo haría normalmente en cada instancia de EC2. Cada script incluye esto al principio (o incluye un solo archivo para cada uno, como lo uso), que establece un objeto ElasticBeanstalk y recupera un lista de todas las instancias. Utiliza solo el primer servidor en la lista, y comprueba si coincide con sí mismo, que si lo hace continúa, de lo contrario muere y se cierra. He comprobado y la lista devuelta parece ser consistente, que técnicamente solo necesita ser consistente durante un minuto más o menos, ya que cada instancia ejecuta el cron programado. Si cambia, no importaría, ya que de nuevo solo es relevante para esa pequeña ventana.

Esto no es elegante de ninguna manera, pero se adapta a nuestra necesidades específicas-que no era aumentar el costo con un servicio adicional o tener que tener una instancia EC2 dedicada, y tendría fail-over en caso de cualquier fallo. Nuestros scripts cron ejecutan scripts de mantenimiento que se colocan en SQS y cada servidor en el clúster ayuda a ejecutarlos. Al menos esto puede darle una opción alternativa si se ajusta a sus necesidades.

-Davey

 11
Author: user1599237,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-07-17 18:08:25

Si estás usando Rails, puedes usar la gema whenever-elasticbeanstalk. Le permite ejecutar trabajos cron en todas las instancias o solo en una. Comprueba cada minuto para asegurarse de que solo hay una instancia de "líder", y promocionará automáticamente un servidor a "líder" si no hay ninguno. Esto es necesario ya que Elastic Beanstalk solo tiene el concepto de líder durante la implementación y puede apagar cualquier instancia en cualquier momento mientras se escala.

ACTUALIZACIÓN Cambié a usar AWS OpsWorks y am ya no mantienen esta gema. Si necesita más funcionalidad de la que está disponible en los conceptos básicos de Elastic Beanstalk, le recomiendo cambiar a OpsWorks.

 7
Author: dignoe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-11-20 17:37:02

Hablé con un agente de AWS Support y así es como conseguimos que esto funcionara para mí. solución de 2015:

Crear un archivo en su .directorio ebextensions con your_file_name.config. En la entrada del archivo de configuración:

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 $2}'`
      REGION=`$METADATA -z | awk '{print substr($2, 0, length($2)-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 $5}'`

      # 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 $4}' | 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

Esta solución tiene 2 inconvenientes:

  1. En implementaciones posteriores, Beanstalk renombra el script cron existente como .bak, pero Cron todavía lo ejecutará. Su Cron ahora se ejecuta dos veces en la misma máquina.
  2. Si su entorno aumenta de escala, obtiene varios instancias, todas ejecutando su script cron. Esto significa que sus disparos de correo se repiten, o sus archivos de base de datos duplicados

Solución:

  1. Asegúrese de que cualquiera .el script ebextensions que crea un cron también elimina el .archivos bak en implementaciones posteriores.
  2. Tiene un script auxiliar que hace lo siguiente: Gets Obtiene el ID de instancia actual de los Metadatos Gets Obtiene el Auto actual Escalar el nombre del grupo desde las etiquetas EC2 Gets Obtiene la lista de EC2 Casos en que Grupo, ordenado alfabéticamente. -- Toma la primera ejemplo de esa lista. -- Compara el ID de instancia del paso 1 con el ID de primera instancia del paso 4. Sus scripts cron pueden usar este script auxiliar para determinar si deben ejecutarse.

Advertencia:

  • El rol IAM utilizado para las instancias de Beanstalk necesita ec2: DescribeTags y autoscaling:DescribeAutoScalingGroups permissions
  • Las instancias elegidas son aquellas mostradas como en servicio por Auto Escalar. Esto no significa necesariamente que estén completamente arrancados y listos para ejecutar su cron.

No tendría que establecer los roles de IAM si está utilizando el rol predeterminado de beanstalk.

 7
Author: Ken,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-09-26 08:23:49

Realmente no quieres ejecutar trabajos cron en Elastic Beanstalk. Dado que tendrá varias instancias de aplicación, esto puede causar condiciones de carrera y otros problemas extraños. En realidad recientemente blogueé sobre esto (4to o 5to consejo en la página). La versión corta: Dependiendo de la aplicación, utilice una cola de trabajos como SQS o una solución de terceros como iron.io .

 6
Author: jamieb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-12-31 19:06:34

Una solución más legible usando files en lugar de container_commands:

files:
  "/etc/cron.d/my_cron":
    mode: "000644"
    owner: root
    group: root
    content: |
      # override default email address
      MAILTO="[email protected]"
      # 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

Tenga en cuenta que el formato difiere del formato habitual de crontab en que especifica el usuario para ejecutar el comando como.

 4
Author: Tamlyn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-02 12:52:05

Alguien se preguntaba acerca de los problemas de escalado automático leader_only cuando surgen nuevos líderes. Parece que no puedo averiguar cómo responder a sus comentarios, pero vea este enlace: http://blog.paulopoiati.com/2013/08/25/running-cron-in-elastic-beanstalk-auto-scaling-environment/

 2
Author: Random5000,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-10-20 05:05:14
 1
Author: poiati,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-08-25 23:49:28

Para controlar si el escalado automático puede terminar una instancia en particular al escalar, use protección de instancia. Puede habilitar la configuración de protección de instancia en un grupo de Auto Scaling o en una instancia individual de Auto Scaling. Cuando Auto Scaling inicia una instancia, la instancia hereda la configuración de protección de instancia del grupo Auto Scaling. Puede cambiar la configuración de protección de instancia para un grupo de Auto Scaling o una instancia de Auto Scaling en cualquier tiempo.

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

 0
Author: Dele,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-08-10 20:23:08

Tenía otra solución para esto si un archivo php necesita ser ejecutado a través de cron y si había establecido cualquier instancia NAT, entonces puede poner cronjob en la instancia NAT y ejecutar el archivo php a través de wget.

 0
Author: prasoon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-08-22 09:25:11

2017: Si está usando Laravel5+

solo necesitas 2 minutos para configurarlo:

  • crear un nivel de trabajador
  • Instalar laravel-aws-worker

    composer require dusterio/laravel-aws-worker

  • Añade un cron.yaml a la carpeta raíz:

Añadir cron.yaml a la carpeta raíz de su aplicación (esto puede ser un parte de su repositorio o puede agregar este archivo justo antes de implementarlo en EB - lo importante es que este archivo está presente en el tiempo de deployment):

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

¡Eso es todo!

Toda tu tarea en App\Console\Kernel ahora será ejecutada

Instrucciones Detalladas y explicaciones: https://github.com/dusterio/laravel-aws-worker

Cómo escribir tareas dentro de Laravel: https://laravel.com/docs/5.4/scheduling

 0
Author: Sebastien Horin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-24 11:25:35

Así que hemos estado luchando con esto durante un tiempo y después de algunas discusiones con un representante de AWS, finalmente se me ocurrió lo que creo que es la mejor solución.

Usando un nivel de trabajo con cron.yaml es definitivamente la solución más fácil. Sin embargo, lo que la documentación no deja claro es que esto pondrá el trabajo al final de la cola SQS que está utilizando para ejecutar realmente sus trabajos. Si sus trabajos cron son sensibles al tiempo (como muchos lo son), esto no es aceptable, ya que dependería de la tamaño de la cola. Una opción es usar un entorno completamente separado solo para ejecutar trabajos cron, pero creo que eso es exagerado.

Algunas de las otras opciones, como comprobar si eres la primera instancia en la lista, tampoco son ideales. ¿Qué pasa si la primera instancia actual está en proceso de cierre?

La protección de instancias también puede venir con problemas: ¿qué pasa si esa instancia se bloquea / congela?

Lo que es importante entender es cómo AWS administra el cron.funcionalidad yaml. Hay un demonio SQS que usa una tabla Dynamo para manejar la "elección de líder". Escribe a esta tabla con frecuencia, y si el líder actual no ha escrito en un corto tiempo, la siguiente instancia se hará cargo como líder. Así es como el demonio decide qué instancia iniciar el trabajo en la cola SQS.

Podemos reutilizar la funcionalidad existente en lugar de intentar reescribir la nuestra. Puede ver la solución completa aquí: https://gist.github.com/dorner/4517fe2b8c79ccb3971084ec28267f27

Eso está en Ruby, pero puede adaptarlo fácilmente a cualquier otro lenguaje que tenga el SDK de AWS. Esencialmente, comprueba al líder actual, luego comprueba el estado para asegurarse de que está en buen estado. Se repetirá hasta que haya un líder actual en buen estado, y si la instancia actual es el líder, ejecute el trabajo.

 0
Author: Cidolfas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-26 14:45:04

Aquí hay una solución en caso de que desee hacer esto en PHP. Sólo necesitas cronjob.config en su .ebextensions para que funcione así.

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

El envvars obtiene las variables de entorno para los archivos. Puede depurar la salida en el tmp / sendemail.registro como arriba.

¡Espero que esto ayude a alguien como seguramente nos ayudó a nosotros!

 0
Author: foxybagga,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-11 21:32:15

Mi 1 centavo de contribución para 2018

Aquí está la manera correcta de hacerlo (usando django/python y django_crontab app):

Dentro de la carpeta .ebextensions crea un archivo como este 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

Debe ser container_commands en lugar de commands

 0
Author: Ronaldo Bahia,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-03-16 16:40:56