通过Kubernetes部署WordPress5.3.2

今天我们就来利用前面学习的知识点来部署⼀个实际的应用 – 将 WordPress 应用部署到集群当中,要部署⼀个 WordPress 应用主要涉及到两个镜像: wordpress 和 mysql , wordpress 是应用的核心程序, mysql 是用于数据存储的。现在我们来看看如何来部署我们的这个 wordpress 应用。

1、⼀个Pod

我们知道⼀个 Pod 中可以包含多个容器,那么很明显我们这里就可以将 wordpress部署成⼀个独立的 Pod 。然后将我们的应用都部署到 image 这个命名空间下面,所以先创建⼀个命名空间:

kubectl create namespace image

img

然后我们来编写 YAML 文件:(wordpress-pod.yaml)

apiVersion: v1
kind: Pod
metadata:
  name: wordpress
  namespace: image
spec:
  containers:
  - name: wordpress
    image: wordpress
    ports:
    - containerPort: 80
      name: wdport
    env: # 定义wordpress的环境变量
    - name: WORDPRESS_DB_HOST
      value: localhost:3306
    - name: WORDPRESS_DB_USER
      value: wordpress
    - name: WORDPRESS_DB_PASSWORD
      value: wordpress
  - name: mysql
    image: mysql:5.6
    imagePullPolicy: IfNotPresent # 定义镜像的拉取方式
    ports:
    - containerPort: 3306
      name: dbport
    env: # 定义数据库的环境变量
    - name: MYSQL_ROOT_PASSWORD
      value: rootPassW0rd
    - name: MYSQL_DATABASE
      value: wordpress
    - name: MYSQL_USER
      value: wordpress
    - name: MYSQL_PASSWORD
      value: wordpress
    volumeMounts: # 持久化,后期修改为PV/PC
    - name: db
      mountPath: /var/lib/mysql
  volumes:
  - name: db
    hostPath: # 这里如果只使用hostPath,这个Pod可能会被调度到其他Node上面而导致数据丢失,后期单独讲解。
      path: /var/lib/mysql

需要注意的是这里针对 mysql 这个容器我们做了⼀个数据卷的挂载,这是为了将 mysql 的数据能够持久化到节点上,这样下次 mysql 容器重启过后数据不至于丢失。 然后我们直接创建上面的 Pod :

img

接下来就是等待拉取镜像,启动容器,同样我们可以使用 describe 指令查看详细信息:

img

我们仔细看看这种单⼀ Pod 的方式有什么缺点呢?假如我们现在需要部署3个 WordPress 的副本,该怎么办?是不是我们只需要在上⾯的 YAML ⽂件中加上 replicas: 3 这个属性就可以了啊?但是有个什么问题呢?是不是不仅仅是 WordPress 这个容器会被部署成3份,连我们的 MySQL 数据库也会被部署成3份了呢? MySQL 数据库单纯的部署成3份他们能联合起来使用吗?

答案肯定是不能的,如果真的这么简单的话就不需要各种数据库集群解决方案了,所以我们这里部署3个 Pod 实例,实际上他们互相之间是独立的,因为数据不互通,所以该怎么办?拆分呗,把 wordpress 和 mysql 这两个容器部署成独立的 Pod 是不是就可以了?

另外⼀个问题是 wordpress 容器需要去连接 mysql 数据库,现在我们这里放在⼀起能保证 mysql 先启动起来吗?好像没有特别的办法,前面学习的 InitContainer 也是针对 Pod 来的,所以无论如何,我们都需要将他们进行拆分。

2、两个Pod

现在来把上⾯的⼀个 Pod 拆分成两个 Pod ,前⾯也我们反复强调过要使用 Deployment 来管理 Pod ,上⾯只是为了单纯给大家演示一下怎么来把前面 Docker 环境下的 wordpress 转换成 Kubernetes 环境的 Pod ,有了上⾯的 Pod 模板,我们现在来转换成 Deployment 很容易了。

第1步:创建⼀个 MySQL 的 Deployment 对象:(wordpress-db.yaml)

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysql-deploy
  namespace: image
  labels: 
    app: mysql
spec:
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
      - name: mysql
        image: mysql:5.6
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 3306
          name: dbport
        env:
        - name: MYSQL_ROOT_PASSWORD
          value: rootPassW0rd
        - name: MYSQL_DATABASE
          value: wordpress
        - name: MYSQL_USER
          value: wordpress
        - name: MYSQL_PASSWORD
          value: wordpress
        volumeMounts:
        - name: db
          mountPath: /var/lib/mysql
      volumes:
      - name: db
        hostPath:
          path: /var/lib/mysql
---
apiVersion: v1
kind: Service
metadata:
  name: mysql
  namespace: image
spec:
  selector:
    app: mysql
  ports:
  - name: mysqlport
    protocol: TCP
    port: 3306
    targetPort: dbport

如果我们只创建上面这个 Deployment 对象,那么应该怎样让后⾯的 WordPress 来访问呢?好像没办法,之前我们在⼀个 Pod 里面还可以使用 localhost 来进行访问,现在分开了该怎样访问呢?没错、就是通过 Service 、所以我们在上⾯的 wordpress-db.yaml 文件中添加上 Service 的信息。现在我们可以直接创建上面的 wordpress-db.yaml 文件了:

img

然后我们查看 Service 的详细情况:

img

可以看到 Endpoints 部分匹配到了⼀个 Pod 并生成了⼀个 ClusterIP : 10.102.171.49,现在我们就可以通过 ClusterIP 加上自定义的3306端口正常访问 mysql 服务了。

第2步:创建 WordPress 核心服务,将上面的 wordpress 的 Pod 转换成 Deployment 对象:(wordpress.yaml)

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: wordpress-deploy
  namespace: image
  labels:
    app: wordpress
spec:
  selector:
    matchLabels:
      app: wordpress
  template:
    metadata:
      labels:
        app: wordpress
    spec:
      containers:
      - name: wordpress
        image: wordpress
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
          name: wdport
        env:
        - name: WORDPRESS_DB_HOST
          value: 10.102.171.49:3306
        - name: WORDPRESS_DB_USER
          value: wordpress
        - name: WORDPRESS_DB_PASSWORD
          value: wordpress

注:这里的环境变量 WORDPRESS_DB_HOST 的值将之前的 localhost 地址更改成了上⾯ mysql 服务的 ClusterIP 地址了,然后创建上⾯的 Deployment 对象,创建完成后,我们可以看看 Pod 的状态:

img

可以看到都已经是 Running 状态了,但是我们需要怎么来验证呢?是不是直接去访问 wordpress 服务就可以了?要访问,我们就需要建立⼀个能让外网用户访问的 Service ,前⾯我们学到过 NodePort 类型的 Service 就可以实现我们的目的,所以我们在上⾯的 wordpress.yaml 文件中添加上 Service 的信息:

---
apiVersion: v1
kind: Service
metadata:
  name: wordpress
  namespace: image
spec:
  type: NodePort
  selector:
    app: wordpress
  ports:
  - name: wordpressport
    protocol: TCP
    port: 80
    targetPort: wdport

注意要添加属性 type: NodePort ,然后重新更新 wordpress.yaml ⽂件:

img

然后我们直接使用 https://172.16.200.1:30827 就可以访问wordpress的安装页面了:

img

输入基本信息之后直接点击安装就可以进入wordpress后台和前台页面了:

img

3、稳定性提升

现在 wordpress 应用已经部署成功了,那么就万事大吉了吗?如果我们的网站访问量突然变大了怎么办,如果我们要更新镜像该怎么办?如果 mysql 服务挂掉了怎么办?所以我们要保证网站能够非常稳定的提供服务,但是我们怎么来提⾼网站的稳定性呢?

第⼀: 增加健康检测

我们前面说过 liveness probe 和 rediness probe 是提高应用稳定性非常重要的方法:

# 注:添加位置参考最下面的汇总文件wordpress-all.yaml
livenessProbe:
  tcpSocket:
    port: 80
  initialDelaySeconds: 3
  periodSeconds: 3
readinessProbe:
  tcpSocket:
    port: 80
  initialDelaySeconds: 5
  periodSeconds: 10

注:这里我们增加 liveness probe 和 rediness probe 两个探针,每10s检测⼀次应用是否可读,每3s检测⼀次应用是否存活。

第⼆:增加 HPA

让我们的应用能够自动应对流量高峰期,我们通过 kubectl autoscale 命令为 wordpress-deploy 创建⼀个 HPA 对象,最小的 pod 副本数为1,最的 pod 副本数为 10, HPA 会根据设定的 cpu使用率(10%)动态的增加或者减少pod数量。当然最好我们也为 Pod 声明⼀些资源限制:

# 注:添加位置参考最下面的汇总文件wordpress-all.yaml
resources:
  limits:
    cpu: 200m
    memory: 200Mi
  requests:
    cpu: 100m
    memory: 100Mi

通过下面的命令创建HPA:

kubectl autoscale deployment wordpress-deploy --cpu-percent=10 --min=1 --max=10 -n image deployment "wordpress-deploy" autoscaled

img

更新 Deployment 后,我们可以来测试下上⾯的 HPA 是否会生效:

kubectl run -i --tty load-generator --image=busybox /bin/sh

# 通过while命令循环访问实现压力测试
while true; do wget -q -O- http://172.16.200.1:31387; done

img

观察 Deployment 的副本数和HPA的状态、我们发现CPU的使用率马上就上来了、Pod也数量也已经开始增加:

img

img

第三:增加滚动更新策略

增加滚动更新策略可以保证我们在更新应用的时候服务不会被中断:

# 注:添加位置参考最下面的汇总文件wordpress-all.yaml
replicas: 2
revisionHistoryLimit: 10
minReadySeconds: 5
strategy:
  type: RollingUpdate
  rollingUpdate:
   maxSurge: 1
   maxUnavailable: 1

第四:服务发现

我们知道如果 mysql 服务被重新创建的话,它的 ClusterIP 非常有可能就变化了,所以我们上⾯环境变量中的 WORDPRESS_DB_HOST 的值就会有问题,就会导致访问不了数据库服务了,这个地方我们可以直接使用 Service 的名称来代替 host ,这样即使 ClusterIP 变化了,也不会有任何影响(服务发现的内容后期会详细讲解):

# 注:添加位置参考最下面的汇总文件wordpress-all.yaml
env:
- name: WORDPRESS_DB_HOST
  value: mysql:3306

第五:服务依赖

我们在部署 wordpress 服务的时候, mysql 服务启动了吗?如果没有启动我们没办法连接数据库了。是不是在启动 wordpress 应⽤之前应该去检查⼀下 mysql 服务,如果服务正常的话我们就开始部署应用了,这是不是就是 InitContainer 的用法:

# 注:添加位置参考最下面的汇总文件wordpress-all.yaml
initContainers:
- name: init-db
  image: busybox
  command: ['sh', '-c', 'until nslookup mysql; do echo waiting for mysql service; sleep 2;done;']

我们可以通过describe命令看到、直到 mysql 服务创建完成后, initContainer 才结束,结束完成后我们才开始下⾯的部署。

最后,我们把部署的应用整合到⼀个 YAML 文件中来:(wordpress-all.yaml)

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: wordpress-deploy
  namespace: image
  labels:
    app: wordpress
spec:
  replicas: 3
  revisionHistoryLimit: 10
  minReadySeconds: 5
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 1
  selector:
    matchLabels:
      app: wordpress
  template:
    metadata:
      labels:
        app: wordpress
    spec:
      initContainers:
      - name: init-db
        image: busybox
        imagePullPolicy: IfNotPresent
        command: ['sh', '-c', 'until nslookup mysql; do echo waiting for mysql service; sleep 2;done;']
      containers:
      - name: wordpress
        image: wordpress
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
          name: wdport
        env:
        - name: WORDPRESS_DB_HOST
          value: mysql:3306
        - name: WORDPRESS_DB_USER
          value: wordpress
        - name: WORDPRESS_DB_PASSWORD
          value: wordpress
        livenessProbe:
          tcpSocket:
            port: 80
          initialDelaySeconds: 3
          periodSeconds: 3
        readinessProbe:
          tcpSocket:
            port: 80
          initialDelaySeconds: 5
          periodSeconds: 10
        resources:
          limits:
            cpu: 200m
            memory: 200Mi
          requests:
            cpu: 100m
            memory: 100Mi
---
apiVersion: v1
kind: Service
metadata:
  name: wordpress
  namespace: image
spec:
  type: NodePort
  selector:
    app: wordpress
  ports:
  - name: wordpressport
    protocol: TCP
    port: 80
    targetPort: wdport
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysql-deploy
  namespace: image
  labels: 
    app: mysql
spec:
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
      - name: mysql
        image: mysql:5.6
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 3306
          name: dbport
        env:
        - name: MYSQL_ROOT_PASSWORD
          value: rootPassW0rd
        - name: MYSQL_DATABASE
          value: wordpress
        - name: MYSQL_USER
          value: wordpress
        - name: MYSQL_PASSWORD
          value: wordpress
        volumeMounts:
        - name: db
          mountPath: /var/lib/mysql
      volumes:
      - name: db
        hostPath:
          path: /var/lib/mysql
---
apiVersion: v1
kind: Service
metadata:
  name: mysql
  namespace: image
spec:
  selector:
    app: mysql
  ports:
  - name: mysqlport
    protocol: TCP
    port: 3306
    targetPort: dbport

最后,我们来把前⾯我们部署的相关服务全部删掉,重新通过上⾯的 YAML ⽂件来创建:

img

img

我们这里主要是针对 wordpress 来做的提高稳定性的方法,关于 mysql 稳定性的方法、感兴趣的同学下去可以试⼀试,我们接下来也会继续讲解 mysql 这类有状态的应用在 Kubernetes 当中的使用方法。好了、关于Kubernetes的常用资源对象全部内容基本上就结束了、后面我们会继续讲解关于持久化存储、服务发现等相关内容。

推荐文章