审校 | 重楼
关于Kubernetes中数据库应该在哪里运行的争论一直是技术界的热门话题。流行的观点是“构建无状态应用程序”,这表明数据库最适合使用云提供商的托管服务。然而,在Kubernetes中成功地运行数据库有一些实用的设计模式。
在大多数云提供商中,卷被限制在单个可用区,这意味着数据库在设计上也被限制在这个可用区。大多数生产集群可能是区域性或多可用区,对于无状态应用程序而言更是如此。使用节点选择器确保数据库pod位于可用区(它们的卷可以挂载)很重要。
例子:
nodeSelector:
topology.kubernetes.io/zone: europe-west6-b
该配置指定数据库pod应该在' europe-west6-b ' 可用区中运行。
规划资源使用情况
由于我们的数据库被限制在一个可用区中,我们必须仔细规划节点到可用区的设计,以避免调度错误和不可用问题。一种有效的策略是针对数据库工作负载运行单独的节点组或节点池。这可以确保所需的可用区始终有足够的资源可用。
例子:
- 为数据库工作负载创建专用节点池。
- 使用污点和容差来确保在这些节点上只调度数据库pod。
# Taint nodes to be dedicated to databases
spec:
taints:
- key: "dedicated"
value: "database"
effect: "NoSchedule"
# Toleration in the DB pod spec
spec:
tolerations:
- key: "dedicated"
operator: "Equal"
value: "database"
effect: "NoSchedule"
高可用性
托管数据库服务通常提供内置的高可用性和故障切换功能。为了在Kubernetes中实现类似的弹性,对恢复和可用性策略进行细致的规划必不可少。这里有两种方法:
1.使用Kubernetes操作符
Zalando Postgres Operator这样的Kubernetes操作符提供了高级功能,比如读取副本和自动故障切换,类似托管数据库服务。这些操作符可以显著简化数据库高可用性的设置和管理。
Zalando Postgres Operator允许你指定读取副本的数量,并自动管理故障切换。该操作符提供了一个UI,你可以在其中配置这些设置,使其成为Kubernetes中管理数据库高可用性的一种直观而强大的工具。下面列出了其他一些操作符,其中一些由各自的社区管理:https://operatorhub.io/?category=Database。
2.自助服务方法
对于那些喜欢动手操作的人而言,特别是针对NoSQL数据库,这里有一个循序渐进的方法:
- 两个pod上挂载数据卷:确保数据卷被主pod和从pod都可以访问。
- pod亲缘性:使用pod亲缘性规则来确保主pod和从pod放在一起,同时尊重卷约束。
- Init容器:在启动时,使用从pod中的Init容器从主pod拷贝所有数据。
- 卷挂载约束:将从pod上的卷挂载设置为只读,以防止数据损坏。
- 使用计划任务(cronjob)进行重启:创建一个简单的计划任务,每六个小时删除旧的pod,允许init容器运行并拷贝新数据。
示例配置
下面的例子展示了如何使用pod亲缘性关联设置Neo4j读取副本、用于数据拷贝的init容器以及挂载存在只读约束的卷以确保数据完整性。
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- primary-db
topologyKey: "kubernetes.io/hostname"
initContainers:
- name: copy-data
image: busybox
command: ["sh", "-c", "cp -r /data/* /backup/"]
volumeMounts:
- name: data-volume
mountPath: /data
- name: backup-volume
mountPath: /backup
volumes:
- name: data-volume
persistentVolumeClaim:
claimName: primary-db-pvc
- name: backup-volume
persistentVolumeClaim:
claimName: secondary-db-pvc
containers:
- name: secondary-db
image: neo4j:latest
volumeMounts:
- name: backup-volume
mountPath: /data
readOnly: true
备份和恢复
许多服务提供商提供了在基于磁盘的卷上调度重复快照的方法。这通常是首选的方法,因为它更容易设置,并且恢复过程更快。在这种情况下,我们可以定期备份托管数据库数据的卷。
另一种方法是结合数据库的专有工具,比如PostgreSQL的pg_dump。
下面是一个使用Kubernetes计划任务将PostgreSQL配置备份到s3的示例:
apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: postgres-backup
spec:
schedule: "0 0 * * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: backup
image: postgres
command: ["sh", "-c", "pg_dumpall -c -U $PGUSER | gzip > /backup/db_backup.gz && aws s3 cp /backup/db_backup.gz s3://your-bucket/db-backup-$(date +\%F).gz"]
volumeMounts:
- name: backup-volume
mountPath: /backup
restartPolicy: OnFailure
volumes:
- name: backup-volume
emptyDir: {}
结语
尽管初始设置或学习曲线可能很陡峭,但在Kubernetes中运行数据库具有很多优势。一个不太被提及的好处是成本。在RDS中运行db.m4.2xlarge(4vCPU和32GB内存)实例的成本大约是1200美元/月,而运行一个类似大小的EC2实例的成本大约是150美元/月。Kubernetes中的节点还可能运行多个pod,从而进一步优化资源使用。
与厂商无关是促使许多人在Kubernetes中运行数据库的另一个主要动机。以最小的调整在任何平台上移动工作负载极具吸引力。
总之,在决定在何处运行生产数据库之前,请考虑利弊。许多人成功地在Kubernetes中运行数据库,这类部署的数量在与日俱增。
原文How To Run Databases in Kubernetes,作者:Kolawole Olowoporoku