1. Docker到底是什么:用一次交付把"环境不一致"这件事讲清楚
先从一个每天都有人问的场景说起。你写了一个Python项目,本地跑得好好的,一发给同事,对方那边缺了几个依赖包,报错。你装好依赖,他又报版本冲突。你锁定了requirements.txt,他那边系统库版本又不对。最后你火了,直接把整个环境打包成虚拟机镜像发过去,四五GB的东西,对方解压完还要改IP、改配置,折腾一上午。
Docker的出现,本质上就是来解决这个"在我电脑上是好的"的世纪难题。它把应用和它运行所需要的依赖环境一起打包成一个标准单元,这个单元叫镜像。镜像运行起来,就是一个容器。你在本地开发、在测试环境跑、在服务器上部署,用的都是同一个镜像,那环境几乎就是完全一致的——这一点是虚拟机做不到的,因为虚拟机打包的是整台机器,而Docker打包的是"应用+它需要的运行环境"。
那Docker和虚拟机到底有什么区别?一句话说清:虚拟机虚拟的是硬件层,相当于在家里复制了一整台电脑,所以它重、启动慢、占资源;Docker虚拟的是操作系统内核之上的运行空间,相当于给每个程序安排了一个独立的"房间",但共用同一套"水电系统",所以它轻、启动秒开、资源占用低。同一个物理机上,虚拟机可能只能跑十个,Docker可以跑上百个。
前几年常听到的"一次构建,到处运行",说的大致就是这个逻辑。你构建好镜像之后,不管是Windows、Linux还是macOS,只要有Docker环境,就能把容器跑起来。这个优势在你做自动化部署、微服务拆分、CI/CD流水线的时候会体现得尤其明显——每台机器上不用再手动装一遍依赖,直接pull镜像、run容器,完事。
所以,Docker不只是一个"装软件的软件",它实际上是现代开发和运维之间的一层通用语言。搞懂它,对你后面学容器编排(比如Docker Compose、Kubernetes)、做持续集成、甚至本地搭建开发环境都有帮助。你甚至可以用Docker在本地一键拉起一套MySQL、Redis、Nginx测试环境,比在电脑上手动安装干净十倍。这也是为什么那么多人刚开始学Docker,第一个实践就是用Docker装MySQL。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 安装前先检查这三项,别等启动失败才回头
Docker本身安装并不难,无论是Windows还是Linux,都有对应的安装方式。但我见过太多人在安装完Docker Desktop之后卡在启动阶段,弹出一个红色报错:virtualization support not detected(未检测到虚拟化支持)。然后就开始到处搜解决方法,其实这个问题的根源,绝大多数情况下是安装之前的准备工作没做足。
这里我把安装Windows版Docker之前必查的三项列出来,每一项都值得你花两分钟确认。
2.1 检查CPU虚拟化是否已经开启
Docker Desktop在Windows上默认依赖虚拟化技术来运行Linux容器,所以CPU的虚拟化功能必须在BIOS里开启。检查方法很简单:打开"任务管理器",切到"性能"标签,点击"CPU",看右下角的"虚拟化"一栏。
如果你看到"已启用",那就没问题。如果看到"已禁用",那就需要重启电脑,进入BIOS设置(各品牌主板快捷键不同,常见的是F2、F10、Del键),找到Intel Virtualization Technology(Intel平台)或者SVM Mode(AMD平台),设为Enabled,保存退出重启。
注意,这个检查非常关键。很多人以为Docker Desktop装完双击就能用,结果卡在这第一步。理论上Windows 11强制要求支持虚拟化的CPU,但在Windows 10上很容易遇到没开启的情况,尤其是办公电脑和老笔记本。
2.2 确认Windows系统版本和WSL2状态
Docker Desktop在Windows上有两种运行后端:一种是基于Hyper-V(Windows专业版和企业版内置的虚拟机平台),另一种是基于WSL2(Windows Subsystem for Linux 2,适用于Linux的Windows子系统第二版)。
现在官方默认推荐并且未来趋势是走WSL2路线,因为它启动快、内存占用小、和Docker引擎的集成度更高。但WSL2有一个硬性要求:你的Windows 10必须是2004及以上版本(build 19041及以上),或者Windows 11。如果你的系统版本太旧,最常见的报错就是:We've detected that you have an incompatible version of Windows. Docker Desktop requires Windows 10 version 2004 or later。
检查方式是Win+R输入winver,弹出来的窗口里看你系统的版本号和内部版本号。如果版本低于2004,建议先更新Windows系统,不要想着绕过去,因为WSL2本身也需要新版本内核的支持。当然,如果你用的是Windows 10 1903/1909这种老版本,也可以选择通过启用Hyper-V的方式来跑Docker Desktop,但配置起来更绕,我不太推荐,能用WSL2就用WSL2。
2.3 内存和磁盘余量
Docker Desktop运行起来之后,至少需要4GB以上的可用内存,如果内存只有4GB,建议再加一条,否则Docker容器一多会非常卡。磁盘方面,Docker默认会把镜像存在系统盘(C盘),一个镜像动辄几百MB,MySQL、Redis这类基础镜像加起来随便几个GB就没了。所以如果你C盘空间紧张,强烈建议在安装完成之后把Docker的数据目录迁移到其他盘,这个我在下一节会讲具体操作。
这三项检查大概只需要三分钟,但能帮你省掉后面一个小时甚至半天的排查时间。安装Docker这事的经验就是:前置检查永远是性价比最高的事。
3. Windows安装全程:从WSL2到Docker Desktop,以及D盘安装
现在正式进入安装环节。Windows上安装Docker Desktop,我习惯的顺序是先装好WSL2,再装Docker Desktop,这样可以避免安装过程中Docker Desktop检测不到WSL后报错的情况。整个过程大概分五步。
3.1 启用WSL2功能
以管理员身份打开PowerShell,依次执行下面两条命令:
powershell复制dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart
dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart
第一条命令启用Windows的Linux子系统功能,第二条命令启用虚拟机平台功能——这是WSL2能跑起来的内核支撑。执行完成之后,重启电脑。
重启后,再次以管理员身份打开PowerShell,将WSL的默认版本设置为2:
powershell复制wsl --set-default-version 2
这里有一点值得说一下:如果WSL2的Linux内核没有安装,系统可能提示你"WSL 2 需要更新其内核组件",这时需要去微软官网下载WSL2内核更新包,安装后再执行上面的设置命令。另外,Win10 2004之前的WSL版本可能默认是WSL1,这种情况下可以运行wsl --set-version 2将指定发行版转换为WSL2,不过对Docker Desktop来说,只要默认版本是2就足够了。
如果你不确定WSL是不是真的启用了,运行:
powershell复制wsl --status
看到"默认版本:2"就说明设置生效了。
3.2 下载并安装Docker Desktop
去Docker官网下载Docker Desktop的Windows安装包(搜索"Docker Desktop download"即可找到官方地址),下载的文件一般是Docker Desktop Installer.exe。双击运行下一步下一步就能装完,但有两个细节值得注意。
第一,安装过程中会有一个"Use WSL 2 instead of Hyper-V"的选项,勾选它,这能保证Docker Desktop使用WSL2后端。如果你没勾选,装完再用默认的Hyper-V也能跑,但性能和兼容性体验会差一些。第二,安装完后可能会提示需要注销或重启,照做,不要跳过。
装完之后,桌面会出现Docker Desktop的图标,运行它。首次启动会有一个接受服务协议的界面,点接受,等Docker引擎启动。看到鲸鱼图标稳定下来(不再闪烁),就说明Docker已经可用了。到这一步,一个最基本的Windows Docker环境就搭好了。
3.3 把Docker安装到D盘
很多人不想让Docker占用C盘,这里分两种情况。安装包本身可以通过命令行参数指定安装路径,比如把安装程序和"WSL 2 backend"数据放到D盘,可以在安装时编辑命令:
powershell复制"Docker Desktop Installer.exe" install --installation-dir=D:\Docker --wsl-default-data-root=D:\DockerData
但如果你已经装完了,不想重新装,那还有更简单的方式:Docker Desktop在WSL2模式下,真正的大头数据存在**WSL的虚拟磁盘文件(ext4.vhdx)**里。这个虚拟磁盘通常是C:\Users\你的用户名\AppData\Local\Docker\wsl\data\ext4.vhdx。要把它迁移到D盘,用wsl --export和wsl --import两个命令就能实现。
这个方法我实测下来非常方便,基本可以避免重装Docker。它不只是省了C盘空间,还能避免C盘空间不足导致Docker容器写数据时磁盘告警的问题。如果你装了Docker Desktop之后发现C盘空间告急,可以优先处理这个虚拟磁盘。
3.4 安装Docker Desktop时常见的"启动失败"排查
在前面的检查没做好时,启动Docker Desktop会看到几个典型的报错:
- 提示"virtualization support not detected"——这是BIOS没开虚拟化,回到前文2.1去检查。
- 提示"WSL 2 installation is incomplete"——说明WSL2内核没装好,去查WSL状态,或者重新执行
wsl --update。 - 提示"docker desktop failed to start because virtualisation support wasn't detected"——同第一类,优先检查BIOS虚拟化。
- 提示"FAILED to connect to the docker api at npipe:////./pipe/dockerDesktopLinuxEngine"——通常是Docker引擎没起来,或者WSL后端卡住了。重启Docker Desktop,实在不行就重启电脑,再看
wsl --shutdown后重新启动。
这些坑几乎每个人都踩过一两个。我的建议是,遇到报错先截图,先看报错里有没有"virtualization""WSL""kernel"这几个关键词,然后再决定排查方向。不要盲目卸载重装,反而容易把问题搞复杂。
4. Linux安装:脚本、仓库与组权限的细节
在Linux服务器上装Docker,路径和Windows完全不同。它不涉及Docker Desktop,直接装Docker Engine就行。这里以最常见的Ubuntu和CentOS为例,把安装过程中的关键细节和踩坑点都说清楚。
4.1 Ubuntu安装Docker Engine
我推荐用官方仓库来装,虽然网上有很多一键脚本,但走官方仓库能保证后续apt upgrade时Docker也是跟着系统升级的,减少维护成本。先说步骤,再说为什么。
先卸载可能残留的旧版本:
bash复制sudo apt remove docker docker-engine docker.io containerd runc
然后安装依赖并添加Docker官方GPG密钥:
bash复制sudo apt update
sudo apt install ca-certificates curl gnupg lsb-release
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
接着添加Docker的APT源:
bash复制echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
之后更新索引并安装:
bash复制sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io docker-compose-plugin
其中docker-ce是社区版引擎,docker-compose-plugin是Docker Compose的插件版本,这个后面编排多个容器时会用到。
装完以后,启动服务并设置开机自启:
bash复制sudo systemctl enable docker --now
用sudo docker version验证安装结果。能看到Client和Server两段版本信息,就说明Docker正常了。
4.2 CentOS安装Docker Engine
CentOS 7和8的安装方式类似,但注意CentOS 7需要额外处理内核和iptables的问题。CentOS 8直接走仓库源就行。
bash复制sudo yum remove docker docker-client docker-common docker-selinux docker-engine
sudo yum install -y yum-utils
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
sudo yum install docker-ce docker-ce-cli containerd.io docker-compose-plugin
启动服务同样用:
bash复制sudo systemctl enable docker --now
CentOS 7上有一个典型问题:如果防火墙用的是firewalld,Docker默认的桥接网卡可能和firewalld冲突,导致容器之间网络不通。解决方法是装完Docker之后重启一下防火墙,或者添加--iptables=false到Docker配置里(不推荐,可能会影响端口映射)。最简单有效的办法是:装完Docker重启一次系统,让防火墙服务和Docker的网络链重新初始化,大部分情况下能解决。
4.3 免sudo执行docker命令
默认情况下,普通用户直接执行docker ps会报权限错误:
bash复制permission denied while trying to connect to the Docker daemon socket
这是因为Docker守护进程的socket文件/var/run/docker.sock属于root用户。解决办法是把当前用户加入docker组:
bash复制sudo usermod -aG docker $USER
然后退出当前终端重新登录,或者执行newgrp docker让组权限立即生效。到这里,普通用户就能直接执行docker命令了,不用再敲sudo。
这里也顺带提一句,把用户加入docker组等于赋予了和root等价的能力,因为docker组内的用户可以通过挂载等方式操作宿主机文件。所以在生产环境里慎用这个方案,个人开发机无所谓。
4.4 Linux安装命令"一键脚本"的取舍
网上看到很多一键安装脚本(比如curl -fsSL https://get.docker.com | sh),它们的本质是把上面的步骤全部自动化。我自己的经验是:新机器、脚本来源可信的情况下,用脚本确实省事;但你最好知道脚本往系统里写入了什么。如果是内网离线环境,脚本就无效了,这时候需要下载rpm/deb包离线安装,建议提前在能联网的机器上下载好对应架构的安装包(比如amd64、arm64),拷贝到内网再用dpkg -i或yum localinstall进行安装。
5. 装完必须干的第一件事:配置镜像加速
Docker装好了,Docker命令也能跑了,接下来拉一个镜像试试吧。然后你会被现实狠狠教育一顿——默认情况下Docker会从Docker Hub拉镜像,在国内网络环境下,那个速度慢得让人想砸电脑。
这不是你网络不行,而是Docker Hub的官方镜像仓库服务在国外,需要走跨境的网络链路,下载速度自然很慢。而且Docker拉镜像时还会对镜像层做校验,网络一不稳定就容易中断重试。解决方案很简单:配置一个国内的镜像加速器,让Docker从离你更近的镜像源拉取。
5.1 给Docker Desktop配置镜像加速
在Windows上,打开Docker Desktop,进入Settings(设置),找到Docker Engine标签页。在JSON配置中添加registry-mirrors字段:
json复制{
"registry-mirrors": [
"https://docker.mirrors.ustc.edu.cn",
"https://hub-mirror.c.163.com",
"https://mirror.baidubce.com"
]
}
点击"Apply & Restart"按钮,Docker Desktop会自动重启并应用新配置。我用的是几个常见的公共镜像加速地址,不同网络环境下的速度可能不一样,你可以都加上,Docker会按顺序尝试。
5.2 Linux配置镜像加速
在Linux上,需要手动编辑Docker的配置文件。Docker守护进程默认读取/etc/docker/daemon.json:
bash复制sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": [
"https://docker.mirrors.ustc.edu.cn",
"https://hub-mirror.c.163.com",
"https://mirror.baidubce.com"
]
}
EOF
然后重启Docker服务:
bash复制sudo systemctl daemon-reload
sudo systemctl restart docker
配置完成后,用docker info查看Registry Mirrors一栏,如果列出了你配置的镜像地址,就说明加速器已经生效。
老有人问我,为什么配置完还要systemctl daemon-reload?因为daemon.json是systemd管理的Docker服务的配置文件,你不重载systemd,Docker进程不会知道配置文件变了。这个细节容易忽略,但忘了就白配置了。
5.3 加速器的原理和选择建议
镜像加速的本质是,Docker在你配置的镜像源服务器上缓存了一份Docker Hub的镜像副本,拉取时直接从这份缓存下载。所以"加速器地址是否可靠"完全取决于维护者是否在稳定更新缓存,这也是为什么有些加速地址过一段时间就失效了。我自己用的原则是:同时配置两三个加速地址,失效一个还能用另一个,挑网速好的那个留着,其余删掉。
这个配置对后面所有镜像拉取都生效,尤其像MySQL、Redis这类大镜像,没加速之前等了半小时都拉不下来,配好之后一分钟内就能搞定,这体验上的差别非常明显。
6. 验证安装与常用命令:从hello-world到日常操作
环境准备好了,加速也配了,接下来自然是验证Docker是不是真的能正常干活。这一步对新手来说也是一个建立信心的过程——看到"Hello from Docker!"的时候,你才算真正跨进了容器世界的大门。
6.1 跑通第一个容器:hello-world
执行:
bash复制docker run hello-world
这条命令做了几件事:先去本地找名为hello-world的镜像,找不到就去Docker Hub拉取镜像,然后创建并运行一个容器,容器执行完输出一段欢迎信息后退出。当你看到类似Hello from Docker!的输出时,说明Docker的客户端、服务端、镜像拉取、容器运行整条链路全部正常。
如果你看到的报错是"Unable to find image",并且卡了很久,大概率是镜像加速没生效,回去看看上一节。
6.2 最常用的Docker命令组
基础验证通过之后,你有必要上手这几组最常用的命令,它们覆盖了日常90%以上的操作场景。
镜像操作:
bash复制docker images # 查看本地镜像列表
docker pull nginx:latest # 拉取指定镜像
docker rmi nginx:latest # 删除镜像
docker tag nginx:latest my-nginx:v1 # 给镜像打标签
容器操作:
bash复制docker ps # 查看运行中的容器
docker ps -a # 查看所有容器(包括已停止的)
docker run -d --name web -p 8080:80 nginx # 后台运行容器并做端口映射
docker stop web # 停止容器
docker start web # 启动已停止的容器
docker restart web # 重启容器
docker rm web # 删除容器
docker exec -it web bash # 进入容器内部,执行交互式命令
docker logs -f web # 实时查看容器日志
docker exec -it 是一个高频命令,你需要进入容器内部查看文件、执行命令时就靠它。-it的含义是交互式加伪终端,不加的话很多命令执行不了。这个细节我在身边见过很多人栽跟头,明明进入了容器却感觉"没反应",多半是忘了-it参数。
清理命令:
bash复制docker system df # 查看磁盘占用
docker system prune # 清理停止的容器、无用的网络、悬空镜像
docker system prune -a # 连没用的镜像一起清理(慎用)
6.3 Docker run的关键参数说明
docker run的参数非常丰富,但新手只需要先掌握几个核心的:
| 参数 | 作用 | 示例 |
|---|---|---|
-d |
后台运行容器 | docker run -d nginx |
--name |
给容器命名 | --name web |
-p |
端口映射,宿主机端口:容器端口 | -p 8080:80 |
-v |
目录挂载,宿主机目录:容器目录 | -v /data:/var/lib/mysql |
-e |
设置环境变量 | -e MYSQL_ROOT_PASSWORD=123456 |
--rm |
容器退出后自动删除 | --rm(适合测试场景) |
--network |
指定网络模式 | --network my-net |
这其中的逻辑是:容器是隔离环境,宿主机访问不到容器内部的服务,所以需要通过-p做端口映射;容器内部产生的数据在容器删除后会消失,所以需要通过-v把数据挂载到宿主机磁盘上。理解了这两个点,你对Docker的运行模型就有了最基本的感知。
7. 第一个正式实战:把MySQL 8.0跑起来
学到现在,你已经具备了用Docker跑一个真实服务的能力。很多人安装Docker的第一个实战目标就是MySQL,这里给出一个完整的命令和详细解释,这一节结束你就等于把Docker的核心闭环走了一遍。
7.1 拉取并运行MySQL容器
先确保镜像加速已经配置好,然后直接拉取MySQL 8.0镜像:
bash复制docker pull mysql:8.0
接着运行容器:
bash复制docker run -d \
--name mysql8 \
-p 3306:3306 \
-e MYSQL_ROOT_PASSWORD=yourpassword \
-v /myapp/mysql-data:/var/lib/mysql \
mysql:8.0
解释一下这条命令背后的思路。-d表示后台运行,--name mysql8是给容器起名叫mysql8。-p 3306:3306把宿主机的3306端口映射到容器的3306端口,这样你本机任何MySQL客户端连localhost:3306就能访问容器里的数据库。
-e MYSQL_ROOT_PASSWORD=yourpassword是MySQL官方镜像要求必须设置的环境变量,它会在容器首次启动时初始化root用户的密码。这个环节有一个很容易踩的坑:如果你不设置这个变量,MySQL容器会启动失败,日志里会告诉你需要指定root密码。另外,如果你在运行之前就手动创建过数据目录,MySQL会认为已经初始化过,就不再读取这个环境变量,此时密码是空的——所以最好不要在一个已存在数据的目录上重新初始化。
-v /myapp/mysql-data:/var/lib/mysql是把容器内的MySQL数据目录挂载到宿主机的/myapp/mysql-data。这一步非常关键,容器删除后数据库的数据保留在宿主机磁盘上,不会跟着容器一起消失。这是生产环境使用Docker数据库的底线要求。
7.2 验证MySQL是否正常运行
运行一段时间后,用docker ps查看容器状态,应该能看到UP状态。如果容器反复重启,用docker logs mysql8看日志,这是排查容器问题的第一入口。
确认容器运行正常后,用docker exec进入容器内部,用MySQL客户端连接本地数据库:
bash复制docker exec -it mysql8 mysql -uroot -p
输入密码后如果看到mysql>提示符,说明MySQL整个链路已经通了。这时候你可以顺便验证一下端口映射:在你自己的电脑上用任意数据库图形客户端(比如Navicat)连接127.0.0.1:3306,用户名root,密码为上面设置的密码,如果能连上就说明一切正常。
7.3 为什么要用Docker跑MySQL而不是直接安装
用Docker跑MySQL,最大的优势是环境干净、卸载也干净。直接安装MySQL,它会往系统里写一堆配置文件、服务注册、数据目录,卸载时还会残留。用Docker的话,删容器、删镜像、删数据目录,三行命令搞定,不留痕迹。对于开发环境的快速搭建和多个项目的版本隔离,这个优势是非常实用的。
更进一步,如果你想搭Redis主从、或者其他中间件的集群,Docker的编排能力会强得多。热搜词里那个"docker安装redis主从",本质上就是用Docker在一台机器上快速跑出多个Redis实例,然后配置主从关系。这类操作在传统方式下要把宿主机环境折腾一遍,在Docker里就是几条命令的事。
7.4 我建议你继续做的两件事
这一步跑通MySQL之后,继续往下走有两个方向。
一是学习Dockerfile,把你的应用代码打成自己的镜像。这需要先写一个Dockerfile文件,里面写清楚基础镜像、复制哪些文件、执行什么命令,然后用docker build构建。这是Docker的核心能力,因为它决定了你能不能把你的服务和依赖完整地交付出去。
二是学习Docker Compose,用一份YAML文件同时定义多个容器。比如一个web应用,需要MySQL、Redis、Nginx三个容器配合,用Compose一个docker compose up -d就全起起来了。Compose目前已经是Docker官方的标准插件,不再是独立安装的工具,学习成本也不高。
我自己的体会是:Docker的学习曲线其实并不陡,最难的不是命令,而是转变思路——从"在系统上安装软件"到"在容器里运行服务"的思维切换。一旦你理解了镜像、容器、数据卷这三个核心概念之间的关系,后面所有东西都是顺水推舟。先去把安装这一步走通,然后亲手跑一个MySQL,你对Docker的整个运作机制就有了实感。剩下的,就是多实际操练、多踩几次坑,自然会越来越熟练。
