「实战记录」集群部署nginx

232 阅读4分钟

为什么需要负载均衡

只要不是可以简化到极致的demo或学习练习工程,一个完整的业务系统都至少分为前端和后端两大部分,前端和后端各自又可能由多个模块组成。

如果没有负载均衡,用户可能会像直接接触到系统内部架构一样,要小心区分自己应该访问哪个地址,要自己记住同一服务的多个实例的地址。

这样一来,用户使用极为不方便,把内部架构暴露在所有用户面前,系统本身面临的风险增大。

7层和4层负载均衡

以下是把最常见的几项功能逻辑出来,并不代表4层和7层负载的差别只有这些。

考虑到所在项目是一个B端系统,并不存在非常高的并发要求,反而要能比较低成本地灵活应对业务需求,选择Nginx更加合适。

功能项4层负载均衡7层负载均衡
分发所在层级传输层应用层
端口范围无限制最大端口65535
支持协议TCP/IPHTTP、HTTPS和DNS等
改写请求头信息不支持支持
根据URL匹配不支持支持
运行效率非常高比较高,比4层的低
代表产品LVS、F5Nginx、HAProxy

Nginx的常用能力

  • 负载均衡;

  • 反向代理;

  • 缓存;

  • 流量控制。

在这里,主要描述Nginx提供反向代理和负载均衡的实践用法。

如何在容器化环境中部署Nginx

  1. 使用Nginx镜像,创建有状态负载;
  2. 通过nginx-ingress插件,直接创建Ingress(路由)

通过Nginx镜像安装

  1. 获取Nginx镜像,如果系统本身的镜像仓库中还没有,最好从网络上的中心仓库拉取并上传到自身的仓库;
# 第1步
docker pull
# 第2步
docker tag
# 第3步
docker login
# 第4步
docker push
  1. 编写相应的yaml文件,通过命令行或可视化界面创建有状态负载;

  2. 通过configMap或hostPath的方式挂载配置文件nginx.conf;

  3. 在启动时指定配置文件nginx.conf,指定方式可以参考如下两种。

containers:
  - name: nginx-test
    image: 'nginx:alpine-perl'
    command:
      - nginx
    args:
      - '-g daemon off;'
      - '-c /xxx/nginx.conf'

或者

containers:
  - name: nginx-test
    image: 'nginx:alpine-perl'
    command:
      - nginx
    args:
      - '-g daemon off;'
      - '-c'
      - /xxx/nginx.conf

我相信上述两种指定配置文件的方法没错,在特定版本的nginx镜像下可以生效。

但是我自己在实际操作过程中,指定的配置文件一直没有生效/(ㄒoㄒ)/~~。

折腾了两天后,最终在其他人的提示下,改用了集群路由,因为我的项目中所有模块都部署在容器中。

安装Nginx-Ingress路由

  1. 在某个命名空间安装插件nginx-ingress,可以通过命令行,或者可视化的操作界面,比如我们在华为云安装它就很方便;

    image-20221031130959427

  2. 因为是HTTPS协议的,要先创建密钥,命名为 mojiayi.com;

    kind: Secret
    type: IngressTLS
    apiVersion: v1
    metadata:
      name: mojiayi.com
      namespace: mojiayi-prod
    data:
      tls.crt: >-
        证书内容
      tls.key: >-
        私钥内容
    
    
  3. 编写nginx ingress的yaml文件,通过命令行或可视化界面创建路由;

    apiVersion: networking.k8s.io/v1beta1
    kind: Ingress
    metadata:
      name: mojiayi.com
      namespace: mojiayi-prod
      annotations:
        kubernetes.io/ingress.class: nginx
      managedFields:
        - manager: nginx-ingress-controller
          operation: Update
          apiVersion: networking.k8s.io/v1
    spec:
      tls:
        - secretName: mojiayi.com
      rules:
        - host: mojiayi.com
          http:
            paths:
              - path: /nacos
                pathType: ImplementationSpecific
                backend:
                  serviceName: nacos-cluster
                  servicePort: 8848
              - path: /xxl-job-admin
                pathType: ImplementationSpecific
                backend:
                  serviceName: xxl-job-admin
                  servicePort: 8080
              - path: /api
                pathType: ImplementationSpecific
                backend:
                  serviceName: mojiayi-gateway
                  servicePort: 8005
              - path: /admin-web
                pathType: ImplementationSpecific
                backend:
                  serviceName: admin-web
                  servicePort: 8099
              - path: /auth-web
                pathType: ImplementationSpecific
                backend:
                  serviceName: auth-web
                  servicePort: 8098
    status:
      loadBalancer:
        ingress:
          - ip: 173.26.102.63
          - ip: 173.26.102.62
    
  4. 本项目中部署了两个ingress实例,对ingress的负载在SLB那一层完成;

  5. spec.rules.http.paths.path中配置的路径,是接口地址或浏览器访问页面时域名后面的那段相对地址

  6. spec.rules.http.paths.backend.serviceName中指定的服务名,是集群访问类型ClusterIP Service中的服务名,为方便管理,一般与无状态负载实例名相同;

  7. spec.rules.http.paths.backend.servicePort中指定的端口,是集群访问类型ClusterIP Service中的端口port,为方便管理,一般与无状态负载实例的容器端口相同。

实践中踩到的坑

  • 多处添加HTTPS证书后,系统无法访问。因为本项目部署时,是在一个内网环境中。对外的域名解析有统一管理,已经添加了HTTPS证书。后来又在SLB和Ingress上添加了证书,导致请求收到之后不断地在域名解析、SLB和Ingress之间重定向。

    解决办法:只保留最外层的证书配置,删除SLB和Ingress上的证书。

重要的题外话

从理论到实践,从设计方案到真实运行的项目,要经历多少波折,只有亲历者才知道。我所写的操作步骤,也许不能直接被其他人复用。

如果能激发一点点解决问题的灵感,是我最大的荣幸~(≧▽≦)/~。

参考文档

  1. 华为云Kubernetes基础知识