도커와 K8S 요약 정리

david1-p·2025년 11월 1일

CS 지식 창고

목록 보기
16/26
post-thumbnail

[2025년 기준] 도커(Docker)와 쿠버네티스(Kubernetes) 핵심 요약


1. 도커 (Docker)

도커란?

도커는 애플리케이션을 컨테이너라는 격리된 환경에 패키징하여 실행하는 기술 및 플랫폼입니다. 컨테이너에는 애플리케이션 실행에 필요한 모든 환경(코드, 라이브러리, 설정)이 포함되어 있어, "제 PC에서는 됐는데..." 하는 문제를 원천적으로 해결합니다.

도커 사용법은 크게 도커 이미지를 다루는 것과 컨테이너를 다루는 것으로 나뉩니다.

도커 이미지 (Docker Image)

도커 이미지는 컨테이너를 실행하기 위한 읽기 전용 템플릿입니다.

  • 운영 체제의 최소한의 파일 시스템 (예: Alpine Linux)
  • 애플리케이션 소스 코드 및 바이너리
  • 애플리케이션 실행에 필요한 의존성(라이브러리, 도구)
  • 실행 환경 설정 정보 (예: 어떤 명령어로 앱을 시작할지)

이 모든 것을 포함하는 아카이브입니다. 이미지를 만드는 과정을 빌드(build)라고 하며, 컨테이너는 이 빌드된 이미지를 기반으로 실행됩니다.

주요 이미지 명령어

1. docker image build - 이미지 빌드

  • `-t: 이미지명과 태그(버전)를 지정합니다. '.'은 현재 디렉터리의 Dockerfile을 사용하라는 의미입니다.
    ex) docker image build -t 내이미지명:태그명 .

  • -f: 특정 파일명을 가진 Dockerfile을 지정할 수 있습니다.

  • --pull: 빌드 시 캐시된 베이스 이미지를 사용하지 않고, 레지스트리에서 항상 새로 받아옵니다. (최신 보안 패치 적용 시 유용)

2. docker image pull - 이미지 내려받기 (레지스트리에서 로컬로)

3. docker image ls - 로컬에 보유한 도커 이미지 목록 보기

4. docker image tag - 이미지에 추가 태그 붙이기 (예: my-image:latest -> my-image:v1.0)

5. docker image push - 이미지를 외부 레지스트리(예: Docker Hub)에 공개(업로드)하기

🚫 docker search 명령어에 대한 주의

CLI의 docker search 명령어는 사용이 권장되지 않습니다. 보안이 검증되지 않은 이미지가 많고 신뢰도를 파악하기 어렵습니다.

(모범 사례): Docker Hub, GCR, ECR 등 신뢰할 수 있는 웹 레지스트리에서 'Official Image' 또는 'Verified Publisher' 배지가 붙은 이미지를 검색하여 사용합니다.


도커 컨테이너 (Docker Container)

컨테이너는 도커 이미지를 실행한 인스턴스입니다. 이미지는 템플릿(설계도)이고, 컨테이너는 그 설계도로 만든 실제 동작하는 개체(집)입니다.

컨테이너의 생애 주기 (Lifecycle)

1) 실행 중 (Running)
docker container run 명령으로 이미지를 기반으로 컨테이너가 생성된 상태입니다. Dockerfile의 CMDENTRYPOINT에 정의된 애플리케이션이 실행됩니다.

2) 정지 (Stopped)
사용자가 명시적으로 정지(stop)시키거나, 컨테이너의 메인 애플리케이션이 종료되면 컨테이너는 '정지' 상태가 됩니다. 가상 환경은 동작하지 않지만, 종료 시점의 상태(데이터 변경분)가 디스크에 저장됩니다.

3) 파기 (Destroyed)
rm 명령 등으로 파기된 상태입니다. 한 번 파기한 컨테이너는 다시 실행할 수 없습니다.

주요 컨테이너 명령어

  • docker container run: 이미지로부터 컨테이너를 생성하고 실행합니다.
  • docker container ls: 실행 중인 컨테이너 목록 보기 (-a 옵션으로 정지된 것 포함)
  • docker container stop: 컨테이너를 정지합니다.
  • docker container restart: 컨테이너를 재시작합니다.
  • docker container rm: 컨테이너를 파기합니다.
  • docker container logs: 컨테이너의 표준 출력을 확인합니다. (-f 옵션으로 실시간 추적)
  • docker container exec: 실행 중인 컨테이너에서 추가 명령을 실행합니다. (예: exec -it [이름] /bin/bash)
  • docker container cp: 호스트와 컨테이너 간 파일을 복사합니다.

리소스 정리 명령어

  • docker container prune: 실행 중이 아닌 모든 컨테이너를 삭제합니다.
  • docker image prune: 태그가 붙지 않은(dangling) 모든 이미지를 삭제합니다.
  • docker system prune: 사용하지 않는 컨테이너, 이미지, 볼륨, 네트워크 등 모든 도커 리소스를 일괄 삭제합니다.

Docker Compose (v2)

docker compose여러 컨테이너로 구성된 애플리케이션을 정의하고 실행하기 위한 도구입니다. (2019년의 docker-compose v1과 달리, 현재는 Docker CLI에 docker compose v2로 통합되었습니다.)

docker-compose.yml 파일 하나로 웹 서버, 데이터베이스, 캐시 서버 등을 한꺼번에 관리할 수 있습니다.

  • docker compose up: yml 파일에 정의된 모든 컨테이너를 생성하고 시작합니다. (-d로 백그라운드 실행)
  • docker compose down: yml 파일로 생성된 컨테이너, 네트워크, 볼륨을 중지하고 삭제합니다.
  • docker compose ps: 현재 compose로 실행 중인 컨테이너 상태를 봅니다.
  • docker compose logs -f: 모든 컨테이너의 로그를 실시간으로 봅니다.

(참고): 최신 docker-compose.yml 파일은 상단에 version: "3.x" 선언이 필수가 아닙니다.



2. 쿠버네티스 (Kubernetes)

쿠버네티스란?

쿠버네티스(K8s)는 컨테이너 오케스트레이션 도구입니다. "오케스트레이션"이란, 수십, 수백 개의 컨테이너를 대규모 프로덕션 환경에서 안정적으로 운영(배포, 스케일링, 복구)하는 작업을 자동화하는 것을 의미합니다.

  • 주요 기능:
    • 서비스 디스커버리 및 로드 밸런싱: 컨테이너에 고유한 IP와 DNS 이름을 부여하고, 트래픽을 분산합니다.
    • 자동화된 롤아웃 및 롤백: 새 버전 배포 시 문제 생기면 자동으로 이전 버전으로 롤백합니다.
    • 자동화된 빈 패킹(Bin Packing): 컨테이너가 필요한 리소스(CPU, Mem)를 계산하여 최적의 서버(노드)에 배치합니다.
    • 자가 치유 (Self-healing): 실행 중이던 컨테이너가 죽으면 자동으로 재시작하거나 교체합니다.
    • 스케일링: 필요에 따라 컨테이너 개수를 자동으로 늘리거나 줄입니다.

(중요) 쿠버네티스와 도커의 관계 (2025년 기준)

과거에는 쿠버네티스가 도커 데몬을 직접 제어(Dockershim 경유)했지만, K8s v1.24 (2022년)부터 Dockershim이 완전히 제거되었습니다.

  • 현재: 쿠버네티스는 CRI(Container Runtime Interface)라는 표준을 따르는 런타임과 통신합니다. 대표적으로 containerdCRI-O가 있습니다.
  • 결론: 개발자는 docker build로 이미지를 만들 수 있습니다. 이 이미지는 CRI 호환 런타임이라면 어디서든 실행 가능하며, 쿠버네티스는 이 이미지를 containerd를 이용해 실행합니다. (참고: 도커 데스크톱도 내부적으로 containerd를 사용합니다.)

쿠버네티스 핵심 리소스

쿠버네티스에서 다루는 모든 것을 '리소스'라고 부릅니다. 이 리소스들은 주로 yaml 매니페스트 파일로 정의됩니다.

리소스용도
노드 (Node)컨테이너가 배치되는 물리/가상 서버 (워커 머신)
네임스페이스 (Namespace)쿠버네티스 클러스터 안의 가상 클러스터 (논리적 분리)
파드 (Pod)K8s의 가장 작은 배포 단위. 하나 이상의 컨테이너 집합.
레플리카세트 (ReplicaSet)파드 복제본(Replica)의 개수를 항상 일정하게 유지.
디플로이먼트 (Deployment)(가장 중요) 배포의 기본 단위. 레플리카세트의 리비전(버전)을 관리하며 롤아웃/롤백 수행.
서비스 (Service)여러 파드에 대한 고정된 진입점(IP/DNS)을 제공. 로드 밸런싱 담당.
인그레스 (Ingress)L7 (HTTP/S). 클러스터 외부 요청을 내부 서비스로 연결 (경로/도메인 기반 라우팅)
Gateway API인그레스의 차세대 표준. 더 강력하고 유연한 L7 라우팅 제공.
컨피그맵 (ConfigMap)설정 정보를 Key-Value 형태로 저장하여 파드에 주입.
시크릿 (Secret)API 키, DB 패워드 등 기밀 정보를 Base64 인코딩하여 저장.
퍼시스턴트볼륨 (PV)파드가 사용할 영구 저장소(스토리지) 자체를 정의 (관리자)
퍼시스턴트볼륨클레임 (PVC)스토리지 사용 요청 (개발자)
스테이트풀세트 (StatefulSet)상태(state)를 가지는 파드(e.g., DB)를 위한 리소스. (고유 ID, 순차적 배포)
잡 (Job)일회성 작업을 실행하고 정상적인 종료를 보장.
크론잡 (CronJob)리눅스 Cron처럼 스케줄링(예: 매일 밤 12시)되는 잡.
PodSecurityAdmission (PSA)K8s의 내장 보안 표준. 파드가 특정 보안 수준(e.g., privileged 금지)을 준수하도록 강제.

파드 (Pod)

파드는 쿠버네티스에서 생성하고 관리할 수 있는 가장 작은 배포 단위이며, 하나 이상의 컨테이너로 이루어집니다.

  • 특징:
    • 같은 파드 안의 컨테이너는 같은 노드에 배치됩니다.
    • 네트워크와 스토리지(볼륨)를 공유합니다. (예: localhost로 통신 가능)
  • 활용 예:
    • (Sidecar 패턴) 메인 앱 컨테이너 + 로그 수집 컨테이너

(참고): 실무에서는 Pod를 직접 생성(Naked Pod)하는 경우는 드물며, DeploymentStatefulSet을 통해 관리하는 것이 표준입니다. Pod 매니페스트는 Deploymentspec.template 부분에서 핵심적인 역할을 합니다.

Pod 매니페스트 예시 (simple-pod.yaml)

apiVersion: v1
kind: Pod
metadata:
  name: simple-nginx-pod
  labels:
    app: webserver
spec:
  containers:
    - name: nginx-container
      image: nginx:latest
      ports:
        - containerPort: 80

배포 리소스 (Deployment, ReplicaSet)

레플리카세트 (ReplicaSet)

파드(kind: Pod)는 죽으면 그걸로 끝입니다. 고가용성을 위해 '레플리카세트'를 사용하면, 지정된 수만큼 파드의 개수를 항상 유지(self-healing)합니다.

디플로이먼트 (Deployment)

(핵심) 실제 운영에서는 레플리카세트를 직접 다루기보다, 그 상위 리소스인 '디플로이먼트'를 사용합니다. 디플로이먼트는 애플리케이션 배포의 표준 단위입니다.

디플로이먼트는 내부적으로 레플리카세트를 관리하며, 앱을 업데이트(롤링 업데이트)하거나 롤백하는 등 리비전(버전) 관리를 담당합니다.

Deployment 매니페스트 예시 (deployment.yaml)

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app-deployment
  labels:
    app: my-web-app
spec:
  replicas: 3 # 3개의 파드를 실행
  selector:
    matchLabels:
      app: my-web-app # 이 label을 가진 Pod를 찾아서 관리
  template: # <-- Pod 템플릿 (여기서 Pod를 정의)
    metadata:
      labels:
        app: my-web-app # Service가 이 label을 보고 파드를 찾음
    spec:
      containers:
        - name: my-app-container
          image: nginx:latest # 실제 사용할 컨테이너 이미지
          ports:
            - containerPort: 80

🌐 네트워크 리소스 (Service, Ingress, Gateway)

서비스 (Service)

'서비스'는 여러 파드 그룹에 접근할 수 있는 고유한 단일 진입점(Entrypoint)을 제공하는 리소스입니다. (내부 DNS 이름 및 고정 IP 제공)

1) ClusterIP (기본값)

  • 쿠버네티스 클러스터 내부 IP 주소에만 서비스를 공개합니다.
  • 클러스터 내의 다른 파드들이 서비스 이름(DNS)으로 접근할 때 사용됩니다.

Service (ClusterIP) 매니페스트 예시 (service-clusterip.yaml)

apiVersion: v1
kind: Service
metadata:
  name: my-app-clusterip-svc
spec:
  type: ClusterIP # 클러스터 내부 IP만 할당 (기본값)
  selector:
    # 'app: my-web-app' label을 가진 파드에 트래픽 전달
    # (위 Deployment 예시의 template.metadata.labels와 일치)
    app: my-web-app 
  ports:
    - protocol: TCP
      port: 80       # 서비스가 80번 포트로 노출됨
      targetPort: 80 # 파드의 80번 포트로 트래픽 전달

2) NodePort

  • ClusterIP의 기능을 포함하며, 추가로 모든 노드(Node)의 특정 포트를 개방합니다.
  • 외부에서 [노드 IP]:[NodePort]로 접근할 수 있게 됩니다. (주로 테스트용)

3) LoadBalancer

  • ClusterIP, NodePort의 기능을 포함합니다.
  • 클라우드 플랫폼(GCP, AWS 등)에서 제공하는 외부 로드 밸런서와 연동됩니다.

Service (LoadBalancer) 매니페스트 예시 (service-loadbalancer.yaml)

apiVersion: v1
kind: Service
metadata:
  name: my-app-loadbalancer-svc
spec:
  type: LoadBalancer # 클라우드 로드밸런서와 연동 (외부 노출용)
  selector:
    app: my-web-app # 'app: my-web-app' label을 가진 파드에 트래픽 전달
  ports:
    - protocol: TCP
      port: 80       # 로드밸런서의 80번 포트
      targetPort: 80 # 파드의 80번 포트로 트래픽 전달

인그레스 (Ingress) & 게이트웨이 API (Gateway API)

Service가 L4에서 동작하는 반면, Ingress는 L7(HTTP/S) 레벨에서 경로/도메인 기반 라우팅을 제공합니다. 최근에는 Ingress의 한계를 극복한 차세대 표준인 Gateway API의 사용이 증가하고 있습니다.

Ingress 매니페스트 예시 (ingress.yaml)

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-app-ingress
  annotations:
    # (예시) Nginx Ingress Controller를 사용할 경우
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
    - host: "myapp.example.com" # 이 도메인으로 오는 요청을 처리
      http:
        paths:
          - path: / # '/' 경로로 오는 모든 요청
            pathType: Prefix
            backend:
              service:
                # 위에서 만든 ClusterIP 서비스로 라우팅
                name: my-app-clusterip-svc 
                port:
                  number: 80

⚙️ 기타 주요 리소스

컨피그맵 (ConfigMap)

ConfigMap은 설정 정보를 Key-Value 형태로 저장하여 파드에 환경변수나 파일로 주입합니다.

ConfigMap 매니페스트 예시 (configmap.yaml)

apiVersion: v1
kind: ConfigMap
metadata:
  name: my-app-config
data:
  # Key-Value 형태의 설정 데이터
  APP_COLOR: "blue"
  APP_MODE: "production"
  GREETING: "Hello from ConfigMap!"

시크릿 (Secret) & 모범 사례

Secret 리소스는 TLS 인증서, API 키, 패스워드 등 기밀 정보를 다룹니다. 데이터는 Base64로 인코딩되어 저장됩니다.

(주의): Base64는 암호화가 아닙니다. 누구나 디코딩할 수 있습니다.
(모범 사례): 프로덕션 환경에서는 K8s Secret에 기밀 정보를 직접 저장하기보다, VaultAWS/GCP Secrets Manager 같은 외부 시크릿 관리 도구와 연동하여 파드가 실행될 때 동적으로 시크릿을 주입받는 방식을 사용합니다.

Secret 매니페스트 예시 (secret.yaml)

apiVersion: v1
kind: Secret
metadata:
  name: my-app-secret
type: Opaque # 가장 일반적인 Secret 타입
data:
  # 값들은 반드시 Base64로 인코딩되어야 함
  # "admin" -> base64 -> "YWRtaW4="
  # "my-db-password123" -> base64 -> "bXktZGItcGFzc3dvcmQxMjM="
  DATABASE_USER: "YWRtaW4="
  DATABASE_PASSWORD: "bXktZGItcGFzc3dvcmQxMjM="

잡 (Job) & 크론잡 (CronJob)

  • Job: 일회성 작업을 위한 리소스. 파드가 '정상 종료(Exit Code 0)'될 때까지 관리합니다.
  • CronJob: 잡(Job)을 스케줄(예: 0 5 * * *)에 따라 정기적으로 실행합니다.

Job 매니페스트 예시 (job.yaml)

apiVersion: batch/v1
kind: Job
metadata:
  name: my-onetime-job
spec:
  template: # Job이 실행할 Pod 템플릿
    spec:
      containers:
        - name: pi-calculator
          image: perl:latest
          # 2000자리 파이(pi) 계산 후 종료하는 일회성 작업
          command: ["perl",  "-Mbignum=bpi", "-wle", "print bpi(2000)"]
      restartPolicy: Never # Job은 재시작(Restart)하지 않고 실패(Failure) 시 재시도(Backoff)
  backoffLimit: 4 # 4번까지 재시도

CronJob 매니페스트 예시 (cronjob.yaml)

apiVersion: batch/v1
kind: CronJob
metadata:
  name: my-nightly-backup
spec:
  schedule: "0 2 * * *" # 매일 새벽 2시 0분에 실행 (Cron 표현식)
  jobTemplate: # CronJob이 생성할 Job 템플릿
    spec:
      template:
        spec:
          containers:
            - name: backup-script
              image: busybox:latest
              command: ["/bin/sh", "-c", "echo 'Running nightly backup...'"]
          restartPolicy: OnFailure # 실패 시에만 재시작

🚢 헬름 (Helm)

헬름은 쿠버네티스의 패키지 관리자입니다.

하나의 앱을 배포하려면 Deployment, Service, ConfigMap, Ingress 등 수많은 리소스가 필요합니다. 헬름은 이 리소스들의 묶음을 '차트(Chart)'라는 패키지로 만들고, 환경별로 달라지는 설정값(DB 주소, 도메인 등)만 변수 처리하여 쉽게 배포/관리/업그레이드할 수 있게 도와줍니다.


🔬 부하 테스트 (Locust)

도커는 부하 테스트에도 유용하게 사용됩니다. Locust는 파이썬으로 구현된 부하 테스트 도구로, 테스트 시나리오를 코드로 작성할 수 있습니다. 도커와 쿠버네티스를 이용해 Locust 컨테이너를 수십~수백 개로 스케일 아웃하여 대규모 분산 부하 테스트를 수행할 수 있습니다.

profile
DONE IS BETTER THAN PERFECT.

0개의 댓글