Nomad/Consul/Nginxでスケールアウト出来るコンテナホスティング環境 on さくらのクラウド


概要

以下のプロダクトを組み合わせることで、Dockerコンテナ(等)のホスティング環境をつくってみました。

全体図は以下のような感じです。

Terraformで一発で構築できるようになっています。定義は以下リポジトリで公開しています。
Github:nomad-on-sakuracloud

某サービスに似てる??似てますね。
この方法なら全部自前で準備できるので、オンプレに構築することも可能ですよ。
それでは解説していきます。
なお、以下の解説では役割ごとにマシンが複数台ある構成にしていますが、最低限各役割に1台づつの構成でもOKです。

全体の流れ

前提条件

フロントエンドのIPアドレスをワイルドカードDNSとして登録しておきます。
ワイルドカードDNSを登録しておくことで、エンドポイントを動的に割り当てても名前解決ができるようになります。

ワイルドカードDNSの登録例

対象ドメイン名がnomad.example.comの場合、以下のようなワイルドカードレコード(A)を登録しておきます。

*.nomad.example.com [フロントエンドのグローバルIP]

フロントエンドが複数ある場合は複数のレコードを登録する or 仮想IPを割り当てるなどしましょう。

コンテナ起動〜サービス提供まで

1. Nomadサーバーでnomad runコマンドを実行しジョブ起動

nomadサーバーにSSH接続してnomad runを実行します。
この時、nomadのサービス定義にnomad-workerというタグをつけておくと
以降のフェーズで自動でエンドポイントが割り当てられるという仕組みにしています。

2. Nomadサーバーが適切なNomadエージェントにジョブ割り振り

Nomadがジョブ定義に応じて適切なエージェントにジョブを割り振ります。

3. ジョブを割り振られたエージェントがDockerコンテナ起動(ポートの自動割り当て)

エージェントはジョブが割り当てられると指定のDockerコンテナを起動します。
ジョブ定義(*.nomad)のポート設定に従いポートを割り当てます
なお、固定のポートを割り当てることもできますが、通常自動割り当てにしておきます。
自動割り当てにしておくことで、同じノード上で複数のコンテナを起動するということもできるようになります。

4. Nomadエージェントがポート番号などのサービス情報をConsulに登録

Nomadでのジョブ定義に従い、Consulへサービス設定が登録されます。
Consulはサービス設定に従い、指定のポートを死活監視します。
指定のDockerコンテナが起動し指定ポートへの疎通が確認できればConsulへIPアドレス/ポート番号などのサービス情報を登録してくれます。

5. Consulのサービス情報変更を受け、ConsulTemplateが起動。Consulからサービス情報を読み取ってNginx設定ファイルを作成

フロントエンドではConsulTemplateが稼働しています。
Consulのサービス情報の変化をフックして起動します。
ConsulTemplateはConsulからサービス情報を読み取り、
「nomad-worker」というタグがつけられたサービスのIPアドレス/ポートに対してリバースプロキシの設定を行います。

エンドポイントの割り当て
リバースプロキシされるエンドポイントのURLにはnomadのジョブ定義で指定したサービス名が利用されます。
サービス名をhogehoge、対象ドメインをnomad.example.comとした場合、エンドポイントはhttp://hogehoge.nomad.example.comとなります。
図のように複数のコンテナがNomadエージェントにて起動されている場合、
Nginxにてラウンドロビンされます。
なお、Nginx設定は以下のような設定がConsulTemplateにて生成されます。

upstream hogehoge {
    server [agent01のIP]:20xxx;
    server [agent02のIP]:20xxx;
    server [agent03のIP]:20xxx;
}
server {
        include /etc/nginx/proxy.conf;
        server_name hogehoge.nomad.example.com;
        location / {
                proxy_pass http://hogehoge;
        }
}

6. Nginxリロード、以後割り当てられたエンドポイントへのアクセスはNomadエージェントへリバースプロキシされる

あとはブラウザでエンドポイントにアクセスしてみるだけです。
なお、現状ではNomadエージェントもグローバルIPを持ち、ポートを公開しているため、
[エージェントのグローバルIP]:[割り当てられたポート]には直接アクセスできるようになっています。

構築方法

GitHubにTerraformの定義ファイルを置いています。
Terraform for さくらのクラウドを用いることで、さくらのクラウド上にコマンド1発でDockerホスティング環境が作れちゃいます。

構築方法の詳細は以下を参照ください。

Github:nomad-on-sakuracloud

実運用に向けて

以下のような課題があります。

  • 永続データの管理
  • セキュリティ
  • ログの管理

NomadエージェントのDockerに分散ストレージ対応のプラグインを入れたりするのもいいかと思います。
また、ログの管理については今後current.shがHashicorp製品と統合されると思いますので、今の内に使っておくのもいいかもしれません。
(nomadでsystemタスクとして登録しておけばOK)

終わりに

いかがでしょうか?
類似の構成として、Mesos + Marathonやkubernetesがありますが、
それらと比較すると各プロダクトが基本的にgoの単一バイナリ形式なため、
マシン環境を整えるのが格段に楽だと思います。

現時点ではNomadサーバーにSSHで接続してのジョブ投入ですが、
Dockerリポジトリを自前で準備し、ちょっとしたAPIラッパーを用意すれば、
herokuのようにイメージをpushしたら即サービス公開、何てこともできるかもしれないですね!

以上です。