Dockerfile을 만들 때 필요한 주요 옵션과 이들의 관계 파악
도커 이미지를 빌드할 때 사용할 파일(docs : Docker builds images by reading the instructions from a Dockerfile.) - What is 도커 이미지?
Dockerfile에 작성된 명령어를 통해 이미지를 빌드합니다.
python3.12 버전 이미지를 기반으로 /app의 실행 위치로 설정해 requirement.txt를 복사해서 설치해 jupyter를 실행하는 Dockerfile
FROM python:3.12
WORKDIR /app
COPY ./requirement.txt .
RUN pip install --upgrade pip
RUN pip install -r requirements.txt
EXPOSE 8888
CMD ["jupyter", "notebook"]
FROM: 컨테이너의 기본 베이스가 될 도커 이미지
WORKDIR: 앞으로 실행될 명령어들이 실행될 위치
위 파일에서는 /app 로 지정했으며 앞으로의 명령어 위치가 /app라는 위치로 지정된 것이다. 물론 무조건 /app에서 작업해야 하는건 아니다. 디렉터리가 없으면 만들며 해당 디렉터리에서 꼭 작업을 하지 않아도 상관없다.
아래 예시대로 WORKDIR를 3번 작성했다 치고 RUN을 실행하면 “/a/b/c” 로 현재 위치로 잡힌다. 즉, WORKDIR은 cd의 역할도 동시에 하고 있다고 볼 수 있다.
WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd
# /a/b/c
COPY(or ADD): 특정 파일(또는 디렉터리) 복사
RUN:
docs: The RUN instruction will execute any commands to create a new layer on top of the current image. The added layer is used in the next step in the Dockerfile.
→ ”당최 무슨 소리인지 알 수가 없다.”
→ 직독하자면 현재 이미지 위에 새로운 레이어를 생성하는 모든 명령을 실행하며 추가된 레이어는 Dockerfile의 다음 단계에서 사용된다고 한다. → ??
간단하고 쉽게 이미지를 빌드하는 과정에서 명령어를 실행하는 것. 으로 이해하자.
사용 형태
# Exec form:
RUN [OPTIONS] ["<command>", ... ]
# Shell form:
RUN [OPTIONS] <command> ...
CMD: 이미지 빌드가 완료되고 docker run 명령어로 컨테이너를 실행할 때 실행하는 명령어
위 파일에서는 컨테이너가 실행되고 “jupyter notebook”을 실행 명령어로 두었다.
하지만 docker run 시 이 명령어는 덮어쓰기가 가능하며 뒤에 나올 ENTRYPOINT와 같이 사용이 가능하다.
사용 형태
# Exec form:
CMD ["executable","param1","param2"]
# Exec form, as default parameters to `ENTRYPOINT`:
CMD ["param1","param2"]
# Shell form:
CMD command param1 param2
ENTRYPOINT: CMD와 비슷하게 컨테이너가 활성화될 때 실행되는 명령어이다.
CMD와 차이점: CMD는 덮어쓰기가 가능하지만 ENTRYPOINT는 덮어쓰기가 불가능하며 명령어가 n번(n≥2)작성되어 있으면 마지막 ENTRYPOINT 만 실행된다.
사용 형태
# The exec form, which is the preferred form:
ENTRYPOINT ["executable", "param1", "param2"]
# The shell form:
ENTRYPOINT command param1 param2
ENTRYPOINT ["executable", "param1", "param2"] # -> 실행 X
ENTRYPOINT ["executable", "param3", "param4"] # -> 실행 O
CMD와 ENTRYPOINT의 상호작용
앞서 CMD를 소개할 때 이 둘을 같이 사용할 수 있다고 설명한 부분이 있다.
같이 사용할 때 지켜야 할 몇 가지 룰이 있다.
Docker 공식 설명. 두 명령어의 관계
| No ENTRYPOINT | ENTRYPOINT exec_entry p1_entry | ENTRYPOINT ["exec_entry", "p1_entry"] | |
|---|---|---|---|
| No CMD | error, not allowed | /bin/sh -c exec_entry p1_entry | exec_entry p1_entry |
| CMD ["exec_cmd", "p1_cmd"] | exec_cmd p1_cmd | /bin/sh -c exec_entry p1_entry | exec_entry p1_entry exec_cmd p1_cmd |
| CMD exec_cmd p1_cmd | /bin/sh -c exec_cmd p1_cmd | /bin/sh -c exec_entry p1_entry | exec_entry p1_entry /bin/sh -c exec_cmd p1_cmd |
이 테이블을 보면 이해가 안되는 것들이 있다. “ENTRYPOINT exec_entry p1_entry” & “No CMD” 까지는 CMD가 없으니까 그런거구만! 하며 이해가 되었지만 그 아래는 뭘까? CMD에서 실행한 명령어가 없어졌다. 이건 덮어쓰인건지 뭔지 알 수가 없다.
CMD or docker run command line arguments.” 라며 해당 Shell form에서는 “CMD 또는 docker run 인자”가 무시되어질 것이라고 적혀져있고 이로 인해 위 테이블과 같은 현상이 일어났다.위 형태말고 다른 형태를 봐보자
ENTRYPOINT ["echo"]
CMD ["hello"]
# echo "hello" 실행
ENTRYPOINT ["python3"]
CMD ["app.py"]
# python3 app.py 실행
RUN vs CMD vs ENTRYPOINT 그럼 이건 차이가 뭘까?
EXPOSE: 컨테이너가 사용할 포트 명시(optional arg : protocol)
해당 컨테이너가 사용할 Port에 대한 설명을 명시해주는 역할만 할 뿐 EXPOSE에 작성한 Port를 무조건적으로 사용하는 것은 아니다.
실제 포트 연결은 docker run -p 옵션을 통해 진행된다.
사용 형태
EXPOSE 80 # default protocol : tcp
EXPOSE 80/tcp
EXPOSE 80/udp
# 같은 경로(명령어를 실행 할 디렉터리)에 Dockerfile이 있어야 한다.
$ docker buildx build -t [tag_name] .
# 만약 파일명이 Dockerfile이 아닌 다른 파일명(Dockerfile-ubuntu)인 경우
$ docker buildx build -t [tag_name] -f Dockerfile-ubuntu .