12-Docker(28)
1. 什么、为什么、如何使用
- Docker是一种容器化技术,它允许开发者将应用程序及其所有依赖项打包到一个独立的容器中,包括操作系统、库、运行时环境等。这个容器可以在任何支持 Docker 的平台上运行,确保应用程序在不同环境中具有一致的行为
- 在本项目中使用 Docker 主要是为了保证代码沙箱服务执行用户代码的安全性,防止影响宿主机
- 首先在 Linux 虚拟机内安装了 Docker,然后用 Docker 命令行跑通了一次从拉取镜像、执行容器再到删除容器的完整流程。在代码沙箱项目中,使用 Docker Java 库来操作 Docker,包括 Docker 容器的创建、连接 Docker 容器执行命令、获取 Docker 容器的日志和输出、获取 Docker 容器的内存占用等
2. 保证代码沙箱执行程序时安全性
虽然 Docker 本身提供了一个隔离的代码执行环境,但仍无法做到绝对的安全,通过以下几种方法,进一步提高 Docker 代码沙箱的安全性
- 超时控制:在向容器发送执行命令时,指定超时参数,超时自动中断
- 资源限制:创建容器实例时,通过 HostConfig 指定分配的最大内存和 CPU 占用
- 网络限制:创建容器实例时,通过 withNetworkDisabled 方法禁用网络
- 权限管理:通过 seccomp 或 Java 安全管理器,限制用户代码允许的操作和调用
3. 基本概念及核心组件
Docker 是一个开源的平台,旨在实现应用的自动化部署。它通过OS级别的虚拟化来交付软件,使其能够在隔离的环境中运行
- 优点:在于“一致性”,即应用程序可以在任何地方运行,而不需要关心底层环境是否一致
核心组件:
- 镜像(Image):镜像是 Docker 的基础,它是一个只读的模板,其中包括了运行代码所需的所有内容(如操作系统、应用程序、库等)。你可以把镜像看作是应用程序或服务的起点
- 容器(Container):容器是镜像的运行实例。它包含了所有必要的组件,以完全隔离的方式运行你的应用程序。容器之间相互独立,让程序在独立的环境中跑起来
- Docker 引擎(Docker Engine):这是 Docker 的核心,它是一个轻量级的运行时和工具集,用于管理容器。Docker引擎包括服务器端的守护进程(daemon)、API,以及CLI工具
- Docker Hub:这是一个云端的镜像库,用于存储和分发 Docker 镜像。你可以在 Docker Hub 上找到成千上万的官方和第三方的镜像,直接拉取下来使用
高级用法和相关概念:
- Docker Compose:用来定义和运行多容器 Docker 应用的工具。通过一个简单的 YAML 文件,可以管理应用所需的所有服务,让你不用一个容器一个容器地去启动和管理
- Docker Swarm:这是 Docker 内置的原生集群管理工具。通过 Swarm,可以将多个 Docker 主机组合在一起,形成一个虚拟的 Docker 主机,以实现负载均衡和高可用性
- 镜像分层技术:使得 Docker 镜像的存储和传输更高效。每个镜像由多层组成,每一层都只包含与前一层的差异。当修改镜像中的某一层时,Docker 只需重新生成和传输这一层
- Namespace、Cgroups:这两个是 Docker 能够实现隔离的核心 Linux 技术。
Namespace
提供了进程、网络、挂载等资源的隔离,而Cgroups
则负责限制和优先级分配,确保容器不会耗尽主机资源 - Dockerfile:用来创建自定义镜像的文件。通过编写 Dockerfile,可以定义镜像中应该包含哪些内容以及如何配置。它采用了一种声明式的语法,使镜像构建过程变得简单而透明
总结起来,Docker 提供了强大的工具集和生态系统,使得应用的开发、测试、部署更加高效和一致。Docker 的技能是每一位现代开发者或运维人员都应当掌握的
4. 镜像的构建过程,Dockerfile作用
构建过程:
- 编写 Dockerfile:Dockerfile 是一个文本文件,其中包含了一系列的指令,描述了如何构建一个 Docker 镜像
- 构建镜像:
docker build
命令,通过读取 Dockerfile 的内容,逐步执行其中的指令,最终生成一个 Docker 镜像 - 保存镜像:构建完成的镜像会被保存到本地的 Docker 镜像库中,可以使用
docker images
命令查看 - 发布镜像:如果需要共享镜像,可以将其推送到 Docker Hub 或其他镜像仓库,使用
docker push
命令完成发布 - 使用镜像:最终用户可以使用
docker run
命令来启动基于该镜像的容器,完成应用的部署和运行
Dockerfile作用:
- 描述构建过程:Dockerfile 通过一系列的指令详细描述了构建镜像的步骤,包括基础镜像、环境配置、软件安装等
- 保证一致性:同一个 Dockerfile 可以在不同环境下生成一致的镜像,确保应用运行环境的稳定和一致
- 自动化构建:通过 Dockerfile,可以方便地实现镜像的自动化构建,简化了持续集成和持续部署(CI/CD)过程
- 版本管理:Dockerfile 可以使用版本控制工具进行管理,方便回滚或跟踪更改记录
1. 具体指令
1)常见指令:
FROM
:指定基础镜像,镜像的构建从这个基础镜像开始RUN
:运行命令来安装软件包或执行其他操作COPY
、ADD
:将本地主机文件和目录复制到镜像的文件系统中,ADD
功能更强大,还可以处理 URL 和解压归档文件CMD
、ENTRYPOINT
:指定容器启动时要执行的命令,两者区别在于 CMD 可以被docker run
的参数覆盖,而 ENTRYPOINT 不会EXPOSE
:声明端口,提示将来容器启动时将使用到的网络接口端口
2)最佳实践:
- 尽量使用官方基础镜像,保证稳定性、安全性
- 在 Dockerfile 中,合并多条
RUN
指令,减少镜像层数,减小镜像体积 - 使用
.dockerignore
文件排除不必要的文件和目录,减小镜像体积,同时加快构建速度 - 尽量使用
COPY
而不是ADD
,保持指令行为的明确性和一致性 - 多用标签(LABEL)来描述镜像的元数据信息。eg:维护者、版本号等,提高镜像的可管理性
3)安全性:
- 定期更新基础镜像,及时获取安全补丁
- 尽量在构建过程中不暴露敏感信息。eg:环境变量、密码等
- 使用非 root 用户运行应用,减少权限提升的风险
5. 管理、查看容器日志
在 Docker 中,管理和查看容器日志主要通过 docker logs
命令来实现。这个命令会显示指定容器的日志输出
1. 查看容器日志
- 启动一个容器,并确保它在运行
docker run -d --name my-container busybox /bin/sh -c "while true; do echo hello world; sleep 1; done"
- 查看容器的日志
docker logs my-container
- 查看实时更新的日志,可以使用
-f
参数,就像用tail -f
查看文件一样docker logs -f my-container
- 只想看最新的几行日志,可以使用
--tail
参数docker logs --tail 10 my-container
- 指定时间范围,
--since
和--until
参数docker logs --since="2021-01-01T00:00:00" --until="2021-01-01T01:00:00" my-container
2. 高级工具
为了在实际生产环境中更高效地管理容器日志,结合一些其他工具和技术
- 日志驱动:Docker 支持多种日志驱动
- eg:
json-file
(默认)、syslog
、journald
等。通过配置不同的日志驱动,可以将日志发送到不同的存储和处理系统
docker run --log-driver=syslog my-container
- eg:
- 集中化日志管理:在大型部署环境中,通常会使用像 ELK(Elasticsearch, Logstash, Kibana)或 EFK(Elasticsearch, Fluentd, Kibana)来集中管理和分析日志。通过配置 Fluentd 或 Logstash 作为日志驱动,Docker 容器的日志可以被发送到集中的 Elasticsearch 中,并且使用 Kibana 进行分析和可视化
docker run --log-driver=fluentd my-container
- 日志轮转:为了防止日志文件变得太大,可以通过配置 Docker 的日志轮转选项来限制日志的大小和数量
- 在 Docker 的守护进程配置文件中设置,eg:
/etc/docker/daemon.json
{ "log-driver": "json-file", "log-opts": { "max-size": "10m", "max-file": "3" } }
- 在 Docker 的守护进程配置文件中设置,eg:
- Sidecar 容器模式:这是一个高级模式,可以在 Kubernetes 等容器编排工具中使用。使用一个专门的 Sidecar 容器来管理主容器的日志。这种方式可以更好地解耦应用和日志管理的逻辑
6. 数据卷管理
在 Docker 中,数据卷(Volumes)是 Docker 推荐的用于持久化数据的机制。数据卷管理主要包括创建、挂载、查看、备份和删除等操作。简单来说:
- 创建数据卷:使用
docker volume create
命令 - 挂载数据卷:在启动容器时,用
-v
或--mount
选项挂载数据卷 - 查看数据卷:使用
docker volume ls
查看当前所有的卷 - 查看特定数据卷详情:使用
docker volume inspect
- 删除数据卷:停止使用该卷的容器后,使用
docker volume rm
删除数据卷
1. eg
创建数据卷: 创建一个名为
my_volume
的数据卷docker volume create my_volume
挂载数据卷: 启动一个容器,并将
my_volume
挂载到容器的/data
目录docker run -d -v my_volume:/data --name my_container nginx # 或使用 `--mount` 选项 docker run -d --mount source=my_volume,target=/data --name my_container nginx
意味着容器中的
/data
目录将持久化到my_volume
查看数据卷: 列出所有的数据卷
docker volume ls
查看特定数据卷详情: 获取
my_volume
的详细信息docker volume inspect my_volume
删除数据卷: 删除前确保没有容器在使用该卷。如果
my_container
正在使用my_volume
,停止并移除容器docker stop my_container docker rm my_container
然后删除数据卷
docker volume rm my_volume
删除不会影响其他卷或正在运行的容器
2. 高级操作
备份和恢复: 备份数据卷,可以把它挂载到一个新容器,并将其内容导出:
docker run --rm -v my_volume:/data -v $(pwd):/backup busybox tar cvf /backup/backup.tar /data
恢复数据卷的方法相似:
docker run --rm -v my_volume:/data -v $(pwd):/backup busybox tar xvf /backup/backup.tar -C /
匿名卷和挂载本地目录: Docker 容器内的数据默认会临时存储,关闭容器数据会丢失。可以直接挂载本地目录到容器
docker run -d -v /path/on/host:/data --name my_container nginx
这样操作适用于开发环境,生产环境推荐使用数据卷
数据卷驱动和远程存储: Docker 支持不同的卷驱动(eg:NFS、NetApp),能够配置并挂载远程存储。具体配置依赖于你的运行环境和存储需求
7. 配置容器网络
- 桥接网络(Bridge Network):这是 Docker 默认使用的网络模式,会创建一个名为
bridge
的虚拟网络,所有容器默认都会连接到这个bridge
网络上 - 主机网络(Host Network):让容器和宿主机共享 IP 地址,如果容器需要高性能的网络通信,考虑使用这种模式
- 无网络(None Network):使容器没有网络接口,适用于需要完全隔离网络的场景
- 覆盖网络(Overlay Network):适用于 Docker Swarm 或 Kubernetes,可以连接多台 Docker 主机上的容器
- macvlan 网络(Macvlan Network):容器会获取一个唯一的 MAC 地址,并且可以通过宿主机的物理网络接口来发送、接收数据包
使用 docker network create
创建自定义网络,使用 docker run --network=<network-name>
将容器连接到指定的网络
1. 扩展
桥接网络(Bridge): 最常见的配置方式。每个 Docker 容器在默认情况下都会连接到一个虚拟的
bridge
网络上优势:可以让不同容器之间进行通信
# 创建一个自定义的桥接网络 docker network create my_bridge # 将容器加入到这个网络 docker run --network=my_bridge
主机网络(Host): 这种模式将容器完全暴露在宿主机的网络环境中,共享同一个 IP 地址以及端口。这个模式适用于那些需要高性能、不需要选择不同网络名称空间的容器
# 启动一个使用主机网络的容器 docker run --network host my_image
无网络(None): 对于一些高度安全性要求的应用,可能需要禁用网络。通过使用
--network none
# 启动一个没有任何网络接口的容器 docker run --network none my_image
覆盖网络(Overlay): Overlay 网络一般用于跨宿主机的容器通信。多用于容器编排工具 Docker Swarm 或 Kubernetes。这种网络模式能够让不同物理主机上的容器互相通信,而且非常适合于集群环境
# 在 Swarm 中创建 overlay 网络 docker network create --driver overlay my_overlay
macvlan 网络(Macvlan): macvlan 网络允许为每个容器分配一个独立的 MAC 地址,并且能够通过宿主机的物理网络适配器来通信。这种模式适合那些需要直接访问宿主机局域网资源的容器。eg:访问存储区域网络(SAN),或获取 DHCP/DNS 服务
# 创建 macvlan 网络 docker network create -d macvlan --subnet=192.168.1.0/24 --gateway=192.168.1.1 -o parent=eth0 my_macvlan
8. 优化容器启动时间
- 使用较小的基础镜像:选择精简的基础镜像。eg:
alpine
,可以显著减少下载和加载时间 - 减少镜像层数:每一层都会增加容器启动的开销,精简 Dockerfile,合并多个
RUN
命令,将有助于减少层数 - 利用缓存:在构建镜像时尽量利用 Docker 的缓存功能,避免每次都重建镜像
- 适当配置健康检查:配置适当的健康检查策略,让容器可以尽快转为运行状态,而不是卡在启动过程中
- 预启动依赖服务:提前启动容器运行所需的依赖服务。eg:数据库等,可降低容器启动后的等待时间
- 本地化镜像:将常用的容器镜像保存在本地镜像库中,避免每次启动时从远程仓库拉取
1. 扩展
1)更优的镜像选择
- 除了选择
alpine
,还可以使用其他定制过的轻量级基础镜像。eg:scratch
- 自行制作适合应用需求的轻量级镜像,尽可能移除不必要的工具和库
2)多阶段构建
- 多阶段构建可以创建分离的构建和运行环境。通过只保留最终运行所需的部分,减少镜像整体大小
FROM golang:alpine as builder
WORKDIR /app
COPY . .
RUN go build -o myapp
FROM alpine
COPY /app/myapp /myapp
CMD ["/myapp"]
3)有效使用入口点
- 避免在入口点脚本中进行大量初始化操作,可以将这些操作尽量移动到镜像构建阶段
- 某些情况下,可以预先生成配置文件,避免每次启动时的生成过程
4)监控和调试
- 使用 Docker 自带的日志和性能监控工具。eg:
docker stats
,来了解容器启动过程的瓶颈 - 可以借助第三方工具,eg:Prometheus 与 Grafana,增强监控能力
5)高效使用 Volume
- 将需要频繁修改的数据放在 Volume 中,而不是每次都重新构建镜像,有助于提升启动和运行性能
9. 实现容器之间的通信
实现的几种方式:
- 使用同一个网络: 将多个容器连接到同一个 Docker 网络中,通过容器名称进行互相通信
- 端口映射: 将容器的端口映射到宿主机的端口,通过宿主机的 IP 和映射的端口进行通信
- Docker Compose: 使用 Docker Compose 来编排多个服务,可以为每个服务定义网络,并对网络进行配置
- 共享网络命名空间: 通过创建共享网络命名空间的方式,使多个容器共享网络设置
1. 细节、场景
使用同一个网络
- 场景: 常用于同一个应用的微服务,彼此之间需要频繁通信的场景
- 容器内部可以通过其它容器的名称(如
container1
)进行通信
# 创建一个自定义网络 docker network create my_custom_network # 启动容器时,将容器加入到该网络 docker run -d --name container1 --network my_custom_network my_image
端口映射
- 场景: 外部应用或服务需要访问 Docker 容器内部的应用
- 使用宿主机IP + 映射端口,eg:
http://localhost:8080
访问
# 启动容器时映射端口 docker run -d -p 8080:80 --name container1 my_image
Docker Compose
- 场景: 适用于开发和测试环境,快速部署多容器应用
- 创建
docker-compose.yml
文件,定义多个服务及其网络配置
version: '3' services: web: image: nginx networks: - my_network db: image: mysql networks: - my_network networks: my_network:
共享网络命名空间
- 场景: 允许多个容器共享一个 IP 地址,但可以进行独立的进程管理
# 启动容器时使用 `--network container:<name>|<id>` 参数共享网络命名空间 docker run -d --name container2 --network container:container1 my_image
10. Docker Swarm主要功能
Docker Swarm 是 Docker 平台内置的集群管理和编排工具。它允许你将多个 Docker 主机集合成一个虚拟的 Docker 主机,从而实现容器的集群管理和自动化部署。Swarm 提供了服务发现、负载均衡、扩展和滚动更新等功能,使得集群管理变得更加简单和高效
- 服务发现和负载均衡
- Docker Swarm 能自动发现集群中的服务,并且能够在各节点之间进行负载均衡。当一个请求到达 Swarm 管理节点时,它会根据当前的负载状况将请求分发到相应的工作节点,从而实现高效的资源利用
- 容器编排和调度
- Swarm 提供了强大的容器编排和调度能力,可以根据预先定义的策略(如资源需求、节点健康状况等)自动将容器调度到最适合的节点上运行。这样即使有节点发生故障,Swarm 也能够自动将容器迁移到其他健康节点上
- 服务扩展和缩减
- Swarm 允许用户轻松地扩展和缩减服务。可以指定希望多少个副本运行某个服务,Swarm 将自动增加或减少节点上的容器数量来符合这个要求
- 滚动更新
- 在服务需进行更新部署时,Swarm 支持滚动更新功能。可以逐步更新每个节点上的容器,确保服务持续可用。如果更新过程出现问题,还可以进行回滚操作,恢复到之前的状态
- 集群管理
- Swarm 通过 manager(管理节点)和 worker(工作节点)实现了集群管理。管理节点负责管理整个 Swarm 集群的状态和配置,而工作节点则执行管理节点下发的任务。这种设计可以实现高可用性和可靠性
11. 配置、管理环境变量
- 在 Dockerfile 中使用
ENV
指令 - 通过
docker run
命令的-e
标志传递环境变量 - 使用 Docker Compose 文件中的
environment
字段 - 在外部
.env
文件中定义环境变量,并在 Docker Compose 文件中引用
1. Dockerfile中ENV
指令
在 Dockerfile 中,可以使用 ENV
指令来设置环境变量,这些变量在镜像构建过程中以及容器运行时都会被使用
MY_VAR
环境变量在运行该镜像生成的容器时会被设置为 "my_value"
FROM ubuntu:latest
ENV MY_VAR="my_value"
2. run
传递环境变量
不想将环境变量硬编码在 Dockerfile 中,可以在启动容器时通过 docker run
命令传入
MY_VAR
会在容器启动时被设置为 "my_value"
docker run -e MY_VAR=my_value my_image
3. Compose文件的environment
在 docker-compose.yml
文件中使用 environment
字段设置环境变量
MY_VAR
在my_service
里会被设置为 "my_value"
version: '3'
services:
my_service:
image: my_image
environment:
- MY_VAR=my_value
4. .env
文件定义环境变量
可以方便地保持环境变量的可维护性,同时可以避免在版本控制系统中暴露敏感信息
- 创建
.env
文件,并在其中定义环境变量
MY_VAR=my_value
- 在
docker-compose.yml
中引用这些变量
version: '3'
services:
my_service:
image: my_image
environment:
- MY_VAR=${MY_VAR}
5. 环境变量优先级
- 通过
docker run
命令传递的环境变量 - Docker Compose 文件中的
environment
字段 - 在 Dockerfile 中使用
ENV
指令设置的环境变量 - 默认的系统环境变量
12. CI/CD,Jenkins与Docker集成
CI/CD 流程中使用 Jenkins 与 Docker 集成:
- 安装 Jenkins:首先需要在服务器或本地环境中安装 Jenkins
- 安装 Docker:确保 Jenkins 服务器上已经安装了 Docker
- 安装必要的插件:在 Jenkins 中,安装
Docker plugin
和Pipeline plugin
等必要插件 - 配置 Jenkins:为 Jenkins 配置 Docker 环境,确保 Jenkins 可以访问 Docker 命令
- 创建 Jenkins Pipeline:在 Jenkins 中创建一个 Pipeline 项目,并在 Pipeline Script 中编写构建、测试和部署的脚本,通常使用 Jenkinsfile
- 运行与监控:配置好所有步骤后,运行 Pipeline 并监控执行过程,确保一切正常工作
- 安装 Jenkins 和 Docker
- 安装 Jenkins:可以使用官方的 WAR 文件或者 Docker 镜像
- 安装 Docker:在大多数 Linux 发行版中,使用包管理器如
apt
或yum
安装。在 Windows / macOS 上,使用 Docker Desktop
- 安装 Jenkins 插件
- 登录 Jenkins 的管理界面,进入
Manage Jenkins
->Manage Plugins
- 在
Available
标签页下,搜索并安装Docker plugin
、Pipeline plugin
- 登录 Jenkins 的管理界面,进入
- 配置 Jenkins 访问 Docker
- 确保 Jenkins 用户对 Docker 命令有访问权限,可以通过将 Jenkins 用户加入 Docker 组来实现
sudo usermod -aG docker jenkins
- 重启 Jenkins 服务和 Docker 服务以确保配置生效
- 编写 Jenkinsfile
- 在项目根目录下创建一个名为
Jenkinsfile
的文件,其中定义 Pipeline 的各个阶段和步骤 - eg:一个基本的 Jenkinsfile
pipeline { agent { docker { image 'maven:3-alpine' } } stages { stage('Build') { steps { sh 'mvn clean install' } } stage('Test') { steps { sh 'mvn test' } } stage('Deploy') { steps { sh 'docker build -t my-app:latest .' sh 'docker run -d -p 8080:8080 my-app:latest' } } } }
- 在项目根目录下创建一个名为
- 运行与监控
- 在 Jenkins 中,创建一个新的 Pipeline 项目,指定源码管理工具(Git),并链接到包含 Jenkinsfile 的仓库
- 保存配置,并点击
Build Now
开始构建 - 通过 Jenkins 的控制台输出和图形化界面,监控 Pipeline 各个阶段的执行情况
通过上述步骤,可以实现 Jenkins 与 Docker 的高效集成,大大提升 CI/CD 流程的自动化程度
Docker Compose:有时候会用 Docker Compose 来管理多容器应用
version: '3' services: web: image: 'my-app:latest' ports: - '8080:8080' db: image: 'mysql:5.7' environment: MYSQL_ROOT_PASSWORD: 'root'
Jenkins Shared Libraries:可以用来共享脚本,提高代码复用性
13. 基本概念、工作原理
- Docker 是一种开源的容器化平台,允许开发者和运维人员以一致的方式部署应用程序。通过将应用程序及其所有依赖打包到一个单独的容器中,Docker 提供了一种便捷的方式来执行和移动应用程序。这种容器在任何符合所需条件的环境中都能保证其运行一致
- 工作原理上,Docker 利用 Linux 容器(LXC)的技术,并通过镜像(Image)、容器(Container)、仓库(Repository)等主要概念来实现应用的生命周期管理。具体来说,开发者首先创建一个 Docker 镜像,镜像是一个只读模板,包含应用程序及其运行所需的所有文件。然后,基于这个镜像,Docker 可以启动一个或多个容器,容器是镜像的运行实例
- 镜像(Images): 镜像是 Docker 的核心组件之一。一个镜像可以包含应用程序、所需的运行库以及配置文件。它可以从 Docker 的官方仓库(Docker Hub)下载,也可以通过 Dockerfile 定制创建。镜像是只读的,每次启动一个容器时,Docker 会从镜像创建一个可写的层
- 容器(Containers): 容器是镜像的一个运行实例,在容器中可以运行一个或多个进程。容器是独立的,具有自己的文件系统、CPU、内存等资源,但它们与宿主机共享一个操作系统内核。这种结构使得容器更轻量、更快速启动,消耗更少的资源
- 仓库(Repositories): 仓库是用来存储镜像的地方,类似于代码的版本控制系统。Docker Hub 是最常用的公共镜像仓库,但也可以使用私有仓库来存储企业内部镜像。镜像仓库支持版本控制,开发者可以基于特定版本的镜像进行开发和部署
- Dockerfile: Dockerfile 是一个包含一系列命令和指令的文本文件,用于自动化地创建一个 Docker 镜像。eg:它可以指示 Docker 从一个基本镜像开始,添加文件、安装依赖、执行命令等
- Docker 网络和存储: 为了支持应用的复杂需求,Docker 提供了网络和存储的解决方案。通过自定义的网络配置,可以实现不同容器之间的通信和隔离。通过卷(Volumes),可以实现对持久化数据的存储和管理
14. Docker Compose作用
Docker Compose 是用于定义和运行多容器 Docker 应用程序的工具。Compose 使用 YAML 文件定义服务、网络和卷,通过一条简单的命令 docker-compose up
就可以启动并运行整个配置的应用环境
- eg:如果有一个 web 应用,需要用到 MySQL 数据库,传统上可能需要分别配置和运行这两个服务。而在 Docker Compose 中,只需要创建一个
docker-compose.yml
文件,定义好 web 服务和 db 服务的配置,然后运行docker-compose up
即可
- 简化多容器管理:用 Docker Compose 可以管理多个容器,避免了手动启动、停止和配置多个容器的繁琐流程。eg:开发一个典型的微服务架构应用时,可能需要管理几十个不同的服务,Compose 大大简化了这个过程
- 适用于开发和测试环境:开发者可以迅速构建和销毁依赖环境,从而节省配置环境的时间,在本地环境就能模拟生产环境。eg:一个团队开发时,大家都可以共享相同的
docker-compose.yml
文件,确保在不同的开发机器上获得一致的环境 - 持续集成与持续部署(CI/CD):在 CI/CD 管道中,Compose 配合 Jenkins、GitLab CI 这样的平台,可以自动化测试和部署过程。可以在构建阶段启动一组服务,测试完成后自动清理环境
- 跨平台支持:Compose 支持在很多平台上运行,包括 Windows、Mac、Linux。使得在不同的OS上开发和测试变得非常容易
- 服务隔离和依赖管理:每个服务的依赖、环境变量、网络等都可以在
docker-compose.yml
中独立定义,避免服务间的冲突。同时,可以细粒度地控制服务间的依赖关系,确保启动顺序和依赖服务的准备状态
version: '3'
services:
web:
image: web-image
ports:
- "8000:8000"
depends_on:
- db
db:
image: mysql
environment:
MYSQL_ROOT_PASSWORD: example
定义了两个服务:web
和 db
,web 服务依赖于 db 服务。docker-compose up
命令将启动和连接这两个服务
15. 镜像、容器区别
- 镜像(image):镜像是一个只读的模板,用来创建容器。它包含了应用运行所需的所有代码、库、环境变量和配置文件。在 Docker 环境中,镜像类似于虚拟机的快照,它是静态的、不可变的
- 容器(container):容器是镜像的一个实例,创建并运行在 Docker 引擎上的一个或多个进程。容器是动态的、可变的,可以启动、停止、移动和删除。在运行时,它拥有独立的文件系统、网络和进程空间,但与物理主机共享操作系统内核
1)镜像的构建和层次结构
- 镜像是由多个只读层组成的,每一层代表了一个特定的操作(eg:安装某个软件包、复制文件等)
- 当构建新的镜像时,Docker 不会从头开始,而是基于现有的镜像层来构建新的层。这样可以显著节省存储空间和提高构建速度
- Dockerfile 是用于定义镜像构建过程的文件,通过逐行执行 Dockerfile 中的指令,可以生成一个新的镜像
2)容器的生命周期管理
- 容器是镜像的可运行实例,而且这个实例是可以动态管理的:可以启动、停止、重启、删除等
- 每个容器有自己的文件系统、网络环境和进程空间,但通过共享主机的操作系统内核实现轻量级隔离
- 常见的管理工具有 Docker CLI 和 Docker Compose,用于启动、停止、查看日志、调试等操作
3)实用案例
- 开发和测试环境:通过镜像统一开发环境,确保在开发和测试过程中使用的环境保持一致
- 持续集成/持续部署(CI/CD):利用容器的高可移植性和隔离性,快速集成、测试和部署代码
- 应用隔离:在同一台机器上运行多个应用,彼此互不干扰,方便管理和资源利用最大化
16. Dockerfile创建自定义镜像
- 编写 Dockerfile: Dockerfile 是一个文本文件,包含了一系列指令,用来描述如何构建镜像。通常包括基础镜像的选择、复制文件、安装包以及配置环境等操作
# 选择基础镜像
FROM ubuntu:latest
# 安装一些软件包
RUN apt-get update && apt-get install -y python3 python3-pip
# 设置工作目录
WORKDIR /app
# 复制当前目录下的文件到工作目录
COPY . /app
# 安装 Python 依赖
RUN pip3 install -r requirements.txt
# 暴露端口
EXPOSE 80
# 设置容器启动时默认执行的命令
CMD ["python3", "app.py"]
- 构建镜像: 使用
docker build
命令来构建镜像
docker build -t my_custom_image:latest .
1. 细节
- Dockerfile 基本指令
FROM
:指定基础镜像,通常是构建镜像的第一条指令RUN
:执行命令,eg:安装软件包COPY
、ADD
:将文件复制到镜像中CMD
、ENTRYPOINT
:指定容器启动后执行的命令EXPOSE
:声明镜像中使用的端口,主要作为文档用途,不会实际发布端口
- Docker 镜像的多阶段构建: 多阶段构建可以显著减少最终镜像的大小,尤其当需要构建和运行环境有所不同的时候
# 第一阶段:构建应用
FROM golang:1.16-alpine AS builder
WORKDIR /app
COPY . .
RUN go build -o myapp
# 第二阶段:创建运行时环境
FROM alpine:latest
COPY /app/myapp /usr/local/bin/myapp
CMD ["myapp"]
- 优化镜像大小的策略
- 使用轻量级基础镜像:eg:
alpine
- 合并运行指令:减少中间层的数量。eg:合并多个
RUN
指令 - 清理缓存和临时文件:eg:在一个
RUN
指令中更新包后马上清理缓存:RUN apt-get update && apt-get install -y python3 && apt-get clean
- 使用轻量级基础镜像:eg:
- 调试和测试 Dockerfile: 可以用
docker run -it --rm my_custom_image:latest /bin/bash
进入镜像进行手动调试,确保所有配置如预期般运作 - 版本控制 Dockerfile: 将 Dockerfile 放置在 Git 等版本控制系统中,可以很好地跟踪变化,同时和项目其他代码一起管理,确保环境和代码的一致性和可移植性
17. Swarm、K8S集群管理区别
Docker Swarm 和 Kubernetes 是两种流行的集群管理和编排工具,但它们在设计理念、功能以及使用场景上存在一定差异
- Swarm适合小团队、简单项目以及希望快速上手
- Kubernetes更适合云原生应用、大规模集群和需要复杂功能的场景
- 同样在选择前也要权衡团队的技术能力和实际需求,做出最适合的决定
- 设计理念
- Swarm:是一种轻量级的集群管理工具,集成在 Docker 中,容易上手,适合小规模的集群
- K8S:是一个由谷歌设计的全面、复杂的容器编编排系统,适合大规模集群,支持自动化部署、扩展和操作应用容器
- 架构
- Swarm:使用简单的主从架构。主节点(Manager)负责管理整个集群和任务调度,从节点(Worker节点)负责运行容器
- K8S:采用更复杂的Master-Worker架构,主节点包括API服务器、调度器和控制器等多个组件,工作节点运行kubelet来管理Pod
- 扩展性和弹性:
- Swarm:支持自动扩展,但功能性相对有限,比较适合简单的分布式应用
- K8S:提供了强大的自动扩展和负载均衡能力,适合更复杂的微服务架构,可扩展性非常高
- 网络设置:
- Swarm:使用简单的覆盖网络,内建网络模型非常简洁
- K8S:网络模型更复杂,支持多种网络插件(如Flannel, Calico),更灵活
- 社区支持和生态系统:
- Swarm:虽然方便,但由于越来越多的人转向 K8S,所以社区支持逐渐减少
- K8S:庞大的社区和支持,无数的第三方工具和插件,生态系统非常丰富
1. 细节上区别
- 日志与监控
- Swarm:日志和监控通常需要借助第三方工具。eg:ELK来实现
- K8S:本身就支持多种监控和日志收集方案。eg:Prometheus、ELK等,更加丰富
- 存储管理
- Swarm:持久化存储支持相对较弱,需要手动配置存储卷
- K8S:提供了成熟的持久化存储管理,包括Persistent Volumes(PV)和Persistent Volume Claims(PVC),可以与各类存储解决方案(eg:NFS、Ceph、AWS EBS)良好集成
- 应用部署的灵活性
- Swarm:应用的部署主要是通过
docker-compose
文件 - K8S:通过YAML文件进行各种资源的配置,包括Deployment, Service, ConfigMap等,虽然复杂,但也极为灵活和强大
- Swarm:应用的部署主要是通过
- 自愈能力
- Swarm:具备有限的自愈能力,如果有节点宕机可以重新调度任务
- K8S:自愈能力非常强大,能自动重新调度Pod,重启失败的容器,确保系统的高可用性
18. 多阶段构建优势
Docker 中的多阶段构建(multi-stage build)有以下优势:
- 减小镜像体积:通过在构建过程中仅保留最终需要的文件,可以显著减少 Docker 镜像的体积,从而加快部署和启动时间
- 提高安全性:减少了镜像中的不必要文件,降低了潜在的安全风险
- 优化构建流程:可以在不同阶段使用不同的基础镜像,从而更好地管理依赖和构建工具,并提高构建效率
- 易于维护:构建过程更加清晰和可维护,因为不同的阶段可以对不同的任务负责,使得 Dockerfile 更加简洁和模块化
1. 减小镜像体积
- 传统的构建过程中,通常会把所有的构建工具、依赖库等一并放进镜像中,这样会导致镜像变得很大
- 多阶段构建中,可以在不同阶段使用不同的基础镜像,只在最终的阶段保留需要运行的文件
- eg:可以在前几个阶段中安装构建工具和进行编译,最后的阶段只保留编译后的二进制文件,极大地减少镜像体积
2. 提高安全性
在多阶段构建中,因为最终的镜像中只保留了必要的运行时文件,许多用于编译和构建的工具和库不会存在于最终的镜像中。这大大降低了镜像中的潜在安全风险,因为这些不必要的工具和库可能拥有漏洞或被攻击者利用
3. 优化构建流程
多阶段构建让我们可以在每个阶段中使用不同的基础镜像
- 可以在一个阶段中使用带有完整构建工具链的镜像来进行编译
- 在下一个阶段中只使用一个小巧的运行时镜像来减少体积。这种方法可以更好地管理依赖和构建工具,同时也提高了构建的效率和灵活性
4. 易于维护
多阶段构建让 Dockerfile 更加模块化,每个阶段负责特定的任务
- 第一个阶段可以用来获取源码并进行依赖安装
- 第二个阶段进行代码编译
- 第三个阶段进行测试
- 最后一个阶段打包最终的应用镜像
这种分离使得 Dockerfile 更加清晰易读,也更易于维护和扩展
5. Go应用多阶段构建示例
# 第一个阶段:构建阶段
FROM golang:1.17 AS builder
WORKDIR /app
COPY . .
RUN go build -o myapp
# 第二个阶段:运行时阶段
FROM alpine:latest
WORKDIR /root/
COPY /app/myapp .
CMD ["./myapp"]
6. 分析和优化
- Docker Slim 来减小镜像体积
- Trivy 来扫描镜像中的漏洞
总结一下,多阶段构建是一个既节约空间又提升安全性和构建效率的利器
19. 网络模型及主要类型
Docker 的网络模型(network model)是指 Docker 容器之间以及容器与外界进行通信的方式
- Bridge(默认):
- Docker 的默认网络类型,创建容器时如果不指定网络,Docker 会自动将其连接到一个叫
bridge
的默认网络 - Bridge 网络适用于单节点(single-host)间容器通信
- 在默认的 bridge 网络中,容器之间通过内置的虚拟网桥通信,外部需要通过端口映射来访问容器服务
- Docker 的默认网络类型,创建容器时如果不指定网络,Docker 会自动将其连接到一个叫
- Host:
- Host 网络模式中,容器共享宿主机的网络栈,没有独立的 网络命名空间(network namespace)
- Host 网络可以提高性能,因为没有网络接口间的开销,也适用于需要与宿主机网络紧密集成的应用
- 使用 host 网络时,端口冲突需要自行管理,因为容器会占用宿主机的端口
- None:
- None 网络模式为容器提供一个完全独立的网络命名空间,但不进行任何网络配置
- 容器需要自行配置网络,适用于需要完全掌控网络配置的特殊应用
- Container:
- Container 网络模式允许一个容器共享另一个容器的网络命名空间。指定的容器将与共享网络的容器使用同样的 IP 地址和所有网络连接
- 适用于需要多个容器共享一个网络堆栈的场景。eg:一些高可用方案中的 SideCar 模式
- Overlay:
- Overlay 网络用于跨主机容器间通信。eg:在 Swarm 或 K8S 中使用
- 它通过在多台宿主机之间创建一个共用的虚拟网络,实现不同宿主机上运行的容器之间的互联
- Macvlan:
- Macvlan 网络模式下,容器能够有一个独立的 MAC 地址,像独立于宿主机的物理设备一样工作
- 每个容器会有一个独立的 IP 和 MAC 地址,适用于需要高度模拟物理网络的场景。eg:一些需要直接和物理网络设备通信的应用
每一种网络类型都有其适用的场景和限制。合理配置容器的网络方案,从而提升整体系统的性能和安全性
此外,Docker 还支持自定义网络驱动程序,可以根据需要开发定制化的网络方案,满足特定的业务需求。这样就可以在复杂网络环境下,如混合云、多数据中心等场景中,自由地进行网络配置和管理
20. 容器编排常见工具
Docker 的容器编排(orchestration)常见工具:
- Kubernetes 在大型分布式系统中表现特别出色,适合那些对性能和稳定性有较高要求的企业
- Docker Swarm 更加适合中小型企业或是个人开发者,入门门槛相对较低
- Nomad 和 Apache Mesos 则提供了更多的灵活性,可以满足特殊业务场景的需求
1. Kubernetes(K8s)
Kubernetes 是目前最流行的容器编排工具,由 Google 开发并开源。它具备丰富的功能,包括自动化部署、扩展应用、管理集群中的多个容器应用等。Kubernetes 可以通过声明式配置和自动化实现应用的维护和管理,使得容器化应用的开发、部署和扩展变得更加容易
- 自动扩展:可以根据流量自动调整应用副本的数量
- 自愈能力:当某个容器出现故障时,Kubernetes 能够自动重新启动或者替换它
- 服务发现:能够自动发现和负载均衡服务
2. Docker Swarm
Docker 自带的容器编排工具,相对于 Kubernetes,它更加轻量级和易于配置。Docker Swarm 把一组 Docker 引擎组织成一个集群,并使它们表现得像一个虚拟的 Docker 引擎,使得管理多个容器的部署和可扩展性任务更加简单
- 简易集成:与 Docker CLI 完美结合,易于设置和使用
- 原生支持:直接集成在 Docker 引擎中,无需额外组件
3. Apache Mesos
Apache Mesos 是一个开源的分布式系统内核,最初由 University of California, Berkeley, 的 AMPLab 研究人员开发。它抽象了计算资源,并将其作为 CPU、内存、存储等维持在一个共同的平台上供应用动态计算资源使用。Mesos 可以管理容器和其它工作负载,且与 Marathon 配合,可以很好地进行应用的编排和调度
- 高可用性:通过 Mesos 主节点的 Leader 选举提高整体系统的可用性
- 多种工作负载支持:不仅支持容器,还支持普通的 Linux 进程等多种工作负载
4. Nomad
由 HashiCorp 开发的 Nomad 是一个灵活的、易于使用的工作负载编排工具。它可以运行在任何主机上,支持多种组合的工作负载,比如 Docker 容器和 VMware 机器等。它设计理念简单,易于操作,且支持大规模的集群环境,广泛适用于各种类型的工作负载
- 简洁设计:更加轻量级,易于配置和上手
- 多种工作负载:不仅支持容器化应用,还支持虚拟机和其他格式的工作负载
21. 数据卷持久化存储
1. volume
Docker 中实现数据卷(volume)的持久化存储,可以通过定义一个 Docker volume,并将其挂载到容器内部的路径来实现
# 创建一个 Docker volume
docker volume create my_volume
# 启动容器并将该 volume 挂载到容器内部的某个路径
docker run -d -v my_volume:/data --name my_container my_image
除了使用 Docker volume 持久化数据外,我还想和你聊聊使用 Bind Mount 的方式,以及两者的区别和各自的使用场景
2. Bind Mount
# 通过指定主机上的一个具体路径,使之与容器内的路径进行挂载
docker run -d -v /path/on/host:/data --name my_container my_image
# 把主机的 `/path/on/host` 目录挂载到容器的 `/data` 目录
3. 区别与使用场景
- Docker Volume
- 优点:由 Docker 自主管理,支持 Docker CLI 命令进行操作(创建、删除、列出)
- 适用场景:需要跨多个容器共享数据,数据需要移动、备份或远程存储的场景
- Bind Mount
- 优点:直接使用主机文件系统上的路径,操作更直观,适合开发调试阶段
- 适用场景
- 需要访问主机文件系统上的具体文件或目录。eg:配置文件或代码目录等
22. 镜像多层结构如何实现
Docker 镜像的多层结构是通过一种名为联合文件系统(Union File System)的技术实现的。Docker 镜像由一个只读的分层文件系统构成,每一层都包含了对其下层的一些改进。镜像的底层是基础层,其上是各种中间层,最上方是一个可写的顶层(容器层)
- 每一层都可以是一个文件、一个文件夹、一个文件系统分区的内容
- 当镜像被拉取时,会一步步下载层,最后组合成完整的镜像
- 如果镜像的某一层已经存在于本地缓存,则会直接复用,而不需要重新下载,从而节省了带宽和时间
- 由于每一层都是只读的,所以层与层之间的互相影响较小,安全性和稳定性更高
- Docker 使用存储驱动将这些层合并成一个统一的文件系统,容器看到的就是一个完整的文件系统
1. 概念
- 联合文件系统(UnionFS)
- 联合文件系统能够把不同的目录(或者称为层)合并到一个目录里。在 Docker 中,常用的联合文件系统包括 OverlayFS、AUFS、btrfs 和 Device Mapper 等
- 存储驱动
- Docker 通过不同的存储驱动来实现对多层结构的管理,不同的存储驱动有不同的性能特征和支持的特性。eg:OverlayFS 是当前 Docker 默认的存储驱动,它比 AUFS 更高效,支持多层次的 union,包括联合只读和可写层
- 镜像缓存
- 由于 Docker 镜像是分层存储的,所以当我们构建新镜像时,如果某些层已经存在于本地,则 Docker 会复用这些已有的层而不是重新构建,从而提高构建效率并减少带宽消耗
- Dockerfile 和分层构建
- Dockerfile 是用来定义 Docker 镜像的配置文件,每一个 Dockerfile 指令(如 COPY、RUN、CMD 等)都会在镜像中生成一个新层。因此,在编写 Dockerfile 时,要尽量将经常变动的部分放在底部,以减少镜像层的重复创建,从而优化构建速度和镜像大小
- 镜像的共享和复用
- Docker 镜像的分层结构极大地提高了镜像的共享和复用效率。不同的镜像可以共享相同的基础层,而不用重复存储相同的内容。eg:多个基于相同基础镜像(Alpine 或 Ubuntu)的应用镜像可以共享该基础层,从而节省存储空间
23. bridge配置和使用
Docker 的 bridge 网络模式其实是 Docker 安装时默认的网络模式之一。它创建了一个虚拟的网络,这个网络允许容器之间进行通信,但与主机网络隔离
# 1. 查看当前 bridge 网络
docker network ls
# 系统默认会有一个名为 'bridge' 的网络
docker network inspect bridge
# 2. 创建自定义 bridge 网络,名为 'my-bridge-network'
docker network create --driver bridge my-bridge-network
# 3. 运行容器并指定网络(--network)在启动容器时
docker run -d --name my-container --network my-bridge-network nginx
# 4. 连接已有容器到桥接网络
docker network connect my-bridge-network my-container
# 5. 断开容器与桥接网络
docker network disconnect my-bridge-network my-container
24. 镜像推送、拉取
# 1. 登录Docker Hub账户。输入 用户名、密码
# - 具备了推送镜像的权限
docker login
# 2. 推送镜像到 Docker Hub,给本地镜像打上标签
# - `username` 是 Docker Hub 用户名
# - `repository` 是仓库名(如果仓库不存在,Docker 会在推的时候自动创建)
# - `tag` 是镜像的标签,通常用来标识版本信息(`latest` 表示最新版本)
docker tag local-image-name username/repository:tag
docker push username/repository:tag
# 3. 从 Docker Hub 拉取镜像
docker pull username/repository:tag
常见问题
- 推送或拉取失败: 如果遇到推送或拉取失败,首先要确保你的网络是通畅的、Docker 服务正常运行并且已经正确登录。如果这些都没问题,可以尝试
docker logout
再重新登录 - 镜像过大: 有时候镜像过大可能会导致推送/拉取超时。尽量使用多阶段构建、减少层数、清理不必要的文件等方法来减小镜像大小
- 访问限制: 如果你在公司内部网环境中,可能会遇到访问受限的情况。你可以通过配置 Docker 使用内部的私有镜像仓库来解决
25. 实现资源限制
在 Docker 中,使用命令行参数来实现容器资源限制,包括 CPU 和内存
- 限制容器使用的 CPU 数量
--cpu-shares
:使用相对权重方式分配 CPU 资源--cpus
:直接指定容器可使用的 CPU 核数
- 限制容器使用的内存量
-m
或--memory
:指定容器最大内存限制
# 某个容器最多使用一个 CPU 核和 512MB 内存
docker run --cpus=1 --memory=512m your_docker_image
在 Docker 中,资源限制基于 Linux 内核的 cgroups 功能。除了 CPU 和内存,Docker 还允许限制或配额其他资源。eg:I/O 性能和设备访问
- CPU 限制的细节:
--cpu-shares
:这是一个相对权重值,默认值是 1024。如果多个容器使用同样的 CPU 份额,则 CPU 时间会按照该权重进行分配。eg:两个容器分别设置--cpu-shares=1024
和--cpu-shares=512
,第一个容器将获得两倍于第二个容器的 CPU 时间--cpus
:这个参数允许更精确地控制容器可以使用多少 CPU 核。eg:--cpus=1.5
表示容器可以使用一个半 CPU 核
- 内存限制的细节:
--memory-swap
:这个参数允许为内存使用设置 swap 限制。通过设置为-1
,可以允许无限制的 swap 使用--memory-reservation
:这是一个软性内存限制,可以设置一个低于硬性限制的警戒线
- 其他资源限制:
--blkio-weight
:设置块 I/O 权重,这影响容器对存储设备的访问优先级--device-read-bps
、--device-write-bps
:用于限制设备的 I/O 读写速率
Docker 提供了灵活的资源控制方式,通过这些参数,可以确保生产环境中的容器既能高效利用系统资源,又能避免资源争夺造成的系统不稳定
对于 K8S 用户,Pod 级别的资源限制可以通过 requests
和 limits
字段进行定义,以确保资源的公平分配和稳定性
26. Swarm部署一个高可用集群
Docker Swarm 是 Docker 原生的集群管理工具,它使多个 Docker 引擎能够作为一个虚拟系统一起工作。它最大的优势在于简单易用和与 Docker 其他组件的良好集成
使用 Docker Swarm 部署一个高可用集群,关键步骤:
- 安装 Docker:确保所有主机都安装了 Docker
- 初始化 Swarm:选择一台主机作为管理节点,运行
docker swarm init
初始化集群 - 添加工作节点:在其他主机上运行管理节点给的命令
- eg:
docker swarm join --token <token> <manager-node-ip>:<port>
,将这些主机加入到 Swarm 集群中
- eg:
- 部署服务:在管理节点上使用
docker service create
命令部署应用服务,确保服务可以在多个工作节点上运行 - 调整配置和扩容:根据实际需求,随时调整服务副本数以扩展或缩减服务
1)安装 Docker
- 在每台主机上安装 Docker
curl -fsSL https://get.docker.com -o get-docker.sh sh get-docker.sh
2)初始化 Swarm
- 选择一台主机作为管理节点,运行以下命令初始化 Swarm 集群
# `<MANAGER-IP>` 这台机器的 IP 地址 docker swarm init --advertise-addr <MANAGER-IP>
3)添加工作节点
- 当初始化 Swarm 后,将得到一个命令
# 在其他主机上运行这条命令,把这些主机加入到 Swarm 集群中 docker swarm join --token <TOKEN> <MANAGER-IP>:<PORT>
4)部署服务
- 在管理节点上部署服务。eg:一个简单的 Nginx 服务
- 将在集群中创建名为 "my-nginx" 的服务,并将它的3个副本分配到不同的节点上,实现高可用
docker service create --name my-nginx --replicas 3 -p 80:80 nginx
5)调整配置和扩容
- 随时根据需求调整服务的副本数。eg:将服务的副本数增加到 5
docker service scale my-nginx=5
1. 高级应用
- 服务更新和滚动更新: Docker Swarm 支持滚动更新,可以逐步替换旧的容器以减少服务停机时间
docker service update --image nginx:latest my-nginx
- 健康检查: 配置服务的健康检查,以确保只有健康的容器接收到流量。具体可以在
docker-compose.yml
文件中设置健康检查 - 网络和服务发现: Swarm 支持多种网络模式,可以创建覆盖网络以实现跨主机容器通信,并且内置了服务发现和负载均衡
- 持久化存储: 需要持久化存储时,可以使用 Docker Volumes 或整合外部存储解决方案
27. overlay网络模式配置
# 1. 启动 Docker Swarm 集群
docker swarm init
# 2. 创建 overlay 网络
# `-d overlay` 指定使用 overlay 网络驱动程序
docker network create -d overlay my-overlay-network
# 3. 服务中使用 overlay 网络
docker service create --name my-service --network my-overlay-network my-image
1. 常见的场景
- 多节点 Swarm 集群配置
- 如果 Swarm 集群有多个节点,在网络配置时,需要在每个节点上初始化 Swarm 并加入到集群中
# 在其他节点上运行命令 docker swarm join --token <SWARM-TOKEN> <MANAGER-IP>:2377
- 管理 overlay 网络
# 查看所有网络 docker network ls # 查看特定网络的详细信息 docker network inspect my-overlay-network # 删除网络 docker network rm my-overlay-network
- 服务发现和负载均衡
- 在 Swarm 模式下,Docker 会自动进行服务发现和负载均衡。所有连接到 overlay 网络中的容器可以通过服务名互相访问,而不用关心其具体 IP 地址
- 对等加密
- Docker overlay 网络支持通过 IPsec 加密的对等加密,提升安全性非常重要
# 创建 overlay 网络时指定 docker network create -d overlay --opt encrypted my-secure-overlay-network
- 限制流量
- 可以通过自定义子网、网关和IP范围来进一步配置 overlay 网络
docker network create -d overlay --subnet=10.0.9.0/24 --gateway=10.0.9.1 my-custom-overlay-network
28. 构建多阶段镜像减少镜像体积
在 Docker 中,通过使用多阶段构建,可以显著减少镜像的体积
- 核心思想是:利用一个以上的
FROM
指令,在初始阶段构建镜像时包含完整的构建环境,而在随后的阶段仅保留真正的运行环境和必要的文件。这样,可以避免把不必要的构建工具和依赖打包到最终的镜像中
# 第一阶段:构建阶段,编译代码
FROM golang:1.17 as builder
# 设置工作目录
WORKDIR /app
# 将源码复制到容器里
COPY . .
# 运行构建命令
RUN go build -o myapp
# 第二阶段:运行阶段,复制二进制文件
FROM alpine:latest
# 设置工作目录
WORKDIR /app
# 从第一个构建阶段复制二进制文件到当前镜像里
COPY /app/myapp .
# 设置容器启动命令
CMD ["./myapp"]
通过上述 Dockerfile,首先使用 Golang 镜像编译代码,然后在更轻量的 Alpine 镜像中运行编译后的二进制文件。这样,最终生成的镜像不会包含 Go 的构建工具,体积也会大大减小
1. 扩展
- 镜像层和缓存:在使用多阶段构建时,每个
FROM
指令会创建一个新的阶段,这些阶段是独立的,但它们之间可以通过COPY --from=<stage>
共享文件。Docker 使用镜像层和缓存机制,使得多阶段构建的镜像管理更加高效 - 优化构建顺序:构建顺序对镜像的缓存利用率有很大的影响。应该把不经常变动的命令和文件放在前面。eg:安装基础依赖包,较频繁变动的文件,放在最后。这样可以有效利用 Docker 缓存,减少每次构建的时间
- 环境变量和多阶段:可以通过
ARG
和ENV
指令在不同的构建阶段传递参数和设置环境变量。在多阶段构建中,注意合理使用这些指令,有助于提升镜像文件的可配置性和灵活性 - 清理不必要的文件:在每个阶段的末尾,可以通过删除不必要的文件和依赖来进一步减小镜像的体积。虽然多阶段构建本身已经很有效,但清理无用文件仍然可以锦上添花
- 自动化构建和测试:在多阶段构建中,可以添加一个中间阶段专门用于测试。通过这种方式,可以在构建过程中执行单元测试或其他验证,确保最终镜像中的代码是经过正确测试且稳定的
强烈建议结合 CI/CD 系统( Jenkins 或 GitLab CI),把多阶段构建过程自动化。这不仅能确保构建出更小、更高效的 Docker 镜像,还可以把 DevOps 的理念贯彻得更好