写了个Go程序,发给同事却跑不起来——这种事,每个程序员都经历过。

问题往往不是代码错了,而是环境不对。对方没装Go,或者版本不同,或者依赖库缺了某个版本。你这边跑得欢,他那边报错一堆。

打开网易新闻 查看精彩图片

Docker就是来解决这个尴尬的。它把代码和运行环境打包成一个"盒子",谁拿到都能原样运行。本文用一个Go应用做案例,手把手教你从单机容器到多容器编排的完整流程。

先理解这个"盒子"是什么

想象一个密封的盒子:里面装着你的代码、Go语言运行时、所有依赖包,甚至操作系统层面的配置。

别人不需要在自己的电脑上装任何东西,打开盒子就能跑。而且无论谁打开,跑出来的结果一模一样。

在Docker的术语里,这个盒子叫镜像(image),打开后的运行状态叫容器(container)

镜像是个只读的模板,容器则是镜像的实时实例。你可以从一个镜像启动无数个容器,就像用同一份安装盘装出多台配置相同的电脑。

第一步:写个能跑的Go应用

我们从一个最简单的HTTP服务开始。这个服务连上MySQL数据库,对外暴露几个REST接口。

代码结构很常规:main.go里启动服务器,handlers处理请求,models定义数据模型。关键是用标准库database/sql配合go-sql-driver/mysql驱动。

本地跑通后,问题来了:怎么把这个服务连带着MySQL一起打包?数据库也是环境的一部分,总不能让对方自己装MySQL再配表结构吧。

第二步:用Dockerfile造盒子

Dockerfile是一份"造盒说明书",告诉Docker怎么一步步构建镜像。

我们采用多阶段构建(multi-stage build),这是Go容器化的最佳实践。第一阶段用golang:1.19镜像编译出二进制文件,第二阶段用更小的alpine镜像只保留编译结果。

这样最终镜像体积能从几百MB压缩到十几MB。Go编译成静态链接的二进制文件,天生适合这种瘦身操作。

关键指令就这几行:FROM选基础镜像,WORKDIR设工作目录,COPY把代码拷进去,RUN执行编译,EXPOSE声明端口,CMD指定启动命令。

注意GOOS=linux GOARCH=amd64的交叉编译参数,确保在Mac或Windows上编译出来的二进制能在Linux容器里跑。

第三步:一台机器跑多个盒子

单个容器还不够。真实场景里,Go服务依赖MySQL,可能还需要phpMyAdmin看数据。三个服务怎么协同?

Docker Compose登场。它用一个YAML文件定义多容器应用,一键启动整套环境。

docker-compose.yml里我们定义三个服务:app(Go应用)、db(MySQL)、phpmyadmin(数据库管理界面)。

每个服务指定镜像来源、端口映射、环境变量、卷挂载。关键是depends_on字段,确保MySQL先启动,Go应用后启动,避免连接报错。

网络配置让三个容器互相可见。Docker Compose自动创建隔离的虚拟网络,服务名就是主机名,Go代码里写"db:3306"就能连上MySQL。

第四步:跑起来看看

命令行里docker-compose up,三个容器依次启动。终端里能看到彩色日志输出,哪个服务报了什么错一目了然。

测试一下:curl http://localhost:8080/users 能拿到数据,打开 http://localhost:8081 是phpMyAdmin登录页。整套环境在一台机器上跑起来了,和本地开发完全一致。

关掉也简单,docker-compose down一键清理,不留垃圾。

这到底改变了什么

以前部署一个Go+MySQL的应用,要写安装文档、配环境变量、处理版本冲突。现在一个docker-compose.yml文件,新人第一天就能跑起来。

更隐蔽的好处是环境一致性。开发、测试、生产用同一个镜像,"我本地没问题"这种对话彻底消失。

对25-40岁的技术从业者来说,这省下的不是装环境的那几小时,而是排查环境差异的整天整天。把时间花在代码上,而不是和机器较劲。