Docker 이미지 생성

DockerBeginner
지금 연습하기

소개

이 포괄적인 가이드는 처음부터 Docker 이미지를 만드는 데 필요한 기본 개념과 최상의 실무를 다룹니다. Docker 이미지를 구축하고, 크기를 최적화하며, 버전 관리 및 태깅을 관리하고, Docker 이미지의 전체 수명주기를 처리하는 방법을 배우게 될 것입니다. Docker 에 처음 접하는 사용자이든 경험이 풍부한 사용자이든, 이 튜토리얼은 Docker 이미지 생성 기술을 마스터하는 데 필요한 지식과 도구를 제공할 것입니다.

Docker 이미지 소개

Docker 이미지는 Docker 생태계에서 배포의 기본 단위인 Docker 컨테이너의 기반입니다. Docker 이미지는 Docker 컨테이너를 생성하기 위한 명령어 집합을 담고 있는 읽기 전용 템플릿입니다. 이러한 명령어에는 애플리케이션 코드, 런타임, 시스템 도구, 라이브러리 및 애플리케이션 실행에 필요한 모든 종속성이 포함됩니다.

Docker 이미지는 Dockerfile 이라는 명령어 집합을 사용하여 구축됩니다. Dockerfile 은 사용자가 Docker 이미지를 조립하는 데 필요한 모든 명령어를 포함하는 텍스트 파일입니다. Docker 이미지를 구축할 때 Docker 는 Dockerfile 의 명령어를 읽고 이미지 레이어별로 이미지를 생성합니다.

Docker 이미지는 Docker 레지스트리에 저장됩니다. Docker 레지스트리는 Docker 이미지를 중앙 집중식으로 저장하는 저장소입니다. 가장 인기 있는 Docker 레지스트리는 사용자가 Docker 이미지를 공유하고 다운로드할 수 있는 공개 레지스트리인 Docker Hub 입니다.

graph TD
    A[Dockerfile] --> B[Docker Image]
    B --> C[Docker Container]
    C --> D[Application]

Docker 이미지는 동일한 애플리케이션의 여러 인스턴스를 생성하여 다양한 환경에서 일관되고 안정적인 배포를 보장하는 데 사용될 수 있습니다. 또한 애플리케이션을 패키징하고 배포하는 방법을 제공하여 프로젝트를 공유하고 협업하기를 용이하게 합니다.

명령어 설명
docker build Dockerfile 에서 Docker 이미지를 구축합니다.
docker pull 레지스트리에서 Docker 이미지를 가져옵니다.
docker push 레지스트리에 Docker 이미지를 푸시합니다.
docker run Docker 이미지에서 Docker 컨테이너를 실행합니다.

다음 섹션에서는 처음부터 Docker 이미지를 구축하는 프로세스, 이미지 레이어 및 캐싱 관리, 이미지 크기 최적화 및 Docker 이미지 생성에 대한 최상의 실무에 대해 자세히 알아볼 것입니다.

처음부터 Docker 이미지 구축하기

처음부터 Docker 이미지를 구축하는 것은 Dockerfile 을 생성하고 docker build 명령어를 사용하여 이미지를 만드는 것을 포함합니다. 처음부터 Docker 이미지를 구축하는 단계별 가이드는 다음과 같습니다.

Dockerfile 생성

Dockerfile 은 Docker 이미지를 구축하기 위한 명령어가 포함된 텍스트 파일입니다. 다음은 예시 Dockerfile 입니다.

## 최신 Ubuntu 기반 이미지 사용
FROM ubuntu:latest

## 작업 디렉토리 설정
WORKDIR /app

## 애플리케이션 코드 복사
COPY . /app

## 필요한 종속성 설치
RUN apt-get update && apt-get install -y \
  python3 \
  python3-pip

## 애플리케이션 종속성 설치
RUN pip3 install -r requirements.txt

## 애플리케이션 포트 노출
EXPOSE 8080

## 애플리케이션 실행 명령 설정
CMD ["python3", "app.py"]

이 Dockerfile 은 최신 Ubuntu 기반 이미지를 사용하고, 작업 디렉토리를 설정하며, 애플리케이션 코드를 복사하고, 필요한 종속성을 설치하며, 애플리케이션 포트를 노출하고, 애플리케이션 실행 명령을 설정합니다.

Docker 이미지 구축

Docker 이미지를 구축하려면 Dockerfile 이 있는 동일한 디렉토리에서 다음 명령어를 실행합니다.

docker build -t my-app .

이 명령어는 현재 디렉토리의 Dockerfile 을 사용하여 태그 my-app이 있는 Docker 이미지를 구축합니다.

graph TD
    A[Dockerfile] --> B[docker build]
    B --> C[Docker Image]

Docker 이미지 검사

Docker 이미지를 구축한 후 다음 명령어를 사용하여 검사할 수 있습니다.

## 모든 Docker 이미지 목록
docker images

## Docker 이미지 세부 정보 검사
docker inspect my-app

docker images 명령어는 시스템의 모든 Docker 이미지를 나열하고, docker inspect 명령어는 특정 Docker 이미지에 대한 자세한 정보를 제공합니다.

처음부터 Docker 이미지를 구축하면 이미지 내용에 대한 완전한 제어권을 확보하여 애플리케이션과 종속성이 다양한 환경에서 올바르고 일관되게 패키징되는 것을 보장합니다.

Docker 이미지 레이어 및 캐싱 사용

Docker 이미지는 레이어로 구축되며, Dockerfile 의 각 줄은 새로운 레이어를 나타냅니다. 이러한 레이어는 Docker 에 의해 캐싱되어 빌드 프로세스를 크게 가속화할 수 있습니다.

Docker 이미지 레이어 이해

Docker 이미지를 구축할 때 Dockerfile 의 각 명령어는 새로운 레이어를 생성합니다. 이러한 레이어는 서로 쌓여 최종 이미지를 형성합니다. 예를 들어, 이전 섹션의 Dockerfile 은 다음과 같은 레이어를 생성할 것입니다.

graph TD
    A[FROM ubuntu:latest] --> B[WORKDIR /app]
    B --> C[COPY . /app]
    C --> D[RUN apt-get update && apt-get install -y ...]
    D --> E[RUN pip3 install -r requirements.txt]
    E --> F[EXPOSE 8080]
    F --> G[CMD ["python3", "app.py"]]

Docker 이미지 캐싱 활용

Docker 는 이미지의 레이어를 캐싱하므로 레이어가 변경되지 않았다면 Docker 는 다시 빌드하는 대신 캐싱된 버전을 재사용할 수 있습니다. 이는 특히 대규모 이미지의 경우 빌드 프로세스를 크게 가속화할 수 있습니다.

Docker 의 캐싱을 활용하려면 Dockerfile 의 명령어를 변경 가능성이 가장 낮은 것부터 변경 가능성이 가장 높은 것으로 순서대로 배치하는 것이 중요합니다. 이렇게 하면 빌드 프로세스 중 캐싱된 레이어를 최대한 재사용할 수 있습니다.

다음은 캐싱을 활용하는 Dockerfile 의 예입니다.

## 최신 Ubuntu 기반 이미지 사용
FROM ubuntu:latest

## 작업 디렉토리 설정
WORKDIR /app

## 애플리케이션 코드 복사
COPY . /app

## 필요한 종속성 설치
RUN apt-get update && apt-get install -y \
  python3 \
  python3-pip

## 애플리케이션 종속성 설치
RUN pip3 install -r requirements.txt

## 애플리케이션 포트 노출
EXPOSE 8080

## 애플리케이션 실행 명령 설정
CMD ["python3", "app.py"]

이 예제에서 COPY 명령어는 종속성을 설치하는 RUN 명령어보다 앞에 배치됩니다. 이렇게 하면 애플리케이션 코드가 변경되지 않으면 캐싱된 레이어를 재사용하여 빌드 프로세스를 가속화할 수 있습니다.

Docker 이미지 레이어 및 캐싱 작동 방식을 이해함으로써 빌드 프로세스를 최적화하고 Docker 이미지가 효율적이고 일관되게 구축되도록 할 수 있습니다.

Docker 이미지 크기 최적화

Docker 이미지를 작게 유지하는 것은 다운로드 속도 향상, 저장 공간 절약 및 성능 개선 등 여러 이유로 중요합니다. Docker 이미지 크기를 최적화하는 몇 가지 기술은 다음과 같습니다.

더 작은 기본 이미지 사용

Docker 이미지에 사용하는 기본 이미지는 최종 이미지 크기에 상당한 영향을 미칩니다. 기존 ubuntu 또는 centos 이미지보다 훨씬 작은 alpine 또는 scratch 이미지와 같은 가능한 한 작은 기본 이미지를 선택하십시오.

레이어 수 최소화

Dockerfile 의 각 명령어는 이미지에 새로운 레이어를 생성합니다. 레이어가 많을수록 최종 이미지 크기가 커집니다. 가능한 경우 여러 명령어를 하나의 레이어로 결합하십시오.

다단계 빌드 사용

다단계 빌드를 사용하면 Dockerfile 에서 각각 다른 기본 이미지를 사용하는 여러 FROM 문을 사용할 수 있습니다. 이는 여러 종속성이 필요한 복잡한 애플리케이션을 구축하면서 최종 이미지 크기를 작게 유지하는 데 유용할 수 있습니다.

다음은 다단계 Dockerfile 의 예입니다.

## 빌드 단계
FROM golang:1.16 AS builder
WORKDIR /app
COPY . .
RUN go build -o myapp

## 최종 단계
FROM alpine:latest
WORKDIR /app
COPY --from=builder /app/myapp .
CMD ["./myapp"]

이 예제에서 첫 번째 단계는 golang:1.16 이미지를 사용하여 애플리케이션을 빌드하고, 최종 단계는 훨씬 작은 alpine:latest 이미지를 사용하여 애플리케이션을 실행합니다.

불필요한 패키지 제거

애플리케이션 실행에 필요한 패키지 및 종속성만 설치하도록 하십시오. 불필요한 패키지 또는 도구를 제거하여 이미지 크기를 줄이십시오.

.dockerignore 사용

.dockerignore 파일을 사용하면 Docker 빌드 컨텍스트에서 파일 및 디렉토리를 제외할 수 있으며, 이는 최종 이미지 크기를 크게 줄일 수 있습니다.

이러한 기술을 따르면 Docker 이미지의 크기를 최적화하여 관리가 더욱 효율적이게 됩니다.

Docker 이미지 버전 관리 및 태깅

Docker 기반 애플리케이션을 관리하는 데 있어 Docker 이미지의 버전 관리 및 태깅은 중요한 부분입니다. 적절한 버전 관리 및 태깅을 통해 변경 사항을 추적하고 이전 버전으로 롤백하며 다양한 환경에서 일관성을 유지할 수 있습니다.

Docker 이미지 태깅

Docker 이미지를 빌드할 때 태그를 할당할 수 있습니다. 태그는 이미지의 특정 버전을 식별하는 데 사용할 수 있는 레이블입니다. 태그는 임의의 문자열이지만, 의미적 버전 관리 (예: v1.0.0, v1.1.2, v2.0.0-beta) 를 사용하는 것이 일반적입니다.

다음은 Docker 이미지를 빌드하고 태깅하는 방법의 예입니다.

docker build -t my-app:v1.0.0 .

이 명령은 태그 v1.0.0을 가진 Docker 이미지를 빌드합니다.

Docker 이미지 버전 관리

Docker 이미지를 버전 관리하는 것은 변경 사항을 추적하고 애플리케이션이 올바른 버전의 이미지로 배포되는지 확인하는 데 중요합니다. Docker 이미지 버전 관리를 위한 여러 전략이 있습니다.

  1. 의미적 버전 관리: 의미적 버전 관리 표준 (예: v1.2.3) 을 따르는 버전 번호를 사용합니다.
  2. 날짜 기반 버전 관리: 이미지가 빌드된 날짜를 포함하는 버전 번호를 사용합니다 (예: 2023-04-15).
  3. Git 기반 버전 관리: Git 커밋 해시를 버전 번호로 사용합니다 (예: abcd1234).

선택한 버전 관리 전략에 관계없이 일관성을 유지하고 버전 관리 접근 방식을 문서화하는 것이 중요합니다.

Docker 이미지 푸시 및 풀

Docker 이미지를 빌드하고 태깅한 후 Docker Hub 또는 개인 레지스트리와 같은 Docker 레지스트리에 푸시할 수 있습니다. 그런 다음 레지스트리에서 이미지를 풀어 애플리케이션을 배포하는 데 사용할 수 있습니다.

다음은 Docker Hub 에 Docker 이미지를 푸시하는 방법의 예입니다.

docker push my-app:v1.0.0

다음은 Docker Hub 에서 Docker 이미지를 풀하는 방법의 예입니다.

docker pull my-app:v1.0.0

Docker 이미지를 버전 관리하고 태깅함으로써 애플리케이션이 일관되게 배포되고 Docker 기반 인프라의 변경 사항을 쉽게 추적하고 관리할 수 있습니다.

Docker 이미지 푸시 및 풀

Docker 이미지를 빌드한 후 Docker Hub 또는 개인 레지스트리와 같은 Docker 레지스트리에 푸시하고, 레지스트리에서 풀어 애플리케이션을 배포할 수 있습니다.

Docker 이미지 푸시

레지스트리에 Docker 이미지를 푸시하려면 먼저 레지스트리에 인증해야 합니다. Docker Hub 를 사용하는 경우 docker login 명령을 사용하여 로그인할 수 있습니다.

docker login

이 명령은 Docker Hub 사용자 이름과 비밀번호를 입력하라는 메시지를 표시합니다.

로그인 후 docker push 명령을 사용하여 Docker 이미지를 레지스트리에 푸시할 수 있습니다.

docker push my-app:v1.0.0

이 명령은 my-app:v1.0.0 이미지를 Docker 레지스트리에 푸시합니다.

Docker 이미지 풀

레지스트리에서 Docker 이미지를 풀하려면 docker pull 명령을 사용할 수 있습니다.

docker pull my-app:v1.0.0

이 명령은 my-app:v1.0.0 이미지를 Docker 레지스트리에서 풀어 로컬 머신에 저장합니다.

graph TD
    A[Docker 이미지] --> B[Docker 레지스트리]
    B --> C[Docker 이미지]
    C --> D[Docker 컨테이너]

개인 레지스트리에서 이미지를 풀하려면 docker pull 명령에 레지스트리 URL 을 지정할 수 있습니다.

docker pull myregistry.example.com/my-app:v1.0.0

이 명령은 myregistry.example.com 레지스트리에서 my-app:v1.0.0 이미지를 풀어옵니다.

Docker 이미지를 푸시하고 풀함으로써 다양한 환경과 팀에서 애플리케이션을 쉽게 공유하고 배포하며, 일관되고 안정적인 배포를 보장할 수 있습니다.

Docker 이미지 생성 최적화 가이드

Docker 이미지 생성은 복잡한 과정일 수 있지만, 최적화된 방법을 따르면 효율적이고 안전하며 유지 관리 가능한 이미지를 생성할 수 있습니다. 다음은 고려해야 할 몇 가지 최적화 가이드라인입니다.

최소한의 베이스 이미지 사용

앞서 언급했듯이 alpine 또는 scratch와 같은 최소한의 베이스 이미지를 사용하면 Docker 이미지 크기를 크게 줄일 수 있습니다. 이는 디스크 공간 및 대역폭 절약뿐만 아니라 공격 표면 축소 및 잠재적 취약점 감소에도 기여합니다.

Dockerfile 구조 최적화

Docker 의 캐싱 메커니즘을 활용하기 위해 Dockerfile 명령어를 체계적으로 구성합니다. 관련 명령어를 그룹화하고, Dockerfile 상단에 변경 빈도가 낮은 명령어를 배치합니다.

다단계 빌드 활용

다단계 빌드를 통해 빌드 환경과 런타임 환경을 분리하여 더 작고 안전한 이미지를 생성할 수 있습니다. Go 나 C++ 와 같은 컴파일 언어의 경우 특히 유용하며, 한 단계에서 애플리케이션을 빌드하고 컴파일된 바이너리를 더 작은 런타임 이미지로 복사할 수 있습니다.

.dockerignore 파일 활용

.dockerignore 파일을 사용하여 Docker 빌드 컨텍스트에서 파일 및 디렉터리를 제외할 수 있습니다. 이는 빌드 컨텍스트 크기를 줄이고 빌드 속도를 높이는 데 도움이 됩니다.

취약점 스캔

trivy 또는 snyk와 같은 도구를 사용하여 Docker 이미지에 알려진 취약점 및 보안 문제를 스캔합니다. 이를 통해 애플리케이션 배포 전에 잠재적인 보안 위험을 식별하고 해결하는 데 도움이 됩니다.

안전한 관행 구현

Dockerfile 이 다음과 같은 안전한 관행을 따르도록 합니다.

  • 비루트 사용자로 프로세스 실행
  • 베이스 이미지에 latest 태그 사용 금지
  • 베이스 이미지를 최신 보안 패치로 업데이트 유지

문서화 및 자동화

Docker 이미지 생성 프로세스 (Dockerfile, 빌드 스크립트 등) 를 문서화하고 관련 정보를 포함합니다. Jenkins, CircleCI 또는 GitHub Actions 와 같은 도구를 사용하여 빌드 및 배포 프로세스를 자동화하여 일관성과 신뢰성을 확보합니다.

이러한 최적화 가이드라인을 따르면 효율적이고 안전하며 유지 관리 가능한 Docker 이미지를 생성하여 Docker 기반 애플리케이션의 견고한 기반을 마련할 수 있습니다.

Docker 이미지 수명주기 관리

건강하고 효율적인 Docker 기반 인프라를 유지 관리하는 데는 Docker 이미지 수명주기 관리가 중요한 부분입니다. 이에는 이미지 버전 관리, 오래된 이미지 정리 및 이미지 보안 업데이트 관리 등의 작업이 포함됩니다.

버전 관리 및 태깅

앞서 언급했듯이 Docker 이미지의 버전 관리 및 태깅은 변경 사항 추적 및 일관된 배포를 위해 필수적입니다. 의미적 버전 관리 (semantic versioning) 또는 날짜 기반 버전 관리와 같은 명확한 버전 관리 전략을 수립하고 Docker 이미지 전반에 일관되게 적용합니다.

오래된 이미지 정리

시간이 지남에 따라 Docker 이미지 레포지토리에는 많은 양의 오래되고 사용되지 않는 이미지가 누적되어 중요한 저장 공간을 차지할 수 있습니다. 자원을 확보하고 효율적인 이미지 레포지토리를 유지하기 위해 정기적으로 이러한 오래된 이미지를 정리합니다.

docker image prune 명령을 사용하여 사용되지 않는 Docker 이미지를 제거할 수 있습니다.

## 모든 사용되지 않는 이미지 제거
docker image prune -a

## 30일 이상 된 이미지 제거
docker image prune -a --filter "until=720h"

보안 업데이트 관리

다른 소프트웨어와 마찬가지로 Docker 베이스 이미지에도 보안 취약점이 존재할 수 있으며, 이를 해결해야 합니다. 정기적으로 보안 업데이트를 모니터링하고 최신 보안 패치를 포함하도록 Docker 이미지를 다시 빌드합니다.

trivy 또는 snyk와 같은 도구를 사용하여 Docker 이미지를 스캔하고 업데이트해야 하는 이미지를 식별할 수 있습니다.

## Docker 이미지의 취약점 스캔
trivy image my-app:v1.0.0

Docker 이미지의 수명주기를 관리하면 Docker 기반 애플리케이션이 안전하고 최신이며 효율적으로 유지될 수 있습니다.

요약

이 튜토리얼을 마치면, Docker 이미지 생성에 대한 심층적인 이해를 얻게 됩니다. 이미지를 처음부터 생성하는 방법부터 수명주기 관리까지 다룹니다. 효율적이고 안전하며 유지 관리 가능한 Docker 이미지를 생성하여 Docker 기반 애플리케이션의 견고한 기반을 마련할 수 있을 것입니다. 이 지식은 Docker 기반 배포를 간소화하고 일관되고 안정적인 애플리케이션 배포를 보장하는 데 도움이 될 것입니다.