137 lines
3.4 KiB
Markdown
137 lines
3.4 KiB
Markdown
---
|
||
title: Docker 编译 musl 可执行文件
|
||
published: 2025-03-27
|
||
updated: 2025-03-27
|
||
image: /posts/docker-musl-build/img/cover.svg
|
||
description: 解决 Go 语言跨平台编译问题,使用 Docker + musl 编译静态链接的可执行文件。
|
||
tags: ['Docker', 'Go', '运维']
|
||
draft: false
|
||
series: Docker 实践笔记
|
||
seriesOrder: 1
|
||
difficulty: 进阶
|
||
---
|
||
|
||
## 解决问题
|
||
|
||
用 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 的请求出现类似错误。
|
||
|
||

|
||
|
||
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 <myapp>
|
||
# 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
|
||
```
|