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"
커맨드가 실행된다.
CMD
와 ENTRYPOINT
를 혼합해서 사용할 수 도 있다. 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을 지정할수 없고 압축파일을 자동으로 풀어주지 않는다.
다시한번 강조할점은, COPY
도 ADD
와 마찬가지로 빌드 디렉토리 밖의 파일들은 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
옵션을 사용하여 env
와 log_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
한 포트도 전부 맵핑 해준다.