はじめに
今回は、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 ポリシーをダウンロード
curl -O https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/v2.5.4/docs/install/iam_policy.json
2. ダウンロードしたポリシーを使用して、AWSLoadBalancerControllerIAMPolicy
という名前の IAM ポリシーを作成
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 ロールを割り当てます
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 ファイルに保存し、以下のコマンドを実行
eksctl create cluster -f config.yml
クラスターが稼働していることを確認します。
以下のコマンド実行で、1つの Amazon EKS ノードと 4つの実行中の Pod が確認できます
kubectl get nodes kubectl get pods -A
3. AWS Load Balancer Controller のインストール
1. AWS Load Balancer Controller が機能するために必要なカスタムリソース定義 (CRD) をインストール
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 をデプロイ
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 がインストールされていることを確認します
kubectl get deployment -n kube-system aws-load-balancer-controller
4. テスト用 Service のデプロイ(NLB)
1. Namespace の作成
ServiceをデプロイするNamespaceを作成します
kubectl create namespace apps
2. Service のデプロイと検証
http-echo イメージを使用する Serviceを作成します${SERVICE_NAME}
変数で定義したService名でリクエストがあったときに、Service名を返すアプリケーション(pod)を5つデプロイします
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をデプロイします
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. 結果を確認します
kubectl get pod,svc -n apps
↓
5つのアプリケーション(Pod)が確認できました
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 であること
- ヘルスチェックのパス
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リソースの状態を確認できます
kubectl get ingress -n apps
以下のコマンドではIngressリソースの詳細が確認できます
kubectl describe ingress apps-ingress -n apps
↓
podへの /first
/second
リスナールールが作成されていることが確認できます
ルールに該当しないものは /error
へ飛びます
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. 動作確認
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へ外部からアクセスできることが確認できました。
error first first second error error
まとめ
AWS Load Balancer Controllerでアプリケーションを公開することができました
今回はパスベースでアクセスできるよう設定しましたが、今後はホストベースでのルーティング設定や external-dnsを使用したRoute53経由での公開も見てみたいと思います