VISASQ TECHBLOG - ビザスク開発ブログ VISASQ TECHBLOG - ビザスク開発ブログ

ENGINEER

  • Ansible
  • GCP
  • Infrastructure
  • linux
  • python
  • 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で作成する迄行きたいと思います。

    エンジニア積極採用中

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