张芷铭的个人博客

前言

几乎所有开发者都踩过这个经典的坑:“代码在我本地跑得好好的,一到线上就崩了”,90%的情况都是环境不一致导致的。

Docker就是来解决这个问题的:它是一个开源的容器化引擎,能把应用和它的所有依赖、运行环境,打包到一个标准化的「容器」里,保证应用在任何安装了Docker的环境下,都能以完全一致的方式运行,真正实现一次构建,到处运行

本文零废话、重实操,从底层原理到上手实战,再到学习资源,新手也能一篇吃透。


一、Docker核心原理:搞懂这3点,就懂了Docker的本质

1. 先搞懂:Docker和传统虚拟机的核心区别

很多人会把Docker和虚拟机混为一谈,其实二者的设计思路完全不同,用一个通俗的类比就能讲清:

  • 传统虚拟机 = 整租一套独立公寓,自带完整的水电、厨卫、家具(完整的Guest OS操作系统),完全硬件级隔离,但占用空间大、启动慢(分钟级)。
  • Docker容器 = 合租精装房,共用房东的基础设施(宿主机的Linux内核),你只需要带自己的行李(应用+依赖+运行配置),有独立的隔离空间,占用极小(MB级)、启动速度毫秒级。

核心差异一目了然:

对比维度传统虚拟机Docker容器
操作系统完整Guest OS共用宿主机内核
启动速度分钟级毫秒级
资源占用GB级,占用高MB级,占用极低
隔离级别硬件级完全隔离内核级轻量隔离
可移植性差,镜像体积大,迁移麻烦极强,镜像小,一次构建到处跑

2. Docker的三大底层基石

Docker不是什么黑科技,它本质上是对Linux内核三大核心能力的封装,搞懂这三个技术,就懂了Docker的底层逻辑。

(1)Namespace:实现「隔离」,给容器造一个独立小世界

Namespace是Linux内核提供的原生隔离机制,核心作用是给每个容器分配一套独立的系统资源视图,让容器里的进程只能看到自己的“小世界”,完全不会影响宿主机和其他容器。

Docker用到的6大核心Namespace,一句话讲清作用:

  • PID Namespace:隔离进程ID,容器里只能看到自己的进程,看不到宿主机的进程
  • NET Namespace:隔离网络栈,容器有自己的网卡、IP、端口、防火墙规则
  • MNT Namespace:隔离文件系统挂载点,容器有自己的根目录,默认看不到宿主机的文件系统
  • UTS Namespace:隔离主机名和域名,容器可以设置独立的主机名
  • IPC Namespace:隔离进程间通信,容器内的进程只能和同容器的进程通信
  • USER Namespace:隔离用户和用户组,容器里的root用户和宿主机的root用户不是同一个,提升安全性

(2)Cgroups(控制组):实现「资源限制」,给容器定资源配额

只有隔离没有限制,会出大问题:一个容器把宿主机的CPU、内存全占满,其他容器和宿主机直接崩掉。

Cgroups就是Linux内核提供的资源管控机制,核心作用是限制单个容器能使用的宿主机资源上限,同时还能做资源优先级、审计等操作。

它能限制的资源包括:CPU、内存、磁盘IO、网络带宽、进程数等。我们平时用的docker run -m 4G --cpus 2,就是通过Cgroup给容器设置了4G内存、2核CPU的使用上限。

(3)UnionFS(联合文件系统):实现「镜像分层」,让镜像复用、体积小、启动快

UnionFS是Docker镜像的核心,它是一种分层、轻量级的文件系统,支持把多个只读的文件系统层,联合挂载成一个统一的视图。

它的两个核心特性,直接决定了Docker的优势:

  1. 镜像分层+只读:Docker镜像是一层一层堆叠起来的,每一层都是只读的,比如基础镜像层、依赖安装层、应用代码层。多个镜像可以共享底层的镜像层——比如10个基于Ubuntu的应用镜像,只需要存一份Ubuntu基础层,极大节省了存储空间。
  2. Copy-on-Write(写时复制):容器启动时,只会在镜像的只读层之上,加一个专属的可写层。容器里所有的文件增删改,都只会发生在可写层,绝不会修改底层的只读镜像。只有当要修改一个文件时,才会把这个文件从只读层复制到可写层再修改,极大提升了容器启动速度和存储效率。

这里也能彻底分清镜像和容器的关系:

  • 镜像 = 只读的分层模板,相当于Java里的「类」
  • 容器 = 镜像+可写层+隔离的运行环境,相当于类「实例化的对象」
  • 一个镜像可以启动无数个互不干扰的容器,就像一个类可以new无数个对象。

二、Docker核心架构与实现

Docker是典型的C/S(客户端-服务端)架构,整体设计非常简洁,核心组件只有两个:

  1. Docker Client(客户端):就是我们平时敲的docker命令(docker pull、docker run等),它只负责一件事:把用户的指令,发送给Docker Daemon。
  2. Docker Daemon(守护进程):运行在宿主机后台的“老大哥”,是真正干活的核心。它负责接收客户端的指令,完成镜像拉取、容器启停、网络配置、数据卷管理等所有Docker相关的操作。

我们平时在本地敲docker命令,本质是本地Client和本地Daemon通信;也可以配置远程Client,连接服务器上的Daemon,实现远程管理容器。

基于这个架构,Docker有三个绕不开的核心概念,所有操作都围绕它们展开:

  • 镜像(Image):应用的标准化“安装包”,只读的分层文件系统,包含了应用运行需要的所有内容:代码、依赖库、环境变量、配置文件、启动命令。
  • 容器(Container):镜像的运行实例,是一个独立、隔离的运行环境。
  • 仓库(Repository):镜像的“远程存储中心”,用来上传、下载、分享镜像。最知名的是官方Docker Hub,国内常用阿里云镜像仓库,解决拉取镜像慢的问题。

三、Docker实战:零门槛上手,跟着敲就能跑通

全程可复制,零基础跟着做,10分钟就能跑通自己的第一个Docker应用。

前置准备:安装Docker

主流系统一键安装命令,复制直接用:

1
2
3
4
5
6
7
8
9
# Ubuntu/Debian 系统
sudo apt update && sudo apt install docker.io -y
sudo systemctl enable --now docker

# CentOS/RHEL 系统
sudo yum install docker -y
sudo systemctl enable --now docker

# Mac/Windows 系统:直接下载Docker Desktop安装包,一键安装即可

验证安装:执行docker --version,能输出版本号即为安装成功。

必配:国内镜像加速器(解决拉镜像慢的问题)

修改Docker配置文件/etc/docker/daemon.json,写入以下内容:

1
2
3
4
5
6
{
  "registry-mirrors": [
    "https://docker.mirrors.ustc.edu.cn",
    "https://hub-mirror.c.163.com"
  ]
}

重启Docker生效:

1
sudo systemctl daemon-reload && sudo systemctl restart docker

1. 核心命令速通(覆盖90%日常场景)

每个命令都给用法+示例+核心参数解释,零废话:

命令核心作用示例&参数解释
docker pull拉取镜像docker pull nginx:alpine
拉取精简版nginx镜像,alpine是极小的Linux发行版,镜像仅几MB
docker run启动容器docker run -d --name my-nginx -p 8080:80 -v /data/nginx/html:/usr/share/nginx/html nginx:alpine
-d:后台运行;--name:给容器命名;-p 宿主机端口:容器端口:端口映射;-v 宿主机目录:容器目录:数据卷挂载(实现数据持久化,容器删了数据还在)
docker ps查看容器docker ps 查看运行中的容器;加-a查看所有容器(包括停止的)
docker exec进入容器docker exec -it my-nginx /bin/sh
进入运行中的容器,alpine镜像用/bin/sh,非alpine用/bin/bash
docker stop/rm停止/删除容器docker stop my-nginx 停止容器;docker rm my-nginx 删除容器,加-f可强制删除运行中的容器

2. 实战案例:构建自定义镜像,跑自己的网页

核心是写Dockerfile——它是构建镜像的“配方文件”,里面写了构建镜像的每一步指令。

步骤1:新建文件夹,创建两个文件

文件1:index.html(自定义网页内容)

1
<h1>Hello Docker! 我的第一个自定义镜像</h1>

文件2:Dockerfile(无后缀名,必须和index.html在同一目录)

1
2
3
4
5
6
7
8
# 1. 基础镜像:基于官方精简版nginx
FROM nginx:alpine
# 2. 把本地的index.html,复制到容器的nginx网页根目录
COPY index.html /usr/share/nginx/html/
# 3. 声明容器要暴露的端口
EXPOSE 80
# 4. 容器启动命令:前台运行nginx
CMD ["nginx", "-g", "daemon off;"]

步骤2:构建自定义镜像

在当前文件夹执行构建命令:

1
docker build -t my-nginx:v1 .
  • -t:给镜像设置名称和版本号,格式为镜像名:版本标签
  • 结尾的.:表示Dockerfile在当前目录

步骤3:启动容器

1
docker run -d --name my-web -p 8080:80 my-nginx:v1

步骤4:验证效果

打开浏览器,访问http://你的服务器IP:8080,就能看到你写的自定义页面了!

3. Dockerfile新手最佳实践(少踩90%的坑)

  1. 优先用精简版基础镜像:首选alpine版本,体积小、安全漏洞少
  2. 减少镜像层数:合并RUN指令,比如把多个安装命令合并成一个,减少分层
  3. 清理缓存:安装依赖后,同步清理缓存文件,减小镜像体积
  4. 不使用latest标签:指定具体版本号,比如nginx:1.25.3-alpine,避免版本更新导致环境不一致
  5. 敏感信息不写在Dockerfile里:密码、密钥等,通过环境变量或机密文件挂载的方式传入

四、Docker学习资源推荐(全是精品,不踩坑)

分梯度推荐,新手按顺序学,不浪费时间。

1. 入门必看(零基础友好)

  • 官方文档Docker官方中文文档,最权威、最准确的资料,新手先看「入门指南」部分
  • 视频教程:B站狂神说Java Docker教程、尚硅谷Docker入门教程,通俗易懂、案例丰富,适合零基础快速入门
  • 在线练习平台Play with Docker,Docker官方免费在线环境,不用本地安装,打开浏览器就能练手,新手福音

2. 进阶深入(搞懂底层,提升工程能力)

  • 书籍:《Docker容器与容器云》(深入讲解底层原理和源码实现)、《Docker实战》(大量工程化案例,提升实战能力)
  • 交互式教程Katacoda,覆盖Docker到K8s的全栈交互式教程,边学边练
  • 开源资源:GitHub awesome-docker 项目,整理了Docker周边所有优质工具、资源和实战案例

3. 实用工具&站点

  • 官方镜像仓库Docker Hub,几乎所有官方镜像都在这里,是找镜像的首选
  • 国内镜像加速:阿里云镜像加速器,免费申请,国内用户必配,拉取镜像速度拉满
  • Dockerfile校验工具:Hadolint,自动检查Dockerfile语法和最佳实践,帮你写出高质量的镜像构建文件

结尾总结

Docker的核心本质,就是基于Linux内核的Namespace、Cgroup、UnionFS三大技术,实现了应用的轻量隔离、环境一致性、标准化打包和分发。它彻底解决了开发和运维之间的环境鸿沟,是云原生时代的基石技术。

学习Docker没有捷径,核心就是:先搞懂基础原理,然后多敲命令、多写Dockerfile、多做实战案例,练得多了,自然就精通了。学完Docker之后,下一步就可以学习Kubernetes(K8s)容器编排技术,搞定大规模容器的管理和调度,进入云原生的核心领域。

Comments