如何在Kubernetes中部署一个高可用的PostgreSQL集群环境

徐春雨 3年前
   <p style="text-align: center;"><img src="https://simg.open-open.com/show/6e6af28037a3ac23c12f9bc67ee5c6c2.png"></p>    <p>创建一个高可用的PostgreSQL集群环境总是一件棘手的事情。在云环境里部署时更是非常困难。我至少找到了3个项目,它们可以在Kubernetes里提供高可用的PostgreSQL解决方案。</p>    <h3><a href="/misc/goto?guid=4959741140271890857" rel="nofollow,noindex">Patroni</a></h3>    <p>Patroni是一个模板,它使用Python为你提供一个自己订制的,高可用的解决方案,为最大程度的可用性,它的配置信息存储在像ZooKeeper, etcd或者Consul中。如果DBAs,DevOps工程师或者SRE正在寻找一个在数据中心中快速部署高可用PostgreSQL方案,或者其他的用途,我希望Patroni能够帮到他们。</p>    <h3><a href="/misc/goto?guid=4959741140356250465" rel="nofollow,noindex">Crunchy</a></h3>    <p>Crunchy容器套件提供一个了Docker容器,它能快速部署PostgreSQL,同时也提供管理和监控的工具。并且支持多种用风格的部署PostgreSQL集群。</p>    <h3><a href="/misc/goto?guid=4959741140426408497" rel="nofollow,noindex">Stolon</a></h3>    <p>Stolon是一个cloud native的PostgreSQL高可用管理工具。它之所以是cloud native的是因为它可以在为容器内部的PostgreSQL提供高可用(kubernetes 集成),而且还支持其他种类的基础设施(比如:cloud Iaas,旧风格的基础设施等)</p>    <p>漂亮的图表 加上一些在kubernets.io上的用户分享 <a href="/misc/goto?guid=4959741140516849919" rel="nofollow,noindex">1</a> <a href="/misc/goto?guid=4959741140586175028" rel="nofollow,noindex">2</a> 说服我去试一下crunchy容器。但是过了一段时间,我改变了想法。</p>    <p>我不想说他设计上的某些缺点或者是其他的什么不好。但是它给我的感觉就好像是我自己在容器里手动安装PostgreSQL一样,并没有云的感觉。</p>    <p>所以我尝试了一下stolon。在一次又一次的安装和卸载之后,我运行了它的statefulset的 例子 并且用 helm chart 创建。</p>    <p>下面我将展示一下安装过程并且演示一下集群环境下的failover。我们假设安装用的是helm chart。</p>    <h2>Stolon 架构图(摘抄自stolon的介绍)</h2>    <p style="text-align: center;"><img src="https://simg.open-open.com/show/b963d3bce19b9c339cfd845343e30fa3.png"></p>    <p>Stolon 是由3个部分组成的:</p>    <ul>     <li>keeper:他负责管理PostgreSQL的实例汇聚到由sentinel(s)提供的clusterview。</li>     <li>sentinel:it负责发现并且监控keeper,并且计算最理想的clusterview。</li>     <li>proxy:客户端的接入点。它强制连接到右边PostgreSQL的master并且强制关闭连接到由非选举产生的master。</li>    </ul>    <p>Stolon 用etcd或者consul作为主要的集群状态存储。</p>    <h2>Installation</h2>    <pre>  $ git clone https://github.com/lwolf/stolon-chart    $ cd stolon-chart    $ helm install ./stolon  </pre>    <h2>You can also install directly from my repository</h2>    <p>helm repo add lwolf-charts http://charts.lwolf.org</p>    <p>helm install lwolf-charts/stolon</p>    <p>安装的过程将会做如下的动作:</p>    <p>首先,会用statefulset创建3个etcd节点。Stolon-proxy和stolon-sentinel也会被部署。Singe time job将集群的安装暂停直到etcd节点状态变成availabe。</p>    <p>chart还会创建两个服务</p>    <ul>     <li><strong>stolon-proxy</strong> —服务来源于官方的例子。他总是指向当前的因该被写入的master。</li>     <li><strong>stolon-keeper</strong> —Stolon自己本身不提供任何读取操作的负载均衡。但是kubernetes的service却可以做到这点。所以对于用户来说,stolon-keeper的读操作是在pod的层面做到负载均衡的。</li>    </ul>    <p>当所有的组件状态变为RUNNING时,我们可以试着连接它们。</p>    <p>我们可以用NodePort这种简单的连接方式部署service。用两个终端分别去连接master service和slave service。在post的过程中,我们假设stolon-proxy服务(RW)已经暴露了30543端口,stolon-keeper服务(RO)已经暴露了30544端口。</p>    <p>连接master并且建立test表</p>    <pre>  psql --host <IP> --port 30543 postgres -U stolon -W    postgres=# create table test (id int primary key not null,    value text not null);    CREATE TABLE    postgres=# insert into test values (1, 'value1');    INSERT 0 1    postgres=# select * from test;    id | value    ---- --------    1 | value1    (1 row)  </pre>    <h2>连接slave并且检查数据。你可以写一些信息以便确认请求已经被slave处理了。</h2>    <p>psql --host <IP> --port 30544 postgres -U stolon -W</p>    <p>postgres=# select * from test;</p>    <p>id | value</p>    <p>---- --------</p>    <p>1 | value1</p>    <p>(1 row)</p>    <p>在测试通过后,我们去试试failover功能。</p>    <h2>测试failover</h2>    <p>这个案例是官方代码库中statefullset的一个 例子 。简单的说,就是为模拟了master挂掉,我们先删除了master的statefulset又删除了master的pod。</p>    <pre>  kubectl delete statefulset stolon-keeper --cascade=false    kubectl delete pod stolon-keeper-0  </pre>    <p>然后,在sentinel的log中我们可以看到新的master被选举出来了。</p>    <pre>  no keeper info available db=cb96f42d keeper=keeper0    no keeper info available db=cb96f42d keeper=keeper0    master db is failed db=cb96f42d keeper=keeper0    trying to find a standby to replace failed master    electing db as the new master db=087ce88a keeper=keeper1  </pre>    <p>现在,在刚才的那两个终端中如果我们重复上一个命令,我们可以看到如下输出。</p>    <pre>  postgres=# select * from test;    server closed the connection unexpectedly    This probably means the server terminated abnormally    before or while processing the request.    The connection to the server was lost. Attempting reset:    Succeeded.    postgres=# select * from test;    id | value    ---- --------    1 | value1    (1 row)  </pre>    <p>Kubernetes的service把不可用的pod去掉,把请求转到可用的pod上。所以,新的读取连接被路由到了健康的pod上。</p>    <p>最后,我们需要重新创建statefulset。最简单的方法就是更新部署了的helm chart。</p>    <pre>  helm ls    NAME REVISION UPDATED    STATUS CHART NAMESPACE    factual-crocodile 1 Sat Feb 18 15:42:50 2017    DEPLOYED stolon-0.1.0 default    helm upgrade factual-crocodile .  </pre>    <h2>2.用chaoskube模拟随机的pod挂掉</h2>    <p>另一个测试集群弹性(resilience)的好方法是用 chaoskube 。Chaoskube是一个小的服务程序,它可以周期性的在集群里随机的kill掉一些的pod。它也可以用helm charts部署。</p>    <pre>  helm install --set labels="release=factualcrocodile,    component!=factual-crocodine-etcd" --set    interval=5m stable/chaoskube  </pre>    <p>这条命令会运行chaoskube,它会每5分钟删除一个pod。它会选择label中 release=factual-crocodile 的pod,但是会忽略etcd的pod。</p>    <p>在做了几个小时的测试之后,我的集群环境仍然是一致并且工作的很稳定。</p>    <h2>结论</h2>    <p>我仍然在我的开发服务器上运行stolon。到目前为止我还是满意的。他真的很想一个本地的运环境。有很好的弹性和自动化的failover能力。</p>    <p> </p>    <p> </p>    <p>来自:http://dockone.io/article/2143</p>    <p> </p>