前端er Go-Frame 的学习笔记:实现 to-do 功能(三),用 docker 封装成镜像,并且同时启动前后端数据库服务

前言

目前我手上已经有了两个项目

  • go-frame
  • React 写的前端

现在来学一下企业级的部署,让 AI 大师给我指条明路


什么是 k8s

Kubernetes(k8s)= 一个用于自动运行、扩缩容、自动恢复你的应用的系统。

简单说:你把镜像给它,它帮你稳定运行(并且几乎不会挂)。

前端项目封装成镜像

给前端项目写一个 Dockerfile

我可能要写两个文件,第一个是 Dockerfile

bash 复制代码
# === 构建阶段 ===
FROM node:22-alpine AS build
WORKDIR /app

COPY package*.json ./
RUN npm install --production=false

COPY . .
RUN npm run build


# === 运行阶段:使用 Caddy 作为静态服务器 ===
FROM caddy:2-alpine

# 将构建产物复制到 Caddy 默认站点目录
COPY --from=build /app/dist /usr/share/caddy

# 复制 Caddyfile(如果你需要自定义路由)
COPY Caddyfile /etc/caddy/Caddyfile

期间遇到了两个问题,第一个是文件放错位置了

第二个是构建到最后报错了

报错内容:

bash 复制代码
cannot replace to directory ... node_modules/@ant-design/icons with file

意思是:容器里 node_modules 是文件夹 你宿主机的 node_modules 中某些内容可能是软链接或文件 COPY 全目录的时候冲突了。 💥 根本原因:你把整个项目(包括本地 node_modules) COPY 进入容器!

这个 .dockerignore的作用如下

我是m1 芯片,16G 内存,大概要打 1 分半的镜像。 构建好的 docker 镜像,我准备测一下

然后在浏览器里看一下

ok 啊,果然失败了,容我检查一下哪里出了问题!

首先,本地构建,预览,没有问题

那非常有可能的是我的代理问题了

问了一下,说是 caddy 需要反向代理

我们来进入容器中试一下

bash 复制代码
docker ps
docker exec -it 容器名 sh
wget -qO- http://localhost/api/v1/todo
wget -qO- http://host.docker.internal:8000/api/v1/todo

# 强制无缓存刷新
docker build --no-cache -t todo-front-test .  
docker run -d -p 2345:80 --name todo-front-test todo-react-app

很好,这个问题折磨了我一阵子,我试了各种各样版本的 caddyfile,只有用 handle 语法的成功了。 我只改了两个地方

一个是 env 文件,改成了如下图所示,这个文件是硬编码的,所以不能写成这个。

问题:那如果改这里的话,dev 环境就不能调试了 所以,我来写 .env.development.env.production 两个,看看能不能解决环境问题 (我自己验证了一下,是可行的,dev 走的 localhost:8000prod 走的 /caddy 的代理)

首先说明一下当前情况: 我想测一下前端容器,访问宿主机的后端

Caddyfile 复制代码
:80 {
	# 静态文件根目录
	root * /usr/share/caddy

	# 1. 优先处理 API 请求(使用 handle 强制隔离和执行)
	# 只要路径匹配 /api/*,就执行反向代理,并停止处理。
	handle /api/* {
		reverse_proxy http://host.docker.internal:8000
	}

	# 2. 处理所有其他请求 (前端路由和静态文件)
	handle {
		# 静态文件服务
		file_server

		# SPA 路由回退:如果文件不存在,返回 index.html
		try_files {path} /index.html
	}
}

后端封装 docker

go-frame 似乎自带了封装 docker 的命令,我们看一下官方的例子 https://goframe.org/docs/cli/docker#%E4%BD%BF%E7%94%A8%E7%A4%BA%E4%BE%8B

bash 复制代码
gf docker main.go -p -tn loads/gf-demos:test

然后这是后端打包的速度, 还行 40 多秒

好吧,感觉看错地方了,应该是这里 https://goframe.org/docs/deploy/container#1-%E7%BC%96%E8%AF%91%E7%A8%8B%E5%BA%8F

写好 dockerfile 文件之后,编译,我的是m1 ,所以说明一下平台

bash 复制代码
docker build -t todo-go-frame .

好哎,又报错了

说是要改一下 go.mod 的版本号

然后上面就飘红了

执行一下 go mod tidyemmm 还是不行,tidy 之后就会变成 1.23.0

好的,说是 dockerfile 用的 go1.20,改一下 dockerfilego 版本

中间又遇到个错误

好的,最后终于成功了

这是能打包的 dockerfile

go 复制代码
# Stage 1: Builder
FROM golang:1.23-alpine AS builder

WORKDIR /app/main

# Copy go.mod and go.sum
COPY go.mod go.sum ./
RUN go mod download

# Copy the rest
COPY . .

# Build
RUN go mod tidy
RUN CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -o main .

# Stage 2: Production
FROM alpine:3.18

LABEL maintainer="john@goframe.org"

ENV WORKDIR /app/main

RUN mkdir -p $WORKDIR

# Copy binary
COPY --from=builder /app/main/main $WORKDIR/main
RUN chmod +x $WORKDIR/main

# Copy resources
COPY resource $WORKDIR/resource

WORKDIR $WORKDIR
CMD ["./main"]

跑了一下容器,但是感觉端口并没有对应上呢

我发现容器里估计缺了 config

bash 复制代码
➜ docker run --rm -it todo-go-frame sh
ls -R

ok,我自己重新加了个文件夹

好,现在问题卡在如何把容器中的后端接口固定住,目前是随机分配的。我打算用框架的目录

bash 复制代码
docker build -t goframe-app:latest -f manifest/docker/Dockerfile .

好啊,容器里终于定下来了

然后我宿主机中映射的 8080,打开看一下!不错子!终于连上了

这里我固定写死了 8000,但是我觉得不对,在部署的时候我应该能随意的更改端口地址,所以,这个问题暂时保留,起码能跑起来了,🥹


数据库容器

我的想法是,前端,后端,数据库,都容器化,然后组合在一个网络里

数据库容器的话, go-frame 的官方例子中已经有了 https://goframe.org/quick/scaffold-api-sql#%E5%BA%94%E7%94%A8%E6%95%B0%E6%8D%AE%E8%A1%A8

bash 复制代码
docker run -d --name mysql \
 -p 3306:3306 \
 -e MYSQL_DATABASE=test \
 -e MYSQL_ROOT_PASSWORD=12345678 \
 loads/mysql:5.7

启动了容器 mysql

在宿主机上连接一下容器 mysql

可以看到用的是容器的,因为我本地的是 mysql 9

docker-compose.yml

我现在要把前端,后端,数据库的容器放到一个网络里

现在在项目根目录下创建 docker-compose.yml 文件

bash 复制代码
docker compose up --build -d

数据库容器从 postgre 换成 mysql 之后,因为有写数据卷(持久化),所以要清理一下。

bash 复制代码
docker compose down

docker volume ls

部署的时候遇到的问题记录

后端接口报错

返回数据了,但是拒接链接

好的,是我 docker-componse.yaml 中没写数据库的名称和密码

bash 复制代码
docker compose down
docker volume ls
docker volume rm <你的卷名,例如 todoList-react-goframe_db_data>
docker compose up --build -d

这个文件也不能硬编码,但是我在想如果是开发的话该怎么办,这里是不是还要改

改了上面的信息之后,报错就变了

markdown 复制代码
 "message": "SELECT `id`,`title`,`done`,`created_at`,`updated_at` FROM `todo`: Error 1146 (42S02): Table 'todo_db.todo' doesn't exist",

终于不是被拒绝了,

init sql

我现在后端创建一个 sql 文件, 然后在 docker compose 的时候跑一下脚本

中途还遇到了些问题

修改了数据库的话要清理卷

bash 复制代码
docker compose down
docker volume ls
docker volume rm <你的卷名,例如 todoList-react-goframe_db_data>
docker compose up --build -d

终于是跑起来了!不过中文好像是乱码!

好,ai 说是环境变量的问题

重启一下,旧的数据应该不行了,不过新的数据是好的!

接下来可能要用 k8s ,或者,在开发一下,体验真实的开发+部署流程

因为有些地方并不合理,比方说我在部署的时候写死了后端的接口,一些部署的环境变量也是硬编码,这不好,不过,先把整个流程跑通吧!

相关推荐
涡能增压发动积21 小时前
同样的代码循环 10次正常 循环 100次就抛异常?自定义 Comparator 的 bug 让我丢尽颜面
后端
Wenweno0o21 小时前
0基础Go语言Eino框架智能体实战-chatModel
开发语言·后端·golang
于慨21 小时前
Lambda 表达式、方法引用(Method Reference)语法
java·前端·servlet
石小石Orz21 小时前
油猴脚本实现生产环境加载本地qiankun子应用
前端·架构
swg32132121 小时前
Spring Boot 3.X Oauth2 认证服务与资源服务
java·spring boot·后端
从前慢丶21 小时前
前端交互规范(Web 端)
前端
tyung21 小时前
一个 main.go 搞定协作白板:你画一笔,全世界都看见
后端·go
gelald21 小时前
SpringBoot - 自动配置原理
java·spring boot·后端
CHU72903521 小时前
便捷约玩,沉浸推理:线上剧本杀APP功能版块设计详解
前端·小程序
GISer_Jing21 小时前
Page-agent MCP结构
前端·人工智能