Dockerfile에 작성하는 지시어들은
어떤 것들이 있을까?
Dockerfile의 파일명이 "Dockerfile"이 아니고 별도로 지정한 경우의 build 명령어
--
Dockerfile의 파일명은 일반적으로 그냥 "Dockerfile"이라고 저장하여 사용한다.
다만 어떠한 상황에 의해 파일명을 다르게 저장해야 하는 경우도 생긴다.
예시로
상황에 알맞게 빌드하기 위해 상황별 Dockerfile을 여러 개 저장하고 build 할 때 원하는 Dockerfile로 build를 하는 상황이다.
Dockerfile을 각각 다른 내용을 작성 후 AAA, BBB, CCC라고 총 3개의 파일을 저장하고
특정 상황마다 build를 할 때 원하는 Dockerfile을 선택하여 build한다.
이렇게 Dockerfile의 파일명이 "Dockerfile"이 아니고 다른 이름으로 저장되어 있을 때
docker build 명령어를 작성 시 어떠한 Dockerfile을 가지고 build 할지 지정해줘야 한다.
Dockerfile 파일명이 "Dockerfile"이 아닌 별도의 Dockerfile를 사용하는 이미지 빌드 명령어 형식
docker build [-f 도커파일명] [-t 이미지명] {Dockerfile경로}
"DockerfileA"이라는 Dockerfile을 가지고 이미지 빌드하는 명령어
Docker build -f DockerfileA -t nginx .
옵션 설명
-f | Dockerfile을 지정할 때 사용하는 옵션 |
--
기본 Dockerfile 지시어
--
베이스 이미지를 지정하는 지시어 형식
FROM {이미지명}
새롭게 빌드할(이미지를 만들) 이미지에 기반이 될 기본 이미지(베이스 이미지)를 지정한다.
빌드 콘텍스트의 파일을 레이어에 복사하는 지시어 형식
COPY {빌드컨텍스트경로} {레이어경로}
호스트 시스템에 존재하는 특정 소스 파일 또는 디렉터리를
Docker 이미지 파일 시스템(내부)의 소스 파일 또는 디렉터리로 복사(덮어씌운다)한다.
빌드 콘텍스트 경로 = 호스트 시스템에서 복사할 파일 or 디렉터리 경로
레이어 경로 = Docker 이미지 내부에 복사될 파일 or 디렉토리 경로
(파일 or 디렉터리가 레이어 경로로 복사하면서 새로운 레이어가 생성된다.)
명령어를 실행하는 지시어 형식
RUN {명령어}
Docker 이미지를 빌드하는 동안 컨테이너 안에서 동작하는 명령어를 지정한다.
(해당 명령어를 실행하고 나온 결과를 새로운 레이어로 저장(생성)한다.)
컨테이너 실행 시 자동으로 동작하는 명령어를 지정하는 지시어 형식
CMD {["명령어"]}
컨테이너가 실행될 때 (시작될 때) 동작할 기본 명령어를 지정한다.
즉, 컨테이너가 시작될 때 한 번 실행되는 기본 명령어를 지정하는 것이다.
레이어가 추가되는 기준
- 파일 시스템의 내용을 변경하는 부분이 있으면 일반적으로 레이어를 추가한다.
- 메타데이터에만 영향을 주는 부분은 레이어를 추가하지 않는다.
RUN 지시어와 CMD 지시어의 차이점
- RUN : 이미지를 빌드할 때 명령어를 실행
- CMD : 컨테이너가 시작될 때 명령어를 실행
- RUN : 이미지 생성 중 필요한 소프트웨어 설치 및 설정을 수행
- CMD : 컨테이너가 시작될 때 실행할 기본 명령어나 스크립트를 정의
- RUN : 여러 번 사용하여 여러 명령어 실행 가능
- CMD : 여러 번 작성은 가능하지만 마지막에 지정된 CMD 명령어만 유효하여 실행 가능
예시 지시어 설명
From node:14 | node.js 14버전을 베이스 이미지로 설치 |
COPY ./ / | 현재 빌드 컨텍스트에 있는 모든 소스 파일들(./)을 컨테이너 내부 root 디렉토리에(/) 복사한다. |
RUN npm install | npm install 명령어를 실행하여 라이브러리, 패키지 등 필요한 모듈들을 설치한다. |
CMD ["npm", "start"] | 컨테이너가 실행될 때 npm start 명령어를 실행하여 애플리케이션을 실행한다. |
동작 과정
- node.js 14버전의 이미지를 기반으로 새로운 이미지를 생성
(새로 생성된 이미지에는 node.js와 npm이 설치됨) - 현재 디렉터리(./) 즉, 빌드 콘텍스트에 있는 모든 파일과 디렉터리를 컨테이너의 root 디렉터리(/)로 복사
(컨테이너에 필요한 소스코드와 파일들이 추가됨) - 복사된 소스 코드의 root 디렉터리에서 "package.json"에 명시된 모든 종속성을 설치
- 해당 이미지로 컨테이너를 실행할 때 "npm start" 명령어가 실행되어 애플리케이션을 시작함
--
시스템과 관련된 기본 Dockerfile 지시어
--
Dockerfile에서 작성한 지시어들이 작업할 디렉토리 위치를 지정하는 지시어 형식
WORKDIR {폴더경로}
다음 지시어(명령어)들이 작업(동작)할 디렉터리의 위치를 지정하는 지시어다.
(리눅스나 윈도우의 터미널에서 폴더 위치를 이동하는 "cd" 명령어와 비슷하다.)
"WORKDIR" 지시어에서 지정한 디렉터리를 기준으로 명령어를 실행할 사용자명을 변경하는 지시어 형식
USER {유저명}
Docker 컨테이너에서 명령어를 실행할 때 해당 명령어를 사용할 기본 사용자 계정을 설정한다.
Docker 컨테이너가 실행될 때는 기본적으로 명령어들이 root 사용자로 실행된다.
root 사용자로 사용하면 실행된 프로세스가 굉장히 많은 권한을 가질 수 있다.
다만 보안상의 이유로 컨테이너가 필요 이상의 권한을 가지지 않도록 root가 아닌 사용자로 실행하는 것이 좋다.
"WORKDIR" 지시어에서 지정한 디렉토리를 기준으로 컨테이너가 사용할 포트를 지정하는 지시어 형식
EXPOSE {포트번호}
컨테이너가 실행될 때 해당 컨테이너가 수신할 네트워크 포트를 지정한다.
사실 EXPOSE 지시어를 사용하지 않아도 기본적으로 모든 포트를 사용할 수 있지만
그럼에도 EXPOSE를 사용하는 이유는 Dockerfile을 읽는 사람들이게
해당 애플리케이션이 사용하는 포트를 문서처럼 기재하기 위해서 작성하는 지시어다.
즉, 컨테이너가 어떤 포트를 사용할지를 명시적으로만 나타내기 위한 것이다.
예시 지시어 설명
FROM node:14 | Node.js 14버전의 이미지를 베이스 이미지로 설정 |
WORKDIR /app | 작업(명령어)를 작성할 위치를 app 디렉토리로 이동 |
COPY . . | 현재 빌드 컨텍스트에서 디렉토리의 모든 파일과 디렉토리를 현재 지시어를 작성 중인 app 디렉토리로 복사 |
RUN npm install | /app 디렉토리에서 "npm install" 명령어를 실행하여 종속성들을 모두 설치 |
USER node | 이제부터 (이후부터) 사용하는 명령어들은 "node" 사용자로 실행하도록 지정 |
EXPOSE 3000 | 해당 컨테이너는 3000포트를 사용한다고 명시 |
CMD ["npm", "start"] | 컨테이너 실행 시 "npm start" 명령어를 실행하도록 설정 |
동작 과정
- Node.js 14버전의 이미지를 베이스로 사용하여 애플리케이션 환경을 설정
- 애플리케이션 파일(빌드 콘텍스트의 모든 파일)을 해당 컨테이너의 "/app" 디렉터리로 복사
- 종속성(라이브러리, 패키지 등)을 설치
- 이제 애플리케이션을 root가 아닌 사용자로 실행하도록 설정
- 컨테이너는 포트 3000번에서 수신을 대기한다고 명시
- 컨테이너가 시작될 때 "npm start" 명령어를 실행하여 애플리케이션을 실행
"WORKDIR" 지시어는
이후에 사용되는 지시어들에게 영향을 줄 수 있기 때문에
가능한 FROM 지시어 다음에 바로 작성하는 것이 좋다.
그리고 해당 지시어로 특정 경로를 지정해 놓으면
기존의 Node.js 이미지에 있던 파일 시스템과 섞이지도 않고
별도의 폴더를 만들어서 관리할 수 있기 때문에
초반에 경로를 지정해 두는 것이 좋다.
--
환경 변수와 관련된 Dockerfile 지시어
--
이미지 빌드 시점에서의 환경 변수를 설정하는 지시어
ARG {변수명=변수값}
"ARG" 지시어는
"Docker build" 명령어를 통해 이미지를 빌드하는 과정에서만 사용되며
빌드가 완료된 후에는 해당 환경 변수는 내부에 저장되지 않는다.
즉, 이미지 빌드하는 동안에만 잠깐 적용하고 다시 되돌릴 환경 변수를 설정하는 지시어다.
환경 변수에 새로운 변수를 정의할 수도 있고
기존에 존재하던 변수의 값을 변경할 수도 있다.
즉, 덮어쓰기가 된다.
해당 설정은
Dockerfile에서 "ARG" 지시어로 설정하는 방법뿐만 아니라
"docker build" 명령어로 이미지를 빌드할 때 명령어에 바로 arg를 설정할 수도 있다.
"docker build [--build-arg 변수명=변수값]"
컨테이너가 실행되는 시점에서의 환경 변수를 설정하는 지시어
ENV {변수명=변수값}
"ENV" 지시어는
이미지를 빌드하는 동안만이 아니라 컨테이너로 실행하는 도중에도 지속적으로 설정이 유지된다.
즉, "ARG" 지시어와 동일하지만 추가로 컨테이너로 실행하는 도중에도 해당 설정이 유지가 된다.
해당 설정은
Dockerfile에서 "ENV" 지시어로 설정하는 방법뿐만 아니라
"docker run" 명령어로 컨테이너를 실행할 때 명령어에 바로 env를 설정할 수 있다.
"docker run [-e 변수명=변수값]"
"ARG"와 "ENV" 지시어의 차이는
컨테이너를 실행할 때 환경 변수가 유지되는지에 대한 여부뿐이다.
ENV 지시어와 메타데이터의 Env는 별개이다.
ENV 지시어는 사용할 환경 변수를 설정하는 것이고
메타데이터의 Env는 이미지에 대한 정보를 설명하는 용도로 사용된 것이다.
예시 지시어 설명
ARG COLOR=red | 환경 변수에 COLOR라는 변수를 설정하고 red라는 값으로 정의한다. |
ENV COLOR=red | 환경 변수에 COLOR라는 변수를 설정하고 red라는 값으로 정의한다. |
--
프로세스를 실행하는 Dockerfile 지시어
--
해당 지시어들은 컨테이너가 실행될 때 자동으로 실행되는 지시어다.
컨테이너가 실행될 때 동작하는 기본 명령어를 설정하는 지시어 형식
CMD {["명령어"]}
"CMD" 지시어는
컨테이너가 실행될 때 처음으로 수행할 명령어를 지정하는 지시어다.
해당 지시어는 Dockerfile 내에서 여러 번 작성할 수 있지만
동작하는 것은 가장 마지막에 작성된 "CMD" 지시어가 동작하고 나머지 "CMD"지시어는 동작하지 않는다.
즉, Dockefile 내에서 "CMD" 지시어는 단 한 번만 동작한다.
명령어를 작성할 때에는 띄어쓰기를 구분할 수 없어서
띄어쓰기를 기준으로 나누어 배열 형태로 정의해야 한다.
해당 지시어를 생략하면 기본으로 설정된 "CMD"가 사용된다.
컨테이너가 실행될 때 동작하는 기본 고정 명령어를 설정하는 지시어 형식
ENTRYPOINT {["명령어"]}
"ENTRYPOINT" 지시어는
"CMD" 지시어와 동일하게 컨테이너가 실행될 때 처음으로 수행할 명령어를 지정하고
단 한 번만 동작하며 배열 형태로 정의하는 것처럼 방식이 완전 동일하다.
다만 다른 점은
명령어가 고정적으로 사용하는 명령어를 설정하는 것이다.
예시로 "npm start", "npm install" 명령어처럼 "npm"이라는 부분이 중복이 된다.
이렇게 중복되는 명령어를 "ENTRYPOINT" 지시어를 통해서 관리할 수 있는데
"ENTRYPOINT" 지시어로 지정한 고정 명령어는
어떠한 명령어를 작성할 때마다 고정 명령어가 먼저 작성되는 것이다.
ENTRYPOINT ["npm"]
CMD ["start"]
라고 Dockerfile에 작성했다면
고정된 명령어 "npm"와 그 뒤에 동작할 명령어 "start"가 합쳐져서
"npm start"라는 명령어가 동작하게 된다.
다만 이러한 방식은 서로 합쳐서 정상적인 명령어가 되어야 한다.
만약 CMD 지시어에 관련 없는 명령어를 작성하면 정상적으로 명령어가 실행되지 않는다.
이러한 부분은 잘 생각해서 사용해야 한다.
역으로 생각하면 "CMD" 지시어의 명령어를 변경하여 실행할 때
의도치 않은 동작을 방지할 수도 있게 된다.
--
참고 및 출처
'Docker' 카테고리의 다른 글
클라우드 네이티브 애플리케이션 (0) | 2024.06.24 |
---|---|
멀티 스테이지 빌드 (Multi-Stage build) 란? (+실습) (0) | 2024.06.22 |
빌드 컨텍스트 (Build Context)란? (0) | 2024.06.20 |
이미지를 만드는(저장) 방법 [ image build ] (+명령어) (+IaC) (+Dockerfile 작성법) (0) | 2024.06.19 |
이미지를 만드는(저장) 방법 [ image commit ] (+명령어) (0) | 2024.06.18 |