주녁, DevNote
article thumbnail

개요

On-premise에서 kubernetes(= k8s) 환경을 직접 구성해보며 학습하는 Hands On 시리즈입니다. 

목표

Ingress 적용을 통해 Service가 어떤 방식으로 트래픽을 전달하는지 이해한다.


여정

Service와 Service Type

Service에서 통신을 위해 사용하는 Type은 아래와 같이 3가지가 있다.

 

NodePort

  • 외부에서 접속하기 위해 사용하는 포트

port

  • Cluster 내부에서 사용할 Service 객체의 포트

targetPort

  • Service객체로 전달된 요청을 Pod(deployment)로 전달할때 사용하는 포트

전체 서비스 흐름으로 보면 NodePort --> Port --> targetPort 이다.


Ingress란?

Ingress는 클러스터 내의 서비스에 대한 외부 접근을 관리하는 API 오브젝트이다.

일반적으로 HTTP를 관리하는데, 인그레스는 부하 분산, SSL 종료, DNS를 기반으로 호스팅을 제공할 수 있다.

즉, 아래 그림과 같이 같은 주소, 같은 포트로 요청이 들어와도, 라우팅 규칙에 따라 트래픽을 다르게 전달할 수 있다.

출처 : 공식문서 이미지

또한, 특이한 점은 오버헤드를 방지하기 위해 아래 그림과 같이

Service를 거치지 않고 IP주소만 참조해서 트래픽을 ByPass로 Pod에게 전달한다.

CloudNet@ Blog

Ingress는 아래 두가지 요소로 구성되어 작동한다.

Ingress Resource : 트래픽을 전달할 규칙을 정의(어플리케이션의 서비스와 경로를 매칭)

Ingress Controller : 규칙에 따라 로드 밸런싱과 트래픽 처리(Nginx와 같은 여러 종류의 구현체가 있음)


Ingress Controller 설치

설치를 진행한 Ingress 버전은 1.5.1이며, 자세한 내용은 공식문서를 참조하자.
# ingress nginx 컨트롤러 생성
# 방법1 : helm으로 설치 (권장)
helm repo add nginx-stable https://helm.nginx.com/stable
helm repo update
helm install nginx-stable nginx-stable/nginx-ingress

# 방법2 : 원격저장소에서 내려받기
wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.5.1/deploy/static/provider/cloud/deploy.yaml
mv deploy.yaml ingress-mandatory.yaml
kubectl apply -f ingress-mandatory.yaml

# 외부트래픽 전략 변경
# Local(default) : 외부 트래픽을 로컬 Node에 있는 Pod로만 전달
# Cluster : 외부 트래픽을 전체 Pod에 분산
kubectl edit svc ${nginx 서비스명} -n ${네임스페이스}
...
spec:
  externalTrafficPolicy: Cluster # Local에서 변경

# 설치 확인
kubectl get pods -n ingress-nginx
kubectl get service/ingress-nginx-controller -n ingress-nginx
kubectl get ingressclass
kubectl get ingressclass nginx -o yaml # 파일로 출력

Ingress Resource 생성

Resource 작성 시 아래 사항을 준수해야 한다.

  • 연결하려는 Service와 동일한 네임스페이스(metadata → namespace)
  • 연결하려는 Service와 Name과 Port가 동일해야 함(spec → rules → backend → service)
kubernetes.io/ingress.class 어노테이션은 deprecate 되었다.
metedata의 annotation은 다양한 종류를 지원하니 공식문서를 한번씩 읽어보자
# 예시
# my-app-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
    name: my-app-ingress
    namespace: my-app-cloud # 대상 Deployment와 반드시 동일하게 작성
    annotations:
				# kubernetes.io/ingress.class: nginx → deprecated

				# rule에 일치하는 경우 redirect
				# rewrite.bar.com/something/new → rewrite.bar.com/new
        nginx.ingress.kubernetes.io/rewrite-target: "/$2" 

spec:
	ingressClassName: nginx
	  defaultBackend: # 이 부분은 path를 설정하지 않은 요청을 처리한다
	    service:
	      name: knowledge-manage-external
	      port:
	        number: 17405
  rules:
    - host: "training.myapp-test.kr" # 도메인으로 구분하는 경우1
      http:
        paths:
          - path: "/"
            pathType: Prefix
            backend:
              service: # 대상 Service와 반드시 동일하게 작성
                name: intent-recommender-training-external
                port:
                  number: 17409

    - host: "myapp-test.kr" # 도메인으로 구분하는 경우2
      http:
        paths:
          - path: "/memory(/|$)(.*)" 	# 하위 주소로 구분하는 경우1
            pathType: Prefix
            backend:
              service: # 대상 Service와 반드시 동일하게 작성
                name: dialog-memory-external
                port:
                  number: 17402

          - path: "/disk(/|$)(.*)"  	# 하위 주소로 구분하는 경우2
            pathType: Prefix
            backend:
              service: # 대상 Service와 반드시 동일하게 작성
                name: dialog-memory-external
                port:
                  number: 17403
# 마스터 노드에서
# path에 작성한 DNS 내용 추가
vi /etc/hosts

211.39.xx.xx   my-app-test.com
...

# 접속하려는 클라이언트 컴퓨터에도 동일하게 적용해야 한다.
# 윈도우의 경우
# C:\Windows\System32\drivers\etc에서
# hosts를 관리자 권한으로 편집


# Ingress Resource 적용
kubectl apply -f my-app-ingress.yaml

# 확인
kubectl describe ingress -n my-app-cloud

# 성공인 경우 내부 IP 주소를 확인할 수 있음
# (실패인 경우 endpoint 에러가 발생할 수 있음)

 

HTTPS 접속을 위한 SSL 설정(Optional)

SSL 생성 순서는 아래와 같다.
개인키 생성 → 공개키 생성 → 인증 서명 요청서(CSR) 생성 → 자체 인증 기관(CA)을 통한 인증서(CRT) 발급
# SSL 파일 생성 방법1 (심플)
openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=${DNS 이름}"

---

# SSL 파일 생성 방법2 (정석)
mkdir certs 
cd certs

# 개인키 생성
openssl genrsa -aes256 -out private.secure.key 2048
# Enter pass phrase for private.key: 패스워드 입력

# 암호를 사용하지 않는 암호키 생성
# (실행시마다 암호 입력을 해야하므로)
openssl rsa -in private.secure.key -out private.key
# Enter pass phrase for private.key: 패스워드 입력

# 암호키 보안 조치(권한 회수)
chmod 600 private.key

# CSR 생성
openssl req -new -key private.key -out cert.csr
... # CSR에 담을 정보 입력
# Common Name (eg, YOUR name) []: ${여기에 DNS 이름 반드시 입력}

# CRT 생성 (10년 간 유지)
openssl x509 -req -sha256 -days 3650 -signkey private.key -in cert.csr -out ${DNS 이름 권장}.crt

# 토큰 확인
# CN 항목에 설정한 주소가 잘 입력되었는지 확인한다.
openssl x509 -text -in ${토큰 파일}
# Secret 생성
kubectl create secret tls my-secret --key ${암호키 파일이름}.key --cert ${인증서 파일이름}.crt -n my-app-cloud

# 기존 설정 변경
kubectl edit Ingress ${인그레스 이름} -n my-app-cloud

---
kind: Ingress
...
spec:
  tls:
  - hosts:
    - ${DNS 이름}
    secretName: my-secret

# Ingress Controller의 HTTPS 포트 확인
# (보통 443 포트와 매칭되어 있다)
kubectl get svc ...

# 확인
curl https://${DNS 주소}:${HTTPS Port}

Q & A

  • Ingress 삭제 후 재생성 시 에러가 발생합니다. : Internal error occurred: failed calling webhook
더보기

# 인증과 관련된 ingress 설정을 제거

kubectl delete validatingwebhookconfiguration ingress-nginx-admission

  • Ingress 사용 시, 외부 클라이언트의 IP는 어떻게 확인할 수 있나요?
더보기

파드는 외부 클라이언트의 IP 획득을 위해서 X-Forwarded-For(XFF)를 참조해야함.

> curl -s <IP>:<Port>/url | egrep '(client_address | x-forwarded-for)'

*client_address : Ingress Controller의 IP

*x-forwarded-for : 클라이언트의 IP

  • Ingress의 Load Balacing 정책을 Round-Robin 방식에서 변경하고 싶습니다
더보기

찾아본 결과 가능한 로드밸런싱 설정은 2가지 정도 있다.


바로 Ingress 어노테이션에서 변경할 수 있는데, 아래와 같다.
1. nginx.ingress.kubernetes.io/load-balance : "Round-Robin" or "ewma"

2. nginx.ingress.kubernetes.io/weight : 0~100 (%)

모두 Session과 Cookie으로 Sticky한 접속 유지 but, 둘 다 사용하지 않는 API 서버일때는 불가능해보임.


마무리

이번 시간에는 ingress를 통해 외부에서 요청을 받아

클러스터 내부까지 안전하게 전달하는 과정을 학습했다.

 

이를 활용하면 3편 대시보드 설치 에서 proxy로 접속했던 것을

DNS로 접속할 수 있게된다.

 

이것으로 기초 및 필수 개념을 전반적으로 한번씩 다루어보았다.

따라서, 쿠버네티스 비긴즈 시리즈를 마무리하고

다음 시간에는 조금 더 발전된 Infra 관련 포스트를 다뤄보도록 하겠다.


참고자료

[번역] 쿠버네티스에서의 Port, TargetPort, NodePort :: Ibiza (kimmj.github.io)

162. [Kubernetes] 1편 : 쿠버.. : 네이버블로그 (naver.com)

쿠버네티스에서 반드시 알아야 할 서비스(Service) 유형 (seongjin.me)

[데브옵스를 위한 쿠버네티스 마스터] 프라이빗 클라우드를 위한 인그레스 Ingress-Nginx 구현하기 (tistory.com)

[kubernetes] nodeport, port, targetport 정리 : 네이버 블로그 (naver.com)

쿠버네티스 Ingress 개념 및 적용방법 (tistory.com)

Rewrite - NGINX Ingress Controller (kubernetes.github.io)

Nginx Ingress Controller Annotations - Rewirte - 호롤리한 하루 (gruuuuu.github.io)

163. [Kubernetes] 2편 : 쿠버네티스 Ingress의 ClusterIP Bypass, Annotation, SSL/TLS를 위한 인증서 적용 : 네이버 블로그 (naver.com)

OpenSSL 로 SSL/TLS 용 인증서 요청 및 발급받기 (lesstif.com)

[OpenSSL] SSL/TLS 인증서 발급받기 (tistory.com)

[OpenSSL] SSL/TLS 통신을 위한 인증서 발급받기 (gptjs409.github.io)

Annotations - NGINX Ingress Controller (kubernetes.github.io)

TLS termination - NGINX Ingress Controller (kubernetes.github.io)

Prerequisites - NGINX Ingress Controller (kubernetes.github.io)

CloudNet@ Blog (notion.so)

 

 

profile

주녁, DevNote

@junwork

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!