관리 메뉴

근묵자흑

도커 엔진 본문

k8s

도커 엔진

Luuuuu 2025. 3. 23. 15:42

2.1 도커 이미지와 컨테이너

2.1.1 도커 이미지

도커 이미지는 애플리케이션과 그 실행 환경을 패키징한 읽기 전용 템플릿입니다. 이미지는 컨테이너 실행에 필요한 모든 요소를 포함하고 있어 어떤 환경에서도 동일하게 작동합니다.

이미지의 주요 특징:

  • 계층화된 구조: 각 레이어는 이전 레이어에 대한 변경사항을 나타냅니다.
  • 불변성(Immutability): 한번 생성된 이미지는 변경되지 않습니다.
  • 효율성: 레이어는 여러 이미지 간에 공유될 수 있어 디스크 공간을 절약합니다.
  • 버전 관리: 태그를 사용하여 여러 버전의 이미지를 관리할 수 있습니다.

이미지 관련 주요 명령어:

  • 이미지 검색:
docker search ubuntu  # Docker Hub에서 ubuntu 관련 이미지 검색
  • 이미지 다운로드:
docker pull ubuntu:20.04  # 특정 태그의 이미지 다운로드
docker pull ubuntu        # 태그 미지정 시 latest 버전 다운로드
docker pull --all-tags ubuntu  # 모든 태그의 ubuntu 이미지 다운로드
  • 이미지 목록 확인:
docker images  # 모든 이미지 목록 표시
docker images -a  # 중간 레이어 이미지를 포함한 모든 이미지 표시
docker images --digests  # 다이제스트 정보 포함
docker images --filter "dangling=true"  # 태그가 없는 이미지만 표시
docker images --format "{{.Repository}}:{{.Tag}}: {{.Size}}"  # 출력 형식 지정
  • 이미지 정보 상세 확인:
docker inspect ubuntu:20.04  # 이미지 상세 정보 확인
docker inspect --format='{{.RepoTags}}' ubuntu:20.04  # 특정 정보만 출력

2.1.2 도커 컨테이너

도커 컨테이너는 이미지의 실행 가능한 인스턴스입니다. 각 컨테이너는 호스트 시스템으로부터 격리된 환경에서 실행되며, 자체 파일 시스템, 네트워크, 프로세스 공간을 가집니다.

컨테이너의 라이프사이클:

  1. 생성(Created): 컨테이너 설정은 완료되었지만 아직 시작되지 않은 상태
  2. 실행(Running): 컨테이너가 실행 중인 상태
  3. 일시 정지(Paused): 컨테이너의 모든 프로세스가 일시 중지된 상태
  4. 중지(Stopped): 컨테이너가 종료된 상태
  5. 삭제(Deleted): 컨테이너가 시스템에서 제거된 상태

컨테이너와 가상 머신의 차이점:

  • 컨테이너는 호스트 OS 커널을 공유하여 가볍고 빠르게 시작합니다.
  • 가상 머신은 각각 완전한 OS를 실행하므로 더 많은 리소스를 사용합니다.
  • 컨테이너는 수 초 내에 시작되지만, 가상 머신은 몇 분이 소요될 수 있습니다.
  • 컨테이너는 마이크로서비스 아키텍처에 적합하며, 가상 머신은 완전한 격리가 필요한 경우에 적합합니다.

2.2 도커 컨테이너 다루기

2.2.1 컨테이너 생성

컨테이너를 생성하고 실행하는 방법에는 여러 가지가 있으며, 각 방법은 서로 다른 목적과 사용 사례를 가집니다.

docker run 명령어와 주요 옵션:

docker run [OPTIONS] IMAGE [COMMAND] [ARG...]

자주 사용되는 옵션:

  • 기본 실행 옵션:
docker run -d nginx  # 백그라운드(detached 모드)에서 실행
docker run -it ubuntu bash  # 대화형 터미널 모드로 실행
docker run --rm nginx  # 컨테이너 종료 시 자동 삭제
docker run --name my-container nginx  # 컨테이너에 이름 지정
  • 네트워크 관련 옵션:
docker run -p 8080:80 nginx  # 호스트의 8080 포트를 컨테이너의 80 포트에 매핑
docker run -P nginx  # 모든 노출 포트를 호스트의 임의 포트에 매핑
docker run --network host nginx  # 호스트 네트워크 사용
docker run --dns 8.8.8.8 nginx  # 사용자 지정 DNS 서버 설정
docker run --add-host example.com:192.168.1.1 nginx  # /etc/hosts에 항목 추가
  • 리소스 제한 옵션:
docker run --cpus=0.5 nginx  # CPU 사용량을 0.5 코어로 제한
docker run --memory=512m nginx  # 메모리 사용량을 512MB로 제한
docker run --memory-reservation=256m nginx  # 메모리 소프트 한도 설정
docker run --pids-limit=100 nginx  # 최대 프로세스 수 제한
  • 볼륨 관련 옵션:
docker run -v /host/path:/container/path nginx  # 바인드 마운트
docker run -v my-volume:/container/path nginx  # 볼륨 마운트
docker run --tmpfs /tmp nginx  # tmpfs 마운트 (메모리에 임시 파일시스템)
docker run --mount type=bind,source=/host/path,target=/container/path nginx  # 마운트 옵션
  • 환경 및 설정 옵션:
docker run -e VAR=value nginx  # 환경 변수 설정
docker run --env-file .env nginx  # 환경 변수 파일에서 로드
docker run -w /app nginx  # 작업 디렉토리 설정
docker run --entrypoint /bin/bash nginx  # 기본 ENTRYPOINT 오버라이드
  • 보안 관련 옵션:
docker run --privileged nginx  # 권한 있는 모드로 실행(호스트의 장치에 접근 가능)
docker run --cap-add SYS_ADMIN nginx  # 특정 Linux 기능 추가
docker run --cap-drop NET_ADMIN nginx  # 특정 Linux 기능 제거
docker run --security-opt seccomp=profile.json nginx  # 보안 옵션 설정

docker createdocker start 분리 사용:

# 컨테이너 생성 (아직 시작하지 않음)
docker create --name my-nginx -p 8080:80 nginx:latest

# 컨테이너 시작
docker start my-nginx

# 시작된 컨테이너에 명령 실행
docker exec -it my-nginx bash

이 방식의 장점은 컨테이너를 미리 구성해 두고, 필요할 때만 시작할 수 있다는 점입니다.

2.2.2 컨테이너 목록 확인

컨테이너 목록을 확인하고 관리하는 다양한 방법이 있습니다.

docker ps 명령어와 옵션:

# 실행 중인 컨테이너만 표시
docker ps

# 모든 컨테이너 표시 (중지된 것 포함)
docker ps -a

# 마지막으로 생성된 n개의 컨테이너만 표시
docker ps -n 5

# 컨테이너 ID만 표시
docker ps -q

# 특정 상태의 컨테이너만 표시
docker ps --filter "status=exited"
docker ps --filter "status=running"

# 특정 이름 패턴의 컨테이너 표시
docker ps --filter "name=nginx"

# 특정 이미지에서 실행된 컨테이너 표시
docker ps --filter "ancestor=nginx:latest"

# 특정 볼륨을 마운트한 컨테이너 표시
docker ps --filter "volume=my-volume"

# 특정 네트워크에 연결된 컨테이너 표시
docker ps --filter "network=my-network"

# 출력 형식 사용자 정의
docker ps --format "table {{.ID}}\t{{.Names}}\t{{.Status}}\t{{.Ports}}"
docker ps --format "{{.Names}} - {{.Status}}"

컨테이너 리소스 사용량 모니터링:

# 모든 실행 중인 컨테이너의 리소스 사용량 실시간 표시
docker stats

# 특정 컨테이너의 리소스 사용량만 표시
docker stats container1 container2

# 출력 형식 사용자 정의
docker stats --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}"

# 스트림 모드 비활성화 (한 번만 출력)
docker stats --no-stream

컨테이너 프로세스 확인:

# 컨테이너 내부에서 실행 중인 프로세스 확인
docker top container-name

# 특정 형식으로 출력 (ps 명령어 옵션 사용)
docker top container-name aux

2.2.3 컨테이너 삭제

컨테이너를 관리하고 삭제하는 다양한 방법이 있습니다.

컨테이너 중지 및 삭제:

# 컨테이너 중지 (SIGTERM 시그널 전송)
docker stop container-name

# 컨테이너 강제 중지 (SIGKILL 시그널 전송)
docker kill container-name

# 컨테이너 일시 정지
docker pause container-name

# 일시 정지된 컨테이너 재개
docker unpause container-name

# 컨테이너 삭제 (중지된 상태여야 함)
docker rm container-name

# 실행 중인 컨테이너 강제 삭제
docker rm -f container-name

# 관련된 볼륨 함께 삭제
docker rm -v container-name

# 여러 컨테이너 한 번에 삭제
docker rm container1 container2 container3

# 종료된 모든 컨테이너 삭제
docker rm $(docker ps -q -f "status=exited")

컨테이너 정리 명령어:

# 중지된 컨테이너, 태그 없는 이미지, 사용되지 않는 네트워크 등 제거
docker system prune

# 볼륨 포함 모두 제거
docker system prune -a --volumes

# 특정 유형의 리소스만 정리
docker container prune  # 중지된 모든 컨테이너 제거
docker image prune      # 태그 없는 이미지 제거
docker network prune    # 사용되지 않는 네트워크 제거
docker volume prune     # 사용되지 않는 볼륨 제거

컨테이너 및 이미지 스토리지 사용량 확인:

docker system df  # 디스크 사용량 요약
docker system df -v  # 상세 디스크 사용량 (컨테이너 및 이미지별)

2.2.4 컨테이너를 외부에 노출

컨테이너 서비스를 외부 또는 다른 컨테이너에 노출하는 다양한 방법이 있습니다.

포트 매핑:

# 호스트의 8080 포트를 컨테이너의 80 포트에 매핑
docker run -p 8080:80 nginx

# 특정 IP 주소의 포트만 매핑
docker run -p 127.0.0.1:8080:80 nginx

# 호스트의 여러 포트를 컨테이너의 동일한 포트에 매핑
docker run -p 8080:80 -p 8443:443 nginx

# 호스트의 임의 포트를 컨테이너의 포트에 매핑
docker run -p 80 nginx
# 확인 방법
docker port container-name

호스트 네트워크 모드:

# 컨테이너가 호스트 네트워크를 직접 사용 (포트 매핑 불필요)
docker run --network host nginx

# 호스트 네트워크의 특정 인터페이스만 사용
docker run --network host --ip 192.168.1.10 nginx

컨테이너 간 통신 방법:

# 컨테이너 링크 (레거시 방식)
docker run --link mysql:db nginx

# 사용자 정의 네트워크 생성 및 사용 (권장)
docker network create my-network
docker run --network my-network --name web nginx
docker run --network my-network --name db mysql

# DNS 확인: 네트워크 내에서 컨테이너 이름으로 통신 가능
# 'web' 컨테이너에서 'db'로 접근 가능

포트 노출과 매핑의 차이:

  • EXPOSE: Dockerfile에서 사용되며, 문서화 목적으로 컨테이너가 리스닝하는 포트를 선언
  • -p 또는 --publish: 실제로 호스트 포트를 컨테이너 포트에 매핑
# EXPOSE로 선언된 모든 포트를 임의의 호스트 포트에 매핑
docker run -P nginx

2.2.6 도커 볼륨

도커 볼륨은 컨테이너 데이터의 영속성을 제공하는 방법입니다. 컨테이너가 삭제되어도 볼륨의 데이터는 유지됩니다.

볼륨 유형:

  1. 이름이 있는 볼륨(Named Volumes): 도커가 관리하는 볼륨
  2. 바인드 마운트(Bind Mounts): 호스트 시스템의 특정 경로를 컨테이너에 마운트
  3. tmpfs 마운트: 호스트 시스템의 메모리에만 저장되는 임시 데이터

볼륨 관리 명령어:

# 볼륨 생성
docker volume create my-volume

# 볼륨 목록 확인
docker volume ls

# 특정 조건의 볼륨만 표시
docker volume ls --filter "dangling=true"  # 미사용 볼륨
docker volume ls --filter "name=my"  # 이름에 'my'가 포함된 볼륨

# 볼륨 상세 정보 확인
docker volume inspect my-volume

# 볼륨 삭제
docker volume rm my-volume

# 미사용 볼륨 모두 삭제
docker volume prune

볼륨 사용 예제:

# 이름이 있는 볼륨 사용
docker run -v my-volume:/app/data nginx

# 바인드 마운트 사용
docker run -v /host/path:/container/path:ro nginx  # 읽기 전용으로 마운트
docker run -v $(pwd):/app nginx  # 현재 디렉토리를 /app에 마운트

# tmpfs 마운트 사용
docker run --tmpfs /app/temp nginx  # 메모리에만 저장

# 새로운 mount 옵션 사용
docker run --mount type=volume,source=my-volume,target=/app/data nginx
docker run --mount type=bind,source=/host/path,target=/container/path nginx
docker run --mount type=tmpfs,target=/app/temp nginx

볼륨 옵션과 드라이버:

# 특정 드라이버 사용하여 볼륨 생성
docker volume create my-volume --driver local

# 볼륨 옵션 추가
docker volume create my-volume --opt device=/dev/sda2 --opt type=ext4

# NFS 볼륨 사용 예제
docker volume create --driver local \
  --opt type=nfs \
  --opt o=addr=192.168.1.1,rw \
  --opt device=:/path/to/dir \
  my-nfs-volume

데이터 백업 및 복원:

# 볼륨 데이터 백업
docker run --rm -v my-volume:/source -v $(pwd):/backup alpine \
  tar czf /backup/my-volume-backup.tar.gz -C /source .

# 볼륨 데이터 복원
docker run --rm -v my-volume:/target -v $(pwd):/backup alpine \
  tar xzf /backup/my-volume-backup.tar.gz -C /target

2.2.7 도커 네트워크

도커 네트워크는 컨테이너 간의 통신과 외부 세계와의 연결을 관리합니다.

기본 네트워크 드라이버:

  1. bridge: 기본 네트워크 드라이버. 동일한 호스트에서 실행되는 컨테이너 간 통신에 사용
  2. host: 컨테이너가 호스트의 네트워킹을 직접 사용
  3. none: 모든 네트워킹을 비활성화
  4. overlay: 여러 도커 호스트에 걸쳐 컨테이너를 연결
  5. macvlan: 컨테이너에 MAC 주소를 할당하여 물리적 장치처럼 보이게 함
  6. ipvlan: macvlan과 유사하지만 MAC 주소 없이 IP 주소만 할당

네트워크 관리 명령어:

# 네트워크 생성
docker network create my-network

# 특정 드라이버 사용
docker network create --driver bridge my-bridge-network
docker network create --driver overlay my-overlay-network

# 서브넷과 게이트웨이 지정
docker network create --subnet=172.18.0.0/16 --gateway=172.18.0.1 my-network

# 네트워크 목록 확인
docker network ls

# 네트워크 상세 정보 확인
docker network inspect my-network

# 네트워크 삭제
docker network rm my-network

# 미사용 네트워크 정리
docker network prune

컨테이너 네트워크 관리:

# 컨테이너를 네트워크에 연결
docker network connect my-network container-name

# 특정 IP 주소 지정
docker network connect --ip 172.18.0.10 my-network container-name

# 컨테이너를 네트워크에서 분리
docker network disconnect my-network container-name

# 네트워크 생성과 동시에 컨테이너 실행
docker run --network my-network nginx

네트워크 격리 예제:

# 프론트엔드 네트워크 생성
docker network create frontend

# 백엔드 네트워크 생성
docker network create backend

# 웹 서버는 프론트엔드와 백엔드 네트워크에 모두 연결
docker run -d --name web --network frontend nginx
docker network connect backend web

# 데이터베이스는 백엔드 네트워크에만 연결
docker run -d --name db --network backend mysql

네트워크 트러블슈팅:

# 컨테이너에서 네트워크 디버깅 도구 실행
docker run --rm --network container:web nicolaka/netshoot ping db

# 네트워크 트래픽 모니터링
docker run --rm --network container:web nicolaka/netshoot tcpdump -i eth0

# 특정 네트워크 인터페이스의 IP 주소 확인
docker exec container-name ip addr show eth0

2.2.8 컨테이너 로깅

도커는 컨테이너의 표준 출력(stdout)과 표준 오류(stderr)를 캡처하여 로깅 시스템에 전달합니다.

로그 확인 명령어:

# 컨테이너 로그 확인
docker logs container-name

# 마지막 n줄만 표시
docker logs --tail 100 container-name

# 타임스탬프 표시
docker logs --timestamps container-name

# 특정 시간 이후의 로그만 표시
docker logs --since 2023-01-01T00:00:00 container-name

# 특정 시간 이전의 로그만 표시
docker logs --until 2023-01-02T00:00:00 container-name

# 실시간 로그 확인
docker logs --follow container-name

# 출력 제한
docker logs --tail 100 --follow container-name

로깅 드라이버:

도커는 다양한 로깅 드라이버를 지원하여 다양한 로그 저장 및 분석 시스템과 통합할 수 있습니다.

# json-file (기본 드라이버)
docker run --log-driver json-file nginx

# 로그 로테이션 설정
docker run --log-driver json-file \
  --log-opt max-size=10m \
  --log-opt max-file=3 \
  nginx

# syslog 드라이버
docker run --log-driver syslog \
  --log-opt syslog-address=udp://syslog-server:514 \
  nginx

# journald 드라이버
docker run --log-driver journald nginx

# fluentd 드라이버
docker run --log-driver fluentd \
  --log-opt fluentd-address=fluentd-host:24224 \
  nginx

# awslogs 드라이버
docker run --log-driver awslogs \
  --log-opt awslogs-region=us-east-1 \
  --log-opt awslogs-group=my-log-group \
  nginx

도커 데몬 전체 로그 드라이버 설정:

/etc/docker/daemon.json 파일에 설정:

{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  }
}

로그 전달 및 중앙화:

로그를 중앙 로그 시스템(예: ELK 스택, Graylog, Splunk)에 통합하는 것이 일반적인 접근 방식입니다:

version: '3'
services:
  app:
    image: my-app
    logging:
      driver: fluentd
      options:
        fluentd-address: localhost:24224
        tag: docker.{{.Name}}

  fluentd:
    image: fluent/fluentd
    volumes:
      - ./fluentd/conf:/fluentd/etc
    ports:
      - "24224:24224"

2.2.9 컨테이너 자원 할당 제한

리소스 제한은 컨테이너가 호스트 시스템의 리소스를 과도하게 사용하는 것을 방지합니다.

CPU 제한:

# CPU 사용량을 코어 수 기준으로 제한
docker run --cpus=1.5 nginx  # 최대 1.5 코어 사용 가능

# CPU 상대적 비중 설정
docker run --cpu-shares=512 nginx  # 기본값은 1024

# 특정 CPU 코어에만 바인딩
docker run --cpuset-cpus="0,3" nginx  # CPU 0과 3만 사용
docker run --cpuset-cpus="0-2" nginx  # CPU 0,1,2 사용

메모리 제한:

# 메모리 사용량 제한
docker run --memory=512m nginx  # 512MB 제한

# 메모리 소프트 한계 설정 (스왑 전 압력 적용 시점)
docker run --memory-reservation=256m nginx

# 스왑 메모리 제한
docker run --memory=512m --memory-swap=1g nginx  # 메모리 512MB + 스왑 512MB = 총 1GB
docker run --memory=512m --memory-swap=-1 nginx  # 스왑 무제한

# OOM(Out of Memory) 킬러 비활성화
docker run --memory=512m --oom-kill-disable=true nginx

스토리지 제한:

# 디스크 I/O 제한 (기기별 읽기/쓰기 바이트 수 제한)
docker run --device-read-bps /dev/sda:1mb nginx
docker run --device-write-bps /dev/sda:1mb nginx

# IOPS 제한 (초당 읽기/쓰기 작업 수 제한)
docker run --device-read-iops /dev/sda:1000 nginx
docker run --device-write-iops /dev/sda:1000 nginx

리소스 제한 확인:

# 컨테이너 리소스 사용량 실시간 모니터링
docker stats

# 특정 컨테이너의 상세 리소스 제한 설정 확인
docker inspect --format='{{.HostConfig.CpuShares}}' container-name
docker inspect --format='{{.HostConfig.Memory}}' container-name

Docker Compose에서의 리소스 제한:

version: '3'
services:
  web:
    image: nginx
    deploy:
      resources:
        limits:
          cpus: '0.5'
          memory: 512M
        reservations:
          cpus: '0.25'
          memory: 256M

2.3 도커 이미지

2.3.1 도커 이미지 생성

도커 이미지를 생성하는 여러 방법이 있습니다.

실행 중인 컨테이너에서 이미지 생성:

# 기본 커밋
docker commit container-name my-image:tag

# 변경 사항 설명 추가
docker commit -m "Added nginx configuration" container-name my-image:tag

# 커밋 시 컨테이너 일시 정지
docker commit -p container-name my-image:tag

# 작성자 정보 추가
docker commit -a "John Doe" container-name my-image:tag

# 설정 변경하며 커밋
docker commit -c "ENV DEBUG=1" container-name my-image:tag

Dockerfile을 사용한 이미지 생성:

# 기본 빌드
docker build -t my-image:tag .

# 다른 경로의 Dockerfile 사용
docker build -t my-image:tag -f path/to/Dockerfile .

# 빌드 인자 전달
docker build --build-arg VERSION=1.0 -t my-image:tag .

# 캐시 없이 빌드 (모든 레이어 재생성)
docker build --no-cache -t my-image:tag .

# 특정 단계까지만 빌드
docker build --target build-stage -t my-image:tag .

# 빌드 컨텍스트 지정 (원격 URL 가능)
docker build -t my-image:tag https://github.com/username/repo.git

이미지 태깅 및 관리:

# 이미지에 새 태그 추가
docker tag my-image:latest my-image:v1.0
docker tag my-image:latest username/my-image:latest

# 이미지 정보 업데이트
docker image inspect my-image:tag

# 이미지 히스토리 확인
docker history my-image:tag

# 이미지 삭제
docker rmi my-image:tag

# 태그만 삭제 (이미지는 유지)
docker rmi my-image:tag  # 다른 태그로도 참조되는 경우

2.3.2 이미지 구조 이해

도커 이미지는 여러 레이어로 구성되어 있으며, 각 레이어는 이전 레이어에 대한 변경사항을 나타냅니다.

이미지 레이어 구조:

+------------------------+
| 애플리케이션 레이어      |
+------------------------+
| 의존성 설치 레이어       |
+------------------------+
| 설정 파일 레이어        |
+------------------------+
| 베이스 OS 레이어        |
+------------------------+

레이어 확인 및 분석:

# 이미지 레이어 히스토리 확인
docker history nginx:latest

# 상세 출력
docker history --no-trunc nginx:latest

# 이미지 메타데이터 및 레이어 상세 정보 확인
docker inspect nginx:latest

레이어 캐싱과 최적화:

  • 각 Dockerfile 명령어는 새 레이어 생성
  • 자주 변경되는 부분은 Dockerfile 후반부에 배치
  • 여러 명령어를 하나로 결합하여 레이어 수 최소화
  • .dockerignore 파일로 불필요한 파일 제외

예시: 효율적인 레이어 구성:

# 비효율적인 방식 (각 패키지마다 레이어 생성)
FROM ubuntu:20.04
RUN apt-get update
RUN apt-get install -y nginx
RUN apt-get install -y openssl
RUN apt-get install -y curl

# 효율적인 방식 (하나의 레이어로 결합)
FROM ubuntu:20.04
RUN apt-get update && apt-get install -y \
    nginx \
    openssl \
    curl \
    && rm -rf /var/lib/apt/lists/*

레이어 공유 이점:

  • 이미지 다운로드 속도 향상 (공통 레이어는 한 번만 다운로드)
  • 디스크 공간 절약 (레이어 재사용)
  • 빌드 시간 단축 (캐시된 레이어 활용)

2.3.3 이미지 추출

도커 이미지와 컨테이너를 파일로 추출하고 이동할 수 있습니다.

컨테이너 추출:

# 컨테이너의 파일 시스템을 tar 파일로 추출
docker export container-name > container.tar

# 압축 추가
docker export container-name | gzip > container.tar.gz

# 선택적 명령어 지정
docker export --output="container.tar" container-name

이미지 저장 및 로드:

# 이미지를 tar 파일로 저장 (모든 레이어와 메타데이터 포함)
docker save my-image:tag > image.tar
docker save -o image.tar my-image:tag

# 여러 이미지 함께 저장
docker save -o images.tar image1:tag1 image2:tag2

# tar 파일에서 이미지 로드
docker load < image.tar
docker load -i image.tar

export와 save의 차이점:

  • docker export: 컨테이너의 파일 시스템만 추출 (레이어 정보 손실)
  • docker save: 이미지의 모든 레이어와 메타데이터 보존

이미지 변환 및 마이그레이션:

# export로 추출한 컨테이너를 새 이미지로 가져오기
docker export container-name | docker import - new-image:tag

# 이미지 압축 (크기 최적화)
docker save my-image:tag | gzip > my-image.tar.gz
gunzip -c my-image.tar.gz | docker load

2.3.4 이미지 배포

도커 이미지를 공유하고 배포하는 다양한 방법이 있습니다.

Docker Hub 이용:

# Docker Hub에 로그인
docker login

# 이미지 태그 지정 (username/image:tag 형식 필요)
docker tag my-image:latest username/my-image:latest

# 이미지 푸시
docker push username/my-image:latest

# 로그아웃
docker logout

비공개 레지스트리 사용:

# 비공개 레지스트리 서버 실행
docker run -d -p 5000:5000 --name registry registry:2

# 이미지 태그 지정
docker tag my-image:latest localhost:5000/my-image:latest

# 로컬 레지스트리에 푸시
docker push localhost:5000/my-image:latest

# 로컬 레지스트리에서 풀
docker pull localhost:5000/my-image:latest

레지스트리에 인증 추가:

# 인증 정보로 로그인
docker login registry.example.com

# 비보안 레지스트리 허용 (도커 데몬 설정)
# /etc/docker/daemon.json에 추가:
{
  "insecure-registries": ["registry.example.com:5000"]
}

이미지 카탈로그 및 검색:

# 레지스트리 API를 통한 이미지 목록 가져오기
curl http://localhost:5000/v2/_catalog

# 특정 이미지의 태그 목록 가져오기
curl http://localhost:5000/v2/my-image/tags/list

CI/CD 파이프라인 통합:

# GitLab CI/CD 예제
build_and_push:
  stage: build
  script:
    - docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG .
    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
    - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG

2.4 Dockerfile

2.4.1 이미지를 생성하는 방법

Dockerfile이란?

Dockerfile은 도커 이미지를 생성하기 위한 스크립트로, 이미지를 구성하는 단계를 정의합니다. 각 명령어는 새 레이어를 생성합니다.

기본 구조:

# 베이스 이미지 지정
FROM ubuntu:20.04

# 메타데이터 설정
LABEL maintainer="example@example.com"
LABEL version="1.0"

# 환경 변수 설정
ENV APP_HOME=/app

# 작업 디렉토리 설정
WORKDIR $APP_HOME

# 필요한 파일 복사
COPY . .

# 명령 실행 (새 레이어 생성)
RUN apt-get update && \
    apt-get install -y python3 python3-pip

# 포트 노출
EXPOSE 8000

# 볼륨 정의
VOLUME ["/app/data"]

# 기본 실행 명령 설정
CMD ["python3", "app.py"]

Dockerfile 위치 및 이름:

  • 일반적으로 프로젝트 루트 디렉토리에 Dockerfile이라는 이름으로 생성
  • 다른 이름이나 경로를 사용할 경우 빌드 시 -f 옵션으로 지정

2.4.2 Dockerfile 작성

주요 명령어 상세 설명:

FROM:

FROM scratch  # 빈 이미지에서 시작
FROM ubuntu:20.04  # 특정 태그 지정
FROM python:3.9-slim  # 작은 크기의 이미지
FROM nginx:latest AS web  # 다단계 빌드를 위한 이름 지정

COPY와 ADD:

# 로컬 파일/디렉토리 복사
COPY app.py .
COPY src/ /app/src/
COPY ["file with spaces.txt", "/app/"]

# 특정 사용자/그룹으로 파일 복사
COPY --chown=user:group files/ /app/

# ADD는 COPY와 유사하지만 추가 기능 제공
ADD app.tar.gz /app/  # 자동 압축 해제
ADD https://example.com/file.txt /app/  # URL에서 다운로드

RUN:

# 쉘 형식 (기본 /bin/sh -c)
RUN apt-get update && apt-get install -y nginx

# 실행 형식 (직접 실행, 쉘 미사용)
RUN ["apt-get", "install", "-y", "nginx"]

# 파이프 및 리디렉션 사용
RUN set -o pipefail && wget -O - https://example.com | tar -xzf -

# 다중 줄 명령
RUN apt-get update && \
    apt-get install -y \
        nginx \
        curl \
        vim && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/*

ENV:

# 개별 환경 변수 설정
ENV APP_HOME=/app
ENV PORT=8000

# 여러 환경 변수 한 번에 설정
ENV APP_HOME=/app \
    PORT=8000 \
    DEBUG=true

# 환경 변수 사용
RUN mkdir -p $APP_HOME
WORKDIR $APP_HOME

WORKDIR:

# 절대 경로 지정
WORKDIR /app

# 상대 경로 (이전 WORKDIR 기준)
WORKDIR src
WORKDIR lib  # /app/src/lib이 됨

# 환경 변수 사용
WORKDIR $APP_HOME/src

EXPOSE:

# 단일 포트 노출
EXPOSE 80

# 여러 포트 노출
EXPOSE 80 443

# UDP 포트 지정
EXPOSE 53/udp

# TCP/UDP 동시 지정
EXPOSE 53/tcp 53/udp

VOLUME:

# 단일 볼륨 마운트 포인트
VOLUME /app/data

# 여러 볼륨 마운트 포인트
VOLUME ["/app/data", "/app/logs"]

# 환경 변수 사용 (JSON 배열 형식에서는 불가)
VOLUME /app/$DATA_DIR

USER:

# 사용자 이름으로 지정
USER nginx

# UID로 지정
USER 1000

# 사용자 및 그룹 지정
USER 1000:1000

# 사용자 전환 예제
RUN useradd -ms /bin/bash appuser
USER appuser

ARG:

# 기본값 없는 빌드 인자
ARG VERSION

# 기본값 있는 빌드 인자
ARG VERSION=latest

# 빌드 인자 사용
RUN echo "Building version: $VERSION"

# 빌드 인자와 환경 변수 함께 사용
ARG VERSION=latest
ENV APP_VERSION=$VERSION

ENTRYPOINT와 CMD의 관계:

# 실행 가능한 형식 (권장)
ENTRYPOINT ["nginx", "-g", "daemon off;"]
CMD ["-v"]  # 추가 인자로 사용됨 -> nginx -g "daemon off;" -v

# 쉘 형식
ENTRYPOINT nginx -g "daemon off;"
CMD -v  # 무시됨

# CMD만 사용 (기본 entrypoint는 /bin/sh -c)
CMD ["nginx", "-g", "daemon off;"]

# 런타임에 오버라이드
# docker run --entrypoint /bin/bash my-image -c "echo hello"

2.4.3 Dockerfile 빌드

기본 빌드 명령:

# 현재 디렉토리의 Dockerfile 사용
docker build -t my-image:tag .

# 특정 Dockerfile 지정
docker build -t my-image:tag -f Dockerfile.prod .

# 다른 경로의 컨텍스트 사용
docker build -t my-image:tag /path/to/context

# 표준 입력으로 Dockerfile 전달
docker build -t my-image:tag - < Dockerfile

고급 빌드 옵션:

# 빌드 인자 전달
docker build --build-arg VERSION=1.0 -t my-image:tag .

# 다중 태그 할당
docker build -t my-image:latest -t my-image:v1.0 .

# 특정 단계까지만 빌드 (다단계 빌드)
docker build --target build-stage -t my-image:build .

# 빌드 캐시 사용하지 않음
docker build --no-cache -t my-image:tag .

# 특정 이미지까지만 캐시 사용
docker build --cache-from my-image:cache -t my-image:tag .

# 특정 플랫폼용 빌드
docker build --platform linux/amd64 -t my-image:tag .

빌드 컨텍스트:

빌드 컨텍스트는 Dockerfile이 참조할 수 있는 파일 집합으로, COPYADD 명령의 소스로 사용됩니다.

# 원격 Git 저장소를 컨텍스트로 사용
docker build -t my-image:tag https://github.com/user/repo.git

# 특정 브랜치나 태그 지정
docker build -t my-image:tag https://github.com/user/repo.git#branch

# 특정 폴더에 있는 Dockerfile 지정
docker build -t my-image:tag https://github.com/user/repo.git#:folder

.dockerignore 파일:

.dockerignore 파일을 사용하여 빌드 컨텍스트에서 특정 파일이나 디렉토리를 제외할 수 있습니다.

# 주석
*.log
.git/
node_modules/
Dockerfile*
.dockerignore
.env*

2.4.4 기타 Dockerfile 명령어

HEALTHCHECK:

컨테이너 내부에서 애플리케이션이 정상적으로 작동하는지 확인하는 명령을 정의합니다.

# 기본 형식
HEALTHCHECK CMD curl -f http://localhost/ || exit 1

# 옵션 지정
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
  CMD curl -f http://localhost/ || exit 1

# 상태 코드
# 0: success - 컨테이너 정상
# 1: unhealthy - 컨테이너 비정상
# 2: reserved - 사용하지 않음

# 비활성화
HEALTHCHECK NONE

SHELL:

기본 쉘을 변경합니다. 기본값은 Linux에서 ["/bin/sh", "-c"], Windows에서 ["cmd", "/S", "/C"]입니다.

# 기본 쉘 변경
SHELL ["/bin/bash", "-c"]

# PowerShell 사용 (Windows)
SHELL ["powershell", "-Command"]

# 변경된 쉘로 명령 실행
RUN echo $HOME  # /bin/bash를 사용

ONBUILD:

이 이미지를 기반으로 하는 다른 이미지가 빌드될 때 실행할 명령을 정의합니다.

# 기본 이미지에서 정의
ONBUILD COPY . /app
ONBUILD RUN pip install -r requirements.txt

# 사용 예시 (다른 Dockerfile)
FROM my-base-image  # ONBUILD 트리거가 여기서 실행됨
# 추가 명령...

STOPSIGNAL:

컨테이너를 중지할 때 사용할 시스템 호출 시그널을 지정합니다.

# 시그널 번호 사용
STOPSIGNAL 9

# 시그널 이름 사용
STOPSIGNAL SIGKILL

2.4.5 Dockerfile로 빌드할 때 주의할 점

최적화 및 모범 사례:

  1. 레이어 수 최소화:
# 나쁜 예
RUN apt-get update
RUN apt-get install -y nginx
RUN apt-get install -y curl

# 좋은 예
RUN apt-get update && \
    apt-get install -y nginx curl && \
    rm -rf /var/lib/apt/lists/*
  1. 캐시 활용:
  • 자주 변경되는 레이어를 Dockerfile 마지막에 배치
  • 의존성 설치를 먼저 수행
# 좋은 예
COPY package.json .
RUN npm install
COPY . .  # 소스 코드는 마지막에 복사
  1. 다단계 빌드 사용:
# 빌드 단계
FROM node:14 AS builder
WORKDIR /app
COPY . .
RUN npm ci && npm run build

# 실행 단계
FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
  1. 적절한 베이스 이미지 선택:
    • 공식 이미지 사용
    • 가능한 작은 이미지 선택 (alpine, slim 등)
    • 특정 버전 태그 사용 (latest 피하기)
  2. .dockerignore 사용:
    • 불필요한 파일 제외
    • 빌드 컨텍스트 크기 최소화
  3. 환경 변수 활용:
    • 구성 정보는 환경 변수로 외부화
    • 런타임에 쉽게 변경할 수 있도록 설계
  4. 보안 고려사항:
    • 루트 사용자 피하기
      RUN useradd -ms /bin/bash appuser
      USER appuser
    • 최소한의 패키지만 설치
    • 보안 취약점 스캔 도구 사용
  5. 이미지 크기 최적화:
    • 불필요한 파일 제거
      RUN apt-get update && \
        apt-get install -y --no-install-recommends pkg && \
        rm -rf /var/lib/apt/lists/*
    • 임시 파일 정리
    • 패키지 캐시 제거
  6. 명확한 태그 관리:
    • 의미 있는 태그 사용
    • 버전 관리와 배포 파이프라인 연동
  7. 테스트 포함:
    • 빌드 단계에서 테스트 실행
      RUN npm test
    • 취약점 검사 자동화

2.5 도커 데몬

2.5.1 도커의 구조

도커는 클라이언트-서버 아키텍처를 사용합니다:

주요 구성 요소:

  1. 도커 클라이언트(Docker Client):
    • 사용자가 도커 명령어를 입력하는 인터페이스
    • 도커 데몬에 명령을 전달하는 역할
  2. 도커 데몬(Docker Daemon - dockerd):
    • 도커 API 요청을 수신하고 처리
    • 이미지, 컨테이너, 네트워크, 볼륨 등의 도커 객체 관리
    • 다른 데몬과 통신 가능
  3. 도커 레지스트리(Docker Registry):
    • 도커 이미지 저장소
    • Docker Hub가 기본 공개 레지스트리
    • 비공개 레지스트리 구축 가능
  4. 도커 객체(Docker Objects):
    • 이미지: 컨테이너 생성을 위한 읽기 전용 템플릿
    • 컨테이너: 이미지의 실행 가능한 인스턴스
    • 네트워크: 컨테이너 간 통신 경로
    • 볼륨: 데이터의 지속성 제공
    • 플러그인 및 추가 기능

통신 흐름:

  1. 클라이언트가 명령 실행 (docker run nginx)
  2. 클라이언트가 도커 API를 통해 데몬에 요청 전송
  3. 데몬이 명령 처리 (이미지 풀, 컨테이너 생성 등)
  4. 결과를 클라이언트에 반환

2.5.2 도커 데몬 실행

도커 데몬 시작 방법:

# 시스템 서비스로 시작 (systemd 사용)
sudo systemctl start docker

# 시스템 부팅 시 자동 시작 설정
sudo systemctl enable docker

# 서비스 상태 확인
sudo systemctl status docker

# 다른 데몬 옵션으로 수동 실행
sudo dockerd --debug --tls=true

데몬 로그 확인:

# 시스템 로그에서 도커 관련 로그 확인
sudo journalctl -u docker

# 실시간 로그 확인
sudo journalctl -fu docker

# 특정 기간의 로그 확인
sudo journalctl -u docker --since "2023-01-01" --until "2023-01-02"

도커 데몬 중지:

# 서비스 중지
sudo systemctl stop docker

# 서비스 재시작
sudo systemctl restart docker

2.5.3 도커 데몬 설정

도커 데몬 설정은 /etc/docker/daemon.json 파일을 통해 관리할 수 있습니다.

기본 설정 예시:

{
  "data-root": "/var/lib/docker",
  "storage-driver": "overlay2",
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  },
  "default-ulimits": {
    "nofile": {
      "Name": "nofile",
      "Hard": 64000,
      "Soft": 64000
    }
  },
  "registry-mirrors": ["https://registry-mirror.example.com"],
  "insecure-registries": ["registry.local:5000"],
  "debug": false,
  "experimental": false,
  "metrics-addr": "0.0.0.0:9323",
  "dns": ["8.8.8.8", "8.8.4.4"]
}

주요 구성 옵션:

  1. 스토리지 관련:
  2. { "data-root": "/path/to/docker/data", "storage-driver": "overlay2", "storage-opts": [ "overlay2.override_kernel_check=true" ] }
  3. 네트워킹:
  4. { "bip": "192.168.1.1/24", "fixed-cidr": "192.168.1.0/25", "dns": ["8.8.8.8", "8.8.4.4"], "default-address-pools": [ {"base": "172.80.0.0/16", "size": 24}, {"base": "172.90.0.0/16", "size": 24} ] }
  5. 로깅:
  6. { "log-driver": "json-file", "log-opts": { "max-size": "10m", "max-file": "3", "labels": "production_status", "env": "os,customer" } }
  7. 레지스트리:
  8. { "registry-mirrors": [ "https://mirror1.example.com", "https://mirror2.example.com" ], "insecure-registries": [ "registry.local:5000" ] }
  9. TLS 설정:
  10. { "tls": true, "tlscacert": "/path/to/ca.pem", "tlscert": "/path/to/server-cert.pem", "tlskey": "/path/to/server-key.pem", "tlsverify": true }
  11. 리소스 제한:
  12. { "default-shm-size": "64M", "default-ulimits": { "nofile": { "Name": "nofile", "Hard": 64000, "Soft": 64000 } } }
  13. 컨테이너 기본 런타임:
  14. { "default-runtime": "runc", "runtimes": { "nvidia": { "path": "/usr/bin/nvidia-container-runtime", "runtimeArgs": [] } } }
  15. API 및 모니터링:
  16. { "hosts": ["unix:///var/run/docker.sock", "tcp://0.0.0.0:2375"], "metrics-addr": "0.0.0.0:9323" }

설정 변경 후 적용:

# 설정 파일 수정 후 데몬 재시작
sudo systemctl restart docker

# 설정 확인
docker info

2.5.4 도커 데몬 모니터링

도커 데몬과 컨테이너의 상태를 모니터링하는 여러 방법이 있습니다.

기본 시스템 정보:

# 도커 시스템 정보 확인
docker info

# 특정 정보만 필터링
docker info --format '{{json .}}' | jq
docker info --format '{{.ContainersRunning}}'

# 디스크 사용량 확인
docker system df
docker system df -v  # 상세 정보

도커 이벤트 모니터링:

# 실시간 이벤트 스트림 확인
docker events

# 특정 이벤트 타입 필터링
docker events --filter 'type=container'
docker events --filter 'type=image'
docker events --filter 'type=volume'
docker events --filter 'type=network'

# 특정 이벤트 필터링
docker events --filter 'event=start'
docker events --filter 'event=stop'
docker events --filter 'event=die'

# 특정 컨테이너에 대한 이벤트
docker events --filter 'container=container-name'

# 이벤트 포맷팅
docker events --format '{{json .}}'

리소스 사용량 모니터링:

# 실시간 컨테이너 리소스 사용량
docker stats

# 모든 컨테이너 (중지된 것 포함) 표시
docker stats --all

# 특정 컨테이너만 모니터링
docker stats container1 container2

# 사용자 정의 출력 형식
docker stats --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}"

Docker API 엔드포인트 노출:

도커 API를 통해 외부 모니터링 도구와 통합할 수 있습니다:

// /etc/docker/daemon.json
{
  "metrics-addr": "0.0.0.0:9323",
  "experimental": true
}

프로메테우스 통합:

# 프로메테우스 설정 예시 (prometheus.yml)
scrape_configs:
  - job_name: 'docker'
    static_configs:
      - targets: ['docker-host:9323']

외부 모니터링 도구:

  1. cAdvisor: 컨테이너 리소스 사용량 모니터링
  2. Prometheus: 시계열 데이터베이스 및 모니터링 시스템
  3. Grafana: 메트릭 시각화 도구
  4. Datadog: 클라우드 모니터링 서비스
  5. New Relic: 애플리케이션 성능 모니터링
  6. Elastic Stack: 로그 수집 및 분석
  7. Portainer: 도커 관리 UI
  • 여러 도커 호스트를 관리하는 중앙 시스템
  • 리소스 할당 최적화