25/10/30 쿠버네티스 오케스트레이션 4

344th·2025년 12월 11일

AWS AI

목록 보기
38/48

서비스

쿠버네티스 클러스터: 아파트 단지

아파트 단지 안에는 여러 방(파드) 존재
방은 얼마든지 생성되고 사라질 수 있고 이사(스케줄링)도 함

→ 클라이언트 입장에서는 방의 IP 주소가 계속 바뀜

그래서 등장하게 된 것이 서비스

  • 서비스: 택배함 주소

서비스는 고정된 IP를 받음

택배함으로 요청을 보내면 쿠버네티스가 살아있는 파드 중 하나에게 연결

서비스의 종류

  • ClusterIP
  • NodePort
  • LoadBalancer

ClusterIP

ClusterIP 실습

**$ kubectl get service**
NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.233.0.1   <none>        443/TCP   2d16h

**$ kubectl get endpoints**
NAME         ENDPOINTS            AGE
kubernetes   192.168.56.11:6443   2d16h

서비스가 있다면 그에 상응하는 엔드포인트도 존재(Name 동일)

엔드포인트의 IP 주소: api 서버로 접근할 수 있는 주소

실습 전 디렉터리 정리

vagrant@kube-control1:~/k8s$ mkdir ex04
vagrant@kube-control1:~/k8s$ cd ex04

서비스 생성

$ vim myapp-svc.yml
apiVersion: v1
kind: Service
metadata:
  name: myapp-svc
spec:
  ports:
  - port: 80
    targetPort: 8080
  selector:
    app: myapp-rs
**$ kubectl apply -f myapp-svc.yml**
service/myapp-svc created

생성한 서비스 확인

**$ kubectl get service myapp-svc**
NAME        TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
myapp-svc   ClusterIP   10.233.27.50   <none>        80/TCP    45s

서비스와 함께 생성됐을 엔드포인트도 확인

**$ kubectl get endpoints myapp-svc**
NAME        ENDPOINTS   AGE
myapp-svc   <none>      2m24s

이름 동일

서비스에 연결할 파드 생성(엔드포인트 연결)

# 기존에 썼던 파일 현재 작업 디렉터리로 가져옴
$ cp ../ex03/myapp-rc.yml .

$ vim myapp-rc.yml
apiVersion: apps/v1
kind: ReplicaSet
metadata:
  **name: myapp-rs**
spec:
  # 복제본 개수 지정
  replicas: 5
  selector:
    matchLabels:
      **app: myapp-rs**
  template:
    metadata:
      # 다수의 파드들의 레이블
      labels:
        **app: myapp-rs**
    spec:
      containers:
      - name: myapp
        image: ghcr.io/c1t1d0s7/go-myweb:alpine
        ports:
        - containerPort: 8080

서비스 셀렉터에 적었던 레이블(app: myapp-rs)와 동일하게 수정

# 파일 이름 수정
**$ mv myapp-rc.yml myapp-rs.yml**

# 구동
**$ kubectl apply -f myapp-rs.yml**
replicaset.apps/myapp-rs created

# 엔드포인트 다시 확인
**$ kubectl get endpoints myapp-svc**
NAME        ENDPOINTS                                                             AGE
myapp-svc   10.233.118.91:8080,10.233.118.92:8080,10.233.73.94:8080 + 2 more...   8m40s

엔드포인트 생긴거 확인 가능

→ 레플리카셋으로 생성한 파드들의 IP

파드들의 IP 주소 확인

**$ kubectl get pods -o wide**
NAME             ... IP              NODE         NOMINATED NODE   READINESS GATES
myapp-rs-4b55g   ... 10.233.74.28    kube-node2   <none>           <none>
myapp-rs-gjph2   ... 10.233.118.92   kube-node3   <none>           <none>
myapp-rs-rpz4j   ... 10.233.73.94    kube-node1   <none>           <none>
myapp-rs-s7vwj   ... 10.233.74.29    kube-node2   <none>           <none>
myapp-rs-wb84r   ... 10.233.118.91   kube-node3   <none>           <none>

네트워크 통신 확인

**$ kubectl run nettool -it --image=ghcr.io/c1t1d0s7/network-multitool --rm bash
nettool:/#** 

쉘 접속 종료시 컨테이너도 종료되도록 --rm 옵션

Cluset-IP 로 요청 보내서 파드 id 확인

nettool:/# curl http://10.233.27.50
Hello World!
myapp-rs-s7vwj
nettool:/# curl http://10.233.27.50
Hello World!
myapp-rs-4b55g
nettool:/# curl http://10.233.27.50
Hello World!
myapp-rs-gjph2
nettool:/# curl http://10.233.27.50
Hello World!
myapp-rs-wb84r
nettool:/# curl http://10.233.27.50
Hello World!
myapp-rs-rpz4j

고정된 Cluster-IP 로 보내면 파드들에게 각각 자동으로 로드밸런싱되는 걸 확인 가능

멀티포트 서비스 설정

$ cp myapp-svc.yml myapp-svc-multiport.yml
$ vim myapp-svc-multiport.yml
apiVersion: v1
kind: Service
metadata:
  name: myapp-svc
spec:
  **ports:
    - name: http
      port: 80
      targetPort: 8080
    - name: https
      port: 443
      targetPort: 8443**
  selector:
    app: myapp-rs

다중 포트 지정 시 이름을 명시해야 함

멀티포트 서비스 구동

**$ kubectl apply -f myapp-svc-multiport.yml**
service/myapp-svc created

생성된 서비스 및 엔드포인트 확인

**$ kubectl get service myapp-svc**
NAME        TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
myapp-svc   ClusterIP   10.233.50.186   <none>        80/TCP,443/TCP   49s

**$ kubectl get endpoints myapp-svc**
NAME        ENDPOINTS                                                             AGE
myapp-svc   10.233.118.91:8443,10.233.118.92:8443,10.233.73.94:8443 + 7 more...   98s

레플리카셋 및 파드 확인

**$ kubectl get rs**
NAME       DESIRED   CURRENT   READY   AGE
myapp-rs   5         5         5       28m

**$ kubectl get pods**
NAME             READY   STATUS    RESTARTS   AGE
myapp-rs-4b55g   1/1     Running   0          28m
myapp-rs-gjph2   1/1     Running   0          28m
myapp-rs-rpz4j   1/1     Running   0          28m
myapp-rs-s7vwj   1/1     Running   0          28m
myapp-rs-wb84r   1/1     Running   0          28m

쿠버네티스 클러스터는 파드를 생성할 때 파드 내부의 환경변수에 서비스의 내용을 명시함

nettool이 어떻게 clusterIp를 찾아갈 수 있었을까?

쿠버네티스 파드에서는 다른 서비스를 찾는 방법은 2가지

1. 환경 변수

2. DNS

환경 변수 확인

$ kubectl run nettool -it --image=ghcr.io/c1t1d0s7/network-multitool --rm bash
nettool:/# env
KUBERNETES_SERVICE_HOST=10.233.0.1

DNS로 확인하기

**$ kubectl get all -n kube-system -l k8s-app=kube-dns**
NAME              TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)                  AGE
service/coredns   ClusterIP   10.233.0.3   <none>        53/UDP,53/TCP,9153/TCP   2d17h

DNS 정보 파일

: /etc/resolve.conf

파드에서 DNS 정보 확인

**$ kubectl run nettool -it --image=ghcr.io/c1t1d0s7/network-multitool --rm bash
nettool:/# cat /etc/resolv.conf**
search default.svc.cluster.local svc.cluster.local cluster.local
nameserver 169.254.25.10
options ndots:5
  • 쿠버네티스 DNS
    구성 요소타입위치역할
    CoreDNSDeploymentkube-system 네임스페이스 (예: kube-control1, kube-node3 등 일부 노드에만)클러스터 전체의 중앙 DNS 서버
    NodeLocal DNS Cache (nodelocaldns)DaemonSet모든 노드에 1개씩 (4/4 표시된 이유)각 노드에서 로컬 DNS 캐시 역할
    Pod의 /etc/resolv.conf설정 파일모든 Pod 내부DNS 질의가 갈 “nameserver” 를 169.254.25.10(노드 로컬 주소)로 지정

    Pod 안에서 DNS 요청 실행

    예를 들어 Pod 내부에서 아래 명령을 실행
    curl http://myapp-svc.default.svc.cluster.local
    ┌──────────────────────────────┐
    │ ① Pod 내부 (/etc/resolv.conf)│
    │ nameserver 169.254.25.10     │
    └──────────────┬───────────────┘
                   │
                   ▼
    ┌──────────────────────────────┐
    │ ② NodeLocal DNS Cache        │
    │ (DaemonSet, 127.0.0.1:53 ↔ 169.254.25.10)│
    │   - 각 노드에 1개씩 존재               │
    │   - 최근 질의 캐싱                    │
    │   - CoreDNS로 요청 전달 (miss 시)     │
    └──────────────┬───────────────┘
                   │
                   ▼
    ┌──────────────────────────────┐
    │ ③ CoreDNS (kube-system)      │
    │   - 중앙 DNS 서버 (Service: 10.96.0.10) │
    │   - Service/Pod 이름 → IP 변환          │
    │   - 외부 도메인은 upstream forward     │
    └──────────────┬───────────────┘
                   │
                   ▼
    ┌──────────────────────────────┐
    │ ④ 외부 DNS (예: 8.8.8.8)     │
    │   - CoreDNS가 포워딩         │
    └──────────────────────────────┘
    

    CoreDNS는 쿠버네티스가 기본으로 설치하는 시스템 구성요소 중 하나이며,
    “Deployment 형태로 동작하는 일반 Pod 세트”

    즉, CoreDNS도 다른 앱처럼 Pod로 실행됨 → 다만 사용자가 만든 앱이 아니라 쿠버네티스 시스템에서 만들고 관리하는 앱일 뿐

로컬 DNS 캐시 확인

**$ kubectl get daemonsets.apps -n kube-system -l k8s-app=kube-dns -o wide**
NAME           DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR            AGE     CONTAINERS   IMAGES                                           SELECTOR
nodelocaldns   4         4         4       4            4           kubernetes.io/os=linux   2d17h   node-cache   registry.k8s.io/dns/k8s-dns-node-cache:1.22.28   k8s-app=node-local-dns

**$ kubectl get pods -n kube-system -l k8s-app=kube-dns -o wide**
NAME                     READY   STATUS    RESTARTS   AGE     IP              NODE            NOMINATED NODE   READINESS GATES
coredns-d665d669-4d59s   1/1     Running   0          2d17h   10.233.118.66   kube-node3      <none>           <none>
coredns-d665d669-9w6ls   1/1     Running   0          2d17h   10.233.70.1     kube-control1   <none>           <none>

coreDNS는 특정 노드에서만 구동

**$ kubectl get pods -n kube-system -l k8s-app=kube-dns -o wide**
NAME                     READY   STATUS    RESTARTS   AGE     IP              NODE            NOMINATED NODE   READINESS GATES
coredns-d665d669-4d59s   1/1     Running   0          2d17h   10.233.118.66   kube-node3      <none>           <none>
coredns-d665d669-9w6ls   1/1     Running   0          2d17h   10.233.70.1     kube-control1   <none>           <none>

특정 clusterIP를 사용하는 서비스로 접근할 수 있는 방식

  1. 서비스의 ip주소로 접근

    # curl 10.233.63.185
    Hello World!
    myapp-rc-multiport-5ptlg
  2. <서비스 이름>.<네임스페이스>.<리소스 종류>.<클러스터 도메인>

    **nettool:/# curl myapp-svc-multiport**
    Hello World!
    myapp-rc-multiport-8pbkv
    **nettool:/# curl myapp-svc-multiport.default**
    Hello World!
    myapp-rc-multiport-vttct
    **nettool:/# curl myapp-svc-multiport.default.svc**
    Hello World!
    myapp-rc-multiport-747kw
    **nettool:/# curl myapp-svc-multiport.default.svc.cluster.local**
    Hello World!
    myapp-rc-multiport-p2w7f
  • 트러블슈팅 문제
    $ kubectl run nettool -it --image=ghcr.io/c1t1d0s7/network-multitool --rm bash
    무한로딩, 접속 안됨 원인 파악
    **vagrant@kube-control1:~$ kubectl get pods -o wide**
    NAME             READY   STATUS              RESTARTS   AGE   IP              NODE         NOMINATED NODE   READINESS GATES
    myapp-rs-2gphq   1/1     Running             0          31m   10.233.74.31    kube-node2   <none>           <none>
    myapp-rs-96pd8   1/1     Running             0          31m   10.233.73.101   kube-node1   <none>           <none>
    myapp-rs-kvn8r   1/1     Running             0          31m   10.233.118.93   kube-node3   <none>           <none>
    myapp-rs-plfv4   1/1     Running             0          31m   10.233.74.30    kube-node2   <none>           <none>
    myapp-rs-wz6ss   1/1     Running             0          31m   10.233.118.94   kube-node3   <none>           <none>
    nettool          0/1     ContainerCreating   0          41s   <none>          kube-node1   <none>           <none>
    
    **vagrant@kube-control1:~$ kubectl describe pod nettool**
    ...
    Events:
      Type     Reason                  Age                 From               Message
      ----     ------                  ----                ----               -------
      Normal   Scheduled               58s                 default-scheduler  Successfully assigned default/nettool to kube-node1
      Warning  FailedCreatePodSandBox  57s                 kubelet            Failed to create pod sandbox: rpc error: code = Unknown desc = failed to setup network for sandbox "f70b7825d0a16c329c9b57aa86acc9025629ba505c2bb5efbfeb83ca6c6c9501": plugin type="calico" failed (add): error getting ClusterInformation: connection is unauthorized: Unauthorized
      Warning  FailedCreatePodSandBox  57s                 kubelet            Failed to create pod sandbox: rpc error: code = Unknown desc = failed to setup network for sandbox "88662ddfd4c50c01be8eadf80eb10bc6df35fb2d17d3cb06288406d74fa703b9": plugin type="calico" failed (add): error getting ClusterInformation: connection is unauthorized: Unauthorized
      Warning  FailedCreatePodSandBox  56s                 kubelet            Failed to create pod sandbox: rpc error: code = Unknown desc = failed to setup network for sandbox "c98ab3359a8ef8148a7ab64aee0d35d95c9afebc417f6a9690914713601baf8f": plugin type="calico" failed (add): error getting ClusterInformation: connection is unauthorized: Unauthorized
      Warning  FailedCreatePodSandBox  55s                 kubelet            Failed to create pod sandbox: rpc error: code = Unknown desc = failed to setup network for sandbox "d20ea232588faa5e962a19cab85b0a7503fece341aab8ba680b398f4db70a5b7": plugin type="calico" failed (add): error getting ClusterInformation: connection is unauthorized: Unauthorized
      Warning  FailedCreatePodSandBox  54s                 kubelet            Failed to create pod sandbox: rpc error: code = Unknown desc = failed to setup network for sandbox "4526f8fbc1e468d33d05a406e68ee5b26f27de70534bf77c7d36e9b754602f58": plugin type="calico" failed (add): error getting ClusterInformation: connection is unauthorized: Unauthorized
      Warning  FailedCreatePodSandBox  53s                 kubelet            Failed to create pod sandbox: rpc error: code = Unknown desc = failed to setup network for sandbox "2ba82edb88df172f6ca35d03a4e0f881f4d3b6e9f9f4f5c770793a90fb519d27": plugin type="calico" failed (add): error getting ClusterInformation: connection is unauthorized: Unauthorized
      Warning  FailedCreatePodSandBox  52s                 kubelet            Failed to create pod sandbox: rpc error: code = Unknown desc = failed to setup network for sandbox "a676777c157d183e059f3a841b878ece14ab5549dbe15a16d7f14ca26926ed1f": plugin type="calico" failed (add): error getting ClusterInformation: connection is unauthorized: Unauthorized
      Warning  FailedCreatePodSandBox  51s                 kubelet            Failed to create pod sandbox: rpc error: code = Unknown desc = failed to setup network for sandbox "335b7990e2536334ec86d87e4e93f974e4c939992d58911dcb88eca4fb713ace": plugin type="calico" failed (add): error getting ClusterInformation: connection is unauthorized: Unauthorized
      Warning  FailedCreatePodSandBox  50s                 kubelet            Failed to create pod sandbox: rpc error: code = Unknown desc = failed to setup network for sandbox "6deb2c78cbf72fa0a3be03d952a362517a4ab95149496b9af996e31a8db3e152": plugin type="calico" failed (add): error getting ClusterInformation: connection is unauthorized: Unauthorized
      Normal   SandboxChanged          46s (x12 over 57s)  kubelet            Pod sandbox changed, it will be killed and re-created.
      Warning  FailedCreatePodSandBox  46s (x4 over 49s)   kubelet            (combined from similar events): Failed to create pod sandbox: rpc error: code = Unknown desc = failed to setup network for sandbox "7cfde278ce139b3c85ab5ee1f578c0c760f00c7f7d7e2acd1a09bfc670cda0ab": plugin type="calico" failed (add): error getting ClusterInformation: connection is unauthorized: Unauthorized
    
    핵심 에러: Failed to create pod sandbox: rpc error: code = Unknown desc = failed to setup network for sandbox "f70b7825d0a16c329c9b57aa86acc9025629ba505c2bb5efbfeb83ca6c6c9501": plugin type="calico" failed (add): error getting ClusterInformation: connection is unauthorized: Unauthorized 해결
    **$ kubectl -n kube-system rollout restart ds/calico-node**
    daemonset.apps/calico-node restarted
    
    **$ kubectl -n kube-system rollout restart deploy/calico-kube-controllers**
    deployment.apps/calico-kube-controllers restarted

클러스터의 외부 서비스

  • ClusterIP: 내부 서비스
  • NodePort
    • 쿠버네티스 모든 노드에 외부 접근용 포트를 할당
    • 노드의 포트를 이용하여 외부에서 접근 가능
    • 노드의 특정 포트로 요청하면 파드로 리다이렉션하는 구조
    • 파드가 할당되지 않은 노드에도 포트가 할당됨
  • LoadBalancer : ClusterIP + NodePort + LoadBalancer : ClusterIP + NodePort + 공인 IP
    • 클러스터 외부의 로드밸런서를 사용하여 외부에서 접근 가능
  • ExternalName : 외부에서 접근하기 위한 용도 X : CNAME(별칭)과 FQDN을 매핑시키는 용도
  • 서비스 정리

    서비스

    Service는 쿠버네티스에서 Pod의 네트워크 접근을 안정적으로 제공하는 추상화 객체

    : 클라이언트와 파드의 연결을 담당
    • Pod는 언제든 새로 생성되거나 삭제될 수 있어 IP가 계속 바뀜

      → 이때 Service가 “고정된 IP와 DNS 이름”을 제공해서, 외부나 내부에서 안정적으로 Pod에 접근할 수 있게 해줌

      서비스 타입(유형)

      **$ kubectl get service**
      NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
      kubernetes   ClusterIP   10.233.0.1   <none>        443/TCP   46h
    • ClusterIP

      : 기본 서비스 타입 (생략 시 자동 적용)

      : 클러스터 내부에서만 파드에 접근될 수 있도록 함

      → 내부 파드들끼리 통신

      : 외부에서는 접근 불가

    • NodePort

      : 외부 접근이 필요한 경우 ClusterIP 위에 노출되는 상위 타입

      : 각 노드의 특정 포트를 통해 외부 접근을 제공하는 유형

      → NAT 를 사용하는 클러스터 내에서 각 노드들의 지정된 포트를 외부에 노출시켜줌

      • 파드들의 차이: 포트 번호

      • <NodeIP>:<NodePort>

        로 클러스터 외부에서 서비스에 접근할 수 있도록 함

      • 내부적으로는 여전히 ClusterIP로 라우팅됨.

        모든 노드가 동일한 포트 개방

    • LoadBalancer

      : ClusterIP + NodePort + 공인 IP

      : 외부 공인 IP가 할당되어 외부 사용자가 직접 접속 가능

      : 외부용 LoadBalancer를 생성하고 서비스에 고정된 공인 IP를 할당

      → IP 및 포트 번호를 활용해 클러스터 외부에서 서비스에 접근 가능

      : 내부적으로는 NodePort/ClusterIP로 연결됨

    • ExternalName

      LoadBalancer
         └── NodePort
               └── ClusterIP
    • ClusterIP: 내부 트래픽 라우팅 (Pod 간)

    • NodePort: ClusterIP + 노드 포트 개방 (외부 진입점 추가)

    • LoadBalancer: NodePort + 클라우드 퍼블릭 IP 부여 (외부 트래픽 자동 분산)

      즉, LoadBalancer → NodePort → ClusterIP 순서로 포워딩

      [외부 클라이언트]
       → LoadBalancer(공인 IP)
         → NodePort(노드 포트)
           → ClusterIP(가상 서비스 IP)
             → Pod(컨테이너)

      보통 로드밸런서를 사용함

      → 로드밸런서는 결국 공인 IP+NodePort+ClusterIP

      문제점

      그러나, 기본적으로 파드는
      파드 종료 후 재시작되면 IP 주소가 재할당됨

      → ClusterIP 는 파드 IP 를 가지고 로드밸런싱하므로 재할당되면 연결이 끊어짐

      → 무중단 서비스 제공 불가

      해결 방법

      Headless Service
      : ClusterIP가 없는(Service Type: ClusterIP, clusterIP: None) 서비스

      즉,

      중간 로드밸런싱 계층(ClusterIP)을 제거하고,

      DNS 이름을 통해 직접 Pod IP 목록을 반환

NodePort 실습

**$ cp myapp-rs.yml myapp-rs-nodeport.yml

$ kubectl apply -f myapp-rs-nodeport.yml**
replicaset.apps/myapp-rs created

노드포트 서비스 yml 파일 작성

$ vim myapp-svc-np.yml
apiVersion: v1
kind: Service
metadata:
  name: myapp-svc-np
spec:
  type: NodePort
  ports:
    - port: 80
      targetPort: 8080
      nodePort: 31111
  selector:
    app: myapp-rs 

type 을 따로 명시(ClusterIP는 기본값이라 지정 안한 것)

nodePort 는 꼭 지정하지 않아도 됨 → 30000-32767 범위에서 랜덤 지정

노드포트 서비스 구동

**$ kubectl apply -f myapp-svc-np.yml**
service/myapp-svc-np created

# 확인
**$ kubectl get service myapp-svc-np**
NAME           TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
myapp-svc-np   NodePort   10.233.47.158   <none>        80:31111/TCP   12s

확인

$ curl 192.168.56.21:31111
Hello World!
myapp-rs-47nvm

$ curl 192.168.56.22:31111
Hello World!
myapp-rs-v7t4l

$ curl 192.168.56.23:31111
Hello World!
myapp-rs-v7t4l

로드밸런서 실습

: AWS 제공하는 ELB를 사용하여 로컬의 서비스와 연결이 가능하도록 만드는 기능

  • 로컬에서 로드밸런서를 사용하려면 metallb를 사용하여 가상의 IP 주소를 부여 받음
$ cp myapp-svc-np.yml myapp-svc-lb.yml
$ vim myapp-svc-lb.yml
apiVersion: v1
kind: Service
metadata:
  name: myapp-svc-lb
spec:
  type: LoadBalancer
  ports:
    - port: 80
      targetPort: 8080
  selector:
    app: myapp-rs

로드밸런서 서비스 구동 및 확인

**$ kubectl apply -f myapp-svc-lb.yml**
service/myapp-svc-lb created

**$ kubectl get service myapp-svc-lb**
NAME           TYPE           CLUSTER-IP      EXTERNAL-IP      PORT(S)        AGE
myapp-svc-lb   LoadBalancer   10.233.47.178   192.168.56.201   80:30629/TCP   9s

**$ kubectl get endpoints**
NAME           ENDPOINTS                                                 AGE
kubernetes     192.168.56.11:6443                                        2d19h
myapp-svc-lb   10.233.118.96:8080,10.233.73.103:8080,10.233.74.32:8080   14s
myapp-svc-np   10.233.118.96:8080,10.233.73.103:8080,10.233.74.32:8080   85m

통신 확인

**$ curl 192.168.56.201**
Hello World!
myapp-rs-c2b48

인그레스

: 클러스터 외부에서 내부에 존재하는 쿠버네티스 서비스에 접근하기 위해 HTTP/HTTPS를 활용한 라우팅 규칙을 제공하는 오브젝트

외부 노출 서비스가 많을 경우 노드포트 사용 시 노드의 각 서비스별 포트를 개방해야 함

→ 인그레스가 HTTP/HTTPS 요청 주소를 구분해 각 서비스에 라우팅 가능

  • LoadBalancer 및 NodePort → OSI 7계층 중 4계층에서 동작(TCP/UDP)
  • 인그레스는 7계층에서 동작(application)

인그레스를 사용하려면 인그레스 컨트롤러 필요

nginx 인그레스 컨트롤러가 가장 대중적으로 사용하는 컨트롤러

nginx ingress controller 확인

**$ kubectl get pod -n ingress-nginx -o wide**
NAME                             READY   STATUS    RESTARTS   AGE     IP              NODE         NOMINATED NODE   READINESS GATES
ingress-nginx-controller-7m9bb   1/1     Running   0          2d20h   10.233.73.65    kube-node1   <none>           <none>
ingress-nginx-controller-vpqql   1/1     Running   0          2d20h   10.233.74.2     kube-node2   <none>           <none>
ingress-nginx-controller-zxpr4   1/1     Running   0          2d20h   10.233.118.65   kube-node3   <none>           <none>

인그레스는 서비스와 같이 동작하기 때문에 노드별로 배치될 서비스에 라우팅해주기 위해 각 노드별로 하나씩 nginx 인그레스 컨트롤러가 존재함

  • .spec.service.name: 라우팅할 기본 백엔드 서비스 이름, 규칙에 매칭되지 않는 트래픽은 기본 백엔드로 전송됨
  • .spec.defaultBackend.service.port.number: 라우팅할 기본 백엔드 서비스의 포트
  • .spec.rules.host: URL 호스트
  • .spec.rules.http.paths.path: URL의 경로
  • .spec.rules.http:paths.pathType: URL의 경로 유형
    • Exact: 대소문자를 엄격하게 일치시킴
    • Prefix: 접두사를 /를 기준으로 일치시킴
  • .spec.rules.http.paths.path.backend: 라우팅할 서비스 밴엔드
  • .spec.rules.http.paths.path.backend.service.name: 라우팅할 서비스 이름
  • .spec.rules.http.paths.path.backend.service.port.number: 서비스 포트
$ vim myapp-ing.yml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: myapp-ing
spec:
  defaultBackend:
    service:
      name: myapp-svc-np
      port:
        number: 80
  rules:
    - host: myapp.example.com
      http:
        paths:
          - path: /
            pathType: Exact
            backend:
              service:
                name: myapp-svc-np
                port:
                  number: 80
**$ kubectl get ingresses.networking.k8s.io**
NAME        CLASS    HOSTS               ADDRESS                                     PORTS   AGE
myapp-ing   <none>   myapp.example.com   192.168.56.21,192.168.56.22,192.168.56.23   80      45s
**$ curl --resolve myapp.example.com:80:192.168.56.21 myapp.example.com**
Hello World!
myapp-rs-47nvm

현재 외부 DNS가 없기 때문에 myapp.example.com FQDN의 A 레코드를 반환하지 못함

curl --resolve 옵션을 사용하여 일시적으로 FQDN의 주소를 ip주소로 매핑

다중 경로 인그레스 설정

http://apps.example.com/web1

http://apps.example.com/web2

**$ vim myapp-ing-multi-paths.yml**
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: myapp-ing
spec:
  defaultBackend:
    service:
      name: myapp-svc-np
      port:
        number: 80
  rules:
    - host: myapp.example.com
      http:
        paths:
          - path: /web1
            pathType: Exact
            backend:
              service:
                name: myapp-svc-ext-np1
                port:
                  number: 80
          - path: /web2
            pathType: Exact
            backend:
              service:
                name: myapp-svc-ext-np2
                port:
                  number: 80
$ kubectl describe ingresses.networking.k8s.io myapp-ing
Rules:
  Host               Path  Backends
  ----               ----  --------
  myapp.example.com
                     /web1   myapp-svc-ext-np1:80 (<error: services "myapp-svc-ext-np1" not found>)
                     /web2   myapp-svc-ext-np2:80 (<error: services "myapp-svc-ext-np2" not found>)

다중 호스트 인그레스 설정

http://web1.example.com

http://web2.example.com

$ vim myapp-ing-multi-hosts.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: myapp-ing
spec:
  defaultBackend:
    service:
      name: myapp-svc-np
      port:
        number: 80
  rules:
    - host: web1.example.com
      http:
        paths:
          - path: /
            pathType: Exact
            backend:
              service:
                name: myapp-svc-ext-np1
                port:
                  number: 80
    - host: web2.example.com
      http:
        paths:
          - path: /
            pathType: Exact
            backend:
              service:
                name: myapp-svc-ext-np2
                port:
                  number: 80
**$ kubectl describe ingresses.networking.k8s.io myapp-ing**
Rules:
  Host              Path  Backends
  ----              ----  --------
  web1.example.com
                    /   myapp-svc-ext-np1:80 (<error: services "myapp-svc-ext-np1" not found>)
  web2.example.com
                    /   myapp-svc-ext-np2:80 (<error: services "myapp-svc-ext-np2" not found>)

볼륨

컨테이너 생성되면 볼륨 같이 생성

일반적으로 컨테이너를 제거하면 생성된 볼륨도 같이 제거

영구 설정을 하면 볼륨 영구적으로 사용 가능

임시 볼륨

  • 로컬 볼륨: emptyDir
  • configMap, secret

영구 볼륨

  • 로컬 볼륨: hostPath, local
  • DB

emptyDir

: 공유 디렉토리

파드는 생성과 동시에 볼륨이 생성되지만 임시로 사용할 볼륨이어도 내부 디렉토리로 공유하자는 취지

  • .spec.volumes: 볼륨 정의
  • .spec.volumes.name: 볼륨의 이름
  • .spec.volumes.<TYPE>: 볼륨의 종류
  • .spec.volumes.emptyDir: emptyDir 타입의 볼륨 정의
    • {}: 값을 비워두면 호스트의 로컬 디스크를 사용
    • { Memory }: tmpfs(RAM 기반 파일시스템)을 사용해 고성능의 볼륨을 제공
  • .spec.volumes.name: 볼륨의 이름
  • .spec.containers.volumeMounts: 컨테이너 마운트 할 볼륨을 선언
  • .spec.containers.volumeMounts.name: 사용할 볼륨 이름
    • .spec.volumes.name 필드의 이름 참조
  • .spec.containers.volumeMounts.mountPath: 컨테이너 내의 마운트 포인트
$ vim myapp-rs-emptydir.yml
apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: myapp-rs-fortune
spec:
  # 복제본 개수 지정
  replicas: 1
  selector:
    matchLabels:
      app: myapp-rs-fortune
  template:
    metadata:
      # 다수의 파드들의 레이블
      labels:
        app: myapp-rs-fortune
    spec:
      containers:
        - name: web-server
          image: nginx:alpine
          volumeMounts:
            - name: web-fortune
              mountPath: /usr/share/nginx/html
              readOnly: true
          ports:
            - containerPort: 80
        - name: html-generator
          image: ghcr.io/c1t1d0s7/fortune
          volumeMounts:
            - name: web-fortune
              mountPath: /var/htdocs
      volumes:
        - name: web-fortune
          emptyDir: {}
$ vim myapp-svc-emptydir.yml
apiVersion: v1
kind: Service
metadata:
  name: myapp-svc-emptydir
spec:
  type: LoadBalancer
  ports:
    - port: 80
      targetPort: 80
  selector:
    app: myapp-rs-fortune

컨테이너 접속해서 내부 파일 확인

**$ kubectl exec myapp-rs-fortune-2875c -c web-server -- cat /usr/share/nginx/html/index.html**
Dear Miss Manners:
        My home economics teacher says that one must never place one's
elbows on the table.  However, I have read that one elbow, in between
courses, is all right.  Which is correct?

Gentle Reader:
        For the purpose of answering examinations in your home
economics class, your teacher is correct.  Catching on to this
principle of education may be of even greater importance to you now
than learning correct current table manners, vital as Miss Manners
believes that is.

**$ kubectl exec myapp-rs-fortune-2875c -c html-generator -- cat /var/htdocs/index.html**
Bug, n.:
        An aspect of a computer program which exists because the
programmer was thinking about Jumbo Jacks or stock options when s/he
wrote the program.

Fortunately, the second-to-last bug has just been fixed.
                -- Ray Simard
**$ curl http://192.168.56.201**
A New York City judge ruled that if two women behind you at the movies
insist on discussing the probable outcome of the film, you have the
right to turn around and blow a Bronx cheer at them.

공유 볼륨 확인 시 노드 먼저 확인

**$ kubectl get pods -o wide**
NAME                     READY   STATUS    RESTARTS   AGE     IP              NODE         NOMINATED NODE   READINESS GATES
myapp-rs-fortune-2875c   2/2     Running   0          7m58s   10.233.73.104   kube-node1   <none>           <none>

uid 확인

**$ kubectl get pod myapp-rs-fortune-2875c -o jsonpath='{.metadata.uid}'**
0155d67a-eebd-4252-85fe-49b40223c7e4

vagrant 접속(kube-node1)

**vagrant@kube-node1:~$ sudo ls /var/lib/kubelet/pods/0155d67a-eebd-4252-85fe-49b40223c7e4/volumes/kubernetes.io~empty-dir/web-fortune**
index.html
profile
새싹 개발자

0개의 댓글