LoginSignup
1
2

IstioのMesh内に仮想マシンを取り込む

Last updated at Posted at 2024-01-31

あまり知られていないような気がするが、Istioは仮想マシン(VM)もMeshに取り込むことが出来る。
これを利用すると以下のような事が出来るようになる。

  • Istioで保護されたネットワーク内でPod↔VM間通信が出来るようになる
    →DBだけVMを使いたいようなケースでもMeshを利用することが出来る
  • VM側でKubernetesの名前を使ってクラスタ内のサービスにアクセスできる 
    (例:curl nginx.mynamespace.svcみたいなのが通るようになる)

めちゃくちゃ便利そうなので実際に構築して挙動を確認する。
ここではIstioのVirtual Machine Installationを参考に進める。

基礎知識

ネットワークをまたぐ構成でPodとVMを直接通信する場合のアーキテクチャは以下となる。
1706683040217.png
(引用元:Virtual Machine Architecture

IstiodはKubernetes側で用意し、DataplaneをVMに配置するような形となる。
PodとVM間はIstioのGatewayを介して通信する形となる。

注意点として、VM上に展開するサイドカーのパッケージが、RPMだとCentOS8しかサポートしていないようなので、試すならCentOS8を使うかUbuntu/Debian系のディストリビューションにしておく方が楽ができる。

前提

以下を用意する

  • Kubernetesクラスタ
  • VM
  • istioctl
  • istioctlのインストール時にダウンロードされるディレクトリ・ファイル一式

今回はKubernetesクラスタにvSphere with Tanzuで構築したKubernetesクラスタを使い、VMはUbuntuを使用した。

また検証するIstioの構成としては、

  • Multi Network(VMとKubernetesで別のネットワークを利用)
  • WorkloadEntry(後述)の自動作成を有効

の構成とする。

検証

事前準備

Multi Network構成ではspec.values.global.networkにKubernetes側のネットワーク名を適当に定義してIstioをインストールする。
インストールに使うYAMLファイルを作成する。

export CLUSTER=tkg-cluster-2
export CLUSTER_NETWORK=kube-network
cat << EOF > ./vm-cluster2.yaml
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
metadata:
  name: istio
spec:
  values:
    global:
      meshID: mesh1
      multiCluster:
        clusterName: "${CLUSTER}"
      network: "${CLUSTER_NETWORK}"
EOF

istioctlでインストールする。WorkloadEntryの自動作成を有効にするために設定用パラメータもコマンドラインに追加して実行する。

istioctl install -f vm-cluster2.yaml --set values.pilot.env.PILOT_ENABLE_WORKLOAD_ENTRY_AUTOREGISTRATION=true --set values.pilot.env.PILOT_ENABLE_WORKLOAD_ENTRY_HEALTHCHECKS=true -y

East-Westで通信するためのEast-West Gatewayをインストールする。

samples/multicluster/gen-eastwest-gateway.sh \
--mesh mesh1 --cluster "${CLUSTER}" --network "${CLUSTER_NETWORK}" | \
istioctl install -y -f -

Istiodを公開するためのkind: VirtualServicekind: Gatewayを作成し、Namespaceistio-systemにネットワークが複数ある場合にどのネットワークを使うかのラベルを付与する。

kubectl apply -n istio-system -f samples/multicluster/expose-istiod.yaml
kubectl apply -n istio-system -f samples/multicluster/expose-services.yaml
kubectl label namespace istio-system topology.istio.io/network="${CLUSTER_NETWORK}"

VMを管理するためのNamespaceServiceAccountを作成する。

kubectl create ns vmtest
kubectl create sa vmtestsa -n vmtest

次にWorkloadGroupを作成する。WorkloadGroupというのはMeshに追加するワークロード(VM)のグループを定義したものの模様。
Podに対するDeploymentのようなものらしい。
なお、Podに相当するものはWorkloadEntryになり、今回の手順ではこのWorkloadEntryを自動でつくる手筈で進めている。
WorkloadGroupの仕様はこちら参照。
ということで、以下で作成してクラスタに適用する。

cat <<EOF > workloadgroup.yaml
apiVersion: networking.istio.io/v1alpha3
kind: WorkloadGroup
metadata:
  name: "ubuntu"
  namespace: "vmtest"
spec:
  metadata:
    labels:
      app: "ubuntu"
  template:
    serviceAccount: "vmtestsa"
    network: "${CLUSTER_NETWORK}"
EOF
kubectl apply -f workloadgroup.yaml -n vmtest

ちなみにWorkloadGroup側でVMにReadinessProbeみたいな感じでヘルスチェックを設定することも出来るが、ここでは割愛する。

作成したら、istioctlに食わせて設定ファイルを生成する。

mkdir vmfiles
istioctl x workload entry configure -f workloadgroup.yaml -o ./vmfiles --clusterID "${CLUSTER}" --autoregister

生成されたファイルはそれぞれ以下となる。

cluster.env サービス名やNamespaceなどの複数の環境変数を定義したファイル
istio-token CAから証明書を取得するのに使うKubernetesトークン
mesh.yaml discoveryAddressを設定するためのProxyConfig
root-cert.pem 認証に使用されるルート証明書
hosts /etc/hostsに追記する内容(istio-eastwestgatewayのExternal IPとistiod.istio-system.svcの組が記載)

ちなみにProxyConfigMeshConfigの違いはWorkloadやNamespace単位など細かな単位でも設定出来るのがProxyConfigで、Mesh全体への設定を行うのがMeshConfigだそう。

生成されたファイルをVMに転送する。

scp ./vmfiles/* ubuntu@10.215.76.71:

以上で下準備は終了となる。

VM側の設定

ルート証明書を配置する。

sudo mkdir -p /etc/certs
sudo cp ./root-cert.pem /etc/certs/root-cert.pem

Kubernetesトークンを配置する。

sudo  mkdir -p /var/run/secrets/tokens
sudo cp ./istio-token /var/run/secrets/tokens/istio-token

サイドカーをインストールする。なお、ここではDebian系のパッケージで入れたが、rpmも用意されている。(ただしCentOS8しかサポートしていない点に注意)

curl -LO https://storage.googleapis.com/istio-release/releases/1.20.2/deb/istio-sidecar.deb
sudo dpkg -i istio-sidecar.deb

ちなみにこれの中身は以下のようになっている。

$ dpkg-deb -c istio-sidecar.deb
drwxr-xr-x 0/0               0 2024-01-03 14:42 ./
drwxr-xr-x 0/0               0 2024-01-03 14:42 ./lib/
drwxr-xr-x 0/0               0 2024-01-03 14:42 ./lib/systemd/
drwxr-xr-x 0/0               0 2024-01-03 14:42 ./lib/systemd/system/
-rw-r--r-- 0/0             382 2024-01-03 14:37 ./lib/systemd/system/istio.service
drwxr-xr-x 0/0               0 2024-01-03 14:42 ./var/
drwxr-xr-x 0/0               0 2024-01-03 14:42 ./var/lib/
drwxr-xr-x 0/0               0 2024-01-03 14:42 ./var/lib/istio/
drwxr-xr-x 0/0               0 2024-01-03 14:42 ./var/lib/istio/envoy/
-rw-r--r-- 0/0            4818 2024-01-03 14:37 ./var/lib/istio/envoy/sidecar.env
-rw-r--r-- 0/0           22679 2024-01-03 14:37 ./var/lib/istio/envoy/envoy_bootstrap_tmpl.json
drwxr-xr-x 0/0               0 2024-01-03 14:42 ./usr/
drwxr-xr-x 0/0               0 2024-01-03 14:42 ./usr/local/
drwxr-xr-x 0/0               0 2024-01-03 14:42 ./usr/local/bin/
-rwxr-xr-x 0/0        44118016 2024-01-03 14:38 ./usr/local/bin/pilot-agent
-rwxr-xr-x 0/0            5847 2024-01-03 14:37 ./usr/local/bin/istio-start.sh
-rwxr-xr-x 0/0       114688376 2024-01-03 14:38 ./usr/local/bin/envoy
drwxr-xr-x 0/0               0 2024-01-03 14:42 ./usr/share/
drwxr-xr-x 0/0               0 2024-01-03 14:42 ./usr/share/doc/
drwxr-xr-x 0/0               0 2024-01-03 14:42 ./usr/share/doc/istio-sidecar/
-rw-r--r-- 0/0             133 2024-01-03 14:42 ./usr/share/doc/istio-sidecar/changelog.gz

また、パッケージインストール時にistio-proxyというユーザが作成される。

環境変数を定義したファイルをEnvoyのディレクトリにコピーする。

sudo cp ./cluster.env /var/lib/istio/envoy/cluster.env

ProxyConfigをIstioのMeshの設定ディレクトリにコピーする。

sudo cp ./mesh.yaml /etc/istio/config/mesh

istio-eastwestgatewayにアクセスするために/etc/hostsに追記する。

sudo sh -c 'cat $(eval echo ~$SUDO_USER)/hosts >> /etc/hosts'

istio-proxyユーザがディレクトリを参照できるようアクセス権を設定する。

sudo mkdir -p /etc/istio/proxy
sudo chown -R istio-proxy /var/lib/istio /etc/certs /etc/istio/proxy /etc/istio/config /var/run/secrets /etc/certs/root-cert.pem

以上でVM上でIstioのサイドカーを動かすための設定は終了となる。
次にIstioのサイドカーを起動する。

sudo systemctl start istio

起動すると以下のような感じのstatusとなる。

$ systemctl status istio
● istio.service - istio-sidecar: The Istio sidecar
     Loaded: loaded (/lib/systemd/system/istio.service; disabled; vendor preset: enabled)
     Active: active (running) since Mon 2024-01-29 07:40:15 UTC; 15s ago
       Docs: http://istio.io/
    Process: 24624 ExecStartPre=/usr/bin/install -d -o istio-proxy -m 0755 /var/run/secrets (code=exited, status=0/SUCCESS)
   Main PID: 24625 (sudo)
      Tasks: 16 (limit: 1012)
     Memory: 34.5M
        CPU: 2.934s
     CGroup: /system.slice/istio.service
             ├─24625 sudo -E -u istio-proxy -s /bin/bash -c "ulimit -n 1024; INSTANCE_IP=10.215.76.71 POD_NAME=ubuntuguest POD_NAMESPACE=vmtest exec /usr/local>
             ├─24711 /usr/local/bin/pilot-agent proxy
             └─24720 /usr/local/bin/envoy -c etc/istio/proxy/envoy-rev.json --drain-time-s 45 --drain-strategy immediate --local-address-ip-version v4 --file-f>

Jan 29 07:40:15 ubuntuguest istio-start.sh[24701]: -A ISTIO_OUTPUT -o lo -p tcp -m tcp ! --dport 53 -m owner ! --gid-owner 997 -j RETURN
Jan 29 07:40:15 ubuntuguest istio-start.sh[24701]: -A ISTIO_OUTPUT -m owner --gid-owner 997 -j RETURN
Jan 29 07:40:15 ubuntuguest istio-start.sh[24701]: -A ISTIO_OUTPUT -d 127.0.0.53/32 -p tcp -m tcp --dport 53 -j REDIRECT --to-ports 15053
Jan 29 07:40:15 ubuntuguest istio-start.sh[24701]: -A ISTIO_OUTPUT -d 127.0.0.1/32 -j RETURN
Jan 29 07:40:15 ubuntuguest istio-start.sh[24701]: -A ISTIO_OUTPUT -j ISTIO_REDIRECT
Jan 29 07:40:15 ubuntuguest istio-start.sh[24701]: -A ISTIO_REDIRECT -p tcp -j REDIRECT --to-ports 15001
Jan 29 07:40:15 ubuntuguest istio-start.sh[24701]: COMMIT
Jan 29 07:40:15 ubuntuguest istio-start.sh[24701]: # Completed on Mon Jan 29 07:40:15 2024
Jan 29 07:40:15 ubuntuguest sudo[24625]:     root : PWD=/ ; USER=istio-proxy ; COMMAND=/bin/bash -c '\\/bin\\/bash -c ulimit\\ -n\\ 1024\\;\\ INSTANCE_IP\\=10\>
Jan 29 07:40:15 ubuntuguest sudo[24625]: pam_unix(sudo:session): session opened for user istio-proxy(uid=997) by (uid=0)

ただし、正常にサービスが起動してもエラーとなってることもあるので、挙動がおかしいと思ったら/var/log/istio/istio.log/var/log/istio/istio.err.logを確認するとよい。
また、正常に起動すればistioctl proxy-statusホスト名.Namespace名で見えるようになる。

$ istioctl proxy-status
NAME                                                    CLUSTER           CDS        LDS        EDS        RDS          ECDS         ISTIOD                      VERSION
istio-eastwestgateway-6fdf6bdf69-tzssk.istio-system     tkg-cluster-2     SYNCED     SYNCED     SYNCED     NOT SENT     NOT SENT     istiod-75f9cbf8b7-249xh     1.20.2
istio-ingressgateway-846c5b8ccd-d7kwl.istio-system      tkg-cluster-2     SYNCED     SYNCED     SYNCED     NOT SENT     NOT SENT     istiod-75f9cbf8b7-249xh     1.20.2
ubuntuguest.vmtest                                      tkg-cluster-2     SYNCED     SYNCED     SYNCED     SYNCED       NOT SENT     istiod-75f9cbf8b7-249xh     1.20.2

また、クラスタ内にkind: WorkloadEntryのオブジェクトが自動生成されることも確認できる。

$ kubectl get workloadentries.networking.istio.io -n vmtest
NAME                  AGE    ADDRESS
ubuntu-10.215.76.71   4m3s   10.215.76.71

動作確認

ここではVMからPodへのアクセス、およびPodからVMへのアクセスを確認する。

まず、検証用にVMからアクセスする検証用のPod(nginx)を起動し公開する。

SAMPLE_NS=nginx-ns
kubectl create ns $SAMPLE_NS
kubectl label namespace $SAMPLE_NS istio-injection=enabled
kubectl run nginx --image nginx -n $SAMPLE_NS
kubectl expose pod nginx --port 80 -n $SAMPLE_NS

また、VMにアクセスするPod(CentOS)も用意する。

kubectl run --image centos centos -n nginx-ns -- sleep infinity

また、VM側でも検証用にHTTPサーバを構築する。
Pythonでhttp.serverモジュールを呼べばポート8000で公開してくれる。

python3 -m http.server &

このHTTPサーバにPodからアクセスするためにはKubernetes側でServiceを作成する必要があるので、以下のように作成する。

cat <<EOF | kubectl apply -f - 
apiVersion: v1
kind: Service
metadata:
  name: ubuntu-svc
  namespace: vmtest
  labels:
    app: ubuntu
spec:
  ports:
  - port: 8000
    name: tcp
  selector:
    app: ubuntu
EOF

以上で検証用のサービスの準備は完了となる。

まず、VMからPodへのアクセスを確認する。Pod間通信と同じ要領で先程作成したnginxのService(nginx.nginx-ns.svc)にアクセスする。

$ curl nginx.nginx-ns.svc
<!DOCTYPE html>
<html>
<head>
:(省略)

問題なくアクセスできた。
次は逆向き、KubernetesクラスタからVMにアクセスしてみる。
先程作成したUbuntu用のServiceにCentOSからアクセスする。

$ kubectl exec -it centos -n nginx-ns -- curl ubuntu-svc.vmtest.svc:8000
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
:(省略)

こちらも問題なくアクセスできた。

所感

今回はVMをMeshに追加してPodとVM間で通信する方法を確認した。
特にDNSなどの設定をせずにPodとVM間をKubernetes上の名前でアクセスできるのは非常に便利だと感じた。
ただ、以下あたりはちょっと課題なのかなとも感じた。

  • Control PlaneはKubernetes上に必要
    →Kubernetes抜きでの構成は組めなさそう
  • RedHat系のサポートOSがCentOS8のみ
    →エンタープライズ系のOSサポートが必要な環境だと利用が厳しい

上記の課題が将来的に解決できればService Meshの幅がかなり広がりそうなので、将来的に改善されることを期待したい。

おまけ:可視化

Kiali、Grafanaを入れて可視化してみる。
なお、本来はKubernetes内の名前を使ってVMのメトリクスを取りたかったのだが、PodからVMのメトリクスのエンドポイントへのアクセス時にエラーが出て断念し、VMのIPを直接叩いてメトリクスを取得した。
(起きた問題は多分これと同件っぽい)

まずメトリクスを取得するためにPrometheusをインストールする。
Istioに付属しているPrometheusのYAMLを以下のように修正し、VMをスクレイピングの対象とする。

--- prometheus.yaml.orig	2024-02-02 14:47:15
+++ prometheus.yaml	2024-02-02 15:42:20
@@ -43,6 +43,15 @@
     - /etc/config/rules
     - /etc/config/alerts
     scrape_configs:
+    - job_name: ubuntu
+      scrape_interval: 15s
+      scrape_timeout: 10s
+      scheme: http
+      metrics_path: /metrics
+      static_configs:
+      - targets:
+        - 10.215.76.71:15020
+        #- ubuntu-svc.vmtest.svc:15020
     - job_name: prometheus
       static_configs:
       - targets:

修正したManifestを使ってPrometheusをインストールする。

kubectl apply -f samples/addons/prometheus.yaml

次にIstioに付属しているKiali、Grafanaをインストールする。

kubectl apply -f samples/addons/kiali.yaml -f samples/addons/grafana.yaml 

適当にPodからVMに負荷を掛けた状態でKialiにアクセスしてみる。
1706856787715.png

上手く見えているようだ。
Grafanaにもアクセスしてみる。
1706857129256.png

こちらも問題なさそうだ。
これを上手く活用すれば、Prometheusのメトリクスのエンドポイントを持たないアプリケーションを動作させているVM環境でも、Prometheusによる監視やKiali,Grafanaによる可視化を実現できそうである。

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2