도커 이미지 구조

image

nginx 이미지는 ubuntu를 기반으로, web app 이미지는 nginx 기반으로 만들어졋다고 가정하자. 공부했었지만 도커 이미지는 레이어 구조로, 새로운 변경사항이 레이어로 쌓인다. 따라서 nginx 이미지는 ubuntu 이미지를 기반으로 만들어졌기 때문에 layerA,B,C 위에 nginx를 구성하기 위한 layer가 쌓인 형태를 띈다.

컨테이너를 생성하면 web app 레이어가 읽기 전용으로 복사되고, 그 위에 컨테이너 레이어가 쌓인다. 컨테이너 레이어는 읽기와 쓰기 모두 가능한 레이어이다.

이제 nginx 이미지 레이어를 직접 확인해보자.

$ docker image inspect nginx:latest

image

각 이미지 레이어는 sha256 해시값으로 표현되어 있다.


Dockerfile 없이 이미지 생성

기존 컨테이너를 기반으로 새 이미지를 생성할 수 있다. 기존 컨테이너에서 변경사항을 만든 후에 새로운 이미지로 커밋할 수 있다.

$ docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]

-a: 누가 변경점을 만드는지 author를 히스토리로 남기는 옵션

-m: 커밋 메세지

# ubuntu:focal 이미지로 my-ubuntu라는 이름의 컨테이너 만들기 
$ docker run -it --name my-ubuntu ubuntu:focal
root@b3858232ad97:/# cat > my_file
hello

# my-ubuntu 컨테이너를 my-ubuntu:1.0.0라는 이름의 이미지로 저장
$ docker commit -a syj -m 'init' my-ubuntu my-ubuntu:1.0.0

$ docker images

# 이미지 레이어 확인
$ docker image inspect ubuntu:focal
$ docker image inspect my_ubuntu:1.0.0

image

my_ubuntu:1.0.0 의 레이어는 ubuntu:focal 이미지의 레이어를 그대로 가져와서 쌓은 구조임을 확인할 수 있다.

image

위에서 보는것이 ubuntu:focal 이미지의 정보이고 아래가 my-ubuntu:1.0.0 이미지의 정보이다.

image


Dockerfile 이용하여 이미지 생성

Dockerfile을 기반으로 새 이미지를 생성할 수 있다. Dockerfile에 있는 명령어는 위에서 부터 한줄씩 순서 대로 실행하면서 레이어를 쌓는다. Dockerfile로 이미지를 빌드하려면 아래 명령어를 사용한다.

$ docker build [OPTIONS] PATH

# ./ 디렉토리를 빌드 컨텍스트로 my_app:v1 이미지 빌드 (Dockerfile 이용)
$ docker build -t my_app:v1 ./

# ./ 디렉토리를 빌드 컨텍스트로 my_app:v1 이미지 빌드 (example/MyDockerfile 이용)
$ docker build -t my_app:v1 -f example/MyDockerfile ./

-t: 빌드한 이미지에 대한 태그 -f: Dockerfile의 경로

# Dockerfile
FROM node:12-alpine
RUN apk add --no-cache python3 g++ make
WORKDIR /app
COPY . .
RUN yarn install --production
CMD ["node", "src/index.js"]
$ docker build -t myapp:v1 ./

이를 실행하면 도커 이미지가 만들어진다. build context 를 docker daemon에게 전달한다는 메세지, step이 6가지인 이유는 Dockerfile이 6줄이기 때문이다.

image

FROM node:12-alpine
RUN apk add --no-cache python3 g++ make
WORKDIR /app
COPY . .
RUN yarn install --production
CMD ["node", "src/index.js", "l"]
$ docker build -t myapp:v2 ./

이번에는 Dockerfile의 CMD를 바꿔서 새로운 도커이미지를 만들어보자. 그러면 using chahe 라고 하면서 docker daemon이 판단했을 때 재사용이 가능한 레이어는 다시 사용하는 것을 볼 수 있다. 우리가 마지막 줄만 바꿧기 때문에 마지막 step6만 새롭게 레이어를 만든다.

image


빌드 컨텍스트

빌드 컨텍스트는 도커 빌드 명령 수행 시 현재 디렉토리(Current Working Directory)에 있는 모든 파일 및 폴더들을 말한다. 현재 디렉토리에 굉장히 많은 파일들이 있을텐데, 도커 데몬이 도커 빌드 명령어를 받을 때 빌드 컨텍스트를 받음으로써 도커 빌드를 정상적으로 수행할 수 있다.

FROM node:12-alpine
RUN apk add --no-cache python3 g++ make
WORKDIR /app
COPY . .
RUN yarn install --production
CMD ["node", "src/index.js"]

여기서 COPY . . 는 현재 디렉토리 내용을 컨테이너 내부로 복사한다는 뜻이다. 이 때 현재 디렉토리를 알기 위해서는 도커 데몬이 빌드 컨텍스트 정보를 가지고 있어야 한다. 이처럼 도커 컨텍스트는 Dockerfile로부터 이미지 빌드에 필요한 정보를 도커 데몬에게 전달하기 위한 목적이다. 그래서 현재 디렉토리에 있는 데이터가 방대하다면 도커 빌드를 하는 시간이 길어지고 비효율적이게 된다. 이를 해결하기 위해 .dockerignore 파일을 사용한다.


.dockerignore

.dockerignore는 특정 디렉토리 혹은 파일 목록을 빌드 컨텍스트에서 제외하기 위한 목적으로 사용된다. .gitignore와 동일한 문법을 가지고 있다.

# comment
*/temp*
*/*/temp*
temp?

*.md
!README.md

이렇게 하면 .dockerignore 에 적혀있는 파일들을 제외한 후에 도커 빌드 컨텍스트로 전달된다.

image

image

!은 예외처리로, README.md를 제외한 모든 .md 파일들 제외