kubernetesのServiceを使ってプライベートサブネットのRDSに接続する方法

EKSとRDSを利用して構築している環境があるのですが、RDSについてはプライベートサブネットに配置しているため、DB接続するには踏み台サーバを置いてポートフォワードするなどの対応が必要になります。
この方法だと踏み台サーバが必要になるため、以下のような構成でRDSに対して接続経路を用意しています。このPodはsocatが同梱されておりプロキシサーバーとなっています。

Podでプロキシを行いRDSに接続する構成

f:id:cloudfish:20200129221205p:plain

負荷も高いわけではなく特に問題はないのですが、このためだけにPodを起動させておくのもなーと思い、Podを使わずにプライベートなRDSへ接続できる方法がないか検証した結果、以下のような構成で接続できましたので、やり方を紹介したいと思います。ただし、RDSの接続先についてはDNSではなくIP指定となるためあまり使い勝手の良い方法ではないと思います。

Podを使わずにRDSへ接続する構成

f:id:cloudfish:20200129225249p:plain

通常ServiceはPodをメンバとして登録しますが、このケースではEndpointsというリソースをメンバとして登録します。そしてEndpointsからRDSへ接続するという形になります。

ELBの作成

以下の設定でロードバランサーを作成します。
当然ですが、セキュリティグループも以下に合わせて作成しておいてください。
Type: CLB
Protocol: TCP
Load Balancer Port: 13306
Instance Port: 30306

Kubernetesのリソースデプロイ

以下がRDS(MySQL)に接続するサンプルになります。
RDSのIPを自環境に合わせて書き換えてapplyしてください。

apiVersion: v1
kind: Service
metadata:
  name: rds-service 
spec:
  type: NodePort
  ports:
    - protocol: TCP
      port: 3306
      targetPort: 3306
      nodePort: 30306

---
apiVersion: v1
kind: Endpoints
metadata:
  name: rds-service 
subsets:
  - addresses:
    - ip: 10.10.213.27 #RDSのIP
    ports:
    - port: 3306

注意点としてはServiceとEndpointsのnameは同じにしておく必要があります。
また、マルチAZを利用している場合は、フェイルオーバーした場合にIPを書き換えるという一手間が必要になりますので注意してください。

以下のコマンドで接続できます。

mysql -h ELB_DNS -u mysql_user -P 13306 -p

初回接続は何故か数十秒かかります。またkeep aliveを調整しておかないと接続がすぐ切れるので長めに設定しておくことをお勧めします。

まとめ

Podを使わずに接続できたのはよかったのですが、Endpointsには接続先をIPでしか登録できないところがすごく惜しい機能です。DNSが指定できるようになったらいいですね。