第一次上传

This commit is contained in:
2025-08-27 14:07:52 +08:00
commit ac04d1bdb4
1310 changed files with 42760 additions and 0 deletions

View File

@@ -0,0 +1,939 @@
# 01.Docker介绍与安装
## 01.Docker介绍与安装
### 1. Docker是什么
Docker是一个在2013年开源的应用程序并且是一个基于go语言编写的PAAS服务。
Docker最早采用LXC技术之后改为自己研发并开源的runc技术运行容器。
Docker相比虚拟机的交付速度更快资源消耗更低Docker采用客户端、服务端架构使用远程api来管理和创建Docker容器。
Docker的三大理念是build构建、ship运输、run运行
Docker通过namespace、cgroup等技术来提供容器的资源隔离与安全保障。
### 2. Docker与虚拟机之间的对比
![img](01.Docker介绍与安装/image-20191028193918568.png)
| **虚拟化** | **容器** |
| ------------------------------------------------ | ------------------------------------------------------- |
| 隔离性强有独立的GUEST OS | 共享内核和OS隔离性弱! |
| 虚拟化性能差(>15%) | 计算/存储无损耗无Guest OS内存开销(~200M) |
| 虚拟机镜像庞大(十几G~几十G), 且实例化时不能共享 | Docker容器镜象200~300M且公共基础镜象实例化时可以共享 |
| 虚拟机镜象缺乏统一标准 | Docker提供了容器应用镜象事实标准OCI推动进一 步标准化 |
| 虚拟机创建慢(>2分钟) | 秒级创建(<10s)相当于建立索引 |
| 虚拟机启动慢(>30s) 读文件逐个加载 | 秒级(<1s,不含应用本身启动) |
| 资源虚拟化粒度低单机10~100虚拟机 | 单机支持1000+容器密度很高适合大规模的部署 |
- 资源利用率更高一台物理机可以运行数百个容器但一般只能运行数十个虚拟机
- 开销更小不需要启动单独的虚拟机占用硬件资源
- 启动速度更快可以在数秒内完成启动
### 3. Docker的组成
官网https://docs.docker.com/get-started/overview/
Docker主机 host一个物理机或者虚拟机用于运行docker服务进程和容器
Docker服务端 ServerDocker守护进程运行docker容器
Docker客户端 client客户端使用docker命令或其他工具调用docker api
Docker仓库 registry保存镜像的仓库类似于git或svn这样的版本控制器
Docker镜像 images镜像可以理解为创建实例使用的模板
Docker容器 container容器是从镜像生成对外提供服务的一个或一组服务
![image-20210531152229098](01.Docker介绍与安装/image-20210531152229098.png)
![image-20210531152329941](01.Docker介绍与安装/image-20210531152329941.png)
### 4. Docker服务端软件选择
Docker CECommunity Edition社区版 Docker EEEnterprise Edition企业版 Docker 产品的两个主要版本它们之间的主要区别在于目标用户功能集支持和维护等方面
1. **目标用户**
- **Docker CE**面向个人开发者小团队以及技术爱好者主要用于开发和测试环境
- **Docker EE**面向大型企业和组织提供企业级的功能和支持
2. **功能集**
- **Docker CE**提供基本的容器化功能包括构建运行和共享容器
- **Docker EE**除了包含 CE 版本的所有功能外还提供了额外的企业级特性如增强的安全管理可扩展性和集成性
3. **支持和维护**
- **Docker CE**社区支持适合自我解决问题的开发者
- **Docker EE**提供商业支持和专业服务适合需要稳定运行环境的企业
4. **安全性**
- **Docker CE**安全性相对较低适合非生产环境
- **Docker EE**提供更高级的安全特性如镜像扫描安全策略和合规性报告
5. **管理**
- **Docker CE**通常不需要复杂的管理工具
- **Docker EE**提供 Docker Universal Control Plane (UCP) Docker Trusted Registry (DTR) 等管理工具帮助企业更有效地管理容器环境
6. **成本**
- **Docker CE**免费
- **Docker EE**需要购买许可证
7. **更新和生命周期**
- **Docker CE**更新频繁可能包含实验性功能生命周期较短
- **Docker EE**更新周期更稳定更注重稳定性和兼容性生命周期较长
### 5. Docker安装
- 安装docker-ce
```bash
[root@localhost ~]# yum install -y yum-utils
[root@localhost ~]# yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
[root@localhost ~]# sed -i 's+download.docker.com+mirrors.aliyun.com/docker-ce+' /etc/yum.repos.d/docker-ce.repo
[root@localhost ~]# yum install docker-ce -y
```
- 启动docker
```bash
[root@localhost ~]# systemctl enable --now docker
Created symlink /etc/systemd/system/multi-user.target.wants/docker.service → /usr/lib/systemd/system/docker.service.
[root@localhost ~]# systemctl status docker
● docker.service - Docker Application Container Engine
Loaded: loaded (/usr/lib/systemd/system/docker.service; enabled; preset: disabled)
Active: active (running) since Sun 2025-03-23 23:36:27 CST; 10s ago
TriggeredBy: ● docker.socket
Docs: https://docs.docker.com
Main PID: 29081 (dockerd)
Tasks: 10
Memory: 25.7M
CPU: 141ms
CGroup: /system.slice/docker.service
└─29081 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
```
#### 5.1 镜像加速配置
由于Docker Image仓库在国外目前从23年底开始国内陆续访问不到了所以要通过一些镜像加速器才能获取到镜像
```bash
[root@localhost ~]# docker pull nginx
Error response from daemon: Get "https://registry-1.docker.io/v2/": context deadline exceeded
# 无法从docker官方镜像仓库docker.io获取镜像
```
**使用国内镜像加速器**不稳定会经常变化
```bash
[root@localhost ~]# mkdir -p /etc/docker
[root@localhost ~]# vim /etc/docker/daemon.json
{
"registry-mirrors": [
"https://docker.m.daocloud.io"
]
}
# 重启容器服务
[root@localhost ~]# systemctl daemon-reload
[root@localhost ~]# systemctl restart docker
# 可选加速地址(不一定有用,随时会跑路):
1、https://docker.m.daocloud.io
2、https://docker.1panelproxy.com
3、https://atomhub.openatom.cn
4、https://docker.1panel.live
5、https://dockerhub.jobcher.com
6、https://hub.rat.dev
7、https://docker.registry.cyou
8、https://docker.awsl9527.cn
9、https://do.nark.eu.org/
10、https://docker.ckyl.me
11、https://hub.uuuadc.top
12、https://docker.chenby.cn
13、https://docker.ckyl.me
# 实在不行的话可以在拉去的时候手动加上镜像加速器因为有时候写到daemon.json中也有可能访问不到
[root@localhost ~]# docker pull nginx
[root@localhost ~]# docker pull docker.m.daocloud.io/nginx
[root@localhost ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest 53a18edff809 6 weeks ago 192MB
```
#### 5.2 快速开始
```bash
[root@localhost ~]# docker pull nginx
[root@localhost ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest d1a364dc548d 5 days ago 133MB
[root@localhost ~]# docker run -d -p 80:80 nginx
e617ca1db9a5d242e6b4145b9cd3dff9f7955c6ab1bf160f13fb6bec081a29e4
[root@localhost ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e617ca1db9a5 nginx "/docker-entrypoint.…" 6 seconds ago Up 5 seconds 0.0.0.0:80->80/tcp, :::80->80/tcp intelligent_turing
[root@localhost ~]# docker exec -it e617ca1db9a5 bash
root@e617ca1db9a5:/# cd /usr/share/nginx/html/
root@e617ca1db9a5:/usr/share/nginx/html# ls
50x.html index.html
root@e617ca1db9a5:/usr/share/nginx/html# echo 'docker nginx test' > index.html
[root@localhost ~]# curl 192.168.88.10
docker nginx test
[root@admin ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED NAMES
e0a818c40b7e nginx "/docker-entrypoint.…" About an hour ago 0.0.0.0:9000->9000/tcp, :::9000->9000/tcp determined_sanderson
9b066ef4bcd2 nginx "/docker-entrypoint.…" About an hour ago 90->80/tcp, :::90->80/tcp vigorous_hypatia
[root@admin ~]# docker stop e0a818c40b7e
e0a818c40b7e
[root@localhost ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
```
- **`-i``--interactive`**
- **功能**保持标准输入stdin打开即使没有附加终端
- **作用**允许用户与容器内的命令进行交互
- **`-t``--tty`**
- **功能**分配一个伪终端TTY)。
- **作用**为用户创建一个类似本地终端的交互环境支持颜色显示光标操作等终端特性
##### 5.2.1 Docker快速搭建RPG小游戏
```bash
[root@localhost ~]# docker pull registry.cn-guangzhou.aliyuncs.com/welldene/games:rpg_game
[root@localhost ~]# docker run -d -p 8000:8000 -p 8787:8787 --name rpg -e HOST_IP=192.168.88.10 registry.cn-guangzhou.aliyuncs.com/welldene/games:rpg_game
9c4bc95c98836a1df0453c282196083e4cb0b5d06e507d5d4567a4c018c13272
[root@localhost ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
35a6b44d5645 registry.cn-guangzhou.aliyuncs.com/welldene/games:rpg_game "bash run.sh" 3 seconds ago Up 2 seconds 0.0.0.0:8000->8000/tcp, [::]:8000->8000/tcp, 0.0.0.0:8787->8787/tcp, [::]:8787->8787/tcp rpg
```
**浏览器访问: http://IP:8787**
![image-20250324001839505](01.Docker介绍与安装/image-20250324001839505.png)
##### 5.2.2 Docker参数说明
```bash
-d, --detach: 以守护进程方式运行容器
-p, --publish: 映射容器端口到宿主机端口
格式: `-p [hostPort]:[containerPort]`
-P大写随机端口映射
-v, --volume: 挂载数据卷
格式: `-v [hostPath]:[containerPath]`
-e, --env: 设置环境变量
--name: 为容器指定名称
--network: 指定容器所属网络
--restart: 容器退出时的重启策略
可选值: `no`, `on-failure`, `unless-stopped`, `always`
-i, --interactive: 保持标准输入打开
-t, --tty: 分配一个伪终端
-u, --user: 指定运行容器的用户
--entrypoint: 覆盖容器的默认入口点
--rm: 容器退出后自动删除
--hostname: 设置容器主机名
--add-host: 添加自定义主机名到 IP 的映射
--link: 添加到另一个容器的链接
--expose: 暴露容器端口
--volume-driver: 指定数据卷驱动程序
--cpu-shares: 设置 CPU 权重
--memory: 设置容器内存限制
```
### 6. Docker核心技术
#### 6.1 Linux namespace技术
如果一个宿主机运行了N个容器多个容器带来的以下问题怎么解决
1. 怎么样保证每个容器都有不同的文件系统并且能互不影响
2. 一个docker主进程内的各个容器都是其子进程那么如何实现同一个主进程下不同类型的子进程各个子进程间通信能相互访问吗
3. 每个容器怎么解决IP以及端口分配的问题
4. 多个容器的主机名能一样吗
5. 每个容器都要不要有root用户怎么解决账户重名问题呢
以上问题怎么解决
Docker Namespace 技术是实现容器隔离的核心机制之一它通过 Linux Namespace 提供的隔离功能为每个容器创建独立的资源视图从而实现容器之间的隔离
**namespace**是Linux系统的底层概念在内核层实现即有一些不同类型的命名空间都部署在核内**各个docker容器运行在同一个docker主进程并且共用同一个宿主机系统内核**各个docker容器运行在宿主机的用户空间每个容器都要有类似于虚拟机一样的相**互隔离的运行空间**但是容器技术是在一个进程内实现运行指定服务的运行环境并且还可以保护宿主机内核不受其他进程的干扰和影响如文件系统网络空间进程空间等目前主要通过以下技术实现容器运行空间的相互隔离
| 隔离类型 | 功能 | 系统调用参数 | 内核 |
| -------------------------------------------- | ---------------------------------- | ------------- | ------ |
| MNT Namespacemount | 提供磁盘挂载点和文件系统的隔离能力 | CLONE_NEWNS | 2.4.19 |
| IPC NamespaceInter-Process Communication | 提供进程间通信的隔离能力 | CLONE_NEWIPC | 2.6.19 |
| UTS NamespaceUNIX Timesharing System | 提供主机名隔离能力 | CLONE_NEWUTS | 2.6.19 |
| PID NamespaceProcess Identification | 提供进程隔离能力 | CLONE_NEWPID | 2.6.24 |
| Net Namespacenetwork | 提供网络隔离能力 | CLONE_NEWNET | 2.6.29 |
| User Namespaceuser | 提供用户隔离能力 | CLONE_NEWUSER | 3.8 |
##### 6.1.1 MNT Namespace
每个容器都要有独立的根文件系统有独立的用户空间以实现容器里面启动服务并且使用容器的运行环境
- 启动三个容器
```bash
[root@localhost ~]# docker run -d --name nginx-1 -p 80:80 nginx
0e72f06bba417073d1d4b2cb53e62c45b75edc699b737e46a157a3249f3a803e
[root@localhost ~]# docker run -d --name nginx-2 -p 81:80 nginx
c8ce6a0630b66e260eef16d8ecf48049eed7b893b87459888b634bf0e9e40f23
[root@localhost ~]# docker run -d --name nginx-3 -p 82:80 nginx
1cddbd412b5997f8935815c2f588431e100b752595ceaa92b95758ca45179096
[root@localhost ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b42378a51c40 nginx "/docker-entrypoint.…" 2 seconds ago Up 1 second 0.0.0.0:82->80/tcp, [::]:82->80/tcp nginx-3
d30f033c2f29 nginx "/docker-entrypoint.…" 5 seconds ago Up 5 seconds 0.0.0.0:81->80/tcp, [::]:81->80/tcp nginx-2
d34a012dcebc nginx "/docker-entrypoint.…" 10 seconds ago Up 10 seconds 0.0.0.0:80->80/tcp, [::]:80->80/tcp nginx-1
```
- 连接进入某一个容器中并创建一个文件
```bash
[root@localhost ~]# docker exec -it nginx-1 bash
root@d34a012dcebc:/# echo 'hello world test!' > /opt/test_nginx-1
root@d34a012dcebc:/# exit
```
- 宿主机是使用了chroot技术把容器锁定到一个指定的运行目录里
```bash
[root@localhost ~]# find / -name test_nginx-1
/var/lib/docker/overlay2/075b51fb5d33011d4b449fde8c14199c1e30f86224862f68a6116b1cb1dacfdf/diff/opt/test_nginx-1
/var/lib/docker/overlay2/075b51fb5d33011d4b449fde8c14199c1e30f86224862f68a6116b1cb1dacfdf/merged/opt/test_nginx-1
```
Docker 文件系统是通过分层存储机制实现的这与 Docker 的镜像和容器的架构有关看到的两个文件路径反映了 Docker 的存储驱动 Overlay2的工作原理
###### 6.1.1.1 Docker 的存储架构
1. **镜像层Read-Only**
- Docker 镜像是由多个只读层组成的每一层代表了镜像的某个状态或修改
- 这些层是不可变的一旦创建不会被修改
2. **容器层Read-Write**
- 当你运行一个容器时Docker 会在镜像层之上添加一个可写层
- 容器的所有写操作如创建文件修改文件等都会在这个可写层中进行而不会影响下面的镜像层
###### 6.1.1.2 Overlay2 存储驱动
Docker 默认使用 Overlay2 存储驱动在支持的系统上)。Overlay2 的工作机制如下
- **`merged` 目录**
- 这是容器的根文件系统是镜像层和容器层的联合视图
- 当你在容器中访问文件时看到的是 `merged` 目录中的内容
- 例如你在容器中创建的文件 `/opt/test_nginx-1`在宿主机上可以通过 `/var/lib/docker/overlay2/<id>/merged/opt/test_nginx-1` 访问
- **`diff` 目录**
- 这是容器的可写层记录了容器对文件系统的修改
- 当你在容器中创建或修改文件时实际的文件数据会存储在 `diff` 目录中
- 例如你在容器中创建的文件 `/opt/test_nginx-1`其实际数据存储在 `/var/lib/docker/overlay2/<id>/diff/opt/test_nginx-1`
- 当你在容器中创建文件 `/opt/test_nginx-1`
- 文件的实际数据被写入到 `diff` 目录中
- `merged` 目录中通过联合文件系统OverlayFS的机制 `diff` 目录中的文件映射到 `merged` 目录中让你在容器中看到完整的文件系统视图
##### 6.1.2 IPC Namespace
一个容器内的进程间通信允许一个容器内的不同进程数据互相访问但是不能跨容器访问其他容器的数据
UTS Namespace包含了运行内核的名称版本底层体系结构类型等信息用于系统表示其中包含了hostname和域名它使得一个容器拥有属于自己hostname标识这个主机名标识独立于宿主机系统和其上的其他容器
##### 6.1.3 PID Namespace
Linux系统中有一个pid为1的进程init/systemd是其他所有进程的父进程那么在每个容器内也要有一个父进程来管理其下属的进程那么多个容器的进程通PID namespace进程隔离
- 安装软件包
```bash
[root@localhost ~]# docker exec -it 065f06e5caa4 bash
root@0e72f06bba41:/# apt update
# ifconfig
root@0e72f06bba41:/# apt install -y net-tools
root@0e72f06bba41:/# apt install -y procps
root@0e72f06bba41:/# ps -ef
UID PID PPID C STIME TTY TIME CMD
root 10 0 03:20 ? 00:00:00 nginx: master process nginx -g d
nginx 32 1 0 03:20 ? 00:00:00 nginx: worker process
nginx 33 1 0 03:20 ? 00:00:00 nginx: worker process
nginx 34 1 0 03:20 ? 00:00:00 nginx: worker process
nginx 35 1 0 03:20 ? 00:00:00 nginx: worker process
nginx 36 1 0 03:20 ? 00:00:00 nginx: worker process
nginx 37 1 0 03:20 ? 00:00:00 nginx: worker process
nginx 38 1 0 03:20 ? 00:00:00 nginx: worker process
nginx 39 1 0 03:20 ? 00:00:00 nginx: worker process
root 59 0 0 03:35 pts/0 00:00:00 bash
root 503 59 0 03:42 pts/0 00:00:00 ps -ef
```
**那么宿主机的PID与容器内的PID是什么关系**
```bash
[root@localhost ~]# yum install psmisc
[root@localhost ~]# pstree -p
[root@localhost ~]# pstree -p
systemd(1)─┬─NetworkManager(769)─┬─{NetworkManager}(772)
│ └─{NetworkManager}(775)
├─agetty(817)
├─atd(799)
├─auditd(693)─┬─sedispatch(695)
│ ├─{auditd}(694)
│ └─{auditd}(696)
├─bluetoothd(742)
├─chronyd(753)
├─containerd(28884)─┬─{containerd}(28886)
│ ├─{containerd}(28887)
│ ├─{containerd}(28888)
│ ├─{containerd}(28889)
│ ├─{containerd}(28890)
│ ├─{containerd}(28891)
│ ├─{containerd}(28892)
│ └─{containerd}(28894)
├─containerd-shim(30330)─┬─bash(30801)
│ ├─nginx(30353)─┬─nginx(30426)
│ │ ├─nginx(30427)
│ │ ├─nginx(30428)
│ │ └─nginx(30429)
│ ├─{containerd-shim}(30332)
│ ├─{containerd-shim}(30333)
│ ├─{containerd-shim}(30334)
│ ├─{containerd-shim}(30335)
│ ├─{containerd-shim}(30336)
│ ├─{containerd-shim}(30337)
│ ├─{containerd-shim}(30338)
│ ├─{containerd-shim}(30339)
│ ├─{containerd-shim}(30340)
│ ├─{containerd-shim}(30703)
│ └─{containerd-shim}(30909)
├─containerd-shim(30447)─┬─nginx(30469)─┬─nginx(30546)
│ │ ├─nginx(30547)
│ │ ├─nginx(30548)
│ │ └─nginx(30549)
│ ├─{containerd-shim}(30448)
│ ├─{containerd-shim}(30449)
│ ├─{containerd-shim}(30450)
│ ├─{containerd-shim}(30451)
│ ├─{containerd-shim}(30452)
│ ├─{containerd-shim}(30453)
│ ├─{containerd-shim}(30454)
│ ├─{containerd-shim}(30455)
│ ├─{containerd-shim}(30456)
│ └─{containerd-shim}(30705)
├─containerd-shim(30566)─┬─nginx(30587)─┬─nginx(30662)
│ │ ├─nginx(30663)
│ │ ├─nginx(30664)
│ │ └─nginx(30665)
│ ├─{containerd-shim}(30567)
│ ├─{containerd-shim}(30568)
│ ├─{containerd-shim}(30569)
│ ├─{containerd-shim}(30570)
│ ├─{containerd-shim}(30571)
│ ├─{containerd-shim}(30572)
│ ├─{containerd-shim}(30573)
│ ├─{containerd-shim}(30574)
│ ├─{containerd-shim}(30593)
│ ├─{containerd-shim}(30706)
│ └─{containerd-shim}(30780)
├─crond(801)
├─dbus-broker-lau(719)───dbus-broker(723)
├─dockerd(29156)─┬─docker-proxy(30381)─┬─{docker-proxy}(30382)
│ │ ├─{docker-proxy}(30383)
│ │ ├─{docker-proxy}(30384)
│ │ ├─{docker-proxy}(30385)
│ │ ├─{docker-proxy}(30386)
│ │ └─{docker-proxy}(30388)
│ ├─docker-proxy(30387)─┬─{docker-proxy}(30389)
│ │ ├─{docker-proxy}(30390)
│ │ ├─{docker-proxy}(30391)
│ │ ├─{docker-proxy}(30392)
│ │ ├─{docker-proxy}(30393)
│ │ ├─{docker-proxy}(30394)
│ │ ├─{docker-proxy}(30395)
│ │ └─{docker-proxy}(30396)
│ ├─docker-proxy(30497)─┬─{docker-proxy}(30498)
│ │ ├─{docker-proxy}(30499)
│ │ ├─{docker-proxy}(30500)
│ │ ├─{docker-proxy}(30501)
│ │ ├─{docker-proxy}(30502)
│ │ ├─{docker-proxy}(30503)
│ │ ├─{docker-proxy}(30504)
│ │ └─{docker-proxy}(30505)
│ ├─docker-proxy(30506)─┬─{docker-proxy}(30507)
│ │ ├─{docker-proxy}(30508)
│ │ ├─{docker-proxy}(30509)
│ │ ├─{docker-proxy}(30510)
│ │ ├─{docker-proxy}(30511)
│ │ ├─{docker-proxy}(30512)
│ │ └─{docker-proxy}(30513)
│ ├─docker-proxy(30616)─┬─{docker-proxy}(30617)
│ │ ├─{docker-proxy}(30618)
│ │ ├─{docker-proxy}(30619)
│ │ ├─{docker-proxy}(30620)
│ │ ├─{docker-proxy}(30621)
│ │ ├─{docker-proxy}(30622)
│ │ ├─{docker-proxy}(30624)
│ │ └─{docker-proxy}(30625)
│ ├─docker-proxy(30623)─┬─{docker-proxy}(30626)
│ │ ├─{docker-proxy}(30627)
│ │ ├─{docker-proxy}(30628)
│ │ ├─{docker-proxy}(30629)
│ │ ├─{docker-proxy}(30630)
│ │ ├─{docker-proxy}(30631)
│ │ └─{docker-proxy}(30632)
│ ├─{dockerd}(29157)
│ ├─{dockerd}(29159)
│ ├─{dockerd}(29161)
│ ├─{dockerd}(29163)
│ ├─{dockerd}(29407)
│ ├─{dockerd}(29420)
│ ├─{dockerd}(29430)
│ ├─{dockerd}(29537)
│ ├─{dockerd}(29711)
│ ├─{dockerd}(29712)
│ ├─{dockerd}(29823)
│ ├─{dockerd}(29844)
│ ├─{dockerd}(29845)
│ ├─{dockerd}(30633)
│ └─{dockerd}(30683)
├─irqbalance(729)───{irqbalance}(738)
├─lsmd(730)
├─mcelog(734)
├─polkitd(944)─┬─{polkitd}(975)
│ ├─{polkitd}(976)
│ ├─{polkitd}(979)
│ ├─{polkitd}(980)
│ ├─{polkitd}(981)
│ ├─{polkitd}(982)
│ └─{polkitd}(1004)
├─rsyslogd(1063)─┬─{rsyslogd}(1095)
│ └─{rsyslogd}(1096)
├─sshd(786)─┬─sshd(1527)───sshd(1541)───bash(1542)───docker(30781)─┬─{docker}(30782)
│ │ ├─{docker}(30783)
│ │ ├─{docker}(30784)
│ │ ├─{docker}(30785)
│ │ ├─{docker}(30786)
│ │ ├─{docker}(30787)
│ │ ├─{docker}(30788)
│ │ └─{docker}(30807)
│ └─sshd(30928)───sshd(30932)───bash(30933)───pstree(31158)
├─systemd(1532)───(sd-pam)(1534)
├─systemd-journal(635)
├─systemd-logind(739)
├─systemd-udevd(648)
└─tuned(791)─┬─{tuned}(1106)
├─{tuned}(1137)
└─{tuned}(1138)
[root@localhost ~]# ps aux | grep b42378a51c40
root 30566 0.0 0.9 1237984 16524 ? Sl 18:42 0:00 /usr/bin/containerd-shim-runc-v2 -namespace moby -id b42378a51c402d7ffa408d331a61ebdefe1b920eb723cd343ebc8e5781bec03d -address /run/containerd/containerd.sock
root 31171 0.0 0.1 3880 2048 pts/1 S+ 18:54 0:00 grep --color=auto b42378a51c40
```
**在宿主机上查看容器的进程**
```bash
[root@localhost ~]# docker top nginx-1
UID PID PPID C STIME TTY TIME CMD
root 30353 30330 0 18:42 ? 00:00:00 nginx: master process nginx -g daemon off;
101 30426 30353 0 18:42 ? 00:00:00 nginx: worker process
101 30427 30353 0 18:42 ? 00:00:00 nginx: worker process
101 30428 30353 0 18:42 ? 00:00:00 nginx: worker process
101 30429 30353 0 18:42 ? 00:00:00 nginx: worker process
root 30801 30330 0 18:46 pts/0 00:00:00 bash
```
首先可以看到容器内的进程在宿主机上的 PID容器内的进程只能看到自己命名空间中的进程而无法看到宿主机或其他容器的进程
所以说明docker采用PID Namespace技术将容器内部的进程与宿主机的进程进行了隔离
并且容器内部的进程和宿主机上的进程还存在一定的对应或者映射关系
1. **独立的 PID 命名空间**:
- 每个 Docker 容器都有自己独立的 PID 命名空间
- 容器内的进程 PID 1 开始编号,与宿主机上的 PID 是相互独立的
2. **PID 映射**:
- 容器内的进程 PID 与宿主机上的进程 PID 之间是有映射关系的
3. **PID 可见性**:
- 容器内的进程只能看到容器内部的 PID
- 宿主机上的进程可以看到容器内部的 PID,但容器内的进程无法看到宿主机上的 PID
4. **PID 隔离**:
- 容器内的进程无法访问或影响宿主机上的其他进程
- 宿主机上的进程可以访问和管理容器内的进程
##### 6.1.4 Net Namespace
每一个容器都类似于虚拟机一样有自己的网卡监听端口TCP/IP协议栈等Docker使用network namespace启动一个vethX接口这样容器将拥有它自己的桥接IP地址通常是docker0而docker0实质就是linux的虚拟网桥
查看容器内部的IP网络信息发现有一个eth0的网卡
```bash
root@d34a012dcebc:/# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.17.0.2 netmask 255.255.0.0 broadcast 172.17.255.255
ether ce:f2:f5:63:47:16 txqueuelen 0 (Ethernet)
RX packets 4713 bytes 10994487 (10.4 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 3888 bytes 212050 (207.0 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
```
而我们的宿主机上的网卡中多了个docker0的虚拟网桥这样以来通过Net Namespace将容器的网络与宿主机的网络进行隔离并且通过虚拟网桥docker0与容器进行网络通信
```bash
[root@localhost ~]# ifconfig
docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.17.0.1 netmask 255.255.0.0 broadcast 172.17.255.255
inet6 fe80::38a5:cdff:fe6b:7dbc prefixlen 64 scopeid 0x20<link>
ether 3a:a5:cd:6b:7d:bc txqueuelen 0 (Ethernet)
RX packets 5820 bytes 11520579 (10.9 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 9483 bytes 11508761 (10.9 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
ens160: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.88.10 netmask 255.255.255.0 broadcast 192.168.88.255
inet6 fe80::20c:29ff:fe26:8384 prefixlen 64 scopeid 0x20<link>
ether 00:0c:29:26:83:84 txqueuelen 1000 (Ethernet)
RX packets 235433 bytes 340010957 (324.2 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 54812 bytes 14709198 (14.0 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
veth51c3173: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet6 fe80::d8fa:18ff:fe0f:d176 prefixlen 64 scopeid 0x20<link>
ether da:fa:18:0f:d1:76 txqueuelen 0 (Ethernet)
RX packets 3888 bytes 212050 (207.0 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 4714 bytes 10994557 (10.4 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
veth813b530: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet6 fe80::e498:2eff:fe08:2c5b prefixlen 64 scopeid 0x20<link>
ether e6:98:2e:08:2c:5b txqueuelen 0 (Ethernet)
RX packets 3 bytes 126 (126.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 15 bytes 1118 (1.0 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
vethc11c399: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet6 fe80::a482:dfff:fe74:dec7 prefixlen 64 scopeid 0x20<link>
ether a6:82:df:74:de:c7 txqueuelen 0 (Ethernet)
RX packets 3 bytes 126 (126.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 18 bytes 1244 (1.2 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
```
- **`docker0` 网桥**
- 它是 Docker 默认创建的一个虚拟网桥用于管理容器的网络通信
- 它为连接到它的容器提供了一个内部网络环境允许容器之间通过这个网桥进行通信
- **`veth3ad3c5b` 接口**
- 这是一个虚拟以太网接口用于连接容器和宿主机的网络
- 它的一端连接到 `docker0` 网桥另一端连接到容器的网络命名空间
- 当容器启动时Docker 会自动创建这样的 veth pair并将一端连接到 `docker0`另一端连接到容器的网络命名空间
逻辑图
![image-20210603144141780](01.Docker介绍与安装/image-20210603144141780.png)
##### 6.1.5 User Namespace
各个容器内可能会出现重名的用户和用户组名称或重复的用户UID或者GID那么怎么隔离各个容器内的用户空间呢
User Namespace允许在宿主机的各个容器空间内创建相同的用户名以及相同的uid和gid只是此用户的有效范围仅仅是当前的容器内不能访问另外一个容器内的文件系统即相互隔离互不影响永不相见
#### 6.2 Linux control groups
在一个容器内部如果不对其做任何资源限制则宿主机会允许其占用无限大的内存空间有时候会因为代码bug程序会一直申请内存直到把宿主机内存占完为了避免此类的问题出现宿主机有必要对容器进行资源分配限制比如cpu内存等Linux Cgroups的全称是Linux control Groups它最重要的作用就是限制一个进程组能够使用的资源上线包括cpu内存磁盘网络等等
- 验证系统内核层已经默认开启cgroup功能
```bash
[root@localhost ~]# cat /boot/config-5.14.0-427.13.1.el9_4.x86_64 | grep cgroup -i
CONFIG_CGROUPS=y
# CONFIG_CGROUP_FAVOR_DYNMODS is not set
CONFIG_BLK_CGROUP=y
CONFIG_CGROUP_WRITEBACK=y
CONFIG_CGROUP_SCHED=y
CONFIG_CGROUP_PIDS=y
CONFIG_CGROUP_RDMA=y
CONFIG_CGROUP_FREEZER=y
CONFIG_CGROUP_HUGETLB=y
CONFIG_CGROUP_DEVICE=y
CONFIG_CGROUP_CPUACCT=y
CONFIG_CGROUP_PERF=y
CONFIG_CGROUP_BPF=y
CONFIG_CGROUP_MISC=y
# CONFIG_CGROUP_DEBUG is not set
CONFIG_SOCK_CGROUP_DATA=y
CONFIG_BLK_CGROUP_RWSTAT=y
CONFIG_BLK_CGROUP_IOLATENCY=y
CONFIG_BLK_CGROUP_FC_APPID=y
# CONFIG_BLK_CGROUP_IOCOST is not set
# CONFIG_BLK_CGROUP_IOPRIO is not set
# CONFIG_BFQ_CGROUP_DEBUG is not set
CONFIG_NETFILTER_XT_MATCH_CGROUP=m
CONFIG_NET_CLS_CGROUP=y
CONFIG_CGROUP_NET_PRIO=y
CONFIG_CGROUP_NET_CLASSID=y
# CONFIG_DEBUG_CGROUP_REF is not set
```
- 关于内存的模块
```bash
[root@localhost ~]# cat /boot/config-3.10.0-957.el7.x86_64 | grep mem -i | grep cg -i
CONFIG_MEMCG=y
CONFIG_MEMCG_SWAP=y
CONFIG_MEMCG_SWAP_ENABLED=y
CONFIG_MEMCG_KMEM=y
```
扩展阅读
https://blog.csdn.net/qyf158236/article/details/110475457
##### 6.2.1 Docker 中的 cgroups 资源限制
###### 6.2.1.1 **CPU 资源限制**
Docker 提供了多种方式来限制容器的 CPU 使用
- **`--cpus`**限制容器可以使用的 CPU 核心数量例如`--cpus="1.5"` 表示容器最多可以使用 1.5 CPU
- **`--cpu-shares`**设置容器的 CPU 使用权重默认值为 1024值越高分配的 CPU 时间片越多
- **`--cpu-period` `--cpu-quota`**更细粒度地控制 CPU 时间片`--cpu-period` 设置 CPU 时间片的周期单位为微秒`--cpu-quota` 设置每个周期内容器可以使用的 CPU 时间
###### 6.2.1.2 **内存资源限制**
Docker 可以通过以下参数限制容器的内存使用
- **`-m` `--memory`**限制容器的物理内存使用量例如`-m 512m` 表示限制容器使用 512MB 的物理内存
- **`--memory-swap`**限制容器的总内存使用量物理内存 + 交换空间)。例如`--memory-swap=1g` 表示容器可以使用 1GB 的总内存
###### 6.2.1.3 **磁盘 I/O 资源限制**
Docker 可以限制容器的磁盘 I/O 使用
- **`--blkio-weight`**设置容器的块设备 I/O 权重范围为 10 1000
- **`--device-read-bps` `--device-write-bps`**限制特定设备的读写速率例如`--device-read-bps /dev/sda:1mb` 表示限制容器对 `/dev/sda` 的读取速率为 1MB/s
##### 6.2.2 查看和管理 cgroups 资源限制
- **查看 cgroups 配置**可以通过访问 `/sys/fs/cgroup` 目录来查看容器的 cgroups 配置例如`/sys/fs/cgroup/cpu/docker/<container_id>` 目录下包含了容器的 CPU 资源限制文件
- **动态调整资源限制**在容器运行时可以通过修改 cgroups 文件的内容来动态调整资源限制
##### 6.2.3 使用压缩工具测试
```plain
[root@bogon ~]# docker pull lorel/docker-stress-ng
Using default tag: latest
latest: Pulling from lorel/docker-stress-ng
c52e3ed763ff: Pull complete
a3ed95caeb02: Pull complete
7f831269c70e: Pull complete
Digest: sha256:c8776b750869e274b340f8e8eb9a7d8fb2472edd5b25ff5b7d55728bca681322
Status: Downloaded newer image for lorel/docker-stress-ng:latest
```
###### 6.2.3.1 测试CPU
不限制cpu使用
```bash
[root@bogon ~]# docker container run --name stress -it --rm lorel/docker-stress-ng:latest --cpu 4
stress-ng: info: [1] defaulting to a 86400 second run per stressor
stress-ng: info: [1] dispatching hogs: 8 cpu
[root@bogon ~]# docker stats
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
92b0b8d916c1 stress 101.54% 15.81MiB / 983.3MiB 1.61% 648B / 0B 0B / 0B 9
[root@bogon ~]# top
top - 19:15:49 up 2 days, 2:38, 2 users, load average: 7.02, 3.00, 1.15
Tasks: 131 total, 10 running, 121 sleeping, 0 stopped, 0 zombie
%Cpu(s): 99.7 us, 0.3 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 1006892 total, 100680 free, 320704 used, 585508 buff/cache
KiB Swap: 2097148 total, 2096628 free, 520 used. 422732 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
40035 root 20 0 6908 4180 252 R 12.6 0.4 0:12.79 stress-ng-cpu
40037 root 20 0 6908 4180 252 R 12.6 0.4 0:12.78 stress-ng-cpu
40038 root 20 0 6908 2136 252 R 12.6 0.2 0:12.78 stress-ng-cpu
40040 root 20 0 6908 2136 252 R 12.6 0.2 0:12.78 stress-ng-cpu
40036 root 20 0 6908 2136 252 R 12.3 0.2 0:12.77 stress-ng-cpu
40039 root 20 0 6908 2136 252 R 12.3 0.2 0:12.78 stress-ng-cpu
40041 root 20 0 6908 4180 252 R 12.3 0.4 0:12.77 stress-ng-cpu
40042 root 20 0 6908 2136 252 R 12.3 0.2 0:12.77 stress-ng-cpu
1 root 20 0 128484 7208 4196 S 0.0 0.7 0:10.12 systemd
```
可以看到cpu使用已经满了
重新启动容器加入CPU限制参数
```bash
[root@bogon ~]# docker container run --name stress --cpus=0.5 -it --rm lorel/docker-stress-ng:latest --cpu 8
stress-ng: info: [1] defaulting to a 86400 second run per stressor
stress-ng: info: [1] dispatching hogs: 8 cpu
[root@bogon ~]# docker stats
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
845220ef9982 stress 51.57% 20.05MiB / 983.3MiB 2.04% 648B / 0B 0B / 0B 9
```
### 7. 容器规范
#### 7.1 容器技术及其标准化组织 OCI
容器技术是一种轻量级的虚拟化技术用于隔离应用程序及其依赖项使其能够在不同的环境中一致地运行除了 Docker 之外还有其他多种容器运行时和工具例如 CoreOS rkt阿里的 Pouch 和红帽的 Podman为了确保容器生态系统的标准性和可持续发展Linux 基金会Docker微软红帽谷歌和 IBM 等公司在 2015 6 月共同成立了 **Open Container Initiative (OCI)** 组织
##### 7.1.1 **OCI 的目标**
OCI 的主要目标是制定开放的容器规范以确保不同容器技术之间的可移植性和互操作性目前OCI 已经发布了两个核心规范
1. **Runtime Spec**定义了容器运行时的规范包括容器的生命周期管理资源隔离和安全等
2. **Image Format Spec**定义了容器镜像的格式和元数据确保镜像可以在不同的容器运行时之间共享和运行
通过遵循这些规范不同的容器运行时和工具可以实现互操作性从而推动容器技术的标准化和健康发展
##### 7.1.2 主流容器运行时
容器运行时是真正运行容器的地方它需要与操作系统的内核紧密合作为容器提供隔离的运行环境以下是目前主流的三种容器运行时
###### 7.1.2.1 **LXC (Linux Containers)**
- **简介**LXC Linux 上早期的容器运行时它利用 Linux 内核的 Namespace Cgroups 技术来实现进程隔离和资源管理
- **特点**
- 提供了完整的 Linux 系统环境支持多种 Linux 发行版
- 早期 Docker 也曾使用 LXC 作为其默认的运行时
- **适用场景**适用于需要完整 Linux 系统环境的容器化应用
###### 7.1.2.2 **Runc**
- **简介**Runc 是目前 Docker 默认的容器运行时它是一个轻量级的命令行工具用于运行和管理容器
- **特点**
- 完全遵循 OCI Runtime Spec 规范确保与 OCI 标准的兼容性
- 由于其轻量级和高性能的特点Runc 已经成为许多容器运行时的底层实现
- **适用场景**适用于需要高性能和轻量级容器运行环境的场景
###### 7.1.2.3 **Rkt (Rocket)**
- **简介**Rkt 是由 CoreOS 开发的容器运行时旨在提供一个安全可靠且符合 OCI 规范的容器运行环境
- **特点**
- Docker 不同Rkt 本身是一个独立的容器运行时不依赖 Docker 的守护进程
- 提供了更好的安全性和隔离性例如通过 AppArmor SELinux 等安全机制
- **适用场景**适用于对安全性要求较高的容器化应用
容器技术的发展离不开标准化的推动OCI 通过制定 Runtime Spec Image Format Spec为容器运行时和工具提供了统一的标准确保了不同容器技术之间的互操作性和可移植性目前主流的容器运行时 LXCRunc Rkt都遵循这些规范从而推动了容器技术的广泛应用和发展
### 8. docker info信息
```bash
[root@localhost ~]# docker info
Client:
Context: default
Debug Mode: false
Plugins:
app: Docker App (Docker Inc., v0.9.1-beta3)
buildx: Build with BuildKit (Docker Inc., v0.5.1-docker)
scan: Docker Scan (Docker Inc.)
Server:
Containers: 2 # 当前主机运行容器总数
Running: 1 # 有几个容器是正在运行的
Paused: 0 # 有几个容器是暂停的
Stopped: 1 # 有几个容器是停止的
Images: 1 # 当前服务器的镜像数
Server Version: 20.10.6 # 服务端版本
Storage Driver: overlay2 # 正在使用的存储引擎
Backing Filesystem: xfs # 后端文件系统,即服务器的磁盘文件系统
Supports d_type: true # 是否支持d_type
Native Overlay Diff: true # 是否支持差异数据存储
userxattr: false
Logging Driver: json-file # 日志文件类型
Cgroup Driver: cgroupfs # cgroups类型
Cgroup Version: 1
Plugins: # 插件
Volume: local # 卷
Network: bridge host ipvlan macvlan null overlay
Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog
Swarm: inactive # 是否支持swarm
Runtimes: io.containerd.runc.v2 io.containerd.runtime.v1.linux runc
Default Runtime: runc # 默认的runtime
Init Binary: docker-init # 初始化容器的守护进程
containerd version: d71fcd7d8303cbf684402823e425e9dd2e99285d
runc version: b9ee9c6314599f1b4a7f497e1f1f856fe433d3b7
init version: de40ad0
Security Options: # 安全选项
seccomp
Profile: default
Kernel Version: 3.10.0-693.el7.x86_64 # 宿主机内核版本
Operating System: CentOS Linux 7 (Core) # 宿主机操作系统
OSType: linux # 宿主机操作系统类型
Architecture: x86_64 # 宿主机架构
CPUs: 1 # 宿主机cpu数量
Total Memory: 1.781GiB # 宿主机总内存
Name: docker-server # 宿主机主机名
ID: ARN5:ESPO:FEZ4:KDZ6:RWGG:WQ3X:SIXN:3FVG:ATXH:JAXA:ENGH:RAVE
Docker Root Dir: /var/lib/docker # 宿主机数据保存目录
Debug Mode: false
Registry: https://index.docker.io/v1/ # 镜像仓库
Labels:
Experimental: false # 是否是测试版
Insecure Registries:
127.0.0.0/8
Live Restore Enabled: false # 是否开启活动容器(重启不关闭容器)
```
### 9. docker 存储引擎
Docker 的存储引擎是 Docker 平台中用于管理容器和镜像数据的核心组件它负责容器的文件系统网络配置权限管理等以及其他与容器运行相关的任务以下是对 Docker 存储引擎的详细介绍
#### 9.1 **核心概念及工作原理**
Docker 存储引擎的核心思想是的概念镜像是由多个只读层组成的而容器则在镜像的基础上添加了一个可读写的层这种分层架构使得镜像的复用和部署变得非常方便同时减少了容器的体积
Docker 使用联合文件系统Union File System来管理容器的文件系统联合文件系统允许将多个目录或文件系统合并为一个统一的文件系统视图Docker 的存储引擎通过这种机制将镜像层和容器层合并在一起使得容器能够看到一个完整的文件系统
Docker 支持多种存储引擎每种存储引擎都有其特点和适用场景以下是一些常见的存储引擎
**AUFSAnother Union File System**
- **特点**AUFS 是一种文件级的存储驱动允许多个目录共享相同的文件系统层次结构它通过联合挂载技术将多个目录挂载到一个单一的文件系统上
- **适用场景**AUFS 曾是 Docker 早期版本的默认存储驱动但在较新的 Docker 版本中已被 Overlay2 替代
**OverlayFS**
- **特点**OverlayFS 是一种更现代的联合文件系统 Linux 内核 3.18 开始支持它将文件系统简化为两层一个只读的下层lowerdir和一个可读写的上层upperdir统一后的视图称为合并层merged)。
- **优势**OverlayFS 支持页缓存共享多个容器如果读取相同层的同一个文件可以共享页缓存从而提高内存利用率此外OverlayFS 在性能和稳定性方面表现更好是目前 Docker 的默认存储驱动
#### 9.2 Docker 的 Overlay2 存储驱动介绍
1. **什么是 Overlay2**
Overlay2 Docker 中的一种存储驱动用于管理容器和镜像的文件系统它是 OverlayFS 的改进版本解决了早期 Overlay 驱动可能遇到的 inode 耗尽问题Overlay2 使用联合文件系统Union File System技术将多个文件系统层合并为一个统一的文件系统视图从而实现高效的容器文件系统管理
2. **Overlay2 的工作原理**
Overlay2 通过以下三个主要目录来管理文件系统
- **`LowerDir`**只读层包含基础镜像的文件系统可以有多个只读层每层都是独立的
- **`UpperDir`**读写层用于存储容器运行时的文件系统变更 diff )。
- **`MergedDir`**联合挂载后的视图容器看到的完整文件系统它将 `LowerDir` `UpperDir` 合并为一个统一的文件系统视图
- **`WorkDir`**工作目录用于联合挂载的内部操作挂载后内容被清空
当启动一个容器时Overlay2 会将镜像层`LowerDir`和容器层`UpperDir`联合挂载到 `MergedDir`容器通过这个目录看到完整的文件系统

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 172 KiB

View File

@@ -0,0 +1,293 @@
# 02.Docker镜像管理
## 02.Docker镜像管理
### 1. 搜索镜像
```bash
[root@docker-server ~]# docker search centos
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
centos The official build of CentOS. 6584 [OK]
ansible/centos7-ansible Ansible on Centos7 134 [OK]
consol/centos-xfce-vnc Centos container with "headless" VNC session… 129 [OK]
jdeathe/centos-ssh OpenSSH / Supervisor / EPEL/IUS/SCL Repos - … 118 [OK]
centos/systemd systemd enabled base container. 99 [OK]
imagine10255/centos6-lnmp-php56 centos6-lnmp-php56 58 [OK]
tutum/centos Simple CentOS docker image with SSH access 48
kinogmt/centos-ssh CentOS with SSH 29 [OK]
pivotaldata/centos-gpdb-dev CentOS image for GPDB development. Tag names… 13
guyton/centos6 From official centos6 container with full up… 10 [OK]
centos/tools Docker image that has systems administration… 7 [OK]
drecom/centos-ruby centos ruby 6 [OK]
pivotaldata/centos Base centos, freshened up a little with a Do… 5
pivotaldata/centos-gcc-toolchain CentOS with a toolchain, but unaffiliated wi… 3
darksheer/centos Base Centos Image -- Updated hourly 3 [OK]
mamohr/centos-java Oracle Java 8 Docker image based on Centos 7 3 [OK]
pivotaldata/centos-mingw Using the mingw toolchain to cross-compile t… 3
miko2u/centos6 CentOS6 日本語環境 2 [OK]
indigo/centos-maven Vanilla CentOS 7 with Oracle Java Developmen… 2 [OK]
amd64/centos The official build of CentOS. 2
dokken/centos-7 CentOS 7 image for kitchen-dokken 2
pivotaldata/centos6.8-dev CentosOS 6.8 image for GPDB development 1
blacklabelops/centos CentOS Base Image! Built and Updates Daily! 1 [OK]
smartentry/centos centos with smartentry 0 [OK]
```
可以看到返回了很多包含关键字的镜像,其中包括镜像名字、描述、点赞数(表示该镜像的受欢迎程度)、是否官方创建、是否自动创建。默认输出结果按照星级评价进行排序。
![image-20250324192816988](02.Docker镜像管理/image-20250324192816988.png)
### 2. 下载镜像
可以使用docker pull命令直接下载镜像语法为
```bash
docker pull NAME:TAG
```
其中NAME是镜像名称TAG是镜像的标签往往用来是表示版本信息通常情况下描述一个镜像需要包括名称+标签如果不指定标签标签的值默认为latest。
- 下载nginx、centos、hello-world镜像
```bash
[root@docker-server ~]# docker pull nginx
[root@docker-server ~]# docker pull centos
[root@docker-server ~]# docker pull hello-world
```
### 3. 查看镜像信息
#### 3.1 docker images
- 列出本地所有镜像
```bash
[root@docker-server ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest d1a364dc548d 2 weeks ago 133MB
hello-world latest d1165f221234 3 months ago 13.3kB
centos latest 300e315adb2f 6 months ago 209MB
```
在列出的信息中可以看到几个字段:
- REPOSITORY镜像仓库名称
- TAG镜像的标签信息
- 镜像ID唯一用来标识镜像如果两个镜像的ID相同说明他们实际上指向了同一个镜像只是具有不同标签名称而已
- CREATED创建时间说明镜像的最后更新时间
- SIZE镜像大小优秀的镜像往往体积都较小
#### 3.2 docker tag
为了方便在后续工作中使用特定镜像可以使用docker tag命令来为本地镜像任意添加新的标签
```bash
[root@localhost ~]# docker tag nginx:latest mynginx:latest
[root@localhost ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mynginx latest 53a18edff809 6 weeks ago 192MB
nginx latest 53a18edff809 6 weeks ago 192MB
hello-world latest 74cc54e27dc4 2 months ago 10.1kB
registry.cn-guangzhou.aliyuncs.com/welldene/games rpg_game 6a963645d135 22 months ago 310MB
```
#### 3.3 docker inspect
可以使用docker inspect命令获取该镜像的详细信息
```bash
[root@localhost ~]# docker inspect nginx:latest
[
{
"Id": "sha256:53a18edff8091d5faff1e42b4d885bc5f0f897873b0b8f0ace236cd5930819b0",
"RepoTags": [
"mynginx:latest",
"nginx:latest"
],
"RepoDigests": [
"nginx@sha256:124b44bfc9ccd1f3cedf4b592d4d1e8bddb78b51ec2ed5056c52d3692baebc19"
],
"Parent": "",
"Comment": "buildkit.dockerfile.v0",
"Created": "2025-02-05T21:27:16Z",
"DockerVersion": "",
"Author": "",
"Config": {
"Hostname": "",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"ExposedPorts": {
"80/tcp": {}
},
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"NGINX_VERSION=1.27.4",
"NJS_VERSION=0.8.9",
"NJS_RELEASE=1~bookworm",
"PKG_RELEASE=1~bookworm",
"DYNPKG_RELEASE=1~bookworm"
],
"Cmd": [
"nginx",
"-g",
"daemon off;"
],
"Image": "",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": [
"/docker-entrypoint.sh"
],
"OnBuild": null,
"Labels": {
"maintainer": "NGINX Docker Maintainers <docker-maint@nginx.com>"
},
"StopSignal": "SIGQUIT"
},
"Architecture": "amd64",
"Os": "linux",
"Size": 192004242,
"GraphDriver": {
"Data": {
"LowerDir": "/var/lib/docker/overlay2/5698387a01cba2eedc0058d1ceec91493ae1c0a55352cc3d3ff2de257add6461/diff:/var/lib/docker/overlay2/3c85557f47aee3bc95423d00407b301ba73ee79e689a4acaa63b22aea3f64a29/diff:/var/lib/docker/overlay2/0dcd12c3dfdc4ca7e74cc05e6ec1ea701bff84acbdbe8c0ece63a1a5cbac85c4/diff:/var/lib/docker/overlay2/3105b0866bd0cba95bb28d3df6e7948853129aaadf4bdb6f162de3d61bb176cc/diff:/var/lib/docker/overlay2/f0864c0d8aa319dbf9e0f63d00b817bd9723badce3eef3879cc3114523ed6831/diff:/var/lib/docker/overlay2/44374136ef63aea5fd69dc1dc7d3c6238b4eca766845f15a869eb1479bd12387/diff",
"MergedDir": "/var/lib/docker/overlay2/d658b597a569f714a0dab28da1ddf3b7b15001f1b1889dfc72f1ea8ed56d2cad/merged",
"UpperDir": "/var/lib/docker/overlay2/d658b597a569f714a0dab28da1ddf3b7b15001f1b1889dfc72f1ea8ed56d2cad/diff",
"WorkDir": "/var/lib/docker/overlay2/d658b597a569f714a0dab28da1ddf3b7b15001f1b1889dfc72f1ea8ed56d2cad/work"
},
"Name": "overlay2"
},
"RootFS": {
"Type": "layers",
"Layers": [
"sha256:1287fbecdfcce6ee8cf2436e5b9e9d86a4648db2d91080377d499737f1b307f3",
"sha256:135f786ad04647c6e58d9a2d4f6f87bd677ef6144ab24c81a6f5be7acc63fbc9",
"sha256:ad2f08e39a9de1e12157c800bd31ba86f8cc222eedec11e8e072c3ba608d26fb",
"sha256:d98dcc720ae098efb91563f0a9abe03de50b403f7aa6c6f0e1dfb8297aedb61f",
"sha256:aa82c57cd9fe730130e35d42c6b26a4a9d3c858f61c23f63d53b703abf30adf8",
"sha256:d26dc06ef910f67b1b2bcbcc6318e2e08881011abc7ad40fd859f38641ab105c",
"sha256:03d9365bc5dc9ec8b2f032927d3d3ae10b840252c86cf245a63b713d50eaa2fd"
]
},
"Metadata": {
"LastTagTime": "2025-03-24T19:26:37.193805768+08:00"
}
}
]
```
#### 3.4 docker history
镜像由多层组成可以使用history子命令该命令将列出各层创建信息
```bash
[root@localhost ~]# docker history nginx
IMAGE CREATED CREATED BY SIZE COMMENT
53a18edff809 6 weeks ago CMD ["nginx" "-g" "daemon off;"] 0B buildkit.dockerfile.v0
<missing> 6 weeks ago STOPSIGNAL SIGQUIT 0B buildkit.dockerfile.v0
<missing> 6 weeks ago EXPOSE map[80/tcp:{}] 0B buildkit.dockerfile.v0
<missing> 6 weeks ago ENTRYPOINT ["/docker-entrypoint.sh"] 0B buildkit.dockerfile.v0
<missing> 6 weeks ago COPY 30-tune-worker-processes.sh /docker-ent… 4.62kB buildkit.dockerfile.v0
<missing> 6 weeks ago COPY 20-envsubst-on-templates.sh /docker-ent… 3.02kB buildkit.dockerfile.v0
<missing> 6 weeks ago COPY 15-local-resolvers.envsh /docker-entryp… 389B buildkit.dockerfile.v0
<missing> 6 weeks ago COPY 10-listen-on-ipv6-by-default.sh /docker… 2.12kB buildkit.dockerfile.v0
<missing> 6 weeks ago COPY docker-entrypoint.sh / # buildkit 1.62kB buildkit.dockerfile.v0
<missing> 6 weeks ago RUN /bin/sh -c set -x && groupadd --syst… 117MB buildkit.dockerfile.v0
<missing> 6 weeks ago ENV DYNPKG_RELEASE=1~bookworm 0B buildkit.dockerfile.v0
<missing> 6 weeks ago ENV PKG_RELEASE=1~bookworm 0B buildkit.dockerfile.v0
<missing> 6 weeks ago ENV NJS_RELEASE=1~bookworm 0B buildkit.dockerfile.v0
<missing> 6 weeks ago ENV NJS_VERSION=0.8.9 0B buildkit.dockerfile.v0
<missing> 6 weeks ago ENV NGINX_VERSION=1.27.4 0B buildkit.dockerfile.v0
<missing> 6 weeks ago LABEL maintainer=NGINX Docker Maintainers <d… 0B buildkit.dockerfile.v0
<missing> 6 weeks ago # debian.sh --arch 'amd64' out/ 'bookworm' '… 74.8MB debuerreotype 0.15
```
### 4. 镜像导入导出
#### 4.1 导出
可以将镜像从本地导出为一个压缩文件,然后复制到其他服务器进行导入使用
- 导出方法一
```bash
[root@localhost ~]# docker save nginx:latest -o /opt/nginx.tar.gz
[root@localhost ~]# ll /opt/nginx.tar.gz
-rw-------. 1 root root 196167168 Mar 24 19:28 /opt/nginx.tar.gz
```
- 导出方法二
```bash
[root@localhost ~]# docker save nginx:latest > /opt/nginx-1.tar.gz
[root@localhost ll /opt/nginx-1.tar.gz
-rw-r--r--. 1 root root 196167168 Mar 24 19:29 /opt/nginx-1.tar.gz
```
#### 4.2 导入
先将导出的镜像发到需要导入的docker服务器中
- 导入方法一
```bash
[root@docker-server ~]# docker load -i /opt/nginx.tar.gz
Loaded image: centos:latest
```
- 导出方法二
```bash
[root@docker-server ~]# docker load < /opt/nginx.tar.gz
Loaded image: centos:latest
```
### 5. 删除镜像
- 使用镜像名称+标签
```bash
[root@docker-server ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest d1a364dc548d 2 weeks ago 133MB
hello-world latest d1165f221234 3 months ago 13.3kB
centos latest 300e315adb2f 6 months ago 209MB
mycentos latest 300e315adb2f 6 months ago 209MB
[root@docker-server ~]# docker rmi nginx:latest
Untagged: nginx:latest
Untagged: nginx@sha256:6d75c99af15565a301e48297fa2d121e15d80ad526f8369c526324f0f7ccb750
Deleted: sha256:d1a364dc548d5357f0da3268c888e1971bbdb957ee3f028fe7194f1d61c6fdee
Deleted: sha256:fcc8faba78fe8a1f75025781c8fa1841079b75b54fce8408d039f73a48b7a81b
Deleted: sha256:a476b265974ace4c857e3d88b358e848f126297a8249840c72d5f5ea1954a4bf
Deleted: sha256:56722ee1ee7e73a5c6f96ea2959fa442fb4db9f044399bcd939bb0a6eb7919dc
Deleted: sha256:c657df997c75f6c1a9c5cc683e8e34c6f29e5b4c1dee60b632d3477fd5fdd644
Deleted: sha256:e9e1f772d2a8dbbeb6a4a4dcb4f0d07ff1c432bf94fac7a2db2216837bf9ec5b
Deleted: sha256:02c055ef67f5904019f43a41ea5f099996d8e7633749b6e606c400526b2c4b33
```
- 使用镜像id
```bash
[root@docker-server ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest d1165f221234 3 months ago 13.3kB
centos latest 300e315adb2f 6 months ago 209MB
mycentos latest 300e315adb2f 6 months ago 209MB
[root@docker-server ~]# docker rmi 300e315adb2f
Error response from daemon: conflict: unable to delete 300e315adb2f (must be forced) - image is referenced in multiple repositories
[root@docker-server ~]# docker rmi 300e315adb2f -f
Untagged: centos:latest
Untagged: centos@sha256:5528e8b1b1719d34604c87e11dcd1c0a20bedf46e83b5632cdeac91b8c04efc1
Untagged: mycentos:latest
Deleted: sha256:300e315adb2f96afe5f0b2780b87f28ae95231fe3bdd1e16b9ba606307728f55
Deleted: sha256:2653d992f4ef2bfd27f94db643815aa567240c37732cae1405ad1c1309ee9859
[root@docker-server ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest d1165f221234 3 months ago 13.3kB
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 KiB

View File

@@ -0,0 +1,400 @@
# 03.Docker容器管理
## 03.Docker容器管理
### 1. docker容器管理
### 2. 创建容器
#### 2.1 docker create
docker create命令新建的容器处于停滞状态可以使用docker start命令来启动它
| 选项 | 说明 |
| ------------- | ------------------------------------------------------------ |
| -d | 是否在后台运行容器,默认为否 |
| -i | 保持标准输入打开 |
| -P | 通过NAT机制将容器标记暴露的端口自动映射到本地主机的临时端口 |
| -p | 指定如何映射到本地主机端口 |
| -t | 分配一个终端 |
| -v | 挂载主机上的文件卷到容器内 |
| --rm | 容器退出后是否自动删除,不能跟-d同时使用 |
| -e | 指定容器内的环境变量 |
| -h | 指定容器内的主机名 |
| --name | 指定容器的别名 |
| --cpu-shares | 允许容器使用cpu资源的相对权重默认一个容器能用满一个核的cpu |
| --cpuset-cpus | 限制容器能使用哪些cpu核心 |
| -m | 限制容器内使用的内存单位可以是b、k、m、g |
```
docker create -it --name mycontainer mycentos bash
docker start mycontainer
```
#### 2.2 docker run
除了创建容器后通过start命令来启动也可以通过docker run直接新建并启动容器。
- 启动一个容器
```bash
[root@docker-server ~]# docker run -it centos:latest bash
[root@4abaf8a399fe /]#
```
- 显示正在运行的容器
```bash
[root@docker-server ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4abaf8a399fe centos:latest "bash" 47 seconds ago Up 46 seconds hardcore_perlman
```
- 显示所有容器,包括停止的所有容器
```bash
[root@docker-server ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
[root@docker-server ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4abaf8a399fe centos:latest "bash" 2 minutes ago Exited (0) 9 seconds ago hardcore_perlman
```
#### 2.3 端口映射
- 前台启动随机映射端口
```bash
[root@docker-server ~]# docker pull nginx
[root@docker-server ~]# docker run -P nginx
# 随机映射端口其实是从32768开始映射
[root@docker-server ~]# ss -tanl
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 *:22 *:*
LISTEN 0 100 127.0.0.1:25 *:*
LISTEN 0 128 *:49153 *:*
LISTEN 0 128 :::22 :::*
LISTEN 0 100 ::1:25 :::*
LISTEN 0 128 :::49153 :::*
```
![image-20210609140116589](03.Docker容器管理/image-20210609140116589.png)
- 指定端口映射
```bash
# 方式1本地端口80映射到容器80端口
[root@docker-server ~]# docker run -p 80:80 --name nginx-1 nginx:latest
# 方式2本地ip本地端口容器端口
[root@docker-server ~]# docker run -p 192.168.204.135:80:80 --name nginx-1 nginx:latest
# 方式3本地ip本地随机端口容器端口
[root@docker-server ~]# docker run -p 192.168.175.10::80 --name nginx-1 nginx:latest
# 方式4本地ip本地端口容器端口/协议默认为tcp协议
[root@docker-server ~]# docker run -p 192.168.175.10:80:80/tcp --name nginx-1 nginx:latest
```
- 查看容器已经映射的端口
```bash
[root@docker-server ~]# docker port nginx-1
80/tcp -> 0.0.0.0:80
80/tcp -> :::80
```
#### 2.4 后台启动容器
- 当容器前台启动时,前台进程退出容器也就退出,更多时候需要容器在后台启动
```bash
[root@docker-server ~]# docker run -d -P --name nginx-2 nginx
c75333168c0dad9094d94828c33998294f2809ae8c5b60881707d9cc33ea4893
```
- 传递运行命令
容器需要由一个前台运行的进程才能保持容器的运行,通过传递运行参数是一种方式,另外也可以在构建镜像的时候指定容器启动时运行的前台命令
```bash
[root@docker-server ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
[root@docker-server ~]# docker run -d centos
9ef312d30f7a396ecb5c93b7b70e70a742f333bbe01e9112d6f22fc52aeb71b8
[root@docker-server ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
[root@docker-server ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
9ef312d30f7a centos "/bin/bash" 12 seconds ago Exited (0) 11 seconds ago upbeat_noether
[root@docker-server ~]# docker run -d centos tail -f /etc/hosts
7b0700c01f9516f49e70ad92e7256d965e0fe4eb8ccc7b30676a03c1d8046c64
[root@docker-server ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7b0700c01f95 centos "tail -f /etc/hosts" 3 seconds ago Up 2 seconds charming_brahmagupta
```
- 单次运行,容器退出后自动删除
```bash
[root@docker-server ~]# docker run --name hello_world_test --rm hello-world
Hello from Docker!
This message shows that your installation appears to be working correctly.
To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
(amd64)
3. The Docker daemon created a new container from that image which runs the
executable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client, which sent it
to your terminal.
To try something more ambitious, you can run an Ubuntu container with:
$ docker run -it ubuntu bash
Share images, automate workflows, and more with a free Docker ID:
https://hub.docker.com/
For more examples and ideas, visit:
https://docs.docker.com/get-started/
[root@docker-server ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
[root@docker-server ~]#
```
### 3. 停止容器
#### 3.1 暂停容器
- 挂起容器
```bash
[root@docker-server ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4c6344c46c80 nginx "/docker-entrypoint.…" 8 seconds ago Up 8 seconds 80/tcp wizardly_hofstadter
[root@docker-server ~]# docker pause wizardly_hofstadter
wizardly_hofstadter
[root@docker-server ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4c6344c46c80 nginx "/docker-entrypoint.…" 17 seconds ago Up 16 seconds (Paused) 80/tcp wizardly_hofstadter
```
- 取消挂起容器
```bash
[root@docker-server ~]# docker unpause wizardly_hofstadter
wizardly_hofstadter
[root@docker-server ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4c6344c46c80 nginx "/docker-entrypoint.…" 33 seconds ago Up 33 seconds 80/tcp wizardly_hofstadter
```
#### 3.2 终止容器
```bash
[root@docker-server ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4c6344c46c80 nginx "/docker-entrypoint.…" About a minute ago Up About a minute 80/tcp wizardly_hofstadter
[root@docker-server ~]# docker stop wizardly_hofstadter
wizardly_hofstadter
[root@docker-server ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4c6344c46c80 nginx "/docker-entrypoint.…" 2 minutes ago Exited (0) 5 seconds ago wizardly_hofstadter
[root@docker-server ~]# docker start wizardly_hofstadter
wizardly_hofstadter
[root@docker-server ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4c6344c46c80 nginx "/docker-entrypoint.…" 2 minutes ago Up 2 seconds 80/tcp wizardly_hofstadter
```
### 4. 删除容器
#### 4.1 docker rm
- 删除正在运行的容器
```bash
[root@docker-server ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
dfd5ba20c3c6 centos:latest "bash" 8 seconds ago Up 6 seconds frosty_elbakyan
[root@docker-server ~]# docker rm -f dfd5ba20c3c6
dfd5ba20c3c6
```
- 批量删除容器
```bash
[root@docker-server ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8e3cb314c9ad nginx "/docker-entrypoint.…" 4 seconds ago Up 3 seconds 80/tcp pedantic_lovelace
4ab46864c8a3 nginx "/docker-entrypoint.…" 5 seconds ago Up 4 seconds 80/tcp beautiful_spence
26a154528469 nginx "/docker-entrypoint.…" 5 seconds ago Up 5 seconds 80/tcp serene_booth
2ecbf60d817a nginx "/docker-entrypoint.…" 6 seconds ago Up 6 seconds 80/tcp dreamy_bassi
d73faf8c2f7d nginx "/docker-entrypoint.…" 8 seconds ago Up 8 seconds 80/tcp beautiful_solomon
[root@docker-server ~]# docker ps -a -q
8e3cb314c9ad
4ab46864c8a3
26a154528469
2ecbf60d817a
d73faf8c2f7d
[root@docker-server ~]# docker rm -f `docker ps -a -q`
8e3cb314c9ad
4ab46864c8a3
26a154528469
2ecbf60d817a
d73faf8c2f7d
[root@docker-server ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
```
### 5. 进入容器
#### 5.1 attach
所有使用此方式进入容器的操作都是同步显示的且exit容器将被关闭且使用exit退出后容器关闭不推荐使用
![image-20210609143957975](03.Docker容器管理/image-20210609143957975.png)
当有一个容器执行exit退出后会导致容器退出
#### 5.2 exec
执行单次命令与进入容器,退出容器后容器还在运行
```bash
[root@docker-server ~]# docker run -d -it centos
129d518869d550e579bcff38608bae38209923dcbfab49c823d5e1473d38214a
[root@docker-server ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
129d518869d5 centos "/bin/bash" 2 seconds ago Up 1 second jovial_haibt
[root@docker-server ~]# docker exec -it jovial_haibt /bin/bash
[root@129d518869d5 /]# echo hello
hello
[root@129d518869d5 /]# exit
exit
[root@docker-server ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
129d518869d5 centos "/bin/bash" 46 seconds ago Up 45 seconds jovial_haibt
```
```
在Docker中docker exec命令用于在正在运行的容器中执行命令。docker exec命令的一般语法如下
docker exec [OPTIONS] CONTAINER COMMAND [ARG...]
其中,参数的含义如下:
OPTIONS可选参数用于指定一些附加选项。常用的选项包括
-i, --interactive保持标准输入stdin打开允许用户与命令交互。
-t, --tty分配一个伪终端pseudo-TTY以便于命令的交互和输出格式化。
-u, --user指定执行命令的用户或用户组。
-d, --detach在后台运行命令。
-e, --env设置环境变量。
-w, --workdir指定命令执行的工作目录。
等等。
CONTAINER必需参数指定要执行命令的容器名称或容器ID。
COMMAND必需参数指定要在容器中执行的命令。
ARG可选参数传递给命令的参数
```
#### 5.3 nsenter
nsenter命令需要通过pid进入到容器内部不过可以使用docker inspect获取到容器的pid
- 可以通过docker inspect获取到某个容器的进程id
```bash
[root@docker-server ~]# docker inspect -f ".State.Pid" 129d518869d5 # .State.Pid 两边需要加上两个花括号
7949
```
- 通过nsenter进入到容器内部
```bash
[root@docker-server ~]# nsenter -t 7949 -m -u -i -n -p
[root@129d518869d5 /]#
```
- 使用脚本方式进入
```bash
[root@docker-server ~]# cat docker_in.sh
#!/bin/bash
docker_in(){
DOCKER_ID=$1
PID=`docker inspect -f ".State.Pid" ${DOCKER_ID}`
nsenter -t ${PID} -m -u -i -n -p
}
docker_in $1
[root@docker-server ~]# chmod +x docker_in.sh
[root@docker-server ~]# ./docker_in.sh 129d518869d5
[root@129d518869d5 /]# exit
logout
[root@docker-server ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
129d518869d5 centos "/bin/bash" 14 minutes ago Up 14 minutes jovial_haibt
[root@docker-server ~]#
```
### 6. 指定容器DNS
dns服务默认采用dns地址
一是通过将dns地址配置在宿主机上
二是将参数配置在docker启动脚本里面
```bash
[root@docker-server ~]# docker run -it --rm --dns 8.8.8.8 centos bash
[root@a6ce80126e75 /]# cat /etc/resolv.conf
nameserver 8.8.8.8
[root@a6ce80126e75 /]# ping www.baidu.com -c 1
PING www.a.shifen.com (180.101.49.11) 56(84) bytes of data.
64 bytes from 180.101.49.11 (180.101.49.11): icmp_seq=1 ttl=127 time=9.35 ms
--- www.a.shifen.com ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 9.346/9.346/9.346/0.000 ms
[root@a6ce80126e75 /]# exit
exit
```
### 7. 导入导出容器
#### 7.1 docker export
导出容器是指,导出一个已经创建的容器到一个文件,不管此时这个容器是否处于运行状态,**导出一个容器快照**
```bash
[root@docker-server ~]# docker run -d -it centos
43f2397b9456d27a3b84dba0d79ae9a1dd8dddf40440d7d73fca71cddea0e10d
[root@docker-server ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
43f2397b9456 centos "/bin/bash" 2 seconds ago Up 2 seconds awesome_rubin
[root@docker-server ~]# docker export -o /opt/centos.tar 43f
[root@docker-server ~]# ll /opt/centos.tar
-rw------- 1 root root 216525312 6月 9 13:28 /opt/centos.tar
```
#### 7.2 docker import
导出的文件可以使用docker import命令导入变成镜像**导入一个容器快照到本地镜像库**
```bash
[root@docker-server ~]# docker import /opt/centos.tar mycentos:v1
sha256:acf250a6cabb56e0464102dabedb0a562f933facd3cd7b387e665459da46bf29
[root@docker-server ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mycentos v1 acf250a6cabb 9 seconds ago 209MB
nginx latest d1a364dc548d 2 weeks ago 133MB
hello-world latest d1165f221234 3 months ago 13.3kB
centos latest 300e315adb2f 6 months ago 209MB
```
适用场景主要用来制作基础镜像比如从一个ubuntu镜像启动一个容器然后安装一些软件和进行一些设置后使用docker export保存为一个基础镜像。然后把这个镜像分发给其他人使用作为基础的开发环境。(因为export导出的镜像只会保留从镜像运行到export之间对文件系统的修改所以只适合做基础镜像)

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

View File

@@ -0,0 +1,469 @@
# 04.Docker镜像制作
## 04.Docker镜像制作
### 1. Docker镜像制作
### 2. 基于rocky手动构建nginx镜像
Docker镜像制作类似于虚拟机的模板制作即按照公司的实际业务将需要安装的软件、相关配置等基础环境配置完成然后将容器再提交为模板最后再批量从模板批量创建新的虚拟机这样可以极大地简化业务中相同环境的虚拟机运行环境的部署工作Docker的镜像制作分为手动制作可自动制作基于DockerFile企业通常都是基于DockerFile制作镜像。
#### 2.1 从初始镜像开始构建
一、启动一个RockyLinux容器安装好nginx以及常用软件
```bash
[root@localhost ~]# docker run -it -d --name mynginx_server rockylinux:9 bash
18914b0f6005e7b20122508f8bc70a830845711ff6200392bf0a7c76dc4a8a60
[root@localhost ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
18914b0f6005 rockylinux:9 "bash" 3 seconds ago Up 2 seconds mynginx_server
[root@localhost ~]# docker exec -it mynginx_server bash
# 进入容器以后安装nginx以及一些常用的软件
[root@18914b0f6005 /]# yum install -y epel-release nginx
[root@18914b0f6005 /]# yum install vim wget pcre pcre-devel zlib zlib-devel openssl openssl-devel iproute net-tools iotop -y
```
二、关闭nginx后台运行
```bash
[root@18914b0f6005 /]# vim /etc/nginx/nginx.conf
......
daemon off;
......
```
三、自定义web界面
```bash
[root@18914b0f6005 /]# vim /etc/nginx/nginx.conf
[root@18914b0f6005 /]# echo "<h1>Welcome to Eagle nginx...</h1>" > /usr/share/nginx/html/index.html
```
#### 2.2 镜像提交
通过commit提交为镜像
```bash
[root@localhost ~]# docker commit --help
Usage: docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]
Create a new image from a container's changes
Aliases:
docker container commit, docker commit
Options:
-a, --author string Author (e.g., "John Hannibal Smith
<hannibal@a-team.com>")
-c, --change list Apply Dockerfile instruction to the created image
-m, --message string Commit message
-p, --pause Pause container during commit (default true)
# 重新打包为新镜像
[root@localhost ~]# docker commit -a "Eagle_nls" -m "my nginx image v1" 18914b0f6005 rocky_nginx:v1
sha256:9411e13b57d003a6d709054ccbbc026a7b005a1727ec470755f987e25ff45a6b
[root@localhost ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
rocky_nginx v1 9411e13b57d0 33 seconds ago 357MB
mynginx v1 81ef4ae01fed 2 hours ago 190MB
codercom/code-server latest 5d9cf2e7e6bb 10 days ago 718MB
neosmemo/memos latest 8f07b54db502 6 weeks ago 65.9MB
```
docker commit**适用场景:**主要作用是将配置好的一些容器复用,再生成新的镜像。
commit是合并了save、load、export、import这几个特性的一个综合性的命令它主要做了
1、将container当前的读写层保存下来保存成一个新层
2、和镜像的历史层一起合并成一个新的镜像
#### 2.3 从新镜像启动容器
从自己的镜像启动容器
```bash
[root@localhost ~]# docker run -d -p 80:80 --name mynginx_rocky rocky_nginx:v1 /usr/sbin/nginx
dc4225c68d28ffdcc559662b8680f9e4b4b95bdaeeca2f1ed566d638aa8fc8fe
[root@localhost ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
dc4225c68d28 rocky_nginx:v1 "/usr/sbin/nginx" 2 seconds ago Up 1 second 0.0.0.0:80->80/tcp, [::]:80->80/tcp mynginx_rocky
```
访问测试:
![image-20250325185125851](04.Docker镜像制作/image-20250325185125851.png)
### 3. DockerFile制作镜像
Dockerfile 是一种可以被 Docker 程序解释的脚本,它是一个文本文件,包含了一系列指令,用于定义如何构建 Docker 镜像。每一条指令都会创建镜像的一层最终生成的镜像是由这些层叠加而成的。Dockerfile 中的指令关键字必须大写,执行顺序是从上到下,且每条指令创建一个镜像层。
Docker 程序会读取 Dockerfile 并根据指令生成 Docker 镜像。Dockerfile 的指令类似于 Linux 下的命令,但 Docker 程序会将这些 Dockerfile 指令翻译成真正的 Linux 命令来执行。相比手动制作镜像的方式Dockerfile 能更直观地展示镜像是如何产生的。有了写好的 Dockerfile 文件,当后期某个镜像有额外的需求时,只需在之前的 Dockerfile 中添加或修改相应的操作,即可重新生成新的 Docker 镜像,避免了重复手动制作镜像的麻烦。
#### 3.1 指令说明
##### 3.1.1 配置指令
| 指令 | 说明 |
| :------------ | :--------------------------------- |
| `ARG` | 定义创建镜像过程中使用的变量 |
| `FROM` | 指定所创建镜像的基础镜像 |
| `LABEL` | 为生成的镜像添加元数据标签信息 |
| `EXPOSE` | 声明镜像内服务监听的端口 |
| `ENV` | 指定环境变量 |
| `ENTRYPOINT` | 指定镜像的默认入口命令 |
| `VOLUME` | 创建一个数据卷挂载点 |
| `USER` | 指定运行容器时的用户名或UID |
| `WORKDIR` | 配置工作目录 |
| `ONBUILD` | 创建子镜像时指定自动执行的操作指令 |
| `STOPSIGNAL` | 指定退出的信号值 |
| `HEALTHCHECK` | 配置所启动容器如何进行健康检查 |
| `SHELL` | 指定默认shell类型 |
##### 3.1.2 操作指令
| 指令 | 说明 |
| :----- | :--------------------------- |
| `RUN` | 运行指定命令 |
| `CMD` | 启动容器时指定默认执行的命令 |
| `ADD` | 添加内容到镜像 |
| `COPY` | 复制内容到镜像 |
#### 3.2 配置指令详解
##### 3.2.1 ARG
定义创建过程中使用到的变量,例如 `HTTP_PROXY``HTTPS_PROXY``FTP_PROXY``NO_PROXY` 等,不区分大小写。
##### 3.2.2 FROM
指定所创建镜像的基础镜像。为了保证镜像精简,可以选用体积较小的 Alpin 或 Debian 作为基础镜像。
##### 3.2.3 EXPOSE
声明镜像内服务监听的端口。例如:
```bash
EXPOSE 22 80 8443
```
该指令只是起到声明作用,并不会自动完成端口映射。
##### 3.2.4 ENTRYPOINT
指定镜像的默认入口命令,该入口命令会在启动容器时作为根命令执行,所有传入值作为该命令的参数。支持两种格式:
- `ENTRYPOINT ["executable","param1","param2"]`exec 调用执行)
- `ENTRYPOINT command param1 param2`(在 shell 中执行)
此时 `CMD` 指令指定值将作为根命令的参数。每个 Dockerfile 中只能有一个 `ENTRYPOINT`,当指定多个时只有最后一个起效。
##### 3.2.5 VOLUME
创建一个数据卷挂载点。例如:
```bash
VOLUME ["/data"]
```
##### 3.2.6 WORKDIR
为后续的 `RUN``CMD``ENTRYPOINT` 指令配置工作目录。例如:
```bash
WORKDIR /path/to/workdir
```
可以使用多个 `WORKDIR` 指令,后续命令如果参数是相对路径,则会基于之前命令指定的路径。例如:
```bash
WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd
```
最终路径为 `/a/b/c`。因此,为了避免出错,推荐在 `WORKDIR` 指令中只使用绝对路径。
##### 3.2.7 操作指令详解
##### 3.2.8 RUN
运行指定Linux命令。每条 `RUN` 指令将在当前镜像基础上执行指定命令,并提交为新的镜像层。当命令较长时可以使用 `\` 来换行。
##### 3.2.9 CMD
`CMD` 指令用来指定启动容器时默认执行的命令。支持三种格式:
- `CMD ["executable","param1","param2"]`(相当于执行 `executable param1 param2`
- `CMD command param1 param2`(在默认的 shell 中执行,提供给需要交互的应用)
- `CMD ["param1","param2"]`(提供给 `ENTRYPOINT` 的默认参数)
每个 Dockerfile 只能有一条 `CMD` 命令。如果指定了多条命令,只有最后一条会被执行。
##### 3.2.10 ADD
添加内容到镜像。例如:
```bash
ADD <src> <dest>
```
该命令将复制指定的 `src` 路径下内容到容器中的 `dest` 路径下。`src` 可以是 Dockerfile 所在目录的一个相对路径,也可以是一个 URL还可以是一个 tar 文件。`dest` 可以是镜像内绝对路径,或者相对于工作目录的相对路径。
##### 3.2.11 COPY
复制内容到镜像。例如:
```bash
COPY <src> <dest>
```
`COPY``ADD` 指令功能类似,当使用本地目录为源目录时,推荐使用 `COPY`
#### 3.3 制作nginx镜像
DockerFile可以说是一种可以被Docker程序解释的脚本DockerFIle是由一条条的命令组成的每条命令对应Linux下面的一条命令Docker程序将这些DockerFile指令再翻译成真正的Linux命令其有自己的书写方式和支持的命令Docker程序读取DockerFile并根据指令生成Docker镜像。
##### 3.3.1 基于编译安装制作nginx小游戏网站
###### 3.3.1.1 环境准备
一、下载镜像
```bash
[root@localhost ~]# docker pull rockylinux:9
```
二、创建所需文件存放的目录环境
```bash
[root@localhost ~]# mkdir -pv dockerfile/nginx
mkdir: created directory 'dockerfile'
mkdir: created directory 'dockerfile/nginx'
```
三、进入到指定目录中
```bash
[root@localhost ~]# cd dockerfile/nginx/
[root@localhost nginx]# pwd
/root/dockerfile/nginx
```
四、下载nginx和小游戏网页的源码包
```bash
[root@localhost nginx]# wget http://nginx.org/download/nginx-1.22.0.tar.gz
[root@localhost nginx]# wget http://file.eagleslab.com:8889/%E8%AF%BE%E7%A8%8B%E7%9B%B8%E5%85%B3%E8%BD%AF%E4%BB%B6/%E4%BA%91%E8%AE%A1%E7%AE%97%E8%AF%BE%E7%A8%8B/%E8%AF%BE%E7%A8%8B%E7%9B%B8%E5%85%B3%E6%96%87%E4%BB%B6/games.tar.gz
[root@localhost nginx]# ll
total 125100
-rw-r--r--. 1 root root 127022187 Jan 18 2022 games.tar.gz
-rw-r--r--. 1 root root 1073322 May 24 2022 nginx-1.22.0.tar.gz
```
###### 3.3.1.2 编写Dockerfile
一、编写DockerFile
```bash
[root@docker-server nginx]# vim Dockerfile
# 第一行先定义基础镜像,后面的本地有效的镜像名,如果本地没有,会从远程仓库下载
FROM rockylinux:9
# 镜像作者的信息
MAINTAINER Eagle_nls 2898485992@qq.com
# 接下来在基础镜像之上构建nginx等所需环境
# 1. 编译安装nginx
# 1.1 安装所需环境及工具
RUN yum install -y vim wget unzip tree lrzsz gcc gcc-c++ automake pcre pcre-devel zlib zlib-devel openssl openssl-devel iproute net-tools iotop
# 1.2 上传nginx的官方源码包到指定目录
ADD nginx-1.22.0.tar.gz /usr/local/src/
# 1.3 由于ADD会直接解压好所以直接编译nginx
RUN cd /usr/local/src/nginx-1.22.0 \
&& ./configure --prefix=/usr/local/nginx --with-http_sub_module \
&& make \
&& make install \
&& cd /usr/local/nginx
# 如果有配置文件,可以上传自己准备好的配置文件
# ADD nginx.conf /usr/local/nginx/conf/nginx.conf
# 2. 完善网站
RUN useradd -s /sbin/nologin nginx \
&& ln -sv /usr/local/nginx/sbin/nginx /usr/sbin/nginx
# 3. 上传小游戏网页源码
ADD games.tar.gz /usr/local/nginx/html/
# 4. 声明端口号
EXPOSE 80 443
# 5. 设定启动时执行命令
CMD ["nginx", "-g", "daemon off;"]
```
###### 3.3.1.3 构建镜像
一、通过docker build来构建镜像
```bash
[root@localhost nginx]# docker build -t nginx_games:v1 .
[root@localhost nginx]# docker images |grep nginx_games
nginx_games v1 9c86d96dfba0 4 minutes ago 686MB
```
二、镜像运行测试
```bash
[root@localhost nginx]# docker run -d -it -p 80:80 --name nginx_games nginx_games:v1
e3c415425f95b3deac80ecb772d1de2a89e18a611c2ecc603f3c0b175bbea335
[root@localhost nginx]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e3c415425f95 nginx_games:v1 "nginx -g 'daemon of…" 3 seconds ago Up 2 seconds 0.0.0.0:80->80/tcp, [::]:80->80/tcp, 443/tcp nginx_games
```
三、访问测试
![image-20250325195752895](04.Docker镜像制作/image-20250325195752895.png)
### 4. 镜像上传
#### 4.1 官方docker仓库
- 准备账户
登陆到docker hub官网创建账号登陆后点击settings完善信息
- 填写账户基本信息
![image-20220920090601269](04.Docker镜像制作/image-20220920090601269.png)
- 登陆仓库
```bash
[root@docker-server ~]# docker login docker.io
Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.
Username: smqy
Password:
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store
Login Succeeded
[root@docker-server ~]# ls -a
. .bash_history .bashrc dockerfile .tcshrc
.. .bash_logout .cshrc docker_in.sh .viminfo
anaconda-ks.cfg .bash_profile .docker .pki
[root@docker-server ~]# cat .docker/config.json
{
"auths": {
"https://index.docker.io/v1/": {
"auth": "YmJqMTAzMDp6aGFuZ2ppZTEyMw=="
}
}
}[root@docker-server ~]#
```
- 给镜像tag标签并上传
```bash
[root@docker-server ~]# docker tag nginx:v1 docker.io/smqy/nginx:v1
[root@docker-server ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx v1 fbd06c1753c0 12 minutes ago 581MB
smqy/nginx v1 fbd06c1753c0 12 minutes ago 581MB
centos_nginx v1 74acdcca8c97 21 hours ago 525MB
nginx latest 2b7d6430f78d 3 weeks ago 142MB
centos 7 eeb6ee3f44bd 12 months ago 204MB
nginx 1.8 0d493297b409 6 years ago 133MB
[root@docker-server ~]# docker push docker.io/smqy/nginx:v1
The push refers to repository [docker.io/smqy/nginx]
4f86a3bf507f: Pushed
0d11c01ff3ef: Pushed
45fc5772a4e4: Pushed
174f56854903: Mounted from library/centos
v1: digest: sha256:385bfe364839b645f1b2aa70a1d779b0dca50256ea01ccbe4ebde53aabd1d96d size: 1164
```
- 到docker官网进行验证
![image-20220920091110123](04.Docker镜像制作/image-20220920091110123.png)
- 更换到其他docker服务器下载镜像
```bash
[root@docker-server ~]# docker login docker.io
```
#### 4.2 阿里云仓库
将本地镜像上传至阿里云,实现镜像备份与统一分发的功能
https://cr.console.aliyun.com/
注册并且登录阿里云镜像仓库创建namespace空间创建一个普通的镜像仓库
![image-20250325201301197](04.Docker镜像制作/image-20250325201301197.png)
具体如何拉取镜像,上传镜像,可以查看阿里云仓库下方提供的操作指南
##### 4.2.1 Push镜像案例
一、登录阿里云仓库
```bash
[root@localhost nginx]# docker login --username=Echooool registry.cn-hangzhou.aliyuncs.com
i Info → A Personal Access Token (PAT) can be used instead.
To create a PAT, visit https://app.docker.com/settings
Password:
Error response from daemon: Get "https://registry.cn-hangzhou.aliyuncs.com/v2/": unauthorized: authentication required
[root@localhost nginx]# docker login --username=Echooool registry.cn-hangzhou.aliyuncs.com
i Info → A Personal Access Token (PAT) can be used instead.
To create a PAT, visit https://app.docker.com/settings
Password:
WARNING! Your credentials are stored unencrypted in '/root/.docker/config.json'.
Configure a credential helper to remove this warning. See
https://docs.docker.com/go/credential-store/
Login Succeeded
```
二、推送镜像
```bash
# 先给要推送的镜像打上标签
[root@localhost nginx]# docker tag 9c86d96dfba0 registry.cn-hangzhou.aliyuncs.com/atopos/docker_hub:nginx_games-v1
# 推送镜像
docker push registry.cn-hangzhou.aliyuncs.com/atopos/docker_hub:nginx_games-v1
```
三、阿里云查看
![image-20250325202050140](04.Docker镜像制作/image-20250325202050140.png)
四、拉取镜像
```bash
[root@localhost nginx]# docker pull registry.cn-hangzhou.aliyuncs.com/atopos/docker_hub:nginx_games-v1
nginx_games-v1: Pulling from atopos/docker_hub
446f83f14b23: Already exists
d9262d5a1401: Already exists
7330c5b74c49: Already exists
55e1c23f0b49: Already exists
5de772a29709: Already exists
f4819c5e7596: Already exists
Digest: sha256:f9a6ac50b9771c524017304847f3d8b2ffa4acbe01cef9279052272e50a9a3f3
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 323 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 834 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

View File

@@ -0,0 +1,314 @@
# 05.Docker数据管理
## 05.Docker数据管理
### 1. Docker数据管理
### 2. 数据管理
#### 2.1 UnionFS联合文件系统
Docker 中的 UnionFS联合文件系统是一种分层、轻量级且高性能的文件系统其核心功能是将多个目录内容联合挂载到同一个目录下形成一个统一的文件系统视图。以下是其主要特点和作用
##### 2.1.1 核心特点
- **分层存储**UnionFS 可以将不同层次的文件和目录合并成单一的目录树。在 Docker 中,每一层可以代表一个镜像层,最低层通常是只读的基础镜像层,上面的层是可写的容器层。
- **写时复制Copy-on-Write, CoW**当容器需要修改一个文件时UnionFS 不会直接更改底层只读镜像中的文件,而是将更改写入到一个可写的上层。这样,原始镜像层保持不变,可以被多个容器共享。
- **隔离性**:由于底层的只读镜像层保持不变,每个容器看到的是一个完整的文件系统视图,包括它们的改动,但这些改动仅存在于它们自己的可写层中。
- **性能优化**UnionFS 通过仅对发生更改的文件进行操作,以及通过页面缓存共享等机制,减少了磁盘 I/O 操作,加快了容器启动时间。
##### 2.1.2 在 Docker 中的应用
- **镜像分层**Docker 镜像是由多个只读层叠加而成的每一层都代表了镜像构建过程中的一个状态。UnionFS 将这些层联合起来,形成一个完整的文件系统。
- **容器运行时的文件系统**当启动一个容器时Docker 会在镜像的最顶层添加一个新的可写层。容器的所有写操作都在这个可写层中进行,而不会影响到镜像的只读层。
- **镜像继承与共享**:由于镜像的分层结构,新的镜像可以基于已有的镜像构建,只需添加新的层即可。同时,多个容器可以共享同一个镜像的只读层,极大地节省了磁盘空间。
##### 2.1.3 常见的 UnionFS 实现
虽然 UnionFS 是一个理念,但 Linux 内核中有多种具体的实现方式Docker 默认使用的是 Overlay2。Overlay2 是一种先进的联合文件系统实现,具有更好的性能和一些先进的功能,如页面缓存共享。
#### 2.2 镜像层与可写层
在 Docker 中镜像层和容器可写层是基于联合文件系统UnionFS实现的关键概念。它们共同构成了容器的文件系统结构使得 Docker 能够高效地管理和运行容器。以下是对镜像层和容器可写层的详细解释:
##### 2.2.1 一、镜像层
镜像层是 Docker 镜像的组成部分,每个镜像由多个只读层组成,这些层是不可修改的。
1. **镜像层的生成**
- 当你构建一个 Docker 镜像时Dockerfile 中的每一条指令(如 `RUN``COPY``ADD` 等)都会生成一个新的镜像层。
- 例如,一个简单的 Dockerfile 如下:
```dockerfile
FROM ubuntu:20.04
RUN apt-get update && apt-get install -y nginx
COPY ./my_nginx.conf /etc/nginx/nginx.conf
```
- 第一层是基础镜像层,如 `ubuntu:20.04`,这是从 Docker Hub 拉取的预构建镜像。
- 第二层是通过 `RUN` 指令安装 Nginx 生成的层,包含了安装过程中产生的所有文件和目录变化。
- 第三层是通过 `COPY` 指令将本地的 `my_nginx.conf` 文件复制到镜像中的 `/etc/nginx/nginx.conf` 位置生成的层。
- 每一层都是基于前一层构建的,新的层只包含与前一层的差异部分。
2. **镜像层的特点**
- **只读性**:镜像层是只读的,一旦创建就不能修改。如果需要修改镜像层中的内容,必须通过构建新的镜像层来实现。
- **共享性**:多个容器可以共享同一个镜像层,因为镜像层是不可变的,这大大节省了磁盘空间。
- **不可变性**:镜像层的不可变性保证了镜像的一致性和可重复性,无论在什么环境下运行,基于同一镜像启动的容器都具有相同的文件系统结构。
3. **镜像层的作用**
- **构建高效**通过分层构建Docker 可以缓存中间层,避免重复构建相同的操作。例如,如果基础镜像层和安装 Nginx 的层已经构建过,再次构建时可以直接使用缓存的层,而不是重新执行命令。
- **节省空间**多个容器可以共享镜像层减少了磁盘空间的占用。例如10 个基于同一个基础镜像的容器,只需要存储一份基础镜像层,而不是每份都单独存储。
- **便于分发**:镜像层的结构使得镜像可以方便地分发和共享。用户可以从 Docker Hub 等镜像仓库拉取镜像,而无需关心镜像的具体构建过程。
##### 2.2.2 二、容器可写层
容器可写层是容器运行时特有的一个层,它是可写的,用于存储容器运行时产生的所有变更。
1. **容器可写层的生成**
- 当你启动一个容器时Docker 会在镜像的最顶层添加一个新的可写层。这个可写层是容器独有的,用于存储容器运行时的文件系统变更。
- 例如,如果你在容器中创建了一个新文件、修改了一个现有文件或删除了一个文件,这些操作都会反映在容器可写层中,而不会影响到镜像层。
2. **容器可写层的特点**
- **可写性**:容器可写层是可写的,容器运行时的所有文件系统操作(如创建、修改、删除文件)都在这个层中进行。
- **独立性**:每个容器都有自己的可写层,容器之间的可写层是隔离的。一个容器的变更不会影响到其他容器。
- **临时性**:容器可写层的内容在容器被删除时也会被删除。如果需要持久化数据,需要将数据存储在外部存储(如卷)中。
3. **容器可写层的作用**
- **隔离性**:容器可写层保证了容器之间的隔离性。每个容器在自己的可写层中进行操作,不会影响到其他容器或镜像层。
- **灵活性**:容器可写层允许容器在运行时动态地修改文件系统,而不会影响到镜像的原始状态。这使得容器可以灵活地运行各种应用程序。
- **数据持久化**虽然容器可写层的内容在容器删除时会被删除但你可以通过挂载卷Volumes将数据持久化到宿主机或其他存储设备中从而实现数据的持久化存储。
##### 2.2.3 三、镜像层与容器可写层的关系
镜像层和容器可写层通过联合文件系统UnionFS联合起来形成了容器的完整文件系统视图。
1. **联合挂载**
- Docker 使用联合文件系统将镜像层和容器可写层联合挂载到同一个目录下。从容器的角度来看,它看到的是一个完整的文件系统,包含了镜像层和容器可写层的内容。
- 例如当你在容器中访问一个文件时Docker 会先在容器可写层中查找该文件。如果找不到,就会在镜像层中查找。如果在镜像层中找到了文件,就会将该文件的内容返回给容器。
2. **写时复制Copy-on-Write**
- 当容器需要修改一个文件时Docker 会使用写时复制机制。具体来说Docker 会将文件从镜像层复制到容器可写层,然后在可写层中进行修改。这样,镜像层保持不变,而容器可写层存储了修改后的文件。
- 例如,假设镜像层中有一个文件 `/etc/nginx/nginx.conf`容器需要修改这个文件。Docker 会将该文件从镜像层复制到容器可写层,然后在可写层中进行修改。从容器的角度来看,它看到的是修改后的文件,而镜像层中的文件保持不变。
3. **删除操作**
- 当容器删除一个文件时Docker 会在容器可写层中记录一个删除操作,而不是真正删除镜像层中的文件。这样,镜像层保持不变,而容器可写层记录了文件的删除状态。
- 例如,假设容器删除了一个文件 `/etc/nginx/nginx.conf`Docker 会在容器可写层中记录一个删除标记。从容器的角度来看,该文件已经被删除,而镜像层中的文件仍然存在。
##### 2.2.4 总结
- **镜像层**:是 Docker 镜像的组成部分,是只读的、不可变的,多个容器可以共享镜像层。镜像层通过分层构建,提高了构建效率、节省了磁盘空间,并保证了镜像的一致性和可重复性。
- **容器可写层**:是容器运行时的可写层,用于存储容器运行时的文件系统变更。容器可写层是独立的、可写的、临时的,保证了容器之间的隔离性和运行时的灵活性。
- **联合文件系统UnionFS**将镜像层和容器可写层联合挂载形成了容器的完整文件系统视图。通过写时复制机制Docker 在不影响镜像层的情况下,允许容器在可写层中进行文件系统操作。
#### 2.3 查看镜像的详细信息
##### 2.3.1 一、查看镜像数据信息
```bash
[root@localhost nginx]# docker inspect nginx_games:v1
"Architecture": "amd64",
"Os": "linux",
"Size": 685997316,
"GraphDriver": {
"Data": {
"LowerDir": "/var/lib/docker/overlay2/ilm8ifbi2gcrqg156w7kbu22f/diff:/var/lib/docker/overlay2/u51fr5eul9csiwghxmnm1acsi/diff:/var/lib/docker/overlay2/lo6sgoxbliga9l2qqqxcu2tvp/diff:/var/lib/docker/overlay2/bi4orr0yujicfufabnw7u8tym/diff:/var/lib/docker/overlay2/e51d5c1c74a99e1b1e41980bb9270fcba562976e40ae7dbf65ff585689a783d2/diff",
"MergedDir": "/var/lib/docker/overlay2/talgtlohecyw3kt8d8idpzw4g/merged",
"UpperDir": "/var/lib/docker/overlay2/talgtlohecyw3kt8d8idpzw4g/diff",
"WorkDir": "/var/lib/docker/overlay2/talgtlohecyw3kt8d8idpzw4g/work"
LoweDirimage镜像层本身只读
UpperDir容器的上层读写层
MergeDir容器的文件系统使用Union FS(联合文件系统)将镜像层和容器层合并给容器使用
WorkDir容器在宿主机的工作目录
```
##### 2.3.2 二、查看镜像层构建过程
```bash
[root@localhost nginx]# docker history nginx_games:v1
IMAGE CREATED CREATED BY SIZE COMMENT
9c86d96dfba0 25 hours ago CMD ["nginx" "-g" "daemon off;"] 0B buildkit.dockerfile.v0
<missing> 25 hours ago EXPOSE map[443/tcp:{} 80/tcp:{}] 0B buildkit.dockerfile.v0
<missing> 25 hours ago ADD games.tar.gz /usr/local/nginx/html/ # bu… 164MB buildkit.dockerfile.v0
<missing> 25 hours ago RUN /bin/sh -c useradd -s /sbin/nologin ngin… 297kB buildkit.dockerfile.v0
<missing> 25 hours ago RUN /bin/sh -c cd /usr/local/src/nginx-1.22.… 16.6MB buildkit.dockerfile.v0
<missing> 25 hours ago ADD nginx-1.22.0.tar.gz /usr/local/src/ # bu… 6.46MB buildkit.dockerfile.v0
<missing> 25 hours ago RUN /bin/sh -c yum install -y vim wget unzip… 323MB buildkit.dockerfile.v0
<missing> 25 hours ago MAINTAINER Eagle_nls 2898485992@qq.com 0B buildkit.dockerfile.v0
<missing> 16 months ago CMD ["/bin/bash"] 0B buildkit.dockerfile.v0
<missing> 16 months ago ADD layer.tar.xz / # buildkit 176MB buildkit.dockerfile.v0
```
如果想要缩小所构建镜像的大小,我们可以尝试少创建镜像层,在一层中多做一些事情,尽可能减少**RUN命令**
### 3. 数据卷
#### 3.1 什么是数据卷?
数据卷实际上就是宿主机上的目录或者是文件可以被直接mount到容器当中使用。
实际生产环境中,需要针对不同类型的服务、不同类型的数据存储要求做相应的规划,最终保证服务的可扩展性、稳定性以及数据的安全性。
![img](05.Docker数据管理/u=1718952600,4159508250&fm=26&fmt=auto&gp=0.jpg)
#### 3.2 数据卷案例
- 创建目录并准备页面
```bash
[root@docker-server1 ~]# mkdir -p /data/web
[root@docker-server1 ~]# echo 'eaglslab nginx test!' > /data/web/index.html
[root@docker-server1 ~]# cat /data/web/index.html
eaglslab nginx test
```
- 启动两个容器并验证数据
```bash
[root@docker-server1 ~]# docker run -d -it --name web1 -v /data/web/:/usr/share/nginx/html/ -p 8080:80 nginx
588c494dc9098e0a43e15bce3162c34676dd981609edc32d46bf4beb59b9cf19
[root@docker-server1 ~]# docker run -d -it --name web2 -v /data/web/:/usr/share/nginx/html/ -p 8081:80 nginx
ff6b3731a9ba3e0f91d2c8d89bb6573eb5e5a9b840163bc1122a9e5678d108b7
[root@docker-server1 ~]# curl 192.168.175.10:8080
eaglslab nginx test!
[root@docker-server1 ~]# curl 192.168.175.10:8081
eaglslab nginx test!
[root@docker-server1 ~]# echo 'hello world!' > /data/web/index.html
[root@docker-server1 ~]# curl 192.168.175.10:8080
hello world!
[root@docker-server1 ~]# curl 192.168.175.10:8081
hello world!
```
- 进入到容器内测试写入数据
```bash
[root@docker-server1 ~]# docker exec -it web1 bash
root@588c494dc909:/# echo 'docker test!' > /usr/share/nginx/html/index.html
[root@docker-server1 ~]# curl 192.168.175.10:8080
docker test!
[root@docker-server1 ~]# curl 192.168.175.10:8081
docker test!
```
- 尝试只读挂载
```bash
# 删除容器的时候不会删除宿主机的目录
[root@docker-server1 ~]# docker rm -fv web1
web1
[root@docker-server1 ~]# docker rm -fv web2
web2
[root@docker-server1 ~]# cat /data/web/index.html
docker test!
# 通过只读方式挂载以后,在容器内部是不允许修改数据的
[root@docker-server1 ~]# docker run -d -it --name web1 -v /data/web/:/usr/share/nginx/html/:ro -p 8080:80 nginx
a395b27958ca0cdcf52a86bd17813dcbcda4ed774895adcc99e85fc114ab84ff
[root@docker-server1 ~]# docker exec -it web1 bash
root@a395b27958ca:/# echo 123 > /usr/share/nginx/html/index.html
bash: /usr/share/nginx/html/index.html: Read-only file system
```
- 文件挂载
```bash
[root@docker-server1 ~]# docker run -d -it --name web2 -v /data/web/index.html:/usr/share/nginx/html/index.html:ro -p 8081:80 nginx
4b34c957372d314cdb0f85d7e2c65b095615adfe3051ae6b4266b7bacd50f374
[root@docker-server1 ~]# curl 192.168.175.10:8081
docker test!
```
#### 3.3 数据卷特点
1. 数据卷是宿主机的目录或者文件,并且可以在**多个容器之间共同使用**
2. 在宿主机对数据卷更改数据后会在所有容器里面会**立即更新**
3. 数据卷的数据可以**持久保存**,即使删除使用该数据卷卷的容器也不影响
4. 在容器里面写入数据不会影响到镜像本身(**隔离性**)。
5. 需要挂载多个目录或者文件的时候可以使用多个-v参数指定
6. 数据卷使用场景包括日志输出、静态web页面、应用配置文件、多容器间目录或文件共享
#### 3.4 数据卷容器
##### 3.4.1 什么是数据卷容器
数据卷容器是一个普通的容器,专门用于提供数据卷供其他容器挂载。它允许用户创建一个专门用于数据存储的容器,并将其数据卷挂载到其他容器中。数据卷容器的主要用途是将数据卷的生命周期与应用容器分离,使数据可以在容器之间共享和持久化。
##### 3.4.2 数据卷容器的用途
1. **数据持久化**:数据卷容器可以确保数据即使在容器被删除后也不会丢失。例如,对于数据库应用,数据卷容器可以持久化数据库文件,避免因容器删除而导致数据丢失。
2. **数据共享**:多个容器可以通过挂载同一个数据卷容器来共享数据。这在多容器应用中非常有用,例如在微服务架构中,多个服务容器可以共享数据库数据。
3. **备份与恢复**:数据卷容器可以用于备份和恢复数据。通过将数据卷容器中的数据卷备份到宿主机或其他存储设备,可以在需要时恢复数据。
4. **迁移数据**:数据卷容器可以方便地迁移数据。通过将数据卷容器中的数据卷迁移到其他主机,可以快速实现数据的迁移。
##### 3.4.3 数据卷容器与本地数据挂载的区别
| 特性 | 数据卷容器 | 本地数据挂载 |
| :--------------------- | :----------------------------------------------------------- | :----------------------------------------------------------- |
| **目录来源** | Docker 自动创建的目录 | 宿主机上已存在的目录 |
| **适用场景** | 数据持久化、容器间共享数据 | 开发调试、快速文件同步 |
| **容器间共享** | 支持 | 不支持 |
| **宿主机文件系统依赖** | 无依赖 | 依赖宿主机文件系统 |
| **数据持久化** | 数据卷的生命周期独立于容器,即使容器被删除,数据卷仍然存在 | 如果容器被删除,挂载的目录和文件仍然存在,但需要手动管理 |
| **数据初始化** | 如果宿主机没有对应的文件,数据卷容器会自动将容器运行所需的文件复制到数据卷中 | 如果宿主机没有对应的文件,容器可能会因缺少运行所需的文件而出错 |
| **数据覆盖** | 数据卷中的数据会覆盖容器内的数据 | 容器内的数据会覆盖宿主机上的数据 |
##### 3.4.4 实例演示
- 先启动一个卷容器Server
```bash
[root@docker-server1 ~]# docker run -d --name nginx-web -v /data/web/:/usr/share/nginx/html/:ro -p 8081:80 nginx
```
- 启动两个客户端容器
```bash
[root@docker-server1 ~]# docker run -d --name web1 -p 8082:80 --volumes-from nginx-web nginx:latest
ac22faa405ec07c065042465cd7f9d456be891effdd5d13d9571b96ef9c550f7
[root@docker-server1 ~]# docker run -d --name web2 -p 8083:80 --volumes-from nginx-web nginx:latest
e084845475b01dedfdae7362f6fbece7b5ab57ff6289c8c9bf08251f5ba448ed
```
- 访问测试
```bash
[root@docker-server1 ~]# curl 192.168.175.10:8081
docker test!
[root@docker-server1 ~]# curl 192.168.175.10:8082
docker test!
[root@docker-server1 ~]# curl 192.168.175.10:8083
docker test!
```
- 停止卷容器可以创建新容器
```bash
[root@docker-server1 ~]# docker stop nginx-web
nginx-web
[root@docker-server1 ~]# docker run -d -it --name web3 -p 8084:80 --volumes-from nginx-web nginx:latest
6ebd95c132ee1a9e4b43d1849efc628ca7185187a59d70b3816ff16dd47b6e8e
[root@docker-server1 ~]# curl 192.168.175.10:8084
docker test!
```
- 删除卷容器之后不可以再创建新容器
```bash
[root@docker-server1 ~]# docker rm -fv nginx-web
nginx-web
[root@docker-server1 ~]# docker run -d -it --name web4 -p 8085:80 --volumes-from nginx-web nginx:latest
docker: Error response from daemon: No such container: nginx-web.
See 'docker run --help'.
# 但是之前已经创建好的容器不会有任何影响
[root@docker-server1 ~]# curl 192.168.175.10:8082
docker test!
```
##### 3.4.5 总结
在当前环境下即使把提供卷的容器Server删除已经运行的容器Client依然可以使用挂载的卷因为容器是通过挂载的方式访问数据的但是无法创建新的卷容器客户端但是再把卷容器Server创建后即可正常创建卷容器client此方式可以用于线上共享数据目录等环境因为即使数据卷容器被删除了其他已经运行的容器依然可以挂载使用
数据卷容器可以作为共享的方式为其他容器提供文件共享,可以在容器生成中启动一个实例挂载本地的目录,然后其他的容器分别挂载此容器的目录,即可保证各个容器之间的数据一致性。

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View File

@@ -0,0 +1,363 @@
# 06.Docker网络管理
## 06.Docker网络管理
### 1. 容器之间的互联
在同一个宿主机上的容器之间可以通过端口映射的方式经过宿主机中转进行互相访问也可以通过docker0网桥互相访问
#### 1.1 直接互联
- 启动两个容器
```bash
[root@localhost ~]# docker run -d -it nginx
[root@localhost ~]# docker run -d -it nginx
```
- 安装相关工具包
```bash
root@855ab8d0bd74:/# apt update
root@855ab8d0bd74:/# apt install net-tools -y
root@855ab8d0bd74:/# apt install iputils-ping -y
root@855ab8d0bd74:/# apt install procps -y
```
- 检测网络连通性
```bash
root@855ab8d0bd74:/# ping 172.17.0.3 -c 2
PING 172.17.0.3 (172.17.0.3) 56(84) bytes of data.
64 bytes from 172.17.0.3: icmp_seq=1 ttl=64 time=0.052 ms
64 bytes from 172.17.0.3: icmp_seq=2 ttl=64 time=0.081 ms
--- 172.17.0.3 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1ms
rtt min/avg/max/mdev = 0.052/0.066/0.081/0.016 ms
```
#### 1.2 使用名称互联
- 启动两个容器
```bash
[root@localhost ~]# docker run -d -it --name web1 nginx:1.8
[root@localhost ~]# docker run -d -it --name web2 --link web1 nginx:1.8
```
- 查看web2容器的hosts文件发现已经实现名称解析
```bash
[root@localhost ~]# docker exec -it web2 bash
root@8a3e9cee9e37:/# cat /etc/hosts
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.2 web1 622eff54876f
172.17.0.3 8a3e9cee9e37
```
- 连通性测试
```bash
root@8a3e9cee9e37:/# ping web1 -c 2
PING web1 (172.17.0.2) 56(84) bytes of data.
64 bytes from web1 (172.17.0.2): icmp_seq=1 ttl=64 time=0.068 ms
64 bytes from web1 (172.17.0.2): icmp_seq=2 ttl=64 time=0.045 ms
--- web1 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1ms
rtt min/avg/max/mdev = 0.045/0.056/0.068/0.013 ms
```
#### 1.3 使用别名互联
自定义的容器名称可能后期会发生变化,那么一旦发生变化也会带来一些影响,这个时候如果每次都更改名称又比较麻烦,这个时候可以使用定义别名的方式解决,即容器名称可以随意更改,只要不更改别名即可。
- 启动一个容器
```bash
[root@localhost ~]# docker run -d -it --name web3 --link web1:nginx-web1 nginx:1.8
```
- 查看容器web3的hosts文件
```bash
[root@localhost ~]# docker exec -it web3 bash
root@c85c73ebf00b:/# cat /etc/hosts
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.2 nginx-web1 622eff54876f web1
172.17.0.4 c85c73ebf00b
```
- 连通性测试
```bash
root@c85c73ebf00b:/# ping nginx-web1 -c2
PING nginx-web1 (172.17.0.2) 56(84) bytes of data.
64 bytes from nginx-web1 (172.17.0.2): icmp_seq=1 ttl=64 time=0.112 ms
64 bytes from nginx-web1 (172.17.0.2): icmp_seq=2 ttl=64 time=0.055 ms
--- nginx-web1 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 2ms
rtt min/avg/max/mdev = 0.055/0.083/0.112/0.029 ms
```
### 2. Docker网络
#### 2.1 四类网络模式
| Docker网络模式 | 配置 | 说明 |
| -------------- | ------------------------- | ------------------------------------------------------------ |
| host模式 | net=host | 容器和宿主机共享Network namespace。 |
| container模式 | net=container:NAME_or_ID | 容器和另外一个容器共享Network namespace。 kubernetes中的pod就是多个容器共享一个Network namespace。 |
| none模式 | net=none | 容器有独立的Network namespace但并没有对其进行任何网络设置如分配veth pair 和网桥连接配置IP等。 |
| bridge模式 | net=bridge | (默认为该模式) |
Docker服务安装完成之后默认在每个宿主机会生成一个名称为docker0的网卡其ip地址都是172.17.0.1/16并且会生成三种不同类型的网络
```bash
[root@localhost ~]# ifconfig
docker0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
inet 172.17.0.1 netmask 255.255.0.0 broadcast 172.17.255.255
ether 02:42:14:75:bf:4c txqueuelen 0 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.80.10 netmask 255.255.255.0 broadcast 192.168.80.255
inet6 fe80::eaf3:dc40:2bf:6da2 prefixlen 64 scopeid 0x20<link>
ether 00:0c:29:f4:79:06 txqueuelen 1000 (Ethernet)
RX packets 13079 bytes 18637594 (17.7 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 1747 bytes 124995 (122.0 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1 (Local Loopback)
RX packets 72 bytes 5776 (5.6 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 72 bytes 5776 (5.6 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
[root@localhost ~]# docker network list
NETWORK ID NAME DRIVER SCOPE
787342a0d883 bridge bridge local
9a6d7244e807 host host local
beace8354cca none null local
```
在启动容器的时候可以使用--network参数去指定网络类型默认使用的是bridge网络类型
#### 2.2 none网络类型
在使用none模式后docker容器**不会进行任何网络配置**其没有网卡、没有ip也没有路由因此默认无法与外界进行通信需要手动添加网卡配置ip等所以**极少使用**
![img](06.Docker网络管理/13618762-3fd41778faebcef5.png)
```bash
[root@localhost ~]# docker run -d -it --name web4 --network none nginx:1.8
```
#### 2.3 container网络类型
这个模式指定新创建的容器和**已经存在的一个容器共享**一个 Network Namespace而不是和宿主机共享。新创建的容器不会创建自己的网卡配置自己的 IP而是和一个指定的容器共享 IP、端口范围等。同样两个容器除了网络方面其他的如文件系统、进程列表等还是隔离的。两个容器的进程可以通过 lo 网卡(环回接口)设备通信。
![img](06.Docker网络管理/13618762-790a69a562a5b358.png)
```bash
[root@localhost ~]# docker run -d -it --name web5 --network container:web1 nginx
83db4f9af6f3d9d42bbd57691fcf82ef06cbf1a5874750effa314a4ec242aaaa
```
#### 2.4 host网络类型
如果启动容器的时候使用host模式那么这个容器将不会获得一个独立的Network Namespace而是和宿主机共用一个Network Namespace。容器将不会虚拟出自己的网卡配置自己的IP等而是**使用宿主机的IP和端口。**
使用host模式的容器可以直接使用宿主机的IP地址与外界通信**,容器内部的服务端口也可以使用宿主机的端口**不需要进行NAThost最大的优势就是**网络性能比较好**但是docker host上已经使用的端口就不能再用了**网络的隔离性不好。**
![img](06.Docker网络管理/13618762-a892da42b8ff9342.png)
```bash
[root@localhost ~]# docker run -d -it --name web7 --network host nginx
e90cb3bfc1a3fbd187319ac3b995b116feb37422534b03662d624680e35eb2bb
[root@localhost ~]# docker exec -it web7 bash
root@localhost:/# ifconfig
docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.17.0.1 netmask 255.255.0.0 broadcast 172.17.255.255
inet6 fe80::42:14ff:fe75:bf4c prefixlen 64 scopeid 0x20<link>
ether 02:42:14:75:bf:4c txqueuelen 0 (Ethernet)
RX packets 9647 bytes 394222 (384.9 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 10932 bytes 43303360 (41.2 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.175.10 netmask 255.255.255.0 broadcast 192.168.175.255
inet6 fe80::eaf3:dc40:2bf:6da2 prefixlen 64 scopeid 0x20<link>
ether 00:0c:29:f4:79:06 txqueuelen 1000 (Ethernet)
RX packets 60855 bytes 81177548 (77.4 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 17770 bytes 1472014 (1.4 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1 (Local Loopback)
RX packets 72 bytes 5776 (5.6 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 72 bytes 5776 (5.6 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
```
#### 2.5 bridge网络类型(默认)
当Docker进程启动时会在主机上创建一个名为**docker0的虚拟网桥**此主机上启动的Docker容器会连接到这个虚拟网桥上。虚拟网桥的工作方式和物理交换机类似这样主机上的所有容器就通过交换机连在了一个二层网络中。
从docker0子网中分配一个IP给容器使用并设置docker0的IP地址为容器的默认网关。在主机上创建一对虚拟网卡veth pair设备Docker将veth pair设备的一端放在新创建的容器中并命名为eth0容器的网卡另一端放在主机中以vethxxx这样类似的名字命名并将这个网络设备加入到docker0网桥中。可以通过brctl show命令查看。
bridge模式是docker的**默认网络模式**,不写--network参数就是bridge模式。**使用docker run -p时docker实际是在iptables做了DNAT规则实现端口转发功能。可以使用iptables -t nat -vnL查看。**
![img](06.Docker网络管理/13618762-f1643a51d313a889.png)
### 3. 创建自定义网络
可以基于docker命令创建自定义网络自定义网络可以自定义ip地址范围和网关等信息。
- 创建一个网络
```bash
[root@localhost ~]# docker network create -d bridge --subnet 10.10.0.0/16 --gateway 10.10.0.1 eagleslab-net
74ee6ecdfc0382ac0abb1b46a3c90e3c6a39f0b7388aa9ba99fddc6bac72e8ce
[root@localhost ~]# docker network list
NETWORK ID NAME DRIVER SCOPE
787342a0d883 bridge bridge local
74ee6ecdfc03 eagleslab-net bridge local
9a6d7244e807 host host local
beace8354cca none null local
```
- 使用自定义网络创建容器
```bash
[root@localhost ~]# docker run -d -it --name web8 --network eagleslab-net nginx
```
- 检查网络
```bash
[root@localhost ~]# docker exec -it web8 bash
root@a7edddb4114e:/# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 10.10.0.2 netmask 255.255.0.0 broadcast 10.10.255.255
ether 02:42:0a:0a:00:02 txqueuelen 0 (Ethernet)
RX packets 1064 bytes 8764484 (8.3 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 738 bytes 41361 (40.3 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
root@a7edddb4114e:/# ping www.baidu.com -c2
PING www.a.shifen.com (112.34.112.83) 56(84) bytes of data.
64 bytes from 112.34.112.83 (112.34.112.83): icmp_seq=1 ttl=127 time=37.8 ms
64 bytes from 112.34.112.83 (112.34.112.83): icmp_seq=2 ttl=127 time=36.9 ms
--- www.a.shifen.com ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 3ms
rtt min/avg/max/mdev = 36.865/37.320/37.776/0.494 ms
```
- iptables会生成nat的相应规则
```bash
[root@localhost ~]# iptables -t nat -vnL
Chain PREROUTING (policy ACCEPT 12 packets, 759 bytes)
pkts bytes target prot opt in out source destination
2 136 DOCKER all -- * * 0.0.0.0/0 0.0.0.0/0 ADDRTYPE match dst-type LOCAL
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 1 packets, 76 bytes)
pkts bytes target prot opt in out source destination
0 0 DOCKER all -- * * 0.0.0.0/0 !127.0.0.0/8 ADDRTYPE match dst-type LOCAL
Chain POSTROUTING (policy ACCEPT 1 packets, 76 bytes)
pkts bytes target prot opt in out source destination
12 759 MASQUERADE all -- * !br-74ee6ecdfc03 10.10.0.0/16 0.0.0.0/0
32 1940 MASQUERADE all -- * !docker0 172.17.0.0/16 0.0.0.0/0
Chain DOCKER (2 references)
pkts bytes target prot opt in out source destination
0 0 RETURN all -- br-74ee6ecdfc03 * 0.0.0.0/0 0.0.0.0/0
1 84 RETURN all -- docker0 * 0.0.0.0/0 0.0.0.0/0
```
### 4. Docker一键搭建typecho博客
镜像选择:**80x86/typecho:latest**
一、部署容器
```bash
[root@localhost ~]# docker run -d \
--name=typecho \
--restart always \
-e PHP_TZ=Asia/Shanghai \
-e PHP_MAX_EXECUTION_TIME=600 \
-p 80:80 80x86/typecho:latest
[root@localhost ~]# ss -nlt
State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
LISTEN 0 4096 0.0.0.0:80 0.0.0.0:*
LISTEN 0 128 0.0.0.0:22 0.0.0.0:*
LISTEN 0 4096 [::]:80 [::]:*
LISTEN 0 128 [::]:22 [::]:*
```
二、浏览器访问初始化博客
![image-20250326222721074](06.Docker网络管理/image-20250326222721074.png)
三、完善信息数据库选择内置的SQL Lite方便一点
![image-20250326222739407](06.Docker网络管理/image-20250326222739407.png)
四、安装完成
![image-20250326222830605](06.Docker网络管理/image-20250326222830605.png)
五、更改主题,默认带了几个主题
![image-20250326222916277](06.Docker网络管理/image-20250326222916277-1750402570103-1070.png)

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

View File

@@ -0,0 +1,332 @@
# 07.Docker资源限制
## 07.Docker资源限制
### 1. Docker 容器资源限制与 OOM 异常处理
#### 1.1 容器资源限制
默认情况下容器没有资源限制可以使用主机内核调度程序允许的尽可能多的给定资源。Docker 提供了控制容器可以使用多少内存或者 CPU 的方法,通过设置 `docker run` 命令的运行时配置标志来实现。
其中一些功能要求宿主机的内核支持 Linux 功能。要检查支持情况,可以使用 `docker info` 命令。如果内核中禁用了某项功能,可能会在输出结尾处看到警告。
#### 1.2 OOM 异常
对于 Linux 主机,如果没有足够的内存来执行其他重要的系统任务,将会抛出 OOM 异常(内存溢出、内存泄漏、内存异常)。随后系统会开始杀死进程以释放内存,凡是运行在宿主机上的进程都有可能被 kill包括 `dockerd` 和其他的应用程序。如果重要的系统进程被 kill会导致和该进程相关的服务全部宕机。
产生 OOM 异常时,`dockerd` 会尝试通过调整 Docker 守护程序上的 OOM 优先级来减轻这些风险,以便它比系统上的其他进程更不可能被杀死。但是,容器的 OOM 优先级未调整时,单个容器被杀死的可能性更大(不推荐调整容器的优先级这种方式)。
#### 1.3 Linux 进程 OOM 评分机制
Linux 会为每个进程计算一个分数,最终它会将分数最高的进程 kill 掉。相关文件说明如下:
- `/proc/PID/oom_score_adj`
- 范围为 -1000 到 1000。
- 值越高越容易被宿主机 kill 掉。
- 如果将该值设置为 -1000则进程永远不会被宿主机 kernel kill。
- `/proc/PID/oom_adj`
- 范围为 -17 到 +15。
- 取值越高越容易被干掉。
- 如果是 -17则表示不能被 kill。
- 该设置参数的存在是为了和旧版本的 Linux 内核兼容。
- `/proc/PID/oom_score`
- 这个值是系统综合进程的内存消耗量、CPU 时间(`utime + stime`)、存活时间(`uptime - start time`)和 `oom_adj` 计算出的进程得分。
- 消耗内存越多得分越高,越容易被宿主机 kernel 强制杀死。
### 2. 容器的内存限制
Docker可以强制执行**硬性内存限制**,即只允许容器使用给定的内存大小
Docker也可以执行**非硬性内存限制**,即容器可以使用尽可能多的内存,除非内核检测到主机上的内存不够用了
#### 2.1 内存限制参数
##### 2.1.1 `-m` 或 `--memory`
- **功能**:限制容器最大可用内存。
- **最小值**4m。
- **示例**
```bash
docker run -m 512m my_image
```
##### 2.1.2 `--memory-swap`
- **功能**:限制容器可用的内存 + swap 总量。
- **前提**:需先设置 `--memory`。
- **特殊值**`-1` 表示不限制 swap 使用。
- **示例**
```bash
docker run --memory 256m --memory-swap 512m my_image
```
##### 2.1.3 `--memory-swappiness`
- **功能**:控制容器使用 swap 的倾向性。
- **范围**0尽量不使用 swap到 100尽量使用 swap
- **示例**
```bash
docker run --memory-swappiness 30 my_image
```
##### 2.1.4 `--kernel-memory`
- **功能**:限制容器使用的内核内存。
- **最小值**4m。
- **注意事项**:不推荐设置,可能影响宿主机和其他容器。
- **示例**
```bash
docker run --kernel-memory 64m my_image
```
##### 2.1.5 `--memory-reservation`
- **功能**:设置软内存限制,低于 `--memory`。
- **激活条件**:主机内存争用或不足时生效。
- **注意事项**:必须小于 `--memory`,且不保证容器一定不超过此限制。
- **示例**
```bash
docker run --memory 1g --memory-reservation 512m my_image
```
##### 2.1.6 `--oom-kill-disable`
- **功能**:禁止 OOM 时杀死容器内进程。
- **前提**:必须与 `--memory` 一起使用。
- **注意事项**:若未设置 `--memory`OOM 时仍可能杀死进程。
- **示例**
```bash
docker run --memory 512m --oom-kill-disable my_image
```
#### 2.2 内从限制案例
如果一个容器未作内存使用限制,则该容器可以利用到系统内存最大空间,默认创建的容器没有做内存资源限制
一、拉取容器压测工具镜像
```bash
[root@localhost ~]# docker pull tylersmith22/docker-stress-ng
[root@localhost ~]# docker run -it --rm tylersmith22/docker-stress-ng -help
```
二、使用压测工具开启两个工作进程每个工作进程最大允许使用内存256M且宿主机不限制当前容器的最大内存
```bash
[root@localhost nginx]# docker run -it --rm --name test1 tylersmith22/docker-stress-ng --vm 2 --vm-bytes 256m
stress-ng: info: [1] defaulting to a 86400 second run per stressor
stress-ng: info: [1] dispatching hogs: 2 vm
# 新建窗口查看
[root@localhost ~]# docker stats
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
3ca32774fc20 test1 185.16% 514.3MiB / 1.781GiB 28.21% 648B / 0B 0B / 0B 5
# 可以看到容器的内存占用大概为256的两倍因为两个进程
```
三、宿主机限制最大内存使用
```bash
[root@localhost nginx]# docker run -it --rm -m 256m --name test2 tylersmith22/docker-stress-ng --vm 2 --vm-bytes 256m
stress-ng: info: [1] defaulting to a 86400 second run per stressor
stress-ng: info: [1] dispatching hogs: 2 vm
# 新建窗口查看
[root@localhost ~]# docker stats
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
d612ce9b0776 test2 0.00% 255.9MiB / 256MiB 99.97% 1.02kB / 126B 4.83GB / 36.8GB 5
```
#### 2.3 **内存软限制**
软限制不会真正限制到内存的使用
```bash
[root@localhost ~]# docker run -it --rm -m 256m --memory-reservation 128m --name test1 tylersmith22/docker-stress-ng --vm 2 --vm-bytes 256m
[root@localhost ~]# docker stats
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
0ffb4b8fdbde test1 174.52% 255.9MiB / 256MiB 99.95% 648B / 0B 5.33GB / 18.1GB 5
```
**交换分区限制**
```bash
[root@localhost ~]# docker run -it --rm -m 256m --memory-swap 512m --name test1 tylersmith22/docker-stress-ng --vm 2 --vm-bytes 256m
```
### 3. 容器的CPU限制
一个宿主机有几十个核心的cpu但是宿主机上可以同时运行成百上千个不同的进程用以处理不同的任务多进程共用一个cpu的核心依赖计数就是为可压缩资源即一个核心cpu可以通过调度而运行多个进程但是在同一个单位时间内只能由一个进程在cpu上运行那么这么多的进程怎么在cpu上执行和调度的呢进程优先级
默认情况下每个容器对主机cpu周期的访问权限是不受限制的但是我们可以人为干扰
#### 3.1 CPU限制参数
##### 3.1.1 `--cpus`
- **功能**:指定容器可以使用的 CPU 资源数量。
- **示例**:主机有 2 个 CPU设置 `--cpus=1.5`,容器最多可使用 1.5 个 CPU。
- **示例命令**
```bash
docker run --cpus 1.5 my_image
```
##### 3.1.2 `--cpu-period` 和 `--cpu-quota`
- **功能**:设置 CPU 调度周期和配额。
- **关系**:必须一起使用,计算方式为 `cpu-quota / cpu-period`。
- **示例**
```bash
docker run --cpu-period 100000 --cpu-quota 50000 my_image
```
##### 3.1.3 `--cpuset-cpus`
- **功能**:指定容器运行的 CPU 编号(绑核)。
- **示例**:限制容器在 CPU 0 和 CPU 1 上运行。
- **示例命令**
```bash
docker run --cpuset-cpus 0,1 my_image
```
##### 3.1.4 `--cpuset-mems`
- **功能**:设置容器使用的内存节点(仅对 NUMA 架构有效)。
- **示例**:限制容器使用内存节点 0。
- **示例命令**
```bash
docker run --cpuset-mems 0 my_image
```
##### 3.1.5 `--cpu-shares`
- **功能**:设置容器的 CPU 时间片权重。
- **默认值**1024。
- **范围**:最小 2最大 262144。
- **示例**:容器 A 设置为 1024容器 B 设置为 2048容器 B 的 CPU 时间片是容器 A 的两倍。
- **示例命令**
```bash
docker run --cpu-shares 2048 my_image
```
#### 3.2 CPU限制案例
##### 3.2.1 **未限制容器cpu**
- 启动1个进程占用4核cpu未限制容器会把cpu全部占完
```bash
# 查看我们宿主机的cup数量
[root@localhost ~]# top
top - 21:32:49 up 43 min, 2 users, load average: 3.54, 1.82, 0.80
Tasks: 186 total, 1 running, 185 sleeping, 0 stopped, 0 zombie
%Cpu0 : 0.0 us, 0.0 sy, 0.0 ni, 99.5 id, 0.0 wa, 0.5 hi, 0.0 si, 0.0 st
%Cpu1 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu2 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu3 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
[root@localhost ~]# docker run -it --rm --name test1 tylersmith22/docker-stress-ng --vm 1 --cpu 4
stress-ng: info: [1] defaulting to a 86400 second run per stressor
stress-ng: info: [1] dispatching hogs: 4 cpu, 1 vm
# 新建窗口查看
[root@localhost ~]# docker stats
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
c6a795e4c09f test1 396.78% 282.6MiB / 1.703GiB 16.21% 876B / 126B 0B / 0B 7
# 可以看出CPU的使用率大概是400% 因为我们是4个核心单个核心跑满是100%
```
##### 3.2.2 **限制容器cpu**
```bash
[root@localhost ~]# docker run -it --rm --cpus 2 --name test1 tylersmith22/docker-stress-ng --vm 1 --cpu 4
stress-ng: info: [1] defaulting to a 86400 second run per stressor
stress-ng: info: [1] dispatching hogs: 4 cpu, 1 vm
[root@localhost ~]# docker stats
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
5b7dcb36d738 test1 200.65% 279.7MiB / 1.703GiB 16.04% 876B / 126B 0B / 0B 7
[root@localhost ~]# top
top - 21:36:15 up 47 min, 3 users, load average: 1.38, 1.92, 1.05
Tasks: 198 total, 8 running, 190 sleeping, 0 stopped, 0 zombie
%Cpu0 : 50.7 us, 1.4 sy, 0.0 ni, 47.2 id, 0.0 wa, 0.7 hi, 0.0 si, 0.0 st
%Cpu1 : 52.9 us, 0.0 sy, 0.0 ni, 47.1 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu2 : 50.7 us, 0.0 sy, 0.0 ni, 48.6 id, 0.0 wa, 0.7 hi, 0.0 si, 0.0 st
%Cpu3 : 50.4 us, 0.0 sy, 0.0 ni, 48.9 id, 0.0 wa, 0.7 hi, 0.0 si, 0.0 st
# 并且是平均使用所有的cup核心
```
##### 3.2.3 将容器运行到指定的cpu上
```bash
[root@localhost ~]# docker run -it --rm --cpus 2 --cpuset-cpus 0,2 --name test1 tylersmith22/docker-stress-ng --vm 1 --cpu 4
[root@localhost ~]# docker stats
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
ee11d834dde5 test1 186.68% 1.488GiB / 1.781GiB 83.60% 648B / 0B 44.8GB / 95.7MB 25
[root@localhost ~]# top
top - 21:38:25 up 49 min, 3 users, load average: 0.92, 1.40, 0.96
Tasks: 197 total, 6 running, 191 sleeping, 0 stopped, 0 zombie
%Cpu0 : 97.3 us, 2.0 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.7 hi, 0.0 si, 0.0 st
%Cpu1 : 0.3 us, 0.0 sy, 0.0 ni, 99.3 id, 0.0 wa, 0.0 hi, 0.3 si, 0.0 st
%Cpu2 : 98.3 us, 1.0 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.7 hi, 0.0 si, 0.0 st
%Cpu3 : 0.0 us, 0.3 sy, 0.0 ni, 99.3 id, 0.0 wa, 0.3 hi, 0.0 si, 0.0 st
MiB Mem : 1743.4 total, 457.2 free, 924.2 used, 531.4 buff/cache
MiB Swap: 2048.0 total, 2047.2 free, 0.8 used. 819.2 avail Mem
```
- 基于cpu-shares对cpu进行切分
```bash
[root@localhost ~]# docker run -it --rm -d --cpu-shares 1000 --name test1 tylersmith22/docker-stress-ng --vm 1 --cpu 4
[root@localhost ~]# docker run -it --rm -d --cpu-shares 500 --name test2 tylersmith22/docker-stress-ng --vm 1 --cpu 4
[root@localhost ~]# docker stats
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
d6dd34edb722 test1 543.41% 819.6MiB / 1.781GiB 44.95% 648B / 0B 102MB / 154MB 13
154b07a94e2f test2 241.15% 711.1MiB / 1.781GiB 39.00% 648B / 0B 406MB / 145MB
```