ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 쿠버네티스 인그레스(kubernetes ingress)
    Kubernetes 2018. 7. 18. 09:00
    인그레스(ingress)는 클러스터 외부에서 내부로 접근하는 요청들을 어떻게 처리할지 정의해둔 규칙들의 모음입니다. 외부에서 접근가능한 URL을 사용할 수 있게 하고, 트래픽 로드밸런싱도 해주고, SSL 인증서 처리도 해주고, 도메인 기반으로 가상 호스팅을 제공하기도 합니다. 인그레스 자체는 이런 규칙들을 정의해둔 자원이고 이런 규칙들을 실제로 동작하게 해주는게 인그레스 컨트롤러(ingress controller)입니다. 
    클라우드 서비스를 사용하게 되면 별다른 설정없이 각 클라우드 서비스에서 자사의 로드밸런서 서비스들과 연동해서 인그레스를 사용할 수 있게 해줍니다. 클라우드 서비스를 사용하지 않고 직접 쿠버네티스 클러스터를 구축해서 사용하는 경우라면 인그레스 컨트롤러를 직접 인그레스와 연동해 주어야 합니다. 이때 가장 많이 사용되는건 쿠버네티스에서 제공하는  ingress-nginx(https://github.com/kubernetes/ingress-nginx) 입니다. 
    nginx 인그레스 컨트롤러는 인그레스에 설정된 내용을 nginx 환경설정으로 변경해서 nginx에 적용합니다. 이외에도 다양한 인그레스 컨트롤러가 있습니다. 인그레스용 yaml 템플릿은 다음과 같은 형식으로 작성할 수 있습니다.
    apiVersion: extensions/v1beta1
    kind: Ingress
    metadata:
      name: test
      annotations:
        nginx.ingress.kubernetes.io/rewrite-target: /
    spec:
      rules:
      - host: foo.bar.com
        http:
          paths:
          - path: /foos1
            backend:
              serviceName: s1
              servicePort: 80
          - path: /bars2
            backend:
              serviceName: s2
              servicePort: 80
      - host: bar.foo.com
        http:
          paths:
          - backend:
              serviceName: s2
              servicePort: 80
    이 인그레스를 생성하면 아래와 같은 결과를 볼 수 있습니다. foo.bar.com으로 요청이 들어오더라도 뒷부분의 경로에 따라 /foos1이면 서비스 s1으로 연결되고 /bars2이면 서비스 s2쪽으로 연결되도록 설정된걸 확인할 수 있습니다. 그리고 또다른 호스트명인 bar.foot.com도 서비스 s2로 연결되어 있습니다. 이처럼 인그레스를 이용하면 외부에서 들어오는 요청을 다양하게 처리할 수 있습니다.



    인그레스 컨트롤러 : nginx
    인그레스는 결국 설정일 뿐이고 이 설정내용대로 동작하는 실제 행위자가 인그레스 컨트롤러 입니다. 인그레스 컨트롤러는 여러가지가 있지만 쿠버네티스가 공식적으로 제공하고 있는건 gce용인 ingress-gce와 nginx용인 ingress-nginx 2가지가 있습니다. ingress-gce는 gce를 이용하면 자동으로 사용할 수 있고 여기서는 직접 설치해서 사용할 수 있는 ingress-nginx를 알아보도록 하겠습니다. ingress-nginx는 github https://github.com/kubernetes/ingress-nginx 에서 확인할 수 있습니다. 
    다음 명령으로 ingress-nginx 를 실행할 수 있습니다.
     kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/mandatory.yaml

    이제 이 인그레스 컨트롤러에 접근해보기위한 서비스를 만들어 보겠습니다.
    kubectl expose deploy nginx-ingress-controller --type=NodePort -n ingress-nginx


    http://localhost:30821/ 로 접근해 보면 아래처럼 화면이 보이는걸 확인할 수 있습니다.

    설정이 없을때는 기본 벡엔드로 설정된 default backend가 보입니다. 이제 앞에서 ingress로 설정한 foo.bar.com에 접근해 보겠습니다. 기존에 만들어 뒀던 nginx-deployment를 인그레스에 연결하기 위해서 인그레스에 지정했던 s1이라는 이름으로 nginx-deployment의 서비스를 아래처럼 만듭니다.
    kubectl expose deploy nginx-deployment --name s1

    도메인 기반으로 접근해야 하기 때문에 현재 장비의 /etc/hosts파일을 변경해 주어야 합니다.
    sudo vi /etc/hosts를 통해서 아래 내용을 hosts파일에 추가해 줍니다.
    127.0.0.1 foo.bar.com

    이제 브라우저에서 http://foo.bar.com:30821/foos1 에 접근해 봅니다. 다음 그림처럼 nginx화면이 나오는걸 확인할 수 있습니다.



    이제 인그레스 컨트롤러의 nginx에 어떻게 실제 설정이 들어 있는지 확인해 보겠습니다. 다음처럼 인그레스 컨트롤러의 포드 이름을 확인해서 직접 컨테이너에 접속합니다.
    kubectl get pods -n ingress-nginx
    kubectl -n ingress-nginx exec -it nginx-ingress-controller-c6d66b4fb-7bjjp /bin/bash
    컨테이너 안에서 다음 명령으로 nginx 설정을 확인해 봅니다.
    cat /etc/nginx/nginx.conf
    다음처럼 10.1.0.118:80쪽으로 연결되어 있는 설정을 보실 수 있습니다.
        upstream default-s1-80 {
            least_conn;

            keepalive 32;

            server 10.1.0.118:80 max_fails=0 fail_timeout=0;

        }
    여기서 눈여겨 봐야할 점은 10.1.0.118이라는 IP입니다. 인그레스 설정에는 s1 서비스를 foo.bar.com이랑 연결했습니다. 그런데 s1 서비스의 IP를 확인해 보면 10.111.129.110으로 나옵니다. 그럼 10.1.0.118은 어디서 온 IP일까요? nginx에 설정된 ip는 포드의 ip입니다. 인그레스 컨트롤러를 통해서 트래픽이 전달될때 중간에 서비스를 거치지 않고 직접 포드로 연결되는 구조입니다. 이 예제에서는 인그레스 컨트롤러자체도 쿠버네티스 클러스터 위에서 돌아가기 때문에 인그레스 컨트롤러에 접근하기위해서 NodePort타입의 서비스를 만들어 줬습니다. 하지만 인그레스 컨트롤러의 네트워크 옵션을 호스트모드로 주게 되면 별도의 노드포트 없이도 인그레스 컨트롤러에 접근가능하게 되고 다시 거기서 포드로 직접 접근가능하게 되기 때문에 중간에 서비스들을 생략해서 좀 더 좋은 성능을 가질 수 있게 됩니다. 구조는 다음 그림과 같습니다.


    댓글 15

    • 프로필사진

      Public 클라우드가 아닌 사설로 클러스터를 구축한 경우에는 External-IP가 자동으로 잡히지 않아 Service LB 구성시 Master의 IP를 지정했는데, LB를 여러개 묶으려면 어떻게 해야 하나요? Ingress에서는 특별히 외부 IP를 지정하는 설정이 없는것 같은데.. On Premise로 구축된 내부 사설 사이트를 외부에 오픈할때 구성 방법등이 궁금합니다.

      2018.09.25 14:13
      • 프로필사진

        방법은 여러가지가 있을것 같아요. 현재 사설망의 구성에 따라 선택할 수 있는 옵션이 달라질것 같은데요.
        장비를 쓴다면 External-IP를 사용할 수 있는 물리LB를 연동할수도 있을거구요.
        클러스터내에서 해결하려면 LB전용 노드를 두고 그 앞에서 물리LB를 두고 LB들을 묶으면 될것 같아요.
        ingress controller를 클러스터 외부에 노출하는 방법은 띄울때 hostport를 지정해주거나, hostnetwork옵션을 주어서 host의 네트워크를 사용하게 할 수 있어요.

        2018.09.28 14:37 신고
    • 프로필사진

      답변 감사합니다. 만일 물리적인 L4 장비를 안쓰고 클러스터내에서 LB를 구성해야 한다면 일반적으로 Load Balancer 역활을 하는 Node를 별도 지정해서 하나요? 그 Node에는 Load Balancing을 해주는 Pod를 올려줘야 하나요? (hxProxy 같은) 그 node가 죽으면 LB가 안될텐데 그럼 LB용 노드를 여러대 두고 DNS RR로 돌려야 하나요?
      AWS나 GCS에선 LB가 제공되니 신경 쓸일이 없는데 On-Premise 환경은 어떻게 해야하지 감이 안잡히네요.

      2018.10.08 18:54
      • 프로필사진

        완벽한 HA를 위해서라면 결국 LB가 있어야 해요. DNS RR로 어느정도 가능하긴 하지만 LB노드가 죽었을때 죽은 LB를 DNS에서 자동으로 제외시켜주는게 아니라서요. consul 같은 서비스 디스커버리 도구를 이용하면 어느 정도는 가능할 것도 같네요.

        2018.10.11 21:30 신고
    • 프로필사진

      안녕하세요? 한가지 질문이 있어 문의 드립니다. 위의 내용을 보면, service 없이 ingress 컨트롤러에서 POD 로 연결이 되었다고 말씀 하셨는데요... 위의 내용을 보면 node port 를 사용하여 POD로 연결한 것 같습니다. 제 생각에는 node port 역시 service 에서 type을 node port 로 지정하여 POD 와 연결한 것 아닌가요? 결론은 nodeport 역시 kind:service 로 생성해야만 하는 것이 아닌지 문의 드립니다.

      2019.09.24 20:31
      • 프로필사진

        Nodeport로 만든 서비스는 포드 정보를 확인하기 위해서만 사용해요. 실제 nginx에서 pod 까지는 직접 연결되는게 맞아요.

        2019.09.24 21:47 신고
    • 프로필사진

      빠른 답변 정말 감사 드립니다. 그렇다면 kind: Service ..... Type=Nodeport 라는 것은 단순히 POD 정보를 확인할 뿐 service 는 아니라는 말씀 이시죠? 아래의 예시처럼요...
      apiVersion: v1
      kind: Service
      metadata:
      name: nodeport-svc
      spec:
      selector:
      app: kss-tomcat
      type: NodePort
      ports:
      - port: 80
      targetPort: 8080
      nodePort: 30123

      2019.09.24 22:21
      • 프로필사진

        아..어제 폰으로 쓰느라 답변이 짧았던거 같네요. service는 맞아요.
        nginx는 그 service의 내용을 보게 되는데요. 이 때 해당 service의 endpoints 정보에 pod ip들이 있어요. 일반적으로 service를 사용하면 service의 ip를 바라보지만 nginx ingress같은 경우는 service의 ip가 아니라 service에 연결된 pod들 목록을 가져와서 그 pod들을 직접 바라보도록 설정이 되요.

        2019.09.25 09:21 신고
    • 프로필사진

      바쁘신데 자꾸 귀찮게 해드리는것 같네요...
      답변 감사합니다~^^
      그러면 맨 아래 그림이 인그레스컨트럴로 --> 포드 가 아니라 인그레스컨트롤러 --> 서비스 --> 포드 이렇게 되야 맞지 않을 까요?

      2019.09.26 09:18
      • 프로필사진

        서비스에 설정된 pod 정보를 이용하는거지 실제 트래픽은 서비스를 통하지 않고 바로 pod쪽으로 가기 때문에 그렇게 표현했어요.

        2019.09.27 16:26 신고
    • 프로필사진

      네 그렇군요... 알겠습니다. 답변해주셔서 정말 감사합니다. 업무에 참고하도록 하겠습니다.~^^

      2019.09.27 16:57
    • 프로필사진

      혹시 ingress에서 부하분산 알고리즘 중 least_conn은 이제 못쓰는건가요?

      2020.04.17 16:09
      • 프로필사진

        nginx에서 제공해 주는걸 사용하는 것이라서 least_conn 여전히 사용가능해요.

        2020.04.18 23:00 신고
      • 프로필사진

        exec 명령어를 치고 들어가면 upstream 이부분이 선생님 본문과 많이 다르더라구요. 더이상 지원하지않고 모듈을 설치하라는 주석도 있구요... 최신버전 한번 확인 부탁드릴 수 있을까요?

        2020.04.22 16:32
      • 프로필사진

        nginx 최신 버전은 설정하는 방법이 바껴서 그래요.
        저 설정 자체가 없어지진 않았어요.
        ingress-nginx에서 nginx 설정을 할 수 있어요.
        https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/configmap/#load-balance
        이 부분을 참고하시면 되요.

        2020.04.22 22:07 신고
Designed by Tistory.