본문 바로가기

Operations/Docker

[Docker] Golang으로 도커 이미지 만들기

기본적으로 golang은 컴파일 언어이기 때문에 go build 명령어를 통해서 하나의 파일을 만들어냅니다. 이 build하는 과정까지 docker image에 포함한다면 이미지의 크기가 커질 수 있기 때문에 멀티 스테이지를 이용한 빌드 방법으로 빌드 된 파일 하나만을 가지고 도커 이미지를 만드는 방법이 있습니다.

빌드 할 예시 파일

gin의 예시코드를 실행시키는 dockerfile을 예시로 build연습을 해보겠습니다!

package main

import (
	"net/http"

	"github.com/gin-gonic/gin"
)

func main() {
	r := gin.Default()
	r.GET("/ping", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{
			"message": "pong",
		})
	})
	r.Run() // listen and serve on 0.0.0.0:8080 (for windows "localhost:8080")
}

일반적인 빌드 방법

FROM golang:1.18-alpine

WORKDIR /usr/src/app
COPY . .

RUN go build -o main .
CMD [ "/main" ]

위와 같은 방법으로 빌드를 하게되면 alpine이미지를 썼음에도 불구하고 500MB정도의 크기를 갖는 이미지를 생성합니다. go의 모든 라이브러리나 소스를 모두 가져와서 이미지를 만들기 때문이죠

멀티 스테이지를 이용한 빌드

### Builder
FROM golang:1.18-alpine as builder
RUN apk update && apk add git && apk add ca-certificates

WORKDIR /usr/src/app
COPY . .

RUN CGO_ENABLED=0 GOOS=linux go build -a -ldflags '-s' -o main .


### Make executable image
FROM scratch

COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
COPY --from=builder /etc/passwd /etc/passwd
COPY --from=builder /usr/src/app/main /main

CMD [ "/main" ]

두 단계를 통해서 이미지를 만드는 멀티 스테이지를 이용하면 빌드 된 파일을 통해서 새로운 이미지를 만들어냅니다. 

멀티 스테이징

코드에는 FROM이 두개가 있습니다. FROM은 새로운 빌드 스테이지(단계)가 시작되었음을 나타냅니다.

두 단계의 스테이지를 통해서 이미지를 생성하는데 첫번째 스테이지에서는 이미지를 빌드하고 main 파일을 떨구는 역할을 합니다.

두번째 스테이지에서는 이 파일을 통해서 실행 가능한 도커 이미지를 만듭니다. COPY --from=builder는 COPY를 도커 호스트가 아닌 'builder' 스테이지에서 실행한다는것을 뜻합니다. 'builder' 스테이지에서 /usr/src/app 경로에 main을 떨궜고 그 main파일을 현재 디렉터리로 옮기는 과정을 실행하고 있습니다. 

추가적으로 넣어줘야 하는 옵션

scratch는 텅텅 빈 이미지로 위와같이 멀티 스테이지를 이용할 때 주로 쓰인다고 합니다. 빌드 된 파일로 이미지를 만들어주면 무려 7MB의 크기가 나옵니다. 거의 100배 차이라고 해도 될만큼 이미지의 크기가 확 줄었습니다.

단, 위 코드에 나온것처럼 넣어줘야 할 옵션들이 있습니다. 

builder 스테이지에서도 alpine으로 빌드를 해줬는데 alpine이미지에는 git이 없으므로 git을 추가해줘야 하고

scratch 이미지에는 https를 지원하는 CA 인증서가 들어가있지 않기때문에 ca-certificates.crt도 넣어줘야 합니다. /etc/passwd 바이너리 등이 필요한 때도 있기 때문에 바이너리를 넣어줘야 합니다. 

결론

위와같이 신경쓸것들이 존재하지만 용량을 많이 줄일 수 있으므로 멀티 스테이지 방법을 쓰는것이 좋아보입니다.

 

https://lynlab.co.kr/blog/64 블로그를 많이 참고 하였습니다!