导读:相比 K8s 集群的其他功能,私有镜像的自动拉取,看起来可能是比较简单的。而镜像拉取失败,大多数情况下都和权限有关。所以,在处理相关问题的时候,我们往往会轻松的说:这问题很简单,肯定是权限问题。但实际的情况是,我们经常为一个问题,花了多个人的时间却找不到原因。这主要还是我们对镜像拉取,特别是私有镜像自动拉取的原理理解不深。这篇文章,作者将带领大家讨论下相关原理。

顺序上来说,私有镜像自动拉取会首先通过阿里云 Acr credential helper 组件,再经过 K8s 集群的 API Server 和 kubelet 组件,最后到 docker 容器运行时。但是我的叙述,会从后往前,从最基本的 docker 镜像拉取说起。

镜像拉取这件小事

为了讨论方便,我们来设想一个场景。很多人会使用网盘来存放一些文件,像照片,文档之类。当我们存取文件的时候,我们需要给网盘提供账户密码,这样网盘服务就能验证我们的身份。这时,我们是文件资源的所有者,而网盘则扮演着资源服务器的角色。账户密码作为认证方式,保证只有我们自己可以存取自己的文件。

这个场景足够简单,但很快我们就遇到新需求:我们需要使用一个在线制作相册的应用。按正常的使用流程,我们需要把网盘的照片下载到本地,然后再把照片上传到电子相册。这个过程是比较很繁琐的。我们能想到的优化方法是,让相册应用,直接访问网盘来获取我们的照片,而这需要我们把用户名和密码授权给相册应用使用。

这样的授权方式,优点显而易见,但缺点也是很明显的:我们把网盘的用户名密码给了相册服务,相册服务就拥有了读写网盘的能力,从数据安全角度,这个是很可怕的。其实这是很多应用都会遇到的一个一般性场景。私有镜像拉取其实也是这个场景。这里的镜像仓库,就跟网盘一样,是资源服务器,而容器集群则是三方服务,它需要访问镜像仓库获取镜像。

理解 OAuth 2.0 协议

OAuth 协议是为了解决上述问题而设计的一种标准方案,我们的讨论针对 2.0 版本。相比把账户密码直接给三方应用,此协议采用了一种间接的方式来达到同样的目的。如下图,这个协议包括六个步骤,分别是三方应用获取用户授权,三方应用获取临时 Token 以及三方应用存取资源。

这六步理解起来不容易,主要是因为安全协议的设计,需要考虑协议的易证明性,所以我们换一种方式来解释这个协议。简单来说,这个协议其实就做了两件事情:

  • 在用户授权的情况下,三方应用获取 token 所表示的临时访问权限;
  • 然后三方应用使用这个 token 去获取资源。

如果用网盘的例子来说明的话,那就是用户授权网盘服务给相册应用创建临时 token,然后相册应用使用这个 token 去网盘服务获取用户的照片。实际上 OAuth 2.0 各个变种的核心差别,在于第一件事情,就是用户授权资源服务器的方式。

  1. 最简单的一种,适用于三方应用本身就拥有被访问资源控制权限的情况。这种情况下,三方应用只需要用自己的账户密码登录资源服务器并申请临时 token 即可;
  2. 当用户对三方应用足够信任的情况下,用户直接把账户密码给三方应用,三方应用使用账户密码向资源服务器申请临时 token;
  3. 用户通过资源服务器提供的接口,登录资源服务器并授权资源服务器给三方应用发放 token;
  4. 完整实现 OAuth 2.0 协议,也是最安全的。三方应用首先获取以验证码表示的用户授权,然后用此验证码从资源服务器换取临时 token,最后使用 token 存取资源。

从上面的描述我们可以看到,资源服务器实际上扮演了鉴权和资源管理两种角色,这两者分开实现的话,协议流程会变成下图这样。

Docker 扮演的角色

大图

镜像仓库 Registry 的实现,目前使用“把账户密码给三方应用”的方式。即假设用户对 Docker 足够信任,用户直接将账户密码交给 Docker,然后 Docker 使用账户密码跟鉴权服务器申请临时 token。

理解 docker login

首先,我们在拉取私有镜像之前,要使用 docker login 命令来登录镜像仓库。这里的登录其实并没有和镜像仓库建立什么会话之类的关系。登录主要就做了三件事情:

  • 第一件事情是跟用户要账户密码。

如下图,当执行登录命令,这个命会提示输入账户密码,这件事情对应的是大图的第一步。

  • 第二件事情,docker 访问镜像仓库的 https 地址,并通过挑战 v2 接口来确认,接口是否会返回 Docker-Distribution-Api-Version 头字段。

这件事情在协议图中没有对应的步骤。它的作用跟 ping 差不多,只是确认下 v2 镜像仓库是否在线,以及版本是否匹配。

  • 第三件事情,docker 使用用户提供的账户密码,访问 Www-Authenticate 头字段返回的鉴权服务器的地址 Bearer realm。

如果这个访问成功,则鉴权服务器会返回 jwt 格式的 token 给 docker,然后 docker 会把账户密码编码并保存在用户目录的 .docker/docker.json 文件里。

下图是我登录仓库之后的 docker.json 文件。这个文件作为 docker 登录仓库的唯一证据,在后续镜像仓库操作中,会被不断的读取并使用。其中关键信息 auth 就是账户密码的 base64 编码。

拉取镜像是怎么回事

镜像一般会包括两部分内容,一个是 manifests 文件,这个文件定义了镜像的元数据,另一个是镜像层,是实际的镜像分层文件。镜像拉取基本上是围绕这两部分内容展开。因为我们这篇文章的重点是权限问题,所以我们这里只以 manifests 文件拉取为例。

拉取 manifests 文件,基本上也会做三件事情:

  • 首先,docker 直接访问镜像manifests的地址,以便获取 Www-Authenticate 头字段。这个字段包括鉴权服务器的地址 Bearer realm,镜像服务地址 service,以及定义了镜像和操作的 scope。
  • 接着,docker 访问上边拿到的 Bearer realm 地址来鉴权,以及在鉴权之后获取一个临时的 token。这对应协议大图使用账户密码获取临时 token 这一步,使用的账户密码直接读取自 docker.json 文件。
  • 最后,使用上边的 token,以 Authorization 头字段的方式,来下载 manifests 文件。这对应的是协议大图下载镜像这一步。当然因为镜像还有分层文件,所以实际 docker 还会用这个临时 token 多次下载文件才能完整镜像下载。

K8s 实现的私有镜像自动拉取

基本功能

K8s 集群一般会管理多个节点,每个节点都有自己的 docker 环境。如果让用户分别到集群节点上登录镜像仓库,这显然是很不方便的。为了解决这个问题,K8s 实现了自动拉取镜像的功能。这个功能的核心,是把 docker.json 内容编码,并以 Secret 的方式作为 Pod 定义的一部分传给 Kubelet。

具体来说,步骤如下:

  1. 创建 secret。这个 secret 的 .dockerconfigjson 数据项包括了一份 base64 编码的 docker.json 文件;
  2. 创建 pod,且 pod 编排中 imagePullSecrets 指向第一步创建的 secret;
  3. Kubelet 作为集群控制器,监控着集群的变化。当它发现新的 pod 被创建,就会通过 API Server 获取 pod 的定义,这包括 imagePullSecrets 引用的 secret;
  4. Kubelet 调用 docker 创建容器且把 .dockerconfigjson 传给 docker;
  5. 最后 docker 使用解码出来的账户密码拉取镜像,这和上一节的方法一致。

进阶方式

上边的功能,一定程度上解决了集群节点登录镜像仓库不方便的问题。但是我们在创建 Pod 的时候,仍然需要给 Pod 指定 imagePullSecrets。K8s 通过变更准入控制(Mutating Admission Control)进一步优化了上边的基本功能。

进一步优化的内容如下:

  1. 在第一步创建 secret 之后,添加 default service account 对 imagePullSecrets 的引用;
  2. Pod 默认使用 default service account,而 service account 变更准入控制器会在 default service account 引用 imagePullSecrets 的情况下,添加 imagePullSecrets 配置到 pod 的编排里。

阿里云实现的 Acr credential helper

阿里云容器服务团队,在 K8s 的基础上实现了控制器 Acr credential helper。这个控制器可以让同时使用阿里云 K8s 集群和容器镜像服务产品的用户,在不用配置自己账户密码的情况下,自动使用私有仓库中的容器镜像。

具体来说,控制器会监听 acr-configuration 这个 configmap 的变化,其主要关心 acr-registry 和 watch-namespace 这两个配置。前一个配置指定为临时账户授权的镜像仓库地址,后一个配置管理可以自动拉取镜像的命名空间。当控制器发现有命名空间需要被配置却没有被配置的时候,它会通过阿里云容器镜像服务的 API,来获取临时账户和密码。

有了临时账户密码,Acr credential helper 为命名空间创建对应的 Secret 以及更改 default SA 来引用这个 Secret。这样,控制器和 K8s 集群本身的功能,一起自动化了阿里云 K8s 集群拉取阿里云容器镜像服务上的镜像的全部流程。

总结

理解私有镜像自动拉取的实现,有一个难点和一个重点。

  • 难点是 OAuth 2.0 安全协议的原理,上文主要分析了为什么 OAuth 会这么设计;
  • 重点是集群控制器原理,因为整个自动化的过程,实际上是包括 Admission control 和 Acr credential helper 在内的多个控制器协作的结果。

原文链接

本文为云栖社区原创内容,未经允许不得转载。

如何拉取k8s镜像_K8s 从懵圈到熟练 – 镜像拉取这件小事相关推荐

  1. K8s 从懵圈到熟练 – 镜像拉取这件小事

    作者 | 声东 阿里云售后技术专家 导读:相比 K8s 集群的其他功能,私有镜像的自动拉取,看起来可能是比较简单的.而镜像拉取失败,大多数情况下都和权限有关.所以,在处理相关问题的时候,我们往往会轻松 ...

  2. k8s ubuntu cni_K8S从懵圈到熟练 – 集群网络详解

    阿里云K8S集群网络目前有两种方案,一种是flannel方案,另外一种是基于calico和弹性网卡eni的terway方案.Terway和flannel类似,不同的地方在于,terway支持Pod弹性 ...

  3. Kubernetes从懵圈到熟练:认证与调度

    不知道大家有没有意识到一个现实,就是大部分时候,我们已经不像以前一样,通过命令行,或者可视窗口来使用一个系统了.现在我们上微博.或者网购,操作的其实不是眼前这台设备,而是一个又一个集群. 通常,这样的 ...

  4. K8S 从懵圈到熟练--大数据平台技术栈18

    回顾:大数据平台技术栈 (ps:可点击查看),今天就来说说其中的K8S! 来自:阿里技术公众号 阿里妹导读:排查完全陌生的问题.不熟悉的系统组件,对许多工程师来说是无与伦比的工作乐趣,当然也是一大挑战 ...

  5. K8S从懵圈到熟练 - 节点下线姊妹篇

    之前分享过一例集群节点NotReady的问题.在那个问题中,我们的排查路劲,从K8S集群到容器运行时,再到sdbus和systemd,不可谓不复杂.那个问题目前已经在systemd中做了修复,所以基本 ...

  6. K8s 从懵圈到熟练-集群伸缩原理

    作者 | 声东  阿里云技术专家 <关注公众号,回复 排查 即可下载电子书> <深入浅出 Kubernetes>一书共汇集 12 篇技术文章,帮助你一次搞懂 6 个核心原理,吃 ...

  7. K8S从懵圈到熟练 - 我们为什么会删除不了集群的命名空间?

    阿里云售后技术团队的同学,每天都在处理各式各样千奇百怪的线上问题.常见的有,网络连接失败,服务器宕机,性能不达标,请求响应慢等.但如果要评选,什么问题看起来微不足道事实上却足以让人绞尽脑汁,我相信答案 ...

  8. K8s 从懵圈到熟练 – 集群网络详解

    作者 | 声东 阿里云售后技术专家 导读:阿里云 K8S 集群网络目前有两种方案:一种是 flannel 方案:另外一种是基于 calico 和弹性网卡 eni 的 terway 方案.Terway ...

  9. K8S从懵圈到熟练 – 集群网络详解

    阿里云K8S集群网络目前有两种方案,一种是flannel方案,另外一种是基于calico和弹性网卡eni的terway方案.Terway和flannel类似,不同的地方在于,terway支持Pod弹性 ...

最新文章

  1. 今天你写控件了吗?----ASP.net控件开发系列(三)
  2. centos7 ssh 密码拒绝_Centos7的ssh connection refused
  3. 高效大数据开发之 bitmap 思想的应用
  4. [Alg] 二叉树的非递归遍历
  5. 使用Wireshark进行SIP包解析
  6. Redis的七种武器及其适合的应用场景
  7. 对Lucene PhraseQuery的slop的理解
  8. python3.7.1安装
  9. Remoting示例
  10. BackTrack5 下破解无线
  11. springboot 微信支付接口(H5)
  12. windows64位首次安装git
  13. Flask知识点串烧(三)--- JInjia2模板
  14. java求一元二次方程:ax2+bx+c=0的根
  15. 入职两个月的总结和反思
  16. 2012美国大选献金项目数据分析(有史以来最全面)
  17. 李清照(诗词介绍收藏)
  18. Android Studio 开发 C盘减肥
  19. 汉芯门主角制造另外一个汉芯?
  20. ​力扣解法汇总954-二倍数对数组

热门文章

  1. c++实现二叉树操作
  2. Centos7制作局域网http的yum源
  3. 需要单机还是集群部署_单机、分布式、集群的区别与联系
  4. 中专计算机专业教研方案,教研活动实施方案电脑基础知识IT计算机专业资料-教研活动实施方案.pdf...
  5. html5图片剪切板,JavaScript 网页端复制图片到剪切板
  6. 电脑公司win11 32位官方版镜像v2021.07
  7. 制表符空格数设置(阿里巴巴使用4个空格)
  8. 浏览器与JavaScript(一)
  9. Websocket判断逻辑Bug
  10. 用python画三维图、某区域的高程,python - 在PyQt中绘制具有高程和降低效果的3D矩形/多边形 - SO中文参考 - www.soinside.com...