tkzwhr's notes

tkzwhrの技術、中国語などのメモです。

k8sでサブドメインごとにサービスを運用するためのローカル開発環境構築

f:id:tkzwhr:20210426004738p:plain

Kubernetes(k8s)にて、図のようにサブドメインごとにサービスを運用するために ローカル開発環境を構築したので、その手順を残しておく。

前提

  • Windows10とWSL2を使う
    • 環境構築ならおそらくMacのほうが楽だけど、性能の割に高いのでWindows
    • ゲストOSはUbuntu 20.04にする
  • ツールはゲストOSにインストールする
    • ホストOSにあまり開発ツールとかを入れたくないので…
  • Kubernetes環境構築にはMinikubeを使う
  • ルーターの設定をしておく
  • *.example.jp が 192.0.2.1 に解決されるようにDNSが設定されている

ネットワーク構成

f:id:tkzwhr:20210426005239p:plain

前提の環境で、1ポッドずつ2サービスを立ち上げると、こんな感じのネットワーク構成になる。

k8sのセットアップ

Ubuntu用のDockerをインストールする。

docs.docker.com

Post-installationに書いてあるとおり、dockerを一般ユーザーでも実行できるようにする。

docs.docker.com

何故かDNS解決がうまく行かず、docker imageのpullでタイムアウトが発生するため、 IPv6を有効化し、コンテナの /etc/resolv.confDNSの設定が追記されるようにする。

/etc/docker/daemon.json

{
  "ipv6": true,
  "fixed-cidr-v6": "fd00::/80",
  "dns": ["8.8.8.8","8.8.4.4"]
}

続いてminikubeを入れる。

minikube.sigs.k8s.io

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の設定を変更する。

office-hack.com

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

これでサブドメインからアクセスができるようになる。