简体   繁体   English

如何使用Packer创建接受用户数据的自定义Linux AMI

[英]How can I create a custom Linux AMI with Packer that accepts user data

The goal is to create an AMI that the end user can customize by including an external database or other instance specific configuration. 目标是通过包括外部数据库或其他特定于实例的配置来创建最终用户可以自定义的AMI。

I have created a custom image that pulls down some assets from a repo as part of the Packer build, then creates a service which runs a script on next boot. 我创建了一个自定义映像,它可以从repo中下载一些资产,作为Packer构建的一部分,然后创建一个在下次启动时运行脚本的服务。 When I launch the instance from this AMI, I include a user data script which just creates a prop file, then echoes some values into the prop file. 当我从这个AMI启动实例时,我包含一个用户数据脚本,它只创建一个prop文件,然后将一些值回显到prop文件中。 Then the service script creates a prop file from user data if it exists or from default values, then starts the assets with those props. 然后,服务脚本根据用户数据(如果存在)或默认值创建prop文件,然后使用这些props启动资产。

However, after I start the instance, the file is not created by the user data. 但是,在我启动实例后,该文件不是由用户数据创建的。 I've found some stuff saying this is a run once per instance id, but this is a new instance. 我发现有些东西说这是每个实例id运行一次,但这是一个新实例。

I've tried fetching the user data as part of the service script, wget http://169.254.169.254/latest/user-data , removing the state files associated with user data as part of the packer build process so the user_data will be run again when the AMI is instantiated, rm -Rf /var/lib/cloud/* , prepending the user data with #cloud-boothook so that it runs every time instead of just first boot. 我已经尝试将用户数据作为服务脚本的一部分获取, wget http://169.254.169.254/latest/user-data ,删除与用户数据相关联的状态文件,作为打包器构建过程的一部分,因此user_data将是在实例化AMI时再次运行rm -Rf /var/lib/cloud/* ,在#cloud-boothook之前添加用户数据,以便每次运行而不是仅首次启动。 However, the tmp file from the user data script is not present, and the assets only start with default values. 但是,用户数据脚本中的tmp文件不存在,资产仅以默认值开头。

Packer build.json Packer build.json

...
{
  "type": "file",
  "source": "../scripts/bootstrap.sh",
  "destination": "/tmp/bootstrap.sh"
},
{
  "type": "file",
  "source": "../scripts/myservice.service",
  "destination": "/tmp/myservice.service"
},
{
  "type": "shell",
  "environment_vars": [
    "REPO_USERNAME={{user `repo_user`}}",
    "REPO_PASSWORD={{user `rep_password`}}"
  ],
  "execute_command": "echo 'packer' | sudo -S sh -c '{{ .Vars }} {{ .Path }}'",
  "inline": [
    "cd /tmp",
    "chmod +x bootstrap.sh",
    "./bootstrap.sh"
  ]
}
...

bootstrap.sh bootstrap.sh

<pull assets>
...
mv /tmp/myservice.service /lib/systemd/system/myservice.service
sudo systemctl enable myservice.service
...

myservice.service myservice.service

if [ -ne ./user_data_retrieved_flag ]
then
   wget http://169.254.169.254/latest/user-data
   touch user_data_retrieved_flag
fi
if [ -e ./user-data ] && [ -ne ./user_data_processed_flag ]
then
  chmod 755 ./user-data
  ./user-data
  touch user_data_processed_flag
fi
if [ -e /tmp/my_props.properties ]
then
    cat /tmp/my_props
    mv /tmp/my_props /home/ubuntu/my_props
fi
<myResources.start>
...

Terraform Terraform

...
resource "aws_instance" "my_instance" {
  ami = "${var.my_custom_ami}"
  ...
  user_data = <<EOF
    #cloud-boothook
    #!/bin/bash
    touch /tmp/my_props
    echo PROP1=${var.prop1} >> /tmp/my_props
    echo PROP2_USER=${var.db_un} >> /tmp/my_props
    chown ubuntu:ubuntu /tmp/my_props
    chmod 777 /tmp/my_props
    EOF
}
...

Edit: To clarify, the assets do run, so I know the service is executing successfully. 编辑:为了澄清,资产确实运行,所以我知道服务正在成功执行。 However, they are using default props and neither the flags mentioned in configure.sh, or the file which should have been created by the user data are present. 但是,它们使用默认道具,并且既没有configure.sh中提到的标志,也没有应该由用户数据创建的文件。

User data scripts are executed via cloud-init , a daemon that can configure instances at creation/boot time independently from what is baked in to the image. 用户数据脚本通过cloud-init执行, cloud-init是一个守护程序,可以在创建/启动时配置实例,独立于图像的内容。

As such, if you want to use user data you probably want to make sure that cloud-init is installed in your image. 因此,如果您想使用用户数据,您可能希望确保在映像中安装了cloud-init。 The easiest option here is to simple create your AMI from a pre-existing AMI that already has cloud-init installed such as Amazon Linux, the official Canonical provided Ubuntu AMIs, the official Red Hat provided Red Hat images etc. Alternatively you should be able to install it via your distro's package manager. 这里最简单的选择是简单地从已经安装了cloud-init的预先存在的AMI创建AMI,例如Amazon Linux,官方Canonical提供的Ubuntu AMI,官方Red Hat提供的Red Hat图像等。或者你应该能够通过你的发行包管理器安装它。

If you want a minimal way of executing user data scripts in AWS without cloud-init (such as for distros where cloud-init isn't available such as OpenBSD) you could use something like this: 如果您想要在没有 cloud-init的情况下在AWS中执行用户数据脚本的最小方式(例如对于没有 cloud-init的发行版,例如OpenBSD),您可以使用以下内容:

#!/bin/sh

# Ghetto cloud-init to execute EC2 user data scripts

ID="$(curl --silent 169.254.169.254/latest/meta-data/instance-id)"

if [ ! -f /var/lib/cloud/instance/boot-finished ] && [ "$(cat /var/lib/cloud/instance/boot-finished)" != "${ID}" ]; then
  curl --silent 169.254.169.254/latest/user-data -o /tmp/user-data
  chmod +x /tmp/user-data

  /tmp/user-data >> /var/log/cloud-init-output.log 2>&1

  mkdir -p /var/lib/cloud/instance/
  echo "${ID}" > /var/lib/cloud/instance/boot-finished
fi

And run this as a daemon, making sure it starts very early in the boot process. 并将其作为守护进程运行,确保它在启动过程中很早就开始运行。

This will scrape the user data script from the EC2 metadata endpoint and then execute it, writing the output to the typical log location for cloud-init and then make sure it is only executed on first boot with a semaphore file that it checks for before running. 这将从EC2元数据端点抓取用户数据脚本然后执行它,将输出写入cloud-init的典型日志位置,然后确保它仅在首次启动时执行,并使用在运行之前检查的信号量文件。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM