本文发布时间已超过一年。较旧的文章可能包含过时的内容。请检查页面中的信息自发布以来是否已变得不正确。

使用 StatefulSets 部署 PostgreSQL 集群

编者按:今天的客座文章由 Crunchy Data 的开发人员 Jeff McCormick 撰写,介绍了如何使用新的 Kubernetes StatefulSet 功能构建 PostgreSQL 集群。

在之前的文章中,我介绍了如何使用 Kubernetes 包管理器 Helm 部署 PostgreSQL 集群。以下示例提供了使用新的 Kubernetes StatefulSets 功能构建 PostgreSQL 集群的步骤。

StatefulSets 示例

步骤 1 - 创建 Kubernetes 环境

StatefulSets 是在 Kubernetes 1.5 中实现的新功能(在早期版本中被称为 PetSets)。因此,运行此示例需要一个基于 Kubernetes 1.5.0 或更高版本的环境。

此博客中的示例使用 kubeadm 在 Centos7 上部署。关于 kubeadm 提供的内容以及如何部署 Kubernetes 集群的一些说明,请参见 此处

步骤 2 - 安装 NFS

此博客中的示例使用 NFS 作为持久卷,但任何共享文件系统也可以工作(例如:ceph、gluster)。

该示例脚本假设您的 NFS 服务器在本地运行,并且您的主机名解析为已知的 IP 地址。

总之,在 Centos 7 主机上使 NFS 工作的步骤如下

sudo setsebool -P virt\_use\_nfs 1

sudo yum -y install nfs-utils libnfsidmap

sudo systemctl enable rpcbind nfs-server

sudo systemctl start rpcbind nfs-server rpc-statd nfs-idmapd

sudo mkdir /nfsfileshare

sudo chmod 777 /nfsfileshare/

sudo vi /etc/exports

sudo exportfs -r

/etc/exports 文件应包含类似这样的行,但指定了适用的 IP 地址

/nfsfileshare 192.168.122.9(rw,sync)

完成这些步骤后,NFS 应在测试环境中运行。

步骤 3 - 克隆 Crunchy PostgreSQL 容器套件

此博客中使用的示例位于 Crunchy Containers GitHub 存储库 此处。将 Crunchy Containers 存储库克隆到您的测试 Kubernetes 主机,然后转到该示例

cd $HOME

git clone https://github.com/CrunchyData/crunchy-containers.git

cd crunchy-containers/examples/kube/statefulset

接下来,拉取 Crunchy PostgreSQL 容器映像

docker pull crunchydata/crunchy-postgres:centos7-9.5-1.2.6

步骤 4 - 运行示例

首先,有必要设置示例中使用的一些环境变量

export BUILDBASE=$HOME/crunchy-containers

export CCP\_IMAGE\_TAG=centos7-9.5-1.2.6

BUILDBASE 是您克隆存储库的位置,而 CCP_IMAGE_TAG 是我们要使用的容器映像版本。

接下来,运行示例

./run.sh

该脚本将创建多个 Kubernetes 对象,包括

  • 持久卷(pv1、pv2、pv3)
  • 持久卷声明(pgset-pvc)
  • 服务帐户(pgset-sa)
  • 服务(pgset、pgset-master、pgset-replica)
  • StatefulSet (pgset)
  • Pod(pgset-0、pgset-1)

此时,两个 pod 将在 Kubernetes 环境中运行

$ kubectl get pod

NAME      READY     STATUS    RESTARTS   AGE

pgset-0   1/1       Running   0          2m

pgset-1   1/1       Running   1          2m

创建 pod 后,部署将如下图所示

步骤 5 - 发生了什么?

此示例将部署一个 StatefulSet,它反过来创建两个 pod。

这两个 pod 中的容器运行 PostgreSQL 数据库。对于 PostgreSQL 集群,我们需要一个容器承担主角色,而其他容器承担副本角色。

那么,容器如何确定谁将成为主服务器,谁将成为副本?

这就是新的 StateSet 机制发挥作用的地方。StateSet 机制为集合中的每个 pod 分配唯一的序号值。

StatefulSets 提供的唯一序号值始终从 0 开始。在容器初始化期间,每个容器都会检查其分配的序号值。序号值为 0 会导致容器在 PostgreSQL 集群中承担主角色。对于所有其他序号值,容器承担副本角色。这是一种非常简单的发现形式,通过 StatefulSet 机制实现。

PostgreSQL 副本被配置为通过专门用于主数据库的服务连接到主数据库。为了支持此复制,该示例为每个主角色和副本角色创建一个单独的服务。一旦副本连接成功,副本将开始从主服务器复制状态。

在容器初始化期间,主容器将使用服务帐户(pgset-sa)更改其容器标签值,以匹配主服务选择器。更改标签对于使发送到主数据库的流量到达 Stateful Set 中的正确容器至关重要。集合中的所有其他 pod 默认承担副本服务标签。

步骤 6 - 部署图

该示例将产生如下图所示的部署

在此部署中,主服务器有一个服务,副本有一个单独的服务。副本已连接到主服务器,并且状态复制已开始。

Crunchy PostgreSQL 容器支持其他形式的集群部署,部署样式由为容器设置 PG_MODE 环境变量来决定。对于 StatefulSet 部署,该值设置为:PG_MODE=set

此环境变量提示容器初始化逻辑我们打算采用的部署样式。

步骤 7 - 测试示例

以下测试假设 psql 客户端已安装在测试系统上。如果未安装,则可以按如下方式安装 psql 客户端

sudo yum -y install postgresql

此外,以下测试假设被测环境 DNS 解析为 Kube DNS,并且被测环境 DNS 搜索路径被指定为与适用的 Kube 命名空间和域匹配。主服务名为 pgset-master,副本服务名为 pgset-replica。

按如下方式测试主服务器(密码为 password)

psql -h pgset-master -U postgres postgres -c 'table pg\_stat\_replication'

如果一切正常,上述命令将返回输出,指示单个副本正在连接到主服务器。

接下来,按如下方式测试副本

psql -h pgset-replica -U postgres postgres  -c 'create table foo (id int)'

上面的命令应该失败,因为副本在 PostgreSQL 集群中是只读的。

接下来,按如下方式扩展集合

kubectl scale statefulset pgset --replicas=3

上面的命令应该成功创建一个名为 pgset-2 的新副本 pod,如下图所示

步骤 8 - 持久化说明

查看结果 NFS 挂载路径上持久化的 PostgreSQL 数据文件

$ ls -l /nfsfileshare/

total 12

drwx------ 20   26   26 4096 Jan 17 16:35 pgset-0

drwx------ 20   26   26 4096 Jan 17 16:35 pgset-1

drwx------ 20   26   26 4096 Jan 17 16:48 pgset-2

状态集中的每个容器都绑定到示例脚本中创建的单个 NFS 持久卷声明 (pgset-pvc)。

由于可以共享 NFS 和 PVC,因此每个 pod 都可以写入此 NFS 路径。

该容器被设计为使用 pod 主机名在该路径上创建唯一性的子目录。

结论

StatefulSets 是 Kubernetes 为正在实现集群的容器构建者添加的一个令人兴奋的功能。分配给集合的序号值提供了一种非常简单的机制,可以在部署 PostgreSQL 集群时做出集群决策。