构建高可用 kubernete 集群

原文:https://kubernetes.io/docs/admin/high-availability/building/

简介

本文介绍了如何构建一个高可用(high-availability, HA)的 Kubernetes 集群。这是一个相当高级的话题。我们鼓励只想尝试性使用 Kubernetes 的用户使用更简单的配置,例如 Minikube,或者尝试 Google Kubernetes Engine 提供的托管 Kubernetes 集群。

此外,目前我们并没有在端到端(e2e)测试中对 Kubernetes 的高可用性支持进行连续测试。我们正在努力添加这个持续测试项,但现在对单节点 master 安装方式测试得更加严格。

  • TOC
    {:toc}

概述

建立一个真正可靠的、高可用的分布式系统需要多个步骤。它类似于穿着内裤、裤子、腰带、吊带、另一条内裤和另一条裤子。我们将对每个步骤进行详细介绍,但是这里给出一个总结,用于帮助指导和引导用户。

涉及的步骤如下:

这是系统完成时应该看起来的样子:


高可用 Kubernetes 示意图

初始设置

本指南的其余部分假设您正在设置一个 3 节点的集群 master,其中的每台机器上都运行着某种 Linux。本指南中的例子针对 Debian 发行版,但他们应该很容易的用于其他发行版上。
同样的,无论是在公有/私有云服务提供商上,还是在裸金属上运行集群,这些设置都应该可以工作。

实现高可用 Kubernetes 集群最简单的方法是从一个现有的单 master 集群开始。https://get.k8s.io 处的说明描述了在各种平台上安装单 master 集群的简单方法。

可靠的节点

在每个 master 节点上,我们都将运行一些实现 Kubernetes API 的进程。为了使这些进程可靠,第一步是保证在它们故障之后能够自动重启。为了实现这一点,我们需要安装一个进程监视器。我们选择使用每个工作节点上都会运行的 kubelet。这很方便,因为我们可以使用容器来分发我们的二进制文件、建立资源限额并审视每个守护进程的资源使用情况。当然,我们也需要一些机制来监控 kubelet 本身(在此插入一个"谁在监视监视者"的笑话)。对于 Debian 系统,我们选择 monit,但也存在一些替代的选择。例如,在基于 systemd 的系统(例如 RHEL,CentOS)上,您可以运行 'systemctl enable kubelet'。

如果您是从标准 Kubernetes 安装扩展而来,那么 kubelet 二进制文件应该已经存在于您的系统之中。您可以运行 which kubelet 来确定此文件是否已经安装。如果没有,您应该安装 kubelet 二进制文件kubelet 初始化文件default-kubelet 脚本。

如果您正在使用 monit,您还应该安装 monit 守护进程(apt-get install monit)和 monit-kubelet 以及 monit-docker 配置。

在 systemd 系统中,您应该执行 systemctl enable kubeletsystemctl enable docker

建立一个冗余的,可靠的数据存储层

高可用性解决方案的核心基础是冗余,可靠的存储层。高可用性的头号规则是保护数据。无论发生什么事情,如果你有数据,你还可以重建。如果失去了数据,你就完了。

集群化的 etcd 已将您的存储复制到了集群中的所有 master 实例上。这意味着要丢失数据,需要让全部三个节点的物理(或虚拟)磁盘同时失效。发生这种情况的可能性相对较低。所以对很多人来说,运行复制的 etcd 集群可能已经足够可靠了。如果仍然不够,您还可以添加 更多的冗余存储层

集群化的 etcd

建立 etcd 集群的完整细节超出了本文的范围,etcd 集群页面 给出了大量的细节。本示例演练了一个简单集群的设置,使用 etcd 内置的发现机制来构建我们的集群。

首先,访问 etcd discovery 服务来创建一个新的令牌:

curl https://discovery.etcd.io/new?size=3

在每个节点上,将 etcd.yaml 文件复制到 /etc/kubernetes/manifests/etcd.yaml

每个节点上的 kubelet 会主动监视该目录的内容,并会按照 etcd.yaml 中对 pod 的定义创建一个 etcd 服务实例。

请注意,您应该将所有机中上 etcd.yaml 中的 ${DISCOVERY_TOKEN} 替换为上面获得的令牌 URL,并将 ${NODE_NAME} 替换为一个不同的名称(例如 node-1),以及将 ${NODE_IP} 替换为每个机器的正确 IP 地址。

验证您的集群

一旦将其复制到所有三个节点中,您应该建立起了一个集群化的 etcd。您可以在 master 上这样验证:

kubectl exec < pod_name > etcdctl member list

以及:

kubectl exec < pod_name > etcdctl cluster-health

您还可以通过在一个节点上运行 etcdctl set foo bar 并在另一个节点上运行 etcdctl get foo 来验证其是否工作正常。

更可靠的存储

当然,如果您对提高数据可靠性感兴趣,还有其他选项可以让您找到比在普通磁盘上安装 etcd 数据更可靠的位置(皮带吊带,ftw!)。

如果您使用云服务提供商,那么他们通常会提供此服务,例如 Google Cloud Platform 上的 Persistent Disk。这是一种可以挂载到虚拟机上的块设备持久性存储。其他云服务提供商也提供了类似的解决方案。

如果您在物理机器上运行,则可以使用通过网络连接的 iSCSI 或 NFS 接口的冗余存储。或者,您可以运行 Gluster 或 Ceph 等集群文件系统。最后,您还可以在每台物理机器上运行 RAID 阵列。

无论您选择如何实现,如果您选择使用这些选项之一,则应确保您的存储已挂载到每台机器上。如果您的存储在集群中的三个 master 之间共享,则应该在存储上为每个节点创建一个不同的目录。在所有的介绍中,我们都将假设这个存储被挂载到您机器中的 /var/etcd/data 目录。

复制的 API Server

一旦正确的设置好了复制的 etcd 集群,我们将使用 kubelet 安装 apiserver。

安装配置文件

首先,您需要创建初始日志文件,以便 Docker 挂载一个文件而不是目录:

touch /var/log/kube-apiserver.log

接下来,您在每个节点上创建一个 /srv/kubernetes/ 目录。这个目录包含:

  • basic_auth.csv - basic auth 用户名和密码
  • ca.crt - 证书颁发机构证书(Certificate Authority cert)
  • known_tokens.csv - 实体(例如 kubelet) 用于同 apiserver 通信的令牌
  • kubecfg.crt - 客户端证书,公钥
  • kubecfg.key - 客户端证书,私钥
  • server.cert - 服务器证书,公钥
  • server.key - 服务器证书,私钥

创建此目录的最简单方法可能是从一个工作集群的 master 节点复制它们,或者您可以自己手动生成这些文件。

启动 API Server

一旦创建了这些文件,请将 kube-apiserver.yaml 复制到每个 master 节点的 /etc/kubernetes/manifests/ 目录下。

kubelet 监视这个目录,并且会使用文件中指定的 pod 定义自动创建一个 kube-apiserver 的容器实例。

负载均衡

此时,您应该有 3 个全部正常工作的 apiserver。如果您设置了一个网络负载均衡器,你就可以通过它访问您的集群,并平衡各个 apiserver 实例的流量。负载均衡器的配置取决于您的平台的具体情况,例如,Google Cloud Platform 的相关说明可以在 这里 找到。

请注意,如果您启用了身份验证,可能需要重新生成证书,在每个独立节点的 IP 地址外,还应包含负载均衡器的IP地址。

对于部署到集群中的 pod 来说,kubernetes service/dns 名称自动的提供了一个 master 的负载均衡 endpoint。

对于 API 的外部用户(例如 kubectl 命令行接口、持续构建管道或其它客户端),您应该配置它们使用外部负载均衡器 IP 地址同 API 进行通信。

Endpoint reconciler

如前一节所述,apiserver 通过一个名为 kubernetes 的 service 进行公开。这个 service 的 endpoint 对应于我们刚刚部署的 apiserver 集群。

由于更新 endpoint 和 service 需要 apiserver 启动,apiserver 中有特殊的代码可以使其直接更新自己的 endpoint。这个代码被称为“reconciler(协调器)”,因为它会对存储在 etcd 中及正在运行的 endpoint 列表进行协调。

在 Kubernetes 1.9 版本之前,reconciler 希望您通过一个命令行参数(例如 --apiserver-count=3)提供 endpoint 的数量(意即 apiserver 的副本数)。如果有更多可用的副本,reconciler 将对 endpoint 列表进行截取。因此,如果一个运行 apiserver 副本的节点宕机并被替换,endpoint 列表将最终被更新。然而,在副本被替换前,它的 endpoint 都将留存在列表中。在此期间,一小部分发送到 kubernetes service 的 API 请求将会失败,因为它们会被发送到一个未运行的 endpoint。

这就是上一节建议您部署负载均衡器并通过它访问 API 的原因。这个 负载均衡器将直接评估 apiserver 的健康状态,确保请求不会发送到崩溃的示例。

如果您不添加 --apiserver-count 参数,其值将默认为 1。您的集群将会正常工作,但每个 apiserver 副本都会持续尝试在删除其它 endpoint 时将自己添加到列表中,这将在 kube-proxy 和其他组件中产生大量无用的更新。

从 Kubernetes 1.9 版本开始,有了一个新的 reconciler 实现。它使用了一个被每个 apiserver 副本定期更新的租约。当副本宕机时,它会停止更新自己的租约,其他副本注意到这个租约过期并从 endpoint 列表中将其删除。您可以在启动 apiserver 副本时,通过添加 --endpoint-reconciler-type=lease 参数来切换到新的 reconciler。

如果您希望了解更多信息,可以查看以下资源:

主选举的组件

到目前为止,我们已经建立起了状态存储,并且已经建立了 API server,但我们还没有运行任何实际修改集群状态的内容,例如 controller manager 和 scheduler。为了可靠的实现这一点,我们每次只希望一个 actor 修改状态,但是我们希望复制这些 actor 实例,以防止有机器宕机。为了达到这个目的,我们将在 API 中使用一个租约锁来执行主选举(master election)。我们将对每个 scheduler 和 controller manager 使用 --leader-elect 参数,以在 API 中使用租约来确保同一时间只有一个 scheduler 和 controller-manager 实例运行。

scheduler 和 controller-manager 可以配置为和相同节点(意即 127.0.0.1)上的 API server 进行通信,或者也可以配置为使用 API server 的负载均衡器地址。不管如何配置它们,当使用 --leader-elect 参数时,scheduler 和 controller-manager 都将完成上文提到的主选举过程。

当无法访问 API server 时,选举的 leader 无法更新其租约,这将导致选举产生新的 leader。在 scheduler 和 controller-manager 通过 127.0.0.1 访问 API server 并且相同节点上的 API server 宕机时,这一点显得尤为重要。

安装配置文件

首先,在每个节点上创建空的日志文件,这样 Docker 将挂载一个文件而不是创建新目录:

touch /var/log/kube-scheduler.log
touch /var/log/kube-controller-manager.log

接下来,通过复制 kube-scheduler.yamlkube-controller-manager.yaml/etc/kubernetes/manifests/ 目录来建立每个节点的 scheduler 和 controller manager 的 pod 的配置描述文件。

结论

目前,您已经完成了 master 组件的配置(耶!),但您仍然需要添加工作节点(噗!)。

如果您有一个存在的集群,这就很简单,只需要重新配置 kubelet 与负载均衡器的 endpoint 通信,并重启每个节点上的 kubelet。

如果您建立的是一个新集群,您将需要在每个工作节点上安装 kubelet 和 kube-proxy,并且将 --apiserver 参数设置为您的复制的 endpoint。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容

  • 安装k8s Master高可用集群 主机 角色 组件 172.18.6.101 K8S Master Kubele...
    jony456123阅读 8,040评论 0 9
  • Kubernetes部属说明 环境准备 资料准备 开始部属 编写yaml文件,用于部属Kubenetes基础容器e...
    俊逸之光阅读 2,599评论 2 0
  • docker实现了更便捷的单机容器虚拟化的管理, docker的位置处于操作系统层与应用层之间; 相对传统虚拟化(...
    Harvey_L阅读 19,888评论 3 44
  • 文‖云飞扬 风,向你吹来的时候 白杨林收藏那抹飘逝的倩影 你已筋疲力尽 在清冷里翻山越岭 凌乱过谁的发丝 守候着谁...
    山东云飞扬阅读 212评论 0 0
  • 不一样的卡梅拉1我想去看海张富林,讲的是一个小鸡叫卡梅拉,那时正好是下蛋时期,他不想下蛋就说下蛋下蛋总是下蛋还有比...
    寂寞的时光者阅读 135评论 0 0