将Go项目部署到Docker,最合适的保姆级教程
准备工作
1、确定项目目录结构
理想情况下在虚拟机中的目录应该有类似下图一样的结构:

-
yml文件与客户端,服务端同级
-
服务端运行文件(server.go)与服务端 Dockerfile 同级,客户端也是如此
2、上传项目
1、最简单直观、基于图形化界面
直接将文件从主机拖进虚拟机
2、最通用、基于网络传输
使用 SCP/SFTP 命令
# 递归上传整个目录, 注意要上传的目录必须已经存在!
scp -r 要上传的项目目录 虚拟机用户名@虚拟机ip地址:要上传到的目录
# 示例,对应我上面的目录结构
eg : scp -r D:\Goproject\onlineChatRoom root@ip地址:/go-project
这里项目目录如果特别大的话,可以先在主机使用命令 tar / zip 进行压缩,然后再进行 scp 传输,到虚拟机上再解压
完成之登录虚拟机、进入 /go-project 然后使用 tree 命令、会得到跟我类似的项目目录、那么恭喜你,完成了第一步!
3、客户端Dockerfile
# 构建阶段
FROM golang:1.24 AS builder
# 基于官方 Golang 1.24 版本的镜像
# 给这个构建阶段命名为 "builder",便于后续引用
WORKDIR /app
# 在容器内设置工作目录为 /app,构建阶段后续命令都在此目录下执行
COPY . .
# 将宿主机根目录所有文件复制到容器的 /app 目录
# 第一个 . 表示构建上下文的所有内容,也就是项目下的所有文件
# 第二个 . 表示容器的 /app 目录
Run go env -w GOPROXY=https://goproxy.cn,direct
#设置 Go 模块代理为国内镜像源,加速依赖下载
RUN go mod tidy && CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o /app/client ./client
# 这一步的作用就是:1、整理模块依赖 2、将app/下的client包下的所有go文件编译成可执行的二进制文件存放在 /app/client
# 整理 Go 模块依赖,添加缺失的模块,移除未使用的模块
# CGO_ENABLED=0: 禁用 CGO,生成纯静态二进制文件,不依赖系统库
# GOOS=linux: 指定目标操作系统为 Linux
# GOARCH=amd64: 指定目标架构为 x86-64
# go build -o /app/client ./client
# -o /app/client: 指定输出文件路径和名称
# ./client: 要编译的包路径(通常是包含 main.go 的目录)
# 运行阶段
FROM alpine:latest
# 基于 Alpine Linux 镜像,这是一个极简的 Linux 发行版
# 相比使用完整的 Golang 镜像,大幅减小最终镜像体积
WORKDIR /app
# 设置运行阶段的工作目录为 /app
COPY --from=builder /app/client .
#--from=builder: 从之前的构建阶段(builder)复制文件
#/app/client: 源文件路径(构建阶段生成的二进制文件)
#. : 目标路径(当前工作目录 /app)
CMD ["./client"]
#容器启动时执行的命令,执行当前目录下的 client 二进制文件
4、服务端Dockerfile
# 跟客户端Dockerfile 基本一样,不再注释
# 构建阶段
FROM golang:1.24 AS builder
WORKDIR /app
COPY . .
RUN go env -w GOPROXY=https://goproxy.cn,direct
RUN go mod tidy && CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o /app/server ./server
# 运行阶段
FROM alpine:latest
WORKDIR /app
COPY --from=builder /app/server .
EXPOSE 8080
# 声明容器运行时监听的端口 8080
CMD ["./server"]
5、docker-compose.yml
services:
mysql: # 服务名
image: mysql:8.0
container_name: mysql # 容器名
restart: always # 容器异常退出时自动重启
environment: # 环境
MYSQL_ROOT_PASSWORD: "12345" # root 用户密码
MYSQL_DATABASE: database # 创建默认数据库
MYSQL_USER: user # 创建普通用户
MYSQL_PASSWORD: password # 普通用户密码
ports:
- "3306:3306" # 主机3306端口映射到容器3306端口
volumes:
- mysql_data:/var/lib/mysql # 挂载、数据持久化
networks:
- go-net # 加入自定义网络
redis:
image: redis:5.0
container_name: redis
restart: always
ports:
- "6379:6379" # Redis 默认端口
volumes:
- redis_data:/data
command: ["redis-server", "--appendonly", "yes"] # 启用 AOF 持久化、确保数据不丢失
networks:
- go-net
server:
build:
context: . # 构建上下文为当前目录
dockerfile: server/Dockerfile # 使用 server/Dockerfile 构建
container_name: go-server # 容器名
depends_on: # 依赖
- mysql
- redis
environment:
MYSQL_HOST: mysql # 使用服务名而非IP
MYSQL_USER: user
MYSQL_PASSWORD: password
MYSQL_DB: database
REDIS_ADDR: redis:6379
networks:
- go-net
ports:
- "8080:8080" # 暴露服务端口
client:
build:
context: .
dockerfile: client/Dockerfile
container_name: go-client
depends_on: # 依赖
- server
environment:
SERVER_ADDR: go-server:8080 # 使用容器名和端口
networks:
- go-net
command: tail -f /dev/null # 保持容器运行,覆盖掉客户端Dockerfile的CMD["./client"]
# 这样是确保容器保持运行,而客户端是手动启动
networks:
go-net:
driver: bridge
volumes:
mysql_data:
redis_data:
好了,恭喜你完成了准备工作!
小问题
1、mysql 连接
dsn := "root:5812@tcp(localhost:3306)/onlinechatroom?charset=utf8mb4&parseTime=True&loc=Local"
// 这是在主机上的连接mysql 需要改为:
//root:密码@tcp(容器名:端口)
dsn := "root:12345@tcp(mysql:3306)/onlinechatroom?charset=utf8mb4&parseTime=True&loc=Local"
2、 redis 连接
RDB = redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "",
DB: 0,
PoolSize: 100, //连接池的大小
})
// 改为:
RDB = redis.NewClient(&redis.Options{
Addr: "redis:6379", //容器名:端口
Password: "",
DB: 0,
PoolSize: 100, //连接池的大小
})
3、 客户端连接服务端
conn, err := net.Dial("tcp", "localhost:8080") //连接服务端
// 改为
conn, err := net.Dial("tcp", "go-server:8080") //容器名:端口
运行
1、docker compose build --no-cache
-
构建所有 Docker 镜像,确保使用最新的代码和依赖
-
--no-cache 忽略 Docker 缓存,从头开始构建每一层
-
适用于:代码更新后、依赖变更后、确保构建一致性
运行完毕之后会成功构建两个镜像:

2、docker compose up -d mysql reids
-
后台启动 mysql 和 redis服务
运行完毕之后会拉取 mysql 和 redis 镜像
然后根据这两个镜像运行容器 mysql,redis 、容器名在yml文件中已经决定

因为我这里已经全部运行了,正常到这一步是只有 mysql 和 redis 的

3、初始化数据库
-
因为我的项目是要用到 mysql 中 onlineChatRoom 库中的 user 表的
-
docker exec -it 容器名 mysql -uroot -p 、进入 mysql
-
create database onlineChatRoom 、创建需要用到的库
-
user onlineChatRoom 、使用库
-
create table user ··········· 、创建表
4、docker compose up -d server
-
后台启动服务端
-
此时 mysql 和 redis已经运行,server 可以正常连接它们
-
server 服务会读取环境变量连接到 mysql 和 redis
-
可以观察服务端启动日志,确认数据库连接成功
5、docker compose up -d client
-
最后后台启动客户端
-
client 依赖 server 服务,等 server 就绪后再启动
-
client 容器会保持运行(因为
tail -f /dev/null)
第四步和第五步运行完毕之后就会如下所示:

6、docker compose logs server -f
-
监控服务端的运行状态和日志输出
-
logs:查看容器日志 -
server:指定查看 server 服务的日志 -
-f:跟随模式(follow),实时显示新日志 -
用于:调试应用、监控运行状态、查看错误信息
运行完毕之后能够监听服务端的日志:

7、docker exec -it go-client /bin/sh
-
进入客户端容器的交互式 shell
-
exec:在运行中的容器内执行命令 -
-it:交互式终端(interactive + TTY) -
go-client:容器名称(在 docker-compose.yml 中定义的 container_name) -
/bin/sh:要执行的 shell(Alpine Linux 默认使用 sh)
运行完毕之后会进入到 /app # 、app也是在上面自己起的名字
./client 表示运行当前目录下的可执行文件client、其实就是运行客户端、然后就可以进行操作了

更多推荐
所有评论(0)