go 版本的不一致,依賴庫不一致,導致編譯失敗;代碼生成工具不一致,導致生成代碼有問題;依賴工具缺失,導致測試不通過等等,開發環境和生產環境之間的差異會導致各種各樣奇怪的問題,而 docker 特別擅長解決這種一致性問題
總體方案
最簡單粗暴的一種方式就是每次都將代碼拷貝到一個新的容器內,執行編譯,編譯完成后直接將容器制作成鏡像,但這種方式每次編譯都需要重新拉取依賴,比較耗時
我們采用在這個基礎上稍作優化,啟動一個固定的容器用於編譯,編譯完成后將生成的結果拷貝出來,制作新的鏡像,能達到近乎本地編譯的效果
編譯環境鏡像
沒有直接使用 dockerhub 上的 golang 鏡像,是因為我們的項目除了 golang 可能還依賴一些別的工具,比如 makefile,python,protoc 等等,就需要自己制作鏡像了,這里我選 centos 作為基礎鏡像,主要是考慮到后面制作服務鏡像的時候也僅需要 centos 即可,不需要完整的 golang 環境
FROM centos:centos7
RUN yum install -y kde-l10n-Chinese && yum reinstall -y glibc-common && localedef -c -f UTF-8 -i zh_CN zh_CN.utf8
RUN yum install -y epel-release
RUN yum install -y docker-io
RUN yum install -y go
RUN yum install -y make
# behave support
RUN yum install -y python36 python36-setuptools python36-pip
RUN pip3 install --upgrade pip
RUN pip3 install requests
RUN pip3 install flask
RUN pip3 install redis
RUN pip3 install pymongo
RUN pip3 install behave
RUN pip3 install pyhamcrest
RUN pip3 install pymysql
RUN pip3 install cryptography
RUN pip3 install grpcio grpcio-tools
# grpc support
RUN yum install -y unzip
RUN curl -OL https://github.com/protocolbuffers/protobuf/releases/download/v3.10.0/protoc-3.10.0-linux-x86_64.zip
RUN unzip protoc-3.10.0-linux-x86_64.zip
RUN export GOPROXY=https://goproxy.cn && \
mkdir -p /src/google.golang.org/grpc && \
cd /src/google.golang.org/grpc && \
export GOPATH=/ && \
export GO111MODULE=on && \
go mod init && \
go get -u google.golang.org/grpc && \
go get -u github.com/golang/protobuf/protoc-gen-go
ENV LANG=zh_CN.UTF-8
ENV LANGUAGE=zh_CN:zh
ENV LC_ALL=zh_CN.UTF-8
編譯環境鏡像可以盡可能多地安裝需要的工具,不用擔心鏡像過大,因為這個鏡像我們僅僅用來編譯
這里我安裝了 make,python,behave 以及 protobuf 工具
啟動編譯環境容器
.PHONY: buildenv
buildenv:
if [ -z "$(shell docker network ls --filter name=testnet -q)" ]; then \
docker network create -d bridge testnet; \
fi
if [ -z "$(shell docker ps -a --filter name=go-build-env -q)" ]; then \
docker run --name go-build-env --network testnet -d hatlonely/go-env:v1.1.0 tail -f /dev/null; \
fi
hatlonely/go-env:v1.1.0
為上一步制作的鏡像,啟動命令 tail -f /dev/null
是為了讓容器一直存在而不退出,這樣就可以一直復用這個容器執行編譯
編譯
.PHONY: image
image: buildenv
docker exec go-build-env rm -rf /data/src/${gituser}/${repository}
docker exec go-build-env mkdir -p /data/src/${gituser}/${repository}
docker cp . go-build-env:/data/src/${gituser}/${repository}
docker exec go-build-env bash -c "cd /data/src/${gituser}/${repository} && make output"
mkdir -p docker/
docker cp go-build-env:/data/src/${gituser}/${repository}/output/${repository} docker/
docker build --tag=hatlonely/${repository}:${version} .
使用 docker cp
命令將本地代碼拷貝到容器里面,執行 docker exec
在 docker 內部執行編譯,編譯完成后,再用 docker cp
將編譯結果拷貝到本機的 docker/
目錄
最后再用 Dockerfile 創建出一個新的服務鏡像,對應的 Dockerfile 內容如下
服務鏡像
FROM centos:centos7
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
RUN echo "Asia/Shanghai" >> /etc/timezone
COPY docker/tpl-go-http /var/docker/tpl-go-http
RUN mkdir -p /var/docker/tpl-go-http/log
EXPOSE 7060
WORKDIR /var/docker/tpl-go-http
CMD [ "bin/echo", "-c", "configs/echo.json" ]
鏈接
- Tips & Tricks for Making Your Golang Container Builds 10x Faster: https://medium.com/windmill-engineering/tips-tricks-for-making-your-golang-container-builds-10x-faster-4cc618a43827
- docker golang 鏡像: https://hub.docker.com/_/golang
- 示例項目: https://github.com/hpifu/tpl-go-http
轉載請注明出處
本文鏈接:https://tech.hatlonely.com/article/54