はじめに
自宅のRaspberry Pi上でAWXを使うためにARM64版のビルドをしているのですが、
Rapsberry Pidでは性能不足ということもあり、ビルド時にAWS EC2のARM64インスタンスを利用しています。
ビルド時しか使わないので、費用削減のために毎回スポットインスタンス作成→ビルド終わったら削除、とコンソールから手作業でやっていましたが、だんだん面倒になってきたため自動化したいと思います。
実現したいこと
AWX 16.0.0を使って、以下のような事を実現させます。
2.作成したEC2インスタンス上でAWXをビルド、完了したらコンテナレジストリにアップロード
3.アップロード完了後作成した環境を削除
コンテナレジストリの準備
今回、コンテナレジストリとしてAmazon Elastic Container Registry
を利用しようと思うので、事前に作成しておきます。
名前(awx)とLinux・ARM64を指定するぐらいです。
EC2インスタンスからコンテナイメージをPush可能にするため、IAMロールを作成しておきます。
トライアンドエラーを繰り返しつつビジュアルエディタでポチポチと作成した結果、以下のようなポリシーであればPush可能なようです。
これを「awx-builder-role」という名前で作成しておきます。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [
"ecr-public:DescribeImages",
"ecr-public:InitiateLayerUpload",
"ecr-public:PutRepositoryCatalogData",
"ecr-public:UploadLayerPart",
"ecr-public:PutImage",
"ecr-public:GetRepositoryCatalogData",
"ecr-public:GetRegistryCatalogData",
"ecr-public:CompleteLayerUpload",
"ecr-public:PutRegistryCatalogData",
"ecr-public:GetRepositoryPolicy",
"ecr-public:BatchCheckLayerAvailability"
],
"Resource": [
"arn:aws:ecr-public::<アカウントID>:repository/*",
"arn:aws:ecr-public::<アカウントID>:registry/*"
]
},
{
"Sid": "VisualEditor1",
"Effect": "Allow",
"Action": [
"ecr-public:GetAuthorizationToken",
"sts:GetServiceBearerToken"
],
"Resource": "*"
}
]
}
IAMユーザー
AWSコンソールからAWXが使うIAMユーザーを作成します。
ポリシーは以下のようにしました。
- AmazonEC2FullAccess
- AmazonVPCFullAccess
- 上記で作成した「awx-builder-role」のGetRole,PassRole(EC2インスタンスにロールを付与するために必要となる)
作成時に表示されるアクセスキーID・シークレットアクセスキーをAWXのCredentials(認証情報)に登録しましょう。
Credential Typeを「Amazon Web Services」とし、
Access Key・Secret Keyをそれぞれ入力して保存します。
インベントリ登録
作成されるEC2インスタンスの情報を取得するため、ダイナミックインベントリを作成します。
まずは名前を付けていったん保存し、
SourcesからAddボタンを押下し以下のように入力していきます。
- Source: Amazon EC2
- Credential: <上記で登録したCredentialを選択>
- Overwrite: チェックを付ける(最新の情報でインベントリを上書きする)
- Update on launch: チェックを付ける(このインベントリを利用するジョブ実行時に毎回インベントリの内容を更新します)
- Source variables: 以下のYAMLを入力し、「Ansible」というタグの値でグループを作るようにします。
---
keyed_groups:
- key: tags.Ansible
separator: ''
認証情報登録
作成するEC2を操作するためのCredential(認証情報)を作成しておきます。
今回、Ubuntuのインスタンスを作成しますが、AWSにおけるUbuntuインスタンスのデフォルトユーザーは「ubuntu」ですので、ユーザー名ubuntuとしてログイン可能な認証情報を作成しておきます。
プロジェクト作成
以下の3つのPlaybookを含んだプロジェクトを作成します。
AWS環境作成用Playbook
---
- name: Create AWS EC2 Spot Instance Environment
hosts: localhost
connection: local
environment:
AWS_REGION: ap-northeast-1
tasks:
- name: Get SSH Authorized key
uri:
url: https://gitlab.com/ussvgr.keys
return_content: yes
register: ssh_key
- name: Dump SSH Authorized key
debug:
msg: "SSH Public key is {{ ssh_key.content }}"
- name: Create SSH Key
ec2_key:
name: my_keypair
key_material: "{{ ssh_key.content }}"
- name: Create a VPC
ec2_vpc_net:
name: Spot VPC
cidr_block: 10.10.0.0/16
register: vpc_result
- name: Create Subnet
ec2_vpc_subnet:
vpc_id: "{{ vpc_result.vpc.id }}"
cidr: 10.10.0.0/24
map_public: yes
state: present
az: ap-northeast-1a
wait: yes
register: subnet_result
- name: Create Internet Gateway
ec2_vpc_igw:
vpc_id: "{{ vpc_result.vpc.id }}"
state: present
register: igw_result
- name: Create Route table
ec2_vpc_route_table:
vpc_id: "{{ vpc_result.vpc.id }}"
tags:
Name: Public
subnets:
- "{{ subnet_result.subnet.id }}"
routes:
- dest: 0.0.0.0/0
gateway_id: "{{ igw_result.gateway_id }}"
- name: Create Security Group
ec2_group:
name: allow_ssh_from_my_environment
description: sg with rule descriptions
vpc_id: "{{ vpc_result.vpc.id }}"
rules:
- proto: tcp
ports:
- 22
cidr_ip: 0.0.0.0/0
rule_desc: allow SSH
register: sg_result
- name: Create Spot Instance
ec2:
spot_price: "0.05"
keypair: my_keypair
vpc_subnet_id: "{{ subnet_result.subnet.id }}"
group_id: "{{ sg_result.group_id }}"
instance_type: t4g.large
image: ami-0d1f7bec0e294ef80 # Ubuntu Server 20.04 LTS
instance_tags:
Ansible: awx_builder
instance_profile_name: awx-builder-role
zone: ap-northeast-1a
count_tag:
Ansible: awx_builder
exact_count: 1
volumes:
- device_name: /dev/sda1
delete_on_termination: yes
volume_size: 16
wait: yes
instance_initiated_shutdown_behavior: terminate
愚直に
- SSH用のキーペア
- VPC
- サブネット
- Internet Gateway
- ルートテーブル
- セキュリティグループ
- EC2インスタンス
を作成するだけのPlaybookです。
後に削除する事を考えて、各リソースに「Ansible: awx_builder」というタグを付けています。
また、EC2インスタンスには上記で作成した「awx-builder-role」を付与しています。
上記ではセキュリティグループはInternet向けに22番全開放になっているので、実際使う環境に合わせ適宜変更すること。
###AWXコンテナイメージビルド用Playbook
---
- name: Create AWS EC2 Spot Instance
hosts: awx_builder
become: yes
tasks:
- name: Install requirement packages
apt:
update_cache: yes
name:
- docker.io
- python3-docker
- ansible
- unzip
- name: Download awscli v2
unarchive:
src: https://awscli.amazonaws.com/awscli-exe-linux-aarch64.zip
dest: /tmp
remote_src: yes
- name: Install awscli v2
shell:
cmd: /tmp/aws/install
- name: Start Docker service
systemd:
name: docker
state: started
- name: Login to ECR
shell:
cmd: /usr/local/bin/aws ecr-public get-login-password --region us-east-1 | docker login --username AWS --password-stdin public.ecr.aws
- name: Get latest AWX release tag
uri:
url: https://api.github.com/repos/ansible/awx/tags
return_content : yes
register: uri_response
- name: (Info) AWX version
debug:
msg: "latest AWX version is {{ uri_response.json[0].name }}"
- name: Clone AWX repo
git:
repo: https://github.com/ansible/awx.git
dest: /src/awx
version: "{{ uri_response.json[0].name }}"
- name: add line to Inventory for Container registory
blockinfile:
path: /src/awx/installer/inventory
block: |
docker_registry=public.ecr.aws
docker_registry_repository=v9x8p9g7
- name: Build AWX image
shell:
cmd: ansible-playbook -i inventory build.yml
chdir: /src/awx/installer/
EC2上でAWXをビルドするためのPlaybookです。
過去のバージョンでビルドしたときはいろいろと手を入れてましたが、最近のバージョンでは何も手を加えずにそのままARM64でビルド可能です。
最新のリリースバージョンを取得するための方法に迷ったのですが、https://api.github.com/repos/ansible/awx/tags で取得できる最初の要素からタグ名を取得しています。(パッと見ちゃんと動いてそうなので、いったんコレで…)
また、ハマったポイントとして、パブリック公開版のECRのパスワードを取得する際は、ECRのリージョンがap-northeast-1だったとしてもawscliでap-northeast-1を指定するとエラーになります。
us-east-1を指定したら動いたようなのでそのままにしています。そのうち改善されるかな?
AWS環境削除用Playbook
---
- name: Delete AWS EC2 Spot Instance Environment
hosts: localhost
connection: local
environment:
AWS_REGION: ap-northeast-1
vars:
tag_ansible: awx_builder
tasks:
- name: get EC2 Instance ID
ec2_instance_info:
filters:
"tag:Ansible": "{{ tag_ansible }}"
register: instance_info_result
- name: get Security Group ID
ec2_group_info:
filters:
"tag:Ansible": "{{ tag_ansible }}"
register: sg_info_result
- name: get Subnet ID
ec2_vpc_subnet_info:
filters:
"tag:Ansible": "{{ tag_ansible }}"
register: subnet_info_result
- name: get InternetGateway ID
ec2_vpc_igw_info:
filters:
"tag:Ansible": "{{ tag_ansible }}"
register: igw_info_result
- name: get Route table ID
ec2_vpc_route_table_info:
filters:
"tag:Ansible": "{{ tag_ansible }}"
register: rt_info_result
- name: Terminate EC2 Instance
ec2:
state: absent
instance_ids: "{{ item.instance_id }}"
wait: yes
loop: "{{ instance_info_result.instances }}"
- name: Delete Security group
ec2_group:
state: absent
group_id: "{{ item.group_id }}"
loop: "{{ sg_info_result.security_groups }}"
- name: Delete Route table
ec2_vpc_route_table:
state: absent
lookup: id
vpc_id: "{{ item.vpc_id }}"
route_table_id: "{{ item.id }}"
loop: "{{ rt_info_result.route_tables }}"
- name: Delete Internet Gateway
ec2_vpc_igw:
state: absent
vpc_id: "{{ item.attachments[0].vpc_id }}"
loop: "{{ igw_info_result.internet_gateways }}"
- name: Delete Subnet
ec2_vpc_subnet:
state: absent
vpc_id: "{{ item.vpc_id }}"
cidr: "{{ item.cidr_block }}"
loop: "{{ subnet_info_result.subnets }}"
- name: Delete VPC
ec2_vpc_net:
name: Spot VPC
cidr_block: 10.10.0.0/16
state: absent
- name: Delete SSH Keys
ec2_key:
name: my_keypair
state: absent
作成時に付けたタグを基にリソースのIDを取得し、作成時と逆の順番で各リソースを削除しています。
AWX上のテンプレート作成
各操作ごとにジョブテンプレートを作成していきます。
###AWS環境作成用ジョブテンプレート
- Inventory: localhostのみ登録したインベントリを作成して指定
- Project/Playbook: 上記のYAMLを含んだProjectを作成し指定
- Credentials: 上記でAWSのIAMを登録した認証情報を指定
###AWXコンテナイメージビルド用ジョブテンプレート
- Inventory: 作成したダイナミックインベントリを指定
- Project/Playbook: 上記のYAMLを含んだProjectを作成し指定
- Credentials: 作成したubuntuユーザーでログインする用の認証情報を指定
###AWS環境削除用ジョブテンプレート
作成用とほぼ同じで、Playbookのみ差し替えます。
###ワークフローテンプレート
上記の3つのジョブテンプレートを、成功時に順々に実行するよう繋いだワークフローを作成します。
#実行
完成したらワークフローを実行します。
30〜40分ほどして問題なく完了していれば、ECR上にコンテナイメージがアップロードされています。
また、ビルドに使ったAWS上の環境もキレイサッパリ消えているはずです。
#おわりに
ビルドしたARM64版のAWXコンテナイメージはココに置いています。