フリートユニットファイルを使用してCoreOSクラスター用の柔軟なサービスを作成する方法

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

ステータス:非推奨

理由: 2016年12月22日、CoreOSはフリートを維持しないことを発表しました。 フリートは、CoreOSから削除される2017年2月まで、セキュリティアップデートとバグ修正を受け取ります。 プロジェクトでは、すべてのクラスタリングのニーズにKubernetesを使用することを推奨しています。

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


序章

CoreOSのインストールでは、多数のツールを活用して、クラスタリングとDockerに含まれるサービスを管理しやすくします。 etcdは、個別のノードのリンクとグローバルデータ用の領域の提供に関与しますが、実際のサービス管理および管理タスクのほとんどは、fleetデーモンの操作を伴います。

以前のガイドでは、サービスとクラスターメンバーを操作するためのfleetctlコマンドの基本的な使用法について説明しました。 そのガイドでは、フリートがサービスを定義するために使用するユニットファイルについて簡単に触れましたが、これらはfleetctlを学習するための実用的なサービスを提供するために使用される簡略化された例です。

このガイドでは、fleetユニットファイルを詳しく調べて、それらを作成する方法と、本番環境でサービスをより堅牢にするためのいくつかの手法について学習します。

前提条件

このチュートリアルを完了するために、クラスタリングガイドで説明されているようにCoreOSクラスターが構成されていることを前提としています。 これにより、次のような名前の3つのサーバーが残ります。

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

このチュートリアルのほとんどはユニットファイルの作成に焦点を当てていますが、これらのマシンは、特定のディレクティブのスケジューリングへの影響を示すために後で使用されます。

また、fleetctlの使用方法に関するガイドを読んだことを前提としています。 これらのユニットファイルをクラスターで送信して使用できるように、fleetctlの実用的な知識が必要です。

これらの要件を完了したら、ガイドの残りの部分に進みます。

ユニットファイルのセクションとタイプ

fleetのサービス管理の側面は、主に各ローカルシステムのsystemd initシステムに依存しているため、systemdユニットファイルを使用してサービスを定義します。

サービスはCoreOSで構成された最も一般的なユニットタイプですが、実際には定義できる他のユニットタイプがあります。 これらは、従来のsystemdユニットファイルで使用できるもののサブセットです。 これらの各タイプは、example.serviceのように、ファイル拡張子として使用されているタイプによって識別されます。

  • service :これは最も一般的なタイプのユニットファイルです。 これは、クラスター内のマシンの1つで実行できるサービスまたはアプリケーションを定義するために使用されます。
  • socket :ソケットまたはソケットのようなファイルに関する詳細を定義します。 これらには、ネットワークソケット、IPCソケット、およびFIFOバッファが含まれます。 これらは、ファイルにトラフィックが見られたときに開始するサービスを呼び出すために使用されます。
  • device :udevデバイスツリーで使用可能なデバイスに関する情報を定義します。 Systemdは、udevルールに基づいて、カーネルデバイスの個々のホストで必要に応じてこれらを作成します。 これらは通常、マウントを試みる前にデバイスが使用可能であることを確認するための注文の問題に使用されます。
  • mount :デバイスのマウントポイントに関する情報を定義します。 これらは、参照するマウントポイントにちなんで名付けられ、スラッシュがダッシュに置き換えられています。
  • automount :自動マウントポイントを定義します。 それらはマウントユニットと同じ命名規則に従い、関連するマウントユニットを伴う必要があります。 これらは、オンデマンドおよび並列マウントを説明するために使用されます。
  • timer :別のユニットに関連付けられたタイマーを定義します。 このファイルで定義された時点に達すると、関連するユニットが開始されます。
  • path :パスベースのアクティブ化を監視できるパスを定義します。 これは、特定のパスに変更が加えられたときに別のユニットを起動するために使用できます。

これらのオプションはすべて利用可能ですが、サービスユニットが最も頻繁に使用されます。 このガイドでは、サービスユニットの構成についてのみ説明します。

ユニットファイルは、ドットと上記のサフィックスのいずれかで終わる単純なテキストファイルです。 内部では、セクションごとに編成されています。 fleetの場合、ほとんどのユニットファイルの一般的な形式は次のとおりです。

[Unit]
generic_unit_directive_1
generic_unit_directive_2

[Service]
service_specific_directive_1
service_specific_directive_2
service_specific_directive_3

[X-Fleet]
fleet_specific_directive

ユニットファイル内のセクションヘッダーとその他すべては大文字と小文字が区別されます。 [Unit]セクションは、ユニットに関する一般的な情報を定義するために使用されます。 すべてのユニットタイプに共通のオプションは、通常、ここに配置されます。

[Service]セクションは、サービスユニットに固有のディレクティブを設定するために使用されます。 上記のユニットタイプのほとんど(すべてではありません)には、ユニットタイプ固有の情報に関連するセクションがあります。 詳細については、 generic systemd unit fileのマニュアルページで、さまざまなユニットタイプへのリンクを確認してください。

[X-Fleet]セクションは、fleetで使用するユニットのスケジューリング要件を設定するために使用されます。 このセクションを使用すると、ユニットをホストでスケジュールするために、特定の条件が真である必要があります。

メインサービスの構築

このセクションでは、CoreOSでのサービスの実行に関する基本ガイドで説明されているユニットファイルのバリアントから始めます。 このファイルはapache.1.serviceと呼ばれ、次のようになります。

[Unit]
Description=Apache web server service

# Requirements
Requires=etcd.service
Requires=docker.service
Requires=apache-discovery.1.service

# Dependency ordering
After=etcd.service
After=docker.service
Before=apache-discovery.1.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
ExecStartPre=-/usr/bin/docker rm apache
ExecStartPre=/usr/bin/docker pull username/apache
ExecStart=/usr/bin/docker run --name apache -p ${COREOS_PUBLIC_IPV4}:80:80 \
username/apache /usr/sbin/apache2ctl -D FOREGROUND

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

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

[Unit]セクションから始めます。 ここでの基本的な考え方は、ユニットを記述し、依存関係情報を配置することです。 まず、一連の要件から始めます。 この例では、厳しい要件を使用しました。 fleetで追加のサービスの開始を試みても、障害が発生しても停止しないようにする場合は、代わりにWantsディレクティブを使用できます。

その後、要件の順序を明示的にリストします。 これは、必要なときに前提条件のサービスを利用できるようにするために重要です。 また、サイドキックなどを自動的に開始して、構築するサービスをアナウンスする方法でもあります。

[Service]セクションでは、サービス起動タイムアウトをオフにします。 ホストでサービスを初めて実行するときは、コンテナをDockerレジストリからプルダウンする必要があります。これは、起動タイムアウトにカウントされます。 これはデフォルトで90秒に設定されており、通常は十分な時間ですが、より複雑なコンテナーでは、さらに時間がかかる場合があります。

次に、killmodeをnoneに設定します。 これが使用されるのは、通常のキルモード(control-group)により、コンテナー削除コマンドが失敗することがあるためです(特に、Dockerの--rmオプションで試行された場合)。 これにより、次回の再起動時に問題が発生する可能性があります。

COREOS_PUBLIC_IPV4にアクセスできるように環境ファイルを取得し、作成中にプライベートネットワークが有効になっている場合は、COREOS_PRIVATE_IPV4環境変数にアクセスできるようにします。 これらは、特定のホストの情報を使用するようにDockerコンテナーを構成する場合に非常に役立ちます。

ExecStartPre行は、実行環境がクリーンであることを確認するために、前の実行から残った残骸を破棄するために使用されます。 これらの最初の2つで=-を使用して、これらのコマンドが失敗した場合にsystemdを無視して続行する必要があることを示します。 このため、Dockerは以前のコンテナーを強制終了して削除しようとしますが、コンテナーが見つからなくても心配する必要はありません。 最後の事前開始は、コンテナーの最新バージョンが実行されていることを確認するために使用されます。

実際のstartコマンドは、Dockerコンテナーを起動し、それをホストマシンのパブリックIPv4インターフェイスにバインドします。 これにより、環境ファイルの情報が使用され、インターフェイスとポートを簡単に切り替えることができます。 実行中のプロセスが終了するとコンテナが終了するため、プロセスはフォアグラウンドで実行されます。 stopコマンドは、コンテナーを正常に停止しようとします。

[X-Fleet]セクションには、fleetに別のApacheサービスをまだ実行していないマシンでサービスをスケジュールするように強制する単純な条件が含まれています。 これは、重複するサービスを別々のマシンで強制的に開始することにより、サービスを高可用性にする簡単な方法です。

メインサービスを構築するための基本的なポイント

上記の例では、かなり基本的な構成を確認しました。 ただし、一般的なサービスの構築を支援するために、これからできることはたくさんあります。

メインサービスを構築する際に留意すべきいくつかの動作:

  • 依存関係と順序付けの個別のロジック:依存関係を満たせない場合に、構築しているユニットが失敗するかどうかに応じて、Requires=またはWants=ディレクティブを使用して依存関係をレイアウトします。 要件が変更された場合に簡単に調整できるように、注文をAfter=Before=の別々の行で区切ります。 依存関係リストを順序付けから分離すると、依存関係の問題が発生した場合のデバッグに役立ちます。
  • 別のプロセスでサービス登録を処理する:サービス検出とこれが可能にする動的構成機能を利用するには、サービスをetcdに登録する必要があります。 ただし、ロジックを分離しておくために、これは別の「サイドキック」コンテナで処理する必要があります。 これにより、他のコンポーネントが必要とする外部の観点から見たサービスの状態をより正確にレポートできます。
  • サービスがタイムアウトする可能性に注意してください:開始時間を長くできるように、TimeoutStartSecディレクティブを調整することを検討してください。 これを「0」に設定すると、起動タイムアウトが無効になります。 Dockerがイメージをプルする必要がある場合があるため(初回実行時または更新が見つかった場合)、これが必要になることがよくあります。これにより、サービスの初期化にかなりの時間がかかる可能性があります。
  • サービスが正常に停止しない場合はKillModeを調整します:サービスまたはコンテナーが正常に停止していないように見える場合は、KillModeオプションに注意してください。 これを「なし」に設定すると、停止後にコンテナが削除されないという問題を解決できる場合があります。 前回の実行で同じ名前のコンテナーが残されているとDockerが失敗するため、コンテナーに名前を付ける場合は特に重要です。 詳細については、KillModeのドキュメントを確認してください
  • 起動する前に環境をクリーンアップする:上記の項目に関連して、起動するたびに以前のDockerコンテナーを必ずクリーンアップしてください。 前回のサービスの実行が期待どおりに終了したと想定しないでください。 これらのクリーンアップラインは、=-指定子を使用して、クリーンアップが不要な場合にサイレントに失敗できるようにする必要があります。 通常はdocker stopでコンテナを停止する必要がありますが、クリーンアップ中はおそらくdocker killを使用する必要があります。
  • サービスの移植性のためにホスト固有の情報を取得して使用する:サービスを特定のネットワークインターフェイスにバインドする必要がある場合は、/etc/environmentファイルを取得してCOREOS_PUBLIC_IPV4にアクセスします]および、構成されている場合はCOREOS_PRIVATE_IPV4。 サービスを実行しているマシンのホスト名を知る必要がある場合は、%Hsystemd指定子を使用してください。 可能な指定子の詳細については、systemd指定子のドキュメントをご覧ください。 [X-Fleet]セクションでは、%n%N%i、および%p指定子のみが機能します。

サイドキックアナウンスサービスの構築

メインサービスを構築する際に留意すべき点についての良いアイデアが得られたので、従来の「サイドキック」サービスの検討を開始できます。 これらのサイドキックサービスはメインサービスに関連付けられており、etcdにサービスを登録するための外部ポイントとして使用されます。

このファイルは、本体ファイルで参照されているため、apache-discovery.1.serviceと呼ばれ、次のようになります。

[Unit]
Description=Apache web server etcd registration

# Requirements
Requires=etcd.service
Requires=apache.1.service

# Dependency ordering and binding
After=etcd.service
After=apache.1.service
BindsTo=apache.1.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_PUBLIC_IPV4}:80; \
    if [ $? -eq 0 ]; then \
      etcdctl set /services/apache/${COREOS_PUBLIC_IPV4} \'{"host": "%H", "ipv4_addr": ${COREOS_PUBLIC_IPV4}, "port": 80}\' --ttl 30; \
    else \
      etcdctl rm /services/apache/${COREOS_PUBLIC_IPV4}; \
    fi; \
    sleep 20; \
  done'

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

[X-Fleet]
# Schedule on the same machine as the associated Apache service
X-ConditionMachineOf=apache.1.service

メインサービスとほぼ同じ方法でサイドキックサービスを開始します。 依存関係情報と順序付けロジックに進む前に、ユニットの目的について説明します。

ここでの最初の新しいアイテムは、BindsTo=ディレクティブです。 このディレクティブにより、このユニットは、リストされたユニットに送信された開始、停止、および再起動コマンドに従います。 基本的に、これは、両方がfleetにロードされたら、メインユニットを操作することによって、これらのユニットの両方を管理できることを意味します。 これは一方向のメカニズムであるため、サイドキックを制御しても本体には影響しません。

[Service]セクションでは、保持する変数が必要なため、/etc/environmentファイルを再度ソースします。 この場合のExecStart=ディレクティブは、基本的に短いbashスクリプトです。 公開されたインターフェイスとポートを使用して、メインサービスに接続しようとします。

接続に成功した場合は、etcdctlコマンドを使用して、etcd内の/services/apache内のホストマシンのパブリックIPアドレスにキーを設定します。 この値は、サービスに関する情報を含むJSONオブジェクトです。 キーは30秒で期限切れになるように設定されているため、このユニットが予期せずダウンした場合でも、etcdに古いサービス情報が残ることはありません。 接続に失敗した場合、サービスが利用可能かどうかを確認できないため、キーはすぐに削除されます。

このループには、20秒のスリープコマンドが含まれます。 これは、20秒ごと(30秒etcdキータイムアウトの前)に、このユニットが本体が使用可能かどうかを再チェックし、キーをリセットすることを意味します。 これにより、基本的にキーのTTLが更新され、さらに30秒間有効であると見なされます。

この場合のstopコマンドは、キーを手動で削除するだけです。 これにより、BindsTo=ディレクティブにより、本体の停止コマンドが本機にミラーリングされると、サービス登録が削除されます。

[X-Fleet]セクションでは、このユニットがメインユニットと同じサーバーで起動していることを確認する必要があります。 これにより、ユニットはリモートマシンへのサービスの可用性についてレポートできなくなりますが、BindsTo=ディレクティブが正しく機能することが重要です。

サイドキックサービスを構築するための基本的なポイント

このサイドキックを構築する際に、これらのタイプのユニットの一般的なルールとして覚えておくべきいくつかのことを見ることができます。

  • 本体の実際の可用性を確認する:本体の状態を実際に確認することが重要です。 サイドキックが初期化されたからといって、本体が使用可能であると思い込まないでください。 これは、本体の設計と機能に依存しますが、チェックが堅牢であるほど、登録状態の信頼性が高くなります。 チェックは、/healthエンドポイントのチェックから、クライアントを使用したデータベースへの接続の試行まで、ユニットにとって意味のあるものであれば何でもかまいません。
  • 登録ロジックをループして定期的に再確認します:開始時にサービスの可用性を確認することは重要ですが、定期的に再確認することも不可欠です。 これにより、予期しないサービス障害のインスタンスをキャッチできます。特に、コンテナが停止しない場合はなおさらです。 サイクル間の一時停止は、メインユニットの追加の負荷に対して迅速な検出の重要性を比較検討することにより、ニーズに応じて微調整する必要があります。
  • 障害の自動登録解除のためにetcdに登録するときにTTLフラグを使用します:サイドキックユニットの予期しない障害により、etcdの検出情報が古くなる可能性があります。 サービスの登録状態と実際の状態の競合を回避するには、キーをタイムアウトさせる必要があります。 上記のループ構造を使用すると、タイムアウト間隔の前に各キーを更新して、サイドキックの実行中にキーが実際に期限切れにならないようにすることができます。 これが正しく機能するようにするには、ループ内のスリープ間隔をタイムアウト間隔よりわずかに短く設定する必要があります。
  • 確認だけでなく、etcdに有用な情報を登録する:サイドキックの最初の反復では、ユニットの起動時にetcdに正確に登録することだけに関心がある場合があります。 しかし、これは他のサービスが利用するために多くの有用な情報を提供する機会を逃しました。 この情報は今は必要ないかもしれませんが、etcdから独自の構成の値を読み取る機能を備えた他のコンポーネントを構築すると、より便利になります。 etcdサービスはグローバルなKey-Valueストアであるため、重要な情報を提供することでこれを活用することを忘れないでください。 JSONオブジェクトに詳細を保存することは、複数の情報を渡すための良い方法です。

これらの考慮事項を念頭に置くことで、etcdが正しい情報を持っていることをインテリジェントに保証できる堅牢な登録ユニットの構築を開始できます。

フリート固有の考慮事項

fleetユニットファイルは、ほとんどの場合、従来のsystemdユニットファイルと同じですが、いくつかの追加機能と落とし穴があります。

最も明らかな違いは、[X-Fleet]と呼ばれるセクションが追加されたことです。このセクションを使用して、fleetにスケジューリングの決定方法を指示できます。 使用可能なオプションは次のとおりです。

  • X-ConditionMachineID :これを使用して、ユニットをロードする正確なマシンを指定できます。 提供される値は完全なマシンIDです。 この値は、/etc/machine-idファイルを調べることによってクラスターの個々のメンバーから取得するか、list-machines -lコマンドを発行することによってfleetctlを介して取得できます。 ID文字列全体が必要です。 これは、データディレクトリが特定のマシンに保持されているデータベースを実行している場合に必要になることがあります。 これを使用する特別な理由がない限り、ユニットの柔軟性が低下するため、使用しないようにしてください。
  • X-ConditionMachineOf :このディレクティブを使用して、指定されたユニットがロードされているのと同じマシンでこのユニットをスケジュールできます。 これは、サイドキックユニットや関連するユニットをまとめる場合に役立ちます。
  • X-Conflicts :これは、このユニットと一緒にスケジュールできないユニットファイルを指定するという点で、上記の宣言の反対です。 これは、同じサービスの複数のバージョンをそれぞれ異なるマシンで開始することにより、高可用性を簡単に構成するのに役立ちます。
  • X-ConditionMachineMetadata :これは、使用可能なマシンのメタデータに基づいてスケジューリング要件を指定するために使用されます。 fleetctl list-machines出力の「METADATA」列には、各ホストに設定されているメタデータが表示されます。 メタデータを設定するには、サーバーインスタンスを初期化するときにcloud-configファイルにメタデータを渡します。
  • Global :これは、クラスター内のすべてのマシンでスケジュールする必要があるかどうかを示すブール引数を取る特別なディレクティブです。 このディレクティブと一緒に使用できるのは、メタデータ条件付きのみです。

これらの追加のディレクティブにより、管理者は、使用可能なマシンでサービスを実行する方法を定義する際の柔軟性と能力が向上します。 これらは、fleetctl loadステージで、特定のマシンのsystemdインスタンスに渡す前に評価されます。

これにより、fleetで関連するユニットを操作するときに注意すべき次のことがわかります。 fleetctlユーティリティは、ユニットファイルの[X-Fleet]セクション以外の依存関係要件を評価しません。 これにより、fleetのコンパニオンユニットを操作するときにいくつかの興味深い問題が発生します。

つまり、fleetctlツールは、ターゲットユニットを目的の状態にするために必要な手順を実行し、指定されたコマンドに基づいて必要に応じて送信、読み込み、開始のプロセスを実行しますが、実行しません。ユニットの依存関係のためにこれ。

したがって、メインユニットとサイドキックユニットの両方を送信したが、ロードしていない場合は、fleetで、fleetctl start main.serviceと入力するとロードされ、main.serviceユニットの起動が試行されます。 ただし、sidekick.serviceユニットはまだロードされておらず、fleetctlは依存関係情報を評価して依存関係ユニットをロードおよび開始プロセスに通さないため、main.serviceユニットは失敗します。 これは、マシンのsystemdインスタンスがmain.serviceユニットを処理すると、itが依存関係を評価するときにsidekick.serviceを見つけることができないためです。 sidekick.serviceユニットがマシンにロードされたことはありません。

コンパニオンユニットを処理するときにこの状況を回避するには、サイドキックを実行状態にするBindsTo=ディレクティブに依存せずに、同時に手動でサービスを開始できます。

fleetctl start main.service sidekick.service

もう1つのオプションは、メインユニットの実行時にサイドキックユニットが少なくともロードされていることを確認することです。 ロード段階では、マシンが選択され、ユニットファイルがローカルsystemdインスタンスに送信されます。 これにより、依存関係が満たされ、BindsTo=ディレクティブが正しく実行されて2番目のユニットが起動できるようになります。

fleetctl load main.service sidekick.service
fleetctl start main.service

関連するユニットがfleetctlコマンドに正しく応答しない場合は、このことに注意してください。

インスタンスとテンプレート

fleetを使用する際の最も強力な概念の1つは、ユニットテンプレートです。

ユニットテンプレートは、「インスタンス」と呼ばれるsystemdの機能に依存しています。 これらは、テンプレートユニットファイルを処理することによって実行時に作成されるインスタンス化されたユニットです。 テンプレートファイルは、ほとんどの場合、通常のユニットファイルと非常によく似ていますが、いくつかの小さな変更が加えられています。 ただし、これらは正しく使用すると非常に強力です。

テンプレートファイルは、ファイル名の@で識別できます。 従来のサービスはこの形式を取りますが:

unit.service

テンプレートファイルは次のようになります。

[email protected]

ユニットがテンプレートからインスタンス化されると、そのインスタンス識別子は@.serviceサフィックスの間に配置されます。 この識別子は、管理者が選択した一意の文字列です。

unit@instance_id.service

基本ユニット名は、%p指定子によってユニットファイル内からアクセスできます。 同様に、指定されたインスタンス識別子には%iでアクセスできます。

テンプレートとしてのメインユニットファイル

つまり、前に見た内容でapache.1.serviceというメインユニットファイルを作成する代わりに、次のような[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 username/apache
ExecStart=/usr/bin/docker run --name apache.%i -p ${COREOS_PUBLIC_IPV4}:%i:80 \
username/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
X-Conflicts=apache@*.service

ご覧のとおり、apache-discovery.1.serviceの依存関係をapache-discovery@%i.serviceに変更しました。 これは、[email protected]というこのユニットファイルのインスタンスがある場合、[email protected]というサイドキックが必要になることを意味します。 %iはインスタンス識別子に置き換えられました。 この場合、識別子を使用して、サービスの実行方法、特にApacheサーバーが使用可能なポートに関する動的な情報を保持しています。

これを機能させるために、コンテナのポートをホスト上のポートに公開するdocker runパラメータを変更しています。 静的ユニットファイルでは、使用したパラメーターは${COREOS_PUBLIC_IPV4}:80:80で、コンテナーのポート80をパブリックIPv4インターフェイス上のホストのポート80にマップしました。 このテンプレートファイルでは、インスタンス識別子を使用して使用するポートを指定しているため、これを${COREOS_PUBLIC_IPV4}:%i:80に置き換えました。 インスタンス識別子を賢く選択することは、テンプレートファイル内の柔軟性を高めることを意味します。

Docker名自体も変更され、インスタンスIDに基づく一意のコンテナー名も使用されるようになりました。 Dockerコンテナは@シンボルを使用できないため、ユニットファイルから別の名前を選択したことに注意してください。 Dockerコンテナで動作するすべてのディレクティブを変更します。

[X-Fleet]セクションでは、以前使用していた静的な種類ではなく、これらのインスタンス化されたユニットを認識するようにスケジューリング情報も変更しました。

テンプレートとしてのサイドキックユニット

同様の手順を実行して、サイドキックユニットをテンプレートに適合させることができます。

新しいサイドキックユニットは[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_PUBLIC_IPV4}:%i; \
    if [ $? -eq 0 ]; then \
      etcdctl set /services/apache/${COREOS_PUBLIC_IPV4} \'{"host": "%H", "ipv4_addr": ${COREOS_PUBLIC_IPV4}, "port": %i}\' --ttl 30; \
    else \
      etcdctl rm /services/apache/${COREOS_PUBLIC_IPV4}; \
    fi; \
    sleep 20; \
  done'

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

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

静的バージョンではなく、インスタンス化されたバージョンのメインユニットプロセスを要求してバインドするのと同じ手順を実行しました。 これにより、インスタンス化されたサイドキックユニットが正しいインスタンス化されたメインユニットと一致します。

curlコマンドで、サービスの実際の可用性を確認するときに、静的ポート80をインスタントIDに置き換えて、正しい場所に接続できるようにします。 これは、メインユニットのDockerコマンド内でポート公開マッピングを変更したために必要です。

また、etcdに記録されている「ポート」を変更して、これと同じインスタンスIDを使用するようにします。 この変更により、etcdに設定されているJSONデータは完全に動的になります。 ホスト名、IPアドレス、およびサービスが実行されているポートを取得します。

最後に、[X-Fleet]セクションの条件を再度変更します。 このプロセスがメインユニットインスタンスと同じマシンで開始されていることを確認する必要があります。

テンプレートからのユニットのインスタンス化

テンプレートファイルからユニットを実際にインスタンス化するには、いくつかの異なるオプションがあります。

fleetsystemdはどちらもシンボリックリンクを処理できます。これにより、次のように、テンプレートファイルへの完全なインスタンスIDを持つリンクを作成するオプションが提供されます。

ln -s [email protected] [email protected]
ln -s [email protected] [email protected]

これにより、[email protected][email protected]という2つのリンクが作成されます。 これらのそれぞれには、fleetおよびsystemdがこれらのユニットを実行するために必要なすべての情報が含まれています。 ただし、必要な変更を1か所で行えるように、テンプレートに戻されています。

次に、次のようにfleetctlを使用して、これらのサービスを送信、ロード、または開始できます。

fleetctl start [email protected] [email protected]

インスタンスを定義するためのシンボリックリンクを作成したくない場合は、次のように、テンプレート自体をfleetctlに送信することもできます。

fleetctl submit [email protected] [email protected]

実行時にインスタンス識別子を割り当てるだけで、fleetctl内からこれらのテンプレートからユニットをインスタンス化できます。 たとえば、次のように入力すると、同じサービスを実行できます。

fleetctl start [email protected] [email protected]

これにより、シンボリックリンクが不要になります。 一部の管理者は、いつでもインスタンスファイルを利用できることを意味するため、リンクメカニズムを好みます。 また、ディレクトリをfleetctlに渡して、すべてを一度に開始することもできます。

たとえば、作業ディレクトリには、テンプレートファイル用にtemplatesというサブディレクトリがあり、インスタンス化されたリンクバージョン用にinstancesというサブディレクトリがある場合があります。 テンプレート化されていないユニットには、staticという名前を付けることもできます。 あなたはそのようにこれを行うことができます:

mkdir templates instances static

次に、静的ファイルをstaticに移動し、テンプレートファイルをtemplatesに移動できます。

mv apache.1.service apache-discovery.1.service static
mv [email protected] [email protected] templates

ここから、必要なインスタンスリンクを作成できます。 ポート55556666、および7777でサービスを実行してみましょう。

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]
ln -s ../templates/[email protected] [email protected]
ln -s ../templates/[email protected] [email protected]

次に、次のように入力して、すべてのインスタンスを一度に開始できます。

cd ..
fleetctl start instances/*

これは、サービスをすばやく開始するのに非常に役立ちます。

結論

この時点で、fleetのユニットファイルを作成する方法を十分に理解しているはずです。 ユニットファイル内で利用可能な動的機能のいくつかを利用することにより、サービスが均等に分散され、依存関係に近くなり、etcdに有用な情報を登録できるようになります。

後のガイドでは、etcdに登録している情報を使用するようにコンテナーを構成する方法について説明します。 これは、バックエンド内の適切なコンテナーに要求を渡すために、サービスが実際のデプロイメント環境の実用的な知識を構築するのに役立ちます。