☰
Docker入门第一课:镜像、容器、基础命令与数据持久化要点
2026/10/20 8:36:49 网站建设 项目流程

咱们直接说正事。这套课的第一节“Docker基础知识(课时1)”,讲的就是你第一次接触容器技术时,最该搞明白的那几件事:Docker到底解决了什么问题、镜像和容器是什么关系、常用的基础命令怎么用、有哪些坑会反复踩到。不扯Kubernetes,不聊Swarm,也不讲网络编排,把最基础的底子打牢。

我见过不少刚接触容器的人,第一天就跑去背命令,结果连“镜像”和“容器”的区别都说不清楚,遇到报错更是全靠百度。这一篇我就把第一节课的内容掰开揉碎,按我实际讲课和带新人的顺序来写。不管你是学生、转行的,还是项目里被迫接手运维工作的开发,这篇内容都能直接用。

1. 先搞懂Docker到底在解决什么问题

很多人一上来就学命令,学到一半才发现自己压根不知道为什么要这么搞。所以第一课,我习惯先花大量时间讲“它解决什么问题”,再碰命令。

1.1 从“环境地狱”说起

先说一个你再熟悉不过的场景:代码在自己电脑上跑得好好的,提交到服务器上就跑不起来了。检查半天,发现服务器上的Python版本不对、缺少某个动态库、环境变量没配好、配置文件路径不一样。

以前我们怎么解决?要么写一堆安装文档,让别人照着一步步配环境;要么用虚拟机,把整个操作系统一起打包带走。但这些方案都有老大难的问题:安装文档永远跟不上环境变化,步骤漏一步就全废;虚拟机倒是环境一致,可一个镜像动辄几个GB甚至十几个GB,启动还慢,运维成本高得离谱。

我举个例子,一个做Java开发的朋友跟我说,他每次部署新环境都要花一整天装依赖、调配置。后来项目组引入Docker,把这些步骤全部固化到镜像里,部署时间从一天缩到几分钟。这种体验的差别,用过的都知道。

1.2 Docker是拿什么思路解决的

Docker的核心思路不复杂,一句话:把应用连同它的运行环境一起打包成一个标准化的交付单元。

什么意思?你做Web开发时用过依赖管理工具吧。Node项目用package.json记录依赖版本,Python用requirements.txt。Docker把这种“依赖锁定”的思路从代码层面扩展到了操作系统层面。它把代码、运行时、系统库、配置全部打包进一个东西里,这个东西就是镜像。你在自己电脑上能跑,换一台机器也一样能跑,因为运行环境全在里面,跟宿主机没啥关系了。

再对比一下虚拟机和Docker容器的差别。虚拟机是虚拟出一整套硬件,然后在上面运行一个完整的操作系统;Docker容器则直接复用宿主机内核,只把应用需要的用户空间文件打包进去。所以Docker镜像体积小得多,启动速度也快得多。同样一台机器,虚拟机可能只跑三五个实例,Docker容器跑几十个都很正常。

这里需要说明一点,Docker容器不完全等同于虚拟机,它做不到虚拟机那么彻底的隔离。同一台宿主机上的容器共享内核,如果内核出问题,所有容器都会受影响。但在绝大多数应用场景下,这种隔离程度已经完全够用了。第一课先把“容器比虚拟机轻量、便携”这个认知建立起来,后面学网络、存储时再逐步加深理解。

1.3 镜像、容器、仓库:一次搞清这三个概念

第一节课最容易卡住的概念,就是镜像和容器的关系。我打个比方:镜像就像程序里的类定义,容器就是根据这个类实例化出来的对象。也可以理解成镜像是“菜谱”,容器是“按菜谱做出来的菜”。你可以用同一份菜谱做无数盘菜,每盘菜有各自的调味、形态,但它们遵循相同的做法。

镜像本身是只读的,里面装好了应用代码、运行时环境、依赖库。当你用docker run启动镜像时,Docker会在镜像之上加一层可写层,运行中的文件修改都发生在这一层。这一层加上镜像一起运行起来的东西,就是容器。

仓库则负责存储和分发镜像。你从仓库拉取别人的镜像,也可以把自己做的镜像推到仓库分享给别人。第一个阶段只要知道docker pull是从仓库拉镜像,docker push是推镜像就够了。

我见过有人问“为什么容器停掉再启动,之前改的文件都没了”。理解了上面的机制就不奇怪了:容器里的可写层随着容器生命周期走,容器删除后这层就没了。解决办法是挂载数据卷,这在后面会专门讲。

2. 环境准备和安装验证

先把Docker装好,否则后面的命令都跑不起来。这一节我按主流平台说一下安装要点和验证方法。

2.1 不同平台的安装方式

Linux平台,特别是服务器环境,最常用的方式是用包管理器直接安装。以Debian/Ubuntu系为例,一般步骤是更新索引、安装依赖、添加官方源、再安装docker-ce。用yum或dnf的CentOS/Rocky系思路也差不多。具体命令我会在后面演示,但原则就一条:用发行版官方源的Docker版本,不要图省事直接从网上复制一段来历不明的脚本。

macOS和Windows桌面用户,官方推荐Docker Desktop。这东西内置了图形界面,能看到镜像列表、容器列表、日志,还支持一键启动、停止。Windows用户注意后台类型是WSL2还是Hyper-V,优先用WSL2,资源占用更小。需要注意Docker Desktop对商业公司有收费要求,个人学习和开源项目使用不受影响,但如果你所在团队是正规商业公司,记得先查清楚授权。

还有一种常见情况:某些服务器是离线内网环境,不能直接访问外网。这时候就需要手动下载对应系统的安装包传到内网安装。Debian系用的是 .deb 包,RHEL系用 .rpm 包,下载时务必选对CPU架构,x86_64和ARM64的包不能混用,否则后面启动服务会报错。

2.2 验证安装:hello-world 到底干了什么

装完后在终端输入 docker version,能正常显示Client和Server信息,说明Docker服务已经跑起来了。然后执行那个最经典的验证命令:

docker run hello-world

很多新手搞不懂,这条命令到底发生了什么。简单说,Docker会先看本地有没有hello-world这个镜像,没有就去仓库拉取,拉下来后放到容器里执行。容器跑完一段欢迎语后退出,任务完成。

我第一次跑这条命令时其实很懵,因为什么都没看懂。后来我建议新手把这条命令拆开来看:docker run是“启动容器”的命令,hello-world是镜像名。Docker自动完成了“本地找不到镜像→从仓库拉取→创建容器→执行→退出”的完整流程。这一条命令背后涉及的知识点,就是镜像、仓库、容器三者的协作关系,跟你后面掌握所有命令都有关。

2.3 配置镜像加速:提升拉取速度的关键一步

安装完Docker,第一个让人头大的问题就是拉镜像慢。特别是访问Docker官方仓库(Docker Hub),速度经常让人怀疑人生。

解决办法是配置镜像加速器。国内有很多团队维护公共的镜像加速地址,不需要注册就能用。具体做法是编辑Docker的daemon.json配置文件,把加速地址加进registry-mirrors字段,然后重启Docker服务。

sudo mkdir -p /etc/docker sudo tee /etc/docker/daemon.json <<-'EOF' { "registry-mirrors": ["https://你的加速地址"] } EOF sudo systemctl daemon-reload sudo systemctl restart docker

配置完可以用 docker info 查看 Registry Mirrors 一栏是否生效。注意加速地址是第三方维护的,时效性不稳定,如果某天突然发现某个地址拉不动了,及时换其他可用地址。另外如果拉取的是比较小众的镜像,加速源里没有缓存,反而可能更慢,这时可以临时去掉加速配置,直接从官方仓库拉。

3. 镜像和容器的生命周期管理

这是第一课的实操重点。我会按“拿镜像→看镜像→跑容器→管容器→清理容器”的顺序讲,顺便把那些文档里写得比较绕的命令统一解释一遍。

3.1 拿镜像与查镜像

从仓库拉取镜像,用docker pull。比如拉一个Nginx的轻量版本:

docker pull nginx:alpine

nginx是镜像名,alpine是标签。标签用于区分同一个镜像的不同版本,常用的有latest、alpine、slim等。alpine标签表示基于Alpine Linux构建,体积小,适合做基础镜像;latest则不一定是最新版,可能只是该仓库默认指向的标签。

看完本地有哪些镜像,用:

docker images

它会列出仓库名、标签、镜像ID、创建时间和大小。镜像是分层的,所以你会看到部分镜像共享中间层,导致docker images显示的总大小比实际占用磁盘空间大。这点在清理空间时会遇到,后面我再细说。

想查看镜像的详细信息,可以用 docker inspect 镜像名。返回的是一个很长的JSON,里面包含环境变量、端口暴露、挂载点、架构等各种信息。第一课不需要全看懂,只要知道有这么个查看入口就行了。

3.2 启动和管理容器

跑一个容器最基础的命令是:

docker run --name web-demo -d -p 8080:80 nginx:alpine

拆开看各参数含义:--name给容器命名,不指定就随机生成;-d表示后台运行;-p 8080:80是把宿主机的8080端口映射到容器的80端口,这样外部访问宿主机的 http://localhost:8080 就等于访问容器里Nginx的80端口。最后是镜像名。

跑起来后,用 docker ps 看正在运行的容器,加 -a 参数能看到所有容器,包括已经退出的。docker logs 容器名或ID可以看日志,这对排查应用问题非常关键。想进到容器内部看现场,用:

docker exec -it web-demo bash

这里-it是两个参数组合:-i保持标准输入打开,-t分配一个伪终端。合起来的含义就是“以交互方式进入容器内部”。很多第一次接触的人忘了加-it,结果发现按什么都没反应,不是命令错了,而是缺了这两个参数。

停止容器用 docker stop 容器名,启动已停止的容器用 docker start 容器名。注意start和run的区别:run是从镜像新建容器,start是启动现有容器。删除容器用 docker rm 容器名,删除前最好先stop,否则会提示冲突;可以用 docker rm -f 强制删除运行中的容器。

有个细节值得强调:容器是临时性的。你创建一个容器,在里面改了配置文件,如果把这个容器删了,所有改动就都没了。所以第一课就要养成习惯:容器应该被当作一次性进程来看待,持久的数据要放在数据卷里,不要存在容器的可写层里。

3.3 从容器生成镜像:commit 与 Dockerfile 初识

把容器改完之后,如果想保存当前状态做成新镜像,可以用:

docker commit web-demo mynginx:v1

这个命令会把容器当前文件系统保存成新镜像。不过在真实项目中,commit方式强烈不推荐。原因很简单:commit会让镜像层变得极其杂乱,还容易把容器内的临时文件、历史操作痕迹都固化进去,别人拿到这种镜像根本不知道它是怎么构建出来的,也没法复现。

生产环境里构建镜像要用Dockerfile。第一课只需要看懂最基本的形式,比如:

FROM nginx:alpine COPY index.html /usr/share/nginx/html/index.html EXPOSE 80

FROM定基础镜像,COPY把本机文件复制进镜像,EXPOSE声明容器对外端口。在项目目录下放好一个index.html,用 docker build -t my-nginx:v1 . 就能构建出镜像。这里最后的点表示构建上下文路径,Docker打包时会把这个目录下的文件都发给Docker守护进程,所以不要把没用的文件放在构建目录里。学到这里就够了,详细的Dockerfile指令后面专门开课讲。

4. 数据持久化和端口映射

容器本身隔离性很强,但这也带来了两个问题:数据容易丢,外部访问麻烦。第一课必须把这两个基础操作搞明白。

4.1 为什么容器里的数据会“丢”

前面说过,容器文件系统在容器删除后就没了。你可能跑了几个星期的服务,写了不少日志或业务数据,一不小心执行了 docker rm,瞬间全部清空。而且容器报错退出后,docker logs还在,但容器里的文件不会保留,想找现场都找不到。

这个“丢”不是消失了,而是容器生命周期结束,底层存储层被回收了。所以容器适合跑无状态的服务,比如定时任务、计算任务、Web服务的无状态副本。凡是有状态的数据,一律要放到宿主机的存储里。

4.2 数据卷:把数据放在容器外

Docker提供数据卷(volume)机制,把宿主机目录或一块独立存储挂载进容器。最直接的用法是绑定挂载,指定宿主机目录和容器目录的映射关系:

docker run -d --name web-demo -v /opt/webdata:/usr/share/nginx/html -p 8080:80 nginx:alpine

这条命令把宿主机 /opt/webdata 目录挂载到容器的 /usr/share/nginx/html 目录。容器里对 /usr/share/nginx/html 下文件的读写,实际都落在宿主机 /opt/webdata 上。就算容器删了,数据还在宿主机上。后续你再起一个新容器,挂载同一个目录就行,数据自动接上。

另一种方式是用具名卷,不直接绑定宿主机目录,而是让Docker管理一个卷:

docker volume create web-data docker run -d --name web-demo -v web-data:/usr/share/nginx/html -p 8080:80 nginx:alpine

具名卷的好处是不依赖宿主机具体路径,迁移时也更方便,适合对接后续要学的docker compose。绑定挂载则更直接,适合开发调试,因为你可以直接改宿主机上的代码文件,容器里立即生效。两种方式各有适用场景,第一课先都记住就行。

4.3 端口映射:把容器里的服务暴露到外部

容器默认网络是隔离的,宿主机外部访问不到。要让外部能访问,就得做端口映射。前面的 -p 8080:80 就是干这个的。第一条是宿主机端口,第二条是容器端口,流量进到宿主机8080端口后,会转发到对应容器的80端口。

映射多个端口就写多个-p参数:

docker run -d --name app -p 8080:8080 -p 8443:8443 myapp:v1

还有一种不指定宿主端口的写法:

docker run -d -P --name app myapp:v1

大写-P会把Dockerfile里EXPOSE声明的端口随机映射到宿主机的某个高位端口,用 docker ps 就能看到实际映射关系。这种写法适合快速测试,但不适合生产,因为端口不稳定。

端口冲突是新手经常遇到的事。如果你启动容器时报“port is already allocated”,说明宿主机的这个端口已经被其他进程占用了。排查方法一种是看是不是别的容器占用了:

docker ps -a

另一种是直接用系统命令查端口占用。不管哪种方式,结论都是换一个宿主机端口,或者停掉占用端口的容器。第一课不需要深入网络模型,只要理解“宿主端口独立分配、容器内端口是应用监听的目标”就足够了。

5. 新手必修:常见报错与排查技巧

基础命令学完以后,你会遇到各种奇奇怪怪的报错。这里把第一课最常碰到的问题整理成一张速查表,后面遇到直接对号入座。

5.1 常见报错速查表

报错内容原因处理办法
Cannot connect to the Docker daemonDocker服务没启动,或当前用户不在docker用户组启动服务:sudo systemctl start docker; 或者 sudo usermod -aG docker 你的用户名,重启终端
port is already allocated宿主机端口被占用换端口,或停掉占用的容器
no matching manifest for linux/amd64 in the manifest list镜像不支持当前CPU架构换对应架构的镜像标签,或用多架构镜像
Get ... context deadline exceeded拉取镜像超时,网络问题检查网络,配置镜像加速,或重试
Unable to find image ... locally本地没有镜像,拉取也失败先确认镜像名是否正确,再检查网络和仓库访问
exec: "bash": executable file not found容器里没有bash改成 sh,例如 docker exec -it 容器名 sh
OCI runtime create failed容器运行时创建失败,常见于权限或内核问题查看完整报错,确认是否用了不兼容的镜像,检查SELinux或AppArmor配置

表格里每一行背后都有具体场景。比如“Cannot connect to the Docker daemon”这个错误,几乎每个新手都遇过。实际上很多Linux发行版的Docker服务默认是开机自启的,但如果你的环境是刚装好的服务器,服务可能还没启动,或者你当前用户的权限不够。第一课就要养成用 journalctl -u docker 看Docker服务日志的习惯,里面会写明原因,比乱猜强得多。

5.2 容器状态码和排查思路

容器退出后,docker ps -a 会显示Exit Code。这个数字不是随机的,是在容器里运行的进程退出状态码。常见的有:

状态码含义排查方向
0正常退出检查是否预期内完成,比如一次性任务跑完就退出
1程序运行出错看容器日志:docker logs 容器名
125docker run命令本身出错检查docker run参数和宿主环境
126容器内命令无法执行检查权限,或命令文件是否可执行
127命令找不到可能依赖缺失、PATH不对,或基础镜像里没有该命令
137被强制终止最常见是内存溢出被系统杀掉,查内存和OOM日志
139内存段错误一般与应用自身有关,检查代码和依赖库

我举一个实际例子。有一次我帮人排查一个nginx容器,一直启动失败,docker logs显示正常,但状态码是137。后来一查,是宿主机内存不足,内核把容器杀掉了。这种情况你去容器配置里找问题永远找不到,必须看宿主机层面的日志。

5.3 命令记不住怎么办

第一课信息量不小,命令又多,记不住很正常。我不建议死记硬背,我自己也记不住所有参数。常用的做法有三个:一是用 docker --help 查看帮助,比如 docker run --help 会列出所有参数;二是给常用命令设置shell别名,比如把 docker compose 简化为 dc;三是依赖图形界面工具。Docker Desktop里可以可视化查看容器和镜像,对新手熟悉概念很有帮助。

帮一个新同事排查问题时,经常发现他们连命令名字都是问一遍查一遍,效率极低。我建议第一课就把 docker pull、docker run、docker ps、docker logs、docker exec、docker stop、docker rm 这七个命令练到形成肌肉记忆,其他命令用到时再查手册,完全没问题。

6. 第一节课后应该达到什么状态

基础课学完,不是记住了多少命令,而是能独立完成一个完整流程。我按这个标准来设计自测点,对应前面所有知识点。

6.1 自测清单

你可以按顺序做一遍,能顺利走完基本就算过关了:

  1. 拉取一个nginx:alpine镜像。
  2. 查看本地镜像列表,找到刚拉下来的镜像。
  3. 用这个镜像启动一个名为 test-web 的容器,后台运行,宿主机8088端口映射到容器80端口。
  4. 在浏览器访问 http://localhost:8088 ,能看到Nginx欢迎页。
  5. 用 docker logs 查看容器日志。
  6. 进入容器内部,看看 /usr/share/nginx/html 下的文件。
  7. 把宿主机某个目录挂载到容器里,修改宿主机文件后刷新页面确认生效。
  8. 停止并删除这个容器,再确认挂载目录里的数据还在。

做到第7步和第8步时,你基本就打通了“镜像→容器→存储→端口”这条主线。这个流程看似简单,但它涵盖了Docker最核心的使用方法。后面无论是学Docker Compose、写生产级Dockerfile,还是接触Kubernetes,基础都是这些。

6.2 接下来的学习方向

第一课结束后,下一步通常是补齐两个方向的短板:一是把Dockerfile写规范,包括多阶段构建、镜像瘦身、基础镜像选型;二是学docker compose 做多容器编排。在这之前,你先花点时间把单容器的生命周期和持久化玩熟练,地基不牢后面会加倍还债。

我每年都会带一些新人和实习生,他们最容易犯的错误就是想一口气把所有内容吞下去。上完课就想立刻学Kubernetes,结果连容器日志在哪看都不知道。我的建议是,第一周只做一件事:用Docker把你熟悉的一个应用跑起来,让它能稳定访问、日志正常、数据不丢。做到这一步,你对容器的理解已经超过相当一部分工作了几年但从不深究的人了。

最后分享一个我自己常用的检查小技巧。拿到一台装有Docker的机器,第一件事永远是 docker version 和 docker info,快速确认服务状态、存储驱动、并发上限等基础信息。第二件事是 docker ps -a,看看当前环境里有什么存量容器。这两步做完,再动手操作会踏实很多。很多线上问题,其实是在环境状态都没搞清楚的情况下就开始跑命令造成的。第一课打好这个“先看状态再动手”的习惯,后面能帮你省下大把排查时间。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询