K8s Ingress 与对外暴露服务

用 Service 决定「怎么被访问」,用 Ingress 决定「按域名和路径把流量分发给谁」。

在你的服务器 / VPS 集群里部署好应用之后,下一个问题就是:怎么让集群外面的人访问到它?Kubernetes 提供了几种「暴露服务」的方式,而 Ingress 是其中最适合托管多个域名和网站的一层。本文先回顾 Service 的三种类型,再讲清 Ingress 的作用、前置条件和一份可以照抄的 YAML。

先回顾:Service 的三种类型

Pod 的 IP 是临时的,重建就变。Service 给一组 Pod 提供一个稳定的访问入口,常见有三种 type:

  • ClusterIP(默认):只在集群内部可达,分配一个集群内的虚拟 IP。适合服务之间互相调用,外部访问不到。
  • NodePort:在每个节点上开一个高位端口(默认范围 30000-32767),通过节点IP:端口从外部访问。简单但端口不好记,也不适合直接暴露给用户。
  • LoadBalancer:向底层的云 / 负载均衡器申请一个对外 IP。在自建集群里通常需要额外组件(如 MetalLB)才能真正拿到外部 IP。

这三种都能「暴露服务」,但都停留在 4 层(IP + 端口)。一旦你要在同一个 IP、同一个 443 端口上托管多个域名或多个网站,就需要 7 层的 HTTP 路由能力——这正是 Ingress 要解决的。

Ingress 是什么

Ingress 是一份路由规则:它根据请求的域名(host)和路径(path),把 HTTP/HTTPS 流量转发到不同的 Service。比如:

  • app.example.com → web-service
  • api.example.com/v1 → api-service

这样多个服务共用一个入口 IP 和证书,对外只暴露 80/443,内部各 Service 保持 ClusterIP 即可。

前提:必须有 Ingress Controller

Ingress 对象只是「规则」,真正干活的是 Ingress Controller——一个常驻的反向代理,读取这些规则并落地。规则写了但没有 Controller,等于没生效。常见选择:

  • ingress-nginx:社区最主流,功能全,需要自己安装。
  • Traefik:轻量,k3s 默认自带并启用,开箱即用。

用 kubectl get pods -n kube-system 或查看 IngressClass 就能确认集群里跑的是哪个:

kubectl get ingressclass
kubectl get pods -A | grep -Ei 'ingress|traefik'

写一份 Ingress YAML

下面这份规则把两个域名/路径分别路由到两个 Service(先假设它们已存在且是 ClusterIP):

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: site-ingress
  namespace: default
spec:
  ingressClassName: nginx   # k3s 自带 traefik 时填 traefik
  rules:
    - host: app.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: web-service
                port:
                  number: 80
    - host: api.example.com
      http:
        paths:
          - path: /v1
            pathType: Prefix
            backend:
              service:
                name: api-service
                port:
                  number: 8080

要点:ingressClassName 必须匹配集群里实际的 Controller;pathType 常用 Prefix(前缀匹配)或 Exact(精确匹配);backend.service.port.number 是 Service 暴露的端口,不是容器端口。应用后用 kubectl get ingress 查看分配到的入口地址。

TLS 证书挂载简述

要走 HTTPS,先把证书和私钥存成一个 kubernetes.io/tls 类型的 Secret:

kubectl create secret tls example-tls \
  --cert=fullchain.pem --key=privkey.pem

然后在 Ingress 的 spec 里加一段 tls,把域名和这个 Secret 关联起来:

  tls:
    - hosts:
        - app.example.com
        - api.example.com
      secretName: example-tls

Controller 会自动为这些 host 启用 443 并完成 TLS 卸载,后端 Service 依旧收明文 HTTP。生产中通常用 cert-manager 自动签发和续期证书,免去手动更新。

小结

  • Service 解决「稳定入口」:ClusterIP 内部、NodePort 简单外露、LoadBalancer 要外部 IP。
  • Ingress 解决「7 层路由」:按域名 + 路径把流量分发到多个 Service,共用一个入口和证书。
  • Ingress 规则要生效,集群里必须有 Ingress Controller(ingress-nginx 需自装,k3s 自带 traefik)。
  • 写规则时 ingressClassName 要对上、pathType 选对、端口填 Service 端口;HTTPS 用 tls Secret 挂载证书即可。