diff --git a/.vuepress/config.js b/.vuepress/config.js index e232585b..81da2ab8 100644 --- a/.vuepress/config.js +++ b/.vuepress/config.js @@ -273,7 +273,20 @@ export default defineUserConfig({ '/container/storage.md', '/container/resource-limit.md', '/container/auto-scaling.md', - '/container/k8s-deploy.md', + { + text: 'kubernetes 生产级部署', + link:'/container/k8s-deploy.md', + collapsable: false, + sidebarDepth: 1, + children: [ + '/container/k8s-deploy-prepare.md', + '/container/k8s-deploy-etcd.md', + '/container/k8s-deploy-containerd.md', + '/container/k8s-deploy-clilium.md', + + ] + }, + '/container/k8s-upgrade.md', /* { diff --git a/GitOps/summary.md b/GitOps/summary.md index 4304a10d..ff906b9c 100644 --- a/GitOps/summary.md +++ b/GitOps/summary.md @@ -1,8 +1,15 @@ # 第十章 GitOps 落地实践 -GitOps 是 DevOps 文化的一种工程实践,它重新定义了云原生场景下的持续交付模型。GitOps 下的整个运维体系使用声明式描述,并使用 Git 类似的版本控制系统对基础设施、应用配置等进行跟踪管理,系统任何变更在 Git 版本的控制下更加便捷地进行跟踪。 +随着 DevOps 文化的盛行,人们也一直在寻找一种能更好解决云环境中持续部署的最佳实践。 -GitOps 以目标为导向,使用 Git 来维护系统的期望状态,结合 CI/CD 流程中的工具,如 Helm、ArgoCD 等,提高了生产力、安全性和合规性,以及升应用交付的效率和质量保证。 +GitOps 起源于 weaveworks 公司在 2017 年发表的一篇博客:​GitOps - Operations by Pull Request[^1]。在这篇文章中,作者 Alexis Richardson 介绍了一种以 Git 为唯一事实来源的软件部署方式。在这种方式下,我们需要将软件设施定义在 Git 仓库中进行管理,这里的软件设施不限于应用本身,也包括 IaaS、Kubernetes 这样的基础设置。每个工程师都可以通过提交 Pull Request 来修改软件设施,然后通过自动化程序(譬如 Flux CD、Argo CD)的方式在线上执行这些修改。 +这种方式的交付(使用声明式描述、使用 Git 类似的版本控制系统进行跟踪管理、更优雅的可观测性)不仅缩短了构建过程、提高部署速度,更为 + + + + + +[^1]: 参见 https://www.weave.works/blog/gitops-operations-by-pull-request diff --git a/assets/cni-benchmark.webp b/assets/cni-benchmark.webp new file mode 100644 index 00000000..f984e991 Binary files /dev/null and b/assets/cni-benchmark.webp differ diff --git a/assets/kubeadm-ha-topology-external-etcd.svg b/assets/kubeadm-ha-topology-external-etcd.svg new file mode 100644 index 00000000..c229542c --- /dev/null +++ b/assets/kubeadm-ha-topology-external-etcd.svg @@ -0,0 +1,958 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + kubeadm 高可用拓扑 - 外部 etcd + 工作节点 + 负载均衡器 + API 服务器 + API 服务器 + 控制器管理器 + 调度器 + etcd 主机 + 控制平面节点 + 外部 etcd 集群 + 控制平面节点 + 控制平面节点 + etcd 主机 + etcd 主机 + 调度器 + 调度器 + 控制器管理器 + 控制器管理器 + API 服务器 + API 服务器 + 工作节点 + 工作节点 + 工作节点 + 工作节点 + diff --git a/container/container-network.md b/container/container-network.md index ac604b0e..a7eb7b27 100644 --- a/container/container-network.md +++ b/container/container-network.md @@ -2,16 +2,16 @@ 在 Docker、Kubernetes 之前,所有接触过 OpenStack 的人心里都有一个难以释怀的阴影,那就是网络问题。于是,后来者 kubernetes 明智地避开了这个“雷区”,把网络功能从容器运行时或者编排系统剥离出去,让更专业的提供商通过插件的设计实现。如此,把网络变成外部可扩展的功能,需要接入什么样的网络,设计一个对应的网络插件即可。 -这一节,我们走进容器网络通信,去了解容器间通信的设计以及 Kubernetes 集群的网络模型定义。 - -在 Kubernetes 网络中有 3 种 IP,Node IP、Pod IP 和 Service IP,这三者之间的关系如下图所示。 - -当我们部署好一套 Kubernetes 集群后,若想要集群提供正常的服务,先思考以下几个问题: +这一节,我们走进容器网络通信,去了解容器间通信的设计以及 Kubernetes 集群的网络模型定义。如果把 Pod 比作超亲密容器组。由亲密关系的远近,也带来以下几个以距离进行分类的容器通信模型。 - 同一个 Pod 内容器 A 与 容器 B 是如何通信 -- Service 如何与对应的 Pod 通信 - 同一个 Node 中的 Pod 如何通信 -- 不同 Node 之间的 Pod 如何通信 + +**不同 Node 之间的 Pod 如何通信** + +Kubernetes 的网络模型设计的一个基本原则,**每个 pod 都拥有一个独立的 IP 地址,而且假定所有的 Pod 都在一个可以直接联通的、扁平的网络空间中,不管它们是否运行在同一个 Node(宿主机)中,都可以直接通过对方的 IP 进行访问**。 + +
@@ -33,4 +33,20 @@ Kubernetes 本身不实现集群内的网络模型,而是通过将其抽象出 - **三层路由**,主要是借助 BGP 等三层路由协议完成路由传递。这种方案优势是传输率较高,不需要封包、解包, 但 BGP 等协议在很多数据中心内部支持,设置较为麻烦。常见的路由方案网络插件有 Calico(BGP 模式)、Cilium(BGP 模式)。 -[^1]: 参见 https://landscape.cncf.io/guide#runtime--cloud-native-network \ No newline at end of file +此外,对于容器编排系统来说,网络并非孤立的功能模块,还要能提供各类的网络访问策略能力支持,譬如 Kubernetes 的 Network Policy 这种用于描述 Pod 之间访问这类 ACL 策略,明显不属于 CNI 范畴,因此并不是每个 CNI 插件都会支持 NetworkPolicy 声明。如果你有这方面的需求,那么 CNI 插件的选择第一个就要排除 Flannel 了。 + + +CNI 插件性能方面,笔者引用 +Alexis Ducastel 发布的文章 《Benchmark results of Kubernetes network plugins (CNI) over 10Gbit/s network (Updated: August 2020)》的数据[^2]供你参考,此文中测试了不同 CNI 插件(Antrea、Calico、Canal、Cilium、Kube-router、Flannel、WeaveNet)在裸金属服务器之间,从 Pod to Pod、Pod to Service、网络策略以及加密影响等的通信表现。受限于篇幅,笔者给出文章的最后的测试结论,其结果如下图所示。 + +
+ +
+ + +如果你只是一个小型节点集群,且不关心安全性,那么建议使用最轻最稳定的 Flannel。如果是一个标准化的集群,Calico + + + +[^1]: 参见 https://landscape.cncf.io/guide#runtime--cloud-native-network +[^2]: 参见 https://itnext.io/benchmark-results-of-kubernetes-network-plugins-cni-over-10gbit-s-network-updated-august-2020-6e1b757b9e49 \ No newline at end of file diff --git a/container/k8s-deploy-clilium.md b/container/k8s-deploy-clilium.md new file mode 100644 index 00000000..fe2b3d11 --- /dev/null +++ b/container/k8s-deploy-clilium.md @@ -0,0 +1 @@ +# 使用 clilium 配置网络 \ No newline at end of file diff --git a/container/k8s-deploy-containerd.md b/container/k8s-deploy-containerd.md new file mode 100644 index 00000000..c3180076 --- /dev/null +++ b/container/k8s-deploy-containerd.md @@ -0,0 +1,3 @@ +# 配置容器运行时 containerd + + diff --git a/container/k8s-deploy-etcd.md b/container/k8s-deploy-etcd.md new file mode 100644 index 00000000..d951f6a0 --- /dev/null +++ b/container/k8s-deploy-etcd.md @@ -0,0 +1,23 @@ +# 高可用 etcd 集群 + + +etcd 是 Kubernetes 的核心存储,Kubernetes 所有的资源对象都保存在 etcd etcd 是否健壮将直接影响 Kubernetes 服务。 + +etcd 使用 Raft 协议,因 raft 选举或者可用性要求,一般部署节点的个数奇数且数量大于 3 个,注意,笔者用的是“一般”,**raft 并不严格限定到底是奇数还是偶数,只要 (n-1)/2 以上的节点正常,集群就能正常工作**。譬如配置 4 个节点,其中 1 个节点宕机了,但还有 (n-1)/2 个节点正常,对 etcd 而言不论是选举还是可用性,都不会产生影响。 + +etcd 的性能极限受两个部分影响:单机性能的影响以及网络的开销。etcd 默认是线性一致性(最强一致性),每次操作所有的节点都要参与,节点越多性能越低,所以增加再多的节点意义不是很大。官方推荐 etcd 节点个数 3、5、7。 + +笔者使用多个可用区的方式部署 etcd,假设的是云商**某个可用区产生重大故障,短时间内无法恢复**。注意这个并不是防止脑裂,官方给到的解释也是 etcd 没有脑裂。 + +:::tip etcd 没有脑裂 +The majority side becomes the available cluster and the minority side is unavailable; there is no “split-brain” in etcd. +::: + +但有一种特殊情况,假如旧的 Leader 和集群其他节点出现了网络分区,其他节点选出了新的 Leader,但是旧 Leader 并没有感知到新的 Leader,那么此时集群可能会出现一个短暂的“双 Leader”状态,但这个并不是脑裂,原因是 raft 有恢复机制,这个状态并不会持续很长,其次 etcd 也有 ReadIndex、Lease read 机制解决这种状态下的一致性问题。 + + +
+ +
+ +[^1]: 参见 https://etcd.io/docs/v3.5/op-guide/failures/ \ No newline at end of file diff --git a/container/k8s-deploy-prepare.md b/container/k8s-deploy-prepare.md new file mode 100644 index 00000000..d52ba1cc --- /dev/null +++ b/container/k8s-deploy-prepare.md @@ -0,0 +1,2 @@ +# 初始化准备 + diff --git a/container/k8s-deploy.md b/container/k8s-deploy.md index 55de930c..ce14d60a 100644 --- a/container/k8s-deploy.md +++ b/container/k8s-deploy.md @@ -1,32 +1,13 @@ # 生产级 Kubernetes 部署实践 +
+ +
+ + ## API Server 高可用负载均衡 在 Kubernetes 集群中,apiserver 是整个集群的入口,任何用户或者程序对集群资源的增删改查操作都需要经过 kube-apiserver,因此它的高可用性决定了整个集群的高可用能力。 kube-apiserver 本质上是一个无状态的服务器,为了实现其高可用,通常会部署多个 kube-apiserver 实例,同时引入外部负载均衡器(以下简称 LB)进行流量代理。后续用户(kubectl 、dashbaord 等其他客户端)和集群内部的组件都将通过访问 LB 来访问 apiserver 。 - - -## etcd 高可用集群 - -etcd 是 Kubernetes 的核心存储,Kubernetes 所有的资源对象都保存在 etcd etcd 是否健壮将直接影响 Kubernetes 服务。 - -etcd 使用 Raft 协议,因 raft 选举或者可用性要求,一般部署节点的个数奇数且数量大于 3 个,注意,笔者用的是“一般”,**raft 并不严格限定到底是奇数还是偶数,只要 (n-1)/2 以上的节点正常,集群就能正常工作**。譬如配置 4 个节点,其中 1 个节点宕机了,但还有 (n-1)/2 个节点正常,对 etcd 而言不论是选举还是可用性,都不会产生影响。 - -etcd 的性能极限受两个部分影响:单机性能的影响以及网络的开销。etcd 默认是线性一致性(最强一致性),每次操作所有的节点都要参与,节点越多性能越低,所以增加再多的节点意义不是很大。官方推荐 etcd 节点个数 3、5、7。 - -笔者使用多个可用区的方式部署 etcd,假设的是云商**某个可用区产生重大故障,短时间内无法恢复**。注意这个并不是防止脑裂,官方给到的解释也是 etcd 没有脑裂。 - -:::tip etcd 没有脑裂 -The majority side becomes the available cluster and the minority side is unavailable; there is no “split-brain” in etcd. -::: - -但有一种特殊情况,假如旧的 Leader 和集群其他节点出现了网络分区,其他节点选出了新的 Leader,但是旧 Leader 并没有感知到新的 Leader,那么此时集群可能会出现一个短暂的“双 Leader”状态,但这个并不是脑裂,原因是 raft 有恢复机制,这个状态并不会持续很长,其次 etcd 也有 ReadIndex、Lease read 机制解决这种状态下的一致性问题。 - - -
- -
- -[^1]: 参见 https://etcd.io/docs/v3.5/op-guide/failures/ \ No newline at end of file diff --git a/distributed-transaction/CAP.md b/distributed-transaction/CAP.md index 3fcec13e..b9feb5ce 100644 --- a/distributed-transaction/CAP.md +++ b/distributed-transaction/CAP.md @@ -32,7 +32,6 @@ weaker the guarantees that can be made about the third. 不管是 CAP 定理还是弱 CAP 原则,都在说明可用性和一致性之间是对立的,需要在他们之间做出权衡。CAP 定理对 C 和 A 的定义非常严苛,只能衡量很少一部分系统,而弱 CAP 原则则给出了一种更普适的权衡。 - 由于 CAP 定理已有严格的证明,本节不去探讨为何 CAP 不可兼得,而是直接分析如果舍弃 C、A、P 时所带来的不同影响。 - **放弃分区容忍性(CA without P)**:意味着我们将假设节点之间通信永远是可靠(注意,笔者开篇的分布式八大缪误),永远可靠的通信在分布式系统中必定不成立,只要用到网络来共享数据,分区现象就会始终存在。没有 P,也谈不上是什么分布式系统。