问题
开发了个Golang的项目,需要部署到一台Linux服务器上。我的开发环境是MacOS+VS Code。Go本身支持交叉编译,但是由于用到了github.com/mattn/go-sqlite3
这个类库,这个类库需要CGO的支持。这样我在MacOS上就没有办法进行编译,并且直接xcopy到服务器端运行了。
解决
作为开发人员,我们其实比较头疼的就是开发环境和部署环境不一致,这会时不时的来个依赖的问题。最初我把上面的Golang程序放到Ubuntu上编译,结果xcopy到服务器上GLIBC的版本不一致,报错:
/lib64/libc.so.6: version 'GLIBC_2.14' not found
之后我ldd --version
看了一下原来我用来编译的服务器端GLIBC的版本和需要部署的服务器上的GLIBC版本也不一致。怎么样能让编译的环境跟服务器端的环境一致呢,以减少这些依赖问题呢?这时候想到了Docker。
构建编译环境镜像,利用镜像进行编译
1. 创建Dockerfile
FROM amd64/centos:7
RUN yum update
RUN yum install -y git wget make gcc
RUN wget https://dl.google.com/go/go1.15.2.linux-amd64.tar.gz
RUN tar -xzf go1.15.2.linux-amd64.tar.gz
RUN mv go /usr/local/
RUN rm -f go1.15.2.linux-amd64.tar.gz
ENV GOROOT=/usr/local/go
ENV PATH="$GOROOT/bin:${PATH}"
这个Dockerfile指定了从CentOS7开始的镜像amd64/centos:7
,然后安装一些依赖项。比如git, wget, make, gcc
等,然后我们再安装golang
之后,我们设置一下环境变量。
2. 构建镜像
我们使用下面的命令来从上面的Dockerfile来创建一个自定义的镜像
docker build -t gocentos:7.0 .
其中gocentos
是Repository的名字,7.0
是Tag。构建完成后我们使用docker images
来查看已经构建好的镜像,如果镜像构建成功,可以看到下面的结果:
$docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
gocentos 7.0 736fb8fda64a 13 minutes ago 1.33GB
3. 使用构建好的镜像来编译
我们可以直接使用下面的方式来交叉编译,即在Docker容器中编译我们的Golang应用。假设我们的开发环境的GOPATH为/MYGOPATH/go
,我们的源代码放在/MYGOPATH/go/src/app
下。
docker run \
--rm \
-v /MYGOPATH/go:/go \
-e GOPATH=/go \
-w /go/src/app \
gocentos:7.0 \
go build
逐行解析:
--rm
容器退出后自动删除,适用于我们这边编译工作,相当于一次性容器-v /MYGOPATH/go:/go
将/MYGOPATH/go映射到容器中的/go位置,这样在容器中可以使用/go来访问开发环境上的/MYGOPATH/go目录-e GOPATH=/go
指定容器中的GOPATH位置-w /go/src/app
指定容器中的工作目录gocentos:7.0
我们上面构建好的容器go build
在容器中执行编译命令进行编译
使用Dockerfile构建的镜像可以通过类似hub.docker.com
来进行分发,这样可以将刚才我们编译好的gocentos:7.0
镜像分发给同事使用。如果只是个人使用,可以直接在容器中安装软件,用已有的容易来编译,这样比较偷懒——虽然我还是建议通过Dockerfile构建镜像。如果要偷懒我们可以这样做
创建编译环境容器,利用容器进行编译
1. 新起个容器
$docker run -i -t \
--name centos \
-v /MYGOPATH/go:/go \
amd64/centos:7 \
/bin/bash
docker run -i -t
创建交互环境容器,分配TTY--name centos
容器的名字为centos-v /MYGOPATH/go:/go
将/MYGOPATH/go映射到容器中的/go位置amd64/centos:7
CentOS7镜像/bin/bash
进入bash进行操作
当容器起来了,你进入了容器的bash,你安装软件,安装依赖跟Dockerfile中步骤一样。之后你Ctrl+P, Ctrl+Q
从容器中detach出来。
2. 在容器中进行编译
容器准备好了,我们开始在容器中编译,执行下面命令:
$docker start centos
$docker exec -it \
-e GOROOT=/usr/local/go \
-e GOPATH=/go \
-e PATH=/usr/local/go/bin:/usr/bin:/usr/local/bin \
-w /go/src/app \
centos \
go buld
docker start centos
确保容器已经运行docker exec -it
以交互方式再容器中执行命令-e
指定容器中的环境变量,主要是GOROOT/GOPATH/PATH-w
指定接下来命令的工作目录centos
在centos这个容器中执行命令go build
在容器中执行的编译命令
编译完成后,你就可以将编译出来的二进制直接拷贝到服务器上进行部署。同样的如果你的服务器是Ubuntu/Gentoo等其他分发版,道理也是通用的。
Comments: