Docker 入门避坑指南:新手常见问题一次讲清
Docker 常见问题汇总|零基础可学
Docker 是近几年后端开发、运维部署、测试环境搭建中非常常见的工具。对于零基础学习者来说,Docker 一开始看起来像是“虚拟机”“服务器”“镜像仓库”“命令行工具”的混合体,概念比较多,但只要理解了它的核心思想,入门并不困难。
本文将以“常见问题汇总”的形式,围绕 Docker 的基础概念、安装使用、镜像与容器、网络、数据卷、Dockerfile、Docker Compose、常见报错以及学习建议等内容进行整理,适合零基础读者系统学习和查漏补缺。
一、Docker 是什么?
Docker 是一种容器化技术,它可以把应用程序以及运行应用所需的环境、依赖、配置一起打包起来,然后在不同机器上快速运行。
简单来说,Docker 可以帮助我们解决一个经典问题:
“为什么我的电脑上可以运行,到了服务器上就不行?”
在传统开发中,一个项目可能依赖特定版本的 Java、Python、Node.js、MySQL、Redis 等环境。开发环境、测试环境、生产环境稍有差异,就可能出现各种问题。Docker 的作用就是把这些环境封装成一个相对独立的“容器”,让应用在不同环境中保持一致。
二、Docker 和虚拟机有什么区别?
很多初学者会把 Docker 理解成虚拟机,其实二者有相似之处,但本质不同。
1. 虚拟机
虚拟机会模拟一整套操作系统。例如你在 Windows 上安装 VMware,然后在里面运行 Ubuntu。虚拟机通常包含完整的操作系统内核、系统服务和应用环境。
优点是隔离性强,缺点是资源占用高、启动慢。
2. Docker 容器
Docker 容器不是完整虚拟机,它共享宿主机的操作系统内核,只隔离进程、文件系统、网络等运行环境。
优点是轻量、启动快、资源占用少,缺点是隔离性相比虚拟机略弱。
3. 简单对比
| 对比项 | 虚拟机 | Docker 容器 |
|---|---|---|
| 启动速度 | 通常较慢 | 通常很快 |
| 资源占用 | 较高 | 较低 |
| 是否包含完整系统 | 是 | 否 |
| 隔离程度 | 更强 | 较强 |
| 使用场景 | 多系统模拟、强隔离 | 应用部署、环境统一 |
三、Docker 的核心概念有哪些?
学习 Docker,最重要的是理解三个核心概念:镜像、容器、仓库。
1. 镜像 Image
镜像可以理解为一个“模板”或“安装包”。它包含运行某个应用所需要的文件系统、依赖环境和默认配置。
例如:
mysql:8.0是 MySQL 8.0 的镜像;redis:7是 Redis 7 的镜像;nginx:latest是 Nginx 最新版本镜像。
镜像本身是静态的,不能直接修改运行状态。
2. 容器 Container
容器是镜像运行起来后的实例。
可以这样理解:
镜像像是类,容器像是对象;
镜像像是安装包,容器像是运行中的软件。
一个镜像可以创建多个容器。例如你可以用同一个 Nginx 镜像启动多个 Nginx 容器,每个容器互相隔离。
3. 仓库 Registry
仓库用于存放和分发镜像。最常见的是 Docker Hub,类似于镜像世界的“应用商店”。
常见镜像仓库包括:
- Docker Hub;
- 阿里云容器镜像服务;
- 腾讯云镜像仓库;
- Harbor 私有仓库。
四、Docker 常用命令有哪些?
下面整理一些最常见的 Docker 命令,适合初学者记忆。
1. 查看 Docker 版本
docker version
或者:
docker --version
2. 查看 Docker 运行信息
docker info
该命令可以查看 Docker 的存储驱动、镜像数量、容器数量、系统信息等。
3. 搜索镜像
docker search nginx
这条命令会在镜像仓库中搜索 Nginx 相关镜像。
4. 拉取镜像
docker pull nginx
如果不指定版本,默认拉取 latest 标签版本。
指定版本:
docker pull mysql:8.0
5. 查看本地镜像
docker images
或者:
docker image ls
6. 删除镜像
docker rmi 镜像ID
如果镜像正在被容器使用,需要先删除相关容器。
7. 创建并运行容器
docker run nginx
但这样运行会占用当前终端。通常会使用后台模式:
docker run -d nginx
8. 端口映射运行容器
例如运行 Nginx,并把宿主机的 8080 端口映射到容器内的 80 端口:
docker run -d -p 8080:80 nginx
访问:
http://localhost:8080
即可看到 Nginx 页面。
9. 查看正在运行的容器
docker ps
查看所有容器,包括已停止的:
docker ps -a
10. 停止容器
docker stop 容器ID或容器名
11. 启动已停止的容器
docker start 容器ID或容器名
12. 重启容器
docker restart 容器ID或容器名
13. 删除容器
docker rm 容器ID或容器名
如果容器正在运行,需要先停止,或者强制删除:
docker rm -f 容器ID
14. 查看容器日志
docker logs 容器ID或容器名
实时查看日志:
docker logs -f 容器ID或容器名
15. 进入容器内部
docker exec -it 容器ID或容器名 bash
如果容器中没有 bash,可以使用 sh:
docker exec -it 容器ID或容器名 sh
五、Docker run 常见参数是什么意思?
docker run 是最常用也最重要的命令之一,常见参数如下。
1. -d
后台运行容器。
docker run -d nginx
2. -p
端口映射。
docker run -d -p 8080:80 nginx
含义是:
宿主机端口:容器端口
3. --name
给容器指定名称。
docker run -d --name my-nginx nginx
以后可以用 my-nginx 来操作容器。
4. -v
挂载数据卷或目录。
docker run -d -v /host/data:/container/data nginx
含义是:
宿主机目录:容器内目录
这样可以实现数据持久化。
5. -e
设置环境变量。
例如运行 MySQL:
docker run -d \
--name mysql8 \
-e MYSQL_ROOT_PASSWORD=123456 \
-p 3306:3306 \
mysql:8.0
6. --restart
设置容器重启策略。
docker run -d --restart=always nginx
常见取值:
| 参数 | 含义 |
|---|---|
| no | 不自动重启 |
| always | 总是自动重启 |
| unless-stopped | 除非手动停止,否则自动重启 |
| on-failure | 容器异常退出时重启 |
六、Docker 容器中的数据会丢失吗?
会,也不会,取决于你如何保存数据。
容器本身是临时性的。如果你把数据直接写在容器内部,当容器被删除后,数据也会随之丢失。因此,数据库、上传文件、配置文件等重要数据,通常需要使用数据卷或目录挂载。
七、什么是 Docker 数据卷?
Docker 数据卷 Volume 是 Docker 提供的数据持久化机制。它可以把容器中的数据保存到宿主机上,即使容器删除,数据仍然存在。
1. 创建数据卷
docker volume create mydata
2. 查看数据卷
docker volume ls
3. 使用数据卷
docker run -d \
--name mysql8 \
-e MYSQL_ROOT_PASSWORD=123456 \
-v mysql_data:/var/lib/mysql \
mysql:8.0
这里的 mysql_data 就是数据卷,MySQL 数据会保存到该卷中。
4. 数据卷和目录挂载有什么区别?
| 类型 | 示例 | 特点 |
|---|---|---|
| 数据卷 | -v mysql_data:/var/lib/mysql |
Docker 管理,适合通用持久化 |
| 目录挂载 | -v /data/mysql:/var/lib/mysql |
用户指定路径,便于直接查看文件 |
一般来说,开发环境常用目录挂载,生产环境可以根据需求选择数据卷或指定目录。
八、Docker 网络是什么?
Docker 容器之间也需要通信,例如 Web 应用要连接 MySQL、Redis。Docker 提供了多种网络模式,其中最常见的是 bridge 网络。
1. 查看 Docker 网络
docker network ls
2. 创建自定义网络
docker network create my-net
3. 容器加入同一个网络
docker run -d --name mysql --network my-net mysql:8.0
docker run -d --name app --network my-net my-app
在同一个自定义网络中,容器可以通过容器名互相访问。例如 app 容器可以通过 mysql:3306 访问 MySQL。
4. 为什么推荐使用自定义网络?
因为在自定义网络中,Docker 会自动提供 DNS 解析能力,容器之间可以直接使用容器名访问,这比写 IP 地址更稳定。
九、Dockerfile 是什么?
Dockerfile 是用来构建镜像的脚本文件。它通过一系列指令描述如何创建一个镜像。
例如,一个简单的 Node.js 项目 Dockerfile:
FROM node:18
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD ["npm", "start"]
十、Dockerfile 常见指令有哪些?
1. FROM
指定基础镜像。
FROM nginx
所有 Dockerfile 通常都要以 FROM 开始。
2. WORKDIR
指定工作目录。
WORKDIR /app
后续命令会在该目录下执行。
3. COPY
复制文件到镜像中。
COPY . /app
4. RUN
构建镜像时执行命令。
RUN apt-get update && apt-get install -y curl
5. EXPOSE
声明容器内部使用的端口。
EXPOSE 8080
注意:EXPOSE 只是声明,并不会自动映射端口,真正映射端口仍需要 -p。
6. CMD
指定容器启动时默认执行的命令。
CMD ["npm", "start"]
7. ENTRYPOINT
也用于指定容器启动命令,通常适合封装固定入口程序。
CMD 和 ENTRYPOINT 有区别,但初学阶段可以先记住:大多数普通应用使用 CMD 就够了。
十一、如何构建自己的 Docker 镜像?
假设当前目录下有 Dockerfile,可以执行:
docker build -t my-app:1.0 .
参数解释:
-t my-app:1.0:给镜像命名并打标签;.:表示构建上下文是当前目录。
构建完成后查看镜像:
docker images
运行镜像:
docker run -d -p 8080:8080 my-app:1.0
十二、Docker Compose 是什么?
当项目只有一个容器时,使用 docker run 比较简单。但真实项目往往不止一个容器,例如:
- Web 应用;
- MySQL;
- Redis;
- Nginx;
- RabbitMQ。
如果每个容器都手动写 docker run,命令会很长也不方便维护。Docker Compose 就是用一个配置文件统一管理多个容器。
十三、Docker Compose 示例
下面是一个简单的 docker-compose.yml 示例:
services:
mysql:
image: mysql:8.0
container_name: mysql8
environment:
MYSQL_ROOT_PASSWORD: 123456
MYSQL_DATABASE: testdb
ports:
- "3306:3306"
volumes:
- mysql_data:/var/lib/mysql
redis:
image: redis:7
container_name: redis7
ports:
- "6379:6379"
volumes:
mysql_data:
启动:
docker compose up -d
停止:
docker compose down
查看日志:
docker compose logs -f
十四、Docker 常见问题与解决方法
问题 1:运行 Docker 命令提示 permission denied
常见报错:
permission denied while trying to connect to the Docker daemon socket
原因通常是当前用户没有权限访问 Docker。
解决方式之一:
sudo docker ps
如果不想每次都加 sudo,可以把当前用户加入 docker 用户组:
sudo usermod -aG docker $USER
然后重新登录终端或重启系统。
问题 2:端口被占用怎么办?
报错可能类似:
Bind for 0.0.0.0:8080 failed: port is already allocated
说明宿主机的 8080 端口已经被其他程序占用。
解决方法:
- 换一个宿主机端口:
docker run -d -p 8081:80 nginx
- 查找占用端口的进程并关闭。
Linux/macOS:
lsof -i :8080
Windows 可以使用:
netstat -ano | findstr 8080
问题 3:容器启动后马上退出
可以先查看容器状态:
docker ps -a
再查看日志:
docker logs 容器ID
常见原因包括:
- 启动命令执行失败;
- 配置文件错误;
- 环境变量缺失;
- 应用程序崩溃;
- 容器内主进程退出。
Docker 容器依赖前台主进程运行,如果主进程退出,容器也会退出。
问题 4:为什么修改容器内文件后,删除容器就没了?
因为容器本身不是用来长期保存数据的。如果需要保存文件,应该使用数据卷或目录挂载。
例如:
docker run -d \
-v /my/data:/app/data \
my-app
这样容器内 /app/data 的数据会保存到宿主机 /my/data。
问题 5:镜像太大怎么办?
镜像过大会导致构建慢、传输慢、部署慢。
优化方式:
- 使用更小的基础镜像,例如
alpine; - 减少不必要依赖;
- 合并清理命令;
- 使用
.dockerignore排除无关文件; - 使用多阶段构建。
例如:
FROM node:18-alpine
但需要注意,alpine 使用 musl libc,某些依赖可能存在兼容问题。
问题 6:什么是 .dockerignore?
.dockerignore 类似 .gitignore,用于告诉 Docker 构建镜像时忽略哪些文件。
示例:
node_modules
.git
logs
*.log
dist
这样可以减少构建上下文大小,提高构建速度,并避免把敏感文件打进镜像。
问题 7:容器之间无法访问怎么办?
排查步骤:
- 确认容器是否在运行:
docker ps
- 确认容器是否在同一个网络:
docker inspect 容器名
- 推荐创建自定义网络:
docker network create app-net
- 让容器加入同一个网络:
docker run -d --name redis --network app-net redis
docker run -d --name app --network app-net my-app
此时 app 可以通过 redis:6379 访问 Redis。
问题 8:Docker 容器时间不对怎么办?
可以挂载宿主机时区文件:
docker run -d \
-v /etc/localtime:/etc/localtime:ro \
nginx
也可以通过环境变量设置时区:
docker run -d \
-e TZ=Asia/Shanghai \
nginx
具体是否生效取决于镜像本身支持情况。
问题 9:如何清理 Docker 占用空间?
Docker 使用久了,会积累很多停止的容器、无用镜像、构建缓存和数据卷。
查看磁盘占用:
docker system df
清理未使用资源:
docker system prune
清理更彻底,包括未使用镜像:
docker system prune -a
清理未使用数据卷:
docker volume prune
注意:清理前一定要确认数据是否还需要,尤其是数据卷。
问题 10:latest 标签是不是最新版本?
不一定。
latest 只是一个标签名,并不一定代表真正意义上的最新版本。它由镜像维护者决定指向哪个版本。
生产环境建议使用明确版本,例如:
mysql:8.0
redis:7.2
nginx:1.25
这样可以避免某次重新拉取镜像后版本变化导致问题。
十五、零基础学习 Docker 的建议路线
如果你是零基础,可以按以下顺序学习:
- 先理解镜像、容器、仓库三个概念;
- 学会
docker pull、docker run、docker ps、docker stop、docker rm; - 用 Docker 跑 Nginx、MySQL、Redis;
- 学习端口映射和数据卷;
- 学习容器网络;
- 学习 Dockerfile,构建自己的镜像;
- 学习 Docker Compose 管理多容器项目;
- 最后再了解镜像优化、日志管理、安全配置和 CI/CD 集成。
不要一开始就追求掌握所有底层原理。Docker 的学习适合“边用边学”,先能跑起来,再逐渐理解为什么这样设计。
十六、一个适合新手的练习案例
目标:使用 Docker 启动一个 Nginx,并挂载自己的网页文件。
1. 创建目录
mkdir -p ~/docker-demo/html
2. 创建网页文件
echo "Hello Docker" > ~/docker-demo/html/index.html
3. 启动 Nginx 容器
docker run -d \
--name my-nginx \
-p 8080:80 \
-v ~/docker-demo/html:/usr/share/nginx/html \
nginx
4. 浏览器访问
http://localhost:8080
如果看到 Hello Docker,说明你已经成功使用 Docker 运行了一个 Web 服务,并完成了目录挂载。
十七、Docker 使用中的几个好习惯
-
容器命名要清晰
使用--name给容器命名,便于管理。 -
生产环境不要依赖 latest
尽量使用明确版本号。 -
重要数据一定要挂载
数据库、上传文件、配置文件不要只放在容器内部。 -
定期清理无用资源
防止磁盘被镜像、容器、缓存占满。 -
编写 Dockerfile 时注意精简
少装无用依赖,合理使用.dockerignore。 -
优先使用 Docker Compose 管理多容器项目
可读性和可维护性更好。 -
不要把密码写死在镜像中
敏感信息建议通过环境变量、配置中心或密钥管理方式注入。
十八、总结
Docker 的核心价值在于:统一环境、快速部署、隔离运行、方便迁移。对于开发者来说,它可以减少环境配置时间;对于运维人员来说,它可以提升部署效率;对于团队协作来说,它可以让每个人在相同环境下工作。
零基础学习 Docker 时,不必被复杂概念吓到。只要先掌握镜像、容器、仓库,再熟悉常用命令,能够运行 Nginx、MySQL、Redis 这类基础服务,就已经迈出了非常重要的一步。之后再逐步学习 Dockerfile、Docker Compose、网络、数据卷和镜像优化,就可以把 Docker 应用到真实项目中。
一句话记住 Docker:
镜像负责打包环境,容器负责运行应用,数据卷负责保存数据,Compose 负责管理多个容器。