KubernetesでLoad BalancerとしてEnvoyを試した
こちらでEnvoyを一通り学習しました。
www.katacoda.com
理解できているかの確認のために、KubernetesでEnvoyを使ってみます。
KubernetesでEnvoyを使う場合、EnvoyをSidecarプロキシにすることで各Podの通信をコントロールする構成が知られています。
サービスメッシュを実現するIstioはそのような構成になっています。
このような最新のシステム構成を理解するためにもEnvoyの理解を深めることが求められていると感じています。
今回はPodへの通信の前段にEnvoyを配置する単純な構成を試しました。
前提
Docker for MacのKubernetes環境で動作確認しています。
構成について
バージョン2とバージョン3のアプリケーションが存在します。
2つのアプリケーションのロードバランサーとしてEnvoyが前段に存在します。
一部の通信をバージョン3に向ける処理をEnvoyが行います。
デプロイするアプリケーションについて
HTTPの通信を受け付けるNode.jsのアプリケーションです。
KubernetesとEnvoyを組み合わせるために、KubernetesのHeadless Serviceを利用します。
Headless Serviceを使うことでEnvoyでService Discoveryが可能になります。
デプロイを行うためのKubernetesのManifestを示します。
下記ではバージョン2とバージョン3のアプリケーションをデプロイします。
nodejs-http-server.yaml
apiVersion: apps/v1 kind: Deployment metadata: name: nodejs-http-server-v2 spec: replicas: 1 selector: matchLabels: app: nodejs-http-server-v2 template: metadata: labels: app: nodejs-http-server-v2 spec: containers: - name: nodejs-http-server-v2 image: hi1280/nodejs-http-server:0.0.2 ports: - containerPort: 3000 --- apiVersion: apps/v1 kind: Deployment metadata: name: nodejs-http-server-v3 spec: replicas: 1 selector: matchLabels: app: nodejs-http-server-v3 template: metadata: labels: app: nodejs-http-server-v3 spec: containers: - name: nodejs-http-server-v3 image: hi1280/nodejs-http-server:0.0.3 ports: - containerPort: 3000
アプリケーションに繋がるHeadless Serviceを作ります。
clusterIPにNoneを指定します。
nodejs-http-server.yaml
apiVersion: v1 kind: Service metadata: name: nodejs-http-server-v2 spec: clusterIP: None ports: - protocol: TCP port: 3000 targetPort: 3000 selector: app: nodejs-http-server-v2 --- apiVersion: v1 kind: Service metadata: name: nodejs-http-server-v3 spec: clusterIP: None ports: - protocol: TCP port: 3000 targetPort: 3000 selector: app: nodejs-http-server-v3
Envoyをデプロイする
Envoyをデプロイします。
envoyの公式のDockerイメージを使ってenvoyを起動します。
my-envoy.yaml
apiVersion: apps/v1 kind: Deployment metadata: name: my-envoy labels: app: my-envoy spec: selector: matchLabels: app: my-envoy template: metadata: labels: app: my-envoy spec: containers: - name: my-envoy image: envoyproxy/envoy:latest volumeMounts: - name: config-volume mountPath: /etc/envoy ports: - name: http containerPort: 8080 - name: envoy-admin containerPort: 9901 volumes: - name: config-volume configMap: name: my-envoy
/etc/envoy
にenvoy.yaml
を配置すると、そのファイルに定義されたenvoyの設定が読み込まれます。
envoy.yaml
を作成するのにConfigMapを使用しています。
ConfigMapでenvoy.yamlを作成します。
my-envoy.yaml
apiVersion: v1 kind: ConfigMap metadata: name: my-envoy data: envoy.yaml: | admin: access_log_path: /tmp/admin_access.log address: socket_address: { address: 0.0.0.0, port_value: 9901 } static_resources: listeners: - name: listener_0 address: socket_address: { address: 0.0.0.0, port_value: 8080 } filter_chains: - filters: - name: envoy.http_connection_manager config: codec_type: auto stat_prefix: ingress_http route_config: name: local_route virtual_hosts: - name: backend domains: ["*"] routes: - match: prefix: "/" route: weighted_clusters: clusters: - name: v2 weight: 80 - name: v3 weight: 20 http_filters: - name: envoy.router clusters: - name: v2 connect_timeout: 0.25s type: STRICT_DNS dns_lookup_family: V4_ONLY lb_policy: ROUND_ROBIN hosts: [{ socket_address: { address: nodejs-http-server-v2, port_value: 3000 }}] - name: v3 connect_timeout: 0.25s type: STRICT_DNS dns_lookup_family: V4_ONLY lb_policy: ROUND_ROBIN hosts: [{ socket_address: { address: nodejs-http-server-v3, port_value: 3000 }}]
route_configの設定でHTTPのルーティングを決めています。
アプリケーションのバージョン2への通信を8割、バージョン3への通信を2割にするようにトラフィックの制御を行なっています。
clustersの設定でアプリケーションの宛先を決めています。
nodejs-http-server-v2
やnodejs-http-server-v3
のHost名になっています。
これはHeadless Serviceによって解決されます。
最後にNodePortでenvoyを外部に公開します。
my-envoy.yaml
apiVersion: v1 kind: Service metadata: name: my-envoy labels: app: my-envoy spec: type: NodePort ports: - name: http port: 80 targetPort: 8080 protocol: TCP selector: app: my-envoy
動作確認する
curlで動作確認します。
公開されるポート番号はランダムに決められますので、kubectl get svc
で確認します。
$ for i in {1..10}; do curl -s http://localhost:30392; done Now v2. This request was processed by host: nodejs-http-server-v2-855b645dcd-x68x6 Now v2. This request was processed by host: nodejs-http-server-v2-855b645dcd-x68x6 Now v2. This request was processed by host: nodejs-http-server-v2-855b645dcd-x68x6 Now v2. This request was processed by host: nodejs-http-server-v2-855b645dcd-x68x6 Now v2. This request was processed by host: nodejs-http-server-v2-855b645dcd-x68x6 Now v2. This request was processed by host: nodejs-http-server-v2-855b645dcd-x68x6 Now v2. This request was processed by host: nodejs-http-server-v2-855b645dcd-x68x6 Now v3. This request was processed by host: nodejs-http-server-v3-7d66cbd7c7-fcq98 Now v2. This request was processed by host: nodejs-http-server-v2-855b645dcd-x68x6 Now v2. This request was processed by host: nodejs-http-server-v2-855b645dcd-x68x6
おおよそ決めた割合で通信が分けられていることが確認できます。
まとめ
今回はEnvoyをLoad Balancer的に使うやり方を理解できました。
これを踏まえるとEnvoyをSidecarプロキシとして利用する構成が理解しやすいのではないでしょうか。