관리 메뉴

피터의 개발이야기

[Docker] Multi-stage 빌드로 Go 애플리케이션 최적화하기 본문

DevOps/Docker

[Docker] Multi-stage 빌드로 Go 애플리케이션 최적화하기

기록하는 백앤드개발자 2024. 12. 3. 23:40
반응형

 

ㅁ 들어가며

 Docker multi-stage 빌드를 사용하여 Go 애플리케이션의 빌드 환경과 배포 환경을 분리하는 방법에 대해 정리해 보았다. 이 방법을 통해 최종 이미지의 크기를 줄일 수 있다.

 

ㅁ Docker Multi-stage 빌드란?

  Docker multi-stage 빌드는 하나의 Dockerfile 내에서 여러 단계(stage)를 나누어 최종 이미지를 생성하는 기술이다. 이를 통해 빌드 환경과 실행 환경을 분리하여 필요 없는 환경을 제거하여 최종 이미지의 크기를 줄인다.

 

ㅁ Go 애플리케이션을 위한 Multi-stage Dockerfile 작성

빌드 단계 정의

# 빌드 단계
FROM golang:1.17 AS builder

# 작업 디렉토리 설정
WORKDIR /app

# Go 모듈 파일 복사 및 의존성 다운로드
COPY go.mod go.sum ./
RUN go mod download

# 소스 코드 복사
COPY . .

# 애플리케이션 빌드
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o main .

먼저 Go 애플리케이션을 빌드하기 위한 단계를 정의한다.

이 단계에서는 Go 공식 이미지를 사용하여 애플리케이션을 빌드한다.

CGO_ENABLED=0GOOS=linux 옵션을 사용하여 정적 링크된 바이너리를 생성한다.

 

실행 단계 정의

# 실행 단계
FROM alpine:latest  

# 필요한 CA 인증서 설치
RUN apk --no-cache add ca-certificates

WORKDIR /root/

# 빌드 단계에서 생성된 바이너리 복사
COPY --from=builder /app/main .

# 애플리케이션 실행
CMD ["./main"]

이 단계에서는 경량화된 Alpine Linux 이미지를 사용하고, 빌드 단계에서 생성된 바이너리만을 복사한다.

 

전체 Dockerfile

# 빌드 단계
FROM golang:1.17 AS builder

WORKDIR /app

COPY go.mod go.sum ./
RUN go mod download

COPY . .

RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o main .

# 실행 단계
FROM alpine:latest  

RUN apk --no-cache add ca-certificates

WORKDIR /root/

COPY --from=builder /app/main .

CMD ["./main"]

 

ㅁ Multi-stage 빌드의 장점

  1. 이미지 크기 감소: 최종 이미지에는 실행에 필요한 바이너리와 최소한의 런타임만 포함되어 이미지 크기 감소됨.
  2. 보안 강화: 빌드 도구와 소스 코드가 최종 이미지에 포함되지 않아 보안이 강화됨.
  3. 빌드 캐시 최적화: 각 단계별로 캐시가 적용되어 빌드 속도가 향상.
  4. 명확한 관심사 분리: 빌드 환경과 실행 환경이 명확히 구분되어 관리가 용이해짐.

 

ㅁ 빌드 및 실행 방법

 

// 이미지 빌드
docker build -t my-go-app .

// 컨테이너 실행
docker run -p 8080:8080 my-go-app

ㅇ Dockerfile을 작성하여 이미지를 빌드하고 실행한다.

 

ㅁ 추가 최적화 팁

멀티 스테이지 빌드 내 캐시 활용

FROM golang:1.17 AS deps
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download

FROM golang:1.17 AS builder
WORKDIR /app
COPY --from=deps /go/pkg /go/pkg
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o main .

ㅇ 의존성 설치 단계와 소스 코드 빌드 단계를 분리하여 캐시를 더욱 효과적으로 활용할 수 있다.

 

경량 베이스 이미지 사용
Alpine Linux보다 더 작은 scratch 이미지를 사용할 수 있다.

단, 이 경우 SSL 인증서나 시간대 정보 등이 포함되지 않으므로 주의가 필요하다.

FROM scratch
COPY --from=builder /app/main .
CMD ["./main"]

 

불필요한 파일 제외
.dockerignore 파일을 사용하여 불필요한 파일이 빌드 컨텍스트에 포함되지 않도록 한다.

 

멀티 아키텍처 지원
GOARCH 환경 변수를 사용하여 다양한 아키텍처를 지원하는 이미지를 빌드할 수 있다.

ARG GOARCH=amd64
RUN CGO_ENABLED=0 GOOS=linux GOARCH=$GOARCH go build -a -installsuffix cgo -o main .

 

ㅁ 마무리

  Docker multi-stage 빌드를 사용하면 Go 애플리케이션의 빌드 환경과 실행 환경을 효과적으로 분리할 수 있다. 이를 통해 최종 이미지의 크기를 크게 줄이고, 보안을 강화하며, 빌드 프로세스를 최적화할 수 있다.

  이 방법은 특히 마이크로서비스 아키텍처나 컨테이너 오케스트레이션 환경에서 매우 유용하다. 작은 이미지 크기는 빠른 배포와 확장을 가능하게 하며, 리소스 사용을 최소화한다.   Multi-stage 빌드는 Go 애플리케이션뿐만 아니라 다른 언어로 작성된 애플리케이션에도 적용할 수 있는 유용한 방법이다. 

 

ㅁ 함께 보면 좋은 사이트

[Docker] Multi-stage build

Deep Dive into Multistage Dockerfile with a Golang App

[Dockerdocs] Multi-stage builds

Docker Multi Stage란?

[Git] go-docker-multi-stage-build
[Docker] Multi-stage 빌드 최적화 하기

반응형
Comments