DevOps

[Docker] Dockerfile 작성 및 사용법 요약

nineDeveloper 2020. 3. 17. 14:34
728x90

Dockerfile 작성 및 사용법 요약

FROM

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

FROM ubuntu:18.04

RUN

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

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

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

EXPOSE

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

EXPOSE 8080

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

ENV

Environment variable을 지정할때 ENV 을 사용하면 된다
ENV 로 지정한 환경변수 는 $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 으로 지정된 환경변수는 docker image를 실행 시킬때 -e 옵션을 사용해서 override 할 수 있다

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

CMD

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

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

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

ENTRYPOINT

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

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 으로 지정된 커맨드를 override 해야 한다면 --entrypoint 옵션을 사용해서 할 수 있다

WORKDIR

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

USER

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

USER nginx

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

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

Runtimeoverride 하고 싶으면 -u 옵션을 사용하면 된다
USER 으로 지정하지 않으면 defaultroot 유저로 image가 실행된다

VOLUME

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

VOLUME ["/opt/project"]

ADD

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

ADD file /some/dir/file

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

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

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

COPY

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

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 타입을 바꿀수 있게 해준다. Linuxdefault shell["/bin/sh", "-c"] 이다

Building Docker Image

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

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

ONBUILD

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

  • -t 옵션을 사용해서 빌드된 이미지의 repository와 이름 그리고 tag도 지정해줄수 있다
    만일 tag를 지정해주지 않으면 디포트로 latesttag된다

  • Docker image를 빌드할때 로컬 소스 뿐만이 아니라 github url를 지정해줄수도 있다

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

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

  • -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 빌드가 도중에 실패하게 되면 마지막으로 실행된 instructionID를 가지고 docker run 커맨드를 실행시켜 그 상테의 docker 이미지를 실행시킬수 있다
그래서 shell 접속을 해서 실패한 Dockerfile instruction을 실행시켜서 디버깅을 할 수 있다.

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

만일 cachelayer를 사용하지 않고 새로 실행하고 싶다면 (예를 들어 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 containerbackground detache되어 실해외도록 한다
    멈추지 않고 계속해서 실행되야 하는, 즉 대부분의 production application, docker image들은 이 옵션을 설정하도록 한다
  • -p 옵션으로 호스트의 포트와 docker containerexpose한 포트를 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한 포트도 전부 맵핑 해준다

Docker 이미지, 컨테이너, 볼륨, 네트워크등 환경정리 prune

docker container prune

중지된 모든 컨테이너를 삭제한다

docker container prune

docker image prune

이름 없는 모든 이미지를 삭제한다

docker image prune

docker network prune

사용되지 않는 도커 네트워크를 모두 삭제한다

docker network prune

docker volume prune

도커 컨테이너에서 사용하지 않는 모든 도커 볼륨을 삭제한다

docker volume prune

docker system prune -a

중지된 모든 컨테이너, 사용되지 않은 모든 네트워크, 하나 이상의 컨테이너에서 사용되지 않는 모든 이미지를 삭제한다
따라서 남아있는 컨테이너 또는 이미지는 현재 실행 중인 컨테이너에서 필요하다

docker system prune -a
728x90