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

本文讲的是Kubernetes Docker-in-Docker存储注意事项【译者的话】本文介绍了基于Kubernetes运行Docker-in-Docker在存储方面应该注意的事项,介绍了Argo这个插件,演示了具体的流程和测试方式。鉴于在功能和性能上都表现良好,为我们开拓了一个权限的玩转Docker容器的思路。

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”。

为卷池中的每个卷创建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中添加对其卷的支持”。

这是如何在高层次上工作的:

  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 JavadekarAbhinav Das是Applatix的技术人员的成员,Applatix是一家产品和服务提供商,旨在帮助开发商在容器和Kubernetes方面取得成功。

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

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

本文作者:justinfu

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

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

时间: 2024-11-03 22:00:08

Kubernetes Docker-in-Docker存储注意事项的相关文章

Docker将在存储上崭露头角?

Docker与存储纪实 在容器中运行应用的想法--也作为OS级虚拟化著称--目前来看是一种潮流技术.这种技术的真身可以追溯到大型机时代. 但是在过去的12个月当中,在单一OS中运行多个相隔离的负载的思想被一款产品重新引爆.这家公司和产品统一命名作Docker. Docker是一款支持单一OS同时运行多应用的平台产品,可以直接部署于物理服务器之上或作为虚拟机. 这一切都实现自"用户空间"的多拷贝,用户空间就是应用在Linux或是Unix平台运行的地方. Docker如此受追捧,原因在于其

Kubernetes持续部署Docker Apps

本文讲的是Kubernetes持续部署Docker Apps[编者的话]本文是Codeship系列文章(Continuous Deployment for Docker Apps to Kubernetes)的第二篇,介绍了Codeship的相关配置项.如果已经等不及了,你可以下载电子书<Continuous Deployment for Docker Apps to Kubernetes> 这一系列文章中,我们介绍过了using Kubernetes for deployments.本篇我们

生产环境中Docker的持久化存储模式

本文讲的是生产环境中Docker的持久化存储模式[编者的话]在生产环境中使用Docker实现持久化存储一直是业界的热点问题,本文从到配置文件.机密材料.数据库.共享数据等方面做了些探讨,文中也谈到了一些需要避免的问题以及尽量将应用设计为无状态服务的原则. 一般看法认为容器对于无状态的应用程序是很好的,但是不适合有持久化数据的有状态应用.如果这是真的,这并不是因为技术不到位,而是因为管理持久化数据和有状态应用程序的模式并不总是为人们所熟知.你面临的挑战很多不是关于持久化状态的,而是如此操作不会影响

Docker镜像的存储机制

近几年 Docker 风靡技术圈,不少从业人员都或多或少使用过,也了解如何通过 Dockerfile 构建镜像,从远程镜像仓库拉取自己所需镜像,推送构建好的镜像至远程仓库,根据镜像运行容器等.这个过程十分简单,只需执行 docker build.docker pull.docker push.docker run 等操作即可.但大家是否想过镜像在本地到底是如何存储的?容器又是如何根据镜像启动的?推送镜像至远程镜像仓库时,服务器又是如何存储的呢?下面我们就来简单聊一聊. Docker 镜像本地存储

浅析Docker镜像分层的注意事项_docker

前言 我们平常在对程序进行Docker镜像打包的时候总会有些困惑,到底是将最终的镜像分层打包最后汇总成程序的镜像(也就是一层一层的 From )合适,还是说直接将程序从Source code就打包出最终的镜像更合适呢?其实这里面没有说那个是对或错的,要看程序包自身的情况做选择. Docker build的注意点 如果接触过Docker,Docker build大家都清楚怎么用了,但是有几个容易忽略的注意点:      1.Dockerfile开头的 From 和 MAINTAINER 其实都是一

十问docker —— 看docker的颜值与气质

云计算的热门带火了一批技术名词,"当红炸子鸡"docker就是其中的一个.有着洋名的docker到底是什么,让我们用十个问题让你看懂. 一问:docker是个什么东东? docker的官方定义是实现轻量级的操作系统虚拟化解决方案. Docker 的基础是 Linux 容器(LXC)等技术. 在 LXC 的基础上 Docker 进行了进一步的封装,让用户不需要去关心容器的管理,使得操作更为简便.用户操作 Docker 的容器就像操作一个快速轻量级的虚拟机一样简单. 通俗的说,docker

Mac OSX系统 Docker启用Docker远程API功能_docker

在Mac OSX系统的Docker机上启用Docker远程API功能 Docker守护进程提供了一套远程REST API,具体可以参考文档: https://docs.docker.com/engine/reference/api/docker_remote_api/ 这套API是提供给客户端与Docker引擎通信时使用,这套API也可以由其他工具调用,比如curl或Chrome浏览器的Postman REST客户端工具. 如果是在Mac OSX Mavericks系统上使用Docker机创建D

深入浅出Docker(1)----Docker核心技术预览

本文为转载文章http://www.infoq.com/cn/articles/docker-core-technology-preview/ http://blog.csdn.net/minimicall [编者按]Docker是PaaS供应商dotCloud开源的一个基于LXC 的高级容器引擎,源代码托管在 GitHub 上, 基于Go语言开发并遵从Apache 2.0协议开源.Docker提供了一种在安全.可重复的环境中自动部署软件的方式,它的出现拉开了基于云计算平台发布产品方式的变革序幕

【理解Docker】Docker与Vagrant的简单区别

本文讲的是[理解Docker]Docker与Vagrant的简单区别,[编者的话]本文翻译自Quora上的一个问题:Docker和Vagrant的区别,以及我们何时使用他们. Vagrant和Docker是两只不同的野兽. Docker是一个由shell层和management层两部分组成的,用来构建并运行基于lxc的虚拟Linux容器. Docker的伟大在于:它是轻量级的(因为它依赖于共享内核的Linux容器),[以及与它的分布无关].虽然所有实例之间的内核共享(但与主机以及互相之间都是隔离