- 部署 Wordpress 示例
- 一个Pod
- 两个Pod
- 提高稳定性
部署 Wordpress 示例
前面的课程中我们基本上了解了Kubernetes当中常见的一些对象资源,这节课我们就来利用前面学习的知识点来部署一个实际的应用 - 将Wordpress应用部署到我们的集群当中,我们前面是不是已经用docker-compose的方式部署过了,我们可以了解到要部署一个Wordpress应用主要涉及到两个镜像:wordpress和mysql,wordpress是应用的核心程序,mysql是用于数据存储的。
现在我们来看看如何来部署我们的这个wordpress应用
一个Pod
我们知道一个Pod中可以包含多个容器,那么很明显我们这里是不是就可以将wordpress部署成一个独立的Pod?我们将我们的应用都部署到blog这个命名空间下面,所以先创建一个命名空间:
$ kubectl create namespace blognamespace "blog" created
然后来编写YAML文件:(wordpress-pod.yaml)
apiVersion: v1kind: Podmetadata:name: wordpressnamespace: blogspec:containers:- name: wordpressimage: wordpressports:- containerPort: 80name: wdportenv:- name: WORDPRESS_DB_HOSTvalue: localhost: 3306- name: WORDPRESS_DB_USERvalue: wordpress- name: WORDPRESS_DB_PASSWORDvalue: wordpress- name: mysqlimage: mysql:5.7imagePullPolicy: IfNotPresentports:- containerPort: 3306name: dbportenv:- name: MYSQL_ROOT_PASSWORDvalue: rootPassW0rd- name: MYSQL_DATABASEvalue: wordpress- name: MYSQL_USERvalue: wordpress- name: MYSQL_PASSWORDvalue: wordpressvolumeMounts:- name: dbmountPath: /var/lib/mysqlvolumes:- name: dbhostPath:path: /var/lib/mysql
要注意这里针对mysql这个容器我们做了一个数据卷的挂载,这是为了能够将mysql的数据能够持久化到节点上,这样下次mysql容器重启过后数据不至于丢失。
然后创建上面的Pod:
$ kubectl create -f wrodpress-pod.yamlpod "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/v1beta1kind: Deploymentmetadata:name: mysql-deploynamespace: bloglabels:app: mysqlspec:template:metadata:labels:app: mysqlspec:containers:- name: mysqlimage: mysql:5.7imagePullPolicy: IfNotPresentports:- containerPort: 3306name: dbportenv:- name: MYSQL_ROOT_PASSWORDvalue: rootPassW0rd- name: MYSQL_DATABASEvalue: wordpress- name: MYSQL_USERvalue: wordpress- name: MYSQL_PASSWORDvalue: wordpressvolumeMounts:- name: dbmountPath: /var/lib/mysqlvolumes:- name: dbhostPath:path: /var/lib/mysql
如果我们只创建上面的Deployment这个对象,那么我们应该怎样让后面的Wordpress来访问呢?貌似没办法是吧,之前在一个Pod里面还可以使用localhost来进行访问,现在分开了该怎样访问呢?还记得前面的Service吗?没错,使用Service就可以了,所以我们在上面的wordpress-db.yaml文件中添加上Service的信息:
---apiVersion: v1kind: Servicemetadata:name: mysqlnamespace: blogspec:selector:app: mysqlports:- name: mysqlportprotocol: TCPport: 3306targetPort: dbport
然后创建上面的wordpress-db.yaml文件:
$ kubectl create -f wordpress-db.yamlservice "mysql" createddeployment.apps "mysql-deploy" created
然后我们查看Service的详细情况:
$ kubectl describe svc mysql -n blogName: mysqlNamespace: blogLabels: <none>Annotations: <none>Selector: app=mysqlType: ClusterIPIP: 10.98.27.19Port: mysqlport 3306/TCPTargetPort: dbport/TCPEndpoints: 10.244.2.213:3306Session Affinity: NoneEvents: <none>
可以看到Endpoints部分匹配到了一个Pod,生成了一个clusterIP:10.98.27.19,现在我们是不是就可以通过这个clusterIP加上定义的3306端口就可以正常访问我们这个mysql服务了。
第二步. 创建Wordpress服务,将上面的wordpress的Pod转换成Deployment对象:(wordpress.yaml)
apiVersion: apps/v1beta1kind: Deploymentmetadata:name: wordpress-deploynamespace: bloglabels:app: wordpressspec:template:metadata:labels:app: wordpressspec:containers:- name: wordpressimage: wordpressimagePullPolicy: IfNotPresentports:- containerPort: 80name: wdportenv:- name: WORDPRESS_DB_HOSTvalue: 10.98.27.19:3306- name: WORDPRESS_DB_USERvalue: wordpress- name: WORDPRESS_DB_PASSWORDvalue: wordpress
注意这里的环境变量WORDPRESS_DB_HOST的值将之前的localhost地址更改成了上面mysql服务的clusterIP地址了,然后创建上面的Deployment对象:
$ kubectl create -f wordpress.yamldeployment.apps "wordpress-deploy" created
创建完成后,我们可以看看我们创建的Pod的状态:
$ kubectl get pods -n blogNAME READY STATUS RESTARTS AGEmysql-deploy-86bdcc7484-fv2dj 1/1 Running 0 19mwordpress-deploy-784cfd6dd4-d9f52 1/1 Running 0 23s
可以看到都已经是Running状态了,然后我们需要怎么来验证呢?是不是去访问下我们的wordpress服务就可以了,要访问,我们就需要建立一个能让外网用户访问的Service,前面我们学到过是不是NodePort类型的Service就可以?所以在上面的wordpress.yaml文件中添加上Service的信息:
---apiVersion: v1kind: Servicemetadata:name: wordpressnamespace: blogspec:type: NodePortselector:app: wordpressports:- name: wordpressportprotocol: TCPport: 80targetPort: wdport
注意要添加属性type: NodePort,然后重新更新wordpress.yaml文件:
$ kubectl apply -f wordpress.yamlservice "wordpress" createdWarning: kubectl apply should be used on resource created by either kubectl create --save-config or kubectl applydeployment.apps "wordpress-deploy" configured
创建完成后,查看下svc:
$ kubectl get svc -n blogNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGEmysql ClusterIP 10.98.27.19 <none> 3306/TCP 25mwordpress 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: 80initialDelaySeconds: 3periodSeconds: 3readinessProbe:tcpSocket:port: 80initialDelaySeconds: 5periodSeconds: 10
增加上面两个探针,每10s检测一次应用是否可读,每3s检测一次应用是否存活
第二. 增加 HPA,让我们的应用能够自动应对流量高峰期:
$ kubectl autoscale deployment wordpress-deploy --cpu-percent=10 --min=1 --max=10 -n blogdeployment "wordpress-deploy" autoscaled
我们用kubectl autoscale命令为我们的wordpress-deploy创建一个HPA对象,最小的 pod 副本数为1,最大为10,HPA会根据设定的 cpu使用率(10%)动态的增加或者减少pod数量。当然最好我们也为Pod声明一些资源限制:
resources:limits:cpu: 200mmemory: 200Mirequests:cpu: 100mmemory: 100Mi
更新Deployment后,我们可以可以来测试下上面的HPA是否会生效:
$ kubectl run -i --tty load-generator --image=busybox /bin/shIf 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-deployNAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGEwordpress-deploy 3 3 3 3 4d
第三. 增加滚动更新策略,这样可以保证我们在更新应用的时候服务不会被中断:
replicas: 2revisionHistoryLimit: 10minReadySeconds: 5strategy:type: RollingUpdaterollingUpdate:maxSurge: 1maxUnavailable: 1
第四. 我们知道如果mysql服务被重新创建了的话,它的clusterIP非常有可能就变化了,所以上面我们环境变量中的WORDPRESS_DB_HOST的值就会有问题,就会导致访问不了数据库服务了,这个地方我们可以直接使用Service的名称来代替host,这样即使clusterIP变化了,也不会有任何影响,这个我们会在后面的服务发现的章节和大家深入讲解的:
env:- name: WORDPRESS_DB_HOSTvalue: mysql:3306
第五. 我们在部署wordpress服务的时候,mysql服务以前启动起来了吗?如果没有启动起来是不是我们也没办法连接数据库了啊?该怎么办,是不是在启动wordpress应用之前应该去检查一下mysql服务,如果服务正常的话我们就开始部署应用了,这是不是就是InitContainer的用法:
initContainers:- name: init-dbimage: busyboxcommand: ['sh', '-c', 'until nslookup mysql; do echo waiting for mysql service; sleep 2; done;']
直到mysql服务创建完成后,initContainer才结束,结束完成后我们才开始下面的部署。
最后,我们把部署的应用整合到一个YAML文件中来:(wordpress-all.yaml)
---apiVersion: apps/v1beta1kind: Deploymentmetadata:name: mysql-deploynamespace: bloglabels:app: mysqlspec:template:metadata:labels:app: mysqlspec:containers:- name: mysqlimage: mysql:5.7ports:- containerPort: 3306name: dbportenv:- name: MYSQL_ROOT_PASSWORDvalue: rootPassW0rd- name: MYSQL_DATABASEvalue: wordpress- name: MYSQL_USERvalue: wordpress- name: MYSQL_PASSWORDvalue: wordpressvolumeMounts:- name: dbmountPath: /var/lib/mysqlvolumes:- name: dbhostPath:path: /var/lib/mysql---apiVersion: v1kind: Servicemetadata:name: mysqlnamespace: blogspec:selector:app: mysqlports:- name: mysqlportprotocol: TCPport: 3306targetPort: dbport---apiVersion: apps/v1beta1kind: Deploymentmetadata:name: wordpress-deploynamespace: bloglabels:app: wordpressspec:revisionHistoryLimit: 10minReadySeconds: 5strategy:type: RollingUpdaterollingUpdate:maxSurge: 1maxUnavailable: 1template:metadata:labels:app: wordpressspec:initContainers:- name: init-dbimage: busyboxcommand: ['sh', '-c', 'until nslookup mysql; do echo waiting for mysql service; sleep 2; done;']containers:- name: wordpressimage: wordpressimagePullPolicy: IfNotPresentports:- containerPort: 80name: wdportenv:- name: WORDPRESS_DB_HOSTvalue: mysql:3306- name: WORDPRESS_DB_USERvalue: wordpress- name: WORDPRESS_DB_PASSWORDvalue: wordpresslivenessProbe:tcpSocket:port: 80initialDelaySeconds: 3periodSeconds: 3readinessProbe:tcpSocket:port: 80initialDelaySeconds: 5periodSeconds: 10resources:limits:cpu: 200mmemory: 200Mirequests:cpu: 100mmemory: 100Mi---apiVersion: v1kind: Servicemetadata:name: wordpressnamespace: blogspec:selector:app: wordpresstype: NodePortports:- name: wordpressportprotocol: TCPport: 80nodePort: 32255targetPort: wdport
我们这里主要是针对的wordpress来做的提高稳定性的方法,如何对mysql提高一些稳定性呢?大家下去可以试一试,我们接下来会和大家讲解mysql这类有状态的应用在Kubernetes当中的使用方法。
最后,我们来把前面我们部署的相关服务全部删掉,重新通过上面的YAML文件来创建:
$ kubectl create -f wordpress-all.yamldeployment.apps "mysql-deploy" createdservice "mysql" createddeployment.apps "wordpress-deploy" createdservice "wordpress" created
看看最后能不能得到我们的最终成果呢?
