새소식

AWS/EKS

[PKOS Study 2주차] 쿠버네티스 Service, Ingress (LoadBalancer controller)

  • -

CloudNet@ 팀의 가시다님께서 Leading 하시는 PKOS 2기 Study 내용 요약

해당 Kubernetes Study 는 '24단계 실습으로 정복하는 쿠버네티스' 책을 기반으로 진행 중입니다.

 

 

이번 포스팅에서는 쿠버네티스에서 AWS LoadBalancer 를 사용할 수 있게 해주는 LoadBalancer Controller 에 대해서 알아보겠습니다.

 

1. Service

로드밸런서 컨트롤러를 알아보기에 앞서, 쿠버네티스 서비스 오브젝트에 대해 간략하게만 짚고 넘어가겠습니다.

Service 오브젝트는 쿠버네티스에서 관리되는 무수히 많은 Pod 에 접근할 수 있는 쿠버네티스의 단일 진입점이라고 생각하면 됩니다.

 

 

Service 에는 ClusterIP , NodePort , LoadBalancer 타입이 존재합니다.

  • ClusterIP
    쿠버네티스 내부에서만 사용할 수 있는 ClusterIP 로 접근, 외부에서 접근 불가
  • NodePort
    외부에서 쿠버네티스 내부의 Pod로 접근하기 위해 실제 Worker Node 의 Port 하나를 지정하여 접근

  • LoadBalancer
    외부에서 로드밸런서를 통해 쿠버네티스 클러스터 내부 Pod 로 접근 가능
    온프레미스에서는 MetalLB 를 주로 사용하고, 클라우드에서는 각 CSP 의 LoadBalancer 를 이용합니다.
    이 때, 클라우드에서 제공하는 LB 서비스를 사용하기 위해서는 LoadBalancer Controller 가 필요합니다.



2. LoadBalancer Controller 배포

2.1. AWS IAM Policy 생성

쿠버네티스가 AWS LB 의 생성 및 Target Group 등을 만들 수 있도록 권한을 부여해주어야 합니다.

AWS CLI를 통해 다음과 같은 IAM Policy 를 생성합니다.

curl -o iam_policy.json https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/v2.4.5/docs/install/iam_policy.json

aws iam create-policy --policy-name AWSLoadBalancerControllerIAMPolicy --policy-document file://iam_policy.json

 

그 후, 생성한 IAM Policy 를 EC2 인스턴스 Role 에 연결해줍니다.

  • 아직 해당 kops 클러스터에 irsa 를 적용하지 않았기에 Service Account 를 생성하지 않고 EC2 인스턴스 역할에 정책을 연결해줍니다.
KOPS_CLUSTER_NAME=kimalarm.net

aws iam attach-role-policy --policy-arn arn:aws:iam::$ACCOUNT_ID:policy/AWSLoadBalancerControllerIAMPolicy --role-name masters.$KOPS_CLUSTER_NAME
aws iam attach-role-policy --policy-arn arn:aws:iam::$ACCOUNT_ID:policy/AWSLoadBalancerControllerIAMPolicy --role-name nodes.$KOPS_CLUSTER_NAME

 

2.2. AWS LoadBalancer Controller 설치

현재 클러스터 환경은 kops 로 구성되어 있기 때문에, 아래 명령어를 통해 kops 에 LB Controller 를 구성해줍니다.

kops edit cluster --name ${KOPS_CLUSTER_NAME}

-----
spec:
  certManager:
    enabled: true
  awsLoadBalancerController:
    enabled: true
-----

 

  • 이후 클러스터 업데이트를 실행합니다.
kops update cluster --yes && echo && sleep 5 && kops rolling-update cluster

 

  • 업데이트 완료 후 컨트롤러를 확인해봅니다.
kubectl describe deploy -n kube-system aws-load-balancer-controller

 

EKS에서 LB Controller 를 설치하려면 아래 Docs 를 참고해주세요.

 

AWS Load Balancer Controller 추가 기능 설치 - Amazon EKS

배포된 차트는 보안 업데이트를 자동으로 수신하지 않습니다. 새 차트가 사용 가능해지면 수동으로 업그레이드해야 합니다. 업그레이드 시 이전 명령에서 install을 upgrade로 변경하되, 이전 명령

docs.aws.amazon.com

 

 

2.3. 서비스 배포

다음 명령어를 통해 테스트 디플로이먼트를 배포합니다.

 

  • 2개의 테스트용 Pod 를 Deployment 형식으로 배포하고, NLB 타입의 로드밸런서를 해당 Deployment 와 연결해줍니다.
cat << EOF | kubectl create -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-echo
spec:
  replicas: 2
  selector:
    matchLabels:
      app: deploy-websrv
  template:
    metadata:
      labels:
        app: deploy-websrv
    spec:
      terminationGracePeriodSeconds: 0
      containers:
      - name: akos-websrv
        image: k8s.gcr.io/echoserver:1.5
        ports:
        - containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
  name: svc-nlb-ip-type
  annotations:
    service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: ip
    service.beta.kubernetes.io/aws-load-balancer-scheme: internet-facing
    service.beta.kubernetes.io/aws-load-balancer-healthcheck-port: "8080"
    service.beta.kubernetes.io/aws-load-balancer-cross-zone-load-balancing-enabled: "true"
spec:
  ports:
    - port: 80
      targetPort: 8080
      protocol: TCP
  type: LoadBalancer
  loadBalancerClass: service.k8s.aws/nlb
  selector:
    app: deploy-websrv
EOF

 

배포를 확인합니다.

kubectl get svc,targetgroupbindings

 

NLB 엔드포인트와 Target Group 이 생성된 것을 확인할 수 있습니다.

 

  • 동일한 NLB 도메인 주소

 

  • 특이한 것은 대상 그룹에 등록된 IP 가 현재 서비스 중인 Pod 의 IP 와 Direct 로 연결된다는 것입니다.

 

 

실제로 LB 가 정상적으로 부하를 분산하는 지 확인해봅시다.

NLB=$(kubectl get svc svc-nlb-ip-type -o jsonpath={.status.loadBalancer.ingress[0].hostname})

for i in {1..100}; do curl -s $NLB | grep Hostname ; done | sort | uniq -c | sort -nr

 

  • 정상적으로 부하를 분산합니다.

 

2.4. AWS LB 대상 그룹 동작 확인

  • Pod 의 개수가 변경될 때 LB와 함께 배포되어 있는 대상 그룹의 설정은 어떻게 변할 지 확인해봅시다.

 

  • Pod 의 개수를 줄여봅니다.
kubectl scale deployment deploy-echo --replicas=1

 

Pod 가 삭제되자 해당 Pod 의 IP 를 대상 그룹에서 자동으로 제거해줍니다.

 

  • 반대로 Pod 의 개수를 늘려봅니다.
kubectl scale deployment deploy-echo --replicas=3

 

Pod 가 생성되자 해당 Pod 의 IP 를 자동으로 등록해줍니다.



3. Ingress

Ingress 는 클러스터 내부 서비스를 외부로 노출 (http/https) 하는 Web Proxy 역할을 하는 Object 입니다.

  • Service 의 LoadBalancer Type 이 4계층의 NLB 서비스를 배포하는 것이었다면,
    Ingress 는 7 계층의 ALB 서비스를 배포하는 것입니다.

 

때문에, Domain Path 를 기반으로 각각 다른 서비스에 접근 할 수 있도록 해주는 것이 가능합니다.



3.1. Cluster에 Ingress 권한 부여

Ingress 또한 ALB 를 생성할 수 있어야 하므로, Service 와 똑같이 LB 권한을 부여합니다.
또한, ALB 에 ExternalDNS 를 부여하기 위해 Route53 권한도 추가해줍니다.

 

  • 이후, 클러스터를 편집합니다.
kops edit cluster
-----
spec:
  certManager:
    enabled: true
  awsLoadBalancerController:
    enabled: true
  externalDns:
    provider: external-dns
-----

kops update cluster --yes && echo && sleep 3 && kops rolling-update cluster

 

3.2. Ingress 배포

다음 명령어를 통해 Ingress 오브젝트를 배포합니다.

 

2048 게임을 실행시키는 2개의 pod 를 가진 deployment 를 생성하고, 서비스를 생성한 뒤 Ingress 를 통해
/ Path 로 진입 시 2048 게임으로 이동하도록 설정해둔 yaml 파일입니다.

cat << EOF > ingress-test.yaml
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: 2
  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
EOF


kubectl apply -f ingress-test.yaml

 

ALB 생성 확인 가능

 

 

3.3. Ingress Domain Path 편집

Ingress 타입은 Domain 을 기반으로 서비스할 위치를 변경할 수 있습니다.

AWS 에서 제공하는 다음 그림을 보면 이해하시기 편합니다.

 

2048 게임은 /2048 으로 들어오게 만들고, 마리오 게임은 /mario 로 들어오게 만들어 봅시다.

그러기 위해서는 우선 마리오 게임을 배포해야 합니다.
실습을 위해 마리오 게임 또한 game-2048 Namespace 위에 배포합니다.

cat << EOF | kubectl create -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  namespace: game-2048
  name: mario
  labels:
    app: mario
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mario
  template:
    metadata:
      labels:
        app: mario
    spec:
      containers:
      - name: mario
        image: pengbai/docker-supermario
---
apiVersion: v1
kind: Service
metadata:
  namespace: game-2048
  name: mario
spec:
  selector:
    app: mario
  ports:
  - port: 80
    protocol: TCP
    targetPort: 8080
  type: NodePort
EOF

 

이후 기존의 Ingress 를 삭제하고 다음과 같은 구성의 Ingress 를 재배포 합니다.

cat << EOF > ingress-path.yml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  namespace: game-2048
  name: ingress-2048
  annotations:
    kubernetes.io/ingress.class: alb
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/target-type: ip
spec:
  ingressClassName: alb
  rules:
    - http:
        paths:
        - path: /game
          pathType: Prefix
          backend:
            service:
              name: service-2048
              port:
                number: 80
        paths:
        - path: /mario
          pathType: Prefix
          backend:
            service:
              name: mario
              port:
                number: 80
EOF

 

 

 


 

Contents

포스팅 주소를 복사했습니다