Files
SuBlog/content/posts/docker-musl-build/index.md
T

137 lines
3.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
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 的请求出现类似错误。
![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
# egdocker run -it -d -v .:/data --name logbus-build go-build:v1 /bin/bash
docker exec -it <容器名称> go build -o <myapp>
# egdocker 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
```