部署 Wordpress 示例
前面的课程中我们基本上了解了Kubernetes当中常见的一些对象资源,这节课我们就来利用前面学习的知识点来部署一个实际的应用 - 将Wordpress应用部署到我们的集群当中,我们前面是不是已经用docker-compose的方式部署过了,我们可以了解到要部署一个Wordpress应用主要涉及到两个镜像:wordpress和mysql,wordpress是应用的核心程序,mysql是用于数据存储的。
现在我们来看看如何来部署我们的这个wordpress应用
一个Pod
我们知道一个Pod中可以包含多个容器,那么很明显我们这里是不是就可以将wordpress部署成一个独立的Pod?我们将我们的应用都部署到blog这个命名空间下面,所以先创建一个命名空间:
$ kubectl create namespace blog
namespace "blog" created
然后来编写YAML文件:(wordpress-pod.yaml)
apiVersion: v1
kind: Pod
metadata:
name: wordpress
namespace: blog
spec:
containers:
- name: wordpress
image: wordpress
ports:
- containerPort: 80
name: wdport
env:
- name: WORDPRESS_DB_HOST
value: localhost: 3306
- name: WORDPRESS_DB_USER
value: wordpress
- name: WORDPRESS_DB_PASSWORD
value: wordpress
- name: mysql
image: mysql:5.7
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
要注意这里针对mysql这个容器我们做了一个数据卷的挂载,这是为了能够将mysql的数据能够持久化到节点上,这样下次mysql容器重启过后数据不至于丢失。 然后创建上面的Pod:
$ kubectl create -f wrodpress-pod.yaml
pod "wordpress" created
接下来就是等待拉取镜像,启动容器,同样我们可以使用describe指令查看详细信息:
$ kubectl describe pod wordpress -n blog
大家可以看看我们现在这种单一Pod的方式有什么缺点?假如我们现在需要部署3个Wordpress的副本,该怎么办?是不是我们只需要在上面的YAML文件中加上replicas: 3这个属性就可以了啊?但是有个什么问题呢?是不是不仅仅是Wordpress这个容器会被部署成3份,连我们的MySQL数据库也会被部署成3份了呢?MySQL数据库单纯的部署成3份他们能联合起来使用吗?不能,如果真的这么简单的话就不需要各种数据库集群解决方案了,所以我们这里部署3个Pod实例,实际上他们互相之间是独立的,因为数据不想通,明白吧?所以该怎么办?拆分呗,把wordpress和mysql这两个容器部署成独立的Pod是不是就可以了。
另外一个问题是我们的wordpress容器需要去连接mysql数据库吧,现在我们这里放在一起能保证mysql先启动起来吗?貌似没有特别的办法,前面学习的InitContainer也是针对Pod来的,所以无论如何,我们都需要将他们进行拆分。
两个Pod
现在来把上面的一个Pod拆分成两个Pod,我们前面也反复强调过要使用Deployment来管理我们的Pod,上面只是为了单纯给大家说明怎么来把前面的Docker环境下的wordpress转换成Kubernetes环境下面的Pod,有了上面的Pod模板,我们现在来转换成Deployment很容易了吧。
第一步,创建一个MySQL的Deployment对象:(wordpress-db.yaml)
---
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: mysql-deploy
namespace: blog
labels:
app: mysql
spec:
template:
metadata:
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql:5.7
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
如果我们只创建上面的Deployment这个对象,那么我们应该怎样让后面的Wordpress来访问呢?貌似没办法是吧,之前在一个Pod里面还可以使用localhost来进行访问,现在分开了该怎样访问呢?还记得前面的Service吗?没错,使用Service就可以了,所以我们在上面的wordpress-db.yaml文件中添加上Service的信息:
---
apiVersion: v1
kind: Service
metadata:
name: mysql
namespace: blog
spec:
selector:
app: mysql
ports:
- name: mysqlport
protocol: TCP
port: 3306
targetPort: dbport
然后创建上面的wordpress-db.yaml文件:
$ kubectl create -f wordpress-db.yaml
service "mysql" created
deployment.apps "mysql-deploy" created
然后我们查看Service的详细情况:
$ kubectl describe svc mysql -n blog
Name: mysql
Namespace: blog
Labels: <none>
Annotations: <none>
Selector: app=mysql
Type: ClusterIP
IP: 10.98.27.19
Port: mysqlport 3306/TCP
TargetPort: dbport/TCP
Endpoints: 10.244.2.213:3306
Session Affinity: None
Events: <none>
可以看到Endpoints部分匹配到了一个Pod,生成了一个clusterIP:10.98.27.19,现在我们是不是就可以通过这个clusterIP加上定义的3306端口就可以正常访问我们这个mysql服务了。
第二步. 创建Wordpress服务,将上面的wordpress的Pod转换成Deployment对象:(wordpress.yaml)
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: wordpress-deploy
namespace: blog
labels:
app: wordpress
spec:
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.98.27.19:3306
- name: WORDPRESS_DB_USER
value: wordpress
- name: WORDPRESS_DB_PASSWORD
value: wordpress
注意这里的环境变量WORDPRESS_DB_HOST的值将之前的localhost地址更改成了上面mysql服务的clusterIP地址了,然后创建上面的Deployment对象:
$ kubectl create -f wordpress.yaml
deployment.apps "wordpress-deploy" created
创建完成后,我们可以看看我们创建的Pod的状态:
$ kubectl get pods -n blog
NAME READY STATUS RESTARTS AGE
mysql-deploy-86bdcc7484-fv2dj 1/1 Running 0 19m
wordpress-deploy-784cfd6dd4-d9f52 1/1 Running 0 23s
可以看到都已经是Running状态了,然后我们需要怎么来验证呢?是不是去访问下我们的wordpress服务就可以了,要访问,我们就需要建立一个能让外网用户访问的Service,前面我们学到过是不是NodePort类型的Service就可以?所以在上面的wordpress.yaml文件中添加上Service的信息:
---
apiVersion: v1
kind: Service
metadata:
name: wordpress
namespace: blog
spec:
type: NodePort
selector:
app: wordpress
ports:
- name: wordpressport
protocol: TCP
port: 80
targetPort: wdport
注意要添加属性type: NodePort,然后重新更新wordpress.yaml文件:
$ kubectl apply -f wordpress.yaml
service "wordpress" created
Warning: kubectl apply should be used on resource created by either kubectl create --save-config or kubectl apply
deployment.apps "wordpress-deploy" configured
创建完成后,查看下svc:
$ kubectl get svc -n blog
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
mysql ClusterIP 10.98.27.19 <none> 3306/TCP 25m
wordpress NodePort 10.101.7.69 <none> 80:32255/TCP 1m
可以看到wordpress服务产生了一个32255的端口,现在我们是不是就可以通过任意节点的NodeIP加上32255端口,就可以访问我们的wordpress应用了,在浏览器中打开,如果看到wordpress跳转到了安装页面,证明我们的嗯安装是没有任何问题的了,如果没有出现预期的效果,那么就需要去查看下Pod的日志来查看问题了:
然后根据页面提示,填上对应的信息,点击“安装”即可,最终安装成功后,我们就可以看到熟悉的首页界面了:
提高稳定性
现在wordpress应用已经部署成功了,那么就万事大吉了吗?如果我们的网站访问量突然变大了怎么办,如果我们要更新我们的镜像该怎么办?如果我们的mysql服务挂掉了怎么办?
所以要保证我们的网站能够非常稳定的提供服务,我们做得还不够,我们可以通过做些什么事情来提高网站的稳定性呢?
第一. 增加健康检测,我们前面说过liveness probe和rediness probe是提高应用稳定性非常重要的方法:
livenessProbe:
tcpSocket:
port: 80
initialDelaySeconds: 3
periodSeconds: 3
readinessProbe:
tcpSocket:
port: 80
initialDelaySeconds: 5
periodSeconds: 10
增加上面两个探针,每10s检测一次应用是否可读,每3s检测一次应用是否存活
第二. 增加 HPA,让我们的应用能够自动应对流量高峰期:
$ kubectl autoscale deployment wordpress-deploy --cpu-percent=10 --min=1 --max=10 -n blog
deployment "wordpress-deploy" autoscaled
我们用kubectl autoscale命令为我们的wordpress-deploy创建一个HPA对象,最小的 pod 副本数为1,最大为10,HPA会根据设定的 cpu使用率(10%)动态的增加或者减少pod数量。当然最好我们也为Pod声明一些资源限制:
resources:
limits:
cpu: 200m
memory: 200Mi
requests:
cpu: 100m
memory: 100Mi
更新Deployment后,我们可以可以来测试下上面的HPA是否会生效:
$ kubectl run -i --tty load-generator --image=busybox /bin/sh
If you don't see a command prompt, try pressing enter.
/ # while true; do wget -q -O- http://10.244.1.62:80; done
观察Deployment的副本数是否有变化
$ kubectl get deployment wordpress-deploy
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
wordpress-deploy 3 3 3 3 4d
第三. 增加滚动更新策略,这样可以保证我们在更新应用的时候服务不会被中断:
replicas: 2
revisionHistoryLimit: 10
minReadySeconds: 5
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
第四. 我们知道如果mysql服务被重新创建了的话,它的clusterIP非常有可能就变化了,所以上面我们环境变量中的WORDPRESS_DB_HOST的值就会有问题,就会导致访问不了数据库服务了,这个地方我们可以直接使用Service的名称来代替host,这样即使clusterIP变化了,也不会有任何影响,这个我们会在后面的服务发现的章节和大家深入讲解的:
env:
- name: WORDPRESS_DB_HOST
value: mysql:3306
第五. 我们在部署wordpress服务的时候,mysql服务以前启动起来了吗?如果没有启动起来是不是我们也没办法连接数据库了啊?该怎么办,是不是在启动wordpress应用之前应该去检查一下mysql服务,如果服务正常的话我们就开始部署应用了,这是不是就是InitContainer的用法:
initContainers:
- name: init-db
image: busybox
command: ['sh', '-c', 'until nslookup mysql; do echo waiting for mysql service; sleep 2; done;']
直到mysql服务创建完成后,initContainer才结束,结束完成后我们才开始下面的部署。
最后,我们把部署的应用整合到一个YAML文件中来:(wordpress-all.yaml)
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: mysql-deploy
namespace: blog
labels:
app: mysql
spec:
template:
metadata:
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql:5.7
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: blog
spec:
selector:
app: mysql
ports:
- name: mysqlport
protocol: TCP
port: 3306
targetPort: dbport
---
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: wordpress-deploy
namespace: blog
labels:
app: wordpress
spec:
revisionHistoryLimit: 10
minReadySeconds: 5
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
template:
metadata:
labels:
app: wordpress
spec:
initContainers:
- name: init-db
image: busybox
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: blog
spec:
selector:
app: wordpress
type: NodePort
ports:
- name: wordpressport
protocol: TCP
port: 80
nodePort: 32255
targetPort: wdport
我们这里主要是针对的wordpress来做的提高稳定性的方法,如何对mysql提高一些稳定性呢?大家下去可以试一试,我们接下来会和大家讲解mysql这类有状态的应用在Kubernetes当中的使用方法。
最后,我们来把前面我们部署的相关服务全部删掉,重新通过上面的YAML文件来创建:
$ kubectl create -f wordpress-all.yaml
deployment.apps "mysql-deploy" created
service "mysql" created
deployment.apps "wordpress-deploy" created
service "wordpress" created
看看最后能不能得到我们的最终成果呢?