в AWS выполняется ли user_data до cloud-init?

Я использую terraform для создания экземпляра EC2 и использую user_data для помещения файла в /var/lib/cloud/scripts/per-once. Это не выполняется - теперь мой вопрос: запускается ли cloud-init до user_data?

=== РЕДАКТИРОВАТЬ ===

Более длинный ответ на очень полезный ответ Dude0001:

Я пробовал вот что - это мой user_data:

#!/bin/bash
cat >/var/lib/cloud/scripts/per-once/install_mysql <<!
#cloud-config

package_update: true

packages:
  - mysql-server

!

cat >>/root/.bashrc <<!
set -o vi
unalias -a
alias ll='ls -lp'
!

cat >>/home/admin/.bashrc <<!
set -o vi
unalias -a
alias ll='ls -lp'
!

cat /root/.vimrc <<!
set t_ti= t_te=
set compatible
set expandtab ts=2 sw=2 ai
!

cat >/home/admin/.vimrc <<!
set t_ti= t_te=
set compatible
set expandtab ts=2 sw=2 ai
!

Это создает все файлы, как и ожидалось (я действительно старомоден и не люблю большинство новых функций vim). Я попытался перезагрузиться после создания экземпляра: нет mysqld. Я изменил разрешения, chmod 755 / var / lib / cloud / scripts / per-once / install_mysql, и перезагрузился: тоже нет результата (причина, по которой я изменил разрешения, заключается в том, что он появляется из кода Python, который cloud-init ищет только исполняемые файлы).

=== РЕДАКТИРОВАТЬ ===

Некоторые пояснения к моему user_data выше:

Эта конструкция может ввести в заблуждение некоторых, поскольку она не слишком распространена:

cat >/some/path/to/a/file <<!
...
!

cat - это команда, которая просто читает из стандартного ввода и записывает в стандартный вывод без изменений - она ​​часто используется с перенаправлением < и >. В приведенной выше конструкции я направляю любой вывод в файл /some/path/to/a/file. Другая часть, включающая <<! и !, известна как здесь документ, что, как я подозреваю, происходит от языка JCL, используемого на мэйнфреймах, но это действительно полезно. Это означает прочитать следующие строки до маркера конца (здесь: !, но это может быть любая строка). Итак, в общем, он говорит создать файл со следующим содержимым: ....

Первый файл /var/lib/cloud/scripts/per-once/install_mysql содержит:

#cloud-config

package_update: true

packages:
  - mysql-server

Я надеюсь, что это должно указать cloud-init обновить репозиторий пакетов и установить mysql-server - этого не происходит.

Следующие 4 файла представляют собой лишь некоторую настройку в root и admin пользовательских средах; в основном я создаю .vimrc и добавляю несколько строк к .bashrc, чтобы убедиться, что некоторые вещи настроены по моему вкусу.

Все файлы созданы, но файл с #cloud-config, похоже, вообще не трогается. Вчера я провел несколько экспериментов, поместив этот файл в разные каталоги в /var/lib/cloud/scripts/, но это выглядит так, как будто этих файлов нет на месте, когда cloud-init читает каталоги. При чтении исходного кода cloud-init он выглядит так, как будто он проходит через 10 этапов - user_data выбирается на этапе 5, и его нужно читать на этапе 7. Я также вижу, что для этого, похоже, требуется установить бит разрешения на выполнение; однако это то, что остается в журнале после перезагрузки:

2019-10-02 08:06:52,884 - handlers.py[DEBUG]: start: modules-final/config-scripts-per-boot: running config-scripts-per-boot with frequency always
2019-10-02 08:06:52,884 - helpers.py[DEBUG]: Running config-scripts-per-boot using lock (<cloudinit.helpers.DummyLock object at 0x7f677362acc0>)
2019-10-02 08:06:52,885 - util.py[DEBUG]: Running command ['/var/lib/cloud/scripts/per-boot/install_mysql'] with allowed return codes [0] (shell=False, capture=False)
2019-10-02 08:06:52,887 - util.py[WARNING]: Failed running /var/lib/cloud/scripts/per-boot/install_mysql [-]
2019-10-02 08:06:52,887 - util.py[DEBUG]: Failed running /var/lib/cloud/scripts/per-boot/install_mysql [-]
Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/cloudinit/util.py", line 1992, in subp
    env=env, shell=shell)
  File "/usr/lib/python3.7/subprocess.py", line 775, in __init__
    restore_signals, start_new_session)
  File "/usr/lib/python3.7/subprocess.py", line 1522, in _execute_child
    raise child_exception_type(errno_num, err_msg, err_filename)
OSError: [Errno 8] Exec format error: b'/var/lib/cloud/scripts/per-boot/install_mysql'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/cloudinit/util.py", line 835, in runparts
    subp(prefix + [exe_path], capture=False)
  File "/usr/lib/python3/dist-packages/cloudinit/util.py", line 2000, in subp
    stderr="-" if decode else b"-")
cloudinit.util.ProcessExecutionError: Exec format error. Missing #! in script?
Command: ['/var/lib/cloud/scripts/per-boot/install_mysql']
Exit code: -
Reason: [Errno 8] Exec format error: b'/var/lib/cloud/scripts/per-boot/install_mysql'
Stdout: -
Stderr: -
2019-10-02 08:06:52,897 - cc_scripts_per_boot.py[WARNING]: Failed to run module scripts-per-boot (per-boot in /var/lib/cloud/scripts/per-boot)
2019-10-02 08:06:52,898 - handlers.py[DEBUG]: finish: modules-final/config-scripts-per-boot: FAIL: running config-scripts-per-boot with frequency always
2019-10-02 08:06:52,898 - util.py[WARNING]: Running module scripts-per-boot (<module 'cloudinit.config.cc_scripts_per_boot' from '/usr/lib/python3/dist-packages/cloudinit/config/cc_scripts_per_boot.py'>) failed
2019-10-02 08:06:52,898 - util.py[DEBUG]: Running module scripts-per-boot (<module 'cloudinit.config.cc_scripts_per_boot' from '/usr/lib/python3/dist-packages/cloudinit/config/cc_scripts_per_boot.py'>) failed
Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/cloudinit/stages.py", line 800, in _run_modules
    freq=freq)
  File "/usr/lib/python3/dist-packages/cloudinit/cloud.py", line 54, in run
    return self._runners.run(name, functor, args, freq, clear_on_fail)
  File "/usr/lib/python3/dist-packages/cloudinit/helpers.py", line 187, in run
    results = functor(*args)
  File "/usr/lib/python3/dist-packages/cloudinit/config/cc_scripts_per_boot.py", line 41, in handle
    util.runparts(runparts_path)
  File "/usr/lib/python3/dist-packages/cloudinit/util.py", line 842, in runparts
    % (len(failed), len(attempted)))
RuntimeError: Runparts: 1 failures in 1 attempted commands

Так что ему определенно не нравится формат файла - он хочет видеть #!... или, возможно, двоичный исполняемый файл.

Попробую сейчас поподробнее опробовать предложения Dude0001.

=== РЕДАКТИРОВАТЬ ===

В конце концов, что действительно работает, так это использование многостраничного / смешанного формата, как предлагает Dude0001:

Content-Type: multipart/mixed; boundary="//"
MIME-Version: 1.0

--//
Content-Type: text/cloud-config; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename="cloud-config.txt"

#cloud-config
package_update: yes
package_upgrade: all

packages:
 - mariadb-server
 - apt-file

--//
Content-Type: text/x-shellscript; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename="userdata.txt"

#!/bin/bash
cat >>/root/.bashrc <<!
set -o vi
unalias -a
alias ll='ls -lp'
!

cat >>/home/admin/.bashrc <<!
set -o vi
unalias -a
alias ll='ls -lp'
!

cat /root/.vimrc <<!
set t_ti= t_te=
set compatible
set expandtab ts=2 sw=2 ai
!

cat >/home/admin/.vimrc <<!
set t_ti= t_te=
set compatible
set expandtab ts=2 sw=2 ai
!

--//

Простое указание #cloud-config, похоже, не работает, но этот способ работает. По крайней мере, для меня. В настоящий момент.


person j4nd3r53n    schedule 30.09.2019    source источник


Ответы (1)


Краткий ответ:

Значение user_data, установленное для сценария оболочки, приведет к запуску данного сценария оболочки на заключительном этапе cloud-init (и я считаю, что после директив cloud-init в одноразовой папке, на которую вы ссылаетесь).

Если вы хотите использовать настраиваемую директиву cloud-init и сценарий оболочки как в свойстве EC2 user_data, вам необходимо использовать формат multipart / mixed mime https://aws.amazon.com/premiumsupport/knowledge-center/execute-user-data-ec2/

Длинный ответ:

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

Если user_data - это необработанные данные, их можно получить с помощью команды curl внутри экземпляра EC2. Вызывающая команда должна интерпретировать данные, это может быть все, что выберет пользователь.

[ec2-user ~]$ curl http://169.254.169.254/latest/user-data

Если user_data является сценарием (например, #!/bin/bash в первой строке), он запускается как шаг в cloud-init на последнем этапе cloud-init https://cloudinit.readthedocs.io/en/latest/topics/boot.html#final.

Если user_data - это директива cloud-init (например, #cloud-config в первой строке), она запускается как указанная директива cloud-init.

Из https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/user-data.html#user-data-cloud-init.

«Чтобы передать директивы cloud-init экземпляру с _10 _..., введите текст директивы cloud-init в текст user_data».

Вот так

#cloud-config
repo_update: true
repo_upgrade: all

packages:
 - httpd
 - mariadb-server

runcmd:
 - [ sh, -c, "amazon-linux-extras install -y lamp-mariadb10.2-php7.2 php7.2" ]
 - systemctl start httpd
 - sudo systemctl enable httpd
 - [ sh, -c, "usermod -a -G apache ec2-user" ]
 - [ sh, -c, "chown -R ec2-user:apache /var/www" ]
 - chmod 2775 /var/www
 - [ find, /var/www, -type, d, -exec, chmod, 2775, {}, \; ]
 - [ find, /var/www, -type, f, -exec, chmod, 0664, {}, \; ]
 - [ sh, -c, 'echo "<?php phpinfo(); ?>" > /var/www/html/phpinfo.php' ]

Составной / смешанный формат mime описан здесь https://aws.amazon.com/premiumsupport/knowledge-center/execute-user-data-ec2/, с примером

Content-Type: multipart/mixed; boundary="//"
MIME-Version: 1.0

--//
Content-Type: text/cloud-config; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename="cloud-config.txt"

#cloud-config
cloud_final_modules:
- [scripts-user, always]

--//
Content-Type: text/x-shellscript; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename="userdata.txt"

#!/bin/bash
/bin/echo "Hello World" >> /tmp/testfile.txt
--//
person Dude0001    schedule 30.09.2019
comment
Это очень полезно, спасибо. Я пробовал простую версию # cloud-config в разных обличьях, чтобы установить mysql-server, но безрезультатно. Как правильно это сделать? Я хочу установить только один раз, конечно, а не каждый раз при перезагрузке - я должен поместить его в ... / per-once, а затем перезагружаться? - person j4nd3r53n; 01.10.2019
comment
Я попробовал несколько вещей, вдохновленных вашим ответом, и отредактировал результаты. - person j4nd3r53n; 01.10.2019
comment
По-прежнему не похоже, что вы используете правильный синтаксис, вам не хватает части Content-Type: multipart / mixed и многих других синтаксисов из отправленного мной примера. Я также не знаком с тем, что делает строка в вашем сценарии оболочки (или сценарии cloud-init, если на то пошло), можете ли вы добавить несколько комментариев к своим user_data, чтобы объяснить, чего вы ожидаете от каждой строки? Извините, я лучше знаком с AWS и cloud-init, чем с другими вещами, которые вы делаете. - person Dude0001; 01.10.2019
comment
Извините, я не видел ваш комментарий раньше - я отредактирую свой вопрос, добавив более подробную информацию. - person j4nd3r53n; 02.10.2019
comment
Это заняло некоторое время, но, наконец, у меня все получилось - когда я использовал многостраничный / смешанный формат. Я обновлю свой пост тем, что я сделал - спасибо за помощь! - person j4nd3r53n; 02.10.2019
comment
Потрясающие! Вы многому научитесь, раскручивая свои собственные сервисы таким образом. Повеселись! - person Dude0001; 02.10.2019