Kubernetes向け便利ツール群の Carvel の一つである kwt を使うとk8sクラスタ外から内部ドメイン名でService / Podへアクセスできます。
データベースや内部APIなどの外部に公開していないServiceに対して、ローカル上の開発環境からアクセスしたい場合や、トラブルシーティングで疎通を確認したい場合に便利です。
通常はkubectl proxyやkubectl port-fowardを使ってPodやServiceにアクセスすることが多いと思いますが、kwtを使うと内部ドメイン名を使用できるのでよりk8s内の環境に近い形でアクセスできますし、個々にport forwardの設定をする必要がありません。
同様なツールに Telepresence があります。Telepresenceを使ったことはないですが、ぱっと見
kwtの方がシンプルで手軽に使えそうに見えます。
ドキュメントは こちら 。
kwtを試すための下準備
kwtのインストール
kwtはBrewでインストールできます。
$ brew tap vmware-tanzu/carvel
$ brew install kwt
あるいは
https://github.com/vmware-tanzu/carvel-kwt/releases
からバイナリをダウンロードできます。OS XとLinuxのみサポートされています。
k8sクラスタの作成
まずはkindでk8sクラスタを作成します。
$ kind create cluster
Creating cluster "kind" ...
✓ Ensuring node image (kindest/node:v1.21.1) 🖼
✓ Preparing nodes 📦
✓ Writing configuration 📜
✓ Starting control-plane 🕹️
✓ Installing CNI 🔌
✓ Installing StorageClass 💾
Set kubectl context to "kind-kind"
You can now use your cluster with:
kubectl cluster-info --context kind-kind
Thanks for using kind! 😊
アプリケーションのデプロイ
サンプルアプリケーションとしてGuestbookをデプロイします。
kubectl apply -f https://github.com/kubernetes/examples/raw/master/guestbook/all-in-one/guestbook-all-in-one.yaml
作成されるPodとServiceは次のとおりです。
$ kubectl get pod,svc
NAME READY STATUS RESTARTS AGE
pod/frontend-6c6d6dfd4d-c5jzr 1/1 Running 0 90s
pod/frontend-6c6d6dfd4d-dc77g 1/1 Running 0 90s
pod/frontend-6c6d6dfd4d-rknb6 1/1 Running 0 90s
pod/redis-master-f46ff57fd-2dmpv 1/1 Running 0 90s
pod/redis-slave-7979cfdfb8-7wgcd 1/1 Running 0 90s
pod/redis-slave-7979cfdfb8-h227s 1/1 Running 0 90s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/frontend NodePort 10.96.51.181 <none> 80:32472/TCP 90s
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 35m
service/redis-master ClusterIP 10.96.66.101 <none> 6379/TCP 90s
service/redis-slave ClusterIP 10.96.250.255 <none> 6379/TCP 90s
なお、kwt net svcとkwt net podコマンドで、ServiceとPodの内部DNS名一覧を取得できます。
$ kwt net svc
Services in namespace 'default'
Name Internal DNS Cluster IP Ports
frontend frontend.default.svc.cluster.local 10.96.51.181 80/tcp
kubernetes kubernetes.default.svc.cluster.local 10.96.0.1 443/tcp
redis-master redis-master.default.svc.cluster.local 10.96.66.101 6379/tcp
redis-slave redis-slave.default.svc.cluster.local 10.96.250.255 6379/tcp
4 services
Succeeded
$ kwt net pod
Pods in namespace 'default'
Name Internal DNS IP Ports
frontend-6c6d6dfd4d-c5jzr 10-244-0-5.default.pod.cluster.local 10.244.0.5 80/tcp
frontend-6c6d6dfd4d-dc77g 10-244-0-9.default.pod.cluster.local 10.244.0.9 80/tcp
frontend-6c6d6dfd4d-rknb6 10-244-0-10.default.pod.cluster.local 10.244.0.10 80/tcp
redis-master-f46ff57fd-2dmpv 10-244-0-6.default.pod.cluster.local 10.244.0.6 6379/tcp
redis-slave-7979cfdfb8-7wgcd 10-244-0-8.default.pod.cluster.local 10.244.0.8 6379/tcp
redis-slave-7979cfdfb8-h227s 10-244-0-7.default.pod.cluster.local 10.244.0.7 6379/tcp
6 pods
Succeeded
kwtを使ってk8s内部にアクセス
次のコマンドを実行して、ローカル環境とk8sクラスタを繋ぎます。
sudo -E kwt net start
次のようなログが出力され、30秒ほどでReadyになります。
12:56:17PM: info: KubeEntryPoint: Creating networking client secret 'kwt-net-ssh-key' in namespace 'default'...
12:56:17PM: info: KubeEntryPoint: Creating networking host secret 'kwt-net-host-key' in namespace 'default'...
12:56:20PM: info: KubeEntryPoint: Creating networking pod 'kwt-net' in namespace 'default'
12:56:20PM: info: KubeEntryPoint: Waiting for networking pod 'kwt-net' in namespace 'default' to start...
12:56:36PM: info: dns.FailoverRecursorPool: Starting with '8.8.8.8:53'
12:56:36PM: info: dns.DomainsMux: Registering cluster.local.->kube-dns
12:56:36PM: info: mdns.Server: Started mDNS resolver on 0.0.0.0:5353
12:56:36PM: info: TCPProxy: Started proxy on 127.0.0.1:51001
12:56:36PM: info: UDPProxy: Started proxy on 127.0.0.1:61048
12:56:36PM: info: dns.Server: Started DNS server on 127.0.0.1:51000 (TCP) and 127.0.0.1:57986 (UDP)
12:56:36PM: info: ForwardingProxy: Forwarding subnets: 10.244.0.5/14, 172.22.0.2/14, 10.96.51.181/14
12:56:36PM: info: ForwardingProxy: Ready!
kwt-netという名前のPodが作成されています。
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
frontend-6c6d6dfd4d-c5jzr 1/1 Running 0 7m36s
frontend-6c6d6dfd4d-dc77g 1/1 Running 0 7m36s
frontend-6c6d6dfd4d-rknb6 1/1 Running 0 7m36s
kwt-net 1/1 Running 0 21s
redis-master-f46ff57fd-2dmpv 1/1 Running 0 7m36s
redis-slave-7979cfdfb8-7wgcd 1/1 Running 0 7m36s
redis-slave-7979cfdfb8-h227s 1/1 Running 0 7m36s
kwt-netのconfigを確認すると、実体がsshdのSOCKSサーバーであることがわかります。
$ kubectl get pod kwt-net -oyaml | kubectl neat
apiVersion: v1
kind: Pod
metadata:
annotations:
sidecar.istio.io/inject: "false"
labels:
kwt.cppforlife.com/net: "true"
name: kwt-net
namespace: default
spec:
containers:
- args:
- -c
- echo "$KWT_CLIENT_PUB_KEY" > /home/tom/.ssh/authorized_keys && echo "$KWT_HOST_PRIV_KEY"
> /etc/ssh/ssh_host_rsa_key && echo "$KWT_HOST_PUB_KEY" > /etc/ssh/ssh_host_rsa_key.pub
&& echo "GatewayPorts clientspecified" >> /etc/ssh/sshd_config && exec /usr/sbin/sshd
-D -p 2048
command:
- /bin/bash
env:
- name: KWT_CLIENT_PUB_KEY
valueFrom:
secretKeyRef:
key: ssh-publickey
name: kwt-net-ssh-key
- name: KWT_HOST_PRIV_KEY
valueFrom:
secretKeyRef:
key: ssh-privatekey
name: kwt-net-host-key
- name: KWT_HOST_PUB_KEY
valueFrom:
secretKeyRef:
key: ssh-publickey
name: kwt-net-host-key
image: index.docker.io/cppforlife/sshd@sha256:6c3170c4d97f2926ec034fc237554db237076bd9014469aac91610d89a9991d1
name: kwt-net
ports:
- containerPort: 2048
name: ssh
# ...
Guestbookのフロントエンドにアクセスしましょう。
ローカル端末上でdigコマンドを使ってfrontend.default.svc.cluster.local名前解決するとCluster IPが返ります。
$ dig frontend.default.svc.cluster.local
; <<>> DiG 9.10.6 <<>> frontend.default.svc.cluster.local
;; global options: +cmd
;; Got answer:
;; WARNING: .local is reserved for Multicast DNS
;; You are currently testing what happens when an mDNS query is leaked to DNS
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 18574
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;frontend.default.svc.cluster.local. IN A
;; ANSWER SECTION:
frontend.default.svc.cluster.local. 0 IN A 10.96.51.181
;; Query time: 4 msec
;; SERVER: 8.8.8.8#53(8.8.8.8)
;; WHEN: Wed Jun 16 13:14:33 JST 2021
;; MSG SIZE rcvd: 102
ブラウザでhttp://frontend.default.svc.cluster.localにアクセスします。

普通にアクセスできました。
"Messages"に"Hello"を入力して、Submitボタンを押せば、"Hello"が出力されます。

Podのうちのひとつ(例: http://10-244-0-5.default.pod.cluster.local)に直接アクセスすることもできます。

次にバックエンドのRedisにアクセスしてみます。
$ redis-cli -h redis-master.default.svc.cluster.local -p 6379
redis-master.default.svc.cluster.local:6379> get messages
",Hello"
ローカル環境から直接redis-cliでk8s上のRedisにアクセスできました。
kwtの停止
kwt net svcコマンドを終了すればk8sクラスタへのアクセスはできなくなります。
kwt net svcコマンドで作成されたリソースは次のコマンドで削除できます。
kwt net clean-up
Guestbookも削除しましょう。
kubectl delete -f https://github.com/kubernetes/examples/raw/master/guestbook/all-in-one/guestbook-all-in-one.yaml
kwtでk8sクラスタ外から内部ドメイン名でService / Podへアクセスする方法を紹介しました。
ローカル環境での開発やトラブルシューティングに便利ではないでしょうか。
次は"Carvel kwtでk8sクラスタ内からローカル環境へアクセスする"方法を紹介します。
懸念は最後のリリース(0.0.6)が2019年12月であること...