はじめに
というわけでpackerとRundeckを連携させた仕組みを紹介したい。
名付けて「常に最新のOSでインスタンスが立ち上がる仕組み」である。
一応書いておくが本記事は何か定義したり方向性を決定するものではない。
思考実験の結果ただ出来上がっただけのものである。
前提
早速紹介したいのだが前提として以下のようなLaunchJobを使っている必要がある。
同じようなことしていればよく全く同じ必要はない。あくまでサンプル。
LaunchJob
- defaultTab: nodes
description: EC2のインスタンスを作成します。
executionEnabled: true
group: OS最新化グループ/インスタンス作成
id: 8f1f4e4a-9c43-4a51-b0ab-718482aad522
loglevel: INFO
name: インスタンス作成(自動更新対応版)
nodeFilterEditable: false
options:
- description: サーバ名を入力してください。
name: name
required: true
- description: |-
AMIイメージのIDを入力してください。(デフォルト:alma9_last)<br>
さかのぼる場合はhttp://54.65.21.190:4440/project/Project/job/show/940c3365-49ee-4f66-9fa1-8e3bfe820744を実行してidをさがしてください。
name: AMI
required: true
value: alma9_last
- description: 台数を指定してください。(デフォルト1台)
label: 台数
name: count
required: true
value: '1'
- description: インスタンスタイプを指定してください。(デフォルト:t3.micro)
label: インスタンスタイプ
name: instancetype
required: true
value: t3.micro
- description: 私用するキーペア名を指定してください。(デフォルト:aws-1)
name: keyname
required: true
value: aws-1
- description: セキュリティグループを指定してください。(デフォルト:sg-03179fefab86413aa)
name: securitygroup
required: true
value: sg-03179fefab86413aa
- description: サブネットIDを指定してください。(デフォルト:subnet-095c2be997f1ffc36)
name: subnetid
required: true
value: subnet-095c2be997f1ffc36
plugins:
ExecutionLifecycle: null
scheduleEnabled: true
sequence:
commands:
- script: |-
ami=`sudo cat /var/lib/rundeck/ami/@option.AMI@`
aws ec2 run-instances --image-id $ami --count @option.count@ --instance-type @option.instancetype@ --key-name @option.keyname@ --security-group-ids @option.securitygroup@ --subnet-id @option.subnetid@ --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=@option.name@}]'
keepgoing: false
strategy: node-first
uuid: 8f1f4e4a-9c43-4a51-b0ab-718482aad522
1.packerインストール
今回先述のLaunchJobを含めて3つのJobを作ったのだがこれが2つ目になる。
内容としては前回packerのインストールとして記載した手順そのままである。
正直この辺りはRundeckのLaunch時に含めてしまえばいいのだが今回の記事をJobだけで説明したいので作った。

Job自体の定義は以下
1.packerインストール
- defaultTab: output
description: packerをrundeckにインストールします。
executionEnabled: true
group: OS最新化グループ/インスタンス作成
id: b9626365-435f-411e-9036-ace00f1765f1
loglevel: INFO
name: 1.packerインストール
nodeFilterEditable: false
plugins:
ExecutionLifecycle: null
scheduleEnabled: true
sequence:
commands:
- description: yum-utilsインストール
exec: sudo yum install -y yum-utils
- description: hashicorp.repoインストール
exec: sudo yum-config-manager --add-repo https://rpm.releases.hashicorp.com/RHEL/hashicorp.repo
- description: packerインストール
exec: sudo yum -y install packer
keepgoing: false
strategy: node-first
uuid: b9626365-435f-411e-9036-ace00f1765f1
2.OS最新化(AlmaLinux9)
今回作成したJobの3つ目。
このJobが今回の肝である。
この後に少しstep毎の解説を入れようと思う。

Job自体の定義は以下
2.OS最新化(AlmaLinux9)
- defaultTab: output
description: AlmaLinux9のAMIに初期設定とOSの最新化を行います。
executionEnabled: true
group: OS最新化グループ/インスタンス作成
id: 2efa29d8-66a5-4176-9b93-20deb849b907
loglevel: INFO
name: 2.OS最新化(AlmaLinux9)
nodeFilterEditable: false
options:
- description: packerが使用するAWSのアクセスキーを指定します。
label: AWSACCESSKEY
name: AWSACCESSKEY
required: true
secure: true
value: AKIARMBDZBNOHKR7A4FA
valueExposed: true
- description: packerが使用するAWSのシークレットアクセスキーを指定します。
label: AWSSECRETACCESSKEY
name: AWSSECRETACCESSKEY
required: true
secure: true
value: KCL7v0xnceY9m33JUhJN6p0JnsSYJzK/X8As5AXk
valueExposed: true
plugins:
ExecutionLifecycle: null
scheduleEnabled: true
sequence:
commands:
- description: /var/lib/rundeck/packer作成
script: |-
if [ -e /var/lib/rundeck/packer ]; then
echo "Directory Exist"
else
mkdir /var/lib/rundeck/packer
fi
- description: Alma9用jsonファイル作成
script: |
cat << EOL > /var/lib/rundeck/packer/ami.json
{
"builders": [
{
"type": "amazon-ebs",
"ami_name": "AlmaLinux9-{{isotime | clean_resource_name}}",
"temporary_key_pair_type": "ed25519",
"access_key": "@option.AWSACCESSKEY@",
"secret_key": "@option.AWSSECRETACCESSKEY@",
"region": "ap-northeast-1",
"source_ami": "ami-0c376282479945650",
"instance_type": "t3.micro",
"vpc_id": "vpc-093046de5a854c9c5",
"ssh_username": "ec2-user",
"security_group_ids": [
"sg-03179fefab86413aa"
],
"subnet_id": "subnet-095c2be997f1ffc36",
"associate_public_ip_address": true
}
],
"provisioners": [
{
"type": "shell",
"inline": [
"sudo update-crypto-policies --set DEFAULT:SHA1",
"sudo su -c\"echo PubkeyAcceptedAlgorithms=+ssh-rsa >> /etc/ssh/sshd_config\"",
"sudo sed -i \"s/=enforcing/=disabled/\" /etc/selinux/config",
"sudo dnf update -y"
]
}
]
}
EOL
- description: AMIイメージ作成
exec: packer build /var/lib/rundeck/packer/ami.json
plugins:
LogFilter:
- config:
invalidKeyPattern: \s|\$|\{|\}|\\
logData: 'false'
name: lastami
regex: '^ap-northeast-1: (.+)$'
type: key-value-data
- description: AMI用ディレクトリ作成
script: |-
if [ -e /var/lib/rundeck/ami ]; then
echo "Directory Exist"
else
mkdir /var/lib/rundeck/ami
fi
- description: 初回実行用
exec: touch /var/lib/rundeck/ami/alma9_last
- description: 過去分アーカイブ
exec: mv /var/lib/rundeck/ami/alma9_last /var/lib/rundeck/ami/alma9_`date +%Y%m%d%H%M%S`
- description: AMI最新化
exec: echo ${data.lastami} > '/var/lib/rundeck/ami/alma9_last
keepgoing: false
strategy: node-first
uuid: 2efa29d8-66a5-4176-9b93-20deb849b907
ステップ1 /var/lib/rundeck/packer作成
前回記載していなかったがpackerはvalidate時などに結構ファイルを作ったりする。
今回Jobにするにあたって管理上専用のディレクトリを設けたほうがよさそうだったので入れておいた。
そこ!「validateしてないじゃん」とか突っ込んではいけない!
ステップ2 Alma9用jsonファイル作成
ここが要点になる。
内容としては前回と一緒だが実行するコマンドの最後にdnf update -yを入れている。
(当たり前だが)これを入れる事でOS(pkg)の状態がその時点での最新になる。
運用の現場でもやっているところはやっているがなんだかんだ忘れがちなところ。
ここにいれておけば新規サーバ立ち上げ時に意識しなくても最新の状態で上がってくれる。
ステップ3 AMIイメージ作成
これはコマンドそのまま。ステップ2の内容でAMIを作成する。
ただここは少し小技を使っている。
以前紹介したlogfilterというプラグインを使ってログ出力から出来上がったAMIのIDを変数にもらってきている。
ステップ4 AMI用ディレクトリ作成
ステップ5 初回実行用
(ステップ4と5でセット)
ここはすごく悩んだ箇所。
当初はAMIを作成したあとほかのJobのOptionを直接書き換えてしまえばいいとおもっていた。
だが直接書き換えたところ書き換えた内容がRundeckの画面で反映されなかった。
そううまく行かせてはもらえないらしい。
仕方ないので下策っぽいがファイルに書き出す形に路線変更している。
とりあえず目的は達成できるので問題はないがこういった場合Runeckではどうするのがよいのか引き続き検討したい。
ステップ6 過去分アーカイブ
ステップ7 AMI最新化
(ステップ6と7でセット)
やりたいことはステップ7だけなのだが往々にして不測の事態は起こるものなのである程度履歴を保持できるようにした。
AMI用ディレクトリをlsするようなJobでも作っておけば過去のAMIIDを確認しつつ使いたいAMIを指定できる。
そのJobも作ってある。(4個目)

Job自体の定義は以下
amiid確認
- defaultTab: nodes
description: ''
executionEnabled: true
id: 940c3365-49ee-4f66-9fa1-8e3bfe820744
loglevel: INFO
name: amiid確認
nodeFilterEditable: false
nodefilters:
dispatch:
excludePrecedence: true
keepgoing: false
rankOrder: ascending
successOnEmptyNodeFilter: false
threadcount: '1'
filter: 'name: Rundeck'
nodesSelectedByDefault: true
plugins:
ExecutionLifecycle: null
scheduleEnabled: true
sequence:
commands:
- exec: sudo "ls -l /var/lib/rundeck/ami |awk '{print $9}'"
keepgoing: false
strategy: node-first
uuid: 940c3365-49ee-4f66-9fa1-8e3bfe820744
まとめ
あとはこの2.OS最新化(AlmaLinux9)を一週間なり1カ月の頻度でスケジュールしておけば自動でOSの各種アップデートに対応してくれる。
そしてインスタンスを作る側はJobが勝手に最新版を使ってくれるので意識せずに最新のバージョンを使用することができる。
また、最新版で動かない場合は自分で確認して動くバージョンを使ってLaunchできるのでこちらの手がかからない。
大変よい仕組みができた。(使いどころは知らないが)
あとがき
うむ、大変良い仕組みである。
Almalinux9単体では意味がなくpacker単体でも意味がなくRundeck単体でも意味はない。
3つが合わさることでよい仕組みができた。大変満足。
ちなみにjsonファイルを増やせばほかのOSにも適用できるので汎用性も高い。
ただ今回久しぶりにRundeckを触ったらCentos8のリポジトリ使えなくなってるし他も色々動かなくなっていて散々だった。
今後しばらくはAlmalinux9用に作り直しがてら細かい解説記事をちょくちょく書いていく生活をしようとおもう。
とにかく記事が少ないので自分で作らねば。
なお、繰り返しになるが私はRundeckの回し者ではない。
