카테고리 없음

2. Minikube 로컬 개발 및 학습용

꼰대코더 2026. 5. 9. 10:44

일단 간단하게 1개 PC(단일 노드(Single Node) 구조)에서의 Kubernetes를 체험해 보자.
※ Minikube는 보통 노드가 1개뿐입니다. 내 PC가 꺼지거나 Minikube 프로세스에 문제가 생기면 서비스 전체가 중단됩니다. (고가용성 부족)

 

Node

  • 정의: 쿠버네티스가 돌아가는 하나의 작업 서버 (물리 PC 또는 가상 머신).
  • 클러스터는 이러한 노드들의 집합을 의미합니다. 
  • IP: 실제 PC의 IP(Host IP)를 사용하지만, Minikube 같은 가상 환경에서는 별도의 가상 IP(예: 192.168.49.2)가 할당됩니다
  • NodePort: 외부 접속을 위한 문 번호입니다. 직접 지정하지 않으면 30000~32767 범위에서 자동 할당됩니다.
  • 접속: 브라우저에서 http://[노드 IP]:[NodePort]로 접속합니다.

Service :  frontend / redis-leader / redis-follower

  • 역할: 여러 개의 Pod를 하나로 묶어주는 고정된 관문이자 로드 밸런서.
  • YAML의 selector 항목에 적힌 라벨과 Pod의 labels가 일치하는 것들을 서비스가 묶어서 관리합니다.
  • 고정 IP: 클러스터 내부용 Virtual(Cluster) IP를 가집니다. Pod가 죽어서 IP가 바뀌어도 서비스 IP는 변하지 않습니다.
  • 포트: port: 80은 서비스 자체가 내부에서 사용하는 포트입니다.

Pod : frontend pod / redis-leader pod / redis-follower pod

  • 정의: 실제 앱(컨테이너)이 실행되는 단위. 주로 Docker 이미지 형태입니다.
  • 관리: Deployment 설정을 통해 실행 개수가 유지되며, Pod가 죽으면 자동으로 새 Pod가 생성(Self-healing)됩니다.
  • IP: 생성될 때마다 새로운 내부 IP를 부여받는 휘발성 주소입니다.
  • 포트: targetPort: 80은 실제 앱이 컨테이너 내부에서 열고 있는 포트입니다.

통신 원리 (중요)

  • 내부 통신: Pod끼리 통신할 때는 상대방 서비스의 이름을 사용합니다. (예: http://redis-leader).
  • DNS 역할: 쿠버네티스 내부 DNS가 서비스 이름을 고정된 Virtual IP로 해석하여 전달합니다.
  • 흐름: 외부 사용자 → Node IP:NodePort → Service(VIP):Port → Pod:TargetPort.

 

Minikube 설치 (로컬PC에서 kubernetes의 개념을 잡고 테스트하는 용도)

# docker 설치
sudo apt update
sudo apt install -y docker.io
sudo usermod -aG docker $USER

# Minikube 설치
curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
sudo install minikube-linux-amd64 /usr/local/bin/minikube

# kubectl (kubernetes와 소통하는 CLI 툴) 설치
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
sudo install kubectl /usr/local/bin/kubectl

 

클러스터 시작과 확인

minikube start --driver=docker
kubectl cluster-info
kubectl get nodes

 

guestbook.yaml 화일 생성 ※ 복수의 yaml 을 하나의 yaml 내에 "---" 를 사용해 분리 통합

# Redis leader (primary)
apiVersion: apps/v1
kind: Deployment
metadata:
  name: redis-leader
spec:
  replicas: 1
  selector:
    matchLabels:
      app: redis
      role: leader
  template:
    metadata:
      labels:
        app: redis
        role: leader
    spec:
      containers:
      - name: redis
        image: redis:7
        ports:
        - containerPort: 6379
---
apiVersion: v1
kind: Service
metadata:
  name: redis-leader
spec:
  selector:
    app: redis
    role: leader
  ports:
  - port: 6379
    targetPort: 6379
---
# Redis followers (replicas)
apiVersion: apps/v1
kind: Deployment
metadata:
  name: redis-follower
spec:
  replicas: 2
  selector:
    matchLabels:
      app: redis
      role: follower
  template:
    metadata:
      labels:
        app: redis
        role: follower
    spec:
      containers:
      - name: redis
        image: gcr.io/google_samples/gb-redisslave:v3
        ports:
        - containerPort: 6379
---
apiVersion: v1
kind: Service
metadata:
  name: redis-follower
spec:
  selector:
    app: redis
    role: follower
  ports:
  - port: 6379
    targetPort: 6379
---
# Frontend web app
apiVersion: apps/v1
kind: Deployment
metadata:
  name: frontend
spec:
  replicas: 3
  selector:
    matchLabels:
      app: guestbook
  template:
    metadata:
      labels:
        app: guestbook
    spec:
      containers:
      - name: guestbook
        image: gcr.io/google_samples/gb-frontend:v5
        ports:
        - containerPort: 80
        env:
        - name: GET_HOSTS_FROM
          value: "dns"
---
apiVersion: v1
kind: Service
metadata:
  name: frontend
spec:
  type: NodePort
  selector:
    app: guestbook
  ports:
  - port: 80
    targetPort: 80
  • Deployment  직원을 채용하고 관리하는 인사팀
                           -> "이 업무를 할 직원 3명을 유지해라"
                           -> "직원이 퇴사하면 새로 채용한다"
    kind: Deployment           # "앱 실행 관리자를 만들겠다"
    metadata:
            name: redis-leader # "이름은 redis-leader이다" 
    spec:
            replicas: 1               # "Pod 1개를 유지해라"
    template:                        # "이 설계도로 Pod를 만들어라"
            spec:
                containers:
                - image: redis:7   # "redis:7 이미지를 실행해라"
  • Service  고객이 전화하는 대표번호
                   -> 대표번호는 항상 같다 (고정 DNS/IP)
                   -> 전화하면 근무 중인 직원 중 한 명에게 연결된다 (로드밸런싱) 
                   -> 직원이 바뀌어도 대표번호는 그대로다 (Pod 변경에 무관)

    kind: Service                    # "네트워크 접속 창구를 만들겠다"
    metadata:
             name: redis-leader  # "이 창구의 이름은 redis-leader이다"
    spec:
             selector:
                 app: redis            # "app=redis, role=leader 라벨을 가진
                 role: leader          # Pod로 연결해라"
             ports:
             - port: 6379              # "6379 포트로 요청을 받아라"
               targetPort: 6379     # "받은 요청을 Pod의 6379 포트로 전달해라"
  • Deployment 와 Service 에 기술되어 있는 selector 의 의미는 자신이 관리하는 Pod의 식별자
    Deployment는  replicas 설정숫자의 Pod를 생성하고 감시해야 하기 때문에 그 Pod의 식별자가 필요
    Service는 로드밸랜싱을 하기위해 관리하는 Pod의 식별자가 필요
  • Deployment 에만 정의되어 있는 template labels 의 의미는 Pod생성시에 자신에 붙이는 식별자
    예)  Pod는 redis-leader-abc-123 /  redis-leader-abc-124 와 같이 레벨을 가지고 생성
           그러면 Deployment 와 Service는 자신이 관리하는 Pod를 redis-leader로 식별

 

# 적용
kubectl apply -f guestbook.yaml

# pods의 생성, 실시간 스케쥴링 보기
kubectl get pods -w

# 생성된 모든 리소스 보기
kubectl get all

# 앱 액세스
minikube service frontend

 

오케스트레이션 행동 테스트

# 자체 힐링
# pods 리스크
kubectl get pods

# 특정 pod 삭제
kubectl delete pod frontend-xxxxx-xxxxx

# 즉시 새로운 pod가 대체되는 것 보기
kubectl get pods -w

# 스케일링
# frontend 를 3개에서 5개로 늘리기
kubectl scale deployment frontend --replicas=5

# 늘려진 pod들 보기
kubectl get pods -w

# 2개로 줄이기
kubectl scale deployment frontend --replicas=2
kubectl get pods -w

# 업데이트
# frontend image 업데이트(v5에서 v4로 다운그레이딩)
kubectl set image deployment/frontend guestbook=gcr.io/google_samples/gb-frontend:v4

# 업데이트 보기
kubectl rollout status deployment/frontend

# 롤백(다시 되돌리기)
kubectl rollout undo deployment/frontend
kubectl rollout status deployment/frontend

# 제거
kubectl delete -f guestbook.yaml
minikube stop