内容简介:Kubernetes主要用于无状态应用程序。 但是,在1.3版本中引入了PetSets,之后它们演变为StatefulSets。 官方文档将StatefulSets描述为“StatefulSets旨在与有状态应用程序和分布式系统一起使用”。对此最好的用例之一是对数据存储服务进行编排,例如MongoDB,ElasticSearch,Redis,Zookeeper等。
如何在Kubernetes上扩展MongoDB
Kubernetes主要用于无状态应用程序。 但是,在1.3版本中引入了PetSets,之后它们演变为StatefulSets。 官方文档将StatefulSets描述为“StatefulSets旨在与有状态应用程序和分布式系统一起使用”。
对此最好的用例之一是对数据存储服务进行编排,例如MongoDB,ElasticSearch,Redis,Zookeeper等。
我们可以把StatefulSets的特性归纳如下:
- 有序索引Pods
- 稳定的网络ID
- 有序并行的Pods管理
- 滚动更新
这些细节可以在 这里 找到。
StatefulSets的一个非常明显的特征是提供稳定网络ID,与 headless-services 一起使用时,功能可以更加强大。
我们不花费很多时间在Kubernetes文档中随时可以查看的信息,让我们专注于运行和扩展 MongoDB 集群。
您需要一个可以运行的Kubernetes群集并启用RBAC(推荐)。 在本教程中,我将使用GKE集群,但是,AWS EKS或Microsoft的AKS或Kops管理的K8S也是可行的替代方案。
我们将为MongoDB集群部署以下组件:
- 配置HostVM的Daemon Set
- Mongo Pods的Service Account和ClusterRole Binding
- 为Pods提供永久性存储SSDs的Storage Class
- 访问Mongo容器的Headless Service
- Mongo Pods Stateful Set
- GCP Internal LB: 从kubernetes集群外部访问MongoDB(可选)
- 使用Ingress访问Pod(可选)
值得注意的是,每个MongoDB Pod都会运行一个sidecar,以便动态配置副本集。Sidecar每5秒检查一次新成员。
Daemon Set for HostVM Configuration:
```yaml
kind: DaemonSet
apiVersion: extensions/v1beta1
metadata:
name: hostvm-configurer
labels:
app: startup-script
spec:
template:
metadata:
labels:
app: startup-script
spec:
hostPID: true
containers:
- name: hostvm-configurer-container
image: gcr.io/google-containers/startup-script:v1
securityContext:
privileged: true
env:
- name: STARTUP_SCRIPT
value: |
#! /bin/bash
set -o errexit
set -o pipefail
set -o nounset
# Disable hugepages
echo 'never' > /sys/kernel/mm/transparent_hugepage/enabled
echo 'never' > /sys/kernel/mm/transparent_hugepage/defrag
```
Configuration for ServiceAccount, Storage Class, Headless SVC and StatefulSet:
yaml apiVersion: v1 kind: Namespace metadata:
name: mongo
apiVersion: v1
kind: ServiceAccount
metadata:
name: mongo
namespace: mongo
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
name: mongo
subjects:
- kind: ServiceAccount
name: mongo
namespace: mongo
roleRef:
kind: ClusterRole
name: cluster-admin
apiGroup: rbac.authorization.k8s.io
apiVersion: storage.k8s.io/v1beta1
kind: StorageClass
metadata:
name: fast
provisioner: kubernetes.io/gce-pd
parameters:
type: pd-ssd
fsType: xfs
allowVolumeExpansion: true
apiVersion: v1
kind: Service
metadata:
name: mongo
namespace: mongo
labels:
name: mongo
spec:
ports:
- port: 27017
targetPort: 27017
clusterIP: None
selector:
role: mongo
apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
name: mongo
namespace: mongo
spec:
serviceName: mongo
replicas: 3
template:
metadata:
labels:
role: mongo
environment: staging
replicaset: MainRepSet
spec:
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: replicaset
operator: In
values:
- MainRepSet
topologyKey: kubernetes.io/hostname
terminationGracePeriodSeconds: 10
serviceAccountName: mongo
containers:
- name: mongo
image: mongo
command:
- mongod
- "--wiredTigerCacheSizeGB"
- "0.25"
- "--bind_ip"
- "0.0.0.0"
- "--replSet"
- MainRepSet
- "--smallfiles"
- "--noprealloc"
ports:
- containerPort: 27017
volumeMounts:
- name: mongo-persistent-storage
mountPath: /data/db
resources:
requests:
cpu: 1
memory: 2Gi
- name: mongo-sidecar
image: cvallance/mongo-k8s-sidecar
env:
- name: MONGO_SIDECAR_POD_LABELS
value: "role=mongo,environment=staging"
- name: KUBE_NAMESPACE
value: "mongo"
- name: KUBERNETES_MONGO_SERVICE_NAME
value: "mongo"
volumeClaimTemplates:
- metadata:
name: mongo-persistent-storage
annotations:
volume.beta.kubernetes.io/storage-class: "fast"
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: fast
resources:
requests:
storage: 10Gi
关键点:
1. 应该使用适当的环境变量仔细配置Mongo的Sidecar,以及为pod提供的标签,和为deployment和service的命名空间。 有关sidecar容器的详细信息,请点击 此处 。
2. 默认缓存大小的指导值是:“50%的RAM减去1GB,或256MB”。 鉴于所请求的内存量为2GB,此处的WiredTiger缓存大小已设置为256MB。
3. Inter-Pod Anti-Affinity确保在同一个工作节点上不会安排2个Mongo Pod,从而使其能够适应节点故障。 此外,建议将节点保留在不同的可用区中,以便集群能够抵御区域故障。
4. 当前部署的Service Account具有管理员权限。 但是,它应该仅限于DB的命名空间。
上面提到的两个配置文件也可以在 这里 找到。
部署MongoDB集群
shell kubectl apply -f configure-node.yml kubectl apply -f mongo.yml
你可以通过以下命令查看所有组件状况:
shell kubectl -n mongo get all
shell root$ kubectl -n mongo get all NAME DESIRED CURRENT AGE statefulsets/mongo 3 3 3m NAME READY STATUS RESTARTS AGE po/mongo-0 2/2 Running 0 3m po/mongo-1 2/2 Running 0 2m po/mongo-2 2/2 Running 0 1m NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE svc/mongo ClusterIP None <none> 27017/TCP 3m
如您所见,该服务没有Cluster-IP,也没有External-IP,它是Headless服务。 此服务将直接解析为StatefulSets的Pod-IP。
让我们来验证一下DNS解析。 我们在集群中启动了一个交互式shell:
shell kubectl run my-shell --rm -i --tty --image ubuntu -- bash root@my-shell-68974bb7f7-cs4l9:/# dig mongo.mongo +search +noall +answer ; <<>> DiG 9.11.3-1ubuntu1.1-Ubuntu <<>> mongo.mongo +search +noall +answer ;; global options: +cmd mongo.mongo.svc.cluster.local. 30 IN A 10.56.7.10 mongo.mongo.svc.cluster.local. 30 IN A 10.56.8.11 mongo.mongo.svc.cluster.local. 30 IN A 10.56.1.4
服务的DNS规则是<服务名称>.<服务的命名空间>,因此,在我们的例子中看到的是mongo.mongo。
IPs(10.56.6.17,10.56.7.10,10.56.8.11)是我们的Mongo StatefulSets的Pod IPs。 这可以通过在集群内部运行nslookup来测试。
shell root@my-shell-68974bb7f7-cs4l9:/# nslookup 10.56.6.17 17.6.56.10.in-addr.arpa name = mongo-0.mongo.mongo.svc.cluster.local. root@my-shell-68974bb7f7-cs4l9:/# nslookup 10.56.7.10 10.7.56.10.in-addr.arpa name = mongo-1.mongo.mongo.svc.cluster.local. root@my-shell-68974bb7f7-cs4l9:/# nslookup 10.56.8.11 11.8.56.10.in-addr.arpa name = mongo-2.mongo.mongo.svc.cluster.local.
如果您的应用程序部署在K8的群集中,那么它可以通过以下方式访问节点:
Node-0: mongo-0.mongo.mongo.svc.cluster.local:27017 Node-1: mongo-1.mongo.mongo.svc.cluster.local:27017 Node-2: mongo-2.mongo.mongo.svc.cluster.local:27017
如果要从集群外部访问mongo节点,你可以为每个pod部署内部负载平衡或使用Ingress Controller(如NGINX或Traefik)创建一个内部Ingress。
GCP Internal LB SVC Configuration (可选)
yaml apiVersion: v1 kind: Service metadata: annotations: cloud.google.com/load-balancer-type: Internal name: mongo-0 namespace: mongo spec: ports: - port: 27017 targetPort: 27017 selector: statefulset.kubernetes.io/pod-name: mongo-0 type: LoadBalancer
为mongo-1和mongo-2也部署2个此类服务。
您可以将内部负载均衡的IP提供给MongoClient URI。
shell root$ kubectl -n mongo get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE mongo ClusterIP None <none> 27017/TCP 15m mongo-0 LoadBalancer 10.59.252.157 10.20.20.2 27017:30184/TCP 9m mongo-1 LoadBalancer 10.59.252.235 10.20.20.3 27017:30343/TCP 9m mongo-2 LoadBalancer 10.59.254.199 10.20.20.4 27017:31298/TCP 9m
mongo-0/1/2的外部IP是新创建的TCP负载均衡器的IP。 这些是您的子网或对等网络,如果有的话。
通过Ingress访问Pods(可选)
也可以使用诸如Nginx之类的Ingress Controller来定向到Mongo StatefulSets的流量。 确保ingress服务是内部服务,而不是通过PublicIP公开。 Ingress对象的配置看起来像这样:
yaml ... spec: rules: - host: mongo.example.com http: paths: - path: '/mongo-0' backend: hostNames: - mongo-0 serviceName: mongo # There is no extra service. This is the headless service. servicePort: '27017'
请务必注意,您的应用程序至少应该知道一个当前处于启动状态的mongo节点,这样可以发现所有其他节点。
我在本地mac上使用Robo 3T作为mongo客户端。 连接到其中一个节点后并运行rs.status(),您可以查看副本集的详细信息,并检查是否已配置其他2个Pods并自动连接到副本集。
rs.status()查看副本集名称和成员个数:
每个成员都可以看到FQDN和状态。 此FQDN只能从群集内部访问。
每个secondary成员正在同步到mongo-0,mongo-0是当前的primary。
现在我们扩展mongo Pods的Stateful Set以检查新的mongo容器是否被添加到ReplicaSet。
shell root$ kubectl -n mongo scale statefulsets mongo --replicas=4 statefulset "mongo" scaled root$ kubectl -n mongo get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE mongo-0 2/2 Running 0 25m 10.56.6.17 gke-k8-demo-demo-k8-pool-1-45712bb7-vfqs mongo-1 2/2 Running 0 24m 10.56.7.10 gke-k8-demo-demo-k8-pool-1-c6901f2e-trv5 mongo-2 2/2 Running 0 23m 10.56.8.11 gke-k8-demo-demo-k8-pool-1-c7622fba-qayt mongo-3 2/2 Running 0 3m 10.56.1.4 gke-k8-demo-demo-k8-pool-1-85308bb7-89a4
可以看出,所有四个pod都部署到不同的GKE节点,因此我们的Pod-Anti Affinity策略工作正常。
扩展操作还将自动提供持久卷,该卷将充当新pod的数据目录。
shell root$ kubectl -n mongo get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE mongo-persistent-storage-mongo-0 Bound pvc-337fb7d6-9f8f-11e8-bcd6-42010a940024 11G RWO fast 49m mongo-persistent-storage-mongo-1 Bound pvc-53375e31-9f8f-11e8-bcd6-42010a940024 11G RWO fast 49m mongo-persistent-storage-mongo-2 Bound pvc-6cee0f97-9f8f-11e8-bcd6-42010a940024 11G RWO fast 48m mongo-persistent-storage-mongo-3 Bound pvc-3e89573f-9f92-11e8-bcd6-42010a940024 11G RWO fast 28m
要检查名为mongo-3的pod是否已添加到副本集,我们将在同一节点上再次运行rs.status()并观察其差异。
对于同一个的Replicaset,成员数现在为4。
新添加的成员遵循与先前成员相同的FQDN方案,并且还与同一主节点同步:
进一步的考虑
- 给Mongo Pod的Node Pool打上合适的label并确保在StatefulSets和HostVM配置的DaemonSets的Spec中指定适当的Node Affinity会很有帮助。 这是因为DaemonSet将调整主机操作系统的一些参数,并且这些设置应仅限于MongoDB Pod。 没有这些设置,对其他应用程序可能会更好。
- 在GKE中给Node Pool打Label非常容易,可以直接从GCP控制台进行。
- 虽然我们在Pod的Spec中指定了CPU和内存限制,但我们也可以考虑部署VPA(Vertical Pod Autoscaler)。
- 可以通过实施网络策略或服务网格(如Istio)来控制从集群内部到我们的数据库的流量。
如果你已经看到这里,我相信你已经浏览了整个博文。 我试图整理很多分散的信息并将其作为一个整体呈现。 我的目标是为您提供足够的信息,以便开始使用Kubernetes上的Stateful Sets,并希望你们中的许多人觉得它很有用。 我们非常欢迎您提出反馈、意见或建议。:)
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 【php 扩展开发】扩展生成器
- 喧喧发布 1.6.0 版本,扩展机制增强,支持服务器扩展
- 为vscode编写扩展
- JavaScript——DOM扩展
- Mac内核扩展开发
- VisualStudio 扩展开发
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Don't Make Me Think
Steve Krug / New Riders Press / 18 August, 2005 / $35.00
Five years and more than 100,000 copies after it was first published, it's hard to imagine anyone working in Web design who hasn't read Steve Krug's "instant classic" on Web usability, but people are ......一起来看看 《Don't Make Me Think》 这本书的介绍吧!
URL 编码/解码
URL 编码/解码
Markdown 在线编辑器
Markdown 在线编辑器