概要
先日の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_fact
、register
)はアンダーバー
で始める
静的変数(host_vars、group_vars、vars)との違いを明確にするため
プログラミングでは、関数内の変数なのか、それとも外部の変数なのかをぱっと見区別できるようにするための手法です
意図せず同じ名前つけて変数を上書きしない効果もあります
# 例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システムの場合
- name: Create Hoge EC2 Instance
hoge_ec2_instance:
変数ファイル
変数ファイルはコメントが記述できるyaml形式を採用
jsonだとコメントを記載できない
変数はdict型
一部のサンプルコードで以下のNGパターンのように変数の意味を示すために変数名が長くなり、保守性が低下します
OKパターンのように変数が階層ごとに表現されるので、ぱっと見わかりやすくなります
※好き嫌いはあると思いますので、以下のNGパターンは私のチームでの決め事になります
# 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はない
# 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をビルドする
- Dockerホストのdocker.sockをAnsibleコンテナにマウントする(ReadOnlyモード)
- Jinjaテンプレート化されたDockerfileはAnsible内の適当なディレクトリに展開する
Ansibleコンテナにマウントしたホストのディレクトリに展開してもよい - 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から渡された外部変数を用いる
- include_vars:
file: ../vars/extra/var.yml
when: hostvars[inventory_hostname]['awx_job_template_name'] is not defined
自作モジュール
自作モジュールの開発言語をシェルスクリプト
かPython
に限定している
好き勝手な言語にすると保守ができなくなる