关于我 壹文 项目 三五好友
使用 Docker 打包 Go 程序(学习笔记) 2024-04-23

docker 部署 go 项目

使用 docker 部署 go 项目有一个通用的范式

那就是分阶段构建

一、分阶段构建

go 的部署只需要编译后的可执行文件就可以了,并不需要 go 的环境

那么我们可以先在有 go 环境的容器中对项目进行构建,得到构建后的可执行文件

然后再把这个可执行文件放到一个比较小的镜像容器里面

1、新建一个 go 项目

go mod init gotest

2、新建 main.go,写入下面的举例代码

package main

import "github.com/gin-gonic/gin"

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

3、安装依赖

 go mod tidy

4、新建 Dockerfile

FROM golang:alpine AS builder

#构建可执行文件
#关闭CGO
ENV CGO_ENABLED=0
#设置国内代理
ENV GOPROXY=https://goproxy.cn,direct
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories

#设置工作目录
WORKDIR /build
ADD go.mod .
ADD go.sum .
ADD main.go .
#开始打包,放在/build
RUN go build -o mian

#一个新的小镜像(非常小,10m)
FROM scratch
#新建工作目录/app
WORKDIR /app
#将/build/main可执行文件复制到/app
COPY --from=builder /build/mian /app
#运行
CMD ["./mian"]

5、开始打包

sudo docker build -t gotest .

6、使用 docker images 查看所有镜像

7、如果 gotest 镜像存在,开始运行

docker run -itd --name gotest -p 8080:8080 gotest

这里写的是最简单的 go 项目

没有使用配置文件,也没有连数据库等这些外部服务

二、使用配置文件映射

package main

import (
  "github.com/gin-gonic/gin"
  "gopkg.in/yaml.v3"
  "log"
  "os"
)

type Conf struct {
  System struct {
    Name string `yaml:"name"`
  } `yaml:"system"`
}

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

  byteData, err := os.ReadFile("settings.yaml")
  if err != nil {
    log.Fatal(err)
  }
  var conf Conf
  err = yaml.Unmarshal(byteData, &conf)
  if err != nil {
    log.Fatal(err)
  }

  r.GET("/", func(context *gin.Context) {
    context.JSON(200, gin.H{"code": 0, "msg": "看到消息就说明部署成功了", "data": gin.H{"name": conf.System.Name}})
  })
  r.Run(":5000")
}

修改 Dockerfile 文件

FROM golang:alpine AS builder

#构建可执行文件
ENV CGO_ENABLED=0
ENV GOPROXY=https://goproxy.cn,direct
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories

WORKDIR /build
ADD go.mod .
ADD go.sum .
ADD main.go .
RUN go build -o mian

FROM scratch
WORKDIR /app
COPY settings.yml .
COPY --from=builder /build/mian /app
CMD ["./mian"]

运行容器

docker run -itd --name go1 -p 5000:5000 -v G:\\IT\\go_pro\\go_study\\go_study\\31.部署\\settings.yaml:/app/settings.yaml go1

三、连接外部服务

以 mysql 为例,mysql 可能在我们的内网服务器上

也可能单独起一个 mysql 容器

面对第一种情况,因为 Docker 默认会将容器连接到宿主机的 Docker0 网桥上,容器和宿主机是可以直接通信的,所以直接连就行了

面对第二种情况,单独起的 mysql 容器和我们的项目容器是可以互相连接的

一般不会使用默认网络的

而是使用自建网络,创建容器的时候指定容器的 ip 地址

创建网络(子网是 10.1.0.0,子网掩码是 24)

docker network create --subnet=10.1.0.0/24 my-network

创建容器用自建网络

这里我用之前的 centos 容器测试

docker run -itd --name c2 --ip 10.1.0.2 --network my-network fengfengzhidao/centos7-ssh:v1
docker run -itd --name c3 --ip 10.1.0.3 --network my-network fengfengzhidao/centos7-ssh:v1

注意:在 settings.yaml中设置mysqlhost,必须写内网ip,而不是 127.0.0.1

mysql:
	host: 192.168.0.111
Not-By-AI