AWS Elastic Beanstalk,运行一个cronjob
我想知道是否有办法设置一个cronjob /任务执行每一分钟。 目前我的任何实例都应该能够运行这个任务。
这是我试图做的configuration文件没有成功:
container_commands: 01cronjobs: command: echo "*/1 * * * * root php /etc/httpd/myscript.php"
我不确定这是否是正确的方法
有任何想法吗?
这就是我向Elastic Beanstalk添加cron作业的方法:
在应用程序的根目录创build一个名为.ebextensions的文件夹,如果它不存在的话。 然后在.ebextensions文件夹中创build一个configuration文件。 出于说明目的,我将使用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
这是Elastic Beanstalk的YAMLconfiguration文件。 确保将其复制到文本编辑器中时,文本编辑器将使用空格而不是制表符。 否则,当你将它推送到EB时,你会得到一个YAML错误。
所以这个是创build一个名为01_some_cron_job的命令。 命令按字母顺序运行,因此01确保它作为第一个命令运行。
然后该命令将获取名为some_cron_job.txt的文件的内容,并将其添加到/etc/cron.d中名为some_cron_job的文件中。
该命令然后更改/etc/cron.d/some_cron_job文件的权限。
leader_only键确保该命令仅在被认为是领导者的ec2实例上运行。 而不是运行在您可能正在运行的每个ec2实例上。
然后在.ebextensions文件夹内创build一个名为some_cron_job.txt的文件。 你将把你的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的path。 然后用php的pathreplace一些php脚本。 这显然假设你的cron作业需要运行一个PHP文件。
此外,请确保some_cron_job.txt文件在文件末尾有一个换行符,就像注释所示。 否则cron不会运行。
更新:当Elastic Beanstalk扩展您的实例时,此解决scheme存在问题。 例如,假设您有一个运行cron作业的实例。 您的stream量会增加,因此Elastic Beanstalk会将您扩展到两个实例。 leader_only将确保您只有一个cron作业在两个实例之间运行。 您的stream量减less,Elastic Beanstalk将您缩小到一个实例。 但是不是终止第二个实例,Elastic Beanstalk终止了第一个领导者的实例。 您现在没有任何正在运行的cron作业,因为它们仅在第一个已终止的实例上运行。 请参阅下面的评论。
更新2:只需从下面的评论中明确说明:AWS现在可以防止自动实例终止。 只要启用它在你的领导实例,你很好去。 – 尼古拉斯·Arévalo16年10月28日在9:23
这是现在正式的做法(2015+)。 请先尝试一下,这是目前最简单的方法,也是最可靠的方法。
根据目前的文件,人们可以在他们所谓的工作层上运行定期任务 。
引用文档:
AWS Elastic Beanstalk支持在运行预定义configuration的环境中使用包含容器名称中的“v1.2.0”的解决scheme堆栈的工作环境层的定期任务。 你必须创造一个新的环境。
有趣的是关于cron.yaml的部分:
要调用周期性任务,您的应用程序源包必须在根级别包含一个cron.yaml文件。 该文件必须包含有关您要安排的定期任务的信息。 使用标准的crontab语法来指定这个信息。
更新:我们能够得到这个工作。 以下是我们的经验(Node.js平台)的一些重要问题:
- 当使用cron.yaml文件时,确保你有最新的awsebcli ,因为旧版本不能正常工作。
- 创造新的环境(至less在我们的情况下)至关重要,不只是克隆旧环境。
- 如果您想确保您的EC2 Worker Tier实例支持CRON,请将其
eb ssh
(eb ssh
),并运行cat /var/log/aws-sqsd/default.log
。 它应该报告为aws-sqsd 2.0 (2015-02-18)
。 如果您没有2.0版本,创build您的环境时出错,您需要创build一个新的如上所述。
关于jamieb的回应,以及alrdinleal提到,您可以使用'leader_only'属性来确保只有一个EC2实例运行cron作业。
引用来自http://docs.amazonwebservices.com/elasticbeanstalk/latest/dg/customize-containers-ec2.html :
你可以使用leader_only。 一个实例被选为Auto Scaling组的领导者。 如果leader_only值设置为true,则该命令仅在标记为首领的实例上运行。
我试图在我的eb上实现一个类似的东西,所以将更新我的post,如果我解决它。
更新:
好吧,我现在有使用以下ebconfiguration工作的cronjobs:
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
本质上,我用cronjob创build一个临时文件,然后设置crontab从临时文件读取,然后删除临时文件。 希望这可以帮助。
如上所述,build立任何crontabconfiguration的根本缺陷是它只发生在部署。 随着群集自动扩展,然后退后,它也成为第一台closures的服务器。 另外也不会出现故障,这对我来说是至关重要的。
我做了一些调查,然后与我们的AWS账户专家进行了交谈,以反驳我的想法,并validation了我提出的解决scheme。 你可以用OpsWorks做到这一点 ,虽然有点像使用房子杀死苍蝇。 也可以在任务运行器中使用数据pipe道(Data Pipeline) ,但是在脚本中它的执行能力有限,我需要能够运行PHP脚本,并访问整个代码库。 您还可以在ElasticBeanstalk集群外部专用一个EC2实例,但是不会再进行故障切换。
所以这就是我想出来的,显然是非传统的(正如AWS代表所评论的),可能被认为是黑客行为,但是它工作起来并且在故障切换时是可靠的。 我select了一个使用SDK的编码解决scheme,我将在PHP中展示,尽pipe你可以用你喜欢的任何语言来做同样的方法。
// 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"); }
因此,通过这个步骤以及如何操作…您可以像在每个EC2实例中通常那样从crontab调用脚本。 每个脚本在开头都包含这个(或者每个脚本包含一个单独的文件),它build立一个ElasticBeanstalk对象并检索所有实例的列表。 它只使用列表中的第一个服务器,并检查它是否与自己匹配,如果它继续,则继续,否则它将死亡并closures。 我已经检查过了,返回的列表似乎是一致的,从技术上讲,只需要一分钟左右的一致性,因为每个实例都执行预定的cron。 如果它确实发生了变化,那就没有关系,因为它只是与那个小窗口相关。
这种方式不够优雅,但却适合我们的特定需求 – 这不是要增加额外的服务来增加成本,或者必须有专门的EC2实例,并且在发生任何故障的情况下可以进行故障切换。 我们的cron脚本运行维护脚本,将其放入SQS中,集群中的每个服务器都可以帮助执行。 至less这可能会给你一个替代select,如果它适合您的需求。
-Davey
如果你使用的是Rails,你可以使用when-elasticbeanstalk gem 。 它允许您在所有实例上运行cron作业,或者只运行一个cron作业。 它会检查每一分钟以确保只有一个“领导者”实例,并且如果没有的话,会自动将一个服务器提升为“领导者”。 这是必需的,因为Elastic Beanstalk在部署期间只有领导的概念,并且可以随时在缩放时closures任何实例。
更新我切换到使用AWS OpsWorks,不再维护这个gem。 如果您需要比Elastic Beanstalk基础知识更多的function,我强烈build议切换到OpsWorks。
您真的不想在Elastic Beanstalk上运行cron作业。 由于您将有多个应用程序实例,这可能会导致竞争条件和其他奇怪的问题。 我最近实际上是在这篇文章的页面上发表了博客 (第四或第五篇)。 简短版本:根据应用程序的不同,使用像SQS这样的作业队列或像iron.io这样的第三方解决scheme。
我跟一个AWS支持代理进行了交谈,这就是我们如何为我工作的。 2015解决scheme:
使用your_file_name.config在.ebextensions目录中创build一个文件。 在configuration文件input中:
文件: “/etc/cron.d/cron_example”: 模式:“000644” 所有者:根 组:根 内容:| * * * * * root /usr/local/bin/cron_example.sh “/usr/local/bin/cron_example.sh”: 模式:“000755” 所有者:根 组:根 内容:| #!/斌/庆典 /usr/local/bin/test_cron.sh || 出口 echo“Cron运行在``date` >> /tmp/cron_example.log #现在做只应该在1个实例上运行的任务... “/usr/local/bin/test_cron.sh”: 模式:“000755” 所有者:根 组:根 内容:| #!/斌/庆典 METADATA = /select/ AWS / bin中/ EC2的元数据 INSTANCE_ID =`$ METADATA -i | awk'{print $ 2}'` REGION =`$ METADATA -z | awk'{print substr($ 2,0,length($ 2)-1)}`` #find我们的Auto Scaling组名称。 ASG =`aws ec2 describe-tags --filters“Name = resource-id,Values = $ INSTANCE_ID”\ --region $ REGION - 输出文字| awk'/ aws:autoscaling:groupName / {print $ 5}'` #find组中的第一个实例 FIRST =`aws autoscaling describe-auto-scaling-groups --auto-scaling-group-names $ ASG \ --region $ REGION - 输出文字| awk'/ InService $ / {print $ 4}'| sorting| 头-1“ #testing它们是否相同。 [“$ FIRST”=“$ INSTANCE_ID”] 命令: rm_old_cron: 命令:“rm * .bak” cwd:“/etc/cron.d” ignoreErrors:true
该解决scheme有两个缺点:
- 在后续部署中,Beanstalk将现有的cron脚本重命名为.bak,但cron仍将运行它。 您的Cron现在在同一台机器上执行两次。
- 如果你的环境扩大,你会得到几个实例,所有的运行你的cron脚本。 这意味着您的邮件拍摄重复,或您的数据库存档重复
解决方法:
- 确保任何创buildcron的.ebextensions脚本也会在后续部署中删除.bak文件。
- 具有执行以下操作的帮助程序脚本: – 从元数据获取当前实例ID – 从EC2获取当前的Auto Scaling组名称标签 – 获取该组中的EC2实例列表,按字母顺序sorting。 – 从列表中拿出第一个例子。 – 将步骤1中的实例ID与步骤4中的第一个实例ID进行比较。然后,您的cron脚本可以使用此帮助程序脚本来确定它们是否应该执行。
警告:
- 用于Beanstalk实例的IAM Role需要ec2:DescribeTags和autoscaling:DescribeAutoScalingGroups权限
- 从中select的实例是通过Auto Scaling显示为InService的实例。 这并不一定意味着它们已经完全启动并准备运行你的cron。
如果您使用默认的beanstalkangular色,则不必设置IAMangular色。
使用files
而不是container_commands
更可读的解决scheme:
文件: “/etc/cron.d/my_cron”: 模式:“000644” 所有者:根 组:根 内容:| #覆盖默认电子邮件地址 MAILTO = “example@gmail.com” #每隔五分钟运行一次Symfony命令(以ec2用户身份) * / 10 * * * * ec2-user / usr / bin / php / var / app / current / app / console do:something 编码:纯文本 命令: #删除Elastic Beanstalk创build的备份文件 clear_cron_backup: 命令:rm -f /etc/cron.d/watson.bak
请注意,格式不同于通常的crontab格式,因为它指定用户运行命令为。
当有新领导人出现时,有人在想领导者只是自动扩展问题。 我似乎无法弄清楚如何回复他们的意见,但看到这个链接: http : //blog.paulopoiati.com/2013/08/25/running-cron-in-elastic-beanstalk-auto-scaling-环境/
以下是解决scheme的完整说明:
http://blog.paulopoiati.com/2013/08/25/running-cron-in-elastic-beanstalk-auto-scaling-environment/
要控制Auto Scaling是否可以在缩放时终止特定实例,请使用实例保护。 您可以在Auto Scaling组或单个Auto Scaling实例上启用实例保护设置。 当Auto Scaling启动实例时,该实例将inheritanceAuto Scaling组的实例保护设置。 您可以随时更改Auto Scaling组或Auto Scaling实例的实例保护设置。
我有另一个解决scheme,如果一个PHP文件需要通过cron运行,如果你已经设置任何NAT实例,那么你可以把cronjob NAT实例,并通过wget运行PHP文件。
2017:如果你正在使用Laravel5 +
你只需要2分钟来configuration它:
- 创build一个工作者层
-
安装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代表的讨论,我终于想出了我认为是最好的解决scheme。
与cron.yaml一起使用工作层绝对是最简单的修复方法。 但是,文档没有明确说明的是,这会将工作放在您用于实际运行作业的SQS队列的末尾 。 如果你的cron作业是时间敏感的(尽可能多),这是不可接受的,因为它取决于队列的大小。 一个select是使用一个完全独立的环境来运行cron作业,但我认为这是过度的。
其他一些选项,比如检查是否是列表中的第一个实例,也不是很理想。 如果目前的初审正在closures,该怎么办?
实例保护也可能带来问题 – 如果该实例被locking/冻结,该怎么办?
重要的是理解AWS本身如何pipe理cron.yamlfunction。 有一个SQS守护进程,它使用一个Dynamo表来处理“领导选举”。 它经常写在这张桌子上,如果现在的领导人没有写一会儿,下一个会接任领导。 守护进程如何决定将哪个实例激发到SQS队列中。
我们可以改变现有的function,而不是试图重写我们自己的function。 你可以在这里看到完整的解决scheme: https : //gist.github.com/dorner/4517fe2b8c79ccb3971084ec28267f27
这在Ruby中,但是您可以轻松地将其调整为具有AWS开发工具包的任何其他语言。 本质上,它检查当前的领导,然后检查状态,以确保它处于良好的状态。 它会一直循环,直到当前领导者处于良好状态,并且如果当前实例是领导者,则执行该作业。
这里是一个修复事件,你想在PHP中做到这一点。 您只需在您的.ebextensions文件夹中使用cronjob.config即可正常工作。
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
环境获取文件的环境variables。 你可以像上面那样在tmp / sendemail.log上debugging输出。
希望这可以帮助一个人,因为它肯定帮助我们!
想知道下面的工作
container_commands: 01_some_cron_job: command: "echo '* * * * * ls' | crontab" leader_only: true