Kubernetes 在 9 月份推出了 1.4 的版本,在这个版本中最招人眼球的就是它推出了 Kubeadm 部署工具。本文由才云云开源高级工程师唐继元从源码的角度来剖析 kubeadm 的部署原理。
k8s version:1.4
Kubeadm app 支持的命令
从函数“NewKubeadmCommand”中可以看出:
cmds.AddCommand(NewCmdInit(out))
cmds.AddCommand(NewCmdJoin(out))
cmds.AddCommand(NewCmdVersion(out))
目前主要支持:“kubeadm init” 和 “kubeadm join” 命令。
kubeadm init
功能:“Run this in order to set up the Kubernetes master.”
主要的 options:
cmd.PersistentFlags().StringVar(
&cfg.Secrets.GivenToken, "token", "",
"Shared secret used to secure cluster bootstrap; if none is provided, one will be generated for you",
)
cmd.PersistentFlags().StringSliceVar(
&cfg.API.AdvertiseAddresses, "api-advertise-addresses", []string{},
"The IP addresses to advertise, in case autodetection fails",
)
cmd.PersistentFlags().StringSliceVar(
&cfg.API.ExternalDNSNames, "api-external-dns-names", []string{},
"The DNS names to advertise, in case you have configured them yourself",
)
cmd.PersistentFlags().StringVar(
&cfg.Networking.ServiceSubnet, "service-cidr", kubeadmapi.DefaultServicesSubnet,
"Use alterantive range of IP address for service VIPs",
)
cmd.PersistentFlags().StringVar(
&cfg.Networking.PodSubnet, "pod-network-cidr", "",
"Specify range of IP addresses for the pod network; if set, the control plane will automatically allocate CIDRs for every node",
)
cmd.PersistentFlags().StringVar(
&cfg.Networking.DNSDomain, "service-dns-domain", kubeadmapi.DefaultServiceDNSDomain,
`Use alternative domain for services, e.g. "myorg.internal"`,
)
cmd.PersistentFlags().StringVar(
&cfg.CloudProvider, "cloud-provider", "",
`Enable cloud provider features (external load-balancers, storage, etc), e.g. "gce"`,
)
cmd.PersistentFlags().StringVar(
&cfg.KubernetesVersion, "use-kubernetes-version", kubeadmapi.DefaultKubernetesVersion,
`Choose a specific Kubernetes version for the control plane`,
)
// … 这里忽略了未来将要Deprecated的flag
下面看看 init 命令到底做了些什么:
// RunInit executes master node provisioning, including certificates, needed static pod manifests, etc.
func RunInit(out io.Writer, cmd *cobra.Command, args []string, cfg *kubeadmapi.MasterConfiguration) error {
// 如果未指定“api-advertise-addresses”,就选择默认路由对应interface的ip
// Auto-detect the IP
if len(cfg.API.AdvertiseAddresses) == 0 {
// TODO(phase1+) perhaps we could actually grab eth0 and eth1
ip, err := netutil.ChooseHostInterface()
if err != nil {
return err
}
cfg.API.AdvertiseAddresses = []string{ip.String()}
}
// 如果指定了“cloud-provider”,则初始化cloud provider,并向k8s注册
// TODO(phase1+) create a custom flag
if cfg.CloudProvider != "" {
if cloudprovider.IsCloudProvider(cfg.CloudProvider) {
fmt.Printf("<cmd/init> cloud provider %q initialized for the control plane. Remember to set the same cloud provider flag on the kubelet.\n", cfg.CloudProvider)
} else {
return fmt.Errorf("<cmd/init> cloud provider %q is not supported, you can use any of %v, or leave it unset.\n", cfg.CloudProvider, cloudprovider.CloudProviders())
}
}
// 如果未指定“token”,则自动创建一个token
// 然后将该token保存在“/etc/kubernetes/pki”目录下:tokens.csv
if err := kubemaster.CreateTokenAuthFile(&cfg.Secrets); err != nil {
return err
}
}
// 根据componentconfig的配置信息创建master节点上的static pod对象,
// 并将static pod以json文件格式保存到“/etc/kubernetes/manifests”目录下:
// kube-apiserver.json kube-controller-manager.json kube-scheduler.json
// 如果用户未指定“external etcd”,则还会创建etcd static pod:etcd.json
if err := kubemaster.WriteStaticPodManifests(cfg); err != nil {
return err
}
// 基于token创建服务相关的key和setificate,保存在“/etc/kubernetes/pki”目录下:
// ca-key.pem ca-pub.pem ca.pem
// apiserver-key.pem apiserver-pub.pem apiserver.pem
// sa-key.pem sa-pub.pem
caKey, caCert, err := kubemaster.CreatePKIAssets(cfg)
if err != nil {
return err
}
// 创建client使用的certificate,并以conf文件保存在“/etc/kubernetes/pki”目录下:
// admin.conf kubelet.conf
// admin.conf和kubelet.conf分别是kubectl和kubelet使用的kubeconfig
kubeconfigs, err := kubemaster.CreateCertsAndConfigForClients(cfg.API.AdvertiseAddresses, []string{"kubelet", "admin"}, caKey, caCert)
if err != nil {
return err
}
for name, kubeconfig := range kubeconfigs {
if err := kubeadmutil.WriteKubeconfigIfNotExists(name, kubeconfig); err != nil {
return err
}
}
// 利用admin.conf创建client,并等待apiserver起来
// 使用这个client就相当于执行了如下命令:
// kubectl --kubeconfig=”/etc/kubernetes/admin.conf” xxxx
// 后面的addons都是通过该client创建的
client, err := kubemaster.CreateClientAndWaitForAPI(kubeconfigs["admin"])
if err != nil {
return err
}
// 设置默认不允许调度pod到master上的taint
// 这种情况下master上就只运行“/etc/kubernetes/manifests”目录下的static pod
// 和master上的一些addons(设置了toleration)
schedulePodsOnMaster := false
if err := kubemaster.UpdateMasterRoleLabelsAndTaints(client, schedulePodsOnMaster); err != nil {
return err
}
// 创建kube-discovery deployment和secret,并等待kube-discovery server起来
// kube-discovery server侦听9898端口
// kube-discovery是必须的addon组件
// 当需要往k8s集群添加node时,“kubeadm join”首先通过URL向kube-discovery server请求cluster的相关信息
// http://MasterIP:9898/cluster-info/v1/?token-id=XXX.YYYY
// kube-discovery服务收到请求之后,将cluster ca证书,endpoint列表和token以k8s secrets的方式回复给发送请求的节点
if err := kubemaster.CreateDiscoveryDeploymentAndSecret(cfg, client, caCert); err != nil {
return err
}
// 创建其他必须的addon,主要是:kube-proxy, kube-dns
// kube-proxy 为daemonSet,而kube-dns为deployment
if err := kubemaster.CreateEssentialAddons(cfg, client); err != nil {
return err
}
}
从上面的分析可以看出:kubeadm init 主要负责创建 k8s 集群的 key、certs 和 conf 文件,创建 etcd、kube-apiserver、kube-controller-manager、kube-scheduler 这些 static pod 的 json 格式的 manifest 文件(kubelet 会监视“/etc/kubernetes/manifests”目录下的 manifest 文件,一旦发现则启动对应的 static pod),然后启动 kube-discovery deployment、kube-proxy daemonSet、kube-dns deployment 这三个 addon。
kubeadm join
kubeadm join --token <token> <master-ip>
功能:“Run this on any machine you wish to join an existing cluster.”,即将当前运行“kubeadm join”命令的节点加入到一个已经存在的 k8s 集群中。
主要的 options:
cmd.PersistentFlags().StringVar(
&cfg.Secrets.GivenToken, "token", "",
"(required) Shared secret used to secure bootstrap. Must match the output of 'kubeadm init'",
)
下面看看 join 命令到底做了些什么:
// RunJoin executes worked node provisioning and tries to join an existing cluster.
func RunJoin(out io.Writer, cmd *cobra.Command, args []string, s *kubeadmapi.NodeConfiguration) error {
// 用户必须要指定token
// 如果用户指定了token,则检查token的格式是否合法
// token格式要求(比如:f0c861.753c505740ecde4c):
// 1. 点分格式(2-part dot-separated format)
// 2. 前面部分为3个字节的tokenID,比如:f0c861
// 3. 后面部分为8个字节的token,比如:753c505740ecde4c
ok, err := kubeadmutil.UseGivenTokenIfValid(&s.Secrets)
if !ok {
if err != nil {
return fmt.Errorf("<cmd/join> %v (see --help)\n", err)
}
return fmt.Errorf("Must specify --token (see --help)\n")
}
// 1. 访问kube-discovery服务,获取cluster相关信息(cluster info对象,主要包括cluster ca证书,endpoint列表和token信息)
// URL: http://MasterIP:9898/cluster-info/v1/?token-id=XXX.YYYY
// 2. 使用用户指定的token检验cluster info对象的签名,如果检验失败则自然不允许加入该k8s集群
clusterInfo, err := kubenode.RetrieveTrustedClusterInfo(s)
if err != nil {
return err
}
// 利用endpoint列表的其中一个apiserver的URL创建能与k8s master建立连接的ConnectionDetails对象
connectionDetails, err := kubenode.EstablishMasterConnection(s, clusterInfo)
if err != nil {
return err
}
// 通过ConnectionDetails对象与apiserver建立连接,并向apiserver请求为该节点创建证书,然后根据该证书创建kubeconfig对象
kubeconfig, err := kubenode.PerformTLSBootstrap(connectionDetails)
if err != nil {
return err
}
// 将kubeconfig对象写入“/etc/kubernetes/kubelet.config”文件
err = kubeadmutil.WriteKubeconfigIfNotExists("kubelet", kubeconfig)
if err != nil {
return err
}
}
然后我们看看 node 节点上 kubelet 是如何运行的:
/usr/bin/kubelet --kubeconfig=/etc/kubernetes/kubelet.conf --require-kubeconfig=true --pod-manifest-path=/etc/kubernetes/manifests --allow-privileged=true --network-plugin=cni --cni-conf-dir=/etc/cni/net.d --cni-bin-dir=/opt/cni/bin --cluster-dns=100.64.0.10 --cluster-domain=cluster.local
所以,节点上的 kubelet 需要通过 kubelet.conf 与 apiserver 进行安全通信。
从上面的分析可以看出:kubeadm join 主要负责创建 kubelet.conf 文件,创建的流程如下:
1.访问 kube-discovery 服务获取 k8s cluster info,主要包含如下信息:cluster ca 证书、endpoint 列表和 token
2.利用用户指定的 token,检验 k8s cluster info 的签名,建议通过才能进行后续步骤
3.与 endpoint 列表的其中一个 apiserver 建立连接,请求 apiserver 为该 node 节点创建证书,然后利用该获取到的证书创建 kubelet.conf
作者介绍:唐继元 ,才云云开源高级工程师。浙江大学软件学院软件工程专业嵌入式系统方向。2016 年初加入才云,加盟才云之前,曾在华为工作 5 年,期间在华为中央软件院服务器 OS 部门负责 LTP (linux 内核测试套件)关于内存管理和内存文件系统的测试代码的开发和完善,后转至中央研究院香农实验室系统软件组负责云计算软件方向的研究(主要包括众核 OS:barralfish 的研究,LibOS:OSv 的研究,DCOS 调度的研究,lwip 并行协议栈的研究,容器方向的研究),以及对 Kubernetes 调度等研究。
本文转载自才云 Caicloud 公众号。
原文链接:https://mp.weixin.qq.com/s/b5VU8Fr4FZtZAnvfL0fBTg
更多内容推荐
53|容器化实战:怎样搭建 K8s 爬虫集群?
这节课让我们把爬虫项目相关的微服务部署到 Kubernetes 中。
2023-02-11
在 Kubeadm 中使用 pod 安全策略
Pod安全策略是一种机制,用于限制容器在k8s上运行时可执行的操作,例如防止其作为特权容器的运行,和主机网络运行等。
基于 vmware16 和 ubuntu20.04, 搭建单节点 kubernetes 1.22.2
2023-09-25
Kubernetes 运行大数据工作负载的探索和实践
在ArchSummit 北京 2019 大会上,王雷博讲师做了《Kubernetes 运行大数据工作负载的探索和实践》主题演讲。
21|应用定义:如何使用 Helm 定义应用?
这节课,我们还是以示例应用为例子,把它从原始的 Kubernetes Manifest 改造成 Helm 应用。
2023-01-25
Kubernetes 将迎来首个 LTS 版本
受新冠病毒的影响,Kubernetes 1.19 的发布将会延后到 8 月 4 日,并且今年只会发布三个版本(1.18-1.20)。并且,LTS 计划将从 1.16 版本开始执行。
2020-05-06
云原生生态周报 Vol. 43:K8s 1.18 正式 release
《云原生生态周报》由阿里云容器平台联合蚂蚁金服共同发布,众多一线社区专家与您一起“跟踪动态,读懂社区”,分享云原生社区项目进展、活动发布、精选博客等信息。
28 天带你玩转 Kubernetes-- 第七天(玩转 Dockerfile)
玩转dockerfile
2021-01-14
云原生生态周报 Vol. 51:Linkerd 2.8 正式发布
《云原生生态周报》由阿里云容器平台联合蚂蚁金服共同发布,众多一线社区专家与您一起“跟踪动态,读懂社区”,分享云原生社区项目进展、活动发布、精选博客等信息。
Kind:用于测试 Kubernetes 的本地集群
Kind 是一种使用 Docker 容器作为 node 节点,运行本地 Kubernetes 集群的工具
小白也能玩转 Kubernetes 你与大神只差这几步(一)
随着Kubernetes技术热度的不断提升,大容器时代的序幕已经开启。容器技术日新月异,在企业应用实践中得到了不断的发展,高效的运维、管理和部署都成为云服务的重头戏。
40|命令式和声明式,谁才是驱动云原生的“引擎”?
这节课我们来聊聊命令式和声明式。
2023-03-10
17|组件监控:Kubernetes Node 组件的关键指标与数据采集
Kubernetes Node组件的关键指标与数据采集
2023-02-15
Kubernetes 常用命令大全,linux 入门经典书籍
kubectl get deployment nginx-app
2021-11-10
K8S CronJob 简单入门,和手动重复操作 Say Goodbye!
有时,调度一个应用程序进程、一些重复的操作(如发送邮件、告警、验证等)是极为必要的。
kube-scheduler 源码解析
源码的同学一个参考。925c127ec。源码进行分析。上,这一过程也叫绑定(Bind)。上。上。Node。
18|组件监控:Kubernetes 控制面组件的关键指标与数据采集
Kubernetes 控制面组件的关键指标与数据采集
2023-02-17
超详细的腾讯云 Kubernetes 一键部署实践
很多人在实际工作中都使用过Kubernetes,我们的容器服务在2016年年底开始提供全托管的Kubernetes服务,主要提供了四个方面的功能。
解放开发者!3 款工具实现快速 K8S 开发
在这篇文章中,我们将探讨开发人员如何使用DevSpace和Rancher来简化Kubernetes开发。
推荐阅读
5. 基于 Kubeadm 及 Kubespray 安装高可用集群
2023-09-26
K8S 太火了!花 10 分钟玩转它不香么?
2022-04-18
强大的 Kubernetes 工具的完整指南
2023-11-30
加餐|尝鲜 Gateway API:更强大、更灵活、面向未来的 Ingress
2023-11-20
Kubernetes 认证管理员(CKA)必过心得
2022-10-10
Karpenter : 新一代 Kubernetes auto scaling 工具
2022-01-13
12、nginx 应用之日志管理
2023-09-28
电子书
大厂实战PPT下载
换一换 魏宝辉 | 中国移动 信息技术中心PaaS架构师
陈旭 | 中兴通讯软件研发资深专家 《说透代码》专栏作者
李欣 | eBay 人工智能平台/首席架构师
评论