リクエスト・ルーティングの制御¶
このチュートリアルでは、Istioを使ってリクエスト・ルーティングの制御を体験します。カナリーデプロイメントのシナリオを想定して、複数バージョンが混在するアプリケーションのコンテナ群に対して、バージョン毎に流量を変えてルーティングしてみます。
前提条件¶
- Istioをインストール済みのKubernetesクラスター
- 上記クラスターに対して実行可能なKubernetes、Istioのコマンドラインツール(kubectl,istioctl)
Note
KubernetesクラスターへのIsitoのインストール手順は、Istioのインストールを参照してください。
以降の手順は、ほとんどの操作をコマンドラインツールから実行します。Mac/Linuxの場合はターミナル、Windowsの場合はWindows PowerShell利用するものとして、手順を記述します。
1. サンプルアプリケーションを配備する¶
このチュートリアルでは、サンプルアプリケーションとしてkubernetes-bootcampアプリケーションを使います。ここでは、リクエスト・ルーティングの制御を行う前に、このアプリケーションをIstioのSidecarなしでデプロイし、動作を確認しておきます。
1.1. Namespaceを作成する¶
以降のチュートリアルの手順で利用するNamespaceとして、"istio-routing"を作成しておきます。
kubectl create namespace istio-routing
デフォルトNamespaceを"istio-routing"に変更しておくことで、kubectlの実行の度にNamespaceを指定しなくても良いようにしておきます。
kubectl config set-context $(kubectl config current-context) --namespace=istio-routing
1.2. bootcampアプリケーションのデプロイ¶
このチュートリアルで利用するmanifestファイル一式をclone
し、出来上がったディレクトリをカレントディレクトリにしておきます。
Mac / Linux
git clone https://github.com/cndjp/istio-request-routing && cd istio-request-routing
Windows
git clone https://github.com/cndjp/istio-request-routing; cd istio-request-routing
続いて、bootcampアプリケーションをデプロイします。
kubectl create -f ./bootcamp.yaml
Podの一覧を表示して、version 1のPodが2つ、varsion 2のPodが1つデプロイされていることを確認してください。
kubectl get pods
正しくPodがデプロイされていれば、以下のような結果が表示されます。
NAME READY STATUS RESTARTS AGE bootcamp-v1-68cb78f87c-l8szm 1/1 Running 0 42s bootcamp-v1-68cb78f87c-zlmqh 1/1 Running 0 42s bootcamp-v2-569574d79f-w4p6g 1/1 Running 0 41s
次に、クラスター外からアプリケーションにアクセスできるようにするために、ServiceおよびIngressオブジェクトを作成します。
Serviceオブジェクトを作成するには以下のコマンドを実行します。
kubectl create -f ./bootcamp-service.yaml
Ingressオブジェクトを作成するには以下のコマンドを実行します。
kubectl create -f ./bootcamp-ingress.yaml
Note
ここではIngress Cotrollerとして、Istioに付属のIstio Ingress Cotrollerを利用します。Ingressオブジェクトを作成すると、その設定内容に合わせてIngress ControllerがL7ロードバランサとして機能します。これによって、クラスター外からのリクエストをアプリケーションに届けることができます。
1.3. bootcampアプリケーションへのアクセスの確認¶
Ingress Controller経由でのアプリケーションへのアクセスを試行してみます。
まず、Ingress ControllerのPodが配備されているNodeのIPアドレスと、公開されているPort番号を取得して、GATEWAY_URLという環境変数に格納しておきます。
Mac / Linux
export GATEWAY_URL=$(kubectl get po -l istio=ingress -n istio-system -o 'jsonpath={.items[0].status.hostIP}'):$(kubectl get svc istio-ingress -n istio-system -o 'jsonpath={.spec.ports[0].nodePort}')
Windows
$GATEWAY_URL=$(kubectl get po -l istio=ingress -n istio-system -o jsonpath='{.items[0].status.hostIP}') + ':'+ $(kubectl get svc istio-ingress -n istio-system -o jsonpath='{.spec.ports[0].nodePort}')
GATEWAY_URLを表示して、[IPアドレス]:[ポート番号]の形式で実際の値が格納されていることを確認してみてください。
echo $GATEWAY_URL
次に、取得したURLの末尾に"/bootcamp"を追加して、その宛先に対してリクエストを送信します。Pod名とアプリケーションのバージョン番号が返却されることを確認してください。
Mac / Linux
curl http://$GATEWAY_URL/bootcamp
Windows
Invoke-RestMethod -Uri "http://$GATEWAY_URL/bootcamp"
この時点では、トラフィックの制御を何も行っていないため、3つのPodに対して均等の割合でルーティングされます。リクエストの送信を繰り返し実行すると、おおよそ2/3がv1、1/3がv2からの応答となります。
以上で、サンプルアプリケーションの配備は完了です。
2. Istioによるリクエスト・ルーティングの制御をおこなう¶
それでは、Istioを使ったリクエスト・ルーティングの制御を実際におこなってみます。
2.1. bootcampアプリケーションのPodをEnvoyを注入したものに置き換える¶
ここまでの手順でデプロイしたアプリケーションは、Kubernetesの通常の方法でデプロイしているため、PodにEnvoyプロキシを含んでいません。まずは、これをEnvoyを含むものに置き換えます。
以下のコマンドで、一度bootcampアプリケーションを削除します。
kubectl delete -f ./bootcamp.yaml
次に、istioctlを使って、bootcampアプリケーションのmanifestファイルにEnvoyの記述を追加します。
istioctl kube-inject --debug -f ./bootcamp.yaml -o ./bootcamp-istio.yaml
新たに作成された、Envoyプロキシ注入後のmanifestファイルの内容を参照してみます。
cat ./bootcamp-istio.yaml
以下は、v1のbootcampアプリケーションに当たる部分を抜粋したものです。主要な追記箇所をハイライトしています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 | apiVersion: apps/v1beta1 kind: Deployment metadata: creationTimestamp: null name: bootcamp-v1 spec: replicas: 2 selector: matchLabels: app: bootcamp strategy: {} template: metadata: + annotations: + sidecar.istio.io/status: '{"version":"15bbcd92b59e99a83360c48bd7af9e84ffd5b961b914e8febcee0e38d08b773e","initContainers":["istio-init","enable-core-dump"],"containers":["istio-proxy"],"volumes":["istio-envoy","istio-certs"]}' creationTimestamp: null labels: app: bootcamp version: v1 spec: containers: - image: docker.io/jocatalin/kubernetes-bootcamp:v1 name: bootcamp ports: - containerPort: 8080 resources: {} + - args: + - proxy + - sidecar + - --configPath + - /etc/istio/proxy + - --binaryPath + - /usr/local/bin/envoy + - --serviceCluster + - bootcamp + - --drainDuration + - 45s + - --parentShutdownDuration + - 1m0s + - --discoveryAddress + - istio-pilot.istio-system:8080 + - --discoveryRefreshDelay + - 1s + - --zipkinAddress + - zipkin.istio-system:9411 + - --connectTimeout + - 10s + - --statsdUdpAddress + - istio-mixer.istio-system:9125 + - --proxyAdminPort + - "15000" + - --controlPlaneAuthPolicy + - NONE + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: INSTANCE_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + image: docker.io/istio/proxy_debug:0.7.1 + imagePullPolicy: IfNotPresent + name: istio-proxy + resources: {} + securityContext: + privileged: true + readOnlyRootFilesystem: false + runAsUser: 1337 + volumeMounts: + - mountPath: /etc/istio/proxy + name: istio-envoy + - mountPath: /etc/certs/ + name: istio-certs + readOnly: true + initContainers: + - args: + - -p + - "15001" + - -u + - "1337" + image: docker.io/istio/proxy_init:0.7.1 + imagePullPolicy: IfNotPresent + name: istio-init + resources: {} + securityContext: + capabilities: + add: + - NET_ADMIN + privileged: true + - args: + - -c + - sysctl -w kernel.core_pattern=/etc/istio/proxy/core.%e.%p.%t && ulimit -c + unlimited + command: + - /bin/sh + image: alpine + imagePullPolicy: IfNotPresent + name: enable-core-dump + resources: {} + securityContext: + privileged: true + volumes: + - emptyDir: + medium: Memory + name: istio-envoy + - name: istio-certs + secret: + optional: true + secretName: istio.default +status: {} |
追記箇所のポイントを挙げると、以下の2点があります。
- {.spec.template.spec.containers}以下に、istio-proxyという名前のコンテナが追加されており、これがEnvoyプロキシの実態となる。また、Envoyプロキシが利用するための環境変数の記述も併せて追加されている
- {.spec.template.spec.initContainers}以下に、istio-init, enable-core-dumpという名前のinitContainerが追加されている
Note
initContainerは、Podのデプロイ時に前処理を行うために利用するコンテナで、これはKubernetesが持っている機能です。
前処理でしか使わないバイナリをinitContainerに集めておく、前処理でしか必要ない権限はinitContainerだけに与える、などをおこなうことで、本体のContainerを必要最低限の機能に絞り込んだものにすることができます。
上の例で、istio-initはEnvoyプロキシが利用するためのiptablesのルールの設定をおこなうもの、enable-core-dumpはコアダンプの出力の設定をおこなうものです。
それでは、このmanifestを使って、bootcampアプリケーションをデプロイします。
kubectl create -f ./bootcamp-istio.yaml
2.2. リクエスト・ルーティングの制御を行う¶
それでは、実際にトラフィックの流量制御を行います。
まずは、全てのトラフィックをv1に振り分けてみます。トラフィックのルールはIstio用のmanifestファイルとして記述することができます。実際のmanifestファイルの内容は以下のようになっています。
cat ./bootcamp-route-rule-all-v1.yaml
1 2 3 4 5 6 7 8 9 10 11 12 | apiVersion: config.istio.io/v1alpha2 kind: RouteRule metadata: name: bootcamp-default spec: destination: name: bootcamp precedence: 1 route: - labels: version: v1 weight: 100 |
{.spec.route}に具体的なルーティングのルールを記述しています。この場合、bootcampというServiceがルーティング対象とするPodで、version: v1というlabelが設定されているものに、全てのトラフィックを送るようにしています。
このルールを適用するには、以下のコマンドを実行します。
istioctl create -n istio-routing -f ./bootcamp-route-rule-all-v1.yaml
改めて、アプリケーションにリクエストを送信します。繰り返し実行してみて、全ての応答がv1から返却されることを確認してください。
Mac / Linux
curl http://$GATEWAY_URL/bootcamp
Windows
Invoke-RestMethod -Uri "http://${GATEWAY_URL}/bootcamp"
次に、v1,v2にトラフィックを均等に送るようにルールを変更します。 まずは、新たにデプロイするルールのmanifestファイルを参照してみます。
cat ./bootcamp-route-rule-50-v2.yaml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | apiVersion: config.istio.io/v1alpha2 kind: RouteRule metadata: name: bootcamp-default spec: destination: name: bootcamp precedence: 1 route: - labels: version: v1 weight: 50 - labels: version: v2 weight: 50 |
このmanifestでは、v1,v2それぞれにweight: 50を記述することで、それぞれのバージョンに均等にトラフィックが送信されるようにしています。
それでは、このルールをデプロイします。以下のようなistioctl replace
コマンドをを使ってルールの置き換えをおこないます。
istioctl replace -n istio-routing -f ./bootcamp-route-rule-50-v2.yaml
再度リクエストの送信を繰り返して、v1とv2からの応答がおおよそ同じ割合で返ってくることを確認してください。
最後に、v2に全てのトラフィックをルーティングするように、ルールを変更します。
istioctl replace -n istio-routing -f ./bootcamp-route-rule-all-v2.yaml
今度は、応答が全てv2からのものになっていることを確認してください。
3. クリーンアップ¶
これまで作ってきたオブジェクトをクリーンアップしたい場合は、以下のコマンドを実行して、作成したオブジェクトを削除してください。
istioctl delete -n istio-routing -f ./bootcamp-route-rule-all-v2.yaml
kubectl delete namespace istio-routing
以上で本チュートリアルは終了です。