ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Kubernetes Ingress-Nginx部署与配置:CKA备考实战指南

Kubernetes Ingress-Nginx部署与配置:CKA备考实战指南 准备备考CKA的时候很多人会把大量时间花在Pod、Deployment、Service这些基础对象上但一碰到Ingress就有点犯怵。其实Ingress-Nginx是整个集群对外提供HTTP流量入口的关键组件考试中很可能直接给你一个“部署Ingress规则、让某域名路由到某Service”的题而且练习环境里亲手搭一遍和只看文档是完全不同的体验。这篇内容就是围绕“Kubernetes中Ingress-Nginx的部署与配置”这条主线以CKA备考练习环境准备为背景把我实际搭建过程中踩过的坑、验证过的方法、以及考试向的注意事项全部整理出来。无论你是刚看完CKA教程准备动手实操还是工作中要在一个裸机k8s集群里快速把Ingress跑起来这篇文章都可以直接配合命令行操作来参考。1. 备考CKA为什么先折腾一套自己的Ingress-Nginx1.1 CKA考试范围里Ingress的分量先说结论CKA考试大纲里Ingress这部分属于“Service、网络和存储”大类虽然不单独作为一个大比重考点但几乎每年都会有相关题目。常见的考法有三种一是给你一个YAML片段让你创建一个Ingress并绑定到指定Service二是让你修改已有Ingress的路径规则或注解三是检查Ingress Controller是否正常运行并暴露正确端口。所以练习环境里如果只开了一堆Pod和Service却从来没有真实跑过一次Ingress-Nginx控制器你在考试时会非常被动。因为考试环境虽然是预装好的但很多集群的访问方式和你平时练习时用的kubectl完全一致唯一不同的是你对“Ingress资源被Controller监听并翻译成Nginx配置”这个过程是否有肌肉记忆。1.2 练习环境 vs 集群环境自己动手的价值不少人会偷懒直接用云厂商托管的Kubernetes服务比如EKS或AKS然后在上面开一个Ingress Controller。但这类环境往往自带负载均衡器你并不需要理解NodePort端口是怎么暴露的也不需要关心Controller的Pod到底监听在哪个节点上。这些细节在CKA考试里恰恰是丢分点。我自己的做法是用一台2核4G的虚拟机或裸机跑一个最小化的单节点集群。单节点集群虽然不满足生产环境的高可用要求但足够练习Ingress的完整链路客户端访问节点IP的某个端口Ingress Controller的Service把流量转给Controller PodController再根据Ingress规则把请求转发到后端Service和Pod。整个过程清晰可见不掺任何云厂商的黑盒逻辑。1.3 版本选型从v1.26.0开始我初始化集群时用的是v1.26.0这也是当时相对稳定且CKA考试经常涉及的版本区间。网络热门搜索里那句“using kubernetes version: v1.26.0”其实就是kubeadm初始化时打出来的日志说明很多人在同一时期都在备这套环境。对应Kubernetes 1.26Ingress-Nginx控制器建议使用v1.8.x或v1.9.x版本。版本匹配很重要Ingress-Nginx的API版本比如networking.k8s.io/v1从1.22开始已经是稳定版本1.26自然没问题但Controller镜像版本如果太老可能不兼容新的K8s特性。我的选择是ingress-nginx/controller-v1.8.1下载官方deploy.yaml时直接拉对应release分支避免用master分支导致某些字段不兼容。2. 部署Ingress-Nginx之前先把集群底座弄稳2.1 kubeadm初始化与容器运行时选择单节点集群初始化命令并不复杂但有一个关键参数必须提前想好Pod网段。比如你想用Calico作为网络插件那么初始化命令里就要指定--pod-network-cidr192.168.0.0/16。如果集群和Ingress Controller的Service网段冲突后面会出现路由不通的问题。sudo kubeadm init \ --kubernetes-versionv1.26.0 \ --pod-network-cidr192.168.0.0/16 \ --apiserver-advertise-address192.168.1.100容器运行时我选的Containerd这也是1.26版本后更常见的默认选择。注意在初始化之前Containerd需要正确处理Kubernetes的pause镜像如果你用国内的源或者离线环境提前把pause镜像拉到本地会更顺。2.2 网络插件与防火墙注意事项网络插件决定了集群里Pod与Pod之间的连通性而Ingress-Nginx Controller需要访问后端Pod的IP所以网络插件没有装好的话即使Ingress资源创建成功流量也转发不出去。我习惯用Calico因为它支持NetworkPolicy而且部署简单kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.25.0/manifests/calico.yaml这里有个很容易忽视的点防火墙或Linux内核参数。如果你的节点开了firewalld或者某些安全组规则必须放行Ingress Controller将来要用的NodePort端口。我自己在练习时曾经因为没关防火墙钢印开了Selector和Port都正确外部curl却超时后来发现是iptables规则把端口拦了。2.3 验证集群健康状态在部署任何东西之前先确认集群本身是健康的kubectl get nodes kubectl get pods -n kube-system -o wide重点关注CoreDNS是否处于Running状态因为Ingress资源本身不依赖DNS但Controller的准入校验Admission Webhook可能需要访问APIServer而Apiserver的可用性基本取决于etcd和网络。到这里底座已经稳了接下来就该让真正的“主角”登场。3. Ingress-Nginx控制器Helm还是裸YAML我选哪种3.1 两种方式的适用场景对比我用下面这张表来说明Helm方式和裸YAML方式在实际备考练习里的差异对比维度Helm方式裸YAML方式安装速度快一条命令完成需要下载文件并apply可控性参数较多需要熟悉values清晰可见每个资源都能单独审视离线环境不方便需要提前拉helm包和镜像提前拉yaml文件后即可离线部署考试联想考试环境一般不让你用helm考试时写YAML更接近底层逻辑调试难度出现问题需要查helm状态出错直接kubectl describe相关资源我自己在练习环境里主用的是裸YAML方式尤其CKA备考阶段越接近底层原生资源的操作方式越能帮助你理解Ingress Controller的组成。Helm适合生产环境快速部署或你本身已经对Chart很熟练但考试时还是要靠手写Ingress规则。3.2 裸YAML方式部署的完整步骤先进入Ingress-Nginx的GitHub release页面选择与K8s 1.26匹配的版本。使用的文件是deploy/static/provider/baremetal/deploy.yaml。裸机环境一般没有外部负载均衡器所以官方推荐用hostNetwork或NodePort方式暴露Controller Service。wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.8.1/deploy/static/provider/baremetal/deploy.yaml kubectl apply -f deploy.yaml这里用baremetal版本的原因在于它默认生成的Service类型是NodePort而不是LoadBalancer。如果你在云上练习反而可能需要改动Service type但备考CKA的话NodePort更能还原考试场景。部署完成后查看Controller Podkubectl -n ingress-nginx get pods NAME READY STATUS RESTARTS AGE ingress-nginx-controller-7d8f7c5f86-abc12 1/1 Running 0 3m3.3 Helm方式部署的完整步骤说到Helm其实它在生产环境更常用。如果你坚持用Helm做练习可以加官方repo后直接安装helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx helm repo update helm install ingress-nginx ingress-nginx/ingress-nginx \ --namespace ingress-nginx \ --set controller.service.typeNodePort \ --set controller.hostNetworktrue第三种方式hostNetwork是很多人喜欢用的因为它直接让Controller Pod监听节点端口省去了一层Service转发。但要注意这样部署后你访问的就是节点IP上的80/443端口而不是一个随机分配的NodePort。CKA考试一般不要求你用hostNetwork但我个人觉得理解了hostNetwork和NodePort两者的区别会对排查问题有很大帮助。3.4 部署后要检查的服务状务无论用哪种方式部署完都必须确认三件事Controller Pod的日志里没有持续报错的记录特别是与Apiserver或webhook相关的报错。Service的端口是否正确映射比如NodePort是否在一个合法区间30000-32767。是否有对应的校验Webhook资源如果webhook没有正常注入创建Ingress时可能报错。我自己遇到的坑是在K8s 1.26环境下如果之前用旧版本Controller部署过再升级时webhook配置不会自动更新导致创建Ingress时一直返回Internal error occurred: failed calling webhook validate.nginx.ingress.kubernetes.io。解决办法就是删除旧的ValidatingWebhookConfiguration重新apply新的deploy.yaml。kubectl delete validatingwebhookconfiguration ingress-nginx-admission kubectl apply -f deploy.yaml4. 让流量真正进集群Service类型与Ingress资源配置4.1 Controller暴露方式NodePort还是LoadBalancerIngress Controller本身就是一个Deployment如果没有外部负载均衡器你必须决定流量从哪个端口进来。在裸机环境里NodePort是最直接的方案。比如Controller Service被分配了30080端口你访问http://192.168.1.100:30080请求就会被转发到Controller Pod的80端口。这里先解释一下数据流很多人不理解为什么Ingress要在Service前面客户端——NodePort——Ingress Controller按域名或路径判断——后端Service——Pod。整个链路的“决策”发生在Controller Pod内部它的本质是一个嵌入Kubernetes配置的动态Nginx。如果练习环境里安装了MetalLB你可以把Service类型改成LoadBalancer这样会得到一个内网IP访问体验更像生产环境。但CKA考试并不涉及MetalLB所以我把主要精力放在NodePort上。4.2 创建Ingress资源Name-based与Path-based示例创建一个Ingress资源最关键的是三个字段ingressClassName、host、path。注意如果用networking.k8s.io/v1必须显式指定ingressClassName为nginx否则Controller不会理会这个Ingress。下面是最基础的一个Name-based Ingress例子apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: test-ingress spec: ingressClassName: nginx rules: - host: app.example.com http: paths: - pathType: Prefix path: / backend: service: name: app-service port: number: 80Path-based则是在同一个host下加多个路径spec: ingressClassName: nginx rules: - host: api.example.com http: paths: - path: /login pathType: Exact backend: service: name: login-svc port: number: 5000 - path: /data pathType: Prefix backend: service: name:>annotations: nginx.ingress.kubernetes.io/rewrite-target: /$2 spec: rules: - host: api.example.com http: paths: - path: /api(/|$)(.*) pathType: ImplementationSpecific backend: service: name: api-svc port: number: 8080这个例子中请求/api/v1/getUser会被Controller改写成/v1/getUser再转发给后端Service。考试不会给你这么复杂的正则但让你修改rewrite-target实现路径重写是很有可能的。关于ssl-redirect如果你没有配置TLS证书又不想让HTTP自动跳转到HTTPS建议显式加上annotations: nginx.ingress.kubernetes.io/ssl-redirect: false否则Controller默认会根据TLS配置自动开启强制跳转本地测试时容易出现浏览器拒绝连接的情况。4.4 调试Ingress时必用的命令配置完Ingress之后我必查的命令是这些kubectl -n ingress-nginx get svc kubectl get ingress kubectl describe ingress test-ingress kubectl -n ingress-nginx logs -f deployment/ingress-nginx-controller第四种命令很关键。Ingress的Event并不总是能快速看出问题但Controller日志会直接告诉你Nginx重新加载时的错误比如上游Service名字解析失败、annotations字段无法识别、404状态码对应哪个upstream等等。很多时候curl直接返回404你以为Pod或Service不对其实Controller里日志早就写清楚了。5. 实测一条龙两个Service一个Ingress全流程验证5.1 创建测试Pod/Service光看YAML不够我准备创建两个最简单的测试Service完整走一遍流程。先部署第一个Service使用现成的nginx镜像kubectl create deployment app-demo --imagenginx --port80 kubectl expose deployment app-demo --nameapp-svc --port80 --target-port80再建一个稍微带点路径要求的Service模拟后端APIkubectl create deployment api-demo --imagenginx --port80 kubectl expose deployment api-demo --nameapi-svc --port80 --target-port80这里用nginx镜像只是为了测试链路实际考试中后端肯定是业务镜像但原理一样。5.2 写Ingress规则然后创建两个Path-based规则域名都用test.local但路径走不同ServiceapiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: demo-ingress annotations: nginx.ingress.kubernetes.io/rewrite-target: / spec: ingressClassName: nginx rules: - host: test.local http: paths: - path: /app pathType: Prefix backend: service: name: app-svc port: number: 80 - path: /api pathType: Prefix backend: service: name: api-svc port: number: 80如果你对rewrite-target不熟悉这里先别着急加这个annotation。因为一旦加上/test路径会被改写为/后端nginx返回的是默认欢迎页有时反而搞混。先不加annotation保持Controller原始转发逻辑重点观察路径是否到达正确的Pod。5.3 本地hosts与curl验证在本地机器或节点上编辑/etc/hosts加入一行192.168.1.100 test.local然后通过NodePort访问curl -H Host: test.local http://192.168.1.100:30080/app正常情况下你应该看到app-demo的响应页面。如果没有先确认Controller Service的NodePort是多少kubectl -n ingress-nginx get svc用结果里的80:30080/TCP替换上面的30080。5.4 排错常见错误与日志定位实测时最容易出现的几个问题我按出现的频率排列404 NotFound多半是path或host不匹配先kubectl describe ingress查看Address和Rules。502 Bad Gateway说明Controller找到了后端Service但Pod没有正常响应。查看后端Pod日志或检查Service的Endpoints是否为空。Connection refused说明NodePort没有被监听大概率Controller Pod挂了或网络插件异常先kubectl get pods -n ingress-nginx看Pod状态。TLS handshake错误有经验的同学肯定想到了Controller默认会尝试抓取TLS证书如果你没有证书配置就加ssl-redirectfalse。我在一次练习中就遇到很诡异的问题curl返回404但Ingress页面显示Rules完全正确。后来打开Controller日志发现日志里有一行error: unexpected upstream default-app-svc-80一看才知道我在Ingress里把service名字写成了default-app-svc-80而实际Service叫app-svc。日志里upstream格式是namespace-service-port能帮你破案。6. CKA考试向的易错点与我的实战心得6.1 不要忽略namespace与资源名大小写CKA考试环境和真实Kubernetes一样namespace是资源分组的重要维度。创建Ingress时如果你没有指定namespace默认在default但考试题里经常会限制-n team-x。还要注意资源名大小写必须完全匹配。myService和myservice是两个不同的对象。我在练习时吃过这个亏创建Ingress时后端service.name写成了大写S然后一直报“could not find service”。这个错误在describe ingress时会很明确地标出来。6.2 短时间快速创建Ingress的模板写法考试时间紧张你不可能每次去背完整YAML。我建议你把下面这个最小模板记熟cat EOF | kubectl apply -f - apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: exam-ingress annotations: nginx.ingress.kubernetes.io/rewrite-target: / spec: ingressClassName: nginx rules: - host: exam.example.com http: paths: - path: / pathType: Prefix backend: service: name: exam-svc port: number: 80 EOF只需改name、host、service.name和port即可。不要花时间手写格式化直接heredoc最稳。6.3 我踩过的坑annotation写错导致404NodePort端口被占用有一次我配置了nginx.ingress.kubernetes.io/rewrite-target: /$1但path里没有正则捕获组导致Nginx加载失败整个Controller Pod不断重启。后来查Controller日志才看到Nginx配置reload错误提示但日志已经被滚动刷掉了。所以我建议在备考阶段先不要用复杂的正则annotation把官方文档里的常见组合练熟。比如rewrite-target配合普通path时先确保不加annotation能通再加进去对比行为差异。NodePort端口被占用也是常见问题。Kubernetes默认的NodePort区间是30000-32767但某些云环境或本地端口监听可能会冲突。你可以用ss -tlnp看看端口是否空闲。如果端口被占用就直接编辑Controller Service把nodePort改成一个没被占用的端口。6.4 资源清理与备份配置的小习惯练习过程中你会反复创建不同的Ingress和Service保持环境整洁很重要。删除资源和删除namespace要注意顺序有些同学直接kubectl delete namespace xxx但里面还有Controller时会导致残留。正确做法是kubectl delete ingress demo-ingress kubectl delete svc app-svc api-svc kubectl delete deployment app-demo api-demo如果你在调整Ingress-Nginx参数建议先把deploy.yaml保存一份在本地git仓库里改坏了一眼就能对比出哪里变了而不是靠记忆回滚。备考CKA的大多数经验最终都会落到“亲手多敲几遍”上。Ingress-Nginx这套组件并不神秘它就是一个跑在集群里、动态生成Nginx配置的控制器。把Controller部署一次、建一个Ingress、curl通一次你对考试里这类题目的把握度会明显不一样。后续如果还有精力可以接着练TLS证书配合Ingress暴露HTTPS服务或者在多个namespace下同时管理不同Ingress的隔离规则这些方向练熟了考试时就不会被Ingress的各种注释和路径匹配绕晕。
返回列表