こんにちは! 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化
始める前に用意していただきたいもの
- GCPアカウント(初めての方はGCPの無料枠があります)
- GCP プロジェクト
- Homebrew
動作環境(ホスト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で作成する迄行きたいと思います。
エンジニア積極採用中
ビザスクでは一緒に働くエンジニアさん積極採用中です。
時期的にビデオ通話での面談になると思うので、ビザスクにちょっとでも興味のある方はいつもより気軽にお話を聞きに来ることができるかなと思います。
- エンジニア採用ページ: https://visasq.co.jp/engineer-recruitment
- ビザスクの中の様子はこちらから >> https://square.visasq.com/