#1. 目的
- AWS Wavelength では、2021/11現在ではELB(CLB/ALB/NLB全て)が未提供。そのため、Wavelength Zoneにてインスタンスやコンテナの負荷分散を行う場合、自分で仕組みを用意する必要がある。例えば、北米でAWS Wavelengthに接続可能な回線を提供するVerizon社の、Wavelengthに関するQAサイトにも、ELBの代替例としてHAProxyが推奨されている。
What can I use in place of AWS Elastic Load Balancing to automatically distribute incoming application traffic across multiple targets, such as Amazon EC2 instances?
Consider using Amazon EC2 as a proxy server and configuring HAProxy, a free, open source software implementation of a high availability load balancer. To learn more about HAProxy, visit the HAProxy configuration manual here.
- 今回は、ELBの代替として、商用プロダクトであり信頼性も高い、F5社のBIG-IP Virtual Edition(AWSなどのクラウドで動作するロードバランサ)を用いて、コンテナの負荷分散が実現可能なことを確認する。
#2. やったこと
- Wavelength上にEKS環境を構築し、コンテナを起動する。
- Wavelength上にBIG-IPをデプロイし、コンテナの負荷分散が可能なことを確認する。以下の2方式で確認する。
- Ingress
- Service type LoadBalancer
- BIG-IPには、EKS環境にデプロイするコントローラ(CIS: F5 Container Ingress Services) から動的に設定を投入する。
- なお今回、Wavelength環境での検証を行っているが、Wavelengthに依存する設定はないため、同様の内容を東京リージョンなどのEKS環境で実現することも可能。
#3. 構成
##全体の構成
- Wavelength上にEKSのノードグループを用意し、コントローラ(CIS)、サンプルアプリをデプロイする。
- ノードグループと同じサブネットにBIG-IPをデプロイし、外部からBIG-IP経由でサンプルアプリにアクセスできるようにする。
##Ingress の場合
- EKS上ではIngressリソースを作成する(BIG-IPがそれに合わせて自動設定される)。
- BIG-IP経由でサンプルアプリのPodまでアクセスできることを確認する。
##Service type LoadBalancerの場合
- EKS上ではService type Loadbalancer リソースを作成する(BIG-IPがそれに合わせて自動設定される)。
- BIG-IP経由でサンプルアプリのPodまでアクセスできることを確認する。
#4. 手順
##4.1 環境の準備
EKS環境の構築
- 以前の記事「【初心者】AWS Wavelengthを使ってみる #2 (Amazon EKSの利用)」を参考に、Wavelength上にEKS環境を構築する。
- Kubernetesのバージョンはv1.21(2021/11時点のEKSでの最新バージョン)
- 通常時のワーカーノード数は2(Wavelength Zoneに t3.mediumのインスタンスが2個ある状態)
- ワーカーノードへキャリアIPを付与する(今回は直接外部にコンテナイメージを取得に行かせるため)。
- ワーカーノードはサブネット内(10.0.10.0/24)からのアクセスを許可する(後で同一サブネットに作成するF5 BIG-IPからコンテナへのアクセスを許可するため)。
テスト用ウェブサービスの作成
- 後でF5 BIG-IPを用いてインターネットへ公開する用の、テスト用のウェブサービスを作成する。(httpアクセスすると、ノード名、pod名が返されるだけのシンプルなサービス)
- nginxが提供するサンプル(cafe.yaml) をそのままデプロイする。結果として以下の状態になる。
[ec2-user@ip-10-0-0-151 ~]$ kubectl get deployment
NAME READY UP-TO-DATE AVAILABLE AGE
coffee 2/2 2 2 26h
tea 3/3 3 3 26h
[ec2-user@ip-10-0-0-151 ~]$ kubectl get pods
NAME READY STATUS RESTARTS AGE
coffee-6f4b79b975-b7tch 1/1 Running 0 26h
coffee-6f4b79b975-n422v 1/1 Running 0 26h
tea-6fb46d899f-5vqlx 1/1 Running 0 26h
tea-6fb46d899f-f98zc 1/1 Running 0 26h
tea-6fb46d899f-x7wkv 1/1 Running 0 26h
[ec2-user@ip-10-0-0-151 ~]$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
coffee-svc ClusterIP 172.20.73.10 <none> 80/TCP 26h
kubernetes ClusterIP 172.20.0.1 <none> 443/TCP 2d6h
tea-svc ClusterIP 172.20.179.79 <none> 80/TCP 26h
- このcoffee-svc/tea-svcについて、BIG-IPを用いて外部からのアクセスを可能にするよう設定していく。
##4.2 BIG-IPの設定
インスタンスの起動
- BIG-IP VEをWavelength上のサブネット(EKSのワーカーノード2個が起動しているのと同じサブネット)にデプロイする。
- イメージ名: F5 BIG-IP VE - ALL (BYOL, 2 Boot Locations) ※ライセンス込みのタイプ(PAYG)もあるが、今回はライセンスはBYOLとし、別途F5社より検証用ライセンスを発行頂いたものを用いる。
- インスタンスタイプ: t3.medium
- バージョン: 16.1.1 Build 0.0.16
- キャリアIPを付与し、外部からのアクセスを可能にする。
- 同一サブネット(10.0.10.0/24)からのアクセスを許可する。(ワーカーノード上に配置されるF5のコントローラからのアクセスを受けるため)
管理画面用パスワード設定
- ssh(user: admin, 秘密鍵) で接続し、管理画面用のパスワードを設定、保存する。
admin@(ip-10-0-10-63)(cfg-sync Standalone)(NO LICENSE)(/Common)(tmos)# modify auth user admin password PASSWORD
admin@(ip-10-0-10-63)(cfg-sync Standalone)(NO LICENSE)(/Common)(tmos)# save sys config
ライセンスの設定
- 管理画面 ( https://BIG-IPインスタンスのキャリアIP:8443 )にアクセスし、user: admin, password: 上記で設定したパスワードで、ログインする。
- F5社から発行頂いた検証用ライセンスを設定する。
Partition作成
- 専用のPartition(BIG-IP内の管理領域のようなもの)を作成する。 System -> Users: Partition List -> New Partition で、新規に「k8s]というPartitionを作成する。
AS3の追加
- 「AS3(Application Services 3 Extension)」は、BIG-IPを外部から操作することを可能とする拡張モジュールのようなもの。
- F5社のGitHubから、rpmファイル(f5-appsvcs-3.28.0-3.noarch.rpm)を作業用PCなどにダウンロードする。今回は v3.28.0 を使用する。
- BIG-IPの管理画面で、iApps -> Package Management LX から、rpmファイルをインポートする。
##4.3 Ingress での設定
CIS 用権限などの作成
- CISは、k8sなどのコンテナ環境とF5 BIG-IPを連携させるような仕組み。
- まずはEKS上でCISのコントローラ(k8s-bigip-ctlr)を動作させるための権限などを用意する。(もう少し細かく権限付与も可能だが、今回は検証のためざっくりclusteradmin権限を付与)
[ec2-user@ip-10-0-0-151 ~]$ kubectl create secret generic bigip-login -n kube-system --from-literal=username=admin --from-literal=password=PASSWORD
secret/bigip-login created
[ec2-user@ip-10-0-0-151 ~]$ kubectl create serviceaccount k8s-bigip-ctlr -n kube-system
serviceaccount/k8s-bigip-ctlr created
[ec2-user@ip-10-0-0-151 ~]$ kubectl create clusterrolebinding k8s-bigip-ctlr-clusteradmin --clusterrole=cluster-admin --serviceaccount=kube-system:k8s-bigip-ctlr
clusterrolebinding.rbac.authorization.k8s.io/k8s-bigip-ctlr-clusteradmin created
CIS (k8s-bigip-ctlr) の作成
- EKS環境でIngressリソースを作成した時に、BIG-IPに適切な設定が自動投入されるようにするため、CIS (k8s-bigip-ctlr) を作成する。これがIngress Controllerとして動作する。
- 以下のマニフェストを用いる。「--bigip-url=https://10.0.10.63:8443」のところは、BIG-IPのインスタンスのローカルIPアドレスを指定する。
- 今回は他環境で動作実績のあるバージョン(v2.5.1)を使用している。
apiVersion: apps/v1
kind: Deployment
metadata:
name: k8s-bigip-ctlr
namespace: kube-system
spec:
replicas: 1
selector:
matchLabels:
app: k8s-bigip-ctlr
template:
metadata:
name: k8s-bigip-ctlr
labels:
app: k8s-bigip-ctlr
spec:
serviceAccountName: k8s-bigip-ctlr
containers:
- name: k8s-bigip-ctlr
image: "f5networks/k8s-bigip-ctlr:2.5.1"
imagePullPolicy: IfNotPresent
env:
- name: BIGIP_USERNAME
valueFrom:
secretKeyRef:
name: bigip-login
key: username
- name: BIGIP_PASSWORD
valueFrom:
secretKeyRef:
name: bigip-login
key: password
command: ["/app/bin/k8s-bigip-ctlr"]
args: [
"--bigip-username=$(BIGIP_USERNAME)",
"--bigip-password=$(BIGIP_PASSWORD)",
"--bigip-url=https://10.0.10.63:8443",
"--insecure=true",
"--bigip-partition=k8s",
"--pool-member-type=cluster"
]
[ec2-user@ip-10-0-0-151 ~]$ kubectl apply -f cluster-deployment.yaml
deployment.apps/k8s-bigip-ctlr created
[ec2-user@ip-10-0-0-151 ~]$ kubectl get pods -n kube-system
NAME READY STATUS RESTARTS AGE
aws-node-8jlzx 1/1 Running 0 55m
aws-node-tb5kn 1/1 Running 0 15h
coredns-76f4967988-5wvjr 1/1 Running 0 14h
coredns-76f4967988-vfxsv 1/1 Running 0 27h
k8s-bigip-ctlr-6989b8bf6c-z9jc9 1/1 Running 0 25s
kube-proxy-85tgh 1/1 Running 0 15h
kube-proxy-qkkbk 1/1 Running 0 55m
- 成功すると、k8s-bigip-ctlrのpodがRunningになる。(BIG-IPのアクセスURLやポートが間違っていたり、BIG-IPへのアクセスがsecuritygroupで拒否されていたりして、BIG-IPにアクセスできない場合、podの作成に失敗する。)
IngressClassの作成
- CISで使用するIngressClassを作成する。
[ec2-user@ip-10-0-0-151 ~]$ kubectl apply -f https://raw.githubusercontent.com/F5Networks/k8s-bigip-ctlr/master/docs/config_examples/ingress/networkingV1/example-default-ingress-class.yaml
ingressclass.networking.k8s.io/f5 created
Ingress リソースの作成
- 以下のマニフェストを用いて、Ingress リソースを作成する。「https://BIG-IPのキャリアIP/tea」 の場合はteaのサービスに、「https://BIG-IPのキャリアIP/coffee」の場合はcoffeeのサービスに転送するような設定としている)
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: cafe-ingress
annotations:
virtual-server.f5.com/partition: "k8s"
virtual-server.f5.com/ip: 10.0.10.63
virtual-server.f5.com/http-port: "80"
virtual-server.f5.com/ssl-redirect: "false"
virtual-server.f5.com/balance: "round-robin"
spec:
ingressClassName: f5
rules:
- http:
paths:
- path: /tea
backend:
serviceName: tea-svc
servicePort: 80
- path: /coffee
backend:
serviceName: coffee-svc
servicePort: 80
[ec2-user@ip-10-0-0-151 ~]$ kubectl apply -f ingress-cafe.yaml
Warning: networking.k8s.io/v1beta1 Ingress is deprecated in v1.19+, unavailable in v1.22+; use networking.k8s.io/v1 Ingress
ingress.networking.k8s.io/cafe-ingress created
[ec2-user@ip-10-0-0-151 ~]$ kubectl get ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
cafe-ingress f5 * 10.0.10.63 80 7s
BIG-IPの自動設定投入確認
-
Ingress リソース作成後、BIG-IPに必要な設定が入ることを確認する。
-
Virtual Server (待ち受けするアドレス・ポート、転送先のPoolなどの設定のセット)が作成される。
- Virtual Server に紐づくPolicy(URIの部分(tea もしくは coffee)を見てそれぞれ別のPoolに転送する)が設定される。
動作確認
- 手元のPC(auスマホでテザリング)のブラウザ(FirefoxとEdge)から、「http://BIG-IPのキャリアIP/coffee」 にアクセスする。coffeeサービス用の2つのPodのどちらかで処理されることを確認する。(アクセス時、以下のように処理を行ったホストのIPアドレスやPod名が表示されることで判別可能)
- 同様に 「http://BIG-IPのキャリアIP/tea」 にアクセスすると、tea サービスを処理するPod(3つのどれか)へアクセス可能。URIに応じて別々のサービスにアクセスできていることが確認できる。
- BIG-IPのStatisticsの画面で、/coffee にアクセスした場合、coffeeサービス用の2つのPodに処理が分散されていることが確認できる。
##4.4 Service Type LoadBalancer での設定
FIC(F5 IPAM Controller)の作成
- Service Type LoadBalancerでの設定の場合、IPアドレスの割り当て管理管理が必要となるため、「FIS(IPAM Controller)」を追加で作成する。
- 以下のマニフェストを使用する。
- 今回はv0.1.4(2021/11時点の最新版はv0.1.5)を使用している。v0.1.5から信頼性の向上のためか、PVの使用が必要となっており検証用としては煩雑だったため。
- 「--ip-range」として、この環境のサブネットの中から、配布したいIPアドレスのレンジを指定する。
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
name: ipam-controller
name: ipam-controller
namespace: kube-system
spec:
replicas: 1
selector:
matchLabels:
app: ipam-controller
template:
metadata:
labels:
app: ipam-controller
spec:
containers:
- args:
- --orchestration
- kubernetes
- --ip-range
- '{"test" : "10.0.10.101-10.0.10.105","prod" : "10.0.10.111-10.0.10.115"}'
- --log-level
- DEBUG
command:
- /app/bin/f5-ipam-controller
image: f5networks/f5-ipam-controller:0.1.4
imagePullPolicy: IfNotPresent
name: ipam-controller
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
dnsPolicy: ClusterFirst
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
serviceAccount: k8s-bigip-ctlr
serviceAccountName: k8s-bigip-ctlr
terminationGracePeriodSeconds: 30
[ec2-user@ip-10-0-0-151 ~]$ kubectl apply -f ipam-controller.yaml
deployment.apps/ipam-controller created
[ec2-user@ip-10-0-0-151 ~]$ kubectl get pod -n kube-system
NAME READY STATUS RESTARTS AGE
aws-node-8jlzx 1/1 Running 0 3d10h
aws-node-tb5kn 1/1 Running 0 4d1h
coredns-76f4967988-5wvjr 1/1 Running 0 3d23h
coredns-76f4967988-vfxsv 1/1 Running 0 4d12h
ipam-controller-5f5cd96b54-4gd2r 1/1 Running 0 8s
k8s-bigip-ctlr-6989b8bf6c-z9jc9 1/1 Running 0 3d9h
kube-proxy-85tgh 1/1 Running 0 4d1h
kube-proxy-qkkbk 1/1 Running 0 3d10h
CRD作成
- BIG-IPの設定値をk8s側で管理するためのCRDを作成する。
-
F5社のGitHubの「customresourcedefinitions.yml」 を以下の2行を修正して使用する。(長いのでyamlファイルの全体の転記は省略)
- name: externaldnses.cis.f5.com -> externaldnss.cis.f5.com
- plural: externaldnses -> externaldnss
- 現在(2021/11)時点で、CIS(このCRDの利用側)と、CRDを作成するyamlで、externaldnsに関する名称の不一致(externaldnss/externaldnses)が発生している。そのうち修正されるのではと想定。
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: externaldnss.cis.f5.com
spec:
group: cis.f5.com
names:
kind: ExternalDNS
plural: externaldnss
shortNames:
- edns
singular: externaldns
[ec2-user@ip-10-0-0-151 ~]$ kubectl apply -f customresourcedefinitions-fixed.yaml
customresourcedefinition.apiextensions.k8s.io/virtualservers.cis.f5.com created
customresourcedefinition.apiextensions.k8s.io/tlsprofiles.cis.f5.com created
customresourcedefinition.apiextensions.k8s.io/transportservers.cis.f5.com created
customresourcedefinition.apiextensions.k8s.io/externaldnss.cis.f5.com created
customresourcedefinition.apiextensions.k8s.io/ingresslinks.cis.f5.com created
customresourcedefinition.apiextensions.k8s.io/policies.cis.f5.com created
CIS(k8s-bigip-ctlr)の修正
- Ingressの実施手順の際に作成したCIS(k8s-bigip-ctlr)の設定を修正して、podを再作成する。修正点は、「"--custom-resource-mode=true","--ipam=true"」の2行の追加。
args: [
"--bigip-username=$(BIGIP_USERNAME)",
"--bigip-password=$(BIGIP_PASSWORD)",
"--bigip-url=https://10.0.10.63:8443",
"--insecure=true",
"--bigip-partition=k8s",
"--pool-member-type=cluster",
"--custom-resource-mode=true",
"--ipam=true"
]
BIG-IP インスタンスへのセカンダリIPの追加
- IPAM ControllerのIPレンジで定義したIPアドレスがBIG-IPに紐づくように、BIG-IPのインスタンスの設定でセカンダリIPとしての設定を行う。
- マネージメントコンソールのEC2の画面にて、BIG-IPのインスタンスを選択し、アクション -> ネットワーキング -> IPアドレスの管理 を選択する。
- 指定したIPレンジをセカンダリIPとして追加する。
Service type LoadBalancerリソース作成
- coffee-svcのほうを外部公開するようなLoadBalancerリソースを作成する。
- 現時点(2021/11)で、EKS環境で何もannotationsを付けずにLoadBalancerリソースを作成するとCLBが作成される。「service.beta.kubernetes.io/aws-load-balancer-type: "external"」を記載することで、CLBが作成されなくなる。
- 「cis.f5.com/ipamLabel: test」を記載することで、「test」ラベルに紐づくIPレンジの中のIPアドレスが使用される。
apiVersion: v1
kind: Service
metadata:
name: coffee-typelb
annotations:
service.beta.kubernetes.io/aws-load-balancer-type: "external"
cis.f5.com/ipamLabel: test
spec:
ports:
- port: 8080
protocol: TCP
selector:
app: coffee
type: LoadBalancer
[ec2-user@ip-10-0-0-151 ~]$ kubectl apply -f typelb.yaml
service/coffee-typelb created
[ec2-user@ip-10-0-0-151 ~]$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
coffee-svc ClusterIP 172.20.73.10 <none> 80/TCP 5d8h
coffee-typelb LoadBalancer 172.20.172.14 10.0.10.101 8080:30304/TCP 4s
kubernetes ClusterIP 172.20.0.1 <none> 443/TCP 6d12h
tea-svc ClusterIP 172.20.179.79 <none> 80/TCP 5d8h
キャリアIP付与
- 今回はIPレンジの中から 10.0.10.101 が 使用されたため、このプライベートアドレスに対してキャリアIPを付与する。(BIG-IPへの管理用アクセスに用いているキャリアIPとは別のものとなる。)
- キャリアIPをインスタンスに関連付けする際、プライベートIPアドレスは先の手順でセカンダリIPとして登録したものの中から選択可能。今回はLoadBalancer用に設定された10.0.10.101を選択する。
BIG-IPの自動設定投入確認
- LoadBalancerのリソース作成後、BIG-IP側でVirtual Server、Poolなどが自動設定されることを確認する。
動作確認
- ブラウザで「https://キャリアIP:8080/」にアクセスし、coffee-svcに接続できることを確認する。
- 2つのpodに負荷分散されていることを確認する。
#5. 所感
- Wavelength環境においても、F5社が提供するCISの仕組みを用いることにより、BIG-IPをk8s環境にうまく組み込む形で、ELBの代替として利用可能なことが確認できた。BIG-IPには今回検証した内容以外にも様々な機能があり、機会があればより深堀してみたい。
#6. 参考URL