.png)
Docker 의 이미지를 생성하는 명령어에는 2가지가 있다.
docker commitdocker container를 image로 생성commit 명령어를 실행하는 시점의 docker container 상태가 보존docker container의 상태를 백업하는 경우에 자주 사용docker buildDockerfile 이라는 단순 텍스트 파일를 사용하여 image 생성Dockerfile 은 지정된 문법을 지켜야 함Dockerfile 을 작성하고 공유하면 image의 구성을 쉽게 알 수 있음 이 게시물에서는 두 번째 생성법인 docker build 명령어를 알아 볼 것이다.
먼저 docker build 명령어와 Dockerfile 파일에 대해 차근차근 알아보자.
참고로 대부분의 내용은 docker 홈페이지의 래퍼런스와 혼자 사용해보면서 알아낸 것을 위주로 작성했다.
docker build 명령어는 docker image 를 빌드할 때 다음 두 가지를 사용한다.
Dockerfilebuild contextDockerfile은 텍스트 파일이고 build 시 사용될 명령어들을 모아놓은 것이다.
build context 는 PATH 또는 URL 을 통해 지정된 다수의 파일을 갖는 경로(위치)이다.
그리고 여기서 말하는 PATH 는 현재 로컬의 파일 시스템의 디렉토리이고,
URL 은 Git 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 context의 root 경로에 넣는다.
하지만 다른 경로에 있는 Dockerfile은 쓰고 싶다면 아래처럼 하면 된다.
docker build -f /path/to/a/Dockerfile .
마지막으로 Docker daemon 은 build 명렁어를 수행하는 과정에서
Dockerfile 을 사용한다. 그리고 안에 기재된 명령어들을 "하나 하나" 수행한다.
필요하다면 하나의 명령어의 결과에 대해서 새로운 이미지를 중간에 생성한다.
최종적으로 build 가 완료되면 최종 완성 이미지의 ID를 출력하고,
Docker daemon 에서 사용된 context 의 모든 정보들은 clean up 된다.
이렇게 해서 docker build 의 처리가 끝나게 된다.
참고로 docker build 는 기본적으로 build cache 라는 것을 사용한다.
기존에 build 를 통해서 생성된 이 캐시는 이후에 build 사용할 때 사용되어
더욱 빠른 빌드 속도를 내준다.
위 내용이 난해하다면 그냥 아래 핵심만 기억하자.
🎯 Dockerfile 는 docker build 시 사용될 명령어들이 기재된 텍스트 파일이다.
🎯 docker build 명령어는 build context 경로를 사용하고, 재귀적으로 하위 모든 파일 콘텐츠를 사용한다.
이전에 docker build 명령어에 대한 개괄적인 것을 알았다.
이제는 Dockerfile에 대해서 하나하나 알아가자.
먼저 Dockerfile 의 포맷부터 보자.
# Comment
INSTRUCTION arguments
INSTRUCTION(명령어)은 대문자, 소문자 상과없이 사용이 가능하다.
하지만 대문자로 쓰는 것이 관례이며, 그렇게 함으로써 arguments(인자) 와 구별을 준다
docker build 명령어는 Dockerfile 의 적힌 명령어들을 위에서 아래로 순차 실행한다.
그리고 반드시 첫 명령어는 FROM 이어야 한다. (예외적으로 ARG는 가능)
나중에 볼 거지만 FROM 명령어는 새로 생성하려는 이미지의 기반이 되는
부모 이미지(Parent image)를 지정하는 것이다.
마지막으로 Dockerfile 도 bash script 처럼 # 를 주석으로 사용할 수 있다.
Dockerfile 의 명령어들을 알아보자.
명령어 목록
| 키워드 | 기능 |
|---|---|
| FROM | Base image 지정 |
| RUN | image 생성 시점에 사용할 명령어 지정docker run 명령어 사용 시 --entrypoint 옵션으로 덮어쓰기 가능 |
| CMD | container 실행 시 실행되는 명령어를 지정한다.docker run 명령어 마지막에 명령어를 작성하면 덮어쓰기 가능 |
| LABEL | 생성할 image 의 메타정보를 등록한다 |
| EXPOSE | 컨테이너 실행 시 열어둘 포트와 통신 네트워크 프로토콜(= TCP/UDP) 지정한다. 기본은 TCP필수로 할 필요는 없지만 다른 사람에게 port에 대한 힌트를 줄 수 있다. |
| ENV | 컨테이너 실행 시 사용할 환경변수를 지정 이미지 생성되면 내부에 설정한 환경변수는 저장됨 |
| ARG | 이미지 생성 시에만 사용하는 변수 컨테이너 실행 후에는 사용 불가 |
| ENTRYPOINT | CMD 와 비슷하지만 약간 다른 것. |
| 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 로 이미지 이름을 지정해준다. 원한다면 <이미지명>[:태그] 식으로 작성해도 된다.docker build --tag my-apache2-server:1.0Dockerfile 이라는 이름 대신에 다른 파일을 Dockerfile로 쓰고 싶다면-f 하고 다른 Dockerfile 경로를 적어주면 된다.--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 이 출력되는 것을 확인할 수 있다.
# 캐시 없이 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
빌드한 결과물(=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 명칭을 그대로 따라갑니다.