部署 Wordpress 示例

    现在我们来看看如何来部署我们的这个wordpress应用

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

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

    1. apiVersion: v1
    2. kind: Pod
    3. metadata:
    4. name: wordpress
    5. namespace: blog
    6. spec:
    7. containers:
    8. - name: wordpress
    9. image: wordpress
    10. ports:
    11. - containerPort: 80
    12. name: wdport
    13. env:
    14. - name: WORDPRESS_DB_HOST
    15. value: localhost: 3306
    16. - name: WORDPRESS_DB_USER
    17. value: wordpress
    18. - name: WORDPRESS_DB_PASSWORD
    19. value: wordpress
    20. - name: mysql
    21. image: mysql:5.7
    22. imagePullPolicy: IfNotPresent
    23. ports:
    24. - containerPort: 3306
    25. name: dbport
    26. env:
    27. - name: MYSQL_ROOT_PASSWORD
    28. value: rootPassW0rd
    29. - name: MYSQL_DATABASE
    30. value: wordpress
    31. - name: MYSQL_USER
    32. value: wordpress
    33. - name: MYSQL_PASSWORD
    34. value: wordpress
    35. volumeMounts:
    36. - name: db
    37. mountPath: /var/lib/mysql
    38. volumes:
    39. - name: db
    40. hostPath:
    41. path: /var/lib/mysql

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

    1. $ kubectl create -f wrodpress-pod.yaml
    2. pod "wordpress" created

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

    1. $ kubectl describe pod wordpress -n blog

    大家可以看看我们现在这种单一Pod的方式有什么缺点?假如我们现在需要部署3个Wordpress的副本,该怎么办?是不是我们只需要在上面的YAML文件中加上replicas: 3这个属性就可以了啊?但是有个什么问题呢?是不是不仅仅是Wordpress这个容器会被部署成3份,连我们的MySQL数据库也会被部署成3份了呢?MySQL数据库单纯的部署成3份他们能联合起来使用吗?不能,如果真的这么简单的话就不需要各种数据库集群解决方案了,所以我们这里部署3个Pod实例,实际上他们互相之间是独立的,因为数据不想通,明白吧?所以该怎么办?拆分呗,把wordpressmysql这两个容器部署成独立的Pod是不是就可以了。

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

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

    第一步,创建一个MySQLDeployment对象:(wordpress-db.yaml)

    1. ---
    2. apiVersion: apps/v1beta1
    3. kind: Deployment
    4. metadata:
    5. name: mysql-deploy
    6. namespace: blog
    7. labels:
    8. app: mysql
    9. spec:
    10. template:
    11. metadata:
    12. labels:
    13. app: mysql
    14. spec:
    15. containers:
    16. - name: mysql
    17. image: mysql:5.7
    18. imagePullPolicy: IfNotPresent
    19. ports:
    20. - containerPort: 3306
    21. name: dbport
    22. env:
    23. - name: MYSQL_ROOT_PASSWORD
    24. value: rootPassW0rd
    25. - name: MYSQL_DATABASE
    26. value: wordpress
    27. - name: MYSQL_USER
    28. value: wordpress
    29. - name: MYSQL_PASSWORD
    30. value: wordpress
    31. volumeMounts:
    32. - name: db
    33. mountPath: /var/lib/mysql
    34. volumes:
    35. - name: db
    36. hostPath:
    37. path: /var/lib/mysql

    如果我们只创建上面的Deployment这个对象,那么我们应该怎样让后面的Wordpress来访问呢?貌似没办法是吧,之前在一个Pod里面还可以使用localhost来进行访问,现在分开了该怎样访问呢?还记得前面的Service吗?没错,使用Service就可以了,所以我们在上面的wordpress-db.yaml文件中添加上Service的信息:

    1. ---
    2. apiVersion: v1
    3. kind: Service
    4. metadata:
    5. name: mysql
    6. spec:
    7. selector:
    8. app: mysql
    9. ports:
    10. - name: mysqlport
    11. protocol: TCP
    12. port: 3306
    13. targetPort: dbport

    然后创建上面的wordpress-db.yaml文件:

    1. $ kubectl create -f wordpress-db.yaml
    2. service "mysql" created
    3. deployment.apps "mysql-deploy" created
    1. Name: mysql
    2. Namespace: blog
    3. Labels: <none>
    4. Annotations: <none>
    5. Selector: app=mysql
    6. Type: ClusterIP
    7. IP: 10.98.27.19
    8. Port: mysqlport 3306/TCP
    9. TargetPort: dbport/TCP
    10. Endpoints: 10.244.2.213:3306
    11. Session Affinity: None
    12. Events: <none>

    可以看到Endpoints部分匹配到了一个Pod,生成了一个clusterIP10.98.27.19,现在我们是不是就可以通过这个clusterIP加上定义的3306端口就可以正常访问我们这个mysql服务了。

    第二步. 创建Wordpress服务,将上面的wordpressPod转换成Deployment对象:(wordpress.yaml)

    注意这里的环境变量WORDPRESS_DB_HOST的值将之前的localhost地址更改成了上面mysql服务的clusterIP地址了,然后创建上面的Deployment对象:

    1. $ kubectl create -f wordpress.yaml
    2. deployment.apps "wordpress-deploy" created

    创建完成后,我们可以看看我们创建的Pod的状态:

    1. $ kubectl get pods -n blog
    2. NAME READY STATUS RESTARTS AGE
    3. mysql-deploy-86bdcc7484-fv2dj 1/1 Running 0 19m
    4. wordpress-deploy-784cfd6dd4-d9f52 1/1 Running 0 23s

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

    1. ---
    2. apiVersion: v1
    3. kind: Service
    4. metadata:
    5. name: wordpress
    6. namespace: blog
    7. spec:
    8. type: NodePort
    9. selector:
    10. app: wordpress
    11. ports:
    12. - name: wordpressport
    13. protocol: TCP
    14. port: 80
    15. targetPort: wdport

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

    1. $ kubectl apply -f wordpress.yaml
    2. service "wordpress" created
    3. Warning: kubectl apply should be used on resource created by either kubectl create --save-config or kubectl apply
    4. deployment.apps "wordpress-deploy" configured

    创建完成后,查看下svc

    1. $ kubectl get svc -n blog
    2. NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
    3. mysql ClusterIP 10.98.27.19 <none> 3306/TCP 25m
    4. wordpress NodePort 10.101.7.69 <none> 80:32255/TCP 1m

    可以看到wordpress服务产生了一个32255的端口,现在我们是不是就可以通过任意节点的NodeIP加上32255端口,就可以访问我们的wordpress应用了,在浏览器中打开,如果看到wordpress跳转到了安装页面,证明我们的嗯安装是没有任何问题的了,如果没有出现预期的效果,那么就需要去查看下Pod的日志来查看问题了:

    然后根据页面提示,填上对应的信息,点击“安装”即可,最终安装成功后,我们就可以看到熟悉的首页界面了:
    wordpress-home

    现在wordpress应用已经部署成功了,那么就万事大吉了吗?如果我们的网站访问量突然变大了怎么办,如果我们要更新我们的镜像该怎么办?如果我们的mysql服务挂掉了怎么办?

    所以要保证我们的网站能够非常稳定的提供服务,我们做得还不够,我们可以通过做些什么事情来提高网站的稳定性呢?

    1. livenessProbe:
    2. tcpSocket:
    3. port: 80
    4. initialDelaySeconds: 3
    5. periodSeconds: 3
    6. readinessProbe:
    7. tcpSocket:
    8. port: 80
    9. initialDelaySeconds: 5
    10. periodSeconds: 10

    增加上面两个探针,每10s检测一次应用是否可读,每3s检测一次应用是否存活

    第二. 增加 HPA,让我们的应用能够自动应对流量高峰期:

    1. $ kubectl autoscale deployment wordpress-deploy --cpu-percent=10 --min=1 --max=10 -n blog
    2. deployment "wordpress-deploy" autoscaled

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

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

    1. $ kubectl run -i --tty load-generator --image=busybox /bin/sh
    2. If you don't see a command prompt, try pressing enter.
    3. / # while true; do wget -q -O- http://10.244.1.62:80; done

    观察Deployment的副本数是否有变化

    1. $ kubectl get deployment wordpress-deploy
    2. NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
    3. wordpress-deploy 3 3 3 3 4d

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

    1. replicas: 2
    2. revisionHistoryLimit: 10
    3. minReadySeconds: 5
    4. strategy:
    5. type: RollingUpdate
    6. rollingUpdate:
    7. maxSurge: 1
    8. maxUnavailable: 1

    第四. 我们知道如果mysql服务被重新创建了的话,它的clusterIP非常有可能就变化了,所以上面我们环境变量中的WORDPRESS_DB_HOST的值就会有问题,就会导致访问不了数据库服务了,这个地方我们可以直接使用Service的名称来代替host,这样即使clusterIP变化了,也不会有任何影响,这个我们会在后面的服务发现的章节和大家深入讲解的:

    1. env:
    2. - name: WORDPRESS_DB_HOST
    3. value: mysql:3306

    第五. 我们在部署wordpress服务的时候,mysql服务以前启动起来了吗?如果没有启动起来是不是我们也没办法连接数据库了啊?该怎么办,是不是在启动wordpress应用之前应该去检查一下mysql服务,如果服务正常的话我们就开始部署应用了,这是不是就是InitContainer的用法:

    1. initContainers:
    2. - name: init-db
    3. command: ['sh', '-c', 'until nslookup mysql; do echo waiting for mysql service; sleep 2; done;']

    直到mysql服务创建完成后,initContainer才结束,结束完成后我们才开始下面的部署。

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

    1. ---
    2. apiVersion: apps/v1beta1
    3. kind: Deployment
    4. metadata:
    5. name: mysql-deploy
    6. namespace: blog
    7. labels:
    8. app: mysql
    9. spec:
    10. template:
    11. metadata:
    12. labels:
    13. app: mysql
    14. spec:
    15. containers:
    16. - name: mysql
    17. image: mysql:5.7
    18. ports:
    19. - containerPort: 3306
    20. name: dbport
    21. env:
    22. - name: MYSQL_ROOT_PASSWORD
    23. value: rootPassW0rd
    24. - name: MYSQL_DATABASE
    25. value: wordpress
    26. - name: MYSQL_USER
    27. value: wordpress
    28. value: wordpress
    29. volumeMounts:
    30. - name: db
    31. mountPath: /var/lib/mysql
    32. volumes:
    33. - name: db
    34. hostPath:
    35. path: /var/lib/mysql
    36. ---
    37. apiVersion: v1
    38. kind: Service
    39. metadata:
    40. name: mysql
    41. namespace: blog
    42. spec:
    43. selector:
    44. app: mysql
    45. ports:
    46. - name: mysqlport
    47. protocol: TCP
    48. port: 3306
    49. targetPort: dbport
    50. ---
    51. apiVersion: apps/v1beta1
    52. kind: Deployment
    53. metadata:
    54. name: wordpress-deploy
    55. namespace: blog
    56. labels:
    57. app: wordpress
    58. spec:
    59. revisionHistoryLimit: 10
    60. minReadySeconds: 5
    61. strategy:
    62. type: RollingUpdate
    63. rollingUpdate:
    64. maxSurge: 1
    65. maxUnavailable: 1
    66. template:
    67. metadata:
    68. labels:
    69. app: wordpress
    70. spec:
    71. initContainers:
    72. - name: init-db
    73. image: busybox
    74. command: ['sh', '-c', 'until nslookup mysql; do echo waiting for mysql service; sleep 2; done;']
    75. containers:
    76. - name: wordpress
    77. image: wordpress
    78. imagePullPolicy: IfNotPresent
    79. ports:
    80. - containerPort: 80
    81. name: wdport
    82. env:
    83. - name: WORDPRESS_DB_HOST
    84. value: mysql:3306
    85. - name: WORDPRESS_DB_USER
    86. value: wordpress
    87. - name: WORDPRESS_DB_PASSWORD
    88. value: wordpress
    89. livenessProbe:
    90. tcpSocket:
    91. port: 80
    92. initialDelaySeconds: 3
    93. periodSeconds: 3
    94. readinessProbe:
    95. tcpSocket:
    96. port: 80
    97. initialDelaySeconds: 5
    98. periodSeconds: 10
    99. resources:
    100. limits:
    101. cpu: 200m
    102. memory: 200Mi
    103. requests:
    104. cpu: 100m
    105. memory: 100Mi
    106. ---
    107. apiVersion: v1
    108. kind: Service
    109. metadata:
    110. name: wordpress
    111. namespace: blog
    112. spec:
    113. selector:
    114. app: wordpress
    115. type: NodePort
    116. ports:
    117. - name: wordpressport
    118. protocol: TCP
    119. port: 80
    120. nodePort: 32255
    121. targetPort: wdport

    我们这里主要是针对的wordpress来做的提高稳定性的方法,如何对mysql提高一些稳定性呢?大家下去可以试一试,我们接下来会和大家讲解mysql这类有状态的应用在Kubernetes当中的使用方法。

    1. $ kubectl create -f wordpress-all.yaml
    2. deployment.apps "mysql-deploy" created
    3. service "mysql" created
    4. service "wordpress" created

    看看最后能不能得到我们的最终成果呢?