Amazon ec2 如何使cloud init启动脚本在每次EC2实例启动时运行?
我有一个EC2实例运行一个基于AmazonLinuxAMI的AMI。与所有此类AMI一样,它支持系统根据传递到每个实例的用户数据运行启动脚本。在这种特殊情况下,我的用户数据输入恰好是一个包含文件,它源于其他几个启动脚本:Amazon ec2 如何使cloud init启动脚本在每次EC2实例启动时运行?,amazon-ec2,cloud,cloud-init,Amazon Ec2,Cloud,Cloud Init,我有一个EC2实例运行一个基于AmazonLinuxAMI的AMI。与所有此类AMI一样,它支持系统根据传递到每个实例的用户数据运行启动脚本。在这种特殊情况下,我的用户数据输入恰好是一个包含文件,它源于其他几个启动脚本: #include http://s3.amazonaws.com/path/to/script/1 http://s3.amazonaws.com/path/to/script/2 第一次启动实例时,cloud init启动脚本运行正常。但是,如果我对实例进行软重启(例如,通
#include
http://s3.amazonaws.com/path/to/script/1
http://s3.amazonaws.com/path/to/script/2
第一次启动实例时,cloud init启动脚本运行正常。但是,如果我对实例进行软重启(例如,通过运行sudo shutdown-r
),实例将在第二次运行启动脚本的情况下重新启动。如果我进入系统日志,我可以看到:
Running cloud-init user-scripts
user-scripts already ran once-per-instance
[ OK ]
这不是我想要的——我可以看到在每个实例生命周期中只运行一次的启动脚本的实用性,但在我的情况下,这些脚本应该在每次实例启动时运行,就像正常的启动脚本一样
我意识到一个可能的解决方案是在第一次运行后手动将脚本插入rc.local
。然而,这似乎很麻烦,因为cloudinit和rc.d环境有细微的不同,我现在必须在第一次启动和所有后续启动时分别调试脚本
有人知道我如何告诉cloud init始终运行我的脚本吗?这听起来很像cloud init的设计者们会考虑的事情。一种可能,尽管有点黑客味,但它可以删除cloud init用来确定用户脚本是否已经运行的锁文件。在我的例子(Amazon Linux AMI)中,这个锁文件位于
/var/lib/cloud/sem/
中,名为user scripts.i-7f3f1d11
(最后的散列部分在每次启动时都会更改)。因此,添加到Include文件末尾的以下用户数据脚本将实现此目的:
#!/bin/sh
rm /var/lib/cloud/sem/user-scripts.*
我不确定这是否会对其他任何东西产生不利影响,但它在我的实验中起到了作用。在
/etc/init.d/cloud init user scripts
中,编辑这一行:
/usr/bin/cloud-init-run-module once-per-instance user-scripts execute run-parts ${SCRIPT_DIR} >/dev/null && success || failure
到
祝你好运 在11.10、12.04及更高版本中,您可以通过让“脚本用户”运行“始终”来实现这一点。 在/etc/cloud/cloud.cfg中,您将看到如下内容:
cloud_final_modules:
- rightscale_userdata
- scripts-per-once
- scripts-per-boot
- scripts-per-instance
- scripts-user
- keys-to-console
- phone-home
- final-message
这可以在引导后修改,或者可以通过用户数据插入覆盖此节的云配置数据。即,在用户数据中,您可以提供:
#cloud-config
cloud_final_modules:
- rightscale_userdata
- scripts-per-once
- scripts-per-boot
- scripts-per-instance
- [scripts-user, always]
- keys-to-console
- phone-home
- final-message
也可以像您在描述中所做的那样“包括”。
不幸的是,现在您无法修改“cloud\u final\u modules”,只能覆盖它。我希望在某个时候添加修改配置部分的功能
在云配置文档中有更多关于这方面的信息
或者,您可以将文件放入/var/lib/cloud/scripts/per boot中,它们将通过“scripts per boot”路径运行。cloud init现在本机支持此功能,请参阅文档()中的runcmd vs bootcmd命令说明: “runcmd”: “bootcmd”: 还要注意bootcmd中的“cloudinitper”命令示例。从它的帮助:
Usage: cloud-init-per frequency name cmd [ arg1 [ arg2 [ ... ] ]
run cmd with arguments provided.
This utility can make it easier to use boothooks or bootcmd
on a per "once" or "always" basis.
If frequency is:
* once: run only once (do not re-run for new instance-id)
* instance: run only the first boot for a given instance-id
* always: run every boot
我与这个问题斗争了将近两天,尝试了我能找到的所有解决方案,最后结合几种方法,得出以下结论:
MyResource:
Type: AWS::EC2::Instance
Metadata:
AWS::CloudFormation::Init:
configSets:
setup_process:
- "prepare"
- "run_for_instance"
prepare:
commands:
01_apt_update:
command: "apt-get update"
02_clone_project:
command: "mkdir -p /replication && rm -rf /replication/* && git clone https://github.com/awslabs/dynamodb-cross-region-library.git /replication/dynamodb-cross-region-library/"
03_build_project:
command: "mvn install -DskipTests=true"
cwd: "/replication/dynamodb-cross-region-library"
04_prepare_for_apac:
command: "mkdir -p /replication/replication-west && rm -rf /replication/replication-west/* && cp /replication/dynamodb-cross-region-library/target/dynamodb-cross-region-replication-1.2.1.jar /replication/replication-west/replication-runner.jar"
run_for_instance:
commands:
01_run:
command: !Sub "java -jar replication-runner.jar --sourceRegion us-east-1 --sourceTable ${TableName} --destinationRegion ap-southeast-1 --destinationTable ${TableName} --taskName -us-ap >/dev/null 2>&1 &"
cwd: "/replication/replication-west"
Properties:
UserData:
Fn::Base64:
!Sub |
#cloud-config
cloud_final_modules:
- [scripts-user, always]
runcmd:
- /usr/local/bin/cfn-init -v -c setup_process --stack ${AWS::StackName} --resource MyResource --region ${AWS::Region}
- /usr/local/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource MyResource --region ${AWS::Region}
这是DynamoDb跨区域复制过程的设置。请使用bash脚本上方的以下脚本 示例:我正在将hello world打印到我的文件中 在添加到userdata之前停止实例 剧本
另一种方法是在用户数据脚本中使用
#cloud boothook
。从:
云引导钩
- 以#cloud boothook或内容类型开始:text/cloud boothook
- 此内容是引导钩数据。它存储在/var/lib/cloud下的文件中,然后立即执行
- 这是最早的“钩子”没有提供只运行一次的机制。引导钩必须小心 这本身就是一个问题。它在环境中提供了实例ID 变量实例\ ID。使用此变量为每个实例提供一次 引导钩数据集
“散列部分”似乎是一个amazon机器id,不是吗?它看起来像一个AWS实例id,在这种情况下,它会随着每个实例的启动而改变,但在同一实例的停止和重新启动时保持不变。>我希望在某个时候添加修改配置部分的功能。现在是否添加了此功能?我看到最新的cloud init中有一个“合并”功能,但我不知道如何使用它来更改“脚本用户”行。不管我通过了什么选项,它都会覆盖整个列表。这里有一行代码可以进行在线修改:
sed-I's/scripts user$/\[scripts user,always\]/'/etc/cloud/cloud.cfg
将文件放入/var/lib/cloud/scripts/per boot
似乎容易多了,我可以用它来设置。从2017年开始,数据已经转移到其他地方。使用/etc/cloud/cloud.cfg.d/并在那里放置一个新文件。@Chetabahana您知道这是否仍然有效吗?即使使用了sudo chmod a+x run.sh
和sudo chown root:root run.sh
,我也无法让它工作。编辑:事实上,无论我尝试什么,它都会运行内置的东西,但不会运行我自己的可执行文件。我不得不改用crontab.update answer,其中引用了官方文档中的相应引用,并链接到原始文档仅供参考bootcmd部分在未完全启动的系统上执行,可能无法按预期工作。如何使用ec2 UserData中的cloud init per在每次启动时运行cfn init脚本?嘿!我将bash脚本文件复制到/var/lib/cloud/scripts/per instance文件夹中,但是,当我实例化一个实例时,脚本不会运行。请帮助你说你“结合了许多方法”。您能否详细说明一下,您的上述cfn中的哪些项目有助于在每次启动时运行您的userdata脚本?谢谢。@CBP,基本上,AWS::CloudFormation::Init
wi
#cloud-config
# boot commands
# default: none
# this is very similar to runcmd, but commands run very early
# in the boot process, only slightly after a 'boothook' would run.
# bootcmd should really only be used for things that could not be
# done later in the boot process. bootcmd is very much like
# boothook, but possibly with more friendly.
# - bootcmd will run on every boot
# - the INSTANCE_ID variable will be set to the current instance id.
# - you can use 'cloud-init-per' command to help only run once
bootcmd:
- echo 192.168.1.130 us.archive.ubuntu.com >> /etc/hosts
- [ cloud-init-per, once, mymkfs, mkfs, /dev/vdb ]
Usage: cloud-init-per frequency name cmd [ arg1 [ arg2 [ ... ] ]
run cmd with arguments provided.
This utility can make it easier to use boothooks or bootcmd
on a per "once" or "always" basis.
If frequency is:
* once: run only once (do not re-run for new instance-id)
* instance: run only the first boot for a given instance-id
* always: run every boot
MyResource:
Type: AWS::EC2::Instance
Metadata:
AWS::CloudFormation::Init:
configSets:
setup_process:
- "prepare"
- "run_for_instance"
prepare:
commands:
01_apt_update:
command: "apt-get update"
02_clone_project:
command: "mkdir -p /replication && rm -rf /replication/* && git clone https://github.com/awslabs/dynamodb-cross-region-library.git /replication/dynamodb-cross-region-library/"
03_build_project:
command: "mvn install -DskipTests=true"
cwd: "/replication/dynamodb-cross-region-library"
04_prepare_for_apac:
command: "mkdir -p /replication/replication-west && rm -rf /replication/replication-west/* && cp /replication/dynamodb-cross-region-library/target/dynamodb-cross-region-replication-1.2.1.jar /replication/replication-west/replication-runner.jar"
run_for_instance:
commands:
01_run:
command: !Sub "java -jar replication-runner.jar --sourceRegion us-east-1 --sourceTable ${TableName} --destinationRegion ap-southeast-1 --destinationTable ${TableName} --taskName -us-ap >/dev/null 2>&1 &"
cwd: "/replication/replication-west"
Properties:
UserData:
Fn::Base64:
!Sub |
#cloud-config
cloud_final_modules:
- [scripts-user, always]
runcmd:
- /usr/local/bin/cfn-init -v -c setup_process --stack ${AWS::StackName} --resource MyResource --region ${AWS::Region}
- /usr/local/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource MyResource --region ${AWS::Region}
Content-Type: multipart/mixed; boundary="//"
MIME-Version: 1.0
--//
Content-Type: text/cloud-config; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename="cloud-config.txt"
#cloud-config
cloud_final_modules:
- [scripts-user, always]
--//
Content-Type: text/x-shellscript; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename="userdata.txt"
#!/bin/bash
/bin/echo "Hello World." >> /var/tmp/sdksdfjsdlf
--//