[DevOps] Dockerfile 명령어
도커를 활용해 컨테이너화를 시키는 데에 있어서 필수적인 작업 중 하나는 docker image를 생성하는 것이며, 이는 프로젝트 최상위 디렉토리에서 Dockerfile을 통해 생성하고 설정할 수 있다.
Dockerfile은 Docker image을 어떠한 과정을 통해 빌드가 되는지를 담고 있는 파일이다.
포맷
명령어(INSTRUCTION) 인자(arguments)
각 명령문은 명령어로 시작하고 여러개의 인자로 끝난다. 인자와 구분이 쉽도록 명령어는 대문자로 써주는 것이 관례이다.
FROM
FROM <이미지>
FROM <이미지>:<태그>
하나의 Docker 이미지는 base 이미지부터 시작해서 기존 이미지 위에 새로운 이미지를 중첩해서 여러 단계의 이미지 층(layer)을 쌓아가며 만들어진다. FROM 명령문은 이 base 이미지를 지정해주기 위해서 사용되는데, 보통 Dockerfile 내에서 최상단에 위치한다. base 이미지는 일반적으로 Docker hub와 같은 Docker Hub와 같은 Docker repository에 올려놓은 잘 알려준 공개 이미지인 경우가 많다.
- Ubuntu 최신 버전을 base 이미지로 사용
FROM ubuntu:latest
- NodeJS 12를 base 이미지로 사용
FROM node:12
- Python 3.8(alpine 리눅스 기반)을 base 이미지로 사용
FROM python:3.8-alpine
WORKDIR
WORKDIR 명령문은 컨테이너 상에서 작업 디렉토리로 전환을 위해서 사용된다. WORKDIR 명령문으로 작업 디렉토리를 전환하면 그 이후에 등장하는 모든 RUN, CMD, ENTRYPOINT, COPY, ADD 명령문은 해당 디렉토리를 기준으로 실행된다.
WORKDIR <이동할 경로>
RUN
RUN ["<커맨드>", "<파라미터1>", "<파라미터2>"]
RUN
RUN 명령문은 이미지 빌드 과정에서 필요한 커맨드를 실행하기 위해서 사용된다. RUN 명령문으로 할 수 있는 작업은 많지만 보통 이미지 안에 특정 소프트웨어를 설치하기 위해서 많이 사용됩니다.
- curl 도구 설치
RUN apk add curl
- npm 패키지 설치
RUN npm install --silent
- pip 패키지 설치
RUN pip install -r requirements.txt
- apache 서버를 설치
RUN apt-get install -y apache
ENTRYPOINT 명령문
ENTRYPOINT ["<커맨드>", "<파라미터1>", "<파라미터2>"]
ENTRYPOINT <전체 커맨드>
ENTRYPOINT 명령문은 이미지를 컨테이너로 띄울 때 항상 실행되야 하는 커맨드를 지정할 때 사용한다. ENTRYPOINT 명령문은 Docker 이미지를 마치 하나의 실행 파일처럼 사용할 때 유용하다. 그 이유는 컨테이너가 뜰 때 ENTRYPOINT 명령문으로 지정된 커맨드가 실행되고, 이 커맨드로 실행된 프로세스가 죽을 때, 컨테이너도 따라서 종료되기 때문이다.
- npm start 스크립트 실행
ENTRYPOINT ["npm", "start"]
- Django 서버 실행
ENTRYPOINT ["python", "manage.py", "runserver"]
CMD
CMD ["<커맨드>", "<파라미터1>", "<파라미터2>"]
CMD ["<파라미터1>", "<파라미터2>"]
CMD <전체 커맨드>
CMD 명령문은 해당 이미지를 컨테이너로 띄울 때 디폴트로 실행할 커맨드나, ENTRYPOINT 명령문으로 지정된 커맨드에 디폴트로 넘길 파라미터를 지정할 때 사용한다.
ENTRYPOINT ["node"]
CMD ["index.js"]
node 커맨드로 디폴트값을 index.js로 실행하되, docker run 커맨드에 인자가 있고 해당 인자를 실행하고 싶은 경우, 다음과 같이 Dockerfile을 작성한다.
- node index.js 실행
docker run test
- node main.js 실행
docker run test main.js
CMD와 RUN 명령은 구분점이 있는데, RUN 명령문은 이미지 빌드 시 항상 실행되며, 한 Dockerfile에 여러 개의 RUN 명령문을 선언할 수 있습니다. CMD 명령문은 이미지를 container로 띄울 때 딱 한번 실행 기회를 가지게 되며, 이 기회마저도 docker run 커맨드에 인자를 넘길 경우 상실하게 된다.
CMD ["echo", "Hi"]
다음과 같이 Dockerfile 파일에 Hi를 출력하는 CMD 명령문이 있을 때, 인자없이 이미지를 실행하면 Hi가 출력되지만, 인자로 대신 실행될 커맨드를 넘기면 해당 인자가 출력되는 것을 알 수 있다.
$ docker run test
Hi
$ docker run test echo Bye
Bye
EXPOSE
EXPOSE <포트>
EXPOSE <포트>/<프로토콜>
EXPOSE 명령문은 네트워크 상에서 컨테이너로 들어오는 트래픽(traffic)을 리스닝하는 포트와 프로토콜을 지정하기 위해서 사용된다. 프로토콜은 TCP와 UDP 중 선택할 수 있는데 지정하지 않으면 TCP가 기본값으로 사용된다.
하지만 주의할 점은 EXPOSE 명령문으로 지정된 포트는 해당 컨테이너의 내부에서만 유효하며, 호스트(host) 컴퓨터에서는 이 포트를 바로 접근을 할 수 있는 것은 아니라는 것이다. 호스트 컴퓨터로부터 해당 포트로의 접근을 허용하려면, docker run 커맨드를 -p 옵션을 통해 호스트 컴퓨터의 특정 포트를 포워딩(forwarding)시켜줘야 한다.
- 80/TCP 포트로 리스닝
EXPOSE 80
- 9999/UDP 포트로 리스닝
EXPOSE 9999/udp
COPY/ADD
COPY <src>... <dest>
COPY ["<src>", ..., "<dest>"]
COPY 명령문은 호스트 컴퓨터에 있는 디렉토리나 파일을 Docker 이미지의 파일 시스템으로 복사하기 위해서 사용된다. 절대 경로와 상대 경로를 모두 지원하며, 상대 경로를 사용할 때는 이전에 등장하는 WORKDIR 명령문으로 작업 디렉토리를 어디로 전환을 해놨는지 고려해야한다.
- package.json 파일만 복사
COPY package.json package.json
- 이미지를 빌드한 디렉토리의 모든 파일을 컨테이너의 app/ 디렉토리로 복사
WORKDIR app/
COPY . .
ADD 명령문은 좀 더 파워풀한 COPY 명령문이다. ADD 명령문은 일반 파일 뿐만 아니라 압축 파일이나 네트워크 상의 파일도 사용할 수 있다. 이렇게 특수한 파일을 다루는 것이 아니라면 COPY 명령문을 사용하는 것이 권장된다.
ENV
ENV <키> <값>
ENV <키>=<값>
ENV 명령문은 환경 변수를 설정하기 위해 사용한다. ENV 명령문으로 설정된 환경 변수는 이미지 빌드 시에도 사용됨은 물론이고, 해당 컨테이너에서 돌아가는 애플리케이션도 접근할 수 있다
- NODE_ENV 환경 변수를 production 으로 설정
ENV NODE_ENV production
- 예를 들어 MYSQL 설치 시 패스워드와 데이터베이스 설정
FROM mysql
ENV MYSQL_ROOT_PASSWORD=1234
ENV MYSQL_DATABASE=testdb
ARG 명령문
ARG <이름>
ARG <이름>=<기본 값>
ARG 명령문은 docker build 커맨드로 이미지를 빌드 시, --build-arg 옵션을 통해 넘길 수 있는 인자를 정의하기 위해 사용한다. 예를 들어, Dockerfile에 다음과 같이 ARG 명령문으로 port를 인자로 선언해준다.
ARG port
다음과 같이 docker build 커맨드에 --build-arg 옵션에 port 값을 넘길 수가 있다.
$ docker build --build-arg port=8080 .
인자의 디폴트 값을 지정해주면, --build-arg 옵션으로 해당 인자가 넘어오지 않았을 때 사용된다.
ARG port=8080
설정된 인자 값은 다음과 같이 ${인자명} 형태로 읽어서 사용 가능하다.
CMD start.sh -h 127.0.0.1 -p ${port}
ENV 와 달리 ARG로 설정한 값은 이미지가 빌드되는 동안에만 유효하니 주의를 해야한다.