前回の続き。
目次
ローカルPCからクラスタ内podへのネットワークアクセス(マルチnodeの場合)
extraPortmappingsで、ホストのポートとnodeのポートを紐付けることで、ローカルPCからnode内のpodへのアクセスができます。ただ、ホストポートを使うので、マルチnodeの場合はポートを分けてやる必要があります。クラスタのマニフェストはこんな感じになります。
apiVersion: kind.x-k8s.io/v1alpha4 kind: Cluster name: sample nodes: - role: control-plane - role: worker extraPortMappings: - containerPort: 30000 hostPort: 30001 protocol: TCP - role: worker extraPortMappings: - containerPort: 30000 hostPort: 30002 protocol: TCP - role: worker extraPortMappings: - containerPort: 30000 hostPort: 30003 protocol: TCP
クラスタを作成します。
$ kind create cluster --config multi-host-ports.yaml
ローカルポート30001〜30003が、それぞれのnodeのポート30000にフォワードされます。
$ kubectl get node NAME STATUS ROLES AGE VERSION sample-control-plane Ready control-plane,master 3m9s v1.21.1 sample-worker Ready <none> 2m39s v1.21.1 sample-worker2 Ready <none> 2m39s v1.21.1 sample-worker3 Ready <none> 2m38s v1.21.1 $ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES a08c381ddc75 kindest/node:v1.21.1 "/usr/local/bin/entr…" 3 minutes ago Up 3 minutes 0.0.0.0:30003->30000/tcp sample-worker3 dba747f1183d kindest/node:v1.21.1 "/usr/local/bin/entr…" 3 minutes ago Up 3 minutes 127.0.0.1:59931->6443/tcp sample-control-plane c8a586bbc81b kindest/node:v1.21.1 "/usr/local/bin/entr…" 3 minutes ago Up 3 minutes 0.0.0.0:30002->30000/tcp sample-worker2 edd676ec1132 kindest/node:v1.21.1 "/usr/local/bin/entr…" 3 minutes ago Up 3 minutes 0.0.0.0:30001->30000/tcp sample-worker
nodeportでserviceを立ち上げます。
apiVersion: v1 kind: Pod metadata: name: my-app labels: app: my-app spec: containers: - name: nginx image: nginx:1.19.2 ports: - containerPort: 80 --- apiVersion: v1 kind: Service metadata: name: my-service spec: selector: app: my-app type: NodePort ports: - protocol: TCP port: 80 targetPort: 80 nodePort: 30000
$ kubectl apply -f nodeport.yaml
nodeportとして動作はしていますがが、これはちょっとわかりにくいですね・・・
$ curl -s localhost:30001 <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> (snip) $ curl -s localhost:30002 <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> (snip) $ curl -s localhost:30003 <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> (snip)
Ingressを使う
ingress-controllerを使う場合もextraPortMappingを使います。公式のドキュメントに従ってみましょう。
クラスタマニフェストはこんな感じです。
apiVersion: kind.x-k8s.io/v1alpha4 kind: Cluster name: sample nodes: - role: control-plane - role: worker kubeadmConfigPatches: - | kind: JoinConfiguration nodeRegistration: kubeletExtraArgs: node-labels: "ingress-ready=true" extraPortMappings: - containerPort: 80 hostPort: 80 protocol: TCP
kindはkubeadmを使ってクラスタを作成しますので、kubeadmConfigPatchesを使うとカスタマイズできます。上記ではworkerに対して、kubeadm joinの際に設定を追加して、"ingress-ready=true"というラベルを付けています。(後述するnginx-ingressのサンプルではnodeSelectorでこれを見るようになっています。)
クラスタ作成後にnodeを見てみると、ラベルが付いているのがわかりますね。
$ kubectl get node NAME STATUS ROLES AGE VERSION sample-control-plane Ready control-plane,master 3m v1.21.1 sample-worker Ready <none> 2m32s v1.21.1 $ kubectl get node sample-worker -o json | jq ".metadata.labels" { "beta.kubernetes.io/arch": "amd64", "beta.kubernetes.io/os": "linux", "ingress-ready": "true", "kubernetes.io/arch": "amd64", "kubernetes.io/hostname": "sample-worker", "kubernetes.io/os": "linux" }
ではingressです。公式のドキュメントでは以下のingress controllerが紹介されています。
- Ambassador
- Contour
- Ingress NGINX
Ingress NGINX以外はちょっと知らないですね・・・・ということで、Ingress NGINXのサンプルのマニフェストを使いましょう。
$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/kind/deploy.yaml
namespace/ingress-nginx created
serviceaccount/ingress-nginx created
configmap/ingress-nginx-controller created
clusterrole.rbac.authorization.k8s.io/ingress-nginx created
clusterrolebinding.rbac.authorization.k8s.io/ingress-nginx created
role.rbac.authorization.k8s.io/ingress-nginx created
rolebinding.rbac.authorization.k8s.io/ingress-nginx created
service/ingress-nginx-controller-admission created
service/ingress-nginx-controller created
deployment.apps/ingress-nginx-controller created
ingressclass.networking.k8s.io/nginx created
validatingwebhookconfiguration.admissionregistration.k8s.io/ingress-nginx-admission created
serviceaccount/ingress-nginx-admission created
clusterrole.rbac.authorization.k8s.io/ingress-nginx-admission created
clusterrolebinding.rbac.authorization.k8s.io/ingress-nginx-admission created
role.rbac.authorization.k8s.io/ingress-nginx-admission created
rolebinding.rbac.authorization.k8s.io/ingress-nginx-admission created
job.batch/ingress-nginx-admission-create created
job.batch/ingress-nginx-admission-patch created
準備ができるまで待ちます。
$ kubectl wait --namespace ingress-nginx \ --for=condition=ready pod \ --selector=app.kubernetes.io/component=controller \ --timeout=90s
ingress-nginx-controllerが起動しました。
$ kubectl get pod -n ingress-nginx NAME READY STATUS RESTARTS AGE ingress-nginx-admission-create-jsbpq 0/1 Completed 0 60s ingress-nginx-admission-patch-sqlcs 0/1 Completed 0 60s ingress-nginx-controller-6c85cb7b5d-rqn6l 1/1 Running 0 61s
では、pod/service/ingressを設定します。公式のまんまです。
$ kubectl apply -f https://kind.sigs.k8s.io/examples/ingress/usage.yaml
pod/foo-app created
service/foo-service created
pod/bar-app created
service/bar-service created
ingress.networking.k8s.io/example-ingress created
usage.yamlの中身はこんな感じです。/fooと/barで振り分けています。
kind: Pod apiVersion: v1 metadata: name: foo-app labels: app: foo spec: containers: - name: foo-app image: hashicorp/http-echo:0.2.3 args: - "-text=foo" --- kind: Service apiVersion: v1 metadata: name: foo-service spec: selector: app: foo ports: # Default port used by the image - port: 5678 --- kind: Pod apiVersion: v1 metadata: name: bar-app labels: app: bar spec: containers: - name: bar-app image: hashicorp/http-echo:0.2.3 args: - "-text=bar" --- kind: Service apiVersion: v1 metadata: name: bar-service spec: selector: app: bar ports: # Default port used by the image - port: 5678 --- apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: example-ingress spec: rules: - http: paths: - pathType: Prefix path: "/foo" backend: service: name: foo-service port: number: 5678 - pathType: Prefix path: "/bar" backend: service: name: bar-service port: number: 5678
実際にアクセスしてみると、ingressが動作しているのがわかります。
$ curl localhost/foo foo $ curl localhost/bar bar
マルチクラスタでやるならばこうなりますかね。
apiVersion: kind.x-k8s.io/v1alpha4 kind: Cluster name: sample nodes: - role: control-plane - role: worker kubeadmConfigPatches: - | kind: JoinConfiguration nodeRegistration: kubeletExtraArgs: node-labels: "ingress-ready=true" extraPortMappings: - containerPort: 30080 hostPort: 30001 protocol: TCP - containerPort: 30443 hostPort: 30011 protocol: TCP - role: worker kubeadmConfigPatches: - | kind: JoinConfiguration nodeRegistration: kubeletExtraArgs: node-labels: "ingress-ready=true" extraPortMappings: - containerPort: 30080 hostPort: 30002 protocol: TCP - containerPort: 30443 hostPort: 30012 protocol: TCP - role: worker kubeadmConfigPatches: - | kind: JoinConfiguration nodeRegistration: kubeletExtraArgs: node-labels: "ingress-ready=true" extraPortMappings: - containerPort: 30080 hostPort: 30003 protocol: TCP - containerPort: 30443 hostPort: 30013 protocol: TCP
$ kind create cluster --config multi-node-ingress.yaml // 以下は公式と同じ $ kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/kind/deploy.yaml $ kubectl wait --namespace ingress-nginx \ --for=condition=ready pod \ --selector=app.kubernetes.io/component=controller \ --timeout=90s // service: ingress-nginx-controllerのnodeportを変更 $ kubectl -n ingress-nginx patch service ingress-nginx-controller --type='json' -p='[{"op": "replace", "path": "/spec/ports/0/nodePort", "value": 30080}]' $ kubectl -n ingress-nginx patch service ingress-nginx-controller --type='json' -p='[{"op": "replace", "path": "/spec/ports/1/nodePort", "value": 30443}]' // ingress/service/podをapply $ kubectl apply -f https://kind.sigs.k8s.io/examples/ingress/usage.yaml
$ for i in 1 2 3; do curl http://localhost:3000${i}/foo; done foo foo foo $ for i in 1 2 3; do curl http://localhost:3000${i}/bar; done bar bar bar $ for i in 1 2 3; do curl -k https://localhost:3001${i}/foo; done foo foo foo $ for i in 1 2 3; do curl -k https://localhost:3001${i}/bar; done bar bar bar
想定どおりですね。
まとめ
ネットワーク周りには制約がありますが、ローカルでマルチnodeの確認ができるのは良いですね。extraPortMappingsあたりの設定はクラスタ作成時にやってしまう必要があり(あとから設定変更する方法はわかっていない)、場合によってはクラスタ作り直しの必要があるのですが、サクッとできてしまうのでそれほど苦にならない気がしました。