2011-06-25 177 views
41

我有一个基于Amazon Linux AMI运行AMI的EC2实例。像所有这样的AMI一样,它支持cloud-init系统根据传递到每个实例的用户数据来运行启动脚本。在这种特殊情况下,我的用户数据输入恰好是一个包含文件来源的其它几个启动脚本:如何在每次启动EC2实例时运行cloud-init启动脚本?

#include 
http://s3.amazonaws.com/path/to/script/1 
http://s3.amazonaws.com/path/to/script/2 

我第一次开机我的实例中,云初始化启动脚本正确运行。但是,如果我对该实例执行软重启(例如,通过运行sudo shutdown -r now),则该实例会在第二次运行启动脚本时返回而没有。如果我去到系统日志,我可以看到:

Running cloud-init user-scripts 
user-scripts already ran once-per-instance 
[ OK ] 

这不是我想要的东西 - 我可以看到具有唯一的每个实例寿命运行一次启动脚本的效用,但对我来说,这些应该每次启动实例时都要运行,就像正常的启动脚本一样。

我意识到一种可能的解决方案是手动让我的脚本在第一次运行后自行插入rc.local。然而,这看起来很繁琐,因为cloud-init和rc.d环境略有不同,我现在必须在首次启动和所有后续启动时分别调试脚本。

有谁知道我如何告诉cloud-init总是运行我的脚本?这听起来像是cloud-init的设计师会考虑的事情。

回答

42

在11.10,12.04和更高版本中,您可以通过使'scripts-user'运行'always'来实现此目的。 在/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 

也可以像您在描述中所做的那样'#included'。 不幸的是,现在,您无法修改'cloud_final_modules',只能覆盖它。我希望增加修改配置部分的功能。

有关于这方面的云配置文档在 http://bazaar.launchpad.net/~cloud-init-dev/cloud-init/trunk/view/head:/doc/examples/cloud-config.txt

更多的信息,或者,你可以把文件在/ var/lib中/云/脚本/每引导,他们会按'脚本每启动'路径运行。

+1

>我希望增加修改配置部分的功能。 现在是否已添加此功能?我发现最新的cloud-init中有一个“合并”功能,但我不知道如何使用它来只改变'scripts-user'这一行。无论我通过的选项如何,它都会覆盖整个列表。 – Meta

+2

下面是一个在线修改的代码:'sed -i's/scripts-user $/\ [scripts-user,always \] /'/ etc/cloud/cloud.cfg' – wjordan

+0

将文件放入'/ var/lib/cloud/scripts/per-boot'似乎更容易,我可以使用它来设置[auto ec2 shutdown](http://stackoverflow.com/a/38186787/4058484)。 – hyip

7

一种可能性,尽管有点冒失,但是要删除cloud-init用来确定用户脚本是否已经运行的锁定文件。在我的情况下(亚马逊Linux AMI),这个锁文件位于/var/lib/cloud/sem/中,并且被命名为user-scripts.i-7f3f1d11(末尾的散列部分每次启动都会改变)。因此,以下用户数据脚本添加到包含文件的末尾将这样的伎俩:

#!/bin/sh 
rm /var/lib/cloud/sem/user-scripts.* 

我不知道这是否会对别的任何不良影响,但它已经在我的工作实验。

+1

“哈希部分”似乎是一个亚马逊机器ID¿是不是? – theist

+1

它看起来像一个AWS实例ID,在这种情况下,它会随着每个实例的启动而改变,但在同一个实例的停止和重新启动期间保持不变。 – froggythefrog

18

/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 

/usr/bin/cloud-init-run-module always user-scripts execute run-parts ${SCRIPT_DIR} >/dev/null && success || failure 

祝你好运!

+4

适用于亚马逊Linux AMI ... – rbawaskar

4

云初始化支持此现在本身,参见RUNCMD VS的文档中bootcmd命令描述(http://cloudinit.readthedocs.io/en/latest/topics/examples.html#run-commands-on-first-boot):

“RUNCMD”:

#cloud-config 

# run commands 
# default: none 
# runcmd contains a list of either lists or a string 
# each item will be executed in order at rc.local like level with 
# output to the console 
# - runcmd only runs during the first boot 
# - if the item is a list, the items will be properly executed as if 
# passed to execve(3) (with the first arg as the command). 
# - if the item is a string, it will be simply written to the file and 
# will be interpreted by 'sh' 
# 
# Note, that the list has to be proper yaml, so you have to quote 
# any characters yaml would eat (':' can be problematic) 
runcmd: 
- [ ls, -l,/] 
- [ sh, -xc, "echo $(date) ': hello world!'" ] 
- [ sh, -c, echo "=========hello world'=========" ] 
- ls -l /root 
- [ wget, "http://slashdot.org", -O, /tmp/index.html ] 

“bootcmd”:

#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 ] 

也记录了bootcmd中的“cloud-init-per”命令示例。从它的帮助:

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 
+0

更新回答来自官方文档的相应引文,并链接到原始文档,仅供参考 –

+1

bootcmd部分在未完全引导并且可能无法正常工作的系统上执行。 – Nico

0

我这个问题挣扎了近两天,尝试了所有的解决方案,我能找到,最后,结合几种方法,具有以下传来:

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_west: 
      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跨区域复制过程的设置。