モチベーション
- マイクロサービス化を進めたり、サービスで利用しているミドルウェアが多くなると、ローカル環境にすべての依存サービス、ミドルウェアを同居させることがリソース的にきびしくなります
- 基本的にすべてをAWS等のクラウドプロバイダ上にデプロイして、開発対象のサービスだけ置き換えられるといいですよね。しかも高速に。
- Kubernetesならできます。
TL;DR;
- minikubeとそれ以外でハマりどころが違いました。
- ややこしいことに、K8Sと開発マシン、どちらからどちらへの通信を可能にするのか、もしくは両方なのか、によってやることがが変わります。
- 以下では特に説明できていませんが、通信だけでなく、K8Sクラスタ内にあるVolumeをマウントしてローカルプロセスから参照したい・・・というような場合は、Telepresence一択です
この記事で説明しないこと
- ローカルでもIngressをテストしたいよ!という場合は @superbrothers さんの「Minikube で快適に Ingress を利用する」がおすすめです
登場するOSS
基本的な考え方
VPN
最もスタンダードなのは、K8Sクラスタ内ネットワークと開発用マシンのネットワークをつなぐためにVPNを使うというものです。
minikube以外
your-laptop <---vpn over internet---> K8S cluster-internal net
minikube
your-laptop <---vpn over private network---> K8S cluster-internal network
ホストオンリーネットワーク
一方で、例えば、VirtualBoxの場合はVirtualBoxが作ったvboxnetに繋がるvboxnet<N>
というインタフェース経由でminikubeVMのネットワークにアクセスできます。
your-laptop <---vboxnet---> VirtualBox machine
minikubeVMはkube-proxyによって設定されたiptablesによって、VM→K8Sクラスタ内ネットワークへのルートが設定されています。かつ、minikubeVMはcat /proc/sys/net/ipv4/ip_forward
が1
となることからわかるようにIPフォワードが有効化されています。
そのため、ホストマシンに、K8SクラスタのServiceやPod IPのCIDRへのパケットをminikubeVM経由でルーティングするようなルートを設定してやれば、結果的にホストマシンからK8Sクラスタ内ネットワークにアクセスすることができます。
macOS --route--> minikubeVM --route--> K8S
iptables + sshポートフォワード = sshuttle
K8Sでは、kubectlでK8SのAPIサーバに繋がる状態でありさえすれば、kubectl port-forward
コマンドでローカルポートフォワードができます。つまり、ローカルの特定ポートへのパケットをK8Sクラスタの特定podの特定ポートに転送することができます。
これを応用して、特定podをssh serverにして、開発用マシンからフォワードされたポート経由でSSHトンネルを作成し、iptablesを使ってK8Sネットワーク宛のパケットをSSHトンネル経由とpod経由でK8Sネットワークに送るようにすれば、あたかもローカルプロセスがK8Sクラスタのネットワークに繋がったような状態にできます。
sshuttleというOSSがこれを実装していて、telepresenceの-m vpn-tcp
はこれを利用しています。
参考: Telepresence - How it works
minikube以外の場合
開発マシン→K8S, K8S→開発マシン,
telepresence
以下の欠点に目を瞑れるのであればtelepresenceを使いましょう。
- telepresenceの設計思想的に、また実際telepresenceのスタンダードなメソッド(inject-tcp)は特に、特定プロセスからK8Sクラスタ内のIPアドレスやDNS名が見えるようにします。
- 結果的に、「開発機で動いているWebアプリを、クラスタ内のDNS名でChromeからアクセス」というようなことはできません。
- IngressなりNodePort and/or LoadBalancerを使うワークアラウンドもありですが、ちょっと面倒かもしれません
kube-openvpn
TODO
minikubeの場合
VirtualBox前提で説明しますが、原理的にはVMWareなどでも一緒なはず…?
kube-openvpn
開発マシン・K8S間の双方向通信ができます。
開発マシン→K8S
K8Sクラスタ外のDNS名前解決ができなくなるのでNG
試してだめだったこと
- OpenVPNサーバ側の設定
- push "redirect-gateway"
を追加してみた
- push "block-outside-dns"
を追加してみた
おそらく、telepresence同様、DNSルックアップがループしている?
気をつけることとしては、あえてSplit DNSにすることと、K8Sクラスタ内ネットワークのドメイン配下の名前解決をするときだけK8SのDNSを使うように、開発用マシン側の設定を変更すること。
あえてSplit DNSにする
具体的には、OpenVPN Server側の設定で以下のようにpush "block-outside-dns"
やpush "dhcp-options DNS ..."
を記述しないようにする。
前者はVPNクランアント側でホストに元々設定されていたDNSを使わないようにする(VPNサーバ側のDNSの使用を矯正する)、後者はDHCP Options経由でVPNクライアント側がVPN接続後に名前解決に使うDNSサーバの場所を強制するという設定。
どちらを設定しても、VPN接続後にホストOSからはminikubeVMから直接見えるホスト名しか解決できなくなってしまう。また、minikubeVMはminikubeVMから直接見えないホスト名についてはホストOSのDNSレゾルバーに委譲するので、ホストOSのDNSリゾルバーをこのように無効化してしまうと、minikubeVMから直接見えるホスト名以外解決できなくなってしまう。例えば、google.comがホストOSからもminikubeVMからも解決できなくなってしまう。
server ${OVPN_NETWORK_ROUTE}
topology subnet
verb ${OVPN_VERB}
# Filled by Secrets object. Use generic names
key ${EASYRSA_PKI}/private.key
ca ${EASYRSA_PKI}/ca.crt
cert ${EASYRSA_PKI}/certificate.crt
dh ${EASYRSA_PKI}/dh.pem
tls-auth ${EASYRSA_PKI}/ta.key
key-direction 0
keepalive 10 60
persist-key
persist-tun
#push "block-outside-dns"
proto ${OVPN_PROTO}
cipher ${OVPN_CIPHER}
tls-cipher ${OVPN_TLS_CIPHER}
# Rely on scheduler to do port mapping, internally always 1194
port 1194
dev tun0
user nobody
group nogroup
push "dhcp-option DOMAIN ${OVPN_K8S_DOMAIN}"
#push "dhcp-option DNS ${OVPN_K8S_DNS}"
参考: Push DNS for only a domain OpenVPN - Server Fault
Mac OS X 10.8.4 で VPNを使うときに知っておきたいこと | hiro345
開発用マシン側で、K8Sクラスタ内のDNS名を解決するときだけK8SのDNSを使う
ここまでの手順でK8S ServiceのCluster IPにVPN経由でアクセスできるようになる。
ただし、まだK8SのServiceのDNS名などは解決できる状態にははなっていない。あえてVPNサーバ側のDNS設定を利用しないようにしたから。
VPN経由でK8S ServiceのIPにアクセスできるということは、kube-dnsのIPにもアクセスできるということ。
この状態で、cluster.local以下の名前解決のためのDNSクエリがkube-dnsにフォワードされるようにすれば名前解決もできるようになる。
/etc/resolver/cluster.local
nameserver 10.0.0.10
K8S→開発マシン
kube-openvpnのRouting back to the client参照
開発マシン→K8S
telepresenceのようにLD_PRELOADを乗っ取ったりVPN over SSHを使わなくてもできる。
KubernetesのService CIDRへの静的ルート追加
sudo route -n add 10.0.0.0/24 $(minikube ip)
これでkube-dnsはじめ、K8S ServiceのCluster IPにminikubeVM経由でアクセスできるようになる。
この状態で、cluster.local以下の名前解決のためのDNSクエリがkube-dnsにフォワードされるようにすればよい。
/etc/resolver/cluster.local
nameserver 10.0.0.10
テスト
nslookupはcurlなどが使うMacOSのDNSスタックを使わないので、このアプローチのテストには使えない。以下のようにdns-sdを使う。
$ dns-sd -G v4 nginx.default.svc.cluster.local
DATE: ---Tue 13 Jun 2017---
11:30:07.937 ...STARTING...
Timestamp A/R Flags if Hostname Address TTL
11:30:07.939 Add 2 0 nginx.default.svc.cluster.local. 10.0.0.242 39
dns-sdが通るなら、curlなどでも通るはず。
試しにkubectl run & exposeで起動したnginxにアクセスしてみる。
$ curl nginx.default.svc.cluster.local
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
Chromeでアクセスすることも可能。
参考リンク集
- minikube - Routing an internal Kubernetes IP address to the host system - Stack Overflow
- networking - Dev machine as part of Minikube's network? - Stack Overflow
-
domain name system - dig & nslookup can't resolve local hosts unless I specify the (local) DNS server to use - Server Fault
- OS標準のDNSではなく、dnsmasqを使ったケース。dnsmasqでupstreamのDNSサーバを変えたのに、nslookupしてもそのDNSサーバが使われないという問題
- この場合、基本的にDNSクエリの経路はOSのDNS→dnsmasq→upstream DNSとなるが、nslookupやpingはこの経路を通らないから。
これはCentOSの例だが、実はmacOSも一緒
-
Using Dnsmasq for local development on OS X - Passing Curiosity
- .devでおわるあらゆるドメイン名を127.0.0.1に解決させる方法
- 今回のトピックとはあまり関係しませんが
- linux - How to enforce dnsmasq to use dns for some hosts? - Server Fault
- dns - Route complete TLD (*.dev for example) to 127.0.0.1 - Ask Ubuntu
- Use different DNS servers for different domains - Mac OS X Hints
- macos - Do /etc/resolver/ files work in Mountain Lion for DNS resolution? - Ask Different