记一次docker部署go项目的环境变量配置

Saturday , 2024-9-14 21:34

问题点

本地使用了.env文件注入环境变量,但是这里面的变量都是敏感数据,.gitignore设置了过滤,这导致我的config配置中err := godotenv.Load(".env")代码无法找到该文件,于是乎直接拉闸了。

思路

  • 根据当前环境(开发或者生产),决定是否直接使用环境变量还是加载.env文件
  • 再dockerfile内就读取环境变量

解决

  • 环境变量判断,这样不至于在非开发环境直接拉闸

    1
    2
    3
    4
    5
    6
    7
    8
    9
    if env := os.Getenv("ENVIRONMENT"); env == "" {
    err := godotenv.Load(".env")
    if err != nil {
    log.Fatalln("Error loading .env file")
    return
    }
    } else {
    log.Println("当前环境==>", os.Getenv("ENV"))
    }
  • 在服务端设置环境变量,如:export WOWNAV_ENVIRONMENT=production,然后在dockerfile中使用ARG WOWNAV_ENVIRONMENT引入环境变量,然后使用--build-arg在构建的时候,注入环境变量即可

1
2
3
4
5
docker build \
--build-arg WOWNAV_ENVIRONMENT=$WOWNAV_ENVIRONMENT \
--build-arg WOWNAV_DB_SOURCE=$WOWNAV_DB_SOURCE \
--build-arg WOWNAV_JWT_SECRET=$WOWNAV_JWT_SECRET \
-t wownav-app .

dockerfile文件内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# 使用 Go 官方镜像
FROM golang:1.22 AS builder

# 设置工作目录
WORKDIR /app

# 复制源代码
COPY . .

# 设置 Go 环境变量
RUN go env -w GO111MODULE=on
RUN go env -w GOPROXY=https://goproxy.cn,direct

# 下载依赖
RUN go mod download

# 构建应用
RUN CGO_ENABLED=0 go build -o main .

# 使用更小的镜像
FROM alpine:latest

# 引入宿主机的环境变量
ARG WOWNAV_ENVIRONMENT
ARG WOWNAV_DB_SOURCE
ARG WOWNAV_JWT_SECRET

# 设置环境变量
ENV ENVIRONMENT=$WOWNAV_ENVIRONMENT
ENV DB_SOURCE=$WOWNAV_DB_SOURCE
ENV JWT_SECRET=$WOWNAV_JWT_SECRET
ENV REDIS_ADDR=localhost:6379

# 复制构建的应用
COPY --from=builder /app/main .

# 暴露端口
EXPOSE 8080

# 启动应用
CMD ["./main"]

后记

原来go的生产环境构建分为两个阶段

  1. 第一阶段: Go 构建环境

    • 使用 golang:1.22 官方镜像作为构建环境。这个镜像包含了完整的 Go 编译工具链,可以方便地进行代码编译和依赖管理。这个阶段构建下来大概1G多的镜像
  2. 第二阶段: 小尺寸的运行环境

    • 在第二阶段,我们使用 alpine:latest 作为基础镜像。这是一个非常小巧的 Linux 发行版,适合作为运行环境。直接将main执行文件拷入,这个阶段构建出来大概只有40M左右,小了接近3倍,这可能就是go如此受欢迎的原因,确实很小,很好集成,毕竟这年头机器成本比人的成本要贵,牛马哭死在厕所!