文章目录
-
- [1. docker环境和基本概念](#1. docker环境和基本概念)
-
- [1. 安装(基于apt包管理器安装)](#1. 安装(基于apt包管理器安装))
- [2. 卸载](#2. 卸载)
- [3. 自定义镜像库](#3. 自定义镜像库)
- [4. 将用户添加到docker组(不用每次都sudo)](#4. 将用户添加到docker组(不用每次都sudo))
- [5. 镜像和容器的关系](#5. 镜像和容器的关系)
- [6. docker解决了什么问题](#6. docker解决了什么问题)
- [7. docker局限](#7. docker局限)
- [8. docker带给开发的改变](#8. docker带给开发的改变)
- [9. docker和虚拟机的区别](#9. docker和虚拟机的区别)
- [10. 基本架构图](#10. 基本架构图)
- [11. rootfs](#11. rootfs)
- [12. linux namespace](#12. linux namespace)
- [13. 进程命名空间](#13. 进程命名空间)
- [14. cgroups](#14. cgroups)
-
- [1. CPU 子系统 (cpu / cpuacct)](#1. CPU 子系统 (cpu / cpuacct))
- [2. CFS (Completely Fair Scheduler)](#2. CFS (Completely Fair Scheduler))
- [3. RT (Real-Time scheduling) 子系统](#3. RT (Real-Time scheduling) 子系统)
- [4. 三者关系总结](#4. 三者关系总结)
- [5. cpuset 子系统](#5. cpuset 子系统)
- [6. cpuacct 子系统](#6. cpuacct 子系统)
- [7. memory 子系统](#7. memory 子系统)
- [8. blkio 子系统](#8. blkio 子系统)
- [9. devices 子系统](#9. devices 子系统)
- [10. freezer 子系统](#10. freezer 子系统)
- [11. net_cls 子系统](#11. net_cls 子系统)
- [12. net_prio 子系统](#12. net_prio 子系统)
- [15. docker常用命令](#15. docker常用命令)
-
- 1.环境信息
- [2. 系统日志](#2. 系统日志)
- [3. 容器生命周期](#3. 容器生命周期)
- [4. 运维](#4. 运维)
- [5. 镜像管理](#5. 镜像管理)
- [6. 镜像仓库](#6. 镜像仓库)
1. docker环境和基本概念
1. 安装(基于apt包管理器安装)
shell
sudo apt install docker.io
2. 卸载
shell
sudo apt-get purge docker.io
sudo rm -rf /var/lib/docker
sudo rm -rf /var/lib/containerd
3. 自定义镜像库
由于存在国内外数据下载速度不一致,所以采用自定义镜像库
linux:/etc/docker/daemon.json
macos:磁盘/用户/mac/(隐藏文件).docker
shell
{
"registry-mirrors": [
"https://hub.xdark.top",
"https://hub.littlediary.cn",
"https://dockerpull.org",
"https://hub.crdz.gq",
"https://docker.1panel.live",
"https://docker.unsee.tech",
"https://docker.udayun.com",
"https://docker.kejilion.pro",
"https://registry.dockermirror.com",
"https://docker.rainbond.cc",
"https://hub.geekery.cn",
"https://docker.1panelproxy.com",
"https://docker.linkedbus.com",
"https://docker.nastool.de"
]
}
接着载入:
linux:
shell
sudo systemctl daemon-reload
sudo systemctl restart docker
macos:
shell
sudo launchctl daemon-reload
sudo launchctl restart docker
4. 将用户添加到docker组(不用每次都sudo)
linux:
shell
sudo groupadd docker # 创建 docker 组(如果不存在)
sudo usermod -aG docker $USER
mac:
macOS 使用 Docker Desktop,它是一个普通用户应用,容器操作通过后台进程管理,不需要 Linux 用户组权限,在终端运行 Docker 命令时,只要 当前用户已经登录 Docker Desktop,就可以直接执行命令:
shell
docker run hello-world
根本不需要 sudo,也不需要设置 docker 组
5. 镜像和容器的关系
是相同引用
镜像是模板,容器是实例
可以从一个镜像创建多个容器
shell
docker run -it ubuntu bash # 用 ubuntu 镜像运行一个容器
docker run -it ubuntu bash # 再运行一个,还是独立的容器
容器删除了,镜像还在
镜像删除了,之前的容器还能跑(因为容器里已经有了写层),但你不能再用那个镜像新建容器
镜像 (Image) ---> 容器 (Container)
只读层 + 可写层
模板 + 实例
6. docker解决了什么问题
- 解决了应用程序本地运行环境与生产运行环境不一致的问题
- 解决了应用程序资源使用的问题,docker会一开始就为每个程序指定内存分配和CPU分配
- 让快速扩展、弹性伸缩变得简单
7. docker局限
docker是容器化技术,针对的是应用及应用所依赖的环境做容器化。遵循单一原则,一个容器只运行一个主进程。多个进程都部署在一个容器中,弊端很多。比如更新某个进程的镜像时,其他进程也会被迫重启,如果一个进程出问题导致容器挂了,所有进程都将无法访问。再根据官网的提倡的原则而言,容器 = 应用 + 依赖的执行环境而不是像虚拟机一样,把一堆进程都部署在一起
8. docker带给开发的改变
环境一致性:开发、测试、生产环境完全统一,避免"在我机器上能跑"的问题。
快速启动与隔离:一行命令即可运行服务,多版本环境互不干扰。
依赖管理清晰:每个项目在独立容器中运行,避免依赖冲突。
提升 CI/CD 效率:镜像打包后可直接部署,发布流程自动化、标准化。
支持微服务架构:每个服务单独容器化,方便扩展、升级和编排。
跨平台迁移方便:镜像自带环境与依赖,可在不同平台无差别运行。
9. docker和虚拟机的区别
传统虚拟机 (VM)
┌───────────────────────────────┐
│ 物理硬件 (Hardware) │
├───────────────────────────────┤
│ 主机操作系统 (Host OS)│
├───────────────────────────────┤
│ Hypervisor (虚拟机管理器) │
├───────────────┬───────────────┤
│ Guest OS │ Guest OS │ (每个虚拟机都有完整的操作系统)
│ Libraries │ Libraries │
│ App1 │ App2 │
└───────────────┴───────────────┘
Docker (容器)
┌───────────────────────────────┐
│ 物理硬件 (Hardware) │
├───────────────────────────────┤
│ 主机操作系统 (Host OS)│
├───────────────────────────────┤
│ Docker Engine │
├───────────────┬───────────────┤
│ Libraries │ Libraries │ (共享同一个内核,无需重复OS)
│ App1 │ App2 │
└───────────────┴───────────────┘
- 虚拟机:每个应用都需要跑一个完整的 Guest OS → 占用资源大,启动慢。
- Docker 容器:共享同一个内核,只隔离应用环境 → 占用小,启动快,部署灵活
10. 基本架构图
docker基本架构图:
┌──────────────────────────┐
│ Docker Registry (注册中心) │
│ Docker Hub / 私有仓库 │
└───────────▲──────────────┘
│ pull/push 镜像
│
┌────────────────────────────┴───────────────────────────┐
│ Docker Host (主机) │
│ │
│ ┌───────────────┐ ┌─────────────────────────┐ │
│ │ Docker Client │─────▶│ Docker Daemon (守护进程) │ │
│ │ (CLI / API) │◀─────│ 接收命令,管理容器/镜像 │ │
│ └───────────────┘ └─────────────────────────┘ │
│ │ │
│ │ run/start/stop │
│ ▼ │
│ ┌────────────────┐ ┌─────────────────────┐ │
│ │ Image (镜像) │───▶ │ Container (容器) │ │
│ │ 只读模板 │ │ 镜像运行的实例,带状态 │ │
│ └────────────────┘ └─────────────────────┘ │
│ │
└────────────────────────────────────────────────────────┘
- 镜像(Image):Docker 镜像是用于创建 Docker 容器的模板,比如 Ubuntu 系统
- 容器(Container):容器是独立运行的一个或一组应用,是镜像运行时的实体
- 客户端(client):Docker 客户端通过命令行或者其他工具使用 Docker SDK(Software Development Kit,开发接口) 与 Docker 的守护进程通信
- 主机(host):一个物理或者虚拟的机器用于执行 Docker 守护进程和容器
- 注册中心(Registry):Docker 仓库用来保存镜像,可以理解为代码控制中的代码仓库。Docker Hub提供了庞大的镜像集合供
11. rootfs
rootfs 是Docker 容器在启动时内部进程可见的文件系统,即Docker容器的根目录。rootfs通常包含一个操作系统运行所需的文件系统,例如可能包含经典的类Unix操作系统中的目录系统,如/dev、/proc、/bin、/etc、/lib、/usr、/tmp及运行Docker容器所需的配置文件、工具等。
12. linux namespace
Namespace(命名空间)是 Linux 内核提供的一种 隔离机制。
它把同一台 Linux 内核分成多个"虚拟的独立环境",每个环境里的进程都认为自己是独立的。
(大寝室->单间)
- PID Namespace
隔离进程号(PID),容器里看到的进程号是从 1 开始的。
好处:容器里的 ps -ef 看不到宿主机的进程。 - NET Namespace
隔离网络协议栈(IP 地址、路由表、端口)。
好处:容器里可以有独立的 IP 地址,绑定自己的端口。 - IPC Namespace
隔离进程间通信(消息队列、信号量、共享内存)。
好处:容器之间不能随便共享内存区。 - UTS Namespace
隔离主机名和域名。
好处:容器里可以设置自己的 hostname。 - MNT Namespace
隔离文件系统挂载点。
(什么是挂载(mount)
在 Linux/Unix 系统里,存储设备(硬盘分区、U盘、ISO 镜像等)上有自己的 文件系统。
这些文件系统默认和系统根目录 / 是分开的,系统本身不能直接访问。
挂载(mount) 就是把一个文件系统 "接到" 某个目录上,让操作系统能通过这个目录访问它的内容。
挂载点(mount point)
挂载点就是一个空目录,挂载文件系统后,这个目录就显示挂载文件系统的内容。
比喻:
系统根目录 / 是房子的大厅。
外接硬盘有自己的内容。
挂载点就是把硬盘"搬进"大厅的某个房间,比如 /mnt/usb,进去这个房间就能看到硬盘里的文件。)
好处:容器有自己的 / 根目录,看不到宿主机完整的文件系统。) - USER Namespace
隔离用户和用户组 ID。
好处:容器里的 root 用户,可以映射成宿主机的普通用户,增强安全性。
Docker Registry
Docker Host
Docker Client
Docker Engine
Components
docker command
HTTP REST API
docker CLI
Docker SDK (API)
Docker Daemon (dockerd)
Images
Containers
Docker Hub / Private Registry
13. 进程命名空间
这里直接拉取ubuntu,在里面进行命令操作
shell
docker pull ubuntu:22.04
#启动ubuntu容器
docker run -it --privileged ubuntu:22.04 /bin/bash
#-it:交互式终端。
#--privileged:允许容器访问更多 Linux 功能,比如命名空间。
#/bin/bash:进入 bash
# 这个时候命令行会变成:root@<container_id>:/#
#安装命令包
apt update
apt install -y util-linux
#然后就可以运行命令
lsns -p <PID>
#退出容器
exit
#直接退出之后,虽然镜像在,但是容器即这个实例没了,之前操作也没有了(默认是不删除的),所以最好保存一下(哪怕只是重命名好记一点)
docker run -it --name myubuntu --privileged ubuntu:22.04 /bin/bash
#以后启动:
docker start -ai myubuntu
# 重命名
docker rename quirky_sammet myubuntu
# 以后可以用:
docker start -ai myubuntu
#在其他终端还想连这个docker
docker exec -it myubuntu /bin/bash
- 查看宿主机命名空间
shell
lsns
显示所有命名空间(PID, NET, UTS, IPC, USER, MNT...)
- 查看某个进程命名空间
shell
# pid=1的命名空间
lsns -p 1
#查看符号连接
ls -l /proc/1/ns
- 查看当前用户shell的命名空间
shell
ls -l /proc/$$/ns
# $$代表当前shell的pid
- 查看容器命名空间
shell
#获取容器内主进程id
docker inspect -f '{{.State.Pid}}' <容器ID或名字>
# 查看它命名空间
ls -l /proc/12345/ns
- 进入容器命名空间
shell
nsenter --target 12345 --pid --uts --net --mount
- Docker 常见隔离实验操作
shell
# (1)查看容器进程(宿主机 vs 容器)
# 宿主机看容器进程:
ps -ef | grep <容器名>
# 容器内看进程(PID 从 1 开始):
docker exec -it <容器> ps -ef
# (2) 网络隔离
# 查看容器网络接口:
docker exec -it <容器> ip addr
# 对比宿主机的:
ip addr
# (3) 挂载点隔离
# 容器里:
mount | head
# 宿主机:
mount | head
# 容器和宿主机看到的文件系统不同。
# (4) UTS 隔离(主机名)
# 宿主机:
hostname
# 容器:
docker exec -it <容器> hostname
# 不同容器有不同 hostname。
# (5) 用户隔离
# 容器里默认 root 其实是 容器内部的 root,和宿主机 root 不一样。
# 可以在容器里 id 查看:
docker exec -it <容器> id
14. cgroups
cgroup全称是control groups,被整合在了linux内核当中,把进程(tasks)放到组里面,对组设置权限,对进程进行控制。可以理解为用户和组的概念,用户会继承它所在组的权限
1. CPU 子系统 (cpu / cpuacct)
在 cgroups 中,cpu 子系统用来限制和调度进程的 CPU 使用率。
常见的控制点有:
cpu.shares:相对权重(权重高的 cgroup 能分到更多 CPU 时间片)。
cpu.cfs_quota_us 和 cpu.cfs_period_us:基于 CFS 调度器的配额机制,决定一个 cgroup 在一段时间内最多能用多少 CPU。
cpuacct:统计 CPU 使用情况(累计使用的 CPU 时间等)。
2. CFS (Completely Fair Scheduler)
CFS = 完全公平调度器,是 Linux 默认的 CPU 调度器。
思路:让所有进程尽量"公平"地分享 CPU 时间。
内部逻辑:维护一个红黑树,把每个进程的 虚拟运行时间 vruntime 排序。运行时间最少的进程最先被调度。
在 cgroups 里,CFS 的参数:
cpu.cfs_period_us:调度周期(默认 100ms = 100000 us)。
cpu.cfs_quota_us:在一个周期内允许使用的时间。
比如:cpu.cfs_quota_us = 20000 且 cpu.cfs_period_us = 100000 → 这个 cgroup 最多能用 20% CPU。
如果 -1,表示不限制。
应用场景:控制容器的 CPU 使用率,避免某个容器把宿主机 CPU 占满。
3. RT (Real-Time scheduling) 子系统
除了 cpu,Linux 还有 cpu.rt_runtime_us 和 cpu.rt_period_us,这是 实时调度 (RT) 的配置。
RT 调度类包括 SCHED_FIFO 和 SCHED_RR,用于需要确定性延迟的实时任务。
参数解释:
cpu.rt_period_us:实时任务的调度周期(比如 1s)。
cpu.rt_runtime_us:在该周期内,允许所有 RT 任务一共能运行的时间。
举个例子:
cpu.rt_period_us = 1000000 (1 秒)
cpu.rt_runtime_us = 200000 (200ms)
→ 那么在 1 秒内,实时任务最多能占用 20% CPU,避免把 CPU 时间全部抢走。
应用场景:
RT 主要用于对延迟极度敏感的任务(工业控制、音视频处理、机器人系统),普通容器一般不用。
shell
# 限制某个容器只能用50%cpu
# 创建一个cgroup
# 注意到在这么深的文件夹内新建,因为这是内核挂载的cgroup虚拟文件系统
mkdir /sys/fs/cgroup/cpu/mygroup
# 限制周期100ms
echo 100000 > /sys/fs/cgroup/cpu/mygroup/cpu.cfs_period_us
# 限制配额50ms -> 50%
echo 50000 > /sys/fs/cgroup/cpu/mygroup/cpu.cfs_quota_us
# 把进程 12345 加入这个 cgroup
echo 12345 > /sys/fs/cgroup/cpu/mygroup/cgroup.procs
4. 三者关系总结
cpu 子系统:cgroups 的 CPU 控制模块,总管 CPU 使用限制。
CFS:Linux 默认的公平调度器,用 cfs_quota/cfs_period 实现 CPU 限额。
RT:实时调度类,用 rt_runtime/rt_period 来保证实时任务的确定性。
5. cpuset 子系统
作用:控制进程运行在哪些 CPU 核心 和 NUMA 内存节点 上。
关键文件:
cpuset.cpus → 允许使用的 CPU 核(如 0-2,4 表示 CPU0、1、2、4)。
cpuset.mems → 允许使用的内存节点。
例子:让某个进程只能跑在 CPU 0 和 CPU 1:
shell
mkdir /sys/fs/cgroup/cpuset/myset
echo 0-1 > /sys/fs/cgroup/cpuset/myset/cpuset.cpus
echo 0 > /sys/fs/cgroup/cpuset/myset/cpuset.mems
echo 12345 > /sys/fs/cgroup/cpuset/myset/cgroup.procs
应用场景:多核环境下做 CPU 绑定(如数据库绑核心,避免抖动)。
6. cpuacct 子系统
作用:统计 CPU 使用情况,通常和 cpu 子系统配合用。
文件:
cpuacct.usage(纳秒级 CPU 时间)
cpuacct.stat(用户态/内核态使用时间)
例子:
shell
cat /sys/fs/cgroup/cpuacct/mygroup/cpuacct.usage
cat /sys/fs/cgroup/cpuacct/mygroup/cpuacct.stat
用来做 监控、计费。
7. memory 子系统
作用:限制/统计内存使用。
常见文件:
memory.limit_in_bytes → 内存上限
memory.usage_in_bytes → 当前内存使用量
memory.oom_control → 是否允许 OOM-killer
例子:限制某进程最多用 200MB 内存:
shell
mkdir /sys/fs/cgroup/memory/mygroup
echo 200M > /sys/fs/cgroup/memory/mygroup/memory.limit_in_bytes
echo 12345 > /sys/fs/cgroup/memory/mygroup/cgroup.procs
应用场景:避免某个容器爆内存导致宿主机崩溃。
8. blkio 子系统
作用:控制块设备 I/O 带宽/IOPS。
文件:
blkio.throttle.read_bps_device
blkio.throttle.write_bps_device
blkio.throttle.read_iops_device
例子:限制进程对 /dev/sda 的读速率不超过 1MB/s:
shell
echo "8:0 1048576" > /sys/fs/cgroup/blkio/mygroup/blkio.throttle.read_bps_device
应用场景:防止某个任务疯狂读写硬盘,拖慢系统。
9. devices 子系统
作用:控制进程能否访问某些设备(如 /dev/sda, /dev/null)。
文件:
devices.allow
devices.deny
例子:允许访问 /dev/null:
shell
echo "c 1:3 rwm" > /sys/fs/cgroup/devices/mygroup/devices.allow
场景:安全隔离,比如容器不能直接访问宿主机硬盘设备。
10. freezer 子系统
作用:挂起/恢复 cgroup 内所有进程。
文件:freezer.state(FROZEN/THAWED)
例子:冻结某个组:
shell
echo FROZEN > /sys/fs/cgroup/freezer/mygroup/freezer.state
应用:暂停容器(类似 docker pause)。
11. net_cls 子系统
作用:给进程打上 网络流量 classid,用于 tc (traffic control) 匹配。
文件:net_cls.classid
例子:
shell
echo 0x10001 > /sys/fs/cgroup/net_cls/mygroup/net_cls.classid
应用:不同容器流量走不同的 QoS 策略。
12. net_prio 子系统
作用:设置网络接口的优先级。
文件:net_prio.ifpriomap
例子:
shell
echo "eth0 5" > /sys/fs/cgroup/net_prio/mygroup/net_prio.ifpriomap
应用:保证关键容器(如数据库)的网络优先级高。
总结表格
| 子系统 | 功能 | 例子/应用场景 |
|---|---|---|
| cpu | 限制 CPU 使用率 | 限制容器只能用 50% CPU |
| cpuset | 绑定 CPU/内存节点 | 数据库绑核 |
| cpuacct | 统计 CPU 使用 | 监控/计费 |
| memory | 限制内存 | 防止 OOM |
| blkio | 限制磁盘 IO | 防止容器拖慢磁盘 |
| devices | 控制设备访问 | 禁止容器访问宿主硬盘 |
| freezer | 挂起/恢复进程 | docker pause |
| net_cls | 打标签,配合 tc 做流量控制 | QoS |
| net_prio | 设置网络优先级 | 关键服务优先 |
15. docker常用命令
1.环境信息
shell
docker info
docker version
2. 系统日志
shell
docker events : 从服务器获取实时事件
# OPTIONS说明:
# -f :根据条件过滤事件;
# --since :从指定的时间戳后显示所有事件;
# --until :流水时间显示到指定的时间为止;
# //第一个终端执行
# docker events
# //第二个终端操作容器
# docker start/stop/restart
# //查看第一个终端输出
# 获取容器日志
docker logs
# 查看指定镜像的创建历史
docker history
3. 容器生命周期
shell
# 创建一个新容器但是不启动
docker create
# 创建一个新的容器并运行一个命令
docker run
#启动一个或多个已经被停止的容器
docker start
# 停止一个运行中的容器(发送信号给主进程,可能造成数据未保存)
docker stop
# 重启容器
docker restart
# 杀掉一个运行中的容器(容器马上退出,可能造成数据没保存)
docker kill
# 删除一个或多个容器。
docker rm
# 暂停容器中所有的进程。
docker pause
# 恢复容器中所有的进程
docker unpause
4. 运维
shell
# 在运行的容器中执行命令
docker exec
# 列出容器
docker ps
# 获取容器/镜像的元数据
docker inspect
# 查看容器中运行的进程信息
docker top
# 连接到正在运行中的容器
docker attach
# 阻塞运行直到容器停止,然后打印出它的退出代码
docker wait
# 将文件系统作为一个tar归档文件导出到STDOUT
docker export
# 用于容器和主机之间的数据拷贝
docker cp
# 检查容器里面文件结构的更改
docker diff
# 重命名
docker rename
# 查看状态
docker stats
# docker update 命令用于 动态修改已经运行的容器的资源限制,不需要重新创建容器
docker update
5. 镜像管理
shell
# 命令用于使用 Dockerfile 创建镜像
docker build
# 列出本地镜像
docker images
# 删除本地一个或多个镜像
docker rmi
# 标记本地镜像,将其归入某一仓库
docker tag
# 将指定镜像保存成 tar 归档文件
docker save
# 导入使用 docker save 命令导出的镜像
docker load
# 从归档文件中创建镜像
docker import
# 从容器创建一个新的镜像
docker commit
6. 镜像仓库
shell
#登陆/登出到一个Docker镜像仓库,如果未指定镜像仓库地址,默认为官方仓库 Docker Hub
docker login/logout
# 从镜像仓库中拉取或者更新指定镜像
docker pull
# 将本地的镜像上传到镜像仓库,要先登陆到镜像仓库
docker push
# 从Docker Hub查找镜像
docker search