docker build & Dockerfile

식빵·2022년 4월 2일
2

docker reference

목록 보기
3/12
post-thumbnail

🍀 이미지 생성 방법

Docker 의 이미지를 생성하는 명령어에는 2가지가 있다.

  • docker commit
    • docker containerimage로 생성
    • commit 명령어를 실행하는 시점의 docker container 상태가 보존
    • 현재 docker container의 상태를 백업하는 경우에 자주 사용
  • docker build
    • Dockerfile 이라는 단순 텍스트 파일를 사용하여 image 생성
    • Dockerfile 은 지정된 문법을 지켜야 함
    • Dockerfile 을 작성하고 공유하면 image의 구성을 쉽게 알 수 있음

이 게시물에서는 두 번째 생성법인 docker build 명령어를 알아 볼 것이다.
먼저 docker build 명령어와 Dockerfile 파일에 대해 차근차근 알아보자.
참고로 대부분의 내용은 docker 홈페이지의 래퍼런스와 혼자 사용해보면서 알아낸 것을 위주로 작성했다.




🍀 docker build

docker build 명령어는 docker image 를 빌드할 때 다음 두 가지를 사용한다.

  • Dockerfile
  • build context

Dockerfile텍스트 파일이고 build 시 사용될 명령어들을 모아놓은 것이다.
build contextPATH 또는 URL 을 통해 지정된 다수의 파일을 갖는 경로(위치)이다.

그리고 여기서 말하는 PATH 는 현재 로컬의 파일 시스템의 디렉토리이고,
URLGit repository 의 위치이다.
이런 context 경로는 하위의 모든 것들을 재귀적(recursively)으로 build 시에 사용한다.

docker build 명령어를 아래처럼 사용하면 현재 디렉토리를 build context로 지정한 것이다.

docker build . # . 이 현재 경로를 의미한다.

docker build 의 실제 처리는 Docker daemon 이 하게 되고,
docker build 요청이 시작되면 제일 먼저 Docker daemon 에게 build context 의 하위 모든 파일에 대한 정보(contents)를 전송한다.

이런 점을 생각해보면 docker build 명령어는 /(루트 경로) 같은 곳에서 쓰면 안된다는 것을 알 수 있다.

대신 하나의 디렉토리를 새로 생성하고, 그 안에 Dockerfile을 두고,
build 시에 필요한 추가적인 파일들을 넣어둔 후에 해당 디렉토리 경로에서 docker build
명령어를 사용하는 것이 일반적이다.

그런데 build context 내에서 원치 않는 build 에 사용하지 말았으면,
무시했으면 하는 목록도 존재한다. 그런 건 .dockerignore 파일에 기재하면 된다.
.dockerignore 파일을 잘 사용하면 build 성능을 올릴 수 있다.


일반적으로 Dockerfile 은 build contextroot 경로에 넣는다.
하지만 다른 경로에 있는 Dockerfile은 쓰고 싶다면 아래처럼 하면 된다.

docker build -f /path/to/a/Dockerfile .

마지막으로 Docker daemonbuild 명렁어를 수행하는 과정에서
Dockerfile 을 사용한다. 그리고 안에 기재된 명령어들을 "하나 하나" 수행한다.

필요하다면 하나의 명령어의 결과에 대해서 새로운 이미지를 중간에 생성한다.
최종적으로 build 가 완료되면 최종 완성 이미지의 ID를 출력하고,
Docker daemon 에서 사용된 context 의 모든 정보들은 clean up 된다.

이렇게 해서 docker build 의 처리가 끝나게 된다.

참고로 docker build 는 기본적으로 build cache 라는 것을 사용한다.
기존에 build 를 통해서 생성된 이 캐시는 이후에 build 사용할 때 사용되어
더욱 빠른 빌드 속도를 내준다.


위 내용이 난해하다면 그냥 아래 핵심만 기억하자.

🎯 Dockerfiledocker build 시 사용될 명령어들이 기재된 텍스트 파일이다.
🎯 docker build 명령어는 build context 경로를 사용하고, 재귀적으로 하위 모든 파일 콘텐츠를 사용한다.




🍀 Dockerfile 포맷

이전에 docker build 명령어에 대한 개괄적인 것을 알았다.
이제는 Dockerfile에 대해서 하나하나 알아가자.
먼저 Dockerfile 의 포맷부터 보자.

# Comment
INSTRUCTION arguments 

INSTRUCTION(명령어)은 대문자, 소문자 상과없이 사용이 가능하다.
하지만 대문자로 쓰는 것이 관례이며, 그렇게 함으로써 arguments(인자) 와 구별을 준다

docker build 명령어는 Dockerfile 의 적힌 명령어들을 위에서 아래로 순차 실행한다.
그리고 반드시 첫 명령어는 FROM 이어야 한다. (예외적으로 ARG는 가능)

나중에 볼 거지만 FROM 명령어는 새로 생성하려는 이미지의 기반이 되는
부모 이미지(Parent image)를 지정하는 것이다.

마지막으로 Dockerfile 도 bash script 처럼 # 를 주석으로 사용할 수 있다.




🍀 Dockerfile 명령어

Dockerfile 의 명령어들을 알아보자.


명령어 목록

키워드기능
FROMBase image 지정
RUNimage 생성 시점에 사용할 명령어 지정
docker run 명령어 사용 시 --entrypoint 옵션으로 덮어쓰기 가능
CMDcontainer 실행 시 실행되는 명령어를 지정한다.
docker run 명령어 마지막에 명령어를 작성하면 덮어쓰기 가능
LABEL생성할 image 의 메타정보를 등록한다
EXPOSE컨테이너 실행 시 열어둘 포트와
통신 네트워크 프로토콜(=TCP/UDP) 지정한다. 기본은 TCP
필수로 할 필요는 없지만 다른 사람에게 port에 대한 힌트를 줄 수 있다.
ENV컨테이너 실행 시 사용할 환경변수를 지정
이미지 생성되면 내부에 설정한 환경변수는 저장됨
ARG이미지 생성 시에만 사용하는 변수
컨테이너 실행 후에는 사용 불가
ENTRYPOINTCMD 와 비슷하지만 약간 다른 것. 좀 애매한 녀석
WORKDIR컨테이너 시작 시 사용될 working directory 경로

사실 이외에도 Dockerfile 에서 사용하는 명령어는 굉장히 많다.
나머지 명령어들은 여기에서 확인하자.




🍀 간단한 실습

아주 간단한 실습을 해보자.
실습 목표는 apache2 웹서버를 띄우는 것이다.
일단 docker build 명령어 사용을 위한 기본적인 준비부터 하자.

# 참고: working directory는 홈 디렉토리
mkdir docker-test && cd docker-test
touch Dockerfile && touch index.html # index.html 은 웹서버에서 사용

apache2 웹서버에서 사용할 index.html 편집한다.
참고로 나는 모든 파일을 vim으로 편집했다.
내용은 아래와 같이 작성했다.

<html>
  <body>
	<h1>
    	Hello World~
    </h1>
  </body>
</html>

이번에는 Dockerfile을 편집해보자.
내용은 아래처럼 작성했다.

FROM ubuntu:20.04

LABEL creator="dailycode@velog.io"
LABEL version="1.0.0"

ARG DEBIAN_FRONTEND=nointeractive
RUN apt-get update && apt-get install -y apache2

ARG APACHE_ROOT=/var/www/html
COPY ./index.html $APACHE_ROOT

EXPOSE 80 # 이건 굳이 안해도 된다. 안 해도 docker run -p 로 포트 포워딩 가능
		  # 하지만 docker config 로 ExposedPort 정보를 확인할 수 있어서 hint를 줄 수 있다.,

ENV WHO_AM_I="dailycode"

ENTRYPOINT ["/usr/sbin/apache2ctl", "-D", "FOREGROUND"]

## 이렇게도 할 수 있음
# ENTRYPOINT ["/usr/sbin/apache2ctl"]
# CMD ["-D", "FOREGROUND"]

이제 이미지를 생성해보자.

docker build --tag my-apache2-image .

# docker images 명령어 수행을 통해서 잘 생성되었는지 확인
REPOSITORY         TAG       IMAGE ID       CREATED          SIZE
my-apache2-image   latest    967f6ec27ad4   16 minutes ago   221MB
ubuntu             20.04     ff0fea8310f3   2 weeks ago      72.8MB
  • --tag 로 이미지 이름을 지정해준다. 원한다면 <이미지명>[:태그] 식으로 작성해도 된다.
    • ex: docker build --tag my-apache2-server:1.0
  • 참고로 Dockerfile 이라는 이름 대신에 다른 파일을 Dockerfile로 쓰고 싶다면
    옵션으로 -f 하고 다른 Dockerfile 경로를 적어주면 된다.
    • ex: `docker build -f /home/ubuntu/docker_test/Dockerfile-Server
  • 만약에 FROM에서 사용한 이미지를 최신으로 다시 받고 싶으면 --pull=true 옵션 사용

이제 컨테이너를 실행시켜보자.

docker run -d --name my-apache2-container -p 80:80 my-apache2-image
# docker ps -a 명령어 수행을 통해서 잘 실행되는지 확인하자

최종적으로 제대로 서버가 켜졌는지 알기 위해서 간단하게 curl 로 확인

curl http://localhost:80/index.html

<html>
  <body>
      <h1>
		Hello World~
	  </h1>
  </body>
</html>

내가 기존에 작성했던 index.html 이 출력되는 것을 확인할 수 있다.




🥟 보충(1) build cache

캐시 없이 rebuild 하기

https://stackoverflow.com/a/58115741 참고

# 캐시 없이 build
docker build --no-cache -t myimage:version .

# 만약에 base 이미지도 가장 최신의 버전을 가져오는 걸 확실히 하고 싶다면
# pull 옵션도 추가하는 게 좋습니다.
docker build --pull --no-cache -t myimage:version .

안 쓰는 쓰레기 캐시 지우기

docker build 를 수행한 후 생성된 중간 Layer 들은 모두 캐싱이 됩니다.
하지만 docker 를 오래 사용하다보면 쓰지 않는 캐시도 존재하는데,
그럴 때는 아래처럼 캐시를 지우면 됩니다.

docker builder prune --all




🥟 보충(2) 이미지 추출/로드

빌드한 결과물(=image)를 때로는 하나의 파일로 다른 사람과
공유하고 싶을 수도 있습니다. 이때는 docker save 와 load 명령어를 사용하면 됩니다.

# 추출
docker save -o hello-world.tar hello-world

# 로드
docker load -i hello-world.tar

참고로 docker load 의 결과물인 image 의 repo:tag 명은 save 할 당시
이미지에 적용됐던 repo:tag 명칭을 그대로 따라갑니다.




✨ 참고

profile
백엔드를 계속 배우고 있는 개발자입니다 😊

0개의 댓글