问题:

    1. 有雀在虚拟化(Libvirt)部署时,worker 节点可以动态调整(横向扩展),导致 ingress(80、443端口) 的地址可能随机掉落到某两个worker节点,导致apps方式提供的路由无法访问。

    2. 虚拟化部署的节点均为NAT网络,虚拟化提供的dnsmasq 解析apps 域名只能解析到一个节点,但ingress是两个节点,无法做到dns级负载均衡。 如果改用dnsmasq的addn-hosts 就无法进行泛解析。

    3. 离线部署,宿主机上的 registry镜像仓库与负载均衡器 80、443端口冲突,只能用http代理,无法使用tcp代理。

分析:

   ingress 是通过deployment 方式部署两个ingress pod,然后这两个pod 做端口映射到pod所在节点,开放80、443两个端口提供路由服务。

现状:

    通过 podman network 创建一个桥接网路, 分配172.10.0.0/24 网段, registry-1 分配 172.10.0.5:5000 、registry-2 分配 172.10.0.6:5000、registry-3 分配 172.10.0.7:5000 。通过nginx 区分镜像仓库项目名进行流量转发(只能是http代理) 占用443端口。

  server {
    listen              443 ssl;
    server_name         registry.uniontech.com;
    ......

    location /v2/uccps-components/  {
        proxy_pass http://registry-1;
    }

    location /v2/uccps-samples/ {
        proxy_pass http://registry-2;
    }

    location /v2/uos-container/ {
        proxy_pass http://registry-3;
    }

    但外部访问NAT网络下的集群也需要一层代理,而且也在宿主机,因此也会占用 宿主机的443, 被迫使用nginx 区分 SNI实现分流。

    但nginx的check模块并不好使,入栈流量在200多个ip内不停轮询,导致服务访问异常缓慢。

统信有雀-负载均衡端口冲突解决方法_解决方法

解决方法 1:

既然 dnsmasq 的泛解析 不能使用addn-hosts,那就用coredns 写一个插件,corefile给定一个网段,指定监测的端口,及dns 返回规则,可以实现每次dns请求都会准确的到达ingress所在的节点,配合nginx的resolver 实现dns级别的负载均衡。

# Corefile
# 注: 未实现插件
.:53 {
....
    ipset {
        # 指定要查询的ip段
        ipset 192.168.120.0/24
        # 检测端口
        check_port 443
        # dns 返回策略 随机
        dns_policy random
        # 缓存超时 1分钟
        cache_timeout 1m
        # 缓存大小,仅缓存两个ip
        cache_size 2
        # 无法解析的dns 传递到下一个插件
        fallthrough
    }
....
}

# nginx 配置
resolver 192.168.120.1;
server {
      listen              443;
      server_name         *.apps.libvirt-22.example.com;
      ....
 	  location / {
          proxy_pass https://$hosts;
          ....
      }
}

解决方法2:

    给registry挪个位置, 443 ---> 5000,利用有雀提供的 ImageContentSourcePolicy api,实现 crio 的mirror功能,也就是 拉取的镜像地址为 registry.uniontech.com/uccps/nginx:latest 在拉取过程中这将被替换为 registry.uniontech.com:5000/uccps/nginx:latest , 然后443 端口可以被haproxy独占,可以使用tcp 负载均衡,搭配 haproxy的check模块检测 每个ip的443端口,实现流量能转发到特定的两个节点。

apiVersion: operator.openshift.io/v1alpha1
kind: ImageContentSourcePolicy
metadata:
  name: images-mirror-test
spec:
  repositoryDigestMirrors:
  # 这将 所有 registry.uniontech.com 替换成 registry.uniontech.com:5000
  # 不影响镜像的拉取、存放、运行
  - mirrors:
    - registry.uniontech.com:5000
    source: registry.uniontech.com
    mirrorByDigestOnly: false
    
# haproxy.cfg
global
    log         127.0.0.1 local2
    chroot      /var/lib/haproxy
    pidfile     /var/run/haproxy.pid
    maxconn     4000
    user        haproxy
    group       haproxy
    daemon
    stats socket /var/lib/haproxy/stats

defaults
    log                     global
    option                  tcplog
    option                  dontlognull
    timeout connect         2s
    timeout client          1m
    timeout server          1m
    timeout check           200

frontend ingress-https
    bind *:443
    default_backend ingress-https
    mode tcp

backend ingress-https
    balance source
    mode tcp
    # 下面就可以写整个Machine Network CIDR地址
    # 
    server worker51 192.168.217.51:443 check
    server worker52 192.168.217.52:443 check
    .........
    server worker52 192.168.217.254:443 check

但 ImageContentSourcePolicy 只能根据 digest 拉取的镜像,无法使用tag拉取。 因此 通过machine config配置一个 containers 的registry.conf 文件。

写一个 registry.conf

[[registry]]
  prefix = ""
  location = "registry.uniontech.com"
  insecure = true
  mirror-by-digest-only = false

  [[registry.mirror]]
    location = "registry.uniontech.com:5000"
    insecure = true

[[registry]]
  prefix = ""
  # 如果没有证书,就需要配置免密
  location = "registry.uniontech.com:5000"
  insecure = true

base64 加密上述文件

base64 -w0 registry.conf
W1tyZWdpc3RyeV1dCiAgcHJlZml4ID0gCiAgbG9jYXRpb24gPSByZWdpc3RyeS51bmlvbnRlY2guY29tCiAgaW5zZWN1cmUgPSB0cnVlCiAgbWlycm9yLWJ5LWRpZ2VzdC1vbmx5ID0gZmFsc2UKCiAgW1tyZWdpc3RyeS5taXJyb3JdXQogICAgbG9jYXRpb24gPSByZWdpc3RyeS51bmlvbnRlY2guY29tOjUwMDAKICAgIGluc2VjdXJlID0gdHJ1ZQoKW1tyZWdpc3RyeV1dCiAgcHJlZml4ID0gCiAgIyDlpoLmnpzmsqHmnInor4HkuabvvIzlsLHpnIDopoHphY3nva7lhY3lr4YKICBsb2NhdGlvbiA9IHJlZ2lzdHJ5LnVuaW9udGVjaC5jb206NTAwMAogIGluc2VjdXJlID0gdHJ1ZQo=

编写 一个machine config配置 (worker同样需要)

apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
metadata:
  labels:
    machineconfiguration.openshift.io/role: master
  name: 99-master-mirror-by-digest-registries
spec:
  config:
    ignition:
      version: 3.1.0
    storage:
      files:
      - contents:
          source: data:text/plain;charset=utf-8;base64,W1tyZWdpc3RyeV1dCiAgcHJlZml4ID0gCiAgbG9jYXRpb24gPSByZWdpc3RyeS51bmlvbnRlY2guY29tCiAgaW5zZWN1cmUgPSB0cnVlCiAgbWlycm9yLWJ5LWRpZ2VzdC1vbmx5ID0gZmFsc2UKCiAgW1tyZWdpc3RyeS5taXJyb3JdXQogICAgbG9jYXRpb24gPSByZWdpc3RyeS51bmlvbnRlY2guY29tOjUwMDAKICAgIGluc2VjdXJlID0gdHJ1ZQoKW1tyZWdpc3RyeV1dCiAgcHJlZml4ID0gCiAgIyDlpoLmnpzmsqHmnInor4HkuabvvIzlsLHpnIDopoHphY3nva7lhY3lr4YKICBsb2NhdGlvbiA9IHJlZ2lzdHJ5LnVuaW9udGVjaC5jb206NTAwMAogIGluc2VjdXJlID0gdHJ1ZQo=
        filesystem: root
        mode: 420
        path: /etc/containers/registries.conf.d/99-master-mirror-by-digest-registries.conf

应用 machine config

oc apply -f 99-master-mirror-by-digest-registries.yaml

现在master和worker节点可以通过5000端口拉取镜像,不用修改其余配置。但部署集群时引导节点会有问题,引导节点并不应用machine config, 因为没有 机器配置池。因此需要对 引导节点的ignition进行修改

# 把上述 base64 加到 引导节点的ign里,帮助引导节点拉取镜像
jq '.storage.files[0].contents.source += "W1tyZWdpc3RyeV1dCiAgcHJlZml4ID0gCiAgbG9jYXRpb24gPSByZWdpc3RyeS51bmlvbnRlY2guY29tCiAgaW5zZWN1cmUgPSB0cnVlCiAgbWlycm9yLWJ5LWRpZ2VzdC1vbmx5ID0gZmFsc2UKCiAgW1tyZWdpc3RyeS5taXJyb3JdXQogICAgbG9jYXRpb24gPSByZWdpc3RyeS51bmlvbnRlY2guY29tOjUwMDAKICAgIGluc2VjdXJlID0gdHJ1ZQoKW1tyZWdpc3RyeV1dCiAgcHJlZml4ID0gCiAgIyDlpoLmnpzmsqHmnInor4HkuabvvIzlsLHpnIDopoHphY3nva7lhY3lr4YKICBsb2NhdGlvbiA9IHJlZ2lzdHJ5LnVuaW9udGVjaC5jb206NTAwMAogIGluc2VjdXJlID0gdHJ1ZQo="' bootstrap.ign.json  > bootstrap.ign
mv bootstrap.ign.json bootstrap.ign


总结:

 除了这两种方法,还有一些比较奇葩的解决方法,就不再提了。

 两种方法各有优劣,第一种得写一个coredns 插件。 第二种虽然能镜像到5000端口,但过程繁复。

 tcp 负载效率比http高出不少,随缘取舍吧。

 容器并不是所有的场景都需要加 privileged 权限,也不是所有场景都要用 host网络,云场景下安全性不得不考虑。