07-15-周三_15-28-35

This commit is contained in:
AaronXu
2026-07-15 15:28:36 +08:00
parent 4c9728b931
commit 8d84941d62
77 changed files with 3361 additions and 1327 deletions

View File

@@ -0,0 +1,935 @@
# Docker是什么
Docker是一个在2013年开源的应用程序并且是一个基于go语言编写的PAAS服务。
Docker最早采用LXC技术之后改为自己研发并开源的runc技术运行容器。
Docker相比虚拟机的交付速度更快资源消耗更低Docker采用客户端、服务端架构使用远程api来管理和创建Docker容器。
Docker的三大理念是build构建、ship运输、run运行
Docker通过namespace、cgroup等技术来提供容器的资源隔离与安全保障。
# 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+容器密度很高适合大规模的部署 |
- 资源利用率更高一台物理机可以运行数百个容器但一般只能运行数十个虚拟机
- 开销更小不需要启动单独的虚拟机占用硬件资源
- 启动速度更快可以在数秒内完成启动
# 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)
# 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**更新周期更稳定更注重稳定性和兼容性生命周期较长
# 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
```
## 镜像加速配置
由于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
```
## 快速开始
```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)。
- **作用**为用户创建一个类似本地终端的交互环境支持颜色显示光标操作等终端特性
### 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**
<img src="01.docker%E4%BB%8B%E7%BB%8D%E4%B8%8E%E5%AE%89%E8%A3%85/image-20250324001839505.png" alt="image-20250324001839505" style="zoom:80%;" />
### 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: 设置容器内存限制
```
# Docker核心技术
## 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 |
### 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的工作原理。
#### Docker 的存储架构
1. **镜像层Read-Only**
- Docker 镜像是由多个只读层组成的。每一层代表了镜像的某个状态或修改。
- 这些层是不可变的,一旦创建,不会被修改。
2. **容器层Read-Write**
- 当你运行一个容器时Docker 会在镜像层之上添加一个可写层。
- 容器的所有写操作(如创建文件、修改文件等)都会在这个可写层中进行,而不会影响下面的镜像层。
#### 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` 目录中,让你在容器中看到完整的文件系统视图。
### IPC Namespace
一个容器内的进程间通信,允许一个容器内的不同进程数据互相访问,但是不能跨容器访问其他容器的数据
UTS Namespace包含了运行内核的名称、版本、底层体系结构类型等信息用于系统表示其中包含了hostname和域名它使得一个容器拥有属于自己hostname标识这个主机名标识独立于宿主机系统和其上的其他容器。
### 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 隔离**:
- 容器内的进程无法访问或影响宿主机上的其他进程。
- 宿主机上的进程可以访问和管理容器内的进程。
### 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)
### User Namespace
各个容器内可能会出现重名的用户和用户组名称或重复的用户UID或者GID那么怎么隔离各个容器内的用户空间呢
User Namespace允许在宿主机的各个容器空间内创建相同的用户名以及相同的uid和gid只是此用户的有效范围仅仅是当前的容器内不能访问另外一个容器内的文件系统即相互隔离、互不影响、永不相见
## 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
### Docker 中的 cgroups 资源限制
#### 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 时间。
#### 2. **内存资源限制**
Docker 可以通过以下参数限制容器的内存使用:
- **`-m``--memory`**:限制容器的物理内存使用量。例如,`-m 512m` 表示限制容器使用 512MB 的物理内存。
- **`--memory-swap`**:限制容器的总内存使用量(物理内存 + 交换空间)。例如,`--memory-swap=1g` 表示容器可以使用 1GB 的总内存。
#### 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。
### 查看和管理 cgroups 资源限制
- **查看 cgroups 配置**:可以通过访问 `/sys/fs/cgroup` 目录来查看容器的 cgroups 配置。例如,`/sys/fs/cgroup/cpu/docker/<container_id>` 目录下包含了容器的 CPU 资源限制文件。
- **动态调整资源限制**:在容器运行时,可以通过修改 cgroups 文件的内容来动态调整资源限制。
### 使用压缩工具测试
```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
```
#### 测试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
```
# 容器规范
## 容器技术及其标准化组织 OCI
容器技术是一种轻量级的虚拟化技术,用于隔离应用程序及其依赖项,使其能够在不同的环境中一致地运行。除了 Docker 之外,还有其他多种容器运行时和工具,例如 CoreOS 的 rkt、阿里的 Pouch 和红帽的 Podman。为了确保容器生态系统的标准性和可持续发展Linux 基金会、Docker、微软、红帽、谷歌和 IBM 等公司在 2015 年 6 月共同成立了 **Open Container Initiative (OCI)** 组织。
### **OCI 的目标**
OCI 的主要目标是制定开放的容器规范以确保不同容器技术之间的可移植性和互操作性。目前OCI 已经发布了两个核心规范:
1. **Runtime Spec**:定义了容器运行时的规范,包括容器的生命周期管理、资源隔离和安全等。
2. **Image Format Spec**:定义了容器镜像的格式和元数据,确保镜像可以在不同的容器运行时之间共享和运行。
通过遵循这些规范,不同的容器运行时和工具可以实现互操作性,从而推动容器技术的标准化和健康发展。
### 主流容器运行时
容器运行时是真正运行容器的地方,它需要与操作系统的内核紧密合作,为容器提供隔离的运行环境。以下是目前主流的三种容器运行时:
#### 1. **LXC (Linux Containers)**
- **简介**LXC 是 Linux 上早期的容器运行时,它利用 Linux 内核的 Namespace 和 Cgroups 技术来实现进程隔离和资源管理。
- **特点**
- 提供了完整的 Linux 系统环境,支持多种 Linux 发行版。
- 早期 Docker 也曾使用 LXC 作为其默认的运行时。
- **适用场景**:适用于需要完整 Linux 系统环境的容器化应用。
#### 2. **Runc**
- **简介**Runc 是目前 Docker 默认的容器运行时,它是一个轻量级的命令行工具,用于运行和管理容器。
- **特点**
- 完全遵循 OCI 的 Runtime Spec 规范,确保与 OCI 标准的兼容性。
- 由于其轻量级和高性能的特点Runc 已经成为许多容器运行时的底层实现。
- **适用场景**:适用于需要高性能和轻量级容器运行环境的场景。
#### 3. **Rkt (Rocket)**
- **简介**Rkt 是由 CoreOS 开发的容器运行时,旨在提供一个安全、可靠且符合 OCI 规范的容器运行环境。
- **特点**
- 与 Docker 不同Rkt 本身是一个独立的容器运行时,不依赖 Docker 的守护进程。
- 提供了更好的安全性和隔离性,例如通过 AppArmor 和 SELinux 等安全机制。
- **适用场景**:适用于对安全性要求较高的容器化应用。
容器技术的发展离不开标准化的推动。OCI 通过制定 Runtime Spec 和 Image Format Spec为容器运行时和工具提供了统一的标准确保了不同容器技术之间的互操作性和可移植性。目前主流的容器运行时如 LXC、Runc 和 Rkt都遵循这些规范从而推动了容器技术的广泛应用和发展。
# 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 # 是否开启活动容器(重启不关闭容器)
```
# docker 存储引擎
Docker 的存储引擎是 Docker 平台中用于管理容器和镜像数据的核心组件。它负责容器的文件系统、网络配置、权限管理等,以及其他与容器运行相关的任务。以下是对 Docker 存储引擎的详细介绍:
## **核心概念及工作原理**
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 的默认存储驱动。
## 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`,容器通过这个目录看到完整的文件系统。

View File

Before

Width:  |  Height:  |  Size: 81 KiB

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

View File

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 172 KiB

View File

@@ -0,0 +1,286 @@
# 搜索镜像
```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]
```
可以看到返回了很多包含关键字的镜像,其中包括镜像名字、描述、点赞数(表示该镜像的受欢迎程度)、是否官方创建、是否自动创建。默认输出结果按照星级评价进行排序。
<img src="02.docker%E9%95%9C%E5%83%8F%E7%AE%A1%E7%90%86/image-20250324192816988.png" alt="image-20250324192816988" style="zoom:80%;" />
# 下载镜像
可以使用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
```
# 查看镜像信息
## 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镜像大小优秀的镜像往往体积都较小
## 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
```
## 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"
}
}
]
```
## 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
```
# 镜像导入导出
## 导出
可以将镜像从本地导出为一个压缩文件,然后复制到其他服务器进行导入使用
- 导出方法一
```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
```
## 导入
先将导出的镜像发到需要导入的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
```
# 删除镜像
- 使用镜像名称+标签
```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
```

View File

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 KiB

View File

@@ -0,0 +1,396 @@
# docker容器管理
# 创建容器
## 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
```
## 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
```
## 端口映射
- 前台启动随机映射端口
```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
```
## 后台启动容器
- 当容器前台启动时,前台进程退出容器也就退出,更多时候需要容器在后台启动
```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 ~]#
```
# 停止容器
## 暂停容器
- 挂起容器
```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
```
## 终止容器
```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
```
# 删除容器
## 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
```
# 进入容器
## attach
所有使用此方式进入容器的操作都是同步显示的且exit容器将被关闭且使用exit退出后容器关闭不推荐使用
![image-20210609143957975](03.docker容器管理/image-20210609143957975.png)
当有一个容器执行exit退出后会导致容器退出
## 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可选参数传递给命令的参数
```
## 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 ~]#
```
# 指定容器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
```
# 导入导出容器
## 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
```
## 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,465 @@
# Docker镜像制作
# 基于rocky手动构建nginx镜像
Docker镜像制作类似于虚拟机的模板制作即按照公司的实际业务将需要安装的软件、相关配置等基础环境配置完成然后将容器再提交为模板最后再批量从模板批量创建新的虚拟机这样可以极大地简化业务中相同环境的虚拟机运行环境的部署工作Docker的镜像制作分为手动制作可自动制作基于DockerFile企业通常都是基于DockerFile制作镜像。
## 从初始镜像开始构建
一、启动一个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
```
## 镜像提交
通过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、和镜像的历史层一起合并成一个新的镜像
## 从新镜像启动容器
从自己的镜像启动容器
```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
```
访问测试:
<img src="04.docker%E9%95%9C%E5%83%8F%E5%88%B6%E4%BD%9C/image-20250325185125851.png" alt="image-20250325185125851" style="zoom:80%;" />
# DockerFile制作镜像
Dockerfile 是一种可以被 Docker 程序解释的脚本,它是一个文本文件,包含了一系列指令,用于定义如何构建 Docker 镜像。每一条指令都会创建镜像的一层最终生成的镜像是由这些层叠加而成的。Dockerfile 中的指令关键字必须大写,执行顺序是从上到下,且每条指令创建一个镜像层。
Docker 程序会读取 Dockerfile 并根据指令生成 Docker 镜像。Dockerfile 的指令类似于 Linux 下的命令,但 Docker 程序会将这些 Dockerfile 指令翻译成真正的 Linux 命令来执行。相比手动制作镜像的方式Dockerfile 能更直观地展示镜像是如何产生的。有了写好的 Dockerfile 文件,当后期某个镜像有额外的需求时,只需在之前的 Dockerfile 中添加或修改相应的操作,即可重新生成新的 Docker 镜像,避免了重复手动制作镜像的麻烦。
## 指令说明
### 配置指令
| 指令 | 说明 |
| :------------ | :--------------------------------- |
| `ARG` | 定义创建镜像过程中使用的变量 |
| `FROM` | 指定所创建镜像的基础镜像 |
| `LABEL` | 为生成的镜像添加元数据标签信息 |
| `EXPOSE` | 声明镜像内服务监听的端口 |
| `ENV` | 指定环境变量 |
| `ENTRYPOINT` | 指定镜像的默认入口命令 |
| `VOLUME` | 创建一个数据卷挂载点 |
| `USER` | 指定运行容器时的用户名或UID |
| `WORKDIR` | 配置工作目录 |
| `ONBUILD` | 创建子镜像时指定自动执行的操作指令 |
| `STOPSIGNAL` | 指定退出的信号值 |
| `HEALTHCHECK` | 配置所启动容器如何进行健康检查 |
| `SHELL` | 指定默认shell类型 |
### 操作指令
| 指令 | 说明 |
| :----- | :--------------------------- |
| `RUN` | 运行指定命令 |
| `CMD` | 启动容器时指定默认执行的命令 |
| `ADD` | 添加内容到镜像 |
| `COPY` | 复制内容到镜像 |
## 配置指令详解
### ARG
定义创建过程中使用到的变量,例如 `HTTP_PROXY``HTTPS_PROXY``FTP_PROXY``NO_PROXY` 等,不区分大小写。
### FROM
指定所创建镜像的基础镜像。为了保证镜像精简,可以选用体积较小的 Alpin 或 Debian 作为基础镜像。
### EXPOSE
声明镜像内服务监听的端口。例如:
```bash
EXPOSE 22 80 8443
```
该指令只是起到声明作用,并不会自动完成端口映射。
### ENTRYPOINT
指定镜像的默认入口命令,该入口命令会在启动容器时作为根命令执行,所有传入值作为该命令的参数。支持两种格式:
- `ENTRYPOINT ["executable","param1","param2"]`exec 调用执行)
- `ENTRYPOINT command param1 param2`(在 shell 中执行)
此时 `CMD` 指令指定值将作为根命令的参数。每个 Dockerfile 中只能有一个 `ENTRYPOINT`,当指定多个时只有最后一个起效。
### VOLUME
创建一个数据卷挂载点。例如:
```bash
VOLUME ["/data"]
```
### WORKDIR
为后续的 `RUN``CMD``ENTRYPOINT` 指令配置工作目录。例如:
```bash
WORKDIR /path/to/workdir
```
可以使用多个 `WORKDIR` 指令,后续命令如果参数是相对路径,则会基于之前命令指定的路径。例如:
```bash
WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd
```
最终路径为 `/a/b/c`。因此,为了避免出错,推荐在 `WORKDIR` 指令中只使用绝对路径。
### 操作指令详解
### RUN
运行指定Linux命令。每条 `RUN` 指令将在当前镜像基础上执行指定命令,并提交为新的镜像层。当命令较长时可以使用 `\` 来换行。
### CMD
`CMD` 指令用来指定启动容器时默认执行的命令。支持三种格式:
- `CMD ["executable","param1","param2"]`(相当于执行 `executable param1 param2`
- `CMD command param1 param2`(在默认的 shell 中执行,提供给需要交互的应用)
- `CMD ["param1","param2"]`(提供给 `ENTRYPOINT` 的默认参数)
每个 Dockerfile 只能有一条 `CMD` 命令。如果指定了多条命令,只有最后一条会被执行。
### ADD
添加内容到镜像。例如:
```bash
ADD <src> <dest>
```
该命令将复制指定的 `src` 路径下内容到容器中的 `dest` 路径下。`src` 可以是 Dockerfile 所在目录的一个相对路径,也可以是一个 URL还可以是一个 tar 文件。`dest` 可以是镜像内绝对路径,或者相对于工作目录的相对路径。
### COPY
复制内容到镜像。例如:
```bash
COPY <src> <dest>
```
`COPY``ADD` 指令功能类似,当使用本地目录为源目录时,推荐使用 `COPY`
## 制作nginx镜像
DockerFile可以说是一种可以被Docker程序解释的脚本DockerFIle是由一条条的命令组成的每条命令对应Linux下面的一条命令Docker程序将这些DockerFile指令再翻译成真正的Linux命令其有自己的书写方式和支持的命令Docker程序读取DockerFile并根据指令生成Docker镜像。
### 基于编译安装制作nginx小游戏网站
#### 环境准备
一、下载镜像
```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
```
#### 编写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;"]
```
#### 构建镜像
一、通过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
```
三、访问测试
<img src="04.docker%E9%95%9C%E5%83%8F%E5%88%B6%E4%BD%9C/image-20250325195752895.png" alt="image-20250325195752895" style="zoom:80%;" />
# 镜像上传
## 官方docker仓库
- 准备账户
登陆到docker hub官网创建账号登陆后点击settings完善信息
- 填写账户基本信息
![image-20220920090601269](04.docker%E9%95%9C%E5%83%8F%E5%88%B6%E4%BD%9C/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%E9%95%9C%E5%83%8F%E5%88%B6%E4%BD%9C/image-20220920091110123.png)
- 更换到其他docker服务器下载镜像
```bash
[root@docker-server ~]# docker login docker.io
```
## 阿里云仓库
将本地镜像上传至阿里云,实现镜像备份与统一分发的功能
https://cr.console.aliyun.com/
注册并且登录阿里云镜像仓库创建namespace空间创建一个普通的镜像仓库
<img src="04.docker%E9%95%9C%E5%83%8F%E5%88%B6%E4%BD%9C/image-20250325201301197.png" alt="image-20250325201301197" style="zoom:80%;" />
具体如何拉取镜像,上传镜像,可以查看阿里云仓库下方提供的操作指南
### 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%E9%95%9C%E5%83%8F%E5%88%B6%E4%BD%9C/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: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

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: 120 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 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: 114 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,310 @@
# Docker数据管理
# 数据管理
## UnionFS联合文件系统
Docker 中的 UnionFS联合文件系统是一种分层、轻量级且高性能的文件系统其核心功能是将多个目录内容联合挂载到同一个目录下形成一个统一的文件系统视图。以下是其主要特点和作用
### 核心特点
- **分层存储**UnionFS 可以将不同层次的文件和目录合并成单一的目录树。在 Docker 中,每一层可以代表一个镜像层,最低层通常是只读的基础镜像层,上面的层是可写的容器层。
- **写时复制Copy-on-Write, CoW**当容器需要修改一个文件时UnionFS 不会直接更改底层只读镜像中的文件,而是将更改写入到一个可写的上层。这样,原始镜像层保持不变,可以被多个容器共享。
- **隔离性**:由于底层的只读镜像层保持不变,每个容器看到的是一个完整的文件系统视图,包括它们的改动,但这些改动仅存在于它们自己的可写层中。
- **性能优化**UnionFS 通过仅对发生更改的文件进行操作,以及通过页面缓存共享等机制,减少了磁盘 I/O 操作,加快了容器启动时间。
### 在 Docker 中的应用
- **镜像分层**Docker 镜像是由多个只读层叠加而成的每一层都代表了镜像构建过程中的一个状态。UnionFS 将这些层联合起来,形成一个完整的文件系统。
- **容器运行时的文件系统**当启动一个容器时Docker 会在镜像的最顶层添加一个新的可写层。容器的所有写操作都在这个可写层中进行,而不会影响到镜像的只读层。
- **镜像继承与共享**:由于镜像的分层结构,新的镜像可以基于已有的镜像构建,只需添加新的层即可。同时,多个容器可以共享同一个镜像的只读层,极大地节省了磁盘空间。
### 常见的 UnionFS 实现
虽然 UnionFS 是一个理念,但 Linux 内核中有多种具体的实现方式Docker 默认使用的是 Overlay2。Overlay2 是一种先进的联合文件系统实现,具有更好的性能和一些先进的功能,如页面缓存共享。
## 镜像层与可写层
在 Docker 中镜像层和容器可写层是基于联合文件系统UnionFS实现的关键概念。它们共同构成了容器的文件系统结构使得 Docker 能够高效地管理和运行容器。以下是对镜像层和容器可写层的详细解释:
### 一、镜像层
镜像层是 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 等镜像仓库拉取镜像,而无需关心镜像的具体构建过程。
### 二、容器可写层
容器可写层是容器运行时特有的一个层,它是可写的,用于存储容器运行时产生的所有变更。
1. **容器可写层的生成**
- 当你启动一个容器时Docker 会在镜像的最顶层添加一个新的可写层。这个可写层是容器独有的,用于存储容器运行时的文件系统变更。
- 例如,如果你在容器中创建了一个新文件、修改了一个现有文件或删除了一个文件,这些操作都会反映在容器可写层中,而不会影响到镜像层。
2. **容器可写层的特点**
- **可写性**:容器可写层是可写的,容器运行时的所有文件系统操作(如创建、修改、删除文件)都在这个层中进行。
- **独立性**:每个容器都有自己的可写层,容器之间的可写层是隔离的。一个容器的变更不会影响到其他容器。
- **临时性**:容器可写层的内容在容器被删除时也会被删除。如果需要持久化数据,需要将数据存储在外部存储(如卷)中。
3. **容器可写层的作用**
- **隔离性**:容器可写层保证了容器之间的隔离性。每个容器在自己的可写层中进行操作,不会影响到其他容器或镜像层。
- **灵活性**:容器可写层允许容器在运行时动态地修改文件系统,而不会影响到镜像的原始状态。这使得容器可以灵活地运行各种应用程序。
- **数据持久化**虽然容器可写层的内容在容器删除时会被删除但你可以通过挂载卷Volumes将数据持久化到宿主机或其他存储设备中从而实现数据的持久化存储。
### 三、镜像层与容器可写层的关系
镜像层和容器可写层通过联合文件系统UnionFS联合起来形成了容器的完整文件系统视图。
1. **联合挂载**
- Docker 使用联合文件系统将镜像层和容器可写层联合挂载到同一个目录下。从容器的角度来看,它看到的是一个完整的文件系统,包含了镜像层和容器可写层的内容。
- 例如当你在容器中访问一个文件时Docker 会先在容器可写层中查找该文件。如果找不到,就会在镜像层中查找。如果在镜像层中找到了文件,就会将该文件的内容返回给容器。
2. **写时复制Copy-on-Write**
- 当容器需要修改一个文件时Docker 会使用写时复制机制。具体来说Docker 会将文件从镜像层复制到容器可写层,然后在可写层中进行修改。这样,镜像层保持不变,而容器可写层存储了修改后的文件。
- 例如,假设镜像层中有一个文件 `/etc/nginx/nginx.conf`容器需要修改这个文件。Docker 会将该文件从镜像层复制到容器可写层,然后在可写层中进行修改。从容器的角度来看,它看到的是修改后的文件,而镜像层中的文件保持不变。
3. **删除操作**
- 当容器删除一个文件时Docker 会在容器可写层中记录一个删除操作,而不是真正删除镜像层中的文件。这样,镜像层保持不变,而容器可写层记录了文件的删除状态。
- 例如,假设容器删除了一个文件 `/etc/nginx/nginx.conf`Docker 会在容器可写层中记录一个删除标记。从容器的角度来看,该文件已经被删除,而镜像层中的文件仍然存在。
### 总结
- **镜像层**:是 Docker 镜像的组成部分,是只读的、不可变的,多个容器可以共享镜像层。镜像层通过分层构建,提高了构建效率、节省了磁盘空间,并保证了镜像的一致性和可重复性。
- **容器可写层**:是容器运行时的可写层,用于存储容器运行时的文件系统变更。容器可写层是独立的、可写的、临时的,保证了容器之间的隔离性和运行时的灵活性。
- **联合文件系统UnionFS**将镜像层和容器可写层联合挂载形成了容器的完整文件系统视图。通过写时复制机制Docker 在不影响镜像层的情况下,允许容器在可写层中进行文件系统操作。
## 查看镜像的详细信息
### 一、查看镜像数据信息
```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容器在宿主机的工作目录
```
### 二、查看镜像层构建过程
```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命令**
# 数据卷
## 什么是数据卷?
数据卷实际上就是宿主机上的目录或者是文件可以被直接mount到容器当中使用。
实际生产环境中,需要针对不同类型的服务、不同类型的数据存储要求做相应的规划,最终保证服务的可扩展性、稳定性以及数据的安全性。
![img](05.docker数据管理/u=1718952600,4159508250&fm=26&fmt=auto&gp=0.jpg)
## 数据卷案例
- 创建目录并准备页面
```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!
```
## 数据卷特点
1. 数据卷是宿主机的目录或者文件,并且可以在**多个容器之间共同使用**
2. 在宿主机对数据卷更改数据后会在所有容器里面会**立即更新**
3. 数据卷的数据可以**持久保存**,即使删除使用该数据卷卷的容器也不影响
4. 在容器里面写入数据不会影响到镜像本身(**隔离性**)。
5. 需要挂载多个目录或者文件的时候可以使用多个-v参数指定
6. 数据卷使用场景包括日志输出、静态web页面、应用配置文件、多容器间目录或文件共享
## 数据卷容器
### 什么是数据卷容器
数据卷容器是一个普通的容器,专门用于提供数据卷供其他容器挂载。它允许用户创建一个专门用于数据存储的容器,并将其数据卷挂载到其他容器中。数据卷容器的主要用途是将数据卷的生命周期与应用容器分离,使数据可以在容器之间共享和持久化。
### 数据卷容器的用途
1. **数据持久化**:数据卷容器可以确保数据即使在容器被删除后也不会丢失。例如,对于数据库应用,数据卷容器可以持久化数据库文件,避免因容器删除而导致数据丢失。
2. **数据共享**:多个容器可以通过挂载同一个数据卷容器来共享数据。这在多容器应用中非常有用,例如在微服务架构中,多个服务容器可以共享数据库数据。
3. **备份与恢复**:数据卷容器可以用于备份和恢复数据。通过将数据卷容器中的数据卷备份到宿主机或其他存储设备,可以在需要时恢复数据。
4. **迁移数据**:数据卷容器可以方便地迁移数据。通过将数据卷容器中的数据卷迁移到其他主机,可以快速实现数据的迁移。
### 数据卷容器与本地数据挂载的区别
| 特性 | 数据卷容器 | 本地数据挂载 |
| :--------------------- | :----------------------------------------------------------- | :----------------------------------------------------------- |
| **目录来源** | Docker 自动创建的目录 | 宿主机上已存在的目录 |
| **适用场景** | 数据持久化、容器间共享数据 | 开发调试、快速文件同步 |
| **容器间共享** | 支持 | 不支持 |
| **宿主机文件系统依赖** | 无依赖 | 依赖宿主机文件系统 |
| **数据持久化** | 数据卷的生命周期独立于容器,即使容器被删除,数据卷仍然存在 | 如果容器被删除,挂载的目录和文件仍然存在,但需要手动管理 |
| **数据初始化** | 如果宿主机没有对应的文件,数据卷容器会自动将容器运行所需的文件复制到数据卷中 | 如果宿主机没有对应的文件,容器可能会因缺少运行所需的文件而出错 |
| **数据覆盖** | 数据卷中的数据会覆盖容器内的数据 | 容器内的数据会覆盖宿主机上的数据 |
### 实例演示
- 先启动一个卷容器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!
```
### 总结
在当前环境下即使把提供卷的容器Server删除已经运行的容器Client依然可以使用挂载的卷因为容器是通过挂载的方式访问数据的但是无法创建新的卷容器客户端但是再把卷容器Server创建后即可正常创建卷容器client此方式可以用于线上共享数据目录等环境因为即使数据卷容器被删除了其他已经运行的容器依然可以挂载使用
数据卷容器可以作为共享的方式为其他容器提供文件共享,可以在容器生成中启动一个实例挂载本地的目录,然后其他的容器分别挂载此容器的目录,即可保证各个容器之间的数据一致性。

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View File

@@ -0,0 +1,351 @@
# 容器之间的互联
在同一个宿主机上的容器之间可以通过端口映射的方式经过宿主机中转进行互相访问也可以通过docker0网桥互相访问
## 直接互联
- 启动两个容器
```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
```
## 使用名称互联
- 启动两个容器
```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
```
## 使用别名互联
自定义的容器名称可能后期会发生变化,那么一旦发生变化也会带来一些影响,这个时候如果每次都更改名称又比较麻烦,这个时候可以使用定义别名的方式解决,即容器名称可以随意更改,只要不更改别名即可。
- 启动一个容器
```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
```
# Docker网络
## 四类网络模式
| 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网络类型
## 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
```
## 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
```
## 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
```
## 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)
# 创建自定义网络
可以基于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
```
# 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 [::]:*
```
二、浏览器访问初始化博客
<img src="06.docker%E7%BD%91%E7%BB%9C%E7%AE%A1%E7%90%86/image-20250326222721074.png" alt="image-20250326222721074" style="zoom:80%;" />
三、完善信息数据库选择内置的SQL Lite方便一点
<img src="06.docker%E7%BD%91%E7%BB%9C%E7%AE%A1%E7%90%86/image-20250326222739407.png" alt="image-20250326222739407" style="zoom:80%;" />
四、安装完成
![image-20250326222830605](06.docker%E7%BD%91%E7%BB%9C%E7%AE%A1%E7%90%86/image-20250326222830605.png)
五、更改主题,默认带了几个主题
<img src="06.docker%E7%BD%91%E7%BB%9C%E7%AE%A1%E7%90%86/image-20250326222916277.png" alt="image-20250326222916277" style="zoom:80%;" />

View File

Before

Width:  |  Height:  |  Size: 9.0 KiB

After

Width:  |  Height:  |  Size: 9.0 KiB

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

Before

Width:  |  Height:  |  Size: 9.7 KiB

After

Width:  |  Height:  |  Size: 9.7 KiB

View File

Before

Width:  |  Height:  |  Size: 18 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

View File

@@ -0,0 +1,328 @@
# Docker 容器资源限制与 OOM 异常处理
## 容器资源限制
默认情况下容器没有资源限制可以使用主机内核调度程序允许的尽可能多的给定资源。Docker 提供了控制容器可以使用多少内存或者 CPU 的方法,通过设置 `docker run` 命令的运行时配置标志来实现。
其中一些功能要求宿主机的内核支持 Linux 功能。要检查支持情况,可以使用 `docker info` 命令。如果内核中禁用了某项功能,可能会在输出结尾处看到警告。
## OOM 异常
对于 Linux 主机,如果没有足够的内存来执行其他重要的系统任务,将会抛出 OOM 异常(内存溢出、内存泄漏、内存异常)。随后系统会开始杀死进程以释放内存,凡是运行在宿主机上的进程都有可能被 kill包括 `dockerd` 和其他的应用程序。如果重要的系统进程被 kill会导致和该进程相关的服务全部宕机。
产生 OOM 异常时,`dockerd` 会尝试通过调整 Docker 守护程序上的 OOM 优先级来减轻这些风险,以便它比系统上的其他进程更不可能被杀死。但是,容器的 OOM 优先级未调整时,单个容器被杀死的可能性更大(不推荐调整容器的优先级这种方式)。
## 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 强制杀死。
# 容器的内存限制
Docker可以强制执行**硬性内存限制**,即只允许容器使用给定的内存大小
Docker也可以执行**非硬性内存限制**,即容器可以使用尽可能多的内存,除非内核检测到主机上的内存不够用了
## 内存限制参数
### `-m` 或 `--memory`
- **功能**:限制容器最大可用内存。
- **最小值**4m。
- **示例**
```bash
docker run -m 512m my_image
```
### `--memory-swap`
- **功能**:限制容器可用的内存 + swap 总量。
- **前提**:需先设置 `--memory`。
- **特殊值**`-1` 表示不限制 swap 使用。
- **示例**
```bash
docker run --memory 256m --memory-swap 512m my_image
```
### `--memory-swappiness`
- **功能**:控制容器使用 swap 的倾向性。
- **范围**0尽量不使用 swap到 100尽量使用 swap
- **示例**
```bash
docker run --memory-swappiness 30 my_image
```
### `--kernel-memory`
- **功能**:限制容器使用的内核内存。
- **最小值**4m。
- **注意事项**:不推荐设置,可能影响宿主机和其他容器。
- **示例**
```bash
docker run --kernel-memory 64m my_image
```
### `--memory-reservation`
- **功能**:设置软内存限制,低于 `--memory`。
- **激活条件**:主机内存争用或不足时生效。
- **注意事项**:必须小于 `--memory`,且不保证容器一定不超过此限制。
- **示例**
```bash
docker run --memory 1g --memory-reservation 512m my_image
```
### `--oom-kill-disable`
- **功能**:禁止 OOM 时杀死容器内进程。
- **前提**:必须与 `--memory` 一起使用。
- **注意事项**:若未设置 `--memory`OOM 时仍可能杀死进程。
- **示例**
```bash
docker run --memory 512m --oom-kill-disable my_image
```
## 内从限制案例
如果一个容器未作内存使用限制,则该容器可以利用到系统内存最大空间,默认创建的容器没有做内存资源限制
一、拉取容器压测工具镜像
```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
```
## **内存软限制**
软限制不会真正限制到内存的使用
```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
```
# 容器的CPU限制
一个宿主机有几十个核心的cpu但是宿主机上可以同时运行成百上千个不同的进程用以处理不同的任务多进程共用一个cpu的核心依赖计数就是为可压缩资源即一个核心cpu可以通过调度而运行多个进程但是在同一个单位时间内只能由一个进程在cpu上运行那么这么多的进程怎么在cpu上执行和调度的呢进程优先级
默认情况下每个容器对主机cpu周期的访问权限是不受限制的但是我们可以人为干扰
## CPU限制参数
### `--cpus`
- **功能**:指定容器可以使用的 CPU 资源数量。
- **示例**:主机有 2 个 CPU设置 `--cpus=1.5`,容器最多可使用 1.5 个 CPU。
- **示例命令**
```bash
docker run --cpus 1.5 my_image
```
### `--cpu-period` 和 `--cpu-quota`
- **功能**:设置 CPU 调度周期和配额。
- **关系**:必须一起使用,计算方式为 `cpu-quota / cpu-period`。
- **示例**
```bash
docker run --cpu-period 100000 --cpu-quota 50000 my_image
```
### `--cpuset-cpus`
- **功能**:指定容器运行的 CPU 编号(绑核)。
- **示例**:限制容器在 CPU 0 和 CPU 1 上运行。
- **示例命令**
```bash
docker run --cpuset-cpus 0,1 my_image
```
### `--cpuset-mems`
- **功能**:设置容器使用的内存节点(仅对 NUMA 架构有效)。
- **示例**:限制容器使用内存节点 0。
- **示例命令**
```bash
docker run --cpuset-mems 0 my_image
```
### `--cpu-shares`
- **功能**:设置容器的 CPU 时间片权重。
- **默认值**1024。
- **范围**:最小 2最大 262144。
- **示例**:容器 A 设置为 1024容器 B 设置为 2048容器 B 的 CPU 时间片是容器 A 的两倍。
- **示例命令**
```bash
docker run --cpu-shares 2048 my_image
```
## CPU限制案例
### **未限制容器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%
```
### **限制容器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核心
```
### 将容器运行到指定的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 --cpus 1 --cpuset-cpus 0 --cpu-shares 1024 --name test1 tylersmith22/docker-stress-ng --cpu 1
[root@localhost ~]# docker run -it --rm -d --cpus 1 --cpuset-cpus 0 --cpu-shares 2048 --name test2 tylersmith22/docker-stress-ng --cpu 1
[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
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 210 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 359 KiB

View File

@@ -272,6 +272,7 @@ d0456365c64d nginx_default bridge local
三、访问测试 三、访问测试
<img src="08.docker%20compose%E5%8D%95%E6%9C%BA%E7%BC%96%E6%8E%92/image-20250327185052680.png" alt="image-20250327185052680" style="zoom:80%;" />
## 启动多个容器 ## 启动多个容器
@@ -392,46 +393,48 @@ d1d6339ba0d7 lnmp-php "docker-php-entrypoi…" 4 minutes ago Up 4 mi
109672c0b1f0 mysql:5.7 "docker-entrypoint.s…" 4 minutes ago Up 4 minutes 3306/tcp, 33060/tcp lnmp-mysql-1 109672c0b1f0 mysql:5.7 "docker-entrypoint.s…" 4 minutes ago Up 4 minutes 3306/tcp, 33060/tcp lnmp-mysql-1
``` ```
`/data/lnmp/nginx/conf.d/default.conf` 中写入nginx 的配置文件 `/data/lnmp/nginx/conf.d/default.conf`中写入nginx 的配置文件
```shell ```bash
server { server {
listen 80; listen 80;
root /usr/share/nginx/html; root /usr/share/nginx/html;
location / { location / {
index index.php index.html; index index.php index.html;
} }
location ~ \.php$ { location ~ \.php$ {
fastcgi_pass php:9000; fastcgi_pass php:9000;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params; include fastcgi_params;
} }
} }
``` ```
准备探针测试 准备探针测试
`/data/lnmp/nginx/html/info.php` 中准备php探针 `/data/lnmp/nginx/html/info.php`中准备php探针
```shell ```bash
<?php <?php
phpinfo(); phpinfo();
?> ?>
``` ```
<img src="08.docker%20compose%E5%8D%95%E6%9C%BA%E7%BC%96%E6%8E%92/image-20250327193919238.png" alt="image-20250327193919238" style="zoom:80%;" />
测试数据库连接 测试数据库连接
`/data/lnmp/nginx/html/mysql.php`中准备php探针 `/data/lnmp/nginx/html/mysql.php`中准备php探针
```shell ```bash
<?php <?php
$dbhost = "mysql"; $dbhost = "mysql";
$dbuser = "root"; $dbuser = "root";
$dbpass = "123456"; $dbpass = "123456";
$db = "login"; $db = "login";
$conn = mysqli_connect($dbhost, $dbuser, $dbpass, $db) or exit("数据库连接失败!"); $conn = mysqli_connect($dbhost, $dbuser, $dbpass, $db) or exit("数据库连接失败!");
echo "数据库连接成功"; echo "数据库连接成功";
?> ?>
``` ```
@@ -439,7 +442,7 @@ server {
所以我们需要定制带有mysqli模块的php编写如下dockerfile 所以我们需要定制带有mysqli模块的php编写如下dockerfile
```shell ```bash
FROM php:7.4-fpm FROM php:7.4-fpm
ENV TZ=Asia/Shanghai ENV TZ=Asia/Shanghai
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini" \ RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini" \
@@ -456,7 +459,7 @@ RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini" \
&& docker-php-ext-install -j$(nproc) gd mysqli && docker-php-ext-enable mysqli && docker-php-ext-install -j$(nproc) gd mysqli && docker-php-ext-enable mysqli
``` ```
然后修改 docker-compose.yml 文件如下 然后修改docker-compose.yml文件如下
```yaml ```yaml
# docker-compose build lnmp # docker-compose build lnmp
@@ -506,9 +509,9 @@ volumes:
dbdata: null dbdata: null
``` ```
测试验证 然后再次运行测试
```shell ```bash
[root@localhost lnmp]# docker compose up -d [root@localhost lnmp]# docker compose up -d
[root@localhost lnmp]# docker ps [root@localhost lnmp]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
@@ -516,3 +519,40 @@ CONTAINER ID IMAGE COMMAND CREATED STATUS
d1d6339ba0d7 lnmp-php "docker-php-entrypoi…" 4 minutes ago Up 4 minutes 9000/tcp lnmp-php-1 d1d6339ba0d7 lnmp-php "docker-php-entrypoi…" 4 minutes ago Up 4 minutes 9000/tcp lnmp-php-1
109672c0b1f0 mysql:5.7 "docker-entrypoint.s…" 4 minutes ago Up 4 minutes 3306/tcp, 33060/tcp lnmp-mysql-1 109672c0b1f0 mysql:5.7 "docker-entrypoint.s…" 4 minutes ago Up 4 minutes 3306/tcp, 33060/tcp lnmp-mysql-1
``` ```
![image-20250327195141708](08.docker%20compose%E5%8D%95%E6%9C%BA%E7%BC%96%E6%8E%92/image-20250327195141708.png)
## z-blog博客部署
官网https://www.zblogcn.com/
一、下载zblog到指定目录并解压
```bash
[root@localhost lnmp]# cd /data/lnmp/nginx/html/
[root@localhost html]# wget https://update.zblogcn.com/zip/Z-BlogPHP_1_7_4_3430_Shelter.zip
[root@localhost html]# ls
Z-BlogPHP_1_7_4_3430_Shelter.zip index.html info.php mysql.php
[root@localhost html]# unzip Z-BlogPHP_1_7_4_3430_Shelter.zip
[root@localhost html]# chmod -R 777 *
```
浏览器访问
<img src="08.docker%20compose%E5%8D%95%E6%9C%BA%E7%BC%96%E6%8E%92/image-20250327195804039.png" alt="image-20250327195804039" style="zoom:80%;" />
二、环境检查
<img src="08.docker%20compose%E5%8D%95%E6%9C%BA%E7%BC%96%E6%8E%92/image-20250327195830286.png" alt="image-20250327195830286" style="zoom:80%;" />
三、需要进入到mysql容器中手动创建一个blog的库然后如下填写
<img src="08.docker%20compose%E5%8D%95%E6%9C%BA%E7%BC%96%E6%8E%92/image-20250327200047631.png" alt="image-20250327200047631" style="zoom:80%;" />
四、安装完成
<img src="08.docker%20compose%E5%8D%95%E6%9C%BA%E7%BC%96%E6%8E%92/image-20250327200608550.png" alt="image-20250327200608550" style="zoom:80%;" />
五、优化网站
<img src="08.docker%20compose%E5%8D%95%E6%9C%BA%E7%BC%96%E6%8E%92/image-20250327200703348.png" alt="image-20250327200703348" style="zoom:80%;" />

View File

@@ -0,0 +1,225 @@
# Docker Registry
Docker Register作为Docker的核心组件之一负责镜像内容的存储与分发客户端的docker pull以及push命令都将直接与register进行交互最初版本的registry由python实现的由于涉及初期在安全性、性能以及API的设计上有着诸多的缺陷该版本在0.9之后停止了开发由新的项目distribution新的docker register被称为Distribution来重新设计并开发了下一代的registry新的项目由go语言开发所有的api底层存储方式系统架构都进行了全面的重新设计已解决上一代registry的问题。
官方文档地址https://docs.docker.com/registry
官方github地址: https://github.com/docker/distribution
## 搭建镜像
- 下载docker registry镜像
```bash
[root@docker-server ~]# docker pull registry
```
- 创建授权使用目录
```bash
[root@docker-server ~]# mkdir /docker/auth -p
[root@docker-server ~]# cd /docker
```
- 创建用户
```bash
[root@docker-server docker]# yum install httpd-tools.x86_64 -y
[root@docker-server docker]# htpasswd -Bbn jack 123456 > auth/htpasswd
[root@docker-server docker]# cat auth/htpasswd
jack:$2y$05$a2wtUYyoC8p/eXzoseT9Q.dhMDgQgwkUiKVfs1z6zijk6M4UIiUsq
[root@docker-server docker]# docker run -d -p 5000:5000 -v /docker/auth/:/auth -e \
"REGISTRY_AUTH=htpasswd" \
-e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \
-e "REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd" registry
7be5539c6cbef114b33a083ef976836a44b97ea54a7c41beb1b568878794b22a
[root@docker-server docker]# docker ps -l
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7be5539c6cbe registry "/entrypoint.sh /etc…" 7 seconds ago Up 6 seconds 0.0.0.0:5000->5000/tcp, :::5000->5000/tcp nostalgic_stonebraker
[root@docker-server docker]#
[root@docker-server docker]#
[root@docker-server docker]#
[root@docker-server docker]#
[root@docker-server docker]# curl http://jack:123456@127.0.0.1:5000/v2/_catalog
{"repositories":[]}
[root@docker-server docker]# docker login 127.0.0.1:5000
Username: jack
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 docker]#
```
将本机的镜像push到仓库中
```bash
[root@localhost ~]# docker pull centos:7
[root@localhost ~]# docker tag centos:7 127.0.0.1:5000/test/centos:9
[root@localhost ~]# docker push 127.0.0.1:5000/test/centos:9
The push refers to repository [127.0.0.1:5000/test/centos]
74ddd0ec08fa: Pushed
9: digest: sha256:a1801b843b1bfaf77c501e7a6d3f709401a1e0c83863037fa3aab063a7fdb9dc size: 529
[root@localhost ~]# curl http://jack:123456@127.0.0.1:5000/v2/_catalog
{"repositories":["test/centos"]}
```
添加本地信任信任之后就可以从自己的仓库下载东西了由于我们测试的是127.0.0.1的地址,不用添加
```bash
cat /etc/docker/daemon.json
{
"registry-mirrors": ["远程的仓库地址"],
"insecure-registries": ["远程的仓库地址"],
"exec-opts": ["native.cgroupdriver=systemd"]
}
```
先删除本地的nginx镜像然后尝试从远程下载一次
```bash
[root@localhost ~]# docker pull 127.0.0.1:5000/test/centos:9
9: Pulling from test/centos
a1d0c7532777: Pull complete
Digest: sha256:a1801b843b1bfaf77c501e7a6d3f709401a1e0c83863037fa3aab063a7fdb9dc
Status: Downloaded newer image for 127.0.0.1:5000/test/centos:9
127.0.0.1:5000/test/centos:9
```
# Docker 仓库之分布式harbor
参考网址https://goharbor.io/docs/2.3.0/install-config/
Harbor是一个用于存储和分发Docker镜像的企业级Registry服务器由vmware开源其通过添加一些企业必须的功能特性例如安全、标识和管理等扩展了开源的Docker Distribution。Harbor也提供了高级的安全特性诸如用户管理访问控制和活动审计等。
## 安装
- 下载镜像
```bash
[root@docker-server1 ~]# wget https://github.com/goharbor/harbor/releases/download/v2.3.1/harbor-offline-installer-v2.3.1.tgz
```
- 解压缩
```bash
[root@docker-server1 ~]# tar xzvf harbor-offline-installer-v2.3.1.tgz
[root@docker-server1 ~]# ln -sv /root/harbor /usr/local/
"/usr/local/harbor" -> "/root/harbor"
```
- 安装harbor
```bash
[root@docker-server1 harbor]# cp harbor.yml.tmpl harbor.yml
[root@docker-server1 harbor]# grep -Ev '#|^$' harbor.yml.tmpl > harbor.yml
[root@docker-server1 harbor]# cat harbor.yml
hostname: 192.168.80.10
http:
port: 80
harbor_admin_password: Harbor12345
database:
password: root123
max_idle_conns: 100
max_open_conns: 900
data_volume: /data
trivy:
ignore_unfixed: false
skip_update: false
insecure: false
jobservice:
max_job_workers: 10
notification:
webhook_job_max_retry: 10
chart:
absolute_url: disabled
log:
level: info
local:
rotate_count: 50
rotate_size: 200M
location: /var/log/harbor
_version: 2.3.0
proxy:
http_proxy:
https_proxy:
no_proxy:
components:
- core
- jobservice
- trivy
[root@docker-server1 harbor]# curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
[root@localhost harbor]# chmod +x /usr/local/bin/docker-compose
[root@localhost harbor]# docker-compose --version
docker-compose version 1.29.2, build 5becea4c
[root@docker-server1 harbor]# ./prepare
[root@docker-server1 harbor]# ./install.sh
[root@docker-server1 harbor]# ss -tnl
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 *:80 *:*
LISTEN 0 128 *:22 *:*
LISTEN 0 100 127.0.0.1:25 *:*
LISTEN 0 128 127.0.0.1:1514 *:*
LISTEN 0 128 :::80 :::*
LISTEN 0 128 :::22 :::*
LISTEN 0 100 ::1:25 :::*
---
# 之后的启动关闭可以通过docker-compose管理自动生成docker-compose.yml文件
[root@docker-server1 harbor]# ls
common docker-compose.yml harbor.yml install.sh prepare
common.sh harbor.v2.3.1.tar.gz harbor.yml.tmpl LICENSE
```
## web访问
默认用户名和密码在harbor.yml中设置为harbor_admin_password: Harbor12345
<img src="09.docker%E4%BB%93%E5%BA%93%E7%AE%A1%E7%90%86/image-20250327203442486.png" alt="image-20250327203442486" style="zoom:80%;" />
<img src="09.docker%E4%BB%93%E5%BA%93%E7%AE%A1%E7%90%86/image-20250327203501846.png" alt="image-20250327203501846" style="zoom:80%;" />
## 推送镜像
一、创建项目
![image-20250327203600071](09.docker%E4%BB%93%E5%BA%93%E7%AE%A1%E7%90%86/image-20250327203600071.png)
二、docker 登录仓库
- 登录后推送镜像
```bash
[root@localhost ~]# cat /etc/docker/daemon.json
{
"registry-mirrors": ["http://192.168.88.10:80/"],
"insecure-registries": ["192.168.88.10:80"]
}
[root@localhost ~]# systemctl restart docker
# 私有仓库需要在此登录
[root@localhost ~]# docker login 192.168.88.10
Username: admin
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
```
- 打标签推送镜像
```bash
[root@localhost harbor]# docker tag centos:7 192.168.88.10/eagleslab/centos:9
[root@localhost harbor]# docker push 192.168.88.10/eagleslab/centos:9
The push refers to repository [192.168.173.136/eagleslab/centos]
74ddd0ec08fa: Pushed
9: digest: sha256:a1801b843b1bfaf77c501e7a6d3f709401a1e0c83863037fa3aab063a7fdb9dc size: 529
```
![image-20220922115258105](09.docker%E4%BB%93%E5%BA%93%E7%AE%A1%E7%90%86/image-20220922115258105.png)

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

View File

@@ -1,8 +0,0 @@
# Docker是什么
Docker 是一个用于开发、发布和运行应用程序的开放平台。Docker 可让将应用程序与基础架构分离,以便快速交付软件。借助 Docker可以像管理应用程序一样管理基础架构。通过利用 Docker 的发布、测试和部署代码方法,可以显著减少编写代码和在生产中运行代码之间的延迟。
[Docker官方文档](https://docs.docker.com/)
[Docker项目地址](https://github.com/docker)

View File

@@ -1,69 +0,0 @@
# Docker平台
Docker 提供了在松散隔离的环境中打包和运行应用程序的功能,该环境称为容器。隔离和安全性可以在给定主机上同时运行多个容器。容器是轻量级的,包含运行应用程序所需的一切,因此无需依赖主机上安装的内容。可以在工作时共享容器,并确保与共享的每个人都能获得以相同方式工作的相同容器。
Docker 提供工具和平台来管理容器的生命周期:
- 使用容器开发应用程序及其支持组件。
- 容器成为分发和测试应用程序的单元。
- 应用程序作为容器或编排服务部署到生产环境(本地数据中心、云提供商等等)。
# Docker使用场景
## 快速、一致地交付应用程序
Docker 允许开发人员使用提供应用程序和服务的本地容器在标准化环境中工作,从而简化了开发生命周期。容器非常适合持续集成和持续交付 (CI/CD) 工作流程。
**示例场景:**
- 开发人员本地编写代码并使用 Docker 容器与同事共享他们的工作。
- 使用 Docker 将应用程序推送到测试环境并运行自动和手动测试。
- 发现错误时,可以在开发环境中修复它们,并将其重新部署到测试环境中进行测试验证。
- 测试验证完成后,将修复后代码构建成镜像并更新至生产环境并部署容器运行。
## 响应式部署和扩展
Docker 基于容器的平台是高度可移植的。Docker 容器可以在开发人员的本地笔记本电脑、数据中心的物理机或虚拟机、云提供商或混合环境中运行。
Docker 的可移植性和轻量级特性还使其能够轻松地动态管理,根据业务需求近乎实时地扩大或拆除应用程序和服务。
## 在相同硬件上运行更多应用
Docker 轻量且快速。它为基于虚拟机的服务程序管理提供了一种可行且经济高效的替代方案因此可以使用更多的服务器容量来实现业务目标。Docker 非常适合高密度环境以及需要使用更少资源完成更多任务的中小型部署。
# Docker架构
Docker 使用客户端-服务器架构。Docker 客户端与 Docker 守护程序通信,后者负责构建、运行和分发 Docker 容器的繁重工作。Docker 客户端和守护程序可以在同一系统上运行,或者可以将 Docker 客户端连接到远程 Docker 守护程序。Docker 客户端和守护程序使用 REST API、通过 UNIX 套接字或网络接口进行通信。另一个 Docker 客户端是 Docker Compose可以管理由一组容器组成的应用程序。
![Docker架构](docker介绍与安装/docker架构图.png)
## Docker Host
Docker Host是一款易于安装的应用程序适用于 Mac、Windows 或 Linux 环境可让构建和共享容器化应用程序和微服务。Docker Host 包括 Docker 守护程序 ( `dockerd` )、Docker 客户端 ( docker )、Docker Compose、Docker Content Trust、Kubernetes 和 Credential Helper。
## Docker Daemon
Docker 守护程序 ( `dockerd` ) 监听 Docker API 请求并管理 Docker 对象例如images、containers、networks和volumes。守护程序还可以与其他守护程序通信以管理 Docker 服务。
## Docker Client
Docker 客户端 ( `docker` ) 是许多 Docker 用户与 Docker 交互的主要方式。当使用诸如 `docker run` 类的命令时,客户端会将这些命令发送到 `dockerd` ,后者会执行这些命令。`docker` 命令使用 Docker API。Docker 客户端可以与多个守护程序进行通信。
## Docker Registry
Docker 镜像仓库是存储 Docker 镜像。Docker Hub 是个公共镜像仓库Docker 默认会在 Docker Hub 上查找镜像。也可以运行自己的私有镜像仓库。
当使用 `docker pull``docker run` 命令时Docker 会从配置的镜像仓库地址中拉取所需的镜像。当使用 `docker push` 命令时Docker 会将镜像推送到配置的镜像仓库。
## Docker Objects
**Images**
镜像是创建 Docker 容器的模版。通常可以基于其他镜像进行二次构建。例如,已经有 `ubuntu` 镜像,但我们还要安装 Apache Web服务 + 应用 + 自定义配置。
基于别人发布在镜像仓库中的镜像,编写 Dockerfile 构建自己的镜像。Dockerfile 中的每条指令都会在镜像中创建一个层。更改 Dockerfile 并重建镜像时,只会重建已更改的层。这正是与虚拟化技术相比,镜像如此轻量、小巧和快速的原因之一。
**Containers**
容器是镜像的运行实例。可以使用 Docker API 或 CLI 创建、启动、停止、移动或删除容器。可以将容器连接到一个或多个网络、附加存储,甚至根据其当前状态创建新镜像。
容器由其镜像和创建或启动容器时提供的任何配置选项定义。当容器被删除时,未持久化存储的更改都会消失。

View File

@@ -1,90 +0,0 @@
# 公共仓库
## 官方Docker仓库
1. 准备账户: 登陆到[Docker Hub](https://hub.docker.com/)官网创建账号登陆后点击settings完善信息。
2. 填写账户基本信息: 重置密码/生成`accesstoken`
3. `docker login docker.io` 输入用户密码即可
4. 国内可能因为网络问题,需要代理
## 阿里云镜像仓库
1. 准备账户: 登录到[Aliyun Hub](https://cr.console.aliyun.com/)官网创建账号
2. 容器镜像服务->实例列表->镜像仓库->创建镜像仓库
3. 执行操作指南
```shell
# 1.登录阿里云Docker Registry
$ docker login --username=15295733404 registry.cn-hangzhou.aliyuncs.com
# 2.从Registry中拉取镜像
$ docker pull registry.cn-hangzhou.aliyuncs.com/zhaohao/eagleslab:[镜像版本号]
# 3.将镜像推送到Registry
$ docker login --username=15295733404 registry.cn-hangzhou.aliyuncs.com
$ docker tag [ImageId] registry.cn-hangzhou.aliyuncs.com/zhaohao/eagleslab:[镜像版本号]
$ docker push registry.cn-hangzhou.aliyuncs.com/zhaohao/eagleslab:[镜像版本号]
# 4.选择合适的镜像仓库地址: 公网访问/VPC网络内访问
```
# 私有仓库
## docker registry
Docker Register作为Docker的核心组件之一负责镜像内容的存储与分发客户端的docker pull以及push命令都将直接与register进行交互最初版本的registry由python实现的由于涉及初期在安全性、性能以及API的设计上有着诸多的缺陷该版本在0.9之后停止了开发由新的项目distribution新的docker register被称为Distribution来重新设计并开发了下一代的registry新的项目由go语言开发所有的api底层存储方式系统架构都进行了全面的重新设计已解决上一代registry的问题。
官方文档地址https://docs.docker.com/registry
官方github地址: https://github.com/docker/distribution
**部署**
```shell
# 执行安装脚本
[root@master01 scripts]# ./install/install_registry.sh
```
## 企业级方案Harbor
参考网址https://goharbor.io/docs/2.3.0/install-config/
Harbor是一个用于存储和分发Docker镜像的企业级Registry服务器由vmware开源其通过添加一些企业必须的功能特性例如安全、标识和管理等扩展了开源的Docker Distribution。Harbor也提供了高级的安全特性诸如用户管理访问控制和活动审计等。
**部署**
```bash
# 1.准备安装包
[root@docker-server1 ~]# wget https://github.com/goharbor/harbor/releases/download/v2.3.1/harbor-offline-installer-v2.3.1.tgz
[root@docker-server1 ~]# tar xzvf harbor-offline-installer-v2.3.1.tgz
[root@docker-server1 ~]# ln -sv /root/harbor /usr/local/
"/usr/local/harbor" -> "/root/harbor"
# 2.配置文件
[root@docker-server1 harbor]# cp harbor.yml.tmpl harbor.yml
[root@docker-server1 harbor]# grep -Ev '#|^$' harbor.yml.tmpl > harbor.yml
[root@docker-server1 harbor]# cat harbor.yml
# 3.执行安装
[root@docker-server1 harbor]# ./prepare
[root@docker-server1 harbor]# ./install.sh
# 之后的启动关闭可以通过docker-compose管理自动生成docker-compose.yml文件
[root@docker-server1 harbor]# ls
common docker-compose.yml harbor.yml install.sh prepare
common.sh harbor.v2.3.1.tar.gz harbor.yml.tmpl LICENSE
```
**web访问**
默认用户名和密码在harbor.yml中设置为harbor_admin_password: Harbor12345
**推送镜像**
参考网站推送教学
```bash
# 登录
[root@docker-server2 ~]# grep 'insecure' /etc/docker/daemon.json
"insecure-registries":["192.168.175.10"]
[root@docker-server2 ~]# systemctl daemon-reload & systemctl restart docker
[root@docker-server2 ~]# docker login 192.168.204.135
Username: admin
Password:
...
Login Succeeded
[root@admin harbor]# docker-compose restart
# 推送
[root@docker-server2 nginx]# docker tag nginx:v1 192.168.175.10/eagles/nginx:v1
[root@docker-server2 nginx]# docker push 192.168.175.10/eagles/nginx:v1
```

View File

@@ -1,90 +0,0 @@
# 存储引擎
Docker 存储引擎是 Docker 容器管理文件系统的核心组件负责镜像层与容器层的组织、读写操作及资源隔离。其核心在于通过联合文件系统UnionFS写时复制Copy-on-Write, CoW机制实现高效存储管理。
## 分层存储与联合挂载
Docker镜像由多个只读层Layer叠加而成容器运行时会在镜像层之上创建可写层。所有层通过 UnionFS 联合挂载到同一视图,上层文件覆盖下层同名文件,但底层数据保持不变。
UnionFS联合文件系统是一种分层、轻量级且高性能的文件系统技术通过将多个目录分支联合挂载到同一目标目录形成统一的文件系统视图。核心机制如下:
- **分层存储**UnionFS 通过分层结构管理文件,每个层(分支)可以是只读或可写。不同层中相同路径的文件会被上层覆盖,但底层内容保持不变。
- **只读层和可写层**:只读层​​通常为基础镜像或依赖文件,不可修改;可写层​​:容器运行时新增的层,所有修改均在此层记录。
## 写时复制CoW机制
当容器需要修改文件时,存储引擎将文件从底层只读层复制到可写层进行修改,而非直接修改原始数据。这种机制减少冗余存储,允许多容器共享同一镜像层,显著降低磁盘占用。
## 工作原理
- **联合挂载Unio Mount**将多个物理目录如目录A和B挂载到同一虚拟目录如目录C合并后的视图包含所有分支目录的内容。若存在同名文件优先显示上层文件。
- **访问优先级**用户访问文件时UnionFS按层从上至下搜索返回第一个匹配的文件。例如可写层优先级高于只读层。
- **数据隔离与共享**:不同容器共享同一基础镜像层,但各自的可写层独立,实现资源复用与运行时隔离。
# 主流存储引擎
Docker支持多种存储驱动不同驱动在性能、稳定性、适用场景上存在差异
| 存储驱动 | 特点 | 优势 | 局限性 | 适用场景 |
|---------|------|------|--------|----------|
| OverlayFS | • Linux内核原生支持≥3.18<br>• 使用overlay2驱动<br>• 仅需一个只读层和一个可写层<br>• 结构简单且性能优异 | • 启动速度快<br>• 适合生产环境<br>• 支持高效的文件系统层叠<br>• 节省存储空间 | • 层数限制通常≤127层<br>• 频繁小文件写入可能增加I/O开销 | • 通用容器环境<br>• 需要高性能的生产系统<br>• 对存储空间敏感的场景 |
| AUFS | • 通过多层联合挂载实现CoW<br>• 稳定性较好<br>• 未集成到内核,需额外安装 | • 内存利用率高<br>• 适合旧版Linux系统 | • 高并发写入性能较差<br>• 逐渐被OverlayFS替代 | • 旧版Linux系统<br>• 对内存资源敏感的环境<br>• 低并发写入场景 |
| Device Mapper | • 基于块设备映射<br>• 使用"thin pool"技术<br>• 支持动态扩容 | • 支持精细的存储控制<br>• 适合块级存储需求<br>• 动态扩容能力强 | • 配置复杂<br>• 需预分配存储池<br>• 可能导致空间浪费 | • 数据库容器<br>• 需要精细存储控制的场景<br>• 大规模存储系统 |
| Btrfs/ZFS | • 支持高级功能(快照/去重/压缩)<br>• 文件系统级别的功能丰富 | • Btrfs写入密集型场景表现优异<br>• ZFS提供数据完整性校验<br>• 支持高效压缩 | • 对系统内核版本依赖性强<br>• 稳定性与兼容性需验证 | • 需要数据快照功能<br>• 写入密集型应用<br>• 对数据完整性要求高的场景 |
# Overlay2
## 工作原理
Docker 默认存储驱动。通过以下三个主要目录来管理文件系统:
- **`LowerDir`**:只读层,包含基础镜像的文件系统。可以有多个只读层,每层都是独立的。
- **`UpperDir`**:读写层,用于存储容器运行时的文件系统变更(即 diff 层)。
- **`MergedDir`**:联合挂载后的视图,容器看到的完整文件系统。它将 `LowerDir``UpperDir` 合并为一个统一的文件系统视图。
- **`WorkDir`**是系统内部使用的临时目录用于处理写时复制CoW和元数据操作。其内容在挂载时会被清空且运行时不可见一般不要动。
当启动一个容器时Overlay2 会将镜像层(`LowerDir`)和容器层(`UpperDir`)联合挂载到 `MergedDir`,容器通过这个目录看到完整的文件系统。
## 实践案例1
通过 Overlay2 挂载目录,理解镜像层与容器层的交互逻辑。
```shell
# 1.目录结构 & 文件
mkdir -p /mnt/overlay2/{lower,upper,work,merged}
echo "基础文件内容" > /mnt/overlay2/lower/base.txt
echo "初始配置" > /mnt/overlay2/lower/config.yaml
# 2.挂载Overlay2
mount -t overlay overlay \
-o lowerdir=/mnt/overlay2/lower,upperdir=/mnt/overlay2/upper,workdir=/mnt/overlay2/work \
/mnt/overlay2/merged
# 3.模拟容器操作
echo "容器修改内容" > /mnt/overlay2/merged/base.txt
## CoW机制生效
[root@master01 ~]# cat /mnt/overlay2/upper/base.txt
容器修改内容
[root@master01 ~]# cat /mnt/overlay2/lower/base.txt
基础文件内容
## 文件名 #40b 是 OverlayFS 在处理文件操作时生成的临时标识符,用于跟踪操作状态
rm /mnt/overlay2/merged/config.yaml
# 卸载并清理
umount /mnt/overlay2/merged
rm -rf /mnt/overlay2/*
```
## 实践案例2
验证运行容器的存储结构,并能快速定位。
```shell
# LowerDir、MergedDir、UpperDir、WorkDir
[root@master01 ~]# docker inspect 379c14648fbb
[root@master01 ~]# docker exec -it 3eb8f9c95ab4 touch /root/1.txt
[root@master01 ~]# ls /var/lib/docker/overlay2/869a09f00704dbbb396d8be90d52b73870073c0a294deceac24a69afbe1a4310/diff/root/
1.txt
```
# 扩展阅读
存储引擎文档:
https://docs.docker.com/storage/storagedriver/select-storage-driver/
存储引擎血案:
https://www.cnblogs.com/youruncloud/p/5736718.html

View File

@@ -1,127 +0,0 @@
# Docker服务端软件选择
Docker CECommunity Edition社区版和 Docker EEEnterprise Edition企业版是 Docker 产品的两个主要版本,它们之间的主要区别在于目标用户、功能集、支持和维护等方面:
| 对比项 | Docker CE | Docker EE |
|--------|-----------|------------|
| **目标用户** | 面向个人开发者、小团队以及技术爱好者,主要用于开发和测试环境 | 面向大型企业和组织,提供企业级的功能和支持 |
| **功能集** | 提供基本的容器化功能,包括构建、运行和共享容器 | 除了包含 CE 版本的所有功能外,还提供了额外的企业级特性,如增强的安全、管理、可扩展性和集成性 |
| **支持和维护** | 社区支持,适合自我解决问题的开发者 | 提供商业支持和专业服务,适合需要稳定运行环境的企业 |
| **安全性** | 安全性相对较低,适合非生产环境 | 提供更高级的安全特性,如镜像扫描、安全策略和合规性报告 |
| **管理** | 通常不需要复杂的管理工具 | 提供 Docker Universal Control Plane (UCP) 和 Docker Trusted Registry (DTR) 等管理工具,帮助企业更有效地管理容器环境 |
| **成本** | 免费 | 需要购买许可证 |
| **更新和生命周期** | 更新频繁,可能包含实验性功能,生命周期较短 | 更新周期更稳定,更注重稳定性和兼容性,生命周期较长 |
# Docker快速安装
```shell
rm -f /etc/yum.repos.d/docker-ce.repo
wget -O /etc/yum.repos.d/docker-ce.repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
yum makecache
yum install -y docker-ce docker-ce-cli containerd.io --allowerasing
systemctl enable --now docker
```
# Docker快速使用
```shell
# 拉取镜像
[root@docker-server ~]# docker pull nginx
# 启动容器
[root@docker-server ~]# docker run --name nginx_container_test -d -p 8080:80 nginx
# 进入容器
[root@docker-server ~]# docker exec -it nginx_container_test bash
echo 'docker nginx test' > /usr/share/nginx/html/index.html
curl 192.168.88.10:8080
# 查看容器
[root@docker-server ~]# docker ps
# 停止容器
[root@docker-server ~]# docker stop nginx_container_test
```
# Docker信息
```bash
[root@docker-server ~]# docker info
```
| 配置项 | 说明 |
| :---| :---|
| **容器状态信息** ||
| Containers | 系统中所有容器的总数。包括运行中、已暂停和已停止的容器,用于整体容器资源评估 |
| Running | 当前正在运行的容器数量。这些容器正常运行并提供服务,是系统负载的主要来源 |
| Paused | 已暂停运行的容器数量。这些容器状态被临时冻结,通常用于调试或资源回收 |
| Stopped | 已停止运行的容器数量。这些容器可能是任务完成或异常停止,需要定期清理 |
| **系统基础信息** ||
| Images | 本地已下载的Docker镜像总数。包括基础镜像、中间镜像和应用镜像影响存储空间使用 |
| Server Version | Docker引擎版本号。决定了可用特性和兼容性建议在生产环境保持版本统一 |
| **存储相关配置** ||
| Storage Driver | 容器存储驱动类型如overlay2、devicemapper。影响容器I/O性能推荐使用overlay2 |
| Backing Filesystem | 底层文件系统类型如ext4、xfs。影响存储性能和可靠性生产环境推荐使用xfs |
| Supports d_type | 文件系统d_type支持状态。对overlay2驱动至关重要确保启用以获得最佳性能 |
| Native Overlay Diff | 原生Overlay差异存储支持。优化镜像层存储效率减少磁盘空间占用 |
| **日志与资源管理** ||
| Logging Driver | 容器日志收集驱动如json-file、syslog。影响日志管理和问题排查能力 |
| Cgroup Driver | 容器资源限制驱动systemd/cgroupfs。建议与系统init保持一致避免资源管理冲突 |
| **功能组件信息** ||
| Plugins | Docker插件列表。包括存储、网络等扩展功能按需启用以增强系统能力 |
| Volume | 数据卷插件配置。用于持久化存储和容器间数据共享,确保数据可靠性 |
| Network | 网络驱动类型。支持bridge、host、overlay等模式根据应用场景选择 |
| **运行时与安全** ||
| Default Runtime | 默认容器运行时通常为runc。可选择其他OCI兼容运行时以满足特定需求 |
| Security Options | 安全特性配置。包括AppArmor、SELinux等建议在生产环境中启用以增强安全性 |
| **系统资源信息** ||
| Kernel Version | 内核版本信息。影响Docker功能和性能建议使用推荐的内核版本 |
| Operating System | 操作系统信息。包括发行版和版本号,影响兼容性和可用特性 |
| Architecture | CPU架构类型。如x86_64、arm64决定可用的容器镜像类型 |
| CPUs | 可用CPU核心数。影响容器并发能力建议预留部分资源给系统使用 |
| Total Memory | 系统总内存。决定可分配给容器的最大内存,建议合理规划以避免资源竞争 |
| **其他配置** ||
| Docker Root Dir | Docker运行时根目录。存储容器和镜像数据建议使用单独分区 |
| Registry | 默认镜像仓库地址。用于拉取和推送镜像,可配置私有仓库加速访问 |
| Experimental | 实验特性状态。包含未稳定功能,生产环境谨慎启用 |
| Live Restore Enabled | 是否启用容器存活恢复功能允许在Docker守护进程重启时保持容器运行|
# 标准化组织OCI
容器技术是一种轻量级的虚拟化技术,用于隔离应用程序及其依赖项,使其能够在不同的环境中一致地运行。除了 Docker 之外,还有其他多种容器运行时和工具,例如 CoreOS 的 rkt、阿里的 Pouch 和红帽的 Podman。为了确保容器生态系统的标准性和可持续发展Linux 基金会、Docker、微软、红帽、谷歌和 IBM 等公司在 2015 年 6 月共同成立了 **Open Container Initiative (OCI)** 组织。
## OCI目标
OCI 的主要目标是制定开放的容器规范以确保不同容器技术之间的可移植性和互操作性。目前OCI 已经发布了两个核心规范:
1. **Runtime Spec**:定义了容器运行时的规范,包括容器的生命周期管理、资源隔离和安全等。
2. **Image Format Spec**:定义了容器镜像的格式和元数据,确保镜像可以在不同的容器运行时之间共享和运行。
通过遵循这些规范,不同的容器运行时和工具可以实现互操作性,从而推动容器技术的标准化和健康发展。
## 容器运行时
容器运行时是真正运行容器的地方,它需要与操作系统的内核紧密合作,为容器提供隔离的运行环境。以下是目前主流的三种容器运行时:
**1. LXC (Linux Containers)**
- **简介**LXC 是 Linux 上早期的容器运行时,它利用 Linux 内核的 Namespace 和 Cgroups 技术来实现进程隔离和资源管理。
- **特点**
- 提供了完整的 Linux 系统环境,支持多种 Linux 发行版。
- 早期 Docker 也曾使用 LXC 作为其默认的运行时。
- **适用场景**:适用于需要完整 Linux 系统环境的容器化应用。
**2. Runc**
- **简介**Runc 是目前 Docker 默认的容器运行时,它是一个轻量级的命令行工具,用于运行和管理容器。
- **特点**
- 完全遵循 OCI 的 Runtime Spec 规范,确保与 OCI 标准的兼容性。
- 由于其轻量级和高性能的特点Runc 已经成为许多容器运行时的底层实现。
- **适用场景**:适用于需要高性能和轻量级容器运行环境的场景。
**3. Rkt (Rocket)**
- **简介**Rkt 是由 CoreOS 开发的容器运行时,旨在提供一个安全、可靠且符合 OCI 规范的容器运行环境。
- **特点**
- 与 Docker 不同Rkt 本身是一个独立的容器运行时,不依赖 Docker 的守护进程。
- 提供了更好的安全性和隔离性,例如通过 AppArmor 和 SELinux 等安全机制。
- **适用场景**:适用于对安全性要求较高的容器化应用。
容器技术的发展离不开标准化的推动。OCI 通过制定 Runtime Spec 和 Image Format Spec为容器运行时和工具提供了统一的标准确保了不同容器技术之间的互操作性和可移植性。目前主流的容器运行时如 LXC、Runc 和 Rkt都遵循这些规范从而推动了容器技术的广泛应用和发展。

View File

@@ -1,169 +0,0 @@
# 容器
## 使用场景
开发一个杀手级的 Web 应用它包含三个主要组件React 前端、Python API 和 MySQL 数据库。如果你想开发这个项目,你必须安装 Node、Python 和 MySQL。
- **如何确保团队中开发人员使用的Python版本一致**
- **如何确保应用运行所需的版本不和现有生产环境版本冲突?**
什么是容器独立进程。React 前端、Python API、MySQL 都在独立的环境中运行,并与其他组件完全隔离。
## 容器和虚拟机
![img](01.docker介绍与安装/容器与虚拟机对比.png)
| **虚拟化** | **容器** |
| ------------------------------------------------ | ------------------------------------------------------- |
| 隔离性强有独立的GUEST OS | 共享内核和OS隔离性弱! |
| 虚拟化性能差(>15%) | 计算/存储无损耗无Guest OS内存开销(~200M) |
| 虚拟机镜像庞大(十几G~几十G), 且实例化时不能共享 | Docker容器镜象200~300M且公共基础镜象实例化时可以共享 |
| 虚拟机镜象缺乏统一标准 | Docker提供了容器应用镜象事实标准OCI推动进一 步标准化 |
| 虚拟机创建慢(>2分钟) | 秒级创建(<10s)相当于建立索引 |
| 虚拟机启动慢(>30s) 读文件逐个加载 | 秒级(<1s,不含应用本身启动) |
| 资源虚拟化粒度低单机10~100虚拟机 | 单机支持1000+容器密度很高适合大规模的部署 |
**对比总结**
- **资源利用率更高**一台物理机可以运行数百个容器但一般只能运行数十个虚拟机
- **开销更小**不需要启动单独的虚拟机占用硬件资源
- **启动速度更快**可以在数秒内完成启动
# 容器管理
## 创建容器
`Usage: docker create [OPTIONS] IMAGE [COMMAND] [ARG...]`
```shell
[root@docker-server ~]# docker create -it --name nginx-test nginx bash
```
## 启动容器
`Usage: docker start [OPTIONS] CONTAINER [CONTAINER...]`
```shell
[root@docker-server ~]# docker start nginx
```
## 重启容器
`Usage: docker restart [OPTIONS] CONTAINER [CONTAINER...]`
```shell
[root@docker-server ~]# docker restart nginx
```
## 停止容器
`Usage: docker stop [OPTIONS] CONTAINER [CONTAINER...]`
```shell
[root@docker-server ~]# docker stop nginx
```
## 列出容器
`Usage: docker ps [OPTIONS]`
```shell
[root@docker-server ~]# docker ps -a
```
## 运行容器
`Usage: docker run [OPTIONS] IMAGE [COMMAND] [ARG...]`
```shell
# 等同于 create + start
[root@docker-server ~]# docker run -it centos:latest bash
# 指定DNS
[root@docker-server ~]# docker run -it --rm --dns 8.8.8.8 centos bash
# 端口映射
## 前台启动随机映射端口
[root@docker-server ~]# docker run -P nginx
## 方式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
## 查看容器已经映射的端口
[root@docker-server ~]# docker port nginx-1
# 传递运行命令
[root@docker-server ~]# docker run -it centos:latest /bin/bash
[root@docker-server ~]# docker run -it centos:latest cat /etc/hosts
# 单次运行,容器退出后自动删除
[root@docker-server ~]# docker run --name hello_world_test --rm hello-world
# 后台运行
[root@docker-server ~]# docker run -d -P --name nginx-2 nginx
```
**参数说明:**
| 选项 | 说明 |
|:---|:---|
| -d | 以守护进程方式在后台运行容器默认为否适用于运行需要持续在线的服务 |
| -i | 保持标准输入打开即使未连接也保持STDIN打开常与-t一起使用 |
| -P | 通过NAT机制将容器标记暴露的端口自动映射到主机的随机临时端口 |
| -p | 手动指定容器端口映射格式主机(宿主)端口:容器端口 |
| -t | 分配一个伪终端pseudo-TTY通常与-i配合使用以提供交互式shell |
| -v | 挂载主机上的文件卷到容器内格式主机目录:容器目录[:权限] |
| --rm | 容器退出后自动删除容器不能与-d同时使用适用于临时测试场景 |
| -e | 设置容器内的环境变量格式-e 变量名=变量值 |
| -h | 指定容器的主机名便于容器间通过主机名访问 |
| --name | 指定容器的别名方便管理和访问容器 |
| --cpu-shares | 设置容器使用CPU的相对权重默认1024数值越高优先级越高 |
| --cpuset-cpus | 限制容器使用特定的CPU核心0-3使用前4个核心或0,2使用第13核心 |
| -m | 限制容器可使用的最大内存量支持的单位bkmg-m 512m
## 挂起/恢复容器
`Usage: docker pause CONTAINER [CONTAINER...]`
```shell
[root@docker-server ~]# docker pause nginx-2
```
`Usage: docker unpause CONTAINER [CONTAINER...]`
```shell
[root@docker-server ~]# docker unpause nginx-2
```
## 进入容器
`Usage: docker exec [OPTIONS] CONTAINER`
```shell
[root@docker-server ~]# docker exec -it nginx-2 bash
# attach不推荐: 所有使用此方式进入容器的操作都是同步显示的且exit容器将被关闭且使用exit退出后容器关闭
[root@docker-server ~]# docker attach nginx-2
# nsenter: 通过pid进入到容器内部不过可以使用docker inspect获取到容器的pid
[root@docker-server ~]# nsenter -t $(docker inspect -f "[.State.Pid]" nginx-2) -m -u -i -n -p
```
## 导入/导出容器
`Usage: docker export [OPTIONS] CONTAINER`
```shell
[root@docker-server ~]# docker export -o /opt/nginx.tar nginx-2
```
`Usage: docker import [OPTIONS] file|URL|- [REPOSITORY[:TAG]]`
```shell
[root@docker-server ~]# docker import /opt/nginx.tar nginx:v50
```
**适用场景:** 主要用来制作基础镜像比如从一个ubuntu镜像启动一个容器然后安装一些软件和进行一些设置后使用docker export保存为一个基础镜像然后把这个镜像分发给其他人使用作为基础的开发环境。(因为export导出的镜像只会保留从镜像运行到export之间对文件系统的修改所以只适合做基础镜像)
## 查看容器日志
`Usage: docker logs [OPTIONS] CONTAINER`
```shell
[root@docker-server ~]# docker logs nginx-2
```
## 删除容器
`Usage: docker rm [OPTIONS] CONTAINER [CONTAINER...]`
```shell
[root@docker-server ~]# docker rm -f nginx-2
```

View File

@@ -1,91 +0,0 @@
# 存储
## 介绍
默认情况下,容器内创建的所有文件都存储在可写的容器层上,该层位于只读、不可变的图像层之上。
写入容器层的数据在容器销毁后不会保留。这意味着,如果其他进程需要这些数据,则很难将其从容器中取出。
每个容器的可写层都是唯一的。无法将数据从可写层提取到主机或其他容器。
## 存储挂载选项
| 挂载类型 | 说明 | 使用场景 | 特点 |
|:---------|:-----|:---------|:-----|
| Volume Mounts | Docker管理的持久化数据卷存储在/var/lib/docker/volumes/目录下 | 数据库存储、应用数据持久化 | 独立于容器生命周期、可在容器间共享、支持数据备份和迁移 |
| Bind Mounts | 将宿主机目录或文件直接挂载到容器内 | 开发环境代码热更新、配置文件挂载 | 方便直接操作文件、依赖宿主机文件系统、适合开发调试 |
| Tmpfs Mounts | 将数据临时存储在宿主机内存中 | 敏感数据存储、临时文件存储 | 高性能、数据易失性、增加内存占用 |
| Named Pipes | 在容器间建立命名管道进行通信 | 容器间进程通信、数据流传输 | 低延迟、进程间通信、适合流式数据传输 |
# Volume mounts
## 管理操作
`Usage: docker volume create [OPTIONS] [VOLUME]`
`Usage: docker volume ls [OPTIONS]`
`Usage: docker volume inspect [OPTIONS] VOLUME [VOLUME...]`
`Usage: docker volume rm [OPTIONS] VOLUME [VOLUME...]`
`Usage: docker volume prune [OPTIONS]`
```shell
```
## 使用卷启动容器
如果使用不存在的卷启动容器Docker 会为创建该卷。
`Usage: docker run --mount type=volume[,src=<volume-name>],dst=<mount-path>[,<key>=<value>...]`
| 参数 | 说明 | 使用示例 | 最佳实践 |
|:---------|:-----|:---------|:---------|
| source, src | 卷的名称,用于指定要挂载的数据卷 | `src=myvolume` | 使用有意义的名称便于识别和管理 |
| target, dst | 容器内的挂载路径,指定数据卷挂载到容器内的位置 | `dst=/data/app` | 遵循容器内标准目录结构 |
| type | 卷的类型可选值volume、bind、tmpfs默认为volume | `type=volume` | 根据数据持久化需求选择合适类型 |
| readonly, ro | 只读挂载标志,设置后容器内无法修改挂载内容 | `ro=true` | 对配置文件等静态内容建议只读挂载 |
| volume-subpath | 卷的子路径,只挂载数据卷中的指定子目录 | `volume-subpath=/config` | 用于精确控制挂载范围,提高安全性 |
| volume-opt | 卷的额外选项,用于指定卷的特定行为 | `volume-opt=size=10G` | 根据实际需求配置,避免过度使用 |
| volume-nocopy | 创建卷时不从容器复制数据 | `volume-nocopy=true` | 用于避免不必要的数据复制,提高性能 |
```shell
docker run -d --name devtest --mount source=myvol2,target=/app nginx:latest
```
`Usage: docker run -v [<volume-name>:]<mount-path>[:opts]`
```shell
docker run -d --name devtest -v myvol2:/app nginx:latest
```
## 实践案例
**需求**运行MySQL容器并支持久化存储进行一次数据备份数据恢复测试验证。
```shell
```
# Bind mounts
使用绑定挂载时,主机上的文件或目录将从主机挂载到容器中。
如果将目录绑定挂载到容器上的非空目录中,则目录的现有内容被绑定挂载隐藏。
## 使用绑定挂载启动容器
```shell
Usage:
docker run --mount type=bind,src=<host-path>,dst=<container-path>[,<key>=<value>...]
docker run -v <host-path>:<container-path>[:opts]
```
| 参数 | 说明 | 使用场景 | 最佳实践 |
|:---------|:-----|:---------|:---------|
| readonly, ro | 将挂载点设置为只读模式,容器内无法修改挂载的内容 | 配置文件、静态资源文件挂载 | 对于不需要容器内修改的内容,建议使用只读模式增加安全性 |
| rprivate | 使挂载点的挂载事件不会传播到其他挂载点 | 默认的挂载传播模式 | 适用于大多数场景,确保挂载隔离性 |
| rshared | 使挂载点的挂载事件双向传播 | 需要在多个挂载点间共享挂载事件的场景 | 谨慎使用,可能影响容器隔离性 |
| rslave | 使挂载点的挂载事件单向传播(从主机到容器) | 需要容器感知主机挂载变化的场景 | 在特定场景下使用,如动态存储管理 |
| rbind | 递归绑定挂载,包含所有子目录 | 需要完整复制目录结构的场景 | 确保目录结构完整性,但注意性能开销 |
## 实践案例
**需求**启动Nginx容器并挂载宿主机nginx配置文件和主页目录容器内无权限修改相关内容测试验证。
```shell
```
# 扩展阅读
tmpfs mounts: https://docs.docker.com/engine/storage/tmpfs/
volumes plugins: https://docs.docker.com/engine/extend/legacy_plugins/

View File

@@ -1,69 +0,0 @@
# 网络
容器网络是指容器能够连接和通信的能力,无论是容器之间还是与外部。
# 用户自定义网络
可以创建自定义的用户定义网络,并将多个容器连接到同一网络。一旦连接到用户定义的网络,容器可以使用容器 IP 地址或容器名称相互通信。
`Usage: docker network create [OPTIONS] NETWORK`
```shell
# 使用bridge网络驱动创建网络并启动容器
docker network create -d bridge my-net
docker run --network=my-net -itd --name=container1 busybox
docker run --network=my-net -itd --name=container2 busybox
# 测试网络连接
[root@master01 ~]# docker exec -it container1 ping www.baidu.com
[root@master01 ~]# docker exec -it container1 cat /etc/hosts | grep 172
172.19.0.3 1adf81f08c86
[root@master01 ~]# docker exec -it container1 ping container2
```
# 网络驱动
Docker服务安装完成之后默认在每个宿主机会生成一个名称为docker0的网卡其ip地址都是172.17.0.1/16并且会生成三种不同类型的网络。
```shell
[root@master01 ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
fe2c2cabeff7 bridge bridge local
459b4a9926ed host host local
526baa2eb8f6 none null local
```
| Docker网络模式 | 配置 | 说明 | 使用场景 |
|--------------|------|------|----------------|
| host模式 | --net=host | 容器和宿主机共享Network namespace直接使用宿主机网络栈。容器不会获得独立的Network namespace也不会配置独立的IP和端口。性能开销最小但缺少网络隔离。 | 适用于对网络性能要求极高的场景,如高性能计算、流媒体服务等
| container模式 | --net=container:NAME_or_ID | 容器和指定的容器共享Network namespace。新容器使用已存在容器的网络栈共享IP地址和端口范围。保持了其他资源如文件系统、进程等的隔离。 | 最典型应用是Kubernetes的Pod实现
| none模式 | --net=none | 容器拥有独立的Network namespace但不做任何网络配置。容器没有网卡、IP、路由等网络配置需要手动配置网络。 | 适用于对安全性要求极高的场景
| bridge模式 | --net=bridge | 默认网络模式。Docker daemon创建docker0虚拟网桥通过veth pair连接容器实现容器间的通信。支持端口映射和地址转换提供基本的网络隔离。 | 最常用的网络模式
# 工作原理
## none网络类型
![img](docker网络管理/None网络类型.png)
## container网络类型
![img](docker网络管理/Container网络类型.png)
## host网络类型
![img](docker网络管理/Host网络类型.png)
## bridge网络类型
![img](docker网络管理/Bridge网络类型.png)
**veth pair 对应关系**
```shell
[root@master01 ~]# ip link show | grep veth0f | awk '{print $1,$2}'
40: veth0fbbd68@if39
[root@master01 ~]# cat /sys/class/net/veth0fbbd68/ifindex
40
[root@master01 ~]# cat /sys/class/net/veth0fbbd68/iflink
39
[root@master01 ~]# docker exec -it container1 ip link show eth0
39: eth0@if40: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
link/ether 02:42:ac:13:00:03 brd ff:ff:ff:ff:ff:ff
```
# 扩展阅读
数据包过滤和防火墙: https://docs.docker.com/engine/network/packet-filtering-firewalls/
网络驱动https://docs.docker.com/engine/network/drivers/

View File

@@ -1,235 +0,0 @@
# 资源限制
默认情况下容器没有资源限制可以使用主机内核调度程序允许的尽可能多的给定资源docker提供了控制容器可以限制容器使用多少内存或者cpu的方法设置docker run命令的运行时配置标志。
其中一些功能要求宿主机的内核支持Linux功能要检查支持可以使用docker info命令如果内核中禁用了某项功能可能会在输出结尾处看到警告。
## cgroup介绍
在一个容器内部如果不对其做任何资源限制则宿主机会允许其占用无限大的内存空间有时候会因为代码bug程序会一直申请内存直到把宿主机内存占完为了避免此类的问题出现宿主机有必要对容器进行资源分配限制比如cpu、内存等Linux Cgroups的全称是Linux control Groups它最重要的作用就是限制一个进程组能够使用的资源上线包括cpu、内存、磁盘、网络等等。
## 开启cgroup功能
- 验证系统内核层已经默认开启cgroup功能
```bash
[root@docker-server ~]# cat /boot/config-3.10.0-957.el7.x86_64| grep cgroup -i
CONFIG_CGROUPS=y
# CONFIG_CGROUP_DEBUG is not set
CONFIG_CGROUP_FREEZER=y
CONFIG_CGROUP_PIDS=y
CONFIG_CGROUP_DEVICE=y
CONFIG_CGROUP_CPUACCT=y
CONFIG_CGROUP_HUGETLB=y
CONFIG_CGROUP_PERF=y
CONFIG_CGROUP_SCHED=y
CONFIG_BLK_CGROUP=y
# CONFIG_DEBUG_BLK_CGROUP is not set
CONFIG_NETFILTER_XT_MATCH_CGROUP=m
CONFIG_NET_CLS_CGROUP=y
CONFIG_NETPRIO_CGROUP=y
```
- 关于内存的模块
```bash
[root@docker-server ~]# 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
```
# 容器CPU限制
一个宿主机有几十个核心的cpu但是宿主机上可以同时运行成百上千个不同的进程用以处理不同的任务多进程共用一个cpu的核心依赖计数就是为可压缩资源即一个核心cpu可以通过调度而运行多个进程但是在同一个单位时间内只能由一个进程在cpu上运行那么这么多的进程怎么在cpu上执行和调度的呢进程优先级
默认情况下每个容器对主机cpu周期的访问权限是不受限制的但是我们可以人为干扰。
## 相关参数说明
| 参数名 | 默认值 | 说明 | 使用建议 |
|--------|---------|------|----------|
| --cpus | 无限制 | 指定容器可使用的CPU核心数量。例如设置为1.5表示容器最多可使用1.5个CPU核心的计算能力。 | • 推荐使用此参数控制CPU使用<br>• 设置范围建议为0.1-核心总数<br>• 生产环境必须设置 |
| --cpu-period | 100000 | 设置CPU CFS调度周期(单位:微秒)。必须与--cpu-quota一起使用。 | • 不建议单独使用<br>• 建议使用--cpus替代<br>• 默认周期100ms适用大多数场景 |
| --cpu-quota | -1 | 设置CPU CFS配额(单位:微秒)。与--cpu-period配合使用,quota/period的值等效于--cpus的值。 | • 不建议单独使用<br>• 建议使用--cpus替代<br>• 仅在需要精细调度时使用 |
| --cpuset-cpus | 无限制 | 指定容器可以使用的CPU核心编号,如"0,2"表示只能使用0号和2号CPU核心。 | • 适用于CPU绑核场景<br>• 可提高缓存命中率<br>• 注意预留系统CPU资源 |
| --cpuset-mems | 无限制 | 指定容器使用的NUMA节点。仅在NUMA架构服务器中有效。 | • 仅用于NUMA架构<br>• 需了解硬件架构再使用<br>• 一般场景不建议使用 |
| --cpu-shares | 1024 | 设置CPU资源分配的权重值。在CPU竞争时,权重值越大获得更多CPU时间片。 | • 设置范围2-262144<br>• 仅在CPU竞争时有效<br>• 适合差异化CPU分配 |
> **最佳实践建议**
> 1. 生产环境建议使用--cpus参数限制CPU使用
> 2. 按实际需求合理设置CPU限制,预留足够系统资源
> 3. 特殊场景(如CPU密集型)可考虑使用cpuset-cpus绑核
> 4. 避免过度限制导致容器性能问题
## 实践案例
### 案例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%
```
### 案例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: 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
```
# 容器MEM限制
## OOM异常
对于Linux主机如果没有足够的内存来执行其他重要的系统任务将会抛出OOM异常内存溢出、内存泄漏、内存异常随后系统会开始杀死进程以释放内存凡是运行在宿主机的进程都有可能被kill包括dockerd和其他的应用程序如果重要的系统进程被kill会导致和该进程相关的服务全部宕机。
产生OOM异常时Dockerd尝试通过调整docker守护程序上的OOM优先级来减轻这些风险以便它比系统上的其他进程更不可能被杀死但是容器的OOM优先级未调整时单个容器被杀死的可能性更大不推荐调整容器的优先级这种方式
## OOM评分机制
Linux会为每个进程计算一个分数最终会将分数最高的进程kill掉。相关参数说明如下:
| 参数名 | 取值范围 | 说明 | 使用建议 |
|--------|----------|------|----------|
| oom_score_adj | -1000 到 1000 | 用于调整进程的OOM评分。值越高进程在内存不足时越容易被kill。设置为-1000时进程永远不会被kernel kill。 | • 关键系统进程建议设置较低值<br>• 非关键应用可保持默认值<br>• 谨慎使用-1000可能导致系统不稳定 |
| oom_adj | -17 到 +15 | 旧版本参数用于调整进程被kill的优先级。值越高越容易被kill-17表示不能被kill。 | • 建议使用oom_score_adj替代<br>• 仅为了兼容旧版本内核<br>• 不推荐在新系统中使用 |
| oom_score | 系统计算得出 | 系统根据进程的内存使用量、CPU时间、运行时长和oom_adj综合计算的得分。得分越高越容易被kill。 | • 用于监控进程的OOM风险<br>• 定期检查高内存占用进程<br>• 发现异常及时优化或限制 |
> **最佳实践建议**
> 1. 为关键进程适当降低OOM评分避免被意外kill
> 2. 定期监控高内存进程的oom_score
> 3. 合理规划内存使用避免触发OOM
> 4. 使用容器时建议设置内存限制
## 相关参数说明
| 参数名 | 说明 | 默认值 | 使用建议 |
|--------|------|--------|----------|
| -m 或 --memory | 容器可使用的最大物理内存量 | 无限制 | • 最小值为4m<br>• 建议根据应用实际需求设置<br>• 生产环境必须设置 |
| --memory-swap | 容器可使用的交换分区和物理内存总和 | -1 (不限制) | • 需要先设置-m参数<br>• 频繁交换会影响性能<br>• 建议生产环境禁用swap |
| --memory-swappiness | 容器使用交换分区的倾向性 | 继承主机设置 | • 范围0-100<br>• 0表示尽量不使用swap<br>• 生产环境建议设为0 |
| --kernel-memory | 容器可使用的最大内核内存量 | 无限制 | • 最小值为4m<br>**不建议使用**<br>• 可能导致主机资源阻塞 |
| --memory-reservation | 内存软限制(小于--memory) | 无限制 | • 系统内存紧张时激活<br>• 作为内存使用预警<br>• 建议设置为--memory的80% |
| --oom-kill-disable | 禁止OOM时杀死容器进程 | false | • 仅在设置-m时有效<br>• 需谨慎使用<br>• 建议保持默认值 |
> **最佳实践建议**
> 1. 生产环境必须设置-m参数限制内存使用
> 2. 建议禁用或限制swap使用
> 3. 合理设置memory-reservation作为预警
> 4. 谨慎使用kernel-memory和oom-kill-disable
## 实践案例
如果一个容器未作内存使用限制,则该容器可以利用到系统内存最大空间,默认创建的容器没有做内存资源限制
### 案例1: MEM无限制
- 拉取容器压测工具镜像
```bash
[root@docker-server1 ~]# docker pull lorel/docker-stress-ng
[root@docker-server1 ~]# docker run -it --rm lorel/docker-stress-ng -help
```
- 使用压测工具开启两个工作进程每个工作进程最大允许使用内存256M且宿主机不限制当前容器的最大内存
```bash
[root@docker-server1 ~]# docker run -it --rm --name test1 lorel/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@docker-server1 ~]# 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
```
### 案例2: MEM限制
- 宿主机限制最大内存使用
```bash
[root@docker-server1 ~]# docker run -it --rm -m 256m --name test2 lorel/docker-stress-ng --vm 2 --vm-bytes 256m
[root@docker-server1 ~]# docker stats
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
bfff488e6185 test1 169.76% 255.8MiB / 256MiB 99.91% 648B / 0B 3.53GB / 10.6GB 5
```
- 可以通过修改cgroup文件值来扩大内存限制缩小会报错
```bash
[root@docker-server1 ~]# cat /sys/fs/cgroup/memory/docker/bfff488e618580b227b5411c91b35517850e95af2ac2225b45180937c14e70c2/memory.limit_in_bytes
```
**内存软限制**
软限制不会真正限制到内存的使用
```bash
[root@docker-server1 ~]# docker run -it --rm -m 256m --memory-reservation 128m --name test1 lorel/docker-stress-ng --vm 2 --vm-bytes 256m
[root@docker-server1 ~]# 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@docker-server1 ~]# docker run -it --rm -m 256m --memory-swap 512m --name test1 lorel/docker-stress-ng --vm 2 --vm-bytes 256m
```

View File

@@ -1,81 +0,0 @@
# Linux namespace技术
如果一个宿主机运行了N个容器多个容器带来的以下问题怎么解决
1. 怎么样保证每个容器都有不同的文件系统并且能互不影响?
2. 一个docker主进程内的各个容器都是其子进程那么如何实现同一个主进程下不同类型的子进程各个子进程间通信能相互访问吗
3. 每个容器怎么解决IP以及端口分配的问题
4. 多个容器的主机名能一样吗?
5. 每个容器都要不要有root用户怎么解决账户重名问题呢
**解决方案**
namespace 是 Linux 系统的底层概念在内核层实现即有一些不同类型的命名空间都部署在核内各个容器运行在同一个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 | 提供网络栈的隔离能力包括网络设备、IP地址、路由表等 | CLONE_NEWNET | 2.6.29 | 容器网络配置、跨主机通信、服务端口映射 |
| User Namespaceuser | 提供用户和用户组的隔离能力,增强容器安全性 | CLONE_NEWUSER | 3.8 | 容器权限控制、用户映射、安全策略管理 |
# MNT Namespace
提供磁盘挂载点和文件系统的隔离能力,使容器拥有独立的文件系统层次结构。
```bash
# 在容器内挂载 tmpfs 文件系统
docker run -it --rm ubuntu bash
mkdir /mnt/tmpfs
mount -t tmpfs -o size=100M tmpfs /mnt/tmpfs
# 宿主机上无法看到此挂载点
df -h
```
# IPC Namespace
提供进程间通信的隔离能力,确保容器内进程通信安全。
```shell
# 容器A创建共享内存段
docker run -it --name shm1 --rm ubuntu bash
ipcmk -M 64M # 返回共享内存 ID如 0
# 容器B无法访问
docker run -it --name shm2 --rm ubuntu bash
ipcs -m
```
# UTS Namespace
提供主机名和域名的隔离能力,使容器拥有独立的主机标识。
```shell
# 启动容器并设置主机名
docker run -it --hostname=myapp --rm ubuntu bash
hostname
```
# PID Namespace
提供进程隔离能力,实现容器内进程树独立管理。
```shell
# 查看当前宿主机所有进程
# 查看当前容器内所有进程
```
**那么宿主机的PID与容器内的PID是什么关系**
1. **独立的 PID 命名空间**:
- 每个 Docker 容器都有自己独立的 PID 命名空间。
- 容器内的进程 PID 从 1 开始编号,与宿主机上的 PID 是相互独立的。
2. **PID 映射**:
- 容器内的进程 PID 与宿主机上的进程 PID 之间是有映射关系的。
- 通过 `docker inspect <container_id>` 命令,可以查看容器内进程的 PID 与宿主机上进程 PID 的对应关系。
3. **PID 可见性**:
- 容器内的进程只能看到容器内部的 PID。
- 宿主机上的进程可以看到容器内部的 PID,但容器内的进程无法看到宿主机上的 PID。
4. **PID 隔离**:
- 容器内的进程无法访问或影响宿主机上的其他进程。
- 宿主机上的进程可以访问和管理容器内的进程。
# Net Namespace
提供网络栈的隔离能力包括网络设备、IP地址、路由表等。参考`08.Docker网络管理`
# User Namespace
提供用户和用户组的隔离能力,增强容器安全性。
```shell
# A容器创建用户在B容器里不可见
```

View File

@@ -1,155 +0,0 @@
# 背景介绍
Docker 镜像制作类似于虚拟机的模板制作即按照公司的实际业务将需要安装的软件、相关配置等基础环境配置完成然后将虚拟机再提交为模板最后再批量从模板批量创建新的虚拟机这样可以极大地简化业务中相同环境的虚拟机运行环境的部署工作Docker的镜像制作分为手动制作可自动制作基于 DockerFile ),企业通常都是基于 DockerFile 制作镜像。
# 手动制作nginx镜像
```shell
[root@docker-server ~]# docker run -it ubuntu bash
root@1d8e32ab39d6:/# apt-get update & apt-get install nginx curl vim-tiny -y
root@1d8e32ab39d6:/# echo 'eagleslab nginx' > /var/www/html/index.nginx-debian.html
root@1d8e32ab39d6:/# grep daemon /etc/nginx/nginx.conf
daemon off;
# 提交为镜像
Usage: docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]
[root@docker-server ~]# docker commit -a "v100" -m "my nginx image v1" 0195bc1d0f7b ubuntu_nginx:v1
# 通过ubuntu_nginx:v1镜像启动容器
[root@docker-server ~]# docker run -d -p 8081:80 ubuntu_nginx:v1
[root@docker-server ~]# curl 127.0.0.1:8081
```
**适用场景**:主要作用是将配置好的一些容器复用,再生成新的镜像。
commit是合并了save、load、export、import这几个特性的一个综合性的命令它主要做了
1. 将容器当前的读写层保存成一个新层。
2. 和镜像的历史层一起合并成一个新的镜像
3. 如果原本的镜像有3层commit之后就会有4层最新的一层为从镜像运行到commit之间对文件系统的修改。
# DockerFile制作镜像
DockerFile可以说是一种可以被Docker程序解释的脚本DockerFile是由一条条的命令组成的每条命令对应linux下面的一条命令Docker程序将这些DockerFile指令再翻译成真正的linux命令其有自己的书写方式和支持的命令Docker程序读取DockerFile并根据指令生成Docker镜像相比手动制作镜像的方式DockerFile更能直观地展示镜像是怎么产生的有了写好的各种各样的DockerFIle文件当后期某个镜像有额外的需求时只要在之前的DockerFile添加或者修改相应的操作即可重新生成新的Docker镜像避免了重复手动制作镜像的麻烦。
## 最佳实践
```shell
# Dockerfile
## 使用官方 Ubuntu 22.04 LTS 作为基础镜像
FROM ubuntu:22.04
## 设置环境变量避免交互式提示
ENV DEBIAN_FRONTEND=noninteractive
## 安装 Nginx 并清理缓存(合并操作用于减少镜像层)
RUN apt-get update && \
apt-get install -y \
nginx \
# 安装常用工具(可选)
curl \
vim-tiny && \
# 清理APT缓存
apt-get clean && \
rm -rf /var/lib/apt/lists/*
## 删除默认配置文件(按需保留)
RUN rm /etc/nginx/sites-enabled/default
## 暴露 HTTP 和 HTTPS 端口
EXPOSE 80 443
## 创建日志目录(确保日志可持久化)
RUN mkdir -p /var/log/nginx && \
chown -R www-data:www-data /var/log/nginx
## 添加自定义配置(示例文件需存在于构建上下文)
# COPY nginx.conf /etc/nginx/nginx.conf
# COPY sites-available/ /etc/nginx/sites-available/
## 设置健康检查
HEALTHCHECK --interval=30s --timeout=3s \
CMD curl -f http://localhost/ || exit 1
## 以非root用户运行Ubuntu官方nginx包已使用www-data用户
USER www-data
## 启动Nginx并保持前台运行
CMD ["nginx", "-g", "daemon off;"]
# 通过Dockerfile构建镜像
[root@docker-server ~]# docker build -t nginx:v1 .
```
## 优化说明
- 层合并: 将多个`RUN`指令合并以减少镜像层数
- 缓存清理: 清理APT缓存减小镜像体积
- 安全实践: 非root用户运行只读挂载配置文件
- 可维护性: 显式声明暴露端口;健康检查配置;日志目录持久化
- 稳定性: 指定精确的ubuntu版本禁用Nginx后台模式
## 指令说明
操作指令
| 指令 | 说明 |
| ------ | ---------------------------- |
| `RUN` | 运行指定命令 |
| `CMD` | 启动容器时指定默认执行的命令 |
| `ADD` | 添加内容到镜像 |
| `COPY` | 复制内容到镜像 |
配置指令
| 指令 | 说明 |
| ------------- | ---------------------------------- |
| `ARG` | 定义创建镜像过程中使用的变量 |
| `FROM` | 指定所创建镜像的基础镜像 |
| `LABEL` | 为生成的镜像添加元数据标签信息 |
| `EXPOSE` | 声明镜像内服务监听的端口 |
| `ENV` | 指定环境变量 |
| `ENTRYPOINT` | 指定镜像的默认入口命令 |
| `VOLUME` | 创建一个数据卷挂载点 |
| `USER` | 指定运行容器时的用户名或UID |
| `WORKDIR` | 配置工作目录 |
| `ONBUILD` | 创建子镜像时指定自动执行的操作指令 |
| `STOPSIGNAL` | 指定退出的信号值 |
| `HEALTHCHECK` | 配置所启动容器如何进行健康检查 |
| `SHELL` | 指定默认shell类型 |
**注意事项**
```shell
# RUN
- 运行指定命令
- 每条RUN指令将在当前镜像基础上执行指定命令并提交为新的镜像层
- 当命令较长时可以使用\来换行
# CMD
- 每个Dockerfile只能有一条CMD命令。如果指定了多条命令只有最后一条会被执行
- CMD指令用来指定启动容器时默认执行的命令,支持三种格式:
CMD ["executable","param1","param2"]
CMD command param1 param2`
CMD ["param1","param2"]
# ADD
- 该命令将复制指定的src路径下内容到容器中的dest路径下
- src可以是DockerFIle所在目录的一个相对路径也可以是一个url还可以是一个tar
- dest可以是镜像内绝对路径或者相对于工作目录的相对路径
# COPY
- COPY与ADD指令功能类似当使用本地目录为源目录时推荐使用COPY
# ARG
- 定义创建过程中使用到的变量;比如:HTTP_PROXY 、HTTPS_PROXY 、FTP_PROXY 、NO_PROXY不区分大小写。
# FROM
- 指定所创建镜像的基础镜像为了保证镜像精简可以选用体积较小的Alpin或Debian作为基础镜像
# EXPOSE
- 声明镜像内服务监听的端口:该指令只是起到声明作用,并不会自动完成端口映射
# ENTRYPOINT
- 指定镜像的默认入口命令,该入口命令会在启动容器时作为根命令执行,所有传入值作为该命令的参数支持两种格式:
ENTRYPOINT ["executable","param1","param2"]
ENTRYPOINT command param1 param2
- 此时CMD指令指定值将作为根命令的参数
- 每个DockerFile中只能有一个ENTRYPOINT当指定多个时只有最后一个起效
# VOLUME: 创建一个数据卷挂载点
# WORKDIR
- 为后续的RUN、CMD、ENTRYPOINT指令配置工作目录建议使用绝对路径
```

View File

@@ -1,118 +0,0 @@
# 镜像
容器是一个独立的进程,它从哪里获取文件和配置?如何共享这些环境?
镜像是一个标准化包,其中包含运行容器所需的所有文件、二进制文件、库和配置。
- MySQL 镜像会打包数据库二进制文件、配置文件和其他依赖项。
- Python Web 应用镜像会打包 Python 运行时、应用代码及其所有依赖项。
镜像两个重要原则:
1. 镜像是不可变的。一旦创建,就无法修改。只能创建新镜像或在其上进行更改。
2. 镜像由层组成。每一层代表一组文件系统变更,包括添加、删除或修改文件。
# 镜像管理
## 搜索镜像
`Usage: docker search [OPTIONS] TERM`
```bash
# 搜索包含关键字的镜像
[root@docker-server ~]# docker search centos
```
可以看到返回了很多包含关键字的镜像,其中包括镜像名字、描述、点赞数(表示该镜像的受欢迎程度)、是否官方创建、是否自动创建。默认输出结果按照星级评价进行排序。
![img](docker镜像管理/docker_hub搜索.png)
## 下载镜像
`Usage: docker pull [OPTIONS] NAME[:TAG|@DIGEST]`
```bash
# 下载nginx、centos、hello-world镜像
[root@docker-server ~]# docker pull nginx
[root@docker-server ~]# docker pull centos
[root@docker-server ~]# docker pull hello-world
```
其中NAME是镜像名称TAG是镜像的标签往往用来是表示版本信息通常情况下描述一个镜像需要包括名称+标签如果不指定标签标签的值默认为latest。
## 镜像列表
`Usage: docker image COMMAND`
```bash
# 列出本地所有镜像
[root@docker-server ~]# docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest d1a364dc548d 2 weeks ago 133MB
...
# 字段说明
- REPOSITORY镜像仓库名称
- TAG镜像的标签信息
- 镜像ID唯一用来标识镜像如果两个镜像的ID相同说明他们实际上指向了同一个镜像只是具有不同标签名称而已
- CREATED创建时间说明镜像的最后更新时间
- SIZE镜像大小优秀的镜像往往体积都较小
```
## 镜像标签
`Usage: docker image tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG]`
```bash
[root@docker-server ~]# docker tag centos:latest mycentos:latest
[root@docker-server ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest d1a364dc548d 2 weeks ago 133MB
...
```
## 镜像信息
`Usage: docker image inspect [OPTIONS] IMAGE [IMAGE...]`
```bash
[root@docker-server ~]# docker inspect centos:latest
[
{
"Id": "sha256:300e315adb2f96afe5f0b2780b87f28ae95231fe3bdd1e16b9ba606307728f55",
"RepoTags": [
"centos:latest",
"mycentos:latest"
]
...
}
]
```
## 镜像创建信息
`Usage: docker image history [OPTIONS] IMAGE`
```bash
[root@docker-server ~]# docker history centos:latest
IMAGE CREATED CREATED BY SIZE COMMENT
300e315adb2f 6 months ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B
...
```
## 镜像导出
`Usage: docker image save [OPTIONS] IMAGE [IMAGE...]`
```bash
[root@docker-server ~]# docker image save centos:latest -o /opt/centos.tar.gz
[root@docker-server ~]# ll /opt/centos.tar.gz
-rw------- 1 root root 216535040 6月 9 10:33 /opt/centos.tar.gz
[root@docker-server ~]# docker image save centos:latest > /opt/centos-1.tar.gz
[root@docker-server ~]# ll /opt/centos-1.tar.gz
-rw-r--r-- 1 root root 216535040 6月 9 10:35 /opt/centos-1.tar.gz
```
## 镜像导入
`Usage: docker image load [OPTIONS]`
```bash
[root@docker-server ~]# docker image load -i /opt/centos.tar.gz
Loaded image: centos:latest
[root@docker-server ~]# docker image load < /opt/centos.tar.gz
Loaded image: centos:latest
```
## 删除镜像
`Usage: docker image rm [OPTIONS] IMAGE [IMAGE...]`
```bash
[root@docker-server ~]# docker image rm nginx:latest
Untagged: nginx:latest
Untagged: nginx@sha256:6d75c99af15565a301e48297fa2d121e15d80ad526f8369c526324f0f7ccb750
[root@docker-server ~]# docker image rm 300e315adb2f
...
```

Binary file not shown.

Before

Width:  |  Height:  |  Size: 668 KiB