使用持久性卷轴部署MariaDB和WordPress的方法

275 阅读6分钟

在这篇博客中,我们将为MariaDB和WordPress应用程序创建单独的部署,并为两者创建一个服务,以便连接它们。此外,我们将在MariaDB部署的Pod中创建卷。

配置文件

最新的博客之前的博客中,我们已经创建了MariaDB Secret和MariaDB ConfigMap,这里我们假设它们存在于集群中。

$ kubectl describe secret/mariadb-secret
Name:         mariadb-secret
Namespace:    default
Labels:       <none>
Annotations:  <none>

Type:  Opaque

Data
====
mariadb-root-password:  6 bytes

$ kubectl describe cm mariadb-configmap
Name:         mariadb-configmap
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
database_url:
----
mariadb-internal-service

BinaryData
====

Events:  <none>

让我们为MariaDB部署和服务添加一个配置文件(GitHub文件)。

apiVersion: v1
kind: Service
metadata:
  name: mariadb-internal-service
spec:
  selector:
    app: mariadb
  ports:
    - protocol: TCP
      port: 3306
      targetPort: 3306
  clusterIP: None
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mariadb-deployment
spec: # specification for deployment resource
  replicas: 1
  selector:
    matchLabels:
      app: mariadb
  template: # blueprint for Pod
    metadata:
      labels:
        app: mariadb # service will look for this label
    spec: # specification for Pod
      containers:
      - name: mariadb
        image: mariadb
        ports:
        - containerPort: 3306 #default one
        env:
        - name: MARIADB_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mariadb-secret
              key: mariadb-root-password
        - name: MARIADB_DATABASE
          value: wordpress

创建的服务是一个Headless 类型的服务,没有分配集群IP,也不需要进行负载均衡。与上一篇博客唯一不同的是,在容器启动时创建了数据库 "wordpress",这是WordPress部署的一个要求。

让我们为WordPress的部署和服务添加一个配置文件(GitHub文件)。

apiVersion: v1
kind: Service
metadata:
  name: wordpress
spec:
  selector:
    app: wordpress
  ports:
    - port: 80
      targetPort: 80
      protocol: TCP #default
      nodePort: 31000
  type: LoadBalancer
---

apiVersion: apps/v1
kind: Deployment
metadata:
  name: wordpress-deployment
spec: # specification for deployment resource
  replicas: 1
  selector:
    matchLabels:
      app: wordpress
  template: # blueprint for Pod
    metadata:
      labels:
        app: wordpress
    spec: # specification for Pod
      containers:
      - name: wordpress
        image: wordpress:latest 
        ports:
        - containerPort: 80
        env:
        - name: WORDPRESS_DB_HOST
          valueFrom:
            configMapKeyRef:
              name: mariadb-configmap
              key: database_url
        - name: WORDPRESS_DB_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mariadb-secret
              key: mariadb-root-password
        - name: WORDPRESS_DB_USER
          value: root
        - name: WORDPRESS_DEBUG
          value: "1"

创建的服务是一个LoadBalancer类型*(Minikube* 支持它),它可以平衡一个服务的负载。我们正在暴露一个固定的节点端口,作为一个外部端口使用。这个数字应该在30000-32767的范围内。创建的部署使用环境变量WORDPRESS_DB_HOST 的ConfigMap信息,环境变量WORDPRESS_DB_PASSWORD的Secret和参考容器端口80。

创建资源并验证

$ kubectl apply -f mariadb-configmap.yaml 
configmap/mariadb-configmap created

$ kubectl apply -f mariadb-secret.yaml 
secret/mariadb-secret created

$ kubectl apply -f mariadb-deployment-pvc.yaml 
service/mariadb-internal-service created
deployment.apps/mariadb-deployment created

$ kubectl apply -f wordpress-deployment-pvc.yaml 
service/wordpress created
deployment.apps/wordpress-deployment created

$ minikube service wordpress
|-----------|-----------|-------------|---------------------------|
| NAMESPACE |   NAME    | TARGET PORT |            URL            |
|-----------|-----------|-------------|---------------------------|
| default   | wordpress |          80 | http://192.168.49.2:31000 |
|-----------|-----------|-------------|---------------------------|
🎉  Opening service default/wordpress in default browser...

在最后一条命令之后,我们将得到一个可以安装WordPress的URL。

添加持久性卷

当Pod崩溃时,kubectl会重新启动容器,并从一个干净的状态开始,这对数据的一致性是一个问题。为了解决这个问题,有一个与Pod相关的的抽象概念。Pod可以有多种卷的类型,比如ephemeral卷类型,它是默认的,与Pod的寿命有关;ConfigMapSecret类型,其数据可以被Pod中的文件所消耗;以及本博客感兴趣的PersistentVolumeClaim类型,作为在Pod中装载PersistentVolume 的一个请求。

PersistentVolume(PV)资源是集群中的一块存储,它由管理员手动配置,或由Kubernetes使用StorageClass动态配置(在集群中有一个默认的StorageClass,使用hostPath配置器)。

PersistentVolumeClaim(PVC)是一个用户对存储的请求,可以由PV来完成。Claim请求特定的大小和访问模式。

PersistentVolumes和PersistentVolumeClaims独立于Pod生命周期,通过重启、重新安排甚至删除Pod来保存数据。

为了验证这一点,让我们添加一些数据并重新启动MariaDB Pod。

$ kubectl get pods -l app=mariadb
NAME                                  READY   STATUS    RESTARTS   AGE
mariadb-deployment-74f8c57cbf-t4whv   1/1     Running   0          73m
$ kubectl exec mariadb-deployment-74f8c57cbf-t4whv -- mariadb -uroot -psecret -e "create database if not exists mytest;use mytest; create table t(t int); insert into t values (1),(2); select * from t";
t
1
2
a

# Watch in first terminal state of Pods (MariaDB Pod will be restarted, wordpress Pod will be running)
$ kubectl get pods -w
NAME                                    READY   STATUS    RESTARTS   AGE
mariadb-deployment-74f8c57cbf-t4whv     1/1     Running   0          78m
wordpress-deployment-79697d4fd5-4qsn7   1/1     Running   0          78m
wordpress-deployment-79697d4fd5-s4gc9   1/1     Running   0          78m
mariadb-deployment-74f8c57cbf-t4whv     1/1     Terminating   0          79m
mariadb-deployment-74f8c57cbf-t4whv     0/1     Terminating   0          79m
mariadb-deployment-74f8c57cbf-t4whv     0/1     Terminating   0          79m

# Scaling deployment replicas to 0, will restart the Pod. 
# Start command in the second terminal
$ kubectl scale deployment mariadb-deployment --replicas=0
deployment.apps/mariadb-deployment scaled

# Watch again MariaDB Pod creation before starting command to scale new replicas
# wordpress Pod is again in running state, not affected
$ kubectl get pods -w
NAME                                    READY   STATUS    RESTARTS   AGE
wordpress-deployment-79697d4fd5-4qsn7   1/1     Running   0          83m
wordpress-deployment-79697d4fd5-s4gc9   1/1     Running   0          83m
mariadb-deployment-74f8c57cbf-qd786     0/1     Pending   0          0s
mariadb-deployment-74f8c57cbf-qd786     0/1     Pending   0          0s
mariadb-deployment-74f8c57cbf-qd786     0/1     ContainerCreating   0          0s
mariadb-deployment-74f8c57cbf-qd786     1/1     Running             0          3s

# In other terminal 
$ kubectl scale deployment mariadb-deployment --replicas=1
deployment.apps/mariadb-deployment scaled

# Check existence of already created database 'mytest'
$ kubectl exec svc/mariadb-internal-service -- mariadb -uroot -psecret -e "show databases"
Database
information_schema
mysql
performance_schema
sys
wordpress

如上图所示,在应用ReplicaSet的零扩展时,旧的Pod被终止,新的Pod被创建,这与Pod的重启类似。

在使用单个副本进行扩展之前,可以看到只有WordPress Pod在运行,没有MariaDB Pod,而在扩展到单个副本之后,我们得到了一个MariaDB Pod,其Status列显示了Pod生命周期的创建阶段。

现在让我们通过添加PersistenceVolumeClaim来改变脚本,之后再运行同样的场景。

首先让我们删除旧的MariaDB部署。

$ kubectl delete -f mariadb-deployment-pvc.yaml 
service "mariadb-internal-service" deleted
deployment.apps "mariadb-deployment" deleted

许多集群环境都安装了一个默认的StorageClass 。当PersistentVolumeClaim中没有指定StorageClass时,集群的默认StorageClass会被替代使用。我们可以检查StorageClass。

$ kubectl get storageclass
NAME                 PROVISIONER                RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
standard (default)   k8s.io/minikube-hostpath   Delete          Immediate           false                  145d

当创建PersistentVolumeClaim时,PersistentVolume是根据StorageClass配置动态配置的。

让我们添加一个名为 "mariadb-pv-claim"的PersistentVolumeClaim资源,它具有RW访问权限,资源存储量为300MB,使用默认的StorageClass(动态配置持久性卷)。

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mariadb-pv-claim
  labels:
    app: mariadb
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 300M

此外,我们将用以下内容更新容器规范

      containers:
      - name: mariadb
        image: mariadb
        ports:
        - containerPort: 3306 #default one
        env:
        - name: MARIADB_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mariadb-secret
              key: mariadb-root-password
        - name: MARIADB_DATABASE
          value: wordpress
        volumeMounts:
        - name: mariadb-pv
          mountPath: /var/lib/mysql
      volumes:
      - name: mariadb-pv
        persistentVolumeClaim:
          claimName: mariadb-pv-claim

在容器 "mariadb"中,有一个名为 "mariadb-pv"的挂载,用于容器内的默认数据目录路径,它的存储大小等于索赔的大小,因为卷挂载名称 "mariadb-pv"是 "mariadb"容器所特有的,属于persistentVolumeClaim类型,它是为Pod定义的,引用集群中已经创建的PersistentVolumeClaim资源 "mariadb-pv-索赔"。

现在让我们应用这个部署,验证结果并再次尝试在Pod中创建数据库,重新启动Pod并尝试获取旧数据。

$ kubectl apply -f mariadb-deployment-pvc.yaml 
persistentvolumeclaim/mariadb-pv-claim created
service/mariadb-internal-service created
deployment.apps/mariadb-deployment created

# Get information about pvc resource - pvc is bound to the pv, check kubectl get pv
$ kubectl get pvc -l app=mariadb
NAME               STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
mariadb-pv-claim   Bound    pvc-57467ba5-bf6e-4b91-8741-c6f24e9c5861   300M       RWO            standard       31s
# Get the pods
$ kubectl get pods -l app=mariadb
NAME                                  READY   STATUS    RESTARTS   AGE
mariadb-deployment-58c7c4d75c-h45nl   1/1     Running   0          100s

# Watch in first terminal
$ kubectl get pods -w -l app=mariadb
NAME                                  READY   STATUS    RESTARTS   AGE
mariadb-deployment-58c7c4d75c-h45nl   1/1     Running   0          3m53s
mariadb-deployment-58c7c4d75c-h45nl   1/1     Terminating   0          4m13s
mariadb-deployment-58c7c4d75c-lsfdw   0/1     Pending       0          0s
mariadb-deployment-58c7c4d75c-lsfdw   0/1     Pending       0          0s
mariadb-deployment-58c7c4d75c-lsfdw   0/1     ContainerCreating   0          0s
mariadb-deployment-58c7c4d75c-h45nl   0/1     Terminating         0          4m15s
mariadb-deployment-58c7c4d75c-h45nl   0/1     Terminating         0          4m15s
mariadb-deployment-58c7c4d75c-h45nl   0/1     Terminating         0          4m15s
mariadb-deployment-58c7c4d75c-lsfdw   1/1     Running             0          4s

# Execute command in the second terminal - note above that new Pod has been created
$ kubectl scale deploy mariadb-deployment --replicas=0 && kubectl scale deploy mariadb-deployment --replicas=1
deployment.apps/mariadb-deployment scaled
deployment.apps/mariadb-deployment scaled

# Verify results from newly created Pod by inspecting data created in the old Pod
$ kubectl exec mariadb-deployment-58c7c4d75c-lsfdw -- mariadb -uroot -psecret -e "show databases like '%test%'; use mytest; select * from t;"
Database (%test%)
mytest
t
1
2

可以看出,我们能够获得对Pod重启/终止有抵抗力的数据。

我们可以在一个部署中拥有多个PVC资源。尝试为WordPress部署创建一个PVC资源,用于卷挂载路径*/var/www/html*。

这样我们就实现了数据的一致性,并部署了statefulset应用程序。

不建议使用Deployment作为部署statefulset应用程序的方式,因为它们是为无状态的应用程序设计的,所以一个Deployment的所有副本共享相同的PersistentVolumeClaim,只有ReadOnlyMany或ReadWriteMany的卷才能在这种设置下工作。甚至不建议使用ReadWriteOnce卷的一个副本的部署,因为由于默认的部署策略,第二个Pod将被创建,并可能发生死锁(更多信息请见此链接)。

结论和未来工作

这篇博客展示了如何创建2个部署以及如何通过服务连接它们。我们还应用了以前学过的K8s概念,以便更多地利用K8s的API。

在数据库的例子中,我们展示了数据一致性的需求和Pod的短暂性,以及介绍了PersistentVolumeClaim资源在K8s集群上的动态配置,这有助于解决这类问题。然而,这篇博客只是为了演示和学习这些概念。在接下来的博客中,我们将创建一个没有部署的StatefulSet应用程序,用来确保数据的一致性。

欢迎大家在Zulip上聊一聊。