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

简介: 本文讲的是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 的基本产品能力,即可以实现快速部署一个在线魔方应用,并借助阿里云容器服务成熟的产品生态,实现在线应用的企业级监控,提升应用稳定性。
云原生实践公开课
课程大纲 开篇:如何学习并实践云原生技术 基础篇: 5 步上手 Kubernetes 进阶篇:生产环境下的 K8s 实践 相关的阿里云产品:容器服务 ACK 容器服务 Kubernetes 版(简称 ACK)提供高性能可伸缩的容器应用管理能力,支持企业级容器化应用的全生命周期管理。整合阿里云虚拟化、存储、网络和安全能力,打造云端最佳容器化应用运行环境。 了解产品详情: https://www.aliyun.com/product/kubernetes
相关文章
|
6月前
|
存储 Kubernetes NoSQL
【K8S系列】深入解析K8S存储
【K8S系列】深入解析K8S存储
159 0
|
4月前
|
存储 Kubernetes Linux
解决Linux中/var/lib/docker/磁盘空间过大及k8s存储卷磁盘空间使用率过高的问题
解决Linux中/var/lib/docker/磁盘空间过大及k8s存储卷磁盘空间使用率过高的问题
146 0
|
6月前
|
存储 Kubernetes 网络协议
kubernetes ConfigMap存储卷
kubernetes ConfigMap存储卷
|
8月前
|
Kubernetes 关系型数据库 Perl
Job资源对象,与k8s存储
Job资源对象,与k8s存储
55 0
|
8月前
|
存储 Kubernetes 数据安全/隐私保护
k8s--配置存储 ConfigMap、Secret
k8s--配置存储 ConfigMap、Secret
|
8月前
|
存储 Unix 应用服务中间件
k8s--数据存储、HostPath、NFS 存储
k8s--数据存储、HostPath、NFS 存储
|
4月前
|
存储 Kubernetes 关系型数据库
kubernetes学习之持久化存储StorageClass(4---nfs存储服务)
kubernetes学习之持久化存储StorageClass(4---nfs存储服务)
47 0
|
4月前
|
存储 Kubernetes API
k8s实战系列:3-存储的花样玩法(下)
k8s实战系列:3-存储的花样玩法(下)
28 0
|
4月前
|
存储 Kubernetes Cloud Native
k8s实战系列:3-存储的花样玩法(上)
k8s实战系列:3-存储的花样玩法(上)
43 0
|
4月前
|
存储 Kubernetes 对象存储
Kubernetes存储:Ceph架构,部署和使用
Kubernetes存储:Ceph架构,部署和使用
78 0