はじめに
ALB LoadBalancer ControllerはKubernetesからELBを操作するためのものです。
元々はALB Ingress Controllerという名称で、複数NamespaceのIngressリソースを1つのALBで対応することができませんでした。
これは以前記事に書いた通り、NGINX Ingress ControllerをALBとアプリケーションの間に挟むことで解決することができました。
ALB Ingress ControllerとNGINX Ingress Controllerを使用するときの構成は下図になります。
一方、ALB LoadBalancer Controllerでは下図のようにIngressリソースなしで1つのALBで複数Namespace上のアプリケーションにルーティングさせることができます。
今回は既存のALBを削除せずにALB Ingress Controller + NGINX Ingress Controllerの構成からALB LoadBalancer Controllerの構成に移行する手順を説明します。
事前準備
ALB Ingress ControllerとNGINX Ingress ControllerをHelmでデプロイします。IAM Role for ServiceAccountを使用しています。
clusterName: <CLUSTER_NAME>
awsRegion: ap-northeast-1
awsVpcID: <VPC_ID>
rbac:
serviceAccountAnnotations:
eks.amazonaws.com/role-arn: <IAM_ROLE_ARN>
controller:
service:
type: NodePort
$ helm install aws-alb-ingress-controller \
incubator/aws-alb-ingress-controller \
-f aws-alb-ingress-controller-values.yaml \
--version 0.1.11 \
-n kube-system
$ helm install nginx-ingress \
stable/nginx-ingress \
-f nginx-ingress-values.yaml \
--version 1.39.0 \
-n kube-system
ALB Ingress Controllerで使用するIAM RoleにアタッチするIAM Policyは以下になります。
後述するALB LoadBalancer Controllerでも同じIAM Roleを使用します。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"acm:DescribeCertificate",
"acm:ListCertificates",
"acm:GetCertificate"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"ec2:AuthorizeSecurityGroupIngress",
"ec2:CreateSecurityGroup",
"ec2:CreateTags",
"ec2:DeleteTags",
"ec2:DeleteSecurityGroup",
"ec2:DescribeAccountAttributes",
"ec2:DescribeAddresses",
"ec2:DescribeInstances",
"ec2:DescribeInstanceStatus",
"ec2:DescribeInternetGateways",
"ec2:DescribeNetworkInterfaces",
"ec2:DescribeSecurityGroups",
"ec2:DescribeSubnets",
"ec2:DescribeTags",
"ec2:DescribeVpcs",
"ec2:ModifyInstanceAttribute",
"ec2:ModifyNetworkInterfaceAttribute",
"ec2:RevokeSecurityGroupIngress"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"elasticloadbalancing:AddListenerCertificates",
"elasticloadbalancing:AddTags",
"elasticloadbalancing:CreateListener",
"elasticloadbalancing:CreateLoadBalancer",
"elasticloadbalancing:CreateRule",
"elasticloadbalancing:CreateTargetGroup",
"elasticloadbalancing:DeleteListener",
"elasticloadbalancing:DeleteLoadBalancer",
"elasticloadbalancing:DeleteRule",
"elasticloadbalancing:DeleteTargetGroup",
"elasticloadbalancing:DeregisterTargets",
"elasticloadbalancing:DescribeListenerCertificates",
"elasticloadbalancing:DescribeListeners",
"elasticloadbalancing:DescribeLoadBalancers",
"elasticloadbalancing:DescribeLoadBalancerAttributes",
"elasticloadbalancing:DescribeRules",
"elasticloadbalancing:DescribeSSLPolicies",
"elasticloadbalancing:DescribeTags",
"elasticloadbalancing:DescribeTargetGroups",
"elasticloadbalancing:DescribeTargetGroupAttributes",
"elasticloadbalancing:DescribeTargetHealth",
"elasticloadbalancing:ModifyListener",
"elasticloadbalancing:ModifyLoadBalancerAttributes",
"elasticloadbalancing:ModifyRule",
"elasticloadbalancing:ModifyTargetGroup",
"elasticloadbalancing:ModifyTargetGroupAttributes",
"elasticloadbalancing:RegisterTargets",
"elasticloadbalancing:RemoveListenerCertificates",
"elasticloadbalancing:RemoveTags",
"elasticloadbalancing:SetIpAddressType",
"elasticloadbalancing:SetSecurityGroups",
"elasticloadbalancing:SetSubnets",
"elasticloadbalancing:SetWebACL"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"iam:CreateServiceLinkedRole",
"iam:GetServerCertificate",
"iam:ListServerCertificates"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"cognito-idp:DescribeUserPoolClient"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"waf-regional:GetWebACLForResource",
"waf-regional:GetWebACL",
"waf-regional:AssociateWebACL",
"waf-regional:DisassociateWebACL"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"tag:GetResources",
"tag:TagResources"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"waf:GetWebACL",
"wafv2:GetWebACLForResource"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"ec2:CreateTags",
"ec2:DeleteTags"
],
"Resource": "arn:aws:ec2:*:*:security-group/*",
"Condition": {
"Null": {
"aws:ResourceTag/ingress.k8s.aws/cluster": "false"
}
}
},
{
"Effect": "Allow",
"Action": [
"elasticloadbalancing:AddTags",
"elasticloadbalancing:RemoveTags",
"elasticloadbalancing:DeleteTargetGroup"
],
"Resource": [
"arn:aws:elasticloadbalancing:*:*:targetgroup/*/*",
"arn:aws:elasticloadbalancing:*:*:loadbalancer/net/*/*",
"arn:aws:elasticloadbalancing:*:*:loadbalancer/app/*/*"
],
"Condition": {
"Null": {
"aws:ResourceTag/ingress.k8s.aws/cluster": "false"
}
}
}
]
}
次に、ALBに設定するためのIngressリソースをデプロイします。
annotationsにalb.ingress.kubernetes.io/load-balancer-attributes
で削除保護を設定しています。これによりIngressリソースを削除してもALBが削除されることはなくなります。
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
alb.ingress.kubernetes.io/scheme: internet-facing
kubernetes.io/ingress.class: alb
alb.ingress.kubernetes.io/load-balancer-attributes: deletion_protection.enabled=true
name: alb-ingress
namespace: kube-system
spec:
rules:
- http:
paths:
- backend:
serviceName: nginx-ingress-controller
servicePort: 80
$ kubectl apply -f alb-ingress.yaml
次に、2つのNamespaceにアプリケーションをデプロイします。今回はNGINXを使用しています。
FQDNは例としてそれぞれapp1.sample.com
、app2.sample.com
と記述しています。
kind: Namespace
apiVersion: v1
metadata:
name: app1
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: app1-ing
namespace: app1
annotations:
kubernetes.io/ingress.class: nginx
spec:
rules:
- host: app1.sample.com
http:
paths:
- backend:
serviceName: app1-svc
servicePort: 80
---
apiVersion: v1
kind: Service
metadata:
name: app1-svc
namespace: app1
spec:
type: ClusterIP
ports:
- name: http-port
protocol: TCP
port: 80
targetPort: 80
selector:
app: app1
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: app1-deploy
namespace: app1
spec:
replicas: 1
selector:
matchLabels:
app: app1
template:
metadata:
labels:
app: app1
spec:
containers:
- name: app1
image: nginx:1.13
ports:
- containerPort: 80
---
kind: Namespace
apiVersion: v1
metadata:
name: app2
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: app2-ing
namespace: app2
annotations:
kubernetes.io/ingress.class: nginx
spec:
rules:
- host: app2.sample.com
http:
paths:
- backend:
serviceName: app2-svc
servicePort: 80
---
apiVersion: v1
kind: Service
metadata:
name: app2-svc
namespace: app2
spec:
type: ClusterIP
ports:
- name: http-port
protocol: TCP
port: 80
targetPort: 80
selector:
app: app2
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: app2-deploy
namespace: app2
spec:
replicas: 1
selector:
matchLabels:
app: app2
template:
metadata:
labels:
app: app2
spec:
containers:
- name: app2
image: nginx:1.13
ports:
- containerPort: 80
$ kubectl apply -f app.yaml
ALB LoadBalancer Controllerへの移行
ここでは、移行する手順を説明します。
1. ALB Ingress Controllerの削除
既存のALB Ingress Controllerを削除します。Ingressリソースは削除しないことに注意します。
$ helm uninstall aws-alb-ingress-controller -n kube-system
2. ALB LoadBalancer Controllerのデプロイ
TargetGroupBindingのCRDをデプロイします。
$ kubectl apply -k "github.com/aws/eks-charts/stable/aws-load-balancer-controller//crds?ref=master"
ALB LoadBalancer ControllerをHelmでデプロイします。バージョンに気をつけます。
clusterName: <CLUSTER_NAME>
region: ap-northeast-1
vpcId: <VPC_ID>
serviceAccount:
annotations:
"eks.amazonaws.com/role-arn": <IAM_ROLE_ARN>
$ helm install aws-load-balancer-controller \
eks/aws-load-balancer-controller \
-f aws-load-balancer-controller-values.yaml \
--version 1.0.8 \
-n kube-system
3. Ingressリソースの削除
ALBの設定をKubernetesリソースから操作することはやめます。Ingressリソースは不要になるため削除します。
$ kubectl delete -f alb-ingress.yaml
4. TargetGroupの作成
Serviceへのルーティングを設定するためにTargetGroupをAWSコンソールから作成していきます。下画像ではALB Ingress Controllerが作成したものが残っていますが、まだ削除しません。
target typeはIP addressにします。
Register targetsには何も記入せず作成します。
今回は2つのアプリケーションをデプロイするので2つ分TargetGroupを追加しました。
5. リスナールールの変更
ALB Ingress Controllerが作成したALBのリスナールールを変更していきます。
全てのリクエストがNGINX Ingress Controllerに向かうようになっています。これにルールを追加します。
ホスト名に合わせて宛先を先ほど作成したTargetGroupになるようにしています。
6. TargetGroupBindingリソースの作成
TargetGroupとServiceを紐づけるための設定を加えます。SecurityGroupはALBに設定されているものを使用します。
apiVersion: elbv2.k8s.aws/v1beta1
kind: TargetGroupBinding
metadata:
name: app1-tgb
namespace: app1
spec:
serviceRef:
name: app1-svc
port: 80
targetGroupARN: <TARGET_GROUP_ARN>
targetType: ip
networking:
ingress:
- from:
- securityGroup:
groupID: <SECURITY_GROUP_ID>
ports:
- protocol: TCP
---
apiVersion: elbv2.k8s.aws/v1beta1
kind: TargetGroupBinding
metadata:
name: app2-tgb
namespace: app2
spec:
serviceRef:
name: app2-svc
port: 80
targetGroupARN: <TARGET_GROUP_ARN>
targetType: ip
networking:
ingress:
- from:
- securityGroup:
groupID: <SECURITY_GROUP_ID>
ports:
- protocol: TCP
$ kubectl apply -f targetgroupbinding.yaml
7. ゴミ掃除
ALBリスナールールからNGINX Ingress Controller向けの設定を削除します。
IngressリソースとNGINX Ingress Controllerは不要なので削除します。
$ kubectl delete ing app1-ing -n app1
$ kubectl delete ing app2-ing -n app2
$ helm uninstall nginx-ingress -n kube-system
確認
移行前のURLでアプリケーションにアクセスできることを確認します。
まとめ
既存のALBを削除せずにALB Ingress Controller + NGINX Ingress ControllerからALB LoadBalancer Controllerに移行する手順を説明しました。
これによりALBをKubernetes側で管理する必要がなくなり、且つ複数Namespace上のアプリケーションにアクセスする時も1つのALBで事足りるので移行するメリットは大きいです。
参考