<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>ha | 伪架构师</title>
    <link>/tags/ha/</link>
      <atom:link href="/tags/ha/index.xml" rel="self" type="application/rss+xml" />
    <description>ha</description>
    <generator>Source Themes Academic (https://sourcethemes.com/academic/)</generator><language>zh</language><lastBuildDate>Wed, 22 Nov 2017 11:19:59 +0800</lastBuildDate>
    <image>
      <url>/img/logo-wide.png</url>
      <title>ha</title>
      <link>/tags/ha/</link>
    </image>
    
    <item>
      <title>搭建高可用 Kubernetes 集群</title>
      <link>/post/ha-kubernetes-cluster/</link>
      <pubDate>Wed, 22 Nov 2017 11:19:59 +0800</pubDate>
      <guid>/post/ha-kubernetes-cluster/</guid>
      <description>

&lt;blockquote&gt;
&lt;p&gt;领导说，只要机器够多，故障是个很平常的事情。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Kubernetes 能很好的管理容器和节点，所以正常的节点故障或者个别应用的故障是不会影响集群运作的。一旦 apiserver 或者所依赖的 etcd 出现问题，情况就不再乐观了。幸好这两个核心服务都提供了高可用相关能力。同时 controller-manager 以及 scheduler 也都具备通过选举产生 leadership 的机制，这就提供了高可用的基础。下面讲讲 Master 组件的高可用部署方式。&lt;/p&gt;

&lt;h2 id=&#34;部署目标&#34;&gt;部署目标&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;每个 apiserver 都使用不同的负载均衡端点访问整个 etcd 集群。&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;每个 controller-manager 和 scheduler 使用各自的 apiserver 进行工作。&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;客户端通过负载均衡机访问 apiserver。&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&#34;images/kubernetes-ha.png&#34; alt=&#34;ha-kubernetes&#34; /&gt;&lt;/p&gt;

&lt;h2 id=&#34;前提条件&#34;&gt;前提条件&lt;/h2&gt;

&lt;p&gt;这里我们假设，ETCD 集群已经成功建立，包含三个节点，采用 https 访问进行访问；Master 节点只有一个。也同样的使用 https 进行访问，集群能够正常工作。&lt;/p&gt;

&lt;p&gt;另外准备若干台服务器安装 haproxy 充当负载均衡。&lt;/p&gt;

&lt;h2 id=&#34;etcd&#34;&gt;ETCD&lt;/h2&gt;

&lt;p&gt;众所周知的是，apiserver 的 &lt;code&gt;--etcd-servers&lt;/code&gt; 参数是可以输入一整个 etcd 集群的，然而在使用中我们发现，一些特定版本的 apiserver 在 第一台 etcd 服务所在节点的特殊故障情况下，虽然 etcd 本身已经能够发现集群健康状态异常，却依然会陷入假死状态，，具体症状是多数 kubectl 的 Workload 相关操作都能完成，然而却不会真正生效。因此我们需要更可靠的对 etcd 集群的访问方式，降低 apiserver 缺陷造成的集群不可用的风险。&lt;/p&gt;

&lt;p&gt;因为采用了 https 方式进行访问，所以这里我们 haproxy 的配置需要使用 tcp 方式。&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;不用 https 端点（也就是对外 https 对内 http 的部署）的方式，纯属个人习惯。
在启用 haproxy 之前，注意要把服务端证书的 IP 进行扩展，令其支持新增的负载均衡地址。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;简单粗暴上代码：&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;...
frontend  in-etcd
    bind *:12379
    mode tcp
    default_backend etcd-cluster

backend etcd-cluster
    mode tcp
    balance     roundrobin
    option httpchk GET /health
    http-check expect string true
    server app1 10.211.55.9:2379 check check-ssl verify none
    server app2 10.211.55.10:2379 check check-ssl verify none
    server app3 10.211.55.11:2379 check check-ssl verify none
...
&lt;/code&gt;&lt;/pre&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;使用负载均衡节点的 12379 端口对外提供服务。&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;前后端均使用 tcp 方式。&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;利用 etcd 节点的 &lt;code&gt;/health&lt;/code&gt; 端点进行健康检查，健康标准是返回字符串 &lt;code&gt;true&lt;/code&gt;。&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;不校验 etcd 服务端证书。&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;启用 haproxy 之后，访问 haproxy 的状态页面，可以看到 etcd 集群的代理已经建立。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;images/etcd.haproxy.png&#34; alt=&#34;etcd-cluster&#34; /&gt;&lt;/p&gt;

&lt;p&gt;任意停止其中一台，会看到在检测窗口过后，对应的服务器状态切换为 &lt;code&gt;DOWN&lt;/code&gt;。&lt;/p&gt;

&lt;p&gt;用同样的方式部署其他两台 haproxy 服务器。&lt;/p&gt;

&lt;h2 id=&#34;master-组件&#34;&gt;Master 组件&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;和 etcd 情况一样，apiserver 的服务证书，也需要更新，加入新的 Master 节点以及前端负载均衡的地址。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;首先更改 apiserver 的 etcd 参数，从原来的三台 etcd 变更为单一的 haproxy 地址，例如 &lt;code&gt;https://haproxy1:12379&lt;/code&gt;。修改之后，重新启动服务，可以看到服务正常启动成功。&lt;/p&gt;

&lt;p&gt;接下来，我们将 apiserver、controller-manager 以及 scheduler 的可执行文件、服务定义、相关证书以及配置文件复制到新加入的服务器中，并启用服务。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;每个 apiserver 需要配置各自的 etcd haproxy。&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;每个 scheduler 和 controller-manager 都访问各自的 apiserver 服务，并使用参数&lt;code&gt;--leader-elect&lt;/code&gt;启用选举（这一参数是缺省启用的）。&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;和 etcd 类似，为 apiserver 配置 haproxy：&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;frontend in-apiserver
    bind *:16443
    mode tcp
    default_backend apiserver-cluster

backend apiserver-cluster
    mode tcp
    balance     roundrobin
    option httpchk GET /healthz
    http-check expect string ok
    server app1 10.211.55.9:6443 check check-ssl verify none
    server app2 10.211.55.10:6443 check check-ssl verify none
    server app3 10.211.55.11:6443 check check-ssl verify none
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;这里我们访问 apiserver 的 &lt;code&gt;/healthz&lt;/code&gt; 端点，如果得到返回内容为 &lt;code&gt;ok&lt;/code&gt;，则判断集群为健康。&lt;/p&gt;

&lt;p&gt;配置后启动 haproxy，查看状态页面，可以看到 apiserver 集群也已经就绪。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;images/apiserver.proxy_.png&#34; alt=&#34;apiserver-cluster&#34; /&gt;&lt;/p&gt;

&lt;p&gt;最后可以修改 kubectl 以及各个 Node 的 kubelet/kube-proxy apiserver 参数到负载均衡地址。&lt;/p&gt;

&lt;h2 id=&#34;测试&#34;&gt;测试&lt;/h2&gt;

&lt;p&gt;停止任意一台 Master 的服务，包括 apiserver/controller-manager/scheduler，会看到 controller-manager 或 scheduler 的选举过程。如果停掉的是 apiserver，则可以在 haproxy 状态页上看到集群可用性的变化。&lt;/p&gt;
</description>
    </item>
    
  </channel>
</rss>
