근묵자흑
도커 엔진 본문
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 도커 컨테이너
도커 컨테이너는 이미지의 실행 가능한 인스턴스입니다. 각 컨테이너는 호스트 시스템으로부터 격리된 환경에서 실행되며, 자체 파일 시스템, 네트워크, 프로세스 공간을 가집니다.
컨테이너의 라이프사이클:
- 생성(Created): 컨테이너 설정은 완료되었지만 아직 시작되지 않은 상태
- 실행(Running): 컨테이너가 실행 중인 상태
- 일시 정지(Paused): 컨테이너의 모든 프로세스가 일시 중지된 상태
- 중지(Stopped): 컨테이너가 종료된 상태
- 삭제(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 create
와 docker 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 도커 볼륨
도커 볼륨은 컨테이너 데이터의 영속성을 제공하는 방법입니다. 컨테이너가 삭제되어도 볼륨의 데이터는 유지됩니다.
볼륨 유형:
- 이름이 있는 볼륨(Named Volumes): 도커가 관리하는 볼륨
- 바인드 마운트(Bind Mounts): 호스트 시스템의 특정 경로를 컨테이너에 마운트
- 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 도커 네트워크
도커 네트워크는 컨테이너 간의 통신과 외부 세계와의 연결을 관리합니다.
기본 네트워크 드라이버:
- bridge: 기본 네트워크 드라이버. 동일한 호스트에서 실행되는 컨테이너 간 통신에 사용
- host: 컨테이너가 호스트의 네트워킹을 직접 사용
- none: 모든 네트워킹을 비활성화
- overlay: 여러 도커 호스트에 걸쳐 컨테이너를 연결
- macvlan: 컨테이너에 MAC 주소를 할당하여 물리적 장치처럼 보이게 함
- 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이 참조할 수 있는 파일 집합으로, COPY
나 ADD
명령의 소스로 사용됩니다.
# 원격 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로 빌드할 때 주의할 점
최적화 및 모범 사례:
- 레이어 수 최소화:
# 나쁜 예
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/*
- 캐시 활용:
- 자주 변경되는 레이어를 Dockerfile 마지막에 배치
- 의존성 설치를 먼저 수행
# 좋은 예
COPY package.json .
RUN npm install
COPY . . # 소스 코드는 마지막에 복사
- 다단계 빌드 사용:
# 빌드 단계
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
- 적절한 베이스 이미지 선택:
- 공식 이미지 사용
- 가능한 작은 이미지 선택 (alpine, slim 등)
- 특정 버전 태그 사용 (latest 피하기)
- .dockerignore 사용:
- 불필요한 파일 제외
- 빌드 컨텍스트 크기 최소화
- 환경 변수 활용:
- 구성 정보는 환경 변수로 외부화
- 런타임에 쉽게 변경할 수 있도록 설계
- 보안 고려사항:
- 루트 사용자 피하기
RUN useradd -ms /bin/bash appuser USER appuser
- 최소한의 패키지만 설치
- 보안 취약점 스캔 도구 사용
- 루트 사용자 피하기
- 이미지 크기 최적화:
- 불필요한 파일 제거
RUN apt-get update && \ apt-get install -y --no-install-recommends pkg && \ rm -rf /var/lib/apt/lists/*
- 임시 파일 정리
- 패키지 캐시 제거
- 불필요한 파일 제거
- 명확한 태그 관리:
- 의미 있는 태그 사용
- 버전 관리와 배포 파이프라인 연동
- 테스트 포함:
- 빌드 단계에서 테스트 실행
RUN npm test
- 취약점 검사 자동화
- 빌드 단계에서 테스트 실행
2.5 도커 데몬
2.5.1 도커의 구조
도커는 클라이언트-서버 아키텍처를 사용합니다:
주요 구성 요소:
- 도커 클라이언트(Docker Client):
- 사용자가 도커 명령어를 입력하는 인터페이스
- 도커 데몬에 명령을 전달하는 역할
- 도커 데몬(Docker Daemon - dockerd):
- 도커 API 요청을 수신하고 처리
- 이미지, 컨테이너, 네트워크, 볼륨 등의 도커 객체 관리
- 다른 데몬과 통신 가능
- 도커 레지스트리(Docker Registry):
- 도커 이미지 저장소
- Docker Hub가 기본 공개 레지스트리
- 비공개 레지스트리 구축 가능
- 도커 객체(Docker Objects):
- 이미지: 컨테이너 생성을 위한 읽기 전용 템플릿
- 컨테이너: 이미지의 실행 가능한 인스턴스
- 네트워크: 컨테이너 간 통신 경로
- 볼륨: 데이터의 지속성 제공
- 플러그인 및 추가 기능
통신 흐름:
- 클라이언트가 명령 실행 (
docker run nginx
) - 클라이언트가 도커 API를 통해 데몬에 요청 전송
- 데몬이 명령 처리 (이미지 풀, 컨테이너 생성 등)
- 결과를 클라이언트에 반환
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"]
}
주요 구성 옵션:
- 스토리지 관련:
{ "data-root": "/path/to/docker/data", "storage-driver": "overlay2", "storage-opts": [ "overlay2.override_kernel_check=true" ] }
- 네트워킹:
{ "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} ] }
- 로깅:
{ "log-driver": "json-file", "log-opts": { "max-size": "10m", "max-file": "3", "labels": "production_status", "env": "os,customer" } }
- 레지스트리:
{ "registry-mirrors": [ "https://mirror1.example.com", "https://mirror2.example.com" ], "insecure-registries": [ "registry.local:5000" ] }
- TLS 설정:
{ "tls": true, "tlscacert": "/path/to/ca.pem", "tlscert": "/path/to/server-cert.pem", "tlskey": "/path/to/server-key.pem", "tlsverify": true }
- 리소스 제한:
{ "default-shm-size": "64M", "default-ulimits": { "nofile": { "Name": "nofile", "Hard": 64000, "Soft": 64000 } } }
- 컨테이너 기본 런타임:
{ "default-runtime": "runc", "runtimes": { "nvidia": { "path": "/usr/bin/nvidia-container-runtime", "runtimeArgs": [] } } }
- API 및 모니터링:
{ "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']
외부 모니터링 도구:
- cAdvisor: 컨테이너 리소스 사용량 모니터링
- Prometheus: 시계열 데이터베이스 및 모니터링 시스템
- Grafana: 메트릭 시각화 도구
- Datadog: 클라우드 모니터링 서비스
- New Relic: 애플리케이션 성능 모니터링
- Elastic Stack: 로그 수집 및 분석
- Portainer: 도커 관리 UI
- 여러 도커 호스트를 관리하는 중앙 시스템
- 리소스 할당 최적화
'k8s' 카테고리의 다른 글
[쿠버네티스] 서비스와 시크릿의 보안 취약점 및 대응 전략 (0) | 2025.04.13 |
---|---|
[쿠버네티스] 서비스, 네임스페이스, 컨피그맵, 시크릿 (0) | 2025.04.13 |
Pod, ReplicaSet, Deployment (0) | 2025.04.06 |
Kubernetes Pod 배포 시 발생하는 주요 오류와 해결 방법 (0) | 2025.04.06 |
Docker Compose (0) | 2025.03.30 |