Go 애플리케이션 Docker 이미지 최적화 가이드

Go 애플리케이션을 Docker 이미지로 빌드할 때, 불필요하게 큰 이미지 크기로 인해 고민하는 경우가 많습니다. 이 글에서는 CGO 사용 여부에 따라 Go 프로젝트의 Dockerfile을 최적화하는 두 가지 모범 사례를 소개합니다.

1. CGO를 사용하지 않는 경우

Go 애플리케이션은 종종 CGO 없이 빌드될 수 있으며, 이 경우 scratch 이미지를 기반으로 매우 작고 효율적인 런타임 이미지를 만들 수 있습니다. scratch 이미지는 아무것도 포함하지 않는 최소한의 베이스 이미지로, 오직 리눅스 커널만 접근 가능합니다.

최적화 전략은 다음과 같습니다:

  1. 먼저, golang 공식 이미지를 사용하여 Go 애플리케이션의 바이너리를 빌드합니다.
  2. 빌드된 바이너리를 scratch 이미지로 복사합니다.
  3. 애플리케이션 실행에 필요한 경우, TLS 인증서와 같은 추가 파일도 함께 복사합니다.

다음은 CGO를 사용하지 않는 경우의 Dockerfile 예시입니다:

# 빌드 단계: golang 이미지를 사용하여 바이너리 생성
FROM golang:1.19-alpine AS builder

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

# 소스 코드 복사
COPY . .

# Go 모듈 의존성 다운로드 (선택 사항, 캐싱 활용)
RUN go mod download

# CGO 비활성화, OS 및 아키텍처 지정 후 바이너리 빌드
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o myapp ./cmd/server/main.go

# TLS 인증서 복사 (https 통신 필요시)
RUN apk add --no-cache ca-certificates

# --- 런타임 단계 ---
# scratch 이미지를 사용하여 최소 이미지 생성
FROM scratch

WORKDIR /app

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

# 빌드 단계에서 복사된 TLS 인증서 복사
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/

# 애플리케이션 실행 환경 변수 설정 (예: 포트)
ENV APP_PORT=8080

# 애플리케이션이 사용할 포트 노출
EXPOSE 8080

# 컨테이너 시작 시 실행할 명령어
ENTRYPOINT ["/app/myapp"]

2. CGO를 사용하는 경우

CGO를 사용해야 하는 경우, scratch 이미지만으로는 빌드된 바이너리가 제대로 작동하지 않을 수 있습니다. 이 경우, alpine과 같은 가볍고 필수적인 시스템 라이브러리를 포함하는 베이스 이미지를 사용하는 것이 좋습니다. alpine 이미지는 매우 작기 때문에 (일반적으로 5MB 내외) 여전히 효율적인 이미지 크기를 유지할 수 있습니다.

Dockerfile은 다음과 같이 수정됩니다:

# 빌드 단계: golang 이미지를 사용하여 바이너리 생성
FROM golang:1.19-alpine AS builder

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

# 소스 코드 복사
COPY . .

# Go 모듈 의존성 다운로드 (선택 사항, 캐싱 활용)
RUN go mod download

# OS 및 아키텍처 지정 후 바이너리 빌드 (CGO 활성화 상태)
RUN GOOS=linux GOARCH=amd64 go build -o myapp ./cmd/server/main.go

# --- 런타임 단계 ---
# alpine 이미지를 사용하여 필수 라이브러리 포함
FROM alpine:latest

WORKDIR /app

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

# 애플리케이션 실행에 필요한 다른 파일 (예: 설정 파일, 정적 파일) 복사
# COPY --from=builder /app/configs /app/configs
# COPY --from=builder /app/static /app/static

# 애플리케이션 실행 환경 변수 설정 (예: 포트)
ENV APP_PORT=8080

# 애플리케이션이 사용할 포트 노출
EXPOSE 8080

# 컨테이너 시작 시 실행할 명령어
ENTRYPOINT ["/app/myapp"]

위 예시에서 GOOSGOARCH 환경 변수를 설정하여 빌드 시 대상 운영체제 및 아키텍처를 명시하는 것이 중요합니다. 또한, 애플리케이션이 실행되는 동안 필요한 모든 종속성 (예: 설정 파일, 정적 파일)도 런타임 이미지에 포함시켜야 합니다.

태그: docker Dockerfile go Golang Optimization

8월 2일 15:03에 게시됨