mirror of
https://github.com/yeasy/docker_practice.git
synced 2026-03-11 04:14:38 +00:00
Fix typography
This commit is contained in:
@@ -102,7 +102,7 @@ $ docker compose up
|
||||
|
||||
Docker 容器共享宿主机内核,无需为每个应用运行完整的操作系统。以一台 64GB 内存的物理服务器为例:
|
||||
- **传统虚拟机方案**:每个虚拟机都需要运行完整的操作系统(每个额外占用如 2GB 内存),产生大量资源开销,实际可用于应用的内存可能只有约 18GB。
|
||||
- **Docker 方案**:容器直接共享宿主机系统,只需付出很少的基础开销(OS及引擎约 4GB),即可将约 60GB 的内存全部用于实际应用。
|
||||
- **Docker 方案**:容器直接共享宿主机系统,只需付出很少的基础开销(OS 及引擎约 4GB),即可将约 60GB 的内存全部用于实际应用。
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
|
||||
@@ -56,7 +56,7 @@ flowchart TB
|
||||
一个完整的 Docker 镜像名称由 Registry 地址、用户名/组织名、仓库名和标签组成。了解其结构有助于我们更准确地定位镜像。基本格式如下:
|
||||
|
||||
```bash
|
||||
[registry地址/][用户名/]仓库名[:标签]
|
||||
[registry 地址/][用户名/]仓库名[:标签]
|
||||
```
|
||||
|
||||
示例:
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
- [Dockerfile 最佳实践](../appendix/best_practices.md):构建高质量镜像的技巧
|
||||
- [底层实现 - 联合文件系统](../12_implementation/12.4_ufs.md):深入理解分层存储的技术原理
|
||||
- [启动容器](../05_container/5.1_run.md):详细的容器启动选项
|
||||
- [后台运行](../05_container/5.2_daemon.md):理解容器为什么会"立即退出"
|
||||
- [后台运行](../05_container/5.2_daemon.md):理解容器为什么会“立即退出”
|
||||
- [进入容器](../05_container/5.4_attach_exec.md):如何操作运行中的容器
|
||||
- [数据管理](../08_data/README.md):Volume 和数据持久化详解
|
||||
- [Docker Hub](../06_repository/6.1_dockerhub.md):Docker Hub 的详细使用
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
下载好之后双击 `Docker Desktop Installer.exe` 开始安装。
|
||||
|
||||
**使用** [**winget**](https://docs.microsoft.com/zh-cn/windows/package-manager/) **安装**
|
||||
**使用**[**winget**](https://docs.microsoft.com/zh-cn/windows/package-manager/)**安装**
|
||||
|
||||
```powershell
|
||||
$ winget install Docker.DockerDesktop
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -77,9 +77,9 @@ $ docker push username/myapp:v1
|
||||
| **免费账户** (已登录) | 每 6 小时 200 次请求 |
|
||||
| **Pro/Team 账户** | 无限制 |
|
||||
|
||||
#### 滥用限流 (Abuse Rate Limit)
|
||||
#### 滥用限流
|
||||
|
||||
除了上述针对特定账号拉取镜像数量的 Pull Rate Limit 之外,Docker Hub 对所有用户(包含已认证及付费用户)还实施了**滥用保护限流 (Abuse Rate Limiting)**。它是根据网络出口 IP (IPv4 或 IPv6 /64 子网) 计算整体请求频率,阈值动态触发(通常为每分钟数千级别请求)。
|
||||
除了上述针对特定账号拉取镜像数量的 Pull Rate Limit 之外,Docker Hub 对所有用户(包含已认证及付费用户)还实施了 **滥用保护限流 (Abuse Rate Limiting)**。它是根据网络出口 IP (IPv4 或 IPv6 /64 子网) 计算整体请求频率,阈值动态触发(通常为每分钟数千级别请求)。
|
||||
|
||||
**两类的差异与排查方法**:
|
||||
- **Pull Rate Limit**:针对拉取量达到上限。报错返回 `429 Too Many Requests`,并且 HTTP 返回体/CLI 错误提示中会带有明确的 `toomanyrequests: You have reached your pull rate limit` 提示,常附有账户升级链接。
|
||||
@@ -102,6 +102,7 @@ $ docker push username/myapp:v1
|
||||
在 Account Settings -> Security 中启用 2FA,保护账号安全。启用后,CLI 登录需要使用 **Access Token** 而非密码。
|
||||
|
||||
#### 2. 使用 Access Token
|
||||
|
||||
> **⚠️ 警告**:绝不要在脚本或 CI/CD 系统中,直接使用 `-p` 参数传递密码或 Token (类似 `docker login -p xxx`)!这会导致凭证直接暴露在系统的命令历史、进程列表和终端输出中。
|
||||
|
||||
1. 在 Docker Hub -> Account Settings -> Security -> Access Tokens 创建 Token (PAT)。
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -5,7 +5,7 @@
|
||||
| 功能 | 说明 |
|
||||
|------|------|
|
||||
| **官方镜像** | 优先使用的基础镜像 |
|
||||
| **拉取限制** | 匿名 100次/6h,登录 200次/6h |
|
||||
| **拉取限制** | 匿名 100 次/6h,登录 200 次/6h |
|
||||
| **安全** | 推荐开启 2FA 并使用 Access Token |
|
||||
| **自动化** | 支持 Webhooks 和自动构建 |
|
||||
|
||||
|
||||
@@ -1,7 +1,36 @@
|
||||
## 7.16 参考文档
|
||||
|
||||
* `Dockerfile` 官方文档:https://docs.docker.com/engine/reference/builder/
|
||||
### 官方文档
|
||||
|
||||
* `Dockerfile` 最佳实践文档:https://docs.docker.com/develop/develop-images/dockerfile_best-practices/
|
||||
* `Dockerfile` 官方参考手册:https://docs.docker.com/engine/reference/builder/
|
||||
|
||||
* `Docker` 官方镜像 `Dockerfile`:https://github.com/docker-library/docs
|
||||
* `Dockerfile` 最佳实践指南:https://docs.docker.com/develop/develop-images/dockerfile_best-practices/
|
||||
|
||||
* `Docker` 官方镜像 `Dockerfile` 库:https://github.com/docker-library/docs
|
||||
|
||||
### 常用指令总结
|
||||
|
||||
Dockerfile 中的常用指令包括:
|
||||
|
||||
- **FROM**: 指定基础镜像,必须是第一条指令
|
||||
- **RUN**: 在镜像中执行命令,用于安装软件包等
|
||||
- **WORKDIR**: 设置工作目录
|
||||
- **COPY/ADD**: 复制文件到镜像中
|
||||
- **EXPOSE**: 声明容器监听的端口
|
||||
- **ENV**: 设置环境变量
|
||||
- **ENTRYPOINT**: 容器启动时的入口点
|
||||
- **CMD**: 容器默认执行的命令
|
||||
|
||||
### 最佳实践建议
|
||||
|
||||
1. 使用具体的基础镜像版本标签而非 latest
|
||||
2. 最小化镜像层数,合并 RUN 指令
|
||||
3. 使用 .dockerignore 文件排除不必要的文件
|
||||
4. 安装必要的软件包后清理缓存
|
||||
5. 使用多阶段构建减小最终镜像体积
|
||||
6. 避免以 root 身份运行容器应用
|
||||
|
||||
### 相关资源
|
||||
|
||||
- Docker 官方镜像库:https://hub.docker.com/
|
||||
- Docker 镜像构建最佳实践:https://docs.docker.com/build/building/best-practices/
|
||||
|
||||
@@ -139,10 +139,10 @@ $ docker run -d \
|
||||
|------|---------|-----|
|
||||
| 语法 | 键值对,更清晰 | 冒号分隔,更简洁 |
|
||||
| **数据卷 (Volume)** 挂载行为 | 卷不存在会自动创建,与 `-v` 结果一致 | 卷不存在会自动创建 |
|
||||
| **绑定挂载 (Bind Mount)** 行为 | ⭐ **宿主机路径不存在会报错**,不会自动创建 | 宿主机路径不存在会**自动创建为目录** |
|
||||
| **绑定挂载 (Bind Mount)** 行为 | ⭐**宿主机路径不存在会报错**,不会自动创建 | 宿主机路径不存在会 **自动创建为目录** |
|
||||
| 推荐程度 | ✅ 推荐 (更明确安全,避免误创建)| 常用 (更简洁)|
|
||||
|
||||
> **提示**:官方更推荐使用 `--mount`。除了语法格式可读性更好之外,最重要的行为差异发生在 **绑定挂载 (Bind Mount)** 时:如果挂载的宿主机源路径尚未存在,`-v` 会擅自将其自动创建为一个空目录;而 `--mount` 则会严格检查并直接报错。这能有效避免因路径拼写错误而在宿主机上留下垃圾目录(以及导致的容器访问空目录问题)。而对于本节的**数据卷 (Volume)** 挂载而言,两者在目标指定的卷不存在时皆会自动创建卷,产生的结果是**完全一致**的。
|
||||
> **提示**:官方更推荐使用 `--mount`。除了语法格式可读性更好之外,最重要的行为差异发生在 **绑定挂载 (Bind Mount)** 时:如果挂载的宿主机源路径尚未存在,`-v` 会擅自将其自动创建为一个空目录;而 `--mount` 则会严格检查并直接报错。这能有效避免因路径拼写错误而在宿主机上留下垃圾目录(以及导致的容器访问空目录问题)。而对于本节的 **数据卷 (Volume)** 挂载而言,两者在目标指定的卷不存在时皆会自动创建卷,产生的结果是 **完全一致** 的。
|
||||
|
||||
#### 只读挂载
|
||||
|
||||
|
||||
@@ -74,10 +74,10 @@ $ docker run -d \
|
||||
| 特性 | --mount | -v |
|
||||
|------|---------|-----|
|
||||
| 语法 | 键值对,更清晰 | 冒号分隔,更简洁 |
|
||||
| 路径不存在时 | 直接报错 (Fail Fast) | 静默自动创建**目录** |
|
||||
| 路径不存在时 | 直接报错 (Fail Fast) | 静默自动创建 **目录** |
|
||||
| 推荐程度 | ✅ 推荐 | 常用 |
|
||||
|
||||
> **⚠️ 陷阱**:如果不小心挂载了一个不存在的宿主机路径,使用 `-v` 会在宿主机上静默创建一个**空目录**(即使你本来想挂载的是一个文件),这常常会导致权限错误或应用无法正常读取。这也正是为什么 Docker 官方更推荐使用 `--mount` 的原因:它会遵循“Fail Fast”原则直接报错,避免弄巧成拙。
|
||||
> **⚠️ 陷阱**:如果不小心挂载了一个不存在的宿主机路径,使用 `-v` 会在宿主机上静默创建一个 **空目录**(即使你本来想挂载的是一个文件),这常常会导致权限错误或应用无法正常读取。这也正是为什么 Docker 官方更推荐使用 `--mount` 的原因:它会遵循“Fail Fast”原则直接报错,避免弄巧成拙。
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ Docker 1.10.0 以后,内建了一个 DNS 服务器,使得容器可以直接
|
||||
Docker 容器的 DNS 配置有两种情况:
|
||||
|
||||
1. **默认 Bridge 网络**:继承宿主机的 DNS 配置 (`/etc/resolv.conf`)。
|
||||
2. **自定义网络** (推荐):使用 Docker 嵌入式 DNS 服务器 (Embedded DNS),支持通过 **容器名** 进行服务发现。
|
||||
2. **自定义网络**(推荐):使用 Docker 嵌入式 DNS 服务器 (Embedded DNS),支持通过 **容器名** 进行服务发现。
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -41,11 +41,11 @@ $ docker buildx build --sbom=true -t myimage .
|
||||
> **⚠️ 注意与失败模式**:
|
||||
> 要使 SBOM (或其它 attestation 元数据) 成功附着并可见,对底层的存储格式有前置要求:默认的 classic image store 不支持 manifest list/index 这种存放 attestation 的结构。
|
||||
>
|
||||
> 如果只简单运行上述命令,你可能会面临**“命令成功执行,但本地镜像中看不到 SBOM”**的体会落差。
|
||||
> 如果只简单运行上述命令,你可能会面临 **“命令成功执行,但本地镜像中看不到 SBOM”** 的体会落差。
|
||||
>
|
||||
> **正确的解决路径有两条**:
|
||||
> 1. 在 Docker 守护进程中启用 `containerd image store` 特性(现代 Docker Desktop 默认推荐)。
|
||||
> 2. 或者使用 `docker-container` driver 的构建器,并直接**加上 `--push` 参数**将产物推送到远端支持 OCI 的镜像仓库,仓库会正确保存这些元数据。
|
||||
> 2. 或者使用 `docker-container` driver 的构建器,并直接 **加上 `--push` 参数** 将产物推送到远端支持 OCI 的镜像仓库,仓库会正确保存这些元数据。
|
||||
|
||||
### 10.2.2 官方文档
|
||||
|
||||
|
||||
@@ -21,4 +21,3 @@ FCOS 使用 rpm-ostree 系统进行事务性升级。无需像 yum 升级那样
|
||||
#### 容器工具
|
||||
|
||||
对于诸如构建,复制和其他管理容器的任务,FCOS 用一组容器工具代替了 **Docker CLI**。**podman CLI** 工具支持许多容器运行时功能,例如运行,启动,停止,列出和删除容器和镜像。**skopeo CLI** 工具可以复制,认证和签名镜像。您还可以使用 **crictl CLI** 工具来处理 CRI-O 容器引擎中的容器和镜像。
|
||||
|
||||
|
||||
Binary file not shown.
@@ -1,6 +1,6 @@
|
||||
## 18.1 内核命名空间
|
||||
|
||||
命名空间 (Namespace) 是 Linux 容器隔离的基础,它确保了容器内的进程无法直接干扰主机或其他容器。虽然在本书第 12 章中我们已经从底层实现的角度介绍了 Namespace,但在本节中,我们将重点探讨其**安全意义**及相关配置。
|
||||
命名空间 (Namespace) 是 Linux 容器隔离的基础,它确保了容器内的进程无法直接干扰主机或其他容器。虽然在本书第 12 章中我们已经从底层实现的角度介绍了 Namespace,但在本节中,我们将重点探讨其 **安全意义** 及相关配置。
|
||||
|
||||
### 18.1.1 隔离的安全本质
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
## 18.2 控制组
|
||||
|
||||
控制组 (Cgroups) 是 Linux 容器机制的另外一个关键组件。如果说命名空间 (Namespace) 决定了容器能**看到**什么,那么控制组就决定了容器能**使用**多少资源。
|
||||
控制组 (Cgroups) 是 Linux 容器机制的另外一个关键组件。如果说命名空间 (Namespace) 决定了容器能 **看到** 什么,那么控制组就决定了容器能 **使用** 多少资源。
|
||||
|
||||
在安全领域中,资源的不可用性本身就是一种安全威胁。控制组负责实现资源的审计和限制,这对于抵御资源耗尽型攻击(如拒绝服务攻击 DoS)至关重要。
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
### 18.2.2 核心资源限制实战
|
||||
|
||||
为了确保多租户平台(如公有或私有的 PaaS 平台)的稳定性,或者在生产环境防止服务级联故障,我们要养成在启动容器时**显式声明资源上限**的习惯。
|
||||
为了确保多租户平台(如公有或私有的 PaaS 平台)的稳定性,或者在生产环境防止服务级联故障,我们要养成在启动容器时 **显式声明资源上限** 的习惯。
|
||||
|
||||
#### 1. 内存限制
|
||||
|
||||
|
||||
@@ -83,4 +83,4 @@ $ docker version
|
||||
|
||||
### 18.3.4 结语
|
||||
|
||||
保障 Docker 服务端的安全主要是做减法:关闭不必要的网络监听点,严管 Socket 访问权限。而一旦基础系统条件允许,**毫不犹豫地在生产环境启用 Rootless 模式**将是一项划算的安全加固选择。
|
||||
保障 Docker 服务端的安全主要是做减法:关闭不必要的网络监听点,严管 Socket 访问权限。而一旦基础系统条件允许,**毫不犹豫地在生产环境启用 Rootless 模式** 将是一项划算的安全加固选择。
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
### 18.4.1 容器内置的 Capability 白名单
|
||||
|
||||
在默认情况下,即便一个容器是在以 `root` 用户运行,Docker 也只为其内核授予了所有可用能力中的**一小部分“白名单”能力**。
|
||||
在默认情况下,即便一个容器是在以 `root` 用户运行,Docker 也只为其内核授予了所有可用能力中的 **一小部分“白名单”能力**。
|
||||
|
||||
常见的 Linux Capabilities 包含:
|
||||
- `CAP_CHOWN`: 修改文件所有者。
|
||||
@@ -14,7 +14,7 @@
|
||||
- `CAP_NET_ADMIN`: 网络管理的最高权限(例如调整路由配置,设置防火墙规则等)。
|
||||
- `CAP_SYS_ADMIN`: 被誉为“Linux 内核的特权网管”,允许各种高危操作(挂载磁盘、访问敏感设备等)。
|
||||
|
||||
为了在**“最小特权原则”**的指导下加强安全,Docker 默认**移除了**大量可能导致容器大范围破坏宿主机的能力,例如:
|
||||
为了在 **“最小特权原则”** 的指导下加强安全,Docker 默认 **移除了** 大量可能导致容器大范围破坏宿主机的能力,例如:
|
||||
* 完全禁止了任何通过 `CAP_SYS_ADMIN` 进行的核心挂载或设备操作。
|
||||
* 禁止修改内核模块。
|
||||
* 禁止直接访问硬件套接字。
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
#### 实战场景一:构建极限安全的 Web 靶机
|
||||
|
||||
假设你正在提供一个公共的 Web 容器。你不希望里面的任何恶意脚本修改进程权限或者创建设备节点,你可以通过命令先移除**所有**默认能力,然后再按需授权该守护进程一个仅仅能绑端口的能力。
|
||||
假设你正在提供一个公共的 Web 容器。你不希望里面的任何恶意脚本修改进程权限或者创建设备节点,你可以通过命令先移除 **所有** 默认能力,然后再按需授权该守护进程一个仅仅能绑端口的能力。
|
||||
|
||||
```bash
|
||||
$ docker run -d \
|
||||
@@ -56,7 +56,7 @@ $ docker run -it --rm \
|
||||
我们只授予了所需的网络管理控制(NET_ADMIN)和侦听底层套接字的权限(NET_RAW),而免去了赋予整个容器终极杀器 `--privileged` 参数。
|
||||
|
||||
> [!WARNING]
|
||||
> 大量开发人员遇到了“权限遭到拒绝”的错误时,往往习惯性图省事添加 `--privileged` 这个核选项。但这将把**宿主机上一切特权和所有访问设备完全投射给容器内的根用户**,其危险性等价于根本没有做隔离!请务必查明进程出错的实际原因,精准施加必要的隔离 `CAP_*` 能力。
|
||||
> 大量开发人员遇到了“权限遭到拒绝”的错误时,往往习惯性图省事添加 `--privileged` 这个核选项。但这将把 **宿主机上一切特权和所有访问设备完全投射给容器内的根用户**,其危险性等价于根本没有做隔离!请务必查明进程出错的实际原因,精准施加必要的隔离 `CAP_*` 能力。
|
||||
|
||||
### 18.4.3 总结
|
||||
|
||||
|
||||
@@ -85,4 +85,4 @@ Total: 2 (UNKNOWN: 0, LOW: 0, MEDIUM: 1, HIGH: 1, CRITICAL: 0)
|
||||
|
||||
### 18.5.4 容器核心层基石结语
|
||||
|
||||
到这里,Docker 为保障宿主和容器界限安全的几个护城河:从**资源剥离限制** (`Cgroups`) 到**进程/网络/身份蒙蔽** (`Namespace`)、到**特权能力回收** (`Capabilities`) 再到**内核强制策略拦截管制** (`Seccomp`/`AppArmor`) 已悉数交代完毕。虽然绝没有“100% 免疫网络穿刺的防线”,只要开发者牢记 **权限最小化原则** ,容器的堡垒就可以做到令攻击者望洋兴叹。
|
||||
到这里,Docker 为保障宿主和容器界限安全的几个护城河:从 **资源剥离限制**(`Cgroups`) 到 **进程/网络/身份蒙蔽**(`Namespace`)、到 **特权能力回收**(`Capabilities`) 再到 **内核强制策略拦截管制**(`Seccomp`/`AppArmor`) 已悉数交代完毕。虽然绝没有“100% 免疫网络穿刺的防线”,只要开发者牢记 **权限最小化原则** ,容器的堡垒就可以做到令攻击者望洋兴叹。
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
* **指标监控**:以 Prometheus + Grafana 为主,完成指标采集、存储与可视化。
|
||||
* **日志管理**:以 EFK/ELK 为例,完成容器日志的集中采集、检索与分析。
|
||||
|
||||
生产环境中,建议将“可观测性”当成一个完整闭环:**采集 -> 存储 -> 展示 -> 告警 -> 排错 -> 容量治理**。
|
||||
生产环境中,建议将”可观测性”当成一个完整闭环:**采集 -> 存储 -> 展示 -> 告警 -> 排错 -> 容量治理**。
|
||||
|
||||
## 19.3 Docker 日志驱动
|
||||
## 扩展阅读:Docker 日志驱动
|
||||
|
||||
Docker 提供了多种日志驱动 (Log Driver),用于将容器标准输出的日志转发到不同后端。
|
||||
|
||||
|
||||
@@ -81,7 +81,7 @@ deploy_staging:
|
||||
1. **不可变基础设施**:一旦镜像构建完成,在各个环境(Dev、Staging、Prod)中都应该使用同一个镜像 tag(通常是 commit hash),而不是重新构建。
|
||||
2. **配置分离**:使用 ConfigMap 和 Secret 管理环境特定的配置,不要打包进镜像。
|
||||
3. **应对 Docker Hub 限额 (Rate Limits)**:
|
||||
- Docker Hub 对匿名拉取实施了严格的限制 (6小时内约100次)。若在 CI/CD 中频繁构建,极易触发 `toomanyrequests` 错误。
|
||||
- Docker Hub 对匿名拉取实施了严格的限制 (6 小时内约 100 次)。若在 CI/CD 中频繁构建,极易触发 `toomanyrequests` 错误。
|
||||
- **最佳策略**:
|
||||
- 在流水线开头始终执行安全的身份认证 (使用 PAT,而非密码)。
|
||||
- 将常用的基础镜像缓存到自建的 Harbor/Nexus,使用 Pull-Through Cache。
|
||||
|
||||
@@ -84,7 +84,7 @@ npx honkit serve
|
||||
<img width="200" src="https://github.com/yeasy/docker_practice/raw/master/_images/donate.jpeg">
|
||||
</p>
|
||||
|
||||
<p align="center"><strong>欢迎鼓励项目一杯 coffee~</strong></p>
|
||||
<p align=“center”><strong>欢迎鼓励项目一杯 coffee~</strong></p>
|
||||
|
||||
## Star History
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
## 1. 安全与凭据处理
|
||||
|
||||
任何示例文档中都**严禁出现将凭据以明文形式直接传递给命令参数**的做法。
|
||||
任何示例文档中都 **严禁出现将凭据以明文形式直接传递给命令参数** 的做法。
|
||||
|
||||
* **错误示例**:`docker login -u myuser -p mysecretpassword` (这会导致密码泄露到历史记录及进程列表中)
|
||||
* **正确示例(交互式)**:推荐读者直接使用 `docker login` (优先使用官方 Device Code Flow)。
|
||||
@@ -17,7 +17,7 @@
|
||||
* **明确声明前置条件**:例如,“此功能需要开启 containerd image store” 或 “需要额外配置 `--push`”。
|
||||
* **描述失败现象**:明确告诉读者,“如果你不这么配置,命令仍会提示成功,但产物将不可见/被丢弃”。
|
||||
|
||||
## 3. 统一使用 "docker compose" 命令
|
||||
## 3. 统一使用 “docker compose” 命令
|
||||
|
||||
早期 Python 编写的 `docker-compose` (V1) 已停止支持。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user