인프라 입문기 - Kubernetes

kim unknown·2025년 1월 10일
0

Infra

목록 보기
2/2
post-thumbnail

1. 쿠버네티스 개념

쿠버네티스는 컨테이너 런타임을 통해 컨테이너를 다루는 도구를 말한다. 여러 서버에 컨테이너를 분산 배치하거나 문제가 생긴 컨테이너를 교체하는 등의 일을 해주며, 이를 컨테이너 오케스트레이션이라고 한다.

  • Pod
    Kubernetes의 기본 실행 단위이다.
    하나 이상의 컨테이너로 구성되며, 같은 네트워크 환경에서 실행된다.
    각 Pod는 자체 IP 주소를 가지며, 컨테이너들 간의 내부 통신이 가능하다.

  • Service
    Pod들을 외부와 연결하거나 클러스터 내에서 접근할 수 있게 한다.
    로드 밸런싱, 서비스 디스커버리 등을 제공하여 여러 Pod들을 단일 IP로 묶어 관리한다.

  • Deployment
    애플리케이션의 상태를 정의하고, 업데이트를 관리한다.
    애플리케이션의 버전 관리와 자동 롤백, 확장 등을 지원한다.

  • ReplicaSet
    특정 수의 Pod 복제본을 항상 유지하기 위해 사용한다.
    Deployment에 의해 관리되며, Pod의 수를 자동으로 조정한다.

  • Namespace
    클러스터 내에서 리소스를 논리적으로 분리할 수 있는 방법이다.
    여러 환경에서 동일한 리소스 이름을 사용하면서도 충돌을 방지할 수 있다.

  • Node
    Kubernetes 클러스터 내에서 애플리케이션을 실행하는 서버이다.
    각 Node는 컨테이너를 실행할 수 있는 하나 이상의 Kubelet 프로세스를 실행하고 있다.

  • Ingress
    외부 HTTP/HTTPS 요청을 클러스터 내부 서비스로 라우팅하는 규칙을 정의한다.
    일반적으로 로드 밸런서와 함께 사용되며, URL 경로 기반으로 요청을 처리할 수 있다.

  • ConfigMap과 Secret
    애플리케이션에 대한 설정 정보를 저장하는 방법입니다.
    ConfigMap은 텍스트 기반 설정 정보를, Secret은 암호화된 민감한 정보를 저장합니다.

장점

  • 자동화: 컨테이너의 배포, 확장, 복구를 자동으로 처리한다.
  • 확장성: 애플리케이션의 요구 사항에 맞게 클러스터 리소스를 동적으로 확장할 수 있다.
  • 자원 최적화: 클러스터 내 리소스를 효율적으로 분배하고, 여러 애플리케이션을 격리하여 실행할 수 있다.
  • 운영 간소화: 상태 관리, 모니터링, 로깅 등을 중앙에서 처리할 수 있어 운영 효율성이 높다.

2. 쿠버네티스 실습


2-0. 미니 쿠베 명령어

# 미니쿠베 시작 (단일노드)
minikube start
minikube start -n 2 # 다중노드
minikube start --driver=docker # 도커를 가상 드라이버로 설정
minikube start -p helloworld # helloworld라는 이름의 프로필로 생성

# 미니쿠베 프로필 목록 확인
minikube profile list

# 현재 사용중인 프로필 확인
minikube profile

# 프로필 변경
minikube profile helloworld # helloword로 변경

# 미니쿠베 상태 확인
minikube status

# 미니쿠베 일시정지
minikube pause

# 미니쿠베 종료
minikube stop

# 미니쿠베 삭제
minikube delete # 미니쿠베 삭제하기

2-1. 미니쿠베 설치 및 시작하기


(1). 미니쿠베 설치

> brew install minikube

==> Auto-updating Homebrew...
Adjust how often this is run with HOMEBREW_AUTO_UPDATE_SECS or disable with
HOMEBREW_NO_AUTO_UPDATE. Hide these hints with HOMEBREW_NO_ENV_HINTS (see `man brew`).
.
.
.
==> minikube
zsh completions have been installed to:
  /opt/homebrew/share/zsh/site-functions

(2). 미니쿠베 실행

> minikube start
>
😄  Darwin 15.2 (arm64) 의 minikube v1.34.0
✨  자동적으로 docker 드라이버가 선택되었습니다
📌  Using Docker Desktop driver with root privileges
👍  Starting "minikube" primary control-plane node in "minikube" cluster
🚜  Pulling base image v0.0.45 ...
💾  쿠버네티스 v1.31.0 을 다운로드 중 ...
    > preloaded-images-k8s-v18-v1...:  307.61 MiB / 307.61 MiB  100.00% 21.89 M
    > gcr.io/k8s-minikube/kicbase...:  441.45 MiB / 441.45 MiB  100.00% 12.76 M
🔥  Creating docker container (CPUs=2, Memory=7789MB) ...
🐳  쿠버네티스 v1.31.0 을 Docker 27.2.0 런타임으로 설치하는 중
    ▪ 인증서 및 키를 생성하는 중 ...
    ▪ 컨트롤 플레인을 부팅하는 중 ...
    ▪ RBAC 규칙을 구성하는 중 ...
🔗  bridge CNI (Container Networking Interface) 를 구성하는 중 ...
🔎  Kubernetes 구성 요소를 확인...
    ▪ Using image gcr.io/k8s-minikube/storage-provisioner:v5
🌟  애드온 활성화 : storage-provisioner, default-storageclass
🏄  끝났습니다! kubectl이 "minikube" 클러스터와 "default" 네임스페이스를 기본적으로 사용하도록 구성되었습니다.

# 실행 상태 확인
> minikube status
>
minikube
type: Control Plane
host: Running
kubelet: Running
apiserver: Running
kubeconfig: Configured

(3). 미니쿠베 프로필 설정

# 기존 실행 중인 미니쿠베 종료
> minikube stop
>"minikube" 노드를 중지하는 중 ...
🛑  "minikube"를 SSH로 전원을 끕니다 ...
🛑  1개의 노드가 중지되었습니다.

# testProfile 이라는 이름의 프로필 생성 및 시작
> minikube start -p testProfile
>
😄  [testProfile] Darwin 15.2 (arm64) 의 minikube v1.34.0
✨  자동적으로 docker 드라이버가 선택되었습니다
📌  Using Docker Desktop driver with root privileges
👍  Starting "testProfile" primary control-plane node in "testProfile" cluster
🚜  Pulling base image v0.0.45 ...
🔥  Creating docker container (CPUs=2, Memory=7789MB) ...
🐳  쿠버네티스 v1.31.0 을 Docker 27.2.0 런타임으로 설치하는 중
    ▪ 인증서 및 키를 생성하는 중 ...
    ▪ 컨트롤 플레인을 부팅하는 중 ...
    ▪ RBAC 규칙을 구성하는 중 ...
🔗  bridge CNI (Container Networking Interface) 를 구성하는 중 ...
🔎  Kubernetes 구성 요소를 확인...
    ▪ Using image gcr.io/k8s-minikube/storage-provisioner:v5
🌟  애드온 활성화 : storage-provisioner, default-storageclass
🏄  끝났습니다! kubectl이 "testProfile" 클러스터와 "default" 네임스페이스를 기본적으로 사용하도록 구성되었습니다.

# 생성된 프로필 리스트 확인
>  minikube profile list
>
|-------------|-----------|---------|--------------|------|---------|---------|-------|----------------|--------------------|
|   Profile   | VM Driver | Runtime |      IP      | Port | Version | Status  | Nodes | Active Profile | Active Kubecontext |
|-------------|-----------|---------|--------------|------|---------|---------|-------|----------------|--------------------|
| minikube    | docker    | docker  | ---.---.--.- | 8443 | v1.31.0 | Stopped |     1 | *              |                    |
| testProfile | docker    | docker  | ---.---.--.- | 8443 | v1.31.0 | Running |     1 |                | *                  |
|-------------|-----------|---------|--------------|------|---------|---------|-------|----------------|--------------------|

# 프로필 변경
> minikube profile minikube
> ✅  minikube profile was successfully set to minikube

2-2. 도커 이미지 배포하기


(1). deployment.yaml 파일 작성

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-web
spec:
  replicas: 1
  selector:
    matchLabels:
      app: my-web
  template:
    metadata:
      labels:
        app: my-web
    spec:
      containers:
        - name: my-web
          image: my-web:1.0
          ports:
            - containerPort: 3000
---
apiVersion: v1
kind: Service
metadata:
  name: my-web-service
spec:
  selector:
    app: my-web
  ports:
    - protocol: TCP
      port: 80
      targetPort: 3000
  type: NodePort

(2). 미니쿠베 이미지 업로드

  • 미니쿠베 활성화 : eval $(minikube docker-env)
# 미니쿠베 도커 활성화
> eval $(minikube docker-env)

# 도커 이미지 빌드
> docker build -t my-web:1.0 .
> [+] Building 19.2s (12/12) FINISHED     

# 이미지 전송
> minikube image load my-web:1.0

# kubectl 컨텍스트 확인
> kubectl config current-context
> minikube

# 컨텍스트가 미니쿠베가 아니라면 미니쿠베로 변경 필요
> kubectl config use-context minikube

# 쿠버네티스 배포
> kubectl apply -f deployment.yaml
> 
deployment.apps/my-web created
service/my-web-service created

(3). 배포 확인

  • 미니쿠베 리소스 확인 : kubectl get all
# minikube 리소스 확인
> kubectl get all
>
NAME                            READY   STATUS             RESTARTS   AGE
pod/my-web-57bc889df4-zc84r     0/1     ImagePullBackOff   0          29m

NAME                       TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
service/my-web-service     NodePort    10.101.36.165   <none>        80:32136/TCP   29m
service/kubernetes         ClusterIP   10.96.0.1       <none>        443/TCP        163m

NAME                       READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/my-web     0/1     1            0           29m

NAME                                  DESIRED   CURRENT   READY   AGE
replicaset.apps/my-web-57bc889df4     1         1         0       29m

2-3. 외부에서 접근할 수 있도록 설정


(1). service.yaml 파일 생성 - nodePort 설정

Node Port는 외부에서 접근할 수 있도록 포트를 개방한다. Node Port를 사용하면 외부에서 지정된 포트를 통해 서비스에 접속할 수 있다.

apiVersion: v1
kind: Service
metadata:
  name: my-web-service
spec:
  type: NodePort
  selector:
    app: my-web
  ports:
    - protocol: TCP
      port: 8080        # 외부에서 접근할 기본 포트
      targetPort: 3000  # 컨테이너의 포트
      nodePort: 30001   # 외부에서 접근할 NodePort (범위: 30000-32767)

(2). deployment / service 배포

  • deployment 반영 : kubectl apply -f deployment.yaml
  • service 반영 : kubectl apply -f service.yaml
> kubectl apply -f deployment.yaml
> deployment.apps/my-web created

> kubectl apply -f service.yaml
> service/my-web-service configured

(3). 서비스 접근

http://<Minikube IP>:<NodePort> url로 접근 가능하게 된다

  • pod 상태 확인 : kubectl get pods
# Pod 상태 확인. Running으로 표시되어야 정상 실행중인 것
> kubectl get pods
>
NAME                        READY   STATUS    RESTARTS   AGE
my-web-78f96cb845-8fhlw     1/1     Running   0          12s

# 미니쿠베 ip 확인
> minikube ip
> 192.168.49.2

# service 확인. 접근 가능 url 출력
> minikube service my-web-service
>
|-----------|------------------|-------------|---------------------------|
| NAMESPACE |       NAME       | TARGET PORT |            URL            |
|-----------|------------------|-------------|---------------------------|
| default   |  my-web-service  |        8080 | http://192.168.49.2:30001 |
|-----------|------------------|-------------|---------------------------|
🏃  my-web-service 서비스의 터널을 시작하는 중
|-----------|------------------|-------------|------------------------|
| NAMESPACE |       NAME       | TARGET PORT |          URL           |
|-----------|------------------|-------------|------------------------|
| default   |  my-web-service  |             | http://127.0.0.1:64487 |
|-----------|------------------|-------------|------------------------|
🎉  Opening service default/my-web-service in default browser...
❗  darwin 에서 Docker 드라이버를 사용하고 있기 때문에, 터미널을 열어야 실행할 수 있습니다

(4). 그 외

  • deployment 확인 : kubectl get deployment
  • pod 로그 확인 : kubectl describe pod <POD_NAME>
  • 서비스 삭제 : kubectl delete service city-web-service
  • 쿠버네티스 모든 리소스 삭제 : kubectl delete all --all
# deployment 확인
> kubectl get deployment
>
NAME       READY   UP-TO-DATE   AVAILABLE   AGE
my-web     1/1     1            1           15m

# pod 로그 확인
> kubectl describe pod my-web-57bc889df4-lh2dh
>
Name:             my-web-57bc889df4-lh2dh
Namespace:        default
Priority:         0
Service Account:  default
Node:             minikube/192.168.49.2
Start Time:       Mon, 30 Dec 2024 10:57:12 +0900
Labels:           app=my-web
                  pod-template-hash=57bc889df4
Annotations:      <none>
Status:           Pending
IP:               10.244.0.7
IPs:
  IP:           10.244.0.7
Controlled By:  ReplicaSet/my-web-57bc889df4
Containers:
  my-web:
    Container ID:   
    Image:          my-web:1.0
    Image ID:       
    Port:           3000/TCP
    Host Port:      0/TCP
    State:          Waiting
      Reason:       ImagePullBackOff
    Ready:          False
    Restart Count:  0
    Environment:    <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-wlpqw (ro)
.
.
.
Events:
  Type     Reason     Age                  From               Message
  ----     ------     ----                 ----               -------
  Normal   Scheduled  2m20s                default-scheduler  Successfully assigned default/my-web-57bc889df4-lh2dh to minikube
  Normal   Pulling    41s (x4 over 2m20s)  kubelet            Pulling image "my-web:1.0"
  Warning  Failed     39s (x4 over 2m17s)  kubelet            Failed to pull image "my-web:1.0": Error response from daemon: pull access denied for my-web, repository does not exist or may require 'docker login': denied: requested access to the resource is denied
  Warning  Failed     39s (x4 over 2m17s)  kubelet            Error: ErrImagePull
  Warning  Failed     25s (x6 over 2m17s)  kubelet            Error: ImagePullBackOff
  Normal   BackOff    13s (x7 over 2m17s)  kubelet            Back-off pulling image "my-web:1.0"

2-4. Port Forwarding

Port Forwarding은 로컬 머신에서 쿠버네티스 Pod으로 트래픽을 포워딩하는 방법이다. 외부에서 서비스에 바로 접근할 수 없고 개발 환경에 사용한다.

항목NodePortPort Forwarding
접속 범위외부에서 접근 가능로컬 머신에서만 접속 가능
설정 위치service.yaml 파일에 포트(NodePort) 지정kubectl port-forward 명령어로 설정
용도프로덕션 환경, 다른 시스템에서 접근할 때 사용개발 및 테스트 환경에서 임시로 연결할 때 사용

(1). Port Forwarding 설정

  • 포트포워딩 :kubectl port-forward pod/<POD_NAME> <LOCAL_PORT>:<POD_PORT>
> kubectl port-forward pod/my-web-78f96cb845-8fhlw 8080:3000
>
Forwarding from 127.0.0.1:8080 -> 3000
Forwarding from [::1]:8080 -> 3000
Handling connection for 8080
Handling connection for 8080
Handling connection for 8080
...

(2). 서비스 접근

http://localhost:<LOCAL_PORT> 로 접근 가능하다.


2-5. Volume

볼륨 : pod 내의 컨테이너에서 데이터를 저장하거나 공유할 수 있도록 하는 스토리지

컨테이너는 일시적인 파일 시스템을 사용하므로, 컨테이너가 재시작되거나 삭제되면 데이터가 사라진다. 이러한 문제를 해결하기 위해 볼륨을 사용한다.

볼륨 특징

  • pod 내의 여러 컨테이너에서 동시에 접근할 수 있다. 이를 통해 컨테이너 간 데이터 공유가 가능하다.
  • 볼륨은 pod의 라이프사이클 동안 유지가 된다. 데이터 영속성을 제공한다.

볼륨 주요 타입

  • EmptyDir
    pod이 실행되는 동안에만 존재하는 임시 볼륨이다. 여러 컨테이너가 데이터를 공유해야하는 경우에 사용한다. pod이 삭제되면 데이터도 함께 삭제된다.
    volumes:
    - name: my-empty-dir
      emptyDir: {}
  • hostPath
    노드의 특정 디렉토리를 pod에 마운트한다. 로컬 파일 시스템 접근이 필요한 경우에 사용한다. 호스트 의존적이므로 클러스터 간 이식성이 떨어진다.
    volumes:
    - name: my-host-path
      hostPath:
        path: /path/on/host
        type: Directory
  • persistentVolumeClaim (PVC)
    PV와 연동하여 스토리지를 동적으로 할당받는다. 클라우드 스토리지나 네트워크 파일 시스템 사용 시에 사용한다. 데이터가 pod의 라이프사이클과 독립적으로 유지된다.
    volumes:
    - name: my-pvc
      persistentVolumeClaim:
        claimName: my-pvc

(1). 로컬 디렉토리 생성

mkdir -p /Users/unknown/k8sData


(2). 컨테이너 내 디렉토리 탐색

# 실행 중인 컨테이너 확인
> docker ps
>
CONTAINER ID   IMAGE                                 COMMAND                   CREATED      STATUS        PORTS                                                                                                                                  NAMES
73b86b6b2209   gcr.io/k8s-minikube/kicbase:v0.0.45   "/usr/local/bin/entr…"   3 days ago   Up 24 hours   127.0.0.1:55674->22/tcp, 127.0.0.1:55675->2376/tcp, 127.0.0.1:55677->5000/tcp, 127.0.0.1:55678->8443/tcp, 127.0.0.1:55676->32443/tcp   minikube

# 컨테이너 쉘 실행
> docker exec -it 73b86b6b2209 /bin/bash

# 내부 경로 확인
> ls /
CHANGELOG  Release.key  bin  boot  data  dev  docker.key  etc  home  kic.txt  kind  lib  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var  version.json
> ls /mnt
> data

(3). 로컬 디렉토리를 VM에 마운트

로컬의 /Users/unknown/k8sData 디렉토리를 컨테이너 /mnt/data로 마운트

> minikube mount /Users/unknown/k8sData:/mnt/data
>
📁  Mounting host path /Users/unknown/k8sData into VM as /mnt/data ...
    ▪ Mount type:   9p
    ▪ User ID:      docker
    ▪ Group ID:     docker
    ▪ 버전:      9p2000.L
    ▪ 메시지 사이즈: 262144
    ▪ 옵션:      map[]
    ▪ 연결된 주소: 127.0.0.1:51567
🚀  Userspace file server: ufs starting
✅  Successfully mounted /Users/unknown/k8sData to /mnt/data

(4). deployment 파일 수정

hostPath 볼륨을 사용하여 /Users/unknown/k8sData 로컬 디렉토리를 컨테이너 내 /app/data 경로에 마운트

	containers:
          volumeMounts:
            - mountPath: /mnt/data  # 컨테이너 내 경로
              name: my-web-volume
      volumes:
        - name: my-web-volume
          hostPath:
            path: /mnt/data  # Minikube VM에서 마운트된 경로
            type: Directory

(5). deployment 적용

수정한 deployment.yaml 파일을 쿠버네티스 클러스터에 적용하여 pod을 배포한다.

명령어 실행 시 쿠버네티스 클러스터 내에 pod이 생성되고, hostPath 볼륨이 설정되어 로컬 PC의 /Users/unknown/k8sData 디렉토리와 컨테이너의 /app/data 경로가 연결된다.

> kubectl apply -f deployment.yaml
> deployment.apps/my-web configured

2-6. replicas 적용


(1). deployment 수정

    # deployment.yaml
    
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: my-web
    spec:
      replicas: 2  # replicas 2
      selector:
        matchLabels:
          app: my-web
      template:
        metadata:
          labels:
            app: my-web
        spec:
          containers:
            - name: my-web
              image: my-web:1.0
              imagePullPolicy: Never
              ports:
                - containerPort: 3000
              volumeMounts:
                - mountPath: /mnt/data 
                  name: my-web-volume
          volumes:
            - name: my-web-volume
              hostPath:
                path: /mnt/data 
                type: Directory

(2). 수정한 deployment 적용

> kubectl apply -f deployment.yaml
> deployment.apps/my-web configured

(3). pod이 2개로 유지 실행되는지 확인

# pod이 2개 실행되고 있는지 확인 (status: Running이어야 정상 실행중)
> kubectl get pods
>                
NAME                        READY   STATUS    RESTARTS   AGE
my-web-54677cd5f6-ffftd     1/1     Running   0          8s
my-web-54677cd5f6-ht6fm     1/1     Running   0          8s

# pod 하나 죽여보기
> kubectl delete pod my-web-54677cd5f6-ffftd
> pod "my-web-54677cd5f6-ffftd" deleted

# 새로운 pod이 자동으로 생성되는지 확인
> kubectl get pods
>
NAME                        READY   STATUS    RESTARTS   AGE
my-web-54677cd5f6-bchbh     1/1     Running   0          4s
my-web-54677cd5f6-ht6fm     1/1     Running   0          5m37s
profile
과거의 나에게 묻기 위한 기록

0개의 댓글