千家信息网

K8s之Ingress-nginx原理及配置

发表于:2026-11-01 作者:千家信息网编辑
千家信息网最后更新 2026年11月01日,前言在Kubernetes中,服务和Pod的IP地址仅可以在集群网络内部使用,对于集群外的应用是不可见的。为了使外部的应用能够访问集群内的服务,在Kubernetes中目前提供了以下几种方案:Node
千家信息网最后更新 2026年11月01日K8s之Ingress-nginx原理及配置

前言

在Kubernetes中,服务和Pod的IP地址仅可以在集群网络内部使用,对于集群外的应用是不可见的。为了使外部的应用能够访问集群内的服务,在Kubernetes中目前提供了以下几种方案:

  • NodePort
  • LoadBalancer
  • Ingress

在之前的博文中介绍过NodePort,简单来说,就是通过service这种资源对象,为后端pod提供一个统一的访问接口,然后将service的统一访问接口映射到群集节点上,最终实现client通过映射到群集节点上的端口访问到后端pod提供的服务。

但是,这种方式有一个弊端,就是当新生成一个pod服务就需要创建对应的service将其映射到节点端口,当运行的pod过多时,我们节点暴露给client端的端口也会随之增加,这样我们整个k8s群集的危险系数就会增加,因为我们在搭建群集之处,官方明确指出,必须关闭firewalld防火墙及清空iptables规则,现在我们又暴露了那么多端口给client,安全系数可想而知。

有没有更安全又简便的一种方法呢?答案是肯定的,就是来利用Ingress这种资源对象来实现。

博文大纲:
一、Ingress-nginx介绍
二、Ingress-nginx配置示例
三、配置HTTPS

一、Ingress-nginx介绍

1、Ingress-nginx组成

  • ingress-nginx-controller:根据用户编写的ingress规则(创建的ingress的yaml文件),动态的去更改nginx服务的配置文件,并且reload重载使其生效(是自动化的,通过lua脚本来实现);
  • ingress资源对象:将Nginx的配置抽象成一个Ingress对象,每添加一个新的Service资源对象只需写一个新的Ingress规则的yaml文件即可(或修改已存在的ingress规则的yaml文件)

1、Ingress-nginx可以解决什么问题?

1)动态配置服务
  如果按照传统方式, 当新增加一个服务时, 我们可能需要在流量入口加一个反向代理指向我们新的k8s服务. 而如果用了Ingress-nginx, 只需要配置好这个服务, 当服务启动时, 会自动注册到Ingress的中, 不需要而外的操作。
2)减少不必要的端口映射
  配置过k8s的都清楚, 第一步是要关闭防火墙的, 主要原因是k8s的很多服务会以NodePort方式映射出去, 这样就相当于给宿主机打了很多孔, 既不安全也不优雅. 而Ingress可以避免这个问题, 除了Ingress自身服务可能需要映射出去, 其他服务都不要用NodePort方式

2、Ingress-nginx工作原理

1)ingress controller通过和kubernetes api交互,动态的去感知集群中ingress规则变化,
2)然后读取它,按照自定义的规则,规则就是写明了哪个域名对应哪个service,生成一段nginx配置,
3)再写到nginx-ingress-controller的pod里,这个Ingress controller的pod里运行着一个Nginx服务,控制器会把生成的nginx配置写入/etc/nginx.conf文件中,
4)然后reload一下使配置生效。以此达到域名分别配置和动态更新的问题。

二、Ingress-nginx配置示例

注:文中所有的yaml文件及镜像都可以通过我的网盘链接下载(httpd和tomcat除外)。

1、搭建registry私有仓库(可跳过配置私有仓库,选择手动导入所需镜像到相应节点)

#运行registry私有仓库[root@master ~]# docker run -tid --name registry -p 5000:5000 --restart always registry[root@master ~]# vim /usr/lib/systemd/system/docker.service      #修改配置文件,指定私有仓库ExecStart=/usr/bin/dockerd -H unix:// --insecure-registry 192.168.20.6:5000#将修改后的文件发送到k8s群集中的其他节点[root@master ~]# scp /usr/lib/systemd/system/docker.service root@node01:/usr/lib/systemd/system/docker.service                      100% 1637     1.6KB/s   00:00    [root@master ~]# scp /usr/lib/systemd/system/docker.service root@node02:/usr/lib/systemd/system/#在各个节点包括master上执行以下命令,重启docker,使更改生效[root@master ~]# systemctl daemon-reload [root@master ~]# systemctl restart docker#上传测试所需的镜像到私有仓库[root@master ~]# docker push 192.168.20.6:5000/httpd:v1 [root@master ~]# docker push 192.168.20.6:5000/tomcat:v1 

2、创建namespace(也可跳过,使用默认的default名称空间也可以,但需要删除下面所有yaml文件中关于自定义的名称空间的配置字段)

[root@master ~]# kubectl create ns test-ns     #创建名称空间test-ns[root@master ~]# kubectl get ns   #确认创建成功

3、创建Deployment、Service资源对象

1)创建httpd服务及其service
[root@master test]# vim httpd-01.yaml    #编写基于httpd服务的资源对象kind: DeploymentapiVersion: extensions/v1beta1metadata:  name: web01  namespace: test-nsspec:  replicas: 3  template:    metadata:      labels:        app: httpd01    spec:      containers:      - name: httpd        image: 192.168.20.6:5000/httpd:v1---apiVersion: v1kind: Servicemetadata:  name: httpd-svc  namespace: test-nsspec:  selector:    app: httpd01  ports:  - protocol: TCP    port: 80    targetPort: 80[root@master test]# kubectl apply -f httpd-01.yaml      #执行yaml文件
2)创建tomcat服务及其service
[root@master test]# vim tomcat-01.yaml   #编写yaml文件如下kind: DeploymentapiVersion: extensions/v1beta1metadata:  name: web02  namespace: test-nsspec:  replicas: 3  template:    metadata:      labels:        app: tomcat01    spec:      containers:      - name: tomcat        image: 192.168.20.6:5000/tomcat:v1---apiVersion: v1kind: Servicemetadata:  name: tomcat-svc  namespace: test-nsspec:  selector:    app: tomcat01  ports:  - protocol: TCP    port: 8080    targetPort: 8080[root@master test]# kubectl apply -f tomcat-01.yaml    #执行yaml文件
3)确认成功创建上述资源对象
[root@master test]# kubectl get po -n test-ns        #确定pod是正常运行状态NAME                     READY   STATUS    RESTARTS   AGEweb01-757cfc547d-fmjnt   1/1     Running   0          8m24sweb01-757cfc547d-pjrrt   1/1     Running   0          9m30sweb01-757cfc547d-v7tdb   1/1     Running   0          8m24sweb02-57c46c759d-l9qzx   1/1     Running   0          4m9sweb02-57c46c759d-vs6mg   1/1     Running   0          4m9sweb02-57c46c759d-zknrw   1/1     Running   0          4m9s[root@master test]# kubectl get svc -n test-ns     #确认SVC创建成功NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGEhttpd-svc    ClusterIP   10.107.211.219           80/TCP     10mtomcat-svc   ClusterIP   10.101.159.1             8080/TCP   5m8s#访问SVC的clusterIP+端口,确定可以访问到后端Pod[root@master test]# curl -I 10.101.159.1:8080    #访问tomcatHTTP/1.1 200       #返回状态码为200Content-Type: text/html;charset=UTF-8Transfer-Encoding: chunkedDate: Fri, 22 Nov 2019 12:34:32 GMT[root@master test]# curl -I 10.107.211.219:80    #访问httpdHTTP/1.1 200 OK      #状态码为200Date: Fri, 22 Nov 2019 12:34:39 GMTServer: Apache/2.4.41 (Unix)         #版本号也有Last-Modified: Sat, 16 Nov 2019 10:00:39 GMTETag: "1a-59773c95e7fc0"Accept-Ranges: bytesContent-Length: 26Content-Type: text/html#如果在上述访问测试中,没有访问到相应的pod,建议使用"kubectl describe svc"命令,#查看相应的service中的Endpoints列中有没有关联后端pod。

4、创建Ingress-nginx资源对象

下载我提供的镜像并导入到需要运行Ingress-nginx的节点上,也可以选择自行下载其他镜像。

方法1:去gitlab搜索Ingress-nginx,点击"deploy",再点击页面下的跳转链接,即可看到如下命令:

#不要直接复制命令到终端执行,先将yaml文件下载下来[root@master test]# wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/static/mandatory.yaml[root@master test]# vim mandatory.yaml      #修改其yaml文件#修改以下内容    spec:               #这是在212行的spec字段      hostNetwork: true          #添加这行,表示使用主机网络      # wait up to five minutes for the drain of connections      terminationGracePeriodSeconds: 300      serviceAccountName: nginx-ingress-serviceaccount      nodeSelector:        Ingress: nginx     #设置节点的标签选择器,指定在哪台节点上运行      containers:        - name: nginx-ingress-controller          image: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.26.1#上面是指定使用什么镜像,若需要更改镜像名称,改这里即可,我保持默认。#修改后保存退出即可[root@master test]# kubectl label nodes node01 Ingress=nginx #对node01节点打相应的标签,以便指定Ingress-nginx运行在node01#可以执行下面的命令,查看node01的标签是否存在[root@master test]# kubectl get nodes node01 --show-labels #在node01节点执行下面命令,导入Ingress-nginx镜像(自行上传这个包,我提供的网盘链接中有)[root@node01 ~]# docker load < nginx-ingress-controller.0.26.1.tar #手动将ingress-nginx镜像导入到node01节点#回到master节点,执行yaml文件[root@master test]# kubectl apply -f mandatory.yaml   #执行ingress-nginx的yaml文件

关于上面yaml文件中写入的"hostNetwork: true"具体解释:如果使用此网络参数,那么pod中运行的应用程序可以直接使用Node节点端口,这样node节点主机所在的网络的其他主机,都可以通过访问到此应用程序。

确定Ingress-nginx的容器运行正常:
[root@master test]# kubectl get pod -n ingress-nginx -o wideNAME                                        READY   STATUS    RESTARTS   AGE    IP             NODE     NOMINATED NODE   READINESS GATESnginx-ingress-controller-77c8f6577b-6shdc   1/1     Running   0          107s   192.168.20.7   node01              

5、定义Ingress规则(编写ingress的yaml文件)

[root@master test]# vim ingress.yaml      #编写yaml文件如下apiVersion: extensions/v1beta1kind: Ingressmetadata:  name: test-ingress  namespace: test-ns  annotations:    nginx.ingress.kubernetes.io/rewrite-target: /spec:  rules:  - host: www.test01.com    http:      paths:      - path: /        backend:          serviceName: httpd-svc          servicePort: 80      - path: /tomcat        backend:          serviceName: tomcat-svc          servicePort: 8080[root@master test]# kubectl apply -f ingress.yaml      #执行ingress规则的yaml文件[root@master test]# kubectl get ingresses -n test-ns      #查看ingresses规则资源对象NAME           HOSTS            ADDRESS   PORTS   AGEtest-ingress   www.test01.com             80      28s

其实,至此已经实现了我们想要的功能,现在就可以通过www.test01.com 来访问到我们后端httpd容器提供的服务,通过www.test01.com/tomcat 来访问我们后端tomcat提供的服务,当然,前提是自行配置DNS解析,或者直接修改client的hosts文件。访问页面如下(注意:一定要自己解决域名解析的问题,若不知道域名对应的是哪个IP,请跳过这两个图,看下面的文字解释):

访问httpd服务(首页内容是我自定义的):

访问tomcat服务:

在上面的访问测试中,虽然访问到了对应的服务,但是有一个弊端,就是在做DNS解析的时候,只能指定Ingress-nginx容器所在的节点IP。而指定k8s集群内部的其他节点IP(包括master)都是不可以访问到的,如果这个节点一旦宕机,Ingress-nginx容器被转移到其他节点上运行(不考虑节点标签的问题,其实保持Ingress-nginx的yaml文件中默认的标签的话,那么每个节点都是有那个标签的)。随之还要我们手动去更改DNS解析的IP(要更改为Ingress-nginx容器所在节点的IP,通过命令"kubectl get pod -n ingress-nginx -o wide"可以查看到其所在节点),很是麻烦。

有没有更简单的一种方法呢?答案是肯定的,就是我们为Ingress-nginx规则再创建一个类型为nodePort的Service,这样,在配置DNS解析时,就可以使用www.test01.com 绑定所有node节点,包括master节点的IP了,很是灵活。

6、为Ingress规则创建一个Service

就在刚才找到Ingress-nginx的yaml文件的页面,然后下拉页面,即可看到以下,可以根据k8s集群环境来选择适合自己的yaml文件,假如自己是在Azure云平台搭建的K8s集群,则选择复制Azure下面的命令即可,我这里是自己的测试环境,所以选择Bare-metal下面的yaml文件:

创建这个Service有两种方法,一是直接复制其web页面的命令到master节点上执行,二是将其链接地址复制到终端使用wget下载下来再执行,我选择第二种方法,因为我想看看里面的内容:

#将其下载到本地[root@master test]# wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/static/provider/baremetal/service-nodeport.yaml[root@master test]# cat service-nodeport.yaml      #仅仅是查看一下内容,并不需要修改apiVersion: v1kind: Servicemetadata:  name: ingress-nginx  namespace: ingress-nginx  labels:    app.kubernetes.io/name: ingress-nginx    app.kubernetes.io/part-of: ingress-nginxspec:  type: NodePort  ports:    - name: http      port: 80      targetPort: 80      protocol: TCP    - name: https      port: 443      targetPort: 443      protocol: TCP  selector:    app.kubernetes.io/name: ingress-nginx    app.kubernetes.io/part-of: ingress-nginx---[root@master test]# kubectl apply -f service-nodeport.yaml       #执行下载下来的yaml文件[root@master test]# kubectl get svc -n ingress-nginx    #查看运行的serviceNAME            TYPE       CLUSTER-IP       EXTERNAL-IP   PORT(S)                      AGEingress-nginx   NodePort   10.109.106.246           80:30465/TCP,443:32432/TCP   56s#可以看到service分别将80和443端口映射到了节点的30645和32432端口(随机映射的,也可以修改yaml文件指定端口)。

至此,这个www.test01.com 的域名即可和群集中任意节点的30465/32432端口进行绑定了。

测试如下(域名解析对应的IP可以是k8s群集内的任意节点IP):

至此,就实现了最初的需求。

基于虚拟主机的Ingress规则

如果现在是另一种需求,我需要将www.test01.com 和www.test02.com 都对应上我后端的httpd容器提供的服务,那么此时应该怎么配置?

配置如下(基于上面的环境进行配置):
[root@master test]# vim ingress.yaml       #修改ingress规则的yaml文件如下apiVersion: extensions/v1beta1kind: Ingressmetadata:  name: test-ingress  namespace: test-ns  annotations:    nginx.ingress.kubernetes.io/rewrite-target: /spec:  rules:  - host: www.test02.com  #增加这一段host配置    http:      paths:      - path: /        backend:          serviceName: httpd-svc     #绑定和www.test01相同的service名字即可          servicePort: 80  - host: www.test01.com    http:      paths:      - path: /        backend:          serviceName: httpd-svc          servicePort: 80      - path: /tomcat        backend:          serviceName: tomcat-svc          servicePort: 8080#增加完上述的host字段保存退出即可[root@master test]# kubectl apply -f ingress.yaml    #重新执行yaml文件

至此,即可实现访问www.test01.com 和www.test02.com 都可以访问到后端的httpd提供的页面(自行解决域名解析问题),如下:

访问www.test01.com:30465

访问www.test02.com:30465

总结上述示例的pod是如何一步一步可以使client访问到的,总结如下:

后端pod===》service====》ingress规则====》写入Ingress-nginx-controller配置文件并自动重载使更改生效===》对Ingress-nginx创建service====》实现client无论通过哪个K8节点的IP+端口都可以访问到后端pod

三、配置HTTPS

在上面的操作中,实现了使用ingress-nginx为后端所有pod提供一个统一的入口,那么,有一个非常严肃的问题需要考虑,就是如何为我们的pod配置CA证书来实现HTTPS访问?在pod中直接配置CA么?那需要进行多少重复性的操作?而且,pod是随时可能被kubelet杀死再创建的。当然这些问题有很多解决方法,比如直接将CA配置到镜像中,但是这样又需要很多个CA证书。

这里有更简便的一种方法,就拿上面的情况来说,后端有多个pod,pod与service进行关联,service又被ingress规则发现并动态写入到ingress-nginx-controller容器中,然后又为ingress-nginx-controller创建了一个Service映射到群集节点上的端口,来供client来访问。

在上面的一系列流程中,关键的点就在于ingress规则,我们只需要在ingress的yaml文件中,为域名配置CA证书即可,只要可以通过HTTPS访问到域名,至于这个域名是怎么关联到后端提供服务的pod,这就是属于k8s群集内部的通信了,即便是使用http来通信,也无伤大雅。

配置如下:

接下来的配置与上面的配置基本没什么关系,但是由于上面已经运行了Ingress-nginx-controller容器,所以这里就没有必要再运行了。只需要配置pod、service、ingress规则即可。

#创建CA证书(测试环境,自己创建吧)[root@master https]# openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=nginxsvc/O=nginxsvc"#当前目录下会生成两个文件,如下:[root@master https]# ls      #确定当前目录下有这两个文件tls.crt  tls.key#将生成的CA证书存储到etcd[root@master https]# kubectl create secret tls tls-secret --key=tls.key --cert tls.crt#创建deploy、service、ingress资源对象[root@master https]# vim httpd03.yaml      #编写yaml文件kind: DeploymentapiVersion: extensions/v1beta1metadata:  name: web03spec:  replicas: 2  template:    metadata:      labels:        app: httpd03    spec:      containers:      - name: httpd3        image: 192.168.20.6:5000/httpd:v1---apiVersion: v1kind: Servicemetadata:  name: httpd-svc3spec:  selector:    app: httpd03  ports:  - protocol: TCP    port: 80    targetPort: 80---apiVersion: extensions/v1beta1kind: Ingressmetadata:  name: test-ingress3spec:  tls:    - hosts:      - www.test03.com      secretName: tls-secret         #这里是指定的是etcd存储的CA证书名称  rules:  - host: www.test03.com    http:      paths:      - path: /        backend:          serviceName: httpd-svc3          servicePort: 80[root@master https]# kubectl apply -f httpd03.yaml     #执行yaml文件

确认创建的资源对象正常运行:

[root@master https]# kubectl get svc      #查看svcNAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGEhttpd-svc3   ClusterIP   10.98.180.104           80/TCP    31skubernetes   ClusterIP   10.96.0.1               443/TCP   19d[root@master https]# kubectl get pod      #查看podNAME                    READY   STATUS    RESTARTS   AGEweb03-66dfbc8cf-w6vvp   1/1     Running   0          34sweb03-66dfbc8cf-zgxd7   1/1     Running   0          34s[root@master https]# kubectl describe ingresses    #查看ingress规则Name:             test-ingress3Namespace:        defaultAddress:          10.109.106.246Default backend:  default-http-backend:80 ()TLS:  tls-secret terminates www.test03.comRules:  Host            Path  Backends  ----            ----  --------  www.test03.com                    /   httpd-svc3:80 (10.244.1.13:80,10.244.2.9:80)#确定关联到对应的service及后端的pod

https访问测试:

使用https://www.test03.com 进行访问(自行解决域名解析问题)

-------- 本文至此结束,感谢阅读 --------

文件 节点 配置 服务 规则 运行 端口 对象 域名 资源 镜像 面的 命令 问题 容器 就是 方法 集群 测试 选择 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 北京互联网科技公司 杭州互联网科技公司 互联网科技排名 华中科技大学互联网 广州互联网络科技有限公司 电子科技大学互联网 易通互联网络科技有限公司 广州凡科互联网科技 唐信互联网科技 大连 上海亿帐通互联网科技 互联网科技博主是什么意思 北京大学互联网科技怎么样 剑昆互联网络科技有限公司临桂 阿里互联网科技企业 伍佰万互联网科技怎么赚钱 梅州GM互联网络科技有限公司 广州有谷有贝互联网科技有限公司 广东鹅鹅鹅互联网科技有限公司 互联网科技平台产品运营 东风日产互联网科技公司叫什么 互联网品科技 科技企业和互联网企业 长亮科技 互联网金融 互联网科技博主是什么意思 中国的互联网科技企业的崛起 佳云科技和互联网广告 互联网科技公司有风险吗 辽宁互联网新科技 洛阳共同富裕互联网科技有限公司 梅州GM互联网络科技有限公司
0