프로그래밍/DevOps

[DevOps]Kubernetes: Deployment와 Service로 웹 앱 배포하기 🚀

다다면체 2025. 2. 20. 16:50
728x90
반응형

안녕하세요, 여러분! ☸️ 드디어 기다리고 기다리던 순간이 왔습니다! Kubernetes 클러스터를 구축했으니, 이제 애플리케이션을 배포해 볼 차례입니다! 오늘은 Kubernetes 배포의 핵심, DeploymentService 리소스를 이용하여 간단한 웹 애플리케이션을 클러스터에 배포하는 방법을 차근차근 알아보겠습니다. 마치 텅 빈 운동장에 멋진 건물을 짓는 것처럼, Kubernetes 위에 여러분의 애플리케이션을 올려보세요! 🏗️


반응형

🚀 Kubernetes 배포, 왜 Deployment와 Service일까요?

Kubernetes에서 애플리케이션을 배포하는 방법은 다양하지만, 가장 기본적이면서도 핵심적인 방법은 DeploymentService 리소스를 사용하는 것입니다. 이 두 가지 리소스는 마치 건물의 뼈대과 같은 역할을 합니다.

Deployment는 애플리케이션의 배포업데이트, 확장, 롤백과 같은 생명주기를 관리하는 역할을 합니다. 마치 건물의 튼튼한 뼈대를 세우고, 건물을 안전하게 유지보수하는 관리자와 같죠. Deployment를 사용하면 무중단 배포자동 복구와 같은 강력한 기능을 활용하여 안정적인 애플리케이션 운영이 가능합니다.

Service는 배포된 애플리케이션에 네트워크 접근을 제공하고, 로드밸런싱서비스 디스커버리 기능을 담당합니다. 마치 건물 정문을 만들어 외부 사용자들이 건물 안으로 들어올 수 있도록 안내하고, 건물 내 여러 서비스들을 효율적으로 연결해주는 역할을 합니다. Service를 통해 애플리케이션을 외부 사용자에게 노출하고, 클러스터 내부 서비스들이 서로 통신할 수 있도록 할 수 있습니다.

Deployment와 Service는 서로 긴밀하게 협력하여 Kubernetes 환경에서 애플리케이션을 안정적이고 효율적으로 운영하는 데 필수적인 요소입니다. 자, 그럼 이제 Deployment부터 자세히 알아볼까요?


📦 Deployment, 애플리케이션 배포의 마스터 키

Deployment는 Kubernetes에서 무상태(Stateless) 애플리케이션을 배포하고 관리하는 데 가장 많이 사용되는 리소스입니다. Deployment를 사용하면 다음과 같은 강력한 기능들을 활용할 수 있습니다.

  • 선언적 배포: 원하는 애플리케이션의 상태를 선언하면, Kubernetes가 자동으로 현재 상태를 원하는 상태로 유지합니다. 마치 레시피대로 요리하면 맛있는 음식이 완성되는 것처럼, Deployment Manifest를 작성하면 Kubernetes가 알아서 애플리케이션을 배포해줍니다. 🍳
  • 롤링 업데이트 및 롤백: 애플리케이션을 무중단으로 업데이트하고, 문제가 발생했을 경우 이전 버전으로 롤백할 수 있습니다. 마치 건물을 리모델링하면서도 건물 기능을 멈추지 않는 것처럼, Deployment는 서비스 중단 없이 애플리케이션을 업데이트할 수 있습니다. 🛠️
  • 확장 및 축소: 트래픽 변화에 따라 애플리케이션의 Pod 수를 자동으로 또는 수동으로 조절할 수 있습니다. 마치 건물의 크기를 필요에 따라 늘렸다 줄였다 할 수 있는 것처럼, Deployment는 애플리케이션의 확장성을 보장합니다. 🏢
  • 자동 복구: Pod가 비정상적으로 종료될 경우, 자동으로 새로운 Pod를 생성하여 애플리케이션의 가용성을 유지합니다. 마치 자가 치유 능력이 있는 생명체처럼, Deployment는 애플리케이션을 항상 건강하게 유지합니다. 🌱

📝 Deployment Manifest 작성 및 배포

Deployment를 배포하기 위해서는 Deployment Manifest 파일을 작성해야 합니다. Deployment Manifest는 YAML 형식으로 작성하며, 애플리케이션의 배포 정보를 선언하는 파일입니다. 기본적인 Deployment Manifest 구조는 다음과 같습니다.

apiVersion: apps/v1 #apiVersion 버전 명시 (Deployment는 apps/v1)
kind: Deployment #리소스 종류 명시 (Deployment)
metadata: #메타데이터 정의
  name: my-app-deployment #Deployment 이름 (고유해야 함)
spec: #Deployment 상세 스펙 정의
  replicas: 3 #Pod 복제본 수 (3개 유지)
  selector: #Deployment가 관리할 Pod를 선택하는 Selector
    matchLabels:
      app: my-app #Label이 app: my-app인 Pod를 관리
  template: #Pod 템플릿 정의 (Pod 스펙)
    metadata:
      labels:
        app: my-app #Pod Label (Selector와 일치해야 함)
    spec:
      containers: #Pod 내 컨테이너 정의
      - name: my-app-container #컨테이너 이름
        image: nginx:latest #컨테이너 이미지 (Docker 이미지)
        ports:
        - containerPort: 80 #컨테이너 Port (80번 포트)

주요 필드 설명:

  • apiVersion: Kubernetes API 버전. Deployment는 apps/v1 버전을 사용합니다.
  • kind: 리소스 종류. Deployment를 배포하므로 Deployment로 설정합니다.
  • metadata.name: Deployment 이름. 클러스터 내에서 고유해야 합니다.
  • spec.replicas: 유지할 Pod 복제본 수. 위 예시에서는 3개의 Pod를 항상 유지합니다.
  • spec.selector: Deployment가 관리할 Pod를 선택하는 Selector. matchLabels를 사용하여 특정 Label을 가진 Pod를 선택합니다.
  • spec.template: Pod 템플릿. Deployment가 생성할 Pod의 스펙을 정의합니다. metadata.labels는 spec.selector의 matchLabels와 일치해야 합니다.
  • spec.template.spec.containers: Pod 내에 실행할 컨테이너 목록. name, image, ports 등의 컨테이너 스펙을 정의합니다.

Deployment Manifest를 작성했다면, kubectl apply 명령어를 사용하여 Kubernetes 클러스터에 배포할 수 있습니다.

kubectl apply -f my-app-deployment.yaml #yaml 파일 경로 지정

⚙️ Deployment 관리 명령어 실습

Deployment를 배포한 후, 다음과 같은 kubectl 명령어를 사용하여 Deployment를 관리할 수 있습니다.

  • kubectl get deployment: Deployment 목록 확인
  • kubectl describe deployment <deployment-이름>: Deployment 상세 정보 확인 (이벤트, 상태 등)
  • kubectl edit deployment <deployment-이름>: Deployment Manifest 수정 (직접 편집기에서 수정)
  • kubectl delete deployment <deployment-이름>: Deployment 삭제 (Deployment와 ReplicaSet, Pod 함께 삭제)

👯 ReplicaSet과 Pod, Deployment의 그림자 군단

Deployment는 직접 Pod를 관리하는 것이 아니라, ReplicaSet을 통해 Pod를 관리합니다. ReplicaSet은 Deployment에 의해 생성되고 관리되는 리소스로, 설정된 복제본 수만큼 Pod를 항상 유지하는 역할을 합니다.

Deployment -> ReplicaSet -> Pod 의 관계를 통해, Deployment는 ReplicaSet을 통해 Pod의 생성, 삭제, 업데이트를 간접적으로 관리하고, ReplicaSet은 설정된 복제본 수를 유지하며 Pod의 생명주기를 관리합니다.

🔄 무중단 배포와 롤백, 안정적인 서비스 운영의 핵심

Deployment의 핵심 기능 중 하나는 무중단 배포 (Rolling Update)롤백 (Rollback) 기능입니다. 애플리케이션을 업데이트할 때, 서비스 중단 없이 새로운 버전으로 점진적으로 업데이트하고, 문제가 발생했을 경우 이전 버전으로 빠르게 롤백할 수 있습니다.

  • 무중단 배포 (Rolling Update): Deployment는 기본적으로 RollingUpdate 전략을 사용하여 애플리케이션을 업데이트합니다. RollingUpdate 전략은 다음과 같은 방식으로 진행됩니다.
    1. 새로운 ReplicaSet 생성 (새로운 버전 Pod 템플릿 기반)
    2. 기존 ReplicaSet의 Pod를 하나씩 줄여나가면서, 새로운 ReplicaSet의 Pod를 하나씩 늘려나감
    3. 업데이트 과정 중에도 서비스는 계속 유지 (로드밸런싱을 통해 트래픽을 정상 Pod로 전달)
    4. 업데이트 완료 후 기존 ReplicaSet 삭제, 새로운 ReplicaSet만 남음
    kubectl rollout status deployment/<deployment-이름> 명령어를 사용하여 롤링 업데이트 진행 상황을 확인할 수 있습니다.
  • 롤백 (Rollback): 롤링 업데이트 중 문제가 발생하거나, 이전 버전으로 되돌리고 싶을 경우, kubectl rollout undo deployment/<deployment-이름> 명령어를 사용하여 이전 버전으로 롤백할 수 있습니다.
  • kubectl rollout history deployment/<deployment-이름> 명령어를 사용하여 Deployment 업데이트 히스토리를 확인하고, 특정 revision으로 롤백할 수 있습니다.

⚙️ Deployment 전략 선택, Recreate vs RollingUpdate

Deployment는 두 가지 주요 배포 전략을 제공합니다.

  • Recreate Deployment: 기존 Pod를 모두 삭제한 후, 새로운 Pod를 생성하는 방식입니다. 서비스 중단이 발생할 수 있지만, 간단하고 빠르게 배포할 수 있습니다. 주로 개발 환경이나, 서비스 중단이 크게 문제가 되지 않는 경우에 사용됩니다.
  • spec.strategy.type: Recreate 설정을 통해 Recreate 전략을 사용할 수 있습니다.
  • RollingUpdate Deployment: Pod를 점진적으로 업데이트하는 방식입니다. 서비스 중단 없이 업데이트할 수 있지만, Recreate 방식보다 배포 시간이 오래 걸릴 수 있습니다. Production 환경에서 무중단 배포가 중요한 경우에 주로 사용됩니다.
    • maxSurge: 업데이트 중 ReplicaSet 개수를 초과하여 추가적으로 생성할 수 있는 Pod 최대 개수 또는 비율. (기본값: 25%)
    • maxUnavailable: 업데이트 중 서비스 불가능한 상태로 허용할 수 있는 Pod 최대 개수 또는 비율. (기본값: 25%)
  • spec.strategy.type: RollingUpdate (기본값) 설정을 통해 RollingUpdate 전략을 사용할 수 있으며, spec.strategy.rollingUpdate 옵션을 통해 업데이트 방식을 세밀하게 조정할 수 있습니다.

Deployment 전략은 애플리케이션의 특성, 서비스 요구 사항, 환경 등을 고려하여 적절하게 선택해야 합니다. 일반적으로 Production 환경에서는 무중단 배포를 위해 RollingUpdate 전략을 사용하는 것이 권장됩니다.

🚪 Service, 애플리케이션을 세상 밖으로!

Service는 Kubernetes 클러스터 내부 또는 외부에서 애플리케이션에 접근할 수 있도록 네트워크 인터페이스를 제공하는 리소스입니다. Service를 사용하면 다음과 같은 기능들을 활용할 수 있습니다.

  • 고정 IP 및 DNS 이름: Pod IP 주소는 동적으로 변동되지만, Service는 고정적인 IP 주소와 DNS 이름을 제공하여 애플리케이션에 안정적으로 접근할 수 있도록 합니다. 마치 건물의 고정 주소와 같은 역할을 합니다. 🏢
  • 로드밸런싱: Service는 여러 Pod로 트래픽을 분산하여 애플리케이션의 가용성과 성능을 향상시킵니다. 마치 교통 정리 경찰처럼, Service는 트래픽을 효율적으로 분산하여 병목 현상을 방지합니다. 🚦
  • 서비스 디스커버리: Service는 DNS 기반의 서비스 디스커버리 기능을 제공하여, 클러스터 내부 서비스들이 서로 이름을 통해 쉽게 통신할 수 있도록 합니다. 마치 전화번호부처럼, Service는 클러스터 내부 서비스들의 주소를 관리하고 제공합니다. 📞

📝 Service Manifest 작성 및 배포

Service를 배포하기 위해서는 Service Manifest 파일을 작성해야 합니다. Service Manifest도 YAML 형식으로 작성하며, 서비스의 네트워크 정보를 선언하는 파일입니다. 기본적인 Service Manifest 구조는 다음과 같습니다.

apiVersion: v1 #apiVersion 버전 명시 (Service는 v1)
kind: Service #리소스 종류 명시 (Service)
metadata: #메타데이터 정의
  name: my-app-service #Service 이름 (고유해야 함)
spec: #Service 상세 스펙 정의
  selector: #Service가 연결할 Pod를 선택하는 Selector
    app: my-app #Label이 app: my-app인 Pod를 연결
  ports: #Port 정보 정의
  - port: 80 #Service Port (외부에서 접근할 Port)
    targetPort: 80 #Pod 컨테이너 Port (실제 애플리케이션 Port)
    protocol: TCP #프로토콜 (TCP, UDP, SCTP)
  type: ClusterIP #Service 타입 (ClusterIP, NodePort, LoadBalancer)

주요 필드 설명:

  • apiVersion: Kubernetes API 버전. Service는 v1 버전을 사용합니다.
  • kind: 리소스 종류. Service를 배포하므로 Service로 설정합니다.
  • metadata.name: Service 이름. 클러스터 내에서 고유해야 합니다.
  • spec.selector: Service가 연결할 Pod를 선택하는 Selector. matchLabels를 사용하여 특정 Label을 가진 Pod를 선택합니다. Deployment의 spec.selector와 일치해야 합니다.
  • spec.ports: Port 정보 목록.
    • port: Service Port. 외부에서 접근할 Port.
    • targetPort: Pod 컨테이너 Port. 실제 애플리케이션이 Listen하는 Port.
    • protocol: 프로토콜. TCP, UDP, SCTP 중 선택합니다. (기본값: TCP)
  • spec.type: Service 타입. ClusterIP, NodePort, LoadBalancer 중 선택합니다. (기본값: ClusterIP)

Service Manifest를 작성했다면, kubectl apply 명령어를 사용하여 Kubernetes 클러스터에 배포할 수 있습니다.

kubectl apply -f my-app-service.yaml #yaml 파일 경로 지정

⚙️ Service 관리 명령어 실습

Service를 배포한 후, 다음과 같은 kubectl 명령어를 사용하여 Service를 관리할 수 있습니다.

  • kubectl get service: Service 목록 확인
  • kubectl describe service <service-이름>: Service 상세 정보 확인 (Endpoint, IP, Port 등)
  • kubectl edit service <service-이름>: Service Manifest 수정 (직접 편집기에서 수정)
  • kubectl delete service <service-이름>: Service 삭제

💡 Service 타입 선택 가이드, ClusterIP vs NodePort vs LoadBalancer

Service는 다양한 타입을 제공하며, 각각 사용 시나리오가 다릅니다.

  • ClusterIP Service: 클러스터 내부 IP 주소를 할당하는 타입입니다. 클러스터 내부 서비스 간 통신에 사용되며, 외부에서 직접 접근할 수 없습니다. spec.type: ClusterIP 설정을 통해 ClusterIP Service를 생성할 수 있습니다. (기본값) 주로 백엔드 서비스, 데이터베이스 등 내부 서비스에 사용됩니다.
  • NodePort Service: 각 Worker Node의 특정 Port를 오픈하여 외부에서 Service에 접근할 수 있도록 하는 타입입니다. spec.type: NodePort 설정을 통해 NodePort Service를 생성할 수 있으며, spec.ports.nodePort 옵션을 통해 노드 포트를 직접 지정할 수도 있습니다. 개발/테스트 환경에서 외부에서 Service에 쉽게 접근하고 싶을 때 유용합니다. 하지만 Production 환경에서는 LoadBalancer Service를 사용하는 것이 일반적입니다.
  • LoadBalancer Service: 클라우드 환경에서 외부 Load Balancer를 프로비저닝하여 외부 트래픽을 Service로 분산하는 타입입니다. spec.type: LoadBalancer 설정을 통해 LoadBalancer Service를 생성할 수 있으며, 클라우드 프로바이더 (AWS, GCP, Azure 등) 에서 제공하는 Load Balancer 서비스를 활용합니다. Production 환경에서 외부 트래픽을 안정적으로 처리하고 싶을 때 가장 적합합니다. Minikube나 Kind와 같은 로컬 클러스터에서는 LoadBalancer 기능을 완벽하게 지원하지 않을 수 있습니다.

Service 타입은 애플리케이션의 접근 방식, 환경, 요구 사항 등을 고려하여 적절하게 선택해야 합니다. 일반적으로 Production 환경에서는 외부 트래픽을 위해 LoadBalancer Service를 사용하고, 내부 서비스 간 통신을 위해 ClusterIP Service를 사용하는 것이 일반적인 Best Practice입니다.

🔎 서비스 디스커버리, 컨테이너들의 효율적인 소통 방식

Kubernetes는 서비스 디스커버리 (Service Discovery) 기능을 제공하여, 클러스터 내부 서비스들이 서로의 위치 (IP 주소, Port) 를 몰라도 이름만으로 쉽게 통신할 수 있도록 합니다. 서비스 디스커버리 방식은 크게 두 가지가 있습니다.

  • 환경 변수 (Environment Variables): Service가 생성되면, Kubernetes는 자동으로 해당 Service 이름으로 환경 변수를 생성하고, Pod에 주입합니다. Pod 내에서 환경 변수를 통해 Service IP 주소와 Port 정보를 얻을 수 있습니다. 간단하지만, Service가 생성된 후에 Pod가 생성되어야 환경 변수를 사용할 수 있다는 제약이 있습니다.
  • DNS 기반 서비스 디스커버리: Kubernetes는 CoreDNS 또는 kube-dns와 같은 DNS 서비스를 클러스터 내부에 제공합니다. Service가 생성되면, DNS 서버에 Service 이름으로 DNS 레코드를 등록하고, Pod는 DNS 쿼리를 통해 Service IP 주소를 조회할 수 있습니다. 환경 변수 방식보다 더 유연하고 확장성 있는 방식이며, 일반적으로 DNS 기반 서비스 디스커버리 방식을 사용하는 것이 권장됩니다.

🚀 웹 애플리케이션 Kubernetes 배포

이제 실제로 간단한 웹 애플리케이션을 Kubernetes에 배포해보는 실습을 진행해 보겠습니다. 이번 실습에서는 이전에 Docker Compose 튜토리얼에서 사용했던 간단한 Node.js 웹 애플리케이션 Docker Image를 재활용하거나, 간단한 Nginx 웹 서버 이미지를 사용할 수 있습니다.

1. 웹 애플리케이션 Docker Image 빌드:

기존 Dockerfile을 재활용하거나, 다음과 같이 간단한 Nginx 웹 서버 Dockerfile을 작성하고 이미지를 빌드합니다.

FROM nginx:latest
COPY index.html /usr/share/nginx/html

 

index.html 파일은 다음과 같이 간단하게 작성합니다.

<!DOCTYPE html>
<html>
<head>
    <title>Hello Kubernetes!</title>
</head>
<body>
    <h1>Hello Kubernetes! from Deployment and Service</h1>
</body>
</html>

 

Docker Image 빌드 명령어 예시:

docker build -t my-webapp:v1 .
docker push <your-dockerhub-id>/my-webapp:v1 #Docker Hub에 이미지 Push (선택 사항)

 

2. Deployment Manifest 및 Service Manifest 작성:

다음과 같이 webapp-deployment.yaml 및 webapp-service.yaml 파일을 작성합니다. webapp-deployment.yaml 파일에서는 spec.template.spec.containers.image 필드에 빌드한 Docker Image 이름을 입력하고, webapp-service.yaml 파일에서는 spec.selector.app 필드에 Deployment Manifest의 spec.template.metadata.labels.app 필드와 동일한 Label 값을 입력합니다.

webapp-deployment.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: webapp-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: webapp
  template:
    metadata:
      labels:
        app: webapp
    spec:
      containers:
      - name: webapp-container
        image: <your-dockerhub-id>/my-webapp:v1 #빌드한 Docker Image 이름으로 변경
        ports:
        - containerPort: 80

 

webapp-service.yaml:

apiVersion: v1
kind: Service
metadata:
  name: webapp-service
spec:
  selector:
    app: webapp #Deployment Label과 일치
  ports:
  - port: 80
    targetPort: 80
  type: LoadBalancer #LoadBalancer Service로 배포 (클라우드 환경 또는 Minikube tunnel 필요)

 

3. kubectl apply 명령어로 Kubernetes 배포 및 웹 애플리케이션 접속 확인:

터미널에서 Manifest 파일이 있는 디렉토리로 이동하여 kubectl apply -f . 명령어를 실행합니다. Kubernetes 클러스터에 Deployment와 Service가 생성되고, 웹 애플리케이션이 배포됩니다.

kubectl apply -f . #webapp-deployment.yaml, webapp-service.yaml 파일 배포
kubectl get deployment webapp-deployment #Deployment 상태 확인
kubectl get service webapp-service #Service 상태 확인

kubectl get service webapp-service 명령어 실행 결과에서 EXTERNAL-IP 주소를 확인하고, 웹 브라우저에서 해당 주소로 접속하여 웹 애플리케이션이 정상적으로 동작하는지 확인합니다. (LoadBalancer Service 타입으로 배포한 경우, 클라우드 환경에서는 Load Balancer 프로비저닝 시간이 다소 소요될 수 있습니다. Minikube 환경에서는 minikube tunnel 명령어를 실행해야 EXTERNAL-IP 주소를 할당받을 수 있습니다.)

➕ 추가 학습

Kubernetes 배포는 오늘 배운 Deployment와 Service 외에도 더욱 다양한 기술과 개념들이 존재합니다. Kubernetes 배포를 더욱 심층적으로 학습하고 싶다면, 다음 주제들을 추가적으로 탐구해 보세요. 🚀

  • Kubernetes 배포 전략 심층 학습: Canary Deployment, Blue/Green Deployment, A/B Testing 등 다양한 배포 전략을 학습하고, 각 전략의 장단점 및 사용 시나리오를 이해하세요. 전략적인 배포는 서비스 안정성을 더욱 높여줍니다. 🚀 전략!
  • Kubernetes 네트워크 정책 (Network Policy): Network Policy를 이용하여 Pod 간 네트워크 격리를 설정하고, 클러스터 보안을 강화하는 방법을 학습하세요. 🛡️ 네트워크 보안!
  • Kubernetes StatefulSet: StatefulSet을 이용하여 데이터베이스와 같이 상태를 유지해야 하는 애플리케이션을 Kubernetes에 배포하는 방법을 학습하세요. 💾 데이터 관리!
  • Helm Chart: Helm Chart를 이용하여 Kubernetes 애플리케이션 배포를 자동화하고, 복잡한 애플리케이션을 효율적으로 관리하는 방법을 미리 알아보세요. ⚙️ 배포 자동화!

✅ 결론: Kubernetes 배포, 이제 당신의 손안에!

축하합니다! 🎉 이 튜토리얼을 통해 Kubernetes Deployment와 Service를 이용하여 웹 애플리케이션을 배포하는 기본적인 방법을 성공적으로 익히셨습니다! 이제 여러분은 Kubernetes를 활용하여 애플리케이션을 배포하고 관리하는 첫 걸음을 내딛었습니다.

다음 장에서는 Kubernetes Ingress를 이용하여 외부 트래픽을 효과적으로 관리하고, 더욱 복잡한 웹 애플리케이션을 Kubernetes에 배포하는 방법을 자세히 알아보겠습니다. Kubernetes를 활용한 웹 서비스 구축의 세계로 함께 나아가 볼까요? 🚀☸️

728x90
반응형