资讯动态

Docker入门第一课:容器化部署、镜像与数据持久化实战

发布时间:2026/10/20 8:37:07 来源:尧图企业网站定制
从“在我电脑上是好的”这句名言说起吧。干开发这些年我见过太多应用部署时炸得一塌糊涂的场景代码在开发环境跑得好好的到了测试环境就开始闹脾气到了生产环境直接罢工。排查到最后通常就是那么一句——环境不一样。版本差一点、依赖缺一个、系统库版本对不上问题就冒出来了。Docker就是来解决这件事的它是目前把“应用运行环境”打包交付最成熟的方案没有之一。这篇内容对应的是Docker学习的第一课时适合刚接触容器、在虚拟机和管理服务器之间反复折腾、被环境问题搞到头大的开发者。不需要你有任何容器基础只要能在命令行里敲几条命令就行。我会尽量把原理讲明白把每一步的命令解释清楚也把我自己早期踩过的坑一并交代了。读完你应该能独立完成Docker的安装、镜像拉取、容器启停、端口映射和数据持久化并且对镜像、容器、仓库这三个核心概念建立起正确的心智模型。1. Docker到底解决什么问题从“环境地狱”到标准化交付1.1 环境不一致的经典场景先还原一个几乎人人都遇到过的场景。你写了一个Python服务本地Python 3.11依赖全装好跑起来一切正常。交付给同事的时候他机器上是Python 3.7某个第三方库的新语法在老版本上直接报错或者他的系统自带OpenSSL版本偏老加密相关的接口全部抛异常。这种时候你会怎么做折腾半天装依赖、升级系统库最后源代码没改一行时间全耗在环境上面。往大了说从开发到测试再到生产每一层的操作系统、运行时、依赖库、配置文件都存在差异。传统部署方式里环境一致性是靠运维人员手工保证的是人就会出错一出错就是事故。Docker的思路从根本上改变了这件事把应用和它依赖的完整运行环境一起打包成一个镜像这个镜像在哪儿跑行为都是一样的。1.2 Docker是怎么解决环境问题的Docker利用Linux内核的命名空间和控制组特性实现了进程级别的隔离。命名空间让容器里的进程拥有自己独立的视图像是独立的文件系统、独立的网络栈、独立的进程树控制组则负责限制容器能使用的CPU、内存等资源。你可以把容器想象成一台台迷你电脑它们共享宿主机的操作系统内核但彼此看不见对方内部的东西。换个更通俗的说法虚拟机是把一整个操作系统完整地虚拟出来所以体积大、启动慢通常要按分钟算容器则只是把宿主机的内核当作底座在上面叠加一层精简的用户态运行环境所以镜像体积小、启动快往往秒级完成。这也是为什么现在很少有人在生产环境为了跑一个应用专门开一台虚拟机了——资源浪费太严重。1.3 学Docker之前先建立的两个认知第一个认知是镜像一旦构建内容就不再变化。你可以把镜像理解成一张光盘内容压制好了就是只读的不能直接在原盘上改。想改怎么办基于它创建容器去里面改改完再提交成新镜像。这保证了同一个镜像跑出来的容器初始状态绝对一致。第二个认知是容器本身是临时的。容器在运行过程中产生的所有文件变更默认都保存在容器那层可写层里。一旦容器被删除这些变更全部消失。这不一定是缺陷反而是一种特性你随时可以从镜像重新起一个全新的容器恢复初始状态这给自动化运维带来了极大的便利。但这也意味着你真正需要保留的数据必须通过挂载卷的方式放到宿主机上这个后面会细说。2. 镜像、容器、仓库课时1必须搞清的三个核心概念2.1 镜像Image只读模板镜像是一个只读的、分层结构的文件系统快照里面包含了运行应用所需的全部内容基础操作系统层、代码、运行时、依赖库、环境变量和默认命令。这里最关键的概念是分层存储。Docker镜像由多层组成每一层都是前一层之上的一个增量修改。比如你基于Ubuntu镜像装了一个Python运行时这就新增了一层接着往里拷代码又是新的一层。拉取镜像时Docker会识别本地已有的层只下载缺少的层这就是为什么你只下载过一次基础镜像、后面基于它构建新镜像时会很快的原因。这种分层设计不只是省流量更重要的是层可以复用。十个不同的应用都在同一个基础镜像上构建宿主机只需要保存一份基础镜像的物理数据。Docker通过写时复制策略将只读层共享给所有容器使用极大节省了磁盘空间。2.2 容器Container镜像的运行时实例容器是镜像运行起来之后的实例。镜像本身是静态的磁盘文件容器则是一个正在运行、拥有自己文件系统和进程空间的动态实体。运行容器的时候Docker在镜像的只读层之上追加了一个可写层应用的所有写入操作都在这个可写层进行。把镜像和容器的关系类比成程序和进程就很贴切程序是保存在磁盘上的静态文件进程是程序加载到内存后运行起来的实例镜像就是这个静态的“程序安装包”容器就是“正在运行的程序实例”。一个镜像可以同时启动多个容器实例彼此互不干扰各跑各的。你也可以随时删除某个容器再重新创建只要镜像还在。2.3 仓库Registry镜像的分布渠道仓库专门用来存储和分发镜像。最常用的是Docker官方的Docker Hub此外还有各大云厂商提供的加速器或私有仓库。镜像的完整名称通常由仓库地址、镜像名和标签三部分组成比如nginx:1.25nginx是镜像名1.25是标签省略地址时默认是从Docker Hub拉取。这里有一个容易混淆的地方仓库Registry和仓库内的镜像Repository在英文里是同一个词根但在具体操作中主要关注两条命令就够了push把本地镜像推到远端仓库pull把远端镜像拉到本地。对于初学者完全可以先把仓库理解成一个镜像的“网盘”先用好pull等自己会构建镜像了再研究push。3. 环境准备与安装在Windows、macOS和Linux上跑起第一个容器3.1 Windows与macOS安装要点Windows平台要求系统必须支持并开启硬件虚拟化Win 10 64位家庭版及以上版本基本都能满足。安装流程其实被官方大大简化了下载Docker Desktop安装包双击安装全程默认配置即可。安装完成后首次启动Docker Desktop会提示你启用WSL 2后端建议选“是”。WSL 2是Docker在Windows上运行时强烈推荐的引擎它的内存占用和启动速度都要优于传统虚拟化方案。早期版的Docker Desktop直接跑Hyper-V虚拟机那个内存占用简直是灾难现在默认的WSL 2方案收敛了很多。安装WSL 2需要两步先在PowerShell管理员模式下执行wsl --install重启后再在Docker Desktop里开启集成选项。macOS的流程几乎一样下载Docker Desktop的dmg文件安装即可Apple Silicon芯片的机器记得下载对应芯片架构的安装包。3.2 Linux安装与加速配置Linux上没有桌面版直接在命令行用包管理器安装。以Ubuntu系为例官方推荐的流程是添加Docker官方软件源然后安装docker-ce、docker-ce-cli和containerd.io这三个包。安装完成后把当前用户加入docker组sudo usermod -aG docker $USER然后退出当前终端重新登录之后运行docker命令就不需要加sudo了。这一步经常被新手跳过结果每次执行docker命令都要加sudo不但麻烦还可能因为权限问题导致一些连接docker引擎的操作失败。Linux下更关键的一步是配置镜像加速器。国内直连Docker官方仓库经常面临拉取超时或者速度极慢的问题我最早用Docker的时候拉一个Ubuntu镜像能卡十几分钟最后直接超时。解决方案是编辑/etc/docker/daemon.json填入你自己申请到的加速地址{ registry-mirrors: [https://你的加速器地址] }配置完成后重启Docker服务sudo systemctl daemon-reload sudo systemctl restart docker3.3 验证安装hello-world背后发生了什么安装完成后运行一条最经典的命令来验证docker run hello-world这条命令会让Docker在本机镜像缓存里找hello-world找不到就去Docker Hub拉取拉取成功后创建容器并运行。容器启动后输出一段欢迎信息就退出了。如果这段欢迎信息正常打印出来说明你的安装是通的。很多人第一次跑这条命令只记住了“安装成功”却没意识到Docker完成了一整套“拉镜像-建容器-跑命令-退出”的完整链路。你可以把这套机制想象成你去餐厅点了一份套餐后厨从柜子里拿出标准化的预制菜加热端上桌吃完走人桌上恢复原样。这份预制菜就是镜像加热上桌就是你平时启动容器做的事情吃完走人则是容器停止。这个基本流程就是之后所有Docker操作的地基。4. 核心生命周期操作跑、停、查、删的完整闭环4.1 拉取镜像先建立镜像缓存池再从池子里取镜像运行。拉取镜像是日常最高频的操作之一docker pull nginx:1.25 docker pull python:3.11-slim docker pull ubuntu:22.04关于tag选择我诚恳地建议生产环境必须写具体版本号绝不可以用latest否则某一天基础镜像上游更新了你的应用会因为环境变化出现莫名其妙的问题。我自己的一个早期线上事故就是latest标签导致的上游镜像更新了一个小版本某个底层库的行为发生了变化服务第二天开始随机报错排查了整整一下午。4.2 创建并启动容器最基本的运行命令docker run -d --name my-nginx -p 8080:80 nginx:1.25逐段拆解一下-d后台运行容器终端不会被占住--name my-nginx给容器命名后续管理时不需要记住容器ID-p 8080:80端口映射。宿主机8080端口收到的流量转发到容器的80端口80是nginx在容器内默认监听的端口nginx:1.25镜像名和标签运行后用docker ps查看看到my-nginx的状态是Up说明容器正在运行。浏览器访问http://localhost:8080就能看到nginx的欢迎页面。这里有个非常实用的知识点docker run是“创建并启动”的合并操作。如果容器已经存在就不能再用run而应该用docker start。run、start、restart这三个命令对应着“新建并运行”“启动已存在的停止容器”“重启”它们的行为不一样一开始很容易混。4.3 查看、停止、删除日常巡检和执行操作的高频命令docker ps # 只显示正在运行的容器 docker ps -a # 显示所有容器包括已停止的 docker stop my-nginx # 停止容器相当于给进程发停止信号 docker start my-nginx # 启动已停止的容器 docker restart my-nginx # 重启容器 docker rm my-nginx # 删除容器删除镜像用的是另一个命令docker rmi nginx:1.25这里有一个初学者经常困惑的问题docker rm删的是容器docker rmi删的是镜像。两个命令差一个字母作用完全不同。删镜像前要保证没有正在运行的容器还在使用它否则会报错。还有一个更彻底的大扫除命令docker system prune它会清理掉所有已停止的容器、未被使用的网络和悬空镜像。加了-a参数还会把没有被任何容器引用的镜像一并清掉磁盘空间瞬间释放不少。不过这条命令要谨慎使用它会确认删除一堆东西在共享机器上别随便执行。4.4 exec进入容器第一次在容器里执行命令容器虽然是隔离的但可以通过exec进入其中执行命令这是调试和实际操作的必备手段docker exec -it my-nginx bash执行后你就进入了容器的交互式Shell。在容器里随便执行ls、cat /etc/nginx/nginx.conf看看内容。想退出就执行exit。-it这两个参数是有讲究的-i保持标准输入打开让命令可以接收你的键盘输入-t分配一个伪终端让输出正常显示。两者组合在一起才能获得一个可以正常交互的终端体验。不交互地执行单条命令也行docker exec my-nginx nginx -v这条命令把nginx -v直接传进容器执行输出nginx版本信息后就结束。这种一次性命令在自动化脚本里非常有用。5. 端口映射与数据持久化让容器真正“能用”起来5.1 端口映射-p参数的完整理解默认情况下容器有自己独立的网络宿主机访问不到容器里的服务。要让外部能访问到容器内进程必须做端口映射。-p 8080:80的本质是宿主机上的一个小程序监听8080端口收到请求后转发给容器内的80端口。这种转发带来的一个直接好处是可以在同一台机器上跑多个同一镜像的容器实例端口错开就行了docker run -d --name web-1 -p 8081:80 nginx:1.25 docker run -d --name web-2 -p 8082:80 nginx:1.25修改宿主机端口时要注意别和其他服务冲突建议执行netstat -tlnp先查一下端口占用情况。另外-p支持多个像-p 8080:80 -p 8443:443这种写法同时映射HTTP和HTTPS端口。5.2 数据卷-v参数与容器数据的持久化前面说过容器默认是临时的删了就什么都没了。解决这个问题的方法是使用数据卷Volume把宿主机上指定的目录挂载到容器内部指定目录这样容器内的写入操作会直接落在宿主机上。举个例子docker run -d --name my-nginx -p 8080:80 \ -v /home/me/nginx-html:/usr/share/nginx/html \ nginx:1.25宿主机上/home/me/nginx-html目录里的文件就是nginx容器/usr/share/nginx/html目录下能看到的文件。直接编辑宿主机里的文件刷新浏览器就能看到效果再也不用进容器里改文件了。这个机制理解起来可以类比成容器是一台临时工位的电脑数据卷则是那个跟工位无关的外接移动硬盘。不管电脑换几台硬盘里的数据一直在。5.3 环境变量-e参数的最简用法很多镜像在启动时会读取环境变量来决定运行行为。以运行一个最简单的MySQL为例docker run -d --name my-mysql \ -e MYSQL_ROOT_PASSWORDmy-secret-pw \ -p 3306:3306 \ mysql:8.0启动MySQL镜像时你必须在环境变量里指定root密码否则容器会创建失败。-e参数就是把环境变量传入容器内部容器内进程就能读取到。环境变量提供了一种很方便的配置方式避免反复修改配置文件。实际项目中还有个常用技巧把环境变量写入文件用--env-file参数整体加载方便管理多个配置项。6. 课时1最容易踩的四个坑与自检清单6.1 坑一Windows下Docker Desktop启动失败排查思路是先看系统是否开启了虚拟化功能。打开任务管理器性能标签页里能看到“虚拟化”一项是否显示“已启用”。如果没启用需要进BIOS打开Intel VT-x或AMD-V。另一个常见原因是WSL 2没有正确安装可以在PowerShell里执行wsl --status查看状态。这类问题最常见的根源就是系统组件缺失而不是Docker本身坏了。6.2 坑二docker pull超时或速度极慢这个在国内环境几乎必现。解决办法就是前面说的配置镜像加速器。注意daemon.json改完之后要重启docker服务才会生效。如果配置了加速还是慢换一个地址试试。大型镜像也可以在深夜网络空闲时段拉取实测下来的确快不少。6.3 坑三容器退出后数据没了经常有人问我“我跑了个Redis存了测试数据容器删了重新创建后数据全没了Redis是不是不支持持久化”问题不在Redis而是默认容器就是个临时环境。解决方法是启动时挂载数据卷把数据目录映射到宿主机上。Redis这类应用要在容器启动前就规划好数据卷等数据丢了再想起来就晚了。6.4 坑四镜像体积越积越大镜像、容器、构建缓存会一点一点蚕食磁盘空间。有个简单办法定时清理不用的资源docker system df这条命令能直观看到镜像、容器、数据卷分别占了多少磁盘。占用异常时用docker system prune -a大扫除一把。删除单个容器时用docker rm -f可以强制删除正在运行的容器省去先stop再rm的步骤但别养成习惯生产环境还是要按流程来。6.5 课时1自检清单你可以用这份清单测试一下这课时有没有真正吃透能否解释镜像和容器的关系以及为什么同样的镜像可以启动多个不同状态的服务能否解释docker run -d -p 8080:80 --name web nginx这条命令里每个参数的含义容器删除后数据去哪里了用什么手段可以让数据保留在宿主机上docker rm和docker rmi各自的作用是什么容器启动后如果报错了用什么命令查看日志和排查问题排查问题这一步很重要具体命令是docker logs my-nginx它会输出容器内部主进程的日志。大多数容器把自己运行时的状态都写在标准输出里看日志是定位问题的第一选择。课程内容到这里基本结束了。结合我自己的学习路线给一条建议不要急着深挖网络模式、Docker Compose和镜像构建先把docker run用熟把镜像、容器、卷这三大模块的概念彻底搞透。这些是容器世界的地基地基稳了后面学Compose编排、K8s集群时你会觉得一切都是自然而然的。我自己当时花了大概一周时间反复练习这些基础命令每天把同一个服务部署三五个变体在不同端口上跑、挂载不同的目录、注入不同的环境变量练完这些之后再看高级特性理解速度明显加快。建议你也准备一台虚拟机或云服务器动手练一遍比看什么都管用。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑