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

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

目标是创建最终用户可以通过包含外部数据库或其他实例特定配置来自定义的 AMI。

我创建了一个自定义映像,作为 Packer 构建的一部分从回购中提取一些资产,然后创建一个服务,该服务 运行 在下次启动时是一个脚本。当我从这个 AMI 启动实例时,我包含了一个用户数据脚本,它只创建一个 prop 文件,然后将一些值回显到 prop 文件中。然后服务脚本根据用户数据或默认值创建一个道具文件,然后使用这些道具启动资产。

但是,我启动实例后,该文件不是由用户数据创建的。我发现有些东西说这是每个实例 ID 一次 运行,但这是一个新实例。

我已经尝试将用户数据作为服务脚本的一部分获取,wget http://169.254.169.254/latest/user-data,作为打包程序构建过程的一部分删除与用户数据关联的状态文件,因此 user_data 将是在实例化 AMI 时再次 运行,rm -Rf /var/lib/cloud/*,在用户数据前加上 #cloud-boothook,这样每次 运行s 而不是第一次启动。但是,用户数据脚本中的 tmp 文件不存在,资产仅以默认值开头。

打包机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

<pull assets>
...
mv /tmp/myservice.service /lib/systemd/system/myservice.service
sudo systemctl enable 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>
...

地形

...
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
}
...

编辑:澄清一下,资产 运行,所以我知道服务正在成功执行。但是,他们使用的是默认道具,configure.sh 中提到的标志或本应由用户数据创建的文件都不存在。

用户数据脚本通过 cloud-init 执行,这是一个守护程序,可以在 creation/boot 时间配置实例,独立于图像中的内容。

因此,如果您想使用用户数据,您可能需要确保在您的映像中安装了 cloud-init。这里最简单的选择是简单地从已经安装了 cloud-init 的预先存在的 AMI 创建您的 AMI,例如 Amazon Linux,官方 Canonical 提供 Ubuntu AMI,官方 Red Hat 提供 Red Hat图片等。或者,您应该能够通过发行版的包管理器安装它。

如果您想要在 AWS 没有 cloud-init 的情况下以最小的方式执行用户数据脚本(例如对于 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

并且运行这是一个守护进程,确保它在引导过程的早期启动。

这将从 EC2 元数据端点抓取用户数据脚本,然后执行它,将输出写入 cloud-init 的典型日志位置,然后确保它仅在第一次启动时使用信号量文件执行它在 运行ning.

之前检查