Docker概述

Docker 是一个开源的容器化平台旨在简化应用程序的开发部署和运行过程它通过将应用程序及其所有依赖项打包进一个可移植的容器中实现了应用程序与基础架构的解耦从而加快了软件交付的速度并增强了其可移植性百度百科 Docker 详细介绍

🏷️关键特性包括

  • 轻量级: Docker容器相比于传统的虚拟机更加轻量因为它们不需要额外的操作系统层而是直接在主机的内核上运行这使得容器启动迅速资源利用率高
  • 隔离性: 尽管轻量Docker容器仍然提供了良好的隔离性每个容器都在自己的进程中运行拥有独立的文件系统CPU内存网络等资源确保应用之间互不干扰
  • 可移植性: Docker容器能够在任何支持Docker的环境中一致地运行不论是在开发者的笔记本电脑测试服务器还是生产环境消除了在我机器上能跑的问题
  • 快速交付: Docker通过镜像Images来定义和封装应用及环境配置使得从开发到测试再到生产的整个流程变得高效且一致
  • DevOps友好: Docker整合了开发和运维的工作流使得持续集成持续部署CI/CD更加顺畅Dockerfile的使用让构建过程可脚本化可重复
  • 生态系统丰富: Docker拥有庞大的社区支持和丰富的工具链如Docker Compose用于定义和运行多容器应用Docker Swarm和Kubernetes用于容器编排以及Docker Hub作为官方的镜像仓库便于镜像的分享和管理

💗💗综上所述Docker通过提供标准化的打包和运行环境极大地提高了软件开发和运维的效率是现代云原生应用架构中的关键技术之一

Docker安装

安装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# 旧版本的Docker被称为docker或docker-engine在尝试安装新版本之前请卸载任何此类旧版本以及相关依赖项
sudo yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine

# 安装 yum 扩展命令行工具
sudo yum install -y yum-utils

# 设置 yum 镜像源地址
sudo yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

# 更新 yum 软件包索引
yum makecache fast

# 安装 docker
yum install docker-ce docker-ce-cli containerd.io

# 启动 docker
systemctl start docker

# docker 版本查看
docker -version

# 通过运行 hello-world 验证 Docker 引擎是否安装成功
# 要是 hello-world 镜像拉取不下来的话配置一下镜像加速器
docker run hello-world

⭐⭐组件介绍

docker-ce, docker-ce-cli, 和 containerd.io 是构成 Docker 容器运行环境的关键组件它们在 Docker 的安装和运行中扮演不同的角色

  • docker-ce (Docker Community Edition)这是 Docker 的社区版包含了完整的容器化平台它提供了 Docker 守护进程 (dockerd)该进程负责管理容器的创建运行暂停恢复和删除等操作此外Docker CE 也包括了 Docker 命令行界面 (CLI)使得用户能够通过命令行与 Docker 守护进程交互执行诸如构建镜像运行容器管理网络和数据卷等任务Docker CE 是面向开发者系统管理员和希望使用最新 Docker 功能的用户的首选版本
  • docker-ce-cli: 功能: 这是 Docker 的命令行客户端工具尽管它通常随 Docker CE 一起安装但也可以单独安装或升级它允许用户通过命令行执行 Docker 相关操作比如构建镜像 (docker build)运行容器 (docker run)查看容器状态 (docker ps) 等当你只需要命令行工具与远程 Docker 守护进程交互而不需要在本地主机上运行容器时单独安装此 CLI 就非常有用
  • containerd.io Containerd 是一个低级别的容器运行时启动容器通常需要运行一个专门的工具来配置内核来运行容器,这些工具也被称为容器运行时它负责容器和镜像的生命周期管理包括镜像的传输存储容器的执行和监控等底层操作它是 Docker 守护进程 (dockerd) 之下的一个组件为 Docker 提供了与操作系统进行交互的能力Containerd 设计为高度模块化和可嵌入式的不仅服务于 Docker还可以被其他容器管理系统使用比如 Kubernetes它是 Docker 实例化和管理容器的核心依赖

💗💗综上所述docker-ce 提供了用户与 Docker 交互的主要界面和后台服务docker-ce-cli 是与这些服务进行命令行交互的工具而 containerd.io 则是负责底层容器运行时的管理和协调这三个组件共同构成了 Docker 在 Linux 系统上的运行环境

配置

⭐⭐配置阿里云镜像加速

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 1. 注册一个阿里云账号
# 2. 进入容器镜像服务 --> 镜像工具 --> 镜像加速器 --> 获取加速器地址https://xxxxxxxx.mirror.aliyuncs.com
# 3. 通过修改daemon配置文件/etc/docker/daemon.json来使用加速器如果没有这个文件的话就新建一个有的话直接修改
vi /etc/docker/daemon.json
# 要添加的内容地址换成你的地址保存并退出
{
"registry-mirrors": ["https://xxxxxxxx.mirror.aliyuncs.com"]
}
# 重启 docker
sudo systemctl daemon-reload
sudo systemctl restart docker
# 查看 docker 信息看是否配置成功
# 存在 Registry Mirrors: https://xxxxxxxx.mirror.aliyuncs.com 说明配置完成
docker info

卸载

1
2
3
4
5
# 卸载docker
sudo yum remove docker-ce docker-ce-cli containerd.io
# 删除目录
sudo rm -rf /var/lib/docker
sudo rm -rf /var/lib/containerd

Docker镜像

镜像的概念

Docker镜像Image是Docker技术中的核心组件它是创建和运行Docker容器的前提镜像可以被理解为轻量级可执行的独立软件包它包含运行某个应用所需的所有内容包括代码运行时环境变量和配置文件形象地说Docker镜像相当于是一个面向应用的预配置的操作系统环境模板

⭐⭐镜像的特性

  • 只读性Docker镜像是只读的这意味着一旦创建就不能被修改当你运行一个容器时Docker会在镜像的顶部添加一个可写层这个可写层用来保存容器运行时产生的变化而底下的镜像层保持不变
  • 分层存储Docker镜像是由多层组成的每一层代表了文件系统的一系列变更这种分层结构使得镜像的构建高效且灵活因为它可以重用已有的层避免重复下载相同的内容当从Docker Hub或其他仓库下载镜像时实际上是在下载构成该镜像的所有层
  • 可移植性因为镜像包含了运行应用所需的一切所以它可以在任何支持Docker的环境中一致地运行无论是开发者的笔记本测试服务器还是生产环境
  • 版本控制镜像可以通过标签tag来标记不同的版本便于管理和识别例如你可以有ubuntu:latestnginx:1.18这样的标签来分别指代最新版的Ubuntu镜像或特定版本的Nginx镜像

⭐⭐构建和管理镜像

  • 构建镜像通常是通过DockerFile来构建的DockerFile是一个文本文件其中包含了逐条指令来定义如何从基础镜像开始一步步添加文件安装软件设置环境变量等最终形成新的镜像
  • 拉取使用docker pull命令可以从Docker Hub或其他注册中心下载镜像到本地
  • 查看使用docker images命令可以列出本地的所有镜像及其相关信息如镜像ID创建时间大小和标签
  • 运行通过docker run命令可以基于镜像创建并启动一个新的容器此时Docker会在镜像的顶部添加一个可写层作为容器的运行环境
  • 推送使用docker push命令可以将自己的镜像推送到Docker Hub或其他私有仓库以便他人或自己在其他地方使用

⭐⭐Docker镜像的设计理念极大地简化了应用的打包分发和部署过程使得应用程序能够在几乎任何基础设施上以一致的方式运行这是容器化技术的一大优势

联合文件系统

Docker的联合文件系统Union File System简称UnionFS是一种特殊的文件系统技术它允许将多个文件系统层叠加在一起形成一个单一的可读写的文件系统视图

这种分层的文件系统设计是Docker的核心技术之一它极大地促进了Docker镜像的高效创建管理和容器的快速启动

在Docker中每个镜像由一系列只读层组成最顶层通常是一个可写层当容器运行时生成这些层是相互依赖的下层的更改不会影响上层而上层可以添加修改或删除文件看起来就像是一个统一的文件系统

⭐⭐关键优势

  • 镜像复用因为层是可以共享的所以多个容器可以共用相同的底层镜像节省了存储空间
  • 快速部署新容器可以从现有镜像的层快速启动只需添加一个可写层用于保存状态和差异
  • 高效的镜像传输当推送或拉取镜像时只需要传输层间差异而非整个文件系统
  • 易于理解的分层结构每个操作如安装软件包都可以视为一个新的层便于追踪和回滚

⭐⭐Docker支持多种联合文件系统的实现包括但不限于

  • AUFSAdvanced Multi-Layered Unification Filesystem早期Docker默认使用的实现支持精细的权限控制和高效的层管理
  • OverlayFSLinux内核原生支持的轻量级联合文件系统逐渐成为许多现代Docker部署的首选
  • Btrfs一种具有高级特性的文件系统支持快照和子卷也可用于Docker存储
  • VFSVirtual File SystemDocker的一个基本实现兼容性好但性能较低
  • ZFS一个功能丰富的文件系统支持高级存储功能如数据校验和自动修复
  • Device MapperLinux内核中用于创建逻辑设备的框架也用于Docker存储驱动

分层存储

Docker镜像的分层存储是基于联合文件系统Union File System实现每一个镜像由多个只读层read-only layers组成这些层叠加在一起形成了一个完整的文件系统

Docker镜像的最底层是 bootfsboot file system它主要包含操作系统的 bootloader引导加载器和 kernel内核bootloader主要是引导加载kernel它提供了系统启动时所需的最基本的文件和程序包括能够加载和初始化 Linux 内核的组件

Docker镜像的最底层 bootfs 之上就是 rootfs (root file system)包含了系统运行所需的最基本目录结构和文件

Docker镜像的最上面的一层通常是可写层writable layer这一层就是我们通常说的容器层容器之下的都叫镜像层运行 docker run 命令时创建该层主要用于保存容器运行时产生的数据和改动

这种分层的设计使得镜像的构建存储和传输都极为高效

⭐⭐层的特性

  • 不可变性一旦创建层的内容就不能被修改这种设计保证了镜像的可重现性和一致性
  • 复用性多个镜像可以共享相同的底层层减少了存储空间的需求
  • 轻量级当提交一个新的层时实际上只是记录了相对于前一层所做的更改而不是整个文件系统的拷贝
  • 写时复制COW, Copy-On-Write当需要修改文件时该文件首先会被复制到一个新的层中然后在新层上进行修改这样的话原始层保持不变确保了高效性和资源利用率

Docker命令

镜像命令

镜像列表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
docker images
docker image ls
docker image list

# 列表项含义
# REPOSITORY 镜像的名称
# TAG 镜像的标签
# IMAGE ID 镜像的id
# CREATED 镜像的创建时间
# SIZE 镜像的大小

# 可选项
-a, --all # 列出所有镜像
-f, --filter filter # 根据所提供的条件过滤输出
--format string # 使用自定义模板格式化输出:
# 'table': 以带有列标题的表格式打印输出默认值
# 'table TEMPLATE': 使用给定的Go模板以表格格式打印输出
# 'json': 以json格式打印
# 'TEMPLATE': 使用给定的Go模板打印输出
--no-trunc # 不截断输出
-q, --quiet # 仅显示镜像ID

# 举例
docker images -aq # 镜像列表只显示ID
docker images --digests # 查看镜像摘要
docker images -f "dangling=true" # 查看标签为 <none> 的镜像
docker images -f "reference=latest" # 查看所有标签为 latest 的镜像
docker images --format "{{json .}}" # 输出 JSON 格式的信息
# 以表格形式显示镜像的仓库名标签和大小
docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}"

搜索镜像

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
docker search image_name

# 列表项含义
# NAME 镜像名称
# DESCRIPTION 镜像描述
# STARS 镜像点赞数量
# OFFICIAL 镜像是否为官方镜像

# 可选项
-f, --filter filter # 根据提供的条件过滤输出
--format string # 使用Go模板进行好看的打印搜索
--limit int # 搜索结果的最大数量
--no-trunc # 不截断输出

# 举例
docker search mysql --filter=STARS=3000 # 搜索点赞数量大于3000的 mysql 镜像
docker search -f is-official=true zookeeper # 查询官方镜像
docker search --limit=5 zookeeper # 展示5条

下载镜像

1
2
3
4
5
6
7
8
9
10
11
12
# [:tag] 镜像的版本号如果不写则下载最新版
docker pull image_name[:tag]

# 可选项
-a, --all-tags # 下载存储库中所有已标记的图像
--disable-content-trust # 跳过镜像验证默认为true
--platform string # 如果服务器支持多平台则设置平台
-q, --quiet # 禁止详细输出

# 举例
docker pull mysql # 根据镜像名称下载镜像
docker pull docker.io/library/mysql:latest # 根据镜像详细地址下载镜像

删除镜像

1
2
3
4
5
6
7
8
9
10
11
12
13
docker rmi image_id     # 根据镜像ID删除镜像
docker rmi image_name # 根据镜像名称删除镜像

# 可选项
-f, --force # 解除占用强制删除镜像
--no-prune # 不删除未标记的父对象

# 举例
docker rmi -f e73346bdf465 # 删除镜像ID为e73346bdf465的镜像
docker rmi -f mysql # 删除镜像名称为 mysql 的镜像
docker rmi -f $(docker images -aq) # 复合删除操作查询出所有的镜像ID然后删除
docker image prune # 删除所有未被任何容器使用的镜像以及它们的未被其他镜像共享的层
docker system prune # 删除所有未运行的容器网络玄虚镜像数据卷

镜像提交

1
2
3
4
5
6
7
8
9
10
11
12
# 提交容器成为一个新的镜像
# 提交到本地可以通过 docker images 命令查看镜像列表
docker commit CONTAINER_ID image_name:[tag]

# 可选项
-a, --author string # 作者名称
-c, --change list # 对创建的镜像应用Dockerfile指令
-m, --message string # 提交消息
-p, --pause # 提交时暂停容器默认为true

# 举例
docker commit -a="作者名称" -m="提交的描述信息" d1e5e331a66a test-image-name:1.0.0

镜像推送

1
2
3
4
5
6
7
8
9
10
# 推送到阿里云
# 首先需要注册一个阿里云账号
# 开通阿里云容器镜像服务
# 创建一个镜像仓库
# 使用Docker登录镜像仓库
docker login --username=阿里云登录用户名 registry.cn-beijing.aliyuncs.com
# 为推送的镜像打标签
docker tag [ImageId] registry.cn-beijing.aliyuncs.com/命名空间/仓库名称:[镜像版本号]
# 推送
docker push registry.cn-beijing.aliyuncs.com/命名空间/仓库名称:[镜像版本号]

镜像打包

⭐⭐可以把镜像打成一个压缩包自己保存或者发送给别人

1
2
3
4
5
6
7
8
9
docker save image_id ...

# 可选项
-o, --output string # 打包后压缩包存放路径

# 举例多个镜像打包为一个压缩包压缩包的名字为 test存放到 home 的 docker 目录下
docker save -o /home/docker/test.jar a3e63372bd98 605c77e624dd
# 第二种写法
docker save a3e63372bd98 605c77e624dd > /home/docker/test.jar

镜像加载

⭐⭐可以把镜像打成一个压缩包自己保存或者发送给别人

1
2
3
4
5
6
7
8
9
10
docker save image_id ...

# 可选项
-i, --input string # 指定要加载的 tar 文件的路径
-q, --quiet # 精简输出信息只显示必要的进度信息

# 举例
docker load -i /home/docker/test.jar
# 或者
docker load < /home/docker/test.jar

容器命令

运行容器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
docker run [可选项] image_id
docker run [可选项] image_name

# 可选项太多可使用 help 命令查看
docker run --help

# 常用选项
--name="container_name" # 自定义容器名字 tomcat01tomcat02用来区分容器
-d # 后台方式运行
-it # 使用交互方式运行
-P # 为容器内部所有端口随机分配宿主机的端口号
-p # 指定容器的端口
-p 容器端口
-p 主机端口:容器端口
-p ip:主机端口:容器端口

# 举例
docker run -it centos /bin/bash # 使用交互方式启动容器
# 后台方式运行 nginx 容器将容器命名为 nginx01并且让主机的3344端口映射到容器的80端口
docker run -d --name nginx01 -p 3344:80 nginx
curl localhost:3344 # 测试是否成功

# 注意
# docker 容器使用后台运行就必须要有要一个应用docker发现没有应用就会自动停止
docker run -d centos

创建容器

⭐⭐ 创建容器命令与运行容器命令基本一致创建容器命令只创建不运行运行容器命令创建并运行

1
docker create [可选项] image_id

查看列表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
docker ps       # 查看正在运行的容器列表

# 列表项含义
# CONTAINER ID 容器的唯一标识符
# IMAGE 创建该容器所使用的镜像名称
# COMMAND 启动容器时执行的命令默认情况下显示的是容器的主进程
# CREATED 容器的创建时间
# STATUS 容器的当前状态容器启动或停止的具体时间信息
# PORTS 容器公开的端口映射信息
# NAMES 容器的名称Docker 自动为每个容器分配一个唯一的名称用户也可以在运行容器时自定义名称

# 可选项
-a, --all # 显示所有容器正在运行的和以往运行过的容器
-f, --filter filter # 根据提供的条件过滤输出
--format string # 使用自定义模板格式化输出
# 'table': 以带有列标题的表格式打印输出默认值
# 'table TEMPLATE': 使用给定的Go模板以表格格式打印输出
# 'json': 以json格式打印
# 'TEMPLATE': 使用给定的Go模板打印输出
-n, --last int # 显示n个上次创建的容器包括所有状态默认值-1
-l, --latest # 显示最新创建的容器包括所有状态
--no-trunc # 不截断输出
-q, --quiet # 仅显示容器ID
-s, --size # 显示文件总大小

# 举例
docker ps -a # 查看所有容器列表

删除容器

1
2
3
4
5
6
7
8
9
10
11
12
docker rm CONTAINER_ID     # 根据容器ID删除容器
docker rm NAMES # 根据容器名称删除容器

# 可选项
-f, --force # 强制删除容器
-l, --link # 删除指定的链接
-v, --volumes # 删除与容器关联的匿名卷

# 举例
docker rm -f c3180317543b # 删除容器ID为e73346bdf465的镜像
docker rm -f $(docker ps -aq) # 复合删除操作查询出所有的容器ID然后删除
docker ps -aq | xargs docker rm -f # 也可以通过 Linux 管道符操作删除全部容器

查看日志

1
2
3
4
5
6
7
8
9
10
11
12
docker logs CONTAINER_ID        # 根据容器ID查看日志

# 可选项
--details # 显示提供给日志的额外详细信息
-f, --follow # 跟踪日志输出
--since string # 显示时间戳 (e.g. "2013-01-02T13:23:37Z") 或相对时间戳 (e.g. "42m" for 42 minutes) 以来的日志
-n, --tail string # 从日志末尾开始显示的行数默认为all
-t, --timestamps # 显示时间戳
--until string # 显示时间戳 (e.g. "2013-01-02T13:23:37Z") 或相对时间戳 (e.g. "42m" for 42 minutes)以来的日志

# 举例
docker logs -tf --tail 10 d1e5e331a66a # 显示10条带有时间戳的日志并跟踪日志输出

拷贝文件

1
2
3
4
## 从容器拷贝文件到宿主机
docker cp d1e5e331a66a:/home/test.java /home
## 从宿主机拷贝文件到容器
docker cp my.tar d1e5e331a66a:/root

容器启动与停止

1
2
3
4
docker start CONTAINER_ID       # 根据容器ID启动容器
docker restart CONTAINER_ID # 根据容器ID重启容器
docker stop CONTAINER_ID # 根据容器ID停止正在运行的容器
docker kill CONTAINER_ID # 根据容器ID杀死正在运行的容器

进入正在运行的容器

1
2
3
4
5
6
7
8
# 进入容器后开启一个新的终端
docker exec -it CONTAINER_ID 命令行
# 进入容器正在执行的终端
docker attach CONTAINER_ID

# 举例
docker exec -it d1e5e331a66a /bin/bash # 进入正在运行的 centos 容器
docker exec -it -w /root d1e5e331a66a /bin/bash # 进入正在运行的 centos 容器并到root目录下

退出正在运行的容器

1
2
exit                                # 停止运行容器并退出
Ctrl + P + Q # 不停止容器退出

查看容器内部的进程

1
docker top CONTAINER_ID

查看容器的元数据

1
docker inspect CONTAINER_ID

导出/导入容器

1
2
3
4
# 导出容器
docker export /home/tomcat-export.tar d1e5e331a66a
# 导入容器
docker import /home/tomcat-export.tar tomcat-export:1.0

暂停容器服务

⭐⭐ 暂停容器对外提供服务并不是暂停容器

1
2
3
4
# 暂停
docker pause d1e5e331a66a
# 取消暂停
docker unpause d1e5e331a66a

容器数据卷

数据卷的概念

Docker容器数据卷是一种由Docker管理的用于存储容器数据的独立于容器的持久化存储机制它是宿主机上的一个特定目录可以被挂载到一个或多个Docker容器中在宿主机中的这个文件/目录就称为数据卷而容器中的这个关联文件/目录则称为该数据卷在该容器中的挂载点

数据卷的设计旨在解决容器数据的持久化问题确保数据不因容器的创建启动停止或删除等操作而丢失使用数据卷是实现 Docker 应用数据持久化和容器间数据共享的有效方式它增强了容器化应用的数据管理灵活性和可靠性

⭐⭐数据卷的关键特性

  • 持久性数据卷中的数据会在容器被删除后继续存在因为数据卷拥有自己的生命周期独立于任何单个容器
  • 可共享性多个容器可以同时挂载同一个数据卷实现数据的实时共享
  • 宿主机集成数据卷直接在宿主机的文件系统中存在可以轻松地从宿主机备份恢复或直接访问数据卷内容
  • 绕过UnionFS数据卷不使用Docker的联合文件系统(UnionFS)这意味着对数据卷内数据的修改是直接的不会受到容器读写层的影响提高了I/O性能
  • 命名卷与匿名卷
    • 命名卷由用户显式创建并命名便于在多个容器间共享和管理
    • 匿名卷在容器创建时自动创建且未命名主要用于临时存储或一次性使用的场景
  • 数据卷容器一种特殊的容器其主要作用是提供数据卷供其他容器挂载这样可以更容易地管理和迁移数据

指定宿主机路径挂载卷

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 交互方式启动 centos 镜像
# /home/ceshi 宿主机数据路径
# /home 容器的数据路径
docker run -it -v /home/ceshi:/home centos /bin/bash

# 启动 mysql 镜像
docker run -d -p 3306:3306 -v /home/mysql/conf:/etc/mysql/conf.d -v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7
# 命令解析
docker run -d # 以后台运行的方式启动
-p 3306:3306 # 端口映射宿主机3306端口映射到mysql容器的3306端口
-v /home/mysql/conf:/etc/mysql/conf.d # 数据卷挂载宿主机mysql文件的储存路径 : mysql容器的配置文件路径
-v /home/mysql/data:/var/lib/mysql # 数据卷挂载宿主机mysql数据的储存路径 : mysql容器的数据储存路径
-e MYSQL_ROOT_PASSWORD=123456 # 容器的配置信息配置mysql容器的登录密码
--name mysql01 # 给容器命名
mysql:5.7 # 启动容器:版本号

不指定宿主机路径挂载卷

⭐⭐不指定路径挂载卷默认保存到 –> /var/lib/docker/volumes 目录下

匿名卷

1
2
3
4
5
6
# -d 后台启动镜像
# -P 随机分配宿主机的端口号
# 匿名挂载卷/etc/nginx 对应的是容器中要挂载的路径
# --name 将容器名称命名为 nginx01
# nginx:latest 启动最新版本的 nginx 镜像
docker run -d -P -v /etc/nginx --name nginx01 nginx:latest

命名卷

1
2
3
4
5
6
7
8
# -d 后台启动镜像
# -P 随机分配宿主机的端口号
# 匿名挂载卷zdy-name:/etc/nginx
# zdy-name-nginx自定义卷的名称
# /etc/nginx对应的是容器中要挂载的路径
# --name 将容器名称命名为 nginx02
# nginx:latest 启动最新版本的 nginx 镜像
docker run -d -P -v zdy-name-nginx:/etc/nginx --name nginx02 nginx:latest

卷的操作

1
2
3
4
5
6
7
8
9
10
11
docker volume [指令]

# 指令
create # 创建卷
inspect # 显示一个或多个卷的详细信息
ls # 列出卷
prune # 删除未使用的本地卷
rm # 删除一个或多个卷

# 举例
docker volume ls # 查看卷的列表

数据卷共享

当一个容器与另一个容器使用相同的数据卷时就称这两个容器实现了数据卷共享

当一个 容器C 启动运行时创建并挂载了数据卷若其它容器也需要共享 容器C 挂载的数据卷这些容器只需在 docker run 启动时通过 –volumes-from[容器C] 选项即可实现数据卷共享此时 容器C 就称为数据卷容器

1
docker run --name myubuntu --volumes-from 容器C -it ubuntu /bin/bash

数据卷的权限

1
2
3
4
# 容器对于卷ro只读在容器内部不能修改数据
docker run -d -P -v zdy-name-nginx:/etc/nginx:ro nginx
# 容器对于卷rw可读写在容器内部可读写
docker run -d -P -v zdy-name-nginx:/etc/nginx:rw nginx

💗💗一旦设置了容器的权限则不可修改默认是可读写权限

DockerFile

DockerFile的概念

Dockerfile 是一个用于自动化构建 Docker 镜像的文本文件其中包含了一系列命令和说明这些命令用于定制基础镜像安装软件设置环境变量暴露端口指定运行时的工作目录和启动命令等创建一个全新的 Docker 镜像Dockerfile 的命令类似于 Linux 的 shell 命令使得开发人员能够以简洁的方式表述镜像的构建过程

⭐⭐Dockerfile 的基本结构通常包括以下几个部分

  • 基础镜像信息
  • 维护者信息
  • 镜像操作指令
  • 容器启动时执行指令

💗💗Docker 引擎会读取 Dockerfile 中的指令依次执行它们最终生成一个新的 Docker 镜像这种方式标准化了应用的打包和部署流程提高了可移植性和重复性

基本结构与指令

基础镜像信息

基础镜像信息在 Dockerfile 中通过 FROM 指令指定这是 Dockerfile 中的第一条也是必备的指令

基础镜像实际上是构建新镜像的起始点它可以是一个预定义的操作系统镜像如 UbuntuAlpine LinuxCentOS或者是一个包含了特定运行环境的镜像比如带有 Java 运行时的 OpenJDK 镜像Python 的官方镜像等

也可以用一个特殊的 Docker 镜像scratch 镜像scratch 镜像表示一个完全空白的基础镜像它不包含任何操作系统层或文件系统实质上是一个空的无父镜像的状态当你使用 FROM scratch 开始一个 Dockerfile 时意味着你正在从零开始创建一个镜像你需要手动添加所有需要的文件和二进制执行文件

⭐⭐ FROM 指令添加基础镜像

1
2
3
4
5
# 格式: FROM <image>:<tag>
# 举例一
FROM scratch
# 举例二
FROM centos:7.9.0

维护者信息

⭐⭐ MAINTAINER 指令添加维护者信息

1
2
3
4
5
6
# 举例一
MAINTAINER name
# 举例二
MAINTAINER name@example.com
# 举例三
MAINTAINER 名字<name@example.com>

⭐⭐ LABEL 指令为生成的镜像添加元数据标签随着 Docker 的发展推荐的做法是使用 LABEL 指令来添加

1
2
3
4
5
# 格式: LABEL <key>=<value> <key>=<value> ...
# 举例
LABEL author.name="your-name" \
author.email="your-name@example.com" \
description="A custom Docker image maintained by your-name."

镜像操作指令

⭐⭐ WORKDIR 指令设置镜像的工作目录后续的RUNCMDENTRYPOINT指令将在这个目录下执行

1
2
# 格式: WORKDIR <dir>
WORKDIR /app

⭐⭐ VOLUME 指令创建一个挂载点用于持久化数据

1
2
3
4
5
# 格式: VOLUME ["/data"]
VOLUME ["/var/log/nginx", "/etc/nginx/conf.d"]

# 创建好后的使用方式
docker run -d -v /host/path/to/data:/data my_image

⭐⭐ RUN 指令在构建镜像的过程中执行命令可以是shell命令或执行器命令

1
2
# 格式: RUN <command> 或 RUN ["executable", "param1", "param2"]
RUN apt-get update && apt-get install -y nginx

⭐⭐ COPY 指令在构建镜像的过程中执行命令可以是shell命令或执行器命令

1
2
# 格式: COPY <src>... <dest>
COPY package.json /app/

⭐⭐ ADD 指令类似COPY但能处理URL和自动解压tar文件

1
2
3
# 格式: ADD <src>... <dest>
ADD file.tar.gz /app/
ADD https://example.com/archive.tar.gz /app/

⭐⭐ ENV 指令设置环境变量在构建过程及容器运行时生效

1
2
# 格式: ENV <key>=<value> <key>=<value> ...
ENV MYSQL_ROOT_PASSWORD=123456

⭐⭐ EXPOSE 指令声明容器运行时监听的端口供宿主机或其他服务访问

1
2
3
4
5
# 格式: EXPOSE <port> [<port>...]
EXPOSE 8080 80 443

# 创建好后的使用方式
docker run -p 10000:8080 -p 80:80 -p 443:443 nginx

⭐⭐ ARG 指令定义构建时变量可以在构建过程中使用这些变量

1
2
3
4
5
6
7
8
9
# 格式: ARG <name>[=<default value>]
ARG VERSION=1.0

# 使用构建参数
LABEL version=$VERSION
# 如果需要在 RUN 指令中使用并且变量名包含特殊字符或空格推荐使用 JSON 格式
RUN ["echo", "Building version", "${VERSION}"]
# 当你使用 docker build 命令构建镜像时可以通过 --build-arg 选项覆盖 Dockerfile 中定义的 ARG 变量的默认值
docker build --build-arg VERSION=2.0 -t my-image-name .

⭐⭐ SHELL 指令设置默认的shell

1
2
# 格式: SHELL ["executable", "param1", "param2"]
SHELL ["/bin/bash", "-c"]

⭐⭐ ONBUILD 指令触发指令当基于当前镜像构建新镜像时这些指令会被执行

1
2
# 格式: ONBUILD <instruction>
ONBUILD RUN npm install

⭐⭐ USER 指令指定运行容器时的用户和用户组

1
2
# 格式: USER <user>[:<group>]
USER nobody:nogroup

⭐⭐ STOPSIGNAL 指令设置容器停止时发送的系统信号默认是 SIGTERM

1
2
# 格式: STOPSIGNAL signal
STOPSIGNAL SIGINT

⭐⭐ HEALTHCHECK 指令配置健康检查命令用于判断容器服务是否健康运行

1
2
# 格式: HEALTHCHECK [OPTIONS] CMD command
HEALTHCHECK --interval=5s --timeout=3s CMD curl -f http://localhost/ || exit 1

容器启动时执行指令

⭐⭐ CMD 指令容器启动时默认执行的命令可以被docker run命令行参数覆盖

1
2
# 格式: CMD ["executable", "param1", "param2"] 或 CMD command param1 param2
CMD ["npm", "start"]

⭐⭐ ENTRYPOINT 指令容器启动时默认执行的命令不会被docker run的命令行参数覆盖命令行参数会追加到 ENTRYPOINT 指令后边

1
2
# 格式: ENTRYPOINT ["executable", "param1", "param2"] 或 ENTRYPOINT command param1 param2直接执行不会拼接
ENTRYPOINT ls -a

构建Docker镜像

编写文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
cd /home
mkdir -p docker/tomcat/bulid
touch Dockerfile
vi Dockerfile
# ---------------- vi 编辑器 --------------------
FROM centos
LABEL author.name="szxck" author.url="szxck.top"

ARG MYPATH=/usr/local

WORKDIR ${MYPATH}

RUN rm -f /etc/yum.repos.d/*.repo

RUN echo "[AppStream]" >> CentOS-Linux-AppStream.repo
RUN echo "name=AppStream" >> CentOS-Linux-AppStream.repo
RUN echo "baseurl=https://mirrors.aliyun.com/centos/\$releasever/AppStream/\$basearch/os/" >> CentOS-Linux-AppStream.repo
RUN echo "gpgcheck=1" >> CentOS-Linux-AppStream.repo
RUN echo "enabled=1" >> CentOS-Linux-AppStream.repo
RUN echo "gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial" >> CentOS-Linux-AppStream.repo

RUN echo "[BaseOS]" >> CentOS-Linux-BaseOS.repo
RUN echo "name=CentOS-\$releasever - BaseOS" >> CentOS-Linux-BaseOS.repo
RUN echo "baseurl=https://mirrors.aliyun.com/centos/\$releasever/BaseOS/\$basearch/os/" >> CentOS-Linux-BaseOS.repo
RUN echo "gpgcheck=1" >> CentOS-Linux-BaseOS.repo
RUN echo "enabled=1" >> CentOS-Linux-BaseOS.repo
RUN echo "gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial" >> CentOS-Linux-BaseOS.repo

RUN mv CentOS-Linux-AppStream.repo /etc/yum.repos.d/
RUN mv CentOS-Linux-BaseOS.repo /etc/yum.repos.d/

RUN yum clean all
RUN yum makecache
RUN yum install -y vim

ADD jdk-8u11-linux-x64.tar.gz ${MYPATH}/java
ADD apache-tomcat-8.5.100.tar.gz ${MYPATH}/tomcat

ENV JAVA_HOME=${MYPATH}/java/jdk1.8.0_11
ENV CLASSPATH=$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV TMOCAT_HOME=${MYPATH}/tomcat/apache-tomcat-8.5.100
ENV TMOCAT_BASH=${MYPATH}/tomcat/apache-tomcat-8.5.100
ENV PATH=$PATH:$JAVA_HOME/bin:${TMOCAT_HOME}/lib:${TMOCAT_HOME}/bin

EXPOSE 8080

CMD /usr/local/tomcat/apache-tomcat-8.5.100/bin/startup.sh && tail -F /usr/local/tomcat/apache-tomcat-8.5.100/logs/catalina.out
# ----------------------------------------------

构建镜像

1
2
3
4
5
# 命令行最后的 点(表示当前目录) 不要忘记
docker build -f Dockerfile -t tomcat-centos:1.0 .

# 构建成功后可以查看镜像的构建流程
docker history image_id

运行镜像

1
2
3
4
5
# 运行构建好的镜像
docker run -d -p 10000:8080 -v /home/docker/tomcat/test:/usr/local/tomcat/apache-tomcat-8.5.100/webapps/test -v /home/docker/tomcat/logs:/usr/local/tomcat/apache-tomcat-8.5.100/logs --name tomcat-centos tomcat-centos:1.0

# 测试
curl localhost:10000

构建运行Jar包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 首先把jar包上传到Linux

# 编写Dockerfile文件
vi Dockerfile
# ---------------- vi 编辑器 --------------------
FROM openjdk:8u102
LABEL auth=szxck email=suzengxin@foxmail.com
WORKDIR /home
COPY app.jar /home/app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
# ----------------------------------------------

# 构建镜像
docker build -t hello-docker .

# 运行镜像
docker run -d -p 8080:8080 --name hello-docker hello-docker

# 测试
curl localhost:8080

Docker缓存机制

Docker Build 缓存机制是为了加速镜像构建过程而设计的当你使用 docker build 命令来创建一个新的镜像时Docker 会根据 Dockerfile 中的指令逐步执行并构建每个镜像层为了提高效率Docker 使用缓存机制避免重新构建那些在之前的构建中没有发生变化的部分

⭐⭐以下是一些关于 Docker Build 缓存机制的关键点

  • 缓存键Cache KeyDocker 计算一个缓存键它基于 Dockerfile 中每条指令的内容及其所依赖的文件如果这些内容或文件没有变化缓存键保持不变Docker 就可以重用缓存缓存键考虑到了文件的元数据如修改时间权限inode 等和文件的实际内容
  • ADD 和 COPY 指令ADD 和 COPY 指令会触发缓存键的重新计算如果在这两个指令中引用的文件发生变化缓存就会失效即使 Dockerfile 没有变化如果文件的修改时间或内容发生变化即使文件名相同缓存也会失效
  • 缓存失效当 Dockerfile 或其引用的文件发生变化时从那个点开始的缓存都会失效后续的指令需要重新执行例如如果 Dockerfile 的第一条 RUN 指令之后是一个 COPY 指令并且 COPY 的源文件被修改那么所有在 COPY 之后的指令都需要重新执行即使它们自身没有变化
  • 禁用缓存可以通过向 docker build 命令添加 –no-cache 参数来完全禁用缓存这通常用于确保镜像是根据最新的代码和依赖项构建的
  • 缓存清理Docker 会自动管理缓存但有时可能需要手动清理以释放磁盘空间可以使用 docker builder prune 命令来清除不再使用的构建缓存
  • BuildKitDocker 18.09 引入了 BuildKit这是一个用于构建镜像的新引擎它提供了更高级别的缓存管理和其他功能比如并行化构建步骤

💗💗Docker Build 缓存机制对于优化构建流程和减少构建时间非常重要正确地组织 Dockerfile 和使用缓存可以帮助你更快地迭代和部署应用

Docker网络原理

Docker网络架构基础

📶📶 Docker0网桥当你在宿主机上安装Docker时会自动创建一个名为docker0的虚拟网桥这个网桥本质上是一个软件定义的网络交换机允许连接到它的网络设备即容器相互通信并可配置与外部网络的连接

📶📶 网络命名空间每个Docker容器都运行在自己的网络命名空间中这意味着每个容器都有独立的网络设备IP地址路由表等实现了容器间的网络隔离

📶📶 Veth Pair vethvirtual Ethernet对是一种虚拟网络设备对通常用于连接两个网络命名空间当创建一个新的Docker容器时会创建一对veth接口一端位于容器内部如eth0另一端则连接到宿主机上的网络栈通常绑定到docker0网桥上这样容器内的网络流量可以通过这对veth接口流向宿主机网络并通过docker0网桥与其他容器通信

1
2
3
4
5
6
7
8
# 宿主机查看Veth Pair
ip addr

# 查看所有的Docker网络
docker network ls

# 查看 Docker0网桥为容器分配的IP地址
docker exec -it CONTAINER_ID ip addr

容器间通信原理

📤📤 同一宿主机上的容器通信同一宿主机上的Docker容器通过共享docker0网桥实现通信每个容器获得一个与docker0网桥同网段的IP地址由于它们处于同一子网可以直接通过IP通信无需额外配置

📤📤 跨宿主机容器通信当容器分布在不同的宿主机上时需要更复杂的网络配置如使用Docker的overlay网络或第三方网络插件实现跨宿主机容器的通信

1
2
3
4
5
6
7
8
9
# 使用IP地址可以实现本地容器的相互通信
docker exec -it CONTAINER_ID ping Docker0网桥为容器分配的IP地址

# 启动镜像时可以配置要连通的镜像就可以使用容器名称进行通讯
# 原理就是修改hosts文件把容器名称指向了IP地址
docker run -d -P --link tomcat01 --name tomcat02 tomcat

# 根据容器名称通讯只是单向的配置好才能使用
docker exec -it tomcat02 ping tomcat01

ARP协议与容器发现

🔎🔎 ARP协议当容器需要与另一个容器通信但只知道目标容器的IP地址时会使用ARPAddress Resolution Protocol协议来解析目标容器的MAC地址容器会发送ARP广播请求询问具有特定IP地址的MAC地址目标容器接收到请求后会回应其MAC地址发起请求的容器即可构建完整的以太网帧进行通信

网络配置与管理

⏩⏪ 端口映射Docker支持端口映射允许将容器内部的服务端口映射到宿主机的某个端口使得外部网络可以通过宿主机的IP和端口访问容器内的服务

💿💿 Docker网络驱动Docker提供了多种网络驱动包括bridge默认hostnoneoverlay等每种模式提供了不同的网络隔离和连接策略满足不同场景下的网络需求

1
2
# 桥接模式在启动时默认会加上--net bridge 
docker run -d -P --net bridge --name tomcat01 tomcat

自定义网络

创建自定义网络

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 自定义一个Docker网络
# --driver bridge桥接模式不写也可以因为它是默认的
# --subnet 192.168.0.0/16子网掩码
# --gateway 192.168.0.1网关地址
# mynet自定义的网络名称
docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet

# 查看创建好的网络
docker network ls

# 查看网络详情
docker network inspect mynet

# 容器使用自定义的网络
docker run -d -P --net mynet --name tomcat-net-01 tomcat
docker run -d -P --net mynet --name tomcat-net-02 tomcat

# 测试连通
docker exec -it tomcat-net-01 ping tomcat-net-02

容器互通

💗💗 在不同的自定义网络中容器的相互通信

1
2
3
4
# 想让其他网络地址下的 tomcat01 容器跟 mynet 网络下的容器进行通信
# 只需要把 tomcat01 容器加入到 mynet 网络下就可以了
# 实际就是给 tomcat01 容器再配置一个 mynet 网段下的IP地址
docker network connect mynet tomcat01

网络共享

1
2
# tomcat02 容器使用 tomcat01 容器的网络
docker run -d -P --network container:tomcat01 --name tomcat02 tomcat

搭建 Redis 集群

💗💗 创建Docker自定义网络

1
docker network create --subnet 192.169.0.0/16 --gateway 192.169.0.1 redis

💗💗 创建Redis容器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# 新建一个脚本创建6个Redis容器
mkdir -p /home/docker/redis
cd /home/docker/redis
vi createRedis.sh
# ---------------- vi 编辑器 --------------------
for port in $(seq 1 6);
do
# 创建Redis配置文件
mkdir -p /home/docker/redis/node-${port}/conf
touch /home/docker/redis/node-${port}/conf/redis.conf
cat << EOF > /home/docker/redis/node-${port}/conf/redis.conf
port 6379
bind 0.0.0.0
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
cluster-announce-ip 192.169.0.1${port}
cluster-announce-port 6379
cluster-announce-bus-port 16379
appendonly yes
EOF

# 创建Redis容器
docker run -p 637${port}:6379 -p 1637${port}:16379 \
-v /home/docker/redis/node-${port}/data:/data \
-v /home/docker/redis/node-${port}/conf/redis.conf:/etc/redis/redis.conf \
-d --net redis --ip 192.169.0.1${port} \
--name redis-${port} \
redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
done
# ----------------------------------------------
# 修改脚本执行权限
chmod +x createRedis.sh
# 执行脚本创建Redis
./createRedis.sh

💗💗 配置Redis集群

1
2
3
4
5
6
7
8
9
10
11
# 进入redis-1容器
docker exec -it redis-1 /bin/sh
# 配置集群
redis-cli --cluster create \
192.169.0.11:6379 \
192.169.0.12:6379 \
192.169.0.13:6379 \
192.169.0.14:6379 \
192.169.0.15:6379 \
192.169.0.16:6379 \
--cluster-replicas 1

💗💗 测试Redis集群

1
2
3
4
5
6
7
8
# 进入Redis集群
redis-cli -c

# 查看集群信息
cluster info

# 查看节点信息
cluster nodes

Docker Compose

Docker Compose 是一个用于定义和运行多容器 Docker 应用程序的工具使用 YAML 文件描述整个应用程序的组件包括每个服务的容器网络卷和其他资源通过这种方式可以将复杂的应用程序环境封装成可移植且可重复的单元

💗💗 Docker Compose 的核心概念

  • 项目Project一个项目是指由一组相关服务组成的集合它们一起构成一个完整的应用程序所有服务都定义在一个 docker-compose.yml 文件中并且属于同一个项目
  • 服务Service每个服务定义了运行该服务的一个或多个容器的配置包括使用的镜像端口映射环境变量卷绑定等
  • 容器Container服务下运行的实际实例每个服务可以运行一个或多个容器实例
  • 网络NetworkDocker Compose 支持自定义网络允许服务之间的容器相互通信
  • Volume用于数据持久化可以在容器重启或重建后保留数据

💗💗 Docker Compose 的优势

  • 简化配置使用 YAML 文件集中管理所有服务的配置便于维护和版本控制
  • 自动化部署可以通过一个命令启动或停止所有服务减少手动配置的错误
  • 环境一致性确保本地开发环境与生产环境保持一致
  • 可扩展性易于添加或删除服务适应应用程序的变化

常用命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
docker compose attach       #将本地标准输入输出和错误流附加到服务的运行容器
docker compose build #生成或重新生成服务
docker compose config #解析解析并呈现规范格式的compose文件
docker compose cp #在服务容器和本地文件系统之间复制文件/文件夹
docker compose create #为服务创建容器
docker compose down #停止并移除容器网络
docker compose events #从容器接收实时事件
docker compose exec #在运行的容器中执行命令
docker compose images #列出创建的容器使用的图像
docker compose kill #强制停止服务容器
docker compose logs #查看容器的输出
docker compose ls #列出正在运行的compose项目
docker compose pause #暂停服务
docker compose port #打印端口绑定的公共端口
docker compose ps #列出容器
docker compose pull #拉取服务镜像
docker compose push #推送服务图片
docker compose restart #重新启动服务容器
docker compose rm #删除已停止的服务容器
docker compose run #在服务上运行一次性命令
docker compose scale #缩放服务
docker compose start #启动服务
docker compose stats #显示容器资源使用统计信息的实时流
docker compose stop #停止服务
docker compose top #显示正在运行的进程
docker compose unpasse #未使用的服务
docker compose up #创建并启动容器
docker compose version #显示docker Compose版本信息
docker compose wait #阻止直到第一个服务容器停止
docker compose watch #监视服务的构建上下文并在文件更新时重建/刷新容器

项目部署

创建构建文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# 把 jar 文件放入该目录下
cd /home/docker/szxck

# 新建 jar 服务的 Dockerfile 文件
vi Dockerfile
# ---------------- vi 编辑器 --------------------
FROM openjdk:8u102
LABEL auth=szxck email=suzengxin@foxmail.com
WORKDIR /home
COPY app.jar /home/app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
# ----------------------------------------------

# 新建 compose 构建文件
vi compose.yml
# ---------------- vi 编辑器 --------------------
networks:
szxck-net:
driver: bridge

services:
szxck-server:
build: ./
image: szxck-server:1.0
container_name: szxck-server
ports:
- 10000:8080
networks:
- szxck-net
volumes:
- ./logs:/home/logs
depends_on:
- szxck-mysql
- szxck-redis

szxck-mysql:
image: mysql:5.7
container_name: szxck-mysql
environment:
MYSQL_ROOT_PASSWORD: 123456
ports:
- 3306:3306
networks:
- szxck-net
volumes:
- /home/docker/mysql/log:/var/log/mysql
- /home/docker/mysql/data:/var/lib/mysql
- /home/docker/mysql/conf:/etc/mysql/conf.d

szxck-redis:
image: redis:latest
container_name: szxck-redis
ports:
- 6379:6379
networks:
- szxck-net
volumes:
- /home/docker/redis/redis.conf:/etc/redis/redis.conf
- /home/docker/redis/data:/data
command: redis-server /etc/redis/redis.conf
# ----------------------------------------------

验证文件

1
docker compose config -q

启动服务

1
docker compose -f compose.yml up -d

Docker Swarm

Docker Swarm 是 Docker 公司提供的一个用于构建和管理容器集群的工具它允许用户将多个 Docker 主机组织成一个集群并且能够统一管理和调度集群内的容器

Docker Swarm 提供了集群级别的特性如服务发现负载均衡以及跨主机的网络连接使得在集群环境中部署和管理容器化应用变得更为简单

💗💗Docker Swarm 的组件

  • 管理节点 (Manager nodes)管理节点负责维护集群状态执行编排决策和协调任务它们存储集群的状态和配置信息并处理加入和离开集群的请求至少需要一个管理节点来启动 Swarm 集群
  • 工作节点 (Worker nodes)工作节点是执行容器和任务的实际机器它们接收来自管理节点的任务并在其上运行容器实例
  • 服务 (Services)服务定义了容器运行的策略包括容器的数量网络设置更新策略等Docker Swarm 使用服务的概念来实现容器的编排
  • 任务 (Tasks)任务是服务的具体实例代表了运行中的容器每个服务可以有多个任务这些任务可以在集群中的不同工作节点上运行
  • 网络 (Networks)Docker Swarm 支持多种网络模式包括覆盖网络 (overlay networks)允许容器在不同的主机之间相互通信
  • 堆栈 (Stacks)堆栈是一个或多个服务的集合通常由 Docker Compose 文件定义可以在 Swarm 模式下部署

💗💗Docker Swarm 的优势

  • 易于使用Swarm 与 Docker 引擎紧密集成使用 Docker CLI 或者 API 即可管理集群
  • 轻量级相比于 KubernetesSwarm 更轻量适合小型或中型部署
  • 内置网络Swarm 提供了内置的覆盖网络简化了跨主机容器间的通信
  • 安全性Swarm 支持加密通信和认证机制确保集群的安全性

常用命令

初始化集群

1
docker swarm init

加入节点

1
2
3
docker swarm join
docker swarm join-token manager
docker swarm join-token worker

部署服务

1
2
docker service create
docker stack deploy

管理节点

1
2
3
4
5
docker info
docker node ls
docker node inspect
docker node update
docker node rm

管理服务

1
2
3
4
docker service ls
docker service inspect
docker service scale
docker service rm

集群搭建

集群初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 初始化 Swarm 集群主机
docker swarm init --advertise-addr 服务器IP地址
# 获取加入到集群主节点的命令主机
docker swarm join-token manager
# 获取加入到集群子节点的命令主机
docker swarm join-token worker

# 根据集群需求选择加入主节点还是子节点一般是三主三从
# 加入到主节点其他服务器以下命令是根据上边的命令获取到的
docker swarm join --token SWMTKN-1-24xzkhefjywjnn078e10w5c6z4c33jbp2hft0dfcmdb4l73jri-4p0mjvzk7xxvsyh08fyj6lbtq 172.14.195.136:2377
# 加入到子节点其他服务器以下命令是根据上边的命令获取到的
docker swarm join --token SWMTKN-1-24xzkhefjywjnn078e10w5c6z4c33jbp2hft0dfcmdb4l73jri-1sr5j29kqudsoreh3ssp0huou 172.14.195.136:2377

# 查看集群列表
docker node ls

添加备注信息

💗💗给节点添加描述信息便于浏览记忆

1
2
3
4
5
6
7
# 添加描述信息
# 5w16y47qf225m8ac2ggyh6mt9 节点标识
# 可以通过 docker info 命令查看要升级节点的标识
docker node update --label-add auth=李四 --label-add email=lisi@163.com 5w16y47qf225m8ac2ggyh6mt9

# 移除描述信息
docker node update --label-rm email 5w16y47qf225m8ac2ggyh6mt9

节点升级/降级

💗💗升级节点为 manager 节点

1
2
3
4
5
# 5w16y47qf225m8ac2ggyh6mt9 节点标识
# 可以通过 docker info 命令查看要升级节点的标识
docker node promote 5w16y47qf225m8ac2ggyh6mt9
# 第二种方式
docker node update --role manager 5w16y47qf225m8ac2ggyh6mt9

💗💗降级节点为 worker 节点

1
2
3
4
5
# 5w16y47qf225m8ac2ggyh6mt9 节点标识
# 可以通过 docker info 命令查看要升级节点的标识
docker node demote 5w16y47qf225m8ac2ggyh6mt9
# 第二种方式
docker node update --role worker 5w16y47qf225m8ac2ggyh6mt9

节点退出集群

1
2
3
4
5
6
7
8
9
10
11
12
# worker节点退出集群
docker swarm leave

# manager节点退出集群
# 先把manager节点变更为worker节点然后在退出集群
# 也可以强制离开集群不推荐
docker swarm leave --force

# 移除节点
# 5w16y47qf225m8ac2ggyh6mt9 节点标识
# 可以通过 docker info 命令查看要升级节点的标识
docker node rm -f 5w16y47qf225m8ac2ggyh6mt9

集群退出自动锁定

💗💗开启集群退出自动锁定后节点中需要至少有一个manager节点运行不然manager节点全部宕机则启动秘钥丢失秘钥保存在内存中集群就不可使用只能离开原有集群重新搭建

1
2
3
4
5
6
7
8
9
10
11
# 开启集群退出自动锁定
docker swarm update --autolock=true

# 关闭集群退出自动锁定
docker swarm update --autolock=false

# 查看启动秘钥
docker swarm unlock-key

# 重新加入集群运行命令后输入秘钥
docker swarm unlock

集群通信安全

Docker Swarm 的通信安全主要围绕着确保集群内部通信以及客户端与集群之间通信的完整性机密性和不可否认性Swarm 通过使用 Transport Layer Security (TLS) 加密来实现这一目标以防止中间人攻击数据窃听和其他安全威胁

Docker Swarm 使用 TLS 加密来保护管理节点和工作节点之间的通信同时也用于保护 Docker 客户端与 Swarm 集群之间的通信TLS 证书可以由任何证书颁发机构CA生成包括自签名证书或第三方 CA

💗💗在 Swarm 集群中TLS 证书通常包括以下几部分

CA 证书这是集群的根证书用于签发所有其他证书


Manager 证书为每个管理节点生成的证书用于与其他节点通信
Worker 证书为每个工作节点生成的证书用于与管理节点通信
客户端证书为每个需要与 Swarm 集群交互的 Docker 客户端生成的证书

💗💗安全通信端口

2377/tcp用于客户端与 Swarm 进行安全通信以及管理节点之间的通信


7946/tcp 和 7946/udp用于节点之间的心跳检测和集群状态的同步
4789/udp用于 overlay 网络的 VXLAN 通信

💗💗Swarm 集群的安全性

定期轮换证书定期更换 TLS 证书尤其是当有节点离开集群或怀疑证书已泄露时


限制对管理节点的访问只允许经过身份验证和授权的客户端访问管理节点
使用强密码策略为 Docker 客户端和节点使用复杂的密码或 SSH 密钥进行身份验证
监控和审计实施日志记录和审计措施监控集群活动以便及时发现异常行为

集群服务

创建服务容器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 跟运行容器命令差不多
# --replicas 3创建三个副本运行任务/运行容器负载均衡轮询分配到各个节点
docker service create -p 9000:8080 --replicas 3 --name tomcat tomcat:8.5.49

# --mode global: 全局模式每个节点分配一个任务
docker service create -p 9000:8080 --mode global --name tomcat tomcat:8.5.49

# 创建服务其他配置服务回滚
docker service create \
-p 9000:8080 \
--replicas 5 \
--name tomcat \
--update-parallelism 2 \ # 更新并发量
--update-delay 3s \ # 更新间歇时间
--update-max-failure-ratio 0.2 \ # 允许更新最大失败率
--update-failure-action rollback \ # 更新超过失败率回滚
--rollback-parallelism 2 \ # 回滚一次两个
--rollback-delay 3s \ # 回滚间歇时间
--rollback-max-failure-ratio 0.2 \ # 回滚最大失败率
--rollback-failure-action contiue \ # 回滚超过失败率继续 | 暂停
tomcat:8.5.39

服务列表查询

1
2
3
docker service ls
docker service ps tomcat
docker node ps

更新服务

1
docker service update --image tomcat:8.5.39 tomcat

服务回滚

1
docker service update --rollback tomcat

服务扩容\缩容

1
2
3
4
5
# 第一种方法
docker service update --replicas 5 --name tomcat

# 第二种方法
docker service scale tomcat=5

节点暂停扩容

1
2
# 集群部署服务时不在给改节点分配任务但原有的任务还可以访问
docker node update --availability pause 5w16y47qf225m8ac2ggyh6mt9

节点清空任务

1
2
# 清空该节点上集群部署的任务集群会把任务重新分配到其他节点
docker node update --availability drain 5w16y47qf225m8ac2ggyh6mt9

删除服务任务

1
docker service rm tomcat

负载均衡验证

1
2
3
# 使用该容器可以验证负载均衡
docker service create -p 8080:80 --replicas 5 --name whoami containous/whoami
curl http://localhost:8080

集群网络

Swarm 使用一种称为 Overlay 网络的技术来实现跨主机的服务通信这使得容器可以在集群中的任何节点上运行同时保持与其他容器的网络连通性

💗💗Swarm 集群网络主要分为以下几个部分


Swarm Overlay 网络: Swarm 提供了一种特殊的网络类型即 Overlay 网络它允许容器跨越不同的物理或虚拟主机进行通信当在一个 Swarm 集群中创建服务时Docker 会自动为服务创建一个 Overlay 网络这个网络类型是基于 VXLAN 的这意味着它使用封装技术在底层网络上创建了一个逻辑上的二层网络这样容器就像在同一台主机上一样进行通信而实际上它们可能分布在集群的不同节点上
Ingress 网络当服务被创建时Swarm 也会创建一个 Ingress 网络这个网络用于将外部流量路由到服务的容器实例上Ingress 网络利用了负载均衡器通常是 Traefik 或 Nginx来转发流量到正确的容器Ingress 网络使用一个虚拟 IP (VIP) 来接收外部请求并将请求路由到集群内服务的实例上
Node 网络每个 Swarm 节点都有一个 Node 网络它负责将容器与本地网络接口连接起来同时也提供了与 Overlay 网络的连接Node 网络是每个节点上的默认桥接网络
端口映射和服务发现服务在 Swarm 集群中可以定义端口映射将容器的端口暴露给外部世界此外Swarm 支持服务发现允许容器自动找到同一服务的其他实例而无需显式配置
网络策略和安全Swarm 允许管理员设置网络策略例如限制容器之间的通信或访问外部网络的权限这可以通过网络的标签和容器的网络连接规则来实现
DNS 解析Swarm 集群中的容器可以自动解析服务名称到其 IP 地址这得益于内置的 DNS 服务使得容器间的通信更加便捷

CI/CD | DevOps

概述

CI/CD 是现代软件开发和运维DevOps中非常关键的概念CI/CD 不仅是一种技术实践也是一种文化和工作流程的变革它鼓励团队采用敏捷开发方法快速迭代同时保持高度的质量标准通过自动化和标准化CI/CD 帮助组织实现了更快的软件交付周期提高了软件质量和客户满意度

💗💗 CI

持续集成Continuous Integration持续集成是一种软件开发实践要求开发人员经常比如每天将他们的工作集成到共享的主干分支中每次集成后会通过自动化构建包括编译和测试来验证以便尽早发现集成错误

💗💗 CD

  • 持续交付Continuous Delivery持续交付扩展了持续集成的概念它不仅包括自动化构建和测试还包含了自动化部署至测试和预生产环境这意味着软件产品在任何时刻都可以被部署到生产环境但实际是否部署则由人工决策
  • 持续部署Continuous Deployment持续部署是持续交付的进一步延伸它指的是每当代码通过了所有预定的测试之后就自动部署到生产环境中无需人工干预

💗💗DevOps

DevOps 是一个结合了软件开发Development和 IT 运维Operations的术语旨在促进软件开发技术运营和质量保证QA部门之间的沟通协作与整合DevOps 文化和实践的目标是缩短系统开发周期提供持续的交付和部署能力同时仍然保持高质量的软件产品DevOps 是一种综合的方法论它改变了传统软件开发和运维的分离模式推动了软件开发的现代化和高效化

💗💗工具链

  • 源代码管理系统如 Git 和 SVN
  • 构建和自动化工具如 JenkinsTravis CIGitLab CI/CD 和 GitHub Actions
  • 自动化测试框架如 JUnitSeleniumPostman 等
  • 容器化和虚拟化平台如 Docker 和 Kubernetes
  • 配置管理工具如 AnsibleChef 和 Puppet
  • 监控和日志工具如 PrometheusGrafana 和 ELK Stack

系统架构

CI/CD简化流程图

graph LR;
A[代码提交] --> B{构建};
B -->|通过| C[测试];
B -->|失败| F[构建失败];
C --> D{代码审查};
D -->|通过| E[制品];
D -->|失败| G[代码审查失败];
E --> H[打包];
H --> I{部署};
  I -->|成功| J[生产环境];
  I -->|失败| K[部署失败];
  J --> L[监控];
  L --> M{问题};
  M -->|是| N[警报];
  M -->|否| J;

classDef success fill:#0f0,stroke:#333,stroke-width:4px;
classDef fail fill:#f00,stroke:#333,stroke-width:4px;
classDef monitoring fill:#ccc,stroke:#333,stroke-width:4px;

class J success;
class F,G,K,N fail;
class L monitoring;

系统整体架构图

C4Container

Person(User, 用户, "Eclipse | IDEA")

Container(GitLab, "源代码仓库", "Git | GitLab | SVN")

Container_Boundary(Jenkins, "Jenkins") {
  Container(Maven, "mvn package", "源代码打包")
  Container(SonarScanner, "SonarScanner", "SonarQube客户端")
  Container(Docker, "cocker build", "构建镜像")
  Container(JT, "监听")
}

Container_Boundary(SonarQube, "SonarQube") {
  Container(SonarQube, "SonarQube")
}

Container_Boundary(Harbor, "Harbor") {
  Container(Harbor, "Harbor", "镜像仓库")
}

Container_Boundary(TargetServer, "TargetServer") {
  Container(DockerServer, Docker, "docker run")
}

Container(DD, "钉钉")

Rel(User, GitLab, "Uses", "git push")
Rel(GitLab, Maven, "git push")
Rel(Maven, SonarScanner, "")
Rel(SonarScanner, Docker, "")
Rel(SonarScanner, SonarQube, "代码质量检测")
Rel(Docker, Harbor, "docker push")
Rel(Docker, DockerServer, "SSH:cmd")
Rel(Harbor, DockerServer, "docker pull")
Rel(JT, DD, "消息推送")

UpdateRelStyle(User, GitLab, $offsetY="10")
UpdateRelStyle(JT, DD, $offsetY="-100", $offsetX="-30")
UpdateRelStyle(SonarScanner, SonarQube, $offsetY="10", $offsetX="-50")
UpdateRelStyle(Harbor, DockerServer, $offsetY="10", $offsetX="-45")

Docker项目配置运行

安装可视化面板

1
2
3
4
5
6
7
8
9
10
11
12
# 后台运行 portainer 容器
# --restart=always守护进程在容器退出后总是重启该容器
# --privileged=true以特权模式运行容器可以访问主机的底层资源和功能
docker run -d \
-p 9000:9000 \
-p 9443:9443 \
-v /data
-v /var/run/docker.sock:/var/run/docker.sock \
--restart=always \
--privileged=true \
--name portainer \
portainer/portainer-ce

安装 Nginx 容器

1
2
3
4
5
6
7
8
docker run --rm --entrypoint=cat nginx /etc/nginx/conf.d/default.conf > /home/docker/nginx/conf.d/default.conf
docker run --rm --entrypoint=cat nginx /etc/nginx/nginx.conf > /home/docker/nginx/nginx.conf
docker run -d -p 10000:80 \
-v /home/docker/nginx/conf.d:/etc/nginx/conf.d\
-v /home/docker/nginx/nginx.conf:/etc/nginx/nginx.conf \
-v /home/docker/nginx/html:/usr/share/nginx/html \
--name nginx \
nginx

安装 MySql 容器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 安装 mysql
docker run -d -p 10000:3306 \
-e MYSQL_ROOT_PASSWORD=123456 \
-v /home/docker/mysql/conf:/etc/mysql/conf.d \
-v /home/docker/mysql/data:/var/lib/mysql \
-v /home/docker/mysql/log:/var/log/mysql \
--name mysql \
mysql:5.7

# 中文乱码问题
vim /home/docker/mysql/conf/my.cnf
# ---------------- vi 编辑器 --------------------
[client]
default_character_set=utf8

[mysql]
default_character_set=utf8

[mysqld]
character_set_server=utf8
# ----------------------------------------------

# 重启容器
docker restart mysql

搭建私有镜像中心registry

安装httpd-tools

1
2
# 需要httpd-tools工具包中的 htpasswd 命令生成密码
yum install -y httpd-tools

创建镜像中心登录用户

1
2
3
4
5
6
7
8
9
# 创建一个目录存放密码文件
mkdir -p /home/docker/auth
cd /home/docker/auth
# 新建文件并且添加用户
htpasswd -Bbc htpasswd.user zhangsan 123
# 添加用户
htpasswd -Bb htpasswd.user lisi 123
# 删除用户
htpasswd -D htpasswd.user lisi

运行容器

1
2
3
4
5
6
7
8
9
10
11
# 运行容器
docker run \
-d -p 5000:5000 \
--restart always \
-v /var/lib/registry:/var/lib/registry \
-v /home/docker/auth:/auth \
-e "REGISTRY_AUTH=htpasswd" \
-e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \
-e "REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd.user \
--name registry \
registry

把请求改为http

1
2
3
4
5
6
7
8
9
10
vi /etc/docker/daemon.json
# ---------------- vi 编辑器 --------------------
# registry-mirrors镜像加速
# insecure-registries注册镜像库地址
# 192.168.192.111:5000registry容器的地址
{
"registry-mirrors": ["https://xxxxxxxx.mirror.aliyuncs.com"],
"insecure-registries": ["192.168.192.111:5000"]
}
# ----------------------------------------------

推送镜像

1
2
3
4
5
6
# 登录
docker login -u zhangsan 192.168.192.111:5000
# 打标签
docker tag hello-world 192.168.192.111:5000/zhangsan/hw:1.0
# 推送
docker push 192.168.192.111:5000/zhangsan/hw:1.0

查看镜像

1
2
3
4
5
curl -u zhangsan:123 -XGET http://192.168.192.111:5000/v2/_catalog

curl -u zhangsan:123 -XGET http://192.168.192.111:5000/v2/zhangsan/hw/tags/list

tree /var/lib/registry

修改配置

1
2
3
4
5
6
7
8
9
10
# 默认是不能删除镜像的需要手动配置
docker exec -it registry /bin/sh
vi /etc/docker/registry/config.yml
# ---------------- vi 编辑器 --------------------
storage:
delete:
enabled: true
# ----------------------------------------------
# 重启容器
docker restart registry

删除镜像

1
2
3
4
5
# 删除镜像
curl -u zhangsan:123 -I -XDELETE http://192,168.192.111:5000/v2/zhangsan/hw/manifests/sha256:7071451ad41asdada1531as3415

# blobs
docker exec -it registry registry garbage-collect /etc/docker/registry/config.yml

搭建源代码仓库GitLab

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# 拉取镜像
docker pull gitlab/gitlab-ce
# 创建目录
mkdir -p /home/docker/gitlab
# 创建构建文件
vi compose.yml
# ---------------- vi 编辑器 --------------------
services:
gitlab:
image: gitlab/gitlab-ce
container_name: gitlab
restart: always
environment:
GITLAB_OMNIBUS_CONFIG:
external_url 'http://192.168.153.128:9999'
gitlab_rails['initial_root_password']=123456789
gitlab_rails['gitlab_shell_ssh_port']=2222
ports:
- 9999:9999
- 2222:2222
volumes:
- ./config:/etc/gitlab
- ./logs:/var/log/gitlab
- ./data:/var/opt/gitlab
# ----------------------------------------------
# 验证文件是否正确
docker compose config -q
# 运行配置文件
docker compose up -d
# 查看是否启动
docker logs gitlab
# 获取登录密码
docker exec -it gitlab bash
cat /etc/gitlab/initial_root_password
# 登录页面
http://192.168.153.128:9999

学习资源