임대일

4.5 도커(Docker) 이미지 빌드: 도커파일(Dockerfile) 지시어 본문

도커/개발자를 위한 쉬운 도커

4.5 도커(Docker) 이미지 빌드: 도커파일(Dockerfile) 지시어

limdae94 2024. 6. 29. 18:40
 

개발자를 위한 쉬운 도커 강의 | 데브위키 - 인프런

데브위키 | 현업 개발자가 도커를 사용한 경험을 녹여낸 새로운 커리큘럼으로 기존 교재 및 강의와 차별된 강의를 제공합니다. 단순한 명령어 사용법이 아닌 도커를 왜 사용해야하는지 대한 근

www.inflearn.com

 

1. 실습 환경

Node.js 애플리케이션 두 개를 실행하는 시나리오

Env Color App 애플리케이션은 단순히 파일을 제공해주는 것이 아니라 서버의 요청이나 사용자의 동작에 따라서 글자 혹은 색상을 변경한다. Node.js 애플리케이션 구성 및 실행 과정으로 Node.js 를 설치해야 하고, 소스코드를 다운로드 받아야 한다. 소스코드를 애플리케이션으로 빌드해야 하고 필요한 라이브러리들을 다운로드 받기 위해 npm install, start을 수행해야 한다. 이미지 빌드와 애플리케이션 빌드는 다른 개념이라는 것을 참고하자.

 

애플리케이션 빌드와 도커파일 빌드

애플리케이션 빌드는 소스코드를 실행 가능한 상태로 만드는 작업을 의미한다. 애플리케이션 빌드를 통해서 만들어낸 결과물을 애플리케이션 프로그램 혹은 아티팩트라고 부른다. 도커 이미지 빌드는 애플리케이션 빌드를 포함하여 이미지를 실행 가능한 상태로 만드는 작업을 의미한다.

 

app.js

app.get 안에 루트 / 는 요청 받을 URI 를 의미한다. res.render(index) 는 응답할 파일을 의미한다. 따라서 오른쪽에 index.ejs 파일이 클라이언트에게 응답이 되는 것이다.

 

URI 쿼리스트링

color, username은 클라이언트에게 응답되는 index.ejs 파일의 변수로 사용된다. 색상을 지정하고 사용자명을 지정할 수 있다. 따라서 응답되는 색상과 문구를 변경할 수 있다. app.get('/:name')은 URI 뒤에 문자열을 입력하면 페이지에 사용될 문구로 사용된다.

 

2. 기본 Dockerfile 지시어

추가된 RUN 명령

 

FROM 이미지명 # 베이스 이미지를 지정
COPY 빌드컨텍스트경로 레이어경로 # 빌드 컨텍스트의 파일을 레이어에 복사(cp) (새로운 레이어 추가)
RUN 명령어 # 명령어 실행 (새로운 레이어 추가)
CMD ["명령어"] # 컨테이너 실행 시 명령어 지정

 

docker build -f 도커파일명 -t 이미지명 Dockerfile경

docker build -f 도커파일명 -t 이미지명 Dockerfile경로 # 도커파일명이 Dockerfile이 아닌 경우 별도 지정

도커 파일의 이름이 도커 파일이 아닌 경우에는 -f 옵션을 주어서 실제 도커 파일에 해당하는 파일을 지정해야 한다.

 

Dockerfile-basic
docker build -f Dockerfile-basic -t buildapp:basic

docker build -f Dockerfile-basic -t buildapp:basic .

도커 파일이름이 지금과 다르게 Dockerfile-basic으로 설정되어 있다. -f 옵션 뒤에 도커 파일명을 작성하고 마지막에 반드시 . 을 작성해야 한다.

 

WORKDIR 폴더명, USER 유저명, EXPOSE 포트번호

WORKDIR 폴더명 # 작업 디렉토리를 지정(cd)(새로운 레이어 추가)
USER 유저명 # 명령을 실행할 사용자 변경 (su)(새로운 레이어 추가)
EXPOSE 포트번호 # 컨테이너가 사용할 포트를 명시

보통은 애플리케이션 안에 사용되는 포트를 명시하는데, EXPOSE에 설정된 포트 번호를 명시적으로 작성하여 직관적으로 포트 번호를 확인할 수 있다.

Dockerfile-meta

FROM 바로 아래에 WORKDIR 지시어를 작성하는 것을 권장한다. 작업 디렉토리가 변경되거나 의도하지 않은 파일을 작업할 수 있기 때문이다.

docker build -f Dockerfile-meta -t buildapp:meata .
docker run -d -p 3000:3000 --name buildapp-meta buildapp:meta

작성된 도커 파일을 빌드하고 실행하자.

 

localhost:3000으로 웹페이지에 접근하면 루트 / 페이지로 이동하게 된다. 이때 color, username을 수정하지 않은 상태이다. app.js 파일 안에 시스템 환경 변수를 읽은 후에 초록색 색상과 사용자 문구가 출력되는 것을 확인할 수 있다.

 

루트 / 경로 뒤에 문자열을 작성하면 작성한 문자열이 문구로 출력되는 것을 확인할 수 있다. app.js 파일 안에 app.get('/:name') 에 따라 URI의 문자열을 username 변수에 입력되어 클라이언트에게 응답하는 것이다.

 

ARG, ENV

 

ARG 변수명 변수값 # 이미지 빌드 시점의 환경 변수 설정 
                #docker build -build -arg 변수명=변수값 으로 덮어쓰기 가능

ENV 변수명 변수값 # 이미지 빌드 및 컨테이너 실행 시점의 환경 변수 설정(새로운 레이어 추가) 
                # docker run -e 변수명=변수값 으로 덮어쓰기 가능

시스템 환경 변수는 다양한 방법으로 활용할 수 있다. 애플리케이션이 DB 에 접속하기 위해 환경 변수에 저장하는 경우도 있으며 실습 예제에서 글자 색상 혹은 문구도 변경했다. 도커 환경 변수 설정은 크게 두 가지로 ARG, ENV 지시어가 존재한다. 다시 한 번 정리하자면 ARG 는 빌드에만 사용할 혼경 변수를 지정할 때 사용하고, ENV 는 애플리케이션을 실행할 때 참고할 용도로 사용한다. 기본적으로 특수한 경우를 제외하고 ENV만 사용하면 된다.

 

ENTRYPOINT ["명령어"] # 고정된 명령어를 지정
CMD ["명령어"] # 컨테이너 실행 시 실행 명령어 지정

 

CMD 에 들어가는 명령어는 띄어쓰기를 기준으로 여러 개의 명령어 작성이 가능하다. 예를 들어 node.js 를 실행한다고 가정을 하자. npm install, npm start 를 사용하는데, npm 이라는 명령이 중복되는 것을 알 수 있다. 이때 ENTRYPOINT 명령으로 반복적으로 사용되는 명령을 작성하여 CMD 명령을 더 쉽게 구성할 수 있다.

ENTRYPOINT, CMD
docker build -f Dockerfile-entrypoint -t buildapp:entrypoint .

  • docker build -f Dockerfile-entrypoint -t buildapp:entrypoint .
    : Dockerfile-entrypoint 도커파일을 사용해 실습 이미지 빌드

 

docker run --name buildapp-entrypoint-list buildapp:entrypoint list

  • docker run --name buildapp-entrypoint-list buildapp:entrypoint list
    : buildapp:entrypoint 이미지를 CMD를 list로 덮어씌우며 컨테이너로 실행

npm list 명령이 실행되어 정상적으로 의존 라이브러리들이 출력되는 것을 확인할 수 있다. 

 

docker run -it --name buildapp-entrypoint-bash buildapp:entrypoint /bin/bash

  • docker run -it --name buildapp-entrypoint-bash buildapp:entrypoint /bin/bash
    buildapp:entrypoint 이미지를 CMD를 /bin/bash로 덮어씌우며 컨테이너로 실행

지금 명령어처럼 덮어쓰기하면 shell 로 접근이 되었다. 그런데 ENTRYPOINT에 NPM 이라는 명령어가 있기 때문에 실제로 실행되는 명령어는 npm bin bash라는 잘못된 명령어가 실행된다. 그래서 엔터를 눌러보면 npm 다음에 올 수 있는 명령어의 리스트들이 출력되면서 잘못된 명령을 입력했다는 에러가 발생하게 된다. 이렇게 ENTRYPOINT를 사용해서 사용자가 의도하지 않은 명령어로 접근하는 것을 1차적으로 방지할 수 있다. 물론, 이 ENTRYPOINT를 사용하는 방법이 100% 보안적으로 안전한 부분은 아니다. 왜냐하면 ENTRYPOINT도 ENV처럼 컨테이너로 실행할 때 덮어쓰기가 가능하기 때문이다. 하지만 ENTRYPOINT를 잘 관리하면 의도하지 않은 동작을 1차적으로 방지할 수 있다.

 

 

  • docker rm -f buildapp-meta buildapp-arg buildapp-env buildapp-entrypoint-list buildapp-entrypoint-bash
    : 실습에 사용한 컨테이너 삭제

실습에 사용한 모든 컨테이너를 삭제하고 이번 시간을 마치도록 하자. 컨테이너 5개를 모두 삭제하고 실습을 마친다. 이번 시간에는 이미지를 빌드하기 위해서 다양한 지시어 사용 방법에 대해 학습했다. 다음 시간에는 이미지 빌드를 더 효율적으로 할 수 있는 멀티스테이징 빌드에 대해 학습한다.