例えば
ゲーム用のDedicated Serverによくありがちな、ConnectionにUDPをQueryにTCPを使用するような、1プロセスで複数のプロトコルを併用するようなプロセスをKubernetes環境に載せようとする。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
kind: Service apiVersion: v1 metadata: name: acserver4-service namespace: acserver labels: app: acserver1 spec: type: LoadBalancer ports: - name: query1 port: 9610 targetPort: 9610 protocol: TCP - name: query2 port: 8085 targetPort: 8085 protocol: TCP - name: connection port: 9610 targetPort: 9610 protocol: UDP selector: app: acserver1 loadBalancerIP: 192.168.1.200 |
このような、UDPとTCPが混在しているServiceをデプロイしようとする。type: NodePortを使用している場合は(恐らくは)問題ないけれど、type: LoadBalancerを使用する環境だと下記の様なエラーが返る。
1 2 3 |
$ kubectl apply -f kubernetes/game_servers/acserver/acservertest.yaml The Service "acserver4-service" is invalid: spec.ports: Invalid value: []core.ServicePort{core.ServicePort{Name:"query1", Protocol:"TCP", Port:9610, TargetPort:intstr.IntOrString{Type:0, IntVal:9610, StrVal:""}, NodePort:0}, core.ServicePort{Name:"query2", Protocol:"TCP", Port:8085, TargetPort:intstr.IntOrString{Type:0, IntVal:8085, StrVal:""}, NodePort:0}, core.ServicePort{Name:"connection", Protocol:"UDP", Port:9610, TargetPort:intstr.IntOrString{Type:0, IntVal:9610, StrVal:""}, NodePort:0}}: cannot create an external load balancer with mix protocols |
このKubernetes環境ではL4LBとしてMetalLBで、L7LBとしてIngressでそれぞれLBが収容しているので、Bare-Metalなk8s環境でLBを用意していないが、type: LoadBalancerを使用することができる。
原因と対策
1 2 |
cannot create an external load balancer with mix protocols |
単純に、type: LoadBalancerはmixed protocolsをサポートしない。今後のk8sも恐らくサポートされない。詳細はこのPull Reqestが詳しいと思う。
Allow for mixed UDP/TCP ports on LoadBalancer Services by Miouge1 · Pull Request #64471 · kubernetes/kubernetes · GitHub
そもそもMetalLBの様なUDPをサポートするLoadBalancerの方が例外的で、通常はTCPの負荷分散に使用される。なのでMixedでLoadBalancer指定はどちらかと言えば例外的(本来は必要ない)と思う。
対策
単純に「別々のserviceを作成する」のが正しい。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
--- kind: Service apiVersion: v1 metadata: name: acserver1-service-tcp namespace: acserver labels: app: acserver1 annotations: metallb.universe.tf/allow-shared-ip: "acserver-service" spec: type: LoadBalancer ports: - name: query1 port: 9610 targetPort: 9610 protocol: TCP - name: query2 port: 8085 targetPort: 8085 protocol: TCP selector: app: acserver1 loadBalancerIP: 192.168.1.144 --- kind: Service apiVersion: v1 metadata: name: acserver1-service-udp namespace: acserver labels: app: acserver1 annotations: metallb.universe.tf/allow-shared-ip: "acserver-service" spec: type: LoadBalancer ports: - name: connection port: 9610 targetPort: 9610 protocol: UDP selector: app: acserver1 loadBalancerIP: 192.168.1.144 --- |
ただし、そのままではプロトコル別にIPアドレスを分けないとMetalLBのRouterからアドレスが割り当てられないので(恐らくPendingの状態で止まると思う)、annotationを付けて調整する必要がある。
1 2 3 |
annotations: metallb.universe.tf/allow-shared-ip: "acserver-service" |
annotationのvalueが、そのまま関連付けるserviceのsharing key(関連付けの為のキー)になるので、適当な一意の名前付けをする。
詳細はMetalLBのドキュメントが詳しい。
MetalLB, bare metal load-balancer for Kubernetes