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

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

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

镜像拉取这件小事

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

4cadd95901e2d0795a88aae884b93e4e.png

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

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

a250be433c821a60c715f6d2a928f105.png

理解 OAuth 2.0 协议

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

0655a80e696fe99979be16d379011518.png

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

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

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

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

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

55ade61452a780163100a6f7d6ab496e.png

Docker 扮演的角色

大图

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

eb4b9d15cf86e09f4e3cd525c5f7d058.png

理解 docker login

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

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

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

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

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

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

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

5e719b82b0902d4b225f70f492c367b5.png

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

ea189aad5898baddf1f8ec8dda3ffbcc.png

拉取镜像是怎么回事

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

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

  • 首先,docker 直接访问镜像manifests的地址,以便获取 Www-Authenticate 头字段。这个字段包括鉴权服务器的地址 Bearer realm,镜像服务地址 service,以及定义了镜像和操作的 scope。

c26b42366ec1aa654bf74a0874f9f6b5.png
  • 接着,docker 访问上边拿到的 Bearer realm 地址来鉴权,以及在鉴权之后获取一个临时的 token。这对应协议大图使用账户密码获取临时 token 这一步,使用的账户密码直接读取自 docker.json 文件。

827871d6e12cbbe651e4d4ba6490d433.png
  • 最后,使用上边的 token,以 Authorization 头字段的方式,来下载 manifests 文件。这对应的是协议大图下载镜像这一步。当然因为镜像还有分层文件,所以实际 docker 还会用这个临时 token 多次下载文件才能完整镜像下载。

6c47092c9adfe2251ec339d7a7443788.png

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

基本功能

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

e962151ad68e05f21e61c10f38d114ab.png

具体来说,步骤如下:

  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)进一步优化了上边的基本功能。

9d79fff665bb7c1c47a685b6dfe119f1.png

进一步优化的内容如下:

  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 集群和容器镜像服务产品的用户,在不用配置自己账户密码的情况下,自动使用私有仓库中的容器镜像。

54917bde156d7500308198801a8acee7.png

具体来说,控制器会监听 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 在内的多个控制器协作的结果。

原文链接

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/561145.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

hadoop没有datanode_Hadoop运行在Kubernetes平台实践

Hadoop与Kubernetes就好像江湖里的两大绝世高手,一个是成名已久的长者,至今仍然名声远扬,一个则是初出茅庐的青涩少年,骨骼惊奇,不走寻常路,一出手便惊诧了整个武林。Hadoop与Kubernetes之间有很深的渊源&a…

git 修改commit_Git从8到13 深入了解Git特性

上一章简单的介绍了一些常用的Git命令,这一章主要是深入了解一下Git的稍微高级的一些知识和指令。8.首先我们先来通过查看Git目录里面的文件来深入了解一下Git版本控制的构造。 查看HEAD可以知道当前所在的分支。在config文件里面存储着Git里面的一些配置信息&#…

eclipse maven打包jar 部分jsp无法访问_Maven系列教材 (九)- 在Eclipse中创建maven风格的java web项目...

Maven系列教材 (九)- 在Eclipse中创建maven风格的java web项目步骤1:删除j2ee目录步骤2:新建Maven 项目步骤3:这个界面点下一步步骤4: 这个界面使用webapp,点下一步 步骤5:这一步填写如图所示的信息步骤6:此时得到的maven web 项目的问题步骤…

final关键字_深入分析Java中的final关键字

Java中被final修饰的变量与普通变量有何区别?被final修饰的变量不可更改、被final修饰的方法不可重写是怎样做到的?带着疑问我们一点点拨开云雾。一、final的内存定义及规则对于final关键字,编译器、处理器从读写两个角度限制了其使用规则&am…

嵌入式和fpga哪个好前景_Java 和 go 哪个就业前景好一点?面向金钱编程,这个回答太现实...

有个朋友问我:ava 和 go 哪个就业前景好一点?现在纠结中,差不多一年半就要毕业了。我也问了几个朋友程序员朋友:朋友A: 可以参考 Boss 直聘,面向金钱编程,我身边的 Java 都是 15k 左右,反正干就…

php解决mysql主从同步_Mysql读写分离,主从同步实现

随着用户量的增多,数据库操作往往会成为一个系统的瓶颈所在,因此我们可以通过实现数据库的读写分离来提高系统的性能。通过设置主从数据库实现读写分离,主库负责“写”操作,从库负责“读”操作,根据压力情况&#xff0…

验证码图片显示不出来怎么办_pr 的蒙版不显示了怎么办?

小白自学pr一路会遇到很多坑,我也是在一个个坑里爬过的。画好的蒙版不显示了,这只能算是一个小坑。解决方法很简单,只需要记住一条:在pr里想要调整或者显示什么东西,首先必须要选中它。举例说明:我给小猫的…

gb2312编码表_汉字编码输入系统模型(一)

通过前面介绍的通信系统模型来分析汉字编码输入系统,将汉字编码输入系统的特殊性整合到通信系统模型中,从而建立起一种基于信息论的汉字编码输入系统模型(参见图3.2),以便指导我们的汉字编码输入实践,设计和…

java中sql语句怎么把开始和结束时间作为参数写sql查询_JDBC数据库连接怎么操作?...

之前一直听说过JDBC,但从来不知道它是何物的小伙伴们看过来啦!一、概述JDBC(Java Data Base Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组…

spring boot整合shiro继承redis_spring-boot-plus集成Shiro+JWT权限管理

SpringBootShiroJWT权限管理ShiroApache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理。使用Shiro的易于理解的API,您可以快速、轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和企业应用程序。三个核心组件:Subject, Secur…

java 整数变负数_一文帮你读懂Java整数的存储原理

前言大家应该都知道,整数包括负数,零,和正数。在Java中,基本类型中byte(8位)、short(16位)、int(32位)、long(64位)属于整数,并且没有无符号数,均是有符号的。对于计算机来说,它只认识二进制&am…

server2019 sqlcmd命令安装_Ubuntu20.04LTS安装MS sql-server2019的方法

在本文中,我将向您展示如何在Ubuntu 20.04 Focal Fossa上安装Microsoft SQL Server。小广告:喜欢网络技术的朋友可以加W信:xfiles_sky一起学习进步。步骤一:更新ubuntu源sudo apt update && sudo apt upgrade步骤二&#…

servlet里面为什么有时候覆_为什么新来的经理强烈推荐?前后端分离知识,学到了...

引言前后端分离这个词相信大家都听过,不知道大家是怎么理解的呢。前阵子看项目的时候,有一段实现硬是没看懂,下面来给大家说一下一段愚蠢的经历哈。(我没正正式式写过前端,所以如果文章有错的地方希望可以在评论区友善交流~)一、交…

microstation添加txt文件_C开发实战-文件操作

文件概述文件几乎无处不在,主要分为磁盘文件和设备文件,典型的磁盘文件有文本文件和二进制文件,磁盘文件存储在外部存储介质(例如磁盘,硬盘,U盘等等)需要加载到内存中才能使用。无论是文本文件还是二进制文件在计算机内…

怎样配置mysql数据源_mysql怎样配置ODBC数据源

选中 sqlserver选择默认连接的数据库 7、配置完成,可以测试连接 扩展资料: spring中配置数据源的几种常见方式:工具/原料 事先配置相应的环境mysql(mysql安装程序)mysql-connector-odbc-3.51.20-win32.exe(mysql数据源dobc安装程序) 步骤/方法…

python字符串用法_笔记:python字符串的使用

Python 没有表示单个字符的字符类型,只有字符串类型str。字符串是用单引号或双引号括起来的一系列字符。单引号表示的字符串中可以包含双引号字符,但不能直接包含单引号字符(否则无法知道字符串的开始和结尾分别在哪里)。同样,双引号表示的字…

new出来的对象怎么回收_JVM的内存模型及垃圾回收算法

1、什么是jvm:虚拟出来的计算机,是jre的一部分,使用jvm是为了支持与操作系统无关,实现跨平台,jvm内部体系结构主要分为三个部分:类加载器子系统,运行时数据区和执行引擎。2、jvm内存区域运行时数…

条令考试小程序辅助器_可以自己编题的答题软件,自定义题库考试出题工具,微信答题小程序...

自制题库自己编题的答题小程序要如何制作?今天给大家介绍下可以自己编题的答题软件,自制题库软件在微信小程序里自己出题,然后给别人来答题。每个人都可以通过这个小程序系统出考题,然后给到别人答题(自己、同事、学生…

编写有效用例电子版_软件测试人员必须编写代码吗?

相信每一个刚入门软件测试的小伙伴都会琢磨一个问题:软件测试人员,要不要写代码?其实这个问题同样困扰着已经在测试行业闯荡了几年的测试小司机们。那今天,我就来给大家分析一下~01各种软件测试角色一般而言软件测试大体可以分为两…

bert 中文 代码 谷歌_ELECTRA中文预训练模型开源,110个参数,性能媲美BERT

感谢参考原文-http://bjbsair.com/2020-03-27/tech-info/7050/ 在去年11月份,NLP大神Manning联合谷歌做的ELECTRA一经发布,迅速火爆整个NLP圈,其中ELECTRA-small模型参数量仅为 BERT-base模型的1/10,性能却依然能与BERT、RoBERTa等…