CoreOSクラスターでサービスを作成して実行する方法

前書き

CoreOSの主な利点の1つは、単一ポイントからクラスター全体のサービスを管理できることです。 CoreOSプラットフォームは、このプロセスを簡単にする統合ツールを提供します。

このガイドでは、CoreOSクラスターでサービスを実行するための一般的なワークフローを示します。 このプロセスでは、アプリケーションをセットアップするためにCoreOSの最も興味深いユーティリティのいくつかと対話するいくつかの簡単で実用的な方法を示します。

前提条件と目標

このガイドを開始するには、少なくとも3台のマシンが構成されたCoreOSクラスターが必要です。 CoreOSクラスターのブートストラップガイドをご覧ください。

このガイドでは、3つのノードは次のようになります。

  • coreos-1

  • coreos-2

  • coreos-3

これらの3つのノードは、フリートアドレスと同様に、etcdクライアントアドレスとピアアドレスのプライベートネットワークインターフェイスを使用して構成する必要があります。 これらは、上記のガイドに示されているように、cloud-configファイルを使用して構成する必要があります。

このガイドでは、CoreOSクラスターでサービスを実行する基本的なワークフローを説明します。 デモンストレーションのために、単純なApache Webサーバーをセットアップします。 コンテナー化されたサービス環境のDockerでのセットアップについて説明し、次にsystemdスタイルのユニットファイルを作成して、サービスとその運用パラメーターを記述します。

コンパニオンユニットファイル内で、etcdに登録するようにサービスに指示します。これにより、他のサービスがその詳細を追跡できるようになります。 両方のサービスをフリートに送信し、クラスター全体のマシンでサービスを開始および管理できます。

ノードに接続してSSHエージェントを渡す

サービスの構成を開始するために最初に行う必要があるのは、SSHを使用してノードの1つに接続することです。

隣接ノードとの通信に使用する「+ fleetctl +」ツールが機能するためには、接続中にSSHエージェント情報を渡す必要があります。

SSHを介して接続する前に、SSHエージェントを開始する必要があります。 これにより、接続しているサーバーに資格情報を転送できるようになり、そのマシンから他のノードにログインできるようになります。 マシンでユーザーエージェントを起動するには、次のように入力する必要があります。

eval $(ssh-agent)

次に、次のように入力して、メモリストレージ内のエージェントの秘密鍵に秘密鍵を追加できます。

ssh-add

この時点で、SSHエージェントが実行され、SSH秘密鍵を認識しているはずです。 次のステップは、クラスター内のノードの1つに接続し、SSHエージェント情報を転送することです。 これを行うには、「+-A +」フラグを使用します。

ssh -A core@

ノードの1つに接続すると、サービスの構築を開始できます。

Dockerコンテナの作成

最初に行う必要があるのは、サービスを実行するDockerコンテナーを作成することです。 これには2つの方法があります。 Dockerコンテナーを起動して手動で構成するか、必要なイメージをビルドするために必要な手順を記述するDockerfileを作成できます。

このガイドでは、最初の方法を使用してイメージを作成します。これは、Dockerを初めて使用する人にとって簡単なためです。 Dockerイメージを構築するの方法について詳しく知りたい場合は、このリンクに従ってください。 Dockerfileから]。 私たちの目標は、Docker内のUbuntu 14.04ベースイメージにApacheをインストールすることです。

開始する前に、Docker Hubレジストリにログインするかサインアップする必要があります。 これを行うには、次を入力します。

docker login

ユーザー名、パスワード、メールアドレスを入力するよう求められます。 これが初めての場合は、指定した詳細を使用してアカウントが作成され、指定したアドレスに確認メールが送信されます。 過去にアカウントを既に作成している場合は、指定された資格情報でログインします。

イメージを作成するための最初のステップは、使用したい基本イメージでDockerコンテナーを開始することです。 必要なコマンドは次のとおりです。

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

上記で使用した引数は次のとおりです。

  • 実行:これにより、Dockerに、後続のパラメーターを使用してコンテナーを起動することが指示されます。

  • * -i *:Dockerコンテナをインタラクティブモードで起動します。 これにより、コンテナ環境へのSTDINが接続されていなくても使用可能になります。

  • * -t *:これは疑似TTYを作成し、コンテナ環境へのターミナルアクセスを許可します。

  • * ubuntu:14.04 *:これは、実行するリポジトリとイメージの組み合わせです。 この場合、Ubuntu 14.04を実行しています。 イメージはhttps://registry.hub.docker.com/_/ubuntu/[Docker HubのUbuntu Dockerリポジトリ]内に保持されます。

  • * / bin / bash *:これは、コンテナで実行するコマンドです。 ターミナルアクセスが必要なため、シェルセッションを生成する必要があります。

ベースイメージレイヤーがDocker HubオンラインDockerレジストリからプルダウンされ、bashセッションが開始されます。 結果のシェルセッションにドロップされます。

ここから、サービス環境の作成を進めることができます。 Apache Webサーバーをインストールするため、ローカルパッケージインデックスを更新し、 `+ apt +`を使用してインストールする必要があります。

apt-get update
apt-get install apache2

インストールが完了したら、デフォルトの `+ index.html +`ファイルを編集できます:

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

終了したら、通常の方法でbashセッションを終了できます。

exit

ホストマシンに戻り、先ほど残したDockerコンテナのコンテナIDを取得する必要があります。 これを行うには、Dockerに最新のプロセス情報を表示するように依頼できます。

docker ps -l
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                      PORTS               NAMES
cb58a2ea1f8f        ubuntu:14.04        "/bin/bash"         8 minutes ago       Exited (0) 55 seconds ago                       jovial_perlman

必要な列は「CONTAINER ID」です。 上記の例では、これは `+ cb58a2ea1f8f +`になります。 行ったすべての変更で同じコンテナを後で起動できるようにするには、ユーザー名のリポジトリに変更をコミットする必要があります。 画像の名前も選択する必要があります。

ここでは、ユーザー名が「+ user_name 」のふりをしますが、少し前にログインしたDocker Hubアカウント名でこれを置き換える必要があります。 イメージを「 apache」と呼びます。 イメージの変更をコミットするコマンドは次のとおりです。

docker commit  /apache

これにより、画像が保存され、コンテナの現在の状態を呼び出すことができます。 これを確認するには、次のように入力します。

docker images
REPOSITORY           TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
user_name/apache     latest              42a71fb973da        4 seconds ago       247.4 MB
ubuntu               14.04               c4ff7513909d        3 weeks ago         213 MB

次に、ノードがプルダウンしてイメージを自由に実行できるように、イメージをDocker Hubに公開する必要があります。 これを行うには、次のコマンド形式を使用します。

docker push /apache

これで、Apacheインスタンスで構成されたコンテナイメージが作成されました。

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

Dockerコンテナーが使用可能になったので、サービスファイルの作成を開始できます。

フリートは、CoreOSクラスター全体のサービススケジューリングを管理します。 各ホストのsystemd initシステムをローカルで操作して適切なアクションを完了する一方で、ユーザーに集中化されたインターフェースを提供します。

各サービスのプロパティを定義するファイルは、わずかに変更されたシステム化されたユニットファイルです。 過去にsystemdを使用したことがある場合は、構文に精通していることでしょう。

まず、ホームディレクトリに「+ apache @ .service 」というファイルを作成します。 ` @ `は、これがテンプレートサービスファイルであることを示します。 それが何を意味するかを少し見ていきます。 CoreOSイメージには、 ` vim +`テキストエディターが付属しています。

サービス定義を開始するには、 `+ [Unit] +`セクションヘッダーを作成し、このユニットに関するメタデータを設定します。 説明を含め、依存関係情報を指定します。 ユニットはetcdとDockerの両方が利用可能になった後に実行する必要があるため、その要件を定義する必要があります。

また、要件として作成する他のサービスファイルを追加する必要があります。 この2番目のサービスファイルは、サービスに関する情報でetcdを更新します。 ここで要求すると、このサービスの開始時に強制的に開始されます。 サービス名の `+%i +`については後で説明します。

[Unit]
Description=Apache web server service
After=etcd.service
After=docker.service
Requires=apache-discovery@%i.service

次に、このユニットを起動または停止するときに何を行う必要があるかをシステムに伝える必要があります。 サービスを設定しているので、 `+ [Service] +`セクションでこれを行います。

最初にしたいことは、サービスのスタートアップのタイムアウトを無効にすることです。 私たちのサービスはDockerコンテナであるため、各ホストで最初に開始されるときに、イメージをDocker Hubサーバーからプルダウンする必要があり、最初の実行で通常よりも長い起動時間が発生する可能性があります。

systemdが「停止」コマンドでDockerプロセスを強制終了できるように、「+ KillMode +」を「なし」に設定します。 これを省略した場合、systemdは、stopコマンドを呼び出したときにDockerプロセスが失敗したと判断します。

また、サービスを開始する前に環境がクリーンであることを確認する必要があります。 これは特に重要です。名前でサービスを参照するため、Dockerでは、一意の名前ごとに1つのコンテナのみを実行できます。

使用する名前の残りのコンテナをすべて削除してから削除する必要があります。 この時点で、Docker Hubから画像を実際にプルダウンします。 同様に、 `+ / etc / environment +`ファイルのソースを取得します。 これには、サービスを実行しているホストのパブリックおよびプライベートIPアドレスなどの変数が含まれます。

[Unit]
Description=Apache web server service
After=etcd.service
After=docker.service
Requires=apache-discovery@%i.service

[Service]
TimeoutStartSec=0
KillMode=none
EnvironmentFile=/etc/environment
ExecStartPre=-/usr/bin/docker kill apache%i
ExecStartPre=-/usr/bin/docker rm apache%i
ExecStartPre=/usr/bin/docker pull /apache

最初の2行の「+ ExecStartPre 」行の「 =-+」構文は、これらの準備行が失敗する可能性があり、ユニットファイルが引き続き続行されることを示しています。 これらのコマンドは、その名前のコンテナが存在する場合にのみ成功するため、コンテナが見つからない場合は失敗します。

上記のディレクティブのApacheコンテナ名の末尾に「+%i +」という接尾辞があることに気づいたかもしれません。 作成するサービスファイルは、実際にはhttps://github.com/coreos/fleet/blob/master/Documentation/unit-files-and-scheduling.md#template-unit-files [テンプレートユニットファイル]です。 つまり、ファイルを実行すると、フリートは一部の情報を適切な値に自動的に置き換えます。 詳細については、提供されたリンクの情報をお読みください。

この場合、「%i +」は、ファイル内の任意の場所で、「。service 」接尾辞の前の「 @ 」の右側のサービスファイル名の部分に置き換えられます。 ただし、ファイルの名前は単純に ` apache @ .service +`です。

`+ apache @ .service `を使用してファイルを ` fleetctl `に送信しますが、ファイルをロードするときは、 ` apache @ .service +`としてロードします。ここで、「PORT_NUM」は必要なポートですこのサーバーを起動します。 簡単に区別できるように、実行するポートに基づいてサービスにラベルを付けます。

次に、実際のDockerコンテナーを実際に開始する必要があります。

[Unit]
Description=Apache web server service
After=etcd.service
After=docker.service
Requires=apache-discovery@%i.service

[Service]
TimeoutStartSec=0
KillMode=none
EnvironmentFile=/etc/environment
ExecStartPre=-/usr/bin/docker kill apache%i
ExecStartPre=-/usr/bin/docker rm apache%i
ExecStartPre=/usr/bin/docker pull /apache
ExecStart=/usr/bin/docker run --name apache%i -p ${COREOS_PUBLIC_IPV4}:%i:80 /apache /usr/sbin/apache2ctl -D FOREGROUND

従来の `+ docker run `コマンドを呼び出して、いくつかのパラメーターを渡しました。 上記で使用したのと同じ形式で名前を渡します。 また、Dockerコンテナからホストマシンのパブリックインターフェイスにポートを公開します。 ホストマシンのポート番号は、 `%i +`変数から取得されます。これにより、実際にポートを指定できます。

`+ COREOS_PUBLIC_IPV4 +`変数(ソースとなる環境ファイルから取得)を使用して、バインドするホストインターフェイスを明示します。 これは省略できますが、プライベートインターフェイスに変更する場合(たとえば、負荷分散を行う場合)、後で簡単に変更できるように設定します。

以前にDocker HubにアップロードしたDockerコンテナーを参照します。 最後に、コンテナ環境でApacheサービスを開始するコマンドを呼び出します。 Dockerコンテナーは、与えられたコマンドが終了するとすぐにシャットダウンするため、デーモンとしてではなくフォアグラウンドでサービスを実行する必要があります。 これにより、コンテナは子プロセスを正常に生成するとすぐに終了せずに実行を継続できます。

次に、サービスを停止する必要があるときに呼び出すコマンドを指定する必要があります。 コンテナを停止するだけです。 コンテナのクリーンアップは、毎回再起動するときに行われます。

また、 `+ [X-Fleet] +`というセクションを追加します。 このセクションは、サービスをスケジュールする方法に関して艦隊に指示を与えるように特に設計されています。 ここで、他のサービスまたはマシンの状態に関連して特定の配置でサービスを実行するかどうかの制限を追加できます。

まだApache Webサーバーを実行していないホストでのみサービスを実行したいのです。これにより、可用性の高いサービスを簡単に作成できるようになるからです。 ワイルドカードを使用して、実行中のApacheサービスファイルをキャッチします。

[Unit]
Description=Apache web server service
After=etcd.service
After=docker.service
Requires=apache-discovery@%i.service

[Service]
TimeoutStartSec=0
KillMode=none
EnvironmentFile=/etc/environment
ExecStartPre=-/usr/bin/docker kill apache%i
ExecStartPre=-/usr/bin/docker rm apache%i
ExecStartPre=/usr/bin/docker pull /apache
ExecStart=/usr/bin/docker run --name apache%i -p ${COREOS_PUBLIC_IPV4}:%i:80 /apache /usr/sbin/apache2ctl -D FOREGROUND
ExecStop=/usr/bin/docker stop apache%i

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

これで、Apacheサーバーユニットファイルが完成しました。 次に、etcdにサービスを登録するためのコンパニオンサービスファイルを作成します。

Etcdでのサービス状態の登録

クラスターで開始されたサービスの現在の状態を記録するために、etcdにいくつかのエントリを書き込みます。 これは、etcdへの登録として知られています。

これを行うために、サーバーがトラフィックに使用可能になったときにetcdを更新できる最小限のコンパニオンサービスを開始します。

新しいサービスファイルは、「+ apache-discovery @ .service +」という名前になります。 今すぐ開く:

前と同じように、 `+ [Unit] `セクションから始めます。 サービスの目的を説明してから、 ` BindsTo +`というディレクティブを設定します。

`+ BindsTo +`ディレクティブは、このサービスが状態情報を探す依存関係を識別します。 リストされたサービスが停止すると、今書いているユニットも停止します。 これを使用して、Webサーバーユニットが予期せず故障した場合に、このサービスがetcdを更新してその情報を反映するようにします。 これにより、他のサービスで誤って使用される可能性のある、etcdに古い情報があるという潜在的な問題が解決されます。

[Unit]
Description=Announce Apache@%i service
BindsTo=apache@%i.service

`+ [Service] +`セクションでは、ホストのIPアドレス情報を使用して環境ファイルを再度取得します。

実際の開始コマンドでは、単純な無限bashループを実行します。 ループ内で、etcd値を変更するために使用される `+ etcdctl `コマンドを使用して、 ` / announce / services / apache%i +`のetcdストアにキーを設定します。 `%

このキーの値は、ノードのパブリックIPアドレスとポート番号に設定されます。 また、値に60秒の有効期限を設定して、サービスが何らかの理由で停止した場合にキーが削除されるようにします。 その後、45秒間スリープします。 これにより、有効期限と重複するため、TTL(time-to-live)値がタイムアウトに達する前に常に更新されます。

停止アクションの場合、同じ `+ etcdctl +`ユーティリティでキーを削除し、サービスを利用不可としてマークします。

[Unit]
Description=Announce Apache@%i service
BindsTo=apache@%i.service

[Service]
EnvironmentFile=/etc/environment
ExecStart=/bin/sh -c "while true; do etcdctl set /announce/services/apache%i ${COREOS_PUBLIC_IPV4}:%i --ttl 60; sleep 45; done"
ExecStop=/usr/bin/etcdctl rm /announce/services/apache%i

最後に行う必要があるのは、このサービスがレポート対象のWebサーバーと同じホストで開始されるようにする条件を追加することです。 これにより、ホストがダウンした場合、etcd情報が適切に変更されるようになります。

[Unit]
Description=Announce Apache@%i service
BindsTo=apache@%i.service

[Service]
EnvironmentFile=/etc/environment
ExecStart=/bin/sh -c "while true; do etcdctl set /announce/services/apache%i ${COREOS_PUBLIC_IPV4}:%i --ttl 60; sleep 45; done"
ExecStop=/usr/bin/etcdctl rm /announce/services/apache%i

[X-Fleet]
X-ConditionMachineOf=apache@%i.service

これで、Apacheサーバーの現在のヘルスステータスをetcdに記録できるサイドキックサービスができました。

ユニットファイルとフリートの操作

これで、2つのサービステンプレートができました。 これらを `+ fleetctl +`に直接送信して、クラスターがそれらを認識できるようにすることができます。

次のように入力して、新しいサービスファイルを表示できるはずです。

fleetctl list-unit-files
UNIT                HASH    DSTATE      STATE       TMACHINE
[email protected]   26a893f inactive    inactive    -
[email protected]         72bcc95 inactive    inactive    -

テンプレートは、クラスタ全体の初期化システムに存在します。

特定のホストでスケジュールされることに依存するテンプレートを使用しているため、次にファイルをロードする必要があります。 これにより、これらのファイルの新しい名前とポート番号を指定できます。 これは、 `+ fleetctl `が ` [X-Fleet] +`セクションを見て、スケジューリング要件を確認するときです。

負荷分散を行っていないため、ポート80でWebサーバーを実行するだけです。 `+ @ `と ` .service +`サフィックスの間に指定することで、各サービスをロードできます:

fleetctl load [email protected]
fleetctl load [email protected]

サービスがロードされているクラスター内のホストに関する情報を取得する必要があります。

Unit [email protected] loaded on 41f4cb9a.../10.132.248.119
Unit [email protected] loaded on 41f4cb9a.../10.132.248.119

ご覧のとおり、これらのサービスは両方とも同じマシンにロードされており、指定したとおりです。 `+ apache-discovery +`サービスファイルはApacheサービスにバインドされているため、後で開始して両方のサービスを開始できます。

fleetctl start [email protected]

ここで、クラスターで実行されているユニットを尋ねると、次のように表示されます。

fleetctl list-units
UNIT                MACHINE             ACTIVE  SUB
[email protected] 41f4cb9a.../10.132.248.119  active  running
[email protected]       41f4cb9a.../10.132.248.119  active  running

Webサーバーが稼働しているようです。 サービスファイルでは、ホストサーバーのパブリックIPアドレスにバインドするようにDockerに指示しましたが、 `+ fleetctl `で表示されるIPはプライベートアドレスです(この例を作成するときにcloud-configで ` $ private_ipv4 +`を渡したため)集まる)。

ただし、パブリックIPアドレスとポート番号をetcdに登録しました。 値を取得するには、 `+ etcdctl `ユーティリティを使用して、設定した値をクエリできます。 思い出すと、設定したキーは「 / announced / services / apache」でした。 サーバーの詳細を取得するには、次を入力します。

etcdctl get /announce/services/apache80
104.131.15.192:80

Webブラウザでこのページにアクセスすると、作成した非常にシンプルなページが表示されます。

image:https://assets.digitalocean.com/articles/coreos_basic/web_page.png [CoreOS基本Webページ]

サービスが正常にデプロイされました。 別のポートを使用して別のインスタンスをロードしてみましょう。 Webサーバーと関連するサイドキックコンテナが同じホストでスケジュールされることを期待する必要があります。 ただし、Apacheサービスファイルの制約により、このホストはポート80サービスを提供するホストとは「異なる」ことを想定する必要があります。

ポート9999で実行されているサービスをロードしましょう:

Unit [email protected] loaded on 855f79e4.../10.132.248.120
Unit [email protected] loaded on 855f79e4.../10.132.248.120

両方の新しいサービスが同じ新しいホストでスケジュールされていることがわかります。 Webサーバーを起動します。

fleetctl start [email protected]

これで、この新しいホストのパブリックIPアドレスを取得できます。

etcdctl get /announce/services/apache9999
104.131.15.193:9999

指定されたアドレスとポート番号にアクセスすると、別のWebサーバーが表示されるはずです。

image:https://assets.digitalocean.com/articles/coreos_basic/web_page.png [CoreOS基本Webページ]

クラスタ内に2つのWebサーバーを展開しました。

Webサーバーを停止すると、サイドキックコンテナーも停止するはずです。

fleetctl stop [email protected]
fleetctl list-units
UNIT                MACHINE             ACTIVE      SUB
[email protected] 41f4cb9a.../10.132.248.119  inactive    dead
[email protected]   855f79e4.../10.132.248.120  active  running
[email protected]       41f4cb9a.../10.132.248.119  inactive    dead
[email protected]     855f79e4.../10.132.248.120  active  running

etcdキーが削除されたことも確認できます。

etcdctl get /announce/services/apache80
Error:  100: Key not found (/announce/services/apache80) [26693]

これは予想どおりに機能しているようです。

結論

このガイドに従うことで、CoreOSコンポーネントを操作する一般的な方法のいくつかに精通するはずです。

実行したいサービスがインストールされた独自のDockerコンテナーを作成し、CoreOSにコンテナーの管理方法を伝えるフリートユニットファイルを作成しました。 Webサーバーに関する状態情報を使用してetcdデータストアを最新の状態に保つために、サイドキックサービスを実装しました。 サービスをfleetctlで管理し、異なるホストでサービスをスケジュールしました。

後のガイドでは、この記事で簡単に触れた分野のいくつかを引き続き検討します。

Related