Gostaria de saber se existe uma maneira de configurar um cronjob / tarefa para executar a cada minuto. Atualmente, qualquer uma das minhas instâncias deve ser capaz de executar esta tarefa.
Isto é o que tentei fazer nos arquivos de configuração sem sucesso:
container_commands:
01cronjobs:
command: echo "*/1 * * * * root php /etc/httpd/myscript.php"
Não tenho certeza se esta é a maneira correta de fazer isso
Alguma ideia?
Respostas:
Foi assim que adicionei um cron job ao Elastic Beanstalk:
Crie uma pasta na raiz do seu aplicativo chamada .ebextensions se ainda não existir. Em seguida, crie um arquivo de configuração dentro da pasta .ebextensions. Usarei example.config para fins ilustrativos. Em seguida, adicione isso a example.config
Este é um arquivo de configuração YAML para Elastic Beanstalk. Certifique-se de que, ao copiar isso para o editor de texto, ele use espaços em vez de tabulações. Caso contrário, você obterá um erro YAML ao enviar para EB.
Então o que isso faz é criar um comando chamado 01_some_cron_job. Os comandos são executados em ordem alfabética, então o 01 garante que seja executado como o primeiro comando.
O comando então pega o conteúdo de um arquivo chamado some_cron_job.txt e o adiciona a um arquivo chamado some_cron_job em /etc/cron.d.
O comando então altera as permissões no arquivo /etc/cron.d/some_cron_job.
A chave leader_only garante que o comando seja executado apenas na instância ec2 que é considerada líder. Em vez de executar em todas as instâncias ec2 que você possa ter em execução.
Em seguida, crie um arquivo chamado some_cron_job.txt dentro da pasta .ebextensions. Você colocará seus cron jobs neste arquivo.
Então, por exemplo:
Portanto, este cron job será executado a cada minuto de cada hora de todos os dias como o usuário root e descartará a saída para / dev / null. / usr / bin / php é o caminho para o php. Em seguida, substitua some-php-script-here pelo caminho para seu arquivo php. Obviamente, isso pressupõe que seu cron job precisa executar um arquivo PHP.
Além disso, certifique-se de que o arquivo some_cron_job.txt tenha uma nova linha no final do arquivo, exatamente como o comentário diz. Caso contrário, o cron não será executado.
Atualização: há um problema com esta solução quando o Elastic Beanstalk escala suas instâncias. Por exemplo, digamos que você tenha uma instância com o cron job em execução. Você obtém um aumento no tráfego, então o Elastic Beanstalk escala você em até duas instâncias. O leader_only garantirá que você tenha apenas um cron job em execução entre as duas instâncias. Seu tráfego diminui e o Elastic Beanstalk reduz você a uma instância. Mas em vez de encerrar a segunda instância, o Elastic Beanstalk encerra a primeira instância que era o líder. Agora você não tem nenhum cron jobs em execução, pois eles só foram executados na primeira instância que foi encerrada. Veja os comentários abaixo.
Atualização 2: Apenas deixando isso claro com os comentários abaixo: AWS agora tem proteção contra encerramento automático de instâncias. Basta habilitá-lo em sua instância líder e você estará pronto para prosseguir. - Nicolás Arévalo 28 de outubro de 16 às 9:23
fonte
01_some_cron_job
para02_some_cron_job
e adicionado01_remove_cron_jobs
com o seguinte:command: "rm /etc/cron.d/cron_jobs || exit 0"
. Dessa forma, após cada implantação, apenas o líder terá ocron_jobs
arquivo. Se os líderes mudarem, você pode simplesmente reimplantar e os crons serão consertados para serem executados apenas mais uma vez.leader_only
propriedade. Ele só é usado durante a implantação e se você reduzir ou sua instância "líder" falhar, você terá problemas de referênciaEsta é a forma oficial de fazer isso agora (2015+). Experimente primeiro, é de longe o método mais fácil disponível atualmente e também mais confiável.
De acordo com os documentos atuais, é possível executar tarefas periódicas em sua chamada camada de trabalho .
Citando a documentação:
Também interessante é a parte sobre cron.yaml :
Atualização: Conseguimos este trabalho. Aqui estão algumas dicas importantes de nossa experiência (plataforma Node.js):
eb ssh
, execute ssh nele ( ) e executecat /var/log/aws-sqsd/default.log
. Deve relatar comoaws-sqsd 2.0 (2015-02-18)
. Se você não tem a versão 2.0, algo deu errado ao criar seu ambiente e você precisa criar um novo conforme mencionado acima.fonte
Com relação à resposta de Jamieb, e como alrdinleal menciona, você pode usar a propriedade 'leader_only' para garantir que apenas uma instância EC2 execute o cron job.
Citação tirada de http://docs.amazonwebservices.com/elasticbeanstalk/latest/dg/customize-containers-ec2.html :
Estou tentando conseguir algo semelhante no meu eb, então atualizarei meu post se eu resolver isso.
ATUALIZAR:
Ok, agora tenho cronjobs funcionando usando a seguinte configuração do eb:
Basicamente, eu crio um arquivo temporário com os cronjobs e, em seguida, defino o crontab para ler do arquivo temporário e, em seguida, excluo o arquivo temporário. Espero que isto ajude.
fonte
Conforme mencionado acima, a falha fundamental em estabelecer qualquer configuração crontab é que isso só acontece na implantação. À medida que o cluster é escalado automaticamente para cima e, em seguida, para baixo, ele também é o primeiro servidor a ser desligado. Além disso, não haveria failover, o que para mim era crítico.
Fiz algumas pesquisas e conversei com nosso especialista em contas da AWS para trocar ideias e validar a solução que encontrei. Você pode fazer isso com OpsWorks , embora seja um pouco como usar uma casa para matar uma mosca. Também é possível usar o Data Pipeline com o Task Runner , mas isso tem capacidade limitada nos scripts que pode executar, e eu precisava ser capaz de executar scripts PHP, com acesso a toda a base de código. Você também pode dedicar uma instância EC2 fora do cluster ElasticBeanstalk, mas não haverá failover novamente.
Então aqui está o que eu inventei, que aparentemente não é convencional (como o representante da AWS comentou) e pode ser considerado um hack, mas funciona e é sólido com failover. Escolhi uma solução de codificação usando o SDK, que mostrarei em PHP, embora você possa fazer o mesmo método em qualquer linguagem de sua preferência.
Então, examinando isso e como ele funciona ... Você chama scripts do crontab como faria normalmente em cada instância do EC2. Cada script inclui isso no início (ou inclui um único arquivo para cada, conforme eu o uso), que estabelece um objeto ElasticBeanstalk e recupera uma lista de todas as instâncias. Ele usa apenas o primeiro servidor da lista e verifica se ele corresponde a si mesmo, o que, se isso acontecer, continua; caso contrário, ele morre e fecha. Verifiquei e a lista retornada parece ser consistente, o que tecnicamente só precisa ser consistente por um minuto ou mais, conforme cada instância executa o cron programado. Se mudar, não importa, já que, novamente, só é relevante para aquela pequena janela.
Isso não era nada elegante, mas atendia às nossas necessidades específicas - que não era aumentar o custo com um serviço adicional ou ter que ter uma instância EC2 dedicada, e teria failover em caso de alguma falha. Nossos scripts cron executam scripts de manutenção que são colocados no SQS e cada servidor no cluster ajuda a executar. Pelo menos isso pode lhe dar uma opção alternativa se for adequado às suas necessidades.
-Davey
fonte
$instanceId = file_get_contents("http://instance-data/latest/meta-data/instance-id");
Então, apenas use aquele $ instanceId var para fazer a comparação.Falei com um agente de suporte da AWS e é assim que fizemos isso funcionar para mim. Solução 2015:
Crie um arquivo em seu diretório .ebextensions com your_file_name.config. Na entrada do arquivo de configuração:
Esta solução tem 2 desvantagens:
Gambiarra:
Embargo:
Você não teria que definir as funções IAM se estiver usando a função beanstalk padrão.
fonte
Se você estiver usando Rails, você pode usar a gem always-elasticbeanstalk . Ele permite que você execute tarefas cron em todas as instâncias ou em apenas uma. Ele verifica a cada minuto para garantir que haja apenas uma instância "líder" e irá promover automaticamente um servidor a "líder" se não houver nenhuma. Isso é necessário porque o Elastic Beanstalk tem apenas o conceito de líder durante a implantação e pode desligar qualquer instância a qualquer momento durante o dimensionamento.
ATUALIZAÇÃO Mudei para o AWS OpsWorks e não estou mais mantendo esta joia. Se você precisar de mais funcionalidade do que está disponível no básico do Elastic Beanstalk, eu recomendo mudar para o OpsWorks.
fonte
Você realmente não quer executar tarefas cron no Elastic Beanstalk. Como você terá várias instâncias de aplicativo, isso pode causar condições de corrida e outros problemas estranhos. Na verdade, recentemente escrevi sobre isso (4ª ou 5ª dica na página). A versão curta: Dependendo da aplicação, use uma fila trabalho como SQS ou uma solução de terceiros como iron.io .
fonte
2017: Se você estiver usando o Laravel5 +
Você só precisa de 2 minutos para configurá-lo:
instalar laravel-aws-worker
composer require dusterio/laravel-aws-worker
adicione um cron.yaml à pasta raiz:
É isso aí!
Todas as suas tarefas
App\Console\Kernel
serão agora executadasInstruções e explicações detalhadas: https://github.com/dusterio/laravel-aws-worker
Como escrever tarefas dentro do Laravel: https://laravel.com/docs/5.4/scheduling
fonte
Uma solução mais legível usando em
files
vez decontainer_commands
:Observe que o formato difere do formato usual do crontab porque especifica o usuário para executar o comando.
fonte
Meu 1 centavo de contribuição para 2018
Aqui é o caminho certo para fazê-lo (usando
django/python
edjango_crontab
app):dentro da
.ebextensions
pasta, crie um arquivo como este98_cron.config
:Precisa ser em
container_commands
vez decommands
fonte
Alguém estava se perguntando sobre os problemas de dimensionamento automático do leader_only quando surgem novos líderes. Não consigo descobrir como responder aos comentários deles, mas veja este link: http://blog.paulopoiati.com/2013/08/25/running-cron-in-elastic-beanstalk-auto-scaling- meio Ambiente/
fonte
O exemplo mais recente da Amazon é o mais fácil e eficiente (tarefas periódicas):
https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/using-features-managing-env-tiers.html
onde você cria uma camada de trabalho separada para executar qualquer um dos seus cron jobs. Crie o arquivo cron.yaml e coloque-o na pasta raiz. Um problema que tive (depois que o cron não parecia estar em execução) foi descobrir que meu CodePipeline não tinha autoridade para realizar uma modificação do dynamodb. Com base nisso, depois de adicionar o acesso FullDynamoDB em IAM -> funções -> seu pipeline e reimplantar (beanstalk elástico), funcionou perfeitamente.
fonte
Aqui está uma explicação completa da solução:
http://blog.paulopoiati.com/2013/08/25/running-cron-in-elastic-beanstalk-auto-scaling-environment/
fonte
Então, estamos lutando com isso há algum tempo e, após alguma discussão com um representante da AWS, finalmente descobri o que considero a melhor solução.
Usar uma camada de trabalho com cron.yaml é definitivamente a solução mais fácil. No entanto, o que a documentação não deixa claro é que isso colocará o trabalho no final da fila SQS que você está usando para realmente executar seus trabalhos. Se seus cron jobs são sensíveis ao tempo (como muitos são), isso não é aceitável, pois dependeria do tamanho da fila. Uma opção é usar um ambiente completamente separado apenas para executar tarefas cron, mas acho isso um exagero.
Algumas das outras opções, como verificar se você é a primeira instância da lista, também não são ideais. E se a primeira instância atual estiver em processo de encerramento?
A proteção de instância também pode apresentar problemas - e se essa instância for bloqueada / congelada?
O que é importante entender é como a própria AWS gerencia a funcionalidade cron.yaml. Existe um daemon SQS que usa uma tabela Dynamo para lidar com a "eleição de líder". Ele escreve nesta tabela com frequência e, se o líder atual não escrever há um curto período, a próxima instância assumirá como líder. É assim que o daemon decide qual instância disparar a tarefa na fila SQS.
Podemos redefinir a finalidade da funcionalidade existente em vez de tentar reescrever a nossa própria. Você pode ver a solução completa aqui: https://gist.github.com/dorner/4517fe2b8c79ccb3971084ec28267f27
Isso está em Ruby, mas você pode adaptá-lo facilmente a qualquer outra linguagem que tenha o SDK da AWS. Basicamente, ele verifica o líder atual e, em seguida, verifica o estado para ter certeza de que está em bom estado. Ele fará um loop até que haja um líder atual em bom estado e, se a instância atual for o líder, execute o trabalho.
fonte
http://docs.aws.amazon.com/autoscaling/latest/userguide/as-instance-termination.html#instance-protection
fonte
Eu tinha outra solução para isso se um arquivo php precisa ser executado por meio do cron e se você definiu qualquer instância NAT, então você pode colocar o cronjob na instância NAT e executar o arquivo php através do wget.
fonte
aqui está uma correção caso você queira fazer isso em PHP. Você só precisa de cronjob.config em sua pasta .ebextensions para fazê-lo funcionar assim.
o envvars obtém as variáveis de ambiente para os arquivos. Você pode depurar a saída no tmp / sendemail.log como acima.
Espero que isso ajude alguém, pois certamente nos ajudou!
fonte
Com base nos princípios da resposta do usuário 1599237 , em que você permite que os cron jobs sejam executados em todas as instâncias, mas, em vez disso, no início dos jobs, determine se eles devem ser executados, fiz outra solução.
Em vez de olhar para as instâncias em execução (e ter que armazenar sua chave e segredo da AWS), estou usando o banco de dados MySQL ao qual já estou me conectando de todas as instâncias.
Não tem desvantagens, apenas pontos positivos:
Como alternativa, você também pode usar um sistema de arquivos comumente compartilhado (como AWS EFS por meio do protocolo NFS) em vez de um banco de dados.
A solução a seguir foi criada dentro da estrutura PHP Yii, mas você pode adaptá-la facilmente para outra estrutura e linguagem. Além disso, o manipulador de exceções
Yii::$app->system
é um módulo meu. Substitua-o pelo que você estiver usando.Este é o esquema de banco de dados que estou usando:
fonte