我使用 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
!
Run Code Online (Sandbox Code Playgroud)
这会按预期创建所有文件(我真的很守旧,不喜欢 vim 的大多数新功能)。我尝试在创建实例后重新启动:没有 mysqld。我更改了权限chmod 755 /var/lib/cloud/scripts/per-once/install_mysql,然后重新启动:也没有结果(我更改权限的原因是从 python 代码看来,cloud-init 仅查找可执行文件)。
===编辑===
对我上面的一些解释user_data:
这种结构可能会让一些人感到困惑,因为它不太常见:
cat >/some/path/to/a/file <<!
...
!
Run Code Online (Sandbox Code Playgroud)
cat是一个简单地从标准输入读取并写入标准输出而无需更改的命令 - 它通常与重定向<和>. 在上面的构造中,我将所有输出定向到文件/some/path/to/a/file。另一部分涉及<<!并被!称为此处文档,我怀疑它起源于大型机上使用的 JCL 语言,但它确实很有用。意思是读取以下几行,直到结束标记(此处为:!,但它可以是任何字符串)。所以,总而言之,它说创建一个包含以下内容的文件: ...。
第一个文件/var/lib/cloud/scripts/per-once/install_mysql包含:
#cloud-config
package_update: true
packages:
- mysql-server
Run Code Online (Sandbox Code Playgroud)
我希望这应该告诉 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
Run Code Online (Sandbox Code Playgroud)
因此,它肯定不喜欢文件的格式 - 它希望看到一个#!...或可能是二进制可执行文件。
我现在将更详细地尝试 Dude0001 的建议。
===编辑===
最后,有效的是使用 multipart/mixed 格式,正如 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
!
--//
Run Code Online (Sandbox Code Playgroud)
仅仅指定#cloud-config似乎不起作用,但这种方式可以。至少对我来说。在当下。
Dud*_*001 10
简短回答:
设置为 shell 脚本的值user_data将导致给定的 shell 脚本在 cloud-init 的最后阶段运行(我相信在您引用的一次性文件夹中的 cloud-init 指令之后)。
如果您想在 EC2 属性中使用自定义 cloud-init 指令和 shell 脚本,user_data则需要使用 multipart/mixed mime 格式https://aws.amazon.com/premiumsupport/knowledge-center/execute-user-data -ec2/
长答案:
可以user_data保存要通过 EC2 元数据、脚本或 cloud-init 指令读取的原始数据。此外,您可以将其设置为多部分/混合 mime 类型并提供其中的每一个。
如果user_data是原始数据,可以在 EC2 实例内使用curl 命令获取。由调用命令来解释数据,它可以是用户选择的任何内容。
[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#最终的。
如果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 指令传递到实例user_data,请在文本中输入您的 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' ]
Run Code Online (Sandbox Code Playgroud)
此处描述了 multipart/mixed 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
--//
Run Code Online (Sandbox Code Playgroud)