这篇文章已超过一年。较旧的文章可能包含过时内容。请检查页面中的信息自发布以来是否已失效。

使用 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)
  • Service Account (pgset-sa)
  • Service (pgset, pgset-master, pgset-replica)
  • StatefulSet (pgset)
  • Pods (pgset-0, pgset-1)

此时,Kubernetes 环境中将运行两个 Pod。

$ 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 集群,我们需要其中一个容器扮演主角色,其他容器扮演副本角色。

那么,这些容器如何确定谁是主库,谁是副本呢?

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

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

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

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

步骤 6 - 部署图

示例的结果部署如下图所示:

在此部署中,有一个用于主库的 Service 和一个单独用于副本的 Service。副本已连接到主库,并且状态复制已开始。

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

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

步骤 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

Stateful Set 中的每个容器都绑定到示例脚本中创建的单个 NFS Persistent Volume Claim (pgset-pvc)。

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

容器被设计为在该路径下使用 Pod 的主机名创建一个子目录以确保唯一性。

结论

StatefulSets 是 Kubernetes 为实现集群的容器构建者添加的一项令人兴奋的特性。分配给集合的顺序值提供了一种非常简单的机制,用于在部署 PostgreSQL 集群时做出集群决策。