문서의 각 단락이 어느 리비전에서 마지막으로 수정되었는지 확인할 수 있습니다. 왼쪽의 정보 칩을 통해 작성자와 수정 시점을 파악하세요.

Dockerfile | |
개발자 | 도커사(Docker, Inc.) |
발표일 | 2013년 3월 13일 |
프로그래밍 언어 | Go |
운영 체제 | 리눅스 윈도우 macOS |
종류 | 운영 체제 수준 가상화 |
라이선스 | 아파치 라이선스 2.0 |
상세 정보 | |
원저자 | 솔로몬 하익스(Solomon Hykes) |
안정화 버전 | 29.2.1[1] |
플랫폼 | 현대의 리눅스 커널이 포함된 x86-64 ARM (실험적) 하이퍼-V 기능이 포함된 x86-64 윈도우 |
정의 | 운영체제 수준 가상화를 사용하여 컨테이너라고 불리는 패키지로 소프트웨어를 전달하는 일련의 서비스형 제품군 |
핵심 소프트웨어 | 도커 엔진(Docker Engine) |
개발 시작 | 솔로몬 하익스가 dotCloud 내의 내부 프로젝트로서 프랑스에서 시작 |
최초 공개 | 2013년 샌타클래라에서 열린 PyCon에서 대중에게 처음 공개 |
초기 실행 환경 | LXC |
주요 변경 | 0.9 버전 출시와 함께 LXC를 자체 구성 요소 libcontainer로 교체 |
웹사이트 | www.docker.com |

Dockerfile은 도커 컨테이너 이미지를 빌드하기 위한 구성 파일이다. 이 파일은 텍스트 형식으로 작성되며, 컨테이너 내부의 운영 체제 환경, 소프트웨어 의존성, 애플리케이션 소스 코드, 실행 명령 등을 정의하는 일련의 명령어로 구성된다. Dockerfile을 사용하면 애플리케이션과 그 실행 환경을 코드로 정의하여 재현 가능하고 일관된 컨테이너 이미지를 생성할 수 있다.
Dockerfile의 핵심 가치는 데브옵스 및 지속적 통합/지속적 배포 파이프라인에서 자동화된 빌드 프로세스를 가능하게 한다는 점이다. 개발자는 Dockerfile을 버전 관리 시스템에 커밋함으로써, 팀원 누구나 동일한 Dockerfile을 기반으로 정확히 똑같은 컨테이너 이미지를 생성할 수 있다. 이는 "내 컴퓨터에서는 되는데"라는 문제를 해결하고, 개발, 테스트, 프로덕션 환경 간의 차이를 최소화한다.
Dockerfile은 도커 엔진의 docker build 명령어를 통해 실행된다. 엔진은 파일에 작성된 명령어들을 순차적으로 실행하며, 각 단계는 이미지 레이어를 생성한다. 이러한 레이어 캐싱 메커니즘은 빌드 시간을 단축시키는 데 기여한다. Dockerfile로 생성된 이미지는 도커 허브와 같은 레지스트리에 푸시되어 배포 및 공유될 수 있다.

Dockerfile의 지시어는 파일의 구문 분석 방식을 제어하는 특별한 유형의 주석이다. 지시어는 Dockerfile의 최상단에 위치하며, 일반적인 주석과 달리 # directive=value 형식으로 작성된다. 주요 지시어로는 syntax와 escape가 있다.
syntax 지시어는 해당 Dockerfile을 빌드할 때 사용할 도커 파일 파서의 위치를 지정한다. 이는 공식 도커 엔진에 포함된 기본 파서 대신, 사용자 정의 또는 외부 파서를 사용할 수 있게 해준다. 이를 통해 실험적인 기능을 활용하거나 특정 빌드 환경을 구성할 수 있다. escape 지시어는 Dockerfile 내에서 사용되는 이스케이프 문자를 설정한다. 기본값은 백슬래시(\)이지만, 특히 윈도우 경로를 다루는 경우 백틱(`` ```)으로 변경하여 사용할 수 있다.
이러한 지시어는 선택 사항이며, 명시적으로 선언하지 않으면 도커의 기본값이 적용된다. 지시어는 반드시 Dockerfile의 가장 첫 줄에 위치해야 하며, 빌드 컨텍스트 내에 존재하는 다른 파일을 참조할 수 없다. 지시어의 사용은 빌드 자동화 과정에서 Dockerfile의 동작을 세밀하게 제어하고, 플랫폼 간 호환성을 높이는 데 기여한다.
Dockerfile의 명령어는 컨테이너 이미지를 구성하는 레이어를 순차적으로 생성하기 위한 구체적인 지시사항이다. 각 명령어는 새로운 파일 시스템 레이어를 만들며, 이는 도커 엔진의 레이어 캐싱 기능을 통해 빌드 효율성을 높인다. 명령어는 대소문자를 구분하지 않으나, 일반적으로 가독성을 위해 대문자로 작성하는 것이 관례이다.
주요 명령어로는 베이스 이미지를 지정하는 FROM, 셸 명령어를 실행하는 RUN, 호스트의 파일을 이미지로 복사하는 COPY와 ADD, 컨테이너 실행 시 기본 명령을 정의하는 CMD와 ENTRYPOINT, 네트워크 포트를 노출하는 EXPOSE, 환경 변수를 설정하는 ENV, 작업 디렉터리를 변경하는 WORKDIR, 사용자를 전환하는 USER 등이 있다. 이러한 명령어들은 조합되어 애플리케이션의 실행 환경을 재현 가능하고 일관되게 정의한다.
명령어의 작성 순서는 빌드 성능에 직접적인 영향을 미친다. 자주 변경되지 않는 의존성 설치 명령어(RUN, COPY 등)는 파일 상단에, 자주 변경되는 애플리케이션 소스 코드 복사 명령어는 하단에 위치시키는 것이 캐시 적중률을 높이는 모범 사례이다. 또한, 각 명령어는 가능한 한 최소한의 작업을 수행하도록 분리하여 레이어 재사용성을 극대화해야 한다.

FROM 지시어는 도커 이미지를 빌드할 때 사용할 기반 이미지를 지정한다. 이는 Dockerfile에서 반드시 첫 번째로 와야 하는 유효한 지시어이며, 모든 빌드 과정은 이 명시된 기반 이미지 위에 새로운 레이어를 쌓는 방식으로 진행된다. 기반 이미지는 도커 허브(Docker Hub)와 같은 공개 레지스트리에서 가져오거나, 사용자가 직접 빌드한 프라이빗 레지스트리의 이미지를 사용할 수 있다.
FROM 지시어의 기본 문법은 FROM <image>[:<tag>] [AS <name>]이다. 여기서 <tag>를 지정하지 않으면 최신 버전을 의미하는 latest 태그가 자동으로 사용된다. 일반적으로 우분투(ubuntu), 알파인 리눅스(alpine), 노드(node), 파이썬(python)과 같은 공식 베이스 이미지를 많이 사용하며, 특정 버전을 명시하여 빌드의 재현성을 보장하는 것이 모범 사례이다. 또한 AS <name> 구문을 사용하면 멀티-스테이지 빌드에서 해당 빌드 단계에 이름을 부여하여 후속 단계에서 참조할 수 있다.
예를 들어, FROM ubuntu:22.04는 우분투 22.04 버전을 기반으로 이미지를 시작하겠다는 의미이다. FROM node:18-alpine AS builder는 경량 알파인 리눅스를 기반으로 한 노드 18 런타임 이미지를 사용하며, 이 빌드 단계를 builder라는 이름으로 참조하도록 설정한다. FROM 지시어를 통해 정의된 기반 이미지는 애플리케이션이 실행될 파일 시스템과 기본 환경을 제공하며, 이후의 RUN, COPY, CMD 등의 모든 명령어는 이 환경 내에서 실행된다.
RUN 지시어는 Dockerfile 내에서 가장 빈번하게 사용되는 명령어 중 하나이다. 이 명령어는 새 컨테이너 이미지를 빌드하는 과정에서, 현재 이미지의 상위 레이어 위에 새로운 레이어를 생성하고 그 안에서 지정된 명령어를 실행한 후 결과를 커밋한다. 실행된 명령어의 결과는 이후의 이미지 빌드 단계에서 지속적으로 사용된다.
RUN 지시어는 주로 두 가지 형식으로 사용된다. 첫 번째는 셸 형식(Shell form)으로, RUN <command>와 같이 작성하며 기본 셸(/bin/sh -c on Linux, cmd /S /C on Windows)에서 명령어를 실행한다. 두 번째는 실행 파일 형식(Exec form)으로, RUN ["executable", "param1", "param2"]와 같이 JSON 배열로 표현한다. 실행 파일 형식은 셸 프로세스를 통해 명령어를 실행하지 않으므로 셸의 환경 변수 확장이나 파이프라인 같은 기능을 사용할 수 없지만, 셸이 없는 기본 이미지에서 명령을 실행해야 하거나 셸의 신호 처리 방식을 피하고자 할 때 유용하다.
RUN 명령어의 일반적인 사용 사례는 패키지 관리자를 통해 소프트웨어 패키지를 설치하거나, 소스 코드를 컴파일하거나, 파일 시스템 내에서 디렉토리를 생성하거나 파일을 조작하는 것이다. 예를 들어, RUN apt-get update && apt-get install -y python3 명령은 우분투 기반 이미지에서 파이썬을 설치하는 데 사용된다. 여러 명령을 하나의 RUN 지시어로 결합하고 &&로 연결하는 것은 불필요한 중간 레이어를 생성하지 않고 캐시 효율성을 높이는 모범 사례이다.
각 RUN 명령은 독립적인 레이어를 생성하므로, 빌드 최적화를 위해 관련된 명령어들을 논리적으로 그룹화하는 것이 중요하다. 또한, RUN 명령 내에서 생성된 임시 파일이나 캐시는 동일한 명령어 내에서 삭제하여 최종 이미지 크기를 줄여야 한다. 이는 도커 이미지의 효율성과 보안에 기여한다.
COPY와 ADD는 Dockerfile에서 호스트 시스템의 파일이나 디렉터리를 도커 이미지 내부로 복사하는 데 사용되는 핵심 명령어이다. 두 명령어의 기본 문법은 유사하지만, 기능과 사용 사례에 중요한 차이가 있다.
COPY 명령어는 호스트의 파일이나 디렉터리를 컨테이너의 파일 시스템으로 단순히 복사하는 데 사용된다. 이 명령어의 주요 역할은 애플리케이션 소스 코드, 구성 파일, 컴파일된 바이너리 등을 이미지에 추가하는 것이다. COPY는 명시적이고 투명한 동작을 원칙으로 하며, 로컬 파일 시스템의 지정된 경로에서만 리소스를 가져온다. 빌드 컨텍스트 내에 존재하지 않는 파일을 복사하려고 하면 빌드가 실패한다.
반면, ADD 명령어는 COPY의 모든 기능을 포함하면서도 추가적인 두 가지 기능을 제공한다. 첫째, 원격 URL에서 파일을 다운로드하여 이미지 내부에 추가할 수 있다. 둘째, 호스트의 tar 아카이브 파일을 이미지 내부로 복사할 때 자동으로 압축을 해제한다. 그러나 이러한 자동 추출 기능은 예상치 못한 동작을 초래할 수 있어, 명시적으로 tar 파일을 복사한 후 RUN 명령어로 압축을 해제하는 방식이 더 선호된다.
일반적인 도커 모범 사례는 COPY를 기본 선택으로 권장한다. ADD의 자동 추출이나 원격 다운로드 기능이 명시적으로 필요한 특별한 경우가 아니라면, 더 간단하고 예측 가능한 COPY 명령어를 사용하여 이미지 빌드 과정을 명확하게 유지하는 것이 좋다. 이는 보안과 재현 가능성을 높이는 데 도움이 된다.
CMD와 ENTRYPOINT는 Dockerfile에서 컨테이너가 실행될 때 수행할 기본 명령을 정의하는 핵심 명령어이다. 두 명령어 모두 컨테이너의 생명주기와 직접적으로 연관되어 있으며, 함께 또는 따로 사용하여 컨테이너의 실행 방식을 제어한다.
CMD 명령어는 컨테이너가 시작될 때 실행될 기본 명령과 인수를 제공한다. 주요 목적은 실행 중인 컨테이너에 대한 기본값을 정의하는 것이다. Dockerfile 내에서 여러 번 사용될 수 있지만, 마지막에 작성된 CMD 명령만이 유효하다. docker run 명령을 실행할 때 새로운 명령을 인자로 주면, Dockerfile에 정의된 CMD 명령은 완전히 재정의된다. 일반적인 형식은 CMD ["executable","param1","param2"]와 같은 실행 형식(exec form)을 사용하는 것이 권장된다.
ENTRYPOINT 명령어는 컨테이너를 실행 파일처럼 구성하고자 할 때 사용한다. 이 명령어로 설정된 명령은 컨테이너가 시작될 때 항상 실행되며, docker run 명령으로 쉽게 재정의되지 않는다는 점이 CMD와 다르다. ENTRYPOINT가 설정되어 있으면, CMD는 ENTRYPOINT에 전달되는 기본 인자 역할을 하게 된다. 즉, docker run 시 추가로 주는 인자는 ENTRYPOINT 명령의 인자로 추가되어 실행된다.
두 명령어를 조합하여 사용하는 것이 일반적이다. 예를 들어, ENTRYPOINT ["nginx"]와 CMD ["-g", "daemon off;"]를 정의하면, 컨테이너는 항상 nginx 실행 파일로 시작하며, 기본 인자로 -g daemon off;를 사용한다. 사용자가 docker run my_image -c /etc/nginx/nginx.conf와 같이 실행하면, 최종 명령은 nginx -g 'daemon off;' -c /etc/nginx/nginx.conf가 되어, CMD의 기본 인자에 사용자가 제공한 인자가 추가된다. 이 방식으로 이미지를 실행 가능한 단일 목적 도구로 만들 수 있어 DevOps 및 지속적 통합 환경에서 유용하게 활용된다.
EXPOSE 지시어는 도커 컨테이너가 런타임에 특정 네트워크 포트에서 수신 대기할 것임을 선언적으로 문서화하는 데 사용된다. 이 명령은 실제로 포트를 열거나 호스트 시스템에 포트를 퍼블리싱하지는 않으며, 컨테이너 내부에서 어떤 포트가 서비스에 사용될 예정인지에 대한 메타데이터를 제공하는 역할을 한다. 이 정보는 docker run 명령에 -P 옵션을 사용할 때 또는 docker-compose.yml 파일에서 포트 매핑을 구성할 때 활용된다.
예를 들어, EXPOSE 80이라는 줄은 해당 이미지로 생성된 컨테이너가 기본적으로 HTTP 트래픽을 위한 80번 포트를 사용할 것임을 나타낸다. 실제로 호스트의 특정 포트(예: 8080)를 컨테이너의 80번 포트에 연결하려면 docker run -p 8080:80 ...과 같은 명령어를 사용해야 한다. EXPOSE 지시어는 웹 서버, 데이터베이스(MySQL, PostgreSQL), Redis와 같은 네트워크 서비스를 패키징하는 이미지를 빌드할 때 흔히 사용된다.
이 명령어의 주요 목적은 이미지의 사용자와 배포 도구(쿠버네티스, 도커 컴포즈)에게 컨테이너가 의도하는 네트워크 인터페이스를 알려주는 것이다. 따라서 이는 문서화 및 컨테이너 간 링크 설정에 도움을 주는 좋은 관행으로 간주된다. 단, 보안상의 이유로 컨테이너가 외부에 노출해야 하는 최소한의 포트만 EXPOSE 하는 것이 권장된다.
ENV 지시어는 Dockerfile 내에서 환경 변수를 설정하는 데 사용된다. 이 지시어를 통해 빌드 중인 도커 이미지 내부에 키-값 쌍 형태의 환경 변수를 정의할 수 있으며, 이 변수들은 생성된 컨테이너의 런타임 환경에 영향을 미친다.
ENV 지시어의 기본 문법은 ENV <key> <value> 또는 ENV <key>=<value> 형태이다. 하나의 ENV 지시어로 여러 개의 변수를 설정할 수도 있다. 이렇게 설정된 환경 변수는 이미지 빌드 과정 중 후속 RUN, CMD, ENTRYPOINT 명령어에서 참조될 수 있으며, 최종적으로 실행되는 컨테이너 내부에서도 유효하다. 이는 애플리케이션의 구성(예: 데이터베이스 연결 문자열, 로그 레벨, API 키 등)을 외부에 노출하지 않고 유연하게 관리하는 데 핵심적인 역할을 한다.
환경 변수를 사용함으로써 동일한 도커 이미지를 다양한 환경(개발, 스테이징, 프로덕션)에 배포할 때 설정만 변경하여 사용할 수 있다. 이는 12요소 애플리케이션 방법론의 구성(config) 저장소에 환경 변수를 사용하라는 원칙과도 일치한다. 또한, ENV로 설정된 값은 docker run 명령어 실행 시 -e 플래그를 사용하여 런타임에 재정의할 수 있어 높은 유연성을 제공한다.
ENV와 유사하게 빌드 시에만 사용되는 변수를 정의하는 ARG 지시어와는 구분된다. ARG는 빌드 시간에만 존재하는 반면, ENV로 설정된 변수는 빌드된 이미지 내부에 지속되어 컨테이너 런타임까지 영향을 미친다. 따라서 비밀키와 같은 민감한 정보는 ENV 대신 도커 시크릿이나 런타임 인자 주입 방식을 고려해야 한다.
WORKDIR 지시어는 Dockerfile 내에서 작업 디렉터리를 설정하는 데 사용된다. 이는 이후에 나오는 RUN, CMD, ENTRYPOINT, COPY, ADD 등의 명령어가 실행될 기준 경로를 정의한다. cd 명령어와 유사하게, 컨테이너 내부의 파일 시스템 경로를 변경하는 효과가 있다.
WORKDIR을 사용하면 상대 경로를 기반으로 한 명령 실행이 가능해져 Dockerfile의 가독성과 유지보수성이 향상된다. 또한, 여러 번 사용될 경우 경로는 상대적으로 해석되어 이전 WORKDIR 지시어로 설정된 경로를 기준으로 누적된다. 이는 애플리케이션 소스 코드를 복사하거나, 의존성을 설치하거나, 최종 애플리케이션을 실행할 때 명확한 작업 공간을 보장하는 데 중요하다.
예를 들어, WORKDIR /app을 선언한 후 COPY package.json . 명령을 실행하면, 호스트의 package.json 파일이 컨테이너 내부의 /app/package.json 경로로 복사된다. 만약 WORKDIR을 설정하지 않으면, 이러한 명령들은 기본 루트 디렉터리(/)를 기준으로 실행되어 파일 경로 관리가 복잡해질 수 있다.
따라서 WORKDIR은 컨테이너 이미지 빌드 과정에서 파일 시스템 구조를 체계적으로 구성하고, 애플리케이션 실행 환경을 일관되게 유지하기 위한 필수적인 명령어이다.
USER 지시어는 도커 이미지를 빌드할 때, 그리고 해당 이미지로부터 생성된 컨테이너 내에서 실행될 프로세스의 사용자(및 그룹)를 설정한다. 기본적으로 도커 컨테이너는 root 사용자로 실행되지만, 보안과 모범 사례를 위해 애플리케이션을 특권이 없는 일반 사용자로 실행하는 것이 권장된다.
USER 지시어는 USER <사용자> 또는 USER <사용자>:<그룹> 형식으로 사용된다. 여기서 지정된 사용자나 그룹은 이미지 내에 미리 존재해야 하며, 일반적으로 이전 RUN 명령어에서 groupadd나 useradd를 통해 생성된다. 이 지시어는 이후의 모든 RUN, CMD, ENTRYPOINT 명령어가 설정된 사용자 권한으로 실행되도록 영향을 미친다.
보안 강화를 위해 애플리케이션 전용 사용자를 생성하고 USER로 전환하는 것이 일반적이다. 이는 컨테이너 내부에서 발생 가능한 취약점이 호스트 시스템의 root 권한으로 확대되는 것을 방지하는 데 도움이 된다. 또한, 호스트 시스템과 볼륨을 마운트할 때 파일 시스템 권한 문제를 예방하는 데에도 유용하다.

Dockerfile의 각 명령어는 이미지를 구성하는 하나의 레이어를 생성한다. 도커 엔진은 빌드 과정에서 이러한 레이어를 캐시하여, 동일한 명령어 시퀀스가 반복될 때 이전에 생성된 레이어를 재사용함으로써 빌드 시간을 크게 단축한다. 이 캐싱 메커니즘은 Dockerfile의 작성 순서에 따라 그 효율성이 결정된다.
레이어 캐싱을 최대화하기 위한 핵심 전략은 변경 빈도가 낮은 명령어를 Dockerfile의 상단에, 변경이 빈번한 명령어를 하단에 배치하는 것이다. 예를 들어, 애플리케이션 소스 코드를 복사하는 COPY . /app 명령어는 의존성을 정의한 파일(예: package.json, requirements.txt)을 먼저 복사하고 의존성을 설치한 후에 배치하는 것이 좋다. 이렇게 하면 소스 코드 일부가 수정되어도 의존성 관련 레이어는 캐시에서 재사용할 수 있다.
또한, RUN apt-get update && apt-get install -y 패키지와 같이 여러 명령을 하나의 RUN 명령으로 결합하면 불필요한 중간 레이어 생성을 방지하고 캐시 효율성을 높일 수 있다. .dockerignore 파일을 사용하여 빌드 컨텍스트에서 불필요한 파일을 제외하는 것도 캐시 무효화를 방지하고 빌드 성능을 개선하는 중요한 방법이다.
.dockerignore 파일은 docker build 명령을 실행할 때, 빌드 컨텍스트에서 이미지에 포함하지 않을 파일과 디렉터리를 지정하는 데 사용된다. 이 파일은 Git의 .gitignore 파일과 유사한 문법과 역할을 가진다. 빌드 컨텍스트는 docker build 명령에 주어진 경로(보통 .)의 모든 파일을 도커 데몬으로 전송하는 과정을 의미한다. .dockerignore 파일을 효과적으로 사용하면 불필요한 파일 전송을 방지하여 빌드 시간을 단축하고, 최종 도커 이미지의 크기를 줄이며, 민감한 정보가 실수로 이미지에 포함되는 것을 방지할 수 있다.
.dockerignore 파일은 일반적으로 Dockerfile이 위치한 디렉터리(빌드 컨텍스트의 루트)에 위치시킨다. 각 줄에는 제외할 파일이나 디렉터리의 패턴을 작성하며, *, ?, ** 등의 와일드카드를 사용할 수 있다. 예를 들어, node_modules/, .git/, *.log, **/__pycache__/와 같은 패턴을 지정하여 빌드 과정에서 불필요한 의존성 디렉터리, 버전 관리 파일, 로그 파일, 캐시 디렉터리 등을 제외할 수 있다. 특히 Node.js의 node_modules나 Python의 __pycache__ 같은 개발 환경에서 생성되는 대용량 디렉터리를 제외하는 것은 빌드 성능 향상에 크게 기여한다.
이 파일을 사용하는 주요 이점 중 하나는 보안 강화이다. 예를 들어, 소스 코드와 함께 위치할 수 있는 .env 파일이나 비밀키가 담긴 설정 파일을 .dockerignore에 명시하여 이미지 내부로 복사되는 것을 원천적으로 차단할 수 있다. 이는 데브옵스 보안 모범 사례의 중요한一环이다. 또한, 빌드 컨텍스트 크기가 줄어들면 도커 데몬이 처리해야 할 데이터 양이 감소하여, 특히 지속적 통합 및 지속적 배포 파이프라인에서 빌드 효율성이 크게 개선된다.
멀티-스테이지 빌드는 하나의 Dockerfile 내에서 여러 개의 FROM 지시어를 사용하여 빌드 과정을 여러 단계로 나누는 고급 기법이다. 이 기법은 주로 최종 컨테이너 이미지의 크기를 최소화하고 보안성을 높이는 데 목적이 있다. 개발 도구나 컴파일러, 중간 빌드 산출물과 같이 최종 애플리케이션 실행에는 필요하지 않은 요소들을 최종 이미지에서 제외할 수 있다.
일반적인 빌드 과정에서는 소스 코드를 컴파일하거나 패키지를 빌드하기 위해 JDK, GCC, Node.js 등의 개발 도구와 라이브러리가 필요하다. 그러나 멀티-스테이지 빌드를 사용하면 첫 번째 스테이지(빌더 스테이지)에서 이러한 도구를 포함한 완전한 환경을 구성하여 애플리케이션을 빌드한 후, 두 번째 스테이지(런타임 스테이지)에서는 JRE나 경량 리눅스 배포판처럼 실행에만 필요한 최소한의 환경을 준비한다. 그런 다음 첫 번째 스테이지에서 생성된 빌드 산출물(예: 컴파일된 JAR 파일, 바이너리)만을 COPY 명령어를 통해 최종 스테이지로 복사한다.
이 방식의 주요 장점은 다음과 같다. 첫째, 최종 이미지 크기가 크게 줄어들어 저장 공간을 절약하고 이미지 풀 속도를 높인다. 둘째, 불필요한 도구와 라이브러리가 포함되지 않아 공격 표면이 줄어들어 보안이 강화된다. 셋째, 하나의 Dockerfile로 복잡한 빌드 파이프라인을 관리할 수 있어 유지보수가 용이하다. 이는 마이크로서비스 아키텍처나 CI/CD 파이프라인에서 특히 유용하게 적용된다.
Dockerfile을 작성할 때는 애플리케이션의 기능뿐만 아니라 보안을 고려하는 것이 중요하다. 취약한 Dockerfile은 컨테이너 이미지에 보안 결함을 유입시켜, 호스트 시스템이나 다른 컨테이너에 위협이 될 수 있다.
기본적으로 최소 권한의 원칙을 따라야 한다. FROM 지시어를 사용할 때는 가능한 한 경량의 베이스 이미지를 선택하고, 불필요한 패키지가 포함되지 않았는지 확인한다. 예를 들어, 알파인 리눅스는 보안과 크기 측면에서 유리한 선택지가 될 수 있다. 또한 USER 지시어를 활용하여 컨테이너 내 프로세스가 루트 사용자 권한으로 실행되지 않도록 해야 한다. 애플리케이션을 위한 전용 사용자를 생성하고, 해당 사용자로 전환하여 실행하는 것이 모범 사례이다.
보안 항목 | 권장 사례 | 비고 |
|---|---|---|
베이스 이미지 | 공식 이미지 또는 신뢰할 수 있는 출처 사용, 정기적 업데이트 | |
권한 |
| |
비밀 정보 | 빌드 인자( | 도커 시크릿 활용 |
패키지 관리 | 명시적 버전 지정, 불필요 패키지 설치 최소화 |
마지막으로, 민감한 정보를 다룰 때는 주의해야 한다. 비밀번호나 API 키와 같은 정보를 Dockerfile에 하드코딩해서는 안 된다. 대신 도커 시크릿이나 빌드 시 전달되는 인자를 사용해야 한다. 또한 COPY나 ADD 명령어를 통해 소스 코드를 복사할 때는 .dockerignore 파일을 활용하여 불필요하거나 민감한 파일이 이미지에 포함되지 않도록 관리한다. 이러한 보안 고려사항을 적용하면 더 안전하고 견고한 컨테이너 이미지를 생성할 수 있다.

docker build 명령어는 Dockerfile에 정의된 지시어를 읽어 도커 이미지를 생성하는 핵심 명령이다. 사용자는 이 명령을 통해 애플리케이션과 그 실행 환경을 하나의 표준화된 이미지로 패키징할 수 있다.
명령어의 기본 형식은 docker build [옵션] 경로이다. 여기서 '경로'는 빌드 컨텍스트의 위치를 지정하며, 일반적으로 Dockerfile과 애플리케이션 소스 코드가 있는 디렉터리를 가리킨다. 주요 옵션으로는 이미지에 태그를 부여하는 -t 또는 --tag, 사용할 Dockerfile의 이름을 지정하는 -f 또는 --file, 빌드 과정에서 사용할 인자를 설정하는 --build-arg 등이 있다. 예를 들어, docker build -t myapp:latest . 명령은 현재 디렉터리(.)를 컨텍스트로 사용하여 myapp:latest 태그를 가진 이미지를 생성한다.
빌드 프로세스는 도커 데몬이 수행한다. 클라이언트가 docker build 명령을 실행하면, 지정된 빌드 컨텍스트 전체를 데몬에게 전송한 후, Dockerfile의 각 명령어를 순차적으로 실행하여 새로운 이미지 레이어를 생성한다. 이 과정에서 레이어 캐싱 기능이 중요한데, Dockerfile의 특정 줄까지의 내용과 빌드 컨텍스트가 이전과 동일하면 해당 레이어는 캐시에서 재사용되어 빌드 시간을 단축한다.
docker build 명령은 지속적 통합 및 지속적 배포 파이프라인에서 자동화된 이미지 생성을 위해 광범위하게 사용된다. 또한, 멀티-스테이지 빌드를 지원하여 최종 이미지의 크기를 최소화하고 보안성을 높이는 고급 빌드 전략을 구현할 수 있게 해준다. 생성된 이미지는 도커 레지스트리에 푸시하거나 로컬에서 도커 컨테이너를 실행하는 데 즉시 사용할 수 있다.
빌드된 도커 이미지는 적절한 태그를 부여하고 레지스트리에 푸시하여 공유하거나 배포할 수 있다. docker build 명령어를 실행할 때 -t 또는 --tag 옵션을 사용하여 이미지에 태그를 지정한다. 태그는 일반적으로 이미지명:태그 형식을 따르며, 태그를 생략하면 자동으로 latest 태그가 부여된다. 예를 들어 docker build -t myapp:1.0 . 명령은 현재 디렉터리의 Dockerfile을 빌드하여 myapp 이미지를 생성하고 1.0 태그를 붙인다. 하나의 이미지에 여러 태그를 동시에 부여하는 것도 가능하다.
이미지를 공개 또는 사설 도커 레지스트리에 업로드하기 위해서는 먼저 docker push 명령어를 사용한다. 푸시하기 전에 레지스트리의 주소를 이미지명에 포함시켜 태그를 다시 지정해야 하는 경우가 많다. 예를 들어, 도커 허브에 푸시하려면 docker tag myapp:1.0 username/myapp:1.0으로 태그를 재지정한 후 docker push username/myapp:1.0 명령을 실행한다. 사설 레지스트리를 사용할 경우에는 레지스트리 서버의 주소와 포트를 태그에 명시한다.
작업 | 명령어 예시 | 설명 |
|---|---|---|
이미지 태깅 |
| 기존 이미지에 새로운 이름과 태그를 부여한다. |
레지스트리 로그인 |
| 푸시 전 필요한 인증을 수행한다. |
이미지 푸시 |
| 태그된 이미지를 레지스트리에 업로드한다. |
이미지 풀 |
| 레지스트리에서 이미지를 다운로드한다. |
이미지를 푸시하면 팀원이나 CI/CD 파이프라인에서 해당 이미지를 docker pull 명령으로 쉽게 가져와 사용할 수 있다. 이를 통해 애플리케이션의 실행 환경을 표준화하고, 개발부터 프로덕션에 이르는 전 과정에서 일관된 컨테이너 이미지를 보장할 수 있다.

