今天我们就来利用前面学习的知识点来部署⼀个实际的应用 – 将 WordPress 应用部署到集群当中,要部署⼀个 WordPress 应用主要涉及到两个镜像: wordpress 和 mysql , wordpress 是应用的核心程序, mysql 是用于数据存储的。现在我们来看看如何来部署我们的这个 wordpress 应用。
1、⼀个Pod
我们知道⼀个 Pod 中可以包含多个容器,那么很明显我们这里就可以将 wordpress部署成⼀个独立的 Pod 。然后将我们的应用都部署到 image 这个命名空间下面,所以先创建⼀个命名空间:
kubectl create namespace image
然后我们来编写 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 :
接下来就是等待拉取镜像,启动容器,同样我们可以使用 describe 指令查看详细信息:
我们仔细看看这种单⼀ 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 文件了:
然后我们查看 Service 的详细情况:
可以看到 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 的状态:
可以看到都已经是 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 ⽂件:
然后我们直接使用 https://172.16.200.1:30827 就可以访问wordpress的安装页面了:
输入基本信息之后直接点击安装就可以进入wordpress后台和前台页面了:
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
更新 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
观察 Deployment 的副本数和HPA的状态、我们发现CPU的使用率马上就上来了、Pod也数量也已经开始增加:
第三:增加滚动更新策略
增加滚动更新策略可以保证我们在更新应用的时候服务不会被中断:
# 注:添加位置参考最下面的汇总文件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 ⽂件来创建:
我们这里主要是针对 wordpress 来做的提高稳定性的方法,关于 mysql 稳定性的方法、感兴趣的同学下去可以试⼀试,我们接下来也会继续讲解 mysql 这类有状态的应用在 Kubernetes 当中的使用方法。好了、关于Kubernetes的常用资源对象全部内容基本上就结束了、后面我们会继续讲解关于持久化存储、服务发现等相关内容。