All Posts

k8s 调度算法分析之 MatchNodeSelector(四)

一、概述 之前的文章有简要分析 k8s 的调度过程,主要就是 1. 节点筛选(选取可用的节点) 2. 节点排序(选取最优节点) 今天我们来详细分析其中的一个筛选算法 MatchNodeSelector 二、代码分析 MatchNodeSelector 对应的函数为 PodMatchNodeSelector // PodMatchNodeSelector checks if a pod node selector matches the node label. func PodMatchNodeSelector(pod *v1.Pod, meta algorithm.PredicateMetadata, nodeInfo *schedulercache.NodeInfo) (bool, []algorithm.PredicateFailureReason, error) { node := nodeInfo.Node() if node == nil { return false, nil, fmt.Errorf("node not found") } if podMatchesNodeLabels(pod, node) { return true, nil, nil } return false, []algorithm.PredicateFailureReason{ErrNodeSelectorNotMatch}, nil } 这个函数看起来超级简单,但内部其实分为两个部分的。 1. selector

k8s 调度算法分析之 PodFitsHostPorts(三)

一、概述 之前的文章有简要分析 k8s 的调度过程,主要就是 1. 节点筛选(选取可用的节点) 2. 节点排序(选取最优节点) 今天我们来详细分析其中的一个筛选算法 PodFitsHostPorts 二、代码分析 // PodFitsHostPorts checks if a node has free ports for the requested pod ports. func PodFitsHostPorts(pod *v1.Pod, meta algorithm.PredicateMetadata, nodeInfo *schedulercache.NodeInfo) (bool, []algorithm.PredicateFailureReason, error) { var wantPorts map[string]bool if predicateMeta, ok := meta.(*predicateMetadata); ok { wantPorts = predicateMeta.podPorts } else { // We couldn't parse metadata - fallback to computing it. wantPorts = schedutil.GetUsedPorts(pod) } if len(wantPorts) == 0 { return true, nil, nil } existingPorts := nodeInfo.

k8s 调度算法分析之 PodFitsResources(二)

一、概述 之前的文章有简要分析 k8s 的调度过程,主要就是 1. 节点筛选(选取可用的节点) 2. 节点排序(选取最优节点) 今天我们来详细分析其中的一个筛选算法 PodFitsResources 二、代码分析 只贴代码是没有任何意义的,我们来逐行分析 // PodFitsResources checks if a node has sufficient resources, such as cpu, memory, gpu, opaque int resources etc to run a pod. // First return value indicates whether a node has sufficient resources to run a pod while the second return value indicates the // predicate failure reasons if the node has insufficient resources to run the pod.

k8s 学习笔记之存储

一、几个存储的概念 1. pv A PersistentVolume is a piece of storage in the cluster that has been provisioned by an administrator. 2. pvc A PersistentVolumeClaims is a request for storage by a user. 3. storageclass A storageclass provides a way for administrator to describe the classes of storage they offer. pv 支持两种方式的 provision,静态和动态 1. static A cluster administrator create a number of PVs. 管理员先创建一堆 PVs,然后提供给 PVC 绑定 2. Dynamic Base StorageClasses, when none of the static PVs the administrator created matches a user’s PersistentVolumeClaim, the cluster may try to dynamically provision a volume specially for the PVC.

k8s pod 调度分析(零)

一、k8s 基础架构 在分析 k8s pod 调度之前,我们先来回顾一下 k8s 的架构 二、k8s pod 调度相关的参数 当用户通过 kubectl 或者 api 创建了一个 deployment 或者 其它 workload 的时候, k8s 会创建对应的 pod 信息,pod 信息最终会传递给 kubelet,实例化成具体的 docker 容器, 那么 k8s 是根据什么条件,怎么把 pod “安排”到 node 上去的呢? 有哪些因数会影响 pod 的调度呢? 我找了一下 pod 的参数,大概会有以下几个参数影响 pod 的调度 1. NodeName 2. NodeSelector 3. Affinity 4. Tolerations 5. PriorityClassName 6. Priority 1. nodeName 一旦你在 pod 里指定了 nodeName ,那么 pod 一定会调度到该节点上, 其实 pod 已经跳过了调度过程了 2. Priority pod 是可以有优先级的,这个优先级是相对于其它 pod 的,也就是说,如果 pod 的优先级高于其它 pod,这个 pod 会被优先调度。

k8s nodeport 端口范围

k8s 的 nodeport 默认范围是 30000-32767,那这个端口范围到底是半开半闭区间,还是开区间,还是闭区间呢? 而且能不能是不连续的呢? 能不能像(80,443, 30000-32767)这样呢? 在 k8s 源码中搜索 32767,在 gopath/src/k8s.io/kubernetes/cmd/kube-apiserver/app/options/options.go 存在代码 fs.Var(&s.ServiceNodePortRange, "service-node-port-range", ""+ "A port range to reserve for services with NodePort visibility. "+ "Example: '30000-32767'. Inclusive at both ends of the range.") 其实上面注释已经说了是闭区间了,但是我还是要看看 搜索 ServiceNodePortRange 在 gopath/src/k8s.io/kubernetes/cmd/kube-apiserver/app/options/options.go 中存在 ServiceNodePortRange: kubeoptions.DefaultServiceNodePortRange, 跟踪 DefaultServiceNodePortRange 找到 var DefaultServiceNodePortRange = utilnet.PortRange{Base: 30000, Size: 2768} 跟踪 PortRange 找到 type PortRange struct { Base int Size int } // Contains tests whether a given port falls within the PortRange.

k8s 源码分析: ReplicaSet 控制器

0x01 RS 控制器 func (rsc *ReplicaSetController) manageReplicas(filteredPods []*v1.Pod, rs *extensions.ReplicaSet) error { // 当前 pod 数量,期望 pod 数量 diff := len(filteredPods) - int(*(rs.Spec.Replicas)) rsKey, err := controller.KeyFunc(rs) if err != nil { utilruntime.HandleError(fmt.Errorf("Couldn't get key for %v %#v: %v", rsc.Kind, rs, err)) return nil } if diff < 0 { // 当前 pod 数量 < 期望 pod 数量 // 需要增加 pod diff *= -1 if diff > rsc.

创建 client (三): HTTP Basic Auth 访问 k8s API Server

0x01 结构体 AuthInfo 如果你留意过上一篇文章,你会发现一个结构体 AuthInfo: clientcmdapi.AuthInfo{ ClientCertificate: "client.crt", ClientKey: "client.key", }, 其对应代码在 client-go 下的 k8s.io/client-go/tools/clientcmd/api 中 type AuthInfo struct { // LocationOfOrigin indicates where this object came from. It is used for round tripping config post-merge, but never serialized. LocationOfOrigin string // ClientCertificate is the path to a client cert file for TLS. // +optional ClientCertificate string `json:"client-certificate,omitempty"` // ClientCertificateData contains PEM-encoded data from a client cert file for TLS.

创建 client (二): 通过配置文件方式访问 k8s API

0x01 概述 前面我讲过集群内通过 ServiceAccount 生成 token 的方式访问 k8s API Server, 那么如果我们要访问 k8s api 的应用不是跑在 k8s 之内,而是在 k8s 集群之外运行呢? 这个时候,我们还有两种认证方式 ca 证书认证 basic 认证 0x02 kubectl 是如何访问 k8s 的? k8s 部署的时候,我们会给 kubectl 配置证书,context 等信息,生成一个 $HOME/.kube/config 这样的文件,文件内容如下 apiVersion: v1 clusters: - cluster: certificate-authority-data: ... server: https://192.168.1.200:6443 name: kube_cluster contexts: - context: cluster: kube_cluster namespace: kube-system user: kubectl name: [email protected]_cluster current-context: [email protected]_cluster kind: Config preferences: {} users: - name: kubectl user: as-user-extra: {} client-certificate-data: .

k8s operator 简介

0x1 Operator 介绍 Operator 是 CoreOS 公司提出的一个概念,用来创建、配置、管理复杂应用,由两部分构成: 1. Resource 1.1 自定义资源 1.2 为用户提供一种简单的方式描述对服务的期望 2. Controller 2.1 创建 Resource 2.2 监听 Resource 的变更,用来实现用户对服务的期望 0x2 Operator 工作流程 1. 注册自定义资源 CustomResource 2. 监听(watch)自定义资源 3. 用户对自定义进行 CREATE/UPDATE/DELETE 操作 4. 当监听到资源变化之后,调用对应的 handler 进行处理 如果你了解 k8s 的内部原理,你会发现其实 k8s 本身就是这样做的, 比如 deployment ,只是 deployment 资源是内置资源, 不用向 APIServer 进行注册了而已,deployment controller 会对资源进行监控和处理。