第六章 Kubernetes网络
1、Service 控制器
在 Kubernetes (K8S) 中,Service 控制器 是一个关键组件,负责管理 Kubernetes 服务的生命周期和实现其功能。Service 控制器确保服务能够正确地将流量路由到后端 Pod,并处理服务的负载均衡和 DNS 解析。
1.1 Service存在的意义
Service 引入主要是解决Pod的动态变化,提供统一访问入口:
- 定义一组Pod的访问策略(负载均衡)
- Pod的生存周期是短暂的动态的,在重建或增加的情况下,Service为了防止Pod失联,动态感知Pod的变化获取最新的IP,找到提供同一个服务的Pod(服务发现)
Service 控制器的主要职责包括:
- 负载均衡: 将流量分发到后端 Pod
- DNS 解析: 提供 DNS 名称解析,使得服务可以通过名称被其他服务或应用访问
- IP 管理: 确保 Service 拥有一个稳定的 IP 地址
- 健康检查: 监控后端 Pod 的健康状态,确保流量只被发送到健康的 Pod
1.2 Pod与Service的关系
Service 通过标签选择器(Label Selector)来选择一组 Pod。标签选择器定义了一组键值对,Service 会根据这些键值对来匹配具有相应标签的 Pod。
- Service 通过 标签 关联一组Pod(selector)
- Service 为一组Pod提供负载均衡能力
1.3 Service定义与创建
前提:之前创建Service是基于Deployment控制器,如:kubectl expose deployment web --port=80 --target-port=80 --type=NodePort
- Kubectl expose 基于已有的Deployment创建service
- kubectl create service 可以直接创建service,不需要基于Deployment
1)创建service:
- 命令:kubectl create service --tcp=port:port
kubectl create service clusterip web --tcp=80:80
2)生成YAML:
kubectl create service clusterip web --tcp=80:80 --dry-run=client -o yaml > clusterip-web.yaml
3)定义 service:
apiVersion: v1
kind: Service
metadata:
name: web
spec:
type: ClusterIP # 服务类型
ports:
- name: 80-80
port: 80 # Service端口,统一的内部访问端口
protocol: TCP # 协议
targetPort: 80 # 容器端口(应用程序监听端口)
selector:
app: web # 指定关联Pod的标签
4)查看 service:
kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
web ClusterIP 10.110.27.138 <none> 80/TCP 6s
测试:Cluster IP类型 Service 内部集群访问
# 由于是直接创建的Service,没有相关的Pod进行关联
[root@k8s-master-1-71 ~]# kubectl get ep
NAME ENDPOINTS AGE
web <none> 10s //相关endpoints为空
# 需创建标签相同的Pod与Service进行关联
[root@k8s-master-1-71 ~]# kubectl run web --image=nginx
[root@k8s-master-1-71 ~]# kubectl label pods web app=web --overwrite //定义标签(--overwrite覆盖)
[root@k8s-master-1-71 ~]# kubectl get pods --show-labels
NAME READY STATUS RESTARTS AGE LABELS
web 1/1 Running 0 13m app=web,run=web
[root@k8s-master-1-71 ~]# kubectl get ep
NAME ENDPOINTS AGE
web 10.244.114.31:80 5m59s //相关endpoints已关联Pod
# 将web作为后端,再创建一个bs作为前端进行测试
[root@k8s-master-1-71 ~]# kubectl run bs --image=busybox -- sleep 24h
[root@k8s-master-1-71 ~]# kubectl exec -it bs -- sh
/ # wget 10.110.27.138:80 //访问并下载web svc的默认首页
/ # cat index.html
<title>Welcome to nginx!</title>
注意:由于镜像是周期性方式存在的,没有相关执行进程将会一直不断拉取镜像重启,而在创建busybox类似镜像时,需要通过加 sleep进行Hold住。
多端口Service定义:
对于某些服务,需要公开多个端口, Service也需要配置多个端口定义,通过端口名称区分。例如https服务:
apiVersion: v1
kind: Service
metadata:
name: web
spec:
type: ClusterIP
ports:
- name: http
port: 80
protocol: TCP
targetPort: 80 //需转发80端口
- name: https
port: 443
protocol: TCP
targetPort: 443 //需转发443端口
selector:
app: web
示例:
# 创建多镜像Pod,注意标签
[root@k8s-master-1-71 ~]# kubectl apply -f pod-mutil.yaml
apiVersion: v1
kind: Pod
metadata:
labels:
run: pod-mutil
name: pod-mutil
spec:
containers:
- image: nginx
name: web
- image: tomcat:6
name: api
[root@k8s-master-1-71 ~]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod-mutil 2/2 Running 0 14m 10.244.114.33 k8s-node2-1-73 <none> <none>
# 创建多端口Service,注意标签
[root@k8s-master-1-71 ~]# kubectl apply -f clusterip-mutil.yaml
apiVersion: v1
kind: Service
metadata:
name: clusterip-mutil
spec:
ports:
- name: 80-80
port: 80
protocol: TCP
targetPort: 80
- name: 88-8080
port: 88
protocol: TCP
targetPort: 8080
selector:
run: pod-mutil //指定Pod的Labels标签
type: ClusterIP
[root@k8s-master-1-71 ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
clusterip-mutil ClusterIP 10.111.231.50 <none> 80/TCP,88/TCP 4m34s
[root@k8s-master-1-71 ~]# kubectl get ep
NAME ENDPOINTS AGE
clusterip-mutil 10.244.114.33:8080,10.244.114.33:80 23m
# 通过bs作为前端进行测试
[root@k8s-master-1-71 ~]# kubectl exec -it bs -- sh
/ # wget 10.111.231.50:80 -O web-index.html
/ # cat web-index.html
<title>Welcome to nginx!</title>
/ # wget 10.111.231.50:88 -O tomcat-index.html
/ # cat tomcat-index.html
<a href="http://tomcat.apache.org/">
1.4 Service 三种类型
类型 |
描述 |
备注 |
Clusterlp |
集群内部使用 (Pod) |
仅集群内部访问,适用于内部服务发现和通信 |
NodePort |
对外暴露应用 (浏览器) |
通过节点端口从集群外部访问,适用于简单的外部访问需求 |
LoadBalancer |
对外暴露应用,适用公有云 |
通过云提供商的负载均衡器从集群外部访问,适用于生产环境和高可用性需求 |
注意:选择哪种 Service 类型取决于您的具体需求和部署环境。
1.4.1 ClusterIP
ClusterIP 是 Kubernetes 中默认的 Service 类型。它为 Service 分配一个仅在集群内部可访问的虚拟 IP 地址。这意味着只有集群内部的 Pod 和组件可以通过这个 IP 地址访问 Service。
特点:
- 仅集群内部访问:Service 只能在集群内部访问,不会暴露在集群外部。
- 负载均衡:Kubernetes 会自动在后端 Pod 之间进行负载均衡。
- 简单的内部通信:适用于集群内部的服务发现和通信。
使用场景:
- 当您只需要在集群内部访问服务时。
- 用于内部微服务之间的通信。
默认创建,会分配一个稳定的IP地址,即VIP(VirtualIP),只能在k8s集群内部进行访问,用于内部维护使用。示例配置:
apiVersion: v1
kind: Service
metadata:
name: my-clusterip-service
spec:
selector:
app: my-app
ports:
- protocol: TCP
port: 80
targetPort: 8080
type: ClusterIP
1.4.2 NodePort
NodePort 通过在每个节点上打开一个特定的端口(称为 NodePort),将外部流量转发到 Service。NodePort 允许外部流量通过节点的 IP 地址和 NodePort 访问 Service。
特点:
- 外部访问:通过节点的 IP 地址和 NodePort 可以从集群外部访问 Service。
- 固定端口:NodePort 的范围通常是 30000-32767,但可以通过配置修改。
- 简单配置:适用于需要简单外部访问的场景。
- 访问地址:<任意NodeIP>:<NodePort>
- 默认端口范围:30000 - 32767
使用场景:
- 当您需要从集群外部访问服务,但没有负载均衡器时。
- 适用于简单的开发和测试环境。
在每个节点上启用一个端口来暴露服务,可以在集群 外部访问。也会分配一个稳定内部集群IP地址。示例配置:
apiVersion: v1
kind: Service
metadata:
name: my-nodeport-service
spec:
selector:
app: my-app
ports:
- protocol: TCP
port: 80
targetPort: 8080
nodePort: 30007
type: NodePort
结论:NodePort可字面理解为节点Port,用于外部访问集群内部使用。
负载均衡器:
NodePort 会在每台Node上监听端口接收用户流量,在实际情 况下,对用户暴露的只会有一个IP和端口,那这么多台Node该使 用哪台让用户访问呢? 这时就需要前面加一个公网负载均衡器为项目提供统一访问入口了。
1.4.3 LoadBalancer
LoadBalancer 类型的 Service 会自动在支持的云提供商(如 AWS、GCP、Azure 等)上创建一个外部负载均衡器。负载均衡器会将外部流量转发到 Service 的 Pod。
特点:
- 外部访问:通过负载均衡器的外部 IP 地址可以访问 Service。
- 自动配置:在支持的云提供商上自动创建和配置负载均衡器。
- 高可用性:通常提供高可用性和负载均衡功能。
使用场景:
- 当您需要从集群外部访问服务,并且希望利用云提供商的负载均衡功能时。
- 适用于生产环境,需要高可用性和负载均衡的场景。
与NodePort类似,在每个节点上启用一个端口来暴 露服务。除此之外,Kubernetes会请求底层云平台(例如阿里云、腾 讯云、AWS等)上的负载均衡器,将每个Node ([NodeIP]:[NodePort])作为后端添加进去。示例配置:
apiVersion: v1
kind: Service
metadata:
name: my-loadbalancer-service
spec:
selector:
app: my-app
ports:
- protocol: TCP
port: 80
targetPort: 8080
type: LoadBalancer
1.5 Service 代理模式
Kubernetes 使用多种代理模式来实现 Service 的负载均衡和流量路由。以下是 Kubernetes 中常见的几种 Service 代理模式:
Service的底层实现主要有iptables和ipvs二种网络模式,决定了如何转发流量;而负责维护转发流量工作的组件则是Kube-proxy。
1.5.1 iptables
iptables 模式 是 Kubernetes 最早使用的 Service 代理模式。它通过修改节点上的 iptables 规则来实现负载均衡和流量路由。
工作原理:
- 当创建一个 Service 时,Kubernetes 会为该 Service 分配一个 ClusterIP。
- Kubernetes 会在每个节点上配置 iptables 规则,将流量从 Service 的 ClusterIP 和端口转发到后端 Pod 的 IP 和端口。
- 当客户端向 Service 的 ClusterIP 发送请求时,iptables 规则会根据负载均衡算法(如轮询)将请求转发到一个后端 Pod。
特点:
- 性能较好:iptables 规则在内核空间中处理,性能较高。
- 配置复杂:需要维护大量的 iptables 规则,配置相对复杂。
- 不支持某些高级功能:不支持基于 HTTP 的路由和负载均衡。
使用场景:
- 适用于需要高性能的场景。
- 适用于不需要基于 HTTP 的路由和负载均衡的场景。
# Pod和svc准备
[root@k8s-node1-1-72 ~]# kubectl create deployment web --image=nginx --replicas=3
[root@k8s-node1-1-72 ~]# kubectl expose deployment web --port=80 --target-port=80 --type=NodePort
[root@k8s-node1-1-72 ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
web NodePort 10.101.124.44 <none> 80:31895/TCP 82s
# 第一步 流程处理入口
[root@k8s-node1-1-72 ~]# iptables-save | grep web
...
-A KUBE-NODEPORTS -p tcp -m comment --comment "default/web" -m tcp --dport 31895 -j KUBE-EXT-LOLE4ISW44XBNF3G
# 解释:处理来自TCP协议,且访问目标端口为 31895,都转发到 KUBE-EXT-LOLE4ISW44XBNF3G 链
-A KUBE-SERVICES -d 10.101.124.44/32 -p tcp -m comment --comment "default/web cluster IP" -m tcp --dport 80 -j KUBE-SVC-LOLE4ISW44XBNF3G
# 解释:与上面意思相同,处理来自NodePort:Port的数据,都转发到 KUBE-SVC-LOLE4ISW44XBNF3G 链
# 第二步 负载均衡
...
-A KUBE-SVC-LOLE4ISW44XBNF3G -m comment --comment "default/web -> 10.244.114.34:80" -m statistic --mode random --probability 0.33333333349 -j KUBE-SEP-GCCHNO42UKXGR227
-A KUBE-SVC-LOLE4ISW44XBNF3G -m comment --comment "default/web -> 10.244.114.35:80" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-7ZMRYMMRUHATZVYE
-A KUBE-SVC-LOLE4ISW44XBNF3G -m comment --comment "default/web -> 10.244.117.26:80" -j KUBE-SEP-4ICTCH44VJXESGBS
# 解释:--mode random为概率计算,按照权重概率进行负载均衡转发
# 第三步 具体的转发
[root@k8s-node1-1-72 ~]# iptables-save | grep KUBE-SEP-GCCHNO42UKXGR227
-A KUBE-SEP-GCCHNO42UKXGR227 -p tcp -m comment --comment "default/web" -m tcp -j DNAT --to-destination 10.244.114.34:80
[root@k8s-node1-1-72 ~]# iptables-save | grep KUBE-SEP-7ZMRYMMRUHATZVYE
-A KUBE-SEP-7ZMRYMMRUHATZVYE -p tcp -m comment --comment "default/web" -m tcp -j DNAT --to-destination 10.244.114.35:80
[root@k8s-node1-1-72 ~]# iptables-save | grep KUBE-SEP-4ICTCH44VJXESGBS
-A KUBE-SEP-4ICTCH44VJXESGBS -p tcp -m comment --comment "default/web" -m tcp -j DNAT --to-destination 10.244.117.26:80
# 解释:每条从负载均衡转发的规则,最终都能对应转发到Service后端的Pod容器中处理
[root@k8s-node1-1-72 ~]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
web-5cc97bc7d5-8v8gc 1/1 Running 0 16m 10.244.114.34 k8s-node2-1-73 <none> <none>
web-5cc97bc7d5-pflrp 1/1 Running 0 16m 10.244.117.26 k8s-node1-1-72 <none> <none>
web-5cc97bc7d5-t5ftc 1/1 Running 0 16m 10.244.114.35 k8s-node2-1-73 <none> <none>
1.5.2 ipvs
IPVS(IP Virtual Server)模式 是 Kubernetes 中另一种 Service 代理模式。它使用 Linux 内核的 IPVS 模块来实现负载均衡和流量路由。
工作原理:
- 当创建一个 Service 时,Kubernetes 会为该 Service 分配一个 ClusterIP。
- Kubernetes 会在每个节点上配置 IPVS 规则,将流量从 Service 的 ClusterIP 和端口转发到后端 Pod 的 IP 和端口。
- IPVS 提供多种负载均衡算法(如轮询、最少连接、源哈希等),可以根据需要选择合适的算法。
特点:
- 性能更优:IPVS 在内核空间中处理流量,性能优于 iptables。
- 支持多种算法:提供多种负载均衡算法,可以根据需求选择。
- 配置相对简单:相对于 iptables,IPVS 的配置相对简单。
使用场景:
- 适用于需要高性能和多种负载均衡算法的场景。
- 适用于大型集群和高流量场景。
IPVS 支持多种负载均衡算法,以下是一些常见的算法:
- 轮询(Round Robin, RR):按顺序将请求分发到后端 Pod。
- 最少连接(Least Connections, LC):将请求分发到当前连接数最少的 Pod。
- 源哈希(Source Hashing, SH):根据客户端 IP 地址的哈希值将请求分发到后端 Pod,保证同一客户端的请求总是被发送到同一个 Pod。
- 本地最少连接(Local Least Connections, LCC):将请求分发到本地节点上连接数最少的 Pod。
- 源掩码哈希(Source Hashing with Mask, SMC):根据客户端 IP 地址的掩码哈希值将请求分发到后端 Pod。
两种不同的底层网络代理模式,都是由Kube-proxy进行维护,所以如果需要修改代理模式,则需修改Kube-proxy的配置文件,而Kube-proxy的配置文件由 configmap 进行存储。
- kube-proxy配置文件以configmap方式存储
- 如果让所有节点生效,需要重建所有节点 kube-proxy pod
查看configmap命令:kubectl get configmap -n kube-system
[root@k8s-master-1-71 ~]# kubectl get configmap -n kube-system | grep kube-proxy
NAME DATA AGE
kube-proxy 2 16d
[root@k8s-master-1-71 ~]# kubectl get pods -n kube-system -o wide | grep kube-proxy
kube-proxy-2np4n 1/1 Running 2 (31h ago) 16d 192.168.1.72 k8s-node1-1-72 <none> <none>
kube-proxy-ch5qf 1/1 Running 2 (31h ago) 16d 192.168.1.73 k8s-node2-1-73 <none> <none>
kube-proxy-sw9qt 1/1 Running 2 (31h ago) 16d 192.168.1.71 k8s-master-1-71 <none> <none>
# 注意:kube-proxy是用dameon-set控制器进行创建,3个Pod即有3个kube-proxy进行维护
— edit方式修改ipvs模式:
- 命令:kubectl edit configmap kube-proxy -n kube-system
# kubectl edit configmap kube-proxy -n kube-system
...
mode: "ipvs" //不填写默认为iptables
...
测试:需要通过删除Pod进行重建才能生效,尝试删除Node2节点的Pod
[root@k8s-node1-1-71 ~]# kubectl delete pod kube-proxy-2np4n -n kube-system
[root@k8s-node1-1-72 ~]# ipvsadm -L -n
TCP 192.168.1.72:31895 rr
-> 10.244.114.34:80 Masq 1 0 0
-> 10.244.114.35:80 Masq 1 0 0
-> 10.244.117.26:80 Masq 1 0 0
— 二进制方式修改ipvs模式:
# vi kube-proxy-config.yml
mode: ipvs
ipvs:
scheduler: "rr“
# systemctl restart kube-proxy
注:配置文件路径根据实际安装目录为准
总结:
- 流程包流程:客户端 -> NodePort/ClusterIP(iptables/Ipvs负载均衡规则) -> 分布在各节点Pod
- 查看负载均衡规则:
- iptables模式 iptables-save | grep
- ipvs模式 ipvsadm -L -n
- Iptables VS IPVS
- Iptables: 灵活,功能强大 ;规则遍历匹配和更新,呈线性时延
- IPVS: 工作在内核态,有更好的性能; 调度算法丰富:rr,wrr,lc,wlc,ip hash..
1.6 Service DNS服务
CoreDNS:是 Kubernetes 集群中默认使用的 DNS 服务,负责提供域名解析服务。它是一个灵活、可扩展且高性能的 DNS 服务器,专为 Kubernetes 环境设计,主要作用包括:
- 域名解析:为集群内部的 Pod 提供 DNS 解析服务,使得 Pod 可以通过服务名称(Service Name)访问其他服务。
- 服务发现:通过 DNS 解析,实现服务之间的自动发现和通信。
- 配置管理:提供灵活的配置选项,可以根据需要进行自定义。
工作原理:
- CoreDNS 监听 DNS 请求,通常是 UDP 和 TCP 端口 53。
- 根据配置的插件顺序处理请求。常见的插件包括 forward、kubernetes、cache 等。
- 根据处理结果生成 DNS 响应并返回给客户端。
CoreDNS 使用插件来处理不同的 DNS 请求。以下是一些核心插件:
- forward:将 DNS 请求转发到其他 DNS 服务器(如外部 DNS 服务器)。
- kubernetes:提供 Kubernetes 服务和 Pod 的 DNS 解析。
- cache:缓存 DNS 响应以提高性能。
- errors:处理和记录 DNS 错误。
- log:记录 DNS 请求和响应日志。
- health:提供健康检查端点。
- ready:提供就绪检查端点。
1.6.1 CoreDNS 的配置
CoreDNS 的配置文件通常位于 /etc/coredns/Corefile。以下是一个典型的 Corefile 示例:
.:53 {
errors
health
ready
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
upstream
fallthrough in-addr.arpa ip6.arpa
}
prometheus :9153
forward . /etc/resolv.conf
cache 30
loop
reload
loadbalance
}
配置说明:
.:53:监听所有接口的 53 端口。
errors:处理和记录 DNS 错误。
health:提供健康检查端点。
ready:提供就绪检查端点。
kubernetes:提供 Kubernetes 服务和 Pod 的 DNS 解析。
cluster.local:集群的默认域名。
in-addr.arpa 和 ip6.arpa:用于反向 DNS 解析。
pods insecure:允许不安全的 Pod 访问。
upstream:使用上游 DNS 服务器。
fallthrough:如果当前插件无法解析请求,则传递给下一个插件。
prometheus:提供 Prometheus 监控端点。
forward:将无法解析的请求转发到 /etc/resolv.conf 中配置的 DNS 服务器。
cache:缓存 DNS 响应 30 秒。
loop:防止 DNS 查询循环。
reload:允许动态重新加载配置。
loadbalance:在多个后端之间进行负载均衡。
1.6.2 CoreDNS 的部署和管理
CoreDNS 通常作为 Kubernetes 集群的一部分自动部署。以下是一些常见的管理任务:
- 查看 CoreDNS Pod:kubectl get pods -n kube-system -l k8s-app=kube-dns
- 查看 CoreDNS 配置:kubectl get configmap coredns -n kube-system -o yaml
- 更新 CoreDNS 配置:kubectl edit configmap coredns -n kube-system
- 查看 CoreDNS 日志:kubectl logs -n kube-system -l k8s-app=kube-dns
CoreDNS服务监视Kubernetes API,为每一个Service创建DNS记录用于域名解析。
ClusterIP A记录格式:<service-name>.<namespace-name>.svc.cluster.local
例如my-svc.my-namespace.svc.cluster.local,在解析过程中填写完整DNS A记录格式可加快解析速度
测试:
[root@k8s-master-1-71 ~]# kubectl run dns-client --image=busybox -- sleep 24h
[root@k8s-master-1-71 ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 16d
web NodePort 10.101.124.44 <none> 80:31895/TCP 52m
[root@k8s-master-1-71 ~]# kubectl exec -it dns-client -- sh
/ # nslookup kubernetes //解析ClusterIP Service服务
Server: 10.96.0.10
Address: 10.96.0.10:53
Name: kubernetes.default.svc.cluster.local
Address: 10.96.0.1
/ # nslookup web //解析默认的NodePort Service服务
Server: 10.96.0.10
Address: 10.96.0.10:53
Name: web.default.svc.cluster.local
Address: 10.101.124.44
注意:不同的命名空间需要指定命名空间才可以解析
[root@k8s-master-1-71 ~]# kubectl get svc -n kube-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP,9153/TCP 16d
metrics-server ClusterIP 10.110.104.55 <none> 443/TCP 27h
/ # nslookup kube-dns.kube-system.svc.cluster.local
/ # nslookup metrics-server.kube-system.svc.cluster.local
2、Ingress 对象(对外暴露应用)
2.1 Ingress 介绍
Ingress 是 Kubernetes 中用于管理外部对集群内服务的访问的一种 API 对象。它提供了一种方式来将集群内部的服务暴露给外部网络,通常通过 HTTP 和 HTTPS 协议。Ingress 可以简化服务的暴露和负载均衡配置。
Ingress为弥补NodePort不足而生,NodePort 存在的不足:
- 暴露的一个端口只能一个服务使用,端口需提前规划(增加维护成本)
- 只能支持4层负载均衡(工作机制限制:iptables、ipvs)
了解OSI七层:
- 四层:基于IP和端口转发、例如LVS、Nginx、Haproxy
- 七层:基于应用层协议(HTTP)转发,例如Nginx、Haproxy
主要作用:
- 外部访问:允许外部用户通过域名访问集群内的服务。
- 负载均衡:将外部请求分发到多个后端服务实例。
- 路由规则:根据 URL 路径或主机名将请求路由到不同的服务。
- SSL/TLS 终止:处理 SSL/TLS 加密,确保数据传输的安全性。
- 日志记录和监控:提供日志记录和监控功能,便于排查问题和优化性能。
工作原理:
Ingress 通过定义一组规则来管理外部对集群内服务的访问。以下是 Ingress 的基本工作流程:
- 定义 Ingress 资源:用户定义 Ingress 资源,指定路由规则和后端服务。
- Ingress Controller:Ingress Controller 监听 Kubernetes API,根据 Ingress 资源的定义动态配置反向代理服务器(如 NGINX、Traefik 等)。
- 反向代理服务器:反向代理服务器根据 Ingress 规则将外部请求转发到相应的后端服务。
典型的 Ingress 资源示例:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example-ingress
namespace: default
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: example.com
http:
paths:
- path: /app1
pathType: Prefix
backend:
service:
name: app1-service
port:
number: 80
- path: /app2
pathType: Prefix
backend:
service:
name: app2-service
port:
number: 80
tls:
- hosts:
- example.com
secretName: example-tls-secret
2.2 Ingress Controller
Ingress Controller 是一个反向代理服务器,负责实现 Ingress 资源定义的规则。常见的 Ingress Controller 包括:
- NGINX Ingress Controller:使用 NGINX 作为反向代理服务器。
- Traefik:使用 Traefik 作为反向代理服务器。
- HAProxy Ingress:使用 HAProxy 作为反向代理服务器。
- AWS ALB Ingress Controller:使用 AWS Application Load Balancer (ALB)。
- GCE Ingress Controller:使用 Google Cloud Load Balancer。
- Contour:使用 Envoy 作为反向代理服务器。
Ingress 与 Ingress Controller 的关系:
- Ingress:K8s中的一个抽象资源,给管理员 提供一个暴露应用的入口定义方法
- Ingress Controller:负责流量路由,根据 Ingress生成具体的路由规则,并对Pod负载 均衡(类似ipvs、iptables)
2.3 Ingress Controller 部署
Ingress Controller :Ingress管理的负载均衡器,为集群提供全局的负载均衡能力。
使用流程:
- 部署Ingress Controller
- 创建Ingress规则
Ingress Controller有很多实现,我们这里采用官方维护的Nginx控制器。
- 其他控制器:Ingress Controllers | Kubernetes
- Git项目地址:GitHub - kubernetes/ingress-nginx: Ingress NGINX Controller for Kubernetes
进入Get started: Installation Guide - Ingress-Nginx Controller
找到 Bare metal clusters 云原生环境,下载官方YAML:
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.6.4/deploy/static/provider/baremetal/deploy.yaml
修改YAML里镜像地址为国内的: lizhenliang/ingress-nginx-controller:v1.1.0
补充:Ingress Controller是以Deployment Pod方式在集群节点进行部署的,如需要外部进行访问,则需要利用NodePort Service进行暴露,所以在部署Ingress Controller时会默认创建Pod和Svc。(Svc默认监听80、443)
- 查看Ingress Controller的Pod命令:kubectl get pods -n ingress-nginx
- 查看Ingress Controller的Svc命令:kubectl get svc -n ingress-nginx
[root@k8s-master-1-71 ~]# kubectl apply -f ingress-controller-1.1.yaml
[root@k8s-master-1-71 ~]# kubectl get pods -n ingress-nginx //会启动3个容器,其中admission为临时容器,状态为completed(类似初始化容器)
NAME READY STATUS RESTARTS AGE
ingress-nginx-admission-create-jp2xl 0/1 Completed 0 71s
ingress-nginx-admission-patch-ctjj5 0/1 Completed 0 71s
ingress-nginx-controller-c4db458f5-qp5ff 1/1 Running 0 71s
[root@k8s-master-1-71 ~]# kubectl get svc -n ingress-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx-controller NodePort 10.108.162.206 <none> 80:30513/TCP,443:32099/TCP 3h8m
ingress-nginx-controller-admission ClusterIP 10.103.217.175 <none> 443/TCP 3h8m
2.4 Ingress 的规则配置
了解:客户端可通过基于域名、IP、端口的方式,访问负载均衡进行分流,比如:Nginx配置文件中的vhost虚拟主机,生成环境大部分是基于域名(创建Ingress的逻辑就是类似vhost)
【rule】中的host,对应【vhost】中的 server_name 域名;
【rule】中的path,对应【vhost】中的 location 访问首页路径;
【rule】中的service.name,对应【vhost】中的 proxy_pass 后端主机(upstream);
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-nginx
spec:
ingressClassName: nginx //指定Ingress控制器(kubectl get ingressclass)
rules:
- host: web.aliangedu.cn //host域名
http:
paths:
- path: / //访问首页路径
pathType: Prefix
backend:
service:
name: web //需要关联的svc(一组Pod)
port:
number: 80
备注:ingressClassName指定Ingress控制器是为了防止一个集群中有2套Ingress Controller
查看ingress Controller标识(用来标识控制器):kubectl get ingressclass
[root@k8s-master-1-71 ~]# kubectl get ingressclass
NAME CONTROLLER PARAMETERS AGE
nginx k8s.io/ingress-nginx <none> 26m
2.5 Ingress Controller 的两种访问方式
2.5.1 Service NodePort暴露Ingress Controller
访问流程:用户(通过域名:端口)— 所有宿主机 SVC NodePort — ingress controller pod(Nginx,基于域名)— 分布在各个节点的Pod
测试:
# Pod和Svc准备
kubectl create deployment nginx-web --image=nginx --replicas=3
kubectl create deployment httpd-web --image=httpd --replicas=3
kubectl expose deployment nginx-web --port=80 --target-port=80
kubectl expose deployment httpd-web --port=80 --target-port=80
# 注意:因为需要进行测试,未指定NodePort,可通过Cluster IP进行访问
[root@k8s-master-1-71 ~]# curl 10.96.113.140
<html><body><h1>It works!</h1></body></html>
[root@k8s-master-1-71 ~]# curl 10.99.20.23
<title>Welcome to nginx!</title>
示例1:创建Nginx的Ingress YAML文件(性质与vhost类似)
[root@k8s-master-1-71 ~]# vi ingress-nginx.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-nginx
spec:
ingressClassName: nginx # 标识控制器(下载的控制器即Nginx)
rules:
- host: nginx.hostname.cn # 域名
http:
paths:
- path: / # 默认首页
pathType: Prefix
backend:
service:
name: nginx-web # 后端SVC
port:
number: 80 # 端口
查看ingress命令:kubectl get ingress
[root@k8s-master-1-71 ~]# kubectl apply -f ingress-nginx.yaml
[root@k8s-master-1-71 ~]# kubectl get ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
ingress-nginx nginx nginx.hostname.cn 80 9s
由于ingress中的host是定义域名,需要在C:\Windows\System32\drivers\etc\hosts进行解析
补充:因为ingress Controller暴露是NodePort Service方式,解析的节点地址任意
[root@k8s-master-1-71 ~]# kubectl get svc -n ingress-nginx //先前创建Ingress controller的NodePort Service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx-controller NodePort 10.108.162.206 <none> 80:30513/TCP,443:32099/TCP 3h42m
ingress-nginx-controller-admission ClusterIP 10.103.217.175 <none> 443/TCP 3h42m
测试外部访问ingress定义的Nginx域名:nginx.hostname.cn:30513
示例2:创建httpd的Ingress YAML文件
[root@k8s-master-1-71 ~]# kubectl apply -f ingress-httpd.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-httpd
spec:
ingressClassName: nginx # 标识控制器(下载的控制器即Nginx)
rules:
- host: httpd.hostname.cn # 域名
http:
paths:
- path: / # 默认首页
pathType: Prefix
backend:
service:
name: httpd-web # 后端SVC
port:
number: 80 # 端口
# 查看ingress
[root@k8s-master-1-71 ~]# kubectl get ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
ingress-nginx nginx nginx.hostname.cn 192.168.1.73 80 33m
ingress-web nginx httpd.hostname.cn 192.168.1.73 80 12m
测试外部访问ingress定义的httpd域名:httpd.hostname.cn:30513
2.5.2 共享宿主机网络
访问流程:用户(通过域名)— 指定宿主机 ingress controller pod(Nginx,基于域名)— 分布在各个节点的Pod
注意:域名必须得解析到 ingress controller pod 所在的节点IP(即该节点要有该ingress controller pod,否则无法监听80、443端口)
# 在ingress-controller.yaml添加HostNetwork:True设置,支持共享宿主机网络
[root@k8s-master-1-71 ~]# vi ingress-controller-1.1.yaml
[root@k8s-master-1-71 ~]# kubectl apply -f ingress-controller-1.1.yaml
# 查看Ingress Controller Pod所在Node IP
[root@k8s-master-1-71 ~]# kubectl get pods -n ingress-nginx -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
ingress-nginx-admission-create-jp2xl 0/1 Completed 0 4h42m 10.244.114.43 k8s-node2-1-73 <none> <none>
ingress-nginx-admission-patch-ctjj5 0/1 Completed 1 4h42m 10.244.117.29 k8s-node1-1-72 <none> <none>
ingress-nginx-controller-85cdb79d-htwwh 1/1 Running 0 2m57s 192.168.1.73 k8s-node2-1-73 <none> <none>
# 查看是否监听80端口
[root@k8s-node2-1-73 ~]# ss -nlptu | grep 80
修改地址解析:Ingress Controller Pod所在Node IP web.hostname.cn
测试:
补充:公网负载均衡器的作用
① 将内网K8S集群的Service、Ingress暴露到互联网
② 提高内网K8S集群的安全性
2.6 Ingress 规则配置HTTPS步骤:
步骤1:准备域名证书文件
- 通过 openssl/cfssl 工具自签或者权威机构颁发
- 准备 certs.sh 脚本,主要生成以下:
- ca-config.json 根证书的配置文件
- ca-csr.json 根证书的请求颁发文件
- web.hostname.cn-csr.json 域名颁发客户端证书文件
[root@k8s-master-1-71 ~]# tar -zxvf cfssl.tar.gz -C /usr/bin/
[root@k8s-master-1-71 ~]# vi certs.sh
cat > ca-config.json <<EOF # 根证书的配置文件
{
"signing": {
"default": {
"expiry": "87600h"
},
"profiles": {
"kubernetes": {
"expiry": "87600h",
"usages": [
"signing",
"key encipherment",
"server auth",
"client auth"
]
}
}
}
}
EOF
cat > ca-csr.json <<EOF # 根证书的请求颁发文件
{
"CN": "kubernetes",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"L": "Beijing",
"ST": "Beijing"
}
]
}
EOF
# 通过以上相关根证书信息,为指定域名颁发客户端证书
cfssl gencert -initca ca-csr.json | cfssljson -bare ca -
cat > web.hostname.cn-csr.json <<EOF
{
"CN": "web.hostname.cn", # 一定要与访问的实际域名保持一致
"hosts": [],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"L": "BeiJing",
"ST": "BeiJing"
}
]
}
EOF
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes web.hostname.cn-csr.json | cfssljson -bare web.hostname.cn
[root@k8s-master-1-71 ~]# mkdir ssl
[root@k8s-master-1-71 ~]# mv certs.sh ssl/
[root@k8s-master-1-71 ~]# cd ssl/
[root@k8s-master-1-71 ssl]# bash certs.sh
[root@k8s-master-1-71 ssl]# ls
ca-config.json ca-csr.json ca.pem web.hostname.cn.csr web.hostname.cn-key.pem
ca.csr ca-key.pem certs.sh web.hostname.cn-csr.json web.hostname.cn.pem
步骤2:将证书文件保存到Secret(不能在YAML文件中直接引用)
- 创建Secret命令:kubectl create secret tls --cert=web.hostname.cn.pem --key=web.hostname.cn-key.pem
- 查看Secret命令:kubectl get secret
[root@k8s-master-1-71 ssl]# kubectl create secret tls web-hostname-cn \
--cert=web.hostname.cn.pem --key=web.hostname.cn-key.pem
[root@k8s-master-1-71 ssl]# kubectl get secret
NAME TYPE DATA AGE
web-hostname-cn kubernetes.io/tls 2 40s
步骤3:Ingress规则配置tls
[root@k8s-master-1-71 ~]# kubectl apply -f ingress-https.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-https //ingress名字
spec:
ingressClassName: nginx
## 添加 tls 配置
tls:
- hosts:
- httpd.hostname.cn //https 解析域名
secretName: web-hostname-cn //secret证书名
rules:
- host: httpd.hostname.cn //http 解析域名
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: httpd-web
port:
number: 80
[root@k8s-master-1-71 ~]# kubectl get ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
ingress-https nginx httpd.hostname.cn 192.168.1.73 80, 443 2m8s
思考:Ingress Controller怎么工作的?
Ingress Controller通过与 Kubernetes API 交互,动态的去感知集群中 Ingress 规则变化,然后读取它, 按照自定义的规则,规则就是写明了哪个域名对应哪个service,生成一段 Nginx 配置,应用到管理的 Nginx服务,然后热加载生效。 以此来达到Nginx负载均衡器配置及动态更新的问题。
流程包流程:客户端 ->Ingress Controller(nginx) -> 分布在各节点Pod
[root@k8s-master-1-71 ~]# kubectl get pods -n ingress-nginx
NAME READY STATUS RESTARTS AGE
ingress-nginx-admission-create-jp2xl 0/1 Completed 0 5h8m
ingress-nginx-admission-patch-ctjj5 0/1 Completed 1 5h8m
ingress-nginx-controller-85cdb79d-htwwh 1/1 Running 0 28m
[root@k8s-master-1-71 ~]# kubectl exec -it ingress-nginx-controller-85cdb79d-htwwh bash -n ingress-nginx
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
bash-5.1$ ps -ef
PID USER TIME COMMAND
1 www-data 0:00 /usr/bin/dumb-init -- /nginx-ingress-controller --election-id=ingress-controller-leader --controller-class=k8
7 www-data 0:01 /nginx-ingress-controller --election-id=ingress-controller-leader --controller-class=k8s.io/ingress-nginx --c
28 www-data 0:00 nginx: master process /usr/local/nginx/sbin/nginx -c /etc/nginx/nginx.conf
32 www-data 0:00 nginx: worker process
33 www-data 0:00 nginx: worker process
34 www-data 0:00 nginx: worker process
35 www-data 0:00 nginx: worker process
36 www-data 0:00 nginx: cache manager process
167 www-data 0:00 bash
173 www-data 0:00 ps -ef
进入ingress-nginx-controller容器查看守护进程,主要以下2个进程:
- nginx-ingress-controller 主要用于访问k8s api 获取创建的ingress原则,生成Nginx Vhost配置并生效;
- nginx 即Nginx本尊,做了一些优化和功能加强
补充:通过命令创建并导出ingress YAML
- 创建ingress:kubectl create ingress --rule=域名/=:80
- 导出ingress:kubectl create ingress --rule=域名/=:80 --dry-run=client -o yaml
# kubectl create ingress ingress-web --rule=nginx.hostname.cn/=nginx:80 --dry-run=client -o yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
creationTimestamp: null
name: ingress-web
spec:
rules:
- host: nginx.hostname.cn
http:
paths:
- backend:
service:
name: nginx
port:
number: 80
path: /
pathType: Exact
status:
loadBalancer: {}
课后作业
1、给一个pod创建service,并可以通过ClusterIP / NodePort访问
- 名称:web-service
- pod名称:web
- 容器端口:80
2、 任意名称创建deployment和service,使用busybox容器nslookup解析service
3、列出命名空间下某个service关联的所有pod,并将pod名称写到/opt/pod.txt文件中(使用标签筛选)
- 命名空间:default
- service名称:web
4、使用Ingress将美女示例应用暴露到外部访问
- 镜像:lizhenliang/java-demo(通过进入容器查看得知为tomcat应用)
小结:
本篇为 【Kubernetes CKA认证 Day6】的学习笔记,希望这篇笔记可以让您初步了解到 K8S中Service控制器以及它的三种类型,了解Service代理模式、Ingress等;课后还有扩展实践,不妨跟着我的笔记步伐亲自实践一下吧!
Tip:毕竟两个人的智慧大于一个人的智慧,如果你不理解本章节的内容或需要相关笔记、视频,可私信小安,请不要害羞和回避,可以向他人请教,花点时间直到你真正的理解。