도커를 공부해보고 있는데, 레이어라는 개념이 좀 신기해서 한번 정리 겸 글을 작성해본다.
1. Docker Imager Layer?
Docke 이미지는 Dockerfile 로 만들어진 여러 레이어로 이루어져 있고 각 레이어는 읽기만 가능(Read-only)합니다.
그림으로 보면 다음과 같죠!
위의 그림에서는 3개의 층으로 구성되어 있는 stack 구조로 도커 이미지를 그려놨다.
이때 각각의 층을 Docker에서는 레이어(layer)라고 부르며 특별히 이미지를 구성하고 있는 레이어를 이미지 레이어라고 부른다.
즉 위의 이미지는 서로 다른 3개의 이미지 레이어로 구성되어 있다고 볼 수 있다.
Dockerfile의 명령들을 하나 하나 실행할 때마다, 레이어가 생기는 구조이고, 이는 그래프 드라이버를 통해 합쳐집니다.
이번에는 Docker 이미지에게 run 명령을 통해 컨테이너를 만들어보자.
Docker 의 이미지를 이용해서 docker run 을 하면 Docker는 도커가 관리하는 파일 시스템 영역에 이미지를 복사한다.
복사 후 docker는 이미지의 최상단에 컨테이너 레이어(Container layer)라고 불리는 하나의 얇은 레이어를 추가하여 컨테이너를 생성한다.
사용자가 컨테이너 안에서 읽고 쓰는 모든 작업은 이 컨테이너 레이어에 기록되고, 이미지 레이어에는 적용되지 않는다.
쉽게 말해 Image layer는 변경 불가하고(read only layer), Container layer는 변경 가능하다(Readable/Writable layer)
또한 Docker는 같은 이미지를 기반으로 실행한 컨테이너 들은 모두 같은 이미지를 기반으로 실행된다.
따라서 하나의 이미지로 여러 컨테이너를 만들 수 있게 됩니다. 즉, 컨테이너는 자신만의 Container Layer를 사용할 뿐입니다.
컨테이너가 종료되면, 이미지 레이어는 삭제되지 않지만 컨테이너 레이어는 소멸된다.
만약에 사용자가 Container Layer에서 작업하던 내용을 Image layer로 적용하고 싶을 경우 docker commit을 사용하면 된다.
docker commit을 사용하게 되면 기존의 Image layer 들과 직접 작성한 Container Layer를 이용해 새로운 이미지를 생성합니다.
2. 필요한 이유?
그럼 왜 이러한 Layer구조를 사용할까요? 장점이 무엇일까요?
기존 이미지에 파일 하나 추가했다고 수백 메가를 다시 다운로드한다면 매우 비효율적일 수밖에 없습니다.
하지만, 레이어 방식은 기존 이미지에 추가적인 파일이 필요할 때 다시 다운로드하는 방법이 아닌 해당 파일을 추가하기 위한 개념입니다.
즉 기존의 이미지 위에 추가적으로 필요한 Layer만 추가한다면 데이터의 저장을 효율적으로 할 수 있습니다.
예를 들어 다음 Dockerfile을 잠시 살펴봅시다. 위에서 말한 적이 있는데,
Dockerfile의 명령들을 하나하나 실행할 때마다, 레이어가 생기는 구조이고, 이는 그래프 드라이버를 통해 합쳐집니다.
FROM node
WORKDIR /app
COPY . /app
RUN npm install
EXPOSE 80
CMD ["node", "server.js"]
명령 한 줄 한 줄이 전부 Layer에 해당되게 됩니다.
우선 처음 다음 명령을 실행시키면 시간이 좀 지난 후에 build에 성공하게 됩니다.
docker build .
하지만 2번째로 같은 파일을 다시 Build 하면 cache로 인하여 매우 빠른 시간 안에 build에 성공하게 됩니다.
WORKDIR ./app
COPY . /app
RUN npm install
위 3개의 step 이 모두 CACHED 수식어가 붙어있다! 즉 캐시 된 결과를 사용하여 빠른 시간에 빌드한 것이다.
여기서 우리의 소스코드 부분을 조금 변경해보자. 이후 Build 할 때 처음부터 다 build 할까?
소스코드가 변경되었으니 "COPY . /app" 레이어부터는 이전 cached 된 내용이 아닌, 새롭게 수행하게 된다.
당연한 것이 위 명령은 현재 Dockerfile이 있는 디렉터리의 소스 코드를 ./app 으로 복사한다는 의미인데, 현재 디렉토리의 소스코드 일부분이 변경되었으니 이전 cached 된 내용을 사용할 수가 없다.
따라서 COPY. /app부터는 새롭게 다시 실행해야 한다.
FROM node
WORKDIR /app
(이전 캐쉬된 내용 사용)
-------------------------
COPY . /app
RUN npm install
EXPOSE 80
CMD ["node", "server.js"]
여기서 생각할 점이 있는데, "COPY. /app" 이후의 모든 레이어를 다시 수행해야 한다는 점이다.
"COPY . /app" 이 수행된 이후의 결과가 이전과 동일한지는 Docker가 보장할 수 없기 때문에 당연한 결과이다.
하지만 소스코드의 일부분만 변경했기 때문에 "COPY. /app"을 재수행 한다는 점은 이해가 가지만,
사실 뒤이어 오는 RUN npm install과 같이 의존성을 설치하는 부분까지 다시 다 수행해야 하는지는 의문이다.
이를 위해 조금 코드의 순서를 바꿔서 최적화해보자. 다음 변경된 도커 파일을 살펴보자.
FROM node
WORKDIR /app
COPY package.json /app
RUN npm install
COPY . /app
EXPOSE 80
CMD ["node", "server.js"]
package.json 레이어가 먼저 수행되기 때문에 이후에 코드 일부분을 수정해도 "COPY . /app" 이후만 다시 수행된다.
이전 과정은 CACHED 된 결과를 사용한다.
단지 순서를 변경만 해도 이렇게 성능상 이점을 얻을 수 있습니다!
3. 출처
https://blog.djjproject.com/782
https://blog.naver.com/alice_k106/221530340759
'DevOps > Docker' 카테고리의 다른 글
[Docker] 도커의 환경변수 설정 (1) | 2022.09.15 |
---|---|
[Docker] Volumes과 Bind Mounts (0) | 2022.09.14 |
[Docker] 외부에서 컨테이너로, 컨테이너에서 외부로 파일 복사하기 (0) | 2022.09.07 |
[Docker] 도커의 Attached, Detached 컨테이너 (1) | 2022.09.07 |
[Docker] Docker 입문 수업 (0) | 2022.02.08 |
댓글