최근 GHA 를 통하여 CI CD 환경을 구성하였는데 빌드 시간을 단축시키기 위하여 캐시를 적용하려고 시도하였다. 패키지 설치 또는 빌드 등 캐시를 적용하여 시간을 단축시켜왔는데 그 중 도커 이미지 빌드 시간을 단축시켰던 경험을 글로 적어 되새김질하고자 한다.
Dockerfile 에는 사용할 베이스 이미지, 환경 변수, 명령어 등을 작성되어있다. 다음과 같이 말이다.
FROM 3.9.16-slim-buster
COPY Pipfile Pipfile.lock /app
WORKDIR /app
RUN pipenv install
COPY src /app/src
RUN python setup.py install
ENTRYPOINT ["python", "main.py"]
위 이미지를 토대로 컨테이너를 띄우면 3.9 버전의 파이썬이 설치되어 있고, 현재 디렉토리에 있는 파일이 모두 복사되어 있으며 파이썬 패키지도 모두 설치되어있다. 이는 각 명령어 별로 레이어가 생성되어 쌓아지고 최종적으로 컨테이너 레이어를 통해 만들어진 것으로 볼 수 있다. 아래는 참고한 사이트의 이미지이다. 이를 보면 쉽게 레이어가 어떻게 쌓이는지 이해가 될 것이다.
개발을 하다보니 소스코드를 수정하여 빌드할 때 변경사항이 생기고, 패키지 인스톨 과정은 대부분 동일하다. 즉, 위 Dockerfile 에서 Pipfile 을 통해 패키지 설치하는 과정까지는 웬만하면 바뀌지 않는다는 것이다. 따라서 해당 레이어까지는 캐시를 적용하고 그 다음부터는 캐시를 적용하지 않는다면 빌드시간이 매우 단축될 것이다. 이는 이미 도커에 기본값으로 설정되어 있어 자동으로 레이어 캐시가 적용된다.
깃헙 액션에서는 크게 두 가지의 러너가 존재한다.
보통 레이어 캐시를 저장하는 곳은 로컬이다. 그러나 깃헙에서 제공하는 러너를 사용한다면 이전에 빌드한 러너와 이후 빌드할 러너는 다를테니 당연히 캐시가 적용이 안된다. 반면 self-hosted runner 에서 빌드한다면 이전에 빌드한 러너를 그대로 사용할 수 있으니 레이어 캐시가 적용된다.
(만약 scalable self-hosted runner 를 적용하였다면 러너가 바뀔 수도 있으니 레이어 캐시는 적용이 안 될 것이다)
그럼 GHA 에서는 어떻게 레이어 캐시를 적용할 수 있을까?
GHA 에서 제공하는 캐시를 사용
actions/cache@v3 액션을 통해 깃헙액션에 캐시로 저장할 수 있다. 실제로 대부분 깃헙 액션에서 캐시를 해야될 때 actions/cache 액션을 다수 사용한다. 그러나 이는 10GB 까지 저장할 수 있다(이후 정책이 바뀔 수도 있음).
CLOUD PLATFORM 에 원격저장소를 사용
나의 경우 AWS 를 주로 이용하니 S3 를 사용하여 캐시를 하였다. 주로 buildx 를 통해 멀티 플랫폼으로 이미지를 빌드할텐데 이때 cache-from
, cache-to
를 통해 캐시 저장소를 지정할 수 있다.
# ref: github.com/moby/buildkit
buildctl build ... \
--output type=image,name=docker.io/username/image,push=true \
--export-cache type=s3,region=eu-west-1,bucket=my_bucket,name=my_image \
--import-cache type=s3,region=eu-west-1,bucket=my_bucket,name=my_image
# 깃헙액션에서 build-push-action 을 사용한다면
- name: Build and push
uses: docker/build-push-action@v4
with:
context: .
push: true
tags: user/app:latest
cache-from: type=s3,region=eu-west-1,bucket=my_bucket,name=my_image
cache-to: type=s3,region=eu-west-1,bucket=my_bucket,name=my_image
참고로 위 cache-from
, cache-to
에 type=gha
로 넣어주면 GHA 캐시를 사용한다.
캐시는 되도록 작은 사이즈 파일을 지정하자
원격 저장소를 통해 캐시를 할 때 이미지 사이즈가 크다면 파일을 내려받고 업로드하는데 오래걸린다(이를 docker 에서는 import/export 라고 한다). 또한 캐시를 export 할 때 Docker 에서는 gzip 등 방식으로 압축하는데 이때 이미지가 크다면 preparing cache 단계에서도 당연히 오래걸린다. 따라서 캐시를 적용하기에 앞서 최대한 이미지의 사이즈를 줄이고 캐싱을 하는 것을 추천한다.
GitHub Actions에서 도커 캐시를 적용해 이미지 빌드하기