ぴよ丸水産

週末ファゴッティストによる技術ブログ

【AWX】GitHubとAWSと連携して、ハンズオン環境をCI/CDする

本記事はエーピーコミュニケーションズ Advent Calendar 2020の12日目の記事です。

はじめに

AWS上のハンズオン環境(使い捨て)をCI/CDする仕組みをAWXとGitHubを連携させて実現してみました。
本記事では、その仕組みの構築方法・運用方法を紹介します。
ハンズオンの内容は、Amazon EC2上で行うAnsible研修を想定しています。
研修内容は他のテーマでも応用可能だと思います。

導入前の課題

本記事で紹介する仕組みは以下のような課題の解決を試みています。

  • 以下の手動作業に時間がかかっている
    • 研修で使用するハンズオン環境の準備・片付け
    • 受講者からの要望を反映した研修内容の実機検証
  • 作業ミスによって、同じ環境が再現されないことがある

構成

全体構成は以下のようになります。

f:id:blue-38:20201206201315p:plain

※役割について補足

  • メンテナンス担当:研修内容・ハンズオン環境のアップデート担当
  • オペレーター:研修で使用するハンズオン環境の準備・片付け担当

環境構築

仕組みの構築方法を説明します。

環境情報

2020/11/23に検証しています。

  • AWXサーバー
項目 バージョン
Instance Type t2.medium
OS Amazon Linux2
Ansible 2.9.15
AWX 15.0.1

事前準備

以下のAWSリソースは事前に作成してある想定です。

  • AWS CLI実行用のIAMユーザ
  • VPC
  • サブネット
  • セキュリティグループ
  • キーペア

Playbook作成

以下の用途のroleとそれをキックするPlaybookを作成し、GitHubリポジトリに登録します。
検証で使用したPlaybookを以下のリポジトリに格納してます。

コントロールノードのみの省エネサンプルですが、ご容赦ください。
また、以下の点は検証時に実際に使った時の状態から修正しています。

  • ハンズオンのサンプルPlaybook
    • 実際は自社研修で使ってるもので検証しましたが、簡易化しています。
  • AWSのリソースID
    • <XXXのid>みたいな書き方に直してます。

各Playbookの概要を簡単に説明します。

Playbook名 処理内容 呼び出すロール
create_env.yml CloudformationでEC2インスタンスのスタックを作成 create_ec2instance
setup_env.yml ハンズオンで使用する教材(サンプルPlaybook)を配置 setup_master
test_scenario.yml ハンズオンのシナリオを実行する handson_scenario
delete_env.yml CloudformationでEC2インスタンスのスタックを削除 delete_ec2instance

構文チェックをGitHub Actionに設定

developブランチへのPushをトリガーにSyntax CheckとAnsible-Lintを実行するGitHub Action定義を仕込みます。
以下のワークフロー定義ファイルを.github/workflow/ansible-lint.ymlに登録します。

# This is a basic workflow to help you get started with Actions

name: CI

# Controls when the action will run. 
on:
  push:
    branches: [ develop ]

# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - name: Check out
        uses: actions/checkout@v2
      - name: Set up Python
        uses: actions/setup-python@v2
      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          pip install ansible==2.9.15 ansible-lint==4.3
      - name: Ansible-Lint
        run: |
          ansible-playbook create_env.yml --syntax-check
          ansible-playbook setup_env.yml --syntax-check
          ansible-playbook test_scenario.yml --syntax-check
          ansible-playbook delete_env.yml --syntax-check
          ansible-lint -x 301 -x 305 --force-color

NGだと以下のように表示されます。
f:id:blue-38:20201206181031p:plain ansible-lint -x 301 -x 305 --force-colorのところを
ansible-lint --force-color(除外ルールなし)で実行してみたら、この結果になりました。
上記、shellモジュール回りで怒られていますが、
shellモジュールの使用は今回のPlaybookはやむを得ないので、
ルールを除外させるようにしてます。

AWX構築

自動テストはAWXから実行させるので、AWXを構築します。
以下のコマンドを順次実行して、AWXをインストールしました。

$ sudo yum update -y
$ sudo yum install -y git
$ sudo yum install -y docker
$ sudo systemctl start docker
$ sudo systemctl enable docker
$ sudo yum install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm 
$ sudo yum --enablerepo=epel install -y ansible
$ sudo yum install -y python3
$ sudo pip3 install docker
$ sudo pip3 install docker-compose
$ git clone https://github.com/ansible/awx
$ cd awx/installer/
$ sudo ansible-playbook -i inventory install.yml

http://AWX構築ホストのPublicIP/にアクセスすると、AWXログイン画面が表示されます。
f:id:blue-38:20201206194236p:plain 以下の情報ででログインします。

ユーザー名 パスワード
admin password

また、AnsibleのCloudformationモジュールを使用するために必要なPythonモジュールをインストールします。

$ sudo yum install -y python-pip
$ sudo pip install boto3
$ sudo pip install botocore

AWX設定

1.認証情報登録

メニューの認証情報を選択し、+ボタンをクリックして、以下の情報を登録します。

  • GitHub認証情報

    項目
    名前 github-auth
    説明 GitHubリポジトリにアクセスするための認証情報
    組織 Default
    認証情報タイプ ソースコントロール
    ユーザ名 (GitHubのユーザ名)
    パスワード (GitHubのパスワード)
  • AWS認証情報

    項目
    名前 aws-auth
    説明 AWS上のインベントリ情報を取得するためのAWS認証情報
    組織 Default
    認証情報タイプ Amazon Web Service
    アクセスキー (IAMユーザのアクセスキー)
    シークレットキー (IAMユーザのシークレットキー)
  • EC2インスタンス認証情報

    項目
    名前 ec2-auth
    説明 EC2インスタンスへ接続するための認証情報
    組織 Default
    認証情報タイプ マシン
    ユーザー名 ec2-user
    SSH秘密鍵 (秘密鍵ドラッグアンドドロップ)

2.プロジェクト作成

メニューのプロジェクトを選択し、+ボタンをクリックして、以下の情報を登録します。

項目
名前 Hanson-Env
説明 ハンズオン環境構築コード
組織 Default
SCMタイプ Git
SCM URL (環境構築コードを登録しているGitHubリポジトリ)
SCM認証情報 github-auth

3. インベントリ登録

メニューのインベントリーを選択し、+ボタンをクリックして、以下の情報を登録します。

  • ローカルホスト(Cloudformationモジュール実行対象)

    項目
    名前 localhost
  • AWS上のEC2インスタンス

    項目
    名前 EC2Instances
    • ソース

      項目
      名前 EC2Instances
      ソース Amazon EC2
      認証情報 aws-auth
      有効な変数 tags.Name
      有効な値 Ansible-Master
      上書き
      起動時の更新
      • 有効な変数有効な値には、Cloudformationで作成するEC2インスタンスに付与されるタグのキー・値を定義します。
      • 起動時の更新を有効にすることで、ジョブ実行時にAWSとの同期が実行されます。
      • また、 上書きを有効にすることで、同期時にすでに削除されたEC2インスタンスはホストから削除されます。
      • 上記の設定により、数が変動するEC2インスタンスに対してジョブ実行が可能になります。

4.ジョブテンプレート登録

メニューのテンプレートを選択し、+ボタン・ジョブテンプレートをクリックして、以下の情報を登録します。

  • EC2インスタンス作成

    項目
    名前 Create_EC2Instances
    ジョブタイプ 実行
    インベントリー localhost
    プロジェクト Handson-Env
    Playbook create_env.yml
    認証情報 aws-auth
  • ハンズオン環境セットアップ

    項目
    名前 Setup-Handson
    ジョブタイプ 実行
    インベントリー EC2Instances
    プロジェクト Handson-Env
    Playbook setup_env.yml
    認証情報 ec2-auth
  • ハンズオンシナリオテスト

    項目
    名前 Test-HandsonScenario
    ジョブタイプ 実行
    インベントリー EC2Instances
    プロジェクト Handson-Env
    Playbook test_scenario.yml
    認証情報 ec2-auth
  • EC2インスタンス削除

    項目
    名前 Delete_EC2Instances
    ジョブタイプ 実行
    インベントリー localhost
    プロジェクト Handson-Env
    Playbook delete_env.yml
    認証情報 aws-auth

5.ワークフローテンプレート登録

メニューのテンプレートを選択し、+ボタン・ワークフローテンプレートをクリックして、以下の情報を登録します。

  • 自動テスト

    項目
    名前 自動テスト
    SCMブランチ develop

    f:id:blue-38:20201206182152p:plain

    • テスト実行後に確実にEC2インスタンスが削除されるように、以下の分岐条件を仕込みます。
      • Setup-Handsonが失敗した場合は、Delete_EC2Instancesに進む
      • Test-HandsonScenario実行後は常時(=ジョブテンプレートの成功・失敗に関わらず)Delete_EC2Instancesに進む
  • ハンズオン環境作成

    項目
    名前 ハンズオン環境作成
    SCMブランチ main

    f:id:blue-38:20201206182206p:plain

    • SURVEYの追加

      項目
      プロンプト Number of handson environment
      説明 構築するハンズオン環境の台数
      回答の変数名 howmany
      回答タイプ 整数
      最小 1
      最大 (受講者の最大数)
      デフォルトの応答
      必須

      SURVEYを設定することによって、ワークフローテンプレート起動時に、
      以下のように構築する環境の数を設定できます。 f:id:blue-38:20201208222733p:plain

  • ハンズオン環境削除

    項目
    名前 ハンズオン環境削除
    SCMブランチ main

    f:id:blue-38:20201206182229p:plain

    • SURVEYの追加

      項目
      プロンプト Number of handson environment
      説明 削除するハンズオン環境の台数
      回答の変数名 howmany
      回答タイプ 整数
      最小 1
      最大 (受講者の最大数)
      デフォルトの応答
      必須

権限設定

オペレーター用のユーザーoperationを作ります。 メニューのユーザーを選択し、+ボタンをクリックして、以下の情報を登録します。

項目
ユーザー名 operation
メール (メールアドレス)
ユーザータイプ 標準ユーザー

以下のワークフローテンプレートの実行権限のみを持つように設定します。
メニューのテンプレートを選択し、ワークフローテンプレート名をクリックします。

  • ハンズオン環境作成
  • ハンズオン環境削除

パーミッションタブを選択し、+ボタンをクリックして、以下の情報を登録します。

項目
ユーザ名 operation
ロール 実行

operationユーザでログインすると、テンプレート一覧は以下のように表示されます。 f:id:blue-38:20201206182128p:plain

運用方法

以下のような手順で運用される想定です。
更新内容はあくまでも一例です。

トリガー

  • 以下の要求が発生
    • サンプルPlaybookの改善要望
    • 最新バージョンのAnsibleでハンズオンを実施したい

f:id:blue-38:20201206171531p:plain

Plan

  • 以下の方針で更新することに決定
    • サンプルPlaybookを更新する
    • Ansibleバージョンを最新化する

f:id:blue-38:20201206171417p:plain

Do

  • メンテナンス担当はHandson-Envリポジトリのdevelopブランチで以下を対応
    • サンプルPlaybookの更新
    • Ansibleバージョン定義部分を更新

f:id:blue-38:20201206172157p:plain

Check

  • 構文チェック
    • Handson-EnvリポジトリのdevelopブランチへのPushをトリガーに、GitHub ActionによってSyntax Checkとansible-lintが自動実行
    • メンテナンス担当はGitHub Actionの実行結果を確認する

f:id:blue-38:20201206175946p:plain

  • 自動テスト
    • メンテナンス担当はワークフローテンプレート自動テストを実行
      • developブランチの定義ファイルに基づいて以下の処理を自動実行
        • ハンズオン環境を自動構築
        • 構築したハンズオン環境に、ハンズオンシナリオを実行
        • ハンズオン環境を削除

f:id:blue-38:20201206173518p:plain

Action

f:id:blue-38:20201206224708p:plain

  • 自動テストの結果を確認し、問題なければmainブランチにマージ・正式版としてタグ付け

Delivery

  • オペレーターはワークフローテンプレートハンズオン環境作成を実行
    • mainブランチの定義ファイルに基づいて、ハンズオン環境を構築
  • 研修実施後、オペレーターはワークフローテンプレートハンズオン環境削除を実行
    • mainブランチの定義ファイルに基づいて、ハンズオン環境を削除

f:id:blue-38:20201206180713p:plain

仕組み導入後の課題の解決状況

  • 研修で使用するハンズオン環境の準備・片付け

    • オペレーターはワンクリックで最新化されたハンズオン環境を受講者の台数分構築できる
    • オペレーターはワンクリックで受講者のハンズオン環境を削除できる
  • 受講者からの要望を反映した研修内容の実機検証

    • メンテナンス担当は、ワンクリックで以下の項目を確認できる
      • 更新した定義ファイルでハンズオン環境が構築できるか
      • ハンズオン環境で更新したシナリオが実行できるか
  • 手動作業による構築のため、作業ミスによって、同じ環境が再現されないことがある
    • 定義ファイルはGitで管理するので、検証済みの環境が確実に構築できる

今回の検証でできなかったこと

  • 自動テストの実行トリガーをWebhookにする

    もう一つブランチがある想定ですが、
    特定のブランチへのマージをトリガーに自動テストが実行されるとか仕込んでみたかったんですが、
    時間切れで挫折しました。次の機会に挑戦します。

  • 生成されるEC2インスタンスのNameタグを連番にする

    今回完成したものは、生成されるEC2インスタンスのNameタグはすべてAnsible-Masterになっています。
    これをAnsible-Master01のように連番にしようと、以下のように試していました。

    • CloudformationのEC2定義ファイルに生成されるEC2インスタンス共通のタグHandson: masterを定義
    • インスタンスEC2Instancesのソースの有効な変数tags.Handson有効な値masterを定義

    しかし、この設定だと、対象のEC2インスタンスが絞れず、
    AWXサーバーもEC2Instancesに含まれてしまいました。
    Nameタグだと絞れるのですが、それ以外のタグだと絞れないようです。
    回避方法は時間切れで挫折、妥協案でNameタグを統一することにしました。

    2021/02/27追記
    上記打消し線の事象はAWX17.0.1では解消されていました。
    Nameタグ以外のタグでも絞れるようになってます。
    バグだったのかな。。

おわりに

少々課題が残りましたが、
Git連携・AWS連携・SURVEY・ユーザー権限の設定など、
AWXの機能を活かした検証ができたので、楽しかったです。

参考