EC2 Image Builder で Ansible playbook を実行してみた

2021.02.13

どうも今年の目標はベンチプレス150kgのオンジーです。

AnsibleのplaybookをEC2 Image Builderで使ってみました。

なおAnsible、Image Builderの基本的な使い方についてはある程度知っている前提で書かれています。最後に入門記事のリンクを載せていますのでご参考ください。

やってみた

AWSが公開しているサンプルを使って実行してみます。

内容としてはAmazon Linux2にapacheをインストールしてHello worldと書かれたトップページを作成するというシンプルなものです。

playbookの中身

my-playbook.ymlの中身です。

- name: Apache Hello World
  hosts: 127.0.0.1
  gather_facts: false
  connection: local
  tasks:
    - name: Install Apache
      yum:
        name: httpd
        state: latest
    - name: Create a default page
      shell: echo "<h1>Hello world from EC2 Image Builder and Ansible</h1>" > /var/www/html/index.html
    - name: Enable Apache
      service: name=httpd enabled=yes state=started

従来のAnsibleではsshやWinRMでリモートホストにアクセスしミドルウェアのインストールや設定ファイルの更新を行いますが

Image Builder 内で Ansible を実行する際はAMIを作成するEC2上で実行することになるのでローカルホスト上で実行するように設定する必要があります。

次の部分がローカルでの実行を強制している箇所になります。

  hosts: 127.0.0.1
  gather_facts: false
  connection: local

このmy-playbook.ymlを事前にS3バケットにアップロードしておきます。

componentの中身

Image Builderで実行するビルドコンポーネント(component.yml)ですが以下の流れになっています。

  • Ansible をインストール
  • S3 バケットからplaybookをダウンロード
  • playbook実行
  • playbook削除(クリーンアップ)
  • Apache が正しいコンテンツを返していることを検証

ここでは解体して説明していますので全文は先ほどのGitHubよりご確認ください。

まずはドキュメントの説明とbuildフェーズの指定をします。

name: 'Ansible Playbook Execution on Amazon Linux 2'
description: 'This is a sample component that demonstrates how to download and execute an Ansible playbook against Amazon Linux 2.'
schemaVersion: 1.0
phases:
  - name: build
    steps:

Amazon Linux 2ではAmazon Linux Extrasを使ってAnsibleをインストールできるので、ExecuteBashアクションを使ってインストールします。

     - name: InstallAnsible
        action: ExecuteBash
        inputs:
          commands:
           - sudo amazon-linux-extras install -y ansible2

S3Download アクションを使用してplaybookをダウンロードし、tmpフォルダに保存します。

S3バケットを指定している箇所は先ほどmy-playbook.ymlをアップロードしたバケットのパスに書き換えてください。

     - name: DownloadPlaybook
        action: S3Download
        inputs:
          - source: 's3://mybucket/my-playbook.yml'
            destination: '/tmp/my-playbook.yml'

ExecuteBinary アクションを使用して Ansible を起動し、playbookに記載されている作業を実行します。

ここでは前段のステップから入力値や出力値を参照できる機能 chaining を使用しています。詳しくは下記をご参照ください。

{{build.DownloadPlaybook.inputs[0].destination}}}は、'/tmp/my-playbook.yml'を指定していることになります。

値の入力ミスによるビルドの失敗を避けるために、このように参照でS3Download先のパスを取得しています。

      - name: InvokeAnsible
        action: ExecuteBinary
        inputs:
          path: ansible-playbook
          arguments:
            - '{{build.DownloadPlaybook.inputs[0].destination}}'

Ansibleを実行したのでダウンロードしたplaybookを削除しています。

ここでも同様に参照によって取得したパスでExecuteBashアクションを実行しています。

      - name: DeletePlaybook
        action: ExecuteBash
        inputs:
          commands:
            - rm '{{build.DownloadPlaybook.inputs[0].destination}}'

ここまででbuildフェーズが終わったのでvalidateフェーズに移ります。

curlを使ってApacheが正しいコンテンツで応答することを確認しています。

  - name: validate
    steps:
      - name: ValidateResponse
        action: ExecuteBash
        inputs:
          commands:
            - curl -s http://127.0.0.1 | grep "Hello world from EC2 Image Builder and Ansible"

validateフェーズが実行されると、EC2が停止しAMIが作成されます。

Image Builderは、このAMIを使用して新しいEC2インスタンスを起動するtestフェーズに移行します。

そのためtestフェーズでもvalidate フェーズと同じ curl コマンドを使用して同様に正しいコンテンツが返ってくるかを確認しています。

※注意:S3バケットへのアクセス権限が必要です。

Image BuilderではAMIをビルドおよびテストする一時的なEC2にIAMロールを設定するのですがそこにplaybookを配置したS3へのアクセス権限が必要です。

ポリシーは下記の様なイメージです。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:GetObject",
                "s3:PutObject"
            ],
            "Resource": "arn:aws:s3:::mybucket/*"
        }
    ]
}

完成したAMIを起動してみる

出来上がったAMIからEC2を起動してみました。

トップページが表示されました!やったね!

おわり

apacheのインストールなどもちろんビルドコンポーネントで記述はできるのですがAnsibleを既に使っていた場合はその資産を使いたいですよね。

上記の手順で実行できますのでお試しください。

参考

合わせて読みたい

Ansible

Image Builder