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

标签 docker amazon-ec2 terraform packer user-data

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

我创建了一个自定义镜像,它从存储库中提取一些 Assets 作为 Packer 构建的一部分,然后创建一个在下次启动时运行脚本的服务。当我从这个 AMI 启动实例时,我包含一个用户数据脚本,它只是创建一个 prop 文件,然后将一些值回显到 prop 文件中。然后服务脚本从用户数据(如果存在)或默认值创建一个 Prop 文件,然后使用这些 Prop 启动 Assets 。

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

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

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

编辑:为了澄清, Assets 确实运行,所以我知道服务正在成功执行。但是,它们使用的是默认 Prop ,并且 configure.sh 中提到的标志或应该由用户数据创建的文件都不存在。

最佳答案

用户数据脚本通过 cloud-init 执行,一个守护进程,可以在创建/启动时配置实例,独立于镜像中的内容。

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

如果您想要在没有 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

并将其作为守护程序运行,确保它在启动过程中很早就开始。

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

关于docker - 如何使用 Packer 创建一个接受用户数据的自定义 Linux AMI,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51144582/

相关文章:

amazon-web-services - 适用于私有(private)容器镜像的 AWS Batch

linux - 克隆 git 存储库时权限被拒绝

security - AWS 限制从云端到负载均衡器的访问

docker - 查找 `k8s.gcr.io/kubernetes-zookeeper:1.0-3.4.10` 的 Dockerfile 构建

docker - 我想在容器中打印 docker run 环境变量

docker - 节点关闭后,Pods不在另一个节点上运行

django 服务器(托管在 ec2 ubuntu 上)对多个用户失败

terraform - 在 Terraform 中使用 for-each 循环本地 json

Terraform 在应用时从远程 URL 下载本地文件并在销毁时删除文件

azure - Terraform 如何跳过 1 个工作区的参数