Red Hat Training

A Red Hat training course is available for OpenShift Container Platform

第4章 ルーターのセットアップ

4.1. ルーターの概要

4.1.1. ルーターについて

トラフィックをクラスターに送る方法は多数あります。最も一般的な方法として、 OpenShift Container Platform インストールで OpenShift Container Platform ルーターを、サービス向けの外部トラフィックの ingress ポイントとして使用できます。

OpenShift Container Platform は以下のルータープラグインを提供し、サポートしています。

  • HAProxy テンプレートルーターはデフォルトのプラグインです。これは、openshift3/ose-haproxy-router イメージを使用して、OpenShift Container Platform のコンテナーにあるテンプレートルータープラグインと共に HAProxy インスタンスを実行します。現在は、HTTP(S) トラフィックと SNI を使用した TLS 対応のトラフィックをサポートしています。ルーターのコンテナーは、プライベート IP でのみリッスンする多数のコンテナーとは異なり、ホストのネットワークインターフェースでリッスンします。ルーターは、ルートに関連付けられたサービスで識別される実際の Pod の IP に対するルート名の外部要求をプロキシー処理します。
  • F5 ルーターは、ルートを同期するためにお使いの環境で既存の F5 BIG-IP® システムに統合されます。F5 iControl REST API を使用するには、F5 BIG-IP® バージョン 11.4 以降が必要です。
注記

F5 ルータープラグインは OpenShift Container Platform 3.0.2 以降で利用できます。

4.1.2. ルーターのサービスアカウント

OpenShift Container Platform クラスターをデプロイする前に、ルーターのサービスアカウントを取得する必要があります。OpenShift Container Platform 3.1 以降では、クイックインストールまたは通常インストール (Advanced installation) の実行時に、ルーターのサービスアカウントが自動的に作成されます (以前は手動で作成する必要がありました)。このサービスアカウントには、ホストポートを指定することを許可する SCC (security context constraint) のパーミッションがあります。

4.1.2.1. ラベルにアクセスするためのパーミッション

namespace ラベルが使用されている場合 (ルーターシャードを作成している場合など)、ルーターのサービスアカウントにはcluster-reader のパーミッションが必要になります。

$ oc adm policy add-cluster-role-to-user \
    cluster-reader \
    system:serviceaccount:default:router

サービスアカウントを準備したら、デフォルト HAProxy ルーターカスタマイズ HAProxy ルーター、または F5 ルーターのインストールに進むことができます。

4.2. デフォルト HAProxy ルーターの使用

4.2.1. 概要

oc adm router コマンドには、新規インストールでのルーターのセットアップタスクを単純化する管理者 CLI が提供されます。 クイックインストールを実行している場合は、デフォルトのルーターが自動的に作成されます。oc adm router コマンドは、サービスとデプロイメント設定オブジェクトを作成します。 --service-account オプションを使用して、ルーターがマスターとの通信で使用するサービスアカウントを指定します。

ルーターサービスアカウントは事前に作成するか、oc adm router --service-account コマンドで作成することができます。

OpenShift Container Platform コンポーネント間のあらゆる形式の通信は TLS によって保護され、各種の証明書や認証方法を使用します。--default-certificate .pem フォーマットファイルは提供されるか、または oc adm router コマンドで作成されます。ルートが作成されると、ユーザーはルートの処理時にルーターが使用するルート証明書を提供できるようになります。

重要

ルーターを削除する際に、デプロイ設定やサービス、およびシークレットも削除されていることを確認します。

ルーターは特定のノードにデプロイされます。これにより、クラスター管理者と外部ネットワークマネージャーはどの IP アドレスがルーターを実行し、ルーターがどのトラフィックを処理するかについて調整しやすくなります。ノードセレクターを使用してルーターを特定のノードにデプロイします。

重要

ルーターはデフォルトでホストネットワークを使用し、ホストのすべてのインターフェースのポート 80 と 443 に直接割り当てられます。ポート 80/443 が利用できるホストにルーターを制限し、他のサービスに使用されないようにします。これはノードセレクタースケジューラー設定を使用して設定します。たとえば、これはルートなどのサービスの実行用として専用のインフラストラクチャーノードを設定することで実行できます。

重要

お使いのルーターで個別の openshift-router サービスアカウントを使用することをお勧めします。--service-account フラグを oc adm router コマンドで使用してこれを指定できます。

$ oc adm router --dry-run --service-account=router 1
1
--service-account は、openshift-routerサービスアカウントの名前です。
重要

oc adm router を使用して作成されるルーター Pod には、ルーター Pod がデプロイされるためにノードが満たさなければならないデフォルトのリソース要求が設定されます。デフォルトのリソース要求は、インフラストラクチャーコンポーネントの信頼性を向上させる取り組みとして、ルーター Pod の QoS 層をリソース要求を持たない Pod よりも高く設定するために使用されます。デフォルト値は、基本的なルーターがデプロイされるのに必要な最小限のリソースを表しており、ルーターデプロイメント設定で編集できます。また、ルーターの負荷に基づいてそれらの値を引き上げることもできます。

4.2.2. ルーターの作成

クイックインストールプロセスは、デフォルトルーターを自動的に作成します。ルーターが存在しない場合は、以下を実行してルーターを作成します。

$ oc adm router <router_name> --replicas=<number> --service-account=router

高可用性の設定が作成されない限り、--replicas は通常 1 になります。

ルーターのホスト IP アドレスを見つけるには、以下を実行します。

$ oc get po <router-pod>  --template={{.status.hostIP}}

また、ルーターシャードを使用して、ルーターを特定の namespace またはルートに絞り込むか、ルーターの作成後に環境変数を設定できます。この場合には、シャードごとにルーターを作成します。

4.2.3. その他の基本ルーターコマンド

デフォルトルーターの確認
router という名前のデフォルトのルーターサービスアカウントは、クイックおよび通常インストール (Advanced installation) 時に自動的に作成されます。このアカウントがすでに存在することを確認するには、以下を実行します。
$ oc adm router --dry-run --service-account=router
デフォルトルーターの表示
デフォルトルーターが作成されている場合でそれを確認するには、以下を実行します。
$ oc adm router --dry-run -o yaml --service-account=router
ラベル付けされたノードへのルーターのデプロイ
指定されたノードラベルに一致するノードにルーターをデプロイするには、以下を実行します。
$ oc adm router <router_name> --replicas=<number> --selector=<label> \
    --service-account=router

たとえば、router という名前のルーターを作成し、それを region=infra とラベルが付けられたノードに配置するには、以下を実行します。

$ oc adm router router --replicas=1 --selector='region=infra' \
  --service-account=router

通常インストール (Advanced installation) の実行時に、openshift_router_selector および openshift_registry_selector Ansible 設定はデフォルトで region=infra に設定されます。region=infra ラベルと一致するノードが存在する場合、デフォルトのルーターとレジストリーは自動的にデプロイされます。

ラベルの更新に関する情報については、「ノードのラベルの更新」を参照してください。

複数のインスタンスが スケジューラーポリシーに従って複数の異なるホストに作成されます。

複数の異なるルーターイメージの使用
複数の異なるルーターイメージを使用し、使用されるルーター設定を表示するには、以下を実行します。
$ oc adm router <router_name> -o <format> --images=<image> \
    --service-account=router

例を以下に示します。

$ oc adm router region-west -o yaml --images=myrepo/somerouter:mytag \
    --service-account=router

4.2.4. ルートを特定のルーターに絞り込む

ROUTE_LABELS 環境変数を使用してルートを絞り込むことで、特定のルーターによってのみ使用されるようできます。

たとえば、複数のルーターと 100 のルートがある場合、ラベルをルートに割り当てることで、それらの一部を 1 つのルーターで処理し、残りを別のルーターで処理するようにできます。

  1. ルーターの作成後に、ROUTE_LABELS 環境変数を使用してルーターにタグ付けします。

    $ oc env dc/<router=name>  ROUTE_LABELS="key=value"
  2. ラベルを必要なルートに追加します。

    oc label route <route=name> key=value
  3. ラベルがルートに割り当てられていることを確認するには、ルートの設定をチェックします。

    $ oc describe route/<route_name>
同時接続の最大数の設定
ルーターはデフォルトで最大 20000 の接続を処理できるようになっています。この上限は必要に応じて変更できます。接続が少なすぎると、ヘルスチェックが機能せず、不必要な再起動が実行されます。システムをこの接続の最大数に対応するように設定する必要があります。'sysctl fs.nr_open''sysctl fs.file-max' に示される上限は十分に大きな値である必要があります。そうでない場合には HAproxy は起動しません。

ルーターを作成したら、--max-connections= オプションで必要な上限を設定します。

$ oc adm router --max-connections=10000   ....

ルーターのデプロイメント設定で ROUTER_MAX_CONNECTIONS 環境変数を編集し、値を変更します。ルーター Pod は新しい値で再起動されます。ROUTER_MAX_CONNECTIONS が存在しない場合は、デフォルト値の 20000 が使用されます。

注記

接続にはフロントエンドおよび内部バックエンドが含まれます。これは 2 つの接続としてカウントされます。必ず ROUTER_MAX_CONNECTIONS の値を作成しようとしている接続数の 2 倍以上になるように設定してください。

4.2.5. HAProxy Strict SNI

HAProxy strict-sni は、ルーターのデプロイメント設定の ROUTER_STRICT_SNI 環境変数によって管理できます。また、これは --strict-sni コマンドラインオプションを使用してルーターを作成する時にも設定できます。

$ oc adm router --strict-sni

4.2.6. TLS 暗号化スイート

ルーターの作成時に --ciphers オプションを使用して、ルーターの暗号化スイートを設定します。

$ oc adm router --ciphers=modern   ....

値は modernintermediate、または old で、デフォルトは intermediateです。または、 ":" で区切られた暗号セットを指定することもできます。暗号は以下によって表示されるセットから取られたものである必要があります。

$ openssl ciphers

また、既存のルーターには ROUTER_CIPHERS 環境変数を使用します。

4.2.7. 高可用性ルーター

IP フェイルオーバーを使用して OpenShift Container Platform クラスターで高可用性ルーターをセットアップできます。このセットアップには複数の異なるノードの複数のレプリカが含まれるため、フェイルオーバーソフトウェアは現在のレプリカが失敗したら別のレプリカに切り替えることができます。

4.2.8. ルーターサービスポートのカスタマイズ

環境変数の ROUTER_SERVICE_HTTP_PORTROUTER_SERVICE_HTTPS_PORT を設定することで、テンプレートルーターがバインドするサービスポートをカスタマイズできます。これは、テンプレートルーターを作成し、そのデプロイメント設定を編集することで実行できます。

以下の例では、0 レプリカのルーターデプロイメントを作成し、ルーターサービス HTTP と HTTPS ポートをカスタマイズし、これを適切に (1 レプリカに) スケーリングしています。

$ oc adm router --replicas=0 --ports='10080:10080,10443:10443' 1
$ oc set env dc/router ROUTER_SERVICE_HTTP_PORT=10080  \
                   ROUTER_SERVICE_HTTPS_PORT=10443
$ oc scale dc/router --replicas=1
1
公開されるポートがコンテナーネットワークモード --host-network=false を使用するルーターに対して適切に設定されていることを確認します。
重要

テンプレートルーターサービスポートをカスタマイズする場合は、ルーター Pod が実行されるノードのファイアウォールでカスタムポートが開いているようにする必要があります (Ansible または iptables のいずれか、または firewall-cmd で使用するその他のカスタム方法を使用します)。

以下は、カスタムルーターサービスポートを開くために iptables を使用した例です。

$ iptables -A INPUT -p tcp --dport 10080 -j ACCEPT
$ iptables -A INPUT -p tcp --dport 10443 -j ACCEPT

4.2.9. 複数ルーターの使用

管理者は同じ定義を使用して複数のルーターを作成し、同じルートのセットを提供することができます。各ルーターは複数の異なるノードに置かれ、異なる IP アドレスを持ちます。ネットワーク管理者は、各ノードに必要なトラフィックを送る必要があります。

複数のルーターをグループ化して、クラスター内や複数テナントでのルーティングの負荷を別のルーターまたはシャードに分散することができます。グループの各ルーターまたはシャードは、ルーターのセレクターに基づいてルートを許可します。管理者は ROUTE_LABELS を使用してクラスター全体でシャードを作成できます。ユーザーは NAMESPACE_LABELS を使用して namespace (プロジェクト) でシャードを作成できます。

4.2.10. デプロイメント設定へのノードセレクターの追加

特定のルーターを特定のノードにデプロイするには、2 つの手順を実行する必要があります。

  1. ラベルを必要なノードに追加します。

    $ oc label node 10.254.254.28 "router=first"
  2. ノードセレクターをルーターのデプロイメント設定に追加します。

    $ oc edit dc <deploymentConfigName>

    template.spec.nodeSelector フィールドに、ラベルに対応するキーと値を追加します。

    ...
      template:
        metadata:
          creationTimestamp: null
          labels:
            router: router1
        spec:
          nodeSelector:      1
            router: "first"
    ...
    1
    router=first ラベルに対応するキーと値はそれぞれ routerfirst になります。

4.2.11. ルーターシャードの使用

ルーターのシャード化では NAMESPACE_LABELSROUTE_LABELS を使用してルーターの namespace とルートを絞り込みます。これにより、複数のルーターデプロイメントでルートのサブセットを分散させることができます。重複しないサブセットを使用することにより、ルートの設定のパーティション設定を効果的に行うことができます。または、ルートの重複するサブセットを構成するシャードを定義することもできます。

デフォルトで、ルーターはすべてのプロジェクト (namespace) からすべてのルートを選択します。シャード化によってラベルがルートまたはルーターの namespace およびラベルセレクターに追加されます。各ルーターシャードは特定のラベルのセットで選択されるルーターを構成するか、または特定のラベルセレクターで選択される namespace に属します。

注記

ルーターサービスアカウントには [cluster reader] パーミッションセットを設定し、他の namespace のラベルにアクセスできるようにする必要があります。

ルーターのシャード化および DNS

外部 DNS サーバーは要求を必要なシャードにルートするために必要となるので、管理者はプロジェクトの各ルーターに個別の DNS エントリーを作成する必要があります。ルーターは不明なルートを別のルーターに転送することはありません。

以下は例を示しています。

  • Router A はホスト 192.168.0.5 にあり、*.foo.com のルートを持つ。
  • Router B はホスト 192.168.1.9 にあり、*.example.com のルートを持つ。

各 DNS エントリーは *.foo.com を Router A をホストするノードに解決し、*.example.com を Router B をホストするノードに解決する必要があります。

  • *.foo.com A IN 192.168.0.5
  • *.example.com A IN 192.168.1.9

ルーターのシャード化の例

このセクションでは、namespace およびルートラベルを使用するルーターのシャード化について説明します。

図4.1 namespace ラベルに基づくルーターのシャード化

Router Sharding Based on Namespace Labels
  1. namespace ラベルセレクターでルーターを設定します。

    $ oc set env dc/router NAMESPACE_LABELS="router=r1"
  2. ルーターには namespace にセレクターがあるため、ルーターは一致する namespace のルートのみを処理します。このセレクターが namespace に一致させるようにするには、namespace に適宜ラベルを付けます。

    $ oc label namespace default "router=r1"
  3. ルートをデフォルトの namespace に作成すると、ルートはデフォルトのルーターで利用できるようになります。

    $ oc create -f route1.yaml
  4. 新規プロジェクト (namespace) を作成し、route2 というルートを作成します。

    $ oc new-project p1
    $ oc create -f route2.yaml

    ルートがルーターで利用できないことを確認します。

  5. namespace p1router=r1 のラベルを付けます。

    $ oc label namespace p1 "router=r1"

このラベルを追加すると、ルートはルーターで利用できるようになります。

ルーターのデプロイメント finops-router はルートセレクター NAMESPACE_LABELS="name in (finance, ops)" を使用して設定され、ルーターのデプロイメント dev-router はラベルセレクター NAMESPACE_LABELS="name=dev" を使用して設定されます。

すべてのルートが name=financename=ops、および name=dev というラベルの付けられた namespace にある場合、この設定により、2 つのルーターのデプロイメント間でルートが効果的に分散されます。

上記のシナリオでは、シャード化は重複するセットを持たないパーティション設定の特別なケースとなります。ルートは複数のルーターシャード間で分割されます。

ルート選択の基準によって、ルートの分散方法が決まります。複数のルーターデプロイメントに重複するルートのサブセットを設定することも可能です。

上記の例では finops-routerdev-router のほかに devops-router があり、これはラベルセレクター NAMESPACE_LABELS="name in (dev, ops)" を使用して設定されます。

name=dev または name=ops というラベルが付けられた namespace のルートは 2 つの異なるルーターデプロイメントによって提供されるようになりました。これは、「namespace ラベルに基づくルーターのシャード化」の手順で説明されているように、ルートの重複するサブセットを定義するケースです。

また、これによりさらに複雑なルーティングルールを作成し、優先度の高いトラフィックを専用の finops-router に転送し、優先度の低いトラフィックは devops-router に送信できます。

ルートラベルに基づくルーターのシャード化

NAMESPACE_LABELS によって、提供するプロジェクトをフィルターでき、それらのプロジェクトからすべてのルートを選択できますが、ルートはルート自体に関連する他の基準に基づいてパーティション設定する必要がある場合があります。ROUTE_LABELS セレクターを使用すると、ルート自体を細かくフィルターできます。

ルーターデプロイメント prod-router はルートセレクター ROUTE_LABELS="mydeployment=prod" を使用して設定され、ルーターデプロイメント devtest-router はラベルセレクター ROUTE_LABELS="mydeployment in (dev, test)" を使用して設定されます。

この設定は、namespace の種類を問わず、ルートのラベルに基づいて 2 つのルーターデプロイメント間のルートのパーティション設定を行います。

この例では、提供されるルートすべてがラベル "mydeployment=<tag>" でタグ付けされていることを想定しています。

4.2.11.1. ルーターシャードの作成

このセクションでは、ルーターシャードのさらに詳細な例を示します。さまざまなラベルを持つ a — z という 26 のルートがあることを想定してください。

ルートで使用可能なラベル

sla=high       geo=east     hw=modest     dept=finance
sla=medium     geo=west     hw=strong     dept=dev
sla=low                                   dept=ops

これらのラベルは、サービスレベルアグリーメント、地理的な場所、ハードウェア要件、部門などの概念を表しています。ルートは各列のラベルを最大 1 つ持つことができます。ルートによっては他のラベルを持つことことも、ラベルをまったく持たないこともあります。

名前SLAGeo (地理的な場所)HWDept (部門)その他のラベル

a

high

east

modest

finance

type=static

b

 

west

strong

 

type=dynamic

c, d, e

low

 

modest

 

type=static

g — k

medium

 

strong

dev

 

l — s

high

 

modest

ops

 

t — z

 

west

  

type=dynamic

これは oc adm routeroc set envoc scale がどのように連携してルーターシャードを作成するかを表している便利なスクリプト mkshard です。

#!/bin/bash
# Usage: mkshard ID SELECTION-EXPRESSION
id=$1
sel="$2"
router=router-shard-$id           1
oc adm router $router --replicas=0  2
dc=dc/router-shard-$id            3
oc set env   $dc ROUTE_LABELS="$sel"  4
oc scale $dc --replicas=3         5
1
作成されたルーターは router-shard-<id> という名前を持ちます。
2
ここではスケーリングを指定しません。
3
ルーターのデプロイメント設定。
4
oc set env を使用して選択式を設定します。選択式は環境変数 ROUTE_LABELS の値です。
5
拡張します。

mkshard を複数回実行して、複数のルーターを作成します。

ルーター選択式ルート

router-shard-1

sla=high

a, l — s

router-shard-2

geo=west

b, t — z

router-shard-3

dept=dev

g — k

4.2.11.2. ルーターシャードの変更

ルーターシャードはラベルに基づいた構成なので、(oc label を使用して) ラベルまたは (oc set env を使用して) 選択式のいずれかを変更できます。

このセクションでは「ルーターシャードの作成」セクションで扱った例をさらに詳細に取り上げ、選択式の変更方法を示します。

これは、新規の選択式を使用できるよう既存のルーターを変更する便利なスクリプト modshard です。

#!/bin/bash
# Usage: modshard ID SELECTION-EXPRESSION...
id=$1
shift
router=router-shard-$id       1
dc=dc/$router                 2
oc scale $dc --replicas=0     3
oc set env   $dc "$@"             4
oc scale $dc --replicas=3     5
1
変更後のルーターの名前は router-shard-<id> になります。
2
変更が発生するデプロイメント設定。
3
縮小します。
4
oc set env を使用して新しい選択式を設定します。「ルーターシャードの作成」セクションの mkshard とは異なり、modshardID 以外の引数として指定される選択式には環境変数名とその値が含まれている必要があります。
5
拡大して元に戻します。
注記

modshard では、router-shard-<id>デプロイメントストラテジーRolling の場合、oc scale コマンドは不要です。

たとえば router-shard-3 の部門を拡張して opsdev を含めるには、以下を実行します。

$ modshard 3 ROUTE_LABELS='dept in (dev, ops)'

結果として、router-shard-3 はルート g — s (g — kl — s の組み合わせ) を選択します。

この例ではシャードから除外する 1 つの部門を指定します。このシナリオ例では 3 つの部門しかないため、これによって前述の例と同じ結果が得られます。

$ modshard 3 ROUTE_LABELS='dept != finance'

この例は 3 つのカンマで区切られた属性を指定しており、結果としてルート b のみが選択されます。

$ modshard 3 ROUTE_LABELS='hw=strong,type=dynamic,geo=west'

ルートのラベルを使用する ROUTE_LABELS と同様に、NAMESPACE_LABELS 環境変数を使用して、ルートはルートの namespace ラベルのラベルに基づいて選択できます。この例では、ラベル frequency=weekly を持つルートの namespace を提供するように router-shard-3 を変更します。

$ modshard 3 NAMESPACE_LABELS='frequency=weekly'

最後の例は ROUTE_LABELSNAMESPACE_LABELS を組み合わせて、ラベルsla=low を持ち、ラベル frequency=weekly を持つ namespace のルート選択します。

$ modshard 3 \
    NAMESPACE_LABELS='frequency=weekly' \
    ROUTE_LABELS='sla=low'

4.2.12. ルーターのホスト名の検索

サービスを公開する際に、ユーザーは外部ユーザーがアプリケーションにアクセスするために使用する DNS 名からの同じルートを使用できます。外部ネットワークのネットワーク管理者は、ホスト名がルートを許可したルーター名に解決することを確認する必要があります。ユーザーはこのホスト名を指す CNAME を使用して DNS をセットアップできます。ただし、ユーザーはルーターのホスト名を知らない場合があり、その場合はクラスター管理者がホスト名を知らせることができます。

クラスター管理者は、--router-canonical-hostname オプションをルーター作成時のルーターの正規ホスト名で使用できます。以下は例になります。

# oc adm router myrouter --router-canonical-hostname="rtr.example.com"

これは、ルーターのホスト名を含む ROUTER_CANONICAL_HOSTNAME 環境変数をルーターのデプロイメント設定に作成します。

すでに存在しているルーターの場合、クラスター管理者はルーターのデプロイメント設定を編集し、ROUTER_CANONICAL_HOSTNAME 環境変数を追加します。

spec:
  template:
    spec:
      containers:
        - env:
          - name: ROUTER_CANONICAL_HOSTNAME
            value: rtr.example.com

ROUTER_CANONICAL_HOSTNAME 値は、ルートを許可したすべてのルーターのルートステータスに表示されます。ルートステータスはルーターがリロードされるたびに更新されます。

ユーザーがルートを作成すると、すべてのアクティブなルーターはそのルートを評価し、条件を満たしていればそのルートを許可します。ROUTER_CANONICAL_HOSTNAME 環境変数を定義するルーターがルートを許可すると、ルーターはルートステータスの routerCanonicalHostname フィールドに値を入力します。ユーザーはルートステータスを検証して、どのルーターがルートを許可したかを確認でき、ルーターを一覧から選択し、ネットワーク管理者に渡すルーターのホスト名を見つけることができます (該当する場合)。

status:
  ingress:
    conditions:
      lastTransitionTime: 2016-12-07T15:20:57Z
      status: "True"
      type: Admitted
      host: hello.in.mycloud.com
      routerCanonicalHostname: rtr.example.com
      routerName: myrouter
      wildcardPolicy: None

oc describe にはホスト名が含まれます (利用可能な場合)。

$ oc describe route/hello-route3
...
Requested Host: hello.in.mycloud.com exposed on router myroute (host rtr.example.com) 12 minutes ago

上記の情報を使用して、ユーザーは DNS 管理者に対し、ルートのホスト hello.in.mycloud.com から CNAME をルーターの正規ホスト名 rtr.example.com に応じてセットアップするよう依頼できます。この結果として、hello.in.mycloud.com へのトラフィックがユーザーのアプリケーションに到達するようになります。

4.2.13. デフォルトのルーティングサブドメインのカスタマイズ

マスター設定ファイル (デフォルトでは /etc/origin/master/master-config.yaml ファイル) を変更することで、お使いの環境のデフォルトルーティングサブドメインとして使用されるサフィックスをカスタマイズできます。ホスト名を指定しないルートの場合、このデフォルトのルーティングサブドメインを使用してホスト名が生成されます。

以下の例は、設定されたサフィックスを v3.openshift.test に設定する方法を示しています。

routingConfig:
  subdomain: v3.openshift.test
注記

この変更には、マスターを実行している場合は再起動が必要となります。

OpenShift Container Platform マスターが上記の設定を実行している場合、 namespace の mynamespace に追加されるホスト名を持たない no-route-hostname というルートの例では、生成されるホスト名は以下のようになります。

no-route-hostname-mynamespace.v3.openshift.test

4.2.14. カスタムルーティングサブドメインへのルートホスト名の強制

管理者がすべてのルートを特定のルーティングサブドメインに限定する場合、--force-subdomain オプションを oc adm router コマンドに渡すことができます。これはルートで指定されたホスト名を上書きし、--force-subdomain オプションに提供されるテンプレートに基づいてホスト名を生成するようルーターに強制します。

以下の例ではルーターを実行し、カスタムサブドメインテンプレート ${name}-${namespace}.apps.example.com を使用してルートホスト名を上書きしています。

$ oc adm router --force-subdomain='${name}-${namespace}.apps.example.com'

4.2.15. ワイルドカード証明書の使用

証明書を含まない TLS 対応のルートはルーターのデフォルト証明書を代わりに使用します。ほとんどの場合、この証明書は信頼された認証局から提供されますが、利便性を考慮して OpenShift Container Platform CA を使用して証明書を作成することができます。以下は例になります。

$ CA=/etc/origin/master
$ oc adm ca create-server-cert --signer-cert=$CA/ca.crt \
      --signer-key=$CA/ca.key --signer-serial=$CA/ca.serial.txt \
      --hostnames='*.cloudapps.example.com' \
      --cert=cloudapps.crt --key=cloudapps.key
注記

oc adm ca create-server-cert コマンドは、2 年間有効な証明書を生成します。この期間は --expire-days オプションを使って変更することができますが、セキュリティー上の理由から、値をこれより大きくすることは推奨されません。

Ansible ホストインベントリーファイル (デフォルトで /etc/ansible/hosts) に最初に一覧表示されているマスターから oc adm コマンドを実行します。

ルーターは、証明書とキーが単一ファイルに PEM 形式で入力されていると予想します。

$ cat cloudapps.crt cloudapps.key $CA/ca.crt > cloudapps.router.pem

ここで --default-cert フラグを使用できます。

$ oc adm router --default-cert=cloudapps.router.pem --service-account=router
注記

ブラウザーは、ワイルドカードを 1 つ深いレベルのサブドメインに有効であると見なします。この例では、証明書は a.cloudapps.example.com に対して有効ですが、a.b.cloudapps.example.com には有効ではありません。

4.2.16. 証明書を手動で再デプロイする

ルーター証明書を手動で再デプロイするには、以下を実行します。

  1. デフォルトのルーター証明書を含むシークレットがルーターに追加されているかどうかを確認します。

    $ oc volumes dc/router
    
    deploymentconfigs/router
      secret/router-certs as server-certificate
        mounted at /etc/pki/tls/private

    証明書が追加されている場合は、以下の手順を省略してシークレットを上書きします。

  2. デフォルト証明書ディレクトリーが以下の変数 DEFAULT_CERTIFICATE_DIR に設定されていることを確認します。

    $ oc env dc/router --list
    
    DEFAULT_CERTIFICATE_DIR=/etc/pki/tls/private

    設定されていない場合は、以下のコマンドを使用してディレクトリーを作成します。

    $ oc env dc/router DEFAULT_CERTIFICATE_DIR=/etc/pki/tls/private
  3. 証明書を PEM 形式にエクスポートします。

    $ cat custom-router.key custom-router.crt custom-ca.crt > custom-router.crt
  4. ルーター証明書シークレットを上書きするか、またはこれを作成します。

    証明書シークレットがルーターに追加されている場合は、シークレットを上書きします。追加されていなければ、新規シークレットを作成します。

    シークレットを上書きするには、以下のコマンドを実行します。

    $ oc create secret generic router-certs --from-file=tls.crt=custom-router.crt --from-file=tls.key=custom-router.key --type=kubernetes.io/tls -o json --dry-run | oc replace -f -

    新規シークレットを作成するには、以下のコマンドを実行します。

    $ oc create secret generic router-certs --from-file=tls.crt=custom-router.crt --from-file=tls.key=custom-router.key --type=kubernetes.io/tls
    
    $ oc volume dc/router --add --mount-path=/etc/pki/tls/private --secret-name='router-certs' --name router-certs
  5. ルーターをデプロイします。

    $ oc rollout latest dc/router

4.2.17. セキュリティー保護されたルートの使用

現時点で、パスワードで保護されたキーファイルはサポートされていません。HAProxy は開始時にパスワードのプロンプトを出しますが、このプロセスを自動化する方法は提供しません。キーファイルからパスフレーズを削除するために、以下を実行できます。

# openssl rsa -in <passwordProtectedKey.key> -out <new.key>

以下の例は、トラフィックが宛先にプロキシー処理される前に TLS 終端がルーターで生じる場合にセキュアな edge termination ルートを使用する方法を示しています。セキュアな edge termination ルートは TLS 証明書とキー情報を指定します。TLS 証明書は、ルーターのフロントエンドで提供されます。

最初にルーターインスタンスを起動します。

# oc adm router --replicas=1 --service-account=router

次に、セキュアな edge ルートのプライベートキー、CSR、証明書を作成します。この手順はお使いの認証局やプロバイダーによって異なります。www.example.test というドメインの単純な自己署名証明書の場合は、以下の例を参照してください。

# sudo openssl genrsa -out example-test.key 2048
#
# sudo openssl req -new -key example-test.key -out example-test.csr  \
  -subj "/C=US/ST=CA/L=Mountain View/O=OS3/OU=Eng/CN=www.example.test"
#
# sudo openssl x509 -req -days 366 -in example-test.csr  \
      -signkey example-test.key -out example-test.crt

上記の証明書とキーを使用してルートを生成します。

$ oc create route edge --service=my-service \
    --hostname=www.example.test \
    --key=example-test.key --cert=example-test.crt
route "my-service" created

その定義を確認します。

$ oc get route/my-service -o yaml
apiVersion: v1
kind: Route
metadata:
  name:  my-service
spec:
  host: www.example.test
  to:
    kind: Service
    name: my-service
  tls:
    termination: edge
    key: |
      -----BEGIN PRIVATE KEY-----
      [...]
      -----END PRIVATE KEY-----
    certificate: |
      -----BEGIN CERTIFICATE-----
      [...]
      -----END CERTIFICATE-----

www.example.test の DNS エントリーがルーターインスタンスを指し、ドメインへのルートが利用できることを確認します。以下の例では、Curl をローカルリゾルバーと共に使用して DNS ルックアップのシミュレーションを行っています。

# routerip="4.1.1.1"  #  replace with IP address of one of your router instances.
# curl -k --resolve www.example.test:443:$routerip https://www.example.test/

4.2.18. (サブドメインの) ワイルドカードルートの使用

HAProxy ルーターはワイルドカードルートをサポートしており、ROUTER_ALLOW_WILDCARD_ROUTES 環境変数を true に設定することでこれを有効にできます。ルーター許可のチェックをパスする Subdomain のワイルドカードポリシーを持つすべてのルートは HAProxy ルーターによって提供されます。次に、HAProxy ルーターはルートのワイルドカードポリシーに基づいて (ルートの) 関連サービスを公開します。

重要

ルートのワイルドカードポリシーを変更するには、ルートを削除してから更新されたワイルドカードポリシーでこれを再作成する必要があります。ルートの .yaml ファイルでルートのワイルドカードポリシーのみを編集しても機能しません。

$ oc adm router --replicas=0 ...
$ oc set env dc/router ROUTER_ALLOW_WILDCARD_ROUTES=true
$ oc scale dc/router --replicas=1

Web コンソールでワイルドカードルートを設定する方法についてはこちらを参照してください。

セキュアなワイルドカード edge termination ルートの使用

以下の例では、トラフィックが宛先にプロキシー処理される前にルーターで生じる TLS 終端を反映しています。サブドメイン example.org (*.example.org) のホストに送られるトラフィックは公開されるサービスにプロキシーされます。

セキュアな edge termination ルートは TLS 証明書とキー情報を指定します。TLS 証明書は、サブドメイン (*.example.org) に一致するすべてのホストのルーターのフロントエンドによって提供されます。

  1. ルーターインスタンスを起動します。

    $ oc adm router --replicas=0 --service-account=router
    $ oc set env dc/router ROUTER_ALLOW_WILDCARD_ROUTES=true
    $ oc scale dc/router --replicas=1
  2. セキュリティー保護された edge ルートについてのプライベートキー、証明書署名要求 (CSR) および証明書を作成します。

    この手順はお使いの認証局やプロバイダーによって異なります。*.example.test というドメインの単純な自己署名証明書の場合はこの例を参照してください。

    # sudo openssl genrsa -out example-test.key 2048
    #
    # sudo openssl req -new -key example-test.key -out example-test.csr  \
      -subj "/C=US/ST=CA/L=Mountain View/O=OS3/OU=Eng/CN=*.example.test"
    #
    # sudo openssl x509 -req -days 366 -in example-test.csr  \
          -signkey example-test.key -out example-test.crt
  3. 上記の証明書とキーを使用してワイルドカードのルートを生成します。

    $ cat > route.yaml  <<REOF
    apiVersion: v1
    kind: Route
    metadata:
      name:  my-service
    spec:
      host: www.example.test
      wildcardPolicy: Subdomain
      to:
        kind: Service
        name: my-service
      tls:
        termination: edge
        key: "$(perl -pe 's/\n/\\n/' example-test.key)"
        certificate: "$(perl -pe 's/\n/\\n/' example-test.cert)"
    REOF
    $ oc create -f route.yaml

    *.example.test の DNS エントリーがお使いのルーターインスタンスを指し、ドメインへのルートが利用できることを確認します。

    この例では curl をローカルリゾルバーと共に使用し、DNS ルックアップのシミュレーションを行います。

    # routerip="4.1.1.1"  #  replace with IP address of one of your router instances.
    # curl -k --resolve www.example.test:443:$routerip https://www.example.test/
    # curl -k --resolve abc.example.test:443:$routerip https://abc.example.test/
    # curl -k --resolve anyname.example.test:443:$routerip https://anyname.example.test/

ワイルドカードルートを許可しているルーター (ROUTER_ALLOW_WILDCARD_ROUTEStrue に設定する) の場合、ワイルドカードルートに関連付けられたサブドメインの所有権についてのいくつかの注意点があります。

ワイルドカードルートの設定前に、所有権は、最も古いルートを持つ namespace のホスト名についての要求に基づいて設定されました (これはその他の要求を行うルートよりも優先されました)。たとえば、ルート r1 がルート r2 より古い場合、one.example.test の要求を持つ namespace ns1 のルート r1 は同じホスト名 one.example.test について namespace ns2 のルート ns2 よりも優先されます。

さらに、他の namespace のルートは重複しないホスト名を要求することを許可されていました。たとえば、namespace ns1 のルート ronewww.example.test を要求でき、namespace d2 の別のルート rtwoc3po.example.test を要求できました。

これは、同じサブドメイン (上記の例では example.test) を要求するワイルドカードルートがない場合には同様になります。

ただし、ワイルドカードルートはサブドメイン内のホスト名 ( \*.example.test 形式のホスト名) をすべて要求する必要があります。ワイルドカードルートの要求は、そのサブドメイン (example.test) の最も古いルートがワイルドカードルートと同じ namespace 内にあるかどうかによって許可または拒否されます。最も古いルートは通常のルートまたはワイルドカードルートのいずれかになります。

たとえば、ホスト owner.example.test を要求する 最も古い ルートが namespace ns1 にすでに存在し、後からそのサブドメイン (example.test) のルートを要求する新規のワイルドカードルート wildthing が追加される場合、そのワイルドカードルートによる要求は、そのルートが所有ルートと同じ namespace (ns1) にある場合にのみ許可されます。

以下の例では、ワイルドカードルートの要求が成功する場合と失敗する場合のさまざまなシナリオを示しています。

以下の例では、ワイルドカードルートを許可するルーターは、ワイルドカードルートがサブドメインを要求していない限り、サブドメイン example.test のホストに対する重複しない要求を許可します。

$ oc adm router ...
$ oc set env dc/router ROUTER_ALLOW_WILDCARD_ROUTES=true

$ oc project ns1
$ oc expose service myservice --hostname=owner.example.test
$ oc expose service myservice --hostname=aname.example.test
$ oc expose service myservice --hostname=bname.example.test

$ oc project ns2
$ oc expose service anotherservice --hostname=second.example.test
$ oc expose service anotherservice --hostname=cname.example.test

$ oc project otherns
$ oc expose service thirdservice --hostname=emmy.example.test
$ oc expose service thirdservice --hostname=webby.example.test

以下の例では、ワイルドカードルートを許可するルーターは、所有している namespace が ns1 なので、owner.example.test または aname.example.test の要求を許可しません。

$ oc adm router ...
$ oc set env dc/router ROUTER_ALLOW_WILDCARD_ROUTES=true

$ oc project ns1
$ oc expose service myservice --hostname=owner.example.test
$ oc expose service myservice --hostname=aname.example.test

$ oc project ns2
$ oc expose service secondservice --hostname=bname.example.test
$ oc expose service secondservice --hostname=cname.example.test

$ # Router will not allow this claim with a different path name `/p1` as
$ # namespace `ns1` has an older route claiming host `aname.example.test`.
$ oc expose service secondservice --hostname=aname.example.test --path="/p1"

$ # Router will not allow this claim as namespace `ns1` has an older route
$ # claiming host name `owner.example.test`.
$ oc expose service secondservice --hostname=owner.example.test

$ oc project otherns

$ # Router will not allow this claim as namespace `ns1` has an older route
$ # claiming host name `aname.example.test`.
$ oc expose service thirdservice --hostname=aname.example.test

以下の例では、ワイルドカードルートを許可するルーターは、所有している namespace が ns1 で、そのワイルドカードルートが同じ namespace に属しているので、`\*.example.test の要求を許可します。

$ oc adm router ...
$ oc set env dc/router ROUTER_ALLOW_WILDCARD_ROUTES=true

$ oc project ns1
$ oc expose service myservice --hostname=owner.example.test

$ # Reusing the route.yaml from the previous example.
$ # spec:
$ #   host: www.example.test
$ #   wildcardPolicy: Subdomain

$ oc create -f route.yaml   #  router will allow this claim.

以下の例では、ワイルドカードルートを許可するルーターは、所有している namespace が ns1 で、ワイルドカードルートが別の namespace cyclone に属するため、`\*.example.test の要求を許可しません。

$ oc adm router ...
$ oc set env dc/router ROUTER_ALLOW_WILDCARD_ROUTES=true

$ oc project ns1
$ oc expose service myservice --hostname=owner.example.test

$ # Switch to a different namespace/project.
$ oc project cyclone

$ # Reusing the route.yaml from a prior example.
$ # spec:
$ #   host: www.example.test
$ #   wildcardPolicy: Subdomain

$ oc create -f route.yaml   #  router will deny (_NOT_ allow) this claim.

同様に、ワイルドカードルートを持つ namespace がサブドメインを要求すると、その namespace 内のルートのみがその同じサブドメインでホストを要求できます。

以下の例では、ワイルドカードルートを持つ namespace ns1 のルートがサブドメイン example.test を要求すると、namespace ns1 内のルートのみがその同じサブドメインのホストを要求することを許可されます。

$ oc adm router ...
$ oc set env dc/router ROUTER_ALLOW_WILDCARD_ROUTES=true

$ oc project ns1
$ oc expose service myservice --hostname=owner.example.test

$ oc project otherns

$ # namespace `otherns` is allowed to claim for other.example.test
$ oc expose service otherservice --hostname=other.example.test

$ oc project ns1

$ # Reusing the route.yaml from the previous example.
$ # spec:
$ #   host: www.example.test
$ #   wildcardPolicy: Subdomain

$ oc create -f route.yaml   #  Router will allow this claim.

$ #  In addition, route in namespace otherns will lose its claim to host
$ #  `other.example.test` due to the wildcard route claiming the subdomain.

$ # namespace `ns1` is allowed to claim for deux.example.test
$ oc expose service mysecondservice --hostname=deux.example.test

$ # namespace `ns1` is allowed to claim for deux.example.test with path /p1
$ oc expose service mythirdservice --hostname=deux.example.test --path="/p1"

$ oc project otherns

$ # namespace `otherns` is not allowed to claim for deux.example.test
$ # with a different path '/otherpath'
$ oc expose service otherservice --hostname=deux.example.test --path="/otherpath"

$ # namespace `otherns` is not allowed to claim for owner.example.test
$ oc expose service yetanotherservice --hostname=owner.example.test

$ # namespace `otherns` is not allowed to claim for unclaimed.example.test
$ oc expose service yetanotherservice --hostname=unclaimed.example.test

以下の例では、所有権のあるルートが削除され、所有権が namespace 内または namespace 間で渡されるさまざまなシナリオが示されています。namespace ns1 のホスト eldest.example.test を要求するルートが存在する場合、その namespace 内のワイルドカードルートはサブドメイン example.test を要求できます。ホスト eldest.example.test のルートが削除されると、次に古いルート senior.example.test が最も古いルートになりますが、これは他のルートに影響を与えません。ホスト senior.example.test のルートが削除されると、次に古いルート junior.example.test が最も古いルートになり、ワイルドカードルートの要求をブロックします。

$ oc adm router ...
$ oc set env dc/router ROUTER_ALLOW_WILDCARD_ROUTES=true

$ oc project ns1
$ oc expose service myservice --hostname=eldest.example.test
$ oc expose service seniorservice --hostname=senior.example.test

$ oc project otherns

$ # namespace `otherns` is allowed to claim for other.example.test
$ oc expose service juniorservice --hostname=junior.example.test

$ oc project ns1

$ # Reusing the route.yaml from the previous example.
$ # spec:
$ #   host: www.example.test
$ #   wildcardPolicy: Subdomain

$ oc create -f route.yaml   #  Router will allow this claim.

$ #  In addition, route in namespace otherns will lose its claim to host
$ #  `junior.example.test` due to the wildcard route claiming the subdomain.

$ # namespace `ns1` is allowed to claim for dos.example.test
$ oc expose service mysecondservice --hostname=dos.example.test

$ # Delete route for host `eldest.example.test`, the next oldest route is
$ # the one claiming `senior.example.test`, so route claims are unaffacted.
$ oc delete route myservice

$ # Delete route for host `senior.example.test`, the next oldest route is
$ # the one claiming `junior.example.test` in another namespace, so claims
$ # for a wildcard route would be affected. The route for the host
$ # `dos.example.test` would be unaffected as there are no other wildcard
$ # claimants blocking it.
$ oc delete route seniorservice

4.2.19. コンテナーネットワークスタックの使用

OpenShift Container Platform ルーターはコンテナー内で実行され、デフォルトの動作として、ホスト (例: ルーターコンテナーが実行されるノードなど) のネットワークスタックを使用します。このデフォルトの動作には、リモートクライアントからのネットワークトラフィックがターゲットサービスとコンテナーに到達するためにユーザー空間で複数のホップを使用する必要がないので、パフォーマンス上のメリットがあります。

さらに、このデフォルト動作によってルーターはノードの IP アドレスではなくリモート接続の実際のソース IP アドレスを取得できます。これは、発信元の IP に基づいて ingress ルールを定義し、スティッキーセッションをサポートし、他に使用されているものの中でトラフィックを監視するのに役立ちます。

このホストネットワークの動作は --host-network ルーターコマンドラインオプションによって制御でき、デフォルトの動作は --host-network=true を使用した場合と等しくなります。コンテナーネットワークスタックを使用してルーターを実行する場合は、ルーターを作成する際に --host-network=false オプションを使用します。以下は例になります。

$ oc adm router --service-account=router --host-network=false

内部的には、これは外部ネットワークがルーターと通信するために、ルーターコンテナーが 80 と 443 ポートを公開する必要があることを意味します。

注記

コンテナーネットワークスタックを使用して実行することで、ルーターは接続のソース IP アドレスを実際のリモート IP アドレスではなくノードの NAT された IP アドレスとして扱うことを意味します。

注記

マルチテナントネットワークの分離を使用する OpenShift Container Platform クラスターでは、--host-network=false オプションを指定したデフォルト以外の namespace のルーターはクラスターのすべてのルートを読み込みますが、ネットワークの分離により複数の namespace にあるルートには到達できません。--host-network=true オプションを指定すると、ルートはコンテナーネットワークをバイパスし、クラスターの任意の Pod にアクセスできます。この場合、分離が必要な場合は、複数の namespace のルートを追加しないでください。

4.2.20. ルーターメトリクスの公開

HAProxy ルーターメトリクス は、外部メトリクス収集および集約システム (例: Prometheus、statsd) で使用されるようにデフォルトで Prometheus 形式で公開されます。メトリクスは独自の HTML 形式でブラウザーで閲覧したり CSV ダウンロードを実行するために HAProxy ルーターから直接利用することもできます。これらのメトリクスには、HAProxy ネイティブメトリクスおよび一部のコントローラーメトリクスが含まれます。

以下のコマンドを使用してルーターを作成する場合、OpenShift Container Platform は Prometheus 形式のメトリクスをデフォルトが 1936 の統計ポートで利用可能にします。

$ oc adm router --service-account=router
  • Prometheus 形式で未加工統計を抽出するには、以下を実行します。

    curl <user>:<password>@<router_IP>:<STATS_PORT>

    例を以下に示します。

    $ curl admin:sLzdR6SgDJ@10.254.254.35:1936/metrics

    メトリクスにアクセスするために必要な情報は、ルーターサービスのアノテーションで確認できます。

    $ oc edit router service <router-service-name>
    
    apiVersion: v1
    kind: Service
    metadata:
      annotations:
        prometheus.io/port: "1936"
        prometheus.io/scrape: "true"
        prometheus.openshift.io/password: IImoDqON02
        prometheus.openshift.io/username: admin

    prometheus.io/port はデフォルトが 1936 の統計ポートです。アクセスを許可するようファイウォールを設定する必要がある場合があります。直前のユーザー名およびパスワードを使用してメトリクスにアクセスします。パスは /metrics です。

    $ curl <user>:<password>@<router_IP>:<STATS_PORT>
    for example:
    $ curl admin:sLzdR6SgDJ@10.254.254.35:1936/metrics
    ...
    # HELP haproxy_backend_connections_total Total number of connections.
    # TYPE haproxy_backend_connections_total gauge
    haproxy_backend_connections_total{backend="http",namespace="default",route="hello-route"} 0
    haproxy_backend_connections_total{backend="http",namespace="default",route="hello-route-alt"} 0
    haproxy_backend_connections_total{backend="http",namespace="default",route="hello-route01"} 0
    ...
    # HELP haproxy_exporter_server_threshold Number of servers tracked and the current threshold value.
    # TYPE haproxy_exporter_server_threshold gauge
    haproxy_exporter_server_threshold{type="current"} 11
    haproxy_exporter_server_threshold{type="limit"} 500
    ...
    # HELP haproxy_frontend_bytes_in_total Current total of incoming bytes.
    # TYPE haproxy_frontend_bytes_in_total gauge
    haproxy_frontend_bytes_in_total{frontend="fe_no_sni"} 0
    haproxy_frontend_bytes_in_total{frontend="fe_sni"} 0
    haproxy_frontend_bytes_in_total{frontend="public"} 119070
    ...
    # HELP haproxy_server_bytes_in_total Current total of incoming bytes.
    # TYPE haproxy_server_bytes_in_total gauge
    haproxy_server_bytes_in_total{namespace="",pod="",route="",server="fe_no_sni",service=""} 0
    haproxy_server_bytes_in_total{namespace="",pod="",route="",server="fe_sni",service=""} 0
    haproxy_server_bytes_in_total{namespace="default",pod="docker-registry-5-nk5fz",route="docker-registry",server="10.130.0.89:5000",service="docker-registry"} 0
    haproxy_server_bytes_in_total{namespace="default",pod="hello-rc-vkjqx",route="hello-route",server="10.130.0.90:8080",service="hello-svc-1"} 0
    ...
  • ブラウザーでメトリクスを取得するには、以下を実行します。

    1. 以下の環境変数をデプロイメント設定ファイルから削除します。

      $ oc edit service router
      
      - name: ROUTER_LISTEN_ADDR
        value: 0.0.0.0:1936
      - name: ROUTER_METRICS_TYPE
        value: haproxy
    2. ブラウザーで以下の URL を使用して統計ウィンドウを起動します。ここでは、STATS_PORT 値はデフォルトで 1936 になります。

      http://admin:<Password>@<router_IP>:<STATS_PORT>

      ;csv を URL に追加して CVS 形式の統計を取得できます。

      例を以下に示します。

      http://admin:<Password>@<router_IP>:1936;csv

      ルーター IP、管理者名、およびパスワードを取得するには、以下を実行します。

      oc describe pod <router_pod>
  • メトリクスのコレクションを表示しないようにするには、以下を実行します。

    $ oc adm router --service-account=router --stats-port=0

    大規模クラスターの ARP キャッシュのチューニング

(net.ipv4.neigh.default.gc_thresh3 の値 (デフォルトで65536) を上回る) 多数のルート を持つ OpenShift Container Platform クラスターでは、ARP キャッシュでより多くのエントリーを許可するためにルーター Pod を実行するクラスターの各ノードで sysctl 変数のデフォルト値を増やす必要があります。

問題が発生している場合、以下のようなカーネルメッセージが表示されます。

[ 1738.811139] net_ratelimit: 1045 callbacks suppressed
[ 1743.823136] net_ratelimit: 293 callbacks suppressed

この問題が発生すると、oc コマンドは以下のエラーを出して失敗することがあります。

Unable to connect to the server: dial tcp: lookup <hostname> on <ip>:<port>: write udp <ip>:<port>-><ip>:<port>: write: invalid argument

IPv4 の ARP エントリーの実際の量を確認するには、以下を実行します。

# ip -4 neigh show nud all | wc -l

数字が net.ipv4.neigh.default.gc_thresh3 しきい値に近づき始めたら、値を増やします。以下を実行して現在値を取得します。

# sysctl net.ipv4.neigh.default.gc_thresh1
net.ipv4.neigh.default.gc_thresh1 = 128
# sysctl net.ipv4.neigh.default.gc_thresh2
net.ipv4.neigh.default.gc_thresh2 = 512
# sysctl net.ipv4.neigh.default.gc_thresh3
net.ipv4.neigh.default.gc_thresh3 = 1024

以下の sysctl は変数を OpenShift Container Platform の現在のデフォルト値に設定します。

# sysctl net.ipv4.neigh.default.gc_thresh1=8192
# sysctl net.ipv4.neigh.default.gc_thresh2=32768
# sysctl net.ipv4.neigh.default.gc_thresh3=65536

これらの設定を永続化するには、このドキュメントを参照してください。

4.2.21. DDoS 攻撃からの保護

timeout http-request をデフォルトの HAProxy ルーターイメージに追加して、分散型の denial-of-service (DDoS) 攻撃 (slowloris など) からデプロイメントを保護します。

# and the haproxy stats socket is available at /var/run/haproxy.stats
global
  stats socket ./haproxy.stats level admin

defaults
  option http-server-close
  mode http
  timeout http-request 5s
  timeout connect 5s 1
  timeout server 10s
  timeout client 30s
1
timeout http-request は最大 5 秒に設定されます。HAProxy は HTTP 要求全体の送信のための 5 秒をクライアントに対して指定します。この指定がないと、HAProxy はエラーを出して接続を切断します。

また、環境変数 ROUTER_SLOWLORIS_TIMEOUT が設定されている場合、クライアントが HTTP 要求全体を送信するためにかかる合計時間が制限されます。これが設定されていない場合、HAProxy は接続を切断します。

環境変数を設定することで、情報をルーターのデプロイメント設定の一部として取得でき、テンプレートを手動で変更することが不要になります。一方、HAProxy 設定を手動で追加すると、ルーター Pod の再ビルドとルーターテンプレートファイルの保守が必要になります。

アノテーションを使用して、以下を制限する機能を含む基本的な DDoS 保護を HAProxy テンプレートルーターに実装します。

  • 同時 TCP 接続の数
  • クライアントが TCP 接続を要求できるレート
  • HTTP 要求を実行できるレート

アプリケーションによってはトラフィックのパターンが完全に異なる場合があるため、これらはルートごとに有効にされます。

表4.1 HAProxy テンプレートルーター設定

設定説明

haproxy.router.openshift.io/rate-limit-connections

設定した内容を有効にします (true に設定した場合など)。

haproxy.router.openshift.io/rate-limit-connections.concurrent-tcp

このルートの同じ IP アドレスで接続できる同時 TCP 接続の数。

haproxy.router.openshift.io/rate-limit-connections.rate-tcp

クライアント IP で開くことができる TCP 接続の数。

haproxy.router.openshift.io/rate-limit-connections.rate-http

クライアント IP が 3 秒間で実行できる HTTP 要求の数。

4.3. カスタマイズされた HAProxy ルーターのデプロイ

4.3.1. 概要

デフォルトの HAProxy ルーターは多数のユーザーのニーズを対応することを目的としています。ただし、このルーターは HAProxy のすべての機能を公開している訳ではありません。そのため、ユーザーはそれぞれのニーズに合わせてルーターを変更する必要があります。

新機能をアプリケーションバックエンド内で実装したり、現在の操作を変更する必要がある場合があります。ルータープラグインはこのカスタマイズを行うために必要なすべての機能を提供します。

ルーター Pod はテンプレートファイルを使用して必要な HAProxy 設定ファイルを作成します。テンプレートファイルは golang テンプレート です。テンプレートを処理する際に、ルーターはルーターのデプロイメント設定、許可されたルートのセット、一部のヘルパー機能などの OpenShift Container Platform 情報にアクセスします。

ルーター Pod が起動し、リロードされるたびに、HAProxy 設定ファイルが作成され、HAProxy が起動します。『HAProxy 設定マニュアル』には HAProxy のすべての機能と有効な設定ファイルの作成方法が記載されています。

configMap を使用して新規テンプレートをルーター Pod に追加することができます。この方法により、ルーターデプロイメント設定を変更して、configMap をルーター Pod のボリュームとしてマウントできます。 TEMPLATE_FILE 環境変数はルーター Pod のテンプレートファイルのフルパス名に設定されます。

または、カスタムルーターイメージをビルドし、ルーターの一部またはすべてをデプロイする際にこれを使用することができます。すべてのルーターが同じイメージを実行する必要はありません。これを実行するには、 haproxy-template.config ファイルを変更し、ルーターイメージを再ビルドします。新しいイメージはクラスターの Docker リポジトリーにプッシュされ、ルーターのデプロイメント設定の image: フィールドが新しい名前で更新されます。クラスターが更新されたら、イメージを再ビルドし、プッシュする必要があります。

いずれの場合でも、ルーター Pod はテンプレートファイルを使用して起動します。

4.3.2. ルーター設定テンプレートの取得

HAProxy テンプレートファイルはかなり大きく複雑です。一部を変更するのであれば、すべてを書き換えるよりも既存のテンプレートを変更する方が簡単です。マスターでルーターを実行し、ルーター Pod を参照することで実行中のルーターから haproxy-config.templateファイルを取得できます。

# oc get po
NAME                       READY     STATUS    RESTARTS   AGE
router-2-40fc3             1/1       Running   0          11d
# oc rsh router-2-40fc3 cat haproxy-config.template > haproxy-config.template
# oc rsh router-2-40fc3 cat haproxy.config > haproxy.config

または、ルーターを実行しているノードにログオンします。

# docker run --rm --interactive=true --tty --entrypoint=cat \
    registry.access.redhat.com/openshift3/ose-haproxy-router:v3.7 haproxy-config.template

イメージ名は docker イメージ から取られます。

この内容をカスタマイズされたテンプレートのベースとして使用するためにファイルに保存します。保存された haproxy.config は実際に実行されているものを示します。

4.3.3. ルーター設定テンプレートの変更

4.3.3.1. 背景

このテンプレートは golang テンプレートに基づいています。これは、ルーターのデプロイメント設定の環境変数や、以下に示す設定情報およびルーターが提供するヘルパー機能を参照することができます。

テンプレートファイルの構造は作成される HAProxy 設定ファイルを反映します。テンプレートの処理時に、{{" something "}} によって囲まれていないものはすべて設定ファイルに直接コピーされます。{{" something "}} で囲まれている部分は評価されます。生成されるテキスト (ある場合) は設定ファイルにコピーされます。

4.3.3.2. Go テンプレートアクション

define アクションは、処理されるテンプレートを含むファイルに名前を付けます。

{{define "/var/lib/haproxy/conf/haproxy.config"}}pipeline{{end}}

表4.2 テンプレートルーター関数

関数意味

processEndpointsForAlias(alias ServiceAliasConfig, svc ServiceUnit, action string) []Endpoint

有効なエンドポイントの一覧を返します。アクションが「Shuffle」の場合、エンドポイントの順序はランダム化されます。

env(variable, default …​string) string

Pod からの名前付き環境変数の取得を試行します。これが定義されていないか、または空の場合、オプションの 2 つ目の引数が返されます。それ以外の場合には空の文字列を返します。

matchPattern(pattern, s string) bool

1 つ目の引数は正規表現を含む文字列で、2 つ目の引数はテストに使用できる変数です。1 つ目の引数として提供される正規表現が 2 つ目の引数として提供される文字列と一致するかどうかを示すブール値を返します。

isInteger(s string) bool

指定された変数が整数かどうかを判別します。

firstMatch(s string, allowedValues …​string) bool

所定の文字列を許可された文字列の一覧と比較します。左から右にスキャンし、最初の一致を返します。

matchValues(s string, allowedValues …​string) bool

所定の文字列を許可された文字列の一覧と比較します。文字列が許可される値の場合は「true」を返します。それ以外の場合は、「false」を返します。

generateRouteRegexp(hostname, path string, wildcard bool) string

ルートホスト (とパス) に一致する正規表現を生成します。最初の引数はホスト名であり、2 つ目はパス、3 つ目はワイルドカードブール値です。

genCertificateHostName(hostname string, wildcard bool) string

証明書の提供/証明書のマッチングに使用するホスト名を生成します。1 つ目の引数はホスト名で、2 つ目はワイルドカードブール値です。

isTrue(s string) bool

所定の変数に「true」が含まれるかどうかを判別します。

これらの関数は、HAProxy テンプレートルータープラグインによって提供されます。

4.3.3.3. ルーターが提供する情報

このセクションでは、ルーターがテンプレートで利用可能にする OpenShift Container Platform の情報について説明しますす。ルーター設定パラメーターは HAProxy ルータープラグインに与えられるデータセットです。フィールドには (dot) .Fieldname を使用してアクセスします。

以下のルーター設定パラメーター表は各種フィールドの定義を詳しく取り上げています。とくに .State には許可されたルートセットが設定されます。

表4.3 ルーター設定パラメーター

フィールド種別説明

WorkingDir

文字列

ファイルが書き込まれるディレクトリー。デフォルトは /var/lib/containers/router に設定されます。

State

map[string](ServiceAliasConfig)`

ルート。

ServiceUnits

map[string]ServiceUnit

サービスのルックアップ。

DefaultCertificate

文字列

pem 形式のデフォルト証明書へのフルパス名。

PeerEndpoints

`[]Endpoint

ピア。

StatsUser

文字列

統計の公開に使用するユーザー名 (テンプレートがサポートしている場合)。

StatsPassword

文字列

統計の公開に使用するパスワード (テンプレートがサポートしている場合)。

StatsPort

整数

統計の公開に使用するポート (テンプレートがサポートしている場合)。

BindPorts

bool

ルーターがデフォルトポートをバインドすべきかどうか。

表4.4 ルーター ServiceAliasConfig (Route)

フィールド種別説明

Name

文字列

ルートのユーザー固有の名前。

Namespace

文字列

ルートの namespace。

Host

文字列

ホスト名。例: www.example.com

Path

文字列

オプションのパス。例: www.example.com/myservice (ここでは、myservice がパスになります)。

TLSTermination

routeapi.TLSTerminationType

このバックエンドの終了ポリシー。マッピングファイルとルーター設定を利用します。

Certificates

map[string]Certificate

このバックエンドをセキュリティー保護するために使用する証明書。証明書 ID で指定します。

Status

ServiceAliasConfigStatus

永続化する必要がある設定のステータスを示します。

PreferPort

文字列

ユーザーが公開したいポートを示します。空の場合、サービスのポートが選択されます。

InsecureEdgeTerminationPolicy

routeapi.InsecureEdgeTerminationPolicyType

edge termination ルートへの非セキュアな接続の必要な動作を示します。 none (または disable)、allow、または redirect

RoutingKeyName

文字列

Cookie ID を隠すために使用するルート + namespace 名のハッシュ。

IsWildcard

bool

このサービスユニットが ワイルドカードサポートを必要とすることを示します。

Annotations

map[string]string

このルートに割り当てられるアノテーション。

ServiceUnitNames

map[string]int32

このルートをサポートするサービスコレクション。マップの他のエントリーに関連してサービス名で指定され、これに割り当てられた重みで評価されます。

ActiveServiceUnits

整数

ゼロ以外の重みを持つ ServiceUnitNames の数。

ServiceAliasConfig はサービスのルートです。ホスト + パスによって特定されます。デフォルトのテンプレートは {{range $cfgIdx, $cfg := .State }} を使用してルートを繰り返し処理します。その {{range}} ブロック内で、テンプレートは $cfg.Field を使用して現在の ServiceAliasConfig のフィールドを参照できます。

表4.5 ルーター ServiceUnit

フィールド種別説明

Name

文字列

名前はサービス名 + namespace に対応します。ServiceUnit を特定します。

EndpointTable

[]Endpoint

サービスをサポートするエンドポイント。これはルーターの最終のバックエンド実装に変換されます。

ServiceUnit はサービスをカプセル化したものであり、そのサービスをサポートするエンドポイントであり、またサービスを参照するルートです。これは、ルーター設定ファイルの作成を進めるデータです。

表4.6 ルーターエンドポイント

フィールド種別

ID

文字列

IP

文字列

Port

文字列

TargetName

文字列

PortName

文字列

IdHash

文字列

NoHealthCheck

bool

Endpoint は、Kubernetes エンドポイントの内部表現です。

表4.7 ルーター証明書、ServiceAliasConfigStatus

フィールド種別説明

Certificate

文字列

パブリック/プライベートキーのペアを表します。これは ID で識別され、ファイル名になります。CA 証明書には PrivateKey が設定されません。

ServiceAliasConfigStatus

文字列

この設定に必要なファイルがディスクに永続化されていることを示します。有効な値の例: "saved" または "" (ブランク)。

表4.8 ルーター証明書タイプ

フィールド種別説明

ID

文字列

 

コンテンツ

文字列

証明書。

PrivateKey

文字列

プライベートキー。

表4.9 ルーター TLSTerminationType

フィールド種別説明

TLSTerminationType

文字列

セキュアな通信が停止する場合を指示します。

InsecureEdgeTerminationPolicyType

文字列

ルートへの非セキュアな接続の必要な動作を示します。各ルーターは公開するポートを独自に決定することがありますが、通常はポート 80 になります。

TLSTerminationTypeInsecureEdgeTerminationPolicyType はセキュアな通信が停止する場合を指示します。

表4.10 ルーター TLSTerminationType 値

定数意味

TLSTerminationEdge

edge

edge ルーターでの暗号化を終了します。

TLSTerminationPassthrough

passthrough

宛先での暗号化を終了し、宛先でトラフィックを復号化します。

TLSTerminationReencrypt

reencrypt

edge ルーターで暗号化を終了し、宛先で提供される新規の証明書を使用して再暗号化します。

表4.11 ルーター InsecureEdgeTerminationPolicyType 値

種別意味

Allow

トラフィックは非セキュアなポートのサーバーに送信されます (デフォルト)。

Disable

トラフィックは非セキュアなポートでは許可されません。

Redirect

クライアントはセキュアなポートにリダイレクトされます。

なし ("") は Disable と同じです。

4.3.3.4. アノテーション

各ルートにはアノテーションが割り当てることができます。各アノテーションは名前と値のみで構成されます。

apiVersion: v1
kind: Route
metadata:
  annotations:
    haproxy.router.openshift.io/timeout: 5500ms
[...]

名前は既存のアノテーションと競合しないものにできます。値は文字列です。文字列では複数のトークンをスペースで区切ることができます (例: aa bb cc)。テンプレートは {{index}} を使用してアノテーションの値を抽出します。以下は例になります。

{{$balanceAlgo := index $cfg.Annotations "haproxy.router.openshift.io/balance"}}

この例は、これをどのようにクライアントの相互承認に使用できるかを示しています。

{{ with $cnList := index $cfg.Annotations "whiteListCertCommonName" }}
  {{   if ne $cnList "" }}
    acl test ssl_c_s_dn(CN) -m str {{ $cnList }}
    http-request deny if !test
  {{   end }}
{{ end }}

このコマンドを使用してホワイトリストの CN を処理できます。

$ oc annotate route <route-name> --overwrite whiteListCertCommonName="CN1 CN2 CN3"

詳細は、「Route-specific Annotations」を参照してください。

4.3.3.5. 環境変数

テンプレートはルーター Pod に存在する任意の環境変数を使用できます。環境変数はデプロイメント設定に設定できます。また、新規の環境変数を追加できます。

これらは env 関数で参照されます。

{{env "ROUTER_MAX_CONNECTIONS" "20000"}}

1 つ目の文字列は変数であり、変数がないか、または nil の場合には 2 つ目の文字列がデフォルトになります。ROUTER_MAX_CONNECTIONS が設定されていないか、または nil の場合、20000 が使用されます。環境変数はマップと言えます。ここでキーは環境変数名で、内容は変数の値になります。

詳細は、「Route-specific Environment variables」を参照してください。

4.3.3.6. 使用例

以下で HAProxy テンプレートファイルに基づく単純なテンプレートを示します。

以下のコメントで開始します。

{{/*
  Here is a small example of how to work with templates
  taken from the HAProxy template file.
*/}}

テンプレートは任意の数の出力ファイルを作成できます。defineコンストラクトを使用して出力ファイルを作成します。ファイル名は定義する引数として指定され、define ブロック内の一致する終了部分までのすべての情報がそのファイルの内容として書き込まれます。

{{ define "/var/lib/haproxy/conf/haproxy.config" }}
global
{{ end }}

上記は global/var/lib/haproxy/conf/haproxy.config ファイルにコピーし、ファイルを閉じます。

ロギングを環境変数に基づいてセットアップします。

{{ with (env "ROUTER_SYSLOG_ADDRESS" "") }}
  log {{.}} {{env "ROUTER_LOG_FACILITY" "local1"}} {{env "ROUTER_LOG_LEVEL" "warning"}}
{{ end }}

env 関数は、環境変数の値を抽出します。環境変数が定義されていないか、または nil の場合、2 つ目の引数が返されます。

with コンストラクトは with ブロック内の "." (ドット) の値を with に引数として提供される値に設定します。with アクションは Dot で nil をテストします。nil ではない場合、その句はend (終了部分) まで処理されます。上記では、ROUTER_SYSLOG_ADDRESS/var/log/msg が含まれ、ROUTER_LOG_FACILITY が定義されておらず、ROUTER_LOG_LEVELinfo が含まれていると想定しています。以下が出力ファイルにコピーされます。

  log /var/log/msg local1 info

許可された各ルートは設定ファイルの行を生成します。range を使用して、許可されたルートを確認します。

{{ range $cfgIdx, $cfg := .State }}
  backend be_http_{{$cfgIdx}}
{{end}}

.StateServiceAliasConfig のマップです。ここで、キーはルート名になります。range はマップを通じて、パスするたびに keyを使用して $cfgIdx を設定し、`$cfg がルートを記述する ServiceAliasConfig をポイントするよう設定します。 myroutehisroute という 2 つのルートがある場合、上記により以下が出力ファイルにコピーされます。

  backend be_http_myroute
  backend be_http_hisroute

ルートアノテーション $cfg.Annotations もマップであり、アノテーション名がキーとなり、コンテンツの文字列が値になっています。ルートは必要な数だけアノテーションを持つことができ、テンプレートの作成者が使用方法を定義します。ユーザーはアノテーションをルートにコード化し、テンプレート作成者は HAProxy テンプレートをカスタマイズしてそのアノテーションを処理できるようにします。

通常はアノテーションをインデックス化して値を取得します。

{{$balanceAlgo := index $cfg.Annotations "haproxy.router.openshift.io/balance"}}

インデックスは指定されたアノテーションの値を抽出します。そのため、`$balanceAlgo はアノテーションまたは nil に関連付けられた文字列が含まれます。上記のように、nil 以外の文字列についてテストし、with コンストラクトを使用して影響を確認することができます。

{{ with $balanceAlgo }}
  balance $balanceAlgo
{{ end }}

$balanceAlgonil でない場合、balance $balanceAlgo は出力ファイルにコピーされます。

2 つ目の例では、アノテーションのタイムアウト値の設定に基づいてサーバータイムアウトを設定します。

$value := index $cfg.Annotations "haproxy.router.openshift.io/timeout"

$value を評価して、適切に作成された文字列が含まれていることを確認できます。matchPattern 関数は正規表現を受け入れ、引数が表現を満たしていれば true を返します。

matchPattern "[1-9][0-9]*(us\|ms\|s\|m\|h\|d)?" $value

これにより 5000ms を受け入れますが、7y は受け取りません。この結果はテストで使用できます。

{{if (matchPattern "[1-9][0-9]*(us\|ms\|s\|m\|h\|d)?" $value) }}
  timeout server  {{$value}}
{{ end }}

これを使用してトークンに一致させることもできます。

matchPattern "roundrobin|leastconn|source" $balanceAlgo

または、matchValues を使用してトークンと一致させることもできます。

matchValues $balanceAlgo "roundrobin" "leastconn" "source"

4.3.4. ConfigMap を使用してルーター設定テンプレートを置き換える

ConfigMap を使用して、ルーターイメージを再ビルドすることなくルーターインスタンスをカスタマイズできます。ルーター環境変数の作成し、変更することができるだけでなく、haproxy-config.templatereload-haproxy その他のスクリプトを変更することもできます。

  1. 上記のように変更する haproxy-config.template をコピーして、必要に応じて変更します。
  2. ConfigMap を作成します。

    $ oc create configmap customrouter --from-file=haproxy-config.template

    customrouter ConfigMap には変更された haproxy-config.template ファイルのコピーが含まれています。

  3. ルーターデプロイメント設定を変更し、ConfigMap をファイルとしてマウントし、TEMPLATE_FILE 環境変数がこれをポイントするようにします。これは、 oc set envoc volume コマンドを使用するか、またはルーターデプロイメント設定を編集して実行できます。

    oc コマンドの使用
    $ oc volume dc/router --add --overwrite \
        --name=config-volume \
        --mount-path=/var/lib/haproxy/conf/custom \
        --source='{"configMap": { "name": "customrouter"}}'
    $ oc set env dc/router \
        TEMPLATE_FILE=/var/lib/haproxy/conf/custom/haproxy-config.template
    ルーターデプロイメント設定の編集

    oc edit dc router を使用して、テキストエディターでルーターデプロイメント設定を編集します。

    ...
            - name: STATS_USERNAME
              value: admin
            - name: TEMPLATE_FILE  1
              value: /var/lib/haproxy/conf/custom/haproxy-config.template
            image: openshift/origin-haproxy-routerp
    ...
            terminationMessagePath: /dev/termination-log
            volumeMounts: 2
            - mountPath: /var/lib/haproxy/conf/custom
              name: config-volume
          dnsPolicy: ClusterFirst
    ...
          terminationGracePeriodSeconds: 30
          volumes: 3
          - configMap:
              name: customrouter
            name: config-volume
    ...
    1
    spec.container.env フィールドに TEMPLATE_FILE 環境変数を追加して、マウントされた haproxy-config.template ファイルをポイントするようにします。
    2
    spec.container.volumeMounts フィールドを追加して、マウントポイントを作成します。
    3
    新しい spec.volumes フィールドを追加し、ConfigMap を示唆します。

    変更を保存し、エディターを終了します。ルーターが再起動します。

4.3.5. Stick Table の使用

以下のカスタマイズの例を高可用なルーティングセットアップで使用することで、ピア間の同期を行う stick-table を使用できます。

ピアセクションの追加

ピア間で stick-table を同期するには、HAProxy 設定でピアセクションを定義する必要があります。このセクションによって、HAProxy がどのようにピアを識別し、接続するかが決まります。プラグインはデータを .PeerEndpoints 変数にあるテンプレートに提供するので、ルーターサービスのメンバーを簡単に識別できます。以下を追加することで、ピアセクションをルーターイメージ内の haproxy-config.template ファイルに追加することができます。

{{ if (len .PeerEndpoints) gt 0 }}
peers openshift_peers
  {{ range $endpointID, $endpoint := .PeerEndpoints }}
    peer {{$endpoint.TargetName}} {{$endpoint.IP}}:1937
  {{ end }}
{{ end }}

リロードスクリプトの変更

stick-table を使用する場合、HAProxy にピアセクションでローカルホスト名として見なすものをオプションで指示することができます。エンドポイントの作成時に、プラグインは TargetName をエンドポイントの TargetRef.Name の値に設定するよう試みます。TargetRef が設定されていない場合、TargetName は IP アドレスに設定されます。TargetRef.Name は Kubernetes ホスト名に対応しているので、-L オプションを reload-haproxy スクリプトに追加してローカルホストをピアセクションで識別できます。

peer_name=$HOSTNAME 1

if [ -n "$old_pid" ]; then
  /usr/sbin/haproxy -f $config_file -p $pid_file -L $peer_name -sf $old_pid
else
  /usr/sbin/haproxy -f $config_file -p $pid_file -L $peer_name
fi
1
ピアセクションで使用されるエンドポイントターゲット名と一致している必要があります。

バックエンドの変更

最後に、stick-table をバックエンド内で使用するために、HAProxy 設定を変更して stick-table およびピアセットを使用することができます。以下は、stick-table を使用するように TCP 接続の既存のバックエンドを変更している例です。

            {{ if eq $cfg.TLSTermination "passthrough" }}
backend be_tcp_{{$cfgIdx}}
  balance leastconn
  timeout check 5000ms
  stick-table type ip size 1m expire 5m{{ if (len $.PeerEndpoints) gt 0 }} peers openshift_peers {{ end }}
  stick on src
                {{ range $endpointID, $endpoint := $serviceUnit.EndpointTable }}
  server {{$endpointID}} {{$endpoint.IP}}:{{$endpoint.Port}} check inter 5000ms
                {{ end }}
            {{ end }}

この変更を行った後に、ルーターを再ビルドできます。

4.3.6. ルーターの再ビルド

ルーターを再ビルドするには、実行中のルーターにある複数のファイルのコピーが必要になります。作業ディレクトリーを作成し、ルーターからファイルをコピーします。

# mkdir - myrouter/conf
# cd myrouter
# oc get po
NAME                       READY     STATUS    RESTARTS   AGE
router-2-40fc3             1/1       Running   0          11d
# oc rsh router-2-40fc3 cat haproxy-config.template > conf/haproxy-config.template
# oc rsh router-2-40fc3 cat error-page-503.http > conf/error-page-503.http
# oc rsh router-2-40fc3 cat default_pub_keys.pem > conf/default_pub_keys.pem
# oc rsh router-2-40fc3 cat ../Dockerfile > Dockerfile
# oc rsh router-2-40fc3 cat ../reload-haproxy > reload-haproxy

これらのファイルのいずれも編集するか、または置き換えることができます。ただし、conf/haproxy-config.templatereload-haproxy が変更される可能性が高くなります。

ファイルの更新後:

# docker build -t openshift/origin-haproxy-router-myversion .
# docker tag openshift/origin-haproxy-router-myversion 172.30.243.98:5000/openshift/haproxy-router-myversion 1
# docker push 172.30.243.98:5000/openshift/origin-haproxy-router-pc:latest 2
1
このバージョンをリポジトリーでタグ付けします。この場合、リポジトリーは 172.30.243.98:5000 になります。
2
タグ付けバージョンをリポジトリーにプッシュします。まずリポジトリーに docker ログイン する必要がある場合があります。

新規ルーターを使用するには、image: 文字列を変更するか、または --images=<repo>/<image>:<tag> フラグを oc adm router コマンドに追加してルーターデプロイ設定を編集します。

変更のデバッグ時に、デプロイメント設定で imagePullPolicy: Always を設定して各 Pod の作成時にイメージプルを強制的に実行すると便利です。デバッグが完了したら、これを imagePullPolicy: IfNotPresent に戻して各 Pod の起動時のプルを回避します。

4.4. HAProxy ルーターを設定して PROXY プロトコルを使用する

4.4.1. 概要

デフォルトで HAProxy ルーターは、非セキュアな edge および re-encrypt ルートへの受信接続に HTTP を使用することを想定しています。ただし、PROXY プロトコルを使用することで、ルーターが受信要求を予想するよう設定することができます。このトピックでは、HAProxy ルーターと外部ロードバランサーを PROXY プロトコルを使用するように設定する方法を説明しています。

4.4.2. PROXY プロトコルを使用する理由

プロキシーサーバーやロードバランサーなどの中間サービスが HTTP 要求を転送する際に、これは接続のソースアドレスを要求の「Forwarded」ヘッダーに追加して、この情報を後続の中間サービスと、要求が最終的に転送されるバックエンドサービスに提供できます。ただし、接続が暗号化されている場合、中間サービスは「Forwarded」ヘッダーを変更できません。この場合、要求が転送されても HTTP ヘッダーは元のソースアドレスを正確に通信することができません。

この問題を解決するために、一部のロードバランサーは、単純に HTTP を転送する代替手段として PROXY プロトコルを使用して HTTP 要求をカプセル化します。カプセル化によって、ロードバランサーは転送される要求自体を変更することなく、情報を要求に追加することができます。これにより、ロードバランサーは、暗号化された接続を転送する場合でもソースアドレスを通信できます。

HAProxy ルーターが PROXY プロトコルを受け入れ、HTTP 要求のカプセル化を解除するように設定できます。ルーターは edge および re-encrypt ルートの暗号化を終了するので、ルーターは要求の「Forwarded」HTTP ヘッダー (および関連する HTTP ヘッダー) を更新でき、PROXY プロトコルを使用して通信されるソースアドレスを追加できます。

警告

PROXY プロトコルと HTTP は互換性がなく、組み合わせることはできません。ルーターの前にロードバランサーを使用する場合、これらがどちらも PROXY プロトコルまたは HTTP のいずれかを使用する必要があります。一方を PROXY プロトコルを使用するように設定し、他方を HTTP を使用するように設定すると、ルーティングが失敗します。

4.4.3. PROXY プロトコルの使用

デフォルトで、HAProxy ルーターは PROXY プロトコルを使用しません。ROUTER_USE_PROXY_PROTOCOL 環境変数を使用することで、ルーターが受信接続に PROXY プロコトルの使用を予想するように設定できます。

PROXY プロコトルの有効化

$ oc env dc/router ROUTER_USE_PROXY_PROTOCOL=true

変数を true または TRUE 以外の値に設定し、PROXY プロコトルを無効にします。

PROXY プロトコルの無効化

$ oc env dc/router ROUTER_USE_PROXY_PROTOCOL=false

ルーターで PROXY プロトコルを有効にする場合、ルーターの前のロードバランサーが PROXY プロコトルを使用するように設定する必要があります。以下は、Amazon の Elastic Load Balancer (ELB) サービスを PROXY プロトコルを使用するように設定した例です。この例では、ELB がポート 80 (HTTP)、443 (HTTPS)、5000 (イメージレジストリーの場合) を 1 つ以上の EC2 インスタンスで実行されるルーターに転送することを想定しています。

Amazon ELB を設定して PROXY プロコトルを使用する

  1. 後続の手順を単純化するために、最初に一部の Shell 変数を設定します。

    $ lb='infra-lb' 1
    $ instances=( 'i-079b4096c654f563c' ) 2
    $ secgroups=( 'sg-e1760186' ) 3
    $ subnets=( 'subnet-cf57c596' ) 4
    1
    ELB の名前。
    2
    ルーターが実行されているインスタンス。
    3
    この ELB のセキュリティーグループ。
    4
    この ELB のサブネット。
  2. 次に、適切なリスナーやセキュリティーグループおよびサブネットを使用して ELB を作成します。

    注記

    すべてのリスナーが HTTP プロトコルではなく TCP プロトコルを使用するよう設定する必要があります。

    $ aws elb create-load-balancer --load-balancer-name "$lb" \
       --listeners \
        'Protocol=TCP,LoadBalancerPort=80,InstanceProtocol=TCP,InstancePort=80' \
        'Protocol=TCP,LoadBalancerPort=443,InstanceProtocol=TCP,InstancePort=443' \
        'Protocol=TCP,LoadBalancerPort=5000,InstanceProtocol=TCP,InstancePort=5000' \
       --security-groups $secgroups \
       --subnets $subnets
    {
        "DNSName": "infra-lb-2006263232.us-east-1.elb.amazonaws.com"
    }
  3. ルーターインスタンスを ELB に登録します。

    $ aws elb register-instances-with-load-balancer --load-balancer-name "$lb" \
       --instances $instances
    {
        "Instances": [
            {
                "InstanceId": "i-079b4096c654f563c"
            }
        ]
    }
  4. ELB のヘルスチェックを設定します。

    $ aws elb configure-health-check --load-balancer-name "$lb" \
       --health-check 'Target=HTTP:1936/healthz,Interval=30,UnhealthyThreshold=2,HealthyThreshold=2,Timeout=5'
    {
        "HealthCheck": {
            "HealthyThreshold": 2,
            "Interval": 30,
            "Target": "HTTP:1936/healthz",
            "Timeout": 5,
            "UnhealthyThreshold": 2
        }
    }
  5. 最後に、ProxyProtocol 属性を有効にしたロードバランサーのポリシーを作成し、ELB の TCP ポート 80 および 443 でポリシーを設定します。

    $ aws elb create-load-balancer-policy --load-balancer-name "$lb" \
       --policy-name "${lb}-ProxyProtocol-policy" \
       --policy-type-name 'ProxyProtocolPolicyType' \
       --policy-attributes 'AttributeName=ProxyProtocol,AttributeValue=true'
    $ for port in 80 443
      do
        aws elb set-load-balancer-policies-for-backend-server \
         --load-balancer-name "$lb" \
         --instance-port "$port" \
         --policy-names "${lb}-ProxyProtocol-policy"
      done

設定の確認

ロードバランサーを以下のように検証して、設定が正しいことを確認します。

$ aws elb describe-load-balancers --load-balancer-name "$lb" |
    jq '.LoadBalancerDescriptions| [.[]|.ListenerDescriptions]'
[
  [
    {
      "Listener": {
        "InstancePort": 80,
        "LoadBalancerPort": 80,
        "Protocol": "TCP",
        "InstanceProtocol": "TCP"
      },
      "PolicyNames": ["infra-lb-ProxyProtocol-policy"] 1
    },
    {
      "Listener": {
        "InstancePort": 443,
        "LoadBalancerPort": 443,
        "Protocol": "TCP",
        "InstanceProtocol": "TCP"
      },
      "PolicyNames": ["infra-lb-ProxyProtocol-policy"] 2
    },
    {
      "Listener": {
        "InstancePort": 5000,
        "LoadBalancerPort": 5000,
        "Protocol": "TCP",
        "InstanceProtocol": "TCP"
      },
      "PolicyNames": [] 3
    }
  ]
]
1
TCP ポート 80 のリスナーには PROXY プロトコルを使用するポリシーが設定されている必要があります。
2
TCP ポート 443 のリスナーには同じポリシーが設定されている必要があります。
3
TCP ポート 5000 のリスナーにはこのポリシーを設定できません

または、ELB をすでに設定していても、PROXY プロトコルを使用するよう設定されていない場合は、 TCP ポート 80 の既存リスナーを、HTTP ではなく TCP プロコトルを使用するように変更する必要があります (TCP ポート 443 はすでに TCP プロトコルを使用しているはずです)。

$ aws elb delete-load-balancer-listeners --load-balancer-name "$lb" \
   --load-balancer-ports 80
$ aws elb create-load-balancer-listeners --load-balancer-name "$lb" \
   --listeners 'Protocol=TCP,LoadBalancerPort=80,InstanceProtocol=TCP,InstancePort=80'

プロコトル更新の確認

プロコトルが以下のように更新されていることを確認します。

$ aws elb describe-load-balancers --load-balancer-name "$lb" |
   jq '[.LoadBalancerDescriptions[]|.ListenerDescriptions]'
[
  [
    {
      "Listener": {
        "InstancePort": 443,
        "LoadBalancerPort": 443,
        "Protocol": "TCP",
        "InstanceProtocol": "TCP"
      },
      "PolicyNames": []
    },
    {
      "Listener": {
        "InstancePort": 5000,
        "LoadBalancerPort": 5000,
        "Protocol": "TCP",
        "InstanceProtocol": "TCP"
      },
      "PolicyNames": []
    },
    {
      "Listener": {
        "InstancePort": 80,
        "LoadBalancerPort": 80,
        "Protocol": "TCP", 1
        "InstanceProtocol": "TCP"
      },
      "PolicyNames": []
    }
  ]
]
1
TCP ポート 80 のリスナーなど、すべてのリスナーが TCP プロコトルを使用している必要があります。

次にロードバランサーポリシーを作成し、上記の手順 5 に説明されているようにこれを ELB に追加します。

4.5. F5 ルータープラグインの使用

4.5.1. 概要

注記

F5 ルータープラグインは OpenShift Container Platform 3.0.2 以降で利用できます。

F5 ルーターブラグインはコンテナーイメージとして提供され、デフォルトの HAProxy ルーターのように Pod として実行されます。

重要

F5 と Red Hat 間のサポート体制により、Red Hat は F5 の統合を完全にサポートしています。F5 は F5 BIG-IP® 製品のサポートを提供しています。F5 と Red Hat は Red Hat OpenShift との統合を共同でサポートしています。Red Hat はバグフィックスおよび機能拡張を支援する一方で、すべての情報が F5 Networks に通信され、それらが開発サイクルの一部として管理されます。

4.5.2. 前提条件とサポート容易性

F5 ルータープラグインのデプロイ時に、以下の要件を満たしていることを確認してください。

  • F5 ホスト IPに以下が設定されている:

    • API アクセスの認証情報
    • プライベートキーによる SSH アクセス
  • 高度な Shell アクセスを持つ F5 ユーザー
  • HTTP ルートの仮想サーバー:

    • HTTP プロファイルhttp である必要があります。
  • HTTP プロファイルルートを持つ仮想サーバー:

    • HTTP プロファイルhttp である必要があります。
    • SSL プロファイル (クライアント)clientssl である必要があります。
    • SSL プロファイル (サーバー)serverssl である必要があります。
  • edge 統合の場合 (非推奨):

    • 稼働中の Ramp ノード
    • Ramp ノードへの稼働中のトンネル
  • ネイティブ統合の場合:

    • ポート 4789/UDP のすべてのノードと通信できるホストの内部 IP
    • F5 ホストにインストールされた sdn-services アドオンライセンス

OpenShift Container Platform は以下の F5 BIG-IP® バージョンのみをサポートしています。

  • 11.x
  • 12.x
重要

以下の機能は F5 BIG-IP® でサポートされていません。

  • ワイルドカードルートと re-encrypt ルートの併用: ルートに証明書とキーを指定する必要があります。証明書、キー、認証局 (CA) を指定しても、CA は使用されません。
  • 関連ルートを持たないサービスを含め、すべてのサービスのプールが作成されます。
  • アプリケーションのアイドリング
  • redirect モードの暗号化されていない HTTP トラフィックと edge TLS 終端。(insecureEdgeTerminationPolicy: Redirect)
  • シャード化、つまり F5 で複数の vservers を設定する。
  • SSL 暗号 (ROUTER_CIPHERS=modern/old)
  • エンドポイントのヘルスチェックの間隔やチェックタイプのカスタマイズ。
  • メトリクスサーバーの使用による F5 メトリクスの提供。
  • サービスでされるポートではない各種ターゲットポート (PreferPort/TargetPort) の指定。
  • ソース IP ホワイトリストのカスタマイズ。つまり特定の IP アドレスのルートのみに対してトラフィックを許可する。
  • max connect time または tcp FIN timeout などのタイムアウト値のカスタマイズ。
  • F5 BIG-IP® の HA モード。

4.5.2.1. 仮想サーバーの設定

openshift-F5 統合ルーターを使用する前提条件として、2 つの仮想サーバー (HTTP および HTTPS プロファイルのそれぞれに 1 つの仮想サーバー) を F5 BIG-IP® アプライアンスでセットアップする必要があります。

F5 BIG-IP® アプライアンスで仮想サーバーを設定するには、F5 の指示に従います。

仮想サーバーを作成する際に、以下の設定が有効であることを確認します。

  • HTTP サーバーの場合は、ServicePort'http'/80 に設定します。
  • HTTPS サーバーの場合は、ServicePort'https'/443 に設定します。
  • 基本設定で、両方の仮想サーバーの HTTP プロファイルを /Common/http に設定します。
  • HTTPS サーバーの場合は、 デフォルトの client-ssl プロファイルを作成し、SSL プロファイル (クライアント) に対してこれを選択します。

    • デフォルトのクライアント SSL プロファイルを作成するには、F5 の指示、とくに 「Configuring the fallback (default) client SSL profile」セクションに従います。このセクションでは、カスタム証明書がルートまたはサーバー名に提供されない場合にデフォルトで提供される証明書/キーのペアについて説明しています。

4.5.3. F5 ルーターのデプロイ

重要

ルート証明書は scp コマンドを使用してコピーされるため、F5 ルーターは特権モードで実行される必要があります。

$ oc adm policy remove-scc-from-user hostnetwork -z router
$ oc adm policy add-scc-to-user privileged -z router

oc adm router コマンドを使用して F5 ルーターをデプロイしますが、F5 BIG-IP® ホストの以下のパラメーターを指定する追加のフラグ (または環境変数) を提供します。

フラグ説明

--type=f5-router

F5 ルーターの起動を指定します (デフォルトの --typehaproxy-routerです)。

--external-host

F5 BIG-IP® ホストの管理インターフェースのホスト名または IP アドレスを指定します。

--external-host-username

F5 BIG-IP® のユーザー名 (通常は admin) を指定します。F5 BIG-IP のユーザーアカウントは F5 BIG-IP システムの Advanced Shell (Bash) へのアクセスがなければなりません。

--external-host-password

F5 BIG-IP® のパスワードを指定します。

--external-host-http-vserver

HTTP 接続の F5 仮想サーバーの名前を指定します。これは、ルーター Pod の起動前にユーザーによって設定される必要があります。

--external-host-https-vserver

HTTPS 接続の F5 仮想サーバーの名前を指定します。これは、ルーター Pod の起動前にユーザーによって設定される必要があります。

--external-host-private-key

F5 BIG-IP® ホストの SSH プライベートキーファイルへのパスを指定します。ルートのキーと証明書ファイルをアップロードし、削除する必要があります。

--external-host-insecure

F5 ルーターが F5 BIG-IP® ホストの証明書の厳しい検証を省略することを示す Boolean フラグ。

--external-host-partition-path

F5 BIG-IP® パーティションパス (デフォルトは /Common) を指定します。

例を以下に示します。

$ oc adm router \
    --type=f5-router \
    --external-host=10.0.0.2 \
    --external-host-username=admin \
    --external-host-password=mypassword \
    --external-host-http-vserver=ose-vserver \
    --external-host-https-vserver=https-ose-vserver \
    --external-host-private-key=/path/to/key \
    --host-network=false \
    --service-account=router

HAProxy ルーターの場合のように、oc adm router コマンドがサービスとデプロイメント設定オブジェクトを作成するため、F5 ルーター自体が実行されるレプリケーションコントローラーと Pod が作成されます。レプリケーションコントローラーはクラッシュが発生した場合に F5 ルーターを再起動します。F5 ルーターはルート、エンドポイント、ノードを監視し、F5 BIG-IP® を適宜設定するため、 F5 ルーターを適切に設定された F5 BIG-IP® デプロイメントで実行することは高可用性の要件を満たすはずです。

4.5.4. F5 ルーターのパーティションパス

パーティションパスによって、デフォルトの /Common パーティションではなく、カスタムの F5 BIG-IP® 管理パーティションで OpenShift Container Platform ルーティング設定を保存できます。カスタム管理パーティションを使用して F5 BIG-IP® 環境を保護することができます。つまり、F5 BIG-IP® システムオブジェクトに保存される OpenShift Container Platform 特有の設定が論理コンテナー内にあり、管理者はその管理パーティションでアクセス制御を定義できます。

管理パーティションの詳細については、F5 BIG-IP® ドキュメントを参照してください。

パーティションパスについて OpenShift Container Platform を設定するには、以下を実行します。

  1. オプションで一部のクリーニング手順を実行できます。

    1. F5 が /Common および /Custom パスに切り替えられるよう設定されていることを確認してください。
    2. vxlan5000 の静的 FDB を削除します。詳細は、F5 BIG-IP® ドキュメントを参照してください。
  2. カスタムパーティションの仮想サーバーを設定します。
  3. --external-host-partition-path フラグを使用して F5 ルーターをデプロイし、パーティションパスを指定します。

    $ oc adm router --external-host-partition-path=/OpenShift/zone1 ...

4.5.5. F5 ネイティブ統合のセットアップ

注記

このセクションでは、OpenShift Container Platform への F5 ネイティブ統合のセットアップ方法を確認します。F5 アプライアンスと OpenShift Container Platform 接続の概念および F5 ネイティブ統合のデータフローはルートに関するトピックの「F5 Native Integration」セクションで説明されています。

注記

F5 BIG-IP® アプライアンスのバージョン 12.x 以降のみが、このセクションに記載されているネイティブ統合に対応しています。また、適切に統合を行うために sdn-services アドオンライセンスが必要になります。バージョン 11.x の場合は、ramp ノード のセットアップ手順に従ってください。

OpenShift Container Platform バージョン 3.4 時点で、F5 の OpenShift Container Platform とのネイティブな統合により、F5 の Ramp ノードを OpenShift SDN で作成されるオーバーレイネットワークの Pod に到達するように設定する必要がありません。

F5 コントローラー Pod は、Pod に直接正常に接続できるようにするために必要な十分な情報を使って起動する必要があります。

  1. OpenShift Container Platform クラスターにゴースト hostsubnet を作成します。

    $ cat > f5-hostsubnet.yaml << EOF
    {
        "kind": "HostSubnet",
        "apiVersion": "v1",
        "metadata": {
            "name": "openshift-f5-node",
            "annotations": {
            "pod.network.openshift.io/assign-subnet": "true",
    	"pod.network.openshift.io/fixed-vnid-host": "0"  1
            }
        },
        "host": "openshift-f5-node",
        "hostIP": "10.3.89.213"  2
    } EOF
    $ oc create -f f5-hostsubnet.yaml
    1
    F5 をグローバルにします。
    2
    F5 アプライアンスの内部 IP です。
  2. 作成したゴースト hostsubnet に割り当てるサブネットを決定します。

    $ oc get hostsubnets
    NAME                    HOST                    HOST IP       SUBNET
    openshift-f5-node       openshift-f5-node       10.3.89.213   10.131.0.0/23
    openshift-master-node   openshift-master-node   172.17.0.2    10.129.0.0/23
    openshift-node-1        openshift-node-1        172.17.0.3    10.128.0.0/23
    openshift-node-2        openshift-node-2        172.17.0.4    10.130.0.0/23
  3. 新たに作成した hostsubnetSUBNET を確認します。この例では 10.131.0.0/23 です。
  4. Pod ネットワーク全体の CIDR を取得します。

    $ oc get clusternetwork

    この値は 10.128.0.0/14 のように表示されます。マスク (この例では 14) に注意してください。

  5. ゲートウェイアドレスを作成するには、hostsubnet から任意の IP アドレス (例: 10.131.0.5) を選択します。Pod ネットワークのマスク (14) を使用します。ゲートウェイアドレスは 10.131.0.5/14 になります。
  6. こちらの指示に従って F5 コントローラー Pod を起動してください。さらに、サービスアカウントに「ノード」のクラスターリソースへのアクセスを許可し、VXLAN のネイティブ統合に 2 つの新しい追加オプションを使用します。

    $ # Add policy to allow router to access nodes using the sdn-reader role
    $ oc adm policy add-cluster-role-to-user system:sdn-reader system:serviceaccount:default:router
    $ # Launch the router pod with vxlan-gw and F5's internal IP as extra arguments
    $ #--external-host-internal-ip=10.3.89.213
    $ #--external-host-vxlan-gw=10.131.0.5/14
    $ oc adm router \
        --type=f5-router \
        --external-host=10.3.89.90 \
        --external-host-username=admin \
        --external-host-password=mypassword \
        --external-host-http-vserver=ose-vserver \
        --external-host-https-vserver=https-ose-vserver \
        --external-host-private-key=/path/to/key \
        --service-account=router \
        --host-network=false \
        --external-host-internal-ip=10.3.89.213 \
        --external-host-vxlan-gw=10.131.0.5/14
    注記

    external-host-username は、F5 BIG-IP システムの Advanced Shell (Bash) へのアクセスを持つ F5 BIG-IP ユーザーアカウントです。

これで Ramp ノードを設定せずに F5 のセットアップを開始できます。