该用法仅适用于在公有云服务商的云平台上搭建服务的场景。在下面的示例中,status.loadBalancer.ingress.ip 中设置的146.148.47.155 是云服务提供商提供的负载均衡器的IP 地址。访问Service 的请求通过LoadBalancer 转发到后端Pod。实现负载均衡依赖于您的云服务提供商提供的LoadBalancer实现机制。
kind:服务
api版本: v1
元数据:
name: 我的服务
规格:
选择器:
app: 我的应用程序
端口:
– 协议: TCP
端口: 80
目标端口: 9376
节点端口: 19376
集群IP: 10.0.171.239
负载平衡器IP: 78.11.24.19
:型负载均衡器
状态:
负载平衡器:
入口:
-ip: 146.148.47.155
k8s 具有三种类型的IP 地址。
节点IP:节点的节点IP地址。这是集群中每个节点的物理网卡的IP地址。
Pod IP:Pod 的IP 地址。由Docker引擎根据docker0网桥的IP地址段分配。这通常是虚拟第2 层网络。
集群IP:服务的IP地址。这也是一个虚拟IP,但它缺少实体网络对象,因此无法响应ping命令,因此它类似于“假”IP地址。它只能与服务端口组合形成特定的通信服务端口。集群IP 本身并不能提供TCP/IP 通信的基础。在k8s 集群内,节点IP 网络、Pod IP 网络和集群IP 网络之间的通信使用k8s 本身设计和实现的特殊路由规则,这些规则不同于一般的IP 路由实现。
该模式提供集群内的虚拟IP(与Pod不在同一网段),用于集群内Pod之间的通信。
headlessservice 要求将spec.clusterIP 设置为None。
由于没有ClusterIP,kube-proxy 将不会处理此类服务。由于没有负载均衡或代理配置,因此访问服务时会返回所有后端Pod IP 地址。主要由开发人员用来执行负载平衡。基于Pod 的开发(选择器集)。
三、Service 服务的VIP 和 Service 网络代理
1、Service 服务的VIP
在Kubernetes 集群中,每个节点都运行一个kube-proxy 进程。每个节点上运行的kube-proxy 进程实际上是一个智能软件负载均衡器,它将服务请求转发到后端pod 实例,并在内部实现服务负载均衡和会话保留机制。
服务不是共享负载均衡器IP,而是分配一个全局唯一的虚拟IP 地址(称为集群IP)。在整个服务生命周期中,其集群IP不会发生变化。
kube-proxy 负责实现服务的VIP(虚拟IP)形式,而不是外部名称形式。
在Kubernetes v1.0 中,代理完全位于用户空间。
Kubernetes v1.1 添加了iptables 代理,但这不是默认的操作模式。
从Kubernetes v1.2 开始,默认使用iptables 代理。
在Kubernetes v1.0 中,服务是“第4 层”(基于IP 的TCP/UDP)概念。 Kubernetes v1.1 添加了Ingress API(测试版),它代表“第7 层”(HTTP)服务。
每当您在k8s 集群中创建服务时,k8s 集群都会为service-cluster-ip-range 内的服务分配一个集群IP,如下所示:
您可以使用kubectl get ep 查看相应的端点信息,即代理的pod。
此外,您还可以以服务的形式将现有服务添加到Kubernetes 集群中。创建服务时不需要指定标签选择器,只需在创建服务后手动添加端点即可。
2、service网络代理模式:
代理模式共有三种:userspace、iptables 和ipvs。
现在默认使用iptables,并从1.8 版本开始添加了ipvs 功能。
1)早期 userspace 代理模式
客户端首先请求一个serviceip 并通过iptables 将其转发到kube-proxy,然后由kube-proxy 将其转发到pod。这种方法效率相对较低。
在这种模式下,kube-proxy 监控Kubernetes master 添加和删除Service 和Endpoints 对象。 在本地节点上为每个服务打开一个端口(随机选择)。连接到“代理端口”的任何请求都将被代理到服务的backendPod 之一(如端点所报告的)。 使用哪个backendPod 根据服务的SessionAffinity 来确定。 最后,安装一条iptables规则,捕获到达服务的clusterIP(虚拟IP)和端口的请求,将其重定向到代理端口,代理端口将请求代理到backendPod。
从网络返回的结果是,到达服务的IP: 端口的任何请求都将被代理到适当的后端,而客户端不知道有关Kubernetes、服务或Pod 的任何信息。
默认策略是通过循环算法选择backendPod。 要实现基于客户端IP 的会话关联,请将service.spec.sessionAffinity 的值设置为“ClientIP”(默认值为“None”)。
2) 当前iptables 代理模式
当客户端请求serviceip 时,服务IP 会直接转发到pod。这种模式下的性能要高得多。 kube-proxy 在节点iptables 规则中生成pod 地址。
在这种模式下,kube-proxy 监控Kubernetes master 添加和删除Service 和Endpoints 对象。 对于每个服务,安装iptables 规则以捕获到达服务的集群IP(虚拟IP)和端口的请求,并将请求重定向到服务的一组后端之一。对于每个Endpoints 对象,还安装一条选择backendPod 的iptables 规则。
默认策略是随机选择一个后端。 要实现基于客户端IP 的会话关联,请将service.spec.sessionAffinity 的值设置为“ClientIP”(默认值为“None”)。
与用户空间代理类似,从网络返回的结果是,到达服务的IP: 端口的任何请求都会被代理到适当的后端,而客户端无需了解有关Kubernetes、服务或Pod 的任何信息。 这比用户空间代理更快、更可靠。然而,与用户空间代理不同的是,iptables 代理依赖于就绪探针,因为如果第一个选定的Pod 变得无响应,它可以自动重试另一个Pod。
3)、ipvs代理方式
该方法通过内核模块ipvs实现转发,效率更高。
3、多端口 Service
许多服务需要公开多个端口。针对这种情况,Kubernetes 支持在Service 对象上定义多个端口。 如果使用多个端口,则必须指定所有端口名称以避免端点上出现歧义。例如:
kind:服务
api版本: v1
元数据:
name: 我的服务
规格:
选择器:
app: 我的应用程序
端口:
– name: http
协议: TCP
端口: 80
目标端口: 9376
– name: https
协议: TCP
端口: 443
目标端口: 9377
4、 选择自己的 IP 地址
您的服务发出的请求可以通过设置spec.clusterIP字段来指定您自己的集群IP地址。 例如,如果您想要替换现有的DNS 条目,或者您的旧系统配置有固定IP 并且难以重新配置。 用户选择的IP地址必须有效,并且在API服务器标识符指定的service-cluster-ip-rangeCIDR范围内。如果IP 地址无效,API 服务器将返回HTTP 状态代码422,指示该值无效。
service为何使用vip而不是不使用 round-robin DNS?
有时我被问到的一个问题是为什么使用VIP 而不是标准的循环DNS。有几个原因。
长期以来,DNS 库并没有认真对待DNS TTL 和缓存域名查询结果。许多应用程序仅查询DNS 一次并缓存结果,即使应用程序或库能够成功查询和解析它,重复重播也会产生负载。 – 解析每个客户端是非常困难的。
我们尽最大努力阻止我们的用户做对他们没有好处的事情,如果很多人问这个问题,我们可能会选择实现它。
四、服务发现和DNS
Kubernetes 支持两种基本的服务发现模式:—— 环境变量和DNS。
1、环境变量
当pod 在节点上运行时,kubelet 会向每个活动服务添加一组环境变量。 它还支持Docker 链接兼容变量(请参阅makeLinkVariables)以及简单的{SVCNAME}_SERVICE_HOST 和{SVCNAME}_SERVICE_PORT 变量。这里的服务名必须大写,横线转为下划线。
例如,名为“redis-master”的服务公开TCP 端口6379 并分配集群IP 地址10.0.0.11。该服务生成以下环境变量:
REDIS_MASTER_SERVICE_HOST=10.0.0.11
REDIS_MASTER_SERVICE_PORT=6379
REDIS_MASTER_PORT=tcp://10.0.0.11:6379
REDIS_MASTER_PORT_6379_TCP=tcp://10.0.0.11:6379
REDIS_MASTER_PORT_6379_TCP_PROTO=tcp
REDIS_MASTER_PORT_6379_TCP_PORT=6379
REDIS_MASTER_PORT_6379_TCP_ADDR=10.0.0.11
这意味着存在一个顺序要求,即—— pod 想要访问的服务必须在pod 本身之前创建。否则,不会给这些环境变量赋值。 DNS 没有这个限制。
2、DNS
DNS 服务器是一个可选(但强烈推荐)的集群插件。 DNS 服务器监视Kubernetes API 以创建新服务,从而为每个服务创建一组DNS 记录。 如果集群范围内的DNS 始终启用,则所有Pod 都应该能够使用服务自动解析名称。
例如:
该服务是webapp,命名空间是“my-ns”。在Kubernetes 集群中为“webapp.my-ns”创建DNS 记录。
1) 同一集群中的Pod(在名为“my-ns”的命名空间中)必须能够仅通过名称查询找到“webapp”。
2) 另一个命名空间中的Pod 必须使用名称“webapp.my-ns”进行限定。 这些名称查询的结果是集群IP。
Kubernetes 还支持端口名称的DNS SRV(服务)记录。如果名为“webapp.my-ns”的服务具有名为“http”的TCP 端口,则可以对“_http._tcp.webapp.my-ns”执行DNS SRV 查询,即可获取端口号。
Kubernetes DNS 服务器是访问外部名称类型服务的唯一方式。 更多信息请参见https://guisu.blog.csdn.net/article/details/93501650。
五、集群外部访问服务
k8s集群外部访问集群内服务的主要方式有hostPort或hostNetwork、NodePort、Ingress。
1、hostPort或hostNetwork
hostPort 和hostNetwork 放在第一位是因为它们很容易被忽视。这允许从集群外部访问集群内的应用程序。
hostNetwork用法:
apiVersion: 应用程序/v1
部署kind:
元数据:
标签:
app:nginx
name: nginx-部署
规格:
复制品: 1
选择器:
匹配标签:
app: nginx
模板:
元数据:
标签:
app: nginx
规格:
nodeSelector: # 节点节点选择器
role: Master # Node 节点标签(Label)
hostNetwork: true # 使用node节点网络
集装箱:
– image: nginx
imagePullPolicy: 如果不存在
name: nginx
端口:
– 集装箱港口: 8080
重点是与容器同级的hostNetwork: true,表示pod应该使用宿主机网络,配合nodeSelector在固定节点上实例化pod。如上,为主节点添加标签role: master。通过.nodeSelector,nginx在master节点上实例化,因此可以通过master节点的ip和8080端口访问它。
hostPort用法:
apiVersion: 应用程序/v1
部署kind:
元数据:
标签:
app: nginx
name: nginx-部署
规格:
复制品: 1
选择器:
匹配标签:
app: nginx
模板:
元数据:
标签:
app: nginx
规格:
nodeSelector: # 节点节点选择器
role: Master # Node 节点标签(Label)
集装箱:
– image: nginx
imagePullPolicy: 如果不存在
name: nginx
端口:
– 集装箱港口: 8080
hostPort: 80 #要点
与hostNetwork相比,它具有更多的映射功能。当然,HostPort需要一个节点选择器来修改节点。否则每次创建节点都会不同。 IP将会改变。
如何访问:用nodeSelector选择的节点ip:hostPort:role=Master Label节点ip:80如上
2、NodePort
NodePorts 是提供集群外部访问的最常见方法之一。该方法使用Service来提供集群外部的访问。
设置物理机映射的nodePort,服务类型设置为NodePort:
kind:服务
api版本: v1
元数据:
name: 我的服务
规格:
type:节点端口
选择器:
app: 我的应用程序
端口:
– 协议: TCP
端口: 80
目标端口: 9376
节点端口:30376
如何访问:将集群中任意节点的IP添加到上面分配给nodePort的端口号中。集群中任何节点上的ip:30376都可以访问该服务。
使用节点端口的缺点:
每个端口只能提供一项服务,端口范围只有30000-32767,并且与节点的IP地址紧密耦合。
nodePort 在本机上可访问,但在其他服务器上不可访问。例如,curl 172.16.1.23:30018 在节点172.16.1.23 上可访问,但在服务器172.16.1.21 上不可访问。
解决办法是:
cat /etc/sysctl.d//etc/sysctl.conf EOF
net.ipv4.ip_forward=1
结束后
系统控制-p
具体原因:Vendor libnetwork @1861587 by sanimej · Pull Request #28257 · moby/moby · GitHub
如果Docker 设置了net.ipv4.ip_forward=1 参数,则iptables FORWARD 将设置为DORP 策略。如果用户设置了net.ipv4.ip_forward=1参数,则用户可能需要对ACCEPT策略进行FORWARD。此时,Docker 不会改变FORWARD 策略。
3、LoadBalancer
通过配置云服务提供商提供的LoadBalancer地址来映射LoadBalancer。
该用法仅适用于在公有云服务商的云平台上搭建服务的场景。在下面的示例中,status.loadBalancer.ingress.ip 中设置的146.148.47.155 是云服务提供商提供的负载均衡器的IP 地址。访问Service 的请求通过LoadBalancer 转发到后端Pod。实现负载均衡依赖于您的云服务提供商提供的LoadBalancer实现机制。
kind:服务
api版本: v1
元数据:
name: 我的服务
规格:
选择器:
app: 我的应用程序
端口:
– 协议: TCP
端口: 80
目标端口: 9376
节点端口: 19376
集群IP: 10.0.171.239
负载平衡器IP: 78.11.24.19
:型负载均衡器
状态:
负载平衡器:
入口:
-ip: 146.148.47.155
4、Ingress
这可以理解为简单的部署一个nginx服务。 nginx服务使用hostNetwork或hostPort提供集群外部的访问,并根据配置的路由规则路由集群内部的各种服务。
根据上述使用服务的步骤,一个服务以IP:Port的形式表示,而对于基于HTTP的服务,不同的URL地址往往对应不同的后端服务或虚拟服务器。这些应用层传输机制只能通过Kubernetes Service机制来实现。 kubernetes V1.1中新增的Ingress将不同URL的访问请求转发到不同的后端服务,并实现了HTTP层业务路由机制。在kubernetes 集群中,Ingress 实现必须与Ingress 和Ingress 控制器定义相结合,才能形成完整的HTTP 负载均衡功能。
1)、创建Ingress Controller
使用Nginx 实现Ingress 控制器时,需要实现的基本逻辑是:
a) 监控您的API 服务器并获取所有入口定义。
b) 根据ingress定义生成Nginx所需的配置文件/etc/nginx/nginx.conf。
c) 运行nginx -s relaod 命令重新加载nginx.conf 文件并创建脚本。
直接下载Google提供的nginx-ingress镜像来创建Ingress控制器。
文件nginx-ingress-rc.yaml
api版本: v1
kind:复制控制器
元数据:
name: nginx-ingress
标签:
app: nginx 入口
规格:
复制品: 1
选择器:
app: nginx 入口
模板:
元数据:
标签:
app: nginx 入口
规格:
集装箱:
– image: gcr.io/google_containers/nginx-ingress:0.1
姓名:
nginx
ports:
– containerPort: 80
hostPort: 80
这里,Nginx应用配置设置了hostPort,即它将容器应用监听的80端口号映射到物理机,以使得客户端应用可以通过URL地址“http://物理机IP:80”来访问该Ingress Controller
#kubectl create -f nginx-ingress-rc.yaml
#kubectl get pods
2)、定义Ingress
为mywebsite.com定义Ingress,设置到后端Service的转发规则:
apiVersion: extensions/vlbeta1
kind: Ingress
metadata:
name: mywebsite-ingress
spec:
rules:
– host: mywebsite.com
http:
paths:
– path: /web
backend:
serviceName: webapp
servicePort: 80
这个Ingress的定义说明对目标http://mywebsite.com/web的访问将被转发到kubernetes的一个Service上 webapp:80
创建该Ingress
#kubectl create -f Ingress.yaml
#kubectl get ingress
NAME |Hosts |Address |Ports |Age
mywebsite-ingress |mywebsite.com |80 |17s
创建后登陆nginx-ingress Pod,查看自动生成的nginx.conf内容
3)访问http://mywebsite.com/web
我们可以通过其他的物理机对其进行访问。通过curl –resolve进行指定
#curl –resolve mywebsite.com:80:192.169.18.3 mywebsite.com/web
3)、使用Ingress 场景
Ingress 可能是暴露服务的最强大方式,但同时也是最复杂的。Ingress 控制器有各种类型,包括 Google Cloud Load Balancer, Nginx,Contour,Istio,等等。它还有各种插件,比如 cert-manager,它可以为你的服务自动提供 SSL 证书。
如果你想要使用同一个 IP 暴露多个服务,这些服务都是使用相同的七层协议(典型如 HTTP),那么Ingress 就是最有用的。如果你使用本地的 GCP 集成,你只需要为一个负载均衡器付费,且由于 Ingress是“智能”的,你还可以获取各种开箱即用的特性(比如 SSL,认证,路由,等等)。
5、总结各方式利弊
hostPort和hostNetwork直接使用节点网络,部署时节点需固定,访问ip也固定(也可以用host),端口为正常端口
nodeport方式部署时不要求固定节点,可通过集群内任一ip进行访问,就是端口为30000以上,很多时候由于公司安全策略导致不能访问。
LoadBalancer依赖于云服务商提供的LoadBalancer的实现机制。
ingress需要额外安装ingress模块,配置路由规则,且仅能通过所配置域名访问,配置好域名后,可以直接对外提供服务,和传统的nginx作用类似
六、Headless Service
**1、定义:**有时不需要或不想要负载均衡,以及单独的Service IP。遇到这种情况,可以通过指定Cluster IP(spec.clusterIP)的值为“None”来创建Headless Service。
2、和普通Service相比:
对这类Headless Service并不会分配Cluster IP,kube-proxy不会处理它们,而且平台也不会为它们进行负载均衡和路由。
它会给一个集群内部的每个成员提供一个唯一的DNS域名来作为每个成员的网络标识,集群内部成员之间使用域名通信。
3、无头服务管理的域名是如下的格式:$(service_name).$(k8s_namespace).svc.cluster.local。其中的\”cluster.local\”是集群的域名,除非做了配置,否则集群域名默认就是cluster.local。
因此选项spec.clusterIP允许开发人员自由的寻找他们自己的方式,从而降低与Kubernetes系统的耦合性。应用仍然可以使用一种自注册的模式和适配器,对其他需要发现机制的系统能够很容易的基于这个API来构建。
因为没有load balancing或 proxy 代理设置,在访问服务的时候回返回后端的全部的Pods IP地址,主要用于开发者自己根据pods进行负载均衡器的开发(设置了selector)。
DNS如何实现自动配置,依赖于Service时候定义了selector。
(1)编写headless service配置清单
vim myapp-svc-headless.yaml
apiVersion: v1
kind: Service
metadata:
name: myapp-headless
namespace: default
spec:
selector:
app: myapp
release: canary
clusterIP: “None” #headless的clusterIP值为None
ports:
– port: 80
targetPort: 80
(2)创建headless service
kubectl apply -f myapp-svc-headless.yaml
[root@k8s-master mainfests]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 443/TCP 36d
myapp NodePort 10.101.245.119 80:30080/TCP 1h
myapp-headless ClusterIP None 80/TCP 5s
redis ClusterIP 10.107.238.182 6379/TCP 2h
(3)使用coredns进行解析验证
[root@k8s-master mainfests]# dig -t A myapp-headless.default.svc.cluster.local. @10.96.0.10
; <<>> DiG 9.9.4-RedHat-9.9.4-61.el7 <<>> -t A myapp-headless.default.svc.cluster.local. @10.96.0.10
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 62028
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 5, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;myapp-headless.default.svc.cluster.local. IN A
;; ANSWER SECTION:
myapp-headless.default.svc.cluster.local. 5 IN A 10.244.1.18
myapp-headless.default.svc.cluster.local. 5 IN A 10.244.1.19
myapp-headless.default.svc.cluster.local. 5 IN A 10.244.2.15
myapp-headless.default.svc.cluster.local. 5 IN A 10.244.2.16
myapp-headless.default.svc.cluster.local. 5 IN A 10.244.2.17
;; Query time: 4 msec
;; SERVER: 10.96.0.10#53(10.96.0.10)
;; WHEN: Thu Sep 27 04:27:15 EDT 2018
;; MSG SIZE rcvd: 349
[root@k8s-master mainfests]# kubectl get svc -n kube-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kube-dns ClusterIP 10.96.0.10 53/UDP,53/TCP 36d
[root@k8s-master mainfests]# kubectl get pods -o wide -l app=myapp
NAME READY STATUS RESTARTS AGE IP NODE
myapp-deploy-69b47bc96d-4hxxw 1/1 Running 0 1h 10.244.1.18 k8s-node01
myapp-deploy-69b47bc96d-95bc4 1/1 Running 0 1h 10.244.2.16 k8s-node02
myapp-deploy-69b47bc96d-hwbzt 1/1 Running 0 1h 10.244.1.19 k8s-node01
myapp-deploy-69b47bc96d-pjv74 1/1 Running 0 1h 10.244.2.15 k8s-node02
myapp-deploy-69b47bc96d-rf7bs 1/1 Running 0 1h 10.244.2.17 k8s-node02
(4)对比含有ClusterIP的service解析
[root@k8s-master mainfests]# dig -t A myapp.default.svc.cluster.local. @10.96.0.10
; <<>> DiG 9.9.4-RedHat-9.9.4-61.el7 <<>> -t A myapp.default.svc.cluster.local. @10.96.0.10
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 50445
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;myapp.default.svc.cluster.local. IN A
;; ANSWER SECTION:
myapp.default.svc.cluster.local. 5 IN A 10.101.245.119
最后的话
最近很多小伙伴找我要Linux学习资料,于是我翻箱倒柜,整理了一些优质资源,涵盖视频、电子书、PPT等共享给大家!
资料预览
给大家整理的视频资料:
给大家整理的电子书资料:
如果本文对你有帮助,欢迎点赞、收藏、转发给朋友,让我有持续创作的动力!
-t A myapp.default.svc.cluster.local. @10.96.0.10
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 50445
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;myapp.default.svc.cluster.local. IN A
;; ANSWER SECTION:
myapp.default.svc.cluster.local. 5 IN A 10.101.245.119
最后的话
最近很多小伙伴找我要Linux学习资料,于是我翻箱倒柜,整理了一些优质资源,涵盖视频、电子书、PPT等共享给大家!
资料预览
给大家整理的视频资料:
[外链图片转存中…(img-bcC3h1Am-1719212063577)]
给大家整理的电子书资料:
[外链图片转存中…(img-ItIrxC68-1719212063578)]
如果本文对你有帮助,欢迎点赞、收藏、转发给朋友,让我有持续创作的动力!
#以上关于k8s实践的相关内容来源网络仅供参考,相关信息请以官方公告为准!
原创文章,作者:CSDN,如若转载,请注明出处:https://www.sudun.com/ask/92017.html