관리 메뉴

즐겁게, 코드

쿠버네티스 베스트 프랙티스 - 01. 작은 이미지 활용하기 본문

☁️ 클라우드/Kubernetes

쿠버네티스 베스트 프랙티스 - 01. 작은 이미지 활용하기

Chamming2 2022. 5. 7. 22:17
본 포스트는 Google Cloud Tech의 영상 내용을 정리하면서 작성한 글입니다.

이번 글에서는 쿠버네티스의 좋은 습관 중 하나인 작은 이미지를 활용하는 방법을 소개해보려 하는데요, 이미지 크기를 작게 유지하는 것은 가장 기본적이면서도 효과적인 방법 중 하나입니다.

  • 테스트용 go 어플리케이션
package main

import "fmt"

func main() {
	fmt.Println("hello world")
}
  • 이미지 빌드용 도커파일 예시
FROM golang

WORKDIR /app

COPY ./* .

RUN cd /app && go build
CMD go run hello

그런데 콘솔에 "hello world" 를 출력하는 정말 간단한 코드조차 빌드하면 자그마치 1GB에 달하는 이미지가 생성되는데요, 생성된 이미지는 아래와 같은 구조를 갖게 됩니다.

위의 도커파일로 생성되는 이미지의 구조

하지만 이렇게 큰 용량의 이미지를 사용하게 되면 다음의 문제들이 계속해서 발목을 잡게 됩니다.

  • 이미지를 클라우드 기반의 레지스트리를 통해 배포한다면 이미지 용량이 클수록 더 많은 저장비용이 부과됩니다.
  • 이미지를 push & pull 하는 과정에서도 많은 시간과 불필요한 네트워크 전송 요금이 부과됩니다.

그럼 어떻게 해야 보다 가벼운 이미지를 생성할 수 있을까요?

운영체제의 경량 배포판 사용하기

보다 작은 이미지를 만들기 위한 첫 번째 방법은 '작은 운영체제를 사용하는 것' 입니다.

 

아마 도커를 배워 보신 분들이라면 'alpine(알파인)' 이라는 베이스 이미지를 한번쯤 만나 보셨을 텐데요, 알파인은 바로 컨테이너 환경을 위한 최소한의 기능만을 남겨둔 리눅스의 버전 중 하나입니다.

alpine 이미지는 컨테이너 기동을 위한 최소한의 기능만을 남겨놓은 덕분에 가벼울 뿐만 아니라 보안 측면에서도 강점을 가집니다.

빌드가 실행되는 베이스 OS를 알파인 기반으로 변경한 구조

그렇다면 알파인 사용 여부에 따라 얼마나 큰 용량 차이가 발생할지 확인해 보겠습니다.

  • 알파인 리눅스 기반의 golang 이미지를 베이스 이미지로 사용하는 예시
FROM golang:alpine

WORKDIR /app

COPY ./* .

RUN cd /app && go build
CMD go run hello​

알파인 이미지 기반 빌드 결과(위, 328MB) / 알파인을 사용하지 않은 결과(아래, 820MB)

굉장하지 않나요? 단순히 베이스 이미지를 변경했을 뿐인데 차지하는 용량이 절반 이하로 줄어든 모습입니다.

하지만 여기서 끝이 아니라, 여기서 용량을 더 줄일 수 있는 방법이 존재합니다.

빌더 패턴을 사용해 이미지 제작하기

경량화된 운영체제를 사용하는 것으로 수백 메가의 용량을 절약할 수 있었는데요, 빌더 패턴 을 적용하면 이미지 용량을 더 줄이는 것도 가능합니다.

빌더 패턴이란 쉽게 어플리케이션의 "빌드 과정" 과 "실행 과정" 을 분리하는 패턴을 의미합니다.

최종 이미지에는 "실행 프로세스" 의 어플리케이션 실행 파일만이 포함됩니다.

빌더 패턴은 도커파일의 멀티 스테이지 빌드를 활용해 빌드와 실행 프로세스를 분리한 후, 최종적으로 실행되는 이미지에는 런타임과 빌드 도구들을 제거한 실행 파일만을 포함시켜 구현할 수 있습니다.

  • 빌드와 실행 단계를 분리하고, 최종 결과물에는 실행 가능한 파일만 포함시키는 예시
# 빌드 프로세스
FROM golang:alpine AS build-env
WORKDIR /app
COPY ./* .
RUN cd /app && go build -o hello

# 빌드된 결과물을 실행하는 프로세스
FROM alpine

# alpine 베이스 이미지는 HTTPS용 인증서가 존재하지 않아 이를 추가해줘야 한다.
RUN apk update && apk add ca-certificates && rm -rf /var/cache/apk/*
WORKDIR /app
COPY --from=build-env /app/hello .
CMD ./hello

위의 도커파일로 생성한 go-with-builder-patten 이미지 (7.6MB)

이미지를 빌드한 결과, 알파인을 사용하지 않았을 때에 비해 1%도 되지 않는 용량을 차지하는 모습입니다.

단순 방법을 바꿨을 뿐인데 800MB의 이미지가 단 8MB로 줄어들다니, 정말 굉장하지 않나요? 

Tip. 인터프리터 언어 기반의 이미지 최적화

Node.js 나 파이썬 등의 인터프리터 언어는 실행 과정에서 컴파일(빌드)를 수행하지 않으므로 빌더 패턴을 적용하기가 쉽지 않은데요, 대신 구글에서 제작한 Distroless 이미지를 활용하면 용량 최적화를 수행할 수 있게 됩니다.

만약 Node.js 기반의 어플리케이션을 최적화하는 예시가 궁금하시다면 이 글 도 참고해 보시는 것을 권해드리겠습니다.

제가 놓친 내용이 있다면 댓글로 보강해주시면 감사드리며, 오늘도 즐거운 하루 보내시길 바라겠습니다.

감사합니다 🙂

반응형
Comments
소소한 팁 : 광고를 눌러주시면, 제가 뮤지컬을 마음껏 보러다닐 수 있어요!
와!! 바로 눌러야겠네요! 😆