我读到您只能在 EC2 AMI 上运行一次 userdata。如果您从 EC2 实例创建自定义 AMI,则无法在该自定义 AMI 上运行 userdata 脚本。在 Ubuntu 实例上,您可以删除 /var/lib/cloud/* ,创建自定义 AMI 并在自定义 AMI 上运行 userdata。我在 FreeBSD 上找不到 /var/lib/cloud/* 的等效项。
有没有办法在自定义 FreeBSD AMI 上运行 userdata 或创建 AMI 的替代方法,以便您可以再次运行 userdata 脚本?
Linux 有#cloud-boothook,但对于 FreeBSD,我只找到了 configinit,它不能满足我的需要。我们在启动实例时将参数从命令行传递到用户数据脚本中。
答案1
AWS 上的 FreeBSD AMI 不提供与其他 AMI 相同级别的 user_data 脚本支持。正如您所指出的,它不支持#cloud-boothook
user_data 并且忽略启动后传递的任何 user_data。
一个简单的解决方案如下:
sed -i '' '/KEYWORD: *firstboot$/d' /usr/local/etc/rc.d/ec2_configinit
这是一个 hack——您的实例现在将执行所有 user_data 脚本,甚至是那些没有标签的脚本#cloud-boothook
,但在我看来,它比脚本的默认行为要好得多。请注意,人们始终可以ec2_configinit
通过在/etc/rc.conf
.
答案2
我提供我自己的答案,因为接受的答案非常粗糙。
更新:我认为接受的答案非常粗糙,但最终我还是使用它因为它最适合我。这里的其余部分只是提供一些可能对某些人有用的额外背景。接受的答案最终最适合我,因为:(1)它允许我始终执行 shell 脚本,(2)除了按照我在下面解释的方式处理用户数据文件之外,它不执行任何其他操作,( 3)如果我愿意,我仍然可以在 rc.conf 中禁用它。
问题是,即使在 Amazon Linux 上,用户数据脚本也仅在首次启动时执行,除非您使用 MIME 多部分/混合技巧。你可以查查看https://cloudinit.readthedocs.io/en/latest/topics/format.html但我举了一个突破极限的例子:
Content-Type: multipart/mixed; boundary="schnipp-schnapp"
MIME-Version: 1.0
--schnipp-schnapp
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]
--schnipp-schnapp
Content-Type: text/x-shellscript; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename="user-data.sh"
#!/bin/bash
echo "Hello World." >> /etc/motd
--schnipp-schnapp
Content-Type: text/x-shellscript; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename="another.sh"
#!/bin/bash
echo "Kilroy was here." >> /etc/motd
--schnipp-schnapp
Content-Type: image/jpeg
MIME-Version: 1.0
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="imput64-8503-small.jpg"
/9j/4AAQSkZJRgABAQEAlgCWAAD/2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcU
FhYaHSUfGhsjHBYWICwgIyYnKSopGR8tMC0oMCUoKSj/2wBDAQcHBwoIChMKChMoGhYaKCgoKCgo
...
JFSUkfQjjHr9yT2T9SSSdLS15R/qM64pbLRUcsExOk6axzpxhiQATFSDIB6E68K/c6WlrzEoTypl
JoceL9zq7NbXis8oopa6RRNUQovmNlCM5IIzxQLkgkD0wQCAFLYaXzKkSSVEkzOZXqJJOUjsfXkf
cknJOMk++lpa9u+AGkJwsuJACiqCeJGm5pJiZJXBr4Sx04IfzZiS3I9r3/TQakADkD260tLWjxQk
hE9/tVFgPm8K/9k=
--schnipp-schnapp--
我发现这两个脚本是按字母顺序执行的,而图像部分被忽略了。
除非 FreeBSD AMI 维护者实现这个多部分内容及其涉及的所有内容
- 文本/云引导
- 文本/云配置
- 文本/云配置存档
- 文/jinja2
- 文本/部分处理程序
- 文/新贵工作
- 文本/x-include-once-url
- 文本/x-include-url
- 文本/x-shell脚本
为什么您希望 ec2-cloudinit 执行的所有其他操作始终像这样执行?最终你只能靠自己了。
自己获取用户数据并决定如何处理它确实没有什么坏处。以下是获取它的方法:
fetch -q -o - http://169.254.169.254/latest/user-data
所以,如果你想执行它,你可以将它放入 rc.local 中:
fetch -q -o - http://169.254.169.254/latest/user-data |sh
或者
fetch -q -o /tmp/user-data.sh http://169.254.169.254/latest/user-data
mkdir 700 /tmp/user-data.sh
/tmp/user-data.sh
真的没什么大不了的。不确定支持复杂的多部分结构是否值得。 FreeBSD AMI 的做法非常不同,而且更简单,而且可以说还不错。
- 如果它以 hash-bang #! 开头它将被保存并执行
- 如果它以“">/var/tmp/here”开头,它将被写入指定的目的地
- 如果它以“>>/var/tmp/here”开头,它将被附加到如此指定的目的地
- 否则,它将被视为 shell 脚本的未压缩 tar 存档,进行扩展,然后使用上述规则执行每个文件。
因为它不是 AWS 标准,所以我不会理会它。只需有一个脚本并强制它在 rc.local 中执行,或者甚至不执行,只是检查以找到以某种方式控制行为的参数。