--- title: Docker 编译 musl 可执行文件 published: 2025-03-27 image: /posts/docker-musl-build/img/cover.svg description: 解决 Go 语言跨平台编译问题,使用 Docker + musl 编译静态链接的可执行文件。 tags: ['Docker', 'Golang', '运维'] draft: false --- ## 解决问题 用 Go 进行跨平台编译时往往步骤复杂,用 Docker 可以轻松解决。但 Docker 的当前最小镜像 Alpine 其动态链接库采用 musl,与主流的 glibc 不同,往往不能方便执行。 ## 查阅资料 ```bash # 启动容器并挂载当前目录到 `/app` docker run -it --rm -v "$PWD":/app -w /app ubuntu:20.04 bash # 在容器内执行以下操作: apt-get update && apt-get install -y musl-tools golang-go # 安装 musl 和 Go export CC=musl-gcc # 指定 musl 编译器 export CGO_ENABLED=1 # 启用 CGO # 设置代理 go env -w GOPROXY=https://goproxy.cn,direct go build -ldflags '-linkmode external -extldflags "-static"' -o myapp # 静态编译 exit # 退出容器 # 验证结果(在宿主机执行) file myapp # 应显示 "statically linked" ldd myapp # 应显示 "not a dynamic executable" wget https://go.dev/dl/go1.21.linux-amd64.tar.gz ENV PATH="/data/go/bin:$PATH" ``` ### 遇到问题 1. `go mod tidy` 时报错 `tls: failed to verify certificate: x509: certificate` 解决:`RUN apt-get update && apt-get install -y ca-certificates && rm -rf /var/lib/apt/lists/*` 基础镜像的证书未更新,导致 https 的请求出现类似错误。 ![image-20250327100813512](/posts/docker-musl-build/img/image-20250327100813512.png) 2. 直接安装 `golang-go` 其版本过低 解决: `PATH="/data/go/bin:$PATH"` 手动指定环境 ## 最终方案 1. 下载 `go1.24.1.linux-amd64.tar.gz` 解压 2. 编写 Dockerfile 3. 执行 `docker build -t go-build:v1 .` Dockerfile 内容: ```dockerfile FROM ubuntu:20.04 LABEL org.opencontainers.image.authors="sutong" COPY go/ /go/ ENV PATH="/go/bin:$PATH" RUN apt-get update && apt-get install -y musl-tools ## go mod tidy 时报错 tls: failed to verify certificate: x509: certificate RUN apt-get update && apt-get install -y ca-certificates && rm -rf /var/lib/apt/lists/* # 指定 musl 编译器 ENV CC=musl-gcc # 启用 CGO ENV CGO_ENABLED=1 VOLUME /data WORKDIR /data CMD ["/bin/bash"] ``` ### 构建 ```bash # docker build -t go-build:v1 . # 直接执行编译 编译后删除 docker run --rm -v .:/data go-build:v1 go build -o app_musl # 构建编译环境 docker run -it -d -v .:/data --name <容器名称> go-build:v1 /bin/bash # eg:docker run -it -d -v .:/data --name logbus-build go-build:v1 /bin/bash docker exec -it <容器名称> go build -o # eg:docker exec -it logbus-build go build -o logbus_musl_1 ``` ### 额外注意 若没科学上网需要设置代理: ```bash docker exec -it <容器名称> /bin/bash go env -w GOPROXY=https://goproxy.cn,direct go build -ldflags '-linkmode external -extldflags "-static"' -o myapp # 静态编译 go build # musl 库编译 ``` ### 运行环境示例 ```dockerfile FROM alpine:latest LABEL org.opencontainers.image.authors="sutong" COPY glog_musl /app/ COPY conf.ini /data/ COPY ipname.ini /data/ WORKDIR /app RUN chmod 777 /app/glog_musl CMD ["./glog_musl", "logsweb", "/data/conf.ini"] # docker build -t glog:v1 . # docker run -p 6801:6801 glog:v1 ```