问题点
本地使用了.env文件注入环境变量,但是这里面的变量都是敏感数据,.gitignore设置了过滤,这导致我的config配置中err := godotenv.Load(".env")代码无法找到该文件,于是乎直接拉闸了。
思路
- 根据当前环境(开发或者生产),决定是否直接使用环境变量还是加载
.env文件 - 再dockerfile内就读取环境变量
解决
- 环境变量判断,这样不至于在非开发环境直接拉闸
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在构建的时候,注入环境变量即可
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文件内容如下:
# 使用 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的生产环境构建分为两个阶段
-
第一阶段: Go 构建环境
- 使用
golang:1.22官方镜像作为构建环境。这个镜像包含了完整的 Go 编译工具链,可以方便地进行代码编译和依赖管理。这个阶段构建下来大概1G多的镜像
- 使用
-
第二阶段: 小尺寸的运行环境
- 在第二阶段,我们使用
alpine:latest作为基础镜像。这是一个非常小巧的 Linux 发行版,适合作为运行环境。直接将main执行文件拷入,这个阶段构建出来大概只有40M左右,小了接近3倍,这可能就是go如此受欢迎的原因,确实很小,很好集成,毕竟这年头机器成本比人的成本要贵,牛马哭死在厕所!
- 在第二阶段,我们使用