24
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

AnsibleからEC2インスタンスをいい感じにつくる

Last updated at Posted at 2018-06-13

はじめに

Ansible上からEC2をたてて見ます。
いい感じにできるようにまとめてみました。

気をつけたところ

EC2は複数台まとめて起動したい事が多いのでそのあたりも意識します。
commandモジュールやshellモジュールはできるだけ使わないようにします。
できるだけ柔軟で簡素で安全な記載にします。

用意しておくもの

以下の情報を控えておきます。
あとで変数定義してAnsible上から使います。

  • 利用するAWSリージョン
  • 利用するAWSの認証方法
    • この記事ではprofileに記載します。
  • keypairの名前
    • keypairを登録していないならしておきます
  • 建てるEC2の要件の確認
  • インスタンスの名前
    • インスタンスタイプ
    • 立ち上げるインスタンスの台数
    • EBSの種類(gp2、iopsなど)、容量
    • OSの種類
    • 利用するサブネットについているNameタグの名前
      • サブネットやVPCを切っていない場合、あらかじめ切っておきます
    • 利用するセキュリティグループの名前
      • セキュリティグループが作られていない場合、あらかじめ作っておきます
    • EIPの要、不要
    • ひもづけるIAM Roleの名前
      • IAM Roleが作られていない場合、あらかじめ作っておきます

手順

変数としてEC2の情報を定義する

Ansibleから上記の情報が利用できるようにします。
Playbookのvarsブロックやvarsファイルの中などに記載すると良いでしょう。

vars/main.yml
# 定義例
aws_profile: sample
region: ap-northeast-1
ec2_ubuntu_version: xenial-16.04
ec2_eip: true
ec2_list:
  - name: sample-instance1
    instance_type: t2.small
    security_group: sample-web-sg-name
	iam_role_name: sample-iam-role-name
    root_volume_size: 8
    subnet_name: sample-1a-public-subnet
  - name: sample-instance2
    instance_type: t2.small
    security_group:
      - sample-web-sg-name
      - sample-admin-sg-name
	iam_role_name: sample-iam-role-name
    root_volume_size: 8
    subnet_name: sample-1c-public-subnet

EC2の起動タスクを記載する

OSの名前からAMIを取得する

この手順は、AWSの提供しているAMI(Amazonマシンイメージ)を取得するときに必要です。
AMIを自分で焼いて利用するときなどは条件にあうようにfilterを変更しましょう。。
ownersパラメータには、amazon、microsoft、もしくは自分の所有しているAWSアカウントのIDを指定しておくと良いでしょう。

tasks/main.yml
- name: search ami list
  ec2_ami_facts:
    filters:
      name: "ubuntu-{{ ec2_ubuntu_version }}-amd64-server-dotnetcore-*"
      block-device-mapping.volume-type: gp2
    region: "{{ region }}"
    owners: amazon
    profile: "{{ aws_profile }}"
  register: list_ami

- name: set latest ami params
  set_fact:
    map_ami_param: "{{ list_ami.images | sort(attribute='creation_date') | last }}"

ec2_ami_factsモジュールはAnsible2.5からの追加となります。
何かしらの理由でAnsible2.5が使えない場合は
ec2_ami_findモジュールを使うとよいでしょう。
 
 
ここでは、gp2タイプのubuntu16.04のOSイメージを所得します。
利用するEBSタイプ、OSのバージョンにあわせて変更するとよいでしょう。
 
この時、取得したAMIリストをソートして最後のイメージを選択しています。
このようにしてAMIのIDを取得することで
その時のAWSで公開されている最新のOSイメージを利用することができます。
WebコンソールでEC2を建てるときに表示されるOSイメージを同じように利用できますね。

サブネットの名前からサブネットIDリストを作る

ec2_vpc_subnet_factsモジュールを利用して、サブネットIDを取得します。
ここでは、少し前処理を加えています。

サブネットリストの取得

単一サブネットに配置するならfactを噛ませれば完了です。
が、AZ対応などで配置するサブネットを分けたいときが多いので
まずサブネットの名前リストを取り出し、まとめてfactsにかけます。

tasks/main.yml
- name: find subnet id
  ec2_vpc_subnet_facts:
    region: "{{ region }}"
    profile: "{{ project }}"
    filters:
      "tag:Name": "{{ item }}"
  with_items:
    "{{ ec2_list | map(attribute='subnet_name') | list | unique }}"
  register: map_subnet_id

uniqueフィルターをかけ、多くのインスタンスを同時に起動するとき
問い合わせが多くかからないようにしましょう。

取り出せるように加工

set_factで取り出したサブネットリストを加工します。
2018/10/02追記
Ansible 2.6.5で、戻り値が変わっていました。
どのバージョンで変わったかまでは不明ですが、
新しいバージョンを利用している方は引数の値を変更してください

tasks/main.yml
- name: make subnet map(new ansible version)
  set_fact:
    name_subnet: "{{ item.tags.Name }}"
    id_subnet: "{{ item.subnet_id }}"
  with_items: "{{ map_subnet_id.subnets }}"
  register: map_subnets_result

#- name: make subnet map(old ansible version)
#  set_fact:
#    name_subnet: "{{ item.tags.Name }}"
#    id_subnet: "{{ item.subnet_id }}"
#  with_items: "{{ map_subnet_id.results | map(attribute='subnets') | list }}"
#  register: map_subnets_result

- name: make subnet list
  set_fact:
    list_subnets:
      "{{ map_subnets_result.results | map(attribute='ansible_facts') | list }}"

まず、with_itemsで取り出したリストをループさせつつ
あとで取り出しやすいようにしておきます。
factだけだと最後のループの変数で上書きされてしまうので
registerに登録しておきます。

そして、registerから取り出したものを切り出して
新しい変数(list_subnets)に設定して完了です。

EC2インスタンスの起動

今まで設定した情報を元に、インスタンスを起動します。

tasks/main.yml
- name: create ec2 instance
  ec2:
    image: "{{ map_ami_param.image_id }}"
    instance_profile_name: "{{ iam_role_name }}"
    instance_type: "{{ item.instance_type }}"
    key_name: "{{ item.key_name | default('default-key')}}"
    vpc_subnet_id: "{{ list_subnets | selectattr ('name_subnet', 'equalto', item.subnet_name) | map(attribute='id_subnet') | list | first }}"
    group: "{{ item.security_group }}"
    wait: yes
    volumes:
      - device_name: "/dev/sda1"
        volume_type: "gp2"
        volume_size: "{{ item.root_volume_size }}"
        delete_on_termination: true
    instance_tags:
      Name: "{{ item.name }}"
      app: "{{ project }}"
      env: "{{ env }}"
      role: "{{ item.role }}"
    count_tag:
      Name: "{{ item.name }}"
    exact_count: 1
    profile: "{{ project }}"
    region: "{{ region }}"
  with_items:
    - "{{ ec2_list }}"
  register:
    ec2

- name: add EIP
  ec2_eip:
    profile: "{{ project }}"
    region: "{{ region }}"
    instance_id: "{{ item.tagged_instances.0.id }}"
  with_items: "{{ ec2.results }}"
  when: ec2_allocate_eip is defined and ec2_allocate_eip == True
  register: ec2_eip

本当はec2_instanceモジュールを使った方がいいのですが
ansible 2.5.4だとinstance profileを設定するとバグが出るのでec2モジュールを使用します。
https://github.com/ansible/ansible/pull/37465
ansible 2.6で修正されているので
stable releaseが作られるのを待ちましょう。
 
パラメータが多いので、テーブルで解説します。
 
https://docs.ansible.com/ansible/2.4/ec2_module.html
きちんとしたドキュメントはこちらを参照してください。

パラメータ名 説明
image AMIのImage IDです。上のami_factから取得しています
instance_profile_name attachするIAM Roleの名前です
instance_type インスタンスタイプをしています
key_name 登録済みのkey_pairの名前を設定します
vpc_subnet_id インスタンスを動かすsubnet_idを指定します。上でfactしたlistから取り出しています
group セキュリティグループの名前です。単一文字列か文字列リストで指定します
wait Ansibleが次のtaskに移る前にEC2の起動を待つかどうかです
volumes 起動時にattachするボリュームインスタンスです。リストで指定します(この例ではシステム用につけるボリュームのみ記載します)
volumes.0-9.device_name デバイス名を記載します。以下のURLを参考にしてください
(補足) https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/device_naming.html
volumes.0-9.volume_type volume typeを記載します。EBSのgpsやiopsなどのボリュームタイプを記載します
volumes.0-9.volume_size EBSに割り当てるボリュームの容量を指定します。単位はGByteです
volumes.0-9.delete_on_termination EC2インスタンス削除時にEBSも消すかどうかの設定をします
instance_tags インスタンス起動時に設定するタグを辞書形式で指定します
count_tag 既存のEC2インスタンスを数え、特定のタグ付いているインスタンスが指定数以下ならEC2を立ち上げません。Nameタグと組み合わせて冪とう性を保つ目的によく使われます
exact_count count_tagで数えるインスタンスの指定数です。1にしてPlaybookに記載したインスタンスを1つだけ起動する目的によく使われます

サブネットは、selectattrで特定のサブネットのパラメータに指定して
mapでサブネットIDを取得しています。

おわりに

EC2の構築も、Ansibleの進歩とともに便利になってきました。
体感ですが、3桁台数ぐらいまでならAnsibleが一番楽に利用できるツールと思います。
昔の設定を見なおしてより効率よく管理したいですね。

編集履歴

2018/09/13

コミュニティAMIを利用するとセキュリティリスクがあったため
一部記事を修正しました。

2018/10/01

新しいAnsibleで戻り値が更新されていたので、一部taskを更新しました。

24
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
24
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?