Ingress 是 Kubernetes 中负责 七层(HTTP/HTTPS)流量入口 的资源对象,提供:
| Service | Ingress | |
|---|---|---|
| 工作层级 | 四层(TCP/UDP) | 七层(HTTP/HTTPS) |
| 路由依据 | 端口 | 域名 / 路径 / Header / 权重 |
| 典型用途 | 集群内服务发现与负载均衡 | 统一外部入口、TLS 卸载、灰度 |
| 维度 | 传统 NGINX(独立部署) | K8S Ingress(ingress-nginx) |
|---|---|---|
| 配置方式 | 手改 nginx.conf + reload,改错易滚挂 | kubectl apply 声明式,Controller 校验后自动热加载 |
| 服务发现 | 手写 upstream IP,后端扩容要人跟改 | 自动 watch Service/Endpoints,Pod 扩缩自动跟进 |
| 负载均衡 | upstream 轮询/权重,目标固定 | 跨 Pod 自动分发,支持会话保持等策略 |
| 发布能力 | Lua/脚本拼灰度,门槛高 | 注解开箱即用:金丝雀、重写、限流、CORS |
| 多团队协作 | 一台机器一份 conf,大家挤着改 | 每个应用一个 Ingress 资源,命名空间隔离、可审计 |
| 适用后端 | 任意 IP:端口(虚机/物理机/容器都行) | 只路由 K8S 集群内的 Service |
upstream,域名和用户无感。server_name/location 分流,一部分转虚机、一部分转集群,迁移期两套并行(本环境 hello1/hello2 老站点与 k8s-web 新站点正是这样过渡)。域名 k8s.ergesanbaishou.com 的完整流量路径:集群外的外层 NGINX(主从架构) 作为统一入口,再进集群内 Ingress → Service → Pod。下面是本站真实部署的架构图与全部配置文件。
/etc/nginx/conf.d/k8s.ergesanbaishou.com.conf(必须以 .conf 结尾!)proxy_pass → 10.18.170.34:31588proxy_set_header Host $host —— 透传域名,丢了 Ingress 必 404ingress-nginx-deploy.yaml(v1.13.9)· 入口端口由 ingress.yaml 第二段固定为 31588host: k8s.ergesanbaishou.com + path: /app: k8s-web → Endpoints(Pod IP:80)/usr/share/nginx/html ← hostPath 节点目录 /data/git/web(本站所有 html 放这里)| 层 | 组件 | 端口 | 对应文件 / 对象 |
|---|---|---|---|
| 统一入口 | 外层 NGINX 主从 | :80 | k8s.ergesanbaishou.com.conf(配置①) |
| 集群入口 | ingress-nginx-controller | NodePort 31588 | ingress-nginx-deploy.yaml(配置④)+ ingress.yaml 第二段(配置③) |
| 路由规则 | Ingress k8s-web | — | ingress.yaml 第一段(配置③) |
| 服务发现 | Service k8s-web | 8080 / 32001 | k8s-web.yaml 第二段(配置②) |
| 工作负载 | Deployment k8s-web ×2 | 容器 :80 | k8s-web.yaml 第一段(配置②) |
| 站点内容 | hostPath 目录 | — | 节点磁盘 /data/git/web/*.html |
.conf 结尾 —— nginx 只 include conf.d/*.conf,无后缀文件静默不加载,nginx -t 也不报错,页面表现为"默认欢迎页"。改完必须 nginx -t && nginx -s reload。(文件头部注释是旧站点遗留,可顺手更新)# =========================================================
# hello1.qingfeng.dev → K8s Ingress → nginx-hello(qingfeng空间)
# 外层nginx:80 → ingress-nginx NodePort:31080 → svc:8080 → pod:80
# (↑ 旧站点遗留注释;实际生效: k8s.ergesanbaishou.com → 31588)
# =========================================================
upstream k8s_ergesanbaishou {
server 10.18.170.34:31588; # ★ ingress-nginx 的 NodePort(HTTP 入口)
keepalive 32;
}
server {
listen 80;
server_name k8s.ergesanbaishou.com;
access_log /var/log/nginx/hello1.access.log;
error_log /var/log/nginx/hello1.error.log;
location / {
proxy_pass http://k8s_ergesanbaishou;
# ★★★ 灵魂行:透传 Host,Ingress 全靠它分流,丢了必 404 ★★★
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# WebSocket 支持(可选,有需要就留着)
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 300s;
proxy_send_timeout 300s;
}
}
32001 可绕过整条 ingress 链路直连 Pod(排障时先测它:curl http://10.18.170.34:32001/);hostPath 指向 Pod 所在节点 的 /data/git/web,改页面即时生效。apiVersion: apps/v1
kind: Deployment
metadata:
name: k8s-web
namespace: ergesanbaishou
labels:
app: k8s-web
spec:
replicas: 2
selector:
matchLabels:
app: k8s-web
template:
metadata:
labels:
app: k8s-web
spec:
# (可选)固定到单一节点,只需维护一份文件:
# kubectl label node <节点名> k8s-web=true
# nodeSelector:
# k8s-web: "true"
containers:
- name: nginx
image: nginx:alpine
ports:
- containerPort: 80
# 用 tcpSocket 而非 httpGet:目录为空时 httpGet / 返回 403 会卡住 NotReady
readinessProbe:
tcpSocket: {port: 80}
initialDelaySeconds: 3
livenessProbe:
tcpSocket: {port: 80}
initialDelaySeconds: 10
resources:
requests: {cpu: 50m, memory: 64Mi}
limits: {cpu: 200m, memory: 128Mi}
volumeMounts:
- name: web
mountPath: /usr/share/nginx/html # 容器内 nginx 站点根目录 → 节点 /data/git/web
volumes:
- name: web
hostPath:
path: /data/git/web # ★ 节点上的真实目录
type: DirectoryOrCreate # 目录不存在时 kubelet 自动创建(空目录访问 / 会 403)
---
apiVersion: v1
kind: Service
metadata:
name: k8s-web
namespace: ergesanbaishou
labels:
app: k8s-web
spec:
type: NodePort
selector:
app: k8s-web
ports:
- name: http
port: 8080 # ★ 线上 Service 统一开放 8080(集群内/Ingress 访问用它)
targetPort: 80 # 容器内 nginx 仍监听 80,这个不用动
nodePort: 32001 # 全集群唯一;直连测试用(curl 节点:32001)
# 域名/Ingress 访问方式见 ingress.yaml(入口端口 31588)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: k8s-web
namespace: ergesanbaishou
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "false" # 暂无证书,先不强制跳 https
spec:
ingressClassName: nginx # 对应 ingress-nginx;其他 controller 名要改
rules:
- host: k8s.ergesanbaishou.com # ★ 指定域名,只有 Host 为它的请求才命中本规则
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: k8s-web # k8s-web.yaml 里部署的 Service
port:
number: 8080 # ← 对应 svc k8s-web 的 port(8080),不是 targetPort(80)
# ---- 第二个站点(备用,当前注释未生效)----
# 上线步骤:部署对应 Deployment+Service → 取消注释 → apply → 外层 nginx 加 server 块
# - host: test2.ergesanbaishou.com
# http:
# paths:
# - path: /
# pathType: Prefix
# backend:
# service:
# name: test2-svc
# port:
# number: 8080
---
apiVersion: v1
kind: Service
metadata:
name: ingress-nginx-controller
namespace: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/component: controller
spec:
type: NodePort
selector:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/component: controller
ports:
- name: http
port: 80
targetPort: 80
protocol: TCP
nodePort: 31588 # ★★★ 集群 HTTP 入口,外层 nginx proxy_pass 指向它
- name: https
port: 443
targetPort: 443
protocol: TCP
# https 的 nodePort 不指定 → 保留/自动分配(30255);上证书要固定时照抄 http 段
apiVersion: v1
kind: Namespace
metadata:
labels:
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
name: ingress-nginx
---
apiVersion: v1
automountServiceAccountToken: true
kind: ServiceAccount
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.13.9
name: ingress-nginx
namespace: ingress-nginx
---
apiVersion: v1
automountServiceAccountToken: true
kind: ServiceAccount
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.13.9
name: ingress-nginx-admission
namespace: ingress-nginx
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.13.9
name: ingress-nginx
namespace: ingress-nginx
rules:
- apiGroups:
- ""
resources:
- namespaces
verbs:
- get
- apiGroups:
- ""
resources:
- configmaps
- pods
- secrets
- endpoints
verbs:
- get
- list
- watch
- apiGroups:
- ""
resources:
- services
verbs:
- get
- list
- watch
- apiGroups:
- networking.k8s.io
resources:
- ingresses
verbs:
- get
- list
- watch
- apiGroups:
- networking.k8s.io
resources:
- ingresses/status
verbs:
- update
- apiGroups:
- networking.k8s.io
resources:
- ingressclasses
verbs:
- get
- list
- watch
- apiGroups:
- coordination.k8s.io
resourceNames:
- ingress-nginx-leader
resources:
- leases
verbs:
- get
- update
- apiGroups:
- coordination.k8s.io
resources:
- leases
verbs:
- create
- apiGroups:
- ""
resources:
- events
verbs:
- create
- patch
- apiGroups:
- discovery.k8s.io
resources:
- endpointslices
verbs:
- list
- watch
- get
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.13.9
name: ingress-nginx-admission
namespace: ingress-nginx
rules:
- apiGroups:
- ""
resources:
- secrets
verbs:
- get
- create
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
labels:
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.13.9
name: ingress-nginx
rules:
- apiGroups:
- ""
resources:
- configmaps
- endpoints
- nodes
- pods
- secrets
- namespaces
verbs:
- list
- watch
- apiGroups:
- coordination.k8s.io
resources:
- leases
verbs:
- list
- watch
- apiGroups:
- ""
resources:
- nodes
verbs:
- get
- apiGroups:
- ""
resources:
- services
verbs:
- get
- list
- watch
- apiGroups:
- networking.k8s.io
resources:
- ingresses
verbs:
- get
- list
- watch
- apiGroups:
- ""
resources:
- events
verbs:
- create
- patch
- apiGroups:
- networking.k8s.io
resources:
- ingresses/status
verbs:
- update
- apiGroups:
- networking.k8s.io
resources:
- ingressclasses
verbs:
- get
- list
- watch
- apiGroups:
- discovery.k8s.io
resources:
- endpointslices
verbs:
- list
- watch
- get
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.13.9
name: ingress-nginx-admission
rules:
- apiGroups:
- admissionregistration.k8s.io
resources:
- validatingwebhookconfigurations
verbs:
- get
- update
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.13.9
name: ingress-nginx
namespace: ingress-nginx
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: ingress-nginx
subjects:
- kind: ServiceAccount
name: ingress-nginx
namespace: ingress-nginx
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.13.9
name: ingress-nginx-admission
namespace: ingress-nginx
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: ingress-nginx-admission
subjects:
- kind: ServiceAccount
name: ingress-nginx-admission
namespace: ingress-nginx
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
labels:
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.13.9
name: ingress-nginx
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: ingress-nginx
subjects:
- kind: ServiceAccount
name: ingress-nginx
namespace: ingress-nginx
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.13.9
name: ingress-nginx-admission
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: ingress-nginx-admission
subjects:
- kind: ServiceAccount
name: ingress-nginx-admission
namespace: ingress-nginx
---
apiVersion: v1
data: null
kind: ConfigMap
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.13.9
name: ingress-nginx-controller
namespace: ingress-nginx
---
apiVersion: v1
kind: Service
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.13.9
name: ingress-nginx-controller
namespace: ingress-nginx
spec:
ipFamilies:
- IPv4
ipFamilyPolicy: SingleStack
ports:
- appProtocol: http
name: http
port: 80
protocol: TCP
targetPort: http
- appProtocol: https
name: https
port: 443
protocol: TCP
targetPort: https
selector:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
type: NodePort
---
apiVersion: v1
kind: Service
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.13.9
name: ingress-nginx-controller-admission
namespace: ingress-nginx
spec:
ports:
- appProtocol: https
name: https-webhook
port: 443
targetPort: webhook
selector:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
type: ClusterIP
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.13.9
name: ingress-nginx-controller
namespace: ingress-nginx
spec:
minReadySeconds: 0
revisionHistoryLimit: 10
selector:
matchLabels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
strategy:
rollingUpdate:
maxUnavailable: 1
type: RollingUpdate
template:
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.13.9
spec:
automountServiceAccountToken: true
containers:
- args:
- /nginx-ingress-controller
- --election-id=ingress-nginx-leader
- --controller-class=k8s.io/ingress-nginx
- --ingress-class=nginx
- --configmap=$(POD_NAMESPACE)/ingress-nginx-controller
- --validating-webhook=:8443
- --validating-webhook-certificate=/usr/local/certificates/cert
- --validating-webhook-key=/usr/local/certificates/key
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: LD_PRELOAD
value: /usr/local/lib/libmimalloc.so
image: registry.k8s.io/ingress-nginx/controller:v1.13.9@sha256:d803625b20d471400fdae9dce0fdd076c0361f8f7e1ecee0dcd2f84fa0d196f8
imagePullPolicy: IfNotPresent
lifecycle:
preStop:
exec:
command:
- /wait-shutdown
livenessProbe:
failureThreshold: 5
httpGet:
path: /healthz
port: 10254
scheme: HTTP
initialDelaySeconds: 10
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
name: controller
ports:
- containerPort: 80
name: http
protocol: TCP
- containerPort: 443
name: https
protocol: TCP
- containerPort: 8443
name: webhook
protocol: TCP
readinessProbe:
failureThreshold: 3
httpGet:
path: /healthz
port: 10254
scheme: HTTP
initialDelaySeconds: 10
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
resources:
requests:
cpu: 100m
memory: 90Mi
securityContext:
allowPrivilegeEscalation: false
capabilities:
add:
- NET_BIND_SERVICE
drop:
- ALL
readOnlyRootFilesystem: false
runAsGroup: 82
runAsNonRoot: true
runAsUser: 101
seccompProfile:
type: RuntimeDefault
volumeMounts:
- mountPath: /usr/local/certificates/
name: webhook-cert
readOnly: true
dnsPolicy: ClusterFirst
nodeSelector:
kubernetes.io/os: linux
serviceAccountName: ingress-nginx
terminationGracePeriodSeconds: 300
volumes:
- name: webhook-cert
secret:
secretName: ingress-nginx-admission
---
apiVersion: batch/v1
kind: Job
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.13.9
name: ingress-nginx-admission-create
namespace: ingress-nginx
spec:
template:
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.13.9
name: ingress-nginx-admission-create
spec:
automountServiceAccountToken: true
containers:
- args:
- create
- --host=ingress-nginx-controller-admission,ingress-nginx-controller-admission.$(POD_NAMESPACE).svc
- --namespace=$(POD_NAMESPACE)
- --secret-name=ingress-nginx-admission
env:
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
image: registry.k8s.io/ingress-nginx/kube-webhook-certgen:v1.6.9@sha256:01038e7de14b78d702d2849c3aad72fd25903c4765af63cf16aa3398f5d5f2dd
imagePullPolicy: IfNotPresent
name: create
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
readOnlyRootFilesystem: true
runAsGroup: 65532
runAsNonRoot: true
runAsUser: 65532
seccompProfile:
type: RuntimeDefault
nodeSelector:
kubernetes.io/os: linux
restartPolicy: OnFailure
serviceAccountName: ingress-nginx-admission
ttlSecondsAfterFinished: 0
---
apiVersion: batch/v1
kind: Job
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.13.9
name: ingress-nginx-admission-patch
namespace: ingress-nginx
spec:
template:
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.13.9
name: ingress-nginx-admission-patch
spec:
automountServiceAccountToken: true
containers:
- args:
- patch
- --webhook-name=ingress-nginx-admission
- --namespace=$(POD_NAMESPACE)
- --patch-mutating=false
- --secret-name=ingress-nginx-admission
- --patch-failure-policy=Fail
env:
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
image: registry.k8s.io/ingress-nginx/kube-webhook-certgen:v1.6.9@sha256:01038e7de14b78d702d2849c3aad72fd25903c4765af63cf16aa3398f5d5f2dd
imagePullPolicy: IfNotPresent
name: patch
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
readOnlyRootFilesystem: true
runAsGroup: 65532
runAsNonRoot: true
runAsUser: 65532
seccompProfile:
type: RuntimeDefault
nodeSelector:
kubernetes.io/os: linux
restartPolicy: OnFailure
serviceAccountName: ingress-nginx-admission
ttlSecondsAfterFinished: 0
---
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.13.9
name: nginx
spec:
controller: k8s.io/ingress-nginx
---
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/version: 1.13.9
name: ingress-nginx-admission
webhooks:
- admissionReviewVersions:
- v1
clientConfig:
service:
name: ingress-nginx-controller-admission
namespace: ingress-nginx
path: /networking/v1/ingresses
port: 443
failurePolicy: Fail
matchPolicy: Equivalent
name: validate.nginx.ingress.kubernetes.io
rules:
- apiGroups:
- networking.k8s.io
apiVersions:
- v1
operations:
- CREATE
- UPDATE
resources:
- ingresses
sideEffects: None
| 症状 | 根因 | 解法 |
|---|---|---|
| 页面显示 nginx 默认欢迎页 | conf 文件名没有 .conf 后缀 → include conf.d/*.conf 静默不加载,nginx -t 也不报错 | 改名加后缀 + nginx -t && nginx -s reload |
| 默认欢迎页(另一种) | hosts 把域名解析到了错误机器(如 K8S 节点,上面另有一个 nginx) | hosts 必须指向外层 NGINX 机器的 IP |
| 直连 31588 返回 404 | 裸 curl IP:31588 没带 Host 头 → Ingress 按 host 路由匹配不上(正常行为,非故障) | curl -H "Host: k8s.ergesanbaishou.com" http://10.18.170.34:31588/ |
| 外层转发放大后 404 | 外层 nginx 没写 proxy_set_header Host $host → 域名没透传给 controller | 补上灵魂行并 reload(见配置①) |
apply 报 namespaces "ingress-nginx" not found | 先 apply 了 Ingress,但 controller 还没安装 | 先装配置④,再 apply 配置③ |
| apply 报 nodePort 32001 冲突 | 旧 test1 的 Service 还占着 32001 | kubectl delete svc test1-ergesanbaishou -n ergesanbaishou |
# ① Pod 层(最内):容器活着吗
kubectl get pods -n ergesanbaishou -o wide
# ② Service 层:绕过 ingress 直测(NodePort 32001)
curl -v http://10.18.170.34:32001/
kubectl get ep -n ergesanbaishou k8s-web # endpoints 必须非空
# ③ Controller 层:带 Host 头直测集群入口(NodePort 31588)
curl -v -H "Host: k8s.ergesanbaishou.com" http://10.18.170.34:31588/
kubectl get ingress -n ergesanbaishou # ADDRESS 列应有 IP
kubectl logs -n ingress-nginx -l app.kubernetes.io/component=controller --tail=30
# ④ 外层 NGINX 层:在 nginx 机器上自测
curl -H "Host: k8s.ergesanbaishou.com" http://127.0.0.1/
nginx -T 2>/dev/null | grep -n "k8s.ergesanbaishou" # 确认配置已加载
tail -f /var/log/nginx/hello1.error.log
# ⑤ 本机层:hosts 解析到哪
ping k8s.ergesanbaishou.com
kube-infra ns(不是默认的 ingress-nginx),NodePort 80:30080 / 443:30443;另有 Istio 网关并存(NodePort 30538/30539)。链路与测试同构:外层 NGINX 主备 VIP → ingress-nginx NodePort → Service → Pod。# 实测命令(★教训:按 -n ingress-nginx 查到空 ≠ 没有,要 -A 跨 ns 搜)
sudo kubectl get svc -A | grep ingress
# kube-infra nginx-ingress-nginx-controller NodePort 10.101.184.130 80:30080/TCP,443:30443/TCP
# istio-system istio-ingressgateway NodePort 10.100.189.102 15021:30542/TCP,80:30538/TCP,443:30539/TCP
与测试环境差异速览:① ns 不同(kube-infra vs ingress-nginx);② NodePort 不同(30080/30443 vs 测试 31588);③ 双网关并存(ingress-nginx + Istio,配套 admission/metrics/defaultbackend 齐全)。外层 NGINX 的 upstream 端口按此对应修改即可。完整线上架构见 线上 K8S 集群架构。
Controller 本身也是一个 Pod,需要先通过 NodePort / LoadBalancer / hostNetwork 之一把自身暴露到集群外。
浏览器 ── http://k8s.ergesanbaishou.com ──→ 外层 NGINX(主从 + VIP) ← 集群外
│ proxy_pass 10.18.170.34:31588 + ★透传 Host 头(丢了必 404)
▼
═══════════════════════ K8S 集群边界(节点 :31588, kube-proxy 监听) ═══════════════════════
▼
┌─ ns: ingress-nginx ─────────────────────────────────┐
│ ingress-nginx-controller-xxx (Pod, nginx 进程) │ ← 查①:controller 活着吗
│ watch 全集群 Ingress 规则 → 动态生成 nginx.conf │
└────────────────────┬────────────────────────────────┘
│ 匹配 Host: k8s.ergesanbaishou.com
▼
Ingress 资源(路由规则) ← 查②:域名 → 哪个 svc
│ 转发到 svc:80
▼
┌─ ns: web ───────────────────────────────────────────┐
│ Service: k8s-web (ClusterIP 10.x.x.x:80) │ ← 查③:svc + Endpoints
│ └─ Endpoints: [10.244.x.x] (后端 Pod IP 列表) │
│ ▼ │
│ Pod: k8s-web-xxxx (nginx:alpine, 提供静态页) │ ← 查④:Pod 状态
│ (Deployment 副本控制 / 滚动更新) │
└─────────────────────────────────────────────────────┘
# ★ 逐层排查命令(502/404 从上往下捋,一层一条)
kubectl get pods -n ingress-nginx -o wide # ① controller Pod 状态
kubectl get svc -n ingress-nginx # 80/443 映射的 nodePort(如 31588)
kubectl get ingress -A # ② 全集群路由规则清单(-A 跨所有 ns)
kubectl describe ingress <名字> -n web # 细节:Host/Path → Backend(svc:port)
kubectl get svc -n web # ③ Service
kubectl get ep -n web # ★ Endpoints 为 <none> = svc 后面没 Pod → 503!
kubectl get pods -n web -o wide # ④ Pod 状态(真正干活的)
kubectl get deploy -n web # Pod 的管理者(副本数/镜像)
kubectl exec -n web <pod名> -- ss -lntp # ⑤ 终点:容器里 nginx 在监听吗
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.11.2/deploy/static/provider/baremetal/deploy.yaml
# 验证:Pod Running,且自动创建 ingress-nginx-controller Service(NodePort)
kubectl get pods -n ingress-nginx
kubectl get svc -n ingress-nginx
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm install ingress-nginx ingress-nginx/ingress-nginx \
--namespace ingress-nginx --create-namespace
| 平台 | 推荐方案 |
|---|---|
| AWS | AWS Load Balancer Controller(ALB Ingress) |
| GCP | GCE Ingress(默认支持) |
| 阿里云 | ALB Ingress / ACK nginx-ingress |
kubernetes/ingress-nginx(社区官方,本文注解以此为准)与 nginxinc/kubernetes-ingress(NGINX Inc 维护),注解与能力不完全兼容。保存为 ingress-demo.yaml 后 kubectl apply -f ingress-demo.yaml:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: demo-ingress
annotations:
# 把 /foo/xxx 转发到后端时重写为 /xxx
nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
ingressClassName: nginx # 由哪个 Controller 处理
rules:
- host: api.example.com # 省略 host 则匹配所有域名
http:
paths:
- path: /foo(/|$)(.*) # 正则捕获组配合 $2 使用
pathType: ImplementationSpecific
backend:
service:
name: foo-svc
port:
number: 80
- path: /bar
pathType: Prefix
backend:
service:
name: bar-svc
port:
number: 8080
defaultBackend: # 兜底后端(都不匹配时返回)
service:
name: default-svc
port:
number: 80
本地没有域名解析时,用 curl -H "Host: api.example.com" http://<INGRESS_IP>/foo/xx 模拟测试。