본문 바로가기
  • 클라우드야 나랑 친해지자!
서버/Docker&Kubernetes

Dockerfile 작성 및 빌드

by 정민규 2021. 4. 16.
반응형

수업을 듣고 배운 내용과 연습한 내용을 정리하였습니다

개인 공부 후 자료를 남기기 위한 목적임으로 내용 상에 오류가 있을 수 있습니다.

 

잘못된 부분이 있거나 질문사항은 댓글로 남겨주시면 성심성의껏 답변해드리겠습니다. 감사합니다!


 

교재 <시작하세요! 도커/쿠버네티스 - 용찬호 지음>를 토대로 실습을 진행하였습니다.

 

 

 

* 실습 요약

1. Dockerfile 작성

2. Dockerfile 빌드

3. 캐시를 이용한 이미지 빌드

4. 멀티 스테이지를 이용한 Dockerfile 빌드하기

 

 

 

 

 

 

* Dockerfile 작성

 

Dockerfile에는 컨테이너에서 수행해야 할 작업을 명시합니다. 이 작업을 Dockerfile에 정의하기 위해서는 Dockerfile에서 쓰이는 명령어를 알아둘 필요가 있습니다.

 

 

 

 

 

Dockerfile을 사용하기 위한 간단한 시나리오로 웹 서버 이미지를 생성해보겠습니다.

디렉터리를 생성하고, 디렉터리 안에 HTML 파일을 미리 만들어둡니다.

 

#mkdir dockerfile && cd dockerfile
#echo test >> test.html

#ls
test.html

 

 

 

 

 

 

새롭게 생성한 디렉터리 내부에서 아래의 내용으로 Dockerfile이라는 이름의 파일을 저장합니다.

아래의 Dockerfile은 이미지에 아파치 웹 서버를 설치한 뒤, 로컬에 있는 test.html 파일을 웹 서버로 접근할 수 있는 컨테이너의 디렉터리인 /var/www/html에 복사합니다.

 

#vi Dockerfile

FROM ubuntu:14.04
MAINTAINER alicek106
LABEL "purpose"="practice"
RUN apt-get update
RUN apt-get install apache2 -y
ADD test.html /var/www/html
WORKDIR /var/www/html
RUN ["/bin/bash", "-c", "echo hello >> test2.html"]
EXPOSE 80
CMD apachectl -DFOREGROUND

 

 

 

* 스크립트 설명

 

FROM : Dockerfile에서 사용할 베이스 이미지를 ubuntu:14.04로 설정합니다.

MAINTAINER : 이미지 MAINTAINER의 이름을 alicek106으로 설정합니다.

LABEL : Dockerfile에서 생성될 이미지의 라벨을 puropose=practice로 설정합니다.

 

RUN : RUN으로 아파치 웹서버를 차례로 설치합니다.

ADD : ADD로 Dockerfile이 위치한 디렉터리에서 test.html 파일을 이미지의 /var/www/html에 추가합니다.

 

WORKDIR : 작업 디렉터리를 /var/www/html로 바꿉니다.

RUN : ["/bin/bash ~] 로 test2.html 파일을 생성합니다.

 

EXPOSE : 컨테이너가 사용해야 할 포트를 80번으로 설정합니다.

CMD : 컨테이너의 명령어를 apachectl -DFOREGROUND로 설정해 이미지 빌드를 마칩니다.

 

 

 

 

 

 

 

 

* Dockerfile 빌드

 

Dockerfile의 기본적인 명령어를 이해했다면 앞에서 만든 Dockerfile을 빌드해 보겠습니다.

build 명령어의 끝에는 Dockerfile이 저장된 경로를 입력합니다.

로컬에 Dockerfile을 저장했으므로 ./(현재 디렉터리)를 입력했습니다.

#docker build -t mybuild:0.0 ./

 

 

 

 

 

최종적으로 mybuild:0.0이라는 이름의 이미지가 생성됩니다.

이 이미지에는 아파치 웹 서버가 설치돼 있으며, 컨테이너가 시작될 때 웹 서버를 실행하도록 CMD(커맨드)를 설정했기 때문에 별다른 설정 없이도 웹 서버가 실행됩니다.

 

이제 생성된 이미지로 컨테이너를 실행해봅니다.

#docker run -d -P --name myserver mybuild:0.0

 

 

 

-P 옵션은 이미지에 설정된 EXPOSE의 모든 포트를 호스트에 연결하도록 설정합니다.

Dockerfile에서 EXPOSE를 80번으로 설정했으며 이는 이미지에 '컨테이너의 80번 포트를 사용한다'는 것을 의미합니다.

즉, 이미지를 생성하기 위한 Dockerfile을 작성하는 개발자로서는 EXPOSE를 이용해 이미지가 실제로 사용될 때 어떤 포트가 사용돼야 하는지 명시할 수 있으며, 이미지를 사용하는 입장에서는 컨테이너의 애플리케이션이 컨테이너 내부에서 어떤 포트를 사용하는지 알 수 있게 됩니다.

 

 

 

 

 

 

Dockerfile에 이미지의 라벨을 purpose=practice로 설정했으므로 docker images 명령어의 필터에 이 라벨을 적용할 수 있습니다. 아래의 명령어는 --filter 옵션을 통해 해당 라벨을 가지는 이미지를 출력합니다.

#docker images --filter "label=purpose=practice"

 

 

 

 

 

 

 

 

 

 

* 캐시를 이용한 이미지 빌드

 

한 번 이미지 빌드를 마치고 난 뒤 다시 같은 빌드를 진행하면 이전의 이미지 빌드에서 사용했던 캐시를 사용합니다.

다음 내용을 파일로 저장하고 다시 이미지를 빌드해 봅니다.

앞서 만들었던 Dockerfil 파일의 내용 일부분을 지웠습니다.

 

FROM ubuntu:14.04
MAINTAINER alicek106
LABEL "purpose"="practice"
RUN apt-get update

 

 

 

 

다음 명령어를 입력해 새로운 이미지를 빌드합니다.

#docker build -f Dockerfile2 -t mycache:0.0 ./

 

 

Using cache라는 출력 내용과 함께 별도의 빌드 과정이 진행되지 않고 바로 이미지가 생성됐습니다.

이전에 빌드했던 Dockerfile에 같은 내용이 있다면 build 명령어는 이를 새로 빌드하지 않고 같은 명령어 줄까지 이전에 사용한 이미지 레이어를 활용해 이미지를 생성합니다.

 

 

 

 

 

 

그러나

 

때로는 캐시 기능이 필요하지 않을 때도 있습니다.

깃허브 같은 소스코드 저장소에서 git clone 등의 명령어를 사용해 빌드할 때가 여기에 해당합니다.

Dockerfile에 RUN git clone ...을 사용해 이미지를 빌드했다면 RUN에 대한 이미지 레이어를 계속 캐시로 사용하기 때문에 실제 깃 저장소에서 리비전 관리가 일어나도 매번 빌드를 할 때마다 고정된 소스코드를 사용하게 될 것입니다.

 

이 경우 캐시를 사용하지 않으려면 build 명령어에 --no-cache 옵션을 추가합니다.

#docker build --no-cache -t mybuild:0.0 .

 

 

또는 캐시로 사용할 이미지를 직접 지정할 수도 있습니다.

예를 들어, 도커 허브의 nginx 공식 저장소에서 nginx:latest 이미지를 빌드하는 Dockerfile에 일부 내용을 추가해 사용한다면 로컬의 nginx:latest 이미지를 캐시로 사용할 수 있습니다.

#docker build --cache-from nginx -t my_extend_nginx:0.0 .

 

 

 

 

 

 

 

 

* 멀티 스테이지를 이용한 Dockerfile 빌드하기

 

 

 

Hello World를 출력하는 간단한 Go 소스코드를 작성한 뒤, 빌드된 프로그램을 실행하는 도커 이미지를 Dockerfile을 사용해 빌드해보겠습니다.

 

#cd ..
#mkdir golang
#cd golang

#vi main.go
package main
import "fmt"
func main() {
     fmt.Println("hello world")
}

#vi Dockerfile
FROM golang
ADD main.go /root
WORKDIR /root
RUN go build -o /root/mainApp /root/main.go
CMD ["./mainApp"]

 

 

docker images 명령어를 통해 확인해보면 단순히 Hello World를 출력하는 프로그램을 실행하는 이미지임에도 불구하고, 이미지의 크기가 무려 864MB에 달하는 것을 확인할 수 있습니다.

실제 실행 파일의 크기는 매우 작지만 소스코드 빌드에 사용된 각종 패키지 및 라이브러리가 불필요하게 이미지의 크기를 차지하고 있는 것입니다.

17..05 버전 이상을 사용하는 도커 엔진이라면 이미지의 크기를 줄이기 위해 멀티 스테이지 빌드 방법을 사용할 수 있습니다. 멀티 스테이지 빌드는 하나의 Dockerfile 안에 여러 개의 FROM 이미지를 정의함으로써 빌드 완료 시 최종적으로 생성될 이미지의 크기를 줄이는 역할을 합니다.

 

 

 

 

 

멀티 스테이지 빌드를 사용해 이미지를 빌드해보겠습니다.

일반적인 Dockerfile과는 다르게, 2개의 FROM을 통해 2개의 이미지가 명시되었습니다.

 

첫 번째 FROM에 명시된 golang 이미지는 이전과 동일하게 main.go 파일을 /root/mainApp으로 빌드하였습니다.

그러나 두 번째 FROM 아래에서 사용된 COPY 명령어는 첫 번째 FROM에서 사용된 이미지의 최종 상태에 존재하는 /root/mainApp 파일을 두 번째 이미지인 alpine:latest 에 복사합니다.

 

즉, 첫 번째 FROM 이미지에서 빌드한 /root/mainApp 파일을 두 번째의 FROM에 명시된 이미지인 alpine:latest 이미지에 복사하는 것입니다.

 

#vi Dockerfile
FROM golang
ADD main.go /root
WORKDIR /root
RUN go build -o /root/mainApp /root/main.go
CMD ["./mainApp]

FROM alpine:latest
WORKDIR /root
COPY --from=0 /root/mainApp .
CMD ["./mainApp"]

 

 

 

 

 

 

 

Dockerfile을 빌드한 뒤 이미지의 크기를 확인해보겠습니다.

#docker build . -t go_helloworld:multi-stage

 

 

 

 

 

이전과 동일한 역할을 하는 이미지임에도 불구하고, 이미지의 최종 크기가 크게 줄은 것을 확인할 수 있습니다.

이와 같이 멀티 스테이지 빌드는 반드시 필요한 실행 파일만 최종 이미지 결과물에 포함시킴으로서 이미지 크기를 줄일 때 유용하게 사용할 수 있습니다.

 

 

 

 

 

 

 

지금까지 여러 방법의 Dockerfile 작성과 빌드에 대해 알아보았습니다~

스크립트 부분을 숙지해두면 좋을 것 같습니다!

 

 

 

반응형

'서버 > Docker&Kubernetes' 카테고리의 다른 글

Docker Compose  (0) 2021.04.22
Docker Swarm  (0) 2021.04.20
Docker 이미지 추출 및 저장소 생성(2/2)  (0) 2021.04.15
Docker 이미지 생성하기- Docker Hub(1/2)  (0) 2021.04.15
Docker Container Logging - awslogs  (0) 2021.04.14

댓글