イングレスゲートウェイ
Istioは、Kubernetes Ingress リソースのサポートに加えて、Istio Gateway または Kubernetes Gateway リソースを使用してイングレストラフィックを設定することもできます。Gateway
は Ingress
よりも広範なカスタマイズと柔軟性を提供し、モニタリングやルートルールなどのIstioの機能をクラスタに流入するトラフィックに適用できます。
このタスクでは、Gateway
を使用してサービスメッシュの外部にサービスを公開するようにIstioを設定する方法について説明します。
始める前に
インストールガイドの手順に従ってIstioをセットアップします。
イングレストラフィックのターゲットサービスとして機能する httpbin サンプルを開始します。
$ kubectl apply -f @samples/httpbin/httpbin.yaml@
このドキュメントでは、ゲートウェイを使用して「Kubernetesクラスタ」へのイングレストラフィックを制御する方法を示しているため、サイドカーインジェクションを有効または無効にして
httpbin
サービスを開始できます(つまり、ターゲットサービスはIstioメッシュの内部または外部のいずれかに配置できます)。
ゲートウェイを使用したイングレスの設定
イングレス Gateway
は、メッシュのエッジで動作し、着信HTTP/TCP接続を受信するロードバランサーを記述します。公開ポート、プロトコルなどを設定しますが、Kubernetes Ingressリソース とは異なり、トラフィックルーティング設定は含まれていません。イングレストラフィックのトラフィックルーティングは、代わりに、内部サービスリクエストの場合とまったく同じ方法で、ルーティングルールを使用して設定されます。
HTTPトラフィック用にポート80で Gateway
を設定する方法を見てみましょう。
Istio Gateway を作成します。
$ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1
kind: Gateway
metadata:
name: httpbin-gateway
spec:
# The selector matches the ingress gateway pod labels.
# If you installed Istio using Helm following the standard documentation, this would be "istio=ingress"
selector:
istio: ingressgateway
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "httpbin.example.com"
EOF
Gateway
を介して入ってくるトラフィックのルートを設定します。
$ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: httpbin
spec:
hosts:
- "httpbin.example.com"
gateways:
- httpbin-gateway
http:
- match:
- uri:
prefix: /status
- uri:
prefix: /delay
route:
- destination:
port:
number: 8000
host: httpbin
EOF
これで、パス /status
と /delay
のトラフィックを許可する2つのルートルールを含む、httpbin
サービスの 仮想サービス 設定が作成されました。
gateways リストは、httpbin-gateway
を介したリクエストのみが許可されることを指定します。その他のすべての外部リクエストは、404レスポンスで拒否されます。
Kubernetes Gateway を作成します。
$ kubectl apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: httpbin-gateway
spec:
gatewayClassName: istio
listeners:
- name: http
hostname: "httpbin.example.com"
port: 80
protocol: HTTP
allowedRoutes:
namespaces:
from: Same
EOF
Kubernetes Gateway
リソースを作成すると、関連付けられたプロキシサービスもデプロイされるため、次のコマンドを実行してゲートウェイの準備ができるまで待ちます。
$ kubectl wait --for=condition=programmed gtw httpbin-gateway
Gateway
を介して入ってくるトラフィックのルートを設定します。
$ kubectl apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: httpbin
spec:
parentRefs:
- name: httpbin-gateway
hostnames: ["httpbin.example.com"]
rules:
- matches:
- path:
type: PathPrefix
value: /status
- path:
type: PathPrefix
value: /delay
backendRefs:
- name: httpbin
port: 8000
EOF
これで、パス /status
と /delay
のトラフィックを許可する2つのルートルールを含む、httpbin
サービスの HTTP Route 設定が作成されました。
イングレスのIPとポートの確認
すべての Gateway
は、LoadBalancerタイプのサービス によって支えられています。このサービスの外部ロードバランサーのIPとポートは、ゲートウェイへのアクセスに使用されます。LoadBalancer
タイプのKubernetesサービスは、ほとんどのクラウドプラットフォームで実行されているクラスタではデフォルトでサポートされていますが、一部の環境(例:テスト)では、次の操作が必要になる場合があります。
minikube
- 別のターミナルで次のコマンドを実行して、外部ロードバランサーを起動します。$ minikube tunnel
kind
-LoadBalancer
タイプのサービスを動作させるには、MetalLBのセットアップガイド に従ってください。その他のプラットフォーム - MetalLB を使用して、
LoadBalancer
サービスのEXTERNAL-IP
を取得できる場合があります。
便宜上、イングレスのIPとポートを環境変数に格納し、後続の手順で使用します。以下の手順に従って、INGRESS_HOST
および INGRESS_PORT
環境変数を設定します。
Istioイングレスゲートウェイがクラスタ内に配置されている名前と名前空間に、次の環境変数を設定します。
$ export INGRESS_NAME=istio-ingressgateway
$ export INGRESS_NS=istio-system
Kubernetesクラスタが外部ロードバランサーをサポートする環境にあるかどうかを判断するには、次のコマンドを実行します。
$ kubectl get svc "$INGRESS_NAME" -n "$INGRESS_NS"
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
istio-ingressgateway LoadBalancer 172.21.109.129 130.211.10.121 ... 17h
EXTERNAL-IP
値が設定されている場合、環境にはイングレスゲートウェイに使用できる外部ロードバランサーがあります。EXTERNAL-IP
値が <none>
(または永久に <pending>
)の場合、環境はイングレスゲートウェイの外部ロードバランサーを提供していません。
環境が外部ロードバランサーをサポートしていない場合は、イングレスゲートウェイにノードポートを使用してアクセスすることを試すことができます。それ以外の場合は、次のコマンドを使用してイングレスのIPとポートを設定します。
$ export INGRESS_HOST=$(kubectl -n "$INGRESS_NS" get service "$INGRESS_NAME" -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
$ export INGRESS_PORT=$(kubectl -n "$INGRESS_NS" get service "$INGRESS_NAME" -o jsonpath='{.spec.ports[?(@.name=="http2")].port}')
$ export SECURE_INGRESS_PORT=$(kubectl -n "$INGRESS_NS" get service "$INGRESS_NAME" -o jsonpath='{.spec.ports[?(@.name=="https")].port}')
$ export TCP_INGRESS_PORT=$(kubectl -n "$INGRESS_NS" get service "$INGRESS_NAME" -o jsonpath='{.spec.ports[?(@.name=="tcp")].port}')
httpbinゲートウェイリソースからゲートウェイのアドレスとポートを取得します。
$ export INGRESS_HOST=$(kubectl get gtw httpbin-gateway -o jsonpath='{.status.addresses[0].value}')
$ export INGRESS_PORT=$(kubectl get gtw httpbin-gateway -o jsonpath='{.spec.listeners[?(@.name=="http")].port}')
イングレスサービスへのアクセス
curl を使用して httpbin サービスにアクセスします。
$ curl -s -I -HHost:httpbin.example.com "http://$INGRESS_HOST:$INGRESS_PORT/status/200" ... HTTP/1.1 200 OK ... server: istio-envoy ...
-H
フラグを使用して、Host HTTPヘッダーを「httpbin.example.com」に設定していることに注意してください。これは、イングレスGateway
が「httpbin.example.com」を処理するように設定されていますが、テスト環境ではそのホストのDNSバインディングがなく、リクエストをイングレスIPに送信しているだけなので、必要です。明示的に公開されていない他のURLにアクセスします。HTTP 404エラーが表示されるはずです。
$ curl -s -I -HHost:httpbin.example.com "http://$INGRESS_HOST:$INGRESS_PORT/headers" HTTP/1.1 404 Not Found ...
ブラウザを使用したイングレスサービスへのアクセス
curl
のようにブラウザに Host ヘッダーを渡すことができないため、ブラウザで httpbin
サービスのURLを入力しても機能しません。実際の状況では、リクエストされたホストを正しく設定し、DNSで解決できるようにするため、これは問題になりません。したがって、URLにはホストのドメイン名を使用します(例:https://httpbin.example.com/status/200
)。
簡単なテストとデモでは、次のようにこの問題を回避できます。
Gateway
および VirtualService
設定のホストにワイルドカード *
値を使用します。たとえば、イングレス設定を次のように変更します。
$ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1
kind: Gateway
metadata:
name: httpbin-gateway
spec:
# The selector matches the ingress gateway pod labels.
# If you installed Istio using Helm following the standard documentation, this would be "istio=ingress"
selector:
istio: ingressgateway
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "*"
---
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: httpbin
spec:
hosts:
- "*"
gateways:
- httpbin-gateway
http:
- match:
- uri:
prefix: /headers
route:
- destination:
port:
number: 8000
host: httpbin
EOF
Gateway
および HTTPRoute
設定からホスト名を削除すると、それらはすべてのリクエストに適用されます。たとえば、イングレス設定を次のように変更します。
$ kubectl apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: httpbin-gateway
spec:
gatewayClassName: istio
listeners:
- name: http
port: 80
protocol: HTTP
allowedRoutes:
namespaces:
from: Same
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: httpbin
spec:
parentRefs:
- name: httpbin-gateway
rules:
- matches:
- path:
type: PathPrefix
value: /headers
backendRefs:
- name: httpbin
port: 8000
EOF
その後、ブラウザのURLで $INGRESS_HOST:$INGRESS_PORT
を使用できます。たとえば、http://$INGRESS_HOST:$INGRESS_PORT/headers
は、ブラウザが送信するすべてのヘッダーを表示します。
何が起こったかの理解
Gateway
設定リソースにより、外部トラフィックがIstioサービスメッシュに流入し、Istioのトラフィック管理およびポリシー機能をエッジサービスで使用できるようになります。
前の手順では、サービスメッシュ内にサービスを作成し、サービスのHTTPエンドポイントを外部トラフィックに公開しました。
イングレスゲートウェイサービスのノードポートの使用
環境が外部ロードバランサーをサポートしていない場合でも、istio-ingressgateway
サービスの ノードポート を使用することで、Istioの一部の機能を試すことができます。
イングレスポートを設定します。
$ export INGRESS_PORT=$(kubectl -n "${INGRESS_NS}" get service "${INGRESS_NAME}" -o jsonpath='{.spec.ports[?(@.name=="http2")].nodePort}')
$ export SECURE_INGRESS_PORT=$(kubectl -n "${INGRESS_NS}" get service "${INGRESS_NAME}" -o jsonpath='{.spec.ports[?(@.name=="https")].nodePort}')
$ export TCP_INGRESS_PORT=$(kubectl -n "${INGRESS_NS}" get service "${INGRESS_NAME}" -o jsonpath='{.spec.ports[?(@.name=="tcp")].nodePort}')
イングレスIPの設定は、クラスタプロバイダーによって異なります。
GKE
$ export INGRESS_HOST=worker-node-address
ingressgateway サービスのポートへのTCPトラフィックを許可するファイアウォールルールを作成する必要があります。HTTPポート、セキュアポート(HTTPS)、またはその両方のトラフィックを許可するには、次のコマンドを実行します。
$ gcloud compute firewall-rules create allow-gateway-http --allow "tcp:$INGRESS_PORT" $ gcloud compute firewall-rules create allow-gateway-https --allow "tcp:$SECURE_INGRESS_PORT"
IBM Cloud Kubernetes Service
$ ibmcloud ks workers --cluster cluster-name-or-id $ export INGRESS_HOST=public-IP-of-one-of-the-worker-nodes
Docker For Desktop
$ export INGRESS_HOST=127.0.0.1
その他の環境
$ export INGRESS_HOST=$(kubectl get po -l istio=ingressgateway -n "${INGRESS_NS}" -o jsonpath='{.items[0].status.hostIP}')
トラブルシューティング
INGRESS_HOST
およびINGRESS_PORT
環境変数の値を調べます。次のコマンドの出力に従って、有効な値が設定されていることを確認します。$ kubectl get svc -n istio-system $ echo "INGRESS_HOST=$INGRESS_HOST, INGRESS_PORT=$INGRESS_PORT"
同じポートに他のIstioイングレスゲートウェイが定義されていないことを確認します。
$ kubectl get gateway --all-namespaces
同じIPとポートにKubernetes Ingressリソースが定義されていないことを確認します。
$ kubectl get ingress --all-namespaces
外部ロードバランサーがあり、それが機能しない場合は、ノードポートを使用してゲートウェイにアクセスすることを試してください。
クリーンアップ
Gateway
および VirtualService
設定を削除し、httpbin サービスをシャットダウンします。
$ kubectl delete gateway httpbin-gateway
$ kubectl delete virtualservice httpbin
$ kubectl delete --ignore-not-found=true -f @samples/httpbin/httpbin.yaml@
Gateway
および HTTPRoute
設定を削除し、httpbin サービスをシャットダウンします。
$ kubectl delete httproute httpbin
$ kubectl delete gtw httpbin-gateway
$ kubectl delete --ignore-not-found=true -f @samples/httpbin/httpbin.yaml@