Skip to content

Git action에서 도커 이미지 빌드 시간을 단축시켜보자

Seungheon Han edited this page Dec 1, 2024 · 1 revision
Pasted image 20241201143430

현재 Media 서버를 한번 배포하는데 걸리는 시간이 평균적으로 10분정도 걸리고 있다. 이는 다른 Api, Chat, Record 서버들에 비교했을 때, 약 5배 이상 오래걸리고 있다.

때문에 변경 사항이 생겨서 배포해서 운영 환경에서도 잘 돌아가는지 확인해야 할 때마다, 코드를 올리고 10분동안 가만히 앉아서 배포가 완료될 때까지 기다리고 있어야 했다.

원인

Pasted image 20241201144048
  • Docker 이미지 빌드가 오래 걸리고 있다.
  • 미디어 서버에서 Mediasoup을 사용하고 있는데, 이게 설치하는데 시간을 많이 사용하고 있다.
  • GitHub Actions는 매번 새로운 인스턴스를 생성하여 작업하기 때문에 Docker 레이어 캐싱이 제대로 활용되지 않는다.
  • 멀티 스테이지 빌드 전략을 사용하고 있어 Base 이미지를 미리 만들어도 최종 이미지에 포함되지 않는다.

도커의 이미지 빌드 과정을 자세히 알아보자

Docker 이미지 레이어

Docker 이미지의 레이어는 파일 시스템 변경사항명령어 실행 결과를 저장한 읽기 전용(read-only) 파일 시스템이다.

레이어의 특징:

  • 이미지의 구조적 구성 요소
    • Docker 이미지는 여러 개의 읽기 전용 레이어로 구성된다.
    • 각 레이어는 Dockerfile의 명령어(RUN, COPY, ADD)로 생성된다.
  • 불변성
    • 한 번 생성된 레이어는 변경되지 않는다.
    • 변경이 필요한 경우 새로운 레이어가 생성된다.
  • 종속성
    • 각 레이어는 바로 아래 레이어에 의존하며, 최종 이미지는 모든 레이어가 병합된 형태이다.

이미지 레이어 구조

FROM node:16-alpine
WORKDIR /app 
COPY package.json ./
RUN npm install
COPY . . 
CMD ["node", "app.js"]

위 도커파일은 다음과 같은 레이어로 구성된다.

  • 베이스 레이어
  • 작업 디렉토리 레이어
  • 파일 복사 레이어
  • 의존성 설치 레이어
  • 애플리케이션 레이어
  • 메타데이터 레이어

Docker 캐싱 메커니즘

Docker는 레이어 단위로 캐싱을 수행한다. 이전 빌드에서 변경되지 않은 레이어를 재사용함으로써 빌드 시간을 줄이고 자원을 절약할 수 있다.

동작 원리

  1. Dockerfile 실행 Docker는 Dockerfile의 각 명령을 순차적으로 실행하며, 이전 빌드 결과를 캐시로 확인한다.
  2. 명령과 결과 비교 각 명령이 이전 빌드에서 생성된 결과와 동일하면, 해당 레이어를 캐시에서 재사용한다.
  3. 변경사항 발생 시 캐시 무효화 이전 단계와 다른 입력이 발생하면 해당 단계부터 새로운 레이어가 생성된다.

캐싱이 작동하는 조건

  1. 명령어가 동일해야 한다
    • 명령어가 동일한 경우에만 캐시를 재사용한다.
  2. 명령어 입력이 동일해야 한다
    • COPY와 ADD는 입력 파일이 변경되면 캐싱되지 않는다.
    • package.json이 변경되면 이후 레이어는 재사용되지 않는다.
	COPY package.json ./
  1. 캐시된 결과가 존재해야 한다
    • 이전 빌드 결과가 삭제되었거나 캐시를 비활성화(--no-cache)하면 캐시를 사용할 수 없다.

캐싱이 안되는 상황

명령어 순서 변경

Docker는 Dockerfile의 각 명령어를 위에서 아래로 순차적으로 실행하며, 이전 명령의 결과를 기반으로 캐싱 여부를 결정한다. 때문에 명령어의 순서가 변경되면 Docker는 이전 캐시를 무효화 한다.

  • 기존 Dockerfile (캐싱 활용 가능)
    • COPY package.json ./ 단계에서 파일이 변경되지 않으면 RUN npm install은 캐싱을 재사용한다
COPY package.json ./       # 파일 복사
RUN npm install            # 의존성 설치
COPY . .                   # 나머지 파일 복사
  • 순서가 변경된 Dockerfile (캐싱 무효화)
    • COPY . . 단계에서 전체 파일을 복사하므로 파일 중 하나라도 변경되면 캐시가 무효화된다.
    • 이로 인해 RUN npm install도 새로 실행된다.
COPY . .                   # 나머지 파일 복사
RUN npm install            # 의존성 설치

위와 같은 상황이 발생하는 이유는 다음과 같다.

  • Docker는 명령어의 입력(파일, 환경 변수 등)과 결과를 기반으로 캐싱 여부를 결정한다.
  • 순서가 바뀌면 이전 단계의 입력이 변경된 것으로 간주되어 캐시를 무효화한다.
  • 파일 변경 가능성이 높은 명령어(COPY . .)를 앞에 배치하면, 그 이후 명령어들의 캐시가 전부 무효화된다.

Git action에서 도커 이미지 캐싱

Git action은 기본적으로 일회성 환경을 제공한다. 각 워크플로 실행 시 새로운 환경이 생성되며, 이전 빌드에서 생성된 Docker 캐시를 기본적으로 사용할 수 없다. 때문에 캐싱을 유지하려면 추가적으로 캐시를 외부에 저장하고 재사용하도록 구성해야 한다.

GitHub Actions의 BuildKit 캐싱 사용

GitHub Actions는 Docker의 BuildKit기반 캐싱 메커니즘을 제공한다. type=gha 설정을 통해 Docker 레이어를 GitHub Actions의 캐시 저장소에 저장하고, 이후 빌드에서 이를 재사용 할 수 있다.

  - name: Build and push Docker image
	uses: docker/build-push-action@v6
	with:
	  context: .
	  file: Dockerfile
	  cache-from: type=gha        # 이전 빌드 캐시 불러오기
	  cache-to: type=gha,mode=max # 새 캐시 저장
	  push: true                  # 이미지 푸시 활성화
	  tags: my-docker-repo/my-app:latest

결과

Pasted image 20241201152523 Pasted image 20241201152539

👥 팀 강점

🧑‍💻 개발 일지

📌 ALL

📌 FE

📌 BE

💥 트러블 슈팅

📌 FE

📌 BE

🤔 고민

📚 학습 정리

📌 김광현

📌 백지연

📌 전희선

📌 한승헌

🤝 회의록

🗒️ 데일리 스크럼

💬 팀 회고


👨‍👩‍👧‍👦 소개

🌱 문화

🔨 기술 스택

⚙️ 서비스 아키텍쳐

🚧 CI/CD

🌊 Flow

💭 6주를 보내면서

Clone this wiki locally