前言
有一位朋友看了 Docker私有仓库搭建&Go服务部署之后就在自己的项目中开发环境用上了, 然后现在项目要部署到测试及生产环境, 因为他们之前的项目没用docker且go的版本为1.12, 当前项目的环境为go 1.14, 老大要求每个项目的环境必须隔离, 打包也必须要镜像内打包(避免人工打包失误), 这位朋友在容器内打包的时候遇到了挺麻烦的问题求助了一下我, 所以就有了这篇文章
上次讲的是开发环境自己在本地打包然后把二进制放在镜像里运行, 方便快捷, 这次线上环境要在容器内用go打包二进制运行文件的话就需要对应的环境和依赖安装了, 包管理的话还是建议go mod, 个人感觉方便好用
在 alpine 上打包运行go服务
之前的Dockerfile是这样
# 设置基础镜像 FROM golang:1.14.4-alpine # 作者描述信息 LABEL maintainer="飞啊飞" # 使用国内源 RUN echo -e http://mirrors.aliyun.com/alpine/v3.7/main/ > /etc/apk/repositories # copy当前目录的文件到镜像里面的工作目录目录下 COPY ./config/test.json /demo/ // 配置文件 COPY server /demo/ // 打包的linux二进制文件 #设置东八区,北京时间 ENV TZ=Asia/Shanghai RUN apk add --no-cache tzdata && ln -sf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone # 指定路径 WORKDIR /demo/ # 执行命令 这里给文件增加执行权限 RUN ["chmod", "+x", "/demo/server"] # 容器入口, 执行命令 CMD ["./server", "-config", "test.json"]
因为服务器版本的问题, 所以需要在docker内打包部署, 奉上一份正确的Dockerfile, 然后下面说遇到的问题
# 设置基础镜像 FROM golang:1.14.4-alpine # 作者描述信息 LABEL maintainer="飞啊飞" # copy整个项目 COPY ./config/test.json /demo/ // 配置文件 COPY . /demo/ // 项目文件 # 使用阿里源&&设置东八区,北京时间 ENV TZ=Asia/Shanghai RUN echo -e http://mirrors.aliyun.com/alpine/v3.10/main/ > /etc/apk/repositories \ && apk update \ && apk add --no-cache tzdata gcc g++ libffi-dev musl-dev openssl-dev make linux-headers libc-dev libc6-compat binutils \ && ln -sf /usr/share/zoneinfo/$TZ /etc/localtime \ && echo $TZ > /etc/timezone # 指定路径 WORKDIR /demo/ # 打包二进制&&增加执行权限 RUN export GOPROXY=https://mirrors.aliyun.com/goproxy/ \ && go mod tidy \ && export GOARCH=amd64 \ && export GOOS=linux \ && go build -o server ./main.go \ && chmod +x server # 容器入口, 执行命令 CMD ["./server", "-config", "test.json"]
说一下主要的两个坑
一 报错如下, 需要安装GCC
exec: "gcc": executable file not found in $PATH # github.com/karalabe/usb exec: "gcc": executable file not found in $PATH # github.com/ethereum/go-ethereum/rpc exec: "gcc": executable file not found in $PATH
二 GCC运行失败
# command-line-arguments /usr/local/go/pkg/tool/linux_amd64/link: running gcc failed: exit status 1 /usr/lib/gcc/x86_64-alpine-linux-musl/6.4.0/../../../../x86_64-alpine-linux-musl/bin/ld: /tmp/go-link-364684937/000000.o: unable to initialize decompress status for section .debug_info /usr/lib/gcc/x86_64-alpine-linux-musl/6.4.0/../../../../x86_64-alpine-linux-musl/bin/ld: /tmp/go-link-364684937/000000.o: unable to initialize decompress status for section .debug_info /usr/lib/gcc/x86_64-alpine-linux-musl/6.4.0/../../../../x86_64-alpine-linux-musl/bin/ld: /tmp/go-link-364684937/000000.o: unable to initialize decompress status for section .debug_info /usr/lib/gcc/x86_64-alpine-linux-musl/6.4.0/../../../../x86_64-alpine-linux-musl/bin/ld: /tmp/go-link-364684937/000000.o: unable to initialize decompress status for section .debug_info /tmp/go-link-364684937/000000.o: file not recognized: File format not recognized collect2: error: ld returned 1 exit status
参考一:
cgo在alpine 上运行需要依赖musl_dev 这个包, 在Dockerfile中加入后还是不行
参考二:
https://github.com/zmap/zlint/issues/316
问题定位到了, 需要binutils 包的版本大于2.32并且 alpine 的版本大于等于 3.10, 我之前仓库用的是alpine 3.7版本的, 下载的binutils 包版本太低, 所以把阿里源的仓库版本改为3.10就好了, 问题解决
总结
找这种问题还是挺费劲的, 所以在此记录一下, 与人方便与己方便