k8s 環境で postgresql するなら pgproxy が便利
はじめに
kubernetes 環境で postgresql のコンテナを建てたり、kubernetes クラスタが存在する VPN に postgresql インスタンスを起動する場合、kubernetes の外から postgresql サーバにアクセスする事ができません。モチベーションとしては自分の端末から kubernetes VPN 内にいる postgresql サーバへ psql で接続したいのです。その為にインターネットに穴を開けたくない。
psql が入ったコンテナを追加する... そうじゃない!
失敗した作戦1
コンテナ環境に socat が入った ubuntu コンテナを建て、postgresql へのプロキシを作成、そのコンテナへ kubectl port-forward する作戦です。
$ socat tcp-listen:5432,reuseaddr,fork tcp-connect:<postgresqlのIP>:5432
残念ながらこのプロキシは接続元 IP が自端末となってしまいます。postgresql はデフォルトでは pg_hba.conf で決められたネットワークの外部からの接続は trust になっていないため、結果として接続できませんでした。
あともし上手く行ったとしても、socat を起動して kubernetes port-forward を起動するのは面倒すぎる。
失敗した作戦2
ならばと今度は kubernetes クラスタ内に tailscale を入れ、サブネットルータ化し、postgresql サーバに直接アクセスしてみました。
tailscale でサブネットルータを作るには tailscale のリポジトリ内に含まれる docs/k8s
を使います。
先に secret を作っておきます。
apiVersion: v1
kind: Secret
metadata:
name: tailscale-auth
stringData:
TS_AUTHKEY: tskey-0123456789abcdef
TS_AUTHKEY は tailscale の設定画面から払い出して下さい。
そして Makefile を使って pod をデプロイします。
$ make subnet-router TS_ACCEPT_DNS=true TS_KUBE_SECRET=tailscale-auth TS_ROUTES=10.0.10.0/24,... | kubectl apply -f -
TS_ROUTS にはアクセスしたいネットワークをカンマ区切りで列挙します。これを使うと自端末からクラスタ内の IP にアクセスしてとても便利です。
これはこれで便利になったのですが、この場合でも接続元 IP が tailnet の IP になってしまうため作戦1と同じエラーになってしまいました。
成功した作戦
そこで紹介したいのが pgproxy を使う方法です。pgproxy は tailscale 社が提供している tailnet を介した postgresql 向けプロキシです。
pgproxy を使うには、kubernetes クラスタ内に tailscale を実行できるコンテナを建てる必要があります。作戦2を実行したのであれば、それを使ってもいいです。
※ 実際には tun kernel module を使えるサーバであれば良いです
僕の場合は作戦2でデプロイした pod を使いました。subnet-router に /bin/sh で入り、以下を実行します。
$ TS_AUTHKEY=tskey-auth-XXXXXXXXXXXXXXXXXXXX ./pgproxy --hostname postgresql-server:5432 --upstream-addr <postgresql サーバのIP>:5432 --upstream-ca-file /tmp/certs.pub --state-dir state
※ certs.pub はサーバ証明書です。
ここで --hostname
で指定するホスト名は 実際に存在しないホスト名 を設定してください。このコマンドを実行したタイミングで pgproxy が tailscale に 新しいマシン名 postgresql-server を登録 してくれます。
あとはそのマシンに対して psql を実行すればよいのです。
$ psql -h postgresql-server -W postgres
この方法だといちいち socat や port-forward を実行する面倒さもありません。
さらにこの方法を使うと kubernetes クラスタ内のアプリケーションが、tailscale ネットワーク内にいる、別ネットワークの postgresql サーバを使う事もできるのです。
おわりに
kubernetes クラスタにサブネットルータを導入し、さらに pgproxy を使って直接 postgresql サーバにアクセスできる様にしました。
世の中には postgresql サーバにアクセスする為にインターネットに口を開けてしまっているサーバが沢山あるらしいです。
この記事内でも書いてある様に、tailscale や pgproxy を使って安全に保っておく必要があります。
Discussion