はじめに
今回は、EKSのKubernetesクラスターで実行されているアプリケーションを、AWS Load Balancer Controllerを使用して外部へ公開する方法を解説します。
AWS Load Balancer Controller (旧AWS ALB Ingress Controller)は、Kubernetesクラスターの Elastic Load Balancer の管理を支援するコントローラーです。
AWS Load Balancer Controllerで作成したALBとNLBでAmazon EKSでのアプリケーション負荷分散、ネットワーク負荷分散を管理します。
AWS Load Balancer Controllerでできること
- NLB(Kubernetes Service)の作成
- クラスター内で1つ以上のPodとして実行されているネットワークアプリケーションを公開します
- Pod内で動作しているアプリケーションへクラスターの外部から到達可能なようにします
- ALB(Kubernetes Ingress)の作成
- クラスター外からクラスター内ServiceへのHTTPとHTTPSのルートを公開します
- Serviceに対して、外部疎通できるURL、負荷分散トラフィック、SSL/TLS終端の機能や、名前ベースの仮想ホスティングを提供します
→ AWS Load Balancer Controller は Kubernetes Service と Ingress 両方のコントローラーの AWS のオープンソース実装です
今回すること・ゴール
- EKSで作成したKubernetesクラスターのノード上で動作する、リクエスト時の引数で指定した文字列を返すアプリケーション(Pod)を作成します
- AWS Load Balancer Controllerで、作成したアプリケーション(Pod)へ外部からアクセスできるようにします
- アプリケーションURLへアクセスし、リクエスト時の引数で指定した文字列が返ってこれば成功です
※ Kubernetesの基本用語はこちらにまとめましたので、よければご確認ください
【初心者向け】Kubernetesの基本用語を調べてまとめました
手順
Kubernetes アプリケーションの公開 Part 2: AWS Load Balancer Controller を参考に進めました
0. 前提条件
1. AWS Load Balancer Controller 用の AWS IAM ポリシーの作成
IRSA を使用して、AWS Load Balancer Controller に IAM アクセス許可を提供します
(IAM ポリシーを紐付ける IAM ロールの作成はEKS クラスターの作成で行います)
1. AWS Load Balancer Controller 用の IAM ポリシーをダウンロード
1 | curl -O https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/v2.5.4/docs/install/iam_policy.json |
2. ダウンロードしたポリシーを使用して、AWSLoadBalancerControllerIAMPolicy
という名前の IAM ポリシーを作成
1 2 3 | aws iam create-policy \ --policy-name AWSLoadBalancerControllerIAMPolicy \ --policy-document file://iam_policy.json |
2. EKS クラスターの作成
- eksctl を使用して Amazon EKS クラスターを作成します
- OIDC IAM プロバイダーの登録、AWS Load Balancer Controller の Service Account の作成、および IAM ロールの作成も同時に行います
- AWS Load Balancer Controller 用の kube-system 名前空間に aws-load-balancer-controller という名前のKubernetes サービスアカウントを作成し、Kubernetes サービスアカウントに IAM ロールを割り当てます
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 | apiVersion: eksctl.io/v1alpha5 kind: ClusterConfig metadata: name: aws-load-balancer-controller-walkthrough region: us-west-2 version: '1.27' iam: withOIDC: true serviceAccounts: - metadata: name: aws-load-balancer-controller namespace: kube-system attachPolicyARNs: - arn:aws:iam::${AWS_ACCOUNT}:policy/AWSLoadBalancerControllerIAMPolicy # 1 で作成した IAM ポリシーの ARN managedNodeGroups: - name: main-ng instanceType: m5.large desiredCapacity: 1 privateNetworking: true |
上記のコードを config.yml ファイルに保存し、以下のコマンドを実行
1 | eksctl create cluster -f config.yml |
クラスターが稼働していることを確認します。
以下のコマンド実行で、1つの Amazon EKS ノードと 4つの実行中の Pod が確認できます
1 2 | kubectl get nodes kubectl get pods -A |
3. AWS Load Balancer Controller のインストール
1. AWS Load Balancer Controller が機能するために必要なカスタムリソース定義 (CRD) をインストール
1 2 | kubectl apply -k \ "github.com/aws/eks-charts/stable/aws-load-balancer-controller//crds?ref=master" |
2. Helm を使用してAmazon EKS の EC2 ノードに AWS Load Balancer Controller をデプロイ
1 2 3 4 5 6 7 | helm repo add eks https://aws.github.io/eks-charts helm upgrade -i aws-load-balancer-controller eks/aws-load-balancer-controller \ --namespace kube-system \ --set clusterName=aws-load-balancer-controller-walkthrough \ # 2 で作成した EKSクラスター名(metadata.name) --set serviceAccount.create=false \ --set serviceAccount.name=aws-load-balancer-controller # 2 で作成した Service Account (iam.serviceAccounts.metadata.name) |
3. AWS Load Balancer Controller がインストールされていることを確認します
1 | kubectl get deployment -n kube-system aws-load-balancer-controller |
4. テスト用 Service のデプロイ(NLB)
1. Namespace の作成
ServiceをデプロイするNamespaceを作成します
1 | kubectl create namespace apps |
2. Service のデプロイと検証
http-echo イメージを使用する Serviceを作成します
${SERVICE_NAME}
変数で定義したService名でリクエストがあったときに、Service名を返すアプリケーション(pod)を5つデプロイします
01 02 03 04 05 06 07 08 09 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 47 48 49 | apiVersion: apps/v1 kind: Deployment metadata: name: ${SERVICE_NAME} namespace: ${NS} labels: app.kubernetes.io/name: ${SERVICE_NAME} spec: selector: matchLabels: app.kubernetes.io/name: ${SERVICE_NAME} replicas: 1 template: metadata: labels: app.kubernetes.io/name: ${SERVICE_NAME} spec: terminationGracePeriodSeconds: 0 containers: - name: ${SERVICE_NAME} image: hashicorp/http-echo imagePullPolicy: IfNotPresent args: - -listen=:3000 - -text=${SERVICE_NAME} ports: - name: app-port containerPort: 3000 resources: requests: cpu: 0.125 memory: 50Mi --- apiVersion: v1 kind: Service metadata: name: ${SERVICE_NAME} namespace: ${NS} labels: app.kubernetes.io/name: ${SERVICE_NAME} spec: type: ClusterIP selector: app.kubernetes.io/name: ${SERVICE_NAME} ports: - name: svc-port port: 80 targetPort: app-port protocol: TCP |
上記のコードを service.yml ファイルで保存し、以下のコマンドを実行して5つのServiceをデプロイします
1 2 3 4 5 | SERVICE_NAME=first NS=apps envsubst < service.yml | kubectl apply -f - SERVICE_NAME=second NS=apps envsubst < service.yml | kubectl apply -f - SERVICE_NAME=third NS=apps envsubst < service.yml | kubectl apply -f - SERVICE_NAME=fourth NS=apps envsubst < service.yml | kubectl apply -f - SERVICE_NAME=error NS=apps envsubst < service.yml | kubectl apply -f - |
3. 結果を確認します
1 | kubectl get pod,svc -n apps |
↓
5つのアプリケーション(Pod)が確認できました
01 02 03 04 05 06 07 08 09 10 11 12 13 | NAME READY STATUS RESTARTS AGE pod/error-759546fcc4-n5dqr 1/1 Running 0 60s pod/first-788fb8b9cd-rxblp 1/1 Running 0 88s pod/fourth-654655d556-bfh24 1/1 Running 0 64s pod/second-75bf747744-57vws 1/1 Running 0 72s pod/third-6b5f65fd67-tsbff 1/1 Running 0 68s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/error ClusterIP 10.100.106.108 <none> 80/TCP 59s service/first ClusterIP 10.100.165.147 <none> 80/TCP 88s service/fourth ClusterIP 10.100.131.147 <none> 80/TCP 63s service/second ClusterIP 10.100.249.80 <none> 80/TCP 72s service/third ClusterIP 10.100.253.123 <none> 80/TCP 67s |
5. Ingress のデプロイ(ALB)
作成したServiceのバックエンドにあるアプリケーション(Pod)へのアクセスを提供するIngressを作成します
Podへ外部からアクセスできるようにします
1. デプロイ
- ingressClassName を alb に設定することで、AWS Load Balancer Controller がこの Ingress リソースを処理するようにします
- アノテーションで以下を定義します
- AWS Load Balancer Controller が作成するロードバランサーの名前
- ロードバランサーのターゲットタイプが ip であること (Pod の IP アドレスをターゲットとして登録します)
- ロードバランサーが internet-facing であること
- ヘルスチェックのパス
01 02 03 04 05 06 07 08 09 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 | apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: ${NS}-ingress namespace: ${NS} annotations: alb.ingress.kubernetes.io/load-balancer-name: ${NS}-ingress alb.ingress.kubernetes.io/target-type: ip alb.ingress.kubernetes.io/scheme: internet-facing alb.ingress.kubernetes.io/healthcheck-path: /healthz spec: ingressClassName: alb defaultBackend: service: name: error port: name: svc-port rules: - http: paths: - path: /first pathType: Prefix backend: service: name: first port: name: svc-port - path: /second pathType: Prefix backend: service: name: second port: name: svc-port |
AWSマネージメントコンソール → EC2 → ロードバランサーより ALB がデプロイされたのを確認できました
以下のコマンドでもIngressリソースの状態を確認できます
1 | kubectl get ingress -n apps |
以下のコマンドではIngressリソースの詳細が確認できます
1 | kubectl describe ingress apps-ingress -n apps |
↓
podへの /first
/second
リスナールールが作成されていることが確認できます
ルールに該当しないものは /error
へ飛びます
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 | Name: apps-ingress Labels: <none> Namespace: apps Address: apps-ingress-xxx.{region}.elb.amazonaws.com Ingress Class: alb Default backend: error:svc-port (xxx.xxx.xxx.xx:3000) Rules: Host Path Backends ---- ---- -------- * /first first:svc-port (xxx.xxx.xxx.xx:3000) /second second:svc-port (xxx.xxx.xxx.xx:3000) Annotations: alb.ingress.kubernetes.io/healthcheck-path: /healthz alb.ingress.kubernetes.io/load-balancer-name: apps-ingress alb.ingress.kubernetes.io/scheme: internet-facing alb.ingress.kubernetes.io/target-type: ip Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal SuccessfullyReconciled 3m18s (x2 over 32m) ingress Successfully reconciled |
2. 動作確認
1 2 3 4 5 6 7 | export ALB_URL=$(kubectl get -n apps ingress/apps-ingress -o jsonpath= '{.status.loadBalancer.ingress[0].hostname}' ) curl ${ALB_URL} curl ${ALB_URL}/first curl ${ALB_URL}/first/something curl ${ALB_URL}/second curl ${ALB_URL}/third curl ${ALB_URL}/something |
↓
作成したServiceへ外部からアクセスできることが確認できました。
1 2 3 4 5 6 | error first first second error error |
まとめ
AWS Load Balancer Controllerでアプリケーションを公開することができました
今回はパスベースでアクセスできるよう設定しましたが、今後はホストベースでのルーティング設定や external-dnsを使用したRoute53経由での公開も見てみたいと思います