All Articles

자주쓰는 Dockerfile instruction들

FROM

FROM instruction을 사용하여 base image를 지정한다. 주로 ubuntu 같은 OS를 지정하게 된다. Base image를 지정할때는 ubuntu:16.04 처럼 OS와 버젼까지 정확히 지정해주는것이 좋다.

FROM ubuntu:16.04

RUN

package를 인스톨 한다든지 등등의 shell command를 해당 docker image에 실행시킬때 사용한다. 예를 들어, 해당 docker image에 nginx를 설치하고 싶다고 한다면 아래와 같이 dockerfile에 명시하면 된다:

RUN ["apt-get", "install", "-y", "nginx"]

RUN instruction은 bin/sh -c command 통해서 주어진 커맨드들을 실행시킨다. 그러므로 만일 shell이 없는 platform에서 커맨드를 실행시켜야 한다면 exec instruction을 사용해야 한다.

EXPOSE

Docker container 외부에 노출할 포트를 지정할때 사용된다. 예를 들어 port 8080을 노출하고 싶다면 아래와 같이 명시하면 된다:

EXPOSE 8080

참고로, 한개 이상의 port를 노출시켜줄수 있다. 조심해야 할 점은, EXPOSE instruction을 지정해주었다고 해서 곧바로 그 포트를 외부에서 접속할수는 없다는 것이다. 보안상 이유 때문에 docker는 포트를 자동으로 open 하지는 않는다. Docker container를 실행할때 EXPOSE를 통해서 지정된 포트를 열어주어야 한다.

ENV

Environment variable을 지정할때 ENV instruction을 사용하면 된다. ENV instruction로 지정한 환경변수 는 $variable_name이나 ${variable_name}으로 사용될 수 있다:

FROM busybox
ENV FOO /bar
WORKDIR ${FOO}   # WORKDIR /bar
ADD . $FOO       # ADD . /bar
COPY \$FOO /quux # COPY $FOO /quux

${variable_name} syntax를 사용하면 아래와 같은 옵션도 가능하다:

  • ${variable:-word}: variable이 만일 정의가 안되어 있으면 word 부분의 값이 사용된다.
  • ${variable:+word}: 위에와 밴다의 경우다. variable이 정의가 되어있으면 word 부분의 값이 사용된다. 정의가 안되어 있으면 empty string으로 지정된다.

ENV instruction으로 지정된 환경변수는 docker image를 실행 시킬때 -e 옵션을 사용해서 override 할 수 있다:

docker run -e FOO='/something-else' test 

CMD

CMD를 사용하여 docker container가 시작할때 실행할 커맨드를 지정할수 있다. RUN instruction 과 기능은 비슷하지만 차이점은 CMD는 docker image를 빌드할때 실행되는 것이 아니라 docker container가 시작될때 실행된다는 것이다. 주로 docker image로 빌드된 application을 실행할때 쓰인다:

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

참고로 CMD instruction 으로 지정된 커맨드들은 docker run 커맨드로 실행시킬때 override 할 수 있다. 그러므로 Dockerfile 에서는 CMD로 디폴트 커맨드를 지정하고 실제 docker run 커맨드를 실행시킬때는 다른 적절한 커맨드를 줄수 있다.

ENTRYPOINT

Docker image가 실행될때 실행되어야할 기본 command를 지정한ㄷ. CMD와 비슷하지만 CMD는 override 가 가능하지만 ENTRYPOINT 는 override 할 수 없다. 대신에 docker run 커맨드로 추가하는 커맨드 들은 ENTRYPOINT instruction에 지정된 커맨드에 옵션으로 추가된다:

ENTRYPOINT ["/usr/sbin/nginx"]

...

$ docker run -t -i test/test:v1 -g "daemon off"

위의 경우 /usr/sbin/nginx -g "daemon off" 커맨드가 실행된다.

CMDENTRYPOINT를 혼합해서 사용할 수 도 있다. CMD 로 지정된 옵션은 만일 docekr run 커멘드로 아무런 커맨드가 추가되지 않으면 default로 추가된다.

ENTRYPOINT ["/usr/sbin/nginx"]
CMD ["-h"]

...


$ docker run -t -i test/test:v1 -g "daemon off"  # « nginx -g "daemon off" 실행
$ docker run -t -t test/test:v1 # « nginx -h 실행

만약 정말로 ENTRYPOINT instruction 으로 지정된 커맨드를 override 해야 한다면 --entrypoint 옵션을 사용해서 할 수 있다.

WORKDIR

Working directory를 지정해준다. Linux의 cd 커맨드의 개념으로 생각하면 된다. WORDIR 마저도 override 할 수 있다. -w 옵션을 사용하면 된다.

USER

해당 docker image를 실행할 user 를 지정 해준다.

USER nginx

위의 대로 지정하면 docker image가 실행될때 docker container에서 nginx 유저로 image를 실행하게 된다. 유저 이름 뿐만이 아니라 UID 나 GID를 사용할 수 도 있다.

USER user
USER user:group
USER uid
USER uid:gid
USER user:gid
USER uid:group

Runtime 때 override 하고 싶으면 -u 옵션을 사용하면 된다. USER instruction 으로 지정하지 않으면 default로 root 유저로 image가 실행된다.

VOLUME

VOLUME instruction 을 사용하여 호스트의 directory를 docker 컨테이너에 연결시킬수 있다. 그리하여 데이터, 소스코드, 외부설정파일 등등을 docker image에 commit 하지 않고 docker container에서 사용 가능 하도록 한다. 주로 로그 수집이나 data 저장에 쓰인다.

VOLUME ["/opt/project"]

ADD

파일과 디렉토리를 호스트에서 docker image로 copy한다.

ADD file /some/dir/file

만일 ADD 할려고 하는 디렉토리가 image에 존재하고 있지 않으면 docker가 자동으로 생성한다. 생성된 directory는 0755 mode와 0 UID & GID로 생성된다.

파일 소스는 파일 이름 과 directory 이외에도 URL이 될수도 있다. Directory를 ADD하기 위해서는 /로 끝나야 한다. 주의할점은 빌드 directory 외부의 파일은 ADD 할 수 없다.

만일 ADD 할려고 하는 파일이 tar 압축파일 이면 docker가 자동으로 압축을 풀어서 ADD 한다. 한가지 더 주의할점은, ADD 할려고 하는 파일이나 디렉토리와 같은 이름의 파일이나 디렉토리가 벌써 image 상에 존재 한다면 덮어 씌우지 않는다.

COPY

ADD와 기본적으로 동일하나 차이점은 URL을 지정할수 없고 압축파일을 자동으로 풀어주지 않는다. 다시한번 강조할점은, COPYADD와 마찬가지로 빌드 디렉토리 밖의 파일들은 COPY 할 수 없다. 그 이유는, COPY (혹은 ADD) 가 호스트에서 이루어지는것이 아니라 현재 빌드 디렉토리 자체가 Docker daemon에 upload 된 후 거기서 이루어지기 때문이다.

LABEL

이름 그대로 label 을 생성한다.

LABEL version="1.0"
LABEL location="SEOUL, KOREA" type="AWESOME"

docker inspect 커맨드를 통해 label들을 확인 할 수 있다.

ARG

docker build 커맨드로 docker image를 빌드할때 설정 할 수 있는 옵션 들을 지정해준다. 예를 들어:

ARG env
ARG log_level=debug

위의 경우 docker build 커맨드로 빌드할때 --build-arg 옵션을 사용하여 envlog_level 값을 설정 해줄수 있다.

docker build --build-arg env=prod -t test/test:v1 .

Secrete key나 계정 비밀번호 같은 민감한 정보는 이러한 방식으로 지정하지 않는걸 권한다. 이렇게 지정하면 image에 그대로 남아있기 때문에 image가 노출되면 정보 또한 노출될수 있다.

SHELL

디포트로 지정되어 있는 shell 타입을 바꿀수 있게 해준다. Linux의 default shell은 ["/bin/sh", "-c"] 이다.

Building Docker Image

docker build command를 사용해서 image를 빌드 하도록 한다.

docker build -t "test/test:v1" .

ONBUILD

해당 iamge가 만일 다른 이미지의 base image로 쓰이는 경우 실행될 커맨드들을 지정할 수 있다.

  • -t 옵션을 사용해서 빌드된 이미지의 repository와 이름 그리고 tag도 지정해줄수 있다. 만일 tag를 지정해주지 않으면 디포트로 “latest”로 tag된다.
  • Docker image를 빌드할때 로컬 소스 뿐만이 아니라 github url를 지정해줄수도 있다.
docker build -t "test/test:v1" github.com/test/docker-test

Github url을 지정해주는 경우 해당 github url에 Dockerfile이 존재해야 한다.

  • -f 옵션을 사용하면 Dockerfile 경로를 지정해 줄수 있다. 파일 이름이 Dockerfile이 아니거나 Dockerfile의 위치가 다른 곳에 위치해 있을때 사용 하면 된다.
docker build -t "test/test:v1" -f /path/to/file
  • .dockerignore 파일을 사용하여 docker 이미지에 포함되면 안되는 파일들을 명시할수 있다 (.gitignore과 같은 기능이라고 생각하면 된다).

Debugging Docker Image Build

docker build 커맨드를 사용하여 Dockerfile을 실행시키면 각각의 instruction이 실행될때 마다 이미지 ID가 생성된다(예를 들어 “22d47c8cva9”). 위에서 언급 했듯이 각각의 instruction 자체가 파일시스템 즉 이미지를 생성시키는 것이므로 이미지 ID가 생성이 되는 것이다. 그러므로 만일 docker image 빌드가 도중에 실패하게 되면 마지막으로 실행된 instruction의 ID를 가지고 docker run 커맨드를 실행시켜 그 상테의 docker 이미지를 실행시킬수 있다. 그래서 shell 접속을 해서 실패한 Dockerfile instruction을 실행시켜서 디버깅을 할 수 있다.

docker run -t -i 22d47c8cva9 /bin/bash
  • Docker image를 빌드할때 이미 실행된 instruction들은 docker가 cache처럼 유지하고 있는다. 그래서 변경사항이 없다면 이미 실행된 instruction들은 다시 실행시키지 않고 이미 만들어진 파일시스템 / 이미지 부터 빌드를 시작을 한다. 그러므로 변경사항이 있는 부분만 빌드를 함으로 효율적으로 빌드를 할 수 있는것이다.

만일 cache된 layer를 사용하지 않고 새로 실행하고 싶다면 (예를 들어 apt-get update 커맨드 같은 경우) --no-cache 옵션을 docker build 커맨드에 추가해서 실행하면 된다.

docker build --no-cache -t="test/test:v1" .
  • docker history를 사용하여 docker image가 빌드된 스텝들을 볼 수 있다.

Deleting a Docker Image

docker rmi 커맨드를 사용하여 docker image를 지울수 있다.

docker rmi test/test:v1

Running Docker Container

  • docker run 커맨드를 사용해서 docker container를 실행시킨다.
  • -d 옵션을 설정함으로서 docker container가 background detache되어 실해외도록 한다. 멈추지 않고 계속해서 실행되야 하는, 즉 대부분의 production application, docker image들은 이 옵션을 설정하도록 한다.
  • -p 옵션으로 호스트의 포트와 docker container가 expose한 포트를 mapping 한다. 설정 하지 않으면 호스트의 랜덤한 포트값이 지정된다. 예를 들어 docker container의 포트 80을 로컬호스트 포트 80에 맵핑 하기 위해서는 아래와 같이 실행하면 된다:
docker run -d -p 80:80 -name test "test/test:v1" 

UDP port를 지정하기 위해서는 /udp suffix를 붙혀주면 된다.

  • -P 옵션을 사용하면 EXPOSE로 지정한 모든 포트를 호스트의 랜덤 포트로 mapping 해준다. 이 옵션은 base image에서 EXPOSE한 포트도 전부 맵핑 해준다.