Docker 의 이미지를 생성하는 명령어에는 2가지가 있다.
docker commit
docker container
를 image
로 생성commit
명령어를 실행하는 시점의 docker container 상태가 보존docker container
의 상태를 백업하는 경우에 자주 사용docker build
Dockerfile
이라는 단순 텍스트 파일를 사용하여 image
생성Dockerfile
은 지정된 문법을 지켜야 함Dockerfile
을 작성하고 공유하면 image의 구성을 쉽게 알 수 있음 이 게시물에서는 두 번째 생성법인 docker build
명령어를 알아 볼 것이다.
먼저 docker build
명령어와 Dockerfile
파일에 대해 차근차근 알아보자.
참고로 대부분의 내용은 docker 홈페이지의 래퍼런스와 혼자 사용해보면서 알아낸 것을 위주로 작성했다.
docker build
명령어는 docker image
를 빌드할 때 다음 두 가지를 사용한다.
Dockerfile
build context
Dockerfile
은 텍스트 파일이고 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.0
Dockerfile
이라는 이름 대신에 다른 파일을 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
명칭을 그대로 따라갑니다.