【AWS】AnsibleでLightsailインスタンスを作る【Lightsail】
【AWS】AnsibleでLightsailインスタンスを作る【Lightsail】:
先日、AWSでLightsailインスタンスを作った際、CloudFormationが未対応だったのでAnsibleでインフラ構成を定義・構築しました。
lightsail - Create or delete a virtual machine instance in AWS Lightsail — Ansible Documentation
2018/11/24現在、まだCloudFormationはLightsailに対応していないようです。
AnsibleでLightsailインスタンスを構築した際、完全に自動化できず幾つか手動で対応が必要だったこと、Lightsail特有のハマりポイントがあったことから、記録として残します。
Ansible Playbookで下記の作業を全て実施できれば理想ですが、lightsailモジュールではStatic IPの操作は未対応のようです。したがって、この作業は手動で行う必要がありました。
Ansible Playbook化出来たのは、以下の項番2~4までとなります。
Static IP addresses in Amazon Lightsail | Lightsail Documentation
作成したPlaybookはGitHub上に公開しました。
https://github.com/tmiki/server-config/tree/master/ansible
上記リポジトリには他のPlaybookもたくさん入っていますので、本稿に関するもののみを抜粋します。
ansible-playbookコマンドから指定して実行するファイルは下記となります。「aws_lightsail_wp」というRoleを別途定義し、これを読み込んでいます。
「aws_lightsail_wp」Roleの実体です。
上記のtaskで利用している変数定義です。
必要な手順は下記のREADME.mdにまとめてあります。
https://github.com/tmiki/server-config/blob/master/ansible/README.md
各ステップについてそれぞれ説明します。
まず最初にSSH用の鍵ペアを作ります。EC2用のものとLightsail用のものは独立して管理されているため、初めてLightsailインスタンスを作る際にはこちらも併せて作る必要があります。
鍵ペアの作成には「aws lightsail create-key-pair」コマンドを実行します。当該鍵ペアは「--key-pair-name」で指定した名前で保存されます。Lightsailインスタンスの作成時には、この名前で鍵ペアを指定することができます。
実行結果に秘密鍵が含まれるため、リダイレクトして保存しておくと良いでしょう。言うまでもないことですが、秘密鍵の取り扱いには十分注意します。
次に、Static IPを取得します。Elastic IPとの大きな違いは、任意の名前を付与して管理できることです。ここでは「dev1-example-site-ip」という名称でStatic IPを取得しています。
「aws lightsail get-static-ips」コマンドで、取得済みのStatic IPを確認することが可能です。
自分の環境に合わせて、Ansible Playbook用の変数定義を編集します。当該Playbookの実行に必要な変数は、「hosts/*/group_vars/all.yml」に定義する想定です。
Playbookを実行します。
このPlaybookは、取得したStatic IPを指すCNAMEレコードを自動的に作成します。
原因は不明(というより詳細は未調査)ですが、AssumeRoleするProfileを利用しているとレコードの作成に失敗します。最新のAnsible/AWS CLI/Boto3の環境で発生するかどうかは不明です。
このような場合、Route53レコードは手動で作る必要があります。
varsで定義したパラメータ等を元に、Lightsailインスタンスを作成します。Lightsailはblueprintとして、WordpressやLAMP、Node.jsなど予め準備しており、これをもとに新たなLightsailインスタンスを構築することができます。
bundle_idは、簡単に言うとインスタンスサイズです。CPUやメモリ容量、転送可能なデータ量などのサーバリソースがセットになったものです。
blueprint_id、bundle_idの取得は下記記事を参照してください。
【小ネタ】AWS LightsailでblueprintIdやbundleIdを確認する【Lightsail】
key_pair_nameとして、先ほど手動で作った鍵ペアが指定されるよう、変数定義しておきます。
Static IPは先ほどのlightsailモジュールでは操作できません。そのため、「command」モジュールを用いて、AWS CLIを実行しています。
「aws lightsail attach-static-ip」コマンドで、先ほど生成したLightsailインスタンスに紐づけています。
なおこれに先立ち、「aws lightsail get-static-ip」コマンドで、先ほど手動で取得したStatic IPの実際のIPアドレスを取りだしていますが、これはこの後、Route53レコード作成に必要な情報となります。
Ansibleのroute53モジュールを利用して、CNAMEレコードを作成します。
ゾーン名は「route53zone」という変数で定義されます。当該Lightsailインスタンスに対応するドメイン名は、「lightsail_wp.site_hostname」変数及び「route53zone」変数を組み合わせたものとなります。
なお先日試した際には、AssumeRoleするProfileを利用したところ、レコードの作成に失敗しました。原因も詳しく調査していないので詳細は不明ですが、このような場合は手動でRoute53レコードを作る必要があります。
Lightsailのインフラ構成を定義・管理するという需要は恐らく小さいと思われるので、CloudFormationもAnsibleも完全に対応するのはまだ先のことでしょう。
それでも、出来る限り構成管理は進めていった方が、後々の管理が楽になりますので、可能な限りやっておいた方が良いでしょう。
はじめに
先日、AWSでLightsailインスタンスを作った際、CloudFormationが未対応だったのでAnsibleでインフラ構成を定義・構築しました。lightsail - Create or delete a virtual machine instance in AWS Lightsail — Ansible Documentation
2018/11/24現在、まだCloudFormationはLightsailに対応していないようです。
AnsibleでLightsailインスタンスを構築した際、完全に自動化できず幾つか手動で対応が必要だったこと、Lightsail特有のハマりポイントがあったことから、記録として残します。
TL;DR
- Lightsail利用時の注意
- SSH用の鍵ペアはEC2とは別管理
- 固定グローバルIPアドレスは「Static IP」というものが用意されている
- Static IP≒Elastic IPであるが、それぞれ別管理
- AnsibleのLightsailモジュール利用時の注意
- Static IPの取得・割り当て等は未対応
- Ansibleのroute53モジュール利用時の注意
- AssumeRoleするprofileを利用しているとtaskが失敗するケースがある
目的・概要
Ansible Playbookで下記の作業を全て実施できれば理想ですが、lightsailモジュールではStatic IPの操作は未対応のようです。したがって、この作業は手動で行う必要がありました。Ansible Playbook化出来たのは、以下の項番2~4までとなります。
- Static IPの確保
- Lightsailインスタンスの作成
- Static IPのLightsailインスタンスへの割り当て
- 当該Static IPを指すRoute53 CNAMEレコードの作成
Static IP addresses in Amazon Lightsail | Lightsail Documentation
作成したPlaybook
作成したPlaybookはGitHub上に公開しました。https://github.com/tmiki/server-config/tree/master/ansible
上記リポジトリには他のPlaybookもたくさん入っていますので、本稿に関するもののみを抜粋します。
ansible-playbookコマンドから指定して実行するファイルは下記となります。「aws_lightsail_wp」というRoleを別途定義し、これを読み込んでいます。
aws_lightsail_wp.yml
# # aws_lightsail_wp.yml # --- - hosts: localhost connection: local gather_facts: False roles: - aws_lightsail_wp
roles/aws_lightsail_wp/tasks/main.yml
# # aws_lightsail_wp # --- - name: Create a Lightsail instance lightsail: state: present name: "{{ lightsail_wp.instance_name }}" profile: "{{ aws_profile }}" region: "{{ region }}" zone: "{{ az_primary }}" blueprint_id: "{{ lightsail_wp.blueprint_id }}" bundle_id: "{{ lightsail_wp.bundle_id }}" key_pair_name: "{{ lightsail_wp.key_pair_name }}" user_data: " echo 'hello world' > /home/ubuntu/test.txt" wait_timeout: 500 register: _lightsail_instance - debug: var: _lightsail_instance - debug: msg: - "Name is {{ _lightsail_instance.instance.name }}" - "Arn is {{ _lightsail_instance.instance.arn }}" when: not ansible_check_mode - name: Retrieve a global IP address from the Static IP 1/2 command: "aws lightsail --profile {{aws_profile}} get-static-ip --static-ip-name {{ lightsail_wp.static_ip_name }}" register: _result when: not ansible_check_mode - name: Retrieve a global IP address from the Static IP 2/2 set_fact: _lightsail_static_ip: "{{ _result.stdout | from_json }}" when: not ansible_check_mode - debug: var: _lightsail_static_ip - debug: msg: "Current static IP is {{ _lightsail_static_ip.staticIp.ipAddress }}" when: not ansible_check_mode - name: Attach the Static IP with the Lightsail instance command: "aws lightsail --profile {{aws_profile}} attach-static-ip --static-ip-name {{ lightsail_wp.static_ip_name }} --instance-name {{ lightsail_wp.instance_name }}" when: - not ansible_check_mode - _lightsail_instance.instance.is_static_ip != true - name: Create a Route53 CNAME record points to the static IP address of the Lightsail instance route53: state: present profile: "{{ aws_profile }}" zone: "{{ route53zone }}" record: "example-site.{{ route53zone }}" type: A ttl: 300 value: "{{ _lightsail_static_ip.staticIp.ipAddress }}" when: not ansible_check_mode
hosts/dev1/group_vars/all.yml
--- env: dev1 Env: "{{ env.capitalize() }}" aws_profile: dev1 route53zone: "dev1.your-domain.com" region: ap-northeast-1 az_primary: ap-northeast-1a az_secondary: ap-northeast-1c lightsail_wp: blueprint_id: "wordpress_4_9_6" bundle_id: "nano_2_0" instance_name: "{{env}}-example-site" static_ip: "{{env}}-example-site-ip" key_pair_name: "{{env}}-lightsail-keypair"
Lightsailインスタンス構築手順
必要な手順は下記のREADME.mdにまとめてあります。https://github.com/tmiki/server-config/blob/master/ansible/README.md
各ステップについてそれぞれ説明します。
1. Create a key pair for Lightsail
まず最初にSSH用の鍵ペアを作ります。EC2用のものとLightsail用のものは独立して管理されているため、初めてLightsailインスタンスを作る際にはこちらも併せて作る必要があります。鍵ペアの作成には「aws lightsail create-key-pair」コマンドを実行します。当該鍵ペアは「--key-pair-name」で指定した名前で保存されます。Lightsailインスタンスの作成時には、この名前で鍵ペアを指定することができます。
実行結果に秘密鍵が含まれるため、リダイレクトして保存しておくと良いでしょう。言うまでもないことですが、秘密鍵の取り扱いには十分注意します。
$ aws lightsail create-key-pair --key-pair-name dev1-lightsail-keypair > dev1-lightsail-keypair.json
2. Allocate a new Static IP
次に、Static IPを取得します。Elastic IPとの大きな違いは、任意の名前を付与して管理できることです。ここでは「dev1-example-site-ip」という名称でStatic IPを取得しています。$ aws lightsail allocate-static-ip --static-ip-name dev1-example-site-ip { "operations": [ { "status": "Succeeded", "resourceType": "StaticIp", "isTerminal": true, "statusChangedAt": 1542990973.062, "location": { "availabilityZone": "all", "regionName": "ap-northeast-1" }, "operationType": "AllocateStaticIp", "resourceName": "dev1-example-site-ip", "id": "47fb700f-ffff-ffff-ffff-ffffffffffff", "createdAt": 1542990972.707 } ] }
$ aws lightsail get-static-ips { "staticIps": [ { "name": "dev1-example-site-ip", "resourceType": "StaticIp", "supportCode": "0123456789012/xx.xx.xx.xx", "arn": "arn:aws:lightsail:ap-northeast-1:123456789012:StaticIp/9283dbfd-ffff-ffff-ffff-ffffffffffff", "isAttached": false, "ipAddress": "xx.xx.xx.xx", "createdAt": 1542990972.707, "location": { "availabilityZone": "all", "regionName": "ap-northeast-1" } } ] }
3. Modify variable definitions
自分の環境に合わせて、Ansible Playbook用の変数定義を編集します。当該Playbookの実行に必要な変数は、「hosts/*/group_vars/all.yml」に定義する想定です。$ vi hosts/dev1/group_vars/all.yml
4. Run the Playbook
Playbookを実行します。$ ansible-playbook -vv -i hosts/dev1 aws_lightsail_wp.yml
5.Create a Route53 record manually, if the Playbook fails.
このPlaybookは、取得したStatic IPを指すCNAMEレコードを自動的に作成します。原因は不明(というより詳細は未調査)ですが、AssumeRoleするProfileを利用しているとレコードの作成に失敗します。最新のAnsible/AWS CLI/Boto3の環境で発生するかどうかは不明です。
このような場合、Route53レコードは手動で作る必要があります。
Playbookの解説
lightsailモジュール
varsで定義したパラメータ等を元に、Lightsailインスタンスを作成します。Lightsailはblueprintとして、WordpressやLAMP、Node.jsなど予め準備しており、これをもとに新たなLightsailインスタンスを構築することができます。bundle_idは、簡単に言うとインスタンスサイズです。CPUやメモリ容量、転送可能なデータ量などのサーバリソースがセットになったものです。
blueprint_id、bundle_idの取得は下記記事を参照してください。
【小ネタ】AWS LightsailでblueprintIdやbundleIdを確認する【Lightsail】
key_pair_nameとして、先ほど手動で作った鍵ペアが指定されるよう、変数定義しておきます。
lightsailモジュール
- name: Create a Lightsail instance lightsail: state: present name: "{{ lightsail_wp.instance_name }}" profile: "{{ aws_profile }}" region: "{{ region }}" zone: "{{ az_primary }}" blueprint_id: "{{ lightsail_wp.blueprint_id }}" bundle_id: "{{ lightsail_wp.bundle_id }}" key_pair_name: "{{ lightsail_wp.key_pair_name }}" user_data: " echo 'hello world' > /home/ubuntu/test.txt" wait_timeout: 500 register: _lightsail_instance - debug: var: _lightsail_instance - debug: msg: - "Name is {{ _lightsail_instance.instance.name }}" - "Arn is {{ _lightsail_instance.instance.arn }}" when: not ansible_check_mode
Static IPをLightsailインスタンスに紐づける
Static IPは先ほどのlightsailモジュールでは操作できません。そのため、「command」モジュールを用いて、AWS CLIを実行しています。「aws lightsail attach-static-ip」コマンドで、先ほど生成したLightsailインスタンスに紐づけています。
なおこれに先立ち、「aws lightsail get-static-ip」コマンドで、先ほど手動で取得したStatic IPの実際のIPアドレスを取りだしていますが、これはこの後、Route53レコード作成に必要な情報となります。
StaticIP
- name: Retrieve a global IP address from the Static IP 1/2 command: "aws lightsail --profile {{aws_profile}} get-static-ip --static-ip-name {{ lightsail_wp.static_ip_name }}" register: _result when: not ansible_check_mode - name: Retrieve a global IP address from the Static IP 2/2 set_fact: _lightsail_static_ip: "{{ _result.stdout | from_json }}" when: not ansible_check_mode - debug: var: _lightsail_static_ip - debug: msg: "Current static IP is {{ _lightsail_static_ip.staticIp.ipAddress }}" when: not ansible_check_mode - name: Attach the Static IP with the Lightsail instance command: "aws lightsail --profile {{aws_profile}} attach-static-ip --static-ip-name {{ lightsail_wp.static_ip_name }} --instance-name {{ lightsail_wp.instance_name }}" when: - not ansible_check_mode - _lightsail_instance.instance.is_static_ip != true
Route53 CNAMEレコードの作成
Ansibleのroute53モジュールを利用して、CNAMEレコードを作成します。ゾーン名は「route53zone」という変数で定義されます。当該Lightsailインスタンスに対応するドメイン名は、「lightsail_wp.site_hostname」変数及び「route53zone」変数を組み合わせたものとなります。
なお先日試した際には、AssumeRoleするProfileを利用したところ、レコードの作成に失敗しました。原因も詳しく調査していないので詳細は不明ですが、このような場合は手動でRoute53レコードを作る必要があります。
Route53
- name: Create a Route53 CNAME record points to the static IP address of the Lightsail instance route53: state: present profile: "{{ aws_profile }}" zone: "{{ route53zone }}" record: "{{ lightsail_wp.site_hostname }}.{{ route53zone }}" type: A ttl: 300 value: "{{ _lightsail_static_ip.staticIp.ipAddress }}" when: not ansible_check_mode
おわりに
Lightsailのインフラ構成を定義・管理するという需要は恐らく小さいと思われるので、CloudFormationもAnsibleも完全に対応するのはまだ先のことでしょう。それでも、出来る限り構成管理は進めていった方が、後々の管理が楽になりますので、可能な限りやっておいた方が良いでしょう。
コメント
コメントを投稿