Edited at

自社クラウドサービスをAnsibleで作った話 recap


概要

 先日のAnsible Night in Tokyo 2019.04にて掲題の内容で発表したのですが、内容の補足を残したいと思います

 下記以外で気になる点や質問があればお気軽にどうぞ!

 

 ※発表資料はこちらです

 当記事をご覧頂いた方でAnsibleを初めてみようと思ったならば、「これからAnsibleを勉強する際におさえておきたいこと」も合わせてどうぞ!


Salesforceで何を管理しているのか?

 顧客が契約しているサービスプランに応じて、環境が異なるため、そういった情報(インスタンスのスペックやディスク容量など)がSalesforceで管理されています

例えば、トライアル契約、本契約の2つあるのですが、その契約によってデプロイされる環境が異なります

つまり、契約と環境の情報を管理し、契約確定した時点でAWXに環境の作成や更新するような仕組みになっています

その間にシステム担当者は一切関与せずに契約に基づいて環境の変更が行われるので、リードタイムの短縮が図れます

 B2Bのサービスといえどもリードタイムの短縮が問われる(コストダウンの側面もある)ので、営業システムと直結できるようなシステム構成を取ることでビジネススピードが飛躍的に向上すると思います。そういった意味ではSalesforceは強力なプラットフォームだと言えます


Salesforceのテスト自動化

 Salesforceではカスタムコード(Apex)のテストカバレッジが75%以上でなければ本番環境にデプロイできない仕組みになっています。なので、前述のようにSalesforce(ビジネスロジック)とAnsible(環境構成)で明確に役割を分離させているとシステムのバージョンアップもスムーズになります。つまり、ビジネスロジックのテストは自動化されていて、そのテスト内でREST API呼ぶためのパラメータを確認すればよい

 これもSalesforceの強みだと言えます


Ansibleを選んだ理由


人件費が高い

 イニシャルコストとしてシステム開発費用は発生するが、ランニングコストを含めたトータルコストで見ると自動化しておくことでコスト削減やシステムの安全運用が望める


可用性が高い

 Ansibleの特徴でもありますが、Linuxに限らず、Windows、ネットワーク機器、VMware、各種クラウドサービス、APIがあるWebサービスなどに適用できるため、普段の業務効率化につなげることも可能。それらが共通言語としてAnsibleでコード化できるので、管理しやすく、人材育成もしやすい

 現に自社クラウドサービスもSalesforce内の顧客管理部分以外はすべて(Zabbix、AWS、アンチウィルス、Slack)Ansibleで構成管理されている


命名規則

補足というよりも反応がよかったので、改めて書きます


動的変数名

各タスク内で動的に生成している変数名(set_factregister)はアンダーバーで始める

静的変数(host_vars、group_vars、vars)との違いを明確にするため

プログラミングでは、関数内の変数なのか、それとも外部の変数なのかをぱっと見区別できるようにするための手法です

意図せず同じ名前つけて変数を上書きしない効果もあります


set_fact.yml


# 例1
- set_fact:
_hoge: "fuga"

# 例2
- command: "env"
register: _env_result



ファイル名

playbook、role、taskのファイル名は種別(名詞)から始めること

ソースツリーで同じ種別のファイルがまとまって見えるので、可読性が高まる

# NGパターン

|- create_ec2_instance.yml
|- create_ecr_image.yml
|- delete_ec2_instance.yml
|- delete_ecr_image.yml

# OKパターン
# 同じ種別のファイルがまとまって見えて管理がしやすくなる
|- ec2_instance_create.yml
|- ec2_instance_delete.yml
|- ecr_image_create.yml
|- ecr_image_delete.yml


自作モジュール名

自作モジュールかどうかをわかりやすくするために、モジュール名はシステム名の略語で開始する


hoge_module.yml

# hogeシステムの場合

- name: Create Hoge EC2 Instance
hoge_ec2_instance:


変数ファイル

変数ファイルはコメントが記述できるyaml形式を採用

jsonだとコメントを記載できない


変数はdict型

一部のサンプルコードで以下のNGパターンのように変数の意味を示すために変数名が長くなり、保守性が低下します

OKパターンのように変数が階層ごとに表現されるので、ぱっと見わかりやすくなります

※好き嫌いはあると思いますので、以下のNGパターンは私のチームでの決め事になります


vars.yml


# NG
aws_ec2_tags: my_ec2
aws_ebs_tags: my_ebs

# OK
aws:
ebs:
tags: my_ebs
ec2:
tags: my_ec2



苦労したこと

補足というよりも、わかりづらかったので、改めて説明します


エラーハンドリング

プログラミングでいうtry/catchはblock/resueで実現できるが、適用範囲はtasks内のみである

下記のようなplaybook内で複数のimport_playbookを包括にblock/resueはない


import_playbook.yml


# blck/resueで一括でエラーハンドリングできない

- name: Create APP Instance
import_playbook: instance_app_create.yml

- name: Create DB Instance
import_playbook: instance_db_create.yml



工夫している点


ビジネスロジックはAnsibleに持ち込まない

前述の契約に応じて環境が作成、更新されるが、ビジネスロジックはAnsibleに持ち込まないようにしています

ビジネスロジックが複数個所に散在すると保守性が低下しますので、

ビジネスロジックはすべてSalesforce上で処理し、その結果としてAnsibleに渡す変数のみをつくるようにしています


AMIに最新のコンテナイメージを含める

APPとDBはコンテナで動作していますが、最新のコンテナイメージをAMIに含めることで、初回デプロイ時にレジストリからプルすることがなくなりデプロイ時間の短縮が図れます。コンテナイメージがギガ単位になるとプルする時間もそれなりにかかるようになるので、この辺を見直すだけでも時間の短縮になると思います


Docker in Docker

「Ansibleの実行環境がコンテナ」+「DockerfileがJinjaテンプレート化」になっている場合は、DockerイメージをビルドするためにDocker in Dockerでビルドしている。つまりAnsible(Docker)内でDockerをビルドする


  1. Dockerホストのdocker.sockをAnsibleコンテナにマウントする(ReadOnlyモード)

  2. Jinjaテンプレート化されたDockerfileはAnsible内の適当なディレクトリに展開する

    Ansibleコンテナにマウントしたホストのディレクトリに展開してもよい

  3. AnsibleコンテナのDockerクライアントからdockerイメージをビルドする

    Ansibleイメージにはdockerをインストールしましょう

ちなみにAnsible Containerは使用せずにdocker_containerモジュールでコンテナを操作している


ドライバ変数


スタブ(stub)とは、コンピュータプログラムのモジュールをテストする際、そのモジュールが呼び出す下位モジュールの代わりに用いる代用品のこと。下位モジュールが未完成でも代わりにスタブを用いることでテストが可能になる。逆に上位モジュールの代わりに用いる代用品をドライバ(ソフトウェアの場合)

※wiki引用


かみ砕くと上位モジュールから渡ってくる予定の変数をテスト用の変数で代用したもの

本番用のシステム構成はSalesforceからAWXにリクエストするが、開発段階ではそのような構成を取らずにローカルで開発しやすくするためにドライバを用いて開発している

各Playbookの最初に必ず以下のタスクを実行している

hostvars[inventory_hostname]['awx_job_template_name']でAWXかどうかを判定している

AWX経由だとhostvarsにawx_xxxの変数が含まれるので、それらをAWX判定に使用している

AWXではない場合(ローカル開発)は、var.yml(ドライバ変数)を読み込む

AWXの場合は、Salesforceから渡された外部変数を用いる


import_extra_vars

- include_vars:

file: ../vars/extra/var.yml
when: hostvars[inventory_hostname]['awx_job_template_name'] is not defined


自作モジュール

自作モジュールの開発言語をシェルスクリプトPythonに限定している

好き勝手な言語にすると保守ができなくなる