0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ALB ControllerでALBを管理させつつ削除させない方法

Posted at

ALB Controllerを使うとK8sのIngressリソースと連動してALBをデプロイできます。しかし、Ingressリソースを消してしまうとALBも一緒に消えてしまいます。ALBのホスト名を外部DNSに登録している場合など、ALBを極力消したくないこともあります。

ALB CotrollerでALBを管理さsつつ削除させない方法をいくつか考えました。

まとめ

以下3つの方法を考えました。

  1. 削除保護の設定: annotationsでalb.ingress.kubernetes.io/load-balancer-attributes: deletion_protection.enabled=trueを設定する方法です。K8sリソースの削除を実行してもIngressおよびALBは削除されません。一見これで十分なような気がしますが削除を実行したコマンドが返ってこなくなる問題があります。
  2. グループの利用: annotationsのalb.ingress.kubernetes.io/group.nameを活用する方法です。デプロイ用とルール設定用でIngressリソースを分けつつ同じIngressグループを指定します。ルール設定用のIngressを削除してもALBは削除されずルールだけ消えます。
  3. 外部管理LB: あらかじめALBを作成しておきCRDのTargetGroupBindingでターゲットを管理する方法です。ALBはK8sの管理外になるためK8sの操作ではALBは消えなくなります。

個人的には1と2を組み合わせて使うのが安全で使いやすいやり方だと思います。具体的にはデプロイ用のIngressに削除保護を設定しルール設定用のIngressでルールを設定します。こうすることでALBを使いまわしつつ気軽にIngressを消したりできます。

3の方法はALBやルールの管理をK8s外で管理する必要があったり、Podとの通信許可(セキュリティグループ)にも気を配る必要があります。しかし、異なるEKS間でALBを共有したり、既存のALBを使用したいユースケースに使えます。

1. 削除保護の設定

AWSのリソースには削除を防止する削除保護の設定があります。Ingressのannotationsでalb.ingress.kubernetes.io/load-balancer-attributes: deletion_protection.enabled=trueを設定するとALB ControllerでデプロイするALBに削除保護が設定されます。ALB Controllerのドキュメントにある説明はこちらです。

設定例

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: test
  annotations:
    alb.ingress.kubernetes.io/target-type: ip
    alb.ingress.kubernetes.io/load-balancer-attributes: deletion_protection.enabled=true
spec:
  ingressClassName: alb
  rules:
  - http:
      paths:
      - backend:
          service:
            name: test
            port:
              number: 80
        path: /
        pathType: Exact

動作確認

上記applyすると以下のようにデプロイされます。

$ kubectl get ingress
NAME   CLASS   HOSTS   ADDRESS                                                                            PORTS   AGE
test   alb     *       internal-k8s-default-test-0beab48a0d-1864872286.ap-northeast-1.elb.amazonaws.com   80      13s

Ingressを削除します。すると以下のようになるものの、プロンプトは返って来なくなります。(10分ほど待っても返って来ません。)

$ kubectl delete ingress test
ingress.networking.k8s.io "test" deleted

ALB Controllerのログを確認すると削除保護により削除できなかった旨を確認できます。

$ kubectl logs -n kube-system aws-load-balancer-controller-7db9f97875-5z766
...
{"level":"error","ts":1739089983.5857038,"logger":"controller-runtime.manager.controller.ingress","msg":"Reconciler error","name":"test","namespace":"default","error":"deletion_protection is enabled, cannot delete the ingress: test"}

Ingressを確認するとまだ残っています。

$ kubectl get ingress
NAME   CLASS   HOSTS   ADDRESS                                                                            PORTS   AGE
test   alb     *       internal-k8s-default-test-0beab48a0d-1864872286.ap-northeast-1.elb.amazonaws.com   80      20m

Ingressを消したい場合、annotationsのalb.ingress.kubernetes.io/load-balancer-attributesを削除します。

$ kubectl annotate ingress test alb.ingress.kubernetes.io/load-balancer-attributes-

するとしばらくするとIngressが消えます。

$ kubectl get ingress
No resources found in default namespace.

このようにdeletion_protection.enabled=trueを設定することでIngressおよびALBの削除を防ぐことができます。しかし、プロンプトが返ってこないのは少々面倒です。

2. グループの利用

ALB ControllerのIngressにはannotationsでalb.ingress.kubernetes.io/group.nameを設定できます。同じグループ名を指定したIngressはALBを共有します。これを使いALBのデプロイ用とルール設定用の2つのIngressを用意します。ALB Controllerのドキュメントにある説明はこちらです。

設定例

以下2つのIngressを準備します。

デプロイ用
pathは何かしらの設定が必要だったのでダミーのパスを設定しています。commonというグループに属します。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: deploy
  annotations:
    alb.ingress.kubernetes.io/group.name: common
    alb.ingress.kubernetes.io/target-type: ip
    alb.ingress.kubernetes.io/actions.response-503: >
      {"type":"fixed-response","fixedResponseConfig":{"contentType":"text/plain","statusCode":"503","messageBody":"503 error text"}}
spec:
  ingressClassName: alb
  rules:
  - http:
      paths:
      - path: /dummy
        pathType: Exact
        backend:
          service:
            name: dummy
            port:
              name: response-503

ルール用
バックエンドへのルート設定をします。こちらもcommonというグループに属します。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: test
  annotations:
    alb.ingress.kubernetes.io/group.name: common
    alb.ingress.kubernetes.io/target-type: ip
spec:
  ingressClassName: alb
  rules:
  - http:
      paths:
      - backend:
          service:
            name: test
            port:
              number: 80
        path: /
        pathType: Exact

動作確認

上記applyすると以下のようにデプロイされます。Ingressは2つありますがADDRESSで同じALBを使用していることがわかります。

$ kubectl get ingress
NAME     CLASS   HOSTS   ADDRESS                                                                      PORTS   AGE
deploy   alb     *       internal-k8s-common-5ba7cb9a7a-1608177685.ap-northeast-1.elb.amazonaws.com   80      26s
test     alb     *       internal-k8s-common-5ba7cb9a7a-1608177685.ap-northeast-1.elb.amazonaws.com   80      27s

ルール設定用のtestを削除します。プロンプトはすぐに返ってきます。

$ kubectl delete ingress test
ingress.networking.k8s.io "test" deleted

確認するとdeployは残っています。

$ kubectl get ingress
NAME     CLASS   HOSTS   ADDRESS                                                                      PORTS   AGE
deploy   alb     *       internal-k8s-common-5ba7cb9a7a-1608177685.ap-northeast-1.elb.amazonaws.com   80      6m2s

このようにcommonグループに属するIngressがすべて消えるまでALBは残り続けます。deployのIngressにはさらに1. 削除保護の設定の設定をしておけばより安全になります。

3. 外部管理LB

ALB ControllerのIngressをデプロイすると内部的にはCRDのTargetGroupBindingリソースも作られます。TargetGroupBindingはALBにアタッチされているターゲットグループを管理するもので、Ingressのターゲットに指定したServiceの背後にいるPodのIPアドレスを自動で登録します。これによりPodが入れ替わっても引き続きALB経由でアクセスできます。

TargetGroupBindingリソースを手動で作成すると既存ALBのターゲットグループをALB Controllerで管理できます。ALB Controllerのドキュメントにある説明はこちらです。TargetGroupBindingリソース自体はALBをデプロイしていないためTargetGroupBindingリソースを消してもALBは削除されません。

しかし、Ingressを使わないためIngressで使用できるALB Controllerのannotationsは使えません。また、IngressだとPodのセキュリティグループも自動で更新されますがそれもされなくなります。ALB関連リソース(ALB、ターゲットグループ、リスナー、セキュリティグループ)はK8s外部で管理します。

設定例

以下のように事前にALBやリスナーを用意します。作成したTargetGroupのARNを確認します。

resource "aws_lb" "this" {
  name               = "alb-test"
  internal           = true
  load_balancer_type = "application"
  security_groups    = [aws_security_group.alb.id]
  subnets            = data.terraform_remote_state.eks.outputs.vpc.private_subnets
}

resource "aws_security_group" "alb" {
  name        = "alb-test"
  description = "alb-test"
  vpc_id      = data.terraform_remote_state.eks.outputs.vpc.vpc_id

  ingress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

resource "aws_lb_target_group" "this" {
  name        = "alb-test"
  port        = 80
  protocol    = "HTTP"
  target_type = "ip"
  vpc_id      = data.terraform_remote_state.eks.outputs.vpc.vpc_id
}

resource "aws_lb_listener" "this" {
  load_balancer_arn = aws_lb.this.arn
  port              = "80"
  protocol          = "HTTP"

  default_action {
    type             = "forward"
    target_group_arn = aws_lb_target_group.this.arn
  }
}

K8sマニフェストは以下の通りです。targetGroupARNに作成したターゲットグループのARNを指定します。

apiVersion: elbv2.k8s.aws/v1beta1
kind: TargetGroupBinding
metadata:
  name: tgb-test
spec:
  serviceRef:
    name: tgb-test
    port: 80
  targetGroupARN: arn:aws:elasticloadbalancing:ap-northeast-1:XXXXXXXXXXXX:targetgroup/alb-test/c43cacc256114e34

動作確認

リソースデプロイ後、TargetGroupBinding、Ingress、Podを確認します。TargetGroupBindingはありますがIngressはありません。

$ kubectl get TargetGroupBinding,ingress,pod -o wide
NAME                                        SERVICE-NAME   SERVICE-PORT   TARGET-TYPE   ARN                                                                                              AGE
targetgroupbinding.elbv2.k8s.aws/tgb-test   tgb-test       80             ip            arn:aws:elasticloadbalancing:ap-northeast-1:XXXXXXXXXXXX:targetgroup/alb-test/c43cacc256114e34   17m

NAME                            READY   STATUS    RESTARTS   AGE   IP           NODE                                           NOMINATED NODE   READINESS GATES
pod/tgb-test-59df87c7df-659lp   1/1     Running   0          17m   10.0.1.253   ip-10-0-1-86.ap-northeast-1.compute.internal   <none>           <none>

ALBとターゲットグループを確認すると以下の通りです。ターゲットはPodのIPアドレスになっています。ヘルスがunhealthyになっていますがPod(Node)にアタッチされたセキュリティグループにALBのセキュリティグループからのインバウンドを許可していないからです。別途セキュリティグループの許可を追加するとhealthyになります。

$ aws elbv2 describe-load-balancers --region=ap-northeast-1 | jq '.LoadBalancers[].LoadBalancerName'
"alb-test"

$ aws elbv2 describe-target-health --target-group-arn="arn:aws:elasticloadbalancing:ap-northeast-1:XXXXXXXXXXXX:targetgroup/alb-test/c43cacc256114e34" --region=ap-northeast-1
{
    "TargetHealthDescriptions": [
        {
            "Target": {
                "Id": "10.0.1.253",
                "Port": 80,
                "AvailabilityZone": "ap-northeast-1a"
            },
            "HealthCheckPort": "80",
            "TargetHealth": {
                "State": "unhealthy",
                "Reason": "Target.Timeout",
                "Description": "Request timed out"
            }
        }
    ]
}

Podを削除してIPアドレスを変えてみます。

$ kubectl delete pod tgb-test-59df87c7df-659lp
pod "tgb-test-59df87c7df-659lp" deleted

$ kubectl get pod -o wide
NAME                        READY   STATUS    RESTARTS   AGE   IP           NODE                                           NOMINATED NODE   READINESS GATES
tgb-test-59df87c7df-4z8sc   1/1     Running   0          27s   10.0.1.138   ip-10-0-1-86.ap-northeast-1.compute.internal   <none>           <none>

ターゲットグループを確認するとターゲットのIPアドレスが更新されています。(ターゲットグループからPodのアドレスが消えるまで少し時間がかかります。)

$ aws elbv2 describe-target-health --target-group-arn="arn:aws:elasticloadbalancing:ap-northeast-1:XXXXXXXXXXXX:targetgroup/alb-test/c43cacc256114e34" --region=ap-northeast-1
{
    "TargetHealthDescriptions": [
        {
            "Target": {
                "Id": "10.0.1.138",
                "Port": 80,
                "AvailabilityZone": "ap-northeast-1a"
            },
            "HealthCheckPort": "80",
            "TargetHealth": {
                "State": "healthy"
            }
        }
    ]
}

TargetGroupBindingを消します。

$ kubectl delete TargetGroupBinding tgb-test
targetgroupbinding.elbv2.k8s.aws "tgb-test" deleted

ALBとターゲットグループは引き続きのこります。(ターゲットグループからPodのアドレスが消えるまで少し時間がかかります。)

$ aws elbv2 describe-load-balancers --region=ap-northeast-1 | jq '.LoadBalancers[].LoadBalancerName'
"alb-test"

$ aws elbv2 describe-target-health --target-group-arn="arn:aws:elasticloadbalancing:ap-northeast-1:XXXXXXXXXXXX:targetgroup/alb-test/c43cacc256114e34" --region=ap-northeast-1
{
    "TargetHealthDescriptions": []
}

このようにTargetGroupBindingを使うと既存のALBやターゲットグループを ALB Controllerで管理でき、TargetGroupBindingを消しても既存のAWSリソースは消えません。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?