开头先从实际痛点切入:做开发这几年,我见过太多时间浪费在“装环境”这件事上。一个项目要装 Nginx、MySQL、Redis、Python 环境,每台机器都折腾一遍,版本对不上、依赖冲突、系统差异,最后能跑起来全靠运气。Docker 把应用和它依赖的整个运行环境一起打包成镜像,用容器跑起来之后,同一台服务器上可以同时存在多个互不干扰的运行时,这就是大家说的“环境一致”和“资源隔离”。这篇文章不带任何废话,从零开始讲清楚两件事:一是 Ubuntu、CentOS、二进制这三种 Docker 安装方式,二是镜像和容器最常用的核心命令。你不用有基础,照着做就能把 Docker 用起来,适合刚入门或者在本地/服务器上折腾环境的同学。
1. 先搞明白:Docker 到底解决了什么问题
1.1 环境一致性与资源隔离
很多人第一次听到 Docker,第一反应是“虚拟机”。它其实不是虚拟机。虚拟机模拟的是整台硬件设备,里面要装完整操作系统,启动慢、占资源。容器跑在宿主机的内核之上,只打包了应用运行所需的文件系统、依赖库和应用代码,启动只要秒级,本身几乎不占额外资源。你可以把镜像理解成一个“独立小房间的装修模板”,容器就是按这个模板造出来的房间,房间之间靠墙壁隔开,但大家共用同一栋大楼的水电结构。
这里有两层核心概念。一是环境一致性:同一个镜像,在你的笔记本里跑是什么样,在云服务器上跑就是什么样,不会再出现“我本地明明好的,一上服务器就报错”。二是资源隔离:Docker 在底层用 namespace 隔离进程、网络、文件系统,用 cgroups 限制 CPU、内存、磁盘 IO。简单说,你起了一个容器,这个容器只能看到它自己那部分资源,访问不到宿主机和别的容器的内部内容,这是很多生产环境敢把多套服务放同一台机器上的底气。
1.2 镜像、容器、仓库:三个词吃透 Docker
Docker 的世界里,最核心的三个概念是镜像、容器、仓库。我习惯用一个类比:镜像好比“安装光盘”,里面存好了应用及其所有运行条件;容器是“光盘装出来的软件实例”,可以启动、停止、删除;仓库则是存放光盘的地方,Docker Hub 就是最大的公共仓库。
常见流程是这样的:从仓库拉取镜像(docker pull),基于镜像创建容器(docker run),容器跑起来后就是一个独立进程。你可以同时基于同一个镜像创建多个容器,互不影响。比如拉一个 nginx 镜像,用同一个镜像起三个容器,分别映射到 8080、8081、8082 三个端口,就相当于在一台机器上跑三个网站入口,这在以前要么装三份,要么折腾端口和系统服务,非常麻烦。
1.3 安装方案怎么选:在线包管理器还是二进制
安装 Docker 主要有三条路:Ubuntu 用 apt、CentOS 用 yum,这是大多数人最推荐的方式,好处是自动处理依赖,卸载也干净;还有一种二进制安装,直接从官网下载静态包解压,适合离线环境、内网服务器,或者对系统版本有特殊要求的场景;另外 Docker Desktop 是图形化方案,主要用于个人电脑本地的开发调试。
我见过不少新手一上来就挑最难的方式硬啃,结果卡在依赖上半天。其实选择很简单:能连外网的系统,优先用 apt 或 yum;没法连外网、要求完全离线安装、或者想自己掌控安装路径,就选二进制。下面是三种方式的完整实操。
2. Ubuntu 安装 Docker:官方源与国内源实测
2.1 系统要求与旧版本清理
安装前先确认系统版本。用lsb_release -a或cat /etc/os-release查看。Docker 官方支持 Ubuntu 的多个长期支持版本,比如 Ubuntu 20.04 LTS、22.04 LTS、24.04 LTS。如果你的系统是 18.04 这种老版本,也能装,但建议先升一下系统,省得后面内核和存储驱动出问题。
如果你以前装过 Docker,或者系统里残留了旧包,先清理干净。这一步很多人忽略,结果装新版本时出现包冲突或者 dockerd 起不来,我踩过好多次。执行下面的命令:
sudo apt remove docker docker-engine docker.io containerd runc注意,这个命令只删旧包,不会动/var/lib/docker里的已有镜像和容器数据。如果你确定旧数据不要了,可以手动删掉这个目录,但我建议第一次清理时先不管它,避免误删。
2.2 用 apt 安装 Docker Engine
最简单可靠的方式是添加 Docker 官方 apt 源。先装依赖工具:
sudo apt update sudo apt install -y ca-certificates curl gnupg lsb-release接着导入官方 GPG 密钥并添加源。网上很多教程把密钥直接写到某个固定文件,官方现在的推荐做法是放到/etc/apt/keyrings目录,更清晰:
sudo install -m 0755 -d /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg sudo chmod a+r /etc/apt/keyrings/docker.gpg再写入 apt 源:
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null这条命令稍微复杂,拆开解释:arch=$(dpkg --print-architecture)是自动获取系统架构,比如 amd64 或 arm64;$(. /etc/os-release && echo "$VERSION_CODENAME")是自动读取系统版本代号,比如 jammy、noble。这样你不用手动填版本号,一条命令搞定。之后更新源并安装:
sudo apt update sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin这里顺便装了 compose 插件,后面编排多个容器会用到。安装完成后先不急着用,把服务启动起来:
sudo systemctl start docker sudo systemctl enable dockerenable的作用是设置开机自启,服务器上一定要做,否则重启后就只剩眼泪了。最后验证:
docker --version docker run hello-worldrun hello-world会拉取一个极小的测试镜像,跑起来打印一段欢迎信息,说明整套链路没问题。
2.3 让普通用户免 sudo 运行 Docker
刚装完你会发现,直接敲docker ps会报权限错误,提示无法连接到 Docker 守护进程。这是因为 Docker 的 socket 默认只给 root 用户访问权限。每次命令都加 sudo 很反人类,正确做法是把当前用户加入 docker 组:
sudo usermod -aG docker $USER改完必须重新登录,或者执行newgrp docker让组权限立即生效。之后就再也不用 sudo 了。
这里提醒一句:把用户加进 docker 组相当于授予该用户几乎等同 root 的权限,因为用户可以挂载宿主机目录、执行特权容器。个人开发机无所谓,但生产服务器上一定要控制加入 docker 组的用户名单,这是很多人没意识到的安全点。
2.4 Ubuntu 下最容易踩的三个坑
第一个坑是 apt 源更新失败。这通常是因为/etc/apt/sources.list.d/docker.list里写入了错误的系统版本代号,或者 GPG 密钥权限不对。排查方式很简单:先cat /etc/apt/sources.list.d/docker.list确认内容,再用sudo apt update看具体报错,大部分问题都能定位到源地址或密钥。
第二个坑是磁盘不足。Docker 默认数据目录在/var/lib/docker,镜像、容器日志都会写到这里,Ubuntu 系统盘如果只有 20G,很快会被填满。建议装完就先确认磁盘大小:df -h /var/lib/docker。如果不够,可以通过配置/etc/docker/daemon.json里的>cat /etc/centos-release uname -r
内核版本至少在 3.10 以上,CentOS 7 默认内核通常满足要求。CentOS 8 和 Stream 版本操作方式基本一致,但要注意 CentOS 8 配置仓库时可能出现 mirrorlist 相关的网络报错,需要针对 mirror 地址做额外处理。还有一点,CentOS 不像 Ubuntu 有那么多版本文档,很多教程写的是老式 docker-io 源,那个包非常旧,最早不要用,直接走 Docker 官方源。
3.2 配置 yum 仓库并安装
安装yum-utils,提供yum-config-manager工具:
sudo yum install -y yum-utils sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo添加完仓库后,建议先清一次缓存再装:
sudo yum makecache fast sudo yum install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin这里 CMake 慢没关系,耐心等。安装过程中如果提示 GPG 密钥确认,按 y 接受即可。装完后用rpm -qa | grep docker确认安装的版本,正常会看到 docker-ce、docker-ce-cli、containerd.io 三个主要包。
3.3 启动服务与配置开机自启
CentOS 上是标准的 systemd 服务管理方式:
sudo systemctl start docker sudo systemctl enable docker systemctl status docker看到状态为active (running)就算成功了。再验证一次客户端和服务端版本是否一致:
sudo docker version注意看 Server 部分的版本号,如果显示Cannot connect to the Docker daemon,说明守护进程没起来,去查日志:journalctl -xu docker。多数是配置问题或 SELinux 拦截,继续往下看。
3.4 CentOS 特有的几个坑
CentOS 上最经典的坑就是防火墙和 SELinux。新装 CentOS 默认开启 firewalld,Docker 端口映射做好后,你从外部访问宿主机 IP 的端口,会发现一直不通。我测过几次,解决方案是:要么在 firewalld 里放行端口,要么干脆关掉 firewalld。生产环境按需放行端口,测试环境图省事可以关:
sudo systemctl stop firewalld sudo systemctl disable firewalldSELinux 配置非常严格也可能导致容器内进程无法访问挂载目录。临时验证方法是setenforce 0,如果这样容器就正常了,说明是 SELinux 的问题。生产环境不要直接关 SELinux,建议用chcon调整文件上下文,或者调整 Docker 的 SELinux 配置。
另一个坑是--add-repo之后源地址失效。CentOS 7 的生命周期结束时间一到,Docker 官方仓库可能不再提供新的 CentOS 7 包。解决办法是把源地址改为 archive 备份地址,或者直接转向二进制安装哪种方式,不要过分依赖 yum 仓库。
4. 离线二进制安装 Docker:一条命令外的完整方案
4.1 什么时候需要二进制安装
二进制安装指从官网下载 Docker 静态二进制压缩包,直接解压到系统路径使用,不经过任何包管理器。这个方法很适合三类场景:内网环境无法访问外部源;包管理器仓库里找不到合适的版本;或者你希望完全掌控 Docker 的安装目录和升级方式。我第一次在项目里这么装,是因为客户服务器在隔离网络,yum 源也换成内部镜像了,但内部镜像里没有 docker-ce 包,只能下载 tar 包拷进去。
静态包的好处是依赖极少。Docker 官方把整体编译成一个包,包含了 dockerd、docker、containerd、runc 等全部组件,解压即用。缺点是后续的升级、卸载、开机自启都得自己写配置,不适合完全没动手经验的新手。
4.2 下载解压与文件说明
去 Docker 官网下载页面找到静态二进制包,或者直接在能联网的机器上用命令下载:
wget https://download.docker.com/linux/static/stable/x86_64/docker-27.3.1.tgzx86_64对应普通 Intel/AMD 服务器,aarch64对应 ARM 架构,别下错了。解压:
tar xzvf docker-27.3.1.tgz生成一个docker目录,里面包含dockerd、docker、containerd、containerd-shim-runc-v2、ctr、runc等二进制文件。把全部文件复制到系统 PATH 目录:
sudo cp docker/* /usr/bin/这个时候你敲docker --version已经能出结果了,但直接运行还会报错,因为缺少 systemd 服务文件,没法开机自启,也没法以服务方式常驻。接下来手动配置。
4.3 手写 systemd 服务文件
我们需要创建两个服务文件:docker.service和docker.socket。这里给出一个在生产环境验证过的版本:
sudo cat > /etc/systemd/system/docker.service <<'EOF' [Unit] Description=Docker Application Container Engine Documentation=https://docs.docker.com After=network-online.target firewalld.service containerd.service Wants=network-online.target [Service] Type=notify ExecStart=/usr/bin/dockerd ExecReload=/bin/kill -s HUP $MAINPID LimitNOFILE=1048576 LimitNPROC=infinity LimitCORE=infinity TasksMax=infinity TimeoutStartSec=0 Delegate=yes KillMode=process Restart=always StartLimitBurst=3 StartLimitInterval=60s [Install] WantedBy=multi-user.target EOF解释几个关键项:Type=notify表示 dockerd 启动完成会通知 systemd,这样systemctl start docker才能准确判断启动成功;LimitNOFILE=1048576调大了文件描述符上限,容器多了之后不会出现无法打开文件的情况;Delegate=yes是关键中的关键,把 CPU、内存等资源控制委托给 Docker,否则 cgroups 资源限制可能失效。
然后启用服务:
sudo systemctl daemon-reload sudo systemctl start docker sudo systemctl enable docker再执行sudo docker run hello-world。如果这一步成功,二进制安装就算真正完成了。注意,这里跑到 hello-world 需要能访问 Docker Hub,如果你的环境完全离线,这一步会卡在 pull 阶段,这是正常的,不意味着安装失败,你只需要后续手动把镜像导入进环境即可。
4.4 升级与卸载的注意事项
二进制安装的升级非常简单:下载新版本包,解压,停掉 Docker,复制覆盖二进制文件,启动服务。完整命令流程:
sudo systemctl stop docker cp docker/* /usr/bin/ sudo systemctl start docker升级前建议先备份/var/lib/docker,尤其是生产服务器上跑着大量容器时。卸载也更粗暴:删掉二进制文件和服务文件,清掉数据目录:
sudo systemctl stop docker sudo rm /usr/bin/dockerd /usr/bin/containerd /usr/bin/docker /usr/bin/runc sudo rm /etc/systemd/system/docker.service sudo rm -rf /var/lib/docker最后一步会清掉所有镜像和容器数据,谨慎操作。
5. 镜像操作:pull、images、rmi、prune 这些命令怎么用
5.1 拉取镜像前先搞懂标签的含义
镜像是 Docker 里最基础的单位。命令行第一个高频操作是拉取镜像:
docker pull 镜像名镜像名一般格式是仓库地址/作者/镜像名:标签。比如nginx:1.25,其中nginx是镜像名,1.25是标签,表示具体版本。如果你不写标签,默认拉取latest标签。这里我强烈建议显式指定版本标签,因为latest是会变的,几个月后再跑同一个命令,拉下来可能已经不是同一个镜像,生产环境的可复现性会大打折扣。
5.2 查看与删除镜像
看本地有哪些镜像:
docker images # 等价 docker image ls输出列包含仓库名、标签、镜像 ID、创建时间和大小。镜像 ID 是 64 位哈希的前 12 位,删除时可以用它代替完整镜像名。删除一个镜像:
docker rmi nginx:1.25如果镜像被容器占用,会报错提示先删除容器。两种解决办法:先删容器再删镜像;或者用docker rm -f强制删容器。另外,镜像删除时只删除指定标签对应的层,多个标签可能共享底层镜像层,删除一个标签不会影响另一个标签引用的底层内容。
5.3 清理悬空镜像与构建缓存
用了一段时间 Docker,本地会积累一堆“悬空镜像”。悬空镜像是指没有任何标签引用、也不再被任何容器使用的镜像层,通常来自反复重新构建镜像。这些内容白白占用磁盘,清理命令:
docker image prune加上-a参数会清理所有未被容器引用的镜像,包括有标签但不再使用的:
docker image prune -a我建议定期执行一次,配合docker system df看看磁盘使用概况。很多服务器磁盘饱满,其实就是镜像和容器日志堆出来的,而不是真实业务数据。
5.4 镜像导入导出和私有仓库
离线环境之间的镜像搬运,最常用的是保存与导入。把镜像保存成一个 tar 文件:
docker save -o nginx.tar nginx:1.25另一台机器上导入:
docker load -i nginx.tarsave保留的是完整的镜像信息和所有层,比export容器更可靠。另一个方案是搭建私有仓库,用docker tag给镜像打上私有仓库地址后docker push:
docker tag nginx:1.25 registry.example.com/nginx:1.25 docker push registry.example.com/nginx:1.25这里registry.example.com需要替换为你自己的仓库地址。小团队内部用这种方式分发镜像最方便,不用到处拷 tar 包。
6. 容器操作:run、exec、logs、ps 的核心用法
6.1 run 命令的完整参数拆解
docker run是容器操作里最重要的命令,新手最容易在上面犯迷糊。最基本的形式:
docker run -d --name web -p 8080:80 nginx:1.25选项拆解:-d表示后台运行,不占用终端;--name web给容器命名,后续操作都靠名字指代;-p 8080:80把宿主机的 8080 端口映射到容器的 80 端口,外部访问宿主机IP:8080就相当于访问容器内 Nginx 的 80 端口。如果没有-p,容器内服务虽然起来了,但宿主机访问不到。
还有其他常用选项,我再列一组:
-it:交互模式进入容器,配合bash使用。--rm:容器退出时自动删除,适合临时测试。-e:设置环境变量,比如-e TZ=Asia/Shanghai。--network host:容器直接用宿主机网络,不需要端口映射,这时候要注意端口冲突。-v:挂载数据卷,后面详细说。--restart=always:容器异常退出时自动重启,生产环境必加。
6.2 进入正在运行的容器:exec 和 attach
容器跑起来后想进去看环境、调试程序,有两个命令:exec和attach。我强烈推荐用exec:
docker exec -it web bash这个命令在容器内启动一个新的 bash 进程,适合执行命令、安装调试工具、查看目录结构。退出时用exit,不会影响容器本身,容器继续后台运行。attach则不同,它会直接连接到容器的主进程,退出时往往会连带着终止容器,因为主进程收到 EOF 就退出了。所以平时调试优先用 exec,少用 attach。
6.3 端口映射与数据卷
端口映射解决的是外部访问问题,数据卷解决的是容器重建后数据丢失问题。容器内部是临时的,删掉容器,容器里写的文件全没了。通过数据卷把宿主机目录挂载进容器:
docker run -d --name web -p 8080:80 -v /home/user/nginx/html:/usr/share/nginx/html nginx:1.25冒号前面是宿主机目录,后面是容器内目录。这样你在宿主机上修改文件,容器里立刻能看到,删掉容器重跑一条命令,数据还在宿主机上。另一种是命名卷:
docker volume create html docker run -d --name web -v html:/usr/share/nginx/html nginx:1.25命名卷由 Docker 管理,目录位置在/var/lib/docker/volumes下,适合保存数据库数据等不需要手动访问的内容。日常开发中,MySQL、Redis 这类有状态服务,我建议务必用命名卷,否则容器删掉数据就没了,这种事故我见过不止一次。
6.4 查看容器状态、日志与资源占用
查看运行中的容器:
docker ps加-a查看所有容器,包括已停止的。输出里有容器 ID、镜像、命令、状态、端口映射、名称。查看某个容器详细信息:
docker inspect web输出是 JSON,包含网络配置、挂载点、环境变量等所有细节,排查问题时信息量很大。看日志:
docker logs web docker logs -f web-f的意思是 follow,持续跟踪日志输出,相当于tail -f,调试时很有用。资源占用实时查看:
docker stats输出显示每个容器的 CPU、内存、网络 IO、磁盘 IO,按下 Ctrl+C 退出。docker stats --no-stream可以只看一次快照,适合写脚本监控。
6.5 停止、重启与删除容器的正确姿势
容器生命周期操作:
docker stop web # 优雅停止,给进程一些时间处理退出 docker start web # 启动一个已停止的容器 docker restart web # 重启 docker pause web # 暂停所有进程,不释放资源 docker unpause web删除容器的正确姿势:
docker rm web docker rm -f web # 强制删除运行中的容器docker stop默认给容器 10 秒做退出处理,时间太短可以把-t参数加上,比如docker stop -t 30 web。生产环境建议用这种优雅退出方式,避免数据库进程强制被杀导致数据损坏。
7. 一个完整的实战流程:用 Docker 部署 Nginx
7.1 五条命令跑起一个网站
说了这么多命令,不如完整跑一个实际例子。场景是:在一台空服务器上部署一个最简单的 Nginx 网站。拉镜像:
docker pull nginx:1.25创建并启动容器:
docker run -d --name web -p 8080:80 --restart=always nginx:1.25此时已经能访问了。浏览器打开http://服务器IP:8080,看到 Nginx 欢迎页。再补充两条常用命令:
docker ps docker logs -f webdocker ps确认容器运行状态,logs -f实时看访问日志,按 Ctrl+C 退出日志跟踪。整个部署流程加起来就是这 5 条命令,没有系统包依赖,没有编译安装,这就是 Docker 最直观的优势。
7.2 修改页面并持久化数据
默认的 Nginx 页面在容器内,要自定义页面就得挂数据卷。先在宿主机建目录:
mkdir -p /data/nginx/html echo '<h1>Hello Docker, from host</h1>' > /data/nginx/html/index.html停掉并删除旧容器,用挂载方式重新启动:
docker stop web docker rm web docker run -d --name web -p 8080:80 -v /data/nginx/html:/usr/share/nginx/html nginx:1.25刷新页面,就能看到宿主机上写好的内容。之后再改页面,直接改宿主机文件就行,容器不用动。这在实际使用中非常重要,结构化的配置、代码、静态资源都应该放在宿主机或命名卷里,容器只负责运行。
7.3 容器故障排查的基本套路
容器起不来或者访问异常时,我的排查顺序是固定的。第一步看状态,docker ps -a看容器是否在运行,状态列如果总是Exited说明进程崩溃或启动失败。第二步看日志,docker logs web找最后的报错,这是定位问题的关键。第三步看启动命令,docker inspect web检查环境变量、端口映射和挂载配置是否写错。第四步查端口监听,在宿主机上用ss -lntp | grep 8080确认端口真的被 dockerd 的映射规则监听。
这几步能解决九成问题。剩下的一成通常和系统配置有关,比如防火墙没放行端口、挂载目录权限不对、容器内进程需要特定内核参数等,这类问题就要结合前文提到的 SELinux、firewalld、系统日志来排查。
8. Docker Desktop 与日常使用建议
8.1 Docker Desktop 适合谁
Docker Desktop 是官方提供的图形化桌面版,支持 Windows 和 macOS。它也底层跑的是 Linux 虚拟机,只不过帮你把环境都封装好了,装完点图标就能用,界面里能看容器列表、日志、停止启动。这个方案和个人开发场景挺搭,尤其是在 Windows 上做开发、但目标环境是 Linux 服务器的同学,本地用 Docker Desktop 调试,部署到服务器时直接用同一套镜像,能省掉不少环境不一致的麻烦。
但注意一点,Docker Desktop 在 Windows 上依赖 WSL2 或 Hyper-V,老机器没有开启虚拟化支持时安装会失败。如果你只需要在 Linux 服务器上跑,完全不必装 Desktop,用 apt 或 yum 安装反而更省资源。Desktop 更适合个人电脑上的本地开发。
8.2 开发者日常的推荐工作流
我用 Docker 几年,总结出的最舒服的工作流是这样的:开发阶段,用 Docker Desktop 或者 Linux 本机 Docker 起中间件,MySQL、Redis、RabbitMQ 都以容器方式运行,应用代码跑在本地,通过-p 3306:3306这类映射连进容器里的服务。交付阶段,把应用打包成镜像,构建好之后 push 到仓库,服务器上直接 pull 下来跑。数据库这类有状态服务在测试环境也用容器,但数据必须挂到命名卷里。配置管理之类的临时任务,用--rm跑一次性容器,用完自动消失,不污染宿主机。
这套流程的好处是,你本地调试的镜像和线上跑的镜像完全一致,不会再出现“本地能跑线上不行”的经典问题。
8.3 我实践中的几个小技巧
最后分享几个很小但能提效的习惯。第一个是给容器加--restart=always,尤其是 MySQL、Redis、Nginx 这类常驻服务,保证重启机器后自动恢复,不用手动去起。第二个是控制镜像体积,多阶段构建、清理 apt 缓存、不要什么调试工具都装进生产镜像,镜像小体积会让 pull 速度明显变快。第三个是善用docker system prune清理磁盘,但注意这个会把暂时不用的数据全清掉,执行前最好先看一眼。第四个是启动容器时都写上--name,没有名字的容器只能通过一长串容器 ID 操作,非常痛苦。
8.4 对我来说,Docker 改变了什么
我个人在项目里用了 Docker 之后,最大的感受不是命令背得多熟,而是心态变了。以前配置环境总是提心吊胆,生怕把系统搞坏,现在随便起容器、删容器,大不了重新拉一个镜像,几分钟又是一条好汉。这种“可丢弃、可重建”的思维,才是最值钱的东西。希望你不要急着背命令,先把一个 Nginx 容器从头跑到尾,体验一下从镜像到容器的完整流程,后面所有东西都会顺很多。