35

在 AWS 中为实例定义用户数据似乎对于执行各种引导类型的操作非常有用。不幸的是,出于 PCI 的原因,我必须使用并非源自提供的 AMI 之一的自定义 CentOS AMI,因此尚未安装和配置 cloud-init。我只希望它设置一个主机名并运行一个小型 bash 脚本。我如何让它工作?

4

4 回答 4

55

cloud-init 是一个非常强大但非常无证的工具。即使安装了它,默认情况下仍有许多处于活动状态的模块会覆盖您可能已经在 AMI 上定义的内容。以下是从头开始进行最小设置的说明:

指示

  1. 从标准存储库安装 cloud-init。如果您担心 PCI,您可能不想使用 AWS 的自定义存储库。

    # rpm -Uvh https://download.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm
    # yum install cloud-init
    
  2. 编辑/etc/cloud/cloud.cfgyaml 文件,以反映您所需的配置。以下是包含每个模块文档的最小配置。

    #If this is not explicitly false, cloud-init will change things so that root
    #login via ssh is disabled. If you don't want it to do anything, set it false.
    disable_root: false
    
    #Set this if you want cloud-init to manage hostname. The current
    #/etc/hosts file will be replaced with the one in /etc/cloud/templates.
    manage_etc_hosts: true
    
    #Since cloud-init runs at multiple stages of boot, this needs to be set so
    #it can log in all of them to /var/log/cloud-init.
    syslog_fix_perms: null
    
    #This is the bit that makes userdata work. You need this to have userdata
    #scripts be run by cloud-init.
    datasource_list: [Ec2]
    datasource:
      Ec2:
        metadata_urls: ['http://169.254.169.254']
    
    #modules that run early in boot
    cloud_init_modules:
     - bootcmd  #for running commands in pre-boot. Commands can be defined in cloud-config userdata.
     - set-hostname  #These 3 make hostname setting work
     - update-hostname
     - update-etc-hosts
    
    #modules that run after boot
    cloud_config_modules:
     - runcmd  #like bootcmd, but runs after boot. Use this instead of bootcmd unless you have a good reason for doing so.
    
    #modules that run at some point after config is finished
    cloud_final_modules:
     - scripts-per-once  #all of these run scripts at specific events. Like bootcmd, can be defined in cloud-config.
     - scripts-per-boot
     - scripts-per-instance
     - scripts-user
     - phone-home  #if defined, can make a post request to a specified url when done booting
     - final-message  #if defined, can write a specified message to the log
     - power-state-change  #can trigger stuff based on power state changes
    
    system_info:
      #works because amazon's linux AMI is based on CentOS
      distro: amazon
    
  3. 如果有defaults.cfgin /etc/cloud/cloud.cfg.d/,删除它。

  4. 要利用此配置,请为新实例定义以下用户数据:

    #cloud-config
    hostname: myhostname
    fqdn: myhostname.mydomain.com
    runcmd:
     - echo "I did this thing post-boot"
     - echo "I did this too"
    

    您也可以通过替换 bash 脚本并将其放入正文中来简单地运行 bash 脚本#cloud-config#!/bin/bash但如果这样做,您应该从cloud_init_modules.


补充说明

请注意,这是一个最小配置,cloud-init 能够管理用户、ssh 密钥、挂载点等。有关这些特定功能的更多文档,请查看下面的参考资料。

一般来说,cloud-init 似乎是根据指定的模块来做事的。一些模块,如“disable-ec2-metadata”,只需指定即可。其他的,比如“runcmd”,只有在 cloud.cfg 或 cloud-config 用户数据中指定了参数时才会执行。下面的大多数文档只告诉您每个模块可以使用哪些参数,而不是模块的名称,但默认的 cloud.cfg 应该有一个完整的模块列表开始。我发现禁用模块的最佳方法就是将其从列表中删除。

在某些情况下,“rhel”可能比“amazon”更适合“distro”标签。我还真不知道什么时候。


参考

于 2014-05-01T15:56:51.933 回答
11

这是关于如何在 AWS EC2 (CentOS) 上 使用cloud-init在启动期间运行脚本的简短教程。

本教程解释:

  • 如何设置配置文件 /etc/cloud/cloud.cfg
  • 云路径的/var/lib/cloud/scripts样子
  • 使用示例的云路径下的脚本文件,以及
  • 如何检查脚本文件是否在实例启动期间执行

配置文件

下面的配置文件在 AWS CentOS6 上。对于 Amazon Linux,请参阅此处

# cat /etc/cloud/cloud.cfg
manage_etc_hosts: localhost
user: root
disable_root: false
ssh_genkeytypes: [ rsa, dsa ]

cloud_init_modules:
 - resizefs
 - update_etc_hosts
 - ssh

cloud_final_modules:
 - scripts-per-once
 - scripts-per-boot
 - scripts-per-instance
 - scripts-user

目录树

这是云路径的/var/lib/cloud/scripts样子:

# cd /var/lib/cloud/scripts
# tree `pwd`
/var/lib/cloud/scripts
├── per-boot
│     └── per-boot.sh
├── per-instance
│     └── per-instance.sh
└── per-once
       └── per-once.sh

脚本文件的内容

以下是示例脚本文件的内容。
这些文件必须在 user 下root。请参阅我创建引导脚本的方法。

# cat /var/lib/cloud/scripts/per-boot/per-boot.sh
#!/bin/sh
echo per-boot: `date` >> /tmp/per-xxx.txt

# cat /var/lib/cloud/scripts/per-instance/per-instance.sh
#!/bin/sh
echo per-instance: `date` >> /tmp/per-xxx.txt

# cat /var/lib/cloud/scripts/per-once/per-once.sh   
#!/bin/sh
echo per-once: `date` >> /tmp/per-xxx.txt

执行结果

在初次启动的情况下

# cat /tmp/per-xxx.txt
per-once: 1 January 3, 2013 Thursday 17:30:16 JST 
per-boot: 1 January 3, 2013 Thursday 17:30:16 JST 
per-instance: 1 January 3, 2013 Thursday 17:30:16 JST

在重新启动的情况下

# cat /tmp/per-xxx.txt
per-once: 1 January 3, 2013 Thursday 17:30:16 JST 
per-boot: 1 January 3, 2013 Thursday 17:30:16 JST 
per-instance: 1 January 3, 2013 Thursday 17:30:16 JST 
per-boot: 1 January 3, 2013 Thursday 17:32:24 JST

从 AMI 开始的情况下

# cat /tmp/per-xxx.txt
per-once: 1 January 3, 2013 Thursday 17:30:16 JST 
per-boot: 1 January 3, 2013 Thursday 17:30:16 JST 
per-instance: 1 January 3, 2013 Thursday 17:30:16 JST 
per-boot: 1 January 3, 2013 Thursday 17:32:24 JST 
per-boot: 1 January 3, 2013 Thursday 17:44:08 JST

参考
在cloud-init(CentOS6)中运行脚本的时间进行了检查(翻译)

于 2016-07-20T10:47:55.823 回答
6

Expanding on the prior answer for anyone trying to create a CentOS AMI that is cloud-init enabled (and capable of actually executing your CloudFormation scripts), you might have some success by doing the following:

  1. launch a marketplace CentOS AMI w/Updates - make sure cloud-init is present or sudo yum install -y cloud-init
  2. rm -rf /var/lib/cloud/data
  3. rm -rf /var/lib/cloud/instance
  4. rm -rf /var/lib/cloud/instances/*
  5. replace /etc/cloud/cloud.cfg with the configuration in the answer above but make sure you set distro: rhel
  6. Add the CloudFormation helpers (http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-helper-scripts-reference.html)
  7. create an AMI image from this instance

Had a heck of a time trying to figure out why my UserData was not being invoked until I realized that the images in the marketplace naturally only run your UserData once per instance AND of course they had already run. Removing the indicators that those had already been executed along with changing the distro: rhel in the cloud.cfg file did the trick.

For the curious, the distro: value should correspond to one of the python scripts in /usr/lib/python2.6/site-packages/cloudinit/distros. As it turns out the AMI I launched had no amazon.py, so you need to use rhel for CentOS. Depending on the AMI you launch and the version of cloud-init, YMMV.

于 2016-10-25T07:55:14.893 回答
0

Thank you to those here who have already clarified so much about cloud-init! However, at least regarding AWS, one issue needs emphasis:

By default, user data scripts and cloud-init directives run only during the first boot cycle when an EC2 instance is launched.

In other words, they will not run during subsequent boots. This is not always mentioned and I suspect is causing confusion. More on this:

cloud-init has to determine whether or not the current boot is the first boot of a new instance or not, so that it applies the appropriate configuration. On an instance’s first boot, it should run all “per-instance” configuration, whereas on a subsequent boot it should run only “per-boot” configuration.

于 2021-03-23T18:54:46.883 回答