yoshikipom Tech Blog

GoReplayのDockerfileがAppleシリコン(M1) Macでうまく動かなかったので自分で書いた

経緯

GoReplayのリポジトリにあったDockerfileはIntel Macだとうまく動いたが、Appleシリコン(M1) Macではうまく動かなかった。 Dockerfile: https://github.com/buger/goreplay/blob/1.3.3/Dockerfile 実行時に以下のエラーが発生。

tunl0: SIOCETHTOOL(ETHTOOL_GLINK) ioctl failed: Function not implemented

--platform オプションでamd64用にビルドして実行してみたが、結果は同様だった。 たまにこういうことはありそう?

The emulation is not perfect https://github.com/docker/for-mac/issues/5328

結論

以下のDockerfileを書いた。これならIntel MacでもAppleシリコン(M1) Macでもうまく動く。

FROM golang:1.19 as builder

RUN apt-get update && apt-get install ruby vim-common -y

RUN apt-get install flex bison -y
RUN wget http://www.tcpdump.org/release/libpcap-1.10.0.tar.gz && tar xzf libpcap-1.10.0.tar.gz && cd libpcap-1.10.0 && ./configure && make install

WORKDIR /go/src/github.com/buger/goreplay/
RUN wget https://github.com/buger/goreplay/archive/refs/tags/v2.0.0-rc2.tar.gz -O gor.tar.gz && tar xzf gor.tar.gz -C . --strip=1
RUN go mod vendor
RUN go build -mod=vendor -tags netgo -o gor -ldflags "-extldflags \"-static\""


FROM alpine:3.17

RUN apk add bash
RUN apk add --no-cache ca-certificates openssl

COPY --from=builder /go/src/github.com/buger/goreplay/gor /
ENTRYPOINT ["./gor"]

build & run

# build
$ docker build --tag goreplay:2.0.0 .                 

# run
$ docker run --rm -it goreplay:2.0.0 -h
Gor is a simple http traffic replication tool written in Go. Its main goal is to replay traffic from production servers to staging and dev environments.

なぜ元のDockerfileだとダメか

以下で取得してきているGoReplayのプログラムがファイル名でもわかるようにx64のCPUアーキテクチャ用にビルドされたものなのが原因。

RUN wget https://github.com/buger/goreplay/releases/download/${RELEASE_VERSION}/gor_${RELEASE_VERSION}_x64.tar.gz -O gor.tar.gz

Dockerfile: https://github.com/buger/goreplay/blob/1.3.3/Dockerfile

--platform オプションをつけずにdocker buildコマンドを実行するとホストのCPUアーキテクチャ用のbuildする。 - Intel Mac -> amd64 (= x86 https://ja.wikipedia.org/wiki/X64) - Appleシリコン(M1) Mac -> arm64v8 dockerで使われるCPUアーキテクチャの種類: https://github.com/docker-library/official-images#architectures-other-than-amd64

AppleシリコンでBuildした場合、OSはarm64v8のCPUを想定するが、元のDockerfileだとx86用のgoプログラムを取得しているのでミスマッチが起こっている。

どう直したのか

go build コマンドもdocker buildと同様にdefaultは実行ホストのCPUアーキテクチャ用にbuildする。なので、Dockerfileにgo buildコマンドを入れた。 buildコマンドはMakefileから必要なオプションを持ってきた。 https://github.com/buger/goreplay/blob/1.3.3/Makefile ちなみにGOOS=linux GOARCH=amd64 go buildのようにすれば成果物のCPUアーキテクチャの指定もできるが、今回は指定しないほうが都合が良かったので特に指定していない。buildするCPUアーキテクチャとと実行するCPUアーキテクチャが違う時は指定が必要。

Makefileはbuild用のDockerコンテナ内でビルドする作りになっていたが、docker in dockerをしたくなかったのでマルチステージビルドを使って書いてみた。golangイメージでビルドして、alpineイメージで実行。goのプログラムは実行ファイルだけあれば実行できるのですごい。