🌟

君たちはどうAWS Load Balancer Controllerを使ってPodを公開するか

2023/09/30に公開

モチベーション

EKSで構築したクラスタ上のServiceを外部公開したいときにはAWS Load Balancer Controllerを利用するのが一般的です。

AWS Load Balancer Controllerにはいくつかの機能があり、要件や運用の都合によって採用するべきアプローチは異なります。

本稿では、実際に手を動かして各機能の挙動を確認し、比較します。

AWS Load Balancer Controller とは

AWS Load Balancer Controller はNLB(L4レイヤ)および、ALB(L7レイヤ)でのロードバランシングをEKSから簡単に扱えるようにするアドオンです。

本稿ではALB(L7レイヤ)でのルーティングについて、基本的な3つの機能(Ingress, IngressGroup, TargetGroupBinding)について、実際の挙動を確認しながら比較します。

前提条件

  • Terraformを利用してEKSクラスタを構築する
  • eks-blueprints-addons を利用してAWS Load Balancer Controllerをデプロイする

本稿の執筆にあたりサンプルリポジトリを用意しました。

https://github.com/isanasan/example-aws-load-balancer-controller

本稿では上記のサンプルリポジトリの内容と手順に従って動作確認を行っていきます。

下準備

EKS クラスタを構築する前に、必要なリソースを作成しておきます。

git clone https://github.com/isanasan/example-eks-terraform.git
cd environment/
terraform init
terraform apply -auto-approve

Ingress

Ingressリソースを作成すると、AWS Load Balancer Controllerがそれを検知して、ALBをプロビジョニングします。クラスタ内のサービスをパブリックIPにアタッチすることで外部からのアクセスが可能になります。

動作確認

1つずつリソースを作成しながら、動作確認をしていきます。

EKS クラスタをTerraformで作成

example-ingress ディレクトリに移動してEKSクラスタを作成します。

cd ../example-ingress
terraform init
terraform apply -auto-approve

outputされるコマンドを実行してkubectlを設定します。

aws eks --region ap-northeast-1 update-kubeconfig --name example-alb-ingress-cluster

nginx コンテナをデプロイ

DeploymentリソースとServiceリソースを作成し、nginxコンテナをデプロイします。

nginx.yaml
nginx.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: sample-nginx-ns
---
apiVersion: v1
kind: Service
metadata:
  name: service-sample-nginx
  namespace: sample-nginx-ns
  labels:
    app: sample-nginx
spec:
  selector:
    app: sample-nginx
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  namespace: sample-nginx-ns
  labels:
    app: sample-nginx
spec:
  selector:
    matchLabels:
      app: sample-nginx
  replicas: 3
  template:
    metadata:
      labels:
        app: sample-nginx
    spec:
      containers:
      - name: nginx
        image: public.ecr.aws/docker/library/nginx:latest
        ports:
        - containerPort: 80

Ingressリソースを作成し、ALBをプロビジョニングします。

alb-nginx.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  namespace: sample-nginx-ns
  name: sample-ingress-nginx
  annotations:
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/target-type: ip
spec:
  ingressClassName: alb
  rules:
    - http:
        paths:
        - path: /
          pathType: Prefix
          backend:
            service:
              name: service-sample-nginx
              port:
                number: 80

AWS コンソールにアクセスしてリソースを確認

コンソールからALBが作成されたことを確認できました。

合わせて、リスナルールが作成されたことを確認できました。

ここで、デプロイされているPod のIPアドレスを確認します。

kubectl get pods -n sample-nginx-ns -o wide
NAME                                READY   STATUS    RESTARTS   AGE   IP            NODE                                             NOMINATED NODE   READINESS GATES
nginx-deployment-57989d486d-nswgt   1/1     Running   0          10m   10.0.49.70    ip-10-0-49-78.ap-northeast-1.compute.internal    <none>           <none>
nginx-deployment-57989d486d-tcmpq   1/1     Running   0          10m   10.0.44.5     ip-10-0-46-115.ap-northeast-1.compute.internal   <none>           <none>
nginx-deployment-57989d486d-vb44c   1/1     Running   0          10m   10.0.43.206   ip-10-0-41-251.ap-northeast-1.compute.internal   <none>           <none>

ターゲットグループにPodのIPアドレスが登録されていることを確認できました。

疎通確認

ALBのDNS名にアクセスしてPodに疎通することを確認できました。

httpd コンテナをデプロイ

追加でコンテナをデプロイして、動作確認をしていきます。同じnginxだと芸がないのでhttpdコンテナをデプロイします。

httpd.yaml
nginx.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: sample-httpd-ns
---
apiVersion: v1
kind: Service
metadata:
  name: service-sample-httpd
  namespace: sample-httpd-ns
  labels:
    app: sample-httpd
spec:
  selector:
    app: sample-httpd
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: httpd-deployment
  namespace: sample-httpd-ns
  labels:
    app: sample-httpd
spec:
  selector:
    matchLabels:
      app: sample-httpd
  replicas: 3
  template:
    metadata:
      labels:
        app: sample-httpd
    spec:
      containers:
      - name: httpd
        image: public.ecr.aws/docker/library/httpd:latest
        ports:
        - containerPort: 80

Ingressリソースを追加します。

alb-httpd.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  namespace: sample-httpd-ns
  name: sample-ingress-httpd
  annotations:
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/target-type: ip
spec:
  ingressClassName: alb
  rules:
    - http:
        paths:
        - path: /
          pathType: Prefix
          backend:
            service:
              name: service-sample-httpd
              port:
                number: 80

AWS コンソールにアクセスしてリソースを確認

再びコンソールを確認してみます。

ALBが新しく追加されたことを確認できました。

同様に、リスナルールが作成されたことを確認できました。

httpdコンテナのPodのIPアドレスを確認します。

kubectl get pods -n sample-httpd-ns -o wide
NAME                               READY   STATUS    RESTARTS   AGE     IP            NODE                                             NOMINATED NODE   READINESS GATES
っhttpd-deployment-b8bc6c5b4-g9bql   1/1     Running   0          6m58s   10.0.43.144   ip-10-0-41-251.ap-northeast-1.compute.internal   <none>           <none>
httpd-deployment-b8bc6c5b4-l8264   1/1     Running   0          6m58s   10.0.50.74    ip-10-0-49-78.ap-northeast-1.compute.internal    <none>           <none>
httpd-deployment-b8bc6c5b4-lgbnt   1/1     Running   0          6m58s   10.0.47.103   ip-10-0-46-115.ap-northeast-1.compute.internal   <none>           <none>

ターゲットグループにPodのIPアドレスが登録されていることを確認できました。

疎通確認

新しく追加された方のALBのDNS名にアクセスしてPodに疎通することを確認できました。

後始末

動作確認が終わったのでリソースを削除します。

kubectl delete -f alb-nginx.yaml
kubectl delete -f alb-httpd.yaml
terraform destroy -auto-approve

IngressGroup

Ingress同様にリソースを作成するとAWS Load Balancer Controllerはそれを検知します。このとき、アノテーションalb.ingress.kubernetes.io/group.name で指定されたグループで複数のIngressリソースをグループ化します。グループ化されたIngressはルールがマージされ、単一のALBによってアクセスが制御されます。

動作確認

Ingressのときと同様の手順でリソースを作成しながら動作確認をしていきます。

EKS クラスタをTerraformで作成

example-ingress-group ディレクトリに移動し、EKSクラスタを作成します。

cd ../example-ingress-group
terraform init
terraform apply -auto-approve

outputされるコマンドを実行してkubectlを設定します。

aws eks --region ap-northeast-1 update-kubeconfig --name example-alb-ingress-group

nginx コンテナをデプロイ

DeploymentリソースとServiceリソースを作成し、nginxコンテナをデプロイします。

manifestの内容はIngressのものと同様です。

nginx.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: sample-nginx-ns
---
apiVersion: v1
kind: Service
metadata:
  name: service-sample-nginx
  namespace: sample-nginx-ns
  labels:
    app: sample-nginx
spec:
  selector:
    app: sample-nginx
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  namespace: sample-nginx-ns
  labels:
    app: sample-nginx
spec:
  selector:
    matchLabels:
      app: sample-nginx
  replicas: 3
  template:
    metadata:
      labels:
        app: sample-nginx
    spec:
      containers:
      - name: nginx
        image: public.ecr.aws/docker/library/nginx:latest
        ports:
        - containerPort: 80

Ingressリソースを作成し、ALBをプロビジョニングします。

Ingressの例とほとんど同じ内容ですが、 alb.ingress.kubernetes.io/load-balancer-name: example-ingress-group というアノテーションを付与します。

alb-nginx.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  namespace: sample-nginx-ns
  name: sample-ingress-group
  annotations:
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/target-type: ip
    alb.ingress.kubernetes.io/group.name: ingress-group-sample
    alb.ingress.kubernetes.io/load-balancer-name: example-ingress-group //グループを指定
spec:
  ingressClassName: alb
  rules:
    - http:
        paths:
        - path: /nginx //動作確認の都合上pathで切り替えます
          pathType: Prefix
          backend:
            service:
              name: service-sample-nginx
              port:
                number: 80

AWS コンソールにアクセスしてリソースを確認

コンソールからALBが作成されたことを確認できました。

同様に、リスナが作成されたことを確認できました。

リスナルールはこのようになっています。

nginxコンテナのPodのIPアドレスを確認します。

kubectl get pods -n sample-nginx-ns -o wide
NAME                                READY   STATUS    RESTARTS   AGE     IP            NODE                                             NOMINATED NODE   READINESS GATES
nginx-deployment-57989d486d-t4j4h   1/1     Running   0          4m40s   10.0.48.118   ip-10-0-50-25.ap-northeast-1.compute.internal    <none>           <none>
nginx-deployment-57989d486d-tvjb8   1/1     Running   0          4m40s   10.0.42.80    ip-10-0-40-204.ap-northeast-1.compute.internal   <none>           <none>
nginx-deployment-57989d486d-vc2gs   1/1     Running   0          4m40s   10.0.45.70    ip-10-0-47-217.ap-northeast-1.compute.internal   <none>           <none>

ターゲットグループにPodのIPアドレスが登録されていることを確認できました。

httpd コンテナをデプロイ

追加でコンテナをデプロイして、動作確認をしていきます。

manifestの内容はIngressのものと同様です。

httpd.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: sample-httpd-ns
---
apiVersion: v1
kind: Service
metadata:
  name: service-sample-httpd
  namespace: sample-httpd-ns
  labels:
    app: sample-httpd
spec:
  selector:
    app: sample-httpd
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: httpd-deployment
  namespace: sample-httpd-ns
  labels:
    app: sample-httpd
spec:
  selector:
    matchLabels:
      app: sample-httpd
  replicas: 3
  template:
    metadata:
      labels:
        app: sample-httpd
    spec:
      containers:
      - name: httpd
        image: public.ecr.aws/docker/library/httpd:latest
        ports:
        - containerPort: 80

Ingressリソースを作成し、ALBをプロビジョニングします。こちらも、alb.ingress.kubernetes.io/load-balancer-name: example-ingress-group というアノテーションを付与します。

alb-httpd.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  namespace: sample-httpd-ns
  name: sample-ingress-group
  annotations:
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/target-type: ip
    alb.ingress.kubernetes.io/group.name: ingress-group-sample
    alb.ingress.kubernetes.io/load-balancer-name: example-ingress-group
spec:
  ingressClassName: alb
  rules:
    - http:
        paths:
        - path: /httpd //動作確認の都合上pathで切り替えます
          pathType: Prefix
          backend:
            service:
              name: service-sample-httpd
              port:
                number: 80

AWS コンソールにアクセスしてリソースを確認

先程とは違い、新たにALBは作成されず、nginx側のIngressを作成したときのままになっています。

kubectl でIngressの詳細を確認してみましょう。

まずはnginx側です。

kubectl describe ingress sample-ingress-group -n sample-nginx-ns
Name:             sample-ingress-group
Labels:           <none>
Namespace:        sample-nginx-ns
Address:          example-ingress-group-0000000000.ap-northeast-1.elb.amazonaws.com
Ingress Class:    alb
Default backend:  <default>
Rules:
  Host        Path  Backends
  ----        ----  --------
  *
              /nginx   service-sample-nginx:80 (10.0.42.80:80,10.0.45.70:80,10.0.48.118:80)
Annotations:  alb.ingress.kubernetes.io/group.name: ingress-group-sample
              alb.ingress.kubernetes.io/load-balancer-name: example-ingress-group
              alb.ingress.kubernetes.io/scheme: internet-facing
              alb.ingress.kubernetes.io/target-type: ip
Events:
  Type    Reason                  Age                  From     Message
  ----    ------                  ----                 ----     -------
  Normal  SuccessfullyReconciled  84s (x2 over 7m17s)  ingress Successfully reconciled

次にhttpd側です。

kubectl describe ingress sample-ingress-group -n sample-httpd-ns
Name:             sample-ingress-group
Labels:           <none>
Namespace:        sample-httpd-ns
Address:          example-ingress-group-0000000000.ap-northeast-1.elb.amazonaws.com
Ingress Class:    alb
Default backend:  <default>
Rules:
  Host        Path  Backends
  ----        ----  --------
  *
              /httpd   service-sample-httpd:80 (10.0.40.51:80,10.0.44.50:80,10.0.49.16:80)
Annotations:  alb.ingress.kubernetes.io/group.name: ingress-group-sample
              alb.ingress.kubernetes.io/load-balancer-name: example-ingress-group
              alb.ingress.kubernetes.io/scheme: internet-facing
              alb.ingress.kubernetes.io/target-type: ip
Events:
  Type    Reason                  Age   From     Message
  ----    ------                  ----  ----     -------
  Normal  SuccessfullyReconciled  91s   ingress  Successfully reconciled

Address: example-ingress-group-0000000000.ap-northeast-1.elb.amazonaws.com とある通り、nginxとhttpdのDNS名が同一になっています。

リスナを確認すると、ルールが3つに増えています。

リスナルールを確認するとnginx側のIngressとhttpd側のIngressのspec.rules.http.paths.path がマージされていることが確認できます。

httpdコンテナのPod のIPアドレスを確認します。

kubectl get pods -n sample-httpd-ns -o wide
NAME                               READY   STATUS    RESTARTS   AGE     IP            NODE                                            NOMINATED NODE   READINESS GATES
httpd-deployment-b8bc6c5b4-pg9gc   1/1     Running   0          6m42s   10.0.46.42    ip-10-0-44-96.ap-northeast-1.compute.internal   <none>           <none>
httpd-deployment-b8bc6c5b4-phq9l   1/1     Running   0          6m42s   10.0.51.129   ip-10-0-48-69.ap-northeast-1.compute.internal   <none>           <none>
httpd-deployment-b8bc6c5b4-v5zr6   1/1     Running   0          6m42s   10.0.41.175   ip-10-0-41-40.ap-northeast-1.compute.internal   <none>           <none>

httpd側のターゲットグループを確認するとPodのIPアドレスが登録されていることが分かります。

疎通確認

ブラウザからアクセスして疎通を確認します。

ALBのDNS名の末尾に/nginxを付与してアクセスします。

/nginx 配下には何もないので404にはなりますが、Podにはアクセスできています。

同様に、ALBのDNS名の末尾に/httpd を付与してアクセスします。

/httpd 配下には何もないので404にはなりますが、Podにはアクセスできています。

後始末

動作確認が終わったのでリソースを削除します。

kubectl delete -f alb-nginx.yaml
kubectl delete -f alb-httpd.yaml
terraform destroy -auto-approve

TargetGroupBinding

TargetGroupBindingはEKS管理の外に存在しているTargetGroupに対してPodを紐つけるカスタムリソースです。

動作確認

EKS クラスタ、ALB 、TargetGroup をTerraform で作成

example-target-group-binding ディレクトリに移動し、EKSクラスタを作成します。

TargetGroupBindingを利用するためにはEKS クラスタ管理外のALBとターゲットグループを事前に作成しておく必要があります。

main.tf
provider "aws" {
  region = var.aws_region
}

provider "kubernetes" {
  host                   = module.eks_cluster.eks_cluster_endpoint
  cluster_ca_certificate = base64decode(module.eks_cluster.cluster_certificate_authority_data)

  exec {
    api_version = "client.authentication.k8s.io/v1beta1"
    command     = "aws"
    args        = ["eks", "get-token", "--cluster-name", module.eks_cluster.eks_cluster_id]
  }
}

provider "helm" {
  kubernetes {
    host                   = module.eks_cluster.eks_cluster_endpoint
    cluster_ca_certificate = base64decode(module.eks_cluster.cluster_certificate_authority_data)

    exec {
      api_version = "client.authentication.k8s.io/v1beta1"
      command     = "aws"
      args        = ["eks", "get-token", "--cluster-name", module.eks_cluster.eks_cluster_id]
    }
  }
}

provider "kubectl" {
  apply_retry_count      = 10
  host                   = module.eks_cluster.eks_cluster_endpoint
  cluster_ca_certificate = base64decode(module.eks_cluster.cluster_certificate_authority_data)
  load_config_file       = false

  exec {
    api_version = "client.authentication.k8s.io/v1beta1"
    command     = "aws"
    args        = ["eks", "get-token", "--cluster-name", module.eks_cluster.eks_cluster_id]
  }
}

data "aws_eks_cluster_auth" "this" {
  name = module.eks_cluster.eks_cluster_id
}

module "eks_cluster" {
  source = "../modules/eks_cluster"

  aws_region      = var.aws_region
  service_name    = "tgb"
  cluster_version = "1.27"

  environment_name    = var.environment_name
}

// ALB とターゲットグループが必要

data "aws_vpc" "vpc" {
  filter {
    name   = "tag:Name"
    values = [var.environment_name]
  }
}

data "aws_subnets" "public" {
  filter {
    name   = "tag:Name"
    values = ["${var.environment_name}-public-*"]
  }
}

resource "aws_security_group" "example_target_group_binding_sg" {
  name   = "example-target-group-bindng-sg"
  vpc_id = data.aws_vpc.vpc.id

  egress = [
    {
      cidr_blocks = [
        "0.0.0.0/0",
      ]
      description      = ""
      from_port        = 0
      ipv6_cidr_blocks = []
      prefix_list_ids  = []
      protocol         = "-1"
      security_groups  = []
      self             = false
      to_port          = 0
    },
  ]
  ingress = [
    {
      cidr_blocks = [
        "119.25.132.221/32",
      ]
      description      = ""
      from_port        = 80
      ipv6_cidr_blocks = []
      prefix_list_ids  = []
      protocol         = "tcp"
      security_groups  = []
      self             = false
      to_port          = 80
    },
  ]
}

module "alb" {
  source  = "terraform-aws-modules/alb/aws"
  version = "~> 8.0"

  name = "example-target-group-binding"

  load_balancer_type = "application"

  vpc_id  = data.aws_vpc.vpc.id
  subnets = data.aws_subnets.public.ids

  security_groups = [
    aws_security_group.example_target_group_binding_sg.id
  ]

  target_groups = [
    {
      name_prefix      = "nginx-"
      backend_protocol = "HTTP"
      backend_port     = 80
      target_type      = "ip"
    },
    {
      name_prefix      = "httpd-"
      backend_protocol = "HTTP"
      backend_port     = 80
      target_type      = "ip"
    }
  ]

  http_tcp_listeners = [
    {
      port               = 80
      protocol           = "HTTP"
      target_group_index = 0
    },
    {
      port               = 80
      protocol           = "HTTP"
      target_group_index = 0
    }
  ]

  http_tcp_listener_rules = [
    {
      http_tcp_listeners_index = 0
      priority                 = 1

      actions = [{
        type               = "forward"
        path               = "/"
        target_group_index = 0
      }]

      conditions = [{
        path_patterns = ["/nginx"]
      }]
    },
    {
      http_tcp_listeners_index = 1
      priority                 = 2

      actions = [{
        type               = "forward"
        path               = "/"
        target_group_index = 1
      }]

      conditions = [{
        path_patterns = ["/httpd"]
      }]
    }
  ]
}
cd example-target-group-binding
terraform init
terraform apply -auto-approve

outputされるコマンドを実行してkubectlを設定します。

aws eks --region ap-northeast-1 update-kubeconfig --name example-alb-tgb

AWS コンソールにアクセスしてリソースを確認

Terraformで作成したALBを確認します。

リスナとルールを確認します。

リスナルールを確認します。

ターゲットグループにはまだ何も登録されていません。

nginx コンテナをデプロイ

DeploymentリソースとServiceリソースを作成し、nginxコンテナをデプロイします。

manifestの内容はIngressのものと同様です。

nginx.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: sample-nginx-ns
---
apiVersion: v1
kind: Service
metadata:
  name: service-sample-nginx
  namespace: sample-nginx-ns
  labels:
    app: sample-nginx
spec:
  selector:
    app: sample-nginx
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  namespace: sample-nginx-ns
  labels:
    app: sample-nginx
spec:
  selector:
    matchLabels:
      app: sample-nginx
  replicas: 3
  template:
    metadata:
      labels:
        app: sample-nginx
    spec:
      containers:
      - name: nginx
        image: public.ecr.aws/docker/library/nginx:latest
        ports:
        - containerPort: 80

TargetGroupBindingリソースを作成します。

tgb-nginx.yaml
apiVersion: elbv2.k8s.aws/v1beta1
kind: TargetGroupBinding
metadata:
  namespace: sample-nginx-ns
  name: sample-tgb
spec:
  serviceRef:
    name: service-sample-nginx
    port: 80
  targetGroupARN: arn:aws:elasticloadbalancing:ap-northeast-1:000000000000:targetgroup/nginx-00000000000000000000000000/xxxxxxxxxxxxxxxx
  targetType: ip
  networking:
    ingress:
    - from:
      - securityGroup:
          groupID: sg-00000000000000000
      ports:
      - protocol: TCP

Pod のIPアドレスを確認します。

kubectl get pods -n sample-nginx-ns -o wide
NAME                                READY   STATUS    RESTARTS   AGE   IP            NODE                                             NOMINATED NODE   READINESS GATES
nginx-deployment-57989d486d-c25d5   1/1     Running   0          86s   10.0.47.117   ip-10-0-47-169.ap-northeast-1.compute.internal   <none>           <none>
nginx-deployment-57989d486d-ltv5v   1/1     Running   0          86s   10.0.50.222   ip-10-0-51-254.ap-northeast-1.compute.internal   <none>           <none>
nginx-deployment-57989d486d-vdvws   1/1     Running   0          86s   10.0.42.96    ip-10-0-41-213.ap-northeast-1.compute.internal   <none>           <none>

ターゲットグループにPodのIPアドレスが登録されていることを確認します。

httpd コンテナをデプロイ

追加でコンテナをデプロイして、動作確認をしていきます。

manifestの内容はIngressのものと同様です。

httpd.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: sample-httpd-ns
---
apiVersion: v1
kind: Service
metadata:
  name: service-sample-httpd
  namespace: sample-httpd-ns
  labels:
    app: sample-httpd
spec:
  selector:
    app: sample-httpd
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: httpd-deployment
  namespace: sample-httpd-ns
  labels:
    app: sample-httpd
spec:
  selector:
    matchLabels:
      app: sample-httpd
  replicas: 3
  template:
    metadata:
      labels:
        app: sample-httpd
    spec:
      containers:
      - name: httpd
        image: public.ecr.aws/docker/library/httpd:latest
        ports:
        - containerPort: 80

TargetGroupBindingリソースを作成します。

tgb-httpd.yaml
apiVersion: elbv2.k8s.aws/v1beta1
kind: TargetGroupBinding
metadata:
  namespace: sample-httpd-ns
  name: sample-tgb
spec:
  serviceRef:
    name: service-sample-httpd
    port: 80
  targetGroupARN: arn:aws:elasticloadbalancing:ap-northeast-1:000000000000:targetgroup/httpd-00000000000000000000000000/xxxxxxxxxxxxxxxx
  targetType: ip
  networking:
    ingress:
    - from:
      - securityGroup:
          groupID: sg-00000000000000000
      ports:
      - protocol: TCP

Pod のIPアドレスを確認します。

kubectl get pods -n sample-httpd-ns -o wide
NAME                               READY   STATUS    RESTARTS   AGE     IP            NODE                                             NOMINATED NODE   READINESS GATES
httpd-deployment-b8bc6c5b4-c2pcp   1/1     Running   0          2m12s   10.0.44.195   ip-10-0-47-169.ap-northeast-1.compute.internal   <none>           <none>
httpd-deployment-b8bc6c5b4-p69vs   1/1     Running   0          2m12s   10.0.42.65    ip-10-0-41-213.ap-northeast-1.compute.internal   <none>           <none>
httpd-deployment-b8bc6c5b4-q6wzr   1/1     Running   0          2m12s   10.0.50.54    ip-10-0-51-254.ap-northeast-1.compute.internal   <none>           <none>

ターゲットグループにPodのIPアドレスが登録されていることを確認します。

疎通確認

ブラウザからアクセスして疎通を確認します。

ALBのDNS名の末尾に/nginxを付与してアクセスします。

/nginx 配下には何もないので404にはなりますが、Podにはアクセスできています。

同様に、ALBのDNS名の末尾に/httpd を付与してアクセスします。

/httpd 配下には何もないので404にはなりますが、Podにはアクセスできています。

後始末

動作確認が終わったのでリソースを削除します。

terraform destroy -auto-approve

まとめ

それぞれの機能の動作とPros/Consをまとめると次のようになります。

動作 Pros Cons
Ingress リソースが作成される度にALBが新規作成される k8s のエコシステム上でALB を扱えるためシンプルで直感的 EKS 以外のAWS 上のリソースと連携するのが困難
IngressGroup アノテーションで指定したグループ毎にALBが作成される ALB をまとめることてコスト削減できる 単一のALB に不可が集中しないように注意が必要
TargetGroupBinding 既存のターゲットグループを指定することでPodにルーティングする ALB とk8sを疎結合にしつつ、ルーティングを管理できる EKS とは別でALB の管理が必要

みなさんの現場では、どうAWS Load Balancer Controllerを使ってPodを公開していますか?

ぜひコメントで教えてください。

Discussion