LinuCエヴァンジェリストの鯨井貴博@opensourcetechです。
はじめに
今回は、こちらの記事で作成したkubernetesクラスター v1.26.00で、
MetalLBとService(type:LoadBalancer)を使って外部クライアントへのサービス公開をやってみます。
なお、サービス公開はDual Stack(IPv4&IPv6)で行います。
Serviceとは
kubernetesにおけるServiceは、起動済みのPod(コンテナ)へと外部からアクセスする手段の一つであり、以下の4種類があります。
ClusterIP:kubernetesクラスター内部のPodなどからアクセスする
NodePort:kubernetesクラスターを構成するノード(Master/Worker)が持つIPアドレスの特定ポート(デフォルト設定だと、30000-32767)を公開する
LoadBalancer:連携するLBから払い出された外部からのアクセスが可能なIPアドレスの指定ポートを公開する
ExternalName:DNSのCNAME(別名)レコードを使って指定したFQDNとServiceを関連付()
※Service以外にも、Ingressを使って外部アクセスを実現する方法があります。
MetalLBとは
AWS・GCP・Azureなどのクラウド環境では、外部からアクセスできるように静的にグローバルIPアドレスなどを利用できるサービスが提供されています。
AWSの静的IPアドレスサービス/Elastic IP アドレス
GCPの静的IPアドレスサービス
Azureの静的IPアドレスサービス
各クラウドサービスでは、ユーザからの静的IPアドレス要求に対して払い出しをするための機能を実装しています。
しかし、ローカルで構築したkubernetes環境ではこれと同等の機能を有していないため、MetalLBなどを使って、これを実現させます。
MetalLBのインストール
こちらに記載されている方法でインストールします。
ログを見ると、namespace(名前空間)"metallb-system"・controller(リソースの管理)・speaker(Serviceに付与するIPへの通信の処理など)・ipaddresspools(Serviceへ付与するIPのリスト)やl2advertisements(Serviceへ付与するIPアドレスの広報)などのCRD(CustomeResourceDifinition)などがデプロイされているのが分かります。
kubeuser@master01:~$ kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.13.9/config/manifests/metallb-native.yaml namespace/metallb-system created customresourcedefinition.apiextensions.k8s.io/addresspools.metallb.io created customresourcedefinition.apiextensions.k8s.io/bfdprofiles.metallb.io created customresourcedefinition.apiextensions.k8s.io/bgpadvertisements.metallb.io created customresourcedefinition.apiextensions.k8s.io/bgppeers.metallb.io created customresourcedefinition.apiextensions.k8s.io/communities.metallb.io created customresourcedefinition.apiextensions.k8s.io/ipaddresspools.metallb.io created customresourcedefinition.apiextensions.k8s.io/l2advertisements.metallb.io created serviceaccount/controller created serviceaccount/speaker created role.rbac.authorization.k8s.io/controller created role.rbac.authorization.k8s.io/pod-lister created clusterrole.rbac.authorization.k8s.io/metallb-system:controller created clusterrole.rbac.authorization.k8s.io/metallb-system:speaker created rolebinding.rbac.authorization.k8s.io/controller created rolebinding.rbac.authorization.k8s.io/pod-lister created clusterrolebinding.rbac.authorization.k8s.io/metallb-system:controller created clusterrolebinding.rbac.authorization.k8s.io/metallb-system:speaker created secret/webhook-server-cert created service/webhook-service created deployment.apps/controller created daemonset.apps/speaker created validatingwebhookconfiguration.admissionregistration.k8s.io/metallb-webhook-configuration created
少し待つと、Deployments/ReplicaSet/Podが起動完了となります。
kubeuser@master01:~$ kubectl get ns NAME STATUS AGE default Active 21h kube-node-lease Active 21h kube-public Active 21h kube-system Active 21h metallb-system Active 21s kubeuser@master01:~$ kubectl get all -n metallb-system NAME READY STATUS RESTARTS AGE pod/controller-68bf958bf9-qpwrj 1/1 Running 0 4m55s pod/speaker-8cmkk 1/1 Running 0 4m55s pod/speaker-fjjfg 1/1 Running 0 4m55s pod/speaker-wgxdr 1/1 Running 0 4m55s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/webhook-service ClusterIP 10.1.53.189 <none> 443/TCP 4m56s NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE daemonset.apps/speaker 3 3 3 3 3 kubernetes.io/os=linux 4m56s NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/controller 1/1 1 1 4m56s NAME DESIRED CURRENT READY AGE replicaset.apps/controller-68bf958bf9 1 1 1 4m56s
Serviceへ付与するIPアドレスリストの適用
IPAddressPoolとL2Advertisementをデプロイします。
※IPv4とIPv6の両方を設定しています。
※設定するIPアドレスは、それぞれの環境で合わせてください。
kubeuser@master01:~$ vi metallb-address-pool.yaml kubeuser@master01:~$ cat metallb-address-pool.yaml apiVersion: metallb.io/v1beta1 kind: IPAddressPool metadata: name: metallb-address-pool namespace: metallb-system spec: addresses: - 192.168.1.50-192.168.1.59 - 240f:32:57b8:1::1:0/112 --- apiVersion: metallb.io/v1beta1 kind: L2Advertisement metadata: name: metallb-l2advertisement namespace: metallb-system spec: ipAddressPools: - metallb-address-pool kubeuser@master01:~$ kubectl apply -f metallb-address-pool.yaml ipaddresspool.metallb.io/metallb-address-pool created l2advertisement.metallb.io/metallb-l2advertisement created
デプロイ出来ました。
これでMetalLBに関する作業は完了です。
kubeuser@master01:~$ kubectl get ipaddresspools.metallb.io -n metallb-system NAME AUTO ASSIGN AVOID BUGGY IPS ADDRESSES metallb-address-pool true false ["192.168.1.50-192.168.1.59","240f:32:57b8:1::1:0/112"] kubeuser@master01:~$ kubectl get l2advertisements.metallb.io -n metallb-system NAME IPADDRESSPOOLS IPADDRESSPOOL SELECTORS INTERFACES metallb-l2advertisement ["metallb-address-pool"]
Service(type:LoadBalancer)のデプロイ
予め用意したDeployments"nginx"をServiceで公開します。
kubeuser@master01:~$ kubectl get deployments NAME READY UP-TO-DATE AVAILABLE AGE nginx 1/1 1 1 22h
Serviceのyamlファイルを作成して、デプロイします。
なお、Dual Stack環境のService yamlファイルの記載方法は、
こちらを参照ください。
kubeuser@master01:~$ vi svc_nginx_loadbalancer.yaml kubeuser@master01:~$ cat svc_nginx_loadbalancer.yaml apiVersion: v1 kind: Service metadata: labels: app: nginx name: nginx spec: ipFamilies: - IPv4 - IPv6 ipFamilyPolicy: RequireDualStack ports: - port: 80 protocol: TCP targetPort: 80 selector: app: nginx type: LoadBalancer status: loadBalancer: {} kubeuser@master01:~$ kubectl apply -f svc_nginx_loadbalancer.yaml service/nginx created kubeuser@master01:~$ kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.1.0.1 <none> 443/TCP 22h nginx LoadBalancer 10.1.243.106 192.168.1.50,240f:32:57b8:1::1:0 80:30586/TCP 5s kubeuser@master01:~$ kubectl get svc nginx -o yaml apiVersion: v1 kind: Service metadata: annotations: kubectl.kubernetes.io/last-applied-configuration: | {"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"labels":{"app":"nginx"},"name":"nginx","namespace":"default"},"spec":{"ipFamilies":["IPv4","IPv6"],"ipFamilyPolicy":"RequireDualStack","ports":[{"port":80,"protocol":"TCP","targetPort":80}],"selector":{"app":"nginx"},"type":"LoadBalancer"},"status":{"loadBalancer":{}}} metallb.universe.tf/ip-allocated-from-pool: metallb-address-pool creationTimestamp: "2023-03-15T12:17:21Z" labels: app: nginx name: nginx namespace: default resourceVersion: "121450" uid: f63b731c-29e8-4d79-a8d2-c261d5e0da12 spec: allocateLoadBalancerNodePorts: true clusterIP: 10.1.243.106 clusterIPs: - 10.1.243.106 - fd12:b5e0:383f::2971 externalTrafficPolicy: Cluster internalTrafficPolicy: Cluster ipFamilies: - IPv4 - IPv6 ipFamilyPolicy: RequireDualStack ports: - nodePort: 30586 port: 80 protocol: TCP targetPort: 80 selector: app: nginx sessionAffinity: None type: LoadBalancer status: loadBalancer: ingress: - ip: 192.168.1.50 - ip: 240f:32:57b8:1::1:0
外部クライアントからのアクセス
Serivce(type:LoadBalancer)で公開されたIPv4/IPv6のアドレスにアクセスしてみます。
アクセス成功!
参考
MetalLBの設定で使った"metallb-address-pool.yaml"ですが、
version0.12まではconfigmapを使って定義していました。
それが、version0.13からはCRDs(CustomeResourceDefinitions)を使うように変更されました。
詳細は、こちら
おわりに
今回kubernetes v1.26(Dual Stack) + MetalLB(CRDs)という環境を使いましたが、
以前 kubernetes v1.22(IPv4のみ) + MetalLB(当時はconfigmapで設定していた)で動作させた時とは設定方法など変化していることを発見しました。
改めて、使用しているソフトウェアの更新情報はちゃんとチェックしないといけないなぁと感じた次第。
今回気づいたこと
・MetalLBがversion0.13からconfigmapではなく、CRDsでipaddresspoolを設定するようになっていた
・kubernetesでIPv6(Single Stack/Dual Stackのいずれも)を使う場合は、明示的に使用することを設定する必要がある
・MetalLBの"l2advertisements"を有効にしないと、外部クライアントでarp解決が出来ずService(type:LoadBalancer)で公開したIPアドレスにはアクセスできない