この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
困っていた内容
AMI起動時に一度だけプログラムを実行させたい場合は
/var/lib/cloud/scripts/per-once/
配下にスクリプトを作成しておくことで可能でしたが、EC2 Image Builder を使用して AMI を作成した時は、Security best practicesのスクリプトが強制的に実施され、/var/lib/cloud/
配下が削除されてしまいます。
他にも削除されてしまうファイルがありますので詳しくはドキュメントをご参照ください。
Security best practices for EC2 Image Builder
The following script is run as a mandatory step when Linux images are customized with EC2 Image Builder.
どうすればいいの?
/var/lib/cloud/
配下が削除されてしまいますので、削除されない場所にスクリプトを置いて、cloud-initの代わりに独自にユニットファイルを作成して、サービスを登録したAMIを作成します。
やってみる
今回は、一度だけ実行したいので、cloud-initのときと同じように、lock fileの有無で実行するかしないかを判断します。
例) cloud.initの場合は、以下ファイルの有無で判断しています。 /var/lib/cloud/sem/config_scripts_per_once.once
スクリプトを作成する
一度だけ実行したいスクリプト
/home/ec2-user/per-once.txt
にper once!
と書き込むスクリプトを作成しました。
- /root/per-once/scripts/per_once.sh
$ sudo vi /root/per-once/scripts/per_once.sh
#!/bin/bash
FILE="/root/per-once/scripts/per_once.lock"
# ロックファイルがあったら終了
if [ -e $FILE ]; then
echo "exist lock file"
exit
fi
# 実行
cat <<EOF >> /home/ec2-user/per-once.txt
per once !
EOF
# 実行したらlockファイルを作成する
touch /root/per-once/scripts/per_once.lock
$ sudo chmod +x /root/per-once/scripts/per_once.sh
ユニットファイルを作成する
$ sudo vi /etc/systemd/system/test.service
[Unit]
Description=per once script
After=cloud-init.target
[Service]
Restart=no
Type=simple
RemainAfterExit=yes
ExecStart=/root/per-once/scripts/per_once.sh
[Install]
WantedBy=cloud-init.target
自動起動の設定
$ sudo systemctl enable test
Created symlink from /etc/sys:q!
::temd/system/cloud-init.target.wants/test.service to /etc/systemd/system/test.service.
$ sudo systemctl is-enabled test
enabled
上記、設定をAMIにしておきます。
参考までに、ansible playbook で作成した時は以下のようになります。
playbook.yml
- hosts: 127.0.0.1
become: yes
roles:
- setup
├── playbook.yml
└── roles
├── setup
│ ├── files
│ │ ├── per_once.sh
│ │ └── test.service
│ └── tasks
│ └── main.yml
roles/setup/tasks/main.yml
---
- name: mkdir scripts
file:
path: /root/per-once/scripts
state: directory
recurse: yes
- name: Copy /root/scripts/per_once.sh
copy:
src: files/per_once.sh
dest: /root/per-once/scripts/per_once.sh
mode: a+x
- name: Copy /etc/systemd/system/test.service
copy:
src: files/test.service
dest: /etc/systemd/system/test.service
mode: 0644
- name: Enable test service
systemd:
name: test
enabled: yes
Ansible playbookを実行する方法は以下エントリーを見てください。
EC2 Image Builder で Rolesディレクトリを使用してる Ansible Playbook を実行するにはどうしたらいいですか?
確認
AMIから初回起動、ロックファイルが作成され、2回目以降は書き込まれないことを確認します。
$ cat /home/ec2-user/per-once.txt
per once !
# ll /root/per-once/scripts/
total 4
-rw-r--r-- 1 root root 0 Oct 26 22:29 per_once.lock
-rwx--x--x 1 root root 320 Oct 26 22:16 per_once.sh
おまけ
一度だけ実行なので、lockファイルの作成じゃなく、サービスの無効化や削除する方法
/etc/systemd/system/test.service
のExecStart
で以下のように対応します。
- 無効化する
ExecStart=/bin/bash -c "/root/per-once/scripts/per_once.sh && /usr/bin/systemctl disable test"
- 削除する
ExecStart=/bin/bash -c "/root/per-once/scripts/per_once.sh && /usr/bin/systemctl disable test && rm -rf /etc/systemd/system/test.service /root/per-once"