Dockerfile 작성 가이드
목차
Iac(Infrasturcture as Code, 코드형 인프라) 사용 이유
- 커맨드 기반의 인프라 구성 시 사용자 실수 등의 인적 오류 가능성이 높다
- APM(Apache + PHP + MySQL)구축을 생각해보자. 설치 순서와 상호 연관성 등을 고려하여 각종 라이브러리, 환경설정 정보, 설치프로그램 요구사항과 함께 복잡한 명령어들을 고민해야한다. → 만일 잘못된 설정이 있다면 수정해야 하고 때론 재설치도 불가피하다.
- 일련의 과정을 하나의 이미지로 만들고 수정사항은 언제든 코드변경이 용이하다면 우리는 개발업무 목적을 이루는 것에만 온전히 집중 할 수 있을 것이다.
- IaC는 탄력성, 확장성, 반복성을 가지고 있어 눈송이서버가 아닌 동일환경을 보유한 서버(컨테이너)를 수십\~수백대를 운영,관리하게 해준다.
- 눈송이서버 → 여러정보가 서로 점점 얽혀가는 서버
Dockerfile ?
- Docker에서 제공하는 베이스 이미지나 사용자가 공유하는 이미지를 통해 컨테이너를 실행하고 거기에 우리가 필요한 환경설정을 들어가서 하는 경우가 있다.
- 우리가 개발하는 모드는 컨네이너 환경은 획일적(베이스 이미지)이고 동일하게 움직이지 않고 아이디어에 따라 다양하게 개발된다.
- 애플리케이션에 적용되는 새로운 환경을 사용자가 직접 정의하여 실현 할 수 있는 것이 바로 코드로서 인프라 환경을 프로비저닝하는 Dockerfile이다.
- Dockerfile은 코드(github)나 이미지(registry)등 다양한 공유방식을 통해 언제 어디서든 컨테이너로 만들 수 있다.

- Dockerfile: 원하는 환경의 Docker Image 개발에 필요한 instruction(명령)을 포함한 텍스트 파일
- docker build: Dockerfile을 사용하여 docker image생성 과정을 트리거 하는 Docker cli
- image registry: 생성된 이미지를 public 또는 private하게 저장 할 수 있는 영역
- Docker Container: Docker image에 포함된 애플리케이션 인프러에 프로세스를 붙여 서비스로 배포되는 것
Dockerfile 명령어
- FROM(layer) 📎필수
- 베이스 이미지를 지정하는 것으로 hub.docker.com에서 제공하는 공식(official) 이미지를 권장한다
- 이미지를 선택 할 때 경량화를 위하여 작은 크기의 이미지 (slim)과 리눅스 배포판인 알파인(alpine)이미지를 권장한다. 하지만, 모든 애플리케이션이 동일하지는 않다.
- 태그를 넣지 않으면 latest로 지정된다.
FROM ubuntu:24.04
FROM python:3.9-slim-buster- MAINTAINER
- 이미지를 빌드한 작성자 이름과 이메일을 작성한다.
MAINTAINER sam.moon<moon@sun.earth>- LABEL(layer)
- 이미지의 작성 목적으로 버전 타이틀, 설명, 라이선스 및 작성자 정보 등을 작성하여 이미지를 관리하는데 사용한다. 하나 이상 작성가능하다
LABEL purpose = 'Nginx for webserver'
LABEL version = '1.0'
LABEL description = 'web service application using Nginx'
#권장
LABEL purpose = 'Nginx for webserver' \\
version = '1.0' \\
description = 'web service application using Nginx'- RUN(layer)
- 설정된 기본 이미지에 패키지 업데이트, 각종 패기지 설치, 명령 실행등을 작성한다.
- 하나이상 작성 가능하다
RUN apt update
RUN apt -y install nginx
RUN apt -y install git
#권장
# RUN 명령어의 개별 수를 줄여서 여러 설치 명령을 설치하면 이미지 레이어 수 감소
# autoremove, autoclean, rm -rf /var/lib/apt/list/* 을 사용하면
# 저장되어있는 apt캐시 삭제됨 이미지 크기 감소
RUN apt update && apt install -y nginx \\
git \\
vim \\
curl \\
&& apt clean -y \\
&& apt autoremove -y \\
&& rm -rf /tmp/* \\
/var/lib/apt/lists/* \\
/var/tmp/*- CMD
- 생성된 이미지를 컨테이너로 실행 할 때 실행되는 명령이고, ENTRYPOINT 명령문으로 지정된 커멘드에 디폴트로 넘길 파라미터 지정시 사용한다.
- 여러 개의 CMD를 작성대도 마지막 하나만 처리된다.
- 일반적으로 이미지가 컨테이너 실행 시 애플리케이션 데몬이 실행되로록 하는 경우 사용된다
#Shell 방식
CMD apachectl -D FOREGROUND
#Exec 방식
CMD [\"/user/sbin/apachectl\", \"-D\", \"FOREGROUND\"]
CMD [\"nginx\", \"-g\", \"daemon off;\"]
CMD [\"python\", \"app,py\"]- ENTRYPOINT
- CMD와 마찬가지로 생성된 이미지가 컨테이너로 실행될 때 사용된다
- 컨테이너가 실행 될 때 명령어 및 인자 값을 전달하여 실행한다(CMD와 다른점)
ENTRYPOINT [\"npm\", \"start\"]
ENTRYPOINT [\"python\", \"runapp.py\"]
#예제
#동일 환경에 entrypoint.sh 쉘 스크립트 이미지에 넣고(ADD) 실행 권한 설정(RUN) 후
#컨테이더 실행 시 entrypoin.sh를 실행(ENTRYPOINT)
ADD ./entrypoint.sh/ /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOOINT [\"/bin/bash\", \"/entrypoint.sh\"]- COPY(layer)
- 호스트에서 환경 파일, 디렉토리를 이미지 않에 복사하는 경우 사용한다.
- 단순한 복사 작업만 지원. 빌드 작업 디렉토리 외부 파일은 COPY 할 수 없다.
- 복사가 필요한 명시적 작업은 ADD보다 COPY를 권장한다.(예측 가능하고 상대적으로 오류가 적다)
COPY index.html /usr/share/nginx/html
COPY ./runapp.py /
#주의
COPY . /app #작업영역 전체를 COPY 하므로 비효율적(Dockerfile 같은...)- ADD(layer)
- 호스트에서 환경 파일, 디렉토리를 이미지 안에 복사하는 경우는 COPY와 동일하다
- URL 주소에서 직접 다운로드하여 이미지에 넣을 수 있다.
- 압축파일(.tar, .tar.gz)인 경우는 지정한 경로에 압축으 풀어서 추가한다
- 빌드 작업 디렉토리 외부 파일은 ADD 할 수 없다.
- 디렉터리 추가시에는 / 로 끝나야한다
ADD index.html /usr/share/nginx/html
ADD http://emample.com/view/custom.tar.gz /add/data/
Add website.tar.gz /var/www/html- ENV(layer)
- 각종 환경 변수를 지정하는 경우 사용한다
- 애플리케이션 사용을 쉽게 하려면 사전에 구성되어야하는 환경 변수들이 있다
- JAVA_HOME
- 특정 실행파일의 경로보장하기 위한 PATH 설정
- 프로그램 버전의 등의 설정
- 반복된 표현이 사용되는 경우
- ENV 설정하면 RUN, WORKDIR 등에서 환경변수를 사용하기 용이해진다(반복을 피할 수 있다)
ENV JAVA_HOME /usr/lib/jvm/java-8-oracle
ENV PATH /usr/local/nginx/bin:$PATH
ENV Python 3.9
#예제
ENV NODE_VERSION v15.1.0
RUN curl -SLO \"http://nodejs.org/dist/$NODE_VERSION/node-$NODE_VERSION-linux-x64.tar.gz\" \\
&& tar -xzvf \"node-$NODE_VERSION-linux-x64.tar.gz\" -C /usr/local \\
&& rm \"node-$NODE_VERSION-linux-x64.tar.gz\"- EXPOSE
- 컨테이너가 호스트 네트워크를 통해 들어오는 트래픽을 listening하는 포트와 프로토콜을 지정하기 위하여 사용한다.
- Nginx or Apache : 80, 443
- cAdvisor : 8080
- portainer : 9000
- 이미지 내 애플리케이션이 사용하는 포트를 사전에 확인 하고 호스트와 연결되도록 구성하는 경우 설정한다 → docker run 시 -p 옵션을 통해 사용한다
EXPOSE 80
EXPOSE 80/tcp
EXPOSE 443
EXPOSE 443/udp- USER
- 컨테이너 기본 사용자는 root이다. 애플리케이션이 권한 없이 서비스를 실행 할 수 있을때 사용한다.
RUN [\"useradd\", \"samMoon\"]
USER samMoon
RUN [\"/bin/bash\", \"-C\", \"date\"]- WORKDIR
- 컨테이너 상에서 작업할 경로 전환을 위해 작성한다.
- WORKDIR을 설정하면 RUN, CMD, ENTRYPOIN, COPY, ADD 명령문은 해당 디렉토리를 기준으로 실행한다.
- 지정한 경로가 없으면 자동생성된다. → 컨테이너 실행 후 접속시 지정된경로에서 시작한다.
WORKDIR /workspace
WORKDIR /usr/share/ngins/html
WORKDIR /go/src/app- ARG
- docker build 시점에서 변수값을 전달하기 위해 “–build-arg=인지”를 정의하여 사용한다.
- 비말키, 계정 비밀번호 같은 민감한 정보 사용시 이미지에 그대로 노출될 위험을 줄이고 build 시에 받아서 사용이 가능하게 한다.
ARG db_name
#docker build 시 변수값을 지정하면 이미지 내부로 인자가 전달됨다.
docker buil --build-arg db_name=moondb ..
#입력 받은 인자는 다음과 같이 명령어에서 사용 가능
CMD db_start.sh -h 127.0.0.1 -d ${db_name}