Kubernetes Docker-in-Docker存储注意事项

本文涉及的产品
容器服务 Serverless 版 ACK Serverless,317元额度 多规格
容器服务 Serverless 版 ACK Serverless,952元额度 多规格
简介: 本文讲的是Kubernetes Docker-in-Docker存储注意事项【译者的话】本文介绍了基于Kubernetes运行Docker-in-Docker在存储方面应该注意的事项,介绍了Argo这个插件,演示了具体的流程和测试方式。
本文讲的是Kubernetes Docker-in-Docker存储注意事项【译者的话】本文介绍了基于Kubernetes运行Docker-in-Docker在存储方面应该注意的事项,介绍了Argo这个插件,演示了具体的流程和测试方式。鉴于在功能和性能上都表现良好,为我们开拓了一个权限的玩转Docker容器的思路。
docker-in-docker.jpeg

Docker容器是运行其他工具的非常有用的工具,因此将Docker容器作为另一个容器的一个工具来调用是非常自然的。Docker-in-Docker(也称DinD)有很多用例 - 1)可以将持续集成(CI)应用程序(例如Jenkins)容器化,并且要为要运行的每个CI作业提供构建/测试容器,2)在Kubernetes群集的pod中运行Docker Compose文件,3)在容器化CI作业内部构建Docker容器镜像等等。

之前的一系列博客 中我们展示了一个案例,在Kubernetes上运行Pod,而Pod本身运行Docker。

在这篇文章中,我们将讨论如何配置和管理Docker-in-Docker的存储,并且确保其功能完整、性能优良。乍一看,这似乎是一个微不足道的事情,但由于各种因素,精确和性能的极致总是鱼和熊掌不可兼得。

我们将采用主机Docker守护程序作为 外部守护程序 ,Docker守护程序作为 内部守护程序 在容器内运行。运行DinD的一个重要方面是处理Docker守护进程存储的配置和管理。

精确和性能 - 您需要二者兼得

精确

Docker要求没有两个Docker守护程序同时使用相同的graph存储。鉴于此,内部和外部Docker守护程序必须具有独立的graph存储。也就是说,内部Docker守护程序的graph存储不能与在主机上运行的外部Docker守护程序的graph存储共享,以确保正确性。

性能

如果多个DinD容器依次运行,即一个容器如果挂掉,一个容器立即创建,而不是同时运行,那么他们如何重用同一个graph存储,以便为Docker镜像获得缓存的优势?例如,考虑内部Docker实例构建一系列提交的情况。用于构建的基础镜像将从一个构建到下一个构建将保持不变。如果镜像被缓存,构建将运行得更快。

正如我们在 上一篇文章 中讨论过的,正确性要求可以使用Kubernetes'emptyDir'作为DinD graph存储卷提供程序来处理。EmptyDir保证在每个pod的主机文件系统上挂载唯一的目录。这样的目录不会被不同的pod共享,从而确保正确性。但是,一旦pod被删除,目录被删除,graph存储层将丢失,导致性能不佳。 

DinD graph存储的可选项

任何支持DinD工作负载,在Kubernetes集群上的Pod中运行Docker命令的存储解决方案,都必须满足正确性和性能要求。下面我们将讨论在AWS上运行Kubernetes集群的两种不同的技术:
  1. 存储池
  2. 带有FlexVolumes的本地磁盘

存储池

使用这种方法,外部Docker守护程序在本地挂载的磁盘上获取一个目录,用于其graph存储。通常,这是根磁盘上的 /var/lib/docker 。内部Docker守护程序获取单独的弹性块存储(EBS)卷以用作其graph存储。此EBS卷来自专门为此而创建的EBS卷。因此命名为“Volume Pool”。
volume-pool.png

为卷池中的每个卷创建Persistent Volume Claim(PVC)。当运行内部Docker守护程序的pod创建时,池中的一个PVC与此pod相关联,并挂载在 /var/lib/docker 上。

优势:

  • 可扩展性。卷池可以基于负载增长或缩小。
  • 可重用性和性能。卷可以附加到不同的节点。由于高速缓存的graph存储层是持久性的,高速缓存随着磁盘移动到集群中的其他节点。

缺点:

  • 必须管理卷池中的EBS卷。“VolumeManager”必须跟踪闲置和正在使用的卷。
  • 当池中的卷被分配到在不同节点上运行的不同pod时,它们必须被相应地移动。EBS卷经过连接,装载,卸载和分离的周期。如果您经常进行此操作,则可以按照此处所述,从AWS开始查看错误。
  • AWS不允许跨多个可用区域访问EBS卷。如果集群有EC2实例分布在不同可用区域之间,则每个区域将需要单独的卷池。需要选择来自相应可用性区域的PVC,具体取决于pod运行的实例。

具有FlexVolume的本地磁盘

使用单独的本地连接的磁盘用于Docker graph存储,而不是依靠几个EBS卷。主要思想很简单:每个主机磁盘都有专用于graph存储缓存的空间。该空间根据磁盘空间的需求分为slab。如果请求大小为X的slab,请检查是否有可用的,没有则创建它,有则重用现有的。这些slab的创建和管理是通过内部Docker守护程序的FlexVolume插件实现的。

Kubernetes文档指出:“FlexVolume使用户能够编写自己的驱动程序,并在Kubernetes中添加对其卷的支持”。
FlexVolume.png

这是如何在高层次上工作的:
  1. 集群中的每个节点都配置了一个额外挂载的EBS卷,该卷仅用作内部Docker守护程序的graph存储。
  2. 这个额外的磁盘与EC2实例一起创建与消亡。磁盘上的实际存储容量由FlexVolume驱动程序管理。
  3. 当运行内部Docker守护程序的pod运行时,pod规范包含一个“flexVolume”规范。这有一个驱动程序名称“ax/vol_plugin”和其他细节,如文件系统类型和所需的存储容量。
  4. FlexBolume插件由Kubernetes调用,用于以下操作“init,unmount,mount,version,getvolumename,waitforattach,attach,detach,isattached,mountdevice,unmountdevice”。鉴于磁盘已经附加,唯一的感兴趣的是调用和卸载。
  5. FlexVolume插件适用于操作在EBS卷上创建的逻辑卷(lvms)。
  6. 在挂载调用中,FlexVolume插件会搜索一个空闲的,与所需大小匹配的现有逻辑卷。如果是这样,它会使用它。否则,FlexVolume将创建一个新的逻辑卷并进行挂载。
  7. 在卸载调用时,FlexVolume插件只会将卷标记为“不可用”,以便它可用于下一个内部Docker守护程序。

优势

  • 由于用于内部Docker守护程序的EBS卷总是附加的,因此AWS速率限制或附加错误几率很小。
  • Pods调度更快,因为没有移动的EBS卷。

缺点

  • FlexVolume插件的安装不是直接的。
  • 如果运行多个DinD pod并且本地磁盘已被充分利用,则后续的pod不得不等待。使用卷池,可以提供新的EBS卷,以便取得进展。同样,我们可以动态扩展我们的本地EBS卷,但这是额外的工作。

Argo FlexVolume插件的源代码可以在 这里 找到。

自己试试FlexVolume插件

如果您想尝试运行DinD,并使用基于FlexVolume的方法,使用本地连接的存储作为内部docker守护程序的存储,请执行以下步骤。
  1. 确保集群中所有的slave节点有一个磁盘“/dev/xvdz”。
  2. 下载插件: wget https://s3-us-west-1.amazonaws.com/ax-public/ax_vol_plugin/bin/1.1.0/vol_plugin
  3. 在每个节点上创建以下路径: sudo mkdir -p /usr/libexec/kubernetes/kubelet-plugins/volume/exec/ax~vol_plugin/
  4. 卷插件应该复制到每个节点的以下路径: cp vol_plugin /usr/libexec/kubernetes/kubelet-plugins/volume/exec/ax~vol_plugin/vol_plugin
  5. 确保该插件可执行: sudo chmod u+x /usr/libexec/kubernetes/kubelet-plugins/volume/exec/ax~vol_plugin/vol_plugin
  6. 在每个节点上重新启动kubelet:
    sudo service kubelet restart
  7. 确保kubelet能够正确启动,并且该卷插件已正确初始化。/var/log/syslog会有 Aug 24 19:40:46 ip-172–20–1–118 kubelet[4282]: I0824 19:40:46.150515 4282 plugins.go:363] Loaded volume plugin “ax/vol_plugin”

一旦插件安装并可以使用,这里是运行此Docker镜像的示例pod规范:
apiVersion: v1
kind: Pod
metadata:
name: dind
spec:
containers:
  - name: docker-cmds
    image: docker:1.12.6
    command: ['docker', 'run', '-p', '80:80', 'httpd:latest']
    resources:
        requests:
            cpu: 10m
            memory: 256Mi
    env:
      - name: DOCKER_HOST
        value: tcp://localhost:2375
  - name: dind-daemon
    image: docker:1.12.6-dind
    resources:
        requests:
            cpu: 20m
            memory: 512Mi
    securityContext:
        privileged: true
    volumeMounts:
      - name: docker-graph-storage
        mountPath: /var/lib/docker
volumes:
- name: docker-graph-storage
  flexVolume:
    driver: "ax/vol_plugin"
    fsType: "ext4"
    options:
      size_mb: "10240"
      ax_vol_type: "ax-docker-graph-storage" 

代码托管在GitHub,点击 这里 查看。

请注意,此pod规格与我们之前的DinD 博客 中提到的格式非常相似。唯一的区别是,这个使用flexVolume插件而不是emptyDir。

我们来运行上面的pod,并验证docker-graph-storage是否真的做了它所声明的事情。
$ kubectl create -f dind_sample.yaml
pod "dind" created

当上述pod第一次运行时,ssh进入'docker-cmds'容器,并确认“ubuntu:16.04”镜像不存在。
$ kubectl exec -it dind sh
Defaulting container name to docker-cmds.
Use 'kubectl describe pod/dind' to see all of the containers in this pod.
/ # docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
httpd               latest              e74fcb59d25b        4 weeks ago         177.3 MB 

现在拉取ubuntu:16.04镜像并验证它现在。
/ # docker pull ubuntu:16.04
16.04: Pulling from library/ubuntu
d5c6f90da05d: Pull complete
1300883d87d5: Pull complete
c220aa3cfc1b: Pull complete
2e9398f099dc: Pull complete
dc27a084064f: Pull complete
Digest: sha256:34471448724419596ca4e890496d375801de21b0e67b81a77fd6155ce001edad
Status: Downloaded newer image for ubuntu:16.04
/ # docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
ubuntu              16.04               ccc7a11d65b1        2 weeks ago         120.1 MB
httpd               latest              e74fcb59d25b        4 weeks ago         177.3 MB 

现在终止pod。
$ kubectl delete pod dind
pod "dind" deleted

再次运行pod,并将ssh进去。 检查“ubuntu:16.04”镜像是否已经存在。
$ kubectl create -f dind_sample.yaml
pod "dind" created
$ kubectl exec -it dind sh
Defaulting container name to docker-cmds.
Use 'kubectl describe pod/dind' to see all of the containers in this pod.
/ # docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
ubuntu              16.04               ccc7a11d65b1        2 weeks ago         120.1 MB
httpd               latest              e74fcb59d25b        4 weeks ago         177.3 MB 

请注意,ubuntu:16.04镜像已经存在于新创建的pod中。 这是因为新的pod与上一个Dock相同。

为Docker内部守护进程创建的slab可能会添加额外的层,因此可能会耗尽容量。当pod完成执行完成,使用容量超过50%时,当前的FlexVolume实现只会删除slab。鉴于此存储是缓存,不会引发错误。

您可以在您的Kubernetes集群上手动执行上述操作,也可以尝试使用Argo。一切都是预配置且开箱即用的。

Argo工作流程本身支持DinD

Argo支持需要在pod内运行Docker命令的DinD工作负载。Argo项目中有两个组成部分共同合作,以实现这一目标。
  1. AXMON - 与Kubernetes互动管理pod
  2. VolumeManager - 用于卷管理。

VolumeManager跟踪闲置、使用和预留的卷等。AXMON调用VolumeManager为每个pod专门保留PVC。然后创建一个Kubernetes pod规范,并将PVC细节放在其中。然后将该pod规范发送到Kubernetes以运行pod。当pod完成其执行时,AXMON调用VolumeManager将PVC标记为空闲,以便可以重新使用。

在Kubernetes上运行Docker-in-Docker pod需要仔细的存储考虑。 这个博客讨论了两种方法,而不牺牲性能,同时确保正确性。

如果您有其他方法,请告诉我们。 如果您尝试在您的Kubernetes群集上的DinD,请告诉我们 @argoproj

Shrinand Javadekar Abhinav Das 是Applatix的技术人员的成员,Applatix是一家产品和服务提供商,旨在帮助开发商在容器和Kubernetes方面取得成功。

原文链接:Kubernetes Docker-in-Docker存储注意事项 (翻译:付辉)

原文发布时间为:2017-10-04

本文作者:justinfu

本文来自云栖社区合作伙伴Dockerone.io,了解相关信息可以关注Dockerone.io。

原文标题:Kubernetes Docker-in-Docker存储注意事项

相关实践学习
容器服务Serverless版ACK Serverless 快速入门:在线魔方应用部署和监控
通过本实验,您将了解到容器服务Serverless版ACK Serverless 的基本产品能力,即可以实现快速部署一个在线魔方应用,并借助阿里云容器服务成熟的产品生态,实现在线应用的企业级监控,提升应用稳定性。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
相关文章
|
1月前
|
Kubernetes 监控 Docker
Docker Compose与Kubernetes的比较
【6月更文挑战第11天】本文探讨了Docker Compose与Kubernetes在容器编排中的角色。Docker Compose适合简单部署和开发环境,提供一键启动多容器的便利;而Kubernetes则适用于大规模生产环境,具备自动化运维、集群管理和负载均衡等功能。Python在容器编排中扮演重要角色,示例代码展示了如何使用Python的Docker SDK和Kubernetes客户端进行部署、扩展和日志管理。通过Python,开发者可以实现自定义监控、自动水平扩展和实时日志监控等高级功能,增强了容器编排的灵活性和自动化。
57 1
Docker Compose与Kubernetes的比较
|
8天前
|
Kubernetes Cloud Native 持续交付
云原生架构的核心组成部分通常包括容器化(如Docker)、容器编排(如Kubernetes)、微服务架构、服务网格、持续集成/持续部署(CI/CD)、自动化运维(如Prometheus监控和Grafana可视化)等。
云原生架构的核心组成部分通常包括容器化(如Docker)、容器编排(如Kubernetes)、微服务架构、服务网格、持续集成/持续部署(CI/CD)、自动化运维(如Prometheus监控和Grafana可视化)等。
|
15天前
|
运维 Kubernetes 负载均衡
docker、docker compose、k8s有什么区别?
Docker 这个东西所扮演的角色,容易理解,它是一个容器引擎,也就是说实际上我们的容器最终是由Docker创建,运行在Docker中,其他相关的容器技术都是以Docker为基础,它是我们使用其他容器技术的核心。
48 1
|
21天前
|
存储 监控 安全
Docker Compose:轻松实现容器编排的利器
【7月更文挑战第2天】 1. **基础与概念**:服务(多容器实例)、网络(灵活通信)、卷(数据持久化)和配置(安全管理)。 2. **实战指南**:安装Compose,编写`docker-compose.yml`文件,启动应用,并介绍依赖、环境变量、健康检查和数据持久化。 3. **最佳实践**:环境隔离、CI/CD集成、资源管理、日志监控、安全策略及案例分析,展示完整应用栈搭建。
40 1
|
1天前
|
运维 Kubernetes Docker
|
26天前
|
jenkins 持续交付 开发者
利用Docker容器化部署应用的实战指南
【6月更文挑战第27天】本文详述Docker应用部署,涵盖Docker基本概念、安装、镜像制作及运行。通过编写Dockerfile构建镜像,使用`docker build`、`run`、`push`及`stop`命令管理。集成CI/CD工具如Jenkins,实现自动化构建、测试和部署,提升开发效率与部署质量。Docker助力轻量级、可移植的微服务架构。
|
3天前
|
Kubernetes 调度 Docker
|
8天前
|
关系型数据库 应用服务中间件 nginx
容器引擎Docker
带你简单了解docker,开发必备!!!
22 0
|
1月前
|
存储 Kubernetes 安全
云上攻防-云原生篇&K8s安全&Config泄漏&Etcd存储&Dashboard鉴权&Proxy暴露
云上攻防-云原生篇&K8s安全&Config泄漏&Etcd存储&Dashboard鉴权&Proxy暴露
|
1月前
|
存储 数据管理 Linux
Linux - 记录问题:docker 迁移 更改镜像默认位置的注意事项
Linux - 记录问题:docker 迁移 更改镜像默认位置的注意事项
35 0