从零到上线:一次真实的 Docker 部署问题记录

本文记录我在 Linux 服务器上使用 Docker Compose 部署一个 Go 聊天系统时遇到的各种坑,以及完整的排障思路。文章不走概念教学路线,而是基于真实错误日志 + 实战修复过程展开。希望能给后来者提供可复用的经验。


1. 背景

项目结构在本地 Windows 环境下开发良好。目标是在 Linux(CentOS)服务器上通过 Docker Compose 启动三大服务:

  • MySQL 8.0

  • Redis 7

  • Go Chat Server(自构建镜像)

本以为是三分钟小事,结果一路从 YAML 语法错、容器冲突、MySQL 初始化失败、Redis 域名解析失败,一直踩到跨系统 MySQL 连接问题。

下面按时间线回放整个排障过程。


2. Docker Compose 报错:服务名冲突

第一次 docker compose up -d 就报:

Error response from daemon: Conflict. The container name "/mysql" is already in use

问题不复杂:服务器上早就有个叫 mysql 的残留容器,Compose 创建新容器冲突。

解决方案:

docker rm -f mysql
docker compose up -d

经验总结:
 docker ps 只会显示活着的容器,很多死掉的容器会被 -a 才能看到,而正是它们在占用着名字。


3. YAML 语法错误:行尾符号、缩进、引号

遇到过几次:

yaml: line 26: mapping values are not allowed in this context

这种报错 90% 是:

  • 多了冒号

  • 引号不成对

  • -v 换行后缩进不一致

  • Windows 文件换行符 CRLF

最终是某一行多了一个意外字符,通过重新复制 YAML 格式解决。

经验总结:
YAML 的错误提示永远不可信。找到报错行没意义,直接从最近修改的几行开始查。


4. 服务启动顺序问题:MySQL 启动慢导致 Chat Server 失败

Chat Server 在启动时不断输出:

初始化数据库失败:连接数据库失败:dial tcp 172.x.x.x:3306: connect: connection refused

原因非常明确:
MySQL 容器启动还没完成,Go 程序就来连,连不上自然报错。

一般要么用 depends_on 配合健康检查,要么让应用层自动重试。

本项目服务端已有重试机制,因此数次“失败 → 成功”是正常现象。

最终日志出现:

MySQL 数据库连接成功!

说明数据库稳定运行。


5. Redis 域名解析失败:服务名不存在

Chat Server 报错:

初始化redis失败:redis ping failed dial tcp: lookup chat-redis on 127.0.0.11:53: no such host

分析:

  • compose 中 redis 的服务名是 redis

  • chat-server 配置用的是 chat-redis

  • 网络别名需要在 compose 中声明

最终通过在 redis 服务中加入:

networks:
  chat-net:
    aliases:
      - chat-redis

成功解决。

经验总结:
Docker Compose 网络下的域名解析走内部 DNS,所有容器以服务名作为 hostname。要用别名,记得添加 alias。


6. MySQL 表不存在:初始化 SQL 未创建表

客户端提示:

Error 1146 (42S02): Table 'net_chat.users' doesn't exist

MySQL 明确没有初始化表结构,原因如下:

  • 我以为 Docker 会自动执行 init SQL

  • 实际上只有在容器第一次创建数据目录时才执行 docker-entrypoint-initdb.d 下文件

  • 我重新部署用了同一个数据卷 → 不会再运行 SQL

最终登录容器内手动建表即可:

CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(255) NOT NULL UNIQUE,
    password_hash VARCHAR(255) NOT NULL,
    create_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

经验总结:
使用 docker-entrypoint-initdb.d 时一定要记住:
初始化脚本只在首次为空数据卷时运行一次


7. 运行客户端:Linux 环境无 go 命令

在服务器执行客户端时报:

bash: go: 未找到命令...

这是因为生产服务器没有安装 Go,解决方法:

wget https://go.dev/dl/go1.24.4.linux-amd64.tar.gz
tar -C /usr/local -xzf go1.24.4.linux-amd64.tar.gz
export PATH=$PATH:/usr/local/go/bin

经验总结:
开发环境和部署环境不等价,尤其生产机器通常不会预装编译工具链。


8. Windows 客户端无法连接 Linux Docker MySQL

Linux 上运行正常,但 Windows 客户端死活连不上 MySQL。

常见原因:

  1. Docker 没映射 3306

  2. 防火墙阻挡 3306

  3. MySQL 用户没有远程权限

  4. bind-address 锁定 127.0.0.1

最终检查发现 Docker Compose 内确实没映射端口。

修复:

mysql:
  ports:
    - "3306:3306"

加上远程用户授权:

CREATE USER 'appuser'@'%' IDENTIFIED BY 'apppass123';
GRANT ALL PRIVILEGES ON net_chat.* TO 'appuser'@'%';
FLUSH PRIVILEGES;

Windows 成功通过:

mysql -h <Linux_IP> -u appuser -papppass123

经验总结:
不开放端口,跨主机永远连不上。
别过度怀疑 MySQL,80% 问题都是端口没映射。


9. 整体架构最终稳定运行

最终 docker compose config 显示:

  • chat-server → 使用 redis:6379 成功连接 redis

  • redis → alias 为 chat-redis

  • mysql → 映射 3306,客户端可访问

  • 三服务共用 chat-net 网络

访问日志确认:

MySQL 数据库连接成功!
初始化redis成功
服务端正在监听端口 :8080

系统在 Linux 上顺利跑通。


10. 全程经验总结

这次部署踩坑总结:

1)容器网络

服务之间通信必须走 服务名 而不是 IP。

2)Compose 的端口

所有跨主机访问必须在 ports: 中映射出来。

3)日志是唯一真相

每个坑都是日志给出线索:

  • DNS 失败

  • 连接拒绝

  • 表不存在

  • 找不到命令

4)顺序问题大于配置问题

数据库启动慢引发的依赖服务报错经常被误判为配置错误。

5)跨平台开发注意连接方式

Windows 客户端要连接容器 MySQL,必须确认:

  • 外部可达

  • 用户已授权

  • 防火墙放行

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值