logo
Back

EKS Workshop - ALB Not Creating 실습

27 views

AWS EKS Workshop 실습 (1): 기본 환경 셋팅하기

오늘은 EKS Workshop 실습을 해 본다.

공식 워크샵 링크를 클릭하면 실습을 따라 해 볼 수 있다.

하지만 처음에 이 링크만 보고 바로 시작하려다 보니 많이 헤맸다. 본격적인 실습에 앞서 먼저 환경 셋팅을 진행해야 한다.

본인의 AWS 계정으로 자원을 만들어 실습하는 기본적인 방법은 아래 가이드 링크에서 확인할 수 있다.

👉 AWS 계정 셋팅 가이드 링크

아래는 가이드 페이지의 캡쳐 사진이다

나는 하단의 링크를 통해 실습용 자원을 직접 생성했다. (us-west-2 리전 기준)

👉 us-west-2 리전 생성: Launch Stack

1. CloudFormation 스택 생성

AWS에 로그인한 상태에서 위 링크를 클릭하면 CloudFormation 생성 화면이 나온다.

화면 하단에서 동의에 체크하고 스택을 생성한다. 내 경우 스택이 모두 만들어지는 데 약 8분 정도가 소요되었다.

2. 웹 IDE 접속 및 비밀번호 확인

자원 생성이 완료되었으면, CloudFormation의 '출력(Outputs)' 탭에 들어가서 출력된 결과를 확인한다.

출력된 키값 중에서 IdePasswordSecret이라고 적힌 Secrets Manager 링크를 클릭하여 접속한다.

해당 링크로 접속 시 나오는 보안 암호 값을 복사한다. (빨간 상자로 표시된 복사 버튼을 누르면 된다.)

이후 다시 CloudFormation 출력 탭으로 돌아와, 이번에는 IdeUrl이라고 적힌 링크로 접속한 뒤 방금 복사한 비밀번호를 입력해 준다.

3. 쿠버네티스 클러스터 환경 셋팅

비밀번호를 입력하고 들어가면 웹 브라우저 화면에 VS Code가 나타난다. 이제 하단 터미널에 아래 명령어를 입력하여 EKS 쿠버네티스 환경을 셋팅한다.

bash
export EKS_CLUSTER_NAME=eks-workshop
curl -fsSL https://raw.githubusercontent.com/aws-samples/eks-workshop-v2/stable/cluster/eksctl/cluster.yaml | \
envsubst | eksctl create cluster -f -

위 사진과 같이 입력해 준 다음 클러스터 생성이 완료 될 때가지 기다린다(약 20분 소요) 여기까지 잘 따라왔다면 EKS Workshop을 진행하기 위한 기본 셋팅은 모두 마무리되었다.

이제 본격적인 실습을 진행해 보면 된다.

ALB Controller 실습

https://www.eksworkshop.com/docs/troubleshooting/alb/ 페이지로 접속 해 본다.

시작 전 명령어를 입력하라고 한다, 우리도 입력해서 실습 환경을 구축한다.

bash
prepare-environment troubleshooting/alb

해당 명령어를 입력하게 되면 아래와 같은 사진이 나오면서 기본 환경을 셋팅 해 준다.

ALB가 생성되지 않음

AWS 로드 밸런서 컨트롤러가 인그레스 리소스에 대한 애플리케이션 로드 밸런서(ALB)를 생성하지 못하는 이유를 조사하는 것이 이번 실습의 목표이다.

애플리케이션 상태 확인 및 인그레스 확인

kubectl get pod -n ui 명령어를 이용해 ui 네임스페이스에 pod 를 확인해 본다.

bash
ec2-user:~/environment:$ kubectl get pod -n ui
NAME                  READY   STATUS    RESTARTS   AGE
ui-5989474687-nlgj6   1/1     Running   0          72s

파드는 정상적으로 동작중인 것을 볼 수 있다. kubectl get ingress/ui -n ui 명령어를 이용해 ingress 도 확인 해 본다.

bash
ec2-user:~/environment:$ kubectl get ingress/ui -n ui
NAME   CLASS   HOSTS   ADDRESS   PORTS   AGE
ui     alb     *                 80      113s

정상적인 경우엔 주소에 alb 주소가 나와야 하는데 나오지 않아 문제가 있는 것을 확인 할 수 있다.

상태 확인 및 서브넷에 태그 추가

kubectl describe ingress/ui -n ui 명령어를 이용해 상태를 확인한다. 문제의 원인은 로드밸런서가 생성될 서브넷은 태그가 있어야 하는데, 찾지를 못해서 생기는 이슈이다.

aws ec2 describe-subnets --filters "Name=tag:alpha.eksctl.io/cluster-name,Values=${EKS_CLUSTER_NAME}" --query 'Subnets[].SubnetId[]' 명령어로 서브넷을 확인해 본다.

bash
ec2-user:~/environment:$ aws ec2 describe-subnets --filters "Name=tag:alpha.eksctl.io/cluster-name,Values=${EKS_CLUSTER_NAME}" --query 'Subnets[].SubnetId[]'
[
    "subnet-097baf0c8c8fd6492",
    "subnet-00f89ccad467dcfb4",
    "subnet-0d25b9ede0b0ccead",
    "subnet-03601fc2cd885d785",
    "subnet-0aa1a833fa35e9c21",
    "subnet-08e2092879cd35dfd"
]

어느 서브넷이 Public subnet 인지 확인 해본다. 아래 명령어로 확인한다.

bash
for subnet_id in $(aws ec2 describe-subnets --filters "Name=tag:alpha.eksctl.io/cluster-name,Values=${EKS_CLUSTER_NAME}" --query 'Subnets[].SubnetId[]' --output text); do \
    echo "Subnet: ${subnet_id}"; \
    aws ec2 describe-route-tables --filters "Name=association.subnet-id,Values=${subnet_id}" \
      --query 'RouteTables[].Routes[].[DestinationCidrBlock,GatewayId]' --output text; \
done

위 사진과 같은 결과가 나오는데, 0.0.0.0/0 이 igw 로 연결된 것이 퍼블릭 서브넷이다. 태그가 있는지 한번 확인 해 본다

aws ec2 describe-subnets --filters 'Name=tag:kubernetes.io/role/elb,Values=1' --query 'Subnets[].SubnetId'

해당 태그가 있는 서브넷이 없다. 아래와 같이 태그 값을 만들어 준다. 위의 public subnet 값을 변경해서 입력하도록 한다.

bash
aws ec2 create-tags --resources subnet-097baf0c8c8fd6492 subnet-0d25b9ede0b0ccead subnet-0aa1a833fa35e9c21 \
      --tags 'Key="kubernetes.io/role/elb",Value=1'

aws ec2 describe-subnets --filters 'Name=tag:kubernetes.io/role/elb,Values=1' --query 'Subnets[].SubnetId' 로 확인한다.

bash
ec2-user:~/environment:$ aws ec2 describe-subnets --filters 'Name=tag:kubernetes.io/role/elb,Values=1' --query 'Subnets[].SubnetId'
[
    "subnet-097baf0c8c8fd6492",
    "subnet-0d25b9ede0b0ccead",
    "subnet-0aa1a833fa35e9c21"
]

정상 적용이 된 것을 확인 가능하다.

load balancer controller 재시작 및 로그 확인

kubectl -n kube-system rollout restart deploy aws-load-balancer-controller 로 재시작한다. 추가로 다시 ingress 확인한다. kubectl describe ingress/ui -n ui 명령어를 입력한다.

위와 같이 권한 문제가 나왔다. 권한 문제를 아래서 해결 해 보자.

AWS LoadBalancer IAM Debug

kubectl get serviceaccounts -n kube-system -l app.kubernetes.io/name=aws-load-balancer-controller -o yaml 명령어를 기용해 ServiceAccount 를 확인한다.

bash
ec2-user:~/environment:$ kubectl get serviceaccounts -n kube-system -l app.kubernetes.io/name=aws-load-balancer-controller -o yaml
apiVersion: v1
items:
- apiVersion: v1
  automountServiceAccountToken: true
  kind: ServiceAccount
  metadata:
    annotations:
      eks.amazonaws.com/role-arn: arn:aws:iam::975372933996:role/alb-controller-20260418125456121100000003
      meta.helm.sh/release-name: aws-load-balancer-controller
      meta.helm.sh/release-namespace: kube-system
    creationTimestamp: "2026-04-18T12:55:00Z"
    labels:
      app.kubernetes.io/instance: aws-load-balancer-controller
      app.kubernetes.io/managed-by: Helm
      app.kubernetes.io/name: aws-load-balancer-controller
      app.kubernetes.io/version: v2.7.1
      helm.sh/chart: aws-load-balancer-controller-1.7.1
    name: aws-load-balancer-controller-sa
    namespace: kube-system
    resourceVersion: "3195"
    uid: f636d808-c433-432c-9b4a-37b97d2b55b2
kind: List
metadata:
  resourceVersion: ""

eks.amazonaws.com/role-arn: arn:aws:iam::975372933996:role/alb-controller-20260418125456121100000003 해당 롤을 가지고 있는데, 해당 롤에 권한이 없다.

사전 정의 된 환경변수가 있어서 아래 명령어를 사용해서 role 에 policy 를 붙여 준다.

bash
aws iam attach-role-policy \
    --role-name ${LOAD_BALANCER_CONTROLLER_ROLE_NAME} \
    --policy-arn ${LOAD_BALANCER_CONTROLLER_POLICY_ARN_FIX}

kubectl -n kube-system rollout restart deploy aws-load-balancer-controller 로 ALB Controller 를 재시작한다.

ALB 생성까지는 시간이 조금 소요되므로, 조금 기다렸다가 kubectl get ingress -n ui 명령어를 입력해 ALB 가 제대로 바인딩 되었는지 확인한다. 해당 트러블 슈팅은 다음과 같이 마무리 되었다.

서비스가 엔드포인트를 등록하지 못함

위에 alb 주소로 접속하게 되면 아래와 같은 사진을 볼 수 있다. 뭔가 정상적이지 않다.

서비스를 확인 해 본다. kubectl -n ui get service/ui -o yaml

bash
ec2-user:~/environment:$ kubectl -n ui get service/ui -o yaml
apiVersion: v1
kind: Service
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"labels":{"app.kubernetes.io/component":"service","app.kubernetes.io/created-by":"eks-workshop","app.kubernetes.io/instance":"ui","app.kubernetes.io/managed-by":"Helm","app.kubernetes.io/name":"ui","helm.sh/chart":"ui-0.0.1"},"name":"ui","namespace":"ui"},"spec":{"ports":[{"name":"http","port":80,"protocol":"TCP","targetPort":"http"}],"selector":{"app.kubernetes.io/component":"service","app.kubernetes.io/instance":"ui","app.kubernetes.io/name":"ui-app"},"type":"ClusterIP"}}
  creationTimestamp: "2026-04-18T12:52:40Z"
  labels:
    app.kubernetes.io/component: service
    app.kubernetes.io/created-by: eks-workshop
    app.kubernetes.io/instance: ui
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/name: ui
    helm.sh/chart: ui-0.0.1
  name: ui
  namespace: ui
  resourceVersion: "3403"
  uid: d3713ac0-6eb6-4150-954e-319ab00eedb4
spec:
  clusterIP: 172.16.81.69
  clusterIPs:
  - 172.16.81.69
  internalTrafficPolicy: Cluster
  ipFamilies:
  - IPv4
  ipFamilyPolicy: SingleStack
  ports:
  - name: http
    port: 80
    protocol: TCP
    targetPort: http
  selector:
    app.kubernetes.io/component: service
    app.kubernetes.io/instance: ui
    app.kubernetes.io/name: ui-app
  sessionAffinity: None
  type: ClusterIP
status:
  loadBalancer: {}

인그레스도 확인 해 본다. kubectl get ingress/ui -n ui -o yaml

bash
ec2-user:~/environment:$ kubectl get ingress/ui -n ui -o yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    alb.ingress.kubernetes.io/healthcheck-path: /actuator/health/liveness
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/target-type: ip
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"networking.k8s.io/v1","kind":"Ingress","metadata":{"annotations":{"alb.ingress.kubernetes.io/healthcheck-path":"/actuator/health/liveness","alb.ingress.kubernetes.io/scheme":"internet-facing","alb.ingress.kubernetes.io/target-type":"ip"},"name":"ui","namespace":"ui"},"spec":{"ingressClassName":"alb","rules":[{"http":{"paths":[{"backend":{"service":{"name":"service-ui","port":{"number":80}}},"path":"/","pathType":"Prefix"}]}}]}}
  creationTimestamp: "2026-04-18T12:55:34Z"
  finalizers:
  - ingress.k8s.aws/resources
  generation: 1
  name: ui
  namespace: ui
  resourceVersion: "8271"
  uid: e73de185-eb46-43c5-99ac-cef11f54f78b
spec:
  ingressClassName: alb
  rules:
  - http:
      paths:
      - backend:
          service:
            name: service-ui
            port:
              number: 80
        path: /
        pathType: Prefix
status:
  loadBalancer:
    ingress:
    - hostname: k8s-ui-ui-5ddc3ba496-1821313371.us-west-2.elb.amazonaws.com

백엔드 ingress 부분에 서비스 이름이 서비스의 이름과 달라서 매핑이 안되고 있는 상태이다. kubectl edit 으로 수정해도 되고, 실습 내용을 기준으로 똑같이 진행해보려고 한다.

kubectl apply -k ~/environment/eks-workshop/modules/troubleshooting/alb/creating-alb/fix_ingress

해당 파일을 조회 해 보면 결국은 이름을 맞춰 주었다.

bash
ec2-user:~/environment:$ cat ~/environment/eks-workshop/modules/troubleshooting/alb/creating-alb/fix_ingress/ingress.yaml 
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ui
  namespace: ui
  annotations:
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/target-type: ip
    alb.ingress.kubernetes.io/healthcheck-path: /actuator/health/liveness
spec:
  ingressClassName: alb
  rules:
    - http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: ui
                port:
                  number: 80

다 될 줄 알았는데, 조회해 보면 503 에러가 발생한다.

503 이슈 해결

kubectl -n ui get endpoints ui 입력한다.

bash
NAME   ENDPOINTS   AGE
ui     <none>      30m

엔드포인트가 없다. 디플로이와 서비스를 조회한다. kubectl -n ui get deploy/ui -o yaml

kubectl -n ui get svc ui -o yaml 해당 서비스는 해당 부분이 ui-app 으로 되어 있다. 그러므로 서비스가 선택이 되지 않은 상태이다.

kubectl apply -k ~/environment/eks-workshop/modules/troubleshooting/alb/creating-alb/fix_ui 명령어로 사전에 수정된 파일을 적용한다. 적용 이후에, 정상적으로 서비스가 접속이 되는 것을 확인 할 수 있다.

자원 전체 제거

bash
delete-environment
eksctl delete cluster $EKS_CLUSTER_NAME --wait
aws cloudformation delete-stack --stack-name eks-workshop-ide

eksctl delete cluster $EKS_CLUSTER_NAME --wait aws cloudformation delete-stack --stack-name eks-workshop-ide 나는 해당 명령어가 되지 않아서, root 로 들어가서 콘솔에서 계속 삭제 했다.

실습 이후 중요한 정보들

실습을 마치면서 페이지에 정리 된 내용을 AI 를 이용해 정리 해 보았다.

1. 보안 및 운영 핵심 체크리스트

보안(Security)

  • KMS 키 정책: 암호화를 구현할 때 KMS 키 정책을 올바르게 구성한다.
  • 권한 확인: 서비스 역할(Service Role)에 필요한 권한이 제대로 부여되었는지 확인한다.
  • 배포 전 검증: 실제 환경에 배포하기 전에 보안 구성을 반드시 검증한다.

기본 문제 해결(Troubleshooting) 접근법

  • 리소스 체인 추적: 문제가 발생하면 노드 → 노드 그룹 → Auto Scaling Group(ASG) → 런치 템플릿의 체인을 따라가며 확인한다.
  • 단계별 점검: 각 단계에서 리소스의 건강 상태(Health)와 오류 메시지를 확인하고, 서비스 역할 권한의 누락 여부를 체크한다.

운영 모범 사례(Best Practices)

  • 보안 구현 및 변경 사항은 항상 비운영 환경에서 먼저 테스트한다.
  • 서비스 역할에 필요한 권한은 명확하게 문서화한다.
  • 적절한 오류 처리 및 모니터링 시스템을 구축한다.

2. AWS Load Balancer Controller 아키텍처 복습

컨트롤러가 애플리케이션 로드 밸런서(ALB)와 어떻게 연동되는지 핵심 구성 요소를 살펴본다.

  • 컨트롤러(Controller) 작동 방식

    • Kubernetes API 서버에서 발생하는 Ingress 이벤트를 지속적으로 감시한다.
    • 적합한 Ingress 리소스를 감지하면 해당 AWS 리소스 생성을 시작하며, 전체 수명 주기를 관리한다.
  • ALB (Application Load Balancer)

    • 각 Ingress 리소스에 대해 하나의 ALB가 생성된다.
    • 인터넷 연결형(Internet-facing) 또는 내부 연결형(Internal)으로 구성할 수 있다.
    • 서브넷 배치는 Ingress의 어노테이션(Annotation)을 통해 제어하며, 생성 및 관리를 위해서는 적절한 IAM 권한이 필수적이다.
  • 대상 그룹 (Target Group)

    • Ingress에 정의된 각 고유한 Kubernetes 서비스(Service)에 대해 생성된다.
    • Pod IP로 직접 트래픽을 전달하는 'IP 모드' 타겟팅을 지원한다.
    • 상태 점검(Health Check)은 어노테이션을 통해 구성할 수 있으며, 여러 서비스에 대해 여러 대상 그룹을 활용할 수 있다.
  • 리스너 (Listener) & 규칙 (Rules)

    • 리스너: 어노테이션에 지정된 포트(기본 80/443)에 대해 생성되며, SSL/TLS 인증서 첨부 및 HTTP/HTTPS 트래픽 구성을 지원한다.
    • 규칙: Ingress 리소스의 경로(Path) 사양을 기반으로 생성되어 트래픽을 적절한 대상 그룹으로 유도한다. 경로 기반 및 호스트 기반 라우팅을 지원하며 우선순위 지정이 가능하다.

3. 자주 발생하는 문제 및 해결 방법

ALB 구성 시 자주 발생하는 문제점과 확인해야 할 사항은 다음과 같다.

서브넷(Subnet) 구성

  • 퍼블릭 서브넷에는 반드시 kubernetes.io/role/elb=1 태그가 있어야 한다.
  • 프라이빗 서브넷에는 반드시 kubernetes.io/role/internal-elb=1 태그가 있어야 한다.
  • 각 서브넷이 라우팅 테이블과 올바르게 연결되어 있는지 확인한다.

IAM 권한

  • K8s 서비스 계정(Service Account)에는 적절한 IAM 역할(IRSA)이 연결되어야 한다.
  • 해당 역할에는 로드 밸런서 및 대상 그룹을 생성하고 수정할 수 있는 권한이 포함되어야 한다.

서비스(Service) 구성

  • 서비스의 셀렉터(Selector)는 타겟이 되는 Pod의 레이블(Label)과 정확히 일치해야 한다.
  • 서비스 포트는 컨테이너 포트와 일치해야 하며, 서비스 이름은 Ingress 백엔드 구성과 동일해야 한다.

4. ALB 운영 모범 사례 및 팁

AWS Load Balancer Controller를 사용할 때 다음 사항들을 권장한다.

  1. 인터넷에 연결되는 ALB를 생성하기 전, 서브넷 태그를 항상 먼저 확인한다.
  2. ALB의 동작을 명확하게 제어하려면 명시적인 어노테이션을 사용한다.
  3. 문제 해결 시 최우선으로 컨트롤러의 로그를 모니터링하고, 서비스 엔드포인트 등록 상태를 확인한다.
  4. 서비스와 Pod에는 직관적이고 의미 있는 레이블을 사용한다.
  5. 💡 Tip: 복잡한 사용자 지정 구성이나 심층적인 문제 해결이 필요할 때는 AWS Load Balancer Controller 공식 문서가 가장 유용한 참고 자료다. 꼭 즐겨찾기 해두고 참고하자.
logo
이 블로그는 NextJS 14, Strapi를 이용해 만들었습니다
Copyright © 2026 김기찬
문의사항은 admin@devchanki.com 으로 주시면 감사 하겠습니다.

문의 보내기

남겨주면 블로그 주인에게 바로 전달돼요.

답장은 별도도 확인 후 연락 드려요.