
docker 이미지 Layer 구조

위의 그림에서 왼쪽은 docker image이고 오른쪽은 docker container이다 도커 이미지가 총 3가지 있는 것을 확인할 수 있는데 왼쪽부터 ubuntu, nginx 그리고 web app 이렇게 구성이 되어있다 여기서는 이해가 쉽게 nginx는 ubuntu이미지 기반으로 만들어졌다고 가정하고 web app는 nginx 이미지 기반으로 만들어졌다고 가정을 해보자 ubnutu 이미지를 보면 A, B, C 3가지의 Layer로 구성되어있다 실제로 docker image는 Layer 아키텍처라고 새로운 환경이 계속 쌓이는 구조로 되어있다 그렇기 때문에 nginx 이미지는 ubuntu 기반으로 만들어졌기 때문에 ubuntu Layer가 그대로 있는 상태에서 nginx 이미지를 구성하는 Layer가 쌓이게 된다 web app 도 마찬가지라고 생각하면 되겠다 오른쪽 docker container는 web app이미지 Layer를 가지고 있는데 이 Layer는 ReadOnly 이미지로 읽기 전용으로 생성된다 그래서 이미지 Layer의 파일들은 변경이 불가한 상태이다 또한 컨테이너가 생성될 때마다 해당 컨테이너 Layer가 생성이 되는데 이 Layer는 읽기와 쓰기가 가능하다 다만 컨테이너가 종료되어 삭제될 때 컨테이너 Layer도 같이 삭제가 된다
docker images

docker images 명령어로 해당 호스트 로컬에 보관 중인 이미지 리스트를 확인할 수 있다
$ docker image inspect nginx:latest
위의 명령어는 특정 이미지의 상세정보를 볼 수 있는 명령어이다 확인해보면 아래의 그림처럼 Layer구조인걸 확인할 수 있다

docker commit
Dockerfile 없이 이미지를 생성해 보자
$ docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]
ubuntu 이미지를 컨테이너로 띄워서 commit 명령어로 my_ubuntu:v1 이미지를 생성했으며 docker images 명령어로 확인까지 해봤다.

docker build
Dockerfile의 명령어부터 알아보자
FROM: 명령 FROM은 새 빌드 단계를 초기화하고 후속 명령을 위해 기본 이미지를 설정한다. 따라서 유효함은 명령어 Dockerfile로 시작해야 한다 FROM. 이미지는 유효한 모든 이미지가 될 수 있다.
RUN: 명령문은 마치 쉘(shell)에서 커맨드를 실행하는 것처럼 이미지 빌드 과정에서 필요한 커맨드를 실행하기 위해서 사용된다. 쉘(shell)을 통해 거의 못하는 작업이 없는 것처럼 RUN 명령문으로 할 수 있는 작업은 무궁무진하지만 보통 이미지 안에 특정 소프트웨어를 설치하기 위해서 많이 사용된다.
WORKDIR: 명령문은 쉘(shell)의 cd 명령문처럼 컨테이너 상에서 작업 디렉토리로 전환을 위해서 사용된다. WORKDIR 명령문으로 작업 디렉터리를 전환하면 그 이후에 등장하는 모든 RUN, CMD, ENTRYPOINT, COPY, ADD 명령문은 해당 디렉터리를 기준으로 실행된다.
COPY: 명령문은 호스트 컴퓨터에 있는 디렉터리나 파일을 Docker 이미지의 파일 시스템으로 복사하기 위해서 사용된다. 절대 경로와 상대 경로를 모두 지원하며, 상대 경로를 사용할 때는 이 전에 등장하는 WORKDIR 명령문으로 작업 디렉터리를 어디로 전환을 해놨는지 고려해야 한다.
CMD: 명령문은 해당 이미지를 컨테이너로 띄울 때 디폴트로 실행할 커맨드나, ENTRYPOINT 명령문으로 지정된 커맨드에 디폴트로 넘길 파라미터를 지정할 때 사용한다.
EXPOSE: 명령문은 네트워크 상에서 컨테이너로 들어오는 트래픽(traffic)을 리스닝(listening)하는 포트와 프로토콜을 지정하기 위해서 사용되며 프로토콜은 TCP와 UDP 중 선택할 수 있는데 지정하지 않으면 TCP가 기본값으로 사용된다.
여기서 주의할 점은 EXPOSE 명령문으로 지정된 포트는 해당 컨테이너의 내부에서만 유효하며, 호스트(host) 컴퓨터에서는 이 포트를 바로 접근을 할 수 있는 것은 아니다. 호스트 컴퓨터로부터 해당 포트로의 접근을 허용하려면, docker run 커맨드를 -p 옵션을 통해 호스트 컴퓨터의 특정 포트를 포워딩(forwarding)시켜줘야 한다.
ENV: 명령문은 환경 변수를 설정하기 위해서 사용한다. ENV 명령문으로 설정된 환경 변수는 이미지 빌드 시에도 사용됨은 물론이고, 해당 컨테이너에서 돌아가는 애플리케이션도 접근할 수 있다.
LABEL: 명령문은 이미지에 메타데이터를 추가하며 LABEL은 키-값 한 쌍이다. 값 내에 공백을 포함하려면 LABEL명령줄 구문 분석에서와 같이 따옴표와 백 슬래시를 사용해야 하며 이미지는 둘 이상의 레이블을 가질 수 있으며 한 줄에 여러 레이블을 지정할 수 있다.
FROM node:16
LABEL maintainer="minhyeok Park <john721@naver.com>"
LABEL description="Simple server with Node.js"
# Create app directory
WORKDIR /app
# Install app dependencies
# A wildcard is used to ensure both package.json AND package-lock.json are copied
# where available (npm@5+)
COPY package*.json ./
RUN npm install
# If you are building your code for production
# RUN npm ci --only=production
# Bundle app source
COPY . .
EXPOSE 8080
CMD [ "node", "server.js" ]
위의 Dockerfile을 명령어로 실행해보자
$ docker build -t alsgur721:v1 -f <Dockerfile경로>


첫 번째 메시지부터 확인해보자면 빌드 컨텍스트를 docker daemon으로 보낸다는 걸 확인할 수 있다.
step은 총 9 스텝으로 이루어져 있는 걸 확인할 수 있는데 위의 Dockerfile을 보면 9줄의 Dockerfile지시어가 있기 때문이다.
이번에는 CMD 부분에 "1"을 추가하고 다시 Dockerfile을 실행해보겠다.

처음과 달라진 점이 있다면 일단 build속도가 빠르다는 것과 Using cache라는 구문이 보일 것이다.
모든 명령어가 cache를 사용하는 것은 아니지만 docker daemon이 판단을 했을 때 이전 이미지 빌드에서 각각의 스텝 즉 layer 재사용 가능한 layer 라면 cache라고 해서 동일한 응답을 다시 실행하지 않는다.
기술출처
https://docs.docker.com/engine/reference/builder/
Dockerfile reference
docs.docker.com
'DevOps > Docker' 카테고리의 다른 글
[Docker] GitHub Actions으로 docker CI (도커캐시) (0) | 2023.01.12 |
---|---|
[Docker] ubuntu에서 docker & docker-compose 설치 방법 (0) | 2022.12.30 |
[Docker] docker 로그 확인하기 (0) | 2022.12.05 |
[Docker] docker 볼륨 컨트롤하기 (0) | 2022.12.05 |
[Docker] docker run 주요 옵션 (0) | 2022.12.05 |