てくなべ (tekunabe)

ansible / network automation / 学習メモ

[AWS] VPC 周りの設定とインバウンド、アウトバウンド通信可否の個人的まとめ

はじめに

AWSVPC 周りを学習中です。

その中で、インターネットゲートウェイ、NAT ゲートウェイ、パブリックIP の有無と、インタネットからEC2 インスタンスへインバウンド、インターネットへのアウトバウンド通信の関係が少々ややこしく感じました。

自分向けに試した結果をまとめておきます。試し方が間違っていたらごめんなさい。

まとめ

パターン No ゲートウェイ (*1) パブリックIP インバウンド (*2) アウトバウンド アウトバウンドの送信元IP (*3) public-ipv4 (*4)
1 インターネットゲートウェイ あり パブリックIP パブリックIP
2 インターネットゲートウェイ なし - × - -
3 NAT ゲートウェイ あり × NAT ゲートウェイの EIP パブリックIP
4 NAT ゲートウェイ なし - NAT ゲートウェイの EIP -

注釈

  • *1 インスタンスが所属しているサブネットのルートテーブルのデフォルトルートの先
  • *2 割り当てたパブリックIPに対してインターネット側からの SSH
  • *3 メタデータ curl http://169.254.169.254/latest/meta-data/public-ipv4 の結果
  • *4 curl ifconfig.io の結果

[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

[Ansible] NetBox のタグを定義する netbox_tag モジュールの使い方

はじめに

NetBox では、デバイスIPアドレスなど様々なオブジェクトにタグを付けることができます。

NetBox 2.8 までは、タグは予め定義は不要だったのですが、NetBox 2.9 から事前の定義が必要になりました。逆にいうと未定義のタグを適用できません。

こうなると、自動化してる場合は対策が必要です。タグの定義 uri モジュールで API を叩けばできるといばできるのですが、netbox.netbox collection1.2.0netbox.netbox.netbox_tag モジュールができました。(changelog はこちら

他のオブジェクトと同じように専用モジュールによって冪等性を保てるようになります。

この記事では、簡単なサンプルで netbox.netbox.netbox_tag モジュールの使い方をご紹介します。

  • 環境
    • ansible 2.10.4
    • netbox.netbox collection 1.2.0
    • Python 3.8.5
    • NetBox 2.10.2

サンプル Playbook

以下がサンプル Playbook です。

---
- hosts: netbox10
  gather_facts: false
  connection: local

  vars:
    ansible_python_interpreter: "{{ ansible_playbook_python }}"

  tasks:
    - name: create tags
      netbox.netbox.netbox_tag:
        netbox_url: "http://{{ ansible_host }}"
        netbox_token: "{{ token }}"
        data:
          name: "{{ item.name }}"                 # タグの名前(必須)
          description: "{{ item.description }}"   # 説明
          color: "{{ item.color }}"               # 色
        state: present
      loop:
        - name: mgmt
          description: management
          color: 4caf50  # Green
        - name: 2021
          description: 2021
          color: ff9800  # Orange

オプションの説明

今この記事を書いている時点では、ドキュメントが生成されていませんが、コード内に埋め込まれたドキュメント用の記載を見ると詳細がわかります。

github.com

いずれ、以下のドキュメントにも反映されると思います。

netbox-ansible-collection.readthedocs.io

netbox_urlnetbox_token オプションは、他の netbox_* モジュールと同じく、接続用のオプションです。

data の中のオプションがタグを定義するためのものです。

data 配下のオプション 説明
name タグの名前(必須)
description 説明
color カラーコード。省略時は 9e9e9e (画面上の名前は Grey)

color は画面で指定できる色のカラーコードにする

画面上は以下のように、指定できる色が決まっています。

f:id:akira6592:20201228133316p:plain:w400
選択できるタグの色
一方で、モジュールのオプションで指定するカラーコードは自由です。ですが、画面で指定できない色に対応するカラーコードを指定してしまうと、画面で編集時に未選択状態となり、色の選択しなおしを迫られます。

そのため、最初からあらかじめ画面で指定できる色のカラーコードにするのが良いでしょう。

NetBox 2.10.2 の画面で指定できるタグのカラーコードと色名(括弧内)は以下のとおりです。

aa1409 (Dark red)
f44336 (Red)
e91e63 (Pink)
ffe4e1 (Rose)
ff66ff (Fuchsia)
9c27b0 (Purple)
673ab7 (Dark purple)
3f51b5 (Indigo)
2196f3 (Blue)
03a9f4 (Light blue)
00bcd4 (Cyan)
009688 (Teal)
00ffff (Aqua)
2f6a31 (Dark green)
4caf50 (Green)
8bc34a (Light green)
cddc39 (Lime)
ffeb3b (Yellow)
ffc107 (Amber)
ff9800 (Orange)
ff5722 (Dark orange)
795548 (Brown)
c0c0c0 (Light grey)
9e9e9e (Grey)
607d8b (Dark grey)
111111 (Black)
ffffff (White)

もしカラーコードがわかりにくい場合は、

color_codes:
  White: "ffffff"
# (略)

のようにまとめた変数を定義して、"{{ color_codes['White'] }}" のようにカラーコードを呼び出せるようにしておくと便利かもしれません。

実行

Playbook を実行します。

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

PLAY [netbox_pwd] *********************************************************************************

TASK [create tags] ********************************************************************************
changed: [netbox_pwd] => (item={'name': 'mgmt', 'description': 'management', 'color': '4caf50'})
changed: [netbox_pwd] => (item={'name': 2021, 'description': 2021, 'color': 'ff9800'})

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

確認

画面の上のメニューの Organization 内の Tags をクリックして、タグ一覧画面を表示します。

f:id:akira6592:20201228132158p:plain
定義したタグが表示される

Playbook で指定した mgmt2021 の2つのタグができたことが確認できます。なお、この状態で再度Playbook を実行すると ok になります。エラーにならず便利です。

これにより、各オブジェクトの上記のタグが適用できるようになります。

f:id:akira6592:20201228132038p:plain
タグの適用

補足

Python 2.7 ではエラー

ansible_python_interpreter をデフォルトに任せてを 2.7 系のままにしていたら、以下のエラーが発生しました。

TASK [create tags] *******************************************************************************************************************************************************************
An exception occurred during task execution. To see the full traceback, use -vvv. The error was: TypeError: super() takes at least 1 argument (0 given)
(略)

非常に感覚的ですが、この手(引数足りない系?)のエラーが出たときは Python インタープリターが意図したものになっているかも確認するのがよさそうです。以前も何かで遭遇した気がします。

この記事の Playbook では、Python 3.8 にインストールした ansible に合わせるため、以下の指定をしていました。

  vars:
    ansible_python_interpreter: "{{ ansible_playbook_python }}"

おわりに

uri モジュールがあればなんとななると思いつつも、はやり専用モジュールは便利です。

docker-compose.yml の内容を上書きする docker-compose.override.yml

はじめに

最近、netbox-docker の README.md を見て知ったのですが、docker-compose.yml の内容を上書きする docker-compose.override.yml というファイルがあるそうです。

docker-compose.yml はそのままのこしておき、docker-compose.override.yml でカスタマイズするのに便利そうです。

公式ドキュメントにも記載がありました。

docs.docker.jp

netbox-docker の README.md の例で試してみます。

docker-compose.yml 単品の場合

nginx を抜粋すると以下の通りです。

  # nginx
  nginx:
    command: nginx -c /etc/netbox-nginx/nginx.conf
    image: nginx:1.19-alpine
    depends_on:
    - netbox
    ports:
    - 8080
    volumes:
    - netbox-static-files:/opt/netbox/netbox/static:ro
    - netbox-nginx-config:/etc/netbox-nginx/:ro

これを docker-compose up -d で起動したあと、確認します。

$ docker-compose ps
            Name                           Command               State                Ports             
--------------------------------------------------------------------------------------------------------
netbox-docker_netbox-worker_1   python3 /opt/netbox/netbox ...   Up                                     
netbox-docker_netbox_1          /opt/netbox/docker-entrypo ...   Up                                     
netbox-docker_nginx_1           /docker-entrypoint.sh ngin ...   Up      80/tcp, 0.0.0.0:49153->8080/tcp
netbox-docker_postgres_1        docker-entrypoint.sh postgres    Up      5432/tcp                       
netbox-docker_redis-cache_1     docker-entrypoint.sh sh -c ...   Up      6379/tcp                       
netbox-docker_redis_1           docker-entrypoint.sh sh -c ...   Up      6379/tcp                       

抜粋すると、以下の通り、49153 が開放されました。

netbox-docker_nginx_1           /docker-entrypoint.sh ngin ...   Up      80/tcp, 0.0.0.0:49153->8080/tcp

ただ、先程の docker-compose.yml ですと、docker-compose up のたびにポートが変わってしまい、たとえば、

netbox-docker_nginx_1           /docker-entrypoint.sh ngin ...   Up      80/tcp, 0.0.0.0:49154->8080/tcp

となってしまい不便です。

docker-compose.override.yml で上書きする

そこで docker-compose.override.yml で上書きして起動する方法を試します。

まず、以下の内容の docker-compose.override.yml を用意します。

version: '3.4'
services:
  nginx:
    ports:
      - 8000:8080
EOF

この状態で docker-compose up -d で起動したあと、確認します。

$ docker-compose ps
            Name                           Command               State                           Ports                         
-------------------------------------------------------------------------------------------------------------------------------
netbox-docker_netbox-worker_1   python3 /opt/netbox/netbox ...   Up                                                            
netbox-docker_netbox_1          /opt/netbox/docker-entrypo ...   Up                                                            
netbox-docker_nginx_1           /docker-entrypoint.sh ngin ...   Up      80/tcp, 0.0.0.0:8000->8080/tcp,0.0.0.0:49153->8080/tcp
netbox-docker_postgres_1        docker-entrypoint.sh postgres    Up      5432/tcp                                              
netbox-docker_redis-cache_1     docker-entrypoint.sh sh -c ...   Up      6379/tcp                                              
netbox-docker_redis_1           docker-entrypoint.sh sh -c ...   Up      6379/tcp  

今度は 8000 も開放されました。「も」なのでマージ的な動作なのでしょうか。

[Ansible] git config に相当する git_config モジュールを試す

はじめに

git の設定を行う git config コマンドに相当する git_config モジュールがあります。

というより、最近存在を知りました。簡単な例ですが、まとめます。

  • 動作環境
    • ansible 2.9.14

Playbook

git config --global user.email sakana@example.com
git config --global user.name sakana

に相当する Playbook です。

---
- hosts: sv
  gather_facts: false

  tasks:
    - name: git config
      git_config:
        scope: global
        name: "{{ item.name }}"
        value: "{{ item.value }}"
      loop:
        - name: user.name
          value: sakana
        - name: user.email
          value: sakana@example.com

事前確認

~/.gitconfig には何も設定がない状態からはじめます。

[admin@centos7 ~]$ cat ~/.gitconfig
cat: /home/admin/.gitconfig: No such file or directory
[admin@centos7 ~]$ git config -l
[admin@centos7 ~]$

Playbook 実行

Playbook を実行します。

$ ansible-playbook -i inventory.ini git.yml
PLAY [sv] ***************************************************************************************

TASK [git config] *******************************************************************************
changed: [sv01] => (item={'name': 'user.name', 'value': 'sakana'})
changed: [sv01] => (item={'name': 'user.email', 'value': 'sakana@example.com'})

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

事後確認

設定されたことを確認します。

[admin@centos7 ~]$ cat ~/.gitconfig
[user]
        name = sakana
        email = sakana@example.com
[admin@centos7 ~]$ git config -l
user.name=sakana
user.email=sakana@example.com
[admin@centos7 ~]$ 

おわりに

もう一度実行したら ok になってくれました。

TASK [git config] *********************************************************************
ok: [netbox01] => (item={'name': 'user.name', 'value': 'sakana'})
ok: [netbox01] => (item={'name': 'user.email', 'value': 'sakana@example.com'})

command モジュールでやってしまっても簡単に実現できるレベルですが、はやり専用モジュールがあるのは便利ですね。

[Ansible] ansible-galaxy コマンドの参照先を Automation Hub に変更する

はじめに

ansbile-galaxy コマンドは role や collection のインストールなどを行います。

デフォルトでは、Ansible Galaxyを参照します。

設定を変更することで、Automation Hub (レッドハット社提供の配布サービス) に変更できます。

ansible.tower collection のように、Ansible Galaxy にはなくAutomation Hub にあるものをインストールする場合は、設定を変更する必要があります。

この記事では手順をご紹介します。

  • 環境
    • Ansible 2.9.15

トークンの取得

ansbile-galaxy コマンドで Automation Hub を参照するにはトークンが必要です。以下の手順でトークンを取得します。

Automation Hub にログインし、左メニューの Connect to Hub をクリックします。

f:id:akira6592:20201227163506p:plain
Connect to Hub をクリック

Load Token ボタンをクリックし、表示されたトークンを控えておきます。

f:id:akira6592:20201227163611p:plain
Load Token

ansible-galaxy コマンドの設定

続いて、ansible-galaxy コマンド側の設定です。

Ansible 公式ドキュメントの Downloading a collection from Automation Hub にある通り、ansible.cfg に以下の設定を行います。

[galaxy]
server_list = automation_hub

[galaxy_server.automation_hub]
url=https://cloud.redhat.com/api/automation-hub/
auth_url=https://sso.redhat.com/auth/realms/redhat-external/protocol/openid-connect/token
token=先程取得したトークンを指定

設定は以上です。

確認

確認として、Automation Hub から入手できる ansible.tower collection をインストールします。

# ansible-galaxy collection install ansible.tower
Process install dependency map
Starting collection install process
Installing 'ansible.tower:3.8.0' to '/root/.ansible/collections/ansible_collections/ansible/tower'

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

なお、Ansible Galaxy を参照する設定のまま ansible.tower collection をインストールしようとすると、見つからないので以下のエラーが発生します。

# ansible-galaxy collection install ansible.towerProcess install dependency map
ERROR! Failed to find collection ansible.tower:*

[Ansible] 「つまずき Ansible 【Part24】2020年のふりかえり」ふりかえり

はじめに

2020/12/26 に、YouTube Live で「つまずき Ansible 【Part24】2020年のふりかえり」という配信をしました。

tekunabe.connpass.com

普段は実際に作業しながら(ときには)エラーと戦って進めるシリーズです。が、今回は2020年最後ということで、今年の Ansible 生活を過去ブログ記事をもとにふりかえりました。

  • 知って便利だとおもったこと
  • びっくりしたこと
  • ハマったこと

なので、ふりかえりのふりかえりです。ほぼリンク集です。


動画

www.youtube.com

  • 0:00 イントロダクション
  • 2:35 便利だと思ったこと
  • 8:00 ハマったこと
  • 14:10 びっくりしたこと(前半)
  • 16:30 便利だと思ったこと(ansible.utils)
  • 20:08 びっくりしたこと(後半)
  • 22:37 延長線(いろいろ)
  • 35:35 おわりに


■ 知って便利だとおもったこと

モジュールのデバッグ方法

tekunabe.hatenablog.jp モジュールをコードレベルでデバッグしたいなぁとかねてより思っていました。

ansible.utils collection による複雑な構造の変数の操作

tekunabe.hatenablog.jp 複雑な構造の変数の値の更新や比較は難しいですが、この collection で結構便利にできそうです。

文字列の連結

tekunabe.hatenablog.jp

いままで、文字列の連結は + でやっていたのですが、数値を文字列として連結するときは | string によるキャストを併用していました。~ なら暗黙的にキャストしてくれて便利でした。

set_fact した値の確認

tekunabe.hatenablog.jp

一時的な確認でも debug をいちいち併用してたのですが、これは便利です。

Playbook の実行結果を JSON で取得

tekunabe.hatenablog.jp

Playbook の実行結果を切りと切り取りたいときに便利です。


■ ハマったこと

見えるはずのファイルが見えない

tekunabe.hatenablog.jp

これはもう、めちゃくちゃにハマってしまいました。

シンタックスエラーになりそうでならない

tekunabe.hatenablog.jp

シンタックスエラーにならない、という点でハマりました。


■ びっくりしたこと

Collection の本格運用

www.slideshare.net

Ansible 2.10 で、標準モジュールが減って、Collection の本格運用がはじまるという大きな変更がありました。 いくつかの仕組みのおかげで、思いの外影響は少ないようですが。

AWX 16.0.0 で画面がガラッと変わった

tekunabe.hatenablog.jp

新しい UI の AWX が来ました。まだまだ先かなと思っていたので、びっくりしました。

Ansible 3.0.0 の足音

tekunabe.hatenablog.jp

いつかは来ると思っていたのですが、Ansible 2.10 結構な変更があった矢先のできごとだったので、びっくりしました。


■ 番外編(Ansible以外)

NUC

tekunabe.hatenablog.jp

NUC を買いました。そうえばこの配信で、デモ環境と OBS(配信ソフト)を同時に動かくとPCスペックが厳しかったのが買うきっかけでした。


おわりに

今年から始めた配信「つまずき Ansible」ですが、ご覧いただいてありがとうございました。来年もマイペースでやっていきたいと思いますので、もし気になったテーマがありましたらご覧いただけると幸いです。

www.youtube.com


Part25 (来年)にむけて

以下のネタを検討中です。気が向いたものをやります。

  • Ansible 2.10 関連
  • connection: local ななにか
  • ansible.cfg
  • Jinja2、フィルター
  • Windows
  • ESXi で VM作成
  • cli_parse モジュール(Part15 の続き)