てくなべ (tekunabe)

ansible / network automation / 学習メモ

[Ansible] AWS CloudShell でも Ansible したい

はじめに

先日、AWS CloudShell が利用できるようになりました。

aws.amazon.com

www.publickey1.jp

とても気軽に使えて良いなと思ったので Ansible をインストールして、AWS 上のリソースを操作できるか使えるか試してみました。

Playbook の実行、ad-hoc コマンドのの実行、ダイナミックインベントリを試しました。

クレデンシャルを別途設定しなくて良いのが AWS CloudShell ならではの特徴かと思います。

インストール

Ansible はデフォルトでインストールされていないので、別途 pip でインストールする必要があります。

まず、venv を作成して有効にします。

python3 -m venv ansible
source ansible/bin/activate

続いて、ansible と、AWS リソースの操作に必要な boto3 をインストールします。

 pip install ansible boto3

インストールされたことをバージョン表示をもって確認します。

$ ansible --version
ansible 2.10.4
...(略)...

無事にインストールできました。

Playbook の実行

まず、インベントリファイルを作成します。大した内容はないのですが、ここで変数の定義をしておくとあとで便利です。

  • inventory.ini
[local]
localhost

[local:vars]
ansible_connection=local
ansible_python_interpreter=~/ansible/bin/python

次に Playbook を作成します。ここでは、VPC を作成するだけのごく簡単なものにします。

  • vpc.yml
---
- hosts: localhost
  gather_facts: false

  tasks:
    - name: create VPC
      amazon.aws.ec2_vpc_net:
        name: sakana_vpc_test1
        cidr_block: 10.0.0.0/16
        region: ap-northeast-1

Playbook を実行します。なお、他に明示的にクレデンシャルの設定はしていません。

$ ansible-playbook -i inventory.ini vpc.yml 

PLAY [localhost] ***********************************************************************************************************************

TASK [create VPC] **********************************************************************************************************************
changed: [localhost]

PLAY RECAP *****************************************************************************************************************************
localhost                  : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0  

無事作成されました。

f:id:akira6592:20201230201159p:plain
VPC が作成された

ad-hoc コマンドの実行

今度は Playbook を作成せずに、ad-hoc コマンド ansible を試します。

ここでは、VPC の情報を取得し、先程作った VPC があることを確認します。

$ ansible -i inventory.ini local -m amazon.aws.ec2_vpc_net_info -a "region=ap-northeast-1"
...(略)...
        {
            "cidr_block": "10.0.0.0/16",
            "cidr_block_association_set": [
                {
                    "association_id": "vpc-cidr-assoc-XXXXXXXXXXXX",
                    "cidr_block": "10.0.0.0/16",
                    "cidr_block_state": {
                        "state": "associated"
                    }
                }
            ],
            "classic_link_dns_supported": false,
            "classic_link_enabled": false,
            "dhcp_options_id": "dopt-XXXXXX",
            "enable_dns_hostnames": true,
            "enable_dns_support": true,
            "id": "vpc-XXXXXXXXXXXX",
            "instance_tenancy": "default",
            "is_default": false,
            "owner_id": "XXXXXXXX",
            "state": "available",
            "tags": {
                "Name": "sakana_vpc_test1"
            },
            "vpc_id": "vpc-XXXXXXXXXXXX"
        },
...(略)...

無事に先ほど作成した、 VPC sakana_vpc_test1 が表示されました。

ダイナミックインベントリの表示

Ansible には、クラウドリソースなどをダイナミックなインベントリとして利用できる機能があります。

EC2 の情報をインベントリとして利用するには aws_ec2 インベントリプラグイン を利用します。

まず、aws_ec2 インベントリプラグインを利用するためのインベントリファイルを作成します。ファイル名の最後は aws_ec2.yml または、aws_ec2.ymal である必要があります。

  • inventory_aws_ec2,yml
---
plugin: aws_ec2
regions:
  - ap-northeast-1
  hostnames:
    - tag:Name

aws_ec2 インベントリプラグイン では、フィルターなどの様々な指定ができますが、ここでは リージョンの指定と、Name タグをホスト名として利用するしていのみで試します。

ansible-inventory コマンドでダイナミックインベントリを確認します。まずは --graph オプションで、グループとホストの関係を表示してみます。

$ ansible-inventory -i inventory_aws_ec2.yml --graph
@all:
  |--@aws_ec2:
  |  |--sakana_server1
  |  |--sakana_server2
  |  |--same1
  |--@ungrouped:

それとなくホストが表示されました。特に指定がなくとも aws_ec2 というグループにまとめられます。

つづいて、--list オプションで詳細な情報を表示します。

$  ansible-inventory -i inventory_aws_ec2.yml --list 
{
    "_meta": {
        "hostvars": {
            "sakana_server1": {
                "ami_launch_index": 0,
                "architecture": "x86_64",
                "block_device_mappings": [
                    {
                        "device_name": "/dev/sda1",
                        "ebs": {
                            "attach_time": "2020-12-29T04:38:07+00:00",
                            "delete_on_termination": true,
                            "status": "attached",
                            "volume_id": "vol-XXXXXXX"
                        }
                    }
                ],
...(略)...

無事に表示できました。

今回は ansible-inventory コマンドによる表示だけでしたが、ansible-playbook コマンドの -i オプションに YAML を指定することで、Playbook の実行対象として利用できます。

復帰直後はエラーになることがある [2021/01/02 追記]

CloudShell は、一定期間何もしないとスリープのような状態になります、復帰直後は、クレデンシャル情報が取得できないためか、以下のよいうなエラーが発生することがあります。

botocore.exceptions.CredentialRetrievalError: Error when retrieving credentials from container-role: Error retrieving metadata: Received non 200 response (500) from ECS metadata: <?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n\t\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n <head>\n  <title>500 - Internal Server Error</title>\n </head>\n <body>\n  <h1>500 - Internal Server Error</h1>\n </body>\n</html>

数分待つと正常に戻ります。

おわりに

AWS CloudShell に Ansible をインストールして、Playbook の実行、ad-hoc コマンドの実行、ダイナミックインベントリの表示を試しました。

いくつか制約はあるものの、クレデンシャルを仕込まなくて利用できるのは便利だと思いました。

参考

connpass.com

dev.classmethod.jp