シルバーウィークに遅い夏休みを満喫した沼野井です。
・・・本当はこれ書いてるの9/14なんですが、公開日の調整の結果↑にような挨拶となりました。
こんな笑点みたいな挨拶をする機会があるとは思ってもいませんでした。
前回までのあらすじ

この構成をansibleで作ろう、と思うCoatiだった・・・

というわけで、前回の続きで、ansibleによるEC2・VPC環境構築の、実際のplaybookの内容についてです。
Playbookの内容
あ、前回すっかり忘れていたのですが、使用しているansibleのバージョンは 2.3 です。ご承知おきください。
Coatiチームで使用している、環境デプロイ用のPlaybookのディレクトリ構成は以下のようになっています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
├── ansible.cfg ├── group_vars │ └── all.yml # 変数定義 ├── hosts ├── roles │ ├── VPC │ │ └── tasks │ │ ├── main.yml # VPC.ymlの本体 │ │ ├── setup_ec2.yml # VPC.ymlの本体 │ │ └── setup_vpc.yml # VPC.ymlの本体 │ └── vpc_peering │ └── tasks │ ├── main.yml # VPC.ymlの本体 │ └── vpc_peering.yml # create_vpc_peering.ymlの本体 ├── create_vpc_peering.yml # 実行するplaybook └── VPC.yml # 実行するplaybook |
なんぞこれ? と目がハテナな方はこちら(英語ですが)
ansibleの標準的なディレクトリ構成と思っていただいてよいと思います。
個々に中身をご紹介していきます。
(1) group_vars/all.yml
全playbookで使う変数を定義しています。以下のような感じです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
|
<span style="font-size: 10pt; font-family: arial, helvetica, sans-serif;"><code> PEER_OWNER_ID: 123456789012 # お客様のAWSアカウント PEERING_VPC_ID: vpc-XXXXXXXX # お客様のVPC ID PEERING_VPC_CIDR: XXX.XXX.XXX.XXX/XX # お客様のVPC CIDR CUSTOMER: Coati Coffee.break.fun # お客様名 EMAIL: COATI@coati.coffee_break_fun.com # お客様のEメールアドレス PREFIX: "CoatiManager_{{ CUSTOMER }}" # VPC, Subnet, ルートテーブル, インスタンス名のprefix REGION: ap-northeast-1 # リージョン(東京) OFFICE_IP: ZZZ.ZZZ.ZZZ.ZZZ # SIOSのオペレーション端末のIPアドレス OFFICE_IP_CIDR: "{{ OFFICE_IP }}/32" # SIOSのオペレーション端末のIPアドレスのCIDR VPC_NAME: "{{ PREFIX }}_VPC" # VPC名称 VPC_CIDR_LEFT: YYY.YYY.YYY # Coati ManagerのCIDRの左部分 VPC_CIDR_BLOCK: "{{ VPC_CIDR_LEFT }}.0/23" # VPCのCIDR Block SUBNET1_NAME: "{{ PREFIX }}_SUBNET1" # Subnet名 SUBNET1_CIDR_BLOCK: "{{ VPC_CIDR_LEFT }}.0/24" # SubnetのCIDR Block ROUTETABLE1_NAME: "{{ PREFIX }}_RT1" # ルートテーブル名 KEY_PAIR: XXXXXXXXXXXXXXXXXXXXXXXXXXX # Coati Managerインスタンスにアクセスするためのキーペア INSTANCE_TYPE: t2.small # Coati Managerインスタンスのインスタンス・タイプ EC2_NAME: "{{ PREFIX }}" # Coati Managerインスタンス名 EC2_PRIVATE_IP: "{{ VPC_CIDR_LEFT }}.10" # Coati ManagerインスタンスのプライベートIPアドレス IAM_ROLE: XXXXXXXXXXXX # Coati Managerインスタンスに割り当てるIAMロール SIOS_ACCOUNT_ID: 987654321098 # サイオスのAWSアカウントID </code></span> |
冒頭の5行の、
|
<span style="font-family: arial, helvetica, sans-serif; font-size: 10pt;"><code> PEER_OWNER_ID: 123456789012 # お客様のAWSアカウント PEERING_VPC_ID: vpc-XXXXXXXX # お客様のVPC ID PEERING_VPC_CIDR: XXX.XXX.XXX.XXX/XX # お客様のVPC CIDR CUSTOMER: Coati Coffee.break.fun # お客様名 EMAIL: COATI@coati.coffee_break_fun.com # お客様のEメールアドレス </code></span> |
はお客様のお申込み内容に従って入力しています。残りの項目は固定値または、↑の内容から自動的に作成されるという寸法です。
(2) VPC.yml
VPCを作成して、その中にCoati Managerインスタンスを作成するplaybookです。インスタンスも作るのにVPC.ymlってネーミングがイマイチです。すみません。
そのネーミングのイマイチなVPC.ymlの中身はこんな感じです。
|
<span style="font-size: 10pt; font-family: arial, helvetica, sans-serif;"><code> --- - name: setup localhost hosts: localhost roles: - VPC </code></span> |
こんだけ。
これは、「ロールVPCのタスクを実行しなさいね」と言ってるだけです。
ロールVPCのタスクとは
|
├── roles │ ├── VPC │ │ └── tasks │ │ ├── main.yml # VPC.ymlの本体 │ │ ├── setup_ec2.yml # VPC.ymlの本体 │ │ └── setup_vpc.yml # VPC.ymlの本体 |
こいつらです。実際にはmain.ymlがまず呼ばれます。
main.ymlは
|
<span style="font-size: 10pt; font-family: arial, helvetica, sans-serif;"><code> --- - include: setup_vpc.yml - include: setup_ec2.yml SUBNET_ID="{{ subnet.subnet.id }}" </code></span> |
これもこんだけで、本体であるsetup_vpc.ymlとsetup_ec2.ymlをincludeしています。
本体の1つ、setup_vpc.ymlの中身を見ていきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
|
<span style="font-size: 10pt; font-family: arial, helvetica, sans-serif;"><code> --- - name: Gather ec2 facts ec2_facts: register: ec2_facts - name: Setup VPC ec2_vpc_net: name: "{{ VPC_NAME }}" cidr_block: "{{ VPC_CIDR_BLOCK }}" dns_hostnames: yes dns_support: yes region: "{{ REGION }}" tags: Role: CoatiManager register: vpc - name: Setup subnet ec2_vpc_subnet: resource_tags: Name: "{{ SUBNET1_NAME }}" cidr: "{{ SUBNET1_CIDR_BLOCK }}" region: "{{ REGION }}" vpc_id: "{{ vpc.vpc.id }}" register: subnet - name: Setup internet gateway ec2_vpc_igw: region: "{{ REGION }}" vpc_id: "{{ vpc.vpc.id }}" register: igw - name: Setup route table ec2_vpc_route_table: resource_tags: Name: "{{ ROUTETABLE1_NAME }}" region: "{{ REGION }}" vpc_id: "{{ vpc.vpc.id }}" subnets: - "{{ subnet.subnet.id }}" routes: - dest: 0.0.0.0/0 gateway_id: "{{ igw.gateway_id }}" register: route_table - name: create temporary file lineinfile: dest: "/tmp/__temp_fact__.yml" create: yes line: "---\n" - name: write vpc_id into temporary file lineinfile: dest: "/tmp/__temp_fact__.yml" line: "manager_vpc_id: {{ vpc.vpc.id }}\n" - name: write route table id into temporary file lineinfile: dest: "/tmp/__temp_fact__.yml" line: "manager_route_table_id: {{ route_table.route_table.id }}\n" - name: Setup security group. part 1 ec2_group: name: default description: default VPC security group region: "{{ REGION }}" vpc_id: "{{ vpc.vpc.id }}" purge_rules: yes rules: - proto: tcp from_port: 80 to_port: 80 cidr_ip: 0.0.0.0/0 - proto: tcp from_port: 22 to_port: 22 cidr_ip: "{{ OFFICE_IP_CIDR }}" - proto: tcp from_port: 22 to_port: 22 cidr_ip: "{{ ec2_facts.ansible_facts.ansible_ec2_public_ipv4 }}/32" - proto: icmp from_port: -1 to_port: -1 cidr_ip: "{{ OFFICE_IP_CIDR }}" - proto: icmp from_port: -1 to_port: -1 cidr_ip: "{{ ec2_facts.ansible_facts.ansible_ec2_public_ipv4 }}/32" changed_when: False register: default_sg - name: Setup security group. part 2 ec2_group: name: default description: default VPC security group region: "{{ REGION }}" vpc_id: "{{ vpc.vpc.id }}" purge_rules: no rules: - proto: all from_port: 0 to_port: 65535 group_id: "{{ default_sg.group_id }}" changed_when: False </code></span> |
一転して長くなりましたね。本体ですから、実際いろいろやってます。順にみていきますと、
|
<span style="font-size: 10pt; font-family: arial, helvetica, sans-serif;"><code> - name: Gather ec2 facts ec2_facts: register: ec2_facts </code></span> |
ec2_factsは(playbookを実行している)ホストの情報を色々集めてくるモジュールです。今回は、パブリックIPアドレスを取得するため(だけ)に使っています。
registerは、集めたネタを変数(この場合 変数名もec2_facts)に格納します。
実際にec2_factsを使っているところは後ほど!
|
<span style="font-size: 10pt; font-family: arial, helvetica, sans-serif;"><code> - name: Setup VPC ec2_vpc_net: name: "{{ VPC_NAME }}" cidr_block: "{{ VPC_CIDR_BLOCK }}" dns_hostnames: yes dns_support: yes region: "{{ REGION }}" tags: Role: CoatiManager register: vpc </code></span> |
Coati Managerインスタンスを格納するVPCを作成しています。ec2_vpc_netモジュールを使います。
{{ VPC_NAME }} は group_vars/all.ymlで定義してあるものです(ansibleでは、”{{}}”で囲むと変数の値が取り出せます)
同様に{{VPC_CIDR_BLOCK}}, {{ REGION }}もgroup_vars/all.ymlで定義しています。
あと、tags:を利用して、 作成したVPCにRole=CoatiManager というタグをつけています。
ec2_vpc_netモジュールは、作成したVPCのIDなどを実行時の結果として戻しますので、実行結果をregisterで変数vpcに格納しておいて、あとで使うことができます。
|
<span style="font-size: 10pt; font-family: arial, helvetica, sans-serif;"><code> - name: Setup subnet ec2_vpc_subnet: resource_tags: Name: "{{ SUBNET1_NAME }}" cidr: "{{ SUBNET1_CIDR_BLOCK }}" region: "{{ REGION }}" vpc_id: "{{ vpc.vpc.id }}" register: subnet </code></span> |
作ったVPCにsubnetを作成します。今作ったVPC IDが必要です。ここで、さきほどregisterで保存した変数vpcを使います。VPC IDは、
|
<span style="font-size: 10pt; font-family: arial, helvetica, sans-serif;"><code> vpc_id: "{{ vpc.vpc.id }}" </code></span> |
のようにして参照できます。
|
<span style="font-size: 10pt; font-family: arial, helvetica, sans-serif;"><code> - name: Setup internet gateway ec2_vpc_igw: region: "{{ REGION }}" vpc_id: "{{ vpc.vpc.id }}" register: igw </code></span> |
同様に、作成したVPCにインターネットゲートウェイを作成しています。ec2_vpc_igwモジュールを使います。
|
<span style="font-size: 10pt; font-family: arial, helvetica, sans-serif;"><code>- name: Setup route table ec2_vpc_route_table: resource_tags: Name: "{{ ROUTETABLE1_NAME }}" region: "{{ REGION }}" vpc_id: "{{ vpc.vpc.id }}" subnets: - "{{ subnet.subnet.id }}" routes: - dest: 0.0.0.0/0 gateway_id: "{{ igw.gateway_id }}" register: route_table </code></span> |
ルートテーブルの作成です。ec2_vpc_route_tableモジュールを使います。ちょっとパラメータが増えましたが、基本は同じです。
なお、ここでは送信先を0.0.0.0/0にしていますが、適切に設定してくださいね!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
|
<span style="font-size: 10pt; font-family: arial, helvetica, sans-serif;"><code> - name: Setup security group. part 1 ec2_group: name: default description: default VPC security group region: "{{ REGION }}" vpc_id: "{{ vpc.vpc.id }}" purge_rules: yes rules: - proto: tcp from_port: 80 to_port: 80 cidr_ip: 0.0.0.0/0 - proto: tcp from_port: 22 to_port: 22 cidr_ip: "{{ OFFICE_IP_CIDR }}" - proto: tcp from_port: 22 to_port: 22 cidr_ip: "{{ ec2_facts.ansible_facts.ansible_ec2_public_ipv4 }}/32" - proto: icmp from_port: -1 to_port: -1 cidr_ip: "{{ OFFICE_IP_CIDR }}" - proto: icmp from_port: -1 to_port: -1 cidr_ip: "{{ ec2_facts.ansible_facts.ansible_ec2_public_ipv4 }}/32" changed_when: False register: default_sg </code></span> |
セキュリティグループの作成です。ec2_groupモジュールを使います。以下のポートに穴をあけています。
ポート番号 |
ソース |
備考 |
80 |
0.0.0.0/0(※) |
|
22 |
手元のPCのIPアドレス |
私がオフィスから直接ログインして操作するため |
22 |
オペレーション端末のIPアドレス |
オペレーション端末からログインして色々設定するため |
-1 |
手元のPCのIPアドレス |
ICMPです。ping用 |
-1 |
オペレーション端末のIPアドレス |
ICMPです。ping用 |
※ここでは0.0.0.0/0と書いてありますが、適切に設定してくださいね!
「オペレーション端末の(グローバル)IPアドレス」の指定に、最初の方で取っておいたec2_factsを使っています。
やっと伏線回収できました!
|
<span style="font-size: 10pt; font-family: arial, helvetica, sans-serif;"><code> - name: Setup security group. part 2 ec2_group: name: default description: default VPC security group region: "{{ REGION }}" vpc_id: "{{ vpc.vpc.id }}" purge_rules: no rules: - proto: all from_port: 0 to_port: 65535 group_id: "{{ default_sg.group_id }}" changed_when: False </code></span> |
セキュリティグループ構築その2、です。同じセキュリティグループに割り当てられたインスタンスからのトラフィックを許可しています。
ここまでの結果
・・・いかがでしたでしょうか。ここまでで、

の構成ができました。
少し長くなってしまったので、Coati Managerインスタンスの作成とVPC Peeringの設定は次回にしようと思います!