背景:仕事でK8Sを使う必要性が出てきた。k8sを理解する必要あり
アプローチ:K8S解説本を読みながら、ローカル環境でK8Sを動かして仕組みを理解する
結論:Pod + LBの構成で、nginxを動かすところまではできた (kind (Kubernetes in Docker)を使用)
詳細:
昨日はkindを使ってUbuntu上にk8s環境を構築、nginxのPODを走らせるまでは進んだが、Ubuntu側のネットワークから、nginxのホストにLB経由で接続することができなかった。再度トライする
再起動したUbuntu上で、kindが動いていて、podも稼働している。試行錯誤したLBService類は一旦全て消した。
$ kubectl get all NAME READY STATUS RESTARTS AGE pod/hello-world 0/1 Completed 0 15h pod/nginx 1/1 Running 1 (4m39s ago) 14h NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 15h $ kubectl describe pod nginx Name: nginx Namespace: default Priority: 0 Service Account: default Node: kind-worker2/172.18.0.2 Start Time: Sat, 10 Jun 2023 21:18:46 +0900 Labels: <none> Annotations: <none> Status: Running IP: 10.244.2.2 IPs: IP: 10.244.2.2
Pod同士が通信するInternalNetworkにおいて、nginxのIPは、10.244.2.2であると。
もう一度NodeやContainerに入って確認する
Node内で確認したIP
# ip address
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: vethcf9343aa@if2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 86:95:4e:35:9e:e7 brd ff:ff:ff:ff:ff:ff link-netns cni-ba734f88-cf32-09d3-7cb1-0f3d7d23e39c
inet 10.244.2.1/32 scope global vethcf9343aa
valid_lft forever preferred_lft forever
5: eth0@if6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:12:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.18.0.2/16 brd 172.18.255.255 scope global eth0Pod内で確認したIP
$ kubectl exec -it nginx -- /bin/bash
# ip address
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0@if2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 92:8e:29:95:85:71 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 10.244.2.2/24 brd 10.244.2.255 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::908e:29ff:fe95:8571/64 scope link
valid_lft forever preferred_lft forever
# apt update
# apt install iproute2
# ss -napt | grep LISTEN
LISTEN 0 511 0.0.0.0:80 0.0.0.0:* users:(("nginx",pid=1,fd=6))
LISTEN 0 511 [::]:80 [::]:* users:(("nginx",pid=1,fd=7))再度解説本に従って、lb-config.yamlを作成
apiVersion: v1
kind: Service
metadata:
name: ngx-lb
spec:
type: LoadBalancer
selector:
app: nginx
ports:
- name: "http-port"
protocol: "TCP"
port: 8080
targetPort: 80読み込ませて確認
$ kubectl apply -f lb_config.yaml service/ngx-lb created $ kubectl describe service ngx-lb Name: ngx-lb Namespace: default Labels: <none> Annotations: <none> Selector: app=nginx Type: LoadBalancer IP Family Policy: SingleStack IP Families: IPv4 IP: 10.96.187.65 IPs: 10.96.187.65 LoadBalancer Ingress: 172.18.255.200 Port: http-port 8080/TCP TargetPort: 80/TCP NodePort: http-port 30028/TCP Endpoints: <none> Session Affinity: None External Traffic Policy: Cluster Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal IPAllocated 103s metallb-controller Assigned IP ["172.18.255.200"] $ curl -v http://172.18.255.200:8080 * Trying 172.18.255.200:8080... * connect to 172.18.255.200 port 8080 failed: No route to host * Failed to connect to 172.18.255.200 port 8080 after 3058 ms: No route to host * Closing connection 0 curl: (7) Failed to connect to 172.18.255.200 port 8080 after 3058 ms: No route to host
やっぱりエラーになる。Endpointsが <none>だし。。そもそも、NodePortが作られていないのがおかしいのではないか。
kind的な書き方をしないとだめなのではなかろうか。
kindのドキュメントに従ってもう一度やってみる。振り出し用IPレンジの設定はOKだろう
$ docker network inspect -f '{{.IPAM.Config}}' kind
[{172.18.0.0/16 172.18.0.1 map[]} {fc00:f853:ccd:e793::/64 fc00:f853:ccd:e793::1 map[]}]
$ kubectl get IPAddressPool -n metallb-system
NAME AUTO ASSIGN AVOID BUGGY IPS ADDRESSES
example true false ["172.18.255.200-172.18.255.250"]
$ kubectl get L2Advertisement -n metallb-system
NAME IPADDRESSPOOLS IPADDRESSPOOL SELECTORS INTERFACES
emptyLB Serviceのdemoを動かしてみる
kind: Pod
apiVersion: v1
metadata:
name: foo-app
labels:
app: http-echo
spec:
containers:
- name: foo-app
image: hashicorp/http-echo:0.2.3
args:
- "-text=foo"
---
kind: Pod
apiVersion: v1
metadata:
name: bar-app
labels:
app: http-echo
spec:
containers:
- name: bar-app
image: hashicorp/http-echo:0.2.3
args:
- "-text=bar"
---
kind: Service
apiVersion: v1
metadata:
name: foo-service
spec:
type: LoadBalancer
selector:
app: http-echo
ports:
- port: 5678$ kubectl describe service foo-service Name: foo-service Namespace: default Labels: <none> Annotations: <none> Selector: app=http-echo Type: LoadBalancer IP Family Policy: SingleStack IP Families: IPv4 IP: 10.96.38.248 IPs: 10.96.38.248 LoadBalancer Ingress: 172.18.255.200 Port: <unset> 5678/TCP TargetPort: 5678/TCP NodePort: <unset> 31116/TCP Endpoints: 10.244.1.3:5678,10.244.2.3:5678 Session Affinity: None $ kubectl get all NAME READY STATUS RESTARTS AGE pod/bar-app 1/1 Running 0 4m12s pod/foo-app 1/1 Running 0 4m12s pod/nginx 1/1 Running 1 (92m ago) 16h NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/foo-service LoadBalancer 10.96.38.248 172.18.255.200 5678:31116/TCP 4m12s service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 16h $ kubectl describe pod foo-app Name: foo-app Namespace: default Priority: 0 Service Account: default Node: kind-worker2/172.18.0.2 Start Time: Sun, 11 Jun 2023 13:28:04 +0900 Labels: app=http-echo Annotations: <none> Status: Running IP: 10.244.2.3
$ kubectl get svc/foo-service -o json
*略*
"status": {
"loadBalancer": {
"ingress": [
{
"ip": "172.18.255.200"
}
]
}
}
}連続的に呼び出してみると確かにバランスしている。NodePortもEndPointも設定されている。
$ while [ 1 ] ; do curl http://172.18.255.200:5678 ; sleep 1 ; done bar bar foo foo bar foo bar bar
nginxに対してLBが設定できないのは、Lables: <none>が原因ではないかと推測
$ kubectl describe pod nginx Name: nginx Namespace: default Priority: 0 Service Account: default Node: kind-worker2/172.18.0.2 Start Time: Sat, 10 Jun 2023 21:18:46 +0900 Labels: <none>
labelを追加したyamlを適用
$ cat nginx-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latest
$ kubectl apply -f nginx-pod.yaml
pod/nginx configured
$ kubectl describe pod nginx
Name: nginx
Namespace: default
Priority: 0
Service Account: default
Node: kind-worker2/172.18.0.2
Start Time: Sat, 10 Jun 2023 21:18:46 +0900
Labels: app=nginx
Annotations: <none>
Status: Running
IP: 10.244.2.2Labelが付いたところで、再度LB設定を行う
$ cat lb-ngin-service.yaml
kind: Service
apiVersion: v1
metadata:
name: lb-nginx
spec:
type: LoadBalancer
selector:
app: nginx
ports:
- port: 8080
$ kubectl apply -f lb-
lb-demo.yaml lb-ngin-service.yaml lb-service.yaml
$ kubectl apply -f lb-ngin-service.yaml
service/lb-nginx created
$ kubectl describe service lb-nginx
Name: lb-nginx
Namespace: default
Labels: <none>
Annotations: <none>
Selector: app=nginx
Type: LoadBalancer
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.96.242.14
IPs: 10.96.242.14
LoadBalancer Ingress: 172.18.255.201
Port: <unset> 8080/TCP
TargetPort: 8080/TCP
NodePort: <unset> 31628/TCP
Endpoints: 10.244.2.2:8080
Session Affinity: None
External Traffic Policy: Cluster今度は、NodePort, Endpointsも設定されている。curlで確認
$ curl -v http://172.18.255.201:8080 * Trying 172.18.255.201:8080... * connect to 172.18.255.201 port 8080 failed: Connection refused * Failed to connect to 172.18.255.201 port 8080 after 0 ms: Connection refused * Closing connection 0 curl: (7) Failed to connect to 172.18.255.201 port 8080 after 0 ms: Connection refused
これはTargetPortが8080になっているためと思われる。再度修正
$ cat lb-ngin-service.yaml
kind: Service
apiVersion: v1
metadata:
name: lb-nginx
spec:
type: LoadBalancer
selector:
app: nginx
ports:
- port: 8080
targetPort: 80
$ kubectl apply -f lb-ngin-service.yaml
service/lb-nginx created
$ kubectl describe service lb-nginx
Name: lb-nginx
Namespace: default
Labels: <none>
Annotations: <none>
Selector: app=nginx
Type: LoadBalancer
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.96.242.14
IPs: 10.96.242.14
LoadBalancer Ingress: 172.18.255.201
Port: <unset> 8080/TCP
TargetPort: 80/TCP
NodePort: <unset> 31628/TCP
Endpoints: 10.244.2.2:80
Session Affinity: None
External Traffic Policy: ClusterTargetPortが80になってるのを確認。curlで叩くとHTMLが返却された。
$ curl http://172.18.255.201:8080
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
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>上記構成を実現するための設定ファイル
file: nginx-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latestfile: lb-nginx-service.yaml
apiVersion: v1
kind: Service
metadata:
name: lb-nginx
spec:
type: LoadBalancer
selector:
app: nginx
ports:
- port: 8080
targetPort: 80■補足 バージョン確認
$ kubectl version --short Flag --short has been deprecated, and will be removed in the future. The --short output will become the default. Client Version: v1.27.2 Kustomize Version: v5.0.1 Server Version: v1.27.1
■K8S 学習パス
K8Sは多機能かつ、複雑であり、どこから勉強を開始したらよいのやらという感じと思います。
自分の場合は、、AWS EKS HandsOnをやってK8Sの全体像を薄く理解して、次に「Dockerから入るKubernetes」をざっと読んで、「Kubernetes完全ガイド」を詳しく読んで勉強しています。
「Dockerから入る・・」は表紙の印象で易しそうな感じですが、実際は手を動かす演習が大量に入っています。「Dockerから入る・・」を読みながら、HelloWorldだけのPODを走らせたり、Nginx+LBの構成を組んでみたりしました。Nginxの入ったPodを単体で動かして上位にLBを配置する構成で、Podとの疎通が行えない問題が発生しました。詳しい人だとログを調べて原因を絞り込めるのかもしれませんが、なぜEndpointが生成されないのか?まで突き止められませんでした。「Kubernetes完全ガイド」は細かい所まで丁寧に解説されていて、K8Sのネットワークサービスがだいたい理解でき、原因も試行錯誤で調べることができました。K8SでLB+Pod構成を組んだ時の構成図が書けたのも、「完全ガイド」のお陰でございます。
■仕事レベルとの差異
K8Sの入り口までは学んだが、、仕事のレベルとは程遠い。今後学ぶべきは、、(1)ロードバランサIngress(ALB)、(2)コンテナイメージを管理するリポジトリ、Dockerイメージのビルド,(3)多重化構成、キャパシティ管理 , (4)AWSで満たすべき各種権限(Policy/Role)、(5) CI/CD化、といった所か。。

