最近在学习Kubernetes,用它部署了Ingress,并用Ingress负载nginx,nginx转发到php服务里的php-fpm,php程序连接MySQL主从。
折腾了好几天,遇到不少问题,好在最后都解决了,列一下做个笔记。
集群环境选择
需要用物理机或虚拟机,不能在Docker下部署,保证在一个局域网内可互相访问,防火墙先关掉,swap内存要一直禁掉。
镜像同步
所有用到的镜像,在几个节点上都要同步拉取。
管理面板选择
Kubernetes Dashboard需要频繁登录,神烦,所以改用Kuboard,很好用。
Ingress装不上
这个多半是因为镜像拉取不到,可使用Kuboard里自带的一键安装,用起来都差不多。
MySQL StatefulSet初始化失败
多半也是因为镜像gcr.io/google-samples/xtrabackup:1.0
拉取不到,解决办法有多种,可以翻墙,也可以在别处拉取或基于原镜像build后再导进来。
写到这里想说一句,有必要搭建一个私有的镜像服务,以应对多节点的频繁拉取。
nginx镜像选择
一开始用官方Nginx镜像,碍于配置不全且不完全可控,最后还是基于Ubuntu20.04自己build了一个镜像。
php镜像选择
一开始也是用官方php:7.4-fpm
镜像的,但是也是很不好用,扩展有的能装有的装不上,装上了不能直接启用,所以最后也是Ubuntu20.04自己build了一个镜像。
容器启动问题
自建的镜像,通过Docker的run
命令可直接启动,但是在kubernetes下,要么启动不起来(启动后就退出),要么所需要的服务如nginx启动不了。原因在于要保持容器一直在运行,而不是执行完入口命令后就退出,这也是很多人推荐直接使用官方的nginx和php镜像的原因。但这始终是一个问题,不仅是在k8s中,即便在Docker下,这也是个大问题,如果解决不了,后面使用kubernetes还会一而再再而三地被它卡脖子。
解决办法:build镜像时,加个入口脚本,脚本内除了写要启动的命令外,最后加一个让容器一直运行不退出的命令。
比如,我的php镜像的Dockerfile最后一段是这么写的
ADD start.sh /usr/bin
RUN chmod +x /usr/bin/start.sh
EXPOSE 9000
ENTRYPOINT ["/usr/bin/start.sh"]
start.sh
内容如下
#!/bin/bash
# 启动php-fpm
/etc/init.d/php7.4-fpm start
# 加上这一条,不然容器会自动退出
tail -f /dev/null
我这里用的tail -f /dev/null
,也可以用其它的,只要能让它一直运行下去即可。那种一运行就结束的命令在Docker下或许可以,在Kubernetes下不一定管用,比如/bin/bash
。
Ingress代理nginx
apiVersionextensions/v1beta1
已过时,需要使用新的API,写法上有变化,但是更好用了。
示例配置
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
labels:
k8s.kuboard.cn/layer: web
k8s.kuboard.cn/name: web-nginx
name: web-nginx
namespace: default
spec:
ingressClassName: nginx
rules:
- host: www.testapp.com
http:
paths:
- backend:
service:
name: web-nginx
port:
number: 80
path: /
pathType: Prefix
Ingress代理MySQL
有人说由于Ingress走的是HTTP协议,而MySQL是TCP协议,所以Ingress可以代理Nginx而不能代理MySQL。如果需要临时用客户端连接MySQL或Redis,可以使用端口转发。
命令
kubectl port-forward service/web-redis 16379:6379
kubectl port-forward -n mysql service/mysql-readwrite 13306:3306
这样就可以在本机通过16379
和13306
端口访问default下的web-redis
和mysql命名空间下的mysql-readwrite
服务,而且加上参数--address 0.0.0.0
就可以从任意地址访问。
实际上Ingress也可以代理TCP/UDP协议,只是需要特定的Ingress版本,配置起来也比较麻烦,先不整它了。
Redis集群
Redis集群还没有找到太好的方法,其实单机版也完全够用了,不同的业务使用不同的Redis节点就好。
Redis节点搭建好后,将PHP的缓存和session都设置为由Redis存储,这样就可以实现分布式访问了。
节点挂掉
从节点挂掉,集群大概会在15秒内收到失联通知。如果挂掉的节点上运行的有Pod,而某一个Deployment当前所正常运行的Pod不满足设置的Replicas时,会在挂掉的节点持续失联约5分钟后在别的正常节点上重新启动新Pod。
主节点挂掉会怎么样?正常节点上的服务还能访问,此时需要将域名重新指向,不过集群不能再正常管理了, Kuboard访问不了。
至此Kubernetes下的Ingress+nginx+php+mysql集群算是搭建完成了,并可轻松扩展。
最后晒一下本地的Kubernetes Kuboard面板截图