k8sでサブドメインごとにサービスを運用するためのローカル開発環境構築
Kubernetes(k8s)にて、図のようにサブドメインごとにサービスを運用するために
ローカル開発環境を構築したので、その手順を残しておく。
前提
- Windows10とWSL2を使う
- 環境構築ならおそらくMacのほうが楽だけど、性能の割に高いのでWindowsで
- ゲストOSはUbuntu 20.04にする
- ツールはゲストOSにインストールする
- ホストOSにあまり開発ツールとかを入れたくないので…
- Kubernetes環境構築にはMinikubeを使う
- ルーターの設定をしておく
- ファイアウォール
- NAT(ポート変換)
-
*.example.jp
が 192.0.2.1 に解決されるようにDNSが設定されている
ネットワーク構成
前提の環境で、1ポッドずつ2サービスを立ち上げると、こんな感じのネットワーク構成になる。
k8sのセットアップ
Ubuntu用のDockerをインストールする。
Post-installationに書いてあるとおり、dockerを一般ユーザーでも実行できるようにする。
何故かDNS解決がうまく行かず、docker imageのpullでタイムアウトが発生するため、
IPv6を有効化し、コンテナの /etc/resolv.conf
にDNSの設定が追記されるようにする。
/etc/docker/daemon.json
{
"ipv6": true,
"fixed-cidr-v6": "fd00::/80",
"dns": ["8.8.8.8","8.8.4.4"]
}
続いてminikubeを入れる。
kubectlコマンドへのエイリアスを作成する。
$ echo "alias kubectl='minikube kubectl -- '" >> ~/.bashrc
$ source ~/.bashrc
minikubeを開始し、サブドメインごとにルーティングするためにIngressを有効にする。
$ minikube start --driver=docker
$ minikube addons enable ingress
サービスを立ち上げる
とりあえず、Expressで適当なアプリを作る。
Dockerfile
FROM node:slim
WORKDIR /work
COPY ./package.json ./package-lock.json ./main.js /work/
RUN npm install
EXPOSE 3000
CMD ["npm", "start"]
main.js
const express = require('express');
const app = express();
const port = process.env.PORT || 3000;
const serverName = process.env.SERVER_NAME || 'unknown';
app.get('/', (req, res) => {
res.json({
message: `Welcome to ${serverName}`
});
});
app.listen(port, () => console.log(`Demo app listening on port ${port}!`));
Container RepositoryにPushするのも面倒なので、ローカルでビルドする。
$ docker build -t node-app:1
k8sサービスを作って立ち上げてみる。
deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: node-app-1
labels:
app: node-app-1
spec:
replicas: 1
selector:
matchLabels:
app: node-app-1
template:
metadata:
labels:
app: node-app-1
spec:
containers:
- name: node-app-1
image: node-app:1
imagePullPolicy: IfNotPresent
ports:
- containerPort: 3000
env:
- name: SERVER_NAME
value: "hoge"
---
kind: Service
apiVersion: v1
metadata:
name: node-app-1
spec:
type: ClusterIP
selector:
app: node-app-1
ports:
- protocol: TCP
port: 3001
targetPort: 3000
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: node-app-2
labels:
app: node-app-2
spec:
replicas: 1
selector:
matchLabels:
app: node-app-2
template:
metadata:
labels:
app: node-app-2
spec:
containers:
- name: node-app-2
image: node-app:1
imagePullPolicy: IfNotPresent
ports:
- containerPort: 3000
env:
- name: SERVER_NAME
value: "piyo"
---
kind: Service
apiVersion: v1
metadata:
name: node-app-2
spec:
type: ClusterIP
selector:
app: node-app-2
ports:
- protocol: TCP
port: 3002
targetPort: 3000
$ kubectl apply -f deployment.yaml
ルーティングを作成する
次に、サブドメインごとにルーティングするためにIngressを作成する。
ingress.yaml
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: virtual-host-ingress
spec:
rules:
- host: hoge.example.jp
http:
paths:
- pathType: Prefix
path: "/"
backend:
serviceName: node-app-1
servicePort: 3001
- host: piyo.example.com
http:
paths:
- pathType: Prefix
path: "/"
backend:
serviceName: node-app-2
servicePort: 3002
$ kubectl apply -f ingress.yaml
$ curl -H 'Host: hoge.example.jp' $(minikube ip)
$ curl -H 'Host: piyo.example.jp' $(minikube ip)
minikubeのnode ipを使ってアクセスできていることが確認できる。
ポートフォワーディングの設定
最後にサブドメインでアクセスされたときにIngressに到達できるようにする。
このあたりの設定がうまく行かず何度も試行錯誤していたので、何気に一番苦労した。。
Internet -> Windows
ファイアウォールを解除する必要がある。
下記のリンクを参考に、Windowsの設定を変更する。
Windows -> Ubuntu on WSL2
PowerShellから、Windowsにポートフォワーディング設定を追加する。
> bash.exe -c "ip r |tail -n1|cut -d ' ' -f9"
(<guest ip addr>が表示されるので、次の行に当てはめる)
> netsh.exe interface portproxy add v4tov4 listenport=80 connectaddress=<guest ip addr>
> sc.exe config iphlpsvc start=auto
> sc.exe start iphlpsvc
Ubuntu -> Ingress
iptablesを使ってUbuntuにポートフォワーディング設定を追加する。
$ sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j DNAT --to $(minikube ip):80
$ sudo iptables -A FORWARD -d $(minikube ip) -p tcp --dport 80 -j ACCEPT
これでサブドメインからアクセスができるようになる。
Discussion