Docker新手学习大全:从容器思维到实战部署
2026/9/7 2:42:24 网站建设 项目流程

简介:一份面向有Linux基础与开发经验技术人员的Docker全景学习手册,内容覆盖从行业痛点与核心概念到生产级实战部署的完整链路。文档从“在我机器上能运行”等经典困境切入,用大量命令实例讲解环境搭建、镜像拉取与构建、容器生命周期管理、自定义网络配置,并深入解析Dockerfile多阶段构建、层缓存优化等最佳实践。资源为1个PDF文件,压缩包大小仅1.11MB,内容结构完整、章节清晰,便于离线阅读与随查随用。目前已有236人学习下载。除基础操作外,文档还系统介绍了Docker Compose、Swarm、Kubernetes等容器编排方案,对比五种网络模式,覆盖生产环境中的安全加固、监控日志、性能调优与典型故障排障思路,并附有分阶段学习计划和免费资源推荐,能帮助读者将所学快速落地到实际项目,实现从新手到专家的稳步进阶。 搞Docker这些年,我最大的感受就是:入门阶段最难的其实不是命令多,而是脑子里没有一套“容器思维”。很多人卡在第一步,是因为老拿Docker跟虚拟机比,结果越学越乱。这份“Docker新手学习大全”就是冲着这个问题去的——从“Docker到底解决什么问题”讲起,再到Windows和Linux下的安装、常用命令、数据持久化,最后用MySQL 8.0和Redis主从两个实战把知识串起来。文章面向的读者很明确:没碰过容器的小白、刚学完Linux想提升效率的开发者、以及想用Docker统一开发和生产环境的运维同学。读完不敢说你能成为容器专家,但至少能独立部署一套带数据库的服务,遇到常见报错知道去哪查、怎么修。

1. Docker到底解决什么问题

1.1 从“环境地狱”说起:为什么需要容器化

你一定遇到过这种场景:代码在本地跑得好好的,一到同事电脑上就报错,版本不对、依赖缺失、配置没同步,光是排查环境问题就耗掉半天。这就是典型的“环境地狱”——软件开发里最磨人、也最没技术含量的事之一。

Docker解决这个问题的方式,是把应用连同它的运行环境一起打包成一个“镜像”。镜像里有什么?有操作系统的基础层、有运行时(比如Python或Node.js)、有项目依赖的库、有配置文件。别人拿到这个镜像,不需要自己安装任何依赖,直接跑起来就是一模一样的环境。

刚入门的人容易把Docker想成一个“轻量级虚拟机”,这个类比方向对,但不够准确。虚拟机会虚拟出一整套硬件,里面跑一个完整的操作系统,启动慢、占资源。容器则直接复用宿主机的操作系统内核,只把文件系统、进程空间、网络这些做了隔离,所以容器秒级启动、占用的内存和磁盘都很小。理解这个差异,你后面看很多Docker的设计就会觉得顺理成章。

1.2 镜像与容器的关系:一次弄懂三个核心概念

Docker有三个概念必须彻底搞懂:镜像、容器、仓库。我的经验是,用“食谱、菜、图书馆”来类比特别容易记住。

镜像就是一张只读的“食谱”或者“模具”,它定义了最终跑起来的程序长什么样、依赖什么环境。容器是镜像运行起来后的“实例”,你可以对它做任何操作——装软件、改配置、跑服务,甚至弄坏了也没关系,删掉再从镜像重新生成一个就行,几秒钟的事。仓库则是存放镜像的地方,默认的Docker Hub就像是全球最大的“食谱图书馆”,里面有MySQL、Redis、Nginx等几百万个现成镜像,pull下来就能用。

这套设计带来的好处非常实用:同一个镜像可以同时跑出多个容器,互不干扰;开发环境和生产环境用同一个镜像,环境差异彻底被消灭。

1.3 新手最容易踩的认知误区

带过不少同事入门,我发现大家的困惑点高度一致。第一个误区是“容器里装了东西会不会丢”——会,如果你没挂载数据卷,容器一删数据就没了。这个问题后面会详细讲,但新手一定要现在就建立意识:容器是临时的,数据要放外面。

第二个误区是“Docker只能跑Linux程序”。早期确实如此,但现在Windows和macOS上都有Docker Desktop,底层帮你跑了一个轻量的Linux虚拟机,跑Linux容器完全没问题。

第三个误区是“镜像一定要自己写”。新手总觉得自己得从零编写Dockerfile才算会Docker,实际工作中80%的场景是直接拉官方镜像,改改参数就上线。学会写Dockerfile是加分项,但先用好现成镜像才是正确路径。

2. 环境准备与安装:Windows和Linux两条路线

2.1 Windows安装Docker Desktop:一步步操作与避坑指南

Windows上目前最主流的方案是Docker Desktop,它自带图形界面,适合新手。安装前有一个硬性检查:CPU的虚拟化必须在BIOS里开启。大部分人的电脑默认是开着的,但一些老机器或品牌机可能默认关闭。

具体安装步骤:先去官网下载Docker Desktop Installer.exe,双击运行,安装过程中保持默认选项即可。装完重启电脑,开始菜单打开Docker Desktop,等右下角小鲸鱼图标变绿就说明启动成功了。

实际上手时你会发现,真正的坑往往在启动报错环节。最经典的一条报错是:“Docker Desktop failed to start because virtualisation support wasn't detected”。这行字的意思直白:Docker需要虚拟化支持,但它没检测到。处理路径按顺序来:

  1. 进BIOS(开机按Del或F2),找到Intel Virtualization Technology或AMD SVM Mode,设为Enabled,保存重启。
  2. 如果BIOS没问题,检查Windows功能是否启用了“适用于Linux的Windows子系统”和“虚拟机平台”。在控制面板的“启用或关闭Windows功能”里勾上这两项,重启。
  3. 打开PowerShell,执行wsl --update升级WSL内核。Docker Desktop 4.26之后对WSL2内核版本有要求,老版本内核会直接导致启动失败。

我遇到过一台机器,BIOS和Windows功能都正常,最后就是wsl --update没执行,更新完立刻就能启动了。

2.2 Linux安装Docker:Ubuntu和CentOS的常用姿势

Linux服务器上装Docker其实就几条命令的事。Ubuntu用户最简单的办法是用官方安装脚本,我在全新的云服务器上实测,执行:

curl -fsSL https://get.docker.com | sh

一条命令装完,再把当前用户加入docker组,省得每次敲命令都加sudo:

sudo usermod -aG docker $USER

CentOS 7用户习惯用yum装。老实的做法是配置Docker官方的yum源后再安装,避免装到过时的版本:

sudo yum install -y yum-utils sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo yum install -y docker-ce docker-ce-cli containerd.io

装完之后不管哪个发行版,都要执行启动和开机自启:

sudo systemctl enable --now docker

如果你之前用yum装过老版本的docker,想升级到新版,直接sudo yum install docker-ce --only-upgrade即可,配置文件一般不用动。

2.3 镜像下载慢的解决办法:配置镜像加速器

国内拉Docker镜像慢是老生常谈的问题了,尤其是第一次docker pull ubuntu的时候,几MB的镜像能卡到怀疑人生。原因很简单:Docker默认从国外仓库拉取,网络路径长,速度自然上不去。

解决办法是给Docker配置“镜像加速器”,也就是registry mirror。原理不复杂:你在国内找一个和官方仓库保持同步的公共镜像服务,让Docker从更近的地方拉镜像。

Linux系统修改/etc/docker/daemon.json(没有就新建),填入:

{ "registry-mirrors": ["https://你的加速服务地址"] }

改完之后执行sudo systemctl daemon-reloadsudo systemctl restart docker,再拉镜像就会明显变快。Windows的Docker Desktop更省事,Settings -> Docker Engine里直接编辑同格式的JSON,应用后会自动重启Docker。

必须提醒一句:不要用来历不明的加速地址,尽量选择有信誉、长期维护的公共镜像服务。另外,拉取失败时不要一根筋重试,换个tag(比如把latest换成具体的版本号),或者换个时间段,往往能解决问题。

3. 核心概念与常用命令:从会用到底层原理

3.1 镜像、容器、仓库:再往深挖一层

第一节用食谱类比帮你建立了整体印象,现在往深一层讲。镜像其实是一堆只读层的堆叠,Docker通过“联合文件系统”把这些层合并成一个统一的文件系统视图。你写Dockerfile时,每一行指令(比如RUN apt-get install)都会生成一个新层。这个设计带来的好处是层可以复用,多个镜像共用同一层时,磁盘占用和拉取时间都会减少,这也是为什么Docker镜像通常比虚拟机镜像小得多。

镜像的tag也有讲究。mysql:8.0的意思是仓库名为mysql、标签为8.0的镜像,标签通常代表版本。不写tag默认拉latest,但这个tag在不同镜像里对应的版本差异很大,生产环境里强烈建议锁定具体版本号。

3.2 生命周期管理命令:日常使用频率最高的十几个

命令不需要背,多用几次自然就熟了。我最常用的命令基本能覆盖90%的日常操作,整理成表格如下:

操作命令
拉取镜像docker pull 镜像名:tag
查看本地镜像docker images
运行容器docker run -d -p 宿主机端口:容器端口 --name 容器名 镜像名:tag
查看运行中的容器docker ps
查看所有容器(含已停止)docker ps -a
进入容器内部docker exec -it 容器名 bash
查看容器日志docker logs -f 容器名
停止容器docker stop 容器名
启动已停止的容器docker start 容器名
删除容器docker rm 容器名
删除镜像docker rmi 镜像名:tag
查看容器详细信息docker inspect 容器名

实测下来,docker exec -it 容器名 bash是排查问题最频繁用到的命令。容器跑起来了但功能不正常,第一件事就是进容器看进程、看配置、看网络。docker logs排第二,大部分启动失败的线索都在这里。

3.3 数据持久化:不挂载,数据说没就没

容器设计哲学是“用完即弃”,但数据库这种服务偏偏不能这样。MySQL的数据如果写在容器里,一个docker rm就全没了。解决办法是数据卷(volume)或目录挂载(bind mount)。

最粗暴也最好理解的用法是目录挂载,启动时加参数:

docker run -d --name mysql8 -p 3306:3306 -v /data/mysql:/var/lib/mysql mysql:8.0

这行命令的意思是把宿主机的/data/mysql目录映射到容器的/var/lib/mysql目录。MySQL往容器里写数据,实际落盘到了宿主机上,容器删了、换了,数据依然还在。

命名卷(named volume)是官方更推崇的用法:

docker run -d --name mysql8 -v mysql_data:/var/lib/mysql mysql:8.0

区别在于你不关心数据具体存在宿主机哪个目录,Docker统一管理。好处是备份迁移方便,坏处是对新手来说不够直观。我的建议:个人学习用挂载目录最直观,生产环境按团队规范来。

3.4 端口映射与网络模式:容器之间怎么通信

容器默认使用桥接网络,它会从Docker分配的子网里拿一个IP。但这个IP是Docker内部的,宿主机和外面网络访问不到。要对外提供服务,必须做端口映射:-p 宿主机端口:容器端口

比如-p 3306:3306就是把宿主机的3306端口流量转发到容器的3306端口。如果宿主机3306已被占用,可以改成-p 3307:3306,外部通过3307访问,这对本地装了原生MySQL、又想在Docker里跑一个的人来说特别实用。

容器之间通信有几种方式。最简单的是通过IP访问,但Docker重启后容器的IP可能变化,所以不推荐。更优雅的方式是创建自定义网络,容器之间通过容器名互相访问:

docker network create my-net docker run -d --name mysql8 --network my-net mysql:8.0 docker run -d --name myapp --network my-net myapp:latest

这样一来,myapp容器里连接数据库只需用mysql8作为主机名,网络层面由Docker自动解析,IP怎么变都不影响。

4. 实战一:用Docker部署MySQL 8.0

4.1 拉取镜像与启动:三分钟跑起一个数据库

选MySQL 8.0做第一个实战,是因为它是目前最主流的关系型数据库,部署过程中会涉及到数据卷、环境变量、端口映射、进入容器排错等多个核心知识点。

第一步拉镜像:

docker pull mysql:8.0

第二步启动容器:

docker run -d \ --name mysql8 \ -p 3306:3306 \ -e MYSQL_ROOT_PASSWORD=MyRootPass123 \ -e TZ=Asia/Shanghai \ -v /data/mysql:/var/lib/mysql \ mysql:8.0

-d表示后台运行;--name给容器起名;-e传入环境变量,MySQL官方镜像用MYSQL_ROOT_PASSWORD指定root密码,用TZ设置时区;-v挂载数据目录。这时候用docker ps看状态,如果变成Up,说明MySQL已经在跑。用Navicat或其他客户端连一下localhost:3306,用户名root,密码就是你设的那个。

4.2 进入容器:验证版本、字符集和配置

容器跑起来了,怎么确认里面配置对不对?答案是进入容器内部直接操作:

docker exec -it mysql8 bash

进去之后就是Linux命令行,执行mysql -uroot -p输入密码进入MySQL客户端。两个东西建议确认一下:一是SELECT VERSION();看版本是否是8.0;二是SHOW VARIABLES LIKE 'character%';看字符集。MySQL 8.0默认字符集就是utf8mb4,一般不需要额外配置,但如果你的项目需要定制配置,比如调低max_connections、修改sql_mode,可以在宿主机建一个配置文件然后挂载进去:

docker run -d \ --name mysql8 \ -p 3306:3306 \ -e MYSQL_ROOT_PASSWORD=MyRootPass123 \ -v /data/mysql/conf.d:/etc/mysql/conf.d \ -v /data/mysql:/var/lib/mysql \ mysql:8.0

把自定义的.cnf文件放到宿主机的/data/mysql/conf.d目录,MySQL启动时会自动加载。这样改配置不用重新构建镜像,改文件后重启容器即可。

4.3 实战中的常见坑:端口冲突、密码失效、时区错乱

先说自己踩过的两个坑。第一个是端口冲突。本机装了原生MySQL的情况下,再启动容器映射3306,必然报错。解决办法就是换宿主机端口,-p 3307:3306,外部连接时填3307。

第二个坑是容器能启动但连不上。这时候按三步排查:先docker ps确认容器状态是Up;再docker logs mysql8看启动日志;最后docker exec -it mysql8 bash进容器内用mysql命令连本机。如果容器内能连、外面连不上,基本就是端口映射或防火墙的问题。

还有一个小细节,MySQL 8.0的caching_sha2_password认证插件对老版本客户端兼容性不太好。如果你是用的Navicat旧版或老项目,连接时报“Authentication plugin 'caching_sha2_password' cannot be loaded”,可以创建用户时指定兼容插件:

CREATE USER 'app'@'%' IDENTIFIED WITH mysql_native_password BY 'password'; GRANT ALL PRIVILEGES ON *.* TO 'app'@'%';

4.4 清理容器与镜像:不用的资源及时回收

测试过程中可能会创建很多容器,堆积在系统里。

docker rm -f mysql8

-f表示强制删除运行中的容器。删除容器不会影响挂载在宿主机/data/mysql的数据,所以你可以尽情折腾,删错了重新run一次,数据都还在。这就是数据卷挂载最实在的价值——把容器当成一次性的进程,而不是需要细心呵护的“虚拟机”。

5. 实战二:用Docker Compose部署Redis主从

5.1 Compose是什么:多容器编排的“一键启动”

手动docker run部署单个容器没问题,但部署有依赖关系的一整套服务时,命令会变得又长又难维护。Docker Compose就是干这个的:用一份YAML文件定义多个服务,一条docker compose up -d全部启动。

Redis主从是个很好的入门场景:一个主节点负责写,一个从节点负责读,配置简单,却覆盖了Compose的核心用法。先看docker-compose.yml文件:

version: '3' services: redis-master: image: redis:7.0 container_name: redis-master ports: - "6379:6379" volumes: - ./redis-master.conf:/etc/redis/redis.conf command: redis-server /etc/redis/redis.conf redis-slave: image: redis:7.0 container_name: redis-slave depends_on: - redis-master ports: - "6380:6379" volumes: - ./redis-slave.conf:/etc/redis/redis.conf command: redis-server /etc/redis/redis.conf

5.2 主从配置文件:一分钟看懂核心参数

主节点配置redis-master.conf,重点是开启密码保护:

requirepass redisMaster123

从节点配置redis-slave.conf,重点是指定主节点地址。注意这里的主机名是Compose服务名redis-master,Compose内部自动做了DNS解析:

requirepass redisMaster123 replicaof redis-master 6379 masterauth redisMaster123

两个配置文件放在docker-compose.yml同目录下,然后执行:

docker compose up -d

docker compose ps查看状态,看到两个服务都是Up,用docker compose logs redis-slave | grep -i "MASTER"可以确认主从是否建立成功。

5.3 实测验证主从复制:写主读从

主从配置好了,怎么验证真在同步数据?启动一个临时Redis客户端容器来测试:

docker exec -it redis-master redis-cli -a redisMaster123 set testkey hello docker exec -it redis-slave redis-cli -a redisMaster123 get testkey

主节点写入testkey,从节点能读到同样的值,说明主从复制已经生效。

这里要强调一个新手特别容易忽略的点:depends_on只保证容器启动顺序,不保证主节点已经就绪。刚才的例子里从节点可能比主节点先完成启动,然后在主节点可用之前就尝试连接,需要重试。Redis从节点有自动重连机制,一般不会出问题,但你在编排复杂服务时,一定要意识到depends_on不是万能的,必要时需要在应用层做健康检查或重试。

5.4 Compose的日常操作:启动、停止、看日志

Compose最舒服的一点是,整个服务组可以通过一条命令统一管理:

docker compose up -d # 启动全部服务 docker compose ps # 查看服务状态 docker compose logs -f # 实时查看所有服务的日志 docker compose down # 停止并删除全部容器

注意docker compose down默认不会删除挂载的volume数据,这点设计很合理,方便你随手重建服务而不丢数据。如果想连数据一起清掉,才需要加-v参数。

实际使用中我发现,把docker-compose.yml提交到Git仓库,团队新成员一拉代码,docker compose up -d就拥有完整环境,比写十几页的环境搭建文档高效得多。

6. 进阶实战:构建自己的镜像与环境一致性

6.1 编写Dockerfile:从零打包一个应用镜像

拉现成镜像只能覆盖通用软件,自己写的应用最终还是要打成一个专属镜像。这份学习的最终目标,是让你能独立完成这一步。

一个最简单的Node.js应用Dockerfile长这样:

FROM node:18 WORKDIR /app COPY package*.json ./ RUN npm install COPY . . EXPOSE 3000 CMD ["npm", "start"]

每一行的含义:FROM指定基础镜像,好比“买了一套带精装修的毛坯房”;WORKDIR设定容器内的工作目录,后续操作都在这里执行;COPY把本地的package.json拷进去;RUN npm install安装依赖;再次COPY把全部源码放进来;EXPOSE声明容器监听端口,不过它只是文档性质的,真正的端口映射还是要靠-pCMD定义容器启动时执行的命令。

构建命令:

docker build -t myapp:1.0 .

-t指定镜像名和tag,最后的.表示Dockerfile所在目录(也叫构建上下文)。

6.2 镜像瘦身的实用技巧:多阶段构建

新手构建镜像最常见的毛病是“什么都往里装”,最后镜像几个GB,拉取慢、占用大。

多阶段构建是解决这个问题的标准姿势。拿一个Java Spring Boot应用举例:

# 第一阶段:使用包含完整JDK的镜像进行编译 FROM maven:3.8-openjdk-17 AS build WORKDIR /app COPY pom.xml . RUN mvn dependency:go-offline COPY src ./src RUN mvn package -DskipTests # 第二阶段:只拷贝编译产物,配合精简运行环境 FROM openjdk:17-jre-slim WORKDIR /app COPY --from=build /app/target/*.jar app.jar EXPOSE 8080 CMD ["java", "-jar", "app.jar"]

关键就在于第一阶段是“编译器”,第二阶段是“运行环境”。最终镜像里只有编译好的jar包和精简版JRE,没有源码、没有Maven、没有临时文件,镜像体积能缩小一大半。

6.3 由“部署一个服务”到“部署一组服务”

学会单镜像构建后,自然要过渡到多服务编排。把前一节的Compose思路和自定义镜像结合,就是一套典型的微服务开发环境:前端一个容器、后端两个服务容器、中间件(MySQL/Redis)各一个容器,全部由Compose管理。

实际项目里我常看到的问题是用IP地址写配置。容器重启IP可能会变,导致服务之间突然连不上。正确的做法是:服务间通信使用服务名,把配置信息(数据库地址、密码)通过环境变量注入,而不是写死。Compose的environment字段和env_file就是干这个的。

还有一个容易被忽略的点:构建镜像时避免把敏感信息写进Dockerfile。比如数据库密码如果你是RUN echo 'password'写进去的,别人一docker history你的镜像,密码就暴露了。正确做法是运行时通过环境变量传入,或者用Docker Secret管理。

7. 常见问题与排查技巧速查

学完前面的内容,剩下的就是实战中不断遇到报错、解决报错的过程。我把自己这一年多来遇到的高频问题整理成一个速查表,方便你直接对照处理:

现象可能原因排查与解决
Docker服务启动失败宿主机内核版本过低、配置文件损坏sudo journalctl -u docker看日志;检查/etc/docker/daemon.json语法是否正确
docker命令提示permission denied当前用户不在docker组执行sudo usermod -aG docker $USER后重新登录;临时方案是命令前加sudo
容器启动后立即退出前台进程结束、配置错误docker logs 容器名查看日志,多数线索都在这里
镜像拉取超时网络问题、镜像过大配置镜像加速;换用体积更小的tag;多试几次
端口映射后外部访问不了防火墙、端口被占用先宿主机curl localhost:端口测试;再检查防火墙;最后看容器IP能否直接访问
磁盘空间告急悬空镜像、无用缓存堆积执行docker system prune清理;docker system df查看空间占用分布
MySQL中文乱码连接时字符集不对确认连接字符串加了characterEncoding=utf8;确认容器内字符集是utf8mb4
Redis主从不生效密码不一致、网络不通检查masterauth是否配置;docker compose logs看主从连接日志

7.1 两个必须养成的习惯:看日志和看状态

排查Docker问题,我始终坚信一条原则:先看日志,再看状态,最后才动用搜索引擎。

很多新手一看到容器没起来,第一反应是把容器删了重新跑,结果还是一样报错,殊不知docker logs早就把原因说得明明白白。容器的标准输出被Docker捕获,docker logs能看到应用打印的日志,服务启动失败、连接失败、配置文件加载错误,全都写在这里。

docker inspect则是看容器配置细节的神器。它输出的是庞大的JSON,包含环境变量、挂载卷、网络配置、重启策略等一切信息。用grep过滤一下,比到处猜靠谱得多。

7.2 资源清理:别让你的机器被镜像堆满

学习阶段你会频繁拉镜像、构建镜像、跑容器,磁盘很容易被吃光。docker system df可以看清磁盘占用分布,docker system prune一条命令清掉停止的容器、悬空镜像和未使用的网络。加-a参数会连未被任何容器使用的镜像一起清理,谨慎使用。

最后再分享一点个人经验

按这套学习路径走下来,你大概需要半个月的时间就能把Docker用得有模有样。我的建议是:不要刻意背命令,把原理搞懂,命令用多了自然就记住了;不要想着看完所有文档再动手,先跑起来一个Nginx,再部署MySQL,然后写自己的Dockerfile,最后上Compose编排。每一步都踩在实地上,遇到问题回来翻这个速查表,基本都能解决。容器技术更新很快,但核心思路——环境隔离、镜像复用、数据持久化——不会变,把这些根基打牢,以后接触Kubernetes、Service Mesh这些上层技术时,你会发现一切都很顺理成章。

本文还有配套的精品资源,点击获取

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

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

立即咨询