零基础Docker+Go完整教程
这是一份为纯新手准备的保姆级 Docker 教程,从 0 开始,带你彻底搞懂 Docker,并且全程使用 Go 语言作为实战演示,所有步骤都可以直接复制执行,看完就能上手。
一、为什么要学 Docker?你必须知道的痛点
你有没有遇到过这些问题?
-
在我电脑上明明能运行啊!:开发完的项目,自己电脑跑的好好的,部署到服务器就各种报错,缺依赖、版本不对、环境变量不一样…
-
环境配置地狱:想跑个 Redis、MySQL,要装半天,不同项目要不同版本的软件,电脑上装了好几个版本,乱成一团。
-
部署慢到崩溃:传统虚拟机,启动要几分钟,打包镜像几个 G,传半天才能传到服务器。
Docker 就是来解决这些问题的!
简单来说,Docker 就是把你的应用 + 所有依赖 + 运行环境 + 配置,全部打包成一个 集装箱。这个集装箱可以在任何装了 Docker 的机器上运行,完全不用管那台机器原来装了什么,真正做到 一次打包,到处运行。
而且 Docker 比虚拟机轻量太多了:
-
容器秒级启动,虚拟机要几分钟
-
镜像体积只有几十 MB,虚拟机几个 G
-
一台机器能跑成百上千个容器,虚拟机跑几个就卡了
二、Docker 核心概念:3 分钟搞懂
学 Docker,首先要搞懂这三个核心概念,记住这三个,你就懂了 80%:
| 概念 | 是什么? | 类比理解 |
|---|---|---|
| 镜像 (Image) | 一个只读的模板,包含了运行应用需要的所有东西:代码、运行时、库、环境变量、配置文件。 | 可以理解成面向对象里的 类,是静态的,不变的。 |
| 容器 (Container) | 镜像的运行实例,是真正跑起来的应用。你可以启动、停止、删除它。 | 可以理解成 类的实例对象,是动态的,运行中的。同一个镜像可以启动 N 个容器,互相隔离。 |
| 仓库 (Repository) | 存放镜像的地方,相当于镜像的 应用商店。最有名的公共仓库是 Docker Hub,里面有几十万现成的镜像,比如 Nginx、MySQL、Redis,你直接拉下来就能用。 | 可以理解成GitHub,只不过存的是镜像,不是代码。 |
三者的关系:你从仓库pull(拉)镜像到本地,然后用这个镜像run(运行)出一个或多个容器。
三、Docker 安装:5 分钟搞定环境
Docker 支持 Windows、Mac、Linux 所有主流系统,新手推荐直接安装 Docker Desktop,它自带了 Docker 引擎、命令行工具、图形化界面,一键安装,非常方便。
3.1 Windows 系统安装
注意:Windows 10/11 家庭版需要开启 WSL2,专业 / 企业版也推荐用 WSL2,这是 Docker 官方推荐的模式。
-
下载 Docker Desktop 安装包:官网下载地址
-
双击安装包,一路下一步,安装的时候记得勾选 Use the WSL 2 based engine
-
安装完成后,启动 Docker Desktop,等待它启动完成(任务栏里的 Docker 图标不转了就好了)
3.2 Mac 系统安装
-
下载 Docker Desktop for Mac:官网下载地址
-
把下载的.dmg 文件打开,把 Docker 拖到 Applications 文件夹里
-
启动 Docker,等待它启动完成就行。
3.3 Linux 系统安装(以 Ubuntu/CentOS 为例)
Linux 用户可以用官方的一键安装脚本,非常简单:
|
|
3.4 验证安装是否成功
安装完成后,打开终端(Windows 用 PowerShell 或者 WSL 终端),执行:
|
|
如果输出类似 Docker version 27.0.3, build 7d4bcd8,说明安装成功了!
然后我们跑一个测试镜像,验证 Docker 能不能正常工作:
|
|
如果看到下面这段文字,说明你的 Docker 已经完全正常了!
|
|
四、必做:配置镜像加速器(解决国内拉取慢的问题)
默认情况下,Docker 拉取镜像要从国外的 Docker Hub 拉,速度非常慢,甚至会失败。所以我们必须配置国内的镜像加速器,这一步一定要做!
4.1 配置方法
Windows/Mac 系统(Docker Desktop)
-
打开 Docker Desktop,点击任务栏 / 菜单栏的 Docker 图标,选择 Settings(设置)
-
找到 Docker Engine 选项
-
在右边的 JSON 配置里,添加
registry-mirrors配置,把下面的内容复制进去:
|
|
- 点击右下角的 Apply & Restart,等待 Docker 重启完成。
Linux 系统
Linux 用户需要修改 Docker 的配置文件:
|
|
4.2 验证加速器是否生效
重启完成后,执行:
|
|
在输出的内容里,找到Registry Mirrors,如果能看到你刚才配置的地址,说明生效了!现在拉镜像速度会快几十倍!
五、第一个 Docker 实战:5 分钟跑一个 Nginx 网站
光说不练假把式,我们先跑一个最简单的 Nginx 网站,体验一下 Docker 的魅力,顺便把基础命令都过一遍。
步骤 1:拉取 Nginx 镜像
首先,我们从仓库拉取 Nginx 的官方镜像:
|
|
如果你没配置加速器,这一步可能会很慢,配置了的话,几秒就下完了。 这里如果不写版本,默认拉取
latest最新版,你也可以指定版本,比如docker pull nginx:1.25
步骤 2:查看本地镜像
拉完之后,我们可以看看本地的镜像:
|
|
输出大概是这样:
你能看到刚才拉的 nginx 镜像。
步骤 3:运行 Nginx 容器
现在我们用这个镜像,启动一个容器:
|
|
这条命令是 Docker 的核心,我们来拆解一下每个参数,一定要记住:
docker run:创建并启动容器的核心命令
--name my-nginx:给这个容器起个名字,叫 my-nginx,不然 Docker 会给你随机起个奇怪的名字
-p 8080:80:端口映射!这是最常用的参数。格式是宿主机端口:容器内端口。 Nginx 默认在容器里监听 80 端口,我们把它映射到我们电脑的 8080 端口,这样我们就能通过电脑的 8080 端口访问到容器里的 Nginx 了。
-d:后台运行容器,不然你的终端会被容器占住,不能干别的了。
nginx:指定用哪个镜像来启动容器,就是我们刚才拉的 nginx 镜像。
步骤 4:验证容器是否运行
执行完之后,我们看看正在运行的容器:
|
|
输出大概是这样:
你能看到 my-nginx 正在运行,端口映射8080->80也生效了。
现在,打开你的浏览器,访问 http://localhost:8080,如果看到 Nginx 的欢迎页面,恭喜你!你已经成功用 Docker 跑了第一个网站!
步骤 5:常用的容器操作
查看容器日志
如果容器出问题了,首先看日志:
|
|
进入容器内部
有时候我们需要进到容器里改配置、看文件:
|
|
这里的
-it是交互式终端的意思,/bin/bash是进入后启动 bash 命令行。 进去之后,你的命令行提示符会变,说明你已经在容器里了,你可以像正常 Linux 一样用 ls、cd 这些命令,输入exit就能退出容器。
停止 / 删除容器
不用的时候,我们可以停止容器:
|
|
停止之后,容器还在,只是不运行了,你可以用docker start my-nginx再启动它。如果彻底不要了,就删除:
|
|
如果你想强制删除正在运行的容器,可以加
-f:docker rm -f my-nginx
六、Docker 常用命令大全(收藏备用)
这里整理了所有日常会用到的 Docker 命令,做成表格,你可以收藏起来,用的时候直接查:
镜像相关命令
| 命令 | 说明 | 示例 |
|---|---|---|
docker images |
列出本地所有镜像 | docker images |
docker pull |
拉取远程镜像 | docker pull mysql:8.0 |
docker rmi |
删除本地镜像 | docker rmi nginx |
docker build |
从 Dockerfile 构建镜像 | docker build -t my-app:1.0 . |
docker search |
在 Docker Hub 搜索镜像 | docker search redis |
docker tag |
给镜像打标签 | docker tag my-app:latest my-app:v1.0 |
docker push |
推送镜像到仓库 | docker push my-repo/my-app:v1.0 |
容器相关命令
| 命令 | 说明 | 示例 |
|---|---|---|
docker run |
创建并启动容器 | docker run -d -p 8080:80 --name my-nginx nginx |
docker ps |
列出正在运行的容器 | docker ps |
docker ps -a |
列出所有容器(包括停止的) | docker ps -a |
docker start |
启动已停止的容器 | docker start my-nginx |
docker stop |
停止运行中的容器 | docker stop my-nginx |
docker restart |
重启容器 | docker restart my-nginx |
docker rm |
删除容器 | docker rm my-nginx |
docker exec |
在运行的容器里执行命令 | docker exec -it my-nginx bash |
docker logs |
查看容器日志 | docker logs -f my-nginx |
docker cp |
宿主机和容器之间复制文件 | docker cp my-file.txt my-nginx:/app/ |
docker inspect |
查看容器 / 镜像的详细信息 | docker inspect my-nginx |
七、自定义镜像:用 Go 语言打包你的应用
看完了别人的镜像,现在我们来自己做一个镜像,把我们自己写的 Go 应用打包进去,这也是你日常开发最常用的场景。
7.1 先写一个简单的 Go 应用
我们先写一个最简单的 HTTP 服务,就几行代码,用来测试。
首先,创建一个项目文件夹,比如叫go-demo:
|
|
然后,在这个文件夹里,创建main.go文件,写入下面的代码:
|
|
这个代码很简单,就是启动一个 HTTP 服务,访问根路径的时候,返回欢迎信息,还有容器的主机名,这样我们能区分是不是在容器里运行。
然后,我们初始化 Go 模块,用来管理依赖:
|
|
执行完之后,会生成一个go.mod文件,这是 Go 的依赖管理文件。
现在,我们可以先在本地跑一下,测试代码对不对:
|
|
然后访问http://localhost:8081,如果能看到 Hello 信息,说明代码没问题,按 Ctrl+C 停止。
7.2 什么是 Dockerfile?
要打包我们的应用,我们需要写一个Dockerfile,它是一个文本文件,里面写了构建镜像的所有步骤,Docker 会根据这个文件,一步步帮你构建出镜像。
我们先来看一下 Dockerfile 里最常用的指令,每个指令都很简单:
| 指令 | 作用 |
|---|---|
FROM |
指定基础镜像,所有的镜像都是基于这个来构建的,这是 Dockerfile 的第一行 |
WORKDIR |
指定工作目录,相当于cd到这个目录,后面的命令都是在这个目录下执行 |
COPY |
把宿主机的文件复制到镜像里 |
RUN |
执行命令,比如编译代码、安装依赖 |
CMD |
容器启动的时候,默认执行的命令,也就是启动我们应用的命令 |
EXPOSE |
声明容器要暴露的端口,只是声明,方便别人知道这个容器用了什么端口,不是实际的端口映射 |
7.3 单阶段构建:最基础的写法
我们先写一个最简单的单阶段 Dockerfile,就是所有的构建和运行都在一个镜像里。
在项目文件夹里,创建Dockerfile文件,写入下面的内容:
|
|
现在,我们来构建镜像:
|
|
这里的
-t go-demo:v1是给镜像起名字,叫 go-demo,版本 v1。最后的.是构建上下文,意思是把当前目录的文件作为构建的上下文,Docker 会把这些文件传给 Docker 引擎,所以这个点不能少!
构建完成之后,我们看看镜像大小:
|
|
你会发现,这个镜像有几百 MB!比如我这里是 431MB,这也太大了,一个几行的程序,镜像 400多MB?
这是因为,这个镜像里包含了整个 Go 的编译环境、所有的依赖源码、中间文件,这些东西在运行的时候根本不需要!我们运行的时候只需要那个编译好的二进制文件而已。
那怎么把镜像变小呢?这就要用到多阶段构建了!
7.4 多阶段构建
多阶段构建就是,我们把构建过程分成两个阶段:
-
构建阶段:用大的 Go 镜像,把代码编译成二进制文件
-
运行阶段:用一个超级小的基础镜像,只把编译好的二进制文件复制过来,其他的都不要!
这样,最终的镜像就只有运行需要的东西,体积会小 90% 以上!
我们来修改一下 Dockerfile,改成多阶段的:
|
|
这里解释一下为什么要加
CGO_ENABLED=0:默认情况下,Go 编译会用 CGO,生成动态链接的程序,在 Alpine 里会因为缺少 glibc 库而运行不了。关闭 CGO 之后,编译出来的是纯静态的二进制文件,不需要任何依赖,直接就能在 Alpine 里跑。
现在,我们重新构建镜像:
|
|
构建完成之后,我们再看看镜像大小:
|
|
你看,原来的 v1 是 431MB,现在的 v2 只有27MB左右!直接缩小了95%左右!这就是多阶段构建的威力!
7.5 运行我们的 Go 应用镜像
现在,我们来运行这个新的镜像:
|
|
然后,打开浏览器,访问http://localhost:8081,你就能看到我们的 Go 应用返回的信息了!
完美!我们的 Go 应用已经成功打包成 Docker 镜像,并且跑起来了!
八、Docker Compose:一键启动多服务应用
平时我们开发的时候,很少只有一个服务,比如我们的 Go 应用,要连 MySQL、Redis,这时候如果一个个启动容器,要写好长的命令,太麻烦了。
这时候就轮到Docker Compose出场了!它可以把你的多个服务,写在一个配置文件里,然后一条命令,就能把所有服务都启动起来,一键搞定!
8.1 什么是 Docker Compose?
Docker Compose 是 Docker 官方的编排工具,用来定义和运行多个容器的应用。你只需要一个docker-compose.yml文件,就能定义你的所有服务,然后一条命令,就能把它们全部启动。
8.2 实战:Go+MySQL 多服务应用
我们来做一个实战,把我们的 Go 应用,加上 MySQL 数据库,用 Compose 一键启动。
首先,我们修改一下我们的 Go 应用,让它连接 MySQL,查询数据。
先修改main.go:
|
|
然后,我们更新一下依赖,把旧的go.mod删掉:
|
|
现在,我们在项目根目录,创建docker-compose.yml文件,写入下面的内容:
|
|
这里有个重点:Compose 会自动给我们的服务创建一个网络,所以服务之间可以直接用服务名互相访问!比如我们的 app 服务,要连接 mysql,直接用
mysql作为主机名就行,不用 IP,Compose 会自动解析,太方便了!
8.3 一键启动所有服务
现在,我们只需要执行一条命令,就能把 Go 应用和 MySQL 一起启动:
|
|
-d是后台运行,和之前的一样。
执行完之后,Compose 会自动帮你:
-
构建 Go 应用的镜像
-
拉取 MySQL 的镜像
-
启动 MySQL 容器,自动创建数据库
-
启动 Go 应用容器,连接 MySQL
等个十几秒,启动完成之后,我们访问http://localhost:8081,就能看到:
完美!两个服务,一条命令就全部启动了!
如果你要停止所有服务,只需要执行:
|
|
所有的容器就都停了,数据卷还在,下次启动数据还在。
九、常见问题与排错指南
新手用 Docker,经常会遇到这些问题,这里给你整理好了解决方案:
1. 端口占用,启动容器报错port is already allocated
这说明你电脑的那个端口已经被别的程序占用了,比如你已经有一个 Nginx 占用了 8080 端口。
解决方法:换一个宿主机端口,比如把-p 8081:80,用 8081 端口就行。
2. 拉取镜像超时 / 失败
这是网络问题,首先检查你有没有配置镜像加速器,配置了的话,换一个加速器地址,或者多试几次。
3. Go 程序在 Alpine 容器里运行报错no such file or directory
这就是我们之前说的 CGO 的问题,你编译的时候没关 CGO,导致程序依赖动态链接库,Alpine 里没有。
解决方法:编译的时候加上CGO_ENABLED=0 GOOS=linux,编译成静态二进制。
4. 容器里的时间不对,比北京时间差 8 小时
这是因为 Alpine 默认是 UTC 时区,解决方法:
-
安装 tzdata 包:
RUN apk --no-cache add tzdata -
设置时区环境变量:
ENV TZ=Asia/Shanghai
5. 容器之间无法访问
如果是用 Compose 的话,检查你是不是用服务名作为主机名,不要用localhost,因为每个容器的localhost都是自己。 如果是单独的容器,检查它们是不是在同一个网络里,或者把它们连到同一个网络。
十、总结
到这里,你已经掌握了 Docker 的核心技能了:
-
理解了 Docker 的核心概念,知道了镜像、容器、仓库是什么
-
学会了安装 Docker,配置镜像加速器,解决了国内的网络问题
-
掌握了 Docker 的常用命令,能熟练操作镜像和容器
-
学会了写 Dockerfile,用多阶段构建把 Go 应用打包成极小的镜像
-
学会了用 Docker Compose,一键启动多服务应用
Docker 是现代开发者的必备技能,学会了它,你再也不用为环境问题头疼,部署应用也变得无比简单。接下来,你可以把你自己的项目,用这个方法打包成 Docker 镜像,试试部署到服务器上,体验一下一键部署的快感!















