kakakakakku blog

Weekly Tech Blog: Keep on Learning!

pyinfra で EC2 インスタンスをプロビジョニングする

pyinfra を使うと Python コードでサーバの構成管理ができる👌

pyinfra.com

最近 pyinfra で Amazon EC2 インスタンスのプロビジョニングを試す機会があって,個人的に検証したことをまとめておく.今までは Chef / Ansible を使ったことがあって,またプロビジョニング後の確認では Serverspec / Goss を使ったことがある.

アドホックコマンド

まずは pyinfra の「アドホックコマンド」を試す.

検証用の Amazon EC2 インスタンス (Amazon Linux 2023) を1つ起動しておく.pyinfra は SSH で接続するためキーペアも設定しておく.そして cowsay コマンドが使えないことも確認しておく🐮

   ,     #_
   ~\_  ####_        Amazon Linux 2023
  ~~  \_#####\
  ~~     \###|
  ~~       \#/ ___   https://aws.amazon.com/linux/amazon-linux-2023
   ~~       V~' '->
    ~~~         /
      ~~._.   _/
         _/ _/
       _/m/'

$ which cowsay
/usr/bin/which: no cowsay in (/home/ec2-user/.local/bin:/home/ec2-user/bin:/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin)

そして pyinfra のアドホックコマンドを実行する.Dnf で cowsay コマンドを使えるようにするため dnf.packages cowsay のように指定している.実行結果の Results を見ると Success1 になっていた💪

$ uvx pyinfra -y --user ec2-user --key ~/.ssh/xxx.pem 57.181.26.191 dnf.packages cowsay _sudo=true
--> Loading config...
--> Loading inventory...
--> Connecting to hosts...
    [57.181.26.191] Connected

--> Preparing operation func...
    [57.181.26.191] Ready: packages

--> Skipping change detection
--> Beginning operation run...
--> Starting operation: dnf.packages (cowsay)
    [57.181.26.191] Success

--> Results:
    Operation               Hosts   Success   Error   No Change   
    dnf.packages (cowsay)   1       1         -       -           
    Grand total             1       1         -       -           

--> Disconnecting from hosts...

もう一度同じ pyinfra のアドホックコマンドを実行すると,今度は No Change1 になっていて,ちゃんと冪等性も考慮されていた👌

$ uvx pyinfra -y --user ec2-user --key ~/.ssh/xxx.pem 57.181.26.191 dnf.packages cowsay _sudo=true
--> Loading config...
--> Loading inventory...
--> Connecting to hosts...
    [57.181.26.191] Connected

--> Preparing operation func...
    [57.181.26.191] Ready: packages

--> Skipping change detection
--> Beginning operation run...
--> Starting operation: dnf.packages (cowsay)
    [57.181.26.191] No changes

--> Results:
    Operation               Hosts   Success   Error   No Change   
    dnf.packages (cowsay)   1       -         -       1           
    Grand total             1       -         -       1           

--> Disconnecting from hosts...

期待通りに Amazon EC2 インスタンスで cowsay コマンドを実行できるようになっていた \( 'ω')/

$ which cowsay
/usr/bin/cowsay

$ cowsay hello
 _______
< hello >
 -------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

デプロイ

次は pyinfra の「デプロイ」を試す.デプロイは Ansible のプレイブックのようにインベントリ(デプロイ対象)とセットアップ操作をコード化したような概念になる.

検証用の Amazon EC2 インスタンス (Amazon Linux 2023) を2つ起動しておく.

👾 inventory.py

まず inventory.py にデプロイ対象の IP アドレスを定義しておく.

all_hosts = [
    '52.195.184.177',
    '54.248.128.224',
]

👾 group_data/all.py

次に group_data/all.py に共通的な設定をしておく.

ssh_user = 'ec2-user'
ssh_key = '~/.ssh/xxx.pem'

docs.pyinfra.com

👾 index.html

pyinfra でファイルをデプロイする操作も確認しておきたく index.html も準備しておく.

hello

👾 main.py

最後は main.py にセットアップ操作を実装する.今回は以下を実装した❗️

  • cowsay コマンド
  • nginx
    • ドキュメントルートに index.html を配置
    • 自動起動 ON
from pyinfra.operations import dnf, files, systemd

dnf.packages(
    name='Install cowsay package',
    packages=['cowsay'],
    _sudo=True,
)

dnf.packages(
    name='Install nginx package',
    packages=['nginx'],
    _sudo=True,
)

files.put(
    name='Deploy custom index.html',
    src='index.html',
    dest='/usr/share/nginx/html/index.html',
    mode='644',
    _sudo=True,
)

systemd.service(
    name='Enable and start nginx service',
    service='nginx',
    running=True,
    enabled=True,
    _sudo=True,
)

docs.pyinfra.com

docs.pyinfra.com

docs.pyinfra.com

そして inventory.pymain.py を指定して pyinfra を実行する.実行結果の Results を見ると Success8 になっていた💪

$ uvx pyinfra -y inventory.py main.py  
--> Loading config...
--> Loading inventory...
--> Connecting to hosts...
    No host key for 52.195.184.177 found in known_hosts, accepting & adding to host keys file
    Added host key for 52.195.184.177 to known_hosts
    No host key for 54.248.128.224 found in known_hosts, accepting & adding to host keys file
    Added host key for 54.248.128.224 to known_hosts
    [52.195.184.177] Connected
    [54.248.128.224] Connected

--> Preparing operation files...
    Loading: main.py
    [52.195.184.177] Ready: main.py
    [54.248.128.224] Ready: main.py

--> Skipping change detection
--> Beginning operation run...
--> Starting operation: Install cowsay package 
    [54.248.128.224] Success
    [52.195.184.177] Success

--> Starting operation: Install nginx package 
    [52.195.184.177] Success
    [54.248.128.224] Success

--> Starting operation: Deploy custom index.html 
    [52.195.184.177] Success
    [54.248.128.224] Success

--> Starting operation: Enable and start nginx service 
    [52.195.184.177] Success
    [54.248.128.224] Success

--> Results:
    Operation                        Hosts   Success   Error   No Change   
    Install cowsay package           2       2         -       -           
    Install nginx package            2       2         -       -           
    Deploy custom index.html         2       2         -       -           
    Enable and start nginx service   2       2         -       -           
    Grand total                      8       8         -       -           

--> Disconnecting from hosts...

Amazon EC2 インスタンスに接続してプロビジョニング結果を確認すると期待通りになっていた \( 'ω')/

$ ssh -i ~/.ssh/pyinfra.pem ec2-user@52.195.184.177

$ which cowsay
/usr/bin/cowsay

$ systemctl is-active nginx
active

$ systemctl is-enabled nginx
enabled

$ curl http://localhost
hello

関連情報

今回は検証しやすく Amazon VPC のパブリックサブネットに Amazon EC2 インスタンスに配置したけど,実際にはプライベートサブネットに配置することが多いだろうし,AWS Systems Manager でできると良さそう.既に issue もある.あとは AWS Systems Manager の SSH を使う案も検討できそう.もう少し試してみよう💪

github.com

docs.aws.amazon.com