[k8s] Nginx Ingress 사용해보기

Kaite.Kang·2024년 12월 29일

이제 nginx ingress를 직접 구성해보자. ingress에 대한 개념은 [k8s] Ingress의 개념과 트레픽 흐름 포스팅을 참고하기 바란다.

1. nginx ingress controller 설치하고 살펴보기

1-1. nginx ingress 트래픽 흐름

1-2. nginx ingress controller 설치하기

Ingress는 Ingress Controller를 통해서 실행된다. Ingress-Nginx Controller 를 먼저 설치해보자. Ingress-Nginx Controller는 k8s 버전 마다 지원되는 버전이 다르다. 2024년 12월 기준으로 ingress-nginx 버전별 k8s 지원 버전은 다음과 같다. 더 자세한 내용은 "[k8s] Ingress의 개념과 트레픽 흐름"포스팅을 참고하면 된다.

현재 테스트 서버의 k8s 버전은 1.31.1 이므로 ingress-nginx 1.12.0을 설치하겠다.

### k8s 버전 확인
# k get nodes
NAME     STATUS   ROLES           AGE   VERSION
kjh-m1   Ready    control-plane   24d   v1.31.1
kjh-m2   Ready    control-plane   24d   v1.31.1
kjh-m3   Ready    control-plane   24d   v1.31.1
kjh-w1   Ready    worker          23d   v1.31.1
kjh-w2   Ready    worker          23d   v1.31.1

### nginx-ingress controller 설치
# kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.12.0-beta.0/deploy/static/provider/baremetal/deploy.yaml

1-3. nginx ingress controller 리소스 살펴보기

전체 리소스

설치 결과 ingress-nginx 네임스페이스가 생성되었고, 그 안에 ingress-nginx 관련 리소스가 생성된 것을 확인할 수 있다.

# k get namespace ingress-nginx
NAME            STATUS   AGE
ingress-nginx   Active   7m39s

# k get all -n=ingress-nginx
root@kjh-m1:~# k get all -n=ingress-nginx
NAME                                            READY   STATUS      RESTARTS   AGE
pod/ingress-nginx-admission-create-2gltg        0/1     Completed   0          7m54s
pod/ingress-nginx-admission-patch-mvwgn         0/1     Completed   0          7m54s
pod/ingress-nginx-controller-8688dd9bfc-zzk66   1/1     Running     0          7m54s

NAME                                         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)                      AGE
service/ingress-nginx-controller             NodePort    10.233.19.196   <none>        80:32244/TCP,443:31810/TCP   8m1s
service/ingress-nginx-controller-admission   ClusterIP   10.233.58.193   <none>        443/TCP                      7m55s

NAME                                       READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/ingress-nginx-controller   1/1     1            1           7m56s

NAME                                                  DESIRED   CURRENT   READY   AGE
replicaset.apps/ingress-nginx-controller-8688dd9bfc   1         1         1       7m56s

NAME                                       STATUS     COMPLETIONS   DURATION   AGE
job.batch/ingress-nginx-admission-create   Complete   1/1           56s        7m56s
job.batch/ingress-nginx-admission-patch    Complete   1/1           57s        7m56s

ingress-nginx-controller pod는 어떻게 배포되나?

ingress-nginx-controller는 Deployment → ReplicaSet → Pod 순서로 배포 및 관리하고 있다.

# k describe deployment.apps/ingress-nginx-controller -n=ingress-nginx |tail -5
NewReplicaSet:   ingress-nginx-controller-8688dd9bfc (1/1 replicas created)
Events:
  Type    Reason             Age   From                   Message
  ----    ------             ----  ----                   -------
  Normal  ScalingReplicaSet  20m   deployment-controller  Scaled up replica set ingress-nginx-controller-8688dd9bfc to 1

# k describe replicasets.apps/ingress-nginx-controller-8688dd9bfc -n=ingress-nginx |tail -4
Events:
  Type    Reason            Age   From                   Message
  ----    ------            ----  ----                   -------
  Normal  SuccessfulCreate  21m   replicaset-controller  Created pod: ingress-nginx-controller-8688dd9bfc-zzk66

# k describe pod/ingress-nginx-controller-8688dd9bfc-zzk66 -n=ingress-nginx |tail -12
Events:
  Type     Reason       Age                From                      Message
  ----     ------       ----               ----                      -------
  Normal   Scheduled    22m                default-scheduler         Successfully assigned ingress-nginx/ingress-nginx-controller-8688dd9bfc-zzk66 to kjh-w1
  Warning  FailedMount  22m (x7 over 22m)  kubelet                   MountVolume.SetUp failed for volume "webhook-cert" : secret "ingress-nginx-admission" not found
  Normal   Pulling      21m                kubelet                   Pulling image "registry.k8s.io/ingress-nginx/controller:v1.12.0-beta.0@sha256:9724476b928967173d501040631b23ba07f47073999e80e34b120e8db5f234d5"
  Normal   Pulled       20m                kubelet                   Successfully pulled image "registry.k8s.io/ingress-nginx/controller:v1.12.0-beta.0@sha256:9724476b928967173d501040631b23ba07f47073999e80e34b120e8db5f234d5" in 38.739s (38.739s including waiting). Image size: 292505050 bytes.
  Normal   Created      20m                kubelet                   Created container controller
  Normal   Started      20m                kubelet                   Started container controller
  Normal   RELOAD       20m                nginx-ingress-controller  NGINX reload triggered due to a change in configuration
  Warning  Unhealthy    20m                kubelet                   Readiness probe failed: HTTP probe failed with statuscode: 500
  Warning  Unhealthy    20m                kubelet                   Liveness probe failed: HTTP probe failed with statuscode: 500

배포된 controller pod의 이미지를 확인해보면 1.12.0 버전이 배포된 것을 확인 할 수 있다.

# kubectl describe pod/ingress-nginx-controller-8688dd9bfc-zzk66  -n ingress-nginx  | grep "Image:"
    Image:           registry.k8s.io/ingress-nginx/controller:v1.12.0-beta.0@sha256:9724476b928967173d501040631b23ba07f47073999e80e34b120e8db5f234d5

ingress 서비스 확인하기

서비스는 Ingress 리소스를 통해 클러스터 외부로부터 들어오는 HTTP(S) 트래픽을 처리하기 한다. NodePort 타입으로 클러스터 외부에서 노드의 특정 포트(80:32244와 443:31810)로 접근 가능하도록 설정되었다.
참고로 ingress-nginx-controller-admission 서비스는 Ingress 리소스를 생성하거나 수정할 때 Validating Webhook(Ingress 리소스의 유효성을 검사하고 올바른 구성을 보장하는 역할)을 수행한다.

# k get service -n=ingress-nginx
NAME                                 TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)                      AGE
ingress-nginx-controller             NodePort    10.233.19.196   <none>        80:32244/TCP,443:31810/TCP   14m
ingress-nginx-controller-admission   ClusterIP   10.233.58.193   <none>        443/TCP                      14m

ingress class

ingress class는 ingress class는 하나의 클러스터에서 여러 인그레스 컨트롤러를 사용할 수 있도록 하기 위해 만들어진 API 리소스이다.
즉 실제 ingress는 하나의 인그레스 클래스와 연결된다. 그리고 그 인그레스 클래스가 사용하는 인그레스 컨트롤러를 통해서 규칙이 정해진다.
ingress class를 확인해보면 이름은 nginx이다. ingress 규칙을 생성할때 이 ingress class 이름을 명시한다. 그러면 ingress 규칙은 같은 ingress class를 가지고 있는 ingress controller와 연동된다.

root@kjh-m1:~/ingress-test# k get ingressclasses.networking.k8s.io
NAME    CONTROLLER             PARAMETERS   AGE
nginx   k8s.io/ingress-nginx   <none>       31m


root@kjh-m1:~/ingress-test# k get ingressclasses.networking.k8s.io -o yaml
apiVersion: v1
items:
- apiVersion: networking.k8s.io/v1
  kind: IngressClass
  metadata:
    annotations:
      kubectl.kubernetes.io/last-applied-configuration: |
        {"apiVersion":"networking.k8s.io/v1","kind":"IngressClass","metadata":{"annotations":{},"labels":{"app.kubernetes.io/component":"controller","app.kubernetes.io/instance":"ingress-nginx","app.kubernetes.io/name":"ingress-nginx","app.kubernetes.io/part-of":"ingress-nginx","app.kubernetes.io/version":"1.12.0-beta.0"},"name":"nginx"},"spec":{"controller":"k8s.io/ingress-nginx"}}
    creationTimestamp: "2024-12-29T06:10:39Z"
    generation: 1
    labels:
      app.kubernetes.io/component: controller
      app.kubernetes.io/instance: ingress-nginx
      app.kubernetes.io/name: ingress-nginx
      app.kubernetes.io/part-of: ingress-nginx
      app.kubernetes.io/version: 1.12.0-beta.0
    name: nginx
    resourceVersion: "4985915"
    uid: 6609e0c8-e332-4d57-bcb3-ac8a65a47930
  spec:
    controller: k8s.io/ingress-nginx
kind: List
metadata:
  resourceVersion: ""

# k get deployment.apps/ingress-nginx-controller -n=ingress-nginx -o yaml |grep -i ingress-class |tail -1
        - --ingress-class=nginx

2. 서비스 배포하기

ingress 테스트에 필요한 서비스 3개를 배포하자. 서비스의 yml 파일은 다음과 같다.

  • grafana
# cat ingress-test/grafana/deployment.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: grafana
  labels:
    app: "grafana"
spec:
  replicas: 1
  selector:
    matchLabels:
      app: "grafana"
  template:
    metadata:
      labels:
        app: "grafana"
    spec:
      containers:
      - name: grafana
        image: grafana/grafana:latest
        ports:
        - name: http
          containerPort: 3000
          
# cat ingress-test/grafana/service.yml
apiVersion: v1
kind: Service
metadata:
  name: grafana
  labels:
    app: "grafana"
spec:
  type: ClusterIP
  ports:
  - name: http
    protocol: TCP
    port: 80
    targetPort: 3000
  selector:
    app: "grafana"
  • httpd
# cat ingress-test/httpd/deployment.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: httpd
  labels:
    app: "httpd"
spec:
  replicas: 1
  selector:
    matchLabels:
      app: "httpd"
  template:
    metadata:
      labels:
        app: "httpd"
    spec:
      containers:
      - name: httpd
        image: httpd:latest
        ports:
        - name: http
          containerPort: 80

# cat ingress-test/httpd/service.yml
apiVersion: v1
kind: Service
metadata:
  name: httpd
  labels:
    app: "httpd"
spec:
  type: ClusterIP
  ports:
  - name: http
    protocol: TCP
    port: 80
    targetPort: 80
  selector:
    app: "httpd"
  • hello
# cat ingress-test/hello/deployment.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello
spec:
  replicas: 3
  selector:
    matchLabels:
      app: hello
  template:
    metadata:
      name: hello
      labels:
        app: hello
    spec:
      containers:
      - name: nginx
        image: nginxdemos/hello:plain-text
        ports:
        - name: http
          containerPort: 80
          protocol: TCP
          
# cat ingress-test/hello/service.yml
apiVersion: v1
kind: Service
metadata:
  name: hello
  labels:
    app: hello
spec:
  type: ClusterIP
  ports:
  - name: http
    protocol: TCP
    port: 8080
    targetPort: 80
  selector:
    app: hello

각 서비스를 배포해보자.

# cd ~/ingress-test

# k apply -f grafana/
deployment.apps/grafana created
service/grafana created

# k apply -f httpd/
deployment.apps/httpd created
service/httpd created

# k apply -f hello/
deployment.apps/hello created
service/hello created

3. 서비스와 ingress 연결시키기

ingress 규칙을 설정하는 방법은 여러 방법이 있는데 그 중에 path, host, defaultBackend를 이용한 구성 방법을 살펴보자.

3-1. path 이용하기

ingress 규칙은 다음과 같다.

# cat ingress-path.yml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: path
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx
  rules:
  - http:
      paths:
      - path: /hello
        pathType: Prefix
        backend:
          service:
            name: hello
            port:
              name: http
  - http:
      paths:
      - path: /grafana
        pathType: Prefix
        backend:
          service:
            name: grafana
            port:
              name: http

설정 파일은 다음과 같이 정의되어 있다.

  • ingress 이름은 path 이고, ingressClass는 nginx에 연결된다.
  • http.paths.path가 /hello일 경우, hello service에 http 포트로 보낸다.
  • http.paths.path가 /grafana일 경우, grafana service에 http 포트로 보낸다.

3-2. host 이용하기

3-3. defaultBackend 이용하기

참고 자료

[1] ingress-nginx conrotller 설치 가이드
https://kubernetes.github.io/ingress-nginx/deploy/#bare-metal-clusters
[2] ingress-nginx controller 버전별 호환 k8s 버전
https://github.com/kubernetes/ingress-nginx/blob/main/README.md#supported-versions-table
[3] ingress 테스트 예제
https://velog.io/@pinion7/Kubernetes-%EB%A6%AC%EC%86%8C%EC%8A%A4-Ingress%EC%97%90-%EB%8C%80%ED%95%B4-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B3%A0-%EC%8B%A4%EC%8A%B5%ED%95%B4%EB%B3%B4%EA%B8%B0

0개의 댓글