Diary

Diary

日々学んだことをアウトプットする場として初めてみました

Golang で Multi-stage builds すると『version `GLIBC_2.34' not found』のエラー

Golang で Dockerfile を Multi-stage builds で作成した際に、
docker run すると『version `GLIBC_2.34' not found』のエラーが出ることがありました。

今回はその原因と解決策について共有します。

事象

環境

  • Host
  • Docker
    • v24.0.7
  • Dockerfile
    • build 用 base image: golang:1.21
    • deploy 用 base image: gcr.io/distroless/static

実行時エラー

$ docker run golang-bff:latest

/api: /lib/aarch64-linux-gnu/libc.so.6: version `GLIBC_2.32' not found (required by /api)
/api: /lib/aarch64-linux-gnu/libc.so.6: version `GLIBC_2.34' not found (required by /api)

Dockerfile

# syntax=docker/dockerfile:1

# 1. build
FROM golang:1.21 AS build

WORKDIR /app

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

COPY *.go ./

RUN go build -o /api

# 2. deploy
FROM gcr.io/distroless/static
WORKDIR /
COPY --from=build /api /api

EXPOSE 8080
USER nonroot:nonroot

ENTRYPOINT ["/api"]

原因

Go 言語でビルドされたバイナリは、通常 GLIBC などに依存しない「静的リンク」バイナリとなります。
これは、Go のランタイムとアプリケーションコードが単一の実行可能ファイルに全て含まれており、外部の共有ライブラリに依存しないことを意味しています。

今回はこれが何かの拍子で無効になっており、動的リンクを使うようなビルドをされていたものと思われます。
そのため、実行時に deploy image の中から外部パッケージの依存性を探しに行ったが見つからなかったのではないかと。

ただし、Go のプログラムが C 言語のコードやライブラリを使用している場合(Cgo)、
ビルドされたバイナリは共有ライブラリに依存する可能性があります。

対策

静的リンクになるよう、CGO_ENABLED の設定をします。

また、ついでに GOOS も強制させておきます。

# syntax=docker/dockerfile:1

# 1. build
FROM golang:1.21 AS build

WORKDIR /app

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

COPY *.go ./

- RUN go build -o /api
+ RUN CGO_ENABLED=0 GOOS=linux go build -o /api

# 2. deploy
FROM gcr.io/distroless/static
WORKDIR /
COPY --from=build /api /api

EXPOSE 8080
USER nonroot:nonroot

ENTRYPOINT ["/api"]