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

前書き

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

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

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

前提条件と目標

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

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

さらに、これから使用する管理ツールのいくつかをよりよく理解するには、次のガイドを参照してください。

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

このチュートリアルでは、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アカウントで既にそのイメージを使用できる場合は、これを再度行う必要はありません。 このコンテナは、Ubuntu 14.04コンテナイメージに基づいています。

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

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

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

apt-get update
apt-get install apache2 -y

また、デフォルトページを設定します。

echo "

Running from Docker on CoreOS

" > /var/www/html/index.html

コンテナは必要な状態にあるため、ここで終了できます。

exit

次のように入力して、Docker Hubにログインするか、アカウントを作成します。

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

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

docker push user_name/apache

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

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

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

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

cd ~
mkdir static templates instances

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

vim templates/[email protected]

次の情報をファイルに貼り付けます。 creating flexible fleet unit filesに関する前のガイドに従うことで、使用している各オプションの詳細を取得できます。

[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リバースプロキシのトラフィックthroughが渡されるため、これは良い考えです。 DigitalOceanでプライベートインターフェイスを使用する場合、スピンアップしたサーバーには、作成時に「プライベートネットワーク」フラグが選択されている必要があります。

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

Sidekickテンプレートユニットファイルの作成

ここで、相棒サービスについても同じことを行います。 これは、後で必要になる情報を見込んで少し変更します。

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

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ディレクトリに移動し、リンクして、それらが実行されるポートを定義します。 ポート7777で1つのサービスを実行し、ポート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

Running from Docker on CoreOS

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

Nginxコンテナーの作成

Apacheサービスに使用したのと同じUbuntu 14.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でconfdreleases pageに移動できます。 最新の安定版リリースへのリンクを見つける必要があります。 この記事の執筆時点では、それは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}

Confd構成ファイルを作成してEtcd値を読み取る

アプリケーションがインストールされたので、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"

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

指令 必須? Type 説明

src

Yes

ひも

情報のレンダリングに使用されるテンプレートの名前。 これが/etc/confd/templatesの外側にある場合は、パス全体を使用する必要があります。

dest

Yes

ひも

レンダリングされた構成ファイルを配置するファイルの場所。

keys

Yes

文字列の配列

テンプレートを正しくレンダリングするために必要なetcdキー。 テンプレートが子キーを処理するように設定されている場合、これはディレクトリにすることができます。

オーナー

No

ひも

レンダリングされた構成ファイルの所有権が付与されるユーザー名。

グループ

No

ひも

レンダリングされた構成ファイルのグループ所有権が付与されるグループ。

mode

No

ひも

レンダリングされたファイルに設定する必要がある8進数のパーミッションモード。

check_cmd

No

ひも

レンダリングされた構成ファイルの構文を確認するために使用する必要があるコマンド。

reload_cmd

No

ひも

アプリケーションの構成を再ロードするために使用する必要があるコマンド。

接頭辞

No

ひも

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 documentationの例を使用して開始します。

上記の構成ファイルで参照したファイルを作成します。 このファイルを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つを選択します。

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

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

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

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

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

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

Note:ループ内の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登録への変更を引き続き監視する必要があります。

スクリプトはMarcel de Graaf’s GitHub pageから取得します。 これは、必要なことをexactlyで実行する、素晴らしくシンプルなスクリプトです。 このシナリオでは、いくつかのマイナーな編集のみを行います。

このスクリプトを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です。 Docker Hubのユーザー名とこのイメージに使用する名前とともに、このIDを使用してコンテナーをコミットします。 このガイドでは、「nginx_lb」という名前を使用します。

docker commit de4f30617499 user_name/nginx_lb

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

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アドレスにアクセスできるようにします。

その後、環境をクリーンアップして、このコンテナの以前のバージョンが強制終了されて削除されるようにします。 作成したばかりのコンテナをプルダウンして、常に最新バージョンを保持するようにします。

最後に、コンテナを起動します。 これには、コンテナを起動し、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

ご覧のとおり、confdは初期構成をetcdに求めていました。 次に、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インスタンスで構成したページが表示されます。

Apache index page

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

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サービスを構成しました。 また、バックグラウンドで設定して、変更を継続的に確認します。 これに、テンプレートに基づく動的な構成生成を組み合わせることで、バックエンドサーバーの最新の状況を常に把握することができました。

Related