wawoon blog

GKE + Istioな環境でCloudSQLを使うための設定

前提

  • CloudSQLにアクセスするためにはcloud_sql_proxyを用いてTCP接続のproxyプロセスを立ち上げる必要がある
  • 一方でIstioを利用しているとき、すべてのネットワークアクセスはIstioによってInterceptされてしまう
    • これはKubernetes内のクラスタ内のIPだけでなく、外部サーバーを利用するときも同様の挙動をする

By default, Istio-enabled services are unable to access URLs outside of the cluster because iptables is used in the pod to transparently redirect all outbound traffic to the sidecar proxy, which only handles intra-cluster destinations.

引用元

何が問題か

  • cloud_sql_proxyは、指定されたサービスアカウントの認証キーを使ってaccounts.google.comなどにアクセスして認証をした上で、CloudSQLのサーバーとコネクションを確立する。
  • Istioがcloud_sql_proxyの外部アクセスをinterceptするのが問題
    • cloud_sql_proxyがaccounts.google.comなどにアクセスできないので、そもそも認証・認可されない
    • 認証・認可されても、CloudSQLのサーバー自体も外部IPなのでこれにもアクセスできない。

解決策

https://istio.io/docs/tasks/traffic-management/egress/#calling-external-services-directly

によると以下の2方針で解決できる。

  1. Istioで外部サービスへの直接的なアクセスを実現するためにはServiceEntryを作成することが必要。
  2. Istioでインストール時にinterceptするIPアドレスをcidrで指定し、外部IPへのアクセスをinterceptしないようにする

今回は前者の方針をとった。

実装

以下のように設定すると無事にKubernetes + Istioの環境でCloudSQLを使える。

cloud_sql_proxyのPodの作成

https://github.com/GoogleCloudPlatform/cloudsql-proxy/blob/master/Kubernetes.md

を参照し、PodとServiceを作成する。

ServiceEntityの作成

以下、ServiceEntityをaccounts.google.com、www.googleapis.com、CloudSQLのサーバーのそれぞれに作成する。

ServiceEntityについては以下を参照。

実際のコードは以下から利用しています。 https://github.com/istio/istio/issues/6593

GCPのAPIサーバーの設定

cat <<EOF | istioctl create -f -
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
  name: account-google-serviceentry-rule
spec:
  hosts:
  - accounts.google.com
  ports:
  - number: 443
    name: https
    protocol: HTTPS
EOF

cat <<EOF | istioctl create -f -
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
  name: googleapis-serviceentry-rule
spec:
  hosts:
  - www.googleapis.com
  ports:
  - number: 443
    name: https
    protocol: HTTPS
EOF

外部MySQLのIPの設定

cat <<EOF | istioctl create -f -
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
  name: mysql-serviceentry-rule
spec:
  hosts:
  - MySQLサーバーのIPを書く
  ports:
  - number: 3307
    name: tcp
    protocol: TCP
EOF

Kubernetes内でMySQLサーバーにアクセスする

Kubernetes内からcloud_sql_proxyのPodへアクセスすればMySQLサーバーにアクセスできる