FROM [--platform=<platform>] <image> [AS <name>]
# or
FROM [--platform=<platform>] <image>[:<tag>] [AS <name>]
# or
FROM [--platform=<platform>] <image>[@<digest>] [AS <name>]
FROM을 통해서 기본 이미지를 설정할 수 있다. 또한 Dockerfile을 생성할 때 반드시 FROM으로 시작해야 한다.
이와 같은 뱃지가 달려있는 저장소는 도커에서 인증하는 공식 이미지이므로 안심하고 사용할 수 있다.
FROM에서 숙지해야 하는 사항은 다음과 같다.
ARG는 유일하게 FROM보다 먼저 사용할 수 있는 지시어이다! (FROM보다 윗줄에 올 수 있다는 뜻)
FROM 하나의 Dockerfile에 여러 번 사용할 수 있다. 이 경우 여러 개의 이미지를 생성하거나 앞서서 사용한 FROM을 통해서 생성한 이미지를 바로 다음 이미지의 종속성으로 사용할 수 있다. FROM을 사용하면 이전에 작업했던 내용을 전부 제거한다. 따라서 각 작업별 ID를 따로 기록해두어야 한다.
AS name을 사용하여 새 빌드 단계에 이름을 지정할 수 있다. 또한 이렇게 지정한 이름은 후에 COPY --from=을 통해서 이전 단계에서 빌드 이미지를 참조할 수 있다.
태그를 따로 작성하지 않는다면 latest를 기본적으로 사용한다. (가장 최신 버전)
--platform을 통해서 바탕이 될 이미지의 플랫폼을 지정할 수 있다. (linux/amd64, linux/arm64, windows/amd64 등)
RUN
RUN은 현재 이미지 위에 있는 새 레이어에서 모든 명령을 실행하는 지시어이다. 쉽게 말해 빌드 시에 이미지 내에서 터미널을 조작하는 지시어라고 생각하면 된다. RUM 지시어는 두 가지 방식이 존재한다.
RUN <command>( 쉘 방식, 명령은 쉘에서 실행되며 기본적으로 /bin/sh -c (Linux) 또는 cmd /S /C (Windows)으로 실행된다)
# or
RUN ["executable", "param1", "param2"]( exec 방식 )
exec 방식은 JSON 형태로 파싱 되기 때문에 반드시 큰 따옴표("")를 사용해야 한다.
exec 방식은 쉘을 호출하지 않는다. 따라서 $HOME 같은 쉘에서 처리되는 것들을 지원하지 않는다. 만약 원한다면 쉘 실행도 지시해주어야 한다. ex) RUN [ "echo", "$HOME" ] -> RUN [ "sh", "-c", "echo $HOME" ]
window 환경과 같은 경로 기호가 백슬래시인 경우 JSON으로 파싱 하는 과정에서 오류를 발생할 수 있으므로 이스케이프 처리를 해주어야 한다. ex) RUN ["c:\windows\system32\tasklist.exe"] -> RUN ["c:\\windows\\system32\\tasklist.exe"]
CMD
Dockerfile에는 한 개의 CMD만 존재할 수 있다. 만약 여러 개의 CMD가 온다면 마지막에 작성한 CMD만 적용이 된다! CMD를 사용하는 주된 목적은 실행 중인 컨테이너에서 기본 동작을 설정하기 위함이다. 실행 파일을 포함하거나 생략할 수 있는데 이경우에는 ENTRYPOINT도작성해야 한다.
CMD지시어에는 세 가지 방식이 존재한다.
CMD ["executable","param1","param2"]( exec 형식, 이것이 선호되는 형식 )
# or
CMD ["param1","param2"]( ENTRYPOINT에 대한 기본 매개변수 )
# or
CMD command param1 param2( 쉘 형식 )
Do not confuse RUN with CMD. RUN actually runs a command and commits the result; CMD does not execute anything at build time, but specifies the intended command for the image.
RUN과 CMD의 차이를 잘 인지해야 한다는 공식문서의 설명이다. RUN은 빌드하는 동안 실행할 명령이고 CMD는 컨테이너를 실행할 때 동작시킬 지시어이다.
와일드카드 사용 가능 ( : 모든 문자, ?: 한 글자 ) 예를 들어 hom.txt로 작성하면 home.txt, homefr.txt 등 hom으로 시작하고 .txt로끝나는 모든 파일을 추가한다. 만약 hom?.txt로 작성하면 home.txt와 같이 hom으로 시작하고 아무 한 글자만 포함되고 .txt로 끝나는 모든 파일들을 추가한다.
목적 경로(dest)에는 절대경로 혹은 상대 경로를 사용할 수 있는데 이때 상대 경로는 WORKDIR을 기준으로 사용한다. 소스 경로(src)의 상대 경로는 dockerfile의 위치 기준이다.
COPY(ADD) --link 옵션이 있는데 이 옵션은 추가할 파일이 자체적인 레이어에서 독립적으로 유지하여 이전 계층의 명령이 변경되어도 동작할 수 있도록 사용하는 옵션이다. 즉 별도의 레이어를 가지게 된다. 만약
# syntax=docker/dockerfile:1
FROM alpine
COPY --link /foo /bar
ENTRYPOINT ["executable", "param1", "param2"]
# or
ENTRYPOINT command param1 param2
예시
FROM ubuntu
ENTRYPOINT ["top", "-b"]
CMD ["-c"]
CMD와 ENTRYPOINT 상호 동작 이해하기 CMD와 ENTRYPOINT는 컨테이너가 실행될 때 동작할 명령을 정의하는 명령어이다. Dockerfile은 최소 한 개 이상의 CMD 혹은 ENTRYPOINT를 명시해야 한다. 컨테이너를 실행파일로 사용할 때에는 ENRTYPOINT를 사용한다. CMD는 Entrypoint 명령에 대한 기본 인수를 정의하거나 컨테이너에서 애드혹 명령을 실행하는 방법으로 사용해야 한다. 대체 인수를 사용하여 컨테이너를 실행하면 CMD가 재정의됩니다.
아래 테이블은 CMD + ENTRYPOINT 조합했을 때 동작하는 방식입니다.
VOLUME
컨테이너가 사라지면 그 안에 데이터도 함께 사라지게 된다. 따라서 이것을 방지하기 위해서 컨테이너 외부에서 관리할 수 있는 볼륨을 설정하도록 할 수 있다. 또한 해당 볼륨은 다른 컨테이너와 서로 공유할 수 있다.
볼륨으로 사용할 경로를 지정해주기만 하면 된다.
VOLUME ["/data"]
USER
OS의 계정을 변경하는 명령을 수행한다. 따라서 해당 계정이 실제로 존재해야 한다. 그래서 동작전에 useradd [사용자명]을 통해서 계정을 생성해 줄 수 있다. 예시
FROM microsoft/windowsservercore
# Create Windows user in the container
RUN net user /add patrick
# Set it for subsequent commands
USER patrick
해당 컨테이너를 실행할 때 patrick 계정으로 실행하게 된다.
WORKDIR
마치 터미널에서 cd 하는 것과 같이 작업할 베이스 경로를 변경하는 것이다. 사용 방법은 아래와 같다.
WORKDIR /path/to/workdir
사용 예시로
WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd
를 수행하면 /a/b/c를 확인할 수 있다. 또한 ENV를 통해 환경 변수로 지정한 뒤 WORKDIR에서 사용할 수 있다.
ENV DIRPATH=/path
WORKDIR $DIRPATH/$DIRNAME
RUN pwd
ARG
ARG는 빌드 과정에서 사용할 변수를 정의할 수 있다. 이는 빌드 내부에서만 사용될 변수이다. 빌드 시에 docker build--build-arg <varname>=<value>의 형태로 지정할 수 도 있다. (이때 내부에 해당 변수가 선언된 적이 없는 경우 경고가 발생한다.)
또한 여러 ARG를 사용할 수 있다.
FROM busybox
ARG user1
ARG buildno
# ...
ARG는 기본 값을 사용할 수 있다.
FROM busybox
ARG user1=someuser
ARG buildno=1
# ...
ARG를 사용하기 위해서는 미리 선언해주어야 한다.
FROM busybox
USER ${username:-some_user}
ARG username
USER $username
# ...
해당 dockerfile로 docker build --build-arg username=what_user .를 빌드한다면 아래와 같은 결과를 얻는다.
2번째 라인에서의 username은 선언되어 있지 않기 때문에 빈문자열로 반환되기 때문에 USER는 some_user가 된다.
4번째 라인에서의 username은 선언되어 있기 때문에 USER는 what_user가 된다.
참고 ${variable:-word}은(는) 변수가 설정된 경우 결과가 해당 값이 된다는 것을 나타냅니다. 변수가 설정되지 않은 경우 단어가 결과가 됩니다. ${variable:+word}은(는) 변수가 설정되면 단어가 결과가 되고, 그렇지 않으면 빈 문자열이 된다는 것을 나타냅니다.
ARG의 범위는 하나의 레이어이다. 따라서 다른 레이어에서는 사용할 수 없기 때문에 다시 지정해주어야 한다.
FROM busybox
ARG SETTINGS
RUN ./run/setup $SETTINGS
FROM busybox
ARG SETTINGS
RUN ./run/other $SETTINGS
사용은 ENV와 마찬가지로 $를 붙여주면 된다. 만약 ENV와 동일한 변수명을 사용할 경우 덮어쓰기가 되기 때문에 주의해야 한다.