本文发表于一年多前。旧文章可能包含过时内容。请检查页面中的信息自发布以来是否已变得不正确。
使用 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)
此时,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 副本配置为通过专用于主数据库的服务连接到主数据库。为了支持这种复制,示例为主角色和副本角色分别创建了一个单独的服务。一旦副本连接成功,副本将开始从主数据库复制状态。
在容器初始化期间,主容器将使用 服务帐户 (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
StatefulSet 中的每个容器都绑定到示例脚本中创建的单个 NFS 持久卷声明 (pgset-pvc)。
由于 NFS 和 PVC 可以共享,因此每个 Pod 都可以写入此 NFS 路径。
容器被设计为在该路径上使用 Pod 主机名创建子目录以实现唯一性。
结论
StatefulSets 是 Kubernetes 为正在实现集群的容器构建者添加的一个激动人心的功能。为集合分配的序号值提供了一种非常简单的机制,用于在部署 PostgreSQL 集群时做出集群决策。