k8sday11服务发现(2/2)

本来打算是直接进行Ingress的学习,但是考虑到昨天Service的学习只是一知半解,很多流程没有很清晰,以及部分概念没有了解的很到位,所以打算在进行Ingress的学习之前进行我的个人理解和补充

Service个人理解+补充

1、加深概念理解

①、为什么需要Service(基本原理)

在k8s集群中,我们可以通过Pod的IP进行服务的访问,但是由于Pod频繁的创建和删除,导致Pod的IP并不固定 ,容易变化,这就会给要使用我们服务的用户带来不方便,用户无法通过固定的IP进行我们服务的访问 。k8s为了解决这个问题才引入的Service资源类型,Service会整合多个Pod,给这些Pod提供一个统一的、固定的IP地址,方便之后对这些Pod上面部署的服务的访问,而这个IP地址在Service的生命周期内是不变的,相当于给这些Pod提供了一个固定入口,用户不再需要访问Pod的IP,而是访问这个固定的入口(Service的IP)。

精简总结:++为了给用户提供一个固定IP入口访问Pod内部服务++

②、Service 是"虚拟入口"(核心原理)

Service只是一个概念,真正起作用的是kube-proxy进程。当我们创建了Service进程时,APIServer会向etcd存储写入刚刚你创建的Service的信息,而运行在每个Node节点上的kube-proxy,当**监控到了Service和Endpoint的信息变化,就会将最新的Service信息转换为对应的访问规则。**该生成的规则会在所有节点(主节点+Node副节点)生成。

精简总结:++监控到了Service和Endpoint的信息变化,kube-proxy就会将最新的Service信息转换为对应的访问规则++

③、Service选择器匹配

表面上看是 Service 选 Pod,实质上是 kube-proxy 根据标签选择器生成的 EndpointSlice,再把它变成内核里的负载均衡规则,最终由内核按规则加上LB算法策略进行选 Pod 转发。

精简总结:++Service通过Selector和Pod标签匹配,其实是kube-proxy进行了相应规则生成++

2、补充知识

①、何为访问规则(kube-proxy的工作模式)
维度 userspace(已废弃) iptables(默认) ipvs(推荐生产) nftables(未来主流)
内核依赖 任意 2.4+ 默认 需加载 ip_vs* 模块 ≥5.13,需 nftables
kube-proxy 担任的真实身份 用户态四层负载均衡器 内核 NAT 规则的"安装与维护者" IPVS 调度器的"配置器 + 兜底 iptables 安装者" nft set & nft rule 的"安装与维护者"
算法 轮询 随机 rr/wrr/lc/wlc/sh/dh... 随机(可扩展)
复杂度 O(n) 用户态 O(n) 规则链 O(1) hash 表 O(1) nft set
规模拐点 <50 服务就卡 1000 服务后 CPU↑ 1 万服务仍平稳 同 ipvs 或更好
延迟/CPU
热更新 全链刷新 增量更新 增量更新
与 NetworkPolicy 兼容性 需确认 CNI 支持 需确认 CNI 支持
kube-proxy 配置 无需 默认 mode: ipvs mode: nftables
备注 仅历史兼容 1.30 仍是默认 生产>100 节点必开 1.33 起 stable

总结:

  • userspace :用户发送请求到Cluster IP后经过iptables规则重新定向给kube-proxy,由kube-proxy充当一个负载均衡器,经过LB算法选择一个Pod,与之建立连接将请求发给Pod。(效率低)

  • iptables :用户发送请求到Cluster IP后经过iptables规则选择一个Pod,与之建立连接将请求发给Pod。kube-proxy只是用来生成iptables规则。(无灵活LB算法,当指向的Pod不可以时不可重试)

  • ipvs :用户发送请求到Cluster IP后经过iptables规则和LB算法选择一个Pod,与之建立连接将请求发给Pod。kube-proxy只是用来生成ipvs规则。(有灵活LB算法,效率高)

    • 要使用ipvs模式,需安装或加载并单独手动开启ipvs内核模块,否则默认是iptables模式
  • nftables :用户发送请求到Cluster IP后经过 nftables DNAT 规则(哈希查表)和LB算法选择一个Pod,与之建立连接将请求发给Pod。kube-proxy是用来写 nftables 规则 + set/映射。(无全局锁)

    • 要安装特殊插件,kube-proxy版本 1.33 起默认启用 nftables 模式,通过 --proxy-mode=nftables 显式切换,Service 数量破千或节点上百时才有明显优化感觉。
②、加载ipvs内核

IPVS 已经随主流 Linux 内核主线发布,通常不需要重新编译内核,只要加载对应模块即可(99% 的现代发行版默认已编译内核带 IPVS)。如果不确定,可以跟着以下步骤加载内核:(我只提供在WSL2的内核加载哈,如果是其他版本,可以问AI看看其他的检测方法)

Ⅰ、确认当前内核到底有没有 IPVS
bash 复制代码
  # 看内核编译选项(适用于 WSL2)
  zcat /proc/config.gz | grep -i 'IP_VS'
  ​
  # 输出类似效果即WSL2 内核已经完整编译了 IPVS 支持
  # CONFIG_IP_VS=m
  # CONFIG_IP_VS_IPV6=y
  # CONFIG_IP_VS_DEBUG=y
  # CONFIG_IP_VS_TAB_BITS=12
  # CONFIG_IP_VS_PROTO_TCP=y等等
Ⅱ、加载内核
bash 复制代码
  # 临时加载
  sudo modprobe ip_vs ip_vs_rr ip_vs_wrr ip_vs_lc ip_vs_sh nf_conntrack
  # 确认已加载
  lsmod | grep ip_vs   

将会输出类似结果:

③、测试访问服务

给出我的测试实例,只进行集群内服务的访问

Ⅰ、确保容器有多个(至少两个)
bash 复制代码
   kubectl get po -o wide
  ​
   # 如果发现只有一个容器,可以使用scale来扩容
   # 注意nginx-deployment1是我的deployment,记得改成自己的
   kubectl scale deployment nginx-deployment1 --replicas=<你要扩容的数量>
  ​
   # 如果扩容之后,过了一会发现容器移动缩容,可以看看是否是设置了HPA
   # 可选择修改其中最低容器数的配置或临时暂停
   kubectl get hpa
Ⅱ、进入容器并修改内容
bash 复制代码
   # 在使用kubectl get po -o wide查看了Pod名称后,选择你要进入的容器名
   kubectl exec -it <你要进入的容器名> /bin/bash
   
   # 修改内容
   # 方法1、使用vi或vim(由于我还没安装故不演示)
   # 方法2、使用echo直接覆盖
   # nginx的html内容在/usr/share/nginx/html/index.html
   echo "<h1>this is nginx-text1</h1>" > /usr/share/nginx/html/index.html

我的实操页面:

Ⅲ、退出容器并查看内容
bash 复制代码
   # 退出容器
   exit
   
   # 查看内容
   # 方法1、一条命令直接查看
   # 注意这里的nginx-deployment1-785fd8f46c-8b5pn是你自己的pod名
   kubectl exec nginx-deployment1-785fd8f46c-8b5pn -- curl http://localhost
   # 方法2、在进入容器并修改后直接查看(即第一步退出容器不用执行,而是直接查看内容)
    curl http://localhost
④、测试服务的问题

刚开始我想通过直接使用curl pod端口:容器暴露端口 直接查看nginx的欢迎页面,但是行不通,一直处于挂起状态,为什么呢?这是因为在 WSL(或任何集群外机器)里没有通往该网段的路由,也缺少 CNI 的 VXLAN/BGP 隧道,所以包发不出去,表现为 curl 一直挂起直到超时。

原因总结:WSL2的网络隔离

以下给出三种解决方案:

Ⅰ、临时测试
bash 复制代码
  # 查看当前已有服务
  kubectl get hpa
  ​
  # 使用 port-forward
  # 注意这里的nginx-deployment1是我的服务名,你应该改为你自己的
  kubectl port-forward svc/nginx-deployment1 8080:80
  ​
  # 注意使用了上面的命令,当前会处于一直挂起的状态,保持这个终端窗口不要关闭。
  # 这时候你需要另开一台虚拟机,或者再开一个终端,来查看你的服务
  curl http://localhost:8080
  ​
  # 当然你也可以在你的windows中直接访问http://localhost:8080

如图:

Ⅱ、长期访问,暴露端口
bash 复制代码
  # 使用 Kind 的 extraPortMappings
  kind: Cluster
  apiVersion: kind.x-k8s.io/v1alpha4
  nodes:
  - role: control-plane
  # 在你的集群配置文件中添加
    extraPortMappings:
    - containerPort: 30080           # Kind 容器内部的端口
      hostPort: 30080               # 映射到 WSL2 和 Windows 主机的端口
      listenAddress: "0.0.0.0"       # 允许外部访问(包括 Windows 主机)
      protocol: TCP
bash 复制代码
  # 删除原有集群
  kind delete cluster --name my-cluster
  # 使用已修改的yaml文件创建新的集群
  kind create cluster --config kind-config.yaml --name my-cluster

注意本方法需要重建集群

bash 复制代码
  # 同时创建 NodePort 类型的 Service
  apiVersion: v1
  kind: Service
  metadata:
    name: nginx-nodeport
  spec:
    type: NodePort
    selector:
      app: nginx
    ports:
      - port: 80
        targetPort: 80
        nodePort: 30080
bash 复制代码
  # 使用已修改的yaml文件创建新的Service
  kubectl apply -f nginx-nodeport.yaml
  ​
  # 直接访问服务
  curl http://localhost:30080

Ingress(ing)

简单理解,Service是一个四层负载均衡器,Ingress是一个七层负载均衡器

Ingress 是 Kubernetes 里"把集群内服务一次性、统一地暴露给集群外部用户"的标准方式,比 NodePort / LoadBalancer / port-forward 更灵活、更可扩展

一、为何需要

场景 是否需要 Ingress
本地调试单个服务 ❌ port-forward 就够
多服务共享 80/443 ✅ Ingress
需要域名、路径路由 ✅ Ingress
需要 HTTPS、限流、认证 ✅ Ingress
云厂商 LoadBalancer 成本太高 ✅ Ingress + NodePort

相当于是k8s中的nginx的反向代理

二、核心概念

1、Ingress

只是 Kubernetes 里的一条/多条 YAML 记录 ,就是一个资源对象,自身不会监听端口、也不会转发流量,就是用来定义用户请求转发到具体Pod服务的规则

2、Ingress Controller

一个 Deployment/DaemonSet (常见实现:nginx-ingress、traefik、istio-gateway 等),负责监听集群里所有的 Ingress 对象,把Ingree定义的规则翻译成自己的配置文件(nginx.conf、envoy.yaml ...),真正监听端口、转发流量给后端的Pod

精简总结:++用户发送请求,Ingress根据请求定义规则,Ingress Controller监听规则变化,翻译为自己的配置文件,给外界提供服务++

三、环境准备

1、安装Ingress Controller

我提供两种方式安装:

①、一条 YAML 直接安装
bash 复制代码
  kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.12.0/deploy/static/provider/cloud/deploy.yaml
  # 该命令会直接拉取yaml文件并应用在集群,生成Pod
  # 当然,可能遇到镜像拉取失败,这个方法适用于"网络好"的用户
②、我的做法:分步安装(适用"网络一般")
Ⅰ、手动拉镜像
Ⅱ、加载到集群
Ⅲ、下载官方 YAML 到本地
Ⅳ、修改官方YAML文件
Ⅴ、应用文件创建Pod

以下给出具体代码:

bash 复制代码
 # 拉取镜像(使用的是国内阿里云的镜像源)
  # 如果你可以直接拉取到国外官方给的,之后步骤内的修改文件就不用改了
  docker pull registry.aliyuncs.com/google_containers/nginx-ingress-controller:v1.12.0
  docker pull registry.aliyuncs.com/google_containers/kube-webhook-certgen:v1.5.0
  ​
  # 导入到集群
  # 注意my-multi-node-cluster1是我的集群名,你要改成自己的
  kind load docker-image registry.aliyuncs.com/google_containers/nginx-ingress-controller:v1.12.0 --name my-multi-node-cluster1
  kind load docker-image registry.aliyuncs.com/google_containers/kube-webhook-certgen:v1.5.0 --name my-multi-node-cluster1
  ​
  # 下载官方文件
  # 用 curl
  curl -Lo ingress-nginx.yaml \
    https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.12.0/deploy/static/provider/cloud/deploy.yaml
  # 用 wget
  wget -O ingress-nginx.yaml \
    https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.12.0/deploy/static/provider/cloud/deploy.yaml
  # 如果两个都由于网络问题无法下载成功,提供网址,直接另存为到本地即可
  # 官方YAML文件网址:
  https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.12.0/deploy/static/provider/cloud/deploy.yaml
  ​
  # 修改文件
  # 记得要导到相对应文件的路径下
  # 同时完成两处替换 + 删除所有 digest
  sed -i \
    -e 's|registry\.k8s\.io/ingress-nginx/controller|registry.aliyuncs.com/google_containers/nginx-ingress-controller|g' \
    -e 's|registry\.k8s\.io/ingress-nginx/kube-webhook-certgen|registry.aliyuncs.com/google_containers/kube-webhook-certgen|g' \
    -e 's/@sha256:[a-f0-9]*//g' \
    ingress-nginx.yaml
    
  # 如果以上方法不可行,可以使用最笨的方法直接用外部编辑器打开,自己修改【100%成功】
  # 第445行image: registry.k8s.io/ingress-nginx/controller:v1.12.0@sha256:...改为:
  image: registry.aliyuncs.com/google_containers/nginx-ingress-controller:v1.12.0
  # 第547、601行image: registry.k8s.io/ingress-nginx/kube-webhook-certgen:v1.5.0@sha256:.改为:
  image: registry.aliyuncs.com/google_containers/kube-webhook-certgen:v1.5.0
  # 保存并退出即可
  # 不放心是否修改成功,可以cat一下,或者外部编辑器打开,划到文件后面部分,大概4/5处可以看到image
  ​
  # 应用文件,重新部署
  kubectl apply -f ingress-nginx.yaml

成功如图:

【注意:这些pod都是在ingress-nginx这个命名空间内的

官方 YAML 自带 Job 是为了自动生成 webhook 证书,确保 controller 能正常启动,跑一次即结束。

2、准备Service和Pod

准备两个Service(nginx-service和tomcat-service)和两个Deployment(一个nginx,一个tomcat),每个Deployment对应3个Pod副本。

最终实现:

①、给出我的yaml配置:
bash 复制代码
# ingress的nginx-deploy1.yaml
  apiVersion: apps/v1               # Deployment 的API的版本
  kind: Deployment                  # 声明资源类型是 Deployment
  metadata:                         # Deployment 的元信息
    name: nginx-deploy1             # Deployment 名称(自定义),注意全小写
    namespace: ingress-nginx        # 目标命名空间
    labels:
      app: nginx-deploy1            # 给 Deployment 打标签
  spec:
    replicas: 3                     # 期望的 Pod 副本数
    selector:                       # 选择器,告诉 Deployment 它要管理哪些 Pod
      matchLabels:                  # 按照标签匹配
        app: nginx-ingress-deploy   # 必须与下方 Pod 模板的 template.metadata.labels 一致
    template:                       # Pod 模板,通过这个模板创建副本
      metadata:                     # Pod 的元信息
        labels:
          app: nginx-ingress-deploy # Pod 标签,和上方matchLabels一致且和下方的nginx-service相匹配
      spec:
        containers:
          - name: nginx             # 容器名称
            image: nginx:1.24.0     # 镜像版本,不加版本号默认最新版
            imagePullPolicy: IfNotPresent  # 镜像拉取策略
            ports:
              - containerPort: 80   # Pod 开放的端口
  ​
  # 使用---隔开多个配置文件
  ---
  # ingress的nginx-service.yaml
  apiVersion: v1                    # Service的API版本(固定为v1)
  kind: Service                     # 资源类型为Service
  metadata:                         # 元数据
    name: nginx-service             # Service的名称(唯一标识)
    namespace: ingress-nginx        # 命名空间
    labels:                         # Service的标签(用于筛选)
      app: nginx-service            # 标签(自定义)
  spec:                             # 规约(期望状态)
    type: ClusterIP                 # Service类型(ClusterIP/NodePort/LoadBalancer/ExternalName)
    selector:                       # 关键!用于选择要暴露的Pod(通过标签匹配)
      app: nginx-ingress-deploy     # 匹配label为"app: nginx-ingress-deploy"的Pod
    ports:                          # 端口映射规则(可配置多个)
      - name: http                    # 端口名称(可选,用于区分多个端口)
        protocol: TCP                 # 协议(TCP/UDP/SCTP,默认TCP)
        port: 80                      # Service暴露的端口(集群内部访问用)
        targetPort: 80                # Pod中容器的端口(Service转发的目标端口)
  ​
  # 使用---隔开多个配置文件
  ---
  # ingress的tomcat-deploy1.yaml
  apiVersion: apps/v1               # Deployment 的API的版本
  kind: Deployment                  # 声明资源类型是 Deployment
  metadata:                         # Deployment 的元信息
    name: tomcat-deploy1            # Deployment 名称(自定义),注意全小写
    namespace: ingress-nginx        # 目标命名空间
    labels:
      app: tomcat-deploy1           # 给 Deployment 打标签
  spec:
    replicas: 3                     # 期望的 Pod 副本数
    selector:                       # 选择器,告诉 Deployment 它要管理哪些 Pod
      matchLabels:                  # 按照标签匹配
        app: tomcat-ingress-deploy  # 必须与下方 Pod 模板的 template.metadata.labels 一致
    template:                       # Pod 模板,通过这个模板创建副本
      metadata:                     # Pod 的元信息
        labels:
          app: tomcat-ingress-deploy # Pod 标签,必须与上方的 selector.matchLabels 一致,和下方的tomcat-service相匹配
      spec:
        containers:
          - name: tomcat             # 容器名称
            image: tomcat:9.0-jdk11-temurin    # 镜像版本,不加版本号默认最新版
            imagePullPolicy: IfNotPresent  # 镜像拉取策略
            ports:
              - containerPort: 8080   # Pod 开放的端口
  ​
  # 使用---隔开多个配置文件
  ---
  # ingress的tomcat-service.yaml
  apiVersion: v1                    # Service的API版本(固定为v1)
  kind: Service                     # 资源类型为Service
  metadata:                         # 元数据
    name: tomcat-service            # Service的名称(唯一标识)
    namespace: ingress-nginx        # 命名空间
    labels:                         # Service的标签(用于筛选)
      app: tomcat-service           # 标签(自定义)
  spec:                             # 规约(期望状态)
    type: ClusterIP                 # Service类型(ClusterIP/NodePort/LoadBalancer/ExternalName)
    selector:                       # 关键!用于选择要暴露的Pod(通过标签匹配)
      app: tomcat-ingress-deploy    # 匹配label为"app: tomcat-ingress-deploy"的Pod
    ports:                          # 端口映射规则(可配置多个)
      - name: http
        protocol: TCP               # 协议(TCP/UDP/SCTP,默认TCP)
        port: 80                    # Service暴露的端口(集群内部访问用)
        targetPort: 8080            # Pod中容器的端口(Service转发的目标端口)

如果镜像拉取失败,还是可以通过手动拉取+导入集群解决哈

②、验证

配置完后应用文件并且验证即可

bash 复制代码
  # 应用文件(记得导到文件对应路径)
  # 注意nginx-tomcat-ingress1.yaml是我的文件名,你要改成你自己的
  kubectl create -f nginx-tomcat-ingress1.yaml
  ​
  # 查看pods和service
  kubectl get svc -n ingress-nginx
  kubectl get po -n ingress-nginx
  # 确认 Service selector 真的能选到 Pod(可选)
  kubectl get endpoints -n ingress-nginx nginx-service
  kubectl get endpoints -n ingress-nginx tomcat-service

如图即成功:

四、 案例HTTP+HTTPS代理

1、配置ingress的yaml文件
bash 复制代码
apiVersion: networking.k8s.io/v1           # Ingress的API版本
  kind: Ingress                              # 声明资源类型为 Ingress
  metadata:                                  # Ingress的元数据
    name: ingress1                           # Ingress的名称(自定义)
    namespace: ingress-nginx                 # 指定目标命名空间
  spec:                                      # Ingress的规约(期望状态)
    rules:                                   # 定义路由规则
      - host: nginx.ingress1.com             # 配置域名
        http:
          paths:
            - path: /
              pathType: Prefix                # 必填字段
              backend:
                service:                      # 后端服务配置
                  name: nginx-service         # 后端第一个service服务名称
                  port:
                    number: 80                # 后端第一个service服务端口号
      - host: tomcat.ingress1.com            # 配置域名
        http:
          paths:
            - path: /
              pathType: Prefix
              backend:
                service:
                  name: tomcat-service       # 后端第二个service服务名称
                  port:
                    number: 80             # 后端第二个service服务端口号
2、应用文件创建Ingress并验证
bash 复制代码
  # 创建Ingress
  kubectl create -f ingress1.yaml
  # 验证
  kubectl describe ing -n ingress-nginx

可得到如图类似信息:

用户通过访问Host域名,通过Ingress转发到Service,之后访问Pod

如:访问nginx.ingress1.com,会将请求发给nginx-service:80,之后将请求按规则分发给其管理的Pod

3、HTTP+HTTPS代理测试
bash 复制代码
   # 使用命令查看对应http暴露端口号
   kubectl get svc -n ingress-nginx

前面的就是http暴露出来的端口号(80:32292)后面的是https暴露的端口号(443:30099)

①、端口转发访问服务
bash 复制代码
  # 开发测试常用
  kubectl port-forward -n ingress-nginx service/ingress-nginx-controller 8080:80
  ​
  # 之后在浏览器访问服务即可
  http://nginx.ingress1.com:8080
  http://tomcat.ingress1.com:8080
②、hosts配置域名访问服务
bash 复制代码
  # 将 ingress-nginx-controller 的 80 和 443 同时映射到本机 80 和 443
  kubectl port-forward -n ingress-nginx svc/ingress-nginx-controller 80:80 443:443
  ​
  # 管理员权限编辑Windows hosts (C:\Windows\System32\drivers\etc\hosts)写:
  # 其实类似nginx的反向代理,可去我的nginx实操二中看看
  127.0.0.1 nginx.ingress1.com
  127.0.0.1 tomcat.ingress1.com
  ​
  # 浏览器访问服务
  http://nginx.ingress1.com:32292
  http://tomcat.ingress1.com:30099

如果发现tomcat还是没有首页,是因为现代默认把应用放在webapps.dist目录,我需要手动复制到webapps目录才可以访问

相关推荐
AI大模型7 分钟前
基于 Docker 的 LLaMA-Factory 全流程部署指南
docker·llm·llama
春人.28 分钟前
PortainerCE 跨云管理:cpolar 内网穿透服务实现多环境统一控制
云原生·eureka
发愤图强的羔羊2 小时前
Docker 搭建 SVN 服务器
docker
为了摸鱼而战3 小时前
Dockerfile知识点梳理,你要搞懂的都在这
docker
Clownseven3 小时前
Docker+Nginx+Node.js实战教程:从零搭建高可用的前后端分离项目
nginx·docker·node.js
zxcxylong4 小时前
almalinux9.6系统:k8s可选组件安装(1)
云原生·容器·kubernetes·metrics·almalinux·hpa·vpa
君不见,青丝成雪5 小时前
大数据云原生是什么
大数据·云原生
一个天蝎座 白勺 程序猿8 小时前
Apache IoTDB(4):深度解析时序数据库 IoTDB 在Kubernetes 集群中的部署与实践指南
数据库·深度学习·kubernetes·apache·时序数据库·iotdb
熊出没9 小时前
微服务如何集成swagger3
微服务·云原生·架构