VisasQ Dev Blog

ビザスク開発ブログ

GCPで基本に戻って始める実践 Infrastructure as code再入門#3

こんにちは! 2020年2月からSREチームにJoinしました木村です!
仕事をする上での座右の銘は「明日交通事故にあってもシステムと仕事を回せるようにすること」です。

基本に戻って始める。と表題では書いていますが、私元々はAWS職人でGCPに本格的にコミットしてからまだ3ヶ月位です!

なのでヒィヒィ?言いながらGCPのキャッチアップに努めているわけですが今回は過去にAWSで得たInfrastructure as Codeの知識とビザスクに入社してキャッチアップで培ったGCPの知識を元に基本に戻って始めるGCPのInfrastructure as Code再入門ということで書かせていただきます。

前回はAnsibleの基本的な用語の説明から初回のAnsibleの実行迄を説明しましたので今回はAnsibleを使った実際のPlaybook,taskの書き方等を説明していきます。

その他のGCPで基本に戻って始める実践 Infrastructure as code再入門シリーズはこちら

今回のGCPのInfrastructure as code再入門シリーズでのゴールイメージ

  • TerraformでCompute Instanceを作成
  • Compute Instanceに対してAnsibleでNginxをインストールする <= 今ココ
  • AnsibleでProvisoningされたサーバーの状態をPackerでImage化


始める前に用意していただきたいもの

動作環境(ホストOS)

  • ホストOS: Mac OSX
  • Python 3.7.5
  • Ansible (2.9.7)

動作環境(ゲストOS)

  • CentOS7

rolesを記述する

rolesとはPlaybookの集合体と考えてください。
rolesの中身の粒度や単位は自由に設定できますがディレクトリの命名規則によってAnsibleがそれが何の設定なのか?を判断します。
今回は代表的な部分だけ説明させてもらいます。

roles/
    nginx/install/
        tasks/
           main.yml
        handlers/
           main.yml
        files/
           hoge.ini
        templates/
           hoge.ini.j2

roles/tasks

このtaskが実際リモートサーバーに対してどのような事を実行するのか?を記述します。今回はyumでnginxをインストールする例です。

yumに関する詳しい書き方は公式Ansible yum moduleのページを参照してください。

moduleの一覧はAnsible公式ドキュメントのAll modulesを参照してください。

# roles/nginx/install/tasks/main.yml

- name: Install nginx
  become: yes
  # Python3ではyum moduleが動作しないのでこのような形でyum moduleを使うときはansibleが実行するPythonをpython2に向けています。
  vars:
    ansible_python_interpreter: /usr/bin/python
  yum:
    name: nginx
    state: present
  notify: Start nginx

roles/handlers

インフラの構築では例えば

  • nginxのinstallをする
  • nginx.confの設定を変更する
  • nginxとgunicornの設定をする
  • nginxとxxxxxの設定をする

....とnginxに紐づく設定が複数あり全ての設定が反映した最後に一度だけnginxの再起動を行いたい。

このようなシーンがあるかと思います。
その場合にhandlersを使います。

例としてnginxをインストール後、最後にnginxの起動を実行させる例です。

roles/nginx/install/{tasks,handlers}/main.ymlを記述する

notifyがhandlersを呼び出す命令になります

# roles/nginx/install/tasks/main.yml

- name: Install nginx
  become: yes
  vars:
    ansible_python_interpreter: /usr/bin/python
  yum:
    name: nginx
    state: present
  notify: Start nginx
# roles/nginx/install/handlers/main.yml

- name: Start nginx
  become: yes
  systemd:
    name: nginx
    # group_vars/allに記載した変数を展開しています。説明は後述
    daemon_reload: "{{ nginx_daemon_reload }}"
    state: started
    enabled: yes

こうすることによってAnsibleを実行した場合の挙動としては

  • nginx/install/tasks/main.ymlを実行
  • nginx/configure/tasks/main.ymlを実行
  • gunicorn/install/tasks/main.ymlを実行
  • ....
  • nginx/install/handlers/main.ymlを実行

となります。またnotifyを複数回呼び出しても実行されるのは1回のみです。

Playbookの変数展開とよく使うであろう条件分岐について

ansibleではjinja2のテンプレート記法を用いる事ができます。
daemon_reload: "{{ nginx_daemon_reload }}"
が該当します。

この他にもwhen等による条件分岐があります。
例えば今回の例でいうと、yumのモジュールを用いているのでOSがDebianの場合は当然のことながらyumがはいっていません。その場合は

# roles/nginx/install/tasks/main.yml

- name: Install nginx
  become: yes
  vars:
    ansible_python_interpreter: /usr/bin/python
  yum:
    name: nginx
    state: present
  notify: Start nginx
  # when でOSがRedHat系OSの場合しか実行しない様にしている
  when: "ansible_os_family == 'RedHat'"

この様に記述できます。

roles/files/{展開したいファイル}

file moduleを使った場合にリモートサーバーに転送するファイルを配置します。
( 設定ファイルとか)

roles/templates/{展開したいファイル}.j2

template moduleを使用してファイルに変数を埋め込みたい場合やifの条件分岐をファイルに指定したい場合に使います。

Top Level Playbookにroleを追加する

最初に記述したsite.ymlを変更します

# site.yml

- name: Top Level Playbook Sample
  hosts:
    - "gcp_service_type_web"
  vars_files:
    - "group_vars/all"
  roles:
    - nginx/install/

group_vars/allに変数を記述する

今回のTop Level Playbookでは明示的にgroup_varsを読み込ませていますが、
Ansibleはデフォルトでhost名と同名のgroup_vars/{host名}をplaybook実行時に読み込みます。

今回変数で追加するのはroles/nginx/install/handlers/main.ymlで記載した"{{ nginx_daemon_reload }}"の変数です。

# group_vars/all
nginx_daemon_reload: "yes"

Ansibleを実行する

roleの内容どおりNginxがinstallされることを確認しましょう。

# 今までのコード

# site.yml
- name: Top Level Playbook Sample
  hosts:
    - "gcp_service_type_web"
  vars_files:
    - "group_vars/all"
  roles:
    - nginx/install


# inventories/dev.gcp.yml

# 先程ansible.cfgのinventoryセクションで指定したgcp_computeモジュールを使う設定です
plugin: gcp_compute
projects: {your gcp projectid}
regions:
  - asia-northeast1-c
filters: []
# ansibleの実行ユーザーはサービスアカウント
auth_kind: serviceaccount
# サービスアカウントのkeyファイルのパス
service_account_file: secrets/gcp-key-ansible-sa.json
keyed_groups:
  - prefix: gcp
    key: labels


# group_vars/all
nginx_daemon_reload: "yes"

# roles/nginx/install/tasks/main.yml

- name: Install nginx
  become: yes
  vars:
    ansible_python_interpreter: /usr/bin/python
  yum:
    name: nginx
    state: present
  notify: Start nginx

# roles/nginx/install/handlers/main.yml

- name: Start nginx
  become: yes
  systemd:
    name: nginx
    daemon_reload: yes
    state: started
    enabled: yes

実行してみます

$ ansible-playbook \
  --inventory=inventories/dev.gcp.yml \
  --private-key secrets/ssh-key-ansible-sa \
  --user sa_123456789 \
  --diff \
  -v \
  site.yml

実行結果

ansible-playbook --inventory=./inventories/dev.gcp.yml --private-key secrets/ssh-key-ansible-sa-dev --user sa_123456789 --limit gcp_service_type_web --diff -v hoge.yml


PLAY [Top Level Playbook Sample] ***********************************************************************************************************************

TASK [Gathering Facts] *********************************************************************************************************************************
ok: [xx.xx.xx.xx]

TASK [nginx/install/ : Install nginx] ******************************************************************************************************************
changed: [xx.xx.xx.xx] => {"changed": true, "changes": 
.
.
.
RUNNING HANDLER [nginx/install/ : Start nginx] *********************************************************************************************************
changed: [xx.xx.xx.xx] => {"changed": true, "enabled": true, "name": "nginx", 
.
.
.

PLAY RECAP *********************************************************************************************************************************************
xx.xx.xx.xx                : ok=3    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

まとめ

今回はAnsibleを実際に書き始める実践的な基本のノウハウを説明しました。

ここらへんの概念を覚えておけば後はplaybookを書く際には困らないかな?と思います。

次回はこのinstallしたnginxのOSImageをPackerで作成する迄行きたいと思います。

エンジニア積極採用中

ビザスクでは一緒に働くエンジニアさん積極採用中です。
時期的にビデオ通話での面談になると思うので、ビザスクにちょっとでも興味のある方はいつもより気軽にお話を聞きに来ることができるかなと思います。