12-Docker(28)

1. 什么、为什么、如何使用

  • Docker是一种容器化技术,它允许开发者将应用程序及其所有依赖项打包到一个独立的容器中,包括操作系统、库、运行时环境等。这个容器可以在任何支持 Docker 的平台上运行,确保应用程序在不同环境中具有一致的行为
  • 在本项目中使用 Docker 主要是为了保证代码沙箱服务执行用户代码的安全性,防止影响宿主机
  • 首先在 Linux 虚拟机内安装了 Docker,然后用 Docker 命令行跑通了一次从拉取镜像、执行容器再到删除容器的完整流程。在代码沙箱项目中,使用 Docker Java 库来操作 Docker,包括 Docker 容器的创建、连接 Docker 容器执行命令、获取 Docker 容器的日志和输出、获取 Docker 容器的内存占用等

2. 保证代码沙箱执行程序时安全性

虽然 Docker 本身提供了一个隔离的代码执行环境,但仍无法做到绝对的安全,通过以下几种方法,进一步提高 Docker 代码沙箱的安全性

  1. 超时控制:在向容器发送执行命令时,指定超时参数,超时自动中断
  2. 资源限制:创建容器实例时,通过 HostConfig 指定分配的最大内存和 CPU 占用
  3. 网络限制:创建容器实例时,通过 withNetworkDisabled 方法禁用网络
  4. 权限管理:通过 seccomp 或 Java 安全管理器,限制用户代码允许的操作和调用

3. 基本概念及核心组件

Docker 是一个开源的平台,旨在实现应用的自动化部署。它通过OS级别的虚拟化来交付软件,使其能够在隔离的环境中运行

  • 优点:在于“一致性”,即应用程序可以在任何地方运行,而不需要关心底层环境是否一致

核心组件:

  1. 镜像(Image):镜像是 Docker 的基础,它是一个只读的模板,其中包括了运行代码所需的所有内容(如操作系统、应用程序、库等)。你可以把镜像看作是应用程序或服务的起点
  2. 容器(Container):容器是镜像的运行实例。它包含了所有必要的组件,以完全隔离的方式运行你的应用程序。容器之间相互独立,让程序在独立的环境中跑起来
  3. Docker 引擎(Docker Engine):这是 Docker 的核心,它是一个轻量级的运行时和工具集,用于管理容器。Docker引擎包括服务器端的守护进程(daemon)、API,以及CLI工具
  4. Docker Hub:这是一个云端的镜像库,用于存储和分发 Docker 镜像。你可以在 Docker Hub 上找到成千上万的官方和第三方的镜像,直接拉取下来使用

高级用法和相关概念:

  1. Docker Compose:用来定义和运行多容器 Docker 应用的工具。通过一个简单的 YAML 文件,可以管理应用所需的所有服务,让你不用一个容器一个容器地去启动和管理
  2. Docker Swarm:这是 Docker 内置的原生集群管理工具。通过 Swarm,可以将多个 Docker 主机组合在一起,形成一个虚拟的 Docker 主机,以实现负载均衡和高可用性
  3. 镜像分层技术:使得 Docker 镜像的存储和传输更高效。每个镜像由多层组成,每一层都只包含与前一层的差异。当修改镜像中的某一层时,Docker 只需重新生成和传输这一层
  4. Namespace、Cgroups:这两个是 Docker 能够实现隔离的核心 Linux 技术。Namespace 提供了进程、网络、挂载等资源的隔离,而 Cgroups 则负责限制和优先级分配,确保容器不会耗尽主机资源
  5. Dockerfile:用来创建自定义镜像的文件。通过编写 Dockerfile,可以定义镜像中应该包含哪些内容以及如何配置。它采用了一种声明式的语法,使镜像构建过程变得简单而透明

总结起来,Docker 提供了强大的工具集和生态系统,使得应用的开发、测试、部署更加高效和一致。Docker 的技能是每一位现代开发者或运维人员都应当掌握的

4. 镜像的构建过程,Dockerfile作用

构建过程:

  1. 编写 Dockerfile:Dockerfile 是一个文本文件,其中包含了一系列的指令,描述了如何构建一个 Docker 镜像
  2. 构建镜像:docker build 命令,通过读取 Dockerfile 的内容,逐步执行其中的指令,最终生成一个 Docker 镜像
  3. 保存镜像:构建完成的镜像会被保存到本地的 Docker 镜像库中,可以使用 docker images 命令查看
  4. 发布镜像:如果需要共享镜像,可以将其推送到 Docker Hub 或其他镜像仓库,使用 docker push 命令完成发布
  5. 使用镜像:最终用户可以使用 docker run 命令来启动基于该镜像的容器,完成应用的部署和运行

Dockerfile作用:

  1. 描述构建过程:Dockerfile 通过一系列的指令详细描述了构建镜像的步骤,包括基础镜像、环境配置、软件安装等
  2. 保证一致性:同一个 Dockerfile 可以在不同环境下生成一致的镜像,确保应用运行环境的稳定和一致
  3. 自动化构建:通过 Dockerfile,可以方便地实现镜像的自动化构建,简化了持续集成和持续部署(CI/CD)过程
  4. 版本管理:Dockerfile 可以使用版本控制工具进行管理,方便回滚或跟踪更改记录

1. 具体指令

1)常见指令:

  • FROM:指定基础镜像,镜像的构建从这个基础镜像开始
  • RUN:运行命令来安装软件包或执行其他操作
  • COPYADD:将本地主机文件和目录复制到镜像的文件系统中,ADD 功能更强大,还可以处理 URL 和解压归档文件
  • CMDENTRYPOINT:指定容器启动时要执行的命令,两者区别在于 CMD 可以被 docker run 的参数覆盖,而 ENTRYPOINT 不会
  • EXPOSE:声明端口,提示将来容器启动时将使用到的网络接口端口

2)最佳实践:

  • 尽量使用官方基础镜像,保证稳定性、安全性
  • 在 Dockerfile 中,合并多条 RUN 指令,减少镜像层数,减小镜像体积
  • 使用 .dockerignore 文件排除不必要的文件和目录,减小镜像体积,同时加快构建速度
  • 尽量使用 COPY 而不是 ADD,保持指令行为的明确性和一致性
  • 多用标签(LABEL)来描述镜像的元数据信息。eg:维护者、版本号等,提高镜像的可管理性

3)安全性:

  • 定期更新基础镜像,及时获取安全补丁
  • 尽量在构建过程中不暴露敏感信息。eg:环境变量、密码等
  • 使用非 root 用户运行应用,减少权限提升的风险

5. 管理、查看容器日志

在 Docker 中,管理和查看容器日志主要通过 docker logs 命令来实现。这个命令会显示指定容器的日志输出

1. 查看容器日志

  1. 启动一个容器,并确保它在运行
    docker run -d --name my-container busybox /bin/sh -c "while true; do echo hello world; sleep 1; done"
    
  2. 查看容器的日志
    docker logs my-container
    
  3. 查看实时更新的日志,可以使用 -f 参数,就像用 tail -f 查看文件一样
    docker logs -f my-container
    
  4. 只想看最新的几行日志,可以使用 --tail 参数
    docker logs --tail 10 my-container
    
  5. 指定时间范围,--since--until 参数
    docker logs --since="2021-01-01T00:00:00" --until="2021-01-01T01:00:00" my-container
    

2. 高级工具

为了在实际生产环境中更高效地管理容器日志,结合一些其他工具和技术

  1. 日志驱动:Docker 支持多种日志驱动
    • eg:json-file(默认)、syslogjournald等。通过配置不同的日志驱动,可以将日志发送到不同的存储和处理系统
    docker run --log-driver=syslog my-container
    
  2. 集中化日志管理:在大型部署环境中,通常会使用像 ELK(Elasticsearch, Logstash, Kibana)或 EFK(Elasticsearch, Fluentd, Kibana)来集中管理和分析日志。通过配置 Fluentd 或 Logstash 作为日志驱动,Docker 容器的日志可以被发送到集中的 Elasticsearch 中,并且使用 Kibana 进行分析和可视化
    docker run --log-driver=fluentd my-container
    
  3. 日志轮转:为了防止日志文件变得太大,可以通过配置 Docker 的日志轮转选项来限制日志的大小和数量
    • 在 Docker 的守护进程配置文件中设置,eg:/etc/docker/daemon.json
    {
      "log-driver": "json-file",
      "log-opts": {
        "max-size": "10m",
        "max-file": "3"
      }
    }
    
  4. Sidecar 容器模式:这是一个高级模式,可以在 Kubernetes 等容器编排工具中使用。使用一个专门的 Sidecar 容器来管理主容器的日志。这种方式可以更好地解耦应用和日志管理的逻辑

6. 数据卷管理

在 Docker 中,数据卷(Volumes)是 Docker 推荐的用于持久化数据的机制。数据卷管理主要包括创建、挂载、查看、备份和删除等操作。简单来说:

  1. 创建数据卷:使用 docker volume create 命令
  2. 挂载数据卷:在启动容器时,用 -v--mount 选项挂载数据卷
  3. 查看数据卷:使用 docker volume ls 查看当前所有的卷
  4. 查看特定数据卷详情:使用 docker volume inspect
  5. 删除数据卷:停止使用该卷的容器后,使用 docker volume rm 删除数据卷

1. eg

  1. 创建数据卷: 创建一个名为 my_volume 的数据卷

    docker volume create my_volume
    
  2. 挂载数据卷: 启动一个容器,并将 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

  3. 查看数据卷: 列出所有的数据卷

    docker volume ls
    
  4. 查看特定数据卷详情: 获取 my_volume 的详细信息

    docker volume inspect my_volume
    
  5. 删除数据卷: 删除前确保没有容器在使用该卷。如果 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. 配置容器网络

  1. 桥接网络(Bridge Network):这是 Docker 默认使用的网络模式,会创建一个名为 bridge 的虚拟网络,所有容器默认都会连接到这个 bridge 网络上
  2. 主机网络(Host Network):让容器和宿主机共享 IP 地址,如果容器需要高性能的网络通信,考虑使用这种模式
  3. 无网络(None Network):使容器没有网络接口,适用于需要完全隔离网络的场景
  4. 覆盖网络(Overlay Network):适用于 Docker Swarm 或 Kubernetes,可以连接多台 Docker 主机上的容器
  5. macvlan 网络(Macvlan Network):容器会获取一个唯一的 MAC 地址,并且可以通过宿主机的物理网络接口来发送、接收数据包

使用 docker network create 创建自定义网络,使用 docker run --network=<network-name> 将容器连接到指定的网络

1. 扩展

  1. 桥接网络(Bridge): 最常见的配置方式。每个 Docker 容器在默认情况下都会连接到一个虚拟的 bridge 网络上

    优势:可以让不同容器之间进行通信

    # 创建一个自定义的桥接网络
    docker network create my_bridge
    
    # 将容器加入到这个网络
    docker run --network=my_bridge
    
  2. 主机网络(Host): 这种模式将容器完全暴露在宿主机的网络环境中,共享同一个 IP 地址以及端口。这个模式适用于那些需要高性能、不需要选择不同网络名称空间的容器

    # 启动一个使用主机网络的容器
    docker run --network host my_image
    
  3. 无网络(None): 对于一些高度安全性要求的应用,可能需要禁用网络。通过使用 --network none

    # 启动一个没有任何网络接口的容器
    docker run --network none my_image
    
  4. 覆盖网络(Overlay): Overlay 网络一般用于跨宿主机的容器通信。多用于容器编排工具 Docker Swarm 或 Kubernetes。这种网络模式能够让不同物理主机上的容器互相通信,而且非常适合于集群环境

    # 在 Swarm 中创建 overlay 网络
    docker network create --driver overlay my_overlay
    
  5. 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. 优化容器启动时间

  1. 使用较小的基础镜像:选择精简的基础镜像。eg:alpine,可以显著减少下载和加载时间
  2. 减少镜像层数:每一层都会增加容器启动的开销,精简 Dockerfile,合并多个 RUN 命令,将有助于减少层数
  3. 利用缓存:在构建镜像时尽量利用 Docker 的缓存功能,避免每次都重建镜像
  4. 适当配置健康检查:配置适当的健康检查策略,让容器可以尽快转为运行状态,而不是卡在启动过程中
  5. 预启动依赖服务:提前启动容器运行所需的依赖服务。eg:数据库等,可降低容器启动后的等待时间
  6. 本地化镜像:将常用的容器镜像保存在本地镜像库中,避免每次启动时从远程仓库拉取

1. 扩展

1)更优的镜像选择

  • 除了选择 alpine,还可以使用其他定制过的轻量级基础镜像。eg:scratch
  • 自行制作适合应用需求的轻量级镜像,尽可能移除不必要的工具和库

2)多阶段构建

  • 多阶段构建可以创建分离的构建和运行环境。通过只保留最终运行所需的部分,减少镜像整体大小
FROM golang:alpine as builder
WORKDIR /app
COPY . .
RUN go build -o myapp
FROM alpine
COPY --from=builder /app/myapp /myapp
CMD ["/myapp"]

3)有效使用入口点

  • 避免在入口点脚本中进行大量初始化操作,可以将这些操作尽量移动到镜像构建阶段
  • 某些情况下,可以预先生成配置文件,避免每次启动时的生成过程

4)监控和调试

  • 使用 Docker 自带的日志和性能监控工具。eg:docker stats,来了解容器启动过程的瓶颈
  • 可以借助第三方工具,eg:Prometheus 与 Grafana,增强监控能力

5)高效使用 Volume

  • 将需要频繁修改的数据放在 Volume 中,而不是每次都重新构建镜像,有助于提升启动和运行性能

9. 实现容器之间的通信

实现的几种方式:

  1. 使用同一个网络: 将多个容器连接到同一个 Docker 网络中,通过容器名称进行互相通信
  2. 端口映射: 将容器的端口映射到宿主机的端口,通过宿主机的 IP 和映射的端口进行通信
  3. Docker Compose: 使用 Docker Compose 来编排多个服务,可以为每个服务定义网络,并对网络进行配置
  4. 共享网络命名空间: 通过创建共享网络命名空间的方式,使多个容器共享网络设置

1. 细节、场景

  1. 使用同一个网络

    • 场景: 常用于同一个应用的微服务,彼此之间需要频繁通信的场景
    • 容器内部可以通过其它容器的名称(如 container1)进行通信
    # 创建一个自定义网络
    docker network create my_custom_network
    
    # 启动容器时,将容器加入到该网络
    docker run -d --name container1 --network my_custom_network my_image
    
  2. 端口映射

    • 场景: 外部应用或服务需要访问 Docker 容器内部的应用
    • 使用宿主机IP + 映射端口,eg:http://localhost:8080 访问
    # 启动容器时映射端口
    docker run -d -p 8080:80 --name container1 my_image
    
  3. Docker Compose

    • 场景: 适用于开发和测试环境,快速部署多容器应用
    • 创建 docker-compose.yml 文件,定义多个服务及其网络配置
    version: '3'
    services:
      web:
        image: nginx
        networks:
          - my_network
      db:
        image: mysql
        networks:
          - my_network
    networks:
      my_network:
    
  4. 共享网络命名空间

    • 场景: 允许多个容器共享一个 IP 地址,但可以进行独立的进程管理
    # 启动容器时使用 `--network container:<name>|<id>` 参数共享网络命名空间
    docker run -d --name container2 --network container:container1 my_image
    

10. Docker Swarm主要功能

Docker Swarm 是 Docker 平台内置的集群管理和编排工具。它允许你将多个 Docker 主机集合成一个虚拟的 Docker 主机,从而实现容器的集群管理和自动化部署。Swarm 提供了服务发现、负载均衡、扩展和滚动更新等功能,使得集群管理变得更加简单和高效

  1. 服务发现和负载均衡
    • Docker Swarm 能自动发现集群中的服务,并且能够在各节点之间进行负载均衡。当一个请求到达 Swarm 管理节点时,它会根据当前的负载状况将请求分发到相应的工作节点,从而实现高效的资源利用
  2. 容器编排和调度
    • Swarm 提供了强大的容器编排和调度能力,可以根据预先定义的策略(如资源需求、节点健康状况等)自动将容器调度到最适合的节点上运行。这样即使有节点发生故障,Swarm 也能够自动将容器迁移到其他健康节点上
  3. 服务扩展和缩减
    • Swarm 允许用户轻松地扩展和缩减服务。可以指定希望多少个副本运行某个服务,Swarm 将自动增加或减少节点上的容器数量来符合这个要求
  4. 滚动更新
    • 在服务需进行更新部署时,Swarm 支持滚动更新功能。可以逐步更新每个节点上的容器,确保服务持续可用。如果更新过程出现问题,还可以进行回滚操作,恢复到之前的状态
  5. 集群管理
    • Swarm 通过 manager(管理节点)和 worker(工作节点)实现了集群管理。管理节点负责管理整个 Swarm 集群的状态和配置,而工作节点则执行管理节点下发的任务。这种设计可以实现高可用性和可靠性

11. 配置、管理环境变量

  1. 在 Dockerfile 中使用 ENV 指令
  2. 通过 docker run 命令的 -e 标志传递环境变量
  3. 使用 Docker Compose 文件中的 environment 字段
  4. 在外部 .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_VARmy_service 里会被设置为 "my_value"
version: '3'
services:
  my_service:
    image: my_image
    environment:
      - MY_VAR=my_value

4. .env 文件定义环境变量

可以方便地保持环境变量的可维护性,同时可以避免在版本控制系统中暴露敏感信息

  1. 创建 .env 文件,并在其中定义环境变量
MY_VAR=my_value
  1. docker-compose.yml 中引用这些变量
version: '3'
services:
  my_service:
    image: my_image
    environment:
      - MY_VAR=${MY_VAR}

5. 环境变量优先级

  1. 通过 docker run 命令传递的环境变量
  2. Docker Compose 文件中的 environment 字段
  3. 在 Dockerfile 中使用 ENV 指令设置的环境变量
  4. 默认的系统环境变量

12. CI/CD,Jenkins与Docker集成

CI/CD 流程中使用 Jenkins 与 Docker 集成:

  1. 安装 Jenkins:首先需要在服务器或本地环境中安装 Jenkins
  2. 安装 Docker:确保 Jenkins 服务器上已经安装了 Docker
  3. 安装必要的插件:在 Jenkins 中,安装 Docker pluginPipeline plugin 等必要插件
  4. 配置 Jenkins:为 Jenkins 配置 Docker 环境,确保 Jenkins 可以访问 Docker 命令
  5. 创建 Jenkins Pipeline:在 Jenkins 中创建一个 Pipeline 项目,并在 Pipeline Script 中编写构建、测试和部署的脚本,通常使用 Jenkinsfile
  6. 运行与监控:配置好所有步骤后,运行 Pipeline 并监控执行过程,确保一切正常工作

  1. 安装 Jenkins 和 Docker
    • 安装 Jenkins:可以使用官方的 WAR 文件或者 Docker 镜像
    • 安装 Docker:在大多数 Linux 发行版中,使用包管理器如 aptyum 安装。在 Windows / macOS 上,使用 Docker Desktop
  2. 安装 Jenkins 插件
    • 登录 Jenkins 的管理界面,进入 Manage Jenkins -> Manage Plugins
    • Available 标签页下,搜索并安装 Docker pluginPipeline plugin
  3. 配置 Jenkins 访问 Docker
    • 确保 Jenkins 用户对 Docker 命令有访问权限,可以通过将 Jenkins 用户加入 Docker 组来实现
    sudo usermod -aG docker jenkins
    
    • 重启 Jenkins 服务和 Docker 服务以确保配置生效
  4. 编写 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'
                }
            }
        }
    }
    
  5. 运行与监控
    • 在 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 可以启动一个或多个容器,容器是镜像的运行实例

  1. 镜像(Images): 镜像是 Docker 的核心组件之一。一个镜像可以包含应用程序、所需的运行库以及配置文件。它可以从 Docker 的官方仓库(Docker Hub)下载,也可以通过 Dockerfile 定制创建。镜像是只读的,每次启动一个容器时,Docker 会从镜像创建一个可写的层
  2. 容器(Containers): 容器是镜像的一个运行实例,在容器中可以运行一个或多个进程。容器是独立的,具有自己的文件系统、CPU、内存等资源,但它们与宿主机共享一个操作系统内核。这种结构使得容器更轻量、更快速启动,消耗更少的资源
  3. 仓库(Repositories): 仓库是用来存储镜像的地方,类似于代码的版本控制系统。Docker Hub 是最常用的公共镜像仓库,但也可以使用私有仓库来存储企业内部镜像。镜像仓库支持版本控制,开发者可以基于特定版本的镜像进行开发和部署
  4. Dockerfile: Dockerfile 是一个包含一系列命令和指令的文本文件,用于自动化地创建一个 Docker 镜像。eg:它可以指示 Docker 从一个基本镜像开始,添加文件、安装依赖、执行命令等
  5. 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 即可

  1. 简化多容器管理:用 Docker Compose 可以管理多个容器,避免了手动启动、停止和配置多个容器的繁琐流程。eg:开发一个典型的微服务架构应用时,可能需要管理几十个不同的服务,Compose 大大简化了这个过程
  2. 适用于开发和测试环境:开发者可以迅速构建和销毁依赖环境,从而节省配置环境的时间,在本地环境就能模拟生产环境。eg:一个团队开发时,大家都可以共享相同的 docker-compose.yml 文件,确保在不同的开发机器上获得一致的环境
  3. 持续集成与持续部署(CI/CD):在 CI/CD 管道中,Compose 配合 Jenkins、GitLab CI 这样的平台,可以自动化测试和部署过程。可以在构建阶段启动一组服务,测试完成后自动清理环境
  4. 跨平台支持:Compose 支持在很多平台上运行,包括 Windows、Mac、Linux。使得在不同的OS上开发和测试变得非常容易
  5. 服务隔离和依赖管理:每个服务的依赖、环境变量、网络等都可以在 docker-compose.yml 中独立定义,避免服务间的冲突。同时,可以细粒度地控制服务间的依赖关系,确保启动顺序和依赖服务的准备状态
version: '3'
services:
  web:
    image: web-image
    ports:
      - "8000:8000"
    depends_on:
      - db
  db:
    image: mysql
    environment:
      MYSQL_ROOT_PASSWORD: example

定义了两个服务:webdb,web 服务依赖于 db 服务。docker-compose up 命令将启动和连接这两个服务

15. 镜像、容器区别

  1. 镜像(image):镜像是一个只读的模板,用来创建容器。它包含了应用运行所需的所有代码、库、环境变量和配置文件。在 Docker 环境中,镜像类似于虚拟机的快照,它是静态的、不可变的
  2. 容器(container):容器是镜像的一个实例,创建并运行在 Docker 引擎上的一个或多个进程。容器是动态的、可变的,可以启动、停止、移动和删除。在运行时,它拥有独立的文件系统、网络和进程空间,但与物理主机共享操作系统内核

1)镜像的构建和层次结构

  • 镜像是由多个只读层组成的,每一层代表了一个特定的操作(eg:安装某个软件包、复制文件等)
  • 当构建新的镜像时,Docker 不会从头开始,而是基于现有的镜像层来构建新的层。这样可以显著节省存储空间和提高构建速度
  • Dockerfile 是用于定义镜像构建过程的文件,通过逐行执行 Dockerfile 中的指令,可以生成一个新的镜像

2)容器的生命周期管理

  • 容器是镜像的可运行实例,而且这个实例是可以动态管理的:可以启动、停止、重启、删除等
  • 每个容器有自己的文件系统、网络环境和进程空间,但通过共享主机的操作系统内核实现轻量级隔离
  • 常见的管理工具有 Docker CLI 和 Docker Compose,用于启动、停止、查看日志、调试等操作

3)实用案例

  • 开发和测试环境:通过镜像统一开发环境,确保在开发和测试过程中使用的环境保持一致
  • 持续集成/持续部署(CI/CD):利用容器的高可移植性和隔离性,快速集成、测试和部署代码
  • 应用隔离:在同一台机器上运行多个应用,彼此互不干扰,方便管理和资源利用最大化

16. Dockerfile创建自定义镜像

  1. 编写 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"]
  1. 构建镜像: 使用 docker build 命令来构建镜像
docker build -t my_custom_image:latest .

1. 细节

  1. Dockerfile 基本指令
    • FROM:指定基础镜像,通常是构建镜像的第一条指令
    • RUN:执行命令,eg:安装软件包
    • COPYADD:将文件复制到镜像中
    • CMDENTRYPOINT:指定容器启动后执行的命令
    • EXPOSE:声明镜像中使用的端口,主要作为文档用途,不会实际发布端口
  2. Docker 镜像的多阶段构建: 多阶段构建可以显著减少最终镜像的大小,尤其当需要构建和运行环境有所不同的时候
# 第一阶段:构建应用
FROM golang:1.16-alpine AS builder
WORKDIR /app
COPY . .
RUN go build -o myapp

# 第二阶段:创建运行时环境
FROM alpine:latest
COPY --from=builder /app/myapp /usr/local/bin/myapp
CMD ["myapp"]
  1. 优化镜像大小的策略
    • 使用轻量级基础镜像:eg:alpine
    • 合并运行指令:减少中间层的数量。eg:合并多个 RUN 指令
    • 清理缓存和临时文件:eg:在一个 RUN 指令中更新包后马上清理缓存:RUN apt-get update && apt-get install -y python3 && apt-get clean
  2. 调试和测试 Dockerfile: 可以用 docker run -it --rm my_custom_image:latest /bin/bash 进入镜像进行手动调试,确保所有配置如预期般运作
  3. 版本控制 Dockerfile: 将 Dockerfile 放置在 Git 等版本控制系统中,可以很好地跟踪变化,同时和项目其他代码一起管理,确保环境和代码的一致性和可移植性

17. Swarm、K8S集群管理区别

Docker Swarm 和 Kubernetes 是两种流行的集群管理和编排工具,但它们在设计理念、功能以及使用场景上存在一定差异

  • Swarm适合小团队、简单项目以及希望快速上手
  • Kubernetes更适合云原生应用、大规模集群和需要复杂功能的场景
  • 同样在选择前也要权衡团队的技术能力和实际需求,做出最适合的决定

  1. 设计理念
    • Swarm:是一种轻量级的集群管理工具,集成在 Docker 中,容易上手,适合小规模的集群
    • K8S:是一个由谷歌设计的全面、复杂的容器编编排系统,适合大规模集群,支持自动化部署、扩展和操作应用容器
  2. 架构
    • Swarm:使用简单的主从架构。主节点(Manager)负责管理整个集群和任务调度,从节点(Worker节点)负责运行容器
    • K8S:采用更复杂的Master-Worker架构,主节点包括API服务器、调度器和控制器等多个组件,工作节点运行kubelet来管理Pod
  3. 扩展性和弹性
    • Swarm:支持自动扩展,但功能性相对有限,比较适合简单的分布式应用
    • K8S:提供了强大的自动扩展和负载均衡能力,适合更复杂的微服务架构,可扩展性非常高
  4. 网络设置
    • Swarm:使用简单的覆盖网络,内建网络模型非常简洁
    • K8S:网络模型更复杂,支持多种网络插件(如Flannel, Calico),更灵活
  5. 社区支持和生态系统
    • Swarm:虽然方便,但由于越来越多的人转向 K8S,所以社区支持逐渐减少
    • K8S:庞大的社区和支持,无数的第三方工具和插件,生态系统非常丰富

1. 细节上区别

  1. 日志与监控
    • Swarm:日志和监控通常需要借助第三方工具。eg:ELK来实现
    • K8S:本身就支持多种监控和日志收集方案。eg:Prometheus、ELK等,更加丰富
  2. 存储管理
    • Swarm:持久化存储支持相对较弱,需要手动配置存储卷
    • K8S:提供了成熟的持久化存储管理,包括Persistent Volumes(PV)和Persistent Volume Claims(PVC),可以与各类存储解决方案(eg:NFS、Ceph、AWS EBS)良好集成
  3. 应用部署的灵活性
    • Swarm:应用的部署主要是通过docker-compose文件
    • K8S:通过YAML文件进行各种资源的配置,包括Deployment, Service, ConfigMap等,虽然复杂,但也极为灵活和强大
  4. 自愈能力
    • Swarm:具备有限的自愈能力,如果有节点宕机可以重新调度任务
    • K8S:自愈能力非常强大,能自动重新调度Pod,重启失败的容器,确保系统的高可用性

18. 多阶段构建优势

Docker 中的多阶段构建(multi-stage build)有以下优势:

  1. 减小镜像体积:通过在构建过程中仅保留最终需要的文件,可以显著减少 Docker 镜像的体积,从而加快部署和启动时间
  2. 提高安全性:减少了镜像中的不必要文件,降低了潜在的安全风险
  3. 优化构建流程:可以在不同阶段使用不同的基础镜像,从而更好地管理依赖和构建工具,并提高构建效率
  4. 易于维护:构建过程更加清晰和可维护,因为不同的阶段可以对不同的任务负责,使得 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 --from=builder /app/myapp .
CMD ["./myapp"]

6. 分析和优化

  • Docker Slim 来减小镜像体积
  • Trivy 来扫描镜像中的漏洞

总结一下,多阶段构建是一个既节约空间又提升安全性和构建效率的利器

19. 网络模型及主要类型

Docker 的网络模型(network model)是指 Docker 容器之间以及容器与外界进行通信的方式

  1. Bridge(默认)
    • Docker 的默认网络类型,创建容器时如果不指定网络,Docker 会自动将其连接到一个叫 bridge 的默认网络
    • Bridge 网络适用于单节点(single-host)间容器通信
    • 在默认的 bridge 网络中,容器之间通过内置的虚拟网桥通信,外部需要通过端口映射来访问容器服务
  2. Host
    • Host 网络模式中,容器共享宿主机的网络栈,没有独立的 网络命名空间(network namespace)
    • Host 网络可以提高性能,因为没有网络接口间的开销,也适用于需要与宿主机网络紧密集成的应用
    • 使用 host 网络时,端口冲突需要自行管理,因为容器会占用宿主机的端口
  3. None
    • None 网络模式为容器提供一个完全独立的网络命名空间,但不进行任何网络配置
    • 容器需要自行配置网络,适用于需要完全掌控网络配置的特殊应用
  4. Container
    • Container 网络模式允许一个容器共享另一个容器的网络命名空间。指定的容器将与共享网络的容器使用同样的 IP 地址和所有网络连接
    • 适用于需要多个容器共享一个网络堆栈的场景。eg:一些高可用方案中的 SideCar 模式
  5. Overlay
    • Overlay 网络用于跨主机容器间通信。eg:在 Swarm 或 K8S 中使用
    • 它通过在多台宿主机之间创建一个共用的虚拟网络,实现不同宿主机上运行的容器之间的互联
  6. 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 镜像由一个只读的分层文件系统构成,每一层都包含了对其下层的一些改进。镜像的底层是基础层,其上是各种中间层,最上方是一个可写的顶层(容器层)

  1. 每一层都可以是一个文件、一个文件夹、一个文件系统分区的内容
  2. 当镜像被拉取时,会一步步下载层,最后组合成完整的镜像
  3. 如果镜像的某一层已经存在于本地缓存,则会直接复用,而不需要重新下载,从而节省了带宽和时间
  4. 由于每一层都是只读的,所以层与层之间的互相影响较小,安全性和稳定性更高
  5. Docker 使用存储驱动将这些层合并成一个统一的文件系统,容器看到的就是一个完整的文件系统

1. 概念

  1. 联合文件系统(UnionFS)
    • 联合文件系统能够把不同的目录(或者称为层)合并到一个目录里。在 Docker 中,常用的联合文件系统包括 OverlayFS、AUFS、btrfs 和 Device Mapper 等
  2. 存储驱动
    • Docker 通过不同的存储驱动来实现对多层结构的管理,不同的存储驱动有不同的性能特征和支持的特性。eg:OverlayFS 是当前 Docker 默认的存储驱动,它比 AUFS 更高效,支持多层次的 union,包括联合只读和可写层
  3. 镜像缓存
    • 由于 Docker 镜像是分层存储的,所以当我们构建新镜像时,如果某些层已经存在于本地,则 Docker 会复用这些已有的层而不是重新构建,从而提高构建效率并减少带宽消耗
  4. Dockerfile 和分层构建
    • Dockerfile 是用来定义 Docker 镜像的配置文件,每一个 Dockerfile 指令(如 COPY、RUN、CMD 等)都会在镜像中生成一个新层。因此,在编写 Dockerfile 时,要尽量将经常变动的部分放在底部,以减少镜像层的重复创建,从而优化构建速度和镜像大小
  5. 镜像的共享和复用
    • 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 和内存

  1. 限制容器使用的 CPU 数量
    • --cpu-shares:使用相对权重方式分配 CPU 资源
    • --cpus:直接指定容器可使用的 CPU 核数
  2. 限制容器使用的内存量
    • -m--memory:指定容器最大内存限制
# 某个容器最多使用一个 CPU 核和 512MB 内存
docker run --cpus=1 --memory=512m your_docker_image

在 Docker 中,资源限制基于 Linux 内核的 cgroups 功能。除了 CPU 和内存,Docker 还允许限制或配额其他资源。eg:I/O 性能和设备访问

  1. CPU 限制的细节
    • --cpu-shares:这是一个相对权重值,默认值是 1024。如果多个容器使用同样的 CPU 份额,则 CPU 时间会按照该权重进行分配。eg:两个容器分别设置 --cpu-shares=1024--cpu-shares=512,第一个容器将获得两倍于第二个容器的 CPU 时间
    • --cpus:这个参数允许更精确地控制容器可以使用多少 CPU 核。eg:--cpus=1.5 表示容器可以使用一个半 CPU 核
  2. 内存限制的细节
    • --memory-swap:这个参数允许为内存使用设置 swap 限制。通过设置为 -1,可以允许无限制的 swap 使用
    • --memory-reservation:这是一个软性内存限制,可以设置一个低于硬性限制的警戒线
  3. 其他资源限制
    • --blkio-weight:设置块 I/O 权重,这影响容器对存储设备的访问优先级
    • --device-read-bps--device-write-bps:用于限制设备的 I/O 读写速率

Docker 提供了灵活的资源控制方式,通过这些参数,可以确保生产环境中的容器既能高效利用系统资源,又能避免资源争夺造成的系统不稳定

对于 K8S 用户,Pod 级别的资源限制可以通过 requestslimits 字段进行定义,以确保资源的公平分配和稳定性

26. Swarm部署一个高可用集群

Docker Swarm 是 Docker 原生的集群管理工具,它使多个 Docker 引擎能够作为一个虚拟系统一起工作。它最大的优势在于简单易用和与 Docker 其他组件的良好集成

使用 Docker Swarm 部署一个高可用集群,关键步骤:

  1. 安装 Docker:确保所有主机都安装了 Docker
  2. 初始化 Swarm:选择一台主机作为管理节点,运行 docker swarm init 初始化集群
  3. 添加工作节点:在其他主机上运行管理节点给的命令
    • eg:docker swarm join --token <token> <manager-node-ip>:<port>,将这些主机加入到 Swarm 集群中
  4. 部署服务:在管理节点上使用 docker service create 命令部署应用服务,确保服务可以在多个工作节点上运行
  5. 调整配置和扩容:根据实际需求,随时调整服务副本数以扩展或缩减服务

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. 常见的场景

  1. 多节点 Swarm 集群配置
    • 如果 Swarm 集群有多个节点,在网络配置时,需要在每个节点上初始化 Swarm 并加入到集群中
    # 在其他节点上运行命令
    docker swarm join --token <SWARM-TOKEN> <MANAGER-IP>:2377
    
  2. 管理 overlay 网络
    # 查看所有网络
    docker network ls
    
    # 查看特定网络的详细信息
    docker network inspect my-overlay-network
    
    # 删除网络
    docker network rm my-overlay-network
    
  3. 服务发现和负载均衡
    • 在 Swarm 模式下,Docker 会自动进行服务发现和负载均衡。所有连接到 overlay 网络中的容器可以通过服务名互相访问,而不用关心其具体 IP 地址
  4. 对等加密
    • Docker overlay 网络支持通过 IPsec 加密的对等加密,提升安全性非常重要
    # 创建 overlay 网络时指定
    docker network create -d overlay --opt encrypted my-secure-overlay-network
    
  5. 限制流量
    • 可以通过自定义子网、网关和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 --from=builder /app/myapp .

# 设置容器启动命令
CMD ["./myapp"]

通过上述 Dockerfile,首先使用 Golang 镜像编译代码,然后在更轻量的 Alpine 镜像中运行编译后的二进制文件。这样,最终生成的镜像不会包含 Go 的构建工具,体积也会大大减小

1. 扩展

  1. 镜像层和缓存:在使用多阶段构建时,每个 FROM 指令会创建一个新的阶段,这些阶段是独立的,但它们之间可以通过 COPY --from=<stage> 共享文件。Docker 使用镜像层和缓存机制,使得多阶段构建的镜像管理更加高效
  2. 优化构建顺序:构建顺序对镜像的缓存利用率有很大的影响。应该把不经常变动的命令和文件放在前面。eg:安装基础依赖包,较频繁变动的文件,放在最后。这样可以有效利用 Docker 缓存,减少每次构建的时间
  3. 环境变量和多阶段:可以通过 ARGENV 指令在不同的构建阶段传递参数和设置环境变量。在多阶段构建中,注意合理使用这些指令,有助于提升镜像文件的可配置性和灵活性
  4. 清理不必要的文件:在每个阶段的末尾,可以通过删除不必要的文件和依赖来进一步减小镜像的体积。虽然多阶段构建本身已经很有效,但清理无用文件仍然可以锦上添花
  5. 自动化构建和测试:在多阶段构建中,可以添加一个中间阶段专门用于测试。通过这种方式,可以在构建过程中执行单元测试或其他验证,确保最终镜像中的代码是经过正确测试且稳定的

强烈建议结合 CI/CD 系统( Jenkins 或 GitLab CI),把多阶段构建过程自动化。这不仅能确保构建出更小、更高效的 Docker 镜像,还可以把 DevOps 的理念贯彻得更好