使用Docker进行交叉编译

问题

开发了个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

逐行解析:

使用Dockerfile构建的镜像可以通过类似hub.docker.com来进行分发,这样可以将刚才我们编译好的gocentos:7.0镜像分发给同事使用。如果只是个人使用,可以直接在容器中安装软件,用已有的容易来编译,这样比较偷懒——虽然我还是建议通过Dockerfile构建镜像。如果要偷懒我们可以这样做

创建编译环境容器,利用容器进行编译

1. 新起个容器

$docker run -i -t \
    --name centos \
    -v /MYGOPATH/go:/go \
    amd64/centos:7 \
    /bin/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

编译完成后,你就可以将编译出来的二进制直接拷贝到服务器上进行部署。同样的如果你的服务器是Ubuntu/Gentoo等其他分发版,道理也是通用的。

@ 2020-10-10 11:54

Comments:

Sharing your thoughts: