Go在docker环境下部署

给大家分享一个Go如何在docker环境下部署Go应用程序,例如:已经写好一个简单的Go应用程序,下面是目录结构。

Go 复制代码
.
├── go.mod
└── main.go

main.go 中的代码如下:

Go 复制代码
package main

// 导入gin包
import "github.com/gin-gonic/gin"

// 入口函数
func main() {
    // 初始化一个http服务对象
    r := gin.Default()

    // 设置一个get请求的路由,url为/ping, 处理函数(或者叫控制器函数)是一个闭包函数。
    r.GET("/ping", func(c *gin.Context) {
        // 通过请求上下文对象Context, 直接往客户端返回一个json
        c.JSON(200, gin.H{
            "message": "pong",
        })
    })

    r.Run() // 监听并在 0.0.0.0:8080 上启动服务
}

Go 代码构建出 docker 镜像,其中分为三步:

  • 本机编译 Go 代码,如果牵涉到 cgo 跨平台编译就会比较麻烦了。
  • 用编译出的可执行文件构建 docker 镜像。
  • 编写 shell 脚本或者 makefile 让这几步通过一个命令可以获得

多阶段构建就是把这一切都放到一个 Dockerfile 里,既没有源码泄漏,又不需要用脚本去跨平台编译,还获得了最小的镜像。

什么是多阶段构建?

在Docker Engine 17.05 中引入了多阶段构建,以此降低构建复杂度,同时使缩小镜像尺寸更为简单。

在一个Dockerfile中使用多个FROM指令,每个FROM都可以使用不同的基镜像,并且每条指令都将开始新阶段构建。在多阶段构建中,我们可以将资源从一个阶段复制到另一个阶段,在最终镜像中只保留我们所需要的内容。

默认情况下构建阶段没有名称,我们可以通过整数0~N来引用,即第一个from0开始。其实我们还可以在FROM指令中添加AS <NAME> 来命名构建阶段,接着在COPY指令中通过<NAME>引用。

  • 只构建某个阶段

构建镜像时,您不一定需要构建整个 Dockerfile,我们可以通过--target参数指定某个目标阶段构建,比如我们开发阶段我们只构建builder阶段进行测试。

arduino 复制代码
#docker build --target builder -t builder_app:v2 .
  • 使用外部镜像 使用多阶段构建时,我们局限于从之前在 Dockerfile 中创建的阶段进行复制。还可以使用COPY --from指令从单独的镜像复制,如本地镜像名称、本地或 Dockerhub上可用的标签或标签 IDDocker 客户端在必要时会拉取需要的镜像到本地。
bash 复制代码
COPY --from  httpd:latest /usr/local/apache2/conf/httpd.conf ./httpd.conf
  • 从上一阶段创建新的阶段 我们可以通过FROM指令来引用上一阶段作为新阶段的开始。

DockerCOPYADD的区别是:

COPY指令不支持从远程URL获取资源,只能从执行docker build所在的主机上读取资源并复制到镜像中;而ADD指令支持从远程URL获取资源,可以通过URL从远程服务器读取资源并复制到镜像中。

ldflags在golang编译中的2个作用

  1. ldflags用于链接过程。 主要是控制打包过程。
  2. ldflags在编译golang的时候,可以传入一些值用来配置golang的应用。

本章主要是讲解Go的打包,更深入的可以参考: ldflags在golang编译中的2个作用

docker访问外部https数字证书问题

一般构建 docker 镜像使用的都是 alpine linux 系统,默认是不带 ca-certificates 根证书的,导致无法识别外部 https 携带的数字证书。

在访问的时候,会抛出509:certificate signed by unknown authority错误,导致 docker 容器的接口服务返回报错。

为了解决证书验证的问题,我们需要在构建 docker 镜像的时候将 ca-certificates 根证书装上。 在 Dockerfile 中加入如下内容:

Dockerfile 复制代码
RUN apk --no-cache add ca-certificates && update-ca-certificates

了解了上面关于Docker的基本知识后,看如下的 Dockerfile 文件用于构建镜像,里面已经包含了详细的注释。

Dockerfile 复制代码
# 阶段1命名为builder
FROM golang:alpine AS builder 

## Labels允许你为Docker对象指定metadata。 可以通过 docker image inspect main:v
LABEL stage=gobuilder

ENV CGO_ENABLED 0
ENV GOPROXY https://goproxy.cn,direct

# RUN apk --no-cache add tzdata 
# 因为alpine 基础镜像中没有包含时区信息文件,当代码中有调用类似下面这样的通过名称获取时区信息的时候

RUN apk update --no-cache && apk add --no-cache tzdata

# 使用 WORKDIR 指令可以来指定工作目录(或者称为当前目录),以后各层的当前目录就被改为指定的目录,如该目录不存在,WORKDIR 会帮你建立目录。

WORKDIR /build

ADD go.mod .
ADD go.sum .
RUN go mod download

# 把当前宿主机中的文件复制进来
COPY . .
RUN go build -ldflags="-s -w" -o /app/main ./main.go


FROM alpine

# 解决证书 和 时区问题,这里时区文件直接复制过来的
RUN apk update --no-cache && apk add --no-cache ca-certificates
COPY --from=builder /usr/share/zoneinfo/Asia/Shanghai /usr/share/zoneinfo/Asia/Shanghai
ENV TZ Asia/Shanghai

# 从builder阶段的镜像中复制过来
WORKDIR /app
COPY --from=builder /app/main /app/main

# run起来后启动服务
CMD ["./main"]

文件内容简要说明:

  1. 第一个 FROM 开始的部分是构建一个 builder 镜像,目的是在其中编译出可执行文件 main,第二个 From 开始的部分是从第一个镜像里 copy 出来可执行文件 main,并且用尽可能小的基础镜像 alpine 以保障最终镜像尽可能小,alpine 大概是5MB,对我们的服务不会构成多少影响。
  2. 默认禁用了 cgo
  3. 启用了 GOPROXY 加速 go mod download
  4. 去掉了调试信息 -ldflags="-s -w" 以减小镜像尺寸
  5. 安装了 ca-certificates,这样使用 TLS 证书就没问题了
  6. tzdatabuilder 镜像安装,并在最终镜像只拷贝了需要的时区
  7. 自动设置了本地时区,这样我们在日志里看到的是北京时间了

执行docker images 查看镜像编译结果。

shell 复制代码
> docker images
REPOSITORY       TAG       IMAGE ID       CREATED         SIZE
main             v1        746f285b01f7   24 hours ago    14.9MB

下面我们启动一个容器实验一下

Dockerfile 复制代码
docker run -it --rm -p 8080:8080 --name main_v1 -d main:v1

docker run 加上--rm退出容器以后,这个容器就被删除了,方便在临时测试使用。 不加--rm 退出容器后,容器只是停止运行,数据任然被保留。

--name main_v1 对容器的命名

最后本地执行: curl http://localhost:8080/ping

看到正确的响应,表示服务部署成功。

相关推荐
梦想很大很大4 小时前
使用 Go + Gin + Fx 构建工程化后端服务模板(gin-app 实践)
前端·后端·go
lekami_兰9 小时前
MySQL 长事务:藏在业务里的性能 “隐形杀手”
数据库·mysql·go·长事务
却尘12 小时前
一篇小白也能看懂的 Go 字符串拼接 & Builder & cap 全家桶
后端·go
ん贤13 小时前
一次批量删除引发的死锁,最终我选择不加锁
数据库·安全·go·死锁
mtngt111 天前
AI DDD重构实践
go
Grassto3 天前
12 go.sum 是如何保证依赖安全的?校验机制源码解析
安全·golang·go·哈希算法·go module
Grassto4 天前
11 Go Module 缓存机制详解
开发语言·缓存·golang·go·go module
程序设计实验室5 天前
2025年的最后一天,分享我使用go语言开发的电子书转换工具网站
go
我的golang之路果然有问题5 天前
使用 Hugo + GitHub Pages + PaperMod 主题 + Obsidian 搭建开发博客
golang·go·github·博客·个人开发·个人博客·hugo
啊汉7 天前
古文观芷App搜索方案深度解析:打造极致性能的古文搜索引擎
go·软件随想