Kubernetes(k8s)にて、図のようにサブドメインごとにサービスを運用するために ローカル開発環境を構築したので、その手順を残しておく。
前提
- Windows10とWSL2を使う
- ツールはゲスト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の設定が追記されるようにする。
{ "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を作成する。
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
これでサブドメインからアクセスができるようになる。