原创

基于gin的golang web开发:docker

Golang天生适合运行在docker容器中,这得益于:Golang的静态编译,当在编译的时候关闭cgo的时候,可以完全不依赖系统环境。

一些基础

测试容器时我们经常需要进入容器查看运行情况,以下命令启动一个centos容器并进入bash交互环境。

docker run -it --rm centos bash

-it 组合参数-i: 以交互模式运行容器,-t: 为容器重新分配一个伪输入终端。

--rm 在容器退出时就能够自动清理容器。

alpine镜像中没有bash,启动容器并进入终端的命令为

docker run -it --rm alpine sh

启动一个golang编译环境并进入bash

docker run -it -p 8081:8081 -v ./project:/app --env --env GO111MODULE=on --env GOPROXY=https://goproxy.cn,direct --rm  --privileged golang:1.15 bash

-v ./project:/app 绑定本机项目的路径映射到容器中/app

--env 设置环境变量,由于我们网络环境的问题直接使用golang容器会很慢所以设置了GOPROXY=https://goproxy.cn,direct。

--privileged 容器内的root拥有真正的root权限,否则容器内root只是外部的一个普通用户。

-p 8081:8001 将本机的8081端口映射到容器的8001端口

docker打包项目

为了方便演示docker,我们准备一个简单Gin项目。要注意r.Run不能绑定127.0.0.1。

func main() {
    r := gin.Default()

    r.GET("/ping", func(c *gin.Context) {
        c.JSON(200, gin.H{
            "message": "pong",
        })
    })

    r.Run("0.0.0.0:9999")
}

启动golang容器,在容器中尝试编译并运行程序。

docker run -it -p 9999:9999 -v ./project:/app --env --env GO111MODULE=on --env GOPROXY=https://goproxy.cn,direct --rm  --privileged golang:1.15 bash

Alpine和其他通用Linux发行版对于Golang编译出来的可执行文件要求有所不同,Alpine要求可执行文件必须是静态链接的可执行文件。所以在编译Golang时需要添加 -tags netgo ,来生成静态链接的可执行文件。

go build -tags netgo -o app .

把编译出来的二进制文件和所有依赖项拷贝到发布目录

mkdir publish && cp app publish && \
    cp -r docs publish

golang镜像的1.15版本有839M,再加上下载依赖编译项目等各种文件的话最终镜像可能会超过1G,大部分文件是在运行时不需要的。我们编写Dockerfile的时候可以把编译和运行两个阶段分开。编译时使用golang镜像,运行时使用alpine镜像。alpine镜像初始大小只有5M左右,非常适合作为基础镜像。最终Dockerfile如下

FROM golang:1.15 as builder

ENV GO111MODULE=on \
    GOPROXY=https://goproxy.cn,direct

WORKDIR /app
COPY . .
RUN GOOS=linux GOARCH=amd64 go build -tags netgo -o app .

RUN mkdir publish && cp app publish && \
    cp -r docs publish


FROM alpine
WORKDIR /app
COPY --from=builder /app/publish .
ENV GIN_MODE=release \
    PORT=8081

EXPOSE 8081
ENTRYPOINT ["./app"]

构建docker镜像,大功告成。

docker build -t test:0.1 .
正文到此结束