Taste of Tech Topics

Acroquest Technology株式会社のエンジニアが書く技術ブログ

DockerとAnsibleの使い分けを手探りで考えてみた

皆さんこんにちは。
アキバです。
久しぶりにエントリ書きます。


突然ですが、今、システムをデプロイすると言ったら自動化しますよね。

そこで、皆さんは何を使っていますか?

私は、最近、DockerAnsibleを仕事でガチに触る機会がありました。
※本番運用のサーバもDockerを使って動作させました。

f:id:acro-engineer:20151201043907p:plain:w200 f:id:acro-engineer:20151201043910p:plain:w200


今回は、そこで得たことについて書きます。
皆さんの参考になればと思います。

命題:Dockerを使うべきか、Ansibleを使うべきか。

作るべきシステムは、いわゆるWebシステムで、WEBサーバとAPサーバで構成しています。
WEBサーバとAPサーバはそれぞれN台のクラスタ構成です。

※以下の図は、本番運用で想定しているサーバ構成を今回の説明用に抽象化したものです。
f:id:acro-engineer:20151201105254p:plain

N台のクラスタ構成ということで、Dockerを使おうとなりました。
コンテナでスケールアウト出来るから…ですね。

さてここで、実際にシステムを構築するのに、Dockerを使うべきか、Ansibleを使うべきか
そこで色々と紆余曲折があったわけです。

結論から書くと

今回は、Dockerコンテナの部分はDockerだけで構築し、Dockerコンテナの外の部分にAnsibleを使うというやり方にしました。

f:id:acro-engineer:20151201111236p:plain

※コンテナは、Docker Registryにpushしておくことで、複数の環境に同じコンテナイメージをデプロイできるようにもしてあります。

ただ、この方式に到達するまでには、いくつかのアンチパターンとも言うべき苦い経験をしています。
それらから、主なものを次に紹介していきますので、同じ失敗をしないように参考にしてもらえればと思います。

アンチパターン1:AnsibleでDockerコンテナの中身を操作しようとする

最初(まだ開発環境の段階でしたが)、この時はAnsibleを使って、Dockerコンテナの中身をコンテナの外から構築しようとしました。
さらに、1つのDockerコンテナを作って、その中にDBとアプリをすべて1コンテナに詰め込もうとしました。

f:id:acro-engineer:20151201111253p:plain

しかし、この構成はうまく行きませんでした。
当初、Ansibleは1.5を使っていたのですが、
DockerコンテナをAnsibleを使って構築するのに、壁がありました。

Dockerコンテナは、その仕組み上、起動するたびにIPアドレスが変わる可能性があります。
Ansibleを使ってアプリ環境を構築する際に、コンテナの外からIPアドレスを調べたり、それを設定ファイルに反映したりといったことになってしまいました。

そもそも、DockerにはDockerfileというものがあって、そこで構築に必要な処理ができますが、
様々な構成変更を適用することを考えると、Ansibleでやったほうが柔軟性があると考えたのです。
#開発中はファイルや設定内容に色々な変更があり、最初からデプロイ対象をFIXして進められるわけではない。
#その度にDockerコンテナを再構築していたら時間がかかってしまう…と。

しかし、Dockerで行えることは、Dockerにやらせるべきでした。
それを、「デプロイ作業はAnsibleにやらせる」とした結果、考えることが多くなり、複雑な形になってしまいました。
この辺の話は、次のアンチパターンともつながっています。

アンチパターン2:Ansibleのスクリプト・ヘルに陥る

1つのシステムを作るのに、Tomcatで動くAPサーバ、PostgreSQL、Couchbase、Elasticsearchなど、色々なコンポーネントを組み合わせるアーキテクチャになっていたのですが、これらをAnsibleで全部やろうとした結果、スクリプトの量が増えました。

といっても、単に各ミドルをインストールするだけならそこまで大変なことにはならなかったでしょう。
ここに、以下の要素を加えた結果、面倒なことになりました。

・データ投入
・設定ファイルの配置

要するに、一回システム作った後、システムのアップデートも含めてAnsibleで対応しようとしました。

一般に、Ansibleを使うメリットを活かすには、やはり冪等性を意識して、何度実行しても同じ結果になるようにできることが1つのポイントになると思います。
しかし、定義ファイルを更新したり、動作中に変更されるデータを更新するといった処理を行おうとすると、冪等性を考慮したスクリプトを作ることが困難になります。
そのような更新のスクリプトを作ろうとした結果、設定の変更が入っていく中でスクリプトの粒度が細かくなり、スクリプト・ヘルに陥りました。


そもそも、システムを構築する際には、以下のようなレイヤを考えるべきです。

  1. ミドルウェアのインストール、設定
  2. アプリケーションのデプロイ
  3. 設定ファイルの適用

Ansibleをなんとなく導入していくと、このあたりのレイヤ分けがうまく行かなくなります。
うまく行かないまま作っていくと、大小さまざまな処理を思いつくままにスクリプト化していくことになりがちです。
それで、収拾がつかなくなってしまう、、、というアンチパターンになります。

というわけで...

ここで、以下のことを理解するべきです。

Dockerと、Ansibleの関係は、いわゆる「Docker vs Ansible」ではないと。

  1. Dockerは、アプリケーション/コンポーネントを組み立てる(ビルド/デプロイ)+コンテナ実行
  2. Ansibleは、システムを構築する(構成管理)

この2つは、似ているようで、似ていないのだと理解しました。
担当するレイヤが異なるので、お互いに補完し合うように使うべきでした。

なので、アプリケーションのデプロイを行う部分は、Dockerに任せ、コンテナ内に必要な環境を閉じ込めました。

コンテナの外

一方で、コンテナの外にあるものは、Ansibleを使うようにしています。

具体的に、以下のようなものは、Ansibleを使って構築するようにしました。

  1. ファイアウォール設定
  2. cronの設定(ログローテート、一時ファイルの削除などの維持タスク)
  3. HAクラスタリング設定

ファイアウォールやcronは、Ansibleが命令を用意してくれているので、これを使えば冪等性も維持できます。

また、PostgreSQLや、サーバ間で相互通信を必要とするCouchbaseやElasticsearchはDockerコンテナを使わずに構築しています。
最近は、Dockerでもコンテナ間通信の仕組みが登場してきていますが、当時は複数サーバに分けた場合の相互通信の仕組みがほぼ用意されていなかったので、諦めました。


これらは、また、上に書いたレイヤを意識して、

  1. ミドルウェアのインストールを行うロール
  2. 定義ファイルを適用するロール
  3. データ投入を行うロール

を分けて整理しました。

まとめ

当たり前ですが、DockerとAnsibleは、それぞれ得意・不得意とするところがあります。
そもそも、2つのツールが異なるレイヤを担当していることを理解して使用するべきだと感じました。


実運用で使い始めてから日が浅いこともあり、まだまだ、手探りで進めている部分があります。
コメントやアドバイスをいただけたら、幸いです。


では。

Acroquest Technologyでは、キャリア採用を行っています。


  • 日頃勉強している成果を、AWSHadoop、Storm、NoSQL、SpringBoot、HTML5/CSS3/JavaScriptといった最新の技術を使ったプロジェクトで発揮したい。
  • 社会貢献性の高いプロジェクトに提案からリリースまで携わりたい。
  • 書籍・雑誌等の執筆や対外的な勉強会の開催を通した技術の発信や、社内勉強会での技術情報共有により、技術的に成長したい。
  • OSSの開発に携わりたい。

 
少しでも上記に興味を持たれた方は、是非以下のページをご覧ください。
 キャリア採用ページ