ConfdとEtcdを使用してCoreOSでサービスを動的に再構成する方法

提供:Dev Guides
移動先:案内検索

序章

CoreOSを使用すると、マシンのクラスター全体でDockerコンテナーでサービスを簡単に実行できます。 これを行う手順には、通常、サービスの1つまたは複数のインスタンスを開始してから、各インスタンスをCoreOSの分散Key-Valueストアであるetcdに登録することが含まれます。

このパターンを利用することで、関連サービスはインフラストラクチャの状態に関する貴重な情報を取得し、この知識を使用して自身の動作を通知できます。 これにより、重要なetcd値が変更されるたびに、サービスが動的に構成できるようになります。

このガイドでは、confdと呼ばれるツールについて説明します。このツールは、分散されたキー値ストアの変更を監視するために特別に作成されています。 Dockerコンテナー内から実行され、構成の変更とサービスのリロードをトリガーするために使用されます。

前提条件と目標

このガイドを実行するには、CoreOSとそのコンポーネントパーツの基本を理解している必要があります。 以前のガイドでは、CoreOSクラスターをセットアップし、クラスターの管理に使用されるいくつかのツールに精通しました。

以下は、この記事を始める前に読むべきガイドです。 これらのガイドで説明されている一部のサービスの動作を変更するため、資料を理解することは重要ですが、このガイドを使用するときは、最初からやり直す必要があります。

さらに、使用する管理ツールのいくつかに慣れるために、次のガイドを参照してください。

テンプレート化されたメイン+サイドキックサービスがこのガイドで設定するフロントエンドサービスの基礎として機能するため、「柔軟なサービスを作成する方法」ガイドはこのガイドにとって特に重要です。 前述したように、上記のガイドではApacheおよびサイドキックサービスの作成について説明していますが、このガイドには、最初から簡単に開始できるようにするための構成変更がいくつかあります。 このガイドでは、これらのサービスの変更バージョンを作成します。

このチュートリアルでは、Nginxを使用した新しいアプリケーションコンテナの作成に焦点を当てます。 これは、テンプレートファイルから生成できるさまざまなApacheインスタンスへのリバースプロキシとして機能します。 Nginxコンテナはconfdで構成され、サイドキックサービスが担当するサービス登録を監視します。

このシリーズで使用していたのと同じ3台のマシンクラスターから始めます。

  • coreos-1
  • coreos-2
  • coreos-3

上記のガイドを読み終えて、3台のマシンクラスターを使用できるようになったら、続行します。

バックエンドApacheサービスの構成

まず、バックエンドのApacheサービスを設定します。 これは主に前のガイドの最後の部分を反映していますが、微妙な違いがあるため、ここでは手順全体を実行します。

開始するには、CoreOSマシンの1つにログインします。

ssh -A core@ip_address

Apacheコンテナのセットアップ

基本的なApacheコンテナを作成することから始めます。 これは実際には前回のガイドと同じであるため、Docker Hubアカウントでそのイメージを既に使用できる場合は、これを再度行う必要はありません。 このコンテナは、Ubuntu14.04コンテナイメージに基づいています。

次のように入力して、ベースイメージをプルダウンし、コンテナインスタンスを開始できます。

docker run -i -t ubuntu:14.04 /bin/bash

コンテナが起動すると、bashセッションにドロップされます。 ここから、ローカルのaptパッケージインデックスを更新し、apache2をインストールします。

apt-get update
apt-get install apache2 -y

デフォルトのページも設定します。

echo "<h1>Running from Docker on CoreOS</h1>" > /var/www/html/index.html

必要な状態になっているので、コンテナを終了できます。

exit

次のように入力して、DockerHubにログインまたはアカウントを作成します。

docker login

Docker Hubアカウントのユーザー名、パスワード、メールアドレスを入力する必要があります。

次に、残したインスタンスのコンテナIDを取得します。

docker ps -l
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                     PORTS               NAMES
1db0c9a40c0d        ubuntu:14.04        "/bin/bash"         2 minutes ago       Exited (0) 4 seconds ago                       jolly_pare

上の強調表示されたフィールドはコンテナIDです。 自分のコンピューターに表示される出力をコピーします。

次に、そのコンテナID、Docker Hubユーザー名、およびイメージの名前を使用してコミットします。 ここでは「apache」を使用します。

docker commit 1db0c9a40c0d user_name/apache

新しいイメージをDockerHubにプッシュします。

docker push user_name/apache

これで、このイメージをサービスファイルで使用できます。

Apacheサービステンプレートユニットファイルの作成

コンテナが利用できるようになったので、fleetsystemdがサービスを正しく管理できるようにテンプレートユニットファイルを作成できます。

始める前に、整理された状態を維持できるようにディレクトリ構造を設定しましょう。

cd ~
mkdir static templates instances

これで、templatesディレクトリ内にテンプレートファイルを作成できます。

vim templates/[email protected]

次の情報をファイルに貼り付けます。 柔軟なフリートユニットファイルの作成に関する以前のガイドに従うことで、使用している各オプションの詳細を取得できます。

[Unit]
Description=Apache web server service on port %i

# Requirements
Requires=etcd.service
Requires=docker.service
Requires=apache-discovery@%i.service

# Dependency ordering
After=etcd.service
After=docker.service
Before=apache-discovery@%i.service

[Service]
# Let processes take awhile to start up (for first run Docker containers)
TimeoutStartSec=0

# Change killmode from "control-group" to "none" to let Docker remove
# work correctly.
KillMode=none

# Get CoreOS environmental variables
EnvironmentFile=/etc/environment

# Pre-start and Start
## Directives with "=-" are allowed to fail without consequence
ExecStartPre=-/usr/bin/docker kill apache.%i
ExecStartPre=-/usr/bin/docker rm apache.%i
ExecStartPre=/usr/bin/docker pull user_name/apache
ExecStart=/usr/bin/docker run --name apache.%i -p ${COREOS_PRIVATE_IPV4}:%i:80 \
user_name/apache /usr/sbin/apache2ctl -D FOREGROUND

# Stop
ExecStop=/usr/bin/docker stop apache.%i

[X-Fleet]
# Don't schedule on the same machine as other Apache instances
Conflicts=apache@*.service

ここで行った変更の1つは、パブリックインターフェイスの代わりにプライベートインターフェイスを使用することです。 すべてのApacheインスタンスは、オープンWebからの接続を処理する代わりに、トラフィックから Nginxリバースプロキシに渡されるため、これは良い考えです。 DigitalOceanでプライベートインターフェイスを使用する場合、スピンアップしたサーバーでは、作成時に「プライベートネットワーク」フラグが選択されている必要があることに注意してください。

また、Dockerファイルを正しくプルダウンするために、user_nameを変更してDockerHubのユーザー名を参照することを忘れないでください。

サイドキックテンプレートユニットファイルの作成

さて、サイドキックサービスについても同じことをします。 これは、後で必要になる情報を見越して少し変更します。

エディターでテンプレートファイルを開きます。

vim templates/[email protected]

このファイルでは、次の情報を使用します。

[Unit]
Description=Apache web server on port %i etcd registration

# Requirements
Requires=etcd.service
Requires=apache@%i.service

# Dependency ordering and binding
After=etcd.service
After=apache@%i.service
BindsTo=apache@%i.service

[Service]

# Get CoreOS environmental variables
EnvironmentFile=/etc/environment

# Start
## Test whether service is accessible and then register useful information
ExecStart=/bin/bash -c '\
  while true; do \
    curl -f ${COREOS_PRIVATE_IPV4}:%i; \
    if [ $? -eq 0 ]; then \
      etcdctl set /services/apache/${COREOS_PRIVATE_IPV4} \'${COREOS_PRIVATE_IPV4}:%i\' --ttl 30; \
    else \
      etcdctl rm /services/apache/${COREOS_PRIVATE_IPV4}; \
    fi; \
    sleep 20; \
  done'

# Stop
ExecStop=/usr/bin/etcdctl rm /services/apache/${COREOS_PRIVATE_IPV4}

[X-Fleet]
# Schedule on the same machine as the associated Apache service
MachineOf=apache@%i.service

上記の構成は、前のガイドの構成とはいくつかの点で異なります。 etcdctl setコマンドで設定した値を調整しました。 JSONオブジェクトを渡す代わりに、単純なIPアドレスとポートの組み合わせを設定しています。 このようにして、この値を直接読み取って、このサービスにアクセスするために必要な接続情報を見つけることができます。

また、他のファイルで行ったように、プライベートインターフェイスを指定するように情報を調整しました。 このオプションを利用できない場合は、これを公開したままにします。

サービスをインスタンス化する

それでは、これらのサービスの2つのインスタンスを作成しましょう。

まず、シンボリックリンクを作成しましょう。 作成した~/instancesディレクトリに移動し、リンクして、それらが実行されるポートを定義します。 1つのサービスをポート7777で実行し、別のサービスをポート8888で実行します。

cd ~/instances
ln -s ../templates/[email protected] [email protected]
ln -s ../templates/[email protected] [email protected]
ln -s ../templates/[email protected] [email protected]
ln -s ../templates/[email protected] [email protected]

これで、~/instancesディレクトリをfleetに渡すことで、これらのサービスを開始できます。

fleetctl start ~/instances/*

インスタンスが起動すると(これには数分かかる場合があります)、サイドキックが作成したetcdエントリを確認できるはずです。

etcdctl ls --recursive /
/coreos.com
/coreos.com/updateengine
/coreos.com/updateengine/rebootlock
/coreos.com/updateengine/rebootlock/semaphore
/services
/services/apache
/services/apache/10.132.249.206
/services/apache/10.132.249.212

これらのエントリのいずれかの値を要求すると、IPアドレスとポート番号を取得していることがわかります。

etcdctl get /services/apache/10.132.249.206
10.132.249.206:8888

curlを使用してページを取得し、正しく機能していることを確認できます。 これは、プライベートネットワークを使用するようにサービスを構成した場合にのみ、マシン内から機能します。

curl 10.132.249.206:8888
<h1>Running from Docker on CoreOS</h1>

これで、バックエンドインフラストラクチャがセットアップされました。 次のステップは、confdに慣れて、etcd/services/apacheの場所で変更を確認し、毎回Nginxを再構成できるようにすることです。

Nginxコンテナの作成

Apacheサービスに使用したのと同じUbuntu14.04ベースからNginxコンテナを起動します。

ソフトウェアのインストール

次のように入力して、新しいコンテナを起動します。

docker run -i -t ubuntu:14.04 /bin/bash

ローカルのaptパッケージキャッシュを更新し、Nginxをインストールします。 ベースイメージにはこれが含まれておらず、GitHubから安定したconfdパッケージを一時的に取得するために、curlもインストールする必要があります。

apt-get update
apt-get install nginx curl -y

これで、ブラウザのGitHubのconfdリリースページに移動できます。 最新の安定版リリースへのリンクを見つける必要があります。 この記事の執筆時点では、それは v0.5.0 ですが、これは変更されている可能性があります。 Linuxバージョンのツールのリンクを右クリックし、「リンクアドレスのコピー」または同様のオプションを選択します。

ここで、Dockerコンテナーに戻り、コピーしたURLを使用してアプリケーションをダウンロードします。 これを/usr/local/binディレクトリに配置します。 出力ファイルとしてconfdを選択する必要があります。

cd /usr/local/bin
curl -L https://github.com/kelseyhightower/confd/releases/download/v0.5.0/confd-0.5.0<^>-linux-amd64 -o confd

次に、ファイルを実行可能にして、コンテナ内で使用できるようにします。

chmod +x confd

また、この機会を利用して、confdが期待する構成構造を作成する必要があります。 これは、/etcディレクトリ内にあります。

mkdir -p /etc/confd/{conf.d,templates}

Etcd値を読み取るためのConfd構成ファイルを作成する

アプリケーションがインストールされたので、confdの構成を開始する必要があります。 まず、構成ファイルまたはテンプレートリソースファイルを作成します。

confdの構成ファイルは、特定のetcd値をチェックし、変更が検出されたときにアクションを開始するようにサービスをセットアップするために使用されます。 これらはTOMLファイル形式を使用します。これは使いやすく、かなり直感的です。

nginx.tomlという名前のファイルを構成ディレクトリ内に作成することから始めます。

vi /etc/confd/conf.d/nginx.toml

ここで構成ファイルを作成します。 次の情報を追加します。

[template]

# The name of the template that will be used to render the application's configuration file
# Confd will look in `/etc/conf.d/templates` for these files by default
src = "nginx.tmpl"

# The location to place the rendered configuration file
dest = "/etc/nginx/sites-enabled/app.conf"

# The etcd keys or directory to watch.  This is where the information to fill in
# the template will come from.
keys = [ "/services/apache" ]

# File ownership and mode information
owner = "root"
mode = "0644"

# These are the commands that will be used to check whether the rendered config is
# valid and to reload the actual service once the new config is in place
check_cmd = "/usr/sbin/nginx -t"
reload_cmd = "/usr/sbin/service nginx reload"

上記のファイルには、いくつかの基本的なアイデアを説明するコメントが含まれていますが、以下のオプションを検討することができます。

指令 必須? タイプ 説明
src はい 情報のレンダリングに使用されるテンプレートの名前。 これが/etc/confd/templatesの外側にある場合は、パス全体を使用する必要があります。
dest はい レンダリングされた構成ファイルを配置するファイルの場所。
キー はい 文字列の配列 テンプレートを正しくレンダリングするために必要なetcdキー。 テンプレートが子キーを処理するように設定されている場合、これはディレクトリになる可能性があります。
オーナー いいえ レンダリングされた構成ファイルの所有権が付与されるユーザー名。
グループ いいえ レンダリングされた構成ファイルのグループ所有権が付与されるグループ。
モード いいえ レンダリングされたファイルに設定する必要がある8進数のアクセス許可モード。
check_cmd いいえ レンダリングされた構成ファイルの構文をチェックするために使用する必要があるコマンド。
reload_cmd いいえ アプリケーションの構成を再ロードするために使用する必要があるコマンド。
プレフィックス いいえ keysディレクティブのキーの前にあるetcd階層の一部。 これを使用して、.tomlファイルをより柔軟にすることができます。

作成したファイルは、confdインスタンスがどのように機能するかについていくつかの重要なことを示しています。 Nginxコンテナは、/etc/confd/templates/nginx.conf.tmplに保存されているテンプレートを使用して、/etc/nginx/sites-enabled/app.confに配置される構成ファイルをレンダリングします。 ファイルには0644のアクセス許可セットが与えられ、所有権はrootユーザーに与えられます。

confdアプリケーションは、/services/apacheノードで変更を探します。 変更が見られると、confdはそのノードの下の新しい情報を照会します。 次に、Nginxの新しい構成をレンダリングします。 構成ファイルの構文エラーをチェックし、ファイルが配置された後にNginxサービスをリロードします。

これで、テンプレートリソースファイルが作成されました。 Nginx構成ファイルのレンダリングに使用される実際のテンプレートファイルで作業する必要があります。

Confdテンプレートファイルを作成する

テンプレートファイルでは、confdプロジェクトのGitHubドキュメントの例を使用して開始します。

上記の構成ファイルで参照したファイルを作成します。 このファイルをtemplatesディレクトリに配置します。

vi /etc/confd/templates/nginx.tmpl

このファイルでは、基本的に、標準のNginxリバースプロキシ構成ファイルを再作成するだけです。 ただし、いくつかのGoテンプレート構文を使用して、confdetcdから取得している情報の一部を置き換えます。

まず、「アップストリーム」サーバーでブロックを構成します。 このセクションは、Nginxがリクエストを送信できるサーバーのプールを定義するために使用されます。 形式は一般的に次のようになります。

upstream pool_name {
    server server_1_IP:port_num;
    server server_2_IP:port_num;
    server server_3_IP:port_num;
}

これにより、リクエストをpool_nameに渡すことができ、Nginxはリクエストを渡すために定義されたサーバーの1つを選択します。

テンプレートファイルの背後にある考え方は、ApacheWebサーバーのIPアドレスとポート番号をetcdで解析することです。 したがって、アップストリームサーバーを静的に定義するのではなく、ファイルのレンダリング時にこの情報を動的に入力する必要があります。 これを行うには、動的コンテンツにGoテンプレートを使用します。

これを行うには、代わりにこれをブロックとして使用します。

upstream apache_pool {
{{ range getvs "/services/apache/*" }}
    server {{ . }};
{{ end }}
}

何が起こっているのか少し説明しましょう。 apache_poolと呼ばれるサーバーのアップストリームプールを定義するためのブロックを開きました。 内部では、二重角かっこを使用してGo言語コードを開始することを指定します。

これらの括弧内に、関心のある値が保持されるetcdエンドポイントを指定します。 リストを反復可能にするためにrangeを使用しています。

これを使用して、etcd/services/apacheの場所の下から取得したすべてのエントリをrangeブロックに渡します。 次に、挿入された値を示す「テンプレート:」および「」内の単一のドットを使用して、現在の反復でキーの値を取得できます。 これを範囲ループ内で使用して、サーバープールにデータを入力します。 最後に、テンプレート:Endディレクティブでループを終了します。

:ループ内のserverディレクティブの後にセミコロンを追加することを忘れないでください。 これを忘れると、構成が機能しなくなります。

サーバープールを設定したら、プロキシパスを使用して、すべての接続をそのプールに転送できます。 これは、リバースプロキシとしての標準サーバーブロックになります。 注意すべき点の1つは、access_logです。これは、瞬間的に作成するカスタム形式を使用します。

upstream apache_pool {
{{ range getvs "/services/apache/*" }}
    server {{ . }};
{{ end }}
}

server {
    listen 80 default_server;
    listen [::]:80 default_server ipv6only=on;

    access_log /var/log/nginx/access.log upstreamlog;

    location / {
        proxy_pass http://apache_pool;
        proxy_redirect off;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

これは、ポート80のすべての接続に応答し、etcdエントリを調べて生成されたapache_poolのサーバーのプールにそれらを渡します。

サービスのこの側面を扱っている間、後で競合が発生しないように、デフォルトのNginx構成ファイルを削除する必要があります。 デフォルトの設定を有効にするシンボリックリンクを削除します。

rm /etc/nginx/sites-enabled/default

テンプレートファイルで参照したログ形式を構成する良い機会でもあります。 これは、構成のhttpブロックに入れる必要があります。これは、メインの構成ファイルで使用できます。 今それを開きます:

vi /etc/nginx/nginx.conf

log_formatディレクティブを追加して、ログに記録する情報を定義します。 訪問しているクライアントと、リクエストが渡されたバックエンドサーバーをログに記録します。 これらの手順にかかる時間に関するデータをログに記録します。

. . .
http {
    ##
    # Basic Settings
    ##
    log_format upstreamlog '[$time_local] $remote_addr passed to: $upstream_addr: $request Upstream Response Time: $upstream_response_time Request time: $request_time';

    sendfile on;
    . . .

終了したら、ファイルを保存して閉じます。

Confdを実行するためのスクリプトの作成

テンプレートリソースファイルとテンプレートファイルを適切なタイミングで使用して、confdを呼び出すスクリプトファイルを作成する必要があります。

スクリプトは、サービスが正しく機能するために2つのことを実行する必要があります。

  • バックエンドインフラストラクチャの現在の状態に基づいて初期Nginx設定をセットアップするには、コンテナーの起動時に実行する必要があります。
  • 使用可能なバックエンドサーバーに基づいてNginxを再構成できるように、Apacheサーバーのetcd登録への変更を引き続き監視する必要があります。

スクリプトはMarceldeGraafのGitHubページから取得します。 これは、必要なことを正確に実行する素晴らしくシンプルなスクリプトです。 このシナリオでは、いくつかの小さな編集のみを行います。

このスクリプトをconfd実行可能ファイルと一緒に配置しましょう。 これをconfd-watchと呼びます。

vi /usr/local/bin/confd-watch

必要なインタープリターを識別するために、従来のbashヘッダーから始めます。 次に、いくつかのbashオプションを設定して、問題が発生した場合にスクリプトがすぐに失敗するようにします。 失敗または実行する最後のコマンドの値を返します。

#!/bin/bash

set -eo pipefail

次に、いくつかの変数を設定します。 bashパラメーター置換を使用することにより、デフォルト値を設定しますが、スクリプトを呼び出すときにハードコードされた値をオーバーライドできるように、ある程度の柔軟性を組み込みます。 これは基本的に、接続アドレスの各コンポーネントを個別に設定し、それらをグループ化して必要な完全なアドレスを取得するだけです。

パラメータ置換は、${var_name:-default_value}の構文で作成されます。 これには、var_nameの値が指定されていて、nullでない場合はその値を使用するという特性があり、それ以外の場合はデフォルトでdefault_valueになります。

デフォルトでは、etcdがデフォルトで期待する値になっています。 これにより、追加情報がなくてもスクリプトが正常に機能するようになりますが、スクリプトを呼び出すときに必要に応じてカスタマイズできます。

#!/bin/bash

set -eo pipefail

export ETCD_PORT=${ETCD_PORT:-4001}
export HOST_IP=${HOST_IP:-172.17.42.1}
export ETCD=$HOST_IP:$ETCD_PORT

ここで、confdを使用して、このスクリプトが呼び出されたときに使用可能なetcdから値を読み取ることにより、Nginx構成ファイルの初期バージョンをレンダリングします。 untilループを使用して、初期構成の構築を継続的に試みます。

etcdがすぐに利用できない場合、またはバックエンドサーバーの前にNginxコンテナがオンラインになった場合は、ループ構造が必要になることがあります。 これにより、最終的に有効な初期構成を生成できるようになるまで、etcdを繰り返しポーリングできます。

呼び出している実際のconfdコマンドは、一度実行されてから終了します。 これは、バックエンドサーバーに登録する機会を与えるために、次の実行まで5秒待つことができるようにするためです。 デフォルトを使用して作成した、またはパラメーターを渡して作成した完全なETCD変数に接続し、テンプレートリソースファイルを使用して、実行する動作を定義します。

#!/bin/bash

set -eo pipefail

export ETCD_PORT=${ETCD_PORT:-4001}
export HOST_IP=${HOST_IP:-172.17.42.1}
export ETCD=$HOST_IP:$ETCD_PORT

echo "[nginx] booting container. ETCD: $ETCD"

# Try to make initial configuration every 5 seconds until successful
until confd -onetime -node $ETCD -config-file /etc/confd/conf.d/nginx.toml; do
    echo "[nginx] waiting for confd to create initial nginx configuration"
    sleep 5
done

初期構成が設定されたら、スクリプトの次のタスクは、継続的なポーリングのメカニズムを導入することです。 Nginxが更新されるように、将来の変更が検出されることを確認したいと思います。

これを行うには、もう一度confdを呼び出すことができます。 今回は、継続的なポーリング間隔を設定し、プロセスをバックグラウンドに配置して、プロセスが無期限に実行されるようにします。 目標は同じであるため、同じetcd接続情報と同じテンプレートリソースファイルを渡します。

confdプロセスをバックグラウンドに置いた後、作成された構成ファイルを使用してNginxを安全に起動できます。 このスクリプトはDockerの「実行」コマンドとして呼び出されるため、この時点でコンテナーが終了しないように、フォアグラウンドで実行し続ける必要があります。 これを行うには、ログを調整するだけで、ログに記録しているすべての情報にアクセスできます。

#!/bin/bash

set -eo pipefail

export ETCD_PORT=${ETCD_PORT:-4001}
export HOST_IP=${HOST_IP:-172.17.42.1}
export ETCD=$HOST_IP:$ETCD_PORT

echo "[nginx] booting container. ETCD: $ETCD."

# Try to make initial configuration every 5 seconds until successful
until confd -onetime -node $ETCD -config-file /etc/confd/conf.d/nginx.toml; do
    echo "[nginx] waiting for confd to create initial nginx configuration."
    sleep 5
done

# Put a continual polling `confd` process into the background to watch
# for changes every 10 seconds
confd -interval 10 -node $ETCD -config-file /etc/confd/conf.d/nginx.toml &
echo "[nginx] confd is now monitoring etcd for changes..."

# Start the Nginx service using the generated config
echo "[nginx] starting nginx service..."
service nginx start

# Follow the logs to allow the script to continue running
tail -f /var/log/nginx/*.log

これが終了したら、ファイルを保存して閉じます。

最後に行う必要があるのは、スクリプトを実行可能にすることです。

chmod +x /usr/local/bin/confd-watch

今すぐコンテナを終了して、ホストシステムに戻ります。

exit

コンテナをコミットしてプッシュする

これで、コンテナをコミットしてDocker Hubにプッシュし、マシンでプルダウンできるようになります。

コンテナIDを確認します。

docker ps -l
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                          PORTS               NAMES
de4f30617499        ubuntu:14.04        "/bin/bash"         22 hours ago        Exited (0) About a minute ago                       stupefied_albattani

強調表示された文字列は、必要なコンテナIDです。 このIDと、DockerHubのユーザー名およびこのイメージに使用する名前を使用してコンテナーをコミットします。 このガイドでは、「nginx_lb」という名前を使用します。

docker commit de4f30617499 user_name/nginx_lb

必要に応じて、DockerHubアカウントにログインします。

docker login

ここで、コミットしたイメージをプッシュアップして、他のホストが必要に応じてイメージをプルダウンできるようにする必要があります。

docker push user_name/nginx_lb

Nginx静的ユニットファイルをビルドする

次のステップは、作成したコンテナを起動するユニットファイルを作成することです。 これにより、fleetを使用してプロセスを制御できるようになります。

これはテンプレートではないため、このディレクトリの先頭に作成した~/staticディレクトリに配置します。

vim static/nginx_lb.service

標準の[Unit]セクションから始めて、サービスについて説明し、依存関係と順序を定義します。

[Unit]
Description=Nginx load balancer for web server backends

# Requirements
Requires=etcd.service
Requires=docker.service

# Dependency ordering
After=etcd.service
After=docker.service

次に、ファイルの[Service]部分を定義する必要があります。 Apacheサービスファイルの場合と同様に、タイムアウトをゼロに設定し、killmodeを再びnoneに調整します。 このコンテナが実行されているホストのパブリックIPアドレスとプライベートIPアドレスにアクセスできるように、環境ファイルを再度プルします。

次に、環境をクリーンアップして、このコンテナの以前のバージョンがすべて強制終了され、削除されていることを確認します。 作成したばかりのコンテナをプルダウンして、常に最新バージョンであることを確認します。

最後に、コンテナを起動します。 これには、コンテナーを起動し、removeおよびkillコマンドで参照した名前を付け、コンテナーが実行されているホストのパブリックIPアドレスをマップポート80に渡すことが含まれます。 実行コマンドとして作成したconfd-watchスクリプトを呼び出します。

[Unit]
Description=Nginx load balancer for web server backends

# Requirements
Requires=etcd.service
Requires=docker.service

# Dependency ordering
After=etcd.service
After=docker.service

[Service]
# Let the process take awhile to start up (for first run Docker containers)
TimeoutStartSec=0

# Change killmode from "control-group" to "none" to let Docker remove
# work correctly.
KillMode=none

# Get CoreOS environmental variables
EnvironmentFile=/etc/environment

# Pre-start and Start
## Directives with "=-" are allowed to fail without consequence
ExecStartPre=-/usr/bin/docker kill nginx_lb
ExecStartPre=-/usr/bin/docker rm nginx_lb
ExecStartPre=/usr/bin/docker pull user_name/nginx_lb
ExecStart=/usr/bin/docker run --name nginx_lb -p ${COREOS_PUBLIC_IPV4}:80:80 \
user_name/nginx_lb /usr/local/bin/confd-watch

ここで、整理する必要があるのは、停止コマンドとfleetのスケジューリング方向だけです。 このコンテナは、他の負荷分散インスタンスまたはバックエンドApacheサーバーを実行していないホストでのみ開始する必要があります。 これにより、サービスが負荷を効果的に分散できるようになります。

[Unit]
Description=Nginx load balancer for web server backends

# Requirements
Requires=etcd.service
Requires=docker.service

# Dependency ordering
After=etcd.service
After=docker.service

[Service]
# Let the process take awhile to start up (for first run Docker containers)
TimeoutStartSec=0

# Change killmode from "control-group" to "none" to let Docker remove
# work correctly.
KillMode=none

# Get CoreOS environmental variables
EnvironmentFile=/etc/environment

# Pre-start and Start
## Directives with "=-" are allowed to fail without consequence
ExecStartPre=-/usr/bin/docker kill nginx_lb
ExecStartPre=-/usr/bin/docker rm nginx_lb
ExecStartPre=/usr/bin/docker pull user_name/nginx_lb
ExecStart=/usr/bin/docker run --name nginx_lb -p ${COREOS_PUBLIC_IPV4}:80:80 \
user_name/nginx_lb /usr/local/bin/confd-watch

# Stop
ExecStop=/usr/bin/docker stop nginx_lb

[X-Fleet]
Conflicts=nginx.service
Conflicts=apache@*.service

終了したら、ファイルを保存して閉じます。

Nginxロードバランサーの実行

チュートリアルの前半からすでに2つのApacheインスタンスが実行されているはずです。 次のように入力して確認できます。

fleetctl list-units
UNIT             MACHINE             ACTIVE  SUB
[email protected]   197a1662.../10.132.249.206  active  running
[email protected]   04856ec4.../10.132.249.212  active  running
[email protected]     197a1662.../10.132.249.206  active  running
[email protected]     04856ec4.../10.132.249.212  active  running

次のように入力して、etcdに正しく登録されていることを再確認することもできます。

etcdctl ls --recursive /services/apache
/services/apache/10.132.249.206
/services/apache/10.132.249.212

これで、Nginxサービスの起動を試みることができます。

fleetctl start ~/static/nginx_lb.service
Unit nginx_lb.service launched on 96ec72cf.../10.132.248.177

画像のプルダウンにかかる時間によっては、サービスの開始に1分程度かかる場合があります。 起動後、fleetctl journalコマンドでログを確認すると、confdのログ情報が表示されるはずです。 次のようになります。

fleetctl journal nginx_lb.service
-- Logs begin at Mon 2014-09-15 14:54:05 UTC, end at Tue 2014-09-16 17:13:58 UTC. --
Sep 16 17:13:48 lala1 docker[15379]: 2014-09-16T17:13:48Z d7974a70e976 confd[14]: INFO Target config /etc/nginx/sites-enabled/app.conf out of sync
Sep 16 17:13:48 lala1 docker[15379]: 2014-09-16T17:13:48Z d7974a70e976 confd[14]: INFO Target config /etc/nginx/sites-enabled/app.conf has been updated
Sep 16 17:13:48 lala1 docker[15379]: [nginx] confd is monitoring etcd for changes...
Sep 16 17:13:48 lala1 docker[15379]: [nginx] starting nginx service...
Sep 16 17:13:48 lala1 docker[15379]: 2014-09-16T17:13:48Z d7974a70e976 confd[33]: INFO Target config /etc/nginx/sites-enabled/app.conf in sync
Sep 16 17:13:48 lala1 docker[15379]: ==> /var/log/nginx/access.log <==
Sep 16 17:13:48 lala1 docker[15379]: ==> /var/log/nginx/error.log <==
Sep 16 17:13:58 lala1 docker[15379]: 2014-09-16T17:13:58Z d7974a70e976 confd[33]: INFO /etc/nginx/sites-enabled/app.conf has md5sum a8517bfe0348e9215aa694f0b4b36c9b should be 33f42e3b7cc418f504237bea36c8a03e
Sep 16 17:13:58 lala1 docker[15379]: 2014-09-16T17:13:58Z d7974a70e976 confd[33]: INFO Target config /etc/nginx/sites-enabled/app.conf out of sync
Sep 16 17:13:58 lala1 docker[15379]: 2014-09-16T17:13:58Z d7974a70e976 confd[33]: INFO Target config /etc/nginx/sites-enabled/app.conf has been updated

ご覧のとおり、confdetcdの初期構成を調べました。 その後、nginxを開始しました。 その後、etcdエントリが再評価され、新しい構成ファイルが作成された行を確認できます。 新しく生成されたファイルが、配置されているファイルのmd5sumと一致しない場合、ファイルは切り替えられ、サービスが再ロードされます。

これにより、負荷分散サービスが最終的にApacheバックエンドサーバーを追跡できるようになります。 confdが継続的に更新されているように見える場合は、ApacheインスタンスがTTLを頻繁に更新していることが原因である可能性があります。 これを回避するために、サイドキックテンプレートのスリープ値とTTL値を増やすことができます。

ロードバランサーの動作を確認するには、Nginxサービスを実行しているホストから/etc/environmentsファイルを要求できます。 これには、ホストのパブリックIPアドレスが含まれます。 この構成を改善したい場合は、Apacheインスタンスの場合と同様に、この情報をetcdに登録するサイドキックサービスを実行することを検討してください。

fleetctl ssh nginx_lb cat /etc/environment
COREOS_PRIVATE_IPV4=10.132.248.177
COREOS_PUBLIC_IPV4=104.131.16.222

ここで、ブラウザーでパブリックIPv4アドレスに移動すると、Apacheインスタンスで構成したページが表示されます。

ここで、ログをもう一度見ると、どのバックエンドサーバーが実際にリクエストを渡されたかを示す情報を確認できるはずです。

fleetctl journal nginx_lb
. . .
Sep 16 18:04:38 lala1 docker[18079]: 2014-09-16T18:04:38Z 51c74658196c confd[28]: INFO Target config /etc/nginx/sites-enabled/app.conf in sync
Sep 16 18:04:48 lala1 docker[18079]: 2014-09-16T18:04:48Z 51c74658196c confd[28]: INFO Target config /etc/nginx/sites-enabled/app.conf in sync
Sep 16 18:04:48 lala1 docker[18079]: [16/Sep/2014:18:04:48 +0000] 108.29.37.206 passed to: 10.132.249.212:8888: GET / HTTP/1.1 Upstream Response Time: 0.003 Request time: 0.003

結論

ご覧のとおり、etcdで構成の詳細を確認するようにサービスを設定することができます。 confdのようなツールは、重要なエントリの継続的なポーリングを可能にすることで、このプロセスを比較的簡単にすることができます。

このガイドの例では、etcdを使用して初期構成を生成するようにNginxサービスを構成しました。 また、バックグラウンドで設定して、継続的に変更を確認しています。 これをテンプレートに基づく動的構成の生成と組み合わせることで、バックエンドサーバーの最新の状況を一貫して把握することができました。