본문 바로가기
Server/Docker

[Docker] 도커파일(Dockerfile)

by 꼬바리 2021. 6. 1.

 

🚀 Dockerfile 이란?

이미지 출처 :   https://data-newbie.tistory.com/516

 

지금까지는 단순히 공식 허브에 이미지를 다운받아서 컨테이너를 생성하고 그 안에서 각종 도구를 사용하고나 파일을 생성하는 과정을 진행했었습니다.

 

하지만, 이렇게 되면 매번 애플리케이션을 동작하는 환경을 구성하기 위해 패키지를 설치하고 환경설정하는 과정을 반복해야 합니다.

 

이런 문제를 간소화하기 위해서 Dockerfile이란게 존재합니다. Dockerfile은 컨테이너에 설치해야하는 패키지, 소스코드, 명령어, 환경변수설정 등을 기록한 하나의 파일입니다. 그리고 이를 빌드하면 자동으로 이미지가 생성됩니다. 이렇게 되면 앞으로는 애플리케이션 빌드 및 배포를 자동화할 수 있게됩니다.

 

근데 생각해보면 컨테이너에서 작업을 한다음에 이미지로 커밋하면 되는거 아닌가? 뭐.. 그럴수도 있겠습니다만 권장하는 방법은 Dockerfile을 이용해서 빌드하고 배포하는게 더 좋다고 합니다. (애플리케이션 패키지 설치를 명확히 함. 이미지 생성을 자동으로 함. 쉽게 배포 가능 등등)

 

✨ Dockerfile 작성

VS Code에서 확장도구를 설치하면 쉽게 작성할 수 있을겁니다.

  • FROM : 생성할 이미지의 베이스가 될 이미지를 뜻합니다. 반드시 한번 이상 입력해야 합니다.
  • LABEL : 이미지에 메타데이터를 추가합니다. (나중에 원하는 조건의 컨테이너, 이미지 등을 쉽게 찾을 수 있도록 도와주기 때문에 기억해두는게 좋습니다)
  • RUN : 이미지를 만들기 위해 컨테이너 내부에서 명령어를 실행합니다. (여기서 주의할 점은 설치과정에서 별도의 입력이 불가능하기 때문에 apache2를 설치할 때 뒤에 -y를 붙여줘야 합니다.
  • ADD : 파일을 이미지에 추가합니다. 여기서는 Dockerfile이 위치한 폴더에 test.html 파일을 가져와서 이미지의 /var/www/html 디렉터리에 추가합니다.
  • WORKDIR : 명령어를 실행할 디렉토리. 배시 셸에서의 cd 명령어와 동일한 기능을 합니다.
  • EXPOSE: 이미지에서 노출할 포트를 설정합니다.
  • CMD : 컨테이너가 시작될 때마다 실행할 명령어. Dockerfile에서 한번만 사용할 수 있습니다.

    부가적으로 RUN ["/bin/bash", "-c", "echo hello > test2.html"] => /bin/bash 셸을 이용해 echo hello > test2.html를 실행하라는 뜻입니다.

 

이를 종합해봤을때 ubuntu18:04를 이용해 컨테이너를 생성합니다. 그리고 그 안에서 apt-get update를 하고 아파치를 설치합니다. 호스트에 있는 test.html을 /var/www/html에 추가한다음, 그 폴더로 이동한 후에 test2.html을 생성합니다. 마지막으로 80번 포트를 노출시킬 포트로 설정한 다음 CMD 명령으로 이미지 빌드를 마칩니다.

 

이제 서버에다가 아래와 같이 해준다음에, 위에서 작성한 도커파일을 추가해줍니다.

$ mkdir dockerfile 
$ cd dockerfile
$ echo test >> test.html

🎵 Dockerfile 빌드

앞서 만든 도커파일을 빌드해봅니다.

$ docker build -t mybuild:0.0 ./

-t 옵션은 생성될 이미지 이름을 설정합니다. build 명령 끝에는 Dockerfile이 저장된 경로를 입력합니다. 여기서는 현재 디렉토리라고 입력했습니다.

빌드를 시작하면 step 1부터 9단계까지 자기가 알아서 실행하고 있는 것을 볼 수 있습니다.

이미지도 잘 생성되었으니 컨테이너를 생성하고 실행시켜보겠습니다. 잘 나오는 것을 확인할 수 있습니다.

$ docker run -d -p 80:80 --name myserver mybuild:0.0

 

🌍 빌드과정 살펴보기

빌드 컨텍스트 읽기

빌드를 시작하면 가장 먼저 시작하는 게 뭔지 나와있습니다. 도커파일이 위치한 디렉터리를 빌드 컨텍스트라고 부르고 도커는 가장먼저 빌드 컨텍스트를 읽어들입니다. (따라서 루트 디렉터리 같은 곳에서 빌드하지 않도록 주의해야합니다)

 

아니면, gitignore 파일처럼 빌드 컨텍스트 읽을때 제외할 폴더 및 파일을 명시할 수 있습니다

 

Dockerfile을 이용한 컨테이너 생성과 커밋

빌드과정을 유심히 살펴보면 눈에 띄는게 바로 Removing~container입니다. 이 이유는 ADD, RUN등의 명령이 실행될때마다 새로운 컨테이너가 하나씩 생성되며 이를 이미지로 커밋하는 것이기 때문입니다. (오... [컨테이너 생성 -> 명령어 실행 -> 레이어 생성 -> 이미지로 커밋] * 반복이라는 소리가 되네요)

 

캐시를 이용한 이미지 빌드

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

 

# Dockerfile2 작성
FROM ubuntu:18.04

LABEL "purpose"="practice"
RUN apt-get update
$ docker build -f Dockerfile2 -t mycahe:0.0 ./

Using cache라는 출력내용과 함께 빌드과정이 진행되지 않고 바로 이미지가 생성되었습니다. 즉, 이전에 빌드했던 Dockerfile에 같은내용이 있다면 build명령어는 이를 새로 빌드하지 않고 같은 명령어 줄까지 이전에 사용한 이미지 레이어를 활용해 이미지를 생성하는 것입니다.

 

단, 캐시기능이 문제가 되는 경우도 있습니다. git clone을 통한 명령어를 사용한 빌드가 일어난다고 가정했을때 실제 git저장소에 소스코드 변경이 생겨도 매번 빌드할때마다 캐시기능 때문에 고정된 소스코드를 사용하게 될 겁니다.

 

이럴때는 --no-cache 옵션을 추가해주면 캐시기능을 끄고 빌드할 수 있습니다.

$ docker build --no-cache -f Dockerfile2 -t mycahe:0.0 ./

🪁 멀티스테이지를 이용한 Dockerfile 빌드

일반적으로 애플리케이션을 빌드하려면 많은 의존성 패키지 및 라이브러리를 필요로합니다. 그래서 이미지자체의 용량이 커지거나 최종적으로 실행할 때 불필요한 라이브러리들이 있을 수 있습니다.

이럴 때는 멀티 스테이지를 활용하여 여러개의 FROM 명령어를 사용하여 최종적으로는 반드시 필요한 실행 파일만 최종 이미지 결과물에 포함시켜 이미지의 용량을 줄일 때 유용합니다.

예를 들어, 여기서는 Hello World를 출력하는 Go 소스코드를 작성한 뒤, golang 이미지를 기반으로 Go소스코드를 컴파일하고 출력하는 Dockerfile을 작성해 빌드해보도록 하겠습니다.

 

// main.go
package main
import "fmt"

func main(){
  fmt.Println("hello world")
}
# Dockerfile3
FROM golang
ADD main.go /root
WORKDIR /root
RUN go build -o /root/mainApp /root/main.go
CMD ["./mainApp"]
$ docker build -f Dockerfile3 -t go_helloworld ./

 

 

넵... 이미지 크기가 엄청나네요. 이번에는 이미지 크기를 줄이기 위해 멀티 스테이지 빌드 방법을 사용해보겠습니다.

 

# Dockerfile3 수정

FROM golang
ADD main.go /root
WORKDIR /root
RUN go build -o /root/mainApp /root/main.go

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

2개의 FROM을 통해 2개의 이미지를 적어주었습니다. 여기서 주의해서 볼 곳은 두번째 FROM에서 /root/mainApp에 존재하는 파일을 .로 이동합니다. 이 때 --from=0은 첫 번째 FROM에서 빌드된 이미지의 최종 상태를 의미합니다. (= 즉, 첫번째 FROM 이미지에서 빌드한 /root/mainApp파일을 두번째 FROM에 명시된 이미지 alpine:latest 이미지에 복사하는것 )


참고로 alpine은 알파인 리눅스를 의미합니다. 용량이 80M인 초경량화된 배포판이므로 Embbeded 나 네트웍 서버등 특정 용도에 적합하며 특히 도커(docker)에 채택되어 5M 크기의 리눅스 이미지로 유명합니다. (도커에서 꽤나 유명한듯...)

출처 : https://www.lesstif.com/docker/alpine-linux-35356819.html

 

🌹 기타 Dockerfile 명령어

ENV

환경변수를 설정할 수 있습니다. 개인적으로 저는 많이 썼었습니다.

ENV test /home

export test=/home 이랑 같은 의미...

VOLUME

호스트와 공유할 컨테이너 내부의 디렉터리 설정

VOLUME /home/volumn

ARG

build 명령어를 실행할때 추가로 입력받아 도커파일 내에서 사용될 변수의 값을 설정

USER

USER로 컨테이너 내에서 사용될 사용자 계정의 이름이나 UID를 설정하면 그 아래 명령어는 해당 사용자 권한으로 실행되도록 설정(권장)

ADD와 COPY

ADD와 COPY는 기능적으로 같은역할로써 이미지에 파일을 복사해줍니다. 다만 차이점은 COPY은 로컬의 파일만 이미지에 추가할 수 있지만, ADD는 URL 및 tar 파일에서도 파일을 추가할 수 있습니다. (권장되는 방법은 COPY라고 하는군요)

CMD과 ENTRYPOINT

생략...

 

출처 : https://velog.io/@ckstn0777/%EB%8F%84%EC%BB%A4%ED%8C%8C%EC%9D%BCDockerfile

728x90
반응형

댓글