Kubernetes部署Ingress+nginx+php+mysql问题集

最近在学习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

这样就可以在本机通过1637913306端口访问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面板截图

面板概览

default空间

Leave a Comment

豫ICP备19001387号-1