도커 컴포즈에서 쿠버네티스 클러스터 배포로 전환할 때, 애플리케이션 관리는 근본적으로 달라집니다. 클러스터는 높은 가용성, 탄력성, 그리고 자동 확장을 제공하지만 새로운 추상화 개념을 도입합니다.
주요 개념 분석
클러스터 환경에서는 더 이상 직접 "컨테이너"를 관리하는 것이 아니라 "워크로드"(Workload)와 "서비스"(Service)를 다룹니다. 아래는 몇 가지 중요한 개념들입니다:
1. 상태 없는 워크로드 (Stateless Workload)
- 쿠버네티스 객체:
Deployment - 핵심 아이디어: 이 워크로드의 모든 인스턴스(파드)는 동일하고 서로 교체 가능합니다. 어떤 데이터도 영구적으로 저장되지 않습니다. 특정 인스턴스가 고장 나면 클러스터는 새로운 인스턴스를 즉시 생성하여 상태를 유지합니다.
- 예시: 웹 서버(Nginx, Apache), API 백엔드, 마이크로서비스 게이트웨이.
- 비유: 패스트푸드점의 계산원처럼 누구나 같은 서비스를 제공할 수 있습니다.
2. 상태 있는 워크로드 (StatefulSet)
- 쿠버네티스 객체:
StatefulSet - 핵심 아이디어: 각각의 파드는 안정적이고 유일한 식별자를 가지고 있으며 독립적인 지속 저장소에 연결됩니다.
- 주요 특징:
- 안정된 네트워크 ID: 파드가 재부팅되더라도 호스트명과 DNS 기록은 변하지 않습니다.
- 안정된 지속 저장소: 각 파드는 자신만의 저장소(PVC)를 가지고 있어 재배치되어도 동일한 저장소에 다시 연결됩니다.
- 예시: 데이터베이스(MySQL, PostgreSQL, Neo4j), 메시지 큐(Kafka, RabbitMQ), 분산 파일 시스템.
- 비유: 은행의 금고처럼 각각 고유한 번호와 데이터를 가지고 있어 대체될 수 없습니다.
3. 저장소 (PersistentVolume - PV)
- 핵심 아이디어: 이는 클러스터 내의 실제 저장소 자원입니다.
- 출처: 구름 서비스의 디스크, NFS 또는 NAS 등이 될 수 있습니다.
- 비유: 이미 나누어지고 라벨이 붙은 창고의 선반이라고 생각할 수 있습니다.
4. 저장 요청 (PersistentVolumeClaim - PVC)
- 핵심 아이디어: 애플리케이션이 저장소를 요청하는 것입니다.
- 작동 방식:
- 정적 할당: 미리 PV를 만들고 이를 정확히 참조하는 PVC를 생성합니다.
- 동적 할당: 단순히 PVC를 만들면 쿠버네티스가 자동으로 PV를 생성하고 연결합니다.
- 비유: 창고의 물건을 가져오기 위한 수령서입니다.
5. 서비스 (Service)
- 핵심 아이디어: 클러스터 내에서 파드의 IP 주소는 변경될 수 있지만, 서비스는 항상 일정한 엔트리 포인트를 제공합니다.
- 기능:
- 서비스 발견: 다른 애플리케이션들은 특정 서비스 이름을 통해 접근할 수 있습니다.
- 로드 밸런싱: 여러 인스턴스가 있을 경우 자동으로 요청을 분산 처리합니다.
- 포트 매핑: 특정 포트를 리스닝하고 이를 컨테이너의 포트와 연결합니다.
6. 라우팅 (Ingress)
- 핵심 아이디어: 클러스터 외부로부터 HTTP/HTTPS 트래픽을 라우팅합니다.
- 기능:
- 도메인 기반 라우팅: 특정 도메인을 특정 서비스로 연결합니다.
- SSL/TLS 종료: HTTPS 암호화를 중앙에서 처리합니다.
- 비유: 사무실의 프론트 데스크처럼 외부 요청을 적절하게 분배합니다.
7. 비밀 정보 (Secret)
- 쿠버네티스 객체:
Secret - 핵심 아이디어: 민감한 데이터(비밀번호, API 키 등)를 안전하게 저장합니다.
- 작동 방식: 비밀 정보를 먼저 저장하고, 해당 정보를 파드의 환경 변수나 파일로 연결합니다.
- 비유: 잠금 장치가 있는 보험함처럼 중요한 정보를 안전하게 보관합니다.
Docker Compose vs Kubernetes 이전 비교
아래는 제공된 docker-compose.yml 파일을 쿠버네티스 YAML 구성 파일로 변환한 예입니다.
Docker Compose 파일
version: '3.8'
services:
neo4j:
image: neo4j:5.20.0
container_name: neo4j_db
ports:
- "7474:7474"
- "7687:7687"
environment:
- NEO4J_AUTH=neo4j/indemind@@
volumes:
- /home/indemind/zy_/neo4j/docker_data:/data
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:7474"]
interval: 10s
timeout: 10s
retries: 5
Kubernetes로의 이전
총괄:
- PV (PersistenVolume): NAS 저장소를 정의합니다.
- PVC (PersistenVolumeClaim): 위 PV를 사용하도록 요청합니다.
- Secret: Neo4j 비밀번호를 안전하게 저장합니다.
- StatefulSet: Neo4j를 관리합니다.
- Service: Neo4j의 포트를 노출합니다.
1. PV (PersistenVolume)
새로운 NAS 디렉토리를 만들어야 합니다. 아래는 k8s-persistent-volume.yml 파일입니다.
apiVersion: v1
kind: PersistentVolume
metadata:
name: neo4j-storage
spec:
capacity:
storage: 10Gi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
csi:
driver: nas.csi.volcengine.com
volumeHandle: neo4j-data
volumeAttributes:
server: "cnbja0e0eda9ce19fe.vpc-1a1zcgj9sn8cg8nveplg3708b.nas.ivolces.com"
path: "/enas-cnbja0e0eda9ce19fe/neo4j-data"
fsType: "Extreme"
mountOptions:
- nolock,proto=tcp,noresvport
- vers=3
2. PVC (PersistenVolumeClaim)
다음은 k8s-persistent-volume-claim.yml 파일입니다.
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: neo4j-claim
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
volumeName: neo4j-storage
storageClassName: ""
3. Secret
Neo4j 비밀번호를 저장하기 위해 k8s-secret.yml 파일을 만듭니다.
apiVersion: v1
kind: Secret
metadata:
name: neo4j-secret-key
type: Opaque
stringData:
NEO4J_PASSWORD: "indemind@@"
4. StatefulSet
Neo4j를 관리하기 위해 k8s-statefulset.yml 파일을 작성합니다.
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: neo4j-db
spec:
serviceName: "neo4j-service"
replicas: 1
selector:
matchLabels:
app: neo4j
template:
metadata:
labels:
app: neo4j
spec:
enableServiceLinks: false
volumes:
- name: neo4j-volume
persistentVolumeClaim:
claimName: neo4j-claim
containers:
- name: neo4j-container
image: docker.io/neo4j:5.22.0
ports:
- containerPort: 7474
name: http
- containerPort: 7687
name: bolt
env:
- name: NEO4J_AUTH
valueFrom:
secretKeyRef:
name: neo4j-secret-key
key: NEO4J_PASSWORD
resources:
limits:
cpu: "2"
memory: 4Gi
requests:
cpu: "1"
memory: 2Gi
readinessProbe:
httpGet:
path: /
port: 7474
initialDelaySeconds: 20
periodSeconds: 10
timeoutSeconds: 10
failureThreshold: 5
livenessProbe:
httpGet:
path: /
port: 7474
initialDelaySeconds: 60
periodSeconds: 10
timeoutSeconds: 10
failureThreshold: 5
volumeMounts:
- name: neo4j-volume
mountPath: /data
5. Service
내부 통신을 위해 k8s-service.yml 파일을 작성합니다.
apiVersion: v1
kind: Service
metadata:
name: neo4j-service
spec:
type: ClusterIP
selector:
app: neo4j
ports:
- port: 7474
targetPort: 7474
name: http
- port: 7687
targetPort: 7687
name: bolt
6. Ingress
외부 접근을 위해 k8s-ingress.yml 파일을 작성합니다.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: neo4j-ingress
spec:
rules:
- host: "neo4j.your-domain.com"
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: neo4j-service
port:
number: 7474