我们在初始一个 AWS EC2 实例时,可以通过 user data 让 EC2 第一次启动后做些事情,可以放置 shell script 或 cloud-init 指令。在控制台设置 user data 可用明文文本,由 awscli 创建时可使用一个文件,或者通过 API 用 base64 编码的内容。
下面是 user data 被执行时需知晓的一些知识
- 是脚本时必须以
#!
开始,俗称 Shebang, 如#!/bin/bash
- user data是以
root
身份执行,所以不要用sudo
, 当然创建的目录或文件的 owner 也是root
,需要ec2-user
用户访问的话需要chmod
修改文件权限,或者直接用chown ec2-user:ec2-user -R abc
修改文件的所有者() - 脚本不能交互,有交互时必须想办法跳过用户输入,如
apt install -y xzy
, 带个-y
标记 - 如果脚本中需访问 AWS 资源,权限由 Instance Profile 所指定的 IAM role 决定
- user data 中的脚本会被存储在
/var/lib/cloud/instances/<instance-id>/user-data.txt
文件中,因此也可以从这里验证 user data 是否设置正确。或者在 EC2 实例上访问 http://169.254.169.254/latest/user-data 也能看到 user data 的内容。并且在 EC2 实例初始化后不被删除,所以以此实例为基础来创建一个新的 AMI 需把它删除了 - user data 的大小限制为 16 KB, 指 base64 编码前的大小
- cloud-init 的输出日志在
/var/log/cloud-init-output.log
, 它会捕获 cloud-init 控制台的输出内容
user data 的内容通常在创建好实例后,还得等一会才完全生效,马上用 SSH 登陆新创建后的实例一般还看不到效果,有可能得等分把钟。
下面是在一个选择了 Ubuntu 18.04 镜像的 EC2 实例的 user data 样例 -- 用来安装 Python 3.9, 并创建虚拟环境, 安装 Python 组件
1 2 3 4 5 6 7 8 9 10 |
#!/bin/bash apt update apt install awscli -y apt install software-properties-common -y add-apt-repository ppa:deadsnakes/ppa -y apt update apt install python3.9 python3.9-venv -y python3.9 -m venv /home/ec2-user/py3.9-venv /home/ec2-user/py3.9-venv/bin/pip install boto3 pymongo psycopg2-binary chown -R ec2-user:ec2-user /home/ec2-user/py3.9-venv |
脚本的内容会存储在 EC2 实例上,但它执行的控制台输出却没地方找,如果脚本执行过程中有问题就难以诊断了,这里有个办法可记录下 user data 中脚本执行的控制台输出,需在 user data 中加上一行,最后把调试也打开
1 2 3 4 |
#!/bin/bash -ex exec > >(tee /var/log/user-data.log|logger -t user-data -s 2>/dev/console) 2>&1 apt update ...... |
对,你没有看错,上面的 exec > >(...
两个大括号之间有空格
这样就能在实例的 /var/log/user-data.log
中看到所有 user data 中脚本执行的控制台输出了,错在哪一步也就能有的放矢的修正。
比如本人有一次发现 user data 中的脚本没发生作用,就查看 /var/log/user-data.log
中的内容发现错误信息
E: Could not get lock /var/lib/dpkg/lock-frontend - open (11: Resource temporarily unavailable)
E: Unable to acquire the dpkg frontend lock (/var/lib/dpkg/lock-frontend), is another process using it?
原来是还有一个进程也在执行 apt,继而 Google 到 apt-daily.service 启动的时候在干那事,查看它的日志
$ journalctl -u apt-daily.service
-- Logs begin at Thu 2021-09-09 07:38:01 UTC, end at Sat 2021-09-18 17:29:41 UTC. --
Sep 18 17:23:21 lin-0aff3d81.mstarext.com systemd[1]: Starting Daily apt download activities...
Sep 18 17:23:46 lin-0aff3d81.mstarext.com systemd[1]: Started Daily apt download activities.
所以在 user data 需要避开它,我们的 user data 可以加一个 sleep 30
进行延迟执行,30 不够的话就 sleep 60
。
已启动 EC2 实例的 user data 只允许在实例停止后被修改,但修改后的内容并不会在重启后得到执行,只不过是更新了一下文件 /var/lib/cloud/instances/<instance-id>/user-data.txt
中内容,无用功,难道是在掩盖现场?
How can I utilize user data to automatically run a script with every restart of my Amazon EC2 Linux instance?(user data 设计为只在第一次初始化 EC2 实例时起作用,有人曲折的方式让实例每次重启时也执行 user data 中的内容,个人觉得没多大意义,每次启动执行何不做成一个服务呢?)
关于 cloud-init 指令式的 user data
要在 user data 中放置 cloud-init
指令, 需在 user data 的第一行写上 #cloud-config
。cloud-init 的用户可比脚本复杂了,它能做一些更高级的事情。这里就不深究,暂时还感觉不到非得用 cloud init
指令不成的境地,下面只看一个节选自官方的例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
#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' ] |
它是 YAML 文件格式,比起用脚本可难看多了, runcmd 中一会用 sh 加中括号参数的形式,一会又直接 shell 脚本。个人认为上面的 sudo
是不需要的。
cloud-init 指令应该与系统中的 cloud-init
命令是相关的,EC2 实例中可以看到一个配置文件 /etc/cloud/cloud.cfg
.
#cloud-config
形式的执行输出到控制台的内容会写到 /var/log/cloud-init-out.log
文件中,希望它记录下更多 cloud-init 执行时调试信息的话,在 user data 的 cloud-init 指令中加上一句
1 |
output : { all : '| tee -a /var/log/cloud-init-output.log' } |
链接:
- Work with instance user data
- Logging user-data Script Output on EC2 Instances
- Run commands on your Linux instance at launch
- How to Fix 'E: Could not get lock /var/lib/dpkg/lock/log' Error in Ubuntu Linux
- How can I utilize user data to automatically run a script with every restart of my Amazon EC2 Linux instance?
[…] EC2 的 Linux 实例,所以之前写过的一篇关于 UserData 的日志 创建 AWS EC2 实例时 userdata 的一些知识 默认就是讲的有关 Linux 实例的 UserData。本文补充上 Windows 的 EC2 实例 UserData […]