EC2の冪等性について考えてみる。
よ〜んです。
最近これを作って運用している影響でよくEC2を触ります。でもAWS CDKで管理していると、色々トラブりがちです… Session Managerで色々触っていると再現性がどんどん怪しくなっていく…
冪等性とは
同じ操作を何回やっても、結果が同じになること。
数学的にいうと f(f(x)) = f(x) です。関数 f に同じ入力を何度通しても、出力が変わらない。
インフラの文脈ではもう少し広い意味で使われていて、「同じ手順を何度実行しても、同じ状態のサーバーができあがる」 ということですね。
逆に冪等じゃない状態のサーバーは スノーフレークサーバーと呼ばれるらしい。
EC2 で冪等性が崩れるパターン
cloud-init
例えば以下
#!/bin/bash
dnf install -y nginx
systemctl enable --now nginx
一見冪等に見えますが、dnf install はバージョン未指定なので、実行タイミングで入るバージョンが変わります。
また、cloud-init のモジュールにはそれぞれ実行頻度(PER_INSTANCE、PER_BOOT、PER_ONCE、PER_ALWAYS)が設定されていて、実行済みかどうかをセマフォファイルで管理しています。PER_INSTANCE のモジュールは同じ instance-id では再実行されないので、AMI から起動し直したときに「あれ、動かない」となることがある。
AMI スナップショット
「動いてるインスタンスから AMI 作ればいいじゃ〜ん」はなんかイケてそうですが…
- 作成タイミングで中身が微妙に違う
/tmpや/var/logにゴミが残る- SSH ホストキーが使い回される
- SSHを使うなというのはその通り
手動変更
人間は楽な方に流れる生き物…
dnf update したり設定ファイルを直接編集したりすると、もう二度と同じものは作れない。
冪等性を担保するためには?
SSM / SSH しない
そもそもインスタンスに入らない。
これが一番大事。
手動変更が入った瞬間に冪等性は崩れるので、「インスタンスは使い捨て」という前提で設計し、設定変更はすべてコードに落として、新しいインスタンスを作り直す。
Packer / EC2 Image Builder
Packer は HashiCorp が開発しているオープンソースのマシンイメージビルドツール。HCL(HashiCorp Configuration Language)でテンプレートを書いて、AMI やコンテナイメージを自動で焼いてくれます。
やってることはシンプルで
- ベース AMI から一時的な EC2 インスタンスを起動する
- SSH で接続して、シェルスクリプトや Ansible 等でプロビジョニングする
- プロビジョニングが終わったらインスタンスから AMI を作成する
- 一時インスタンスを破棄する
Packer 自体は無料。ビルド中の EC2 インスタンス料金だけかかる。AWS 以外にも Azure、GCP、Docker など複数のプラットフォームに対応しているのが特徴ですね。
ちなみに AWS には EC2 Image Builder というフルマネージドの AMI ビルドサービスもあります。AWS に閉じるなら Image Builder、マルチクラウドであれば Packerという使い分けかなと。
Packerはまた触ってみます、すません。
SSM State Manager でドリフト検知
Systems Manager の State Manager を使えば、定期的に「あるべき状態」を適用し続けることができます。
手動変更が入っても気づけるのは助かりますね。ドリフト検知的な使い方ができる。
気になるお値段ですが、State Manager は追加料金なしです。SSM の無料枠に含まれてる。えらい。
(Run Command、Fleet Manager、メンテナンスウィンドウなども無料。SSM は太っ腹ですね)
AL2023 固有の話
Deterministic updates
AL2023 はリポジトリのバージョンロックができます。特定時点のパッケージセットを固定できるので、「いつ dnf install しても同じバージョンが入る」が実現できる。
これは冪等性を担保する上でめちゃくちゃ重要な機能。
まとめ(?)
要するに SSM / SSH するなって話ですね、あとはAL2023の機能に乗っかっておくと幸せになれそう。
ところで、よく考えたら Packer って EC2 版の Dockerfile みたいなもんじゃない?ベースイメージ指定して、プロビジョニングして、イメージ焼く。やってること同じですね。
久しぶりのブログなので最後どんな感じで締めていたか忘れちゃいました。