本着折腾,基于源码编译 Golang!
1. Go 源码编译安装的介绍 Golang 的通常安装方式是基于官网下载一个指定操作系统(Linux/Mac/Windows)版本的编译安装好的包,亦或者是基于SourceCode
源码安装(Git 或者下载指定版本的源码包);
针对 Golang 的源码编译安装,又有两种方式:
基于gc Go Compiler
编译器,即 Go 语言进行自举编译安装(gcc 支持的 go 最后一个版本是 1.4),细节参见:https://golang.org/doc/install/source 基于gccgo
(使用 GCC 后端的更传统的编译器), 细节参见:https://golang.org/doc/install/gccgo 以下主要基于Go编译器
安装 Go 语言环境,同时当指定好GOOS
和GOARCH
后,这块也可以支持跨平台交叉编译。
2. Go 编译器和工具安装说明 Go 工具链是用 Go 编写的,要构建它,需要安装 Go 编译器;由于我们没有 GO 编译器,同时 1.4 以后的 GO 语言版本没有直接支持 GCC,支持GO 编译器 和GCCGO ,因此我们需要先现在 1.4 版本的 GO,利用 GCC 编译好 GO 编译器后,再利用 1.4 版本的 GO 编译器编译最新版本的 GO(比如以下的 1.13);
注意,进行工具初始构建的脚本在$GOROOT_BOOTSTRAP
中查找现有的 Go 工具链,如果未设置,则GOROOT_BOOTSTRAP
的默认值为$HOME/go1.4
;
3. 源码编译安装 下载 go1.4 版本,源码从官方下载 下载 go1.13 版本 进入到 docker alpine 容器内(其他的 Linux 环境流程类似) 先编译 go1.4 版本 利用 go1.4 的 go 编译器,编译 go1.13 在第 5 不可以支持交叉编译:usage: GOOS=os GOARCH=arch ./bootstrap.bash
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
Copy // Go 1.4编译的依赖环境安装
apk update && apk add bash gcc musl-development
// 解压go1.4,源码从官方下载
tar -zxf go1.4-bootstrap-20171003.tar.gz
mv go /usr/local/go1.4
// 解压go1.13版本
tar -zxf go1.13.3.src.tar.gz
mv go /usr/local/go
// 环境变量设置( GOROOT_BOOTSTRAP是编译器环境设定需要)
echo 'export GOROOT_BOOTSTRAP=/usr/local/go1.4' >> ~/.bash_profile
echo 'export GOROOT=/usr/local/go' >> ~/.bash_profile
echo 'export GOPATH=/data/go' >> /data/go
echo 'export GOPATH=/data/go' >> ~/.bash_profile
echo 'export PATH=${GOROOT}/bin:${PATH}' >> ~/.bash_profile
// 重载环境配置变量(主要是重载GOROOT_BOOTSTRAP)
source ~/.bash_profile
// 编译go1.4的版本
cd /usr/local/go1.4/src && ./make.bash
// 编译go1.13版本
cd /usr/local/go1.13/src && ./make.bash
// 版本检测
go version
// 编译不同操作系统的Go,相关GOOS和GOARCH的支持,查看:https://golang.org/doc/install/source
cd /usr/local/go1.13/src
GOOS = linux GOARCH = amd64 ./bootstrap.bash
4. 流程转换成 Dockerfile 具体可以参见:
Tips: 注意,这块我把 go 源码 Clone 到了本地目录,这块也可以直接在 Dockerfile 的 Run 中修改,这样就不用 Copy 的相关部分了!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
Copy # Build Golang
FROM alpine:latest as builder
# ARG Setting
ARG VERSION = 1.13
ARG GOOS = ""
ARG GOARCH = ""
# ENV Setting
LABEL Description = "Build Go on alpine" Version = "Go version $VERSION "
# Go source
COPY ./go-source /usr/local/go
# Building
RUN set -eux; \
# Go 1.4编译的依赖环境安装
apk add --no-cache --virtual .build-deps \
bash gcc musl-development git; \
# 编译go1.4的版本
export GOROOT_BOOTSTRAP = /usr/local/go1.4 \
INSTALL = /usr/local \
GOROOT = /usr/local/go \
; \
cd $INSTALL \
#&& git clone https://github.com/golang/go.git
&& cp -a go go1.4 && cd go1.4/src \
&& git checkout release-branch.go1.4 \
&& ./make.bash \
; \
# 编译指定版本go
cd $GOROOT /src \
&& git checkout release-branch.go$VERSION \
&& if [[ " $GOOS " != "" && " $GOARCH " != "" ]] ; then \
GOOS = $GOOS GOARCH = $GOARCH ./bootstrap.bash; else ./make.bash; fi \
# 移除相关依赖
&& apk del .build-deps \
&& rm -rf $GOROOT_BOOTSTRAP \
&& rm -rf $GOROOT /.git \
&& $GOROOT /bin/go version
# Build a clean Go image
FROM alpine:latest
# 复制构建完成的最新版本Go到当前镜像
COPY --from= builder /usr/local/go /usr/local/go
# Go 编译环境初始化
ENV GOPROXY = https://goproxy.io \
GOROOT = /usr/local/go \
GOPATH = /go
ENV PATH = $GOPATH /bin:$GOROOT /bin:$PATH
# 其他初始化相关
RUN echo "alias ll='ls -al'" >> ~/.profile \
&& echo "export PATH= $GOPATH /bin: $GOROOT /bin: $PATH " >> ~/.profile
# 指定Volume和Workdir
VOLUME [ "/data/go" ]
WORKDIR "/data/go"
5. 官方 alpine 版本 Dockerfile 文件 查看docker-library/golang
下的 alpine 版本的Dockerfile
文件,可以发现其实通过 apk 安装完 go 后,再下载安装指定的 Go 版本。
这一步操作等同于利用 gcc 编译好 go1.4,在利用 go 编译最新版本的 go,这块可以按自己的需要自行引入!
详细参见:https://github.com/docker-library/golang/blob/a4deea14ce3306822bb9352ccf124af8c0eea257/1.13/alpine3.10/Dockerfile
1
2
3
4
5
6
7
8
9
10
Copy // 如果采用直接安装go,则无需下载go1.4版本的go,并编译安装,可以直接利用apk安装apk库中的go
RUN set -eux; \
apk add --no-cache --virtual .build-deps \
bash \
gcc \
musl-development \
openssl \
go \
; \
...
6. 自建 Dockerfile 的坑点 6.1. 调试相关 1
2
3
4
5
6
Copy // 调试相关,可以显示更多的信息
-u :默认不激活。若激活后,当使用未配置变量时,会显示错误信息;
-v :默认不激活。若激活后,在信息被输出前,会先显示信息的原始内容(未做变量解析);
-x :默认不激活。若激活后,在命令被运行前,会显示命令内容( 做了变量解析,前面有 ++ 符号)
RUN set -eux
6.2. 降低镜像大小 COPY、RUN 会创建镜像层,拷贝之前的层内容会叠加,导致镜像很大(解决方案,采用多阶段构建;排查镜像过大,可以通过docker history 镜像ID
分析哪些层导致镜像增大) apk 安装依赖,构建完成移除依赖,如果基于多阶段构建,可以不用考虑这块! 1
2
3
4
5
6
7
8
9
10
11
Copy // 加入依赖内容
RUN set -eux; \
# Go 1.4编译的依赖环境安装
apk add --no-cache --virtual .build-deps \
bash gcc musl-development git; \
...
// 移除依赖内容
&& apk del .build-deps \
&& rm -rf $GOROOT_BOOTSTRAP \
&& rm -rf $GOROOT /.git \
...
6.3. ENV 的问题 ENV 在构建阶段中所有后续指令的环境中使用,并且在许多情况下也可以内联替换。 环境变量在同一行,无法立即生效,正常情况下,执行export a=1 b=2 c=$a
,c=2,但在 Dockerfile 中以下有差别! 1
2
3
4
5
6
7
8
9
10
11
Copy // PATH, it not works:
ENV GOPROXY = https://goproxy.io \
GOROOT = /usr/local/go \
GOPATH = /go \
PATH = $GOPATH /bin:$GOROOT /bin:$PATH
// PATH, it works:
ENV GOPROXY = https://goproxy.io \
GOROOT = /usr/local/go \
GOPATH = /go
ENV PATH = $GOPATH /bin:$GOROOT /bin:$PATH
6.4. bash shell 提示问题 以下命令,让.profile
生效的话,需要基于登陆 shell ,即docker run --rm -it go-builder sh -l
1
2
3
Copy // Dockerfile中的alias命令添加
RUN echo "alias ll='ls -al'" >> ~/.profile \
echo "export PATH= $GOPATH /bin: $GOROOT /bin: $PATH " >> ~/.profile
7. 最后 如果不想自己 Build,最容易的方式,直接拖go-alpine
镜像,大小其实和自行编译的差不多,而且还省事省力!
1
2
3
4
Copy $ docker images|grep golang
golang 1.13-alpine f23ef2e47d30 8 days ago 359MB
//docker images|grep builder,对比以下....
go-builder latest 85783217bc33 42 minutes ago 358MB
最后,清理下相关现场:
1
2
Copy docker image prune
docker container prune