目录
前言——Service策略的作用
1.外部访问方案
2.使用场景和限制
2.1NodePort
2.2LoadBalancer
2.3externalIPs
2.4Ingress
3.Ingress如何实现对外服务
4.LB和Ingress结合起来实现对外服务的过程
一、Ingress
1.定义
2.组成
3.工作原理
4.总结
二、部署Nginx-Ingress-Controller
1.下载配置并修改集群角色(ClusterRole)
2.暴露Ingress服务
2.1Deployment+LoadBalancer 模式的 Service
2.2DaemonSet+HostNetwork+nodeSelector
2.3Deployment+NodePort模式的 Service
三、采用DaemonSet+HostNetwork+nodeSelector暴露服务
1.指定Nginx-Ingress-Controller运行在Node2节点
2.修改控制器并指定节点运行开启网络
3.上传加载镜像
4.启动Nginx-Ingress-Controller
5.创建Ingress规则
5.1创建Deployment和SVC
5.2创建Ingress规则
6.测试访问
7.查看Nginx-Ingress-Controller
四、采用Deployment+NodePort模式的Service
1.下载配置文件
2.在所有 Node 节点上传镜像包并加载镜像
3.启动Nginx-Ingress-Controller
五、Ingress HTTP代理访问
1.编写Yaml文件并创建资源
2.测试
六、Ingress HTTP 代理访问虚拟主机
1.创建虚拟主机1资源
2.创建虚拟主机2资源
3.创建Ingress资源
4.测试访问
七、Ingress HTTPS代理访问
1.创建SSL证书
2.创建Secret资源存储
3.创建Deployment、Service、Ingress资源
4.测试访问
八、Nginx进行BasicAuth
1.生成用户密码认证文件,创建Secret资源进行存储
2.创建Ingress资源
3.访问测试
九、Nginx重写
1.编写配置文件
2.访问测试
十、总结
1.Ingress数据流向
2.基于主机名的虚拟主机
3.HTTPS
4.Rewrite重定向
前言——Service策略的作用
在Kubernetes中,Service是一种抽象,用于定义一组Pod的访问方式和网络策略。它提供了一种稳定的网络终结点,以便其他应用程序可以访问这些Pod。Service的作用主要体现在两个方面:
- 服务发现: Service允许其他应用在集群内发现并访问特定的Pod,即使Pod的IP地址会随着时间的变化而改变,Service提供了一个稳定的虚拟IP和DNS名称,使得其他应用能够持续地与服务通信。
- 负载均衡: 当一个Service代表多个Pod时,它可以在这些Pod之间进行负载均衡,确保请求被均匀地分发到各个Pod上,从而提高应用程序的可用性和性能。
在 Kubernetes 中,Pod 的 IP 地址和 Service 的 ClusterIP 只能在集群内部网络中访问。这意味着,对于集群外部的应用来说,这些地址是不可见的。
1.外部访问方案
- NodePort:通过在每个节点上开放一个端口(NodePort),可以将service服务暴露给外部网络。Kube-Proxy 负责在服务网络、Pod 网络和节点网络之间进行通信。这种方式在测试环境中适用,但在生产环境中,当服务数量众多时,端口管理会变得复杂,因为每个端口只能对应一种服务,且端口范围有限(通常为 30000-32767)。
- LoadBalancer:这种方式通过云服务提供商的负载均衡器(LoadBalancer)来暴露服务。这通常在公有云平台上使用,但受限于云平台的支持,并且可能需要额外的费用。
- externalIPs:Service 可以被分配一个或多个外部 IP 地址。如果这些 IP 地址能够路由到集群中的一个或多个节点,那么服务就会通过这些 IP 地址暴露。流量通过这些外部 IP 进入集群后,会被路由到 Service 的 Endpoint。
- Ingress:Ingress 提供了一种更为高效的方式,它允许使用一个或少量的公网 IP 地址和负载均衡器(LB)来同时暴露多个 HTTP 服务。Ingress 可以看作是 Service 的进一步抽象,它基于域名和 URL 路径来定义规则,将用户的请求转发到一个或多个 Service。
2.使用场景和限制
2.1NodePort
- 适用场景:在小型集群或测试环境中,NodePort 是一个简单且易于设置的选项。它允许直接通过节点的 IP 地址和特定端口访问服务。
- 限制:在生产环境中,由于端口范围有限(30000-32767),并且每个端口只能映射到一个服务,这可能导致端口资源耗尽和管理复杂性增加。
2.2LoadBalancer
- 适用场景:在云服务提供商(如 AWS、Azure、Google Cloud 等)的环境中,LoadBalancer 是最常使用的方案。它提供了自动的负载均衡和扩展能力,适合需要高可用性和可扩展性的生产环境。
- 成本:使用 LoadBalancer 可能会产生额外的费用,因为它通常涉及云服务提供商的负载均衡服务。
2.3externalIPs
- 适用场景:当集群部署在具有固定公网 IP 地址的环境中,或者需要直接使用外部 IP 地址时,externalIPs 是一个合适的选择。这在私有云或混合云部署中较为常见。
- 限制:需要确保外部 IP 地址能够正确路由到集群节点,并且可能需要额外的网络配置。
2.4Ingress
- 适用场景:Ingress 是最灵活的方案,它允许通过一个或少量的公网 IP 地址来暴露多个服务。这在需要管理大量服务的复杂应用场景中非常有用,尤其是在需要基于域名和路径进行细粒度流量控制时。
- 优势:Ingress 提供了更高级的功能,如 SSL/TLS 终端、HTTP 重写、负载均衡、虚拟主机等。它也支持更复杂的路由规则,如基于路径的路由和重定向。
在实际部署中,Ingress 由于其灵活性和高级功能,通常被认为是最常使用的方案,尤其是在生产环境中。它允许开发者和运维人员以声明式的方式管理入口流量,而无需关心底层的网络实现细节。此外,Ingress 控制器(如 nginx-ingress 或 traefik)的流行也促进了 Ingress 的广泛采用。
3.Ingress如何实现对外服务
在Kubernetes中,LB(负载均衡器)和Ingress一起使用时,LB通常指的是负载均衡器服务,而Ingress是一种资源,用于定义应用程序的外部入口。LB通过将外部流量路由到Kubernetes集群内的Ingress Controller来实现对多个服务的管理。Ingress Controller会根据Ingress规则将请求路由到相应的服务,为应用提供统一的入口。这组合提供了高级别的路由和负载平衡功能,使得在Kubernetes环境中更灵活地管理服务的访问。
4.LB和Ingress结合起来实现对外服务的过程
- LB配置: 负载均衡器(Load Balancer)通过配置将外部流量引导到Kubernetes集群。这可能涉及到云服务商的负载均衡器设置或其他物理设备。
- Ingress Controller部署: 在Kubernetes集群中部署Ingress Controller,它负责管理Ingress资源并根据其规则处理请求。
- Ingress资源定义: Kubernetes用户通过创建Ingress资源定义外部访问规则,包括路径、主机等信息。这些规则描述了如何将外部请求路由到集群内的服务。
- Ingress Controller监听: Ingress Controller会监听集群中的Ingress资源的变化,并根据定义的规则更新其配置。
- 请求路由: 当外部请求到达负载均衡器时,LB将请求转发到Ingress Controller。Ingress Controller根据Ingress规则将请求路由到相应的服务。
- 服务响应: 被选中的服务接收请求并提供相应的响应。这使得在Kubernetes环境中,可以更加灵活地管理多个服务的对外访问。
这整个过程的目标是实现集中化的入口管理,允许动态调整路由规则而无需修改底层服务。
一、Ingress
1.定义
Ingress 是 Kubernetes 中的一个 API 对象,它允许你定义一组规则,这些规则控制着外部访问你的集群内服务的方式。Ingress 可以被看作是集群的入口点,它提供了一种机制来管理外部访问到集群内部服务的 HTTP 和 HTTPS 流量。Ingress 规则基于域名和 URL 路径,将用户的请求转发到一个或多个后端服务。
Ingress并不直接处理或转发流量,它需要与Ingress Controller一起使用。Ingress Controller是一个实际处理流量的组件,它根据Ingress资源中定义的规则,将请求路由到正确的服务。这种组合使得在Kubernetes环境中能够方便地管理多个服务的访问入口。
2.组成
- Ingress 资源对象:这是通过 YAML 文件配置的,它定义了请求如何转发到服务的规则。Ingress 对象可以包含多个规则,每个规则可以指定不同的域名、路径和后端服务。
- Ingress 控制器(Ingress Controller):这是一个运行在 Kubernetes 集群中的组件,它负责实现 Ingress 资源对象中定义的规则。Ingress 控制器通常是一个反向代理服务器,如 Nginx 或 Traefik,它根据 Ingress 规则来处理进入集群的流量。
一般,ingress-controller的形式都是一个pod,里面跑着daemon程序和反向代理程序。daemon负责不断监控集群的变化,根据 ingress对象生成配置并应用新配置到反向代理,比如ingress-nginx就是动态生成nginx配置,动态更新upstream,并在需要的时候reload程序应用新配置。为了方便,后面的例子都以k8s官方维护的ingress-nginx为例。
Ingress-Nginx github 地址:https://github.com/kubernetes/ingress-nginx
Ingress-Nginx 官方网站:https://kubernetes.github.io/ingress-nginx/
总结来说:ingress-controller才是负责具体转发的组件,通过各种方式将它暴露在集群入口,外部对集群的请求流量会先到 ingress-controller, 而ingress对象是用来告诉ingress-controller该如何转发请求,比如哪些域名、哪些URL要转发到哪些service等等。
3.工作原理
- Ingress 控制器通过与 Kubernetes API Server 交互,动态感知集群中 Ingress 规则的变化。
- 控制器读取这些规则,并根据自定义的规则生成相应的配置(例如 Nginx 配置),而规则就是写明了哪个域名对应哪个service。
- 控制器将这些配置应用到其运行的反向代理服务中,例如将配置写入 Nginx 的配置文件,并重新加载服务以使配置生效。也就是写到nginx-ingress-controller的pod里,这个ingress-controller的pod里运行着一个Nginx服务,控制器会把生成的 nginx配置写入 /etc/nginx.conf文件中。
- reload后配置生效
4.总结
- Ingress作为请求入口
- Ingress确实是Kubernetes集群的入口点,它允许外部流量进入集群内部。Ingress提供了一种机制,可以根据定义的规则将外部HTTP和HTTPS请求路由到集群内的多个服务。
- Ingress资源对象与Ingress Controller
- Ingress资源对象定义了路由规则,包括URL路径、主机名、重定向、负载均衡等。
- Ingress Controller是一个运行在集群中的组件,它负责实现Ingress资源对象中定义的规则。Ingress-Nginx是Kubernetes社区原生支持的一种Ingress Controller实现,它使用Nginx作为反向代理服务器。
- Ingress Controller的选择
- 根据具体的需求,可以选择不同的Ingress Controller。除了Ingress-Nginx,还有其他实现,如Traefik、HAProxy等。每种实现都有其特点和优势,选择合适的Ingress Controller可以提高集群的灵活性和性能。
- Ingress的暴露方式
- Ingress可以通过多种方式暴露服务,包括NodePort、LoadBalancer、IngressClass等。
- NodePort在集群节点上为服务提供一个静态端口,外部流量可以通过这个端口访问服务。
- LoadBalancer通常用于云环境,它创建一个负载均衡器,为服务提供一个外部可访问的IP地址。
- IngressClass提供了一种更灵活的方式来定义Ingress资源的行为,允许管理员定义不同的Ingress策略。
二、部署Nginx-Ingress-Controller
1.下载配置并修改集群角色(ClusterRole)
mkdir /opt/ingress
cd /opt/ingress
由于官方下载地址可能无法下载,可以使用国内的Gitee镜像来下载所需的YAML配置文件。这里有两个版本的配置文件,一个是nginx-0.25.0,另一个是nginx-0.30.0。可以选择一个版本进行下载。#对于nginx-0.25.0版本
wget https://gitee.com/mirrors/ingress-nginx/raw/nginx-0.25.0/deploy/static/mandatory.yaml#对于nginx-0.30.0版本
wget https://gitee.com/mirrors/ingress-nginx/raw/nginx-0.30.0/deploy/static/mandatory.yaml#确保下载的是最新版本的配置文件,因为新版本可能包含了安全更新和功能改进。如果不确定哪个版本更适合你,可以查看官方文档或者社区讨论来决定。mandatory.yaml文件中包含了很多资源的创建,包括namespace、ConfigMap、role,ServiceAccount等等所有部署ingress-controller需要的资源。
#修改 集群角色(ClusterRole) 资源配置
#clusterRole用于定义集群中资源的权限vim mandatory.yaml
......
apiVersion: rbac.authorization.k8s.io/v1beta1
#RBAC相关资源从1.17版本开始改用rbac.authorization.k8s.io/v1,rbac.authorization.k8s.io/v1beta1在1.22版本即将弃用
#指定 Kubernetes API 的版本,此处使用的是 rbac.authorization.k8s.io/v1beta1 版本,但注释中提到从 1.17 版本开始应改用 rbac.authorization.k8s.io/v1,而 v1beta1 版本将在 1.22 版本后弃用。
kind: ClusterRole
#指定资源的类型,这里是 ClusterRole,表示集群级别的角色
metadata:
#指定资源的元数据,包括名称和标签等信息name: nginx-ingress-clusterrolelabels:app.kubernetes.io/name: ingress-nginxapp.kubernetes.io/part-of: ingress-nginx
rules:
#定义了针对不同资源的访问规则。在这里,包含了多个规则,每个规则指定了对一类资源的访问权限- apiGroups:- ""resources:- configmaps- endpoints- nodes- pods- secretsverbs:- list- watch#对 ConfigMaps、Endpoints、Nodes、Pods 和 Secrets 等资源的 list 和 watch 权限- apiGroups:- ""resources:- nodesverbs:- get#对 Nodes 资源的 get 权限- apiGroups:- ""resources:- servicesverbs:- get- list- watch#对 Services 资源的 get、list 和 watch 权限- apiGroups:- "extensions"- "networking.k8s.io" # (0.25版本)增加 networking.k8s.io Ingress 资源的 api resources:- ingressesverbs:- get- list- watch#对 Ingress 资源的 get、list 和 watch 权限,其中包括了对 "extensions" 和 "networking.k8s.io" API 组的 Ingress 资源的权限- apiGroups:- ""resources:- eventsverbs:- create- patch#对 Events 资源的 create 和 patch 权限- apiGroups:- "extensions"- "networking.k8s.io" # (0.25版本)增加 networking.k8s.io/v1 Ingress 资源的 api resources:- ingresses/statusverbs:- update#对 Ingress 资源状态的 update 权限,同样包括了 "extensions" 和 "networking.k8s.io" API 组的 Ingress 资源#这份 YAML 文件是对 Kubernetes 中的 ClusterRole 资源进行配置的,ClusterRole 用于定义对集群中资源的权限。这些规则定义了该 ClusterRole 在集群中对各种资源的访问权限,以及允许的操作。这样配置的 ClusterRole 可以被绑定到用户、服务账户或者其他身份上,以控制它们对集群资源的访问权限
2.暴露Ingress服务
2.1Deployment+LoadBalancer 模式的 Service
- 这种方式适用于在公有云环境中部署 Ingress。首先使用 Deployment 来部署 ingress-controller。
- 然后创建一个 type 为 LoadBalancer 的 Service,这个 Service 会与 ingress-controller 的 Pod 关联。
- 大多数公有云服务提供商会为 LoadBalancer 类型的 Service 自动创建一个负载均衡器,并分配一个公网 IP 地址。
- 只需要将域名解析到这个公网 IP 地址,就可以实现服务的外部访问。
2.2DaemonSet+HostNetwork+nodeSelector
- 使用 DaemonSet 部署 ingress-controller,这样可以确保在每个节点上都运行一个 ingress-controller 的 Pod。
- 通过设置 hostNetwork: true,使得 Pod 直接使用宿主机的网络命名空间,这样 Pod 就可以直接使用宿主机的 IP 地址和端口。
- 使用 nodeSelector 可以选择特定的节点来部署 ingress-controller。
- 这种方式下,Ingress 控制器所在的节点就像传统的边缘节点,例如机房入口的 Nginx 服务器。
- 这种方式的优点是请求链路简单,性能较好。但缺点是每个节点只能部署一个 ingress-controller Pod,因为它们直接使用了宿主机的网络和端口。
2.3Deployment+NodePort模式的 Service
- 同样使用 Deployment 来部署 ingress-controller。
- 创建一个 type 为 NodePort 的 Service,这样 Ingress 会暴露在集群节点的 IP 地址上的一个特定端口。
- NodePort 模式会为每个节点分配一个随机端口,通常你会在前面设置一个负载均衡器来转发请求到这些端口。
- 这种方式适用于宿主机 IP 地址相对固定且不会变化的场景。
- 虽然 NodePort 方式简单方便,但由于多了一层网络地址转换(NAT),在高并发情况下可能会对性能产生影响。
三、采用DaemonSet+HostNetwork+nodeSelector暴露服务
1.指定Nginx-Ingress-Controller运行在Node2节点
#为节点添加标签
kubectl label node node2 ingress=true#查看节点标签
kubectl get nodes --show-labels
2.修改控制器并指定节点运行开启网络
#修改 Deployment 为 DaemonSet ,指定节点运行,并开启 hostNetwork 网络
vim mandatory.yaml
...
apiVersion: apps/v1
# 修改 kind
# kind: Deployment
kind: DaemonSet
metadata:name: nginx-ingress-controllernamespace: ingress-nginxlabels:app.kubernetes.io/name: ingress-nginxapp.kubernetes.io/part-of: ingress-nginx
spec:
# 删除Replicas,DaemonSet 不需要 replicas 字段,因为它会确保 Pod 在每个选定的节点上运行一个实例
# replicas: 1selector:matchLabels:app.kubernetes.io/name: ingress-nginxapp.kubernetes.io/part-of: ingress-nginxtemplate:metadata:labels:app.kubernetes.io/name: ingress-nginxapp.kubernetes.io/part-of: ingress-nginxannotations:prometheus.io/port: "10254"prometheus.io/scrape: "true"spec:# 使用主机网络,在 spec.template.spec 下添加 hostNetwork: true,这将使 Pod 使用宿主机的网络命名空间hostNetwork: true# 选择节点运行,在 spec.template.spec 下添加 nodeSelector 字段,并设置 ingress: "true",以便 Pod 只在带有 ingress=true 标签的节点上运行nodeSelector:ingress: "true"serviceAccountName: nginx-ingress-serviceaccount
......
3.上传加载镜像
- 上传镜像压缩包: 首先,需要将 ingree.contro.tar.gz 文件上传到所有节点的 /opt/ingress 目录。这可以通过 SSH 或其他文件传输方法完成。如果你有多个节点,你可以使用如 scp 或 rsync 这样的工具来批量传输文件。
- 解压镜像压缩包: 通过 SSH 登录到每个节点,然后导航到 /opt/ingress 目录并解压镜像文件。
- 加载 Docker 镜像: 解压后,可以使用
docker load
命令来加载镜像。确保已经切换到了包含解压后的 Docker 镜像文件的目录。然后执行
cd /opt/ingress
tar zxvf ingree.contro.tar.gz
docker load -i ingree.contro.tar
请注意,如果你的 Kubernetes 集群使用的是 Containerd 或其他容器运行时,而不是 Docker,那么加载镜像的命令可能会有所不同。在这种情况下,可能需要使用相应的工具来导入镜像。
4.启动Nginx-Ingress-Controller
kubectl apply -f mandatory.yamlkubectl get pod -n ingress-nginx -o widekubectl get cm,daemonset -n ingress-nginx -o wide
确保
nginx-ingress-controller
Pod 的状态是Running
,并且READY
列显示为1/1
,这表示 Pod 已经准备好接收流量。
#到Node2节点查看
netstat -lntp | grep nginx
nginx-ingress-controller 已经在 node02 节点上成功运行,并且配置了 hostNetwork,这意味着 nginx 直接在宿主机上监听了 80、443 和 8181 端口。这样,任何对这些端口的请求都会被转发到 nginx-ingress-controller。
其中 8181 是 nginx-controller 默认配置的一个 default backen(Ingress 资源没有匹配的 rule 对象时,流量就会被导向这个 default backend)。
这样,只要访问 node 主机有公网 IP,就可以直接映射域名来对外网暴露服务了。如果要 nginx 高可用的话,可以在多个 node上部署,并在前面再搭建一套 LVS+keepalived 做负载均衡。
5.创建Ingress规则
5.1创建Deployment和SVC
vim service-nginx.yamlapiVersion: apps/v1
kind: Deployment
metadata:name: nginx-app
spec:replicas: 2selector:matchLabels:app: nginxtemplate:metadata:labels:app: nginxspec:containers:- name: nginximage: nginximagePullPolicy: IfNotPresentports:- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:name: nginx-app-svc
spec:type: ClusterIPports:- protocol: TCPport: 80targetPort: 80selector:app: nginx
#在应用这个配置文件之前,请确保已经有一个名为 ingress-nginx 的命名空间,因为 Ingress 控制器通常在这个命名空间中运行。如果还没有这个命名空间,可以创建它kubectl create namespace ingress-nginx
kubectl apply -f service-nginx.yaml -n ingress-nginx
#创建 Deployment 和 Service
5.2创建Ingress规则
#方法一:(extensions/v1beta1 Ingress 在1.22版本即将弃用)
vim ingress-app.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:name: nginx-app-ingress
spec:rules:- host: www.cxk.comhttp:paths:- path: /backend:serviceName: nginx-app-svcservicePort: 80#方法二:
vim ingress-app.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:name: nginx-app-ingress
spec:rules:- host: www.cxk.comhttp:paths:- path: /pathType: Prefix backend:service:name: nginx-app-svcport:number: 80
现在,已经准备好应用 Ingress 规则。在应用 Ingress 规则之前,请确保域名 www.test.com 已经正确解析到了运行 nginx-ingress-controller 的节点的公网 IP 地址。如果域名解析还没有设置好,Ingress 规则将无法正常工作,因为外部请求无法正确路由到你的服务。
#应用 Ingress 规则
kubectl apply -f ingress-app.yaml -n ingress-nginx#创建一个名为 nginx-app-ingress 的 Ingress 资源,它将所有到 www.test.com 的 HTTP 请求路由到 nginx-app-svc 服务的 80 端口。#检查 Ingress 资源的状态
kubectl get ingress -n ingress-nginx#检查 Pod 的状态
kubectl get pods -n ingress-nginx#现在,当访问 www.test.com 时,请求应该会被 nginx-ingress-controller 接收,并转发到 nginx-app-svc 服务。因为 nginx-ingress-controller 配置了 hostNetwork,那么它将直接在节点的 80 端口上监听,并将流量转发到相应的服务。如果遇到问题,可以查看 nginx-ingress-controller 的日志来帮助诊断问题。
6.测试访问
vim /etc/hosts
#添加host域名解析192.168.241.11 master
192.168.241.22 node01
192.168.241.23 node02
192.168.241.23 www.cxk.comcurl www.cxk.com
7.查看Nginx-Ingress-Controller
kubectl get pod -n ingress-nginx -o widekubectl exec -it nginx-ingress-controller-qkrsk -n ingress-nginx bashmore /etc/nginx/nginx.conf |grep .com
四、采用Deployment+NodePort模式的Service
1.下载配置文件
创建一个新的目录 /opt/ingress-nodeport
,然后下载 nginx-ingress-controller
的配置文件和 NodePort 服务的配置文件。
官方下载地址:
wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.30.0/deploy/static/mandatory.yaml
wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.30.0/deploy/static/provider/baremetal/service-nodeport.yaml国内 gitee 资源地址:
wget https://gitee.com/mirrors/ingress-nginx/raw/nginx-0.30.0/deploy/static/mandatory.yaml
wget https://gitee.com/mirrors/ingress-nginx/raw/nginx-0.30.0/deploy/static/provider/baremetal/service-nodeport.yaml
2.在所有 Node 节点上传镜像包并加载镜像
将 ingress-controller-0.30.0.tar
镜像包上传到所有节点的 /opt/ingress-nodeport
目录,并使用 docker load
命令加载镜像。
# 假设你已经有了 ingress-controller-0.30.0.tar 文件
# 将文件上传到所有节点的 /opt/ingress-nodeport 目录
# 然后加载镜像
docker load -i ingress-controller-0.30.0.tar
3.启动Nginx-Ingress-Controller
使用 kubectl apply
命令应用 mandatory.yaml
和 service-nodeport.yaml
配置文件来启动 nginx-ingress-controller
。
vim mandatory.yamlapiVersion: v1
kind: Namespace
metadata:name: ingress-nginxlabels:app.kubernetes.io/name: ingress-nginxapp.kubernetes.io/part-of: ingress-nginx---kind: ConfigMap
apiVersion: v1
metadata:name: nginx-configurationnamespace: ingress-nginxlabels:app.kubernetes.io/name: ingress-nginxapp.kubernetes.io/part-of: ingress-nginx---
kind: ConfigMap
apiVersion: v1
metadata:name: tcp-servicesnamespace: ingress-nginxlabels:app.kubernetes.io/name: ingress-nginxapp.kubernetes.io/part-of: ingress-nginx---
kind: ConfigMap
apiVersion: v1
metadata:name: udp-servicesnamespace: ingress-nginxlabels:app.kubernetes.io/name: ingress-nginxapp.kubernetes.io/part-of: ingress-nginx---
apiVersion: v1
kind: ServiceAccount
metadata:name: nginx-ingress-serviceaccountnamespace: ingress-nginxlabels:app.kubernetes.io/name: ingress-nginxapp.kubernetes.io/part-of: ingress-nginx---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:name: nginx-ingress-clusterrolelabels:app.kubernetes.io/name: ingress-nginxapp.kubernetes.io/part-of: ingress-nginx
rules:- apiGroups:- ""resources:- configmaps- endpoints- nodes- pods- secretsverbs:- list- watch- apiGroups:- ""resources:- nodesverbs:- get- apiGroups:- ""resources:- servicesverbs:- get- list- watch- apiGroups:- ""resources:- eventsverbs:- create- patch- apiGroups:- "extensions"- "networking.k8s.io"resources:- ingressesverbs:- get- list- watch- apiGroups:- "extensions"- "networking.k8s.io"resources:- ingresses/statusverbs:- update---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: Role
metadata:name: nginx-ingress-rolenamespace: ingress-nginxlabels:app.kubernetes.io/name: ingress-nginxapp.kubernetes.io/part-of: ingress-nginx
rules:- apiGroups:- ""resources:- configmaps- pods- secrets- namespacesverbs:- get- apiGroups:- ""resources:- configmapsresourceNames:# Defaults to "<election-id>-<ingress-class>"# Here: "<ingress-controller-leader>-<nginx>"# This has to be adapted if you change either parameter# when launching the nginx-ingress-controller.- "ingress-controller-leader-nginx"verbs:- get- update- apiGroups:- ""resources:- configmapsverbs:- create- apiGroups:- ""resources:- endpointsverbs:- get---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: RoleBinding
metadata:name: nginx-ingress-role-nisa-bindingnamespace: ingress-nginxlabels:app.kubernetes.io/name: ingress-nginxapp.kubernetes.io/part-of: ingress-nginx
roleRef:apiGroup: rbac.authorization.k8s.iokind: Rolename: nginx-ingress-role
subjects:- kind: ServiceAccountname: nginx-ingress-serviceaccountnamespace: ingress-nginx---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:name: nginx-ingress-clusterrole-nisa-bindinglabels:app.kubernetes.io/name: ingress-nginxapp.kubernetes.io/part-of: ingress-nginx
roleRef:apiGroup: rbac.authorization.k8s.iokind: ClusterRolename: nginx-ingress-clusterrole
subjects:- kind: ServiceAccountname: nginx-ingress-serviceaccountnamespace: ingress-nginx---apiVersion: apps/v1
kind: Deployment
metadata:name: nginx-ingress-controllernamespace: ingress-nginxlabels:app.kubernetes.io/name: ingress-nginxapp.kubernetes.io/part-of: ingress-nginx
spec:replicas: 1selector:matchLabels:app.kubernetes.io/name: ingress-nginxapp.kubernetes.io/part-of: ingress-nginxtemplate:metadata:labels:app.kubernetes.io/name: ingress-nginxapp.kubernetes.io/part-of: ingress-nginxannotations:prometheus.io/port: "10254"prometheus.io/scrape: "true"spec:# wait up to five minutes for the drain of connectionsterminationGracePeriodSeconds: 300serviceAccountName: nginx-ingress-serviceaccountnodeSelector:kubernetes.io/os: linuxcontainers:- name: nginx-ingress-controllerimage: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.30.0args:- /nginx-ingress-controller- --configmap=$(POD_NAMESPACE)/nginx-configuration- --tcp-services-configmap=$(POD_NAMESPACE)/tcp-services- --udp-services-configmap=$(POD_NAMESPACE)/udp-services- --publish-service=$(POD_NAMESPACE)/ingress-nginx- --annotations-prefix=nginx.ingress.kubernetes.iosecurityContext:allowPrivilegeEscalation: truecapabilities:drop:- ALLadd:- NET_BIND_SERVICE# www-data -> 101runAsUser: 101env:- name: POD_NAMEvalueFrom:fieldRef:fieldPath: metadata.name- name: POD_NAMESPACEvalueFrom:fieldRef:fieldPath: metadata.namespaceports:- name: httpcontainerPort: 80protocol: TCP- name: httpscontainerPort: 443protocol: TCPlivenessProbe:failureThreshold: 3httpGet:path: /healthzport: 10254scheme: HTTPinitialDelaySeconds: 10periodSeconds: 10successThreshold: 1timeoutSeconds: 10readinessProbe:failureThreshold: 3httpGet:path: /healthzport: 10254scheme: HTTPperiodSeconds: 10successThreshold: 1timeoutSeconds: 10lifecycle:preStop:exec:command:- /wait-shutdown---apiVersion: v1
kind: LimitRange
metadata:name: ingress-nginxnamespace: ingress-nginxlabels:app.kubernetes.io/name: ingress-nginxapp.kubernetes.io/part-of: ingress-nginx
spec:limits:- min:memory: 90Micpu: 100mtype: Container
vim service-nodeport.yamlapiVersion: v1
kind: Service
metadata:name: ingress-nginxnamespace: ingress-nginxlabels:app.kubernetes.io/name: ingress-nginxapp.kubernetes.io/part-of: ingress-nginx
spec:type: NodePortports:- name: httpport: 80targetPort: 80protocol: TCP- name: httpsport: 443targetPort: 443protocol: TCPselector:app.kubernetes.io/name: ingress-nginxapp.kubernetes.io/part-of: ingress-nginx
kubectl apply -f mandatory.yaml
kubectl apply -f service-nodeport.yaml
这将创建 nginx-ingress-controller
的 Deployment 和相关的 RBAC 配置,以及一个 NodePort 类型的 Service,该 Service 将暴露 80 和 443 端口,允许外部流量通过这些端口访问 Ingress 控制器。
如果 Kubernetes Pod 调度失败,并且 kubectl describe pod 命令的输出显示了 "0/2 nodes are available: 2 node(s) didn't match node selector" 的警告时,这意味着 Pod 的调度请求无法找到符合其节点选择器(nodeSelector)的节点。这通常发生在 Pod 定义中指定了特定的节点选择器,但是集群中没有节点带有相应的标签。
要解决这个问题,有两个选择:
- 给需要调度的节点添加标签: 如果 Pod 需要在特定的节点上运行,需要确保这些节点有正确的标签。可以使用 kubectl label nodes 命令来给节点添加标签。例如,如果 Pod 需要在操作系统为 Linux 的节点上运行
kubectl label nodes <node_name> kubernetes.io/os=linux
将 <node_name> 替换为实际的节点名称。
- 删除或修改 Pod 定义中的节点选择器: 如果 Pod 不需要在特定的节点上运行,可以从 Pod 的定义中删除节点选择器。这通常在 Pod 的 YAML 文件中进行。例如,如果你的 Pod 定义如下:
spec:nodeSelector:kubernetes.io/os: linux
spec:nodeSelector: {}
#可以删除 nodeSelector 字段,或者将其设置为一个空对象
kubectl apply -f <pod_definition.yaml>
#然后重新应用 Pod 的 YAML 文件
请确保在修改 Pod 定义后重新应用配置,以便更改生效。
kubectl get pod,svc -n ingress-nginx
#查看状态
从输出来看,nginx-ingress-controller Pod 正在 ingress-nginx 命名空间中正常运行,状态为 Running。同时,ingress-nginx 服务是 NodePort 类型,这意味着它在集群的每个节点上都开放了特定的端口(80 端口映射到 32383 端口,443 端口映射到 32133 端口)以供外部访问。
五、Ingress HTTP代理访问
1.编写Yaml文件并创建资源
vim ingress-nginx.yaml apiVersion: apps/v1
kind: Deployment
#名为nginx-app,包含两个Nginx容器副本,监听容器端口80
metadata:name: nginx-app
spec:replicas: 2selector:matchLabels:name: nginxtemplate:metadata:labels:name: nginxspec:containers:- name: nginximage: nginximagePullPolicy: IfNotPresentports:- containerPort: 80
---
apiVersion: v1
kind: Service
#名为nginx-svc,类型为ClusterIP,端口80,选择器为name=nginx
metadata:name: nginx-svc
spec:ports:- port: 80targetPort: 80protocol: TCPselector:name: nginx
---
apiVersion: networking.k8s.io/v1
kind: Ingress
#名为nginx-test,配置了一个规则,将访问www.cxk.com域名的流量转发到nginx-svc服务的端口80
metadata:name: nginx-test
spec:rules:- host: www.cxk.comhttp:paths:- path: /pathType: Prefixbackend:service:name: nginx-svcport: number: 80kubectl apply -f ingress-nginx.yamlkubectl get svc,pods -o wide
为了使外部流量能够访问到这个服务,需要确保:
- Ingress Controller已正确安装并运行。
- 域名
www.cxk.com
已正确解析到Ingress Controller的外部IP地址。 - 如果在云服务提供商上部署,可能需要配置负载均衡器或网络策略。
2.测试
#进入Pod并修改HTML文件
kubectl get svc,pods -o widekubectl exec -it nginx-app-57dd86f5cc-dncj9 bashecho 'this is web01' > /usr/share/nginx/html/index.htmlkubectl exec -it nginx-app-57dd86f5cc-n6rdz bashecho 'this is web02' > /usr/share/nginx/html/index.html
#获取Service信息
kubectl get svc -n ingress-nginx
#使用kubectl get svc -n ingress-nginx命令获取名为ingress-nginx的Service信息。该Service配置了NodePort类型,监听端口80和443,并且有对应的NodePort(例如,80端口对应的NodePort为30080)
#添加本地域名解析
vim /etc/hosts192.168.241.11 master1
192.168.241.22 node1
192.168.241.23 node2
192.168.241.23 www.cxk.com
#使用curl命令尝试通过外部域名www.cxk.com和NodePort32383访问服务。
curl http://www.cxk.com:30080
六、Ingress HTTP 代理访问虚拟主机
mkdir vhost
cd vhost
1.创建虚拟主机1资源
#在Kubernetes集群中创建一个名为deployment1的Deployment和一个名为svc-1的Servicevim deployment1.yamlapiVersion: apps/v1
kind: Deployment
metadata:name: deployment1
spec:replicas: 2selector:matchLabels:name: nginx1template:metadata:labels:name: nginx1spec:containers:- name: nginx1image: soscscs/myapp:v1imagePullPolicy: IfNotPresentports:- containerPort: 80
#定义了一个Deployment,名为deployment1,它包含两个Nginx容器的副本,这些容器使用标签name: nginx1进行选择;容器使用的镜像是soscscs/myapp:v1,并且监听容器端口80
---
apiVersion: v1
kind: Service
metadata:name: svc-1
spec:ports:- port: 80targetPort: 80protocol: TCPselector:name: nginx1#配置了一个端口80,用于将外部流量转发到选择器name: nginx1匹配的Pod的80端口;Service类型默认为ClusterIP,这意味着它只能在集群内部访问kubectl apply -f deployment1.yaml
#允许在集群内部通过svc-1服务访问名为nginx1的Deployment中的Nginx容器
2.创建虚拟主机2资源
#在Kubernetes集群中创建第二个虚拟主机资源,包括一个名为deployment2的Deployment和一个名为svc-2的Service
vim deployment2.yamlapiVersion: apps/v1
kind: Deployment
metadata:name: deployment2
spec:replicas: 2selector:matchLabels:name: nginx2template:metadata:labels:name: nginx2spec:containers:- name: nginx2image: soscscs/myapp:v2imagePullPolicy: IfNotPresentports:- containerPort: 80
#定义了一个Deployment,名为deployment2,它包含两个Nginx容器的副本,这些容器使用标签name: nginx2进行选择;容器使用的镜像是soscscs/myapp:v2,并且监听容器端口80
---
apiVersion: v1
kind: Service
metadata:name: svc-2
spec:ports:- port: 80targetPort: 80protocol: TCPselector:name: nginx2#该Service配置了一个端口80,用于将外部流量转发到选择器name: nginx2匹配的Pod的80端口;Service类型默认为ClusterIP,这意味着它只能在集群内部访问kubectl apply -f deployment2.yaml
#这些资源的创建将允许在集群内部通过svc-2服务访问名为nginx2的Deployment中的Nginx容器。与之前创建的deployment1和svc-1类似,deployment2和svc-2也是内部服务,需要通过Ingress资源来实现外部访问。
3.创建Ingress资源
vim ingress-nginx.yamlapiVersion: networking.k8s.io/v1
kind: Ingress
metadata:name: ingress1
spec:rules:- host: www1.cxk.comhttp:paths:- path: /pathType: Prefixbackend:service: name: svc-1port:number: 80
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:name: ingress2
spec:rules:- host: www2.cxk.comhttp:paths:- path: /pathType: Prefixbackend:service: name: svc-2port:number: 80#在该文件中定义了两个Ingress资源,ingress1和ingress2。#ingress1配置了一个规则,当访问www1.cxk.com时,流量将被路由到名为svc-1的服务的端口80。
#ingress2配置了一个规则,当访问www2.cxk.com时,流量将被路由到名为svc-2的服务的端口80。kubectl apply -f ingress-nginx.yaml#这些配置已经在集群中安装并配置了Ingress Controller,例如Nginx Ingress Controller。Ingress Controller将根据这些规则处理进入集群的HTTP流量,并将请求根据主机名转发到相应的后端服务
4.测试访问
kubectl get svc -n ingress-nginx
#使用kubectl get svc -n ingress-nginx命令查看Ingress Controller的Service信息。会看到了ingress-nginx服务,它是一个NodePort类型的服务,没有外部IP地址,但有一个内部的ClusterIP,并且配置了两个端口:80和443,分别映射到NodePort的30080和30799。vim /etc/hosts192.168.241.11 master1
192.168.241.22 node1
192.168.241.23 node2
192.168.241.23 www.cxk.com www1.cxk.com www2.cxk.comcurl www1.cxk.com:30080curl www2.cxk.com:30080#使用curl命令尝试从集群内部访问两个不同的虚拟主机www1.cxk.com和www2.cxk.com。由于在集群内部执行这些命令,您可以直接使用NodePort(30080)来访问这些服务。
会收到了两个不同的响应,每个响应都显示了相应的应用版本(v1和v2),这表明Ingress规则正确地将请求路
七、Ingress HTTPS代理访问
在Kubernetes集群中配置HTTPS代理访问通常涉及以下步骤:
- 获取或生成SSL/TLS证书和私钥。
- 将证书和私钥文件放置在集群节点可以访问的位置,例如您刚刚创建的https目录。
- 创建Ingress资源的YAML配置文件,指定SSL/TLS证书和私钥的位置,以及需要启用HTTPS的虚拟主机规则。
一旦这些步骤完成,就可以使用kubectl apply
命令应用Ingress配置,从而启用HTTPS代理访问。这将允许外部用户通过安全的HTTPS连接访问您的服务。
mkdir https
cd https
1.创建SSL证书
openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=nginxsvc/O=nginxsvc"#使用openssl req命令创建一个新的自签名SSL证书(tls.crt)和私钥(tls.key)。
#证书的主题(-subj)被设置为/CN=nginxsvc/O=nginxsvc,这通常代表证书的通用名称(Common Name)和组织名称(Organization)。
#证书有效期设置为365天,使用2048位的RSA密钥。
2.创建Secret资源存储
kubectl create secret tls tls-secret --key tls.key --cert tls.crt
#使用kubectl create secret tls命令创建一个新的Kubernetes Secret资源,名为tls-secret;该Secret资源包含您之前创建的tls.key(私钥)和tls.crt(证书)文件。kubectl get secret
#使用kubectl get secret命令查看当前命名空间(默认为default)中的Secret资源列表;可以看到了名为tls-secret的Secret资源,它包含TLS类型的数据。kubectl describe secret tls-secret
#使用kubectl describe secret tls-secret命令获取tls-secret的详细信息;可以看到了Secret资源的类型为kubernetes.io/tls,并且包含了证书和私钥的数据。
现在,可以在创建Ingress资源时引用这个Secret,以便为Ingress Controller配置HTTPS支持。这将允许Ingress Controller使用这个SSL证书来终止外部HTTPS请求。
3.创建Deployment、Service、Ingress资源
#创建YAML配置文件vim ingress-https.yamlapiVersion: apps/v1
kind: Deployment
metadata:name: nginx-app
spec:replicas: 2selector:matchLabels:name: nginxtemplate:metadata:labels:name: nginxspec:containers:- name: nginximage: nginximagePullPolicy: IfNotPresentports:- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:name: nginx-svc
spec:ports:- port: 80targetPort: 80protocol: TCPselector:name: nginx
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:name: nginx-https
spec:tls:- hosts:- www3.cxk.comsecretName: tls-secretrules:- host: www3.cxk.comhttp:paths:- path: /pathType: Prefixbackend:service: name: nginx-svcport:number: 80#在该文件中定义一个Deployment(nginx-app),它包含两个Nginx容器的副本;定义一个Service(nginx-svc),它将端口80的流量转发到标签为name: nginx的Pod;定义一个Ingress资源(nginx-https),它配置了HTTPS支持,使用之前创建的tls-secret证书和私钥;Ingress资源中定义了一个规则,当访问www3.cxk.com时,流量将被路由到nginx-svc服务的端口80。kubectl apply -f ingress-https.yamlkubectl get svc -n ingress-nginx
#获取Ingress Controller的Service信息。会看到了ingress-nginx服务,它是一个NodePort类型的服务,监听端口80和443,但没有外部IP地址。
#现在,已经为www3.cxk.com配置了HTTPS代理访问。
4.测试访问
192.168.241.23 www3.cxk.com
#将该内容写入文件内
请注意,由于使用的是NodePort而不是外部IP地址,这种访问方式通常只适用于集群内部或者在知道NodePort端口号的情况下。对于外部用户,他们需要通过域名解析到Ingress Controller的外部IP地址,并且Ingress Controller需要配置为使用您创建的TLS证书来处理HTTPS请求。
八、Nginx进行BasicAuth
在Kubernetes集群中配置Nginx Ingress Controller以实现基本的HTTP身份验证(BasicAuth)
mkdir basic-auth
cd basic-auth
1.生成用户密码认证文件,创建Secret资源进行存储
yum -y install httpd
htpasswd -c auth ghd
#认证文件名必须为 auth
kubectl create secret generic basic-auth --from-file=auth
#创建一个新的Kubernetes Secret资源,名为basic-auth,并将之前生成的auth文件作为数据
2.创建Ingress资源
vim ingress-auth.yamlapiVersion: networking.k8s.io/v1
kind: Ingress
metadata:name: ingress-authannotations:#设置认证类型basicnginx.ingress.kubernetes.io/auth-type: basic#设置secret资源名称basic-authnginx.ingress.kubernetes.io/auth-secret: basic-auth#设置认证窗口提示信息nginx.ingress.kubernetes.io/auth-realm: 'Authentication Required - ghd'
spec:rules:- host: auth.cxk.comhttp:paths:- path: /pathType: Prefixbackend:service: name: nginx-svcport:number: 80kubectl apply -f ingress-auth.yaml#完成这些步骤后,当用户尝试访问auth.cxk.com时,他们将被提示输入用户名和密码。只有输入正确的凭据后,才能访问该域名下的服务。
3.访问测试
kubectl get svc -n ingress-nginx
#获取Ingress Controller的Service信息,可以看到了ingress-nginx服务,它是一个NodePort类型的服务,监听端口80和443,没有外部IP地址echo '192.168.241.23 auth.cxk.com' >> /etc/hosts
#修改本地hosts文件浏览器访问:http://auth.cxk.com:30080
九、Nginx重写
在Kubernetes集群中配置Nginx Ingress Controller以实现URL重写。
mkdir rewrite
cd rewrite
1.编写配置文件
vim ingress-rewrite.yamlapiVersion: networking.k8s.io/v1
kind: Ingress
metadata:name: nginx-rewriteannotations:nginx.ingress.kubernetes.io/rewrite-target: http://www1.cxk.com:30080
spec:rules:- host: re.cxk.comhttp:paths:- path: /pathType: Prefixbackend:#由于re.cxk.com只是用于跳转不需要真实站点存在,因此svc资源名称可随意定义service: name: nginx-svcport:number: 80kubectl apply -f ingress-rewrite.yaml
2.访问测试
kubectl get svc -n ingress-nginx
#获取Ingress Controller的Service信息,查看Ingress Controller的Service信息。可以看到了ingress-nginx服务,它是一个NodePort类型的服务,监听端口80和443,没有外部IP地址#写入域名解析
192.168.241.23 re.gzb.com#浏览器访问:http://re.cxk.com:30080
十、总结
1.Ingress数据流向
- DaemonSet + Hostwork + NodeSelector Ingress-Controller
客户端------>Ingress-Controller(Pod和Host共享IP和Port)------>业务应用Service------>业务的应用Pod
- Deployment + NodePort
客户端------>域名访问------>Ingress-Service------>Ingress-Controller(Pod)------>业务应用Service------>业务的应用Pod,域名可以解析成NodePortIP或者负载均衡VIP
2.基于主机名的虚拟主机
rules:
- host: hostname1
......
- host: hostname2
3.HTTPS
要生成TLS证书和私钥文件(在企业需要到域名中的网站下载,有免费正常购买的时候,其次收费的大概在3000/年)
创建Secret资源TLS类型,把证书信息保存到K8S集群内
tls:
- host- 主机列表
......
secretName: tle_secret 资源名称
4.Rewrite重定向
metadataLannotations:nginx.ingress.kubernets.io/rewrite-target#指定重定向的URL路径(http://域名:ingress-controller的端口)
spec:rules:- host: 源主机名backend#这里源主机名仅用于跳转所有不需要实际站点存在,因此后端绑定的Service资源可以随意定义
ingress是k8s集群的请求入口,可以理解为对多个service的再次抽象。
通常说的ingress一般包括ingress资源对象及ingress-controller两部分组成
ingress-controller有多种实现,社区原生的是ingress-nginx,根据具体需求选择
ingress自身的暴露有多种方式,需要根据基础环境及业务类型选择合适的方式 。Ingress Controller 可以理解为控制器,它通过不断的跟 Kubernetes APl交互,实时获取后端Service、Pod的变化,比如新增、删除等,结合Ingress 定义的规则生成配置,然后动态更新上边的Nginx 或者 trafik负载均衡器,并刷新使配置生效,来达到服务自动发现的作用。
Ingress 则是定义规则,通过它定义某个域名的请求过来之后转发到集群中指定的 Service。它可以通过Yaml 文件定义,可以给一个或多个 Service 定义一个或多个 Ingress 规则。