Как я могу создать собственный Linux AMI с Packer, который принимает пользовательские данные

Цель состоит в том, чтобы создать AMI, который конечный пользователь может настроить, включив внешнюю базу данных или другую конфигурацию конкретного экземпляра.

Я создал собственный образ, который извлекает некоторые ресурсы из репо как часть сборки Packer, а затем создает службу, которая запускает сценарий при следующей загрузке. Когда я запускаю экземпляр из этого AMI, я включаю сценарий пользовательских данных, который просто создает файл опоры, а затем отображает некоторые значения в файле опоры. Затем служебный скрипт создает файл опоры из пользовательских данных, если он существует, или из значений по умолчанию, а затем запускает ресурсы с этими реквизитами.

Однако после запуска экземпляра файл не создается пользовательскими данными. Я нашел кое-что, в котором говорится, что это запускается один раз для каждого идентификатора экземпляра, но это новый экземпляр.

Я попытался получить пользовательские данные как часть служебного сценария wget http://169.254.169.254/latest/user-data, удалив файлы состояния, связанные с пользовательскими данными, как часть процесса сборки упаковщика, поэтому user_data будет запускаться снова при создании экземпляра AMI, rm -Rf /var/lib/cloud/*, добавляя пользователя data с #cloud-boothook, чтобы он запускался каждый раз, а не только при первой загрузке. Однако файл 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>
...

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

Изменить: чтобы уточнить, активы запускаются, поэтому я знаю, что служба выполняется успешно. Однако они используют свойства по умолчанию, и ни флаги, упомянутые в configure.sh, ни файл, который должен был быть создан пользовательскими данными, отсутствуют.


person thejames42    schedule 02.07.2018    source источник


Ответы (1)


Скрипты пользовательских данных выполняются с помощью cloud-init, демона, который может настраивать экземпляры при создании / время загрузки независимо от того, что встроено в образ.

Таким образом, если вы хотите использовать пользовательские данные, вы, вероятно, захотите убедиться, что в вашем образе установлен cloud-init. Самый простой вариант здесь - просто создать свой AMI из уже существующего AMI, в котором уже установлен cloud-init, такой как Amazon Linux, официальные образы Ubuntu, предоставленные Canonical, официальные образы 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, а затем убедитесь, что он выполняется только при первой загрузке с файлом семафора, который он проверяет перед запуском. .

person ydaetskcoR    schedule 03.07.2018
comment
Лучше, чем касаться boot-finished, - записать instance-id (из curl http://169.254.169.254/latest/meta-data/) и повторно запустить, если оно изменилось. - person Rickard von Essen; 03.07.2018
comment
@RickardvonEssen хороший крик, добавил это в пример скрипта облачной инициализации гетто. - person ydaetskcoR; 03.07.2018