<aside> 💡 Docker는 layer라는 개념을 통해 이미지를 구성합니다. 각각의 layer에서 변화를 감지해 변화가 없으면 이전에 캐싱해둔 것을 가져다 쓰는 방식으로 이미지 빌드 시간을 단축합니다.

하지만 github action에서 docker 이미지를 그냥 빌드하는 경우, 로컬 환경과 달리 캐싱이 되지 않는다는 것을 알고 계셨나요? 이 부분을 확인하고 개선한 결과 이미지 빌드 과정은 2분 30초에서 46초로 약 1분 40~50초 정도, 66%가량 줄었습니다.

여기서는 이미지 캐싱, 멀티 스테이지 빌드에 관해 간략히 알아보고, github action runner상에서 docker 이미지를 위한 캐싱을 적용하는 방법을 알아봅니다.

저희 팀에서 CI, CD를 위해 Github action을 활용한 방법은 Github Action, Docker를 활용한 CI, CD(미완) 에, Github action과 docker에 대한 간단한 용어들은 Github Actions?Docker 기본에 정리해뒀습니다.

</aside>

<aside> 💡 캐시와 multi-stage 빌드의 개념을 알아야해서 1, 2번째에서 먼저 소개합니다. 해당 개념을 알고 계신 경우 3. 열심히 알아봤는데.. 웨..않뒈..로 건너뛰어주세요

</aside>

1. Docker Layer, 캐시

1) Docker Layer

Untitled

Dokcer의 이미지는 layer들로 이루어져있습니다. Dockerfile을 기반으로 해 위 사진과 같이 base 이미지를 두고 그 위로 layer를 쌓아올라가는 형식입니다.

일단 이미지가 빌드되면 이 layer들은 변하지 않습니다. 컨테이너가 올라가면 가장 최상단 layer인 layer N 위에 쓰기 전용 layer가 하나 더 올라가고, 컨테이너가 운영되며 변하는 모든 사항들은 이 쓰기 전용 layer에 저장되게 됩니다.

2) 빌드와 캐시

위에서 언급한 layer들이 변하는 경우가 있기는 합니다. 언제일까요?

당연히 다시 빌드했을 때입니다. 이미지가 만들어지는 시점은 빌드하는 경우일 뿐이니까요.

그럼에도 불구하고 빌드를 다시 한다고 모든 이미지가 재생성되는 것은 아닙니다.

도커는 똑똑해서 변경된게 없으면 다시 빌드하지는 않거든요

캐시

# BUILD
FROM node:18.12.1

WORKDIR /app

COPY package*.json ./

RUN npm install

COPY . .

RUN npm run build

CMD ["npm", "run", "start:dev-remote"]

위 코드는 예제로 쓸 Dockerfile입니다. Dockerfile 내에 있는 저 한줄 한줄은 각각 layer를 이루게 됩니다. Docker는 각각의 layer들에 대해 digest라는 해시값을 만들고, 빌드시 이 해시값을 비교해 변경 여부를 판단합니다. 이 때 변경 사항이 없다면 이전에 캐싱해둔 것을 그대로 사용합니다.

[+] Building 62.0s (11/11) FINISHED                                                       
...
=> [1/6] FROM docker.io/library/node:18.12.1  0.0s
=> [internal] load build context              17.5s
=> => transferring context: 182.36MB          17.3s
=> CACHED [2/6] WORKDIR /app                  0.0s
=> [3/6] COPY package*.json ./                0.7s
=> [4/6] RUN npm install                      25.2s
=> [5/6] COPY . .                             6.8s
=> [6/6] RUN npm run build                    4.9s 
=> exporting to image                         6.7s
...