目录
2.1Deployment+LoadBalancer 模式的 Service
2.2DaemonSet+HostNetwork+nodeSelector
2.3Deployment+NodePort模式的 Service
三、采用DaemonSet+HostNetwork+nodeSelector暴露服务
1.指定Nginx-Ingress-Controller运行在Node2节点
四、采用Deployment+NodePort模式的Service
3.创建Deployment、Service、Ingress资源
前言——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-clusterrole
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
rules:
#定义了针对不同资源的访问规则。在这里,包含了多个规则,每个规则指定了对一类资源的访问权限
- apiGroups:
- ""
resources:
- configmaps
- endpoints
- nodes
- pods
- secrets
verbs:
- list
- watch
#对 ConfigMaps、Endpoints、Nodes、Pods 和 Secrets 等资源的 list 和 watch 权限
- apiGroups:
- ""
resources:
- nodes
verbs:
- get
#对 Nodes 资源的 get 权限
- apiGroups:
- ""
resources:
- services
verbs:
- get
- list
- watch
#对 Services 资源的 get、list 和 watch 权限
- apiGroups:
- "extensions"
- "networking.k8s.io" # (0.25版本)增加 networking.k8s.io Ingress 资源的 api
resources:
- ingresses
verbs:
- get
- list
- watch
#对 Ingress 资源的 get、list 和 watch 权限,其中包括了对 "extensions" 和 "networking.k8s.io" API 组的 Ingress 资源的权限
- apiGroups:
- ""
resources:
- events
verbs:
- create
- patch
#对 Events 资源的 create 和 patch 权限
- apiGroups:
- "extensions"
- "networking.k8s.io" # (0.25版本)增加 networking.k8s.io/v1 Ingress 资源的 api
resources:
- ingresses/status
verbs:
- 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-controller
namespace: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
spec:
# 删除Replicas,DaemonSet 不需要 replicas 字段,因为它会确保 Pod 在每个选定的节点上运行一个实例
# replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
template:
metadata:
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
annotations:
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.yaml
kubectl get pod -n ingress-nginx -o wide
kubectl 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.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-app
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx-app-svc
spec:
type: ClusterIP
ports:
- protocol: TCP
port: 80
targetPort: 80
selector:
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.com
http:
paths:
- path: /
backend:
serviceName: nginx-app-svc
servicePort: 80
#方法二:
vim ingress-app.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx-app-ingress
spec:
rules:
- host: www.cxk.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nginx-app-svc
port:
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.com
curl www.cxk.com
7.查看Nginx-Ingress-Controller
kubectl get pod -n ingress-nginx -o wide
kubectl exec -it nginx-ingress-controller-qkrsk -n ingress-nginx bash
more /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.yaml
apiVersion: v1
kind: Namespace
metadata:
name: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
---
kind: ConfigMap
apiVersion: v1
metadata:
name: nginx-configuration
namespace: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
---
kind: ConfigMap
apiVersion: v1
metadata:
name: tcp-services
namespace: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
---
kind: ConfigMap
apiVersion: v1
metadata:
name: udp-services
namespace: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: nginx-ingress-serviceaccount
namespace: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
name: nginx-ingress-clusterrole
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
rules:
- apiGroups:
- ""
resources:
- configmaps
- endpoints
- nodes
- pods
- secrets
verbs:
- list
- watch
- apiGroups:
- ""
resources:
- nodes
verbs:
- get
- apiGroups:
- ""
resources:
- services
verbs:
- get
- list
- watch
- apiGroups:
- ""
resources:
- events
verbs:
- create
- patch
- apiGroups:
- "extensions"
- "networking.k8s.io"
resources:
- ingresses
verbs:
- get
- list
- watch
- apiGroups:
- "extensions"
- "networking.k8s.io"
resources:
- ingresses/status
verbs:
- update
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: Role
metadata:
name: nginx-ingress-role
namespace: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
rules:
- apiGroups:
- ""
resources:
- configmaps
- pods
- secrets
- namespaces
verbs:
- get
- apiGroups:
- ""
resources:
- configmaps
resourceNames:
# 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:
- configmaps
verbs:
- create
- apiGroups:
- ""
resources:
- endpoints
verbs:
- get
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: RoleBinding
metadata:
name: nginx-ingress-role-nisa-binding
namespace: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: nginx-ingress-role
subjects:
- kind: ServiceAccount
name: nginx-ingress-serviceaccount
namespace: ingress-nginx
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
name: nginx-ingress-clusterrole-nisa-binding
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: nginx-ingress-clusterrole
subjects:
- kind: ServiceAccount
name: nginx-ingress-serviceaccount
namespace: ingress-nginx
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-ingress-controller
namespace: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
template:
metadata:
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
annotations:
prometheus.io/port: "10254"
prometheus.io/scrape: "true"
spec:
# wait up to five minutes for the drain of connections
terminationGracePeriodSeconds: 300
serviceAccountName: nginx-ingress-serviceaccount
nodeSelector:
kubernetes.io/os: linux
containers:
- name: nginx-ingress-controller
image: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.30.0
args:
- /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.io
securityContext:
allowPrivilegeEscalation: true
capabilities:
drop:
- ALL
add:
- NET_BIND_SERVICE
# www-data -> 101
runAsUser: 101
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
ports:
- name: http
containerPort: 80
protocol: TCP
- name: https
containerPort: 443
protocol: TCP
livenessProbe:
failureThreshold: 3
httpGet:
path: /healthz
port: 10254
scheme: HTTP
initialDelaySeconds: 10
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 10
readinessProbe:
failureThreshold: 3
httpGet:
path: /healthz
port: 10254
scheme: HTTP
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 10
lifecycle:
preStop:
exec:
command:
- /wait-shutdown
---
apiVersion: v1
kind: LimitRange
metadata:
name: ingress-nginx
namespace: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
spec:
limits:
- min:
memory: 90Mi
cpu: 100m
type: Container
vim service-nodeport.yaml
apiVersion: v1
kind: Service
metadata:
name: ingress-nginx
namespace: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
spec:
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
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: 2
selector:
matchLabels:
name: nginx
template:
metadata:
labels:
name: nginx
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
#名为nginx-svc,类型为ClusterIP,端口80,选择器为name=nginx
metadata:
name: nginx-svc
spec:
ports:
- port: 80
targetPort: 80
protocol: TCP
selector:
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.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nginx-svc
port:
number: 80
kubectl apply -f ingress-nginx.yaml
kubectl get svc,pods -o wide
为了使外部流量能够访问到这个服务,需要确保:
- Ingress Controller已正确安装并运行。
- 域名
www.cxk.com
已正确解析到Ingress Controller的外部IP地址。 - 如果在云服务提供商上部署,可能需要配置负载均衡器或网络策略。
2.测试
#进入Pod并修改HTML文件
kubectl get svc,pods -o wide
kubectl exec -it nginx-app-57dd86f5cc-dncj9 bash
echo 'this is web01' > /usr/share/nginx/html/index.html
kubectl exec -it nginx-app-57dd86f5cc-n6rdz bash
echo '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/hosts
192.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的Service
vim deployment1.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deployment1
spec:
replicas: 2
selector:
matchLabels:
name: nginx1
template:
metadata:
labels:
name: nginx1
spec:
containers:
- name: nginx1
image: soscscs/myapp:v1
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
#定义了一个Deployment,名为deployment1,它包含两个Nginx容器的副本,这些容器使用标签name: nginx1进行选择;容器使用的镜像是soscscs/myapp:v1,并且监听容器端口80
---
apiVersion: v1
kind: Service
metadata:
name: svc-1
spec:
ports:
- port: 80
targetPort: 80
protocol: TCP
selector:
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.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deployment2
spec:
replicas: 2
selector:
matchLabels:
name: nginx2
template:
metadata:
labels:
name: nginx2
spec:
containers:
- name: nginx2
image: soscscs/myapp:v2
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
#定义了一个Deployment,名为deployment2,它包含两个Nginx容器的副本,这些容器使用标签name: nginx2进行选择;容器使用的镜像是soscscs/myapp:v2,并且监听容器端口80
---
apiVersion: v1
kind: Service
metadata:
name: svc-2
spec:
ports:
- port: 80
targetPort: 80
protocol: TCP
selector:
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.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress1
spec:
rules:
- host: www1.cxk.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: svc-1
port:
number: 80
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress2
spec:
rules:
- host: www2.cxk.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: svc-2
port:
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/hosts
192.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.com
curl www1.cxk.com:30080
curl 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.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-app
spec:
replicas: 2
selector:
matchLabels:
name: nginx
template:
metadata:
labels:
name: nginx
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx-svc
spec:
ports:
- port: 80
targetPort: 80
protocol: TCP
selector:
name: nginx
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx-https
spec:
tls:
- hosts:
- www3.cxk.com
secretName: tls-secret
rules:
- host: www3.cxk.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nginx-svc
port:
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.yaml
kubectl 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.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-auth
annotations:
#设置认证类型basic
nginx.ingress.kubernetes.io/auth-type: basic
#设置secret资源名称basic-auth
nginx.ingress.kubernetes.io/auth-secret: basic-auth
#设置认证窗口提示信息
nginx.ingress.kubernetes.io/auth-realm: 'Authentication Required - ghd'
spec:
rules:
- host: auth.cxk.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nginx-svc
port:
number: 80
kubectl 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.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx-rewrite
annotations:
nginx.ingress.kubernetes.io/rewrite-target: http://www1.cxk.com:30080
spec:
rules:
- host: re.cxk.com
http:
paths:
- path: /
pathType: Prefix
backend:
#由于re.cxk.com只是用于跳转不需要真实站点存在,因此svc资源名称可随意定义
service:
name: nginx-svc
port:
number: 80
kubectl 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重定向
metadataL
annotations:
nginx.ingress.kubernets.io/rewrite-target
#指定重定向的URL路径(http://域名:ingress-controller的端口)
spec:
rules:
- host: 源主机名
backend
#这里源主机名仅用于跳转所有不需要实际站点存在,因此后端绑定的Service资源可以随意定义
#metadata.annotations 配置说明
nginx.ingress.kubernetes.io/rewrite-target: <字符串>
#必须重定向流量的目标URI
nginx.ingress.kubernetes.io/ssl-redirect: <布尔值>
#指示位置部分是否仅可访问SSL(当Ingress包含证书时,默认为true)
nginx.ingress.kubernetes.io/force-ssl-redirect: <布尔值>
#即使Ingress未启用TLS,也强制重定向到HTTPS
nginx.ingress.kubernetes.io/app-root: <字符串>
#定义Controller必须重定向的应用程序根,如果它在'/'上下文中
nginx.ingress.kubernetes.io/use-regex: <布尔值>
#指示Ingress上定义的路径是否使用正则表达式
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 规则。