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

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

ステータス:期限切れ

この記事は最新ではありません。 この記事の更新を書くことに興味がある場合は、DigitalOceanが技術チュートリアルを公開したいのをご覧ください。

理由: 2016年12月22日、CoreOSはフリートを維持しなくなったことを発表しました。 CoreOSは、すべてのクラスタリングのニーズにKubernetesを使用することをお勧めします。

代わりに参照してください:フリートなしでCoreOSでKubernetesを使用するガイダンスについては、CoreOSドキュメントのKubernetesを参照してください。


序章

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

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

前提条件と目標

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

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

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

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

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

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

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

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

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

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

eval $(ssh-agent)

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

ssh-add

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

ssh -A core@coreos_node_public_IP

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

Dockerコンテナの作成

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

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

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

docker login

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

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

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

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

  • run :これは、次のパラメーターを使用してコンテナーを起動することをDockerに通知します。
  • -i :Dockerコンテナをインタラクティブモードで起動します。 これにより、コンテナ環境にSTDINが接続されていなくても、確実に使用できるようになります。
  • -t :これにより疑似TTYが作成され、コンテナー環境への端末アクセスが可能になります。
  • ubuntu:14.04 :これは実行したいリポジトリとイメージの組み合わせです。 この場合、Ubuntu14.04を実行しています。 イメージは、DockerHubUbuntuDockerリポジトリ内に保持されます。
  • / bin / bash :これはコンテナーで実行するコマンドです。 ターミナルアクセスが必要なので、シェルセッションを生成する必要があります。

ベースイメージレイヤーがDockerHubオンライン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

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

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

docker commit container_ID user_name/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

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

docker push user_name/apache

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

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

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

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

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

まず、ホームディレクトリに[email protected]というファイルを作成します。 @は、これがテンプレートサービスファイルであることを示します。 それが何を意味するのかを少し説明します。 CoreOSイメージには、vimテキストエディターが付属しています。

vim [email protected]

サービス定義を開始するには、[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サーバーからプルダウンする必要があり、初回実行時に通常よりも長い起動時間が発生する可能性があります。

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

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

使用したい名前の残りのコンテナをすべて削除してから削除する必要があります。 この時点で、DockerHubからも実際にイメージをプルダウンします。 /etc/environmentファイルも入手したいと思います。 これには、サービスを実行しているホストのパブリックIPアドレスやプライベート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 user_name/apache

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

上記のディレクティブのapacheコンテナ名の最後に%iサフィックスがあることに気付いたかもしれません。 作成しているサービスファイルは、実際にはテンプレートユニットファイルです。 これは、ファイルを実行すると、フリートがいくつかの情報を適切な値に自動的に置き換えることを意味します。 詳細については、提供されているリンクの情報をお読みください。

この場合、%iは、ファイル内に存在するすべての場所で、.serviceサフィックスの前の@の右側にあるサービスファイルの名前の部分に置き換えられます。 ただし、ファイルの名前は単に[email protected]です。

[email protected]を使用してファイルをfleetctlに送信しますが、ファイルをロードするときに、apache@PORT_NUM.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 user_name/apache
ExecStart=/usr/bin/docker run --name apache%i -p ${COREOS_PUBLIC_IPV4}:%i:80 user_name/apache /usr/sbin/apache2ctl -D FOREGROUND

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

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

以前にDockerHubにアップロードした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 user_name/apache
ExecStart=/usr/bin/docker run --name apache%i -p ${COREOS_PUBLIC_IPV4}:%i:80 user_name/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を更新できる最小限のコンパニオンサービスを開始します。

新しいサービスファイルは[email protected]と呼ばれます。 今すぐ開く:

vim [email protected]

以前と同じように、[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ストアにキーを設定します。 %iは、@.serviceサフィックスの間にロードするサービス名のセクションに置き換えられます。これもApacheサービスのポート番号になります。

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

停止アクションでは、同じ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 submit [email protected] [email protected]

次のように入力すると、新しいサービスファイルが表示されるはずです。

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

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

特定のホストでのスケジュールに依存するテンプレートを使用しているため、次にファイルをロードする必要があります。 これにより、これらのファイルの新しい名前をポート番号で指定できるようになります。 これは、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サーバーが稼働しているようです。 サービスファイルでは、DockerにホストサーバーのパブリックIPアドレスにバインドするように指示しましたが、fleetctlで表示されるIPはプライベートアドレスです(cloud-configで$private_ipv4を渡したため、このサンプルクラスターの作成)。

ただし、パブリックIPアドレスとポート番号はetcdに登録しています。 値を取得するには、etcdctlユーティリティを使用して、設定した値を照会できます。 思い出してください。私たちが設定したキーは/announce/services/apachePORT_NUMでした。 したがって、サーバーの詳細を取得するには、次のように入力します。

etcdctl get /announce/services/apache80
104.131.15.192:80

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

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

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

fleetctl load [email protected] [email protected]
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サーバーが表示されます。

これで、クラスター内に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にコンテナーの管理方法を指示するフリートユニットファイルを作成しました。 etcdデータストアをWebサーバーに関する状態情報で最新の状態に保つために、サイドキックサービスを実装しました。 fleetctlを使用してサービスを管理し、さまざまなホストでサービスをスケジュールしました。

後のガイドでは、この記事で簡単に触れたいくつかの領域を引き続き調査します。