Istioエグレスゲートウェイを使用したレガシーサービスのプロキシ
メッシュからのエグレス通信をきめ細かく制御するために、複数のIstioエグレスゲートウェイを独立してデプロイします。
Deutsche Telekom Pan-Netでは、サービスを包括するためにIstioを採用しています。残念ながら、まだKubernetesに移行されていない、または移行できないサービスがあります。
これらのアップストリームサービスに対するプロキシサービスとしてIstioを設定できます。これにより、レガシーサービスがそのままの状態であっても、認証/認可、トレーサビリティ、可観測性などの機能を利用できます。
この記事の最後には、シナリオをシミュレートできる実践的な演習があります。演習では、https://httpbin.orgでホストされているアップストリームサービスがIstioエグレスゲートウェイによってプロキシされます。
Istioに詳しい方であれば、アップストリームサービスに接続するために提供される方法の1つがエグレスゲートウェイであることはご存知でしょう。
すべてのアップストリームトラフィックを制御するために1つデプロイすることも、きめ細かい制御を行い、この図に示すように単一責任の原則を満たすために複数デプロイすることもできます。
このモデルでは、1つのエグレスゲートウェイが1つのアップストリームサービスを正確に担当します。
Operatorの仕様では複数のエグレスゲートウェイをデプロイできますが、マニフェストが管理しにくくなる可能性があります。
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
[...]
spec:
egressGateways:
- name: egressgateway-1
enabled: true
- name: egressgateway-2
enabled: true
[egressgateway-3, egressgateway-4, ...]
- name: egressgateway-N
enabled: true
[...]
エグレスゲートウェイをOperatorマニフェストから切り離すことで、サービス(ゲートウェイとアップストリームサービス)の両方を整合させるために、カスタムの readiness プローブを設定できるようになります。
また、OPAをサイドカーとしてポッドに注入して、複雑なルールで認証を実行することもできます(OPA Envoyプラグイン)。
ご覧のとおり、可能性が広がり、Istioは非常に拡張性が高くなります。
このパターンを実装する方法を見てみましょう。
ソリューション
このタスクを実行する方法はいくつかありますが、ここでは複数のOperatorを定義し、生成されたリソースをデプロイする方法を紹介します。
次のセクションでは、アップストリームサービス: httpbin
(https://httpbin.org/)に接続するためのエグレスゲートウェイをデプロイします。
最終的に、次のものが得られます
実践
前提条件
Kind
これをconfig.yaml
として保存します。
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
kubeadmConfigPatches:
- |
apiVersion: kubeadm.k8s.io/v1beta2
kind: ClusterConfiguration
metadata:
name: config
apiServer:
extraArgs:
"service-account-issuer": "kubernetes.default.svc"
"service-account-signing-key-file": "/etc/kubernetes/pki/sa.key"
$ kind create cluster --name <my-cluster-name> --config config.yaml
ここで、<my-cluster-name>
はクラスターの名前です。
Istioctlを使用したIstio Operator
Operatorをインストールします
$ istioctl operator init --watchedNamespaces=istio-operator
$ kubectl create ns istio-system
これをoperator.yaml
として保存します。
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
metadata:
name: istio-operator
namespace: istio-operator
spec:
profile: default
tag: 1.8.0
meshConfig:
accessLogFile: /dev/stdout
outboundTrafficPolicy:
mode: REGISTRY_ONLY
$ kubectl apply -f operator.yaml
エグレスゲートウェイのデプロイ
このタスクの手順では、次のことを前提としています。
- サービスは名前空間:
httpbin
の下にインストールされます。 - サービス名は:
http-egress
です。
Istio 1.8では、作成されたリソースをきめ細かく制御するために、オーバーレイ構成を適用する機能が導入されました。
これをegress.yaml
として保存します。
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
profile: empty
tag: 1.8.0
namespace: httpbin
components:
egressGateways:
- name: httpbin-egress
enabled: true
label:
app: istio-egressgateway
istio: egressgateway
custom-egress: httpbin-egress
k8s:
overlays:
- kind: Deployment
name: httpbin-egress
patches:
- path: spec.template.spec.containers[0].readinessProbe
value:
failureThreshold: 30
exec:
command:
- /bin/sh
- -c
- curl https://#:15021/healthz/ready && curl https://httpbin.org/status/200
initialDelaySeconds: 1
periodSeconds: 2
successThreshold: 1
timeoutSeconds: 1
values:
gateways:
istio-egressgateway:
runAsRoot: true
エグレスゲートウェイをインストールする名前空間を作成します
$ kubectl create ns httpbin
ドキュメントで説明されているように、複数のOperatorリソースをデプロイできます。ただし、事前に解析してからクラスターに適用する必要があります。
$ istioctl manifest generate -f egress.yaml | kubectl apply -f -
Istioの設定
次に、https://httpbin.orgのアップストリームサービスへの接続を許可するようにIstioを設定します。
TLSの証明書
クラスター外部からエグレスサービスへの安全な接続を行うには、証明書が必要です。
証明書の生成方法については、Istio イングレスドキュメントで説明しています。
この記事の最後に、クラスター外部からサービスにアクセスするために使用する証明書を作成して適用します(<my-proxied-service-hostname>
)
$ kubectl create -n istio-system secret tls <my-secret-name> --key=<key> --cert=<cert>
ここで、<my-secret-name>
はGateway
リソースに使用される名前です。<key>
と<cert>
は証明書のファイルです。<cert>
。
イングレスゲートウェイ
リクエストを受け入れるようにイングレスゲートウェイを操作するためのGateway
リソースを作成します。
例
apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
name: my-ingressgateway
namespace: istio-system
spec:
selector:
istio: ingressgateway
servers:
- hosts:
- "<my-proxied-service-hostname>"
port:
name: http
number: 80
protocol: HTTP
tls:
httpsRedirect: true
- port:
number: 443
name: https
protocol: https
hosts:
- "<my-proxied-service-hostname>"
tls:
mode: SIMPLE
credentialName: <my-secret-name>
ここで、<my-proxied-service-hostname>
はmy-ingressgateway
を介してサービスにアクセスするためのホスト名であり、<my-secret-name>
は証明書を含むシークレットです。
エグレスゲートウェイ
別のGatewayオブジェクトを作成しますが、今回はすでにインストールしたエグレスゲートウェイを操作するためのものです
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: "httpbin-egress"
namespace: "httpbin"
spec:
selector:
istio: egressgateway
service.istio.io/canonical-name: "httpbin-egress"
servers:
- hosts:
- "<my-proxied-service-hostname>"
port:
number: 80
name: http
protocol: HTTP
ここで、<my-proxied-service-hostname>
はmy-ingressgateway
を介してアクセスするためのホスト名です。
Virtual Service
3つのユースケースに対応するVirtualService
を作成します。
- メッシュ内のサービス間通信用のメッシュゲートウェイ
- メッシュ外部からの通信用のイングレスゲートウェイ
- アップストリームサービスへの通信用のエグレスゲートウェイ
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: "httpbin-egress"
namespace: "httpbin"
spec:
hosts:
- "<my-proxied-service-hostname>"
gateways:
- mesh
- "istio-system/my-ingressgateway"
- "httpbin/httpbin-egress"
http:
- match:
- gateways:
- "istio-system/my-ingressgateway"
- mesh
uri:
prefix: "/"
route:
- destination:
host: "httpbin-egress.httpbin.svc.cluster.local"
port:
number: 80
- match:
- gateways:
- "httpbin/httpbin-egress"
uri:
prefix: "/"
route:
- destination:
host: "httpbin.org"
subset: "http-egress-subset"
port:
number: 443
ここで、<my-proxied-service-hostname>
はmy-ingressgateway
を介してアクセスするためのホスト名です。
Service Entry
アップストリームサービスへの通信を許可するためのServiceEntry
を作成します
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
name: "httpbin-egress"
namespace: "httpbin"
spec:
hosts:
- "httpbin.org"
location: MESH_EXTERNAL
ports:
- number: 443
name: https
protocol: TLS
resolution: DNS
Destination Rule
ドキュメントで説明されているように、エグレストラフィックのTLSオリジネーションを許可するためのDestinationRule
を作成します
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: "httpbin-egress"
namespace: "httpbin"
spec:
host: "httpbin.org"
subsets:
- name: "http-egress-subset"
trafficPolicy:
loadBalancer:
simple: ROUND_ROBIN
portLevelSettings:
- port:
number: 443
tls:
mode: SIMPLE
ピア認証
サービス間を安全にするには、mTLSを強制する必要があります
apiVersion: "security.istio.io/v1beta1"
kind: "PeerAuthentication"
metadata:
name: "httpbin-egress"
namespace: "httpbin"
spec:
mtls:
mode: STRICT
テスト
オブジェクトがすべて正しく指定されていることを確認します
$ istioctl analyze --all-namespaces
外部アクセス
ingressgateway
サービスのポートを転送し、サービスを呼び出して、クラスター外部からエグレスゲートウェイをテストします
$ kubectl -n istio-system port-forward svc/istio-ingressgateway 15443:443
$ curl -vvv -k -HHost:<my-proxied-service-hostname> --resolve "<my-proxied-service-hostname>:15443:127.0.0.1" --cacert <cert> "https://<my-proxied-service-hostname>:15443/status/200"
ここで、<my-proxied-service-hostname>
はmy-ingressgateway
を介してアクセスするためのホスト名であり、<cert>
はingressgateway
オブジェクト用に定義された証明書です。これは、TLSを終端しないtls.mode: SIMPLE
が原因です
サービス間アクセス
スリープサービスをデプロイして、クラスター内からエグレスゲートウェイをテストします。これはフェイルオーバーを設計する場合に役立ちます。
$ kubectl label namespace httpbin istio-injection=enabled --overwrite
$ kubectl apply -n httpbin -f https://raw.githubusercontent.com/istio/istio/release-1.24/samples/sleep/sleep.yaml
$ kubectl -n httpbin "$(kubectl get pod -n httpbin -l app=sleep -o jsonpath={.items..metadata.name})" -- curl -vvv http://<my-proxied-service-hostname>/status/200
ここで、<my-proxied-service-hostname>
はmy-ingressgateway
を介してアクセスするためのホスト名です。
次に、他のアップストリームサービスを指す2番目、3番目、4番目のエグレスゲートウェイを作成します。
終わりに
Istioは構成が複雑に見えるかもしれません。しかし、サービスにもたらす大きなメリット(Kialiにもオレー!)を考えると、間違いなく価値があります。
Istioの開発方法により、この記事で紹介したような特殊な要件を最小限の労力で満たすことができます。
最後に、優れたクラウドネイティブテクノロジーとしてのIstioは、大規模なチームによる保守を必要としないことを指摘しておきたいと思います。たとえば、現在のチームは3人のエンジニアで構成されています。
Istioとその可能性についてさらに議論するには、私たちの一人にご連絡ください