k8s教程(service篇)-总结(下)

本文涉及的产品
云解析 DNS,旗舰版 1个月
应用型负载均衡 ALB,每月750个小时 15LCU
网络型负载均衡 NLB,每月750个小时 15LCU
简介: k8s教程(service篇)-总结(下)
2.2.6.2 LoadBalancer类型

通常在公有云环境中设置Service的类型为 “LoadBalancer‘” ,可以将Service映射到公有云提供的某个负载均衡器的IP地址上,客户端通过负载均衡器的IPService的端口号就可以访问到具体的服务,无须再通过kube-proxy提供的负载均衡机制进行流量转发。公有云提供的LoadBalancer可以直接将流量转发到后端Pod上,而负载分发机制依赖于公有云服务商的具体实现。

举例:

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
type: LoadBalancer
  selector:
    app: MyApp
  ports:
  - protocol: TCP
    port: 80
    targetPort: 9376
  clusterIP: 10.0.171.239

在服务创建成功之后,云服务商会在Service的定义中补充LoadBalancerIP 地址(status字段):

status:
  loadBalancer:
    ingress:
    - ip:192.0.2.127
2.2.6.3 ExternalName类型

ExternalName类型的服务用于将集群外的服务定义为Kubernetes的集群的Service,并且通过externalName字段指定外部服务的地址,可以使用域名或IP格式,集群内的客户端应用通过访问这个Service就能访问外部服务了

这种类型的Service没有后端Pod,所以无须设置Label Selector。例如:

apiVersion: v1
kind: Service
metadata:
  name: my-service
  namespace: prod
spec:
  type: ExternalName
  externalName: my.database.example.com

在本例中设置的服务名为my-service,所在namespace为prod,客户端访问服务地址my-service.prod.svc.cluster.local时,系统将自动指向外部域名my.database.example.com

2.2.7 Service支持的网络协议

目前Service支持的网络协议如下.

类型 描述
TCP Service的默认网络协议,可用于所有类型的Service
UDP 可用于大多数类型的Service,LoadBalancer类型取决于云服务商对UDP的支持
HTTP 取决于云服务商是否支持HTTP和实现机制
PROXY 取决于云服务商是否支持HTTP和实现机制
SCTP 从Kubernetes1.12版本引入,到1.19版本时达到Beta阶段,默认启用,如需关闭该特性,则需要设置kube-apiserver的启动参数–feature- gates=-SCTPSupport=-false进行关闭

2.2.8 k8s的服务发现机制

2.2.8.1 环境变量的方式

在一个Pod运行起来的时候,系统会自动为其容器运行环境注入所有集群中有效Service的信息。

Service的相关信息包括服务IP、服务端口号、各端口号相关的协议等,通过{SVCNAME_SERVICE_HOST}{SVCNAME_SERVICE_PORT}格式进行设置。

webapp服务为例:

apiVersion: v1
kind: Service
metadata:
  name: webapp
spec: 
  ports:
  - protocol: TCP
    port: 8080
    targetPort: 8080
  selector:
    app: webapp

在一个新创建的Pod(客户端应用)中,可以看到系统自动设置的环境变量如下:

WEBAPP_SERVICE_HOST=169.169.81.175
WEBAPP_SERVICE_PORT=8080
WEBAPP_P0RT=tcp://169.169.81.175:8080
WEBAPP_P0RT_8080_TCP=tcp://169.169.81.175:8080
WEBAPP_PORT_8080_TCP_PROTO=tcp
WEBAPP_PORT_8080_TCP_PORT=8080
WEBAPP_PORT_8080_TCP_ADDR=169.169.81.175

然后,客户端应用就能够根据Service相关环境变量的命名规则,从环境变量中获取需要访问的目标服务的地址了,例如:

curl http://${WEBAPP_SERVICE_HOST}:${WEBAPP_SERVICE_HOST}
2.2.8.2 DNS的方式

Service在Kubernetes系统中遵循DNS命名规范,Service的DNS域名表示方法为<servicename>.<namespace>.svc.<clusterdomain>,其中:

字段 解析
servicename 服务的名称
namespace 所在namespace的名称
clusterdomain Kubernetes集群设置的域名后缀(例如cluster.local),服务名称的命名规则遵循RFC 1123规范的要求

webapp服务为例,将其端口号命名为“http”:

apiversion: v1
kind: Service
metadata:
  name: webapp
spec:
  ports:
  - protocol: TCP
    port: 8080
    targetPort: 8080
    name: http
  selector:
    app: webapp

解析名为 “http” 端口的DNS SRV记录

_http._tcp.webapp.default.svc.cluster.local'”,可以查询到其端口号的值为8080

2.2.9 headless service

在某些应用场景中,客户端应用不需要通过Kubernetes内置Service实现的负载均衡功能,需要自行完成对服务后端各实例的服务发现机制,或者需要自行实现负载均衡功能,此时可以通过创建一种特殊的名为 Headless‘”的服务来实现。

服务名(DNS域名)的解析机制取决于该Headless Service是否设置了Label Selector

2.2.9.1 已设置Label Selector

如果Headless Service设置了Label Selector,Kubernetes则将根据Label Selector查询后端Pod列表,自动创建Endpoint列表,将服务名(DNS域名)的解析机制设置为:当客户端访问该服务名时,得到的是全部Endpoint列表(而不是一个确定的IP地址)。

以下面的Headless Service为例,其设置了Label Selector:

apiversion: v1
kind: Service
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  ports:
  - port: 80
  clusterIP: None
  selector:
    app: nginx

使用kubectl create命令创建完之后,可以查看该Headless Service的详细信息,可以看到后端的Endpoint列表:

当客户端通过DNS服务名 “nginx"和服务端口号访问该Headless服务(URL=nginx:80)时,将得到Service后端Endpoint列表"10.0.95.12:80,10.0.9513:80,10.0.95.14:80”,然后由客户端程序自行决定如何操作,例如:通过轮询机制访问各个Endpoint

2.2.9.2 未设置Label Selector

如果headless Service没有设置Label Selector,则Kubernetes将不会自动创建对应的Endpoint列表。

DNS系统会根据下列条件尝试对该服务名设置DNS记录:

  • 如果Service的类型为ExternalName,则对服务名的访问将直接被DNS系统转换为Service设置的外部名称(externalName);
  • 如果系统中存在与Service同名的Endpoint定义,则服务名将被解析为Endpoint定义中的列表,适用于非ExternalName类型的Service。

2.2.10 端点分片和服务拓扑

2.2.10.1 端点分片

EndpointSlice通过对Endpoint进行分片管理来实现降低Master和各Node之间的网络传输数据量及提高整体性能的目标。对于Deployment的滚动升级,可以实现仅更新部分Node上的Endpoint信息,Master与Node之间的数据传输量可以减少100倍左右,能够大大提高管理效率。


EndpointSlice根据Endpoint 所在Node的拓扑信息进行分片管理,如图所示

Endpoint Slices要实现的第2个目标是为基于Node拓扑的服务路由提供支持,这需要与服务拓扑(Service Topology)机制共同实现

2.2.10.2 服务拓扑

在默认情况下,发送到一个Service的流量会被均匀转发到每个后端Endpoint,但无法根据更复杂的拓扑信息设置复杂的路由策略。服务拓扑机制的引入就是为了实现基于Node拓扑的服务路由,允许Service创建者根据来源Node和目标Node的标签来定义流量路由策略


通过对来源Node和目标Node标签的匹配,用户可以根据业务需求对Node进行分组,设置有意义的指标值来标识 “较近” 或者 “较远” 的属性:

例如:对于公有云环境来说,通常有区域(Zone或Region)的划分,云平台倾向于把服务流量限制在同一个区域内,这通常是因为跨区域网络流量会收取额外的费用。另一个例子是把流量路由到由DaemonSet管理的当前Node的Pod 上。又如希望把流量保持在相同机架内的Node上,以获得更低的网络延时。

2.3 dns服务搭建和配置

详情参考: 《k8s教程(service篇)-DNS服务搭建和配置》

2.3.1 dns在k8s服务的发展

发展:SkyDNS => KubeDNS =>CoreDNS

CoreDNS架构图如下:

描述:

  • 它是由go语言实现的一套高性能、插件式,易于扩展的DNS服务端;
  • 解决了KubeDNS的一些问题, 例如dnsmasq的安全漏洞、externalName不能使用stubDomains进行设置等等;
  • 支持自定义DNS记录及配置upstream DNS Server,可以统一管理Kubernetes基于服务的内部DNS和数据中心的物理DNS;
  • 它没有使用多个容器的架构,只用一个容器便实现了KubeDNS内3个容器的全部功能。

2.3.2 coredns搭建

① 修改每个Node上kubelet的启动参数,在其中加上以下两个参数:

  • --cluster-dns=169.169.0.100:为DNS服务的ClusterIP地址。
  • --cluster-domain=cluster.local:为在DNS服务中设置的域名。

② 重启kubelet服务


③ 部署:需要创建3个资源对象:1个ConfigMap、1个Deployment和1个Service

apiVersion: v1
kind: ConfigMap
metadata:
  name: coredns
  namespace: kube-system 
  labels: 
    addonmanager.kubernetes.io/mode: EnsureExists
data:
  Corefile: | 
    cluster.local{
      errors
      health{
        lameduck 5s 
      }
      ready
      kubernetes cluster.local 169.169.0.0/16{ 
        fallthrough in-addr.arpa ip6.arpa
      }
      prometheus: 9153
      forward ./etc/resolv.conf 
      cache 30 
      loop
      reload
      loadbalance
    }
    . {
      cache 30 
      loadbalance
      forward /etc/resolv.conf
    }
---
apiversion: apps/v1
kind: Deployment
metadata:
  name: coredns
  namespace: kube-system 
  labels:
    k8s-app: kube-dns
    kubernetes.io/name: "CoreDNS"
spec:
  replicas: 1
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 1
  selector:
    matchLabels: 
      k8s-app: kube-dns
  template:
    metadata:
      labels:
        k8s-app: kube-dns
    spec:
    priorityClassName: system-cluster-critical 
    tolerations:
      - key: "CriticalAddonsonly"
        operator: "Exists"
    nodeSelector:
      kubernetes.io/os: linux 
    affinity:
      podAntiAffinity:
      preferredDuringSchedulingIgnoredDuringExecution: 
      - weight: 100
        podAffinityTerm:
          labelSelector:
          matchExpressions:
          - key: k8s-app
                operator: In
                values: ["kube-dns"]
          topologyKey: kubernetes.io/hostname
    containers:
    - name: coredns
      image: coredns/coredns:1.7.0 
      imagePullPolicy: IfNotPresent
      resources:
        limits:
          memory: 170Mi
        requests:
          cpu: 100m
          memory: 70Mi
      args: ["-conf","/etc/coredns/Corefile" ]
    volumeMounts:
    - name: config-volume 
      mountPath: /etc/coredns 
      readOnly: true
    ports:
    - containerPort: 53
      name: dns
      protocol: UDP
    - containerPort: 53
      name: dns-tcp
      protocol: TCP
    - containerPort: 9153
      name: metrics
      protocol: TCP
    securityContext:
      allowPrivilegeEscalation: false
      capabilities:
        add:
        - NET_BIND_SERVICE
        drop:
        - a11
      readOnlyRootFilesystem: true 
    livenessProbe:
      httpGet:
        path: /health
        port: 8080
        scheme: HTTP
      initialDelaySeconds: 60 
      timeoutSeconds: 5
      successThreshold: 1
      failureThreshold: 5
    readinessProbe:
      httpGet:
        path: /ready
        port: 8181
        scheme: HTTP
    dnsPolicy: Default
    volumes:
    - name: config-volume
      configMap:
        name: coredns
        items:
        - key: Corefile
          path: Corefile
---
apiVersion: v1
kind: Service
metadata:
  name: kube-dns
  namespace: kube-system 
  annotations:
    prometheus.io/port: "9153" 
    prometheus.io/scrape: "true" 
  labels:
    k8s-app: kube-dns
    kubernetes.io/cluster-service: "true" 
    kubernetes.io/name: "CoreDNS" 
spec:
  selector:
    k8s-app: kube-dns
  clusterIP: 169.169.0.100 
  ports:
  - name: dns
    port: 53
    protocol: UDP
  - name: dns-tcp
    port: 53
    protocol: TCP
  - name: metrics
    port: 9153
    protocol: TCP 

使用kubectl create命令依次把资源对象创建,然后可以看到创建成功:

2.3.3 配置解析

CoreDNS的主要功能是通过插件系统实现的,CoreDNS实现了一种链式插件结构,将DNS的逻辑抽象成了一个个插件,能够灵活组合使用。常用的插件如下:

插件 描述
loadbalance 提供基于DNS的负载均衡功能
loop 检测在DNS解析过程中出现的简单循环问题
cache 提供前端缓存功能
health 对Endpoint进行健康检查
kubernetes 从Kubernetes中读取zone数据
etcd 从etcd中读取zone数据,可用于自定义域名记录
file 从RFC 1035格式文件中读取zone数据
hosts 使用/etc/hosts文件或者其他文件读取zone数据,可用于自定义域名记录
auto 从磁盘中自动加载区域文件
reload 定时自动重新加载Corefile配置文件的内容
forward 转发域名查询到上游DNS服务器上
prometheus 为Prometheus系统提供采集性能指标数据的URL
pprof 在URL路径/debug/pprof下提供运行时的性能数据
log 对DNS查询进行日志记录
errors 对错误信息进行日志记录

2.3.4 举例(自定义域名)

etcd和hosts插件都可以用于用户自定义域名记录。

下面是使用etcd插件的配置示例,将以“.com”结尾的域名记录配置为从etcd中获取,并将域名记录保存在/skydns路径下:

{
  etcd com{
    path /skydns
    endpoint http://192.168.18.3:2379 
    upstream /etc/resolv.conf 
  }
  cache 160 com 
  loadbalance
  proxy /etc/resolv.conf
}

如果用户在etcd中插入一条“10.1.1.1 mycompany” DNS记录:

$ ETCDCTL_API=3 etcdctl put "/skydns/com/mycompany" '["host":"10.1.1.","ttl":60]'

客户端应用就能访问域名"mycompany.com"了:

$ nslookup mycompany.com
Server:       169.169.0.100
Address:      169.169.0.100#53
Name:       mycompany.com
Address:      10.1.1.1

2.4 node本地dns缓存

详情参考: 《k8s教程(service篇)-Node本地DNS缓存》

Node本地DNS缓存(NodeLocal DNSCache)的工作流程如图所示,客户端Pod首先会通过本地DNS缓存进行域名解析,当缓存中不存在域名时,会将请求转发到集群DS服务进行解析

部署Node本地DNS缓存工具,主要包括 ServiceAccount、Daemonset、ConfigMap和Service 几个资源对象,详情看原文。

2.5 pod的dns域名

详情参考: 《k8s教程(service篇)-pod的dns域名》

对Pod来说,Kubernetes会为其设置一个<pod-ip>.<namespace>.pod.<cluster-domain>格式的DNS域名,其中Pod IP部分需要用 “-” 替换 “.” 符号,例如下面Pod的IP地址为10.0.95.63


系统为这个Pod设置的DNS域名为10-0-95-63.default.pod.cluster.local,用 nslookup进行验证,便可以成功解析该域名的IP地址为10.0.95.63

其它与Service差不多,详情参考原文。

2.6 ingress 7层路由机制

详情参考: 《k8s教程(service篇)-ingress 7层路由机制》

Kubernetes 使用了一个Ingress策略定义一个具体提供转发服务的Ingress Controller,两者结合,实现了基于灵活Ingress策略定义的服务路由功能。

如果是对Kubernetes集群外部的客户端提供服务,那么Ingress Controller实现的是类似于边缘路由器(Edge Router)的功能。

需要注意的是,Ingress只能以HTTPHTTPS提供服务,对于使用其他网络协议的服务,可以通过设置Service的类型 typeNodePortLoadBalancer对集群外部的客户端提供服务


举例:使用Ingress进行服务路由时,Ingress Controller基于Ingress规则将客户端请求直接转发到Service对应的后端Endpoint(Pod)上,这样会跳过kube-proxy设置的路由转发规则,以提高网络转发效率,下图是一个典型的HTTP层路由的例子:

其中:

  • 对http:/mywebsite.com/api的访问将被路由到后端名为api的Service上;
  • 对http:/mywebsite.com/web的访问将被路由到后端名为web的Service上;
  • 对http:/mywebsite.com/docs的访问将被路由到后端名为docs的Service上。

主要流程:部署ingress controller -> 创建ingress策略 -> 客户端通过ingress controller访问后端web-app服务。


关系图大致如下:(图片来自:https://www.cnblogs.com/rancherlabs/p/12034075.html

03 疑问

如果还是对service的一些概念不清晰,比如:kube-proxy与ingress的关系,可以参考阅读:《Using a Network Load Balancer (NLB) to Expose an Application Outside the Kubernetes Cluster》

暴露k8s的服务的三种方式:

  • NodePort
  • Network Load Balancer (NLB)
  • Ingress (application load balancer, ALB)

原理图如下,以便于理解:

04 文末

本文主要总结k8s关于Service的一些学习笔记,以便后续的回顾,谢谢大家的阅读,本文完!

相关实践学习
通过Ingress进行灰度发布
本场景您将运行一个简单的应用,部署一个新的应用用于新的发布,并通过Ingress能力实现灰度发布。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
目录
相关文章
|
3月前
|
Kubernetes 容器
K8S的Service的LoadBanlance之Metallb解决方案
本文介绍了如何在Kubernetes中使用MetalLB来实现Service的LoadBalancer功能,包括MetalLB的部署、配置、以及通过创建地址池和部署服务来测试MetalLB的过程。
147 1
K8S的Service的LoadBanlance之Metallb解决方案
|
4月前
|
Kubernetes 网络安全 容器
在K8S中,有个服务使用service的nodeport进行暴露,发现访问不到如何排查?
在K8S中,有个服务使用service的nodeport进行暴露,发现访问不到如何排查?
|
4月前
|
Kubernetes 负载均衡 网络协议
在K8S中,Service的类型有哪几种,请说⼀下他们的用途?
在K8S中,Service的类型有哪几种,请说⼀下他们的用途?
|
4月前
|
Kubernetes 负载均衡 网络协议
在K8S中,Service的类型有哪些?
在K8S中,Service的类型有哪些?
|
4月前
|
Kubernetes API 容器
在K8S中,Service的Nodeport端口范围?
在K8S中,Service的Nodeport端口范围?
|
4月前
|
Kubernetes 网络协议 网络安全
在K8S中,k8s中service访问有问题,该如何排查?
在K8S中,k8s中service访问有问题,该如何排查?
|
4月前
|
Kubernetes Perl 容器
在k8S中,Service怎么关联Pod的?
在k8S中,Service怎么关联Pod的?
|
2天前
|
存储 Kubernetes 关系型数据库
阿里云ACK备份中心,K8s集群业务应用数据的一站式灾备方案
本文源自2024云栖大会苏雅诗的演讲,探讨了K8s集群业务为何需要灾备及其重要性。文中强调了集群与业务高可用配置对稳定性的重要性,并指出人为误操作等风险,建议实施周期性和特定情况下的灾备措施。针对容器化业务,提出了灾备的新特性与需求,包括工作负载为核心、云资源信息的备份,以及有状态应用的数据保护。介绍了ACK推出的备份中心解决方案,支持命名空间、标签、资源类型等维度的备份,并具备存储卷数据保护功能,能够满足GitOps流程企业的特定需求。此外,还详细描述了备份中心的使用流程、控制台展示、灾备难点及解决方案等内容,展示了备份中心如何有效应对K8s集群资源和存储卷数据的灾备挑战。
|
23天前
|
Kubernetes 监控 Cloud Native
Kubernetes集群的高可用性与伸缩性实践
Kubernetes集群的高可用性与伸缩性实践
58 1
|
2月前
|
JSON Kubernetes 容灾
ACK One应用分发上线:高效管理多集群应用
ACK One应用分发上线,主要介绍了新能力的使用场景