Docker从入门到精通
Docker安装部署
Docker安装
安装前需要清理之前的安装环境,基于ubuntu24.04的命令如下,详细可参考docker官方文档Install Docker Engine on Ubuntu | Docker Docs
sudo apt remove $(dpkg --get-selections docker.io docker-compose docker-compose-v2 docker-doc docker-buildx podman-docker containerd runc | cut -f1)
我的是全新安装系统所以执行命令之后没有任何包被卸载清除。

接下来开始执行安装命令,执行如下命令
sudo apt update
sudo apt install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
sudo tee /etc/apt/sources.list.d/docker.sources <<EOF
Types: deb
URIs: https://download.docker.com/linux/ubuntu
Suites: $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}")
Components: stable
Architectures: $(dpkg --print-architecture)
Signed-By: /etc/apt/keyrings/docker.asc
EOF
sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
安装完毕后执行一下docker --version可以看到现在安装的版本是哪个

基础理论知识点

文件系统
- AUFS(Advanced Multilayered Unification Filesystem,版本 2 之前旧称 Another Union FS)是一种 Union FS,属于文件级存储驱动。Aufs 是 UnionFS 的重新实现,由 Junjiro Okajima 于 2006 年开发。UnionFS 的核心思想是将不同物理位置的目录合并挂载(mount)到同一目录下,简单来说,它支持将多个目录挂载到一个虚拟文件系统中,并允许层层叠加修改文件。底层所有层均为只读,仅最上层可写。当需要修改文件时,AUFS 会创建该文件的副本,通过写时复制(Copy-on-Write, CoW)机制将文件从只读层复制到可写层进行修改,结果保存在 Docker 中。其中,底层的只读层对应 image,可写层则对应 Container。
- aufs 曾被拒绝合并到 Linux 内核主线,其代码被批评为“dense, unreadable, uncommented”(密集、不可读、未注释)。相反,OverlayFS 被成功合并到 Linux 内核。在多次尝试将 aufs 合并到主线内核失败后,作者最终放弃了这一努力。
- AUFS 曾是 Docker 18.06 及更早版本的首选存储驱动程序,但在内核 3.13 上运行 Ubuntu 14.04 时不支持 overlay2。
- Overlay:一种 Union FS 文件系统,自 Linux 内核 3.18 起获得支持。
- Overlay2:Linux 内核中的一种联合文件系统(UnionFS),是 OverlayFS 的演进版本,专为容器场景设计。目前,所有 Linux 发行版推荐使用的存储类型,也是 Docker 默认的存储引擎即为 overlay2。它要求磁盘分区支持 d_type 功能,因此需要系统磁盘的额外支持。相较于 AUFS,Overlay2 具有以下优势:设计更简洁;自内核 3.18 起已进入 Linux 内核主线;资源消耗更少。Overlay2 依赖并建立在其他文件系统之上,不参与磁盘空间结构的划分,仅将底层文件系统中的不同目录“合并”后呈现给用户。用户看到的 overlay 文件系统根目录内容,实际上是挂载 overlay 文件系统时指定的不同目录的合集。Overlay2 支持多个 lower 层,但只有一个 upper 层。上层会覆盖下层相同的内容,用户最终看到的是 Merged 层。用户只能操作 Merged 层,所有操作变化都会记录在 upper 层中,而 lower 层的内容始终保持只读。
- devicemapper:由于 CentOS 7.2 和 RHEL 7.2 的早期版本内核不支持 overlay2,因此默认使用此存储驱动程序。但其最大数据容量仅支持 100GB,且性能不佳。当前较新版本的 CentOS 已支持 overlay2,故推荐使用 overlay2。此外,该存储引擎已在 Docker Engine 18.09 中弃用。
- ZFS (Sun - 2005) / btrfs (Oracle - 2007):目前尚未被广泛使用。
- vfs:适用于测试环境,当无法使用写时复制(copy-on-write)机制时可考虑此驱动。但其性能较差,通常不建议用于生产环境。
查看docker使用的默认存储引擎

说明:
| 对比项 | overlay2(Docker 原生) |
overlayfs(containerd 管理) |
|---|---|---|
| 管理层 | dockerd 直接管理 | 交给 containerd 的 snapshotter |
| 数据目录 | /var/lib/docker/overlay2/ |
/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/ |
| 触发方式 | 默认行为 | 需开启 containerd-snapshotter 特性 |
这是 Docker 较新版本从docker29.0引入的新架构,将存储管理交给 containerd 统一处理,是未来发展方向。底层都是 OverlayFS 联合文件系统,支持写时复制、分层存储等特性,性能无差异。overlay2 由 dockerd 直接管理,overlayfs 由 containerd 管理。
配置镜像加速
vim /etc/docker/daemon.json
{
"registry-mirrors": [
"https://docker.m.daocloud.io",
"https://docker.1panel.live",
"https://docker.1ms.run",
"https://hub.rat.dev",
"https://docker.fnnas.com",
"https://docker.unsee.tech",
"https://docker.hlmirror.com"
],
"log-driver": "json-file",
"log-opts": {
"max-size": "100m",
"max-file": "3"
}
}
保存退出后需要重启docker生效
systemctl restart docker
容器镜像管理
镜像结构和原理

镜像拉取
拉取了最新版的nginx镜像,使用docker image ls查看镜像版本信息,查看镜像分层信息docker image history nginx:latest
docker inspect查看镜像、容器具体信息
搜索镜像去hub.docker.com进行查找,以官方镜像为主。
镜像本地导出与导入
镜像导入,镜像导入只能导入单个镜像,现在删除从官方拉取的alpine镜像
常见用法docker load -i 压缩包名 docker load < 包名
清理dngling状态镜像
当像像信息中RESPOSITORY TAG字段为<none>时认定此镜你为dangling镜像,清除此类镜像和不使用的镜像使用docker image prune -a -f 慎用。
现在没有使用的镜像,使用docker image prune -a -f 试一下效果
已经全部清除。
镜像打标签
删除镜像
docker rmi 镜像名称/ID
容器操作
容器启动
docker run [选项] [镜像名] [shell命令] [参数]
docker run --name ubuntu_test -d -it --rm ubuntu:latest /bin/bash
启动一个名称为 ubuntu_test的容器,并从控制台终端连入,并在后台运行。
--name 启动的的容器名称
-d 后台运行
-it 生成一个终端连入
--rm 自动删除匿名卷,测试使用
--always 确保实现宿主机开机时自动启动容器
#说明 当 -d与-it同时使用时 docker强制忽略-i -t,上面的命令执行结果是启动了一个ubuntu_test的容器,但是没有连到终端,需要再次执行docker exec -it ubuntu_test /bin/bash才可以进入终端。
容器运行时容器名称要唯一
docker rm 容器名 清理已经关闭的容器 docker rm -f 清理运行中和已经关闭的容器慎用
dcoker ps 查看所有运行的容器
docker ps -a 显示全部容器包括退出状态容器
docker ps -a -s 显示容器大小
docker ps -f 'status=exit'查看退出状态的容器
docker stats 容器名 查看容器资源使用情况
docker stop 优雅关闭容器等待
docker kill 强制退出
docker logs 查看容器日志
快捷键cril+p+q退出容器不会停止容器
docker run -e MYSQL_ROOT_PASSWORD=123456 -e
MYSQL_DATABASE=wordpress -e MYSQL_USER=wordpress -e MYSQL_PASSWORD=123456 --name
mysql -d --restart=always registry.cnbeijing.aliyuncs.com/wangxiaochun/mysql:8.0.29-oracle
-e 后面接传递的环境变量 也可以以--env-flie将环境变量定义到文件中引用文件。
docker run -P 可以将事先容器预定义的所有端口映射宿主机的网卡的随机端口,默认从32768开始
使用随机端口 时,当停止容器后再启动可能会导致端口发生变化
docker run -p 3306:3306 将容器的3306端口映射为宿主机的3306 前一个是宿主机的端口后一个是容器的端口
docker run --dns --add-host
--dns 指定容器使用的DNS
--add-host www.test.com:x.x.x.x 增加hosts绑定条目
创建后【无法直接修改】的参数(必须重建容器)
| 参数 | 说明 |
|---|---|
--name |
容器名(但可以用 docker rename 改名,见下文) |
-p / --publish |
端口映射 |
-v / --volume |
数据卷挂载 |
--mount |
挂载(同 -v) |
--network |
加入哪个网络 |
--dns |
DNS 服务器 |
--dns-search |
DNS 搜索域 |
--dns-opt |
DNS 选项 |
--hostname |
主机名 |
--ip |
指定容器 IP |
--mac-address |
MAC 地址 |
--privileged |
特权模式 |
--cap-add / --cap-drop |
Linux 能力 |
--runtime |
运行时 |
--entrypoint |
入口点 |
| 镜像本身 | 容器基于哪个镜像 |
| 启动命令 CMD | 容器的主进程命令 |
创建后【可以修改】的少数参数
| 操作 | 命令 | 说明 |
|---|---|---|
| 改容器名 | docker rename 旧名 新名 |
运行中也能改 |
| 改重启策略 | docker update --restart=always 容器名 |
运行中也能改 |
| 改资源限制 | docker update --memory=512m --cpus=1.5 容器名 |
CPU/内存/blkio 等,运行中也能改 |
| 改暂停/恢复 | docker pause / unpause |
冻结进程 |
docker ps 查看运行中的容器

查看容器信息
docker inspect 容器名
{{.ID}}:容器的ID。
{{.Image}}:容器使用的映像名称。
{{.Command}}:容器的启动命令。
{{.CreatedAt}}:容器的创建时间。
{{.RunningFor}}:容器运行的时间。
{{.Ports}}:容器的端口映射信息。
{{.Status}}:容器的状态。
{{.Size}}:容器的大小。
{{.Names}}:容器的名称。
{{.Label}}:容器的标签。
容器内与宿主机之间数据拷贝
# 宿主机 → 容器
docker cp [选项] 宿主机路径 容器名:容器内路径
# 容器 → 宿主机
docker cp [选项] 容器名:容器内路径 宿主机路径
# 把宿主机的配置文件复制到容器内
docker cp /home/user/app.conf my-container:/etc/nginx/conf.d/app.conf
1、如果目标路径 /etc/nginx/conf.d/ 不存在,会创建
2、如果目标路径已存在同名文件,直接覆盖(无确认提示)
3、如果目标是一个目录(如 /etc/nginx/conf.d/),文件会被复制到该目录下,保留原文件名
场景 1:宿主机单个文件 → 容器
# 把宿主机的配置文件复制到容器内
docker cp /home/user/app.conf my-container:/etc/nginx/conf.d/app.conf
如果目标路径 /etc/nginx/conf.d/ 不存在,会报错
如果目标路径已存在同名文件,直接覆盖(无确认提示)
如果目标是一个目录(如 /etc/nginx/conf.d/),文件会被复制到该目录下,保留原文件名
场景 2:容器单个文件 → 宿主机
# 把容器内的日志拷出来分析
docker cp my-container:/var/log/nginx/access.log /tmp/access.log
容器必须存在(已停止的容器也可以,不需要运行中)
如果宿主机目标路径只写了目录 /tmp/,文件保留原名放入该目录
场景 3:宿主机整个目录 → 容器
# 把本地项目代码复制到容器里
docker cp /home/user/my-project/. my-container:/app/
⚠️ 注意末尾的 /.:
/home/user/my-project/. → 把目录内容复制到 /app/ 下(/app/file1, /app/file2)
/home/user/my-project (不带 /.)→ 把整个目录复制到 /app/my-project/ 下
# 对比效果
docker cp /src/my-project container:/app/ # → /app/my-project/...
docker cp /src/my-project/. container:/app/ # → /app/...(内容直接铺在 /app 下)
场景 4:容器整个目录 → 宿主机
# 备份容器内的数据目录
docker cp my-container:/var/lib/mysql/. /backup/mysql-data/
同样注意 /. 的含义,逻辑与上面一致。
场景 5:使用 -a 保留原始 UID/GID
docker cp -a /host/file.txt container:/container/file.txt
默认行为:复制到容器内的文件 UID/GID 会变成容器内当前用户的
加 -a(archive):保留源文件的原始 UID/GID 和权限位
当您需要保持文件属主不变时(比如数据库文件、证书密钥),务必加 -a
场景 6:从 STDIN/STDOUT 流式传输
# 通过管道把内容写入容器文件
echo "server_name example.com;" | docker cp - my-container:/etc/nginx/conf.d/custom.conf
# 把容器文件内容输出到 stdout(可配合重定向)
docker cp my-container:/etc/nginx/nginx.conf - > /tmp/nginx.conf
用 - 代替路径,表示从 stdin 读取或向 stdout 写入。适合脚本自动化、不想产生临时文件的场景。
docker cp 的重要特性与限制
✅ 支持的特性
| 特性 | 说明 |
|---|---|
| 容器无需运行 | 已停止(Exited)的容器也能 cp |
| 自动创建目标目录 | 目标父目录不存在时会自动创建(仅限单文件复制) |
| 符号链接 | 默认跟随符号链接(复制实际内容) |
-L 选项 |
始终跟随符号链接(与默认行为相同,显式声明) |
-q 选项 |
静默模式,不输出进度信息 |
❌ 不支持 / 需注意的限制
| 限制 | 说明 |
|---|---|
| 不能通配符 | docker cp container:/var/log/*.log /tmp/ ❌ 不支持 * 通配符 |
| 不能跨容器 | 只能宿主机↔容器,不能容器A→容器B |
| 不保留时间戳 | 默认不保留 mtime/atime(加 -a 可部分保留) |
| 大文件性能 | 走 Docker API,大文件/大量文件比 volume 慢 |
| 权限问题 | 容器内文件可能属于 root,拷到宿主机后仍是 root 属主 |
| SELinux/AppArmor | 某些安全策略可能阻止 cp 操作 |
通配符的解决办法
既然 docker cp 不支持通配符,可以这样绕过:
# 方法 1:在容器内用 exec + tar 打包再 cp
docker exec my-container tar cf - /var/log/*.log | tar xf - -C /tmp/
# 方法 2:先 cp 整个目录,再在宿主机筛选
docker cp my-container:/var/log/. /tmp/container-logs/
ls /tmp/container-logs/*.log
# 方法 3:exec + cat 单文件
docker exec my-container cat /var/log/error.log > /tmp/error.log
docker cp 不是唯一选择,不同场景有更优解:
| 方案 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
docker cp |
一次性拷贝少量文件 | 简单直接,容器无需运行 | 不支持通配符,大文件慢 |
Volume 挂载 (-v) |
持续共享目录 | 实时同步,性能最好 | 需创建时指定,事后无法添加 |
docker exec + 重定向 |
小文件/文本内容 | 灵活,可配合管道 | 不适合二进制/大文件 |
tar 管道 |
批量文件/保留权限 | 支持通配符,保留属性 | 命令较复杂 |
| Bind Mount | 开发环境实时编辑 | 宿主机改文件容器立即生效 | 同 Volume,需创建时指定 |
- 能够长期运行
- 无需交互式会话
- 适合运行应用程序和服务
镜像制作
知识点
1、镜像中没有内核
- 镜像为了更小和运行效率,镜像中是不包含内核的,而使用宿主机的内核
- 镜像本身则只提供应用所依赖的根文件系统和相关文件,即系统运行所必要的文件目录,比如: /sys, /dev/,/proc,/bin,/etc等目录 基于内核的名称空间实现容器的各种资源隔离
基于容器手动制镜像
- 安装基础命令
- 配置运行环境
- 安装服务和配置服务
- 放业务程序代码
基于ubuntu官方镜像安装nginx并手动commit制作镜像



nginx已经安装完毕,可以看到容器大小已经从45.4m变成了73.9m
修改一下html文件 welcome to nginx-test-docker并commit提交成新镜像ubuntu-test-nginx:v1.18.0

从制作的镜像启动容器并访问

访问测试

使用Dockerfile执行docker build自动构建镜像
dockerfile使用详解
Dockerfile文件格式
- Dockerfile 是一个有特定语法格式的文本文件
- dockerfile 官方说明: https://docs.docker.com/engine/reference/builder/
- 帮助: man 5 dockerfile
- 每一行以Dockerfile的指令开头,指令不区分大小写,但是惯例使用大写
- 使用 # 开始作为注释
- 每一行只支持一条指令,每条指令可以携带多个参数
- 指令按文件的顺序从上至下进行执行
- 每个指令的执行会生成一个新的镜像层,为了减少分层和镜像大小,尽可能将多条指令合并成一条指令
- 制作镜像一般可能需要反复多次,每次执行dockfile都按顺序执行,从头开始,已经执行过的指令已经缓存,不需要再执行,如果后续有一行新的指令没执行过,其往后的指令将会重新执行,所以为加速镜像制作,将最常变化的内容放下dockerfile的文件的后面
| 指令 | 英文描述 | 中文含义 | 详细说明 | 语法示例 |
|---|---|---|---|---|
| FROM | Create a new build stage from a base image | 指定基础镜像 | 必须是 Dockerfile 的第一条指令(ARG 除外)。定义从哪个镜像开始构建,可多次出现实现多阶段构建 | FROM ubuntu:26.04FROM nginx:latest AS builder |
| RUN | Execute build commands | 构建时执行命令 | 在镜像构建阶段执行命令,每执行一条就生成一个新的镜像层。常用于安装软件包 | RUN apt update && apt install -y nginx |
| CMD | Specify default commands | 指定容器默认启动命令 | 容器启动时执行的默认命令,可被 docker run 后的参数覆盖。一个 Dockerfile 只能有一个 CMD(多个则最后一个生效) |
CMD ["nginx", "-g", "daemon off;"] |
| ENTRYPOINT | Specify default executable | 指定容器入口程序 | 配置容器启动时的入口可执行程序,不易被覆盖,常与 CMD 配合(ENTRYPOINT 定程序,CMD 定默认参数) | ENTRYPOINT ["nginx"]CMD ["-g", "daemon off;"] |
| EXPOSE | Describe which ports your application is listening on | 声明监听端口 | 声明容器运行时监听的端口(仅文档作用,不会真正映射)。真正映射要靠 docker run -p |
EXPOSE 80EXPOSE 80/tcp 443/tcp |
| ENV | Set environment variables | 设置环境变量 | 设置环境变量,在构建和运行时都有效,会被子镜像继承 | ENV DEBIAN_FRONTEND=noninteractiveENV NGINX_VERSION=1.26 |
| ADD | Add local or remote files and directories | 添加文件/目录(高级) | 把本地文件/URL/压缩包复制到镜像。会自动解压 tar、自动下载 URL,功能比 COPY 强但行为不可预期 | ADD app.tar.gz /opt/ADD https://example.com/file /tmp/ |
| COPY | Copy files and directories | 复制文件/目录 | 把本地文件/目录复制到镜像。只做单纯复制,不解压不下载,行为可预期,优先于 ADD 使用 | COPY nginx.conf /etc/nginx/COPY . /app/ |
| VOLUME | Create volume mounts | 创建挂载点 | 声明一个挂载点,使该目录的数据持久化或可被宿主机/其他容器共享,绕过联合文件系统 | VOLUME /var/log/nginxVOLUME ["/data", "/config"] |
| WORKDIR | Change working directory | 设置工作目录 | 为后续的 RUN/CMD/COPY 等指令设置工作目录(相当于 cd),可多次使用(相对路径会叠加) | WORKDIR /appWORKDIR src # → /app/src |
| USER | Set user and group ID | 设置运行用户 | 指定后续 RUN/CMD/ENTRYPOINT 执行时的用户身份(UID/GID),出于安全建议不用 root | USER www-dataUSER 1000:1000 |
| ARG | Use build-time variables | 定义构建时变量 | 定义构建时(docker build)可用的变量,通过 --build-arg 传值,不会保留到运行时的镜像中 |
ARG VERSION=1.0RUN echo $VERSION构建: docker build --build-arg VERSION=2.0 . |
| LABEL | Add metadata to an image | 添加镜像元数据 | 给镜像添加键值对元数据(如作者、版本、描述),用于组织和查询,不影响运行 | LABEL maintainer="admin@example.com"LABEL version="1.0" description="nginx image" |
| HEALTHCHECK | Check a container's health on startup | 配置健康检查 | 告诉 Docker 如何检测容器是否健康,定期执行指定命令,结果反映在 docker ps 的 STATUS 列 |
HEALTHCHECK --interval=30s --timeout=3s CMD curl -f http://localhost/ || exit 1 |
| SHELL | Set the default shell of an image | 设置默认 Shell | 修改 RUN/CMD/ENTRYPOINT 使用 shell 形式时的默认 shell(Linux 默认 /bin/sh -c) |
SHELL ["powershell", "-command"]SHELL ["/bin/bash", "-c"] |
| STOPSIGNAL | Specify the system call signal for exiting a container | 设置停止信号 | 指定 docker stop 时发送给容器的系统调用信号(默认 SIGTERM),用于优雅退出 |
STOPSIGNAL SIGQUITSTOPSIGNAL 9 |
| ONBUILD | Specify instructions for when the image is used in a build | 设置触发器指令 | 注册一个触发器,当本镜像被用作其他镜像的 FROM 基础镜像时,触发的指令才在子镜像构建时执行 | ONBUILD RUN echo "被继承时执行"ONBUILD COPY . /app/ |
| MAINTAINER | Specify the author of an image | 指定镜像作者(已弃用) | 旧版指定作者的指令,已被弃用,现在推荐用 LABEL maintainer="..." 代替 |
MAINTAINER admin@example.com(❌ 弃用)改用 LABEL maintainer="..." |
FROM ... # 1. 基础镜像(必须第一)
LABEL ... # 2. 元数据
ARG ... # 3. 构建变量
ENV ... # 4. 环境变量
WORKDIR ... # 5. 工作目录
COPY 依赖文件 ... # 6. 先复制依赖(利用缓存)
RUN 安装依赖 ... # 7. 安装依赖
COPY 源码 ... # 8. 再复制源码(变动频繁,放后面)
RUN 编译/构建 ... # 9. 编译
VOLUME ... # 10. 挂载点
EXPOSE ... # 11. 声明端口
HEALTHCHECK ... # 12. 健康检查
USER ... # 13. 切换用户
ENTRYPOINT / CMD ... # 14. 启动命令(最后)

FROM: 指定基础镜像
FROM [--platform=<platform>] <image> [AS <name>]
FROM [--platform=<platform>] <image>[:<tag>] [AS <name>]
FROM [--platform=<platform>] <image>[@<digest>] [AS <name>]
#说明:
--platform 指定镜像的平台,比如: linux/amd64, linux/arm64, or windows/amd64
tag 和 digest是可选项,如果不指定,默认为latest
关于scratch 镜像
FROM scratch
参考链接:
https://hub.docker.com/_/scratch?tab=description
https://docs.docker.com/develop/develop-images/baseimages/
该镜像是一个空的镜像,可以用于构建busybox等超小镜像,可以说是真正的从零开始构建属于自己的镜像
该镜像在构建基础镜像(例如debian和busybox)或超最小镜像(仅包含一个二进制文件及其所需内容,例
如:hello-world)的上下文中最有用。
LABEL: 指定镜像元数据
可以指定定镜像元数据,如: 镜像作者等
LABEL <key>=<value> <key>=<value> <key>=<value> ...
LABEL "com.example.vendor"="ACME Incorporated"
LABEL com.example.label-with-value="foo"
LABEL version="1.0"
LABEL description="This text illustrates \
that label-values can span multiple lines."
一个镜像可以有多个label ,还可以写在一行中,即多标签写法,可以减少镜像的层数
范例: 多标签写法
#一行格式
LABEL multi.label1="value1" multi.label2="value2" other="value3"
#多行格式
LABEL multi.label1="value1" \
multi.label2="value2" \
other="value3
docker inspect 命令可以查看LABEL
"Labels": {
"com.example.vendor": "ACME Incorporated"
"com.example.label-with-value": "foo",
"version": "1.0",
"description": "This text illustrates that label-values can span multiple
lines.",
"multi.label1": "value1",
"multi.label2": "value2",
"other": "value3"
},
MAINTAINER: 指定维护者信息此指令已过时,用LABEL代替
RUN: 执行 shell 命令
#shell 格式: 相当于 /bin/sh -c <命令> 此种形式支持环境变量
RUN <命令>
#如果想使用其它shell,可以用SHELL指令指定不同的shell
SHELL ["/bin/bash", "-c"]
RUN <命令>
#exec 格式: 此种形式不支持环境变量,注意:是双引号,不能是单引号
RUN ["executable","param1","param2"...]
#exec格式可以指定其它shell
RUN ["/bin/bash","-c","echo hello wang"]
shell格式中,<command>通常是一个shell命令,且以"/bin/sh -c”来运行它,这意味着此进程在容器中
的PID不为1,不能接收Unix信号,因此,当使用docker stop <container>命令停止容器时,此进程接收
不到SIGTERM信号
exec格式中的参数是一个JSON格式的数组,其中<executable>为要运行的命令,后面的<paramN>为传递
给命令的选项或参数;然而,此种格式指定的命令不会以"/bin/sh -c"来发起,因此常见的shell操作如变
量替换以及通配符(?,*等)替换将不会进行;不过,如果要运行的命令依赖于此shell特性的话,可以将其替换
为类似下面的格式。
RUN ["/bin/bash", "-c", "<executable>", "<param1>"]
关于 shell 和 exec 形式
范例:shell 和 exec 格式比较
[root@ubuntu2204 alpine]#cat Dockerfile
FROM registry.cn-beijing.aliyuncs.com/wangxiaochun/alpine:3.20.0
LABEL maintainer="wangxiaochun<root@wangxiaochun.com>"
RUN sed -i 's@dl-cdn.alpinelinux.org@mirrors.tuna.tsinghua.edu.cn@'
/etc/apk/repositories
RUN apk add bash
RUN echo {1..10} > a.txt
RUN ["bash","-c","echo {1..10} > b.txt"]
[root@ubuntu2204 alpine]#docker run --rm -it alpine:3.20.0-2024-06-14_1718345655
cat b.txt
1 2 3 4 5 6 7 8 9 10
[root@ubuntu2204 alpine]#docker run --rm -it alpine:3.20.0-2024-06-14_1718345655
cat a.txt
{1..10}
RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
RUN ["/bin/bash", "-c", "echo hello world"]
RUN yum -y install epel-release \
&& yum -y install nginx \
&& rm -rf /usr/share/nginx/html/*
&& echo "<h1> docker test nginx </h1>" > /usr/share/nginx/html/index.html
FROM alpine:3.19.1
LABEL author=wang class=m57
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.tuna.tsinghua.edu.cn/'
/etc/apk/repositories && apk update && apk --no-cache add curl bash tzdata
&& ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
多个 前后RUN 命令独立无关和shell命令不同
#world.txt并不存放在/app内
RUN cd /app
RUN echo "hello" > world.txt
#下面写法可以实现关联关系
RUN cd /app && echo "hello" > world.txt
ENV: 设置环境变量
ENV 可以定义环境变量和值,会被后续指令(如:ENV,ADD,COPY,RUN等)通过$KEY或${KEY}进行引用,
并在容器运行时保持
#变量赋值格式1
ENV <key> <value> #此格式只能对一个key赋值,<key>之后的所有内容均会被视作其<value>的组成
部分
#变量赋值格式2
ENV <key1>=<value1> <key2>=<value2> \ #此格式可以支持多个key赋值,定义多个变量建议使用,
减少镜像层
<key3>=<value3> ...
#如果<value>中包含空格,可以以反斜线\进行转义,也可通过对<value>加引号进行标识;另外,反斜线也
可用于续行
#只使用一次变量
RUN <key>=<value> <command>
#引用变量
RUN $key .....
docker run -e|--env <key>=<value>
#说明
-e, --env list #Set environment variables
--env-file filename #Read in a file of environment variables
#格式1
ENV myName="John Doe" myDog=Rex\ The\ Dog \
myCat=fluffy
#格式2
ENV myName John Doe
ENV myDog Rex The Dog
ENV myCat fluffy
ENV VERSION=1.0 DEBUG=on NAME="Happy Feet"
ENV PG_MAJOR 9.3
ENV PG_VERSION 9.3.4
RUN curl -SL http://example.com/postgres-$PG_VERSION.tar.xz | tar -xJC
/usr/src/postgress && …
ENV PATH /usr/local/postgres-$PG_MAJOR/bin:$PATH
[root@ubuntu1804 dockerfile]#cat Dockerfile
FROM busybox
LABEL maintainer="wangxiaochun <root@wangxiaochun.com>"
ENV NAME wang xiao chun
RUN touch $NAME.txt
COPY: 复制文本
复制本地宿主机的 到容器中的 。
COPY [OPTIONS] [--chown=<user>:<group>] <src>... <dest>
COPY [OPTIONS] [--chown=<user>:<group>] ["<src>",... "<dest>"] #路径中有空白字符时,
建议使用此格式
可以是多个,可以使用通配符,通配符规则满足Go的filepath.Match 规则
filepath.Match 参考链接: https://golang.org/pkg/path/filepath/#Match
必须是build上下文中的相对路径(为 Dockerfile 所在目录的相对路径),不能是其父目录中的文
件
如果是目录,则其内部文件或子目录会被递归复制,但目录自身不会被复制
如果指定了多个, 或在中使用了通配符,则必须是一个目 录,且必须以 / 结尾
可以是绝对路径或者是 WORKDIR 指定的相对路径
使用 COPY 指令,源文件的各种元数据都会保留。比如读、写、执行权限、文件变更时间等
如果事先不存在,它将会被自动创建,这包括其父目录路径,即递归创建目录
COPY hom* /mydir/
COPY hom?.txt /mydir/
#多阶段构建
COPY --from=build /myapp /usr/bin/
ADD: 复制和解包文件
该命令可认为是增强版的COPY,不仅支持COPY,还支持自动解压缩。可以将复制指定的 到容器中的
说明:
可以是Dockerfile所在目录的一个相对路径;也可是一个 URL;还可是一个 tar 文件(自动解压)
可以是绝对路径或者是 WORKDIR 指定的相对路径
如果是目录,只复制目录中的内容,而非目录本身
如果是一个 URL ,下载后的文件权限自动设置为 600
如果为URL且不以/结尾,则指定的文件将被下载并直接被创建为,如果以 / 结尾,则文件名URL指定
的文件将被直接下载并保存为/< filename>
如果是一个本地文件系统上的打包文件,如: gz, bz2 ,xz ,它将被解包 ,其行为类似于"tar -x"命令,
但是通过URL获取到的tar文件将不会自动展开
如果有多个,或其间接或直接使用了通配符,则必须是一个以/结尾的目录路径;如果不以/结尾,则
其被视作一个普通文件,的内容将被直接写入到
ADD test relativeDir/ # adds "test" to `WORKDIR`/relativeDir/
ADD test /absoluteDir/ # adds "test" to /absoluteDir/
ADD --chown=55:mygroup files* /somedir/
ADD --chown=bin files* /somedir/
ADD --chown=1 files* /somedir/
ADD --chown=10:11 files* /somedir/
ADD ubuntu-xenial-core-cloudimg-amd64-root.tar.gz /
ADD nginx-1.26.2.tar.gz /usr/local/src
RUN apk --no-cache add gcc make libgcc libc-dev libcurl libc-utils pcre-dev
zlib-dev libnfs pcre pcre2 libevent libevent-dev && cd /usr/local/src/nginx-
1.26.2 && ./configure --prefix=/apps/nginx && make && make install && rm -rf
/usr/local/src/nginx-1.26.2
CMD: 容器启动命令
- 一个容器中通常需要一个持续运行的业务主进程
- CMD 用来指定启动容器时默认执行的一个初始命令
- 如果容器内没有一个持续运行的前台进程,容器会停止 所以一般CMD 指定的命令为持续运行且为前台命令,如果有多个命令,需要保证有一个命令是前台并持续 运行的 如果docker run没有指定任何的执行命令或者dockerfile里面也没有ENTRYPOINT命令,那么开启 容器时就会使用执行CMD指定的默认的命令
- RUN 命令是在构建镜像时执行的命令
- 每个 Dockerfile 只能有一条 CMD 命令。如指定了多条,只有最后一条被执行
- 如果用户启动容器时用 docker run xxx 指定运行的命令,则会覆盖 CMD 指定的命令
#https://docs.docker.com/reference/dockerfile/#shell-and-exec-form
#格式1:使用exec形式,推荐方式,第一个参数必须是命令的全路径,此种形式不支持环境变量,注意:是双引
号,不能是单引号
CMD ["executable","param1","param2"]
#格式2:shell形式,默认/bin/sh 中执行,提供给需要交互的应用;此种形式支持环境变量,相当于执行
/bin/sh -c "command param1 param2"
CMD command param1 param2
#指定不同的shell
#方法1
SHELL ["/bin/bash", "-c"]
CMD command param1 param2
#方法2
CMD ["/bin/bash", "-c","executable","param1","param2"]
#格式3:使用exec形式,提供给 ENTRYPOINT 命令的充当其参数
CMD ["param1","param2"]
范例:通过CMD基于alpine编译安装Nginx并结合脚本实现启动容器时的定制功能
CMD ["nginx", "-g", "daemon off;"]
CMD ["/apps/nginx/sbin/nginx", "-g","daemon off;"]
#如下格式报错
CMD /apps/nginx/sbin/nginx -g ”daemon off;"
构建镜像docker build 命令
docker build命令使用Dockerfile文件创建镜像
docker build [OPTIONS] PATH | URL | -
说明:
PATH | URL | - #可以使是本地路径,也可以是URL路径。若设置为 - ,则从标准输入获取
Dockerfile的内容
-f, --file string #Dockerfile文件名,默认为 PATH/Dockerfile
--force-rm #总是删除中间层容器,创建镜像失败时,删除临时容器
--no-cache #不使用之前构建中创建的缓存
-q --quiet=false #不显示Dockerfile的RUN运行的输出结果
--rm=true #创建镜像成功时,删除临时容器
-t --tag list #设置注册名称、镜像名称、标签。格式为 <注册名称>/<镜像名称>:<标签>(标签
默认为latest)
docker history 镜像ID查看镜像构建历史
使用Dockerfile构建基于Centos的nginx镜像
root@docker01:~/soft# cat Dockerfile
FROM quay.io/centos/centos:stream9
LABEL maintainer="kaikai<kaikai@126.com>"
RUN dnf install -y nginx && echo "nginx website2 in Docker" > /usr/share/nginx/html/index.html
ENV PEFRESH_DATA=2020-01-01
EXPOSE 81
CMD ["nginx", "-g", "daemon off;"]
因为Centos7 8都已经停止维护这里使用了stream 9

Doker容器数据管理
cat /proc/$(docker inspect -f '{{.State.Pid}}' 容器名称)/mountinfo | grep overlay
哪些数据需要持久化
容器数据持久保存方式
数据卷的特点和使用
数据卷使用场景
- 数据库
- 日志输出
- 静态web页面
- 应用配置文件
- 多容器间目录或文件共享
数据卷的特点
- 数据卷是目录或者文件,并且可以在多个容器之间共同使用,实现容器之间共享和重用
- 对数据卷更改数据在所有容器里面会立即更新
- 数据卷的数据可以持久保存,即使删除使用使用该容器卷的容器也不影响
- 在容器里面的写入数据不会影响到镜像本身,即数据卷的变化不会影响镜像的更新
- 依赖于宿主机目录,宿主机出问题,上面容器会受影响,当宿主机较多时,不方便统一管理
-
匿名和命名数据卷在容器启动时初始化,如果容器使用的镜像在挂载点包含了数据,会拷贝到新初 始化的数据卷中
数据卷分类
- 指定宿主机目录或文件: 指定宿主机的具体路径和容器路径的挂载关系,此方式不会创建数据卷
- 匿名卷: 不指定数据名称,只指定容器内目录路径充当挂载点,docker自动指定宿主机的路径进行挂 载,此方式会创建匿名数据卷,Dockerfile中VOLUME指定的卷即为此种
- 命名卷: 指定数据卷的名称和容器路径的挂载关系,此方式会创建命名数据卷
数据卷使用方法
-v, --volume=[host-src:]container-dest[:<options>]
<options>
ro 从容器内对此数据卷是只读,不写此项默认为可读可写
rw 从容器内对此数据卷可读可写,此为默认值
host-src 宿主机目录如果不存在,会自动创建
container-dest 容器目录如果不存在,会自动创建
绑定挂载
#指定宿主机目录或文件格式:
-v <宿主机绝对路径的目录(文件)或者相对路径的文件>:<容器目录或文件>[:ro] #将宿主机目录挂载容
器目录,两个目录都可自动创建
#注意:如果初始容器中有旧数据,将被宿主机目录覆盖
#注意:如果挂载文件,必须指定文件的相对(以.开头的相对路径)或绝对路径,否则会将目录名或文件名当成
命名卷
匿名卷
#匿名卷,只指定容器内路径,没有指定宿主机路径信息,宿主机自动生成/var/lib/docker/volumes/<卷
ID>/_data目录,并挂载至容器指定路径
#注意:如果初始容器中有旧数据,将被复制到宿主机数据卷目录
-v <容器内路径>
#示例:
docker run --name nginx -v /etc/nginx nginx
命名卷
#命名卷将固定的存放在/var/lib/docker/volumes/<卷名>/_data
#注意:如果初始容器中有旧数据,将被复制到宿主机数据卷目录
-v <卷名>:<容器目录路径>
#可以通过以下命令事先创建,如可没有事先创建卷名,docker run时也会自动创建卷
docker volume create <卷名>
#示例:
docker volume create vol1 #也可以事先不创建
docker run -d -p 80:80 --name nginx01 -v vol1:/usr/share/nginx/html nginx
docker volume COMMAND
Commands:
create Create a volume
inspect Display detailed information on one or more volumes
ls List volumes
prune Remove all unused local volumes
rm Remove one or more volumes
docker inspect --format="{{.Mounts}}" <容器ID>
范例: 删除所有数据卷
docker volume rm `docker volume ls -q`
创建命名卷并删除


删除不再使用的数据卷
docker volume prune -f 慎用
关于匿名数据卷和命名数据卷
命名卷就是有名字的卷,使用 docker volume create <卷名> 形式创建并命名的卷;而匿名卷就是没名
字的卷,一般是 docker run -v /data 这种不指定卷名的时候所产生,或者 Dockerfile 里面的定义
直接使用的。
有名字的卷,在用过一次后,以后挂载容器的时候还可以使用,因为有名字可以指定。所以一般需要保存的数
据使用命名卷保存。
而匿名卷则是随着容器建立而建立,随着容器消亡而淹没于卷列表中(对于 docker run 匿名卷不会被自动
删除)。 因此匿名卷只存放无关紧要的临时数据,随着容器消亡,这些数据将失去存在的意义。
Dockerfile中指定VOLUME为匿名数据卷,其目的只是为了将某个路径确定为卷。
按照最佳实践的要求,不应该在容器存储层内进行数据写入操作,所有写入应该使用卷。如果定制镜像的时
候,就可以确定某些目录会发生频繁大量的读写操作,那么为了避免在运行时由于用户疏忽而忘记指定卷,导
致容器发生存储层写入的问题,就可以在 Dockerfile 中使用 VOLUME 来指定某些目录为匿名卷。这样即
使用户忘记了指定卷,也不会产生不良的后果。
这个设置可以在运行时覆盖。通过 docker run 的 -v 参数或者 docker-compose.yml 的 volumes
指定。使用命名卷的好处是可以复用,其它容器可以通过这个命名数据卷的名字来指定挂载,共享其内容(不
过要注意并发访问的竞争问题)。
比如,Dockerfile 中说 VOLUME /data,那么如果直接 docker run,其 /data 就会被挂载为匿名
卷,向 /data 写入的操作不会写入到容器存储层,而是写入到了匿名卷中。但是如果运行时 docker run
-v mydata:/data,这就覆盖了 /data 的挂载设置,要求将 /data 挂载到名为 mydata 的命名卷中。
所以说 Dockerfile 中的 VOLUME 实际上是一层保险,确保镜像运行可以更好的遵循最佳实践,不向容器
存储层内进行写入操作。
数据卷默认可能会保存于 /var/lib/docker/volumes,不过一般不需要、也不应该访问这个位置。
mysql操作实例--绑定挂载

说明:nginx tomcat如果要加载宿主机的配置文件前提是宿主机相关的目录中要有配置正确的文件,需要事先在本地配置好,启动指定容器时加载进去。
docker run -d -v
/data/bin/catalina.sh:/apps/tomcat/bin/catalina.sh:ro -v
/data/testapp:/data/tomcat/webapps/testapp -v /data/logs:/apps/tomcat/logs -p
8080:8080 tomcat-web:app1
nginx我做实验时只是加载了目录因为里面没有配置文件没有正常创建启动
docker run --name test -v /data/testdir/conf:/etc/nginx -v /data/testdir/html:/usr/share/nginx/html nginx_centos9:v1.18.0
nginx: [emerg] open() "/etc/nginx/nginx.conf" failed (2: No such file or directory)
匿名数据卷实战
匿名卷 -v 后面是挂载到容器内的目录,执行启动后docker会在/var/lib/docker/volumes目录下生成一个目录,并将生成这个目录中的子目录_data挂载到指定的-v后的目录中,并可以读写这个目录中的文件,清除容器后宿主机中的这个目录中的文件不丢失。
已经启动了一个容器,容器中的nginx html目录中有两个文件。

上面的操作是将nginx-test容器关闭,清理,现在启动一个新的nginx-test容器,并将匿名卷挂载到容器的/usr/share/nginx/html目录下,进行实验。



最后再总结一下匿名卷
- 挂载方向:严格来说是宿主机的
_data目录挂载到容器内的指定路径,容器内对该路径的读写实际上就是在操作宿主机_data目录中的文件。 - 数据保留的前提:删除容器(
docker rm)不会删除匿名卷,数据保留。但如果手动执行docker volume rm <卷名>或docker volume prune,卷及其数据才会被真正删除。 - 匿名卷的缺点:由于卷名是随机哈希值,没有可读性,时间久了很难分辨哪个卷属于哪个容器,因此生产环境更推荐使用具名卷(
-v my-volume:/容器内路径)。
命名卷实战
创建命名数据卷
docker volume create vol

使用命名数据卷创建容器
docker run -d --name nginx-test -p 8080:80 -v vol1:/usr/share/nginx/html nginx:latest




创建容器时自动创建命名数据卷
docker run -d --name nginx-test1 -p 8081:80 -v vol2:/usr/share/nginx/html nginx:latest


访问验证

说明:vol1是之前创建并挂载到过nginx-test的,之后nginx-test容器清除,然后这个里面有了我已经修改过的index.html,这时我们验证得到生效的文件是vol1上的index.html,说明命名卷里文件会覆盖容器目录中的文件。
vol2自动创建命名系统挂载到容器内的/usr/share/nginx/html中时原来里央没有文件,容器会以容器内这个目录有的文件进行生效。
Docker 卷挂载时:如果卷是空的,容器内目录的文件会复制到卷中;如果卷已有数据,则卷中的数据会直接覆盖容器目录的内容。对像是目录级别的操作。
数据卷容器
- 在Dockerfile中创建的是匿名数据卷,无法直接实现多个容器之间共享数据
- 数据卷容器主要的功能是可以让数据在多个docker容器之间共享
备份还原
#在执行备份命令容器上执行备份方式
docker run -it --rm --volumes-from [container name] -v $(pwd):/backup ubuntu
root@ca5bb2c1f877:/#tar cvf /backup/backup.tar [container data volume]
#说明
[container name] #表示需要备份的匿名数据卷的容器
[container data volume] #表示容器内的需要备份的匿名数据卷对应的目录
#还原方式
docker run -it --rm --volumes-from [container name] -v $(pwd):/backup ubuntu
root@ca5bb2c1f877:/#tar xvf /backup/backup.tar -C [container data volume]
实战使用数据卷容器备份mysql数据库
1、启动一个mysql容器,默认使用的匿名卷
docker run -d --name mysql-test -p 3306:3306 -e MYSQL_ROOT_PASSWORD=work123 mysql:8.0
2、查看这个容器的匿名卷信息
docker volume ls
DRIVER VOLUME NAME
local 93df89073a1ffb0449f329f7276ff2a8db8b157f25d11218b8fd53167ebdb4f9
local vol1
local vol2
root@docker01:~# docker inspect mysql-test --format="{{.Mounts}}"
[{volume 93df89073a1ffb0449f329f7276ff2a8db8b157f25d11218b8fd53167ebdb4f9 /var/lib/docker/volumes/93df89073a1ffb0449f329f7276ff2a8db8b157f25d11218b8fd53167ebdb4f9/_data /var/lib/mysql local true }]
3、写入一点测试数据
docker exec -it mysql-test /bin/bash
输入用户名密码登陆数据库并创建测试库
mysql> create database testdb;
Query OK, 1 row affected (0.00 sec)
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
| testdb |
+--------------------+
4、创建数据卷容器
root@docker01:~# docker create --name volume-server --volumes-from mysql-test alpine:3.24.1
dc05b8c34ef58e9fa3a5503ac3484d09702d49723a58ee678595271c70d9b82c
root@docker01:~# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
dc05b8c34ef5 alpine:3.24.1 "/bin/sh" 3 seconds ago Created volume-server
51a88de14ae5 mysql:8.0 "docker-entrypoint.s…" 29 minutes ago Up 29 minutes 0.0.0.0:3306->3306/tcp, [::]:3306->3306/tcp, 33060/tcp mysql-test
5、使用临时容器备份数据
在root目录下创建backup目录
mkdir backup
root@docker01:~# docker run --rm --volumes-from mysql-test -v /root/backup:/backup alpine:3.24.1 tar cvf /backup/mysql-bak.tar -C /var/lib/mysql .
./
./testdb/
./testdb/users.ibd
./ibtmp1
./mysql.sock
./#innodb_temp/
./#innodb_temp/temp_6.ibt
./#innodb_temp/temp_5.ibt
root@docker01:~# cd backup/
root@docker01:~/backup# ls
mysql-bak.tar
6、清除mysql-test容器,这时匿名卷还在
root@docker01:~# docker rm -f mysql-test
mysql-test
root@docker01:~# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
root@docker01:~# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
dc05b8c34ef5 alpine:3.24.1 "/bin/sh" 5 minutes ago Created volume-server
root@docker01:~# docker volume ls
DRIVER VOLUME NAME
local 93df89073a1ffb0449f329f7276ff2a8db8b157f25d11218b8fd53167ebdb4f9
7、启动一个新的mysql-test容器
root@docker01:~# docker run -d --name mysql-test -p 3306:3306 mysql:8.0
45b8984bc65019c67aa3b771ebd8550388ac67234ca33ef1b1ed393469f34515
root@docker01:~# docker volume ls
DRIVER VOLUME NAME
local 93df89073a1ffb0449f329f7276ff2a8db8b157f25d11218b8fd53167ebdb4f9
local a800d7ad8096ca2566fc5831cd00348be2eed0f63c535122987a6fc9d48c1b91
root@docker01:~# docker inspect mysql-test --format="{{.Mounts}}"
[{volume a800d7ad8096ca2566fc5831cd00348be2eed0f63c535122987a6fc9d48c1b91 /var/lib/docker/volumes/a800d7ad8096ca2566fc5831cd00348be2eed0f63c535122987a6fc9d48c1b91/_data /var/lib/mysql local true }] 现在新的容器的匿名卷是a800d7ad8096ca2566fc5831cd00348be2eed0f63c535122987a6fc9d48c1b91
8、数据还原
root@docker01:~# docker stop mysql-test
mysql-test
root@docker01:~# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
45b8984bc650 mysql:8.0 "docker-entrypoint.s…" 4 minutes ago Exited (1) 4 minutes ago mysql-test
dc05b8c34ef5 alpine:3.24.1 "/bin/sh" 14 minutes ago Created volume-server
root@docker01:~# docker run --rm --volumes-from mysql-test -v /root/backup:/backup alpine:3.24.1 sh -c "rm -f /var/lib/mysql/* && tar xvf /backup/mysql-bak.tar -C /var/lib/mysql"
9、数据验证
docker exec -it mysql-restored mysql -uroot -pwork123 -e "USE testdb; SELECT * FROM users;"
+----+--------+
| id | name |
+----+--------+
| 1 | 张三 |
| 2 | 李四 |
| 3 | 王五 |
+----+--------+
数据卷容器总结
Docke网络管理
Docker安装后默认的网络设置
创建容器后的网络配置
同一个宿主机的不同容器可相互通信
#dockerd 的 --icc=false 选项可以禁止同一个宿主机的不同容器间通信
/etc/docker/daemon.json
{
"registry-mirrors": ["https://xxx"],
"icc": false
}
#添加--icc选项,本质上就是修改iptables规则 -A FORWARD -i docker0 -o docker0 -j
ACCEPT修改为DROP
vim /etc/docker/daemon.json
{
"bip": "192.168.100.1/24",
"registry-mirrors": ["https://xx.xx.com"]
}
apt -y install bridge-utils
#brctl addbr br0
给网桥添加IP,用于给容器分配置IP,如果不指定IP,会自动向后续网段,默认是172.18.0.0/16
以上操作是增加一个新的br0
容器名称互联
- 容器名称
- 容器名称的别名
--link list #Add link to another container
格式:
docker run --name <容器名称> #先创建指定名称的容器
docker run --link <目标通信的容器ID或容器名称> #再创建容器时引用上面容器的名称
root@docker01:~# docker run --name test1 -it --rm alpine:3.24.1 sh
/ # ls
bin dev etc home lib media mnt opt proc root run sbin srv sys tmp usr var
/ # cat /etc/hosts
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00:: ip6-localnet
ff00:: ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.2 f9c8f5eb1399
root@docker01:/etc/docker# docker run -it --name test2 --link test1 alpine:3.24.1 sh
WARNING: Links on the default bridge network are deprecated and will be removed in a future release. Use a custom network instead.
/ # cat /etc/hosts
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00:: ip6-localnet
ff00:: ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.2 test1 f9c8f5eb1399
172.17.0.3 cd2c6a478fb3
在test1上ping test2
/ # ping test2
ping: bad address 'test2'
/ #
在test2上ping test1
/ # ping test1
PING test1 (172.17.0.2): 56 data bytes
64 bytes from 172.17.0.2: seq=0 ttl=64 time=0.176 ms
64 bytes from 172.17.0.2: seq=1 ttl=64 time=0.126 ms
^C
--- test1 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.126/0.151/0.176 ms
新建第二个容器时引用第一个容器的名称
会自动将第一个主机的名称加入/etc/hosts文件,从而可以利用第一个容器名称进行访问
通过自定义容器别名互联
docker run --name <容器名称>
#先创建指定名称的容器
docker run --name <容器名称> --link <目标容器名称>:"<容器别名1> <容器别名2> ..."
#给上面创建的容器起别名,来创建新容器
root@docker01:~# docker run -it --name test3 --rm --link test1:test1-alias alpine:3.24.1
/ # cat /etc/hosts
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00:: ip6-localnet
ff00:: ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.2 test1-alias f9c8f5eb1399 test1
172.17.0.4 da1dcbfb0581
/ # ping test1
PING test1 (172.17.0.2): 56 data bytes
64 bytes from 172.17.0.2: seq=0 ttl=64 time=0.159 ms
64 bytes from 172.17.0.2: seq=1 ttl=64 time=0.043 ms
^C
--- test1 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.043/0.101/0.159 ms
/ # ping test1-alias
PING test1-alias (172.17.0.2): 56 data bytes
64 bytes from 172.17.0.2: seq=0 ttl=64 time=0.075 ms
64 bytes from 172.17.0.2: seq=1 ttl=64 time=0.044 ms
Docker 网络连接模式
root@docker01:~# docker network ls
NETWORK ID NAME DRIVER SCOPE
39c48a5e6c06 bridge bridge local
b72c03e4a37d host host local
1325c077d0cb none null local
docker run --network <mode>
docker run --net=<mode>
<mode>: 可是以下值
none
bridge
host
container:<容器名或容器ID>
<自定义网络名称>
Bridge 网络模式架构
- 网络资源隔离: 不同宿主机的容器无法直接通信,各自使用独立网络
- 无需手动配置: 容器默认自动获取172.17.0.0/16的IP地址,此地址可以修改
- 可访问外网: 利用宿主机的物理网卡,SNAT连接外网
- 外部主机无法直接访问容器: 可以通过配置DNAT接受外网的访问
- 低性能较低: 因为可通过NAT,网络转换带来更的损耗
- 端口管理繁琐: 每个容器必须手动指定唯一的端口,容器产生端口冲容
查看bridge模式信息
root@docker01:~# docker network inspect bridge
[
{
"Name": "bridge",
"Id": "39c48a5e6c0629087e10224cfcbee314b2ebd73d9c02aab05819766784b4c96b",
"Created": "2026-08-22T02:30:16.257253917Z",
"Scope": "local",
"Driver": "bridge",
"EnableIPv4": true,
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
"Subnet": "172.17.0.0/16",
"Gateway": "172.17.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Options": {
"com.docker.network.bridge.default_bridge": "true",
"com.docker.network.bridge.enable_icc": "true",
"com.docker.network.bridge.enable_ip_masquerade": "true",
"com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
"com.docker.network.bridge.name": "docker0",
"com.docker.network.driver.mtu": "1500"
},
"Labels": {},
"Containers": {},
"Status": {
"IPAM": {
"Subnets": {
"172.17.0.0/16": {
"IPsInUse": 3,
"DynamicIPsAvailable": 65533
}
}
}
}
}
]
root@docker01:~# cat /proc/sys/net/ipv4/ip_forward
1
修改Bridge网络配置方法
#vim /etc/docker/daemon.json
{
"hosts": ["tcp://0.0.0.0:2375", "fd://"],
"bip": "192.168.100.100/24", #分配docker0网卡的IP,24是容器IP的netmask
"fixed-cidr": "192.168.100.128/26", #分配容器IP范围,26不是容器IP的子网掩码,只表示地址
范围
"fixed-cidr-v6": "2001:db8::/64",
"mtu": 1500,
"default-gateway": "192.168.100.200", #网关必须和bip在同一个网段
"default-gateway-v6": "2001:db8:abcd::89",
"dns": [ "1.1.1.1", "8.8.8.8"]
}
Host模式
- 使用参数 --network host 指定
- 共享宿主机网络
- 各容器网络无隔离
- 网络性能无损耗
- 网络故障排除相对简单
- 容易产生端口冲突
- 网络资源无法分别统计
- 不支持端口映射
None模式
Container 模式
- 使用参数 –-network container:名称或ID 指定
- 与宿主机网络空间隔离
- 容器间共享网络空间,直接使用对方的网络
- 第一个容器的网络可能是bridge,或none,或者host,而第二个容器模式依赖于第一个容器,它们共享网络
- 如果第一个容器停止,将导致无法创建第二个容器
- 第二个容器可以直接使用127.0.0.1访问第一个容器
- 适合频繁的容器间的网络通信
- 默认不支持端口映射,较少使用
自定义网络模式
docker network create -d <mode> --subnet <CIDR> --gateway <网关> <自定义网络名称>
#注意mode不支持host和none,默认是bridge模式
-d <mode> 可省略,默认为bridge,支持bridge,overlay,macvlan等driver模式
查看自定义网络
docker network inspect <自定义网络名称或网络ID>
引用自定义网络
docker run --network <自定义网络名称> <镜像名称>
docker run --net <自定义网络名称> --ip <指定静态IP> <镜像名称>
#注意:静态IP只支持自定义网络模型
#指定自定义网络中的容器的别名
docker run --network <自定义网络名称> --network-alias list <镜像名称>
删除自定义网络
doccker network rm <自定义网络名称或网络ID
内置的三个网络无法删除 none host bridge
root@docker01:~# docker network create -d bridge --subnet 172.27.0.0/16 --gateway 172.27.0.1 test-net
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
link/ether e2:82:c7:70:d6:75 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
valid_lft forever preferred_lft forever
inet6 fe80::e082:c7ff:fe70:d675/64 scope link
valid_lft forever preferred_lft forever
62: br-6c38466c3d81: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
link/ether ba:f0:6a:d9:f7:75 brd ff:ff:ff:ff:ff:ff
inet 172.27.0.1/16 brd 172.27.255.255 scope global br-6c38466c3d81
valid_lft forever preferred_lft forever
root@docker01:~#
br-6c38466c3d81 自定义网络的新虚拟网卡
root@docker01:~# brctl show
bridge name bridge id STP enabled interfaces
br-6c38466c3d81 8000.baf06ad9f775 no 新加的一个网桥
docker0 8000.e282c770d675 no




在同一个自定义网络中两个容器通过IP和容器名都可以通信。
1、创建自定义网络
root@docker01:~# docker network create -d bridge --subnet 172.27.0.0/16 --gateway 172.27.0.1 test-net
2、创建6个redis容器所需的配置目及配置文件
for port in {1..6};do
mkdir -p /data/redis/node-${port}/conf
cat >> /data/redis/node-${port}/conf/redis.conf << EOF
port 6379
bind 0.0.0.0
masterauth work123
requirepass work123
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
cluster-announce-ip 172.27.0.1${port}
cluster-announce-port 6379
cluster-announce-bus-port 16379
appendonly yes
EOF
done
3、创建6个容器
root@docker01:~# for port in {1..6};do
> docker run -p 637${port}:6379 -p 1667${port}:16379 --name redis-${port} \
> -v /data/redis/node-${port}/data:/data \
> -v /data/redis/node-${port}/conf:/etc/redis \
> -d --net test-net --ip 172.27.0.1${port} redis:8.8-alpine redis-server /etc/redis/redis.conf
> done
4、创建redis cluster
登陆到一个redis容器节点进行cluster配置
root@docker01:~# docker exec -it redis-3 sh
/data # redis-cli -a work123 --cluster create 172.27.0.11:6379 172.27.0.12:6379 172.27.0.13:6379 172.27.0.14:6379 172.27.0.15:6379 172.27.0.16:6379 --
cluster-replicas 1
5、测试集群访问
root@docker01:~# docker exec -it redis-5 sh
/data # redis-cli -a work122 -c
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
AUTH failed: WRONGPASS invalid username-password pair or user is disabled.
127.0.0.1:6379> exit
/data # redis-cli -a work123 -c
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:6379> cluster info
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:3
cluster_current_epoch:6
cluster_my_epoch:1
cluster_stats_messages_ping_sent:294
127.0.0.1:6379> cluster nodes
5b912482f713898648fdbafaaa6ac3ad6960c356 172.27.0.14:6379@16379 slave a69d8482f24a4340ebfd7a97fbec19c1e761c8f9 0 1787410632413 3 connected
9ddfd4111f64bcf978e29f23f3f83118a94d1f18 172.27.0.12:6379@16379 master - 0 1787410631000 2 connected 5461-10922
1c2099ff82953880846ed11a58249a63fa402ddd 172.27.0.15:6379@16379 myself,slave 31e235870bb06b79bc700b44e2b859c09653e292 0 0 1 connected
31e235870bb06b79bc700b44e2b859c09653e292 172.27.0.11:6379@16379 master - 0 1787410632110 1 connected 0-5460
a69d8482f24a4340ebfd7a97fbec19c1e761c8f9 172.27.0.13:6379@16379 master - 0 1787410632513 3 connected 10923-16383
4bfa5fd0cdb8e5e6efb64900d9efd397d1cf629f 172.27.0.16:6379@16379 slave 9ddfd4111f64bcf978e29f23f
127.0.0.1:6379> set name kaikai
-> Redirected to slot [5798] located at 172.27.0.12:6379
OK
172.27.0.12:6379> set age 18
-> Redirected to slot [741] located at 172.27.0.11:6379
OK
172.27.0.11:6379> set study docker
-> Redirected to slot [8312] located at 172.27.0.12:6379
OK
172.27.0.12:6379> get name
"kaikai"
172.27.0.12:6379> get age
-> Redirected to slot [741] located at 172.27.0.11:6379
"18"
172.27.0.11:6379> get study
-> Redirected to slot [8312] located at 172.27.0.12:6379
"docker"
6、模拟一个节点故障
>>> Performing Cluster Check (using node 127.0.0.1:6379)
M: 9ddfd4111f64bcf978e29f23f3f83118a94d1f18 127.0.0.1:6379
slots:[5461-10922] (5462 slots) master
1 additional replica(s)
S: 4bfa5fd0cdb8e5e6efb64900d9efd397d1cf629f 172.27.0.16:6379
slots: (0 slots) slave
replicates 9ddfd4111f64bcf978e29f23f3f83118a94d1f18
M: a69d8482f24a4340ebfd7a97fbec19c1e761c8f9 172.27.0.13:6379
slots:[10923-16383] (5461 slots) master
1 additional replica(s)
M: 1c2099ff82953880846ed11a58249a63fa402ddd 172.27.0.15:6379
slots:[0-5460] (5461 slots) master
S: 5b912482f713898648fdbafaaa6ac3ad6960c356 172.27.0.14:6379
slots: (0 slots) slave
replicates a69d8482f24a4340ebfd7a97fbec19c1e761c8f9
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
15这时成了主,现在将11启动起来再看
>>> Performing Cluster Check (using node 127.0.0.1:6379)
M: 9ddfd4111f64bcf978e29f23f3f83118a94d1f18 127.0.0.1:6379
slots:[5461-10922] (5462 slots) master
1 additional replica(s)
S: 4bfa5fd0cdb8e5e6efb64900d9efd397d1cf629f 172.27.0.16:6379
slots: (0 slots) slave
replicates 9ddfd4111f64bcf978e29f23f3f83118a94d1f18
M: a69d8482f24a4340ebfd7a97fbec19c1e761c8f9 172.27.0.13:6379
slots:[10923-16383] (5461 slots) master
1 additional replica(s)
M: 1c2099ff82953880846ed11a58249a63fa402ddd 172.27.0.15:6379
slots:[0-5460] (5461 slots) master
1 additional replica(s)
S: 31e235870bb06b79bc700b44e2b859c09653e292 172.27.0.11:6379
slots: (0 slots) slave
replicates 1c2099ff82953880846ed11a58249a63fa402ddd
S: 5b912482f713898648fdbafaaa6ac3ad6960c356 172.27.0.14:6379
slots: (0 slots) slave
replicates a69d8482f24a4340ebfd7a97fbec19c1e761c8f9
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered. 11启动后重新加入集群成了slave
Docker Compose 容器单机编排
安装 Docker Compose
使用apt及dnf yum方式安装的docker会将docker compose也安装上,二进制安装的docker需要单独安装docker compose
docker compose命令
docker compose --help
Define and run multi-container applications with Docker.
Usage:
docker compose [-f <arg>...] [options] [COMMAND] [ARGS...]
docker compose -h|--help
#选项说明:
-f,–file FILE #指定Compose 模板文件,默认为docker-compose.yml|yaml
-p,–project-name NAME #指定项目名称,默认将使用当前所在目录名称作为项目名。
--verbose #显示更多输出信息
--log-level LEVEL #定义日志级别 (DEBUG, INFO, WARNING, ERROR, CRITICAL)
--no-ansi #不显示ANSI 控制字符
-v, --version #显示版本
#以下为命令选项,需要在docker-compose.yml|yaml 文件所在在目录里执行
config -q #查看当前配置,没有错误不输出任何信息
up #创建并启动容器
build #构建镜像
bundle #从当前docker compose 文件生成一个以<当前目录>为名称的json格式的Docker Bundle 备
份文件
create #创建服务
down #停止和删除所有容器、网络、镜像和卷
events #从容器接收实时事件,可以指定json 日志格式
exec #进入指定容器进行操作
help #显示帮助细信息
images #显示镜像信息
kill #强制终止运行中的容器
logs #查看容器的日志
pause #暂停服务
port #查看端口
ps #列出容器
pull #重新拉取镜像,镜像发生变化后,需要重新拉取镜像
push #上传镜像
restart #重启服务
rm #删除已经停止的服务
run #一次性运行容器
scale #设置指定服务运行的容器个数,新版已废弃
start #启动服务
stop #停止服务
top #显示容器运行状态
unpause #取消暂定
从 docker compose 启动单个容器
mkdir -p /data/docker-compose
cd /data/docker-compose
cat docker-compose
services:
service-nginx-web:
image: 192.168.10.22/test/nginx:v1.24.0
container_name: nginx-web
expose:
- 80
- 443
ports:
- "80:80"
- "443:443"
docker compose config 查看配置格式检查有没有借误
docker compose config -q
root@docker01:/data/docker-compose# docker compose up -d
[+] up 2/2
✔ Network docker-compose_default Created 0.0s
✔ Container nginx-web Started 0.2s
root@docker01:/data/docker-compose# curl 127.0.0.1:85
<h1>Welcome to nginx!</h1>
使用终端连入到docker compose 管理的容器
root@docker01:/data/docker-compose# docker compose ps
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
nginx-web 192.168.10.22/test/nginx:v1.24.0 "/docker-entrypoint.…" service-nginx-web 2 minutes ago Up 2 minutes 0.0.0.0:443->443/tcp, [::]:443->443/tcp, 0.0.0.0:85->80/tcp, [::]:85->80/tcp
oot@docker01:/data/docker-compose# docker compose exec service-nginx-web bash #exec后面要跟SERVICE 的名称,这里的名称是service-nginx-web
root@e8eabaf6cf33:/# ls
bin boot dev docker-entrypoint.d docker-entry
root@docker01:/data/docker-compose# docker compose images
CONTAINER REPOSITORY TAG PLATFORM IMAGE ID SIZE CREATED
nginx-web 192.168.10.22/test/nginx v1.24.0 linux/amd64 8f029c543423 63.3MB 3 days ago
root@docker01:/data/docker-compose# docker compose ps
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
nginx-web 192.168.10.22/test/nginx:v1.24.0 "/docker-entrypoint.…" service-nginx-web 8 minutes ago Up 8 minutes 0.0.0.0:443->443/tcp, [::]:443->443/tcp, 0.0.0.0:85->80/tcp, [::]:85->80/tcp
root@docker01:/data/docker-compose# docker compose inspect nginx-web
root@docker01:/data/docker-compose# docker compose logs -f
nginx-web | /docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
nginx-web | /docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
nginx-web | /docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
nginx-web | 10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
nginx-web | 10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
nginx-web | /docker-entrypoint.sh: Sourcing /docker-entrypoint.d/15-local-resolvers.envsh
nginx-web | /docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
nginx-web | /docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
nginx-web | /docker-entrypoint.sh: Configuration complete; ready for start up
root@docker01:/data/docker-compose# docker compose stop
[+] stop 1/1
✔ Container nginx-web Stopped 0.2s
root@docker01:/data/docker-compose# docker compose ps -a
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
nginx-web 192.168.10.22/test/nginx:v1.24.0 "/docker-entrypoint.…" service-nginx-web 11 minutes ago Exited (0) 31 seconds ago
root@docker01:/data/docker-compose# docker compose start
[+] start 1/1
✔ Container nginx-web Started
root@docker01:/data/docker-compose# docker compose start
[+] start 1/1
✔ Container nginx-web Started 0.2s
root@docker01:/data/docker-compose# docker compose ps -a
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
nginx-web 192.168.10.22/test/nginx:v1.24.0 "/docker-entrypoint.…" service-nginx-web 12 minutes ago Up 35 seconds 0.0.0.0:443->443/tcp, [::]:443->443/tcp, 0.0.0.0:85->80/tcp, [::]:85->80/tcp
#只删除停止的容器
docker compose rm
#停止并删除容器及镜像
docker-compose down
root@docker01:/data/docker-compose# docker compose down
[+] down 2/2
✔ Container nginx-web Removed 0.2s
✔ Network docker-compose_default Removed 0.1s
root@docker01:/data/docker-compose# docker compose ps -a
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
root@docker01:/data/docker-compose# docker compose images
CONTAINER REPOSITORY TAG PLATFORM IMAGE ID SIZE CREATED
root@docker01:/data/docker-compose#
Docker compose启动多个容器
root@docker01:/data/docker-compose# docker tag tomcat:latest 192.168.10.22/test/tomcat:v1.88.0
root@docker01:/data/docker-compose# docker push 192.168.10.22/test/tomcat:v1.88.0
The push refers to repository [192.168.10.22/test/tomcat]
0926a8eb0e60: Pushed
c79111691f56: Pushed
先将一个镜像改一下tag上传到harbor仓库
root@docker01:/data/docker-compose# cat docker-compose.yml
services:
service-nginx-web:
image: 192.168.10.22/test/nginx:v1.24.0
container_name: nginx-web
volumes:
- /data/nginx:/apps/nginx/html/
expose:
- 80
- 443
ports:
- "80:80"
- "443:443"
service-tomcat-app1:
image: 192.168.10.22/test/tomcat:v1.88.0
container_name: tomcat-app1
expose:
- 8080
ports:
- "8081:8080"
service-tomcat-app2:
image: 192.168.10.22/test/tomcat:v1.88.0
container_name: tomcat-app2
expose:
- 8080
ports:
- "8082:8080"
docker compose up -d
docker compose stop
root@docker01:/data/docker-compose# cd
root@docker01:~# docker compose -f /data/docker-compose/docker-compose.yml start
[+] start 3/3
✔ Container nginx-web Started 0.3s
✔ Container tomcat-app1 Started 0.4s
✔ Container tomcat-app2 Started 0.3s
root@docker01:~# ls
alpine_3.24.1.tar backup soft
扩容与缩容
临时扩容缩容
# 扩容:将 web 服务扩展到 3 个实例
docker compose up -d --scale web=3
# 缩容:将 web 服务缩减到 1 个实例
docker compose up -d --scale web=1
注意配置中不能固定container name、不能固定端口映射 这两个需要随机生成才可以
在配置文件中修改重新启动
services:
web:
image: nginx:alpine
deploy:
replicas: 3 这里
实战项目jumpserver安装部署
由于官方已经找到docker-compose.yml配置,现在以官方单机安装操作,依赖docker。
从官网注册登陆后下载官网安装包
1、解压后
root@docker01:/data/jumpserver-ce-v4.10.19-x86_64# ls
compose config-example.txt config_init jmsctl.sh LICENSE locale README.md scripts static.env utils
2、./jmsctl.sh install 即可
3、安装完毕后我们查一下docker相关信息
可以看到启动了三个容器,用自定义网络jms_net


Docker仓库管理
Harbor介绍
Harbor 功能
- 基于角色的访问控制: 用户与Docker镜像仓库通过“项目”进行组织管理,一个用户可以对多个镜像仓库在同一命名空间(project)里有不同的权限
- 镜像复制: 镜像可在多个Registry实例中复制(同步)。尤其适合于负载均衡,高可用,混合云和多云的场景
- 图形化用户界面: 用户可以通过浏览器来浏览,检索当前Docker镜像仓库,管理项目和命名空间
- AD/LDAP 支: Harbor可以集成企业内部已有的AD/LDAP,用于鉴权认证管理
- 审计管理: 所有针对镜像仓库的操作都可以被记录追溯,用于审计管理
- 国际化: 已拥有英文、中文、德文、日文和俄文的本地化版本。更多的语言将会添加进来
- RESTful API: 提供给管理员对于Harbor更多的操控, 使得与其它管理软件集成变得更容易
- 部署简单: 提供在线和离线两种安装工具, 也可以安装到vSphere平台(OVA方式)虚拟设备

Harbor安装部署
1、下载离线安装包
root@docker01:~/soft# wget https://github.com/goharbor/harbor/releases/harbor-offline-installer-v2.15.2.tgz
2、解压缩,配置harbor.yml
hostname: 192.168.10.21
harbor_admin_password: work123
data_volume: /data/harbor
没有证书先关闭https相关配置,证书引用也注视掉
3、执行安装脚本
root@docker01:/usr/local/harbor# ./install.sh -h
Note: Please set hostname and other necessary attributes in harbor.yml first. DO NOT use localhost or 127.0.0.1 for hostname, because Harbor needs to be accessed by external clients.
Please set --with-trivy if needs enable Trivy in Harbor.
Please do NOT set --with-chartmuseum, as chartmusuem has been deprecated and removed.
Please do NOT set --with-notary, as notary has been deprecated and removed.

创建相关项目上传镜像
打tag上传镜像
root@docker01:~# docker tag alpine:3.24.1 192.168.10.21/test/alpine:3.24.1
root@docker01:~# docker push 192.168.10.21/test/alpine:3.24.1
The push refers to repository [192.168.10.21/test/alpine]
55afa1ecc21d: Pushed
3.24.1: digest: sha256:79ff19e9084a00eece421b2523fb93e22d730e2c0e525905de047e848e56d95f size: 1022
i Info → Not all multiplatform-content is present and only the available single-platform image was pushed
sha256:28bd5fe8b56d1bd048e5babf5b10710ebe0bae67db86916198a6eec434943f8b -> sha256:79ff19e9084a00eece421b2523fb93e22d730e2c0e525905de047e848e56d95f
root@docker01:~# docker images
下载镜像
root@docker02:~# docker pull 192.168.10.21/test/alpine:3.24.1
3.24.1: Pulling from test/alpine
55afa1ecc21d: Pull complete
Digest: sha256:79ff19e9084a00eece421b2523fb93e22d730e2c0e525905de047e848e56d95f
Status: Downloaded newer image for 192.168.10.21/test/alpine:3.24.1
192.168.10.21/test/alpine:3.24.1
root@docker02:~# ls
root@docker02:~# docker images
i Info → U In Use
IMAGE ID DISK USAGE CONTENT SIZE EXTRA
192.168.10.21/test/alpine:3.24.1 79ff19e9084a 12.9MB 3.85MB
Harbor高可用

在另一台宿主机之上安装harbor方法与第一台相同。

两台harbor主机上都进行目标配置互相让其进行复制。
创建复制规则两个harbor上可以互相同步镜像到对方。

Docker资源限制
OOM
linux会为每个进程计算一个分数,最终将分数最高的kill
/proc/PID/oom_score_adj
#范围为 -1000 到 1000,值越高容易被宿主机 kill掉,如果将该值设置为 -1000 ,则进程永远不会被
宿主机 kernel kill
/proc/PID/oom_adj
#该设置参数是为了和旧版本的 Linux 内核兼容的旧接口文件,范围为 -17 到+15 ,会被线性映射到
oom_score_adj,取值越高越容易被干掉,如果是 -17 , 则表示不能被 kill, root可读写,
/proc/PID/oom_score
#这个值是系统综合进程的内存消耗量,只读文件,取值范围0 –- 1000,0代表never kill,1000代表
aways kill,值越大,进程被选中的概率越大。
#oom_score = 占用消耗内存/总内存 *1000
#内存消耗=常驻内存RSS + 进程页面 +交换内存
#总内存=总的物理内存 +交换分区
#消耗内存越多得分越高,容易被宿主机 kernel 强制杀死
#当内存紧张的时候,内核通过 oom = oom_score + oom_score_adj 计算出分数最高的进程,向其发送
关闭信号
# 查看 nginx 的 PID
pidof nginx
# 或者随便找一个正在运行的进程
ps aux | grep nginx
root@docker01:/proc# pidof dockerd
100269
root@docker01:/proc# cd 100269/
root@docker01:/proc/100269# cat oom_score_adj
-500 #现在我的主机中的dockerd的分数是-500
容器内存限制
- Docker 可以强制执行硬性内存限制,即只允许容器使用给定的内存大小。
- Docker 也可以执行非硬性内存限制,即容器可以使用尽可能多的内存,除非内核检测到主机上的内存不 够用了
| 选项 | 描述 |
|---|---|
-m, --memory= |
容器可以使用的最大物理内存量 RSS,硬限制,此选项最小允许值为 4m (4 MB),此项较常用 |
--memory-swap |
允许此容器交换到磁盘的内存量。必须先用 -m 对内存限制才可以使用,详细说明如下 |
--memory-swappiness |
设置容器使用交换分区的倾向性,值越高表示越倾向于使用 swap 分区,范围为 0-100,0 为能不用就不用,100 为能用就用,N 表示内存使用率达到 N% 时,就会使用 swap 空间 |
--memory-reservation |
允许指定小于 --memory 的软限制,当 Docker 检测到主机上的争用或内存不足时会激活该限制,如果使 --memory-reservation,则必须将其设置为低于 --memory 才能使其优先生效。因为它是软限制,所以不能保证容器不超过限制 |
--kernel-memory |
容器可以使用的最大内核内存量,最小为 4m,由于内核内存与用户空间内存隔离,因此无法与用户空间内存直接交换,因此内核内存不足的容器可能会阻塞宿主机资源,这会对主机和其他容器或者其他服务进程产生影响,因此不建议设置内核内存大小 |
--oom-kill-disable |
新内核不再支持,默认情况下,如果发生内存不足 (OOM) 错误,则内核将终止容器中的进程。要更改此行为,请使用该 --oom-kill-disable 选项。建议仅在设置了该 -m/--memory 选项的容器上禁用 OOM。如果 -m 未设置该标志,则主机可能会用完内存,内核可能需要终止主机系统的进程以释放内存 |
docker run -e MYSQL_ROOT_PASSWORD=XXXX -it --rm -m 1g mysql:8.0
docker run 命令可以使用--memory-swap 选项控制swap的使用
--memory-swap #只有在设置了 --memory 后才会有意义。使用 Swap,可以让容器将超出限制部分的内存
置换到磁盘上,WARNING: 经常将内存交换到磁盘的应用程序会降低性能
-memory-swap #值为正数, 那么--memory 和--memory-swap 都必须要设置,--memory-swap 表示
你能使用的内存和 swap 分区大小的总和,例如: --memory=300m, --memory-swap=1g, 那么该容
器能够使用 300m 物理内存和 700m swap,即--memory 是实际物理内存大小值不变,而 swap 的实际大
小计算方式为(--memory-swap)-(--memory)=容器可用 swap
--memory-swap #如果设置为 0,则忽略该设置,并将该值视为未设置,即未设置交换分区
--memory-swap #如果等于--memory 的值,并且--memory 设置为正整数,容器无权访问 swap
-memory-swap #如果未设置,如果宿主机开启了 swap,则实际容器的swap 值最大为 2x( --
memory),即两倍于物理内存大小,例如,如果--memory="300m"与--memory-swap没有设置,该容器可
以使用300m总的内存和600m交撒空间,但是并不准确(在容器中使用free 命令所看到的 swap 空间并不精
确,毕竟每个容器都可以看到具体大小,宿主机的 swap 是有上限的,而且不是所有容器看到的累计大小)
--memory-swap #如果设置为-1,如果宿主机开启了 swap,则容器可以使用主机上 swap 的最大空间
| --memory-swap | --memory | 功能 |
|---|---|---|
| 正数 S | 正数 M | 容器可用内存总空间为 S,其中 RAM 为 M,Swap 为 S-M。若 S=M,则无可用 Swap 资源 |
| 0 | 正数 M | 相当于未设置 Swap (unset) |
| unset (未设置) | 正数 M | 若主机 (Docker Host) 启用了 Swap,则容器的可用 Swap 为 2*M |
| -1 | 正数 M | 若主机 (Docker Host) 启用了 Swap,则容器可使用最大至主机上所有 Swap 空间 |
- 默认行为(unset):如果不显式设置
--memory-swap,Docker 默认会将 Swap 设置为与内存限制相同的值(即总限制变为2 * Memory)。例如-m 512m,实际可用总空间是 1GB(512m 内存 + 512m Swap)。 - 禁用 Swap:如果你想限制容器只能使用物理内存,完全不让它用 Swap,需要将
--memory-swap设置为与--memory相同的值。 -
假如一个容器未做内存使用限制,则该容器可以利用到系统内存最大空间,默认创建的容器没有做内存 资源限制。
启动一个容器没有限制内存
root@docker01:~# docker run --name c1 -it --rm alexeiled/stress-ng:latest --vm 2

指定内存最大值
root@docker01:~# docker run --name test --it --rm -m 300m alexeiled/stress-ng:latest --vm 2

容器cpu限制
- CPU 密集型的场景: 计算密集型任务的特点是要进行大量的计算,消耗CPU 资源,比如计算圆周率、数据处理、对视频进行高清解码等等,全靠CPU 的运算能力。
- IO 密集型的场景: 涉及到网络、磁盘IO 的任务都是IO 密集型任务,这类任务的特点是 CPU 消耗很 少,任务的大部分时间都在等待 IO 操作完成(因为 IO 的速度远远低于 CPU 和内存的速度),比 如 Web 应用,高并发,数据量大的动态网站来说,数据库应该为IO 密集型
| 选项 | 描述 |
|---|---|
--cpus= |
指定一个容器可以使用多少个可用的CPU核心资源。例如,如果主机有两个CPU,如果设置了 --cpus="1.5",则可以保证容器最多使用1.5个的CPU。如果是4核CPU,那么还可以是4核心上每核用一点,但是总计是1.5核心的CPU。这相当于设置 --cpu-period="100000" 和 --cpu-quota="150000"。此设置可在 Docker 1.13 及更高版本中可用,目的是替代 --cpu-period 和 --cpu-quota 两个参数,从而使配置更简单,但是最大不能超出宿主机的CPU总核心数(在操作系统看到的CPU超线程后的数值),此项较常用 |
--cpu-period= |
过时选项,指定CPU CFS调度程序周期,必须与 --cpu-quota 一起使用。默认为100微秒。大多数用户不会更改默认设置。如果使用Docker 1.13或更高版本,请改用 --cpus |
--cpu-quota= |
过时选项,在容器上添加 CPU CFS 配额,计算方式为 cpu-quota / cpu-period 的结果值,docker1.13 及以上版本通常使用 --cpus 设置此值 |
--cpuset-cpus |
用于指定容器运行的 CPU 编号,也就是所谓的CPU绑定。如果一个或多个CPU,则容器可以使用逗号分隔的列表或用连字符分隔的CPU范围。第一个CPU的编号为0。有效值可能是 0-3 (使用第一,第二,第三和第四CPU)或 1,3 (使用第二和第四CPU) |
--cpu-shares |
用于设置 cfs 中调度的相对最大比例权重,cpu-share 的值越高的容器,将会分得更多的时间片(宿主机多核 CPU 总数为 100%,假如容器 A 为1024,容器 B 为2048,那么容器 B 将最大是容器 A 的可用的 CPU 的两倍)。默认的时间片 1024,最大 262144。这是一个软限制。注意:进程数要多个CPU的核数才能看到效果,此值不能设置太小 |
root@docker01:~# docker run --name test -it --rm -m 300m alexeiled/stress-ng:latest --cpu 4
stress-ng: info: [1] defaulting to a 86400 second (1 day, 0.00 secs) run per stressor
stress-ng: info: [1] dispatching hogs: 4 cpu


绑定CPU
一般不绑在0号cpu上,因为0号cpu一般比较忙
root@docker01:~# docker run -it --rm --name c1 --cpus 1.5 --cpuset-cpus 2,4-5 alexeiled/stress-ng:latest --cpu 4
stress-ng: info: [1] defaulting to a 86400 second (1 day, 0.00 secs) run per stressor
stress-ng: info: [1] dispatching hogs: 4 cpu
| 参数 | 含义 |
|---|---|
-it |
以交互模式运行,分配终端 |
--rm |
容器退出后自动删除 |
--name c1 |
容器命名为 c1 |
--cpus 1.5 |
限制容器最多使用 1.5 个 CPU 核心(硬限制) |
--cpuset-cpus 2,4-5 |
容器只能运行在宿主机的第 2、4、5 号 CPU 核心上(绑核) |
alexeiled/stress-ng:latest |
使用的压测镜像 |
--cpu 4 |
启动 4 个 CPU 压测进程 |

关键点
虽然 stress-ng 内部启动了 4 个压测进程,但由于 Docker 的 --cpus 1.5 限制,这 4 个进程总共只能使用 1.5 个 CPU 核心的算力。你可以打开另一个终端,用 docker stats c1 观察,CPU 使用率会被限制在 150% 左右,不会跑满 400%。

GPU限制
在启动容器以访问 GPU 资源时包含标志。指定要使用的 GPU 数量。 例如: --gpus
docker run -it --rm --gpus all ubuntu nvidia-smi
使用该选项指定 GPU。 例如: device
docker run -it --rm --gpus device=GPU-3a23c669-1f69-c64e-cf85-44e9b07e7a2a
ubuntu nvidia-smi
公开该特定 GPU
docker run -it --rm --gpus '"device=0,2"' ubuntu nvidia-smi
公开第一个和第三个 GPU。注意:NVIDIA GPU 只能由运行单个引擎的系统访问。
您可以手动设置功能。例如,在 Ubuntu 上,您可以运行 以后:
docker run --gpus 'all,capabilities=utility' --rm ubuntu nvidia-smi
这将启用驱动程序功能,该功能将工具 utility``nvidia-smi 添加到容器中
功能以及其他配置可以通过环境变量在镜像中设置。
Specialized Configurations with Docker — NVIDIA Container Toolkit
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐



所有评论(0)