08-27-周三_17-09-29

This commit is contained in:
2025-08-27 17:10:05 +08:00
commit 86df397d8f
12735 changed files with 1145479 additions and 0 deletions

8
Docker/Docker.md Normal file
View File

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

69
Docker/Docker介绍.md Normal file
View File

@@ -0,0 +1,69 @@
# 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

@@ -0,0 +1,90 @@
# 公共仓库
## 官方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

@@ -0,0 +1,90 @@
# 存储引擎
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

124
Docker/Docker安装.md Normal file
View File

@@ -0,0 +1,124 @@
# Docker服务端软件选择
Docker CECommunity Edition社区版和 Docker EEEnterprise Edition企业版是 Docker 产品的两个主要版本,它们之间的主要区别在于目标用户、功能集、支持和维护等方面:
| 对比项 | Docker CE | Docker EE |
|--------|-----------|------------|
| **目标用户** | 面向个人开发者、小团队以及技术爱好者,主要用于开发和测试环境 | 面向大型企业和组织,提供企业级的功能和支持 |
| **功能集** | 提供基本的容器化功能,包括构建、运行和共享容器 | 除了包含 CE 版本的所有功能外,还提供了额外的企业级特性,如增强的安全、管理、可扩展性和集成性 |
| **支持和维护** | 社区支持,适合自我解决问题的开发者 | 提供商业支持和专业服务,适合需要稳定运行环境的企业 |
| **安全性** | 安全性相对较低,适合非生产环境 | 提供更高级的安全特性,如镜像扫描、安全策略和合规性报告 |
| **管理** | 通常不需要复杂的管理工具 | 提供 Docker Universal Control Plane (UCP) 和 Docker Trusted Registry (DTR) 等管理工具,帮助企业更有效地管理容器环境 |
| **成本** | 免费 | 需要购买许可证 |
| **更新和生命周期** | 更新频繁,可能包含实验性功能,生命周期较短 | 更新周期更稳定,更注重稳定性和兼容性,生命周期较长 |
# Docker快速安装
```shell
[root@docker-server ~]# chmod +x install_docker_ce.sh
[root@docker-server ~]# ./install_docker_ce.sh
```
# 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

@@ -0,0 +1,169 @@
# 容器
## 使用场景
开发一个杀手级的 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

@@ -0,0 +1,518 @@
# Docker compose单机编排
## Docker Compose 简介
当在宿主机上启动多个容器时,手动操作会比较繁琐,且容易出错。在这种情况下,推荐使用 Docker 单机编排工具 **Docker Compose**。Docker Compose 是 Docker 官方提供的一个开源工具,用于管理和编排多个容器。它可以解决容器之间的依赖关系,简化容器的创建、启动和停止操作。
例如,启动一个 Nginx 前端服务时,可能需要调用后端的 Tomcat 服务,而 Tomcat 容器又依赖于数据库。在这种嵌套依赖关系中Docker Compose 可以按照正确的顺序启动这些容器确保每个容器在启动时都能正确依赖所需的其他容器。因此Docker Compose 完全可以替代 `docker run` 来创建和管理容器。
## Docker Compose 项目结构
Docker Compose 项目将所管理的容器分为三层,分别是:
- **工程Project**:工程是 Docker Compose 管理的最高层级,通常对应一个包含多个服务的应用场景。一个工程可以包含多个服务,这些服务通过 `docker-compose.yml` 文件进行定义。
- **服务Service**:服务是工程中的一个逻辑单元,通常对应一个容器模板。服务定义了容器的镜像、环境变量、端口映射等配置。一个服务可以启动多个容器实例。
- **容器Container**容器是服务的具体运行实例。Docker Compose 会根据服务的定义创建并管理容器。
通过这种分层结构Docker Compose 能够高效地管理和编排多个容器,简化复杂的容器依赖关系,提高开发和部署效率。
# 基础环境准备
## Docker compose部署
yum安装docker-compese
从 Docker 20.10 版本开始Docker Compose 被集成到了 Docker 中作为插件使用而不是独立的命令行工具所以说在20以后的版本中我们直接使用docker compose(中间用空格隔开)即可
```bash
# 旧版本中安装docker-compose的方式
[root@localhost ~]# yum install -y epel-release
[root@localhost ~]# yum install docker-compose.noarch -y
[root@localhost ~]# docker-compose version
docker-compose version 1.18.0, build 8dd22a9
docker-py version: 2.6.1
CPython version: 3.6.8
OpenSSL version: OpenSSL 1.0.2k-fips 26 Jan 2017
```
## 相关参数
```bash
# docker-compose --help
Define and run multi-container applications with Docker.
## Usage
```bash
docker-compose [-f <arg>...] [options] [COMMAND] [ARGS...]
docker-compose -h|--help
```
### 选项说明
- `-f`, `--file FILE`:指定 Compose 模板文件,默认为 `docker-compose.yml`
- `-p`, `--project-name NAME`:指定项目名称,默认将使用当前所在目录名称作为项目名。
- `--verbose`:显示更多输出信息。
- `--log-level LEVEL`:定义日志级别 (DEBUG, INFO, WARNING, ERROR, CRITICAL)。
- `--no-ansi`:不显示 ANSI 控制字符。
- `-v`, `--version`:显示版本。
### 命令选项
以下命令需要在 `docker-compose.yml``yaml` 文件所在目录里执行。
- `build`:构建或重新构建服务中定义的镜像。
- `bundle`:从当前 `docker-compose` 文件生成一个以 `<当前目录>` 为名称的 JSON 格式的 Docker Bundle 文件,用于离线部署。
- `config -q`:验证 Compose 文件格式是否正确,若无错误则不输出任何内容。
- `create`:创建服务所需的所有容器,但不启动它们。
- `down`:停止和删除所有容器、网络、卷,以及由 `docker-compose up` 创建的镜像(可选)。
- `events`:实时显示容器的日志事件,支持指定日志格式(如 JSON
- `exec`:在指定的容器中运行一个命令。
- `help`:显示指定命令的帮助信息。
- `images`:列出所有由 `docker-compose` 创建的镜像。
- `kill`:强制终止正在运行的容器。
- `logs`:查看容器的日志输出。
- `pause`:暂停服务中的所有容器。
- `port`:查看服务的端口映射情况。
- `ps`:列出所有由 `docker-compose` 管理的容器。
- `pull`:从镜像仓库拉取服务中定义的镜像。
- `push`:将服务中定义的镜像推送到镜像仓库。
- `restart`:重启服务中的所有容器。
- `rm`:删除所有已停止的容器。
- `run`:在指定服务中运行一个命令,创建一个临时容器。
- `scale`:设置指定服务运行的容器数量。
- `start`:启动已创建但未运行的服务。
- `stop`:停止正在运行的服务。
- `top`:显示正在运行的容器的进程信息。
- `unpause`:恢复之前暂停的服务。
- `up`:构建、创建并启动所有服务,如果服务已存在则重新启动。
### 示例 `docker-compose.yml` 文件
以下是一个详细的 `docker-compose.yml` 文件示例,包含注释和可能用到的所有指令。这个示例展示了如何定义一个包含多个服务(如 Nginx、Tomcat 和 MySQL的 Docker Compose 项目。
```yaml
# docker-compose.yml
# 定义版本,指定 Compose 文件的格式版本
version: '3.8'
# 定义服务
services:
# 定义 MySQL 服务
mysql:
# 使用的镜像名称
image: mysql:5.7
# 容器的名称
container_name: mysql_container
# 环境变量,用于设置 MySQL 的 root 密码
environment:
MYSQL_ROOT_PASSWORD: mypassword
MYSQL_DATABASE: mydb
# 持久化数据卷
volumes:
- mysql_data:/var/lib/mysql
# 端口映射,将宿主机的 3306 端口映射到容器的 3306 端口
ports:
- "3306:3306"
# 重启策略,始终重启
restart: always
# 网络配置,连接到默认网络
networks:
- my_network
# 定义 Tomcat 服务
tomcat:
# 使用的镜像名称
image: tomcat:9.0
# 容器的名称
container_name: tomcat_container
# 环境变量,设置 Tomcat 的一些配置
environment:
- CATALINA_OPTS=-Xms512M -Xmx1024M
# 持久化 Tomcat 的 webapps 目录
volumes:
- tomcat_webapps:/usr/local/tomcat/webapps
# 端口映射,将宿主机的 8080 端口映射到容器的 8080 端口
ports:
- "8080:8080"
# 依赖关系,确保 MySQL 服务先启动
depends_on:
- mysql
# 重启策略,始终重启
restart: always
# 网络配置,连接到默认网络
networks:
- my_network
# 定义 Nginx 服务
nginx:
# 使用的镜像名称
image: nginx:1.19
# 容器的名称
container_name: nginx_container
# 持久化 Nginx 的配置文件和静态资源
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
- ./html:/usr/share/nginx/html
# 端口映射,将宿主机的 80 端口映射到容器的 80 端口
ports:
- "80:80"
# 依赖关系,确保 Tomcat 服务先启动
depends_on:
- tomcat
# 重启策略,始终重启
restart: always
# 网络配置,连接到默认网络
networks:
- my_network
# 定义卷
volumes:
# 定义 MySQL 数据卷
mysql_data:
driver: local
# 定义 Tomcat webapps 卷
tomcat_webapps:
driver: local
# 定义网络
networks:
# 定义默认网络
my_network:
driver: bridge
```
### 文件说明
1. **版本**
- `version: '3.8'`:指定 Compose 文件的格式版本。不同的版本支持不同的功能和语法。
2. **服务**
- `services`:定义项目中包含的所有服务。
- 每个服务(如 `mysql``tomcat``nginx`)都有自己的配置,包括:
- `image`:指定使用的 Docker 镜像。
- `container_name`:指定容器的名称。
- `environment`:设置环境变量。
- `volumes`:定义数据卷,用于持久化数据或挂载本地文件。
- `ports`:定义端口映射。
- `depends_on`:定义服务之间的依赖关系。
- `restart`:设置重启策略。
- `networks`:定义服务所属的网络。
3. **卷**
- `volumes`:定义数据卷,用于持久化数据。这里定义了两个卷:`mysql_data``tomcat_webapps`
4. **网络**
- `networks`:定义网络,用于服务之间的通信。这里定义了一个默认的桥接网络 `my_network`
### 可能用到的 Docker Compose 命令
以下是在 `docker-compose.yml` 文件所在目录中可以执行的常用命令:
- **`docker-compose up`**:构建、创建并启动所有服务。如果服务已存在,则重新启动。
- **`docker-compose down`**:停止并删除所有容器、网络、卷以及由 `docker-compose up` 创建的镜像(可选)。
- **`docker-compose build`**:构建或重新构建服务中定义的镜像。
- **`docker-compose create`**:创建服务所需的所有容器,但不启动它们。
- **`docker-compose start`**:启动已创建但未运行的服务。
- **`docker-compose stop`**:停止正在运行的服务。
- **`docker-compose restart`**:重启服务中的所有容器。
- **`docker-compose kill`**:强制终止正在运行的容器。
- **`docker-compose rm`**:删除所有已停止的容器。
- **`docker-compose logs`**:查看容器的日志输出。
- **`docker-compose exec`**:在指定的容器中运行一个命令。
- **`docker-compose ps`**:列出所有由 `docker-compose` 管理的容器。
- **`docker-compose config`**:验证 Compose 文件格式是否正确,若无错误则不输出任何内容。
- **`docker-compose bundle`**:从当前 `docker-compose` 文件生成一个 JSON 格式的 Docker Bundle 文件,用于离线部署。
- **`docker-compose pull`**:从镜像仓库拉取服务中定义的镜像。
- **`docker-compose push`**:将服务中定义的镜像推送到镜像仓库。
- **`docker-compose scale`**:设置指定服务运行的容器数量。
# 实战案例
## 启动单个容器
一、编写docker-compose文件
```yaml
[root@localhost ~]# mkdir -pv docker-compose/nginx
[root@localhost ~]# cd docker-compose/nginx
[root@localhost nginx]# pwd
/root/docker-compose/nginx
[root@localhost nginx]# vim docker-compose.yml
# docker-compose.yml
services:
nginx:
image: nginx
container_name: nginx_web1
restart: always
ports:
- "80:80"
volumes:
- /data/web:/usr/share/nginx/html
```
二、启动容器
```bash
[root@localhost nginx]# docker compose up -d
[+] Running 2/2
✔ Network nginx_default Created 0.0s
✔ Container nginx_web1 Started 0.2s
[root@localhost nginx]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
09d091a0c1a1 nginx "/docker-entrypoint.…" 29 seconds ago Up 28 seconds 0.0.0.0:80->80/tcp, [::]:80->80/tcp nginx_web1
# 不指定网络的话会默认创建一个类型为bridge的网络
[root@localhost nginx]# docker network ls
NETWORK ID NAME DRIVER SCOPE
36f9c2f8e090 bridge bridge local
93ffe4510dd0 host host local
d0456365c64d nginx_default bridge local
61f0d0d9b051 none null local
```
三、访问测试
## 启动多个容器
一、编辑docker-compose文件
```bash
[root@localhost docker]# cat docker-compose.yml
service-nginx:
image: nginx
container_name: nginx_web1
ports:
- "80:80"
service-tomcat:
image: tomcat
container_name: tomcat_web1
ports:
- "8080:8080"
[root@localhost docker]# docker-compose up -d
nginx_web1 /docker-entrypoint.sh ngin ... Up 0.0.0.0:80->80/tcp,:::80->80/tcp
tomcat_web1 catalina.sh run Up 0.0.0.0:8080->8080/tcp,:::8080-
>8080/tcp
```
## 定义数据卷挂载
- 创建数据卷目录和文件
```bash
[root@localhost docker]# mkdir -p /data/nginx
[root@localhost docker]# echo 'docker nginx' > /data/nginx/index.html
```
- 编辑配置文件
```bash
[root@localhost docker]# cat docker-compose.yml
service-nginx:
image: nginx
container_name: nginx_web1
volumes:
- /data/nginx/:/usr/share/nginx/html
ports:
- "80:80"
service-tomcat:
image: tomcat
container_name: tomcat_web1
ports:
- "8080:8080"
```
- 访问测试
```bash
[root@localhost docker]# curl localhost
docker nginx
```
# Docker Compose部署LNMP实战
## 部署LNMP环境
- 使用docker-compose实现编排nginx+phpfpm+mysql容器
- 部署一个博客系统
- 首先编写一个如下的配置文件
```yaml
services:
web:
image: nginx:latest
restart: always
ports:
- 80:80
volumes:
- /data/lnmp/nginx/conf.d:/etc/nginx/conf.d
- /data/lnmp/nginx/html:/usr/share/nginx/html
- /data/lnmp/nginx/log:/var/log/nginx
depends_on:
- php
- mysql
networks:
- lnmp-network
php:
image: php:7.4-fpm
restart: always
volumes:
- /data/lnmp/nginx/html:/usr/share/nginx/html
networks:
- lnmp-network
depends_on:
- mysql
mysql:
image: mysql:5.7
restart: always
volumes:
- /data/lnmp/dbdata:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: "123456"
MYSQL_DATABASE: login
networks:
- lnmp-network
networks:
lnmp-network:
driver: bridge
volumes:
dbdata: null
```
运行docker-compose.yml
```bash
[root@localhost lnmp]# docker compose up -d
[root@localhost lnmp]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
825b8630de47 nginx:latest "/docker-entrypoint.…" 4 minutes ago Up 4 minutes 0.0.0.0:80->80/tcp, [::]:80->80/tcp lnmp-web-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
```
`/data/lnmp/nginx/conf.d/default.conf` 中写入nginx 的配置文件
```shell
server {
listen 80;
root /usr/share/nginx/html;
location / {
index index.php index.html;
}
location ~ \.php$ {
fastcgi_pass php:9000;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
```
准备探针测试
`/data/lnmp/nginx/html/info.php` 中准备php探针
```shell
<?php
phpinfo();
?>
```
测试数据库连接
`/data/lnmp/nginx/html/mysql.php`中准备php探针
```shell
<?php
$dbhost = "mysql";
$dbuser = "root";
$dbpass = "123456";
$db = "login";
$conn = mysqli_connect($dbhost, $dbuser, $dbpass, $db) or exit("数据库连接失败!");
echo "数据库连接成功";
?>
```
访问测试后发现连接mysql报错提示找不到mysqli_connect()看来是官方构建的php没有mysqli模块
所以我们需要定制带有mysqli模块的php编写如下dockerfile
```shell
FROM php:7.4-fpm
ENV TZ=Asia/Shanghai
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini" \
&& sed -i 's/deb.debian.org/mirrors.ustc.edu.cn/g' /etc/apt/sources.list \
&& sed -i -e 's|security.debian.org/\? |security.debian.org/debian-security |g' \
-e 's|security.debian.org|mirrors.ustc.edu.cn|g' \
-e 's|deb.debian.org/debian-security|mirrors.ustc.edu.cn/debian-security|g' \
/etc/apt/sources.list \
&& apt-get update && apt-get install -y \
libfreetype6-dev \
libjpeg62-turbo-dev \
libpng-dev \
&& docker-php-ext-configure gd -with-freetype -with-jpeg \
&& docker-php-ext-install -j$(nproc) gd mysqli && docker-php-ext-enable mysqli
```
然后修改 docker-compose.yml 文件如下
```yaml
# docker-compose build lnmp
services:
web:
image: nginx:latest
restart: always
ports:
- 80:80
volumes:
- /data/lnmp/nginx/conf.d:/etc/nginx/conf.d
- /data/lnmp/nginx/html:/usr/share/nginx/html
- /data/lnmp/nginx/log:/var/log/nginx
depends_on:
- php
- mysql
networks:
- lnmp-network
php:
# image: dockerfile:php:7.4-fpm
# 这里来让compose自动构建指定dockerfile的文件位置即可
build:
context: .
dockerfile: dockerfile
restart: always
volumes:
- /data/lnmp/nginx/html:/usr/share/nginx/html
networks:
- lnmp-network
depends_on:
- mysql
mysql:
image: mysql:5.7
restart: always
volumes:
- /data/lnmp/dbdata:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: "123456"
MYSQL_DATABASE: login
networks:
- lnmp-network
networks:
lnmp-network:
driver: bridge
volumes:
dbdata: null
```
测试验证
```shell
[root@localhost lnmp]# docker compose up -d
[root@localhost lnmp]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
825b8630de47 nginx:latest "/docker-entrypoint.…" 4 minutes ago Up 4 minutes 0.0.0.0:80->80/tcp, [::]:80->80/tcp lnmp-web-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
```

View File

@@ -0,0 +1,91 @@
# 存储
## 介绍
默认情况下,容器内创建的所有文件都存储在可写的容器层上,该层位于只读、不可变的图像层之上。
写入容器层的数据在容器销毁后不会保留。这意味着,如果其他进程需要这些数据,则很难将其从容器中取出。
每个容器的可写层都是唯一的。无法将数据从可写层提取到主机或其他容器。
## 存储挂载选项
| 挂载类型 | 说明 | 使用场景 | 特点 |
|:---------|:-----|:---------|:-----|
| 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

@@ -0,0 +1,69 @@
# 网络
容器网络是指容器能够连接和通信的能力,无论是容器之间还是与外部。
# 用户自定义网络
可以创建自定义的用户定义网络,并将多个容器连接到同一网络。一旦连接到用户定义的网络,容器可以使用容器 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

@@ -0,0 +1,235 @@
# 资源限制
默认情况下容器没有资源限制可以使用主机内核调度程序允许的尽可能多的给定资源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

@@ -0,0 +1,81 @@
# 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

@@ -0,0 +1,155 @@
# 背景介绍
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

@@ -0,0 +1,118 @@
# 镜像
容器是一个独立的进程,它从哪里获取文件和配置?如何共享这些环境?
镜像是一个标准化包,其中包含运行容器所需的所有文件、二进制文件、库和配置。
- 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.

After

Width:  |  Height:  |  Size: 668 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB