RAKUS Developers Blog | ラクス エンジニアブログ

株式会社ラクスのITエンジニアによる技術ブログです。

そのAnsibleコード適用して大丈夫?安全性を高めるAnsible CI環境を紹介します。

インフラ開発部でテックリードを務めております上畑です。

みなさんはAnsibleコードを修正した後に そのAnsibleコードを本番環境へ適用する際、ドキドキしていませんでしょうか?

前回、Ansibleをバージョンアップする記事を執筆し、大量のコード修正が必要になりました。

この記事では、ラクスがどのようにしてAnsibleコードをドキドキせずに本番に適用しているか、その仕組みを紹介します。

目次

1. はじめに

一般的に、Ansibleコードを修正してマージする際には、以下のような事前チェックを行うことが多いのではないでしょうか?

  • Lint(構文)チェック
  • 複数人によるコードレビュー
  • 本番環境へのAnsible Dry-Run実行
  • ステージングや開発環境でのAnsible実行

特にAnsibleコードの修正で厄介なのは、

AnsibleのDry-Runでは確認できず、実際に実行しなければ挙動が確認できないコードがある

という点ではないでしょうか。(例えばcronモジュールなど)

そのため、多くの方が以下のような対策を取っているかもしれません。

  • 本番環境の複製やステージング環境でAnsibleを実行し、問題を検証する

しかし、これには次のような課題があります。

  • 修正を繰り返すたびに実行が必要
  • 環境準備が大変
  • 作業後の環境復元でミスが発生する可能性

2. DockerによるAnsible自動実行CIシステム

ラクスでは上記の対策に加え、次の方法を採用しています。

本番環境に近いDockerイメージを用意し、そのDockerイメージ対してAnsibleを実行するCI環境を構築しました。

これにより、Dry-Runではなく実行時の変更差異をAnsibleコードの修正を行いながら何度でも確認可能です。 Docker環境のため、一部実行できないコードや挙動の違いはありますが、実際にAnsibleを実行できるというのは大きなメリットです。

具体的なCI環境の処理フローは以下の通りです。

  1. AnsibleコードをGitサーバにPush
  2. Gitサーバから親JenkinsのCI用ジョブへWebhook通知
  3. CI用ジョブが、Lintチェックジョブを立ち上げてLintチェック(Ansible Lint、YAML Lint)を実行
  4. CI用ジョブが、Ansibleチェックジョブを立ち上げて、指定した本番相当のDockerイメージを起動し、Ansibleを実行
  5. 本番環境に対してAnsibleのDry-Runを実行

3. その他、CI環境の工夫

3-1. 本番環境Dockerイメージの最新化

上記CIを完了後にmainブランチへマージして本番環境へAnsibleの適用を行いますが、

その際、本番相当のDockerイメージへもAnsibleを適用してDockerイメージの更新を行います。この作業も自動化されています。

3-2. CI実行時のエラー調査

Ansibleを実行した際にエラーが発生して調査を行いたいことがありますが、CI環境では実行後にDockerコンテナを停止する為、エラーになった状態を維持することができません。

その為、CI実行後にDockerコンテナを停止しないオプションを用意し、Dockerコンテナにアクセスして調査できるようにしています。

3-3. CI/CDの並列実行を実現するコード化

弊社では、配配メールのサービスだけでも10種類以上のサーバがあり、1つのAnsibleリポジトリでこれらの環境を維持しています。

共通利用のコードに変更を行う際、すべての環境に対して手動でジョブを実行するのは非効率なため、

以下の様なYAMLファイルを用意して並列実行を自動化しています。

CDも同じ仕組みで自動デプロイを行っています。

# Docker CIジョブ
ANSIBLE_DOCKER_RUN:
-
  IMAGE: 'serverA:latest'
  PLAYBOOK: 'serverA.yml'
  stage: 'production'
  DOCKER_KILL: false
-
  IMAGE: 'serverB:latest'
  PLAYBOOK: 'serverB.yml'
  stage: 'production'
  DOCKER_KILL: false

# 本番Dry-Runジョブ
ANSIBLE_HONBAN_DRY_RUN
-
  PLAYBOOK: 'serverA.yml'
  stage: 'production'
-
  PLAYBOOK: 'serverB.yml'
  stage: 'production'

3-4. 定期Dockerイメージの構築

Ansibleコードは当然ながら新規から構築を行っても同一の環境である必要があります。

よくあるコード修正の失敗として既存環境に対して適用することはできるが、新規に構築した環境では実行できないコードを作成してしまうことがあります。 例えば、以下のように実行順が逆になっている場合など

# 新規に追加したコード
- name: Install Package
  ansible.builtin.dnf:
    name: "A"
    enablerepo: "epel"

# 修正前からあるコード
- name: Enable Epel Repo
  ansible.buitin.file:
    src: "epel.repo"
    dest: "/etc/yum.repos.d/epel.repo"
    owner: "root"
    group: "root"

これは既存の環境に適用した際はepel.repoが存在する為、エラーになることはありませんが新規に構築した際にはエラーになります。

実際にこんな単純なミスはないでしょうが、例えばrole単位に分かれていてplaybook内でrole名の指定順が逆であったため発生するなど

以外と発生するケースはあります。

これは上記DockerCIでも発見できない為、定期的(毎日)素のOSのイメージからAnsibleを実行して新規から構築することが可能か確認を行っています。

4. 最後に

ラクスではAnsibleによるサーバの構成管理の環境を維持する為、その安全性を高める継続的な改善を行っています。

これ以外にもbehaveやmoleculeによる振る舞いテストの追加など強化を行っており、継続的改善を行っていきます。

以上、ありがとうございました!

Copyright © RAKUS Co., Ltd. All rights reserved.