Service 를 사용하여 Deployment 노출하기

KubernetesBeginner
지금 연습하기

소개

Pod 는 일시적인 존재입니다. Deployment 는 롤아웃, 재시작 또는 스케일링 과정에서 Pod 를 교체할 수 있으므로, 클라이언트는 개별 Pod 의 IP 에 직접 연결해서는 안 됩니다. Service 는 클라이언트에게 안정적인 이름과 가상 IP 를 제공하며, 레이블을 사용하여 트래픽을 현재 일치하는 Pod 로 라우팅합니다.

이 실습에서는 간단한 웹 Deployment 를 생성하고, ClusterIP Service 로 노출하며, Service 가 백엔드 Pod 를 선택하는 방식을 확인하고, 클라이언트 Pod 에서 Service 를 테스트한 뒤, Deployment 를 스케일링하여 Service 엔드포인트가 업데이트되는 과정을 살펴봅니다.

웹 Deployment 생성

이 단계에서는 네임스페이스를 준비하고, 나중에 Service 로 노출할 수 있는 Deployment 를 생성합니다.

/home/labex/project에서 시작합니다:

mkdir -p /home/labex/project
cd /home/labex/project

Kubernetes API 서버에 연결할 수 있는지 확인합니다. VM 이 막 시작되어 노드가 아직 준비되지 않았다면, 몇 초 기다린 후 명령어를 다시 실행하세요.

kubectl get nodes --request-timeout=5s

예상 출력은 다음과 같습니다:

NAME         STATUS   ROLES           AGE   VERSION
labex-v135   Ready    control-plane   ...   v1.35...

클러스터 네트워킹 Pod 가 준비 (Ready) 상태가 될 때까지 기다립니다. 이 실습에서는 Service 를 통해 Pod 간 트래픽을 전송하므로, 접근을 테스트하기 전에 클러스터 네트워킹이 정상 상태여야 합니다.

kubectl wait --namespace kube-system --for=condition=Ready pod -l k8s-app=calico-node --timeout=120s

예상 출력:

pod/calico-node-... condition met

ckad-prep-service라는 이름의 네임스페이스를 생성하고 현재 네임스페이스로 설정합니다:

kubectl create namespace ckad-prep-service
kubectl config set-context --current --namespace=ckad-prep-service

하나의 NGINX Pod 를 포함하는 web-front라는 이름의 Deployment 를 생성합니다. --port=80 플래그는 Pod 템플릿에 컨테이너 포트를 기록하는 역할을 합니다. 이 명령어 자체가 Service 를 생성하지는 않습니다.

kubectl create deployment web-front --image=nginx:1.25 --port=80

Deployment 가 사용 가능해질 때까지 기다린 후, Pod 레이블을 확인합니다. app=web-front 레이블은 Service 가 백엔드 Pod 를 찾는 데 사용되므로 중요합니다.

kubectl rollout status deployment/web-front --timeout=120s
kubectl get pods -l app=web-front --show-labels

예상 출력은 다음과 같습니다:

deployment "web-front" successfully rolled out
NAME                         READY   STATUS    RESTARTS   AGE   LABELS
web-front-...                1/1     Running   0          ...   app=web-front,...

ClusterIP Service 로 Deployment 노출

이 단계에서는 Deployment 를 위한 Service 를 생성하고, Service 와 Pod 를 연결하는 필드들을 확인합니다.

kubectl expose deployment를 사용하여 ClusterIP Service 를 생성합니다. Service 포트는 80이며, --target-port=80은 일치하는 Pod 의 80번 포트로 트래픽을 전달하도록 Service 에 지시합니다.

kubectl expose deployment web-front --name=web-front --port=80 --target-port=80

예상 출력:

service/web-front exposed

Service 를 확인합니다:

kubectl get service web-front

예상 출력은 다음과 같습니다:

NAME        TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
web-front   ClusterIP   ...          <none>        80/TCP    ...

이제 Service 셀렉터와 포트 매핑을 확인합니다. 셀렉터는 Service 가 Pod 를 찾는 방법이며, 포트 매핑은 클라이언트 트래픽이 컨테이너에 도달하는 방법입니다.

kubectl get service web-front -o jsonpath='{.spec.selector.app}{" "}{.spec.ports[0].port}{":"}{.spec.ports[0].targetPort}{"\n"}'

예상 출력:

web-front 80:80

Kubernetes 는 선택된 백엔드 주소를 EndpointSlice 에 저장합니다. 이 Service 를 위해 생성된 EndpointSlice 를 나열합니다:

kubectl get endpointslice -l kubernetes.io/service-name=web-front

예상 출력은 다음과 같습니다:

NAME              ADDRESSTYPE   PORTS   ENDPOINTS   AGE
web-front-...     IPv4          80      ...         ...

클러스터 내부에서 Service 테스트

이 단계에서는 임시 클라이언트 Pod 를 생성하고 Service 에 HTTP 요청을 보냅니다. ClusterIP Service 는 클러스터 내부 접근을 위한 것이므로, 다른 Pod 에서 테스트하는 것이 가장 직접적인 검증 방법입니다.

실행 상태를 유지하는 클라이언트 Pod 를 생성합니다:

kubectl run service-client --image=busybox:1.36 --restart=Never --command -- sleep 3600

클라이언트 Pod 가 준비될 때까지 기다립니다:

kubectl wait --for=condition=Ready pod/service-client --timeout=120s

예상 출력:

pod/service-client condition met

클라이언트 Pod 내부에서 wget을 사용하여 http://web-front에 요청을 보냅니다. web-front라는 이름은 네임스페이스 내부에서 Service 로 해석됩니다.

kubectl exec service-client -- wget -qO- http://web-front | head -n 5

예상 출력에는 기본 NGINX 페이지의 시작 부분이 포함됩니다:

<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>

이는 클라이언트가 안정적인 Service 이름에 도달했으며, Service 가 트래픽을 현재 백엔드 Pod 로 성공적으로 전달했음을 증명합니다.

백엔드 스케일링 및 엔드포인트 재확인

이 단계에서는 Deployment 를 스케일링하고, 백엔드 엔드포인트가 변경되어도 Service 는 동일한 안정적인 진입점을 유지하는지 확인합니다.

Deployment 를 2 개의 레플리카로 스케일링합니다:

kubectl scale deployment web-front --replicas=2
kubectl rollout status deployment/web-front --timeout=120s

예상 출력은 다음과 같습니다:

deployment.apps/web-front scaled
deployment "web-front" successfully rolled out

Pod 를 나열합니다. 이제 동일한 app=web-front 레이블을 가진 2 개의 실행 중인 백엔드 Pod 가 있어야 합니다.

kubectl get pods -l app=web-front

예상 출력에는 2 개의 Pod 가 포함됩니다:

NAME                         READY   STATUS    RESTARTS   AGE
web-front-...                1/1     Running   0          ...
web-front-...                1/1     Running   0          ...

Service 뒤에 있는 엔드포인트 개수를 셉니다. 이 명령어는 각 엔드포인트 주소마다 한 줄씩 출력한 뒤 줄 수를 셉니다.

kubectl get endpointslice -l kubernetes.io/service-name=web-front -o jsonpath='{range .items[*].endpoints[*]}{.addresses[0]}{"\n"}{end}' | wc -l

예상 출력:

2

동일한 클라이언트 Pod 에서 Service 에 다시 요청을 보냅니다:

kubectl exec service-client -- wget -qO- http://web-front | grep '<title>Welcome to nginx'

예상 출력:

<title>Welcome to nginx!</title>

요약

ClusterIP Service 를 사용하여 Deployment 를 노출하고 전체 클러스터 내부 접근 경로를 검증했습니다. 백엔드 Deployment 를 생성하고, 셀렉터와 포트 매핑이 포함된 Service 를 만들었으며, Service 를 위해 생성된 EndpointSlice 를 확인하고, 클라이언트 Pod 에서 접근을 테스트한 뒤, Deployment 를 스케일링하여 Service 가 업데이트된 백엔드 세트로 계속 라우팅하는 것을 확인했습니다.