Dockerfile 생성 및 사용 입문 가이드

DockerBeginner
지금 연습하기

소개

이 Dockerfile 튜토리얼은 Dockerfile 을 생성하고 사용하는 데 대한 포괄적인 소개를 제공하도록 설계되었습니다. Docker 에 대한 경험이 있는지 여부 또는 기존 지식을 향상시키고자 하는지 여부에 관계없이, 이 가이드는 Docker 이미지와 컨테이너를 이해하는 것부터 자신만의 맞춤형 Docker 이미지를 구축하고 최적화하는 기본 사항까지 Dockerfile 의 기본 사항을 안내해 드릴 것입니다.

Docker 및 Dockerfile 소개

Docker 란 무엇인가?

Docker 는 개발자가 컨테이너라는 일관되고 격리된 환경에서 애플리케이션을 구축, 배포 및 실행할 수 있도록 하는 오픈소스 플랫폼입니다. 컨테이너는 애플리케이션과 그 종속성을 단일하고 휴대 가능한 단위로 패키징하여, 기본 인프라에 관계없이 애플리케이션이 동일한 방식으로 실행되도록 보장합니다.

Dockerfile 이해

Dockerfile 은 Docker 이미지를 구축하기 위한 일련의 지침을 포함하는 텍스트 기반 스크립트입니다. 기본 이미지, 실행할 단계 및 컨테이너의 구성 설정을 지정합니다. Dockerfile 을 사용하면 Docker 이미지를 생성하고 관리하는 프로세스를 자동화하여 애플리케이션을 빌드, 배포 및 배포하는 작업을 더욱 용이하게 만들 수 있습니다.

Dockerfile 사용의 이점

  • 일관성: Dockerfile 은 개발 환경에서 프로덕션 환경에 이르기까지 다양한 환경에서 애플리케이션이 동일한 방식으로 실행되도록 보장합니다.
  • 재현성: Dockerfile 을 통해 애플리케이션의 환경을 재현할 수 있어 문제 해결 및 디버깅을 용이하게 합니다.
  • 확장성: Docker 컨테이너는 애플리케이션의 리소스 요구 사항에 따라 쉽게 확장하거나 축소할 수 있습니다.
  • 이식성: Docker 이미지는 다양한 플랫폼 및 클라우드 환경에서 공유 및 배포될 수 있습니다.

Docker 및 Dockerfile 시작하기

Docker 및 Dockerfile 을 시작하려면 시스템에 Docker 가 설치되어 있어야 합니다. 공식 Docker 웹사이트 (https://www.docker.com/get-started) 에서 Docker 를 다운로드하여 설치할 수 있습니다. Docker 를 설치한 후에는 자신만의 Dockerfile 을 만들고 Docker 이미지를 구축하기 시작할 수 있습니다.

## Ubuntu 22.04에서 Docker 설치
sudo apt-get update
sudo apt-get install -y docker.io

다음 섹션에서는 Dockerfile 의 구조와 구문에 대해 자세히 알아보고 사용자 정의 Docker 이미지를 구축하는 방법을 배울 것입니다.

Docker 이미지와 컨테이너 이해

Docker 이미지

Docker 이미지는 Docker 컨테이너를 생성하기 위한 일련의 지침을 담고 있는 읽기 전용 템플릿입니다. 애플리케이션 코드, 런타임, 시스템 도구, 라이브러리 및 애플리케이션 실행에 필요한 모든 다른 파일을 포함합니다. Docker 이미지는 Dockerfile 을 사용하여 구축되며 Docker Hub 와 같은 Docker 레지스트리를 통해 공유 및 배포될 수 있습니다.

Docker 컨테이너

Docker 컨테이너는 Docker 이미지의 실행 가능한 인스턴스입니다. 컨테이너는 코드, 런타임, 시스템 도구 및 시스템 라이브러리 등 애플리케이션 실행에 필요한 모든 것을 포함하는 경량, 독립형 및 실행 가능한 패키지입니다. 컨테이너는 서로 그리고 호스트 운영 체제와 격리되어 일관되고 안정적인 애플리케이션 배포를 보장합니다.

## 간단한 Ubuntu 컨테이너 실행
docker run -it ubuntu:22.04 bash

이미지 레이어 및 Docker 이미지 캐시

Docker 이미지는 기본 이미지에 적용된 변경 사항 집합을 나타내는 여러 레이어로 구성됩니다. 새 이미지를 구축할 때 Docker 는 이미지 캐시를 사용하여 이러한 레이어를 재사용하여 구축 프로세스를 더욱 효율적으로 만듭니다. 이 캐싱 메커니즘은 구축 프로세스를 가속화하고 최종 이미지의 크기를 줄이는 데 도움이 됩니다.

graph TD A[기본 이미지] --> B[레이어 1] B --> C[레이어 2] C --> D[레이어 3] D --> E[애플리케이션 이미지]

Docker 이미지 푸시 및 풀

사용자 정의 Docker 이미지를 Docker Hub 와 같은 레지스트리에 푸시하여 다른 사용자와 공유하거나 다른 환경에 배포할 수 있습니다. 반대로, 레지스트리에서 이미지를 풀하여 자신의 프로젝트에서 사용할 수 있습니다.

## Docker Hub에 Docker 이미지 푸시
docker push labex/my-app:latest

## Docker Hub에서 Docker 이미지 풀
docker pull labex/my-app:latest

다음 섹션에서는 사용자 정의 Docker 이미지를 구축하는 데 사용할 수 있는 Dockerfile 의 필수 구문과 구조를 살펴볼 것입니다.

Dockerfile 구문 및 구조 기본

Dockerfile 구문

Dockerfile 은 Docker 이미지를 구축하기 위한 일련의 지침을 포함하는 텍스트 기반 스크립트입니다. Dockerfile 의 기본 구문은 다음과 같습니다.

## 주석
INSTRUCTION argument

Dockerfile 에서 가장 일반적인 지침은 다음과 같습니다.

지침 설명
FROM 빌드에 사용할 기본 이미지를 지정합니다.
RUN 빌드 중 컨테이너에서 명령을 실행합니다.
COPY 호스트에서 컨테이너로 파일 또는 디렉터리를 복사합니다.
ADD COPY와 유사하지만 원격 파일을 다운로드하고 아카이브를 추출할 수도 있습니다.
CMD 컨테이너 시작 시 기본적으로 실행할 명령을 지정합니다.
EXPOSE 컨테이너가 지정된 네트워크 포트에서 수신을 기다린다는 것을 Docker 에 알립니다.
ENV 환경 변수를 설정합니다.
WORKDIR 이후에 나오는 RUN, CMD, ENTRYPOINT, COPY, 및 ADD 지침에 대한 작업 디렉터리를 설정합니다.

Dockerfile 구조

일반적인 Dockerfile 은 다음과 같은 구조를 따릅니다.

  1. 기본 이미지: FROM 지침을 사용하여 ubuntu:22.04와 같은 기본 이미지로 시작합니다.
  2. 업데이트 및 종속성 설치: 패키지 관리자를 업데이트하고 필요한 종속성을 설치하기 위해 RUN 지침을 사용합니다.
  3. 애플리케이션 코드 복사: COPY 지침을 사용하여 애플리케이션 코드를 컨테이너로 복사합니다.
  4. 환경 변수 설정: 필요한 환경 변수를 설정하기 위해 ENV 지침을 사용합니다.
  5. 포트 노출: 애플리케이션이 수신할 포트를 노출하기 위해 EXPOSE 지침을 사용합니다.
  6. 진입점 정의: 컨테이너 시작 시 기본적으로 실행할 명령을 지정하기 위해 CMD 또는 ENTRYPOINT 지침을 사용합니다.

다음은 간단한 Python 웹 애플리케이션을 위한 Dockerfile 예제입니다.

FROM python:3.9-slim

## 패키지 관리자 업데이트 및 종속성 설치
RUN apt-get update && apt-get install -y \
  build-essential \
  libpq-dev \
  && rm -rf /var/lib/apt/lists/*

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

## Python 종속성 설치
RUN pip install --no-cache-dir -r requirements.txt

## 애플리케이션이 실행될 포트 노출
EXPOSE 8000

## 진입점 정의
CMD ["python", "app.py"]

다음 섹션에서는 Dockerfile 을 사용하여 사용자 정의 Docker 이미지를 구축하는 방법을 살펴볼 것입니다.

Dockerfile 을 사용한 사용자 정의 Docker 이미지 구축

Dockerfile 생성

사용자 정의 Docker 이미지를 구축하려면 Dockerfile 을 생성해야 합니다. 프로젝트 디렉터리에 Dockerfile이라는 새 파일을 생성하여 시작합니다. 이 파일에는 Docker 이미지 구축 지침이 포함됩니다.

Docker 이미지 구축

Dockerfile 이 준비되면 docker build 명령을 사용하여 Docker 이미지를 구축할 수 있습니다.

docker build -t labex/my-app:latest .

이 명령은 Dockerfile 을 읽고 지침을 실행하여 labex/my-app:latest라는 이름의 새 Docker 이미지를 생성합니다. 명령 끝의 .은 빌드 컨텍스트를 지정하며, Dockerfile 이 있는 디렉터리입니다.

구축 프로세스 이해

docker build 명령을 실행하면 Docker 는 Dockerfile 의 지침을 단계별로 실행합니다. 각 지침은 이미지에 새로운 레이어를 생성하고, Docker 는 이미지 캐시를 사용하여 구축 프로세스를 최적화합니다.

graph TD A[Dockerfile] --> B[빌드 단계 1] B --> C[빌드 단계 2] C --> D[빌드 단계 3] D --> E[Docker 이미지]

이미지 태깅 및 푸시

이미지를 구축한 후 특정 버전 또는 레이블로 태깅하고 Docker Hub 와 같은 Docker 레지스트리에 푸시하여 다른 사람들이 사용할 수 있도록 할 수 있습니다.

## 이미지 태깅
docker tag labex/my-app:latest labex/my-app:v1.0

## Docker Hub에 이미지 푸시
docker push labex/my-app:v1.0

이미지 풀 및 실행

이미지가 레지스트리에 사용 가능해지면 이미지를 풀하고 이미지를 기반으로 컨테이너를 실행할 수 있습니다.

## Docker Hub에서 이미지 풀
docker pull labex/my-app:v1.0

## 이미지에서 컨테이너 실행
docker run -p 8000:8000 labex/my-app:v1.0

다음 섹션에서는 효율성을 높이기 위해 Dockerfile 레이어를 최적화하는 방법에 대해 설명합니다.

효율적인 Dockerfile 레이어 최적화

Docker 이미지 레이어 이해

앞서 언급했듯이 Docker 이미지는 기본 이미지에 적용된 변경 사항 집합을 나타내는 여러 레이어로 구성됩니다. Docker 는 이러한 레이어를 캐싱하여 빌드 프로세스를 가속화합니다.

Dockerfile 레이어 최적화

효율적인 Dockerfile 레이어를 최적화하려면 다음과 같은 권장 사항을 따르세요.

  1. 관련 지침 그룹화: 이미지 캐시를 활용하기 위해 관련 지침을 함께 그룹화합니다. 예를 들어, 여러 RUN 지침 대신 단일 RUN 지침으로 모든 종속성을 설치합니다.

  2. 레이어 수 최소화: Dockerfile 의 각 지침은 새로운 레이어를 생성하므로 가능한 경우 지침을 결합하여 레이어 수를 최소화합니다.

  3. 멀티 스테이지 빌드 사용: 멀티 스테이지 빌드를 사용하면 단일 Dockerfile 에서 여러 FROM 지침을 사용할 수 있으며, 이를 통해 더 작고 효율적인 이미지를 생성할 수 있습니다.

  4. 이미지 캐시 활용: Dockerfile 지침을 이미지 캐시를 활용하는 방식으로 배열합니다. 예를 들어, Dockerfile 에서 시스템 종속성 설치와 같이 변경될 가능성이 낮은 지침을 앞쪽에 배치합니다.

다음은 최적화된 Dockerfile 예제입니다.

FROM python:3.9-slim AS base

## 시스템 종속성 설치
RUN apt-get update && apt-get install -y \
  build-essential \
  libpq-dev \
  && rm -rf /var/lib/apt/lists/*

## 비루트 사용자 생성
RUN useradd -m -s /bin/bash appuser
USER appuser

WORKDIR /app

## Python 종속성 설치
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

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

## 포트 노출 및 진입점 정의
EXPOSE 8000
CMD ["python", "app.py"]

이 예제에서는 관련 지침을 그룹화하고, 레이어 수를 최소화하며, 이미지 캐시를 활용하여 더 효율적인 Dockerfile 을 생성했습니다.

Dockerfile 에서 환경 변수 관리

Dockerfile 에서 환경 변수 정의

Dockerfile 에서 ENV 지시문을 사용하여 환경 변수를 정의할 수 있습니다. 이를 통해 컨테이너 실행 시 환경 변수를 설정하여 컨테이너 내에서 사용할 수 있도록 합니다.

ENV APP_ENV=production
ENV DB_HOST=postgres.example.com
ENV DB_PASSWORD=secret

환경 변수 참조

Dockerfile 에서 환경 변수를 정의한 후에는 다른 지침에서 $ 접두사를 사용하여 참조할 수 있습니다.

ENV APP_ENV=production
COPY config.$APP_ENV.yml /app/config.yml

실행 시 환경 변수 재설정

컨테이너를 실행할 때 -e 또는 --env 플래그를 사용하여 실행 시 환경 변수를 재설정할 수도 있습니다.

docker run -e DB_PASSWORD=newpassword labex/my-app:latest

환경 변수 관리를 위한 권장 사항

Dockerfile 에서 환경 변수를 효과적으로 관리하기 위한 권장 사항은 다음과 같습니다.

  1. 설명적인 변수 이름 사용: 각 변수의 목적을 쉽게 이해할 수 있도록 설명적이고 의미 있는 변수 이름을 사용합니다.
  2. 민감한 변수와 일반 변수 분리: 비밀번호나 API 키와 같은 민감한 변수는 Dockerfile 외부의 시크릿 또는 환경 변수로 저장합니다.
  3. 합리적인 기본값 제공: Dockerfile 에서 환경 변수에 기본값을 설정하고, 실행 시 재설정할 수 있도록 합니다.
  4. 환경 변수 문서화: 프로젝트의 README 또는 설명서에 각 환경 변수의 목적과 예상 값을 문서화합니다.

이러한 권장 사항을 따르면 Dockerfile 에서 환경 변수를 효과적으로 관리하고 컨테이너가 올바르게 구성되도록 할 수 있습니다.

컨테이너에서 포트 노출 및 명령 실행

Dockerfile 에서 포트 노출

컨테이너 외부에서 애플리케이션에 접근하려면 애플리케이션이 수신 대기하는 포트를 노출해야 합니다. Dockerfile 에서 EXPOSE 지시문을 사용하여 노출할 포트를 지정할 수 있습니다.

EXPOSE 8000
EXPOSE 5432

이 이미지를 기반으로 컨테이너를 실행할 때 -p 또는 --publish 플래그를 사용하여 노출된 포트를 호스트 시스템에 매핑할 수 있습니다.

docker run -p 8000:8000 -p 5432:5432 labex/my-app:latest

컨테이너에서 명령 실행

Dockerfile 에서 CMDENTRYPOINT 지시문을 사용하여 컨테이너 시작 시 기본적으로 실행될 명령을 지정할 수 있습니다.

CMD 지시문은 기본 명령과 해당 명령에 전달할 인수를 설정합니다. CMD 지시문이 사용되면 docker run 명령으로 기본 명령을 재정의할 수 있습니다.

CMD ["python", "app.py"]

ENTRYPOINT 지시문은 컨테이너가 시작될 때 기본적으로 실행될 애플리케이션을 설정합니다. ENTRYPOINT 명령은 docker run 명령으로 재정의할 수 없지만, 인수를 전달할 수 있습니다.

ENTRYPOINT ["python"]
CMD ["app.py"]

이 예제에서 컨테이너를 실행하면 python app.py 명령이 실행됩니다.

docker run labex/my-app:latest

RUN 지시문을 사용하여 빌드 프로세스 중에 명령을 실행할 수도 있습니다. 이는 종속성 설치 또는 애플리케이션 환경 설정과 같은 작업에 유용합니다.

RUN apt-get update && apt-get install -y \
 build-essential \
 libpq-dev \
 && rm -rf /var/lib/apt/lists/*

컨테이너에서 포트를 노출하고 명령을 실행하는 방법을 이해하면 Docker 환경 내에서 애플리케이션에 접근하고 올바르게 구성할 수 있습니다.

Docker 이미지에 파일 및 디렉터리 복사

COPY 지시문

Dockerfile 에서 COPY 지시문은 호스트 머신의 파일 또는 디렉터리를 Docker 이미지로 복사하는 데 사용됩니다. COPY 지시문의 구문은 다음과 같습니다.

COPY <src> <dest>

여기서 <src>는 호스트 머신의 파일 또는 디렉터리 경로이고, <dest>는 Docker 컨테이너 내부에서 파일 또는 디렉터리가 복사될 경로입니다.

COPY requirements.txt /app/
COPY . /app/

위의 예제에서 requirements.txt 파일과 현재 디렉터리 (.) 는 Docker 컨테이너 내부의 /app/ 디렉터리로 복사됩니다.

ADD 지시문

ADD 지시문은 COPY 지시문과 유사하지만 추가적인 기능을 제공합니다. ADD 지시문은 원격 URL 에서 파일을 복사할 수 있으며, 압축된 아카이브 (예: .tar.gz, .zip) 를 Docker 이미지 내부로 직접 추출할 수 있습니다.

ADD https://example.com/file.tar.gz /app/
ADD local_file.tar.gz /app/

위의 예제에서 file.tar.gz 파일은 원격 URL 에서 다운로드되어 /app/ 디렉터리로 추출되고, local_file.tar.gz 파일은 복사되어 /app/ 디렉터리로 추출됩니다.

파일 복사를 위한 권장 사항

Docker 이미지에 파일 및 디렉터리를 복사할 때 고려해야 할 권장 사항은 다음과 같습니다.

  1. COPY 를 ADD 보다 우선 사용: 일반적으로 ADD 대신 COPY 지시문을 사용하는 것이 좋습니다. COPY는 더 간결하고 예기치 않은 동작을 일으킬 가능성이 적습니다.
  2. 필요한 것만 복사: 애플리케이션 실행에 필요한 파일 및 디렉터리만 복사합니다. 불필요한 파일을 복사하면 Docker 이미지의 크기가 커집니다.
  3. .dockerignore 사용: 프로젝트 디렉터리에 .dockerignore 파일을 만들어 Docker 빌드 컨텍스트에 포함하지 않으려는 파일 및 디렉터리를 제외합니다.
  4. 빌드 캐시 활용: Docker 빌드 캐시를 활용하도록 COPY 지시문을 배치합니다. 변경될 가능성이 적은 파일을 복사하는 지시문을 Dockerfile 의 앞쪽에 배치합니다.

이러한 권장 사항을 따르면 Docker 이미지가 효율적이고 유지 관리 가능하며 필요한 파일 및 종속성만 포함되도록 할 수 있습니다.

유지 관리 가능한 Dockerfile 작성을 위한 권장 사항

설명적인 이름과 주석 사용

Dockerfile 과 Docker 이미지에 목적을 명확하게 나타내는 설명적인 이름을 지정합니다. 또한 Dockerfile 의 각 섹션이나 지시문의 목적을 설명하는 주석을 사용합니다.

## 최신 보안 업데이트가 포함된 베이스 이미지 사용
FROM ubuntu:22.04

## 필요한 종속성 설치
RUN apt-get update && apt-get install -y \
 build-essential \
 libpq-dev \
 && rm -rf /var/lib/apt/lists/*

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

다단계 빌드 활용

다단계 빌드는 단일 Dockerfile 에서 여러 FROM 지시문을 사용할 수 있도록 하여 더 작고 효율적인 이미지를 생성하는 데 도움이 됩니다. 특정 도구 체인을 사용하여 애플리케이션을 빌드해야 하지만 최종 이미지에 전체 도구 체인을 포함하고 싶지 않은 경우에 특히 유용합니다.

## 빌드 단계
FROM python:3.9-slim AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

## 최종 단계
FROM python:3.9-slim
COPY --from=builder /usr/local/lib/python3.9/site-packages /usr/local/lib/python3.9/site-packages
COPY --from=builder /app /app
WORKDIR /app
CMD ["python", "app.py"]

환경 변수 효과적으로 사용

앞서 설명한 바와 같이, 환경 변수를 사용하여 구성 설정을 저장하고 Dockerfile 에서 이를 관리하는 최선의 방법을 따르십시오.

레이어 및 캐시 최적화

Docker 빌드 캐시를 활용하도록 Dockerfile 지시문을 배치합니다. 관련 지시문을 그룹화하고 변경될 가능성이 적은 지시문을 Dockerfile 의 앞쪽에 배치합니다.

.dockerignore 활용

최종 Docker 이미지에 필요하지 않은 파일 및 디렉터리를 제외하기 위해 .dockerignore 파일을 사용하여 빌드 컨텍스트를 줄이고 빌드 시간을 개선합니다.

Dockerfile 문서화 및 유지 관리

이미지의 목적, 사용된 환경 변수 및 컨테이너 빌드 또는 실행에 대한 특별한 지시사항을 포함하여 Dockerfile 을 잘 문서화합니다.

이러한 권장 사항을 따르면 이해하고 유지 관리하며 확장하기 쉬운 Dockerfile 을 만들 수 있으며, Docker 기반 애플리케이션을 더욱 강력하고 확장 가능하게 만들 수 있습니다.

일반적인 Dockerfile 문제 해결

구문 오류

Dockerfile 구문이 올바른지 확인하십시오. 일반적인 구문 오류에는 지시문 누락 또는 오류, 따옴표 누락 및 들여쓰기 오류가 포함됩니다.

## 구문 오류 예시
FROM ubuntu:22.04
RUN apt-get update
    apt-get install -y build-essential

빌드 실패

Docker 빌드가 실패하면 오류 메시지를 확인하여 문제를 식별하는 데 도움이 되는 빌드 로그를 확인하십시오. 일반적인 빌드 실패 문제는 다음과 같습니다.

  • 종속성 누락
  • 파일 경로 오류
  • 권한 문제
  • 네트워크 연결 문제
## 종속성 누락으로 인한 빌드 실패 예시
RUN apt-get update && apt-get install -y \
    build-essential \
    libpq-dev \
    ## 이 패키지가 누락됨
    libssl-dev \
    && rm -rf /var/lib/apt/lists/*

실행 문제

Docker 컨테이너가 예상대로 작동하지 않으면 컨테이너 로그를 확인하여 오류 메시지 또는 예기치 않은 동작을 확인하십시오. 일반적인 실행 문제는 다음과 같습니다.

  • 환경 변수 오류
  • 포트 매핑 오류
  • 권한 문제
  • 애플리케이션 특정 오류
## 잘못된 포트 매핑으로 인한 실행 문제 예시
EXPOSE 8000
## 컨테이너를 실행할 때 포트가 올바르게 매핑되지 않음
docker run -p 8080:8000 labex/my-app:latest

Dockerfile 디버깅

다음 기술을 사용하여 Dockerfile 을 디버깅할 수 있습니다.

  1. docker build 명령과 --no-cache 플래그를 사용하여 전체 재빌드를 강제하고 이미지 캐시를 우회합니다.
  2. docker run 명령과 --rm 플래그를 사용하여 컨테이너가 종료되면 자동으로 제거하여 컨테이너 상태를 더 쉽게 검사할 수 있습니다.
  3. docker logs 명령을 활용하여 실행 중인 컨테이너의 로그를 확인합니다.
  4. docker exec 명령을 사용하여 실행 중인 컨테이너에 들어가 파일 시스템을 검사하거나 추가 명령을 실행합니다.

일반적인 Dockerfile 문제를 이해하고 적절한 디버깅 기술을 사용하면 Docker 기반 애플리케이션의 문제를 신속하게 식별하고 해결할 수 있습니다.

요약

이 Dockerfile 튜토리얼을 마치면 Dockerfile 구문 및 구조에 대한 확실한 이해를 갖게 되어 효과적으로 자신의 Docker 이미지를 생성하고 관리할 수 있게 됩니다. 유지 관리 가능한 Dockerfile 작성에 대한 최상의 방법과 일반적인 문제 해결 기술을 배울 것입니다. 이 지식을 통해 Docker 의 기능을 활용하여 개발 및 배포 워크플로를 효율적으로 개선할 수 있을 것입니다.