kubernetes 版本

[root@master-47-35 ~]# kubectl version
Client Version: version.Info{Major:"1", Minor:"11+", GitVersion:"v1.11.0-168+f47446a730ca03", GitCommit:"f47446a730ca037473fb3bf0c5abeea648c1ac12", GitTreeState:"clean", BuildDate:"2018-08-25T21:05:52Z", GoVersion:"go1.10.3", Compiler:"gc", Platform:"linux/amd64"}
Server Version: version.Info{Major:"1", Minor:"11+", GitVersion:"v1.11.0-168+f47446a730ca03", GitCommit:"f47446a730ca037473fb3bf0c5abeea648c1ac12", GitTreeState:"clean", BuildDate:"2018-08-25T21:05:52Z", GoVersion:"go1.10.3", Compiler:"gc", Platform:"linux/amd64"}
[root@master-47-35 ~]#

pod name生成规则

kubernetes生成pod有三种方式,如下图
$GOPATH/src/k8s.io/kubernetes/pkg/kubelet/types/pod_update.go

生成pod name的方式有以下几种方式:
1.静态podname的生成方式
2.kube-controller-manager生成方式
a. statefulset生成podName方式
b. deployment生成podName方式
c. job生成podName方式
d. daemonset生成podName方式
e. replicaset生成podName方式
f. cronjob生成podName方式
标准podName统一生成name的格式是controllerName-5个随机字符转,也有例外,比如statefulset,静态podname的生成方式就不一样了


下面一一讲解

1.静态podname的生成方式
这种方式一般是通过kubelet方式创建的,指定kubelet的指定方式--pod-manifest-path
例如:
--pod-manifest-path=/etc/kubernetes/manifests


指定之后kubelet会拉取pod起来,并且监听文件是否变化,一有变化就马上重建pod

--pod-manifest-path 对应的kubelet的命令行启动参数接收值为 StaticPodPath,
源码如下


启动一个协程计时器去监听文件是否变化

listConfig()函数的具体实现

extractFromDir(path)函数实现

extractFromFile实现



这样子就实现了修改podName的功能了:文件指定的podName-主机名

2.kube-controller-manager生成方式
这一类podName的特点就是controllerName结合5个随机字符串组成,每一个资源对象都继承podControl的方法,podControl有增删改pod信息的接口

a. statefulset生成podName方式
首先查看defaultStatefulSetControl对象的生成方法

NewDefaultStatefulSetControl这个方法被NewStatefulSetController这个方法调用
NewStatefulSetController 方法调用了Informer实时监控内存的信息,Informer这个框架在这里就不多说了,就是一个实时监听内存中相关k8s资源对象的工具

podControl直接用的实现就是RealPodControl,

RealPodControl实现了PodControlInterface接口
接下来查看RealPodControl在statefulsetController中如何使用,大概流程图是这样子的:
worker—>processNextWorkItem—>sync—>syncStatefulSet—>UpdateStatefulSet—>updateStatefulSet—>ssc.podControl.CreateStatefulPod—>identityMatches—>getPodName

其中worker就是消费ssc的队列,只要有事件发生,就会add事件到队列里

sync的具体实现

syncStatefulSet具体实现

UpdateStatefulSet

如果是创建就执行CreateStatefulPod函数请求kube-apiserver创建pod,具体实现请看下图

updateStatefulSet函数的部分实现

...// Enforce the StatefulSet invariantsif identityMatches(set, replicas[i]) && storageMatches(set, replicas[i]) {continue}
...

在identityMatches函数实现了pod的name的修改


这样子就实现statefulset的podname生成规则了:statefulsetName-1…
我们再回到函数CreateStatefulPod

func (spc *realStatefulPodControl) CreateStatefulPod(set *apps.StatefulSet, pod *v1.Pod) error {// Create the Pod's PVCs prior to creating the Podif err := spc.createPersistentVolumeClaims(set, pod); err != nil {spc.recordPodEvent("create", set, pod, err)return err}// If we created the PVCs attempt to create the Pod_, err := spc.client.CoreV1().Pods(set.Namespace).Create(pod)// sink already exists errorsif apierrors.IsAlreadyExists(err) {return err}spc.recordPodEvent("create", set, pod, err)return err
}

该函数通过client-go向kube-apiserver发出创建pod对象的请求时,实际上已经有生成podName的规则了,也就是statefulset的name加上5个随机字符串,但是由于statefuleset的特殊性,因此把返回来的podname重新按照statefuleset的方式生成了podName

接下来我们看看生成podName的规则如何实现
追踪spc.client.CoreV1().Pods(set.Namespace).Create(pod)函数,实际上就是向kube-apiserver发出POST方法创建POD资源对象的请求
因此基于这个思路,我们来看POST请求的具体实现
$GOPATH/src/k8s.io/kubernetes/vendor/k8s.io/apiserver/pkg/endpoints/installer.go

func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storage, ws *restful.WebService) (*metav1.APIResource, error) {admit := a.group.AdmitoptionsExternalVersion := a.group.GroupVersionif a.group.OptionsExternalVersion != nil {optionsExternalVersion = *a.group.OptionsExternalVersion}...case "POST": // Create a resource.var handler restful.RouteFunctionif isNamedCreater {handler = restfulCreateNamedResource(namedCreater, reqScope, admit)} else {handler = restfulCreateResource(creater, reqScope, admit)}handler = metrics.InstrumentRouteFunc(action.Verb, resource, subresource, requestScope, handler)article := getArticleForNoun(kind, " ")doc := "create" + article + kindif isSubresource {doc = "create " + subresource + " of" + article + kind}route := ws.POST(action.Path).To(handler).Doc(doc).Param(ws.QueryParameter("pretty", "If 'true', then the output is pretty printed.")).Operation("create" + namespaced + kind + strings.Title(subresource) + operationSuffix).Produces(append(storageMeta.ProducesMIMETypes(action.Verb), mediaTypes...)...).Returns(http.StatusOK, "OK", producedObject).// TODO: in some cases, the API may return a v1.Status instead of the versioned object// but currently go-restful can't handle multiple different objects being returned.Returns(http.StatusCreated, "Created", producedObject).Returns(http.StatusAccepted, "Accepted", producedObject).Reads(defaultVersionedObject).Writes(producedObject)addParams(route, action.Params)routes = append(routes, route)...

查看restfulCreateResource的实现

func restfulCreateResource(r rest.Creater, scope handlers.RequestScope, admit admission.Interface) restful.RouteFunction {return func(req *restful.Request, res *restful.Response) {handlers.CreateResource(r, scope, admit)(res.ResponseWriter, req.Request)}
}
// CreateResource returns a function that will handle a resource creation.
func CreateResource(r rest.Creater, scope RequestScope, admission admission.Interface) http.HandlerFunc {return createHandler(&namedCreaterAdapter{r}, scope, admission, false)
}

$GOPATH/src/k8s.io/kubernetes/vendor/k8s.io/apiserver/pkg/endpoints/handlers/create.go

func createHandler(r rest.NamedCreater, scope RequestScope, admit admission.Interface, includeName bool) http.HandlerFunc {return func(w http.ResponseWriter, req *http.Request) {// For performance tracking purposes.trace := utiltrace.New("Create " + req.URL.Path)defer trace.LogIfLong(500 * time.Millisecond)if isDryRun(req.URL) {scope.err(errors.NewBadRequest("dryRun is not supported yet"), w, req)return}// TODO: we either want to remove timeout or document it (if we document, move timeout out of this function and declare it in api_installer)timeout := parseTimeout(req.URL.Query().Get("timeout"))var (namespace, name stringerr             error)if includeName {namespace, name, err = scope.Namer.Name(req)} else {namespace, err = scope.Namer.Namespace(req)}if err != nil {scope.err(err, w, req)return}...trace.Step("About to store object in database")result, err := finishRequest(timeout, func() (runtime.Object, error) {return r.Create(ctx,name,obj,rest.AdmissionToValidateObjectFunc(admit, admissionAttributes),includeUninitialized,)})...

finishRequest该函数的作用就是存储对象到etcd里
这时我们得了解$GOPATH/src/k8s.io/kubernetes/vendor/k8s.io/apiserver/pkg/endpoints/installer.go文件的registerResourceHandlers函数storage rest.Storage入参的含义

// Install handlers for API resources.
func (a *APIInstaller) Install() ([]metav1.APIResource, *restful.WebService, []error) {var apiResources []metav1.APIResourcevar errors []errorws := a.newWebService()glog.Infof("a.group.Storage===== : %s \n", a.group.Storage)// Register the paths in a deterministic (sorted) order to get a deterministic swagger spec.paths := make([]string, len(a.group.Storage))var i int = 0for path := range a.group.Storage {paths[i] = pathglog.Infof("a.group.Storage[%s]=%s \n", path,a.group.Storage[path])i++}sort.Strings(paths)for _, path := range paths {apiResource, err := a.registerResourceHandlers(path, a.group.Storage[path], ws)if err != nil {errors = append(errors, fmt.Errorf("error in registering resource: %s, %v", path, err))}if apiResource != nil {apiResources = append(apiResources, *apiResource)}}return apiResources, ws, errors
}

追踪发现它就是k8s的资源对象,竟然是资源对象,那就要查看这个资源对象的实现这个接口的具体实现在哪里
查看具体实现形式
$GOPATH/src/k8s.io/kubernetes/vendor/k8s.io/apiserver/pkg/registry/rest/rest.go

// that objects may implement any of the below interfaces.
type Storage interface {// New returns an empty object that can be used with Create and Update after request data has been put into it.// This object must be a pointer type for use with Codec.DecodeInto([]byte, runtime.Object)New() runtime.Object
}

查看Storage这个接口以及所有的接口实现形式,猜测是etcd实现了这些接口
顺着这个猜测去查看Storage这个接口所在的目录发现了RESTCreateStrategy,而这里有个函数BeforeCreate就是生成资源对象的名字的,而且调用了随机生成5个字符串的包k8s.io/apiserver/pkg/storage/names,那就基本上可以知道BeforeCreate这个函数是生成podname的方法,那我们可以知道BeforeCreate函数就是生成podName的关键,因此我们就从BeforeCreate调用的地方入手

追踪发现有以下这几个地方使用到

接着跟踪
$GOPATH/src/k8s.io/kubernetes/pkg/registry/core/service/storage/rest.go 158行使用到了,但是这个是服务对象,不是我们分析的POD的对象,这个文件猜测是针对service对象的restful api,没有完全实现Interface这个接口$GOPATH/src/k8s.io/kubernetes/vendor/k8s.io/apiserver/pkg/storage/interfaces.go


这里是Service调用BeforeCreate的方法的地方

// Create inserts a new item according to the unique key from the object.
func (e *Store) Create(ctx context.Context, obj runtime.Object, createValidation rest.ValidateObjectFunc, includeUninitialized bool) (runtime.Object, error) {if err := rest.BeforeCreate(e.CreateStrategy, ctx, obj); err != nil {return nil, err}// at this point we have a fully formed object.  It is time to call the validators that the apiserver// handling chain wants to enforce.if createValidation != nil {if err := createValidation(obj.DeepCopyObject()); err != nil {return nil, err}}

接着查看发现
$GOPATH/src/k8s.io/kubernetes/vendor/k8s.io/apiserver/pkg/registry/generic/registry/store.go的对象继承Interface这个接口以及实现了以下接口

接下来查看Interface这个接口到底是谁实现了,可以看出,这个就是etcdv2以及etcdv3实现了Interface这个接口,具体实现代码在/src/k8s.io/kubernetes/vendor/k8s.io/apiserver/pkg/storage这个路径下的etcd etcd3两个文件夹,这里就不去详细讲解了
讲到这里,基本上流程走完了,接着,我们来看BeforeCreate这个函数里的方法就是生成podName的具体实现过程

方法就是生成podName的具体实现的方法

...
if len(objectMeta.GetGenerateName()) > 0 && len(objectMeta.GetName()) == 0 {objectMeta.SetName(strategy.GenerateName(objectMeta.GetGenerateName()))}
...


再分析发现每个k8s资源对象都实现了Store这个对象的方法


基本上都有rest,storage 这两个目录以及策略的方法方便操作以及存储数据到etcd,
$GOPATH/src/k8s.io/kubernetes/pkg/registry/core/rest/storage_core.go
这里有各种资源汇集生成NewLegacyRESTStorage
在注册路由的时候使用到
$GOPATH/src/k8s.io/kubernetes/pkg/master/master.go

func (m *Master) InstallLegacyAPI(c *completedConfig, restOptionsGetter generic.RESTOptionsGetter, legacyRESTStorageProvider corerest.LegacyRESTStorageProvider) {legacyRESTStorage, apiGroupInfo, err := legacyRESTStorageProvider.NewLegacyRESTStorage(restOptionsGetter)if err != nil {glog.Fatalf("Error building core storage: %v", err)}controllerName := "bootstrap-controller"coreClient := coreclient.NewForConfigOrDie(c.GenericConfig.LoopbackClientConfig)bootstrapController := c.NewBootstrapController(legacyRESTStorage, coreClient, coreClient, coreClient)m.GenericAPIServer.AddPostStartHookOrDie(controllerName, bootstrapController.PostStartHook)m.GenericAPIServer.AddPreShutdownHookOrDie(controllerName, bootstrapController.PreShutdownHook)if err := m.GenericAPIServer.InstallLegacyAPIGroup(genericapiserver.DefaultLegacyAPIPrefix, &apiGroupInfo); err != nil {glog.Fatalf("Error in registering group versions: %v", err)}
}

同时每个k8s资源都实现RESTStorageProvider该接口

同时每个k8s资源都有Strategy策略方法,是为了存储到etcd的时候选择存储策略

到此为止,分析了statefuleset的生成podName的流程已经搞定,接下来继续分析
b. deployment生成podName方式
deployment继承的接口是controller.RSControlInterface,原因是需要扩容缩容,滚动升级,回滚等操作,具体生成podName的流程如下,ReplicaSetController实现了controller.PodControlInterface,基本都一样 :
DeploymentController.syncHandler —>syncDeployment–>getReplicaSetsForDeployment—> NewReplicaSetControllerRefManager—> NewBaseController —>syncHandler(属性值)—>syncReplicaSet—>manageReplicas —>CreatePodsWithControllerRef—>createPods
getNewReplicaSet函数

CreatePodsWithControllerRef

createPods 原理跟statefulset一样,都是在BreforeCreate方法中添加5个随机字符串,这里就不多说了

原理和statefulset一样,都是增加队列,消费队列,逻辑,流程都是差不多的,接下来的 c. job生成podName方式 d. daemonset生成podName方式 e. replicaset生成podName方式 f. cronjob生成podName方式也差不多,这里就不再详细分析了

容器名字生成规则

源代码
$GOPATH/src/k8s.io/kubernetes/pkg/kubelet/dockershim/naming.go


SanboxName生成规则

ContainerName生成规则

例子

容器名字生成规则具体请参考:
容器生成规则

kubernetes pod-name生成过程 源码分析相关推荐

  1. Kubernetes监控之Heapster源码分析

    源码版本 heapster version: release-1.2 简介 Heapster是Kubernetes下的一个监控项目,用于进行容器集群的监控和性能分析. 基本的功能及概念介绍可以回顾我之 ...

  2. kubeadm源码分析(内含kubernetes离线包,三步安装)

    k8s离线安装包 三步安装,简单到难以置信 kubeadm源码分析 说句实在话,kubeadm的代码写的真心一般,质量不是很高. 几个关键点来先说一下kubeadm干的几个核心的事: kubeadm ...

  3. kubernetes 源码分析之节点异常时 pod 驱逐过程

    概述 在 Kubernetes 集群中,当节点由于某些原因(网络.宕机等)不能正常工作时会被认定为不可用状态(Unknown 或者 False 状态),当时间超过了 pod-eviction-time ...

  4. Kubernetes StatefulSet源码分析

    2019独角兽企业重金招聘Python工程师标准>>> Author: xidianwangtao@gmail.com,Based on Kubernetes 1.9 摘要:Kube ...

  5. kubeadm源码分析(kubernetes离线安装包,三步安装)

    k8s离线安装包 三步安装,简单到难以置信 kubeadm源码分析 说句实在话,kubeadm的代码写的真心一般,质量不是很高. 几个关键点来先说一下kubeadm干的几个核心的事: kubeadm ...

  6. k8s源码分析 pdf_Spark Kubernetes 的源码分析系列 - features

    1 Overview features 包里的代码,主要是用于构建 Spark 在 K8S 中的各类资源所需要的特征,个人觉得可以理解成这些 features 就是帮你写各类 Kind 的 YAML ...

  7. Kubernetes Node Controller源码分析之配置篇

    2019独角兽企业重金招聘Python工程师标准>>> Author: xidianwangtao@gmail.com Kubernetes Node Controller源码分析之 ...

  8. Kubernetes Client-go Informer 源码分析

    几乎所有的Controller manager 和CRD Controller 都会使用Client-go 的Informer 函数,这样通过Watch 或者Get List 可以获取对应的Objec ...

  9. Istio Pilot 源码分析(一)

    张海东, ‍多点生活(成都)云原生开发工程师. Istio 作为目前 Servic Mesh 方案中的翘楚,吸引着越来越多的企业及开发者.越来越多的团队想将其应用于微服务的治理,但在实际落地时却因为不 ...

最新文章

  1. linux备份svn仓库脚本,Centos详细搭建svn以及备份脚本
  2. 在JavaScript中深度克隆对象的最有效方法是什么?
  3. 计算机软件和硬件比较,软件与硬件RAID优劣之比较
  4. p2657 windy数
  5. Hive 正则匹配函数 regexp_extract
  6. python numpy矩阵索引_Numpy中的矩阵索引
  7. .NET Core运行时和基础类库性能提升
  8. 代码chaid_R或Python中的CHAID决策树
  9. 怎么彻底卸载cad2017_Win10系统怎么彻底卸载cad【图文教程】
  10. 【1084】幂的尾数
  11. React-Pdf使用过程心得
  12. 移动通信网络规划:多址技术
  13. nuxt 引入iconfont多色图标
  14. 函数式程序设计为什么至关重要(转载)
  15. Burpsuite破解用户名和密码
  16. 使用library(tseries)命令,报错“Error in library(tseries) : there is no package called ‘tseries’
  17. Python单元测试unittest测试框架
  18. 柯基数据携手亚马逊云科技打造一站式知识图谱平台案例
  19. checkbox 实现互斥选择
  20. object...object和object[]...obj[]的区别

热门文章

  1. Arduino-LED亮度渐变
  2. 锂电池标3.7V或4.2V的区别
  3. (转载)STM32与LAN9252构建EtherCAT从站
  4. docker挂载 -v
  5. 三极管之开关电路(一)
  6. 某云服务器挖矿病毒查杀日记
  7. 十二、T100销售管理之销售折扣合同管理篇
  8. 信息系统合同管理的分类
  9. js 在js字符串中添加空格
  10. Wirecast Pro 12.1.0 中文特别版 Mac 多机位的现场网络视频直播工具