KANS 스터디 6주차 - Ingress - 1편

유형욱·2022년 2월 26일
1
post-thumbnail

🏡 실습환경 : K8S v1.22.6 , 노드 OS(Ubuntu 20.04.3) , CNI(Calico v3.21, Direct mode) , IPTABLES proxy mode

  • 컨테이너 런타임(CRI) : containerd
  • 실습 편의를 위해 ‘모든 VM’ 에 kubectl, calicoctl 설정을 추가

0. Ingress 요약

클러스터 내부를 외부에 노출 - 발전 단계

  1. 파드 생성 : K8S 클러스터 내부에서만 접속

  2. 서비스(Cluster Type) 연결 : K8S 클러스터 내부에서만 접속

  • 동일한 애플리케이션의 다수의 파드의 접속을 용이하게 하기 위한 서비스에 접속

  1. 서비스(NodePort Type) 연결 : 외부 클라이언트가 서비스를 통해서 클러스터 내부의 파드로 접속

📢 참고 : 서비스(NodePort Type)의 일부 단점을 보완한 서비스(LoadBalancer Type) 도 있습니다!

  1. 인그레스 컨트롤러 파드를 배치 : 서비스 앞단에 HTTP 고급 라우팅 등 기능 동작을 위한 배치
  • 서비스 앞단에 HTTP 고급 라우팅 등 기능 동작을 위한 배치

  1. 인그레스 컨트롤러 파드 이중화 구성 : Active(Leader) - Standby(Follower) 로 Active 파드 장애에 대비

  1. 인프레스 컨트롤러 파드를 외부에 노출 : 인그레스 컨트롤러 파드를 외부에서 접속하기 위해서 노출(expose)
  • 인그레스 컨트롤러 노출 시 서비스(NodePort Type) 보다는 좀 더 많은 기능을 제공하는 서비스(LoadBalancer Type)를 권장합니다 (80/443 포트 오픈 시)

7. 인그레스와 파드간 내부 연결의 효율화 방안 : 인그레스 컨트롤러 파드(Layer7 동작)에서 서비스 파드의 IP로 직접 연결

  • 인그레스 컨트롤러 파드는 K8S API서버로부터 서비스의 엔드포인트 정보(파드 IP)를 획득 후 바로 파드의 IP로 연결 - 링크
  • 지원되는 인그레스 컨트롤러 : Nginx, Traefix 등 현재 대부분의 인그레스 컨트롤러가 지원함

📢 참고 : 일반적으로 Ingress를 구성해서 사용한다면 이러한 형태!


1. 인그레스(Ingress) 소개

👋 인그레스 소개 : 클러스터 내부의 서비스(ClusterIP, NodePort, Loadbalancer)를 외부로 노출(HTTP/HTTPS) - Web Proxy 역할


출처 : https://kubernetes.io/ko/docs/concepts/services-networking/ingress/


2. Nginx 인그레스 컨트롤러 설치


출처 : https://k8s.networkop.co.uk/ingress/ingress/

인그레스(Ingress) : 클러스터 내부의 HTTP/HTTPS 서비스를 외부로 노출(expose) - 링크
인그레스 컨트롤러 : 인그레스의 실제 동작 구현은 인그레스 컨트롤러(Nginx, Kong 등)가 처리 - 링크

  • 쿠버네티스는 Ingress API 만 정의하고 실제 구현은 add-on 에 맡김
  • Nginx 인그레스 컨트롤러 - 링크 ⇒ 간편한 테스트를 위해서 NodePort 타입(externalTrafficPolicy: Local) 설정

  • 다양한 Nginx 인그레스 컨트롤러 인입 방법 : MetalLB 사용, Via the host network 사용, Using a self-provisioned edge 사용, External IPs 사용 - 링크

Nginx 인그레스 컨트롤러 생성

참고 : 인그레스 컨트롤러가 생성될 때 서비스 타입은 NodePort로 생성되며, 각종 SA, Role, RoleBinding 등이 생성된다.

# 모니터링
watch kubectl get all -n ingress-nginx

# nginx ingress controller v1.1.1 설치 (마스터 노드에 설치)
# https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.1.1/deploy/static/provider/cloud/deploy.yaml
kubectl apply -f https://raw.githubusercontent.com/gasida/KANS/main/6/nginx-ingress.yaml

# 네임스페이스 확인
kubectl get namespaces

# 관련된 정보 확인 : 포드(Nginx 서버), 서비스, 디플로이먼트, 리플리카셋, 잡, 컨피그맵, 롤, 클러스터롤, 서비스 어카운트 등
kubectl get all -n ingress-nginx
kubectl get pod -n ingress-nginx -o wide -l app.kubernetes.io/component=controller
kubectl get svc -n ingress-nginx ingress-nginx-controller
kubectl get pod,svc -n ingress-nginx -l app.kubernetes.io/component=controller

# ingress-nginx-controller NodePort(HTTP 접속용) 변수 지정
export IngHttp=$(kubectl get service -n ingress-nginx ingress-nginx-controller -o jsonpath='{.spec.ports[0].nodePort}')
echo $IngHttp
31080

# ingress-nginx-controller NodePort(HTTPS 접속용) 변수 지정
export IngHttps=$(kubectl get service -n ingress-nginx ingress-nginx-controller -o jsonpath='{.spec.ports[1].nodePort}')
echo $IngHttps
30836
  • (옵션) Helm 설치 - ArtifactHub => Helm Chart를 통해 설치하는 방법
cat <<EOT> ingress-values.yaml
controller:
  service:
    type: NodePort
EOT

helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update

helm install ingress-nginx ingress-nginx/ingress-nginx --version 4.0.17 -f ingress-values.yaml --create-namespace --namespace ingress-nginx

3. 인그레스(Ingress) 실습 및 통신 흐름 확인

실습 구성도

  • 마스터 노드에 인그레스 컨트롤러(Nginx) 파드를 생성, NodePort 로 외부에 노출
  • 인그레스 정책 설정 : Host/Path routing, 실습의 편리를 위해서 도메인 없이 IP로 접속 설정 가능

3.1 디플로이먼트와 서비스를 생성

  • 생성 및 확인
# 모니터링
watch -d 'kubectl get ingress,svc,ep;echo; calicoctl get wep'

# 생성
curl -s -O https://raw.githubusercontent.com/gasida/NDKS/main/7/svc1-pod.yaml
curl -s -O https://raw.githubusercontent.com/gasida/NDKS/main/7/svc2-pod.yaml
curl -s -O https://raw.githubusercontent.com/gasida/NDKS/main/7/svc3-pod.yaml
kubectl apply -f svc1-pod.yaml,svc2-pod.yaml,svc3-pod.yaml

# 확인 : svc1, svc3 은 ClusterIP 로 클러스터 외부에서는 접속할 수 없다 >> Ingress 는 연결 가능!
kubectl get pod,svc,ep

3.2 인그레스(정책) 생성 - 링크

  • ingress1.yaml
cat <<EOT> ingress1.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-1
  annotations:
    #nginx.ingress.kubernetes.io/upstream-hash-by: "true"
spec:
  ingressClassName: nginx
  rules:
  - http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: svc1-web
            port:
              number: 80
      - path: /guest
        pathType: Prefix
        backend:
          service:
            name: svc2-guest
            port:
              number: 8080
      - path: /admin
        pathType: Prefix
        backend:
          service:
            name: svc3-admin
            port:
              number: 8080
EOT
  • 인그레스 생성 및 확인
# 모니터링
watch -d 'kubectl get ingresses,svc,ep;echo; calicoctl get wep'

# 생성
kubectl apply -f ingress1.yaml

# 확인
kubectl get ingress
kubectl describe ingress ingress-1

3.3 인그레스를 통한 내부 접속

  • Nginx 인그레스 컨트롤러를 통한 접속(HTTP 인입) 경로 : 인그레스 컨트롤러 파드에서 서비스 파드의 IP로 직접 연결 (아래 오른쪽 그림)

💡 요약 : 앞서 확인했던 것 처럼 Ingress -> SVC -> Pod 순으로 접속하는 것이 아니라 SVC는 Bypass하고 바로 E.P인 Pod로 접속을 한다!

참고1 : URI(Uniform Resource Identifier, RFC3986)
참고2 : X-Forwarded-For 헤더, X-Forwarded-Proto 헤더

  • X-Forwarded-For 헤더는 송신지 IP 주소가 변환되는 환경(장비, 서버, 솔루션 등)에서, 변환 전 송신지(클라이언트) IP 주소를 저장하는 헤더입니다.
  • X-Forwarded-Proto 헤더는 변환 전 프로토콜을 저장합니다. (예. SSL Offload 환경에서 서버 측에서 클라이언트가 요청 시 사용한 원래 프로토콜을 확인)

💡 참고 : Client IP를 가져오는 방법!

  • 웹 애플리케이션이 client IP를 추출하기 위해서 Http request header를 다음과 같은 순서로 뒤짐
    1. Proxy-Client-IP : 특정 웹 어플리케이션에서 사용 (예. WebLogic Connector - mod_wl)
    2. WL-Proxy-Client-IP : 특정 웹 어플리케이션에서 사용 (예. WebLogic Connector - mod_wl)
    3. X-Forwarded-For : HTTP RFC 표준에는 없지만 사실상 표준!!!
    4. request.getRemoteAddr()
    5. CLIENT_IP
  • 3번 X-Forwarded-For: <client>, <proxy1>, <proxy2>
    요청이 여러 프록시를 거치는 경우 X-Forwarded-For 요청 헤더의 clientIPAddress 다음에는 로드 밸런서에 도달하기 전에 요청이 통과하는 각 연속 프록시의 IP주소가 온다.
    따라서, 가장 오른쪽의 IP 주소는 가장 최근의 프록시의 IP주소이고 가장 왼쪽의 IP 주소는 원래 클라이언트의 IP 주소이다.
  • 참고 링크 : 링크1 링크2
  • (참고) nginx ingress controller 기본 설정 : forwarded-for-header - 링크

💻 실습 : 인그레스(Nginx 인그레스 컨트롤러)를 통한 접속(HTTP 인입) 확인 : HTTP 부하분산 & PATH 기반 라우팅, 애플리케이션 파드에 연결된 서비스는 Bypass

# 인그레스 정책 확인
kubectl describe ingress ingress-1 | sed -n "5, \$p"
Rules:
  Host        Path   Backends
  ----        ----   --------
  *           /      svc1-web:80 ()
              /guest svc2-guest:8080 ()
              /admin svc3-admin:8080 ()
              

3.4 패킷 분석

  • 외부에서 접속(그림 왼쪽) 후 Nginx 파드(Layer7 동작)는 HTTP 헤더에 정보 추가(XFF)후 파드의 IP로 직접 전달

(옵션) 패킷 분석 >> 파드(veth) 패킷 캡쳐 후 merge 하였습니다 : Proxy(대리인) 존재감 확인!

  • 중간 빨간색 부분이 Nginx 파드의 IP(172.16.29.11)입니다 → 외부에서 Nginx 파드에 접속 후 Nginx 파드가 내부의 파드 IP로 직접 연결(옵션:부하분산)

💡 팁 : Wireshark Flow Graph 설정방법


3.5 (옵션) Nginx 분산 알고리즘 변경

💡 느낀점 요약 : 실제로 서비스를 하다보면 효율적인 운영을 위해 Session Affinity 등에 대해서 고민해야 하는 경우가 있다. 필요에 따라 IP-Hash, Session Cookie 기반으로 좀 더 효율적인 웹서비스를 운영할 수 있을 것 같다.
참고) 물론 Session Clustering 등이 되어있다면 상관 없겠지만, 그래도 새로운 세션을 맺는 것 보다는 기존 접속했던 서버로 접속하면 캐싱등 효과를 볼 수 있어 속도 면에서 장점이 있는 것 같다. (아닐수도)

nginx 는 기본 라운드 로빈 이지만, IP-Hash 나 Session Cookie 설정으로 대상 유지 가능 - 링크


3.6 (참고) AWS Ingress (ALB) 모드

💡 느낀점 요약 : EKS 환경에서 Ingress를 사용할 떄 마다 헷갈리는 부분이 많았는데, 이번 스터디를 통해서 많이 정리된 것 같다. 인스턴스 모드, IP 모드 등을 필요에 따라 잘 활용하고 NLB, ALB를 어떻게 사용해아 할지 등을 조만간 테스트를 하면서 정리해보면 좋을 것 같다.


3.7 Host 기반 라우팅

💡 느낀점 요약 : 최근 프로젝트에서 호스트 기반의 라우팅 설정을 통해서 Ingress를 활용했던 기억이 있어 쉽게 실습할 수 있었다.

  • ingress2.yaml
cat <<EOT> ingress2.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-2
spec:
  ingressClassName: nginx
  rules:
  - host: kans.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: svc3-admin
            port:
              number: 8080
  - host: "*.kans.com"
    http:
      paths:
      - path: /echo
        pathType: Prefix
        backend:
          service:
            name: svc3-admin
            port:
              number: 8080
EOT
  • 인그레스 생성 및 확인
# 터미널1 (PC)
watch -d 'kubectl get ingresses,svc,ep;echo; calicoctl get wep'

----------------------------------------------------------------

# 도메인 변경
MYDOMAIN1=hyungwook.com
sed -i "s/kans.com/$MYDOMAIN1/g" ingress2.yaml

# 생성
kubectl apply -f ingress2.yaml,svc3-pod.yaml

# 확인
kubectl get ingress
kubectl describe ingress ingress-2

kubectl describe ingress ingress-2 | sed -n "5, \$p"
Rules:
  Host        Path  Backends
  ----        ----  --------
  hyungwook.com    /     svc3-admin:8080 ()
  *.hyungwook.com  /echo svc3-admin:8080 ()
...
  • 인그레스(Nginx 인그레스 컨트롤러)를 통한 접속(HTTP 인입) 확인 : hosts 파일 수정

참고 : hosts 파일 등록 후 확인해야 할 부분!


3.8 카나리 업그레이드

💡 느낀점 요약 : 예전에 K8s 기반의 서비스를 운영할 때 카나리 업데이트를 고려했던적이 있다. 하지만 새 버전을 특정 사용자에게만 오픈하거나, 서비스가 정상적으로 동작한다는 보장을 하기가 쉽지가 않았던 기억이 있다.
당시에는 Ingress에 대한 사용방법이 익숙지 않아서 카나리 배포는 수작업으로 해야한다고 생각했었는데, 이번 스터디를 통해서 간단하게 annotations 설정만으로 되는 것을 보니 당시에 잘 알았더라면 하는 아쉬움이..😂

배포 자동화 지원(최소 중단, 무중단) - 롤링 업데이트, 카나리 업데이트, 블루/그린 업데이트 - 링크 링크2 하이커퍼넥스-블로그

  • 롤링 업데이트(Ramped)

    • 한 대씩 재시작
    • 롤백이 가능하다는 장점
  • 카나리 업데이트

    • 카나리아라는 새의 이름에서 유래(광산의 유독가스 사전대응)
    • capacity testing
  • 블루/그린 업데이트

    • 구 버전을 블루 신 버전을 그린
    • 자원이 두배로 필요


(출처) : https://martinfowler.com/bliki/BlueGreenDeployment.html

  • A/B 테스트

3.9 HTTPS 처리 (TLS 종료) - 링크

💡 느낀점 요약 : TLS 종료에 대해서 궁금한 점이 많았으나 알고보니 이미 사용하고 있는 방식이었다. 앞단에 Ingress에서 TLS 인증서를 타고 뒷단에 연결된 서비스는 평문(HTTTP)로 통신 하도록 하는 방법이다.
여기서 중요한 부분은 이미 개발된 소스코드가 HTTPS 베이스로 설정되어있다면 개발팀과 협업하여 HTTP로 변경하는 작업이 필요하다. 물론 리다이렉트 등 문제가 발생할 수 있기 때문에 약간(?)의 공수가 들어간다.


3.10 (옵션) HTTP → HTTPS Redirect 설정 - 링크

💡 느낀점 요약 : 실제로 HTTP로 접속하면 자동으로 HTTPS로 Redirect 해줘야 하는 경우가 굉장히 많다. 대부분의 유저(Client)들은 http/https 를 기입하지 않고 도메인만 입력하기 때문에 기본적으로 HTTP -> HTTTPS로 Redirect 해주는 설정은 필수적인 것 같다.

# nginx 서비스 편집 : 아래 내용 추가
kubectl edit svc -n ingress-nginx ingress-nginx-controller
---
  annotaion
    nginx.ingress.kubernetes.io/ssl-redirect: 'true'
---


4. Gateway API 소개

Gateway API 소개 : 기존의 Ingress 에 좀 더 기능을 추가

  • 서비스 메시(istio)에서 제공하는 Rich 한 기능 중 일부 기능들과 혹은 운영 관리에 필요한 기능들을 추가
  • 추가 기능 : 헤더 기반 라우팅, 헤더 변조, 트래픽 미러링(쉽게 트래픽 복제), 역할 기반

구성 요소 (Resource)

  • GatewayClass,Gateway, HTTPRoute, TCPRoute, Service

5. 과제!

🔥 목표 : 아래 지정된 조건을 만족하는 구성을 설정 후 각 조건을 확인 할 수 있는 스샷을 제출해주세요.

  1. Service(LoadBalancer) 사용을 위해서 MetalLB(ARP 모드)를 배포 할 것

  2. Nginx Ingress 컨트롤러 배포 시 Service(LoadBalancer) 타입을 사용 할 것

  3. Ingress 에 'Host 기반 라우팅' 설정을 하며, 각자 자신의 '닉네임'을 도메인으로 설정 할 것

  4. Ingress 접속 시 HTTPS 처리 (TLS 종료)를 설정 할 것

  5. Ingress 통신 관련 패킷을 캡쳐해서 스샷과 패킷을 제출할 것

    • Ingress 인입 패킷(HTTPS) 과 Pod 로 인입 시 패킷(HTTP,Host, XFF 필드값) 스샷
    # 패킷 캡처 명령어 참고
    tcpdump -i <nginx 파드 veth> -nnq tcp port 80 or tcp port 443 or tcp port 8080
    tcpdump -i <nginx 파드 veth> -nn  tcp port 80 or tcp port 443 or tcp port 8080 -w /tmp/ingress-tls.pcap

6. 과제 풀이

1. MetalLB 설치

  • YAML 배포 및 확인
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.11.0/manifests/namespace.yaml
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.11.0/manifests/metallb.yaml

# 확인
kubectl get pod -n metallb-system -o wide
NAME                          READY   STATUS    RESTARTS   AGE     IP               NODE     NOMINATED NODE   READINESS GATES
controller-7dcc8764f4-h7qks   1/1     Running   0          4m31s   172.16.184.0     k8s-w2   <none>           <none>
speaker-7588q                 1/1     Running   0          4m31s   192.168.10.101   k8s-w1   <none>           <none>
speaker-rgsnf                 1/1     Running   0          4m31s   192.168.10.102   k8s-w2   <none>           <none>
speaker-xn4l5                 1/1     Running   0          4m31s   192.168.10.10    k8s-m    <none>           <none>
  • CM 생성
# 컨피그맵 생성
cat <<EOF | kubectl create -f -
apiVersion: v1
kind: ConfigMap
metadata:
  namespace: metallb-system
  name: config
data:
  config: |
    address-pools:
    - name: default
      protocol: layer2
      addresses:
      - 192.168.10.200-192.168.10.210
EOF

# 컨피그맵 확인
kubectl get cm -n metallb-system
NAME               DATA   AGE
config             1      5m56s
kube-root-ca.crt   1      6m12s

2. Ingress Controller 배포(LoadBalancer 타입)

  • Helm을 활용한 Ingress Controller 배포 사전준비
cat <<EOT> ingress-values.yaml
controller:
  service:
    type: LoadBalancer
EOT

-------------------------------------------------------------------------

# repo 추가
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
"ingress-nginx" has been added to your repositories

# repo 업데이트
helm repo update
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "ingress-nginx" chart repository
Update Complete. ⎈Happy Helming!
  • Ingress Controller 배포
# ingress controller 차트 설치
helm install ingress-nginx ingress-nginx/ingress-nginx --version 4.0.17 -f ingress-values.yaml --create-namespace --namespace ingress-nginx
NAME: ingress-nginx
LAST DEPLOYED: Sat Feb 26 13:44:59 2022
NAMESPACE: ingress-nginx
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
The ingress-nginx controller has been installed.
It may take a few minutes for the LoadBalancer IP to be available.
You can watch the status by running 'kubectl --namespace ingress-nginx get services -o wide -w ingress-nginx-controller'

An example Ingress that makes use of the controller:
  apiVersion: networking.k8s.io/v1
  kind: Ingress
  metadata:
    name: example
    namespace: foo
  spec:
    ingressClassName: nginx
    rules:
      - host: www.example.com
        http:
          paths:
            - backend:
                service:
                  name: exampleService
                  port:
                    number: 80
              path: /
    # This section is only required if TLS is to be enabled for the Ingress
    tls:
      - hosts:
        - www.example.com
        secretName: example-tls
If TLS is enabled for the Ingress, a Secret containing the certificate and key must also be provided:
  apiVersion: v1
  kind: Secret
  metadata:
    name: example-tls
    namespace: foo
  data:
    tls.crt: <base64 encoded cert>
    tls.key: <base64 encoded key>
  type: kubernetes.io/tls
  • LoadBalancer 타입으로 생성 확인!

3. Ingress 에 'Host 기반 라우팅' 설정을 하며, 각자 자신의 '닉네임'을 도메인으로 설정

  • 샘플 SVC 및 Deployments 배포!
# 💻 모니터링
watch -d 'kubectl get ingress,svc,ep;echo; calicoctl get wep'

kubectl get ingress,svc,ep;echo; calicoctl get wep;
NAME                 TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
service/kubernetes   ClusterIP   10.96.0.1       <none>        443/TCP          56m
service/svc1-web     ClusterIP   10.107.116.67   <none>        9001/TCP         38s
service/svc2-guest   NodePort    10.107.55.37    <none>        9002:30641/TCP   38s
service/svc3-admin   ClusterIP   10.106.29.95    <none>        9003/TCP         38s

NAME                   ENDPOINTS                             AGE
endpoints/kubernetes   192.168.10.10:6443                    56m
endpoints/svc1-web     <none>                                38s
endpoints/svc2-guest   172.16.158.2:8080,172.16.184.3:8080   38s
endpoints/svc3-admin   172.16.158.3:8080,172.16.158.4:8080   38s

WORKLOAD                            NODE     NETWORKS          INTERFACE
deploy1-websrv-596b6fb7db-b6r7w     k8s-w2   172.16.184.2/32   cali6a3b33c8af9
deploy2-guestsrv-864dffb7fc-ps9dl   k8s-w1   172.16.158.2/32   calib5db9669938
deploy2-guestsrv-864dffb7fc-qvn9b   k8s-w2   172.16.184.3/32   cali1eaad245288
deploy3-adminsrv-f9f957b4b-ck9hx    k8s-w2   172.16.184.4/32   calia9a5ae60a51
deploy3-adminsrv-f9f957b4b-gh8xw    k8s-w1   172.16.158.3/32   calia32338ba993

-----------------------------------------------------------------------------

# 생성
curl -s -O https://raw.githubusercontent.com/gasida/NDKS/main/7/svc1-pod.yaml
curl -s -O https://raw.githubusercontent.com/gasida/NDKS/main/7/svc2-pod.yaml
curl -s -O https://raw.githubusercontent.com/gasida/NDKS/main/7/svc3-pod.yaml
kubectl apply -f svc1-pod.yaml,svc2-pod.yaml,svc3-pod.yaml
  • Host 기반 Ingress YAML 작성
cat <<EOT> ingress2.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-2
spec:
  ingressClassName: nginx
  rules:
  - host: hyungwook.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: svc3-admin
            port:
              number: 8080
  - host: "*.hyungwook.com"
    http:
      paths:
      - path: /echo
        pathType: Prefix
        backend:
          service:
            name: svc3-admin
            port:
              number: 8080
EOT
  • Ingress 배포 및 확인
# 배포
k apply -f ingress2.yaml
ingress.networking.k8s.io/ingress-2 created

# 확인
k get ingress
NAME        CLASS   HOSTS                           ADDRESS          PORTS   AGE
ingress-2   nginx   hyungwook.com,*.hyungwook.com   192.168.10.200   80      64s

💡 참고 : ADDRESS에 LoadBalancer로 생성된 External IP가 할당 된 것을 확인할 수 있다.

k get svc -n ingress-nginx | grep Load
ingress-nginx-controller             LoadBalancer   10.109.208.100   192.168.10.200   80:32475/TCP,443:30137/TCP   12m
  • hosts 파일 등록

  • 브라우저 접속 확인 : 80

  • 브라우저 접속 확인 : 443

🔥 이유 : Backend 서비스에 TLS 인증서를 적용한 서비스가 없으므로 400 Bad Request 발생

4. Ingress 접속 시 HTTPS 처리 (TLS 종료)를 설정 할 것

  • svc, pod YAML 작성
apiVersion: v1
kind: Pod
metadata:
  name: pod-https
  labels:
    app: https
spec:
  containers:
  - name: container
    image: k8s.gcr.io/echoserver:1.6
  terminationGracePeriodSeconds: 0
---
apiVersion: v1
kind: Service
metadata:
  name: svc-https
spec:
  selector:
    app: https
  ports:
  - port: 8080
  • svc, pod 배포
k apply -f svc-pod.yaml
pod/pod-https created
service/svc-https created
(🥕 |Ingress-k8s:default) root@k8s-m:~# k get pods,svc
NAME            READY   STATUS              RESTARTS   AGE
pod/pod-https   0/1     ContainerCreating   0          5s

NAME                 TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
service/kubernetes   ClusterIP   10.96.0.1        <none>        443/TCP    24s
service/svc-https    ClusterIP   10.106.252.223   <none>        8080/TCP   5s
  • ssl-termination-ingress.yaml 작성
cat <<EOT> ssl-termination-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: https
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - hyungwook.com
    secretName: secret-https
  rules:
  - host: hyungwook.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: svc-https
            port:
              number: 8080
EOT
  • SSL Termination Ingress 배포
k apply -f ssl-termination-ingress.yaml
ingress.networking.k8s.io/https created

k get ingress
NAME    CLASS   HOSTS      ADDRESS          PORTS     AGE
https   nginx   kans.com   192.168.10.200   80, 443   15s
  • TLS 인증서 생성
# 변수 선언
(🥕 |Ingress-k8s:default) root@k8s-m:~# MYDOMAIN1=hyungwook.com
(🥕 |Ingress-k8s:default) root@k8s-m:~# echo $MYDOMAIN1
hyungwook.com

# TLS 인증서 생성
(🥕 |Ingress-k8s:default) root@k8s-m:~# mkdir key && cd key
enssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=$MYDOMAIN1/O=$MYDOMAIN1"
tree(🥕 |Ingress-k8s:default) root@k8s-m:~/key# openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=$MYDOMAIN1/O=$MYDOMAIN1"
Generating a RSA private key
.....+++++
.................................+++++
writing new private key to 'tls.key'
-----
  • TLS Secrets 생성 및 확인
(🥕 |Ingress-k8s:default) root@k8s-m:~/key# kubectl create secret tls secret-https --key tls.key --cert tls.crt
secret/secret-https created
(🥕 |Ingress-k8s:default) root@k8s-m:~/key# kubectl get secrets secret-https -o yaml
apiVersion: v1
data:
  tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURRVENDQWltZ0F3SUJBZ0lVR0FRRUFiaEF6bnU2NnAvcFZwYnByYVZ6b2FFd0RRWUpLb1pJaHZjTkFRRUwKQlFBd01ERVdNQlFHQTFVRUF3d05hSGwxYm1kM2IyOXJMbU52YlRFV01CUUdBMVVFQ2d3TmFIbDFibWQzYjI5cgpMbU52YlRBZUZ3MHlNakF5TWpZeE5EVXdNVFZhRncweU16QXlNall4TkRVd01UVmFNREF4RmpBVUJnTlZCQU1NCkRXaDVkVzVuZDI5dmF5NWpiMjB4RmpBVUJnTlZCQW9NRFdoNWRXNW5kMjl2YXk1amIyMHdnZ0VpTUEwR0NTcUcKU0liM0RRRUJBUVVBQTRJQkR3QXdnZ0VLQW9JQkFRQ3FuK3IrS29tNlFSSytJMTZ2ZSt5QjVXalNZNzNPcE9oNwpRYml3VVZSbTRCdzlkYmJoNkp5OEJhdTVZdzhVanc2S1A2TmUvdGJnL2ZSQzlqek15Ly95ejhwdGhOVlFQTFluClRpTjVaemh2NXk1ZHhOeVJPd0JBb1lROFR6NWpCNkVtTEFvdXRWeFk4REFXWUNnc29EOEdUWHh1NWV0Ym9lVE0KZzVpbThZYVA5cnJLTDgxNTVZNjZlaGNURG1VcWJic3NiZFpmaS84RWZOcC9hdGM1amRwMDF1OUNqV2dyWm9IbwpMSFVobDRaWk16dk1vQ3N5cTZKSU5rUitTY3VPRzNkcDEzVEpKazVwc2JsaSs2c09RZDN4QVMyZGZlcmJxTWhLCjBTNWNtMnJUNVdwOVE0VjBKS051cmZKc2xUNlJzb1EwR09IMnlMTklLQlhSNDVuSjh0V1RBZ01CQUFHalV6QlIKTUIwR0ExVWREZ1FXQkJSN0VFR0p3SU9iRFBzWmFyZVA5cUZJaWYwWVdqQWZCZ05WSFNNRUdEQVdnQlI3RUVHSgp3SU9iRFBzWmFyZVA5cUZJaWYwWVdqQVBCZ05WSFJNQkFmOEVCVEFEQVFIL01BMEdDU3FHU0liM0RRRUJDd1VBCkE0SUJBUUJJK01vN1F5Zjd0NW1CSzV6VXd4aTBjSzJSbDdVcGtCZFg0VzFoMkdPUFVTTURzN1lwN2p4MlIzM3kKbVZSVmpKMzZ3R0M4UDhMQmFvWlZBakp4eW91S3QwV3MzY29nN2JiZmx2YlZLaGJoellScFV0cUxnZjdJOGJvRApycEoxTVQyUXBXM0Y3VUhTK1hQRDZiNE52cW1udEJkbjVSQ1dPcVAyU0s0MkVLUGNKczAxUW83MEJxK01LNEx1CkoxNjhCQVZ5bnRUbXMvY0VpdTE2aHhJQ0Yyc2lBL1prRXVhb0llMWhuTVprMU44dUVMdVdVbWxuV0tlbTQ1aTIKMTZLZ0xnM1R3U3IyVDFNTjBoYkUxUXVOdFlUK1lGZDNpZzVFWFE3akVVRFFockw5TTVrVVdZRFg2YXhpaUFMRgpPeTF0MVRwWHhyTi9QOXk1ZW80a1dzUlpLdVEwCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
  tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2Z0lCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktnd2dnU2tBZ0VBQW9JQkFRQ3FuK3IrS29tNlFSSysKSTE2dmUreUI1V2pTWTczT3BPaDdRYml3VVZSbTRCdzlkYmJoNkp5OEJhdTVZdzhVanc2S1A2TmUvdGJnL2ZSQwo5anpNeS8veXo4cHRoTlZRUExZblRpTjVaemh2NXk1ZHhOeVJPd0JBb1lROFR6NWpCNkVtTEFvdXRWeFk4REFXCllDZ3NvRDhHVFh4dTVldGJvZVRNZzVpbThZYVA5cnJLTDgxNTVZNjZlaGNURG1VcWJic3NiZFpmaS84RWZOcC8KYXRjNWpkcDAxdTlDaldnclpvSG9MSFVobDRaWk16dk1vQ3N5cTZKSU5rUitTY3VPRzNkcDEzVEpKazVwc2JsaQorNnNPUWQzeEFTMmRmZXJicU1oSzBTNWNtMnJUNVdwOVE0VjBKS051cmZKc2xUNlJzb1EwR09IMnlMTklLQlhSCjQ1bko4dFdUQWdNQkFBRUNnZ0VBVkx4VXRPTWxRUlYrSEdWdWFaSU9zN2ZkcGRhWTlkNGFBdFJ4eDBhc3R1YUgKdjlJTkFBWklpR3Y4aTNYeGtGRTNkRnNFWkhJRS92bS82OTFqOW9VOVdEWHZueEkvNmJnczhqb3hEZUxBT1hyRApJUmhhUGRuaVZ6YWZlR0FXYUpIcWF3Mm1CT3BXc1dpZlNRMTZCaWVUQlN0SUo3OFJjcEZsRWxnc1lJUkVRb3dDCjhxVE04K3JaWnNGeWZ2SFZqRUFiR1hhQmdjMWVGL0Y5eXU4a3lXTmlEcmswMW1teGdUUHRuS3FDZDVPdFNqZFEKcGFWZ2ZhV2JMbXp2Rnl1VFp3clhkeCtVMzR5WmpFRFIyRys2U203dkUwcERyTVM3OUk2VUQ4L1RwT3VaUnlGcApDbVVJZEVReG9XTEJrRGtSaUgvRUdpN1RqYkxjcjBnTXNLOXczWkhta1FLQmdRRGMxakhFY2hUTUpGdHoyVk95CnlJTHlUcFMrOFloWjliMml0QUZrMXJlb2ZWYks5QlpkSzd6a28yalM4L25vd3diQkxyYU9RcVpkdTE4OGV1QUwKQzVVb2twNlBUT0hKQW41T0N2MFZ3c2RHS1pJaVNOYkFXUEx4cGl2bkNuYWhiMUFiZG1wVXgvY0xlM3FTbitVVQo2TEpKWlNVdHZJc3UvWXdscGdsQjBnamhxd0tCZ1FERnl2ZTA2U1F5QVVmMkVmdHBJVVhkYkRPcDNqdWw5YTdGCjdmYzd2Mis4SytnWXF5SDZTd2JlcG5ZUi9uLzZyeUJaODVkKzRoVUNFZjZ6ZVQzYmxBWUlXWlhpQ2c1aHUrancKalhuR2lpNW5OeU02Z0FjODcvRmVMK1Bxam54OGFqZW8vcExCWFdaSUNBNmNiV2hrT3YyeE9ZSFNJTkRKekZSdwp5SEJ3QTJoRHVRS0JnUUNwV2hGY1J1Z3dEUW1jOCtLOXpncXRheG1pdkhNR0dlL05ZQ0ZaaFZmZWZCQWRIOFl1CnVTWG9hSEF3cGl6V0ZRbVBDQld6VHVWcUtCREd2cXdsakVKY2xPUEhuUHZoUEdwRHl5VitsSnBnOGV4QkluNmQKanhqdnU3RWJRdWpxc0FSTXF5aXJ6NVZpVnRVT3NGUHJEdS82WFBoLzlJRUFEaXgxaXJpNm95bHdkUUtCZ1FDVApnYUdvQm5MYTQvK3hzSWxwUnNvZXJuSDlEZUk0QzNneTNod1NMOXQ1WHRreGhIYkxmYVo2NTNPSVNkOVJxY2NiCnJrRmQrK2NrNnh5aTVobE9weDYwblhMYzV4a0FwQzI5TUJVUURyODZkSEZPVUdxVmRHL3lDUThWUHZ2eG9Sa3YKYStNd1Y2Sk90OHVGdDBZeDhaaCswZDlTUU96VWdoQzdKNUJLeVErNTZRS0JnRWgxK0RiRjUyaTNRTUd1ZTBDegpKcWx6blZBeExJSy9lbGE0UE53RElYSG5KcytQeWFOVThpS1FCZWw3WGQ0YzFOSkdVTHpZMjJ2SW54eEVXR0RzCm9BSC9sT3NxQkVHa1FKYndMTzJkOVc3WjErNWg2VTdrazNWK3Q1N1Buem9UakR3MmlOT3JyUDFyTWtoK3kyUG0KUGVPdDB0QnBoUXprWXIyN1hLc1pnK1R0Ci0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0K
kind: Secret
metadata:
  creationTimestamp: "2022-02-26T14:51:18Z"
  name: secret-https
  namespace: default
  resourceVersion: "11353"
  uid: f602f7da-39ec-43a2-9a87-1e6adc6e9a74
type: kubernetes.io/tls
  • 접속 테스트1 : https://hyungwook.com 접속

🔥 참고 : 앞선 실습에서는 LoadBalancer 서비스의 externalTrafficPolicy: Cluster로 설정해두어 Client IP가 NAT되어 접속되었었다. 해당 실습에서는 정확한 확인을 위해 ingress-controller의 LoadBalancer 설정을 externalTrafficPolicy: Local로 변경 후 테스트 하였다.

  • 접속 테스트2 : curl 명령 활용

5. Ingress 통신 관련 패킷을 캡쳐해서 스샷과 패킷을 제출할 것

  • veth 확인 후 TCP 덤프
root@k8s-w1:~# calicoctl get workloadEndpoint -A
NAMESPACE        WORKLOAD                                    NODE     NETWORKS          INTERFACE
default          pod-https                                   k8s-w1   172.16.158.5/32   cali2c3a5c32196
ingress-nginx    ingress-nginx-controller-6dc9476ccf-tjkdn   k8s-w1   172.16.158.1/32   caliaa086680352
kube-system      calico-kube-controllers-76c5bc74-tnj6d      k8s-m    172.16.116.2/32   calib1d4d423d30
kube-system      coredns-78fcd69978-g95nz                    k8s-m    172.16.116.0/32   calieb66cab8292
kube-system      coredns-78fcd69978-km7q4                    k8s-m    172.16.116.1/32   cali1c5fd0ecc3b
metallb-system   controller-7dcc8764f4-h7qks                 k8s-w2   172.16.184.0/32   calib62b86ed085

![](https://velog.velcdn.com/images%2Fhyungwook%2Fpost%2Fc9685101-135f-40e9-9495-53c25826c5bb%2Fimage.png)
  • Wireshark 분석!

💡 요약 : Client -> Ingress로 들어갈 통신할 때는 TLS 통신을 통해 암호화 되어있고 Ingress - Pod로 통신할 땐 평문으로 통신되는 것을 확인할 수 있었다!

profile
DevOps를 꿈꾸는 엔지니어 입니다.

0개의 댓글