AWS ALB Ingress Controller
ALB Ingress Controller는 k8s 클러스터내에 정의한 Ingress 리소스를 관리하기 위한 컨트롤러이다.
Ingress만 정의해주면 알아서 해당 Ingress를 처리할 ALB를 동적으로 프로비저닝 해준다.
클러스터에 설치하기
AWS는 controller를 설치하는 방법으로 Helm Chart 와 manifest yaml 파일을 제공하고 있다.
기존에 인프라를 테라폼과 Helm으로 관리하고 있었어서, 본 포스팅은 Helm Chart를 사용한다.
Helm Chart가 아닌, 일반적인 manifest yaml 파일로도 설치하는 방법은 아래 링크를 참고하자.
https://docs.aws.amazon.com/ko_kr/eks/latest/userguide/aws-load-balancer-controller.html
AWS Load Balancer Controller 추가 기능 설치 - Amazon EKS
배포된 차트는 보안 업데이트를 자동으로 수신하지 않습니다. 새 차트가 사용 가능해지면 수동으로 업그레이드해야 합니다. 업그레이드 시 이전 명령에서 install을 upgrade로 변경하되, 이전 명령
docs.aws.amazon.com
먼저, 공식 문서를 읽어보면 적절한 IAM Policy, Role, SA 가 필요한것을 알 수 있다.
ALB Controller는 많은 사람들이 사용하기에, AWS 테라폼 공식 모듈에서도 지원하고 있었다.
위의 링크에서 ALB Controller가 아닌 다른 IRSA 들도 참고할 수 있다.
module "load_balancer_controller_irsa_role" {
source = "terraform-aws-modules/iam/aws//modules/iam-role-for-service-accounts-eks"
role_name = "aws-load-balancer-controller"
attach_load_balancer_controller_policy = true
oidc_providers = {
ex = {
provider_arn = module.eks.oidc_provider_arn
namespace_service_accounts = ["kube-system:aws-load-balancer-controller"]
}
}
}
모듈로 금방 controller를 위한 irsa를 마련했다. 이제 필요한건 SA와 Helm Chart이다.
resource "kubernetes_service_account" "aws-load-balancer-controller" {
metadata {
name = "aws-load-balancer-controller"
namespace = "kube-system"
annotations = {
"eks.amazonaws.com/role-arn" = module.load_balancer_controller_irsa_role.iam_role_arn
}
}
}
SA는 IRSA에서 정의했던대로, kube-system 네임스페이스안에 aws-load-balancer-controller라는 이름으로 만들어주었다.
그런 다음 Role Binding을 해주었다.
resource "helm_release" "aws-load-balancer-controller" {
depends_on = [module.load_balancer_controller_irsa_role]
name = "aws-load-balancer-controller"
repository = "https://aws.github.io/eks-charts"
chart = "aws-load-balancer-controller"
namespace = "kube-system"
set {
name = "image.repository"
value = "602401143452.dkr.ecr.ap-northeast-2.amazonaws.com/amazon/aws-load-balancer-controller" # Changes based on Region - This is for us-east-1 Additional Reference: https://docs.aws.amazon.com/eks/latest/userguide/add-ons-images.html
}
set {
name = "serviceAccount.create"
value = "false"
}
set {
name = "serviceAccount.name"
value = "aws-load-balancer-controller"
}
set {
name = "clusterName"
value = module.eks.cluster_name
}
}
Helm 리소스에서는, 이미 SA를 만들었기에 따로 SA를 create하지 않았고 기존 이름을 붙여넣어주었다.
여기서 image.repository는 Region마다 상이하니 꼭 자신의 Region에 맞는 곳을 사용하자.
여기까지 정의한 다음 클러스터에 적용시키면 설치가 끝나게 된다.
동작 확인
먼저 SA가 제대로 생성됐나 확인해보자.
Annotation에 우리가 정의한 Role도 제대로 들어가있는것을 확인할 수 있다.
잘 작동하는지 확인해 보려면 Ingress 를 클러스터에 적용시키면 된다.
---
apiVersion: v1
kind: Namespace
metadata:
name: game-2048
---
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: game-2048
name: deployment-2048
spec:
selector:
matchLabels:
app.kubernetes.io/name: app-2048
replicas: 5
template:
metadata:
labels:
app.kubernetes.io/name: app-2048
spec:
containers:
- image: public.ecr.aws/l6m2t8p7/docker-2048:latest
imagePullPolicy: Always
name: app-2048
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
namespace: game-2048
name: service-2048
spec:
ports:
- port: 80
targetPort: 80
protocol: TCP
type: NodePort
selector:
app.kubernetes.io/name: app-2048
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
namespace: game-2048
name: ingress-2048
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-2048
port:
number: 80
AWS 에서 예제로 제공하는 Yaml 파일이다.
정의한 리소스들이 생성되는것을 볼 수 있다.
AWS 콘솔에서도 로드밸런서가 생성되는것을 볼 수 있다.
완전히 프로비저닝 되기까지는 보통 2~3분정도 걸리니 기다리면 된다.
본론
이 글을 작성하게 됐던 이유는,
ALB Ingress Controller를 이용해 서로 다른 네임스페이스에 있는 Ingress를 처리하는 과정이 순탄치 않았기 때문이다.
Ingress는 여러 서비스를 Path 기반으로 라우팅 할 수 있게 해주는데,
문제는 이 서비스가 네임스페이스에 종속적이라는 것이다. 더군다나 Ingress도 네임스페이스에 종속적이다.
위의 예제에서 Ingress가 처리하는 service-2048 이라는 서비스는 Ingress와 같은 game-2048 네임스페이스에 속한다.
하지만 다른 네임스페이스에 있는 서비스를 처리해야 한다면?
그게 왜 필요한데?
현재 프로젝트 CI CD 환경 구성을 위해 Jenkins와 ArgoCD를 설치하던 중이었다.
둘 다 Helm으로 배포하기로 결정했는데 문제는 namespace 값에 종속적인 value들이 너무 많기도 하고,
공식 문서에서도 각자 jenkins, argocd 라는 네임스페이스를 만드는것을 기준으로 설명하고 있었다.
Jenkins와 ArgoCD는 외부에서 접근하기 위해 Service가 필수적인데, 이 때 문제에 직면했다.
각자 Ingress와 ALB를 따로 두면 문제가 없지만, 쓸데없는 비용이 발생한다는 점과,
나중에 도메인을 구입했을 때 admin.xxx/jenkins, admin.xxx/argocd 로 한곳에서 관리하여 편의성을 높이고 싶었다.
한번 해보자
지금까지의 구성도는 다음과 같다.
Another ns에 Another Service가 있다고 가정해보자.
혹시 모르니 Ingress에 무작정 추가해보기
혹시 이런 구성이 가능하지 않을까?
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
namespace: game-2048
name: ingress-2048
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-2048
port:
number: 80
- path: /another ## 추가
pathType: Prefix
backend:
service:
name: service-another
port:
number: 80
이렇게 끝났다면 정말 해피했을테지만,,,, 글 내용은 아직 더 남았다.
앞서 언급한것처럼 Ingress 와 Service는 네임스페이스에 종속적이다.
다시 말해, 논리적으로 완벽히 분리되어 있어 /another 경로로 아무리 요청이 와도 service에 접근할 수 없다.
Service의 externalName
externalName은 Service를 소개하면서 잠깐 다루었었다.
https://imsongkk.tistory.com/66#article-2-4--externalname
[Kubernetes] 쿠버네티스 오브젝트 [Service]
Service 이전까지 컨테이너를 구성하는 오브젝트들을 살펴봤다면 이 포스트에서는 생성한 파드를 외부에 노출시킬 수 있는 오브젝트를 다룬다. 외부에 노출이라 하면 파드 외부, 노드 외부, 클러
imsongkk.tistory.com
Service에게 일종의 별칭을 부여하는 느낌인데, 이런 DNS를 resolving 해주는건 CoreDNS라는 녀석이다.
EKS를 구성하면서 기본 AddOn으로 포함되어있던걸 보았는데,
Ingress에서 라우팅 할 Service를 찾을때도 CoreDNS를 이용한다고 한다.
일반적으로 Service들은 <service-name>.<namespace>.svc.cluster.local 이라는 이름으로 CoreDNS에 등록되어 있다.
externalName을 설정하여 다른 네임스페이스에 있는 서비스도 가리킬 수 있게 만드는 방식이다.
kind: Service
apiVersion: v1
metadata:
name: my-service
spec:
type: ExternalName
externalName: test-service.namespacename.svc.cluster.local
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: example-ingress
spec:
rules:
- host: example.com
http:
paths:
- path: /
backend:
serviceName: my-service
servicePort: 80
my-service는 현재 네임스페이스에 속한 service이지만, 실제로 가리키는 곳은 다른 네임스페이스에 있는 service이다.
이를 통해 Ingress 단에서 다른 네임스페이스에 속한 Service로 라우팅이 가능해진다.
하지만 Service가 중간에 하나 더 생긴다는 점과, CoreDNS의 정확한 동작방식을 모르기에 도입이 망설여졌다.
ALB Ingress Controller Annotations
그렇게 망설이던중, 한줄기 빛을 발견했다,,,, 역시 있을줄 알았어
k8s 기본 리소스도 그렇고, 특히나 외부 클라우드 플랫폼 리소스를 사용할 때 Annotation을 이용하는 일이 많은데,
내가 해결하고 싶었던 문제도 Annotation을 통해 비교적 간단하게 해결할 수 있는 문제였다.
Annotations - AWS Load Balancer Controller
Ingress annotations You can add annotations to kubernetes Ingress and Service objects to customize their behavior. Annotation keys and values can only be strings. Advanced format should be encoded as below: boolean: 'true' integer: '42' stringList: s1,s2,s
kubernetes-sigs.github.io
문서를 읽어보면, group.name을 통해 여러 개의 Ingress들을 단일 ALB에서 처리할 수 있다고 한다.
즉, 여러 개의 Ingress 들을 하나의 group으로 묶을 수 있다는 뜻이다.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
namespace: jenkins
name: jenkins-ingress
annotations:
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
alb.ingress.kubernetes.io/group.name: admin-ingress # 같은 그룹!
alb.ingress.kubernetes.io/group.order: 1 # 1 순위로 처리되는 Rule
spec:
ingressClassName: alb
rules:
- http:
paths:
- path: /jenkins
pathType: Prefix
backend:
service:
name: service-jenkins
port:
number: 80
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
namespace: argocd
name: argocd-ingress
annotations:
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
alb.ingress.kubernetes.io/group.name: admin-ingress # 같은 그룹!
alb.ingress.kubernetes.io/group.order: 2 # 2 순위로 처리되는 Rule
spec:
ingressClassName: alb
rules:
- http:
paths:
- path: /argocd
pathType: Prefix
backend:
service:
name: service-argocd
port:
number: 80
서로 다른 네임스페이스에 존재하는 Ingress이지만, annotation에 group.name을 추가함으로 인해
같은 Ingress group으로 묶여서 처리된다고 한다.
이때 각 ingress 마다 order를 주어 먼저 처리해야 할 rule을 정할수도 있다.
최종적으로는 다음과 같이 구성되게 된다.
단일 ALB로 admin 작업에 필요한 Pod들을 외부로 노출시킬 수 있게 되었다.
'Trouble Shooting' 카테고리의 다른 글
AWS EKS ArgoCD 환경 구축하기 [1/2] (0) | 2023.08.28 |
---|---|
Jenkins Webhook Multiple branch 빌드 하기 (0) | 2023.08.28 |
MSA 환경에서 Swagger 서버 구축하기 (0) | 2023.08.05 |
AWS EKS Jenkins 환경 구축하기 [2/2] (0) | 2023.07.31 |
AWS EKS Jenkins 환경 구축하기 [1/2] (0) | 2023.07.31 |