DevOps/Docker

[Docker] 기초 시리즈 (7) 자주 사용하는 Dockerfile 명령어

유자맛바나나 2022. 5. 8. 03:01

 

[도커 기초 시리즈 포스팅]

[Docker] 기초 시리즈 (1) 도커의 개념과 사용이유

[Docker] 기초 시리즈 (2) Ubuntu에 도커 엔진 설치

[Docker] 기초 시리즈 (3) 이미지와 컨테이너 관계, 도커 아키텍처

[Docker] 기초 시리즈 (4) 도커 이미지의 구조

[Docker] 기초 시리즈 (5) 도커 이미지 다루기 - Docker Hub(Registry)

[Docker] 기초 시리즈 (6) 도커 이미지 다루기 - 이미지 직접 생성

[Docker] 기초 시리즈 (7) 자주 사용하는 Dockerfile 명령어 (Now)

[Docker] 기초 시리즈 (8) 자주 사용하는 도커 명령어 모음

[Docker] 기초 시리즈 (9) 도커 컨테이너 - 개념, 기본 사용법

[Docker] 기초 시리즈 (10) 도커 컨테이너 - Volume 관리

 

자주 사용하는 Dockerfile 명령어

FROM

FROM <base image>:<tag>
예) FROM ubuntu:20.04
  • 베이스 이미지 지정. 반드시 한 번 이상 입력해야 함

 

WORKDIR

WORKDIR <경로>
예) WORKDIR /app
  • WORKDIR를 지정하면 그 이후 명령어는 컨테이너에서 해당 디렉토리를 기준으로 동작한다.
  • 일반적으로 절대 경로를 사용하며 상대 경로를 사용하면 가장 마지막으로 입력한 WORKDIR를 기준으로 경로를 추가한다.
  • WORKDIR는 도커 파일 내 여러 번 사용할 수 있으며, 지정하지 않을 경우 Default WORKDIR는 ' / ' 로 설정된다.

 

RUN

1) RUN <전체 명령문>
2) RUN ["<명령문>", "<파라미터1>", "<파라미터2>"]
*일반적으로 RUN <수행 명령문>을 사용한다
예) RUN apt-get update
예) RUN npm install
  • 쉘(shell)에서 커맨드를 실행하는 것 처럼 이미지를 빌드하는데 필요한 어플리케이션 또는 패지키를 설치하는데 사용한다.
  • RUN 명령어가 실행되면 새로운 이미지 layer를 생성 후 실행하고 커밋한다. 커밋된 이미지는 RUN 이후 Dockerfile에서 이뤄지는 작업에 사용된다.

COPY

COPY source(도커 호스트 OS 파일) dest(이미지 내 위치)
*dest에 상대 경로를 입력할 경우 설정된 WORKDIR에 복사한다
예) COPY build/libs/app.jar app.jar
→ 호스트 시스템 내 build/libs/app.jar 파일을 WORKDIR 위치에 app.jar라는 이름으로 복사한다
  • 호스트 시스템의 파일/디렉토리를 이미지에 복사한다.

ADD

ADD source(로컬 파일) dest(이미지 내 위치)
  • 호스트 시스템의 파일/디렉토리를 이미지에 복사한다는 점에선 동일하다. 하지만 ADD는 그 외 두 가지 기능을 더 제공한다.
    1. 자동 압축해제
      복사 대상 파일이 압축 파일(tar, tar.gz)일 경우 압축을 해제하여 복사한다
    2. Remote file URL
      호스트 시스템의 파일/디렉토리가 아닌 URL을 사용해 복사할 수 있다

 

ENTRYPOINT

1) ENTRYPOINT <전체 명령문>
2) ENTRYPOINT ["<명령문>", "<파라미터1>", "<파라미터2>"]
*일반적으로 2번을 사용한다
예1) ENTRYPOINT ["java", "-jar", "/app.jar"]예) ENTRYPOINT ["npm", "start"]
예2) ENTRYPOINT ["python", "app.py", "param1"]
  • 이미지를 컨테이너로 실행시킬 때 항상 실행되는 명령어를 지정한다.
  • 생략할 수 있으며, 생략될 경우 커맨드에 지정된 명령어로 수행

 

CMD

1) CMD ["<명령문>","<파라미터1>","<파라미터2>"] : exec form
2) CMD ["<파라미터1>","<파라미터2>"] : ENTRYPOINT의 parameter로 사용
3) CMD <전체 커맨드> : shell form
예1) CMD에 실행 명령문 입력
[Dockerfile]
CMD echo "echo from CMD" // 실행 명령문

[docker run 실행 시 실행 명령문 지정 X]
$ docker run -it <image-name>
결과) echo from CMD

[docker run 실행 시 실행 명령문 지정 O]
$ docker run -it <image-name> echo "echo from docker run"
결과) echo from docker run

예2) CMD에 ENTRYPOINT 인수로 사용
[Dockerfile]
ENTRYPOINT ["java", "-jar"]
CMD ["app.jar"]

[docker run 실행 시 실행 명령문 지정 X]
$ docker run -it <image-name>
결과) app.jar 실행

[docker run 실행 시 실행 명령문 지정 O]
$ docker run -it <image-name> run.jar
결과) run.jar 실행
  • 도커 컨테이너가 실행될 때 수행할 명령어(예1) 또는 ENTRYPOINT의 인수(arguments)가 될 수 있는데(예2), 일반적으로 ENTRYPOINT의 인수로 사용된다.
  • CMD와 ENTRYPOINT는 기본적으로 같은 동작을 한다. 차이점은 ENTRYPOINT는 명시된 내용을 바꿀 수 없지만 CMD의 경우 docker run 실행시 커맨드를 입력해 CMD에 명시된 내용을 바꿔 실행시킬 수 있다.
  • CMD는 도커 파일 내 한 번만 적용된다. 만약 여러 개의 CMD가 작성되었을 경우 마지막 CMD만 적용된다.
  • docker run 실행시 커맨드를 입력하지 않으면 CMD에서 설정한 값이 실행된다. (예1의 실행 명령문 지정 X 참고)
  • 컨테이너에 적용된 엔트리포인트와 커맨드는 docker inspect 명령어 입력 후 "Config"에서 "Cmd", "Entrypoint" 항목에서 확인할 수 있다.

 

EXPOSE

EXPOSE <port> [<port>/<protocol>...]
예)
[Dockerfile]
EXPOSE 80

[docker run 실행 시 -p로 매핑]
docker run -it <image-name> -p 80:80
결과) 80->80/tcp

[docker run 실행 시 -P로 매핑]
docker run -it <image-name> -P
결과) 15548->80/tcp
  • 컨테이너가 EXPOSE에서 지정한 포트를 수신(listen)하도록 명시한다. 즉, "이 컨테이너는 <port>를 외부에 공개한다" 라고 설정하는 것과 같다.
  • <protocol>로 TCP 또는 UDP를 지정할 수 있으며 지정하지 않을 경우 TCP가 디폴트다.
  • 주의할 점은 EXPOSE로 포트를 지정했다고 해서 해당 포트가 호스트 시스템에 공개(publish)된건 아니라는 것이다. 실제 호스트 시스템에 연결되기 위해선 docker run 명령어에서 -p 옵션으로 포트를 매핑하거나 또는 -P 옵션을 사용해야 한다.
  • [참고]
    포트 매핑 결과는 'docker ps' 명령어 입력 후 PORTS 항목에서 확인할 수 있다

 

ENV

ENV <key>=<value>
예1) ENV MY_NAME="John Doe"
→ "는 제거됨

예2) ENV MY_DOG=Rex\ The\ Dog
→ white space를 넣고 싶을땐 \(back slash)를 사용

예3) ENV MY_CAT=fluffy
  • 환경변수 설정을 하는데 사용한다. 환경변수는 이미지를 빌드할 때 사용되며, 이미지로 실행된 컨테이너에서도 접근할 수 있다.
  • docker inspect 명령어를 통해 "Config" > "Env" 항목을 통해 정의된 환경변수를 확인할 수 있고, 'docker run --env ='를 통해 수정할 수 있다.
  • value에 "를 사용할 때 escape가 아닐 경우 제거된다.
  • [참고] docker 명령어의 -e 옵션을 통한 환경변수 설정
    -e 옵션을 통해 환경변수 설정을 할 수 있다.
    예) docker run -it -e MY_HOST=fastcampus.com ubuntu bash
  • [참고] 환경변수 설정시 컨테이너에서의 영향을 고려해야 한다
    컨테이너에서도 환경변수가 남기 때문에 다른 프로그램에서 사용하는 용어를 잘못 설정할 경우 예상치 못한 side effect가 발생할 수 있다. 예컨대, ENV DEBIAN_FRONTEND=noninteractive 로 지정할 경우, apt-get 명령어가 비정상 동작할 수 있다. 이런 문제는 ARG 명령어를 사용하면 해결할 수 있다. ARG 명령어를 통해 정의된 변수는 최종 이미지에서 제거되기 때문이다.

 

ARG

1) ARG <name> : docker build 명령어에서 value 지정
2) ARG <name>=<default value> : docker build 명령어에서 지정하지 않을 때 사용할 기본값 지정
예1) ARG 사용법
[Dockerfile]
ARG user1
ARG user2=banana # user2의 기본값을 banana로 설정

[docker 명령어]
$ docker build --build-arg user1=citron
결과) 이미지 빌드시 user1은
citron, user2는 banana가 사용됨

예2) multiple build stage에서 동일 ARG 변수 사용
[Dockerfile]
FROM busybox
ARG SETTINGS
RUN ./run/setup $SETTINGS
→ RUN 실행했으므로 ARG SETTINGS는 제거됨

FROM busybox
ARG SETTINGS
RUN ./run/other $SETTINGS
  • docker build 명령어 사용시 --build-arg <varname>=<value> 옵션을 통해 넘기고 싶은 인자(argument)를 정의한다.
  • 도커파일 내 ARG 명령어를 정의하기 전의 line에서 변수를 사용하면 빈 문자열이 생성된다.
  • ARG 명령어로 생성된 변수는 각 빌드 단계(build stage)가 끝나면 제거된다. 따라서 여러 빌드 단계(multiple stages)에서 사용하고 싶다면 각 빌드 단계에 ARG 명령어로 변수를 지정해줘야 한다.
    *build stage는 하나의 RUN 명령어 실행을 말하는 듯. 즉, RUN 명령어를 실행후에는 이전에 정의한 ARG 변수를 다시 정의해줘야한다. → 예2 참고
  • 도커파일에서 정의하지 않은 인자를 docker build 명령어에서 사용할 경우 해당 인자가 사용되지 않는다는 warning 메시지를 띄운다
  • ARG 명령어로 보안상 노출되면 안되는 값은 사용하지 않을 것을 경고하고 있다. ARG 명령어와 같은 Build-time 변수는 docker history 커맨드를 통해 노출되기 때문이다.

 

LABEL

LABEL <key>:<value>
예)
[Dockerfile]
LABEL author="citronbanana"
LABEL version="1.0"

[docker 명령어]
docker image inspect --format='' <image-name>
  • 이미지에 대한 metadata(이미지의 버전 정보, 작성자, 코멘드 등)를 작성하는데 사용된다
  • docker image inspect --format='' <image-name>으로 확인할 수 있다

 

기타

# : 주석

 

❑ REFERENCE

Dockerfile Official Reference | https://docs.docker.com/engine/reference/builder/
https://www.daleseo.com/dockerfile/
https://jfrog.com/knowledge-base/a-beginners-guide-to-understanding-and-building-docker-images/