はじめに
- 以前の記事で Amazon EKS で LoadBalancer に設定されたサービスを作成すると、Elastic Load Balancing (ELB) が自動的に生成され、EKS のサービスが外部に公開できることを試しましたが、EKS で利用できるロードバランサーについてもう少し深く調べてみました。
- EKS で利用できるロードバランサーのうち、 ALB を利用してサービスを公開してみます。
- ALB は EKS のデータプレーンとして EC2 を利用した場合でも Fargate を利用した場合でも利用できる唯一の手段です(2020年6月時点)。
本記事で使用した K8s のマニフェストや IAM ポリシーの yaml ファイルはGitLabのリポジトリで公開しております。
Elastic Load Balancing (ELB) の概要
- Elastic Load Balancing は AWS へのリクエストを複数のターゲット (Amazon EC2 インスタンス、コンテナ、IP アドレス、Lambda 関数など) に自動的に分散します。
- ロードバランサーを使用することで、アプリケーションの可用性と耐障害性が向上します。
- ELB には以下の 3 種類のロードバランサーが用意されています。
Classic Load Balancer (CLB)
- Amazon EC2 インスタンスにおける基本的な負荷分散を提供します。
- OSI モデルのレイヤー 4 のトランスポート層と、レイヤー 7 のアプリケーション層のどちらでも機能するロードバランサーで、TCP、SSL、HTTP、HTTPS に対応しています。
- CLB は、EC2-Classic ネットワーク内に構築されたアプリケーションを対象としています。
- 近年デフォルトとなっている Virtual Private Cloud (VPC) を使用する場合は、CLB ではなく、以下に挙げる ALB や NLB の利用が推奨されます(参考:AWS 保里氏の発表資料 )。
Application Load Balancer (ALB)
- ALB はレイヤー 7 のアプリケーション層での機能に特化したロードバランサーです。
- CLB を利用するのと違い、主に以下のメリットがあります。
Network Load Balancer (NLB)
- NLB は、レイヤー 4 のトランスポート層で機能します。
- 毎秒数百万のリクエストを処理できるため、高パフォーマンスが必要な環境においての負荷分散に最適とされるロードバランサーモデルです。
- CLB や ALB と異なり、トラフィックの宛先IP をターゲットのIPに書き換えて転送するため、帰りはロードバランサを介さず、ターゲットからクライアントに直接通信する形になります。
- そのため、NLBのターゲットはクライアントへのネットワーク到達性を考慮する必要があります。
EKS におけるロードバランサー
- 前回の記事で試したように、LoadBalancer のサービスを作成した場合、デフォルトでは CLB のロードバランサーが作成されます。
- 指定や設定を変更することで、NLB や ALB を選択することが出来ます。
AWS ALB Ingress Controller for Kubernetes
- EKS では、
kubernetes.io/ingress.class: alb
のアノテーションが付与されたイングレスリソースがクラスターで作成されると、AWS ALB Ingress Controller for Kubernetes によって ALB と必要な AWS サポートリソースの作成がなされます。
EKS で ALB を利用できるようにする
EKS クラスターに ALB Ingress Controller をデプロイする
- データプレーンとして EC2 を利用している場合も、Fargate を利用している場合も以下の手順は同じです。
①eksctl
コマンドを利用してクラスタを作成した場合はすでに VPC のサブネットに必要なタグ付けセットはなされていますが、別の方法でクラスタを作成した場合は、Amazon EKS の ALB Ingress Controller - Amazon EKS を参考に、適切なタグ付けをする必要があります。
②IAM OIDC プロバイダーの作成とクラスターへの関連付けを行います。
$ eksctl utils associate-iam-oidc-provider \ --region [リージョン名] \ --cluster [クラスター名] \ --approve
③以下の内容の IAM ポリシーを ALBIngressControllerIAMPolicy という名前で作成します。
policy-alb-ingress-controller.yml
{ "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": [ "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" ], "Resource": "*" } ] }
$ aws iam create-policy \ --policy-name ALBIngressControllerIAMPolicy \ --policy-document policy-alb-ingress-controller.yml
④alb-ingress-controller という名前の Kubernetes サービスアカウントを kube-system 名前空間に作成します。以下のコマンドを実行します。
$ kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/aws-alb-ingress-controller/v1.1.4/docs/examples/rbac-role.yaml
⑤ALB Ingress Controller の IAM ロールを作成し、このロールを前のステップで作成したサービスアカウントにアタッチします。
$ eksctl create iamserviceaccount \ --region [リージョン名] \ --name alb-ingress-controller \ --namespace kube-system \ --cluster [クラスター名] \ --attach-policy-arn [ALBIngressControllerIAMPolicy の arn] \ --override-existing-serviceaccounts \ --approve
⑥ALB Ingress Controller をデプロイします。 https://raw.githubusercontent.com/kubernetes-sigs/aws-alb-ingress-controller/v1.1.4/docs/examples/alb-ingress-controller.yaml の内容を参考に下記の内容のマニフェスト(alb-ingress-controller.yml
)を作成し、適用する。
alb-ingress-controller.yml
apiVersion: apps/v1 kind: Deployment metadata: labels: app.kubernetes.io/name: alb-ingress-controller name: alb-ingress-controller namespace: kube-system spec: selector: matchLabels: app.kubernetes.io/name: alb-ingress-controller template: metadata: labels: app.kubernetes.io/name: alb-ingress-controller spec: containers: - name: alb-ingress-controller args: - --ingress-class=alb - --cluster-name=[クラスター名] - --aws-vpc-id=[EKS の VPC ID] - --aws-region=[リージョン名] image: docker.io/amazon/aws-alb-ingress-controller:v1.1.4 serviceAccountName: alb-ingress-controller
$ kubectl apply -f alb-ingress-controller.yml
⑦次のコマンドで正常に動作していることを確認します。
$ kubectl get pods -n kube-system NAME READY STATUS RESTARTS AGE alb-ingress-controller-69b4c465df-4fxb2 1/1 Running 0 44s
- ここまでで ALB を利用する準備は完了です。
EC2 をデータプレーンとして利用している場合で ALB を利用してアプリケーションを作成する
- 前回作成した nginx の初期画面を表示するだけのサービスを ALB を用いて公開します。以下の 4 つのマニフェストを作成します。
namespace.yml
apiVersion: v1 kind: Namespace metadata: name: "sample"
- 名前空間として「sample」を定義します。
deployment.yml
apiVersion: apps/v1 kind: Deployment metadata: name: "sample-deployment" namespace: "sample" spec: selector: matchLabels: app: "sample-app" replicas: 1 template: metadata: labels: app: "sample-app" spec: containers: - name: nginx-container image: nginx:1.7.9 ports: - containerPort: 80
- こちらは前回作成したデプロイメントと変わりはほとんどありません(名前空間の情報のみ追加)。
service.yml
apiVersion: v1 kind: Service metadata: name: "sample-service" namespace: "sample" spec: type: NodePort selector: app: "sample-app" ports: - protocol: TCP port: 80 targetPort: 80
- サービスとしては、前回と異なり「NodePort」を指定します。
ingress.yml
apiVersion: extensions/v1beta1 kind: Ingress metadata: name: "sample-ingress" namespace: "sample" annotations: kubernetes.io/ingress.class: alb alb.ingress.kubernetes.io/scheme: internet-facing labels: app: "sample-ingress" spec: rules: - http: paths: - path: /* backend: serviceName: "sample-service" servicePort: 80
- ALB を利用するために Ingress のサービスを定義します。
metadata.annotations
に ALB を利用する際に必要な注釈をつけています。
- 作成したら、適用してデプロイをします。
$ kubectl apply -f namespace.yml $ kubectl apply -f deployment.yml $ kubectl apply -f service.yml $ kubectl apply -f ingress.yml
- 数分後、次のコマンドを使用して、Ingress リソースが作成されたことを確認します。
$ kubectl get ingress/sample-ingress -n sample
- 正しくサービスが公開されている場合は、
ADDRESS
に公開先の URL が表示されます。そこにアクセスして、前回同様に Nginx の初期画面が表示されたら成功です。- 数分経っても
ADDRESS
に URL が表示されない場合、下記のコマンドでログを出すことによって原因を探ることが出来ます。
- 数分経っても
$ kubectl logs -n kube-system deployment.apps/alb-ingress-controller
- 確認が終了したら、下記コマンドでアプリケーションを削除します。
$ kubectl delete -f ingress.yml $ kubectl delete -f service.yml $ kubectl delete -f deployment.yml $ kubectl delete -f namespace.yml
Fargate をデータプレーンとして利用している場合で ALB を利用してアプリケーションを作成する
$ eksctl create fargateprofile --cluster [クラスター名] --region [リージョン名] --name [プロファイル名] --namespace [名前空間名]
- EC2 で行ったのと同じ内容の
namespace.yml
、deployment.yml
、service.yml
を作成します。 ingress-fargate.yml
については、以下の内容で作成します。
ingress-fargate.yml
apiVersion: extensions/v1beta1 kind: Ingress metadata: name: "sample-ingress" namespace: "sample" annotations: kubernetes.io/ingress.class: alb alb.ingress.kubernetes.io/scheme: internet-facing alb.ingress.kubernetes.io/target-type: ip labels: app: "sample-ingress" spec: rules: - http: paths: - path: /* backend: serviceName: "sample-service" servicePort: 80
ingress.yml
との違いは、metadata.annotations
のalb.ingress.kubernetes.io/scheme: internet-facing
の下の行にalb.ingress.kubernetes.io/target-type: ip
を加えています。
- 作成したら、適用してデプロイをします。
$ kubectl apply -f namespace.yml $ kubectl apply -f deployment.yml $ kubectl apply -f service.yml $ kubectl apply -f ingress-fargate.yml
- 数分後、次のコマンドを使用して、Ingress リソースが作成されたことを確認します。
ADDRESS
に公開先の URL が表示されます。そこにアクセスして、前回同様に Nginx の初期画面が表示されたら成功です。
$ kubectl get ingress/sample-ingress -n sample
- こちらも、試用が終わったら、アプリケーションを削除しておきます。
$ kubectl delete -f ingress-fargate.yml $ kubectl delete -f service.yml $ kubectl delete -f deployment.yml $ kubectl delete -f namespace.yml
まとめ
- AWS EKS で利用可能なロードバランサーについてまとめました
- ロードバランサーのうち、ALB については利用する場面が多そうなため、EC2 上のクラスターの場合と Fargate 上のクラスターの場合の両方で作成してみました。
- NLB については利用方法が独特なため、別の機会に触ってみようと思います。
参考
- 負荷分散 - Amazon EKS
- AWS ELB(ALB,CLB,NLB)を1分で掴む - Qiita
- 【ALBとELBの違い】初心者でもわかる簡単 AWS 用語解説 | WafCharm(ワフチャーム)|AIによるAWS WAFのルール自動運用サービス
- Amazon EKS の ALB Ingress Controller - Amazon EKS
- 高良(2019)「15Stepで習得 Dockerから入るKubernetes」リックテレコム
- イングレスの概念の説明を参考にしました。