HwangHub

도커 이미지 생성하기 본문

DEV-STUDY/Infra

도커 이미지 생성하기

HwangJerry 2023. 7. 22. 10:48

우리는 도커허브로부터 이미 만들어진 이미지만 받아서 사용할 수 있는 게 아니고, 우리가 직접 이미지를 만들어서 사용하거나, 도커 허브에 올려서 공유할 수도 있습니다.

 

우리가 지금까지 학습한 컨테이너는 도커 이미지를 통해 생성하며, 컨테이너 생성 명령어는 아래와 같습니다.

docker create <이미지 이름>

 

그렇다면 도커 이미지는 어떻게 생성할까요?

1. Dockerfile 작성

도커파일은 도커 이미지를 만들기 위한 config 파일입니다. 컨테이너가 어떻게 행동해야 하는지에 대한 설정값들을 정의해줍니다.

 

2. 도커 클라이언트에 전달

도커 파일에 입력된 것이 도커 클라이언트에 전달합니다.

 

3. 도커 서버에 전달

도커 서버는 도커 클라이언트에 전달된 중요한 작업들을 모두 처리하는 곳으로, 위 단계에서 도커 클라이언트에 전달된 도커파일을 바탕으로 이미지를 생성하게 됩니다.

 

그럼 이제 차근차근 하나하나 다시 살펴봅시다.

 

도커 파일은 어떻게 만들어야 할까요?

1. FROM 베이스 이미지를 명시해줍니다. (파일 스냅샷에 해당)

도커 이미지는 베이스 이미지와 여러 개의 레이어로 구성됩니다. 베이스 이미지는 그 레이어 중에서 도커 이미지의 기반이 되는 부분입니다. 거진 컨테이 내에서 OS의 역할을 하는 것이라고 이해해도 괜찮습니다. 그리고 레이어는 중간 단계의 이미지라고 생각하면 됩니다.

 

FROM <이미지 이름>:<태그> 형식으로 작성하며, 만약 태그를 붙이지 않으면 자동으로 가장 최신의 것으로 다운받게 됩니다. 보통 우리는 자바 어플리케이션을 사용할 것이므로 여기에 JDK 이미지를 입력하게 될 겁니다.

ex) ubuntu:14.04, openjdk:17

 

2. RUN 추가적으로 스냅샷을 위해 필요한 파일을 다운로드 받기 위한 몇가지 명령어를 명시해줍니다. (파일 스냅샷에 해당)

RUN <명령어> 형식으로 작성하며, 도커 이미지가 생성되기 전에 수행되어야 하는 쉘 명령어를 작성해둡니다.

 

3. CMD 컨테이너가 시작될 때 실행되어야 하는 명령어를 명시해줍니다. (시작시 실행 될 명령어에 해당)

CMD <파일/스크립트> 형식으로 작성하며, 컨테이너가 시작되었을 때 실행해야 하는 파일 또는 쉘 스크립트를 작성해둡니다. 이 명령어는 Dockerfile 내에서 1회만 쓸 수 있습니다.

 

위 과정을 참고하여 hello 문자열을 반환하는 이미지를 작성해 보겠습니다.

단순한 작업만을 수행할 것이므로 ubuntu와 같은 무거운 베이스 이미지보다는, 가벼운 alpine 이미지를 base image로 설정하였고, 문자열 출력에 다른 파일들이 필요하지 않으므로 RUN은 주석처리 하였습니다. 그리고 CMD 를 통해 echo hello 를 실행하도록 설정해 주었습니다.

 

진짜 도커파일 작성하기

사실 위 명령어 조합으로는 실제로 사용하는 도커파일을 만들기에 부족합니다.

FROM으로 베이스 이미지를 설정하는 것과, 실행 명령어를 CMD로 설정하는 것 외에 의존성 파일이나 실행 파일들이 해당 컨테이너에 없기 때문에 이를 로컬에서 컨테이너로 복사해주어야 하는데요. 이를 COPY라는 명령어로 수행할 수 있습니다.

COPY 명령어는 COPY <로컬 환경에서 복사할 파일 (경로)> <컨테이너 내의 파일 (경로)> 로 사용할 수 있습니다.

 

이를 활용한 도커파일은 다음과 같습니다. ARG는 arguments를 의미하며, 아마 자연스럽게 이해되실 거라고 생각합니다. 그 외에 WORKDIR는 필수는 아니지만 권장 사항이므로 별도로 다루겠습니다.

COPY 외에 "자주" 바뀌는 파일에 대하여, 마치 reference 타입에 대한 pointer처럼 도커 컨테이너가 로컬 파일과 mapping되어 지속적으로 해당 파일을 바라보고 업데이트 사항을 바로 반영시키고 싶다면 VOLUME을 사용할 수도 있습니다.
FROM openjdk:17
ARG JAR_FILE=build/libs/*.jar
VOLUME /tmp # 예시로 작성, 사용X
WORKDIR /usr/src/app
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","-Duser.timezone=Asia/Seoul","-Dspring.profiles.active=client","/usr/src/app/app.jar"]

여기서 "-Dspring.profiles.active=client"은 "application-client.yml"을 실행하게 만드는 옵션입니다.

저기서 CMD 대신 ENTRYPOINT 라고 설정하는 경우도 있는데, 두 명령어의 차이가 무엇일까요?

둘 다 컨테이너 시작시 실행할 명령어를 지정해주는 역할을 수행합니다. 즉, 컨테이너를 시작하려면 둘 중에 하나는 지정해주어야 합니다.

<차이점>
1. ENTRYPOINT 명령어는 오버라이딩이 어렵고 CMD 명령어는 오버라이딩이 쉽습니다.
2. docker run 시에 다른 실행 명령어가 있으면 CMD 명령어에 써준 내용은 무시된다. 반면에 ENTRYPOINT 명령어는 무시되지 않고 docker run에 붙여준 실행 명령어를 인자로 받아서 컨테이너를 실행한다.
3. CMD 명령어는 docker run 명령 내에 명시된 매개변수가 있는 경우 Daemon에서 무시된다.ENTRYPOINT 명령어는 무시되지 않고 대신 명령의 인수로 취급하여 매개변수로 추가된다.

<결론>
항상 실행해야 하는 명령을 사용하여 실행 가능한 도커 이미지를 빌드할 때는 ENTRYPOINT를 사용한다.
CMD 명령어는 도커 컨테이너가 실행될 때 command line에 명시적으로 인자값을 지정하지 않는 경우에 기본 명령어 역할을 하는 인자를 설정하는 데에 사용한다.

 

이미지 생성하기

위의 Dockerfile을 이미지로 생성해 보겠습니다.

 

docker build ./

Dockerfile이라는 이름으로 생성해두면 도커가 build 명령어를 수행할 때 해당 파일을 자동으로 인식합니다. 여기서 ./ 은 현재 경로의 모든 하위 폴더에 대하여 Docker파일을 찾는다는 의미입니다. 여기서 git 처럼 . 으로도 가능하지만 더 명확하게 하기 위해서 ./ 이 더 권장됩니다.

새로운 이미지를 생성한다는 건, 내부적으로는 베이스 이미지를 임시 컨테이너로 실행시킨 후에, 새로운 명령어와 파일 스냅샷을 추가하여 새로운 이미지를 만들어내는 것을 의미합니다. 이 과정이 마치면 생성되었던 임시 컨테이너는 지워집니다.

 

이미지 이름 설정하기

여기서 문제가 하나 남은 게 있다면, 도커허브에서 hello-world 이미지와 같이 우리도 이미지를 빌드할 때 이미지 이름을 부여할 수 있다면 실행할 때 더욱 편하고 기억하기 좋지 않을까 하는 것입니다.

 

이를 위해서는 build할 때 docker build -t <나의 도커 아이디>/<저장소-프로젝트이름>:<버전> ./ 명령어를 활용하면 됩니다.



참고:

 

ENTRYPOINT, CMD 차이

레퍼런스 > > - https://www.bmc.com/blogs/docker-cmd-vs-entrypoint/ > - https://docs.docker.com/engine/reference/builder/#understand-how-cmd-and-entrypoint-interact 둘 다 컨테이너 시작시 실행할 명령어를 지정해준다. 컨테이너를

velog.io

 

'DEV-STUDY > Infra' 카테고리의 다른 글

Working Directory 명시하기  (0) 2023.07.23
도커 이미지 실행하기  (0) 2023.07.22
도커 커맨드 분석  (0) 2023.07.22
도커 기본 사용 흐름 이해하기  (0) 2023.07.22
도커는 왜 쓰나요?  (0) 2023.07.22
Comments