잘못된 정보가 있다면, 꼭 댓글로 알려주세요(비로그인 익명도 가능).

여러분의 피드백이 저와 방문자 모두를 올바른 정보로 인도할 수 있습니다.

감사합니다. -현록

후원해주실 분은 여기로→

현록의 기록저장소

Dockerfile 작성 (Dockerfile로 배포) 본문

Study/Docker

Dockerfile 작성 (Dockerfile로 배포)

현록 2023. 1. 3. 18:36

Docker의 계층(Layer)형 구조와 가상화에 대한 이론 내용을 깨우쳤다면,

이제 Docker를 제대로 응용할 차례다.

앞서 본 Docker의 명령어들은 라이브러리에서 원하는 이미지를 내려받고, 실행해보는 것이었다.

이제 Dockerfile을 작성함으로써, 내가 원하는 레이어들을 쌓은 최종이미지를 빌드하여

Docker로 프로젝트를 배포하는 예제를 볼 것이다.

(Dockerfile 작성(이미지 빌드)이 왜 프로젝트 배포로 이어지는 것인지는 [두 번째 예시]에 조금 더 언급)

 

 


원하는 환경을 구상해본다.

 

 

[첫 번째 예시]

1. 이미 빌드된 파일을 바로 구동환경에서 실행

구동환경에 맞는 빌드된 파일을 준비해놨으니, 빌드과정이 없어 시간이 대폭 줄어든다.

하지만 해당 파일을 Dockerfile과 함께 제공할 수 있어야한다.

 

 

[두 번째 예시]

1. git으로 공개 프로젝트를 내려받고

2. 빌드이미지에서 빌드하고

3. 빌드한 파일을 구동환경에서 실행

각 단계마다 다른 이미지에서 작업을 수행하도록 할 것이다.

1단계에서는 내려받는 것만을,

2단계에서는 빌드만을,

3단계에서는 실행만을 담당한다.

최종이미지는 3단계만 가지면 되므로, 1과 2의 내용은 최종 구동환경에 포함되지 않으니 용량을 줄일 수 있다.

 

 

[세 번째 예시]

1. 하나의 최종 구동환경 이미지에서 wget, unzip, git, gradle을 설치(리눅스 yum, apt-get 등)

2. wget, unzip 등으로 yum 및 apt-get에 없는 프로그램들을 설치

3. 환경변수 설정

4. 프로젝트를 내려받고

5. 빌드하고

6. 실행

사실 한 번 하고 버리면 될 내려받기나 빌드한 후에도 남는 빌드 프로그램들이 최종 이미지에 포함되므로

용량이 쓸데없이 커진다. 그렇지만 내가 필요한 프로그램이 공개된 이미지에 없을 수 있으니, 명령어 예시용으로 본다.

 

 


[첫 번째 예시]

1. 이미 빌드된 파일을 바로 구동환경에서 실행

 

 

 

Dockerfile

FROM amazoncorretto:8u352
LABEL stage=forbuild
COPY ./myproject.war /myproject
WORKDIR /myproject
EXPOSE 8090
ENTRYPOINT [ "java", "-jar", "/myproject/myproject.war" ]

docker 명령

docker build   --no-cache    -t 생성될이미지명:태그    Dockerfile경로

docker image prune   --filter  label=stage=forbuild 

docker run   -d   -it    -p 28090:8090     --name 생성될컨테이너명    생성한이미지명

※ docker build할 때에 줄마다 레이어 및 캐시를 형성하는데,

 같은 Dockerfile을 또 build할 때에, 명령줄만 비교하고 그 내용이 가리키는 파일까지는 비교해주진 않으니,

 (로컬 파일이든 wget이나 curl이든 git이든...)

 필요에 따라 캐시 사용을 하지 않도록 함 (--no-cache 옵션).

※ 만약 Docker Desktop 환경에서 ERROR [internal] load metadata for docker.io/library/... 에러를 낸다면,

 ~/.docker/config.json에서 "credStore": "desktop", 부분을 "credStore": "",로 수정하고 Docker Desktop을 재시작해준다.

 

FROM 이후 한 줄 마다 레이어로 중간 이미지(intermediate image)가 생성된 채 남게 되는데,

부여했던 LABEL를 필터(--filter 옵션)로 사용하여 docker image prune 명령어로 중간 이미지들을 모두 삭제해줄 수 있다.

buildkit을 사용한다면 FROM 이미지든 중간 이미지든 모두 캐시로 관리하고 이미지로 남기지 않으므로,

해당 과정이 필요없다.

 

 


위 예시의 Dockerfile의 명령어들

FROM   작업할_이미지

LABEL   라벨명

COPY   source   destination

WORKDIR   이미지에서_cd될_곳

EXPOSE   외부로_노출될_포트: -P 옵션으로 컨테이너를 생성하면 해당 포트는 무작위로 배정됨.

ENTRYPOINT   생성된_컨테이너에서_실행될_명령: CMD와는 달리, 컨테이너 생성시 명령을 지정하더라도 이 명령이 실행됨.

 

 


[두 번째 예시]

1. git으로 공개 프로젝트를 내려받고

2. 빌드이미지에서 빌드하고

3. 빌드한 파일을 구동환경에서 실행

 

 

 

Dockerfile

FROM bitnami/git:latest
LABEL stage=forbuild
RUN [ "git", "clone", "https://github.com/BlackdeerY/restdocs-maven.git", "myproject" ]

FROM maven:3.8.7-openjdk-18
LABEL stage=forbuild
COPY --from=0 /myproject /myproject
WORKDIR /myproject
RUN [ "mvn", "package" ]

FROM amazoncorretto:8u352
LABEL stage=forbuild
COPY --from=1 /myproject/target/restdocs-maven-0.0.1-SNAPSHOT.war /myproject/myproject.war
WORKDIR /myproject
EXPOSE 8090
ENTRYPOINT [ "java", "-jar", "/myproject/myproject.war" ]

docker 명령

docker build   --no-cache    -t 생성될이미지명:태그    Dockerfile경로

docker image prune   --filter  label=stage=forbuild 

docker run   -d   -it    -p 28090:8090     --name 생성될컨테이너명    생성한이미지명

 

 


위 예시의 추가된 Dockerfile의 명령어들

COPY   --from=이전이미지번호   source   destination: 이전 작업 이미지 영역에서도 파일을 가져올 수 있음

 

이미지마다 필요한 작업만을 하고, 결과물만 옮겨올 수 있음.

이렇게 최종이미지에 불필요한 프로그램이 없도록 하여 용량을 줄일 수 있음.

 

 


실제로 위 명령어를 그대로 따라하여

이미지가 생성된 것을 확인하고, 컨테이너 생성을 했을 때,

http://localhost:28090/docs/v.1.0.0.html

웹브라우저로 위 주소에 접속해보면 바로 서버가 돌아가고 있는 것을 확인할 수 있다.

(위 예시에서의 Restdocs 문서)

 

사용자가 docker를 설치한 후라면

몇 줄만으로 빠르게 구동환경과 실행까지 바로 제공할 수 있는 것.

 

 


[세 번째 예시] (비효율적이지만 명령어 예시)

1. 하나의 최종 구동환경 이미지에서 wget, unzip, git, gradle을 설치(리눅스 yum, apt-get 등)

2. wget, unzip 등으로 yum 및 apt-get에 없는 프로그램들을 설치

3. 환경변수 설정

4. 프로젝트를 내려받고

5. 빌드하고

6. 실행

 

 

 

Dockerfile

FROM amazoncorretto:8u352
LABEL stage=forbuild

RUN yum install wget -y
RUN yum install unzip -y
RUN yum install git -y

RUN wget https://services.gradle.org/distributions/gradle-7.6-bin.zip -P /tmp
RUN unzip -d /opt/gradle -oq /tmp/gradle-7.6-bin.zip
RUN rm /tmp/gradle-7.6-bin.zip
ENV PATH /opt/gradle/gradle-7.6/bin:$PATH

RUN [ "git", "clone", "https://github.com/BlackdeerY/restdocs-maven.git", "restdocs" ]

WORKDIR /restdocs
RUN [ "gradle", "jar" ]

EXPOSE 8090
ENTRYPOINT [ "java", "-jar", "/restdocs/build/libs/restdocs-maven-0.0.1-SNAPSHOT.war" ]

docker 명령

docker build   --no-cache    -t 생성될이미지명:태그    Dockerfile경로

docker image prune   --filter  label=stage=forbuild 

docker run   -d   -it    -p 28090:8090     --name 생성될컨테이너명    생성한이미지명

 

 


위 예시의 추가된 Dockerfile의 명령어들

ENV   key   value: 환경변수를 설정

 

 


결과적으로 최종 이미지에 구동과는 필요 없는 프로그램들이 남은 채이므로,

최종 이미지 용량이 쓸데없이 커진다.

라이브러리에 이미 존재하는 이미지들을 활용하도록 하고,

없더라도 최종 구동과 상관이 없다면 이전 단계의 이미지에서 설치하여 사용 후 결과만 이동시켜서 사용한다.

 

 


Dockerfile 공식 문서는

https://docs.docker.com/engine/reference/builder/

 

Dockerfile reference

 

docs.docker.com

 

 

'Study > Docker' 카테고리의 다른 글

컨테이너에서 로그나 파일을 생성할 수 없는 문제  (0) 2023.11.11
Docker Compose 사용 (docker-compose.yml)  (0) 2023.01.04
Docker 마운팅  (0) 2021.04.02
Docker 실행  (0) 2021.04.01
Docker 이미지들 (Docker Hub)  (0) 2021.03.31
Comments

잘못된 정보가 있다면, 꼭 댓글로 알려주세요(비로그인 익명도 가능).

여러분의 피드백이 저와 방문자 모두를 올바른 정보로 인도할 수 있습니다.

감사합니다. -현록

후원해주실 분은 여기로→