Amazon EKS 클러스터의 여러 Kubernetes 서비스에 대한 외부 액세스를 제공하려면 어떻게 해야 하나요?

9분 분량
0

Amazon Elastic Kubernetes Service(Amazon EKS) 클러스터에서 여러 Kubernetes 서비스에 대한 외부 액세스를 제공하려고 합니다.

간략한 설명

Kubernetes용 NGINX 인그레스 컨트롤러 또는 AWS Load Balancer Controller를 사용하여 Amazon EKS 클러스터의 여러 Kubernetes 서비스에 대한 외부 액세스를 제공합니다. NGINX 인그레스 컨트롤러는 주로 NGINX에 의해 유지 관리됩니다. NGINX 인그레스 컨트롤러와 관련된 문제를 확인하려면 GitHub 웹 사이트의 문제 목록을 참조하세요. AWS Load Balancer Controller는 Amazon Web Services(AWS)에서 유지 관리합니다. AWS Load Balancer Controller 관련 문제를 확인하려면 GitHub 웹 사이트의 문제 목록을 참조하세요.

중요: 인그레스 컨트롤러 및 Kubernetes 웹 사이트의 IngressClass는 Kubernetes 웹 사이트의 Ingress와 다릅니다. Ingress는 클러스터 외부에서 클러스터 내 서비스로 HTTP 및 HTTPS 경로를 노출하는 Kubernetes 리소스입니다. 인그레스 컨트롤러는 보통 로드 밸런서를 사용하여 Ingress를 이행합니다. 인그레스 컨트롤러 없이는 Ingress를 사용할 수 없습니다. IngressClass는 Ingress 객체 요청을 이행하는 데 사용할 인그레스 컨트롤러를 식별하는 데 사용됩니다.

전제 조건: AWS Load Balancer Controller를 설치합니다. AWS Load Balancer Controller를 사용하여 Amazon EKS에서 LoadBalancer 유형 서비스 객체에 대한 Network Load Balancer를 생성하고 관리하는 것이 가장 좋습니다.

해결 방법

다음 해결 방법은 Kubernetes GitHub 웹사이트의 kubernetes/ingress-nginx 인그레스 컨트롤러를 사용하는 것입니다. 공개적으로 사용할 수 있는 다른 인그레스 컨트롤러는 NGINX GitHub 웹사이트의 nginxinc/kubernetes-ingress입니다.

Kubernetes용 NGINX 인그레스 컨트롤러 배포

전송 제어 프로토콜(TCP) 또는 전송 계층 보안(TLS)으로 Kubernetes용 NGINX 인그레스 컨트롤러를 배포할 수 있습니다.

참고: 다음 해결 방법은 Amazon EKS 버전 1.22, NGINX 인그레스 컨트롤러 버전 1.3.0 및 AWS Load Balancer Controller 버전 2.4.3에서 테스트되었습니다.

(옵션 1) Network Load Balancer에서 TCP를 사용하는 NGINX 인그레스 컨트롤러

1.    다음 Kubernetes 객체를 배포하기 위해 YAML 파일을 가져옵니다. namespace, serviceaccounts, configmap, clusterroles, clusterrolebindings, roles, rolebindings, services, deployments, ingressclasses, validatingwebhookconfigurations

wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/aws/deploy.yaml

2.    파일을 편집합니다. 그런 다음 ingress-nginx-controller 서비스 객체 섹션에서 모든 service.beta.kubernetes.io 주석을 다음과 같이 바꿉니다.

service.beta.kubernetes.io/aws-load-balancer-backend-protocol: tcp
service.beta.kubernetes.io/aws-load-balancer-cross-zone-load-balancing-enabled: "true"
service.beta.kubernetes.io/aws-load-balancer-type: "external"
service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: "instance"
service.beta.kubernetes.io/aws-load-balancer-scheme: "internet-facing"

3.    매니페스트를 적용합니다.

kubectl apply -f deploy.yaml

예시 출력:

namespace/ingress-nginx created 
serviceaccount/ingress-nginx created 
configmap/ingress-nginx-controller created 
clusterrole.rbac.authorization.k8s.io/ingress-nginx created 
clusterrolebinding.rbac.authorization.k8s.io/ingress-nginx created 
role.rbac.authorization.k8s.io/ingress-nginx created 
rolebinding.rbac.authorization.k8s.io/ingress-nginx created 
service/ingress-nginx-controller-admission created 
service/ingress-nginx-controller created 
deployment.apps/ingress-nginx-controller created 
ingressclass.networking.k8s.io/nginx created
validatingwebhookconfiguration.admissionregistration.k8s.io/ingress-nginx-admission created 
serviceaccount/ingress-nginx-admission created 
clusterrole.rbac.authorization.k8s.io/ingress-nginx-admission created 
clusterrolebinding.rbac.authorization.k8s.io/ingress-nginx-admission created

(옵션 2) Network Load Balancer에서 NGINX 인그레스 컨트롤러 TLS 종료

기본적으로 이전 솔루션은 NGINX 인그레스 컨트롤러에서 TLS를 종료합니다. Network Load Balancer에서 TLS를 종료하도록 NGINX 인그레스 서비스를 구성할 수도 있습니다.

1.    deploy.yaml 템플릿을 다운로드합니다.

wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/aws/nlb-with-tls-termination/deploy.yaml

2.    파일을 편집합니다. 그런 다음 ingress-nginx-controller 서비스 객체 섹션에서 모든 service.beta.kubernetes.io 주석을 다음과 같이 바꿉니다.

service.beta.kubernetes.io/aws-load-balancer-cross-zone-load-balancing-enabled: "true"
service.beta.kubernetes.io/aws-load-balancer-ssl-cert: arn:aws:acm:us-west-2:XXXXXXXX:certificate/XXXXXX-XXXXXXX-XXXXXXX-XXXXXXXX
service.beta.kubernetes.io/aws-load-balancer-ssl-ports: "443"
service.beta.kubernetes.io/aws-load-balancer-type: "external"
service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: "instance"
service.beta.kubernetes.io/aws-load-balancer-scheme: "internet-facing"

참고: service.beta.kubernetes.io/aws-load-balancer-ssl-cert에 대한 ARN을 포함해야 합니다.

3.    파일을 편집하고 Kubernetes 클러스터에 대한 Amazon Virtual Private Cloud(VPC) CIDR을 변경합니다.

proxy-real-ip-cidr: XXX.XXX.XXX/XX

4.    매니페스트를 적용합니다.

kubectl apply -f deploy.yaml

참고: 이전 매니페스트는 ExternalTrafficPolicy로컬로 사용하여 소스(클라이언트) IP 주소를 보존합니다. Amazon VPC에서 사용자 지정 DHCP 이름과 함께 이 구성을 사용하면 문제가 발생합니다. 문제가 발생하지 않도록 하려면 kube-proxy에 다음 패치를 적용합니다.

kubectl edit daemonset kube-proxy -n kube-system

5.    다음 스니펫을 포함하도록 매니페스트를 편집합니다.

spec:
  template:
    spec:
      containers:
        - name: kube-proxy
          command:
            - kube-proxy
            - --hostname-override=$(NODE_NAME)
            - --v=2
            - --config=/var/lib/kube-proxy-config/config
           env:
            - name: NODE_NAME
              valueFrom:
                fieldRef:
                  apiVersion: v1
                  fieldPath: spec.nodeName

배포된 리소스 확인

AWS Load Balancer Controller

명령:

kubectl get all -n kube-system --selector app.kubernetes.io/instance=aws-load-balancer-controller

예시 출력:

NAME                                                READY   STATUS    RESTARTS   AGE   IP               NODE                                           NOMINATED NODE   READINESS GATES
pod/aws-load-balancer-controller-85cd8965dc-ctkjt   1/1     Running   0          48m   192.168.37.36    ip-192-168-59-225.us-east-2.compute.internal   none             none 
pod/aws-load-balancer-controller-85cd8965dc-wpwx9   1/1     Running   0          48m   192.168.53.110   ip-192-168-59-225.us-east-2.compute.internal   none>         none 
NAME                                        TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE   SELECTOR 
service/aws-load-balancer-webhook-service   ClusterIP   10.100.154.44   none          443/TCP   19h   app.kubernetes.io/instance=aws-load-balancer-controller,app.kubernetes.io/name=aws-load-balancer-controller 
NAME                                           READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS                   IMAGES                                                                                    SELECTOR 
deployment.apps/aws-load-balancer-controller   2/2     2            2           19h   aws-load-balancer-controller 602401143452.dkr.ecr.us-west-2.amazonaws.com/amazon/aws-load-balancer-controller:v2.4.0   app.kubernetes.io/instance=aws-load-balancer-controller,app.kubernetes.io/name=aws-load-balancer-controller 
NAME                                                      DESIRED   CURRENT   READY   AGE   CONTAINERS                     IMAGES                                                                                    SELECTOR 
replicaset.apps/aws-load-balancer-controller-85cd8965dc   2         2         2       19h   aws-load-balancer-controller   602401143452.dkr.ecr.us-west-2.amazonaws.com/amazon/aws-load-balancer-controller:v2.4.0   app.kubernetes.io/instance=aws-load-balancer-controller,app.kubernetes.io/name=aws-load-balancer-controller,pod-template-hash=85cd8965dc

NGINX 인그레스 컨트롤러

명령:

kubectl get all -n ingress-nginx --selector app.kubernetes.io/instance=ingress-nginx

예시 출력:

NAME                                           READY  STATUS   RESTARTS  AGE   IP               NODE                                           NOMINATED NODE  READINESS GATES
pod/ingress-nginx-controller-54d8b558d4-k4pdf  1/1    Running  0         56m   192.168.46.241   ip-192-168-59-225.us-east-2.compute.internal   none            none
NAME                                        TYPE           CLUSTER-IP      EXTERNAL-IP                                                                     PORT(S)                      AGE   SELECTOR
service/ingress-nginx-controller            LoadBalancer   10.100.99.129   ad9bba7a8239a475297d24bd2f617782-a579e639079f8270.elb.us-east-2.amazonaws.com   80:32578/TCP,443:30724/TCP   15h   app.kubernetes.io/component=controller,app.kubernetes.io/instance=ingress-nginx,app.kubernetes.io/name=ingress-nginx
service/ingress-nginx-controller-admission  ClusterIP      10.100.190.61   none                                                                            443/TCP                      15h   app.kubernetes.io/component=controller,app.kubernetes.io/instance=ingress-nginx,app.kubernetes.io/name=ingress-nginx
NAME                                       READY   UP-TO-DATE   AVAILABLE    AGE   CONTAINERS   IMAGES                                                                                                               SELECTOR
deployment.apps/ingress-nginx-controller   1/1     1            1            15h   controller   k8s.gcr.io/ingress-nginx/controller:v1.1.1@sha256:0bc88eb15f9e7f84e8e56c14fa5735aaa488b840983f87bd79b1054190e660de   app.kubernetes.io/component=controller,app.kubernetes.io/instance=ingress-nginx,app.kubernetes.io/name=ingress-nginx
NAME                                                  DESIRED   CURRENT   READY   AGE   CONTAINERS   IMAGES                                                                                                               SELECTOR
replicaset.apps/ingress-nginx-controller-54d8b558d4   1         1         1       15h   controller   k8s.gcr.io/ingress-nginx/controller:v1.1.1@sha256:0bc88eb15f9e7f84e8e56c14fa5735aaa488b840983f87bd79b1054190e660de   app.kubernetes.io/component=controller,app.kubernetes.io/instance=ingress-nginx,app.kubernetes.io/name=ingress-nginx,pod-template-hash=54d8b558d4
NAME                                       COMPLETIONS   DURATION   AGE   CONTAINERS   IMAGES                                                                                                                         SELECTOR
job.batch/ingress-nginx-admission-create   1/1           2s         15h   create       k8s.gcr.io/ingress-nginx/kube-webhook-certgen:v1.1.1@sha256:64d8c73dca984af206adf9d6d7e46aa550362b1d7a01f3a0a91b20cc67868660   controller-uid=242bdf56-de16-471d-a691-1ca1dbc10a41
job.batch/ingress-nginx-admission-patch    1/1           2s         15h   patch        k8s.gcr.io/ingress-nginx/kube-webhook-certgen:v1.1.1@sha256:64d8c73dca984af206adf9d6d7e46aa550362b1d7a01f3a0a91b20cc67868660   controller-uid=a9e710d2-5001-4d40-a435-ddc8993bfe42

IngressClass

명령:

kubectl get ingressclass

예시 출력:

NAME    CONTROLLER             PARAMETERS                             AGE 
alb     ingress.k8s.aws/alb    IngressClassParams.elbv2.k8s.aws/alb   19h 
nginx   k8s.io/ingress-nginx   none                                   15h

배포 설정 테스트

참고: 다음 단계는 두 개의 마이크로서비스를 실행하는 단계입니다. 마이크로서비스는 Kubernetes를 기본 유형으로 사용하여 내부적으로 노출됩니다.

1.    배포 또는 마이크로서비스를 설정합니다. 예를 들어, hostname-appapache-app입니다.

hostname-app에 대한 hostname-app-svc.yaml 파일의 예:

apiVersion: apps/v1 
kind: Deployment 
metadata:
  name: hostname-app
  namespace: default 
spec:
  replicas: 2
  selector:
    matchLabels:
      app: hostname-app
  template:
    metadata:
      labels:
        app: hostname-app
    spec:
      containers:
      - name: hostname-app
        image: k8s.gcr.io/serve_hostname:1.1 

--- 
apiVersion: v1 
kind: Service 
metadata:
  name: hostname-svc
  namespace: default 
spec:
  ports:
  - port: 80
    targetPort: 9376
    protocol: TCP
  selector:
    app: hostname-app

apache-app에 대한** apache-app-svc.yaml** 파일의 예:

apiVersion: apps/v1 
kind: Deployment 
metadata:
  name: apache-app
  namespace: default 
spec:
  replicas: 2
  selector:
    matchLabels:
      app: apache-app
  template:
    metadata:
      labels:
        app: apache-app
    spec:
      containers:
      - name: apache-app
        image: httpd:latest
        ports:
        - containerPort: 80 

--- 
apiVersion: v1 
kind: Service 
metadata:
  name: apache-svc
  namespace: default
  labels: 
spec:
  ports:
  - port: 80
    targetPort: 80
    protocol: TCP
  selector:
    app: apache-app

2.    구성을 적용합니다.

hostname-app:

kubectl apply -f hostname-app-svc.yaml

apache-app:

kubectl apply -f apache-app-svc.yaml

3.    리소스가 생성되었는지 확인합니다.

배포

명령:

kubectl get deployment hostname-app apache-app -n default

예시 출력:

NAME           READY   UP-TO-DATE   AVAILABLE   AGE 
hostname-app   2/2     2            2           29m
apache-app     2/2     2            2           29m

서비스

명령:

kubectl get svc apache-svc hostname-svc -n default

예시 출력:

NAME           TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE 
apache-svc     ClusterIP   10.100.73.51    none          80/TCP    29m 
hostname-svc   ClusterIP   10.100.100.44   none          80/TCP    29m

NGINX 인그레스 컨트롤러 테스트

1.    명령줄에서 검색한 로드 밸런서의 DNS URL에 액세스합니다.

curl -I ad9bba7a8239a475297d24bd2f617782-a579e639079f8270.elb.us-east-2.amazonaws.com

예시 출력:

HTTP/1.1 404 Not Found 
Date: Thu, 03 Mar 2022 14:03:11 GMT 
Content-Type: text/html 
Content-Length: 146 
Connection: keep-alive

참고: 기본 서버는 인그레스 규칙이 정의되지 않은 모든 도메인 요청에 대해 404 Not Found 페이지를 반환합니다. 정의된 규칙에 따라 인그레스 컨트롤러는 요청이 구성과 일치하지 않는 한 지정된 백엔드 서비스로 트래픽을 전환하지 않습니다. 호스트 필드가 Ingress 객체에 대해 구성되어 있기 때문에 요청의 호스트 헤더에 동일한 호스트 이름을 제공해야 합니다. 테스트 환경에서는 curl 플래그를 사용하여 호스트 헤더를 제공합니다. 프로덕션 환경에서는 로드 밸런서 DNS 이름을 Amazon Route 53과 같은 DNS 공급자의 호스트 이름에 매핑합니다.

2.    NGINX 인그레스 컨트롤러에서 제공하는 단일 로드 밸런서를 사용하여 서비스와 인터페이스하도록 인그레스를 구현합니다.

micro-ingress.yaml 예시:

apiVersion: networking.k8s.io/v1 
kind: Ingress 
metadata:
  name: micro-ingress
  namespace: default
  annotations: 
    kubernetes.io/ingress.class: nginx 
spec:
  rules:
    - host: hostname.mydomain.com
      http:
        paths:
        - backend:
            service:
              name: hostname-svc
              port:
                number: 80
          path: /
          pathType: Prefix
  - host: apache.mydomain.com
    http:
      paths:
      - backend:
          service:
            name: apache-svc
            port:
              number: 80
        path: /
        pathType: Prefix

참고: 자세한 내용은 Kubernetes 웹 사이트의 이름 기반의 가상 호스팅을 참조하세요.

3.    리소스가 생성되었는지 확인합니다.

Ingress

명령:

kubectl get ingress -n default

예시 출력:

NAME           CLASS   HOSTS                                       ADDRESS                                                                         PORTS   AGE 
micro-ingress  none    hostname.mydomain.com,apache.mydomain.com   ad9bba7a8239a475297d24bd2f617782-a579e639079f8270.elb.us-east-2.amazonaws.com   80      29m

4.    요청에 호스트 헤더를 추가합니다.

처음 구성된 도메인:

curl -i -H "Host: hostname.mydomain.com" http://aaa71bxxxxx-11xxxxx10.us-east-2.elb.amazonaws.com/

예시 출력:

HTTP/1.1 200 OK Date: Sat, 26 Mar 2022 18:50:38 GMT Content-Type: text/plain; charset=utf-8 Content-Length: 29 Connection: keep-alive

두 번째로 구성된 도메인:

curl -i -H "Host: apache.mydomain.com" http://aaa71bxxxxx-11xxxxx10.us-east-2.elb.amazonaws.com/

예시 출력:

HTTP/1.1 200 OK 
Date: Sat, 26 Mar 2022 18:51:00 GMT 
Content-Type: text/html 
Content-Length: 45 
Connection: keep-alive 
Last-Modified: Mon, 11 Jun 2007 18:53:14 GMT 
ETag: "2d-432a5e4a73a80" 
Accept-Ranges: bytes

호스트 헤더를 추가한 후 인그레스 컨트롤러가 Ingress에 정의된 구성과 일치하는 백엔드 구성 서비스로 트래픽을 리디렉션합니다.

동일한 도메인 이름을 유지하면서 액세스한 경로를 기반으로 트래픽을 전환하려면 Ingress를 사용하여 경로 기반 라우팅을 추가해야 합니다.

예를 들어 다음과 같습니다.

apiVersion: networking.k8s.io/v1 
kind: Ingress 
metadata:
  name: path-ingress
  namespace: default
  annotations:
    kubernetes.io/ingress.class: nginxd
    nginx.ingress.kubernetes.io/rewrite-target: / 
spec:
  rules:
  - host: mydomain.com
    http:
      paths:
      - backend:
          service:
            name: hostname-svc
            port:
              number: 80
        path: /hostname
        pathType: Prefix
  - host: mydomain.com
    http:
      paths:
      - backend:
          service:
            name: apache-svc
            port:
              number: 80
        path: /apache
        pathType: Prefix

참고: 앞의 예시에서는 요청에 mydomain.com호스트 헤더로 있는 경우 200개의 응답만 반환됩니다. 요청은 /hostname 또는 /apache 경로에서 액세스됩니다. 다른 모든 요청의 경우 404 응답이 반환됩니다.

5.    경로 기반 라우팅이 추가되었는지 확인합니다.

명령:

kubectl get ingress -n default

출력:

NAME            CLASS  HOSTS                                       ADDRESS                                                                         PORTS  AGE
micro-ingress   none   hostname.mydomain.com,apache.mydomain.com   ad9bba7a8239a475297d24bd2f617782-a579e639079f8270.elb.us-east-2.amazonaws.com   80     164m
path-ingress    none   mydomain.com,mydomain.com                   ad9bba7a8239a475297d24bd2f617782-a579e639079f8270.elb.us-east-2.amazonaws.com   80     120m

명령:

curl -i -H "Host: mydomain.com" http://aaa71bxxxxx-11xxxxx10.us-east-2.elb.amazonaws.com/hostname

-또는-

curl -i -H "Host: mydomain.com" http://aaa71bxxxxx-11xxxxx10.us-east-2.elb.amazonaws.com/apache

AWS Load Balancer Controller를 사용하여 인그레스 테스트

1.    다음 예시 인그레스 매니페스트를 사용하여 Application Load Balancer를 시작합니다.

apiVersion: networking.k8s.io/v1 
kind: Ingress 
metadata:
  name: micro-ingress-alb
  namespace: default
  annotations:
    kubernetes.io/ingress.class: alb 
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/target-type: ip 
spec:
  rules:
  - host: alb.hostname.mydomain.com
    http:
      paths:
      - backend:
          service:
            name: hostname-svc
            port:
              number: 80
        path: /
        pathType: Prefix
   - host: alb.apache.mydomain.com
     http:
       - backend:
            service:
              name: apache-svc
              port:
                number: 80
         path: /
         pathType: Prefix

2.    Application Load Balancer가 시작되는지 확인합니다.

명령:

kubectl get ingress -n default

출력:

NAME               CLASS  HOSTS                                               ADDRESS                                                                         PORTS  AGE
micro-ingress      none   hostname.mydomain.com,apache.mydomain.com           ad9bba7a8239a475297d24bd2f617782-a579e639079f8270.elb.us-east-2.amazonaws.com   80     164m
micro-ingress-alb  none   alb.hostname.mydomain.com,alb.apache.mydomain.com   k8s-default-microing-8a252bde81-1907206594.us-east-2.elb.amazonaws.com          80     18m
path-ingress       none   mydomain.com,mydomain.com                           ad9bba7a8239a475297d24bd2f617782-a579e639079f8270.elb.us-east-2.amazonaws.com   80     120m

첫 번째로 구성된 도메인을 기반으로 한 요청:

curl -i -H "Host: alb.hostname.mydomain.com" http://k8s-default-microing-8a252bde81-1907206594.us-east-2.elb.amazonaws.com

예시 출력:

HTTP/1.1 200 OK Date: Sat, 26 Mar 2022 20:46:02 GMT Content-Type: text/plain; charset=utf-8 Content-Length: 29 Connection: keep-alive

두 번째로 구성된 도메인을 기반으로 한 요청:

curl -i -H "Host: alb.apache.mydomain.com" http://k8s-default-microing-8a252bde81-1907206594.us-east-2.elb.amazonaws.com

예시 출력:

HTTP/1.1 200 OK 
Date: Sat, 26 Mar 2022 20:46:14 GMT 
Content-Type: text/html Content-Length: 45 
Connection: keep-alive 
Server: Apache/2.4.53 (Unix) 
Last-Modified: Mon, 11 Jun 2007 18:53:14 GMT 
ETag: "2d-432a5e4a73a80" 
Accept-Ranges: bytes

AWS 공식
AWS 공식업데이트됨 2년 전
댓글 없음