Kubernetes服务发布基础

        通过k8s的调度,我们可以成功的将服务部署到Kubernetes,应用部署后,最重要的就是对用户开放。

        在传统的架构中,用户访问公司内的服务可能通过了多层代理、网关、防火墙等。在Kubernetes中,访问Kubernetes中的的应用同样也会经过多层代理、网关、防火墙等。但是在传统架构中,可能是通过Nginx、Haproxy、LVS、公有云的SLB、ELB等实现的负载均衡和域名路由,虽然Kubernetes也是通过诸如此类的技术实现的域名路由或者负载均衡,只不过对应的名字叫法可能有所变化,不要把这些当做个比较新颖的东西,其实内部的实现和之前并无区别

        在传统架构配置多个相同服务的负载均衡可能使用的是Nginx的upstream 在Kubernetes中用Service实现。在传统架构配置域名访问应用可能使用Nginx的Server配置,在Kubernetes中用Ingress实现域名路由的配置

一. Service的定义

        service用于为一组提供服务的Pod抽象一个稳定的网络访问地址,是k8s实现微服务的核心概念通过Service的定义设置的访问地址是DNS域名格式的服务名称,对于客户端应用来说,网络访问方式并没有改变。Service还提供了负载均衡器的功能,将客户端请求负载分发到后端提供具体服务的各个Pod上。

        service主要用于提供网络服务,通过Service的定义,能够为客户端应用提供稳定的访问地址(域名或IP地址)和负载均衡功能,以及屏蔽后端EndPoint的变化,是Kubernetes实现微服务的核心资源        

        总之,service是kubernetes中一个非常重的概念,service用于将外部请求代理到内部pod上,提供4层负载均衡和服务发现的功能, 使得我们可以建高可用和可扩展的应用程序。

二.Service的概念和原理

        service是kubernetes中的一种抽象,用于定义一组pod以及访问这一组pod的策略、service的作用是将一组pod封装为一个虚拟的服务,并提供一个统一的入口,供客户端访问。service支持负载均衡、服务发现、服务暴露等功能。

        在kubernetes中,pod的IP地址是动态变化的,因此无法直接通过pod的IP地址进行访问servic的出现正式为了解决找个问题的。service会为一组pod创建一个虚拟的IP地址,通过这个IP地址可以访问这组pod中的任意一个pod。当客户端请求这个虚拟IP地址时,请求会被负载均衡到一组pod中的某一个pod上,从而完成对pod的访问。

    service的实现依赖于kube-proxy组件。kube-proxy会在每个节点上监听service的变化,一有service发生变化,kube-proxy会更新本地的iptables规则,从而实现流量的转发和负载均衡。另外,service还与CoreDNS有关。CoreDNS是kubernetes集群中的DNS解析服务在kubernetes中service的虚拟IP地址还会注册到CoreDNS中,从而使得客户端还可以通过service名称访问service的虚拟IP地址。在service的定义中,可以通过spec.selector字段指定哪些pod属于这个service,这样,就可以将请求负载均衡到这些pod中

        总之,service是kubernetes中一种非常重要的资源对象,它可以让pod对外提供服务,并提供负载均衡、服务发现等功能service的实现依赖于kube-proxyy和CoreDNS组件,他们共同协作,将servic与pod连接起来,实现对pod的代理访问,如下图所示。

三.Service的负载均衡机制

        当一个Service对象在Kubernetes集群中被定义出来时,集群内的客户端应用就可以通过服务IP访问到具体的Pod容器提供的服务了,从服务IP到后端Pod的负载均衡机制,则是由每个node上的kube-proxy代理来负责实现的。

kubproxy代理模式 

kube-proxy的代理模式有:userspace,iptables,ipvs和kernelspace 

1.userspace

        起初,kube-proxy进程是一个真实TCP/UDP代理,当某个pod以ClusterIP方式 访问某个service的时候,这个流量会被pod所在的本机的iptables转发到本机的kube-proxy进程,然后将请求转发到后端某个pod上。

流程:

  • kube-proxy为每个service在node上打开一个随机端口作为代理端口
  • 建立iptables规则,将Clusterip的请求重定向到代理端口
  • 到达代理端口的请求再由kuproxy转发到后端

 

2.iptables

        Kubernetes从1.2版本开始将iptables作为默认模式,这种模式下kube-proxy不再起到proxy的作用。其核心功能:通过API server的Watch接口 实时跟踪service和endpoint的变更信息,并更新对应的iptables规则,client的请求流量通过iptables的NAT机制“直接路由”到目标pod

3.ipvs模式 

  • 工作原理kube-proxy 使用 IPVS(IP Virtual Server)来处理 Service 流量。IPVS 是 Linux 内核提供的负载均衡器。
  • 优点
    • 支持更高效的负载均衡算法(如轮询、加权轮询等)。
    • 适合处理大量的并发连接和高吞吐量。
  • 缺点
    • 配置和管理可能会更复杂。
    • 需要内核支持 IPVS 模块。
  • 配置:你可以通过 kube-proxy 的配置文件来启用 IPVS 模式。
apiVersion: v1
kind: ConfigMap
metadata:
  name: kube-proxy
  namespace: kube-system
data:
  config.conf: |
    mode: "ipvs"

ipvs为负载均衡提供了更多的算法:

  • rr:轮询
  • lc:最小连接数
  • df:目标哈希
  • sh:源哈希
  • sed:预计延迟最短
  • nq:从不排队

4.kernelspace

是WIndow server上的代理模式

四.service的四种类型

1.ClusterIP

(1)介绍

        最常用的service类型, 它为pod提供了一个虚拟的IP地址。当其他Pod需要访问该Service时,它们只需要使用该虚拟IP地址即可。Kubernetes会自动将请求路由到相应的pod上。

(2)实验
1.生成用于测试Service的Deployment

        编写deployment,用于各种service的验证

        在应用service概念之前,先创建一个提供web服务的Pod集合,有两个Tomcat容器副本组成,每个容器提供的服务端口都为8080。(后续的实验都用此来测试)

(1)编写demloyment
[root@k8s-master ~]# vim webapp-deployment.yaml 

apiVersion: apps/v1
kind: Deployment
metadata:
  name: webapp
spec:
  replicas: 2
  selector:
    matchLabels:
      app: webapp
  template:
    metadata:
      labels:
        app: webapp
    spec:
      containers:
      - name: webapp
        image: kubeguide/tomcat-app:v1
        ports:
        - name: http
          containerPort: 8080
          protocol: TCP
 (2)生成pod
kubectl create -f webapp-deployment.yaml
kubectl get pod -l app=webapp -o wide
2.service的创建
2.1创建一个Cluster类型service

        描述:ClusterIP是默认service类型,它将创建一个虚拟的ClusterIp地址,用于在集群内部访问service

        使用场景:适用于集群内部的服务通信,例如将前端服务和后端服务连接起来,供内部其他服务使用。

(1)执行expose 命令暴露端口(创建service)

[root@k8s-master ~]# ku expose deployment webapp
service/webapp exposed

备注:为标签为webapp的deployment暴露一个ClusterIP类型的Kubernetes service。

(2)查看创建的service

[root@k8s-master ~]# kubectl get  svc 
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
kubernetes   ClusterIP   10.96.0.1        <none>        443/TCP    4d6h
webapp       ClusterIP   10.108.145.159   <none>        8080/TCP   99s

(3)测试访问

[root@k8s-master ~]# curl 10.108.145.159:8080

(4)删除service

[root@k8s-master ~]# ku delete svc webapp
service "webapp" deleted
[root@k8s-master ~]# ku get  svc 
NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP   4d6h
2.2.使用yaml文件创建service

        除了使用expose的命令创建service外,更便于管理的方式是yaml文件来创建service

(1)编写service文件

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

备注:

ports:定义的是service本身的端口号8080(用于提供给集群内部用户访问使用的端口)。

targetport:指定后端pod的容器端口号,selector定义的是后端pod所拥有的label。

(2)创建service,并测试

[root@k8s-master ~]# ku create -f webapp-service.yaml 
service/webapp created

[root@k8s-master ~]# ku get svc
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
kubernetes   ClusterIP   10.96.0.1       <none>        443/TCP    4d6h
webapp       ClusterIP   10.111.18.173   <none>        8080/TCP   28s


[root@k8s-master ~]# curl 10.111.18.173:8080

(3)查看endpoint列表

        一个service对应的后端由pod的IP地址和容器的端口号组成,即一个完整的IP:port访问地址,这在k8s中叫做endpoint,通过查看service 的详细信息,可以看到起后端的Endpoint列表

[root@k8s-master ~]# ku describe svc webapp
Name:              webapp
Namespace:         default
Labels:            <none>
Annotations:       <none>
Selector:          app=webapp
Type:              ClusterIP
IP Family Policy:  SingleStack
IP Families:       IPv4
IP:                10.111.18.173
IPs:               10.111.18.173
Port:              <unset>  8080/TCP
TargetPort:        8080/TCP
Endpoints:         10.244.140.71:8080,10.244.196.135:8080
Session Affinity:  None
Events:            <none>

 (4)查看endpoint资源对象

        实际上,k8s自动创建了与service关联的endpoint资源对象

[root@k8s-master ~]# ku get endpoints webapp
NAME     ENDPOINTS                                AGE
webapp   10.244.140.71:8080,10.244.196.135:8080   7m52s

(5)删除这个service

kubectl delete -f webapp-service.yaml 
service "webapp" deleted
[root@k8s-master ~]# ku get svc
NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP   4d6h

或者

[root@k8s-master ~] ku delete svc webapp
service "webapp" deleted
[root@k8s-master ~]# ku get svc
NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP   4d6h

 2.NodePort

(1)解释

        这种Service类型将pod公开为集群中所有节点上的某个端口,当外部请求到达任何一个节点上的该端口时,Kubernetes会将请求路由到响应的Pod上。

 (2)实验
1.基础环境deployment
2.创建nodeport类型的service

        描述:NodePort将在每个节点上公开一个端口,并将流量转发到service。他会创建一个clusterIP,并使用端口映射到每个节点的相同端口。

        使用场景:适用与需要从外部访问集群中的服务时,可以通过节点的IP地址和映射的端口进行访问。这对于开发和测试环境非常重要。

(1)创建service文件

设置service类型为NodePort,并设置具体的nodePort端口号为30008

[root@k8s-master ~]# vim webapp-svc-nodeport.yaml 

apiVersion: v1
kind: Service
metadata:
  name: webapp
spec:
  type: NodePort
  ports:
  - port: 8080
    targetPort: 8080
    nodePort: 30008
  selector:
    app: webapp

备注:port :设置的是 Service 对象暴露的端口,用于集群内部通信

           targetport: 容器内部的端口号。Service 将请求转发到这个端口。这个端口通常是 Pod 内运行的应用服务的端口。

           nodePort:Service 类型为 NodePort 时,nodePort 是 Kubernetes 集群的每个节点上暴露的端口号,允许外部流量通过此端口访问 Service

(2)创建和查看与ClusterIP类型相同
[root@k8s-master ~]# ku create -f webapp-svc-nodeport.yaml 
service/webapp created
[root@k8s-master ~]# ku get svc
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
kubernetes   ClusterIP   10.96.0.1        <none>        443/TCP          4d7h
webapp       NodePort    10.109.129.168   <none>        8080:30008/TCP   6s
(3)测试在WIndow宿主机上用浏览器测试访问

Apache Tomcat/8.0.35icon-default.png?t=N7T8http://192.168.10.101:30008/ 

3.LoadBalancer类型

(1)介绍

         LoadBalancer  Service:这种Service类型使用云提供商的负载均衡器将请求路由到后端Pod。Kubernetes会自动创建和配置负载均衡器,并将其绑定到service上。

 (2)实验

        通常在公有云的环境中会使用LoadBalancer的类型,可以将Service映射到公有云提供的某个负载均衡器的IP地址上,客户端通过负载均衡器的IP和Service的端口号就可以访问到具体的服务。

        描述:LoadBalancer为Service创建一个外部负载均衡器,并分配一个外部IP地址。它通常由云提供商的负载均衡服务实现

        使用场景:适用于需要将流量从外部负载均衡器分发到集群内部的服务,例如在生产环境中暴露web应用程序。

1.编写LoadBalancer
[root@k8s-master ~]# vim webapp-svc-loadbalancer.yaml 

apiVersion: v1
kind: Service
metadata:
  name: webapp
  namespace: default
  labels:
    app: webapp
spec:
  type: LoadBalancer
  ports:
    - port: 8080
      targetPort: http
      protocol: TCP
      name: http
  selector:
    app: webapp

备注:这个service创建好后,云服务商会在service定义中补充LoadBalancer的IP地址,之后可以在客户端访问该Service

nodePort的端口范围在30000-32767之间 

2.创建并查看
[root@k8s-master ~]# ku create -f webapp-svc-loadbalancer.yaml 
service/webapp created
[root@k8s-master ~]# ku get svc
NAME         TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)          AGE
kubernetes   ClusterIP      10.96.0.1      <none>        443/TCP          4d7h
webapp       LoadBalancer   10.109.149.6   <pending>     8080:30287/TCP   6s

因为没有连到云服务商后面的操作不在演示。 

4. ExternalName

(1)介绍

        externalName Service:这种service类型允许你将service映射到集群外部的某个名称。当Pod需要访问该service时,它们将使用该名称来解析出相应的IP地址

(2)实验 

        描述:ExternalName允许Service通过返回CNAME记录来引用集群外部的服务。它没有clusterIP,NodePort或 LoadBalancer

        使用场景:适用于需要将K8s内部的服务与集群外的现有服务进行关联,例如连接到外部的数据库或其他资源。        

        ExternalName类型是Service的特例,用于将集群外的服务定义为Kubernetes的集群Service并通过ExternalName字段指定外部服务的地址,可以使用域名或IP格式。集群内客户端应用通过访问这个Service就能访问外部服务了。他没有选择器,没有定义任何端口和Endpoint,他通过返回该外部服务的别名来提供服务。也可以用于两个不同的namespace之间的不同pod可以通过name的形式访问。

注意:

        两个不同的命名空间中的pod,可以直接使用他们的IP地址进行通信,但是pod的IP地址是随机分配的,重建pod后其IP地址就改变了,因此我们要用pod对应的service名称进行通信。但是跨命名空间是不能解析其他命名空间中创建的service名称的。这个时候就可以使用ExternalName实现两个不同命名空间中的各个pod间的通信

1.创建两个命名空间
[root@k8s-master ~]# ku create namespace test01
[root@k8s-master ~]# ku create namespace test02
2.第一个pod
(1)编写命名空间为test01的Pod文件并创建pod
[root@k8s-master ~]# vim myapp01.yaml 

apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp01
  namespace: test01
spec:
  replicas: 1
  selector: #标签选择器
    matchLabels: #匹配的标签为
      app: myapp01
      release: canary
  template:
    metadata:
      labels:
        app: myapp01 #和上面的myapp要匹配
        release: canary
    spec:
      containers:
      - name: myapp
        image: ikubernetes/myapp:v1
        ports:
        - name: http01
          containerPort: 80

 创建该pod

ku create -f myapp01.yaml
(2)创建一个无头(headless)service
[root@k8s-master ~]# vim myapp-svc-headless01.yaml 

apiVersion: v1
kind: Service
metadata:
  name: myapp-svc01
  namespace: test01
spec:
  selector:
    app: myapp01 #挑选的pod还是myapp01。一个pod可以有多个service
    release: canary
  clusterIP: None #None表示是无头service
  ports:
  - port: 39320 #service ip中的端口
    targetPort: 80 #容器ip中的端口

备注:

 (HeadlessService)无头Service:这种服务没有入口地址(没有clusterIP),kube-proxy也不会为其创建负载转发的规则,服务名的解析机制取决于这个无头Service是否设置了标签选择器

注意:

无头服务创建出来之后,对于其他外部的pod来讲,该pod对应的名字就确定了下来,其固定的格式是:无头服务名.命名空间.svc.cluster.local

[root@k8s-master ~]# ku create -f myapp-svc-headless01.yaml 
(3)创建extername
[root@k8s-master ~]# vim myapp-svc-extername01.yaml 

kind: Service
apiVersion: v1
metadata:
  name: myapp-svcname02
  namespace: test01
spec:
  type: ExternalName
  externalName: myapp-svc02.test02.svc.cluster.local

备注:

name:myapp-是vcname02 指的是外部的服务名称

myapp-svc02.test02.svc.cluster.local    对方无头服务的名称.对方命令空间的名称.svc.cluster.local

可用以下命令查看

[root@k8s-master ~]# ku get svc -n test01
NAME              TYPE           CLUSTER-IP   EXTERNAL-IP                            PORT(S)     AGE
myapp-svc01       ClusterIP      None         <none>                                 39320/TCP   8h
myapp-svcname02   ExternalName   <none>       myapp-svc02.test02.svc.cluster.local   <none>      8h

 备注:myapp-svc02.test02.svc.cluster.local为对方nds的名称,是能通过名称访问的

 创建

[root@k8s-master ~]# ku create -f myapp-svc-extername01.yaml 
3.第二个pod
(1)编写并创建命名空间为test02的pod
[root@k8s-master ~]# vim myapp02.yaml 

apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp02
  namespace: test02
spec:
  replicas: 1
  selector: #标签选择器
    matchLabels: #匹配的标签为
      app: myapp02
      release: canary
  template:
    metadata:
      labels:
        app: myapp02 #和上面的myapp要匹配
        release: canary
    spec:
      containers:
      - name: myapp02
        image: ikubernetes/myapp:v1
        ports:
        - name: http02
          containerPort: 80

创建pod

ku create -f myapp02.yaml 
(2)创建无头(headless)service
[root@k8s-master ~]# vim myapp-svc-headless02.yaml 

apiVersion: v1
kind: Service
metadata:
  name: myapp-svc02
  namespace: test02
spec:
  selector:
    app: myapp02 #挑选的pod还是myapp。一个pod可以有多个service
    release: canary
  clusterIP: None #None表示是无头service
  ports:
  - port: 39320 #service ip中的端口
    targetPort: 80 #容器ip中的端口

创建无头service

ku create -f myapp-svc-headless02.yaml 
(3)创键extername
[root@k8s-master ~]# vim myapp-svc-extername02.yaml 

kind: Service
apiVersion: v1
metadata:
  name: myapp-svcname01
  namespace: test02
spec:
  type: ExternalName
  externalName: myapp-svc01.test01.svc.cluster.local

创建

ku create -f myapp-svc-extername02.yaml
4.验证pod间的通信
[root@k8s-master ~]# ku get pods -n test01

NAME                       READY   STATUS    RESTARTS   AGE
myapp01-696c886d6b-2p5ks   1/1     Running   0          8h
[root@k8s-master ~]# ku exec -it myapp01-696c886d6b-2p5ks -n test01 -- sh

/ # ping myapp-svcname02
PING myapp-svcname02 (10.244.140.72): 56 data bytes
64 bytes from 10.244.140.72: seq=0 ttl=62 time=1.131 ms
64 bytes from 10.244.140.72: seq=1 ttl=62 time=0.300 ms
[root@k8s-master ~]# ku get pod -n test02 -o wide

NAME                       READY   STATUS    RESTARTS   AGE   IP              NODE     NOMINATED NODE   READINESS GATES
myapp02-55ffcd5f64-w9tw4   1/1     Running   0          8h    10.244.140.72   node02   <none>           <none>
[root@k8s-master ~]# ku get pod -n test01 -o wide

NAME                       READY   STATUS    RESTARTS   AGE   IP               NODE     NOMINATED NODE   READINESS GATES
myapp01-696c886d6b-2p5ks   1/1     Running   0          8h    10.244.196.136   node01   <none>           <none>

五。service的其他应用

service的多端口设置

        一个容器应用可以提供多个端口的服务,在service的定义中可以相应的设置多个端口号

(1)创建文件

[root@k8s-master ~]# vim service-multiple-ports.yaml 

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

注意:selector中的app:webapp的标签对应的是webapp-deployment.yaml的pod标签

(2)创建service

[root@k8s-master ~]# ku create -f service-multiple-ports.yaml 
service/webapp created

(3)查看endpoint列表

[root@k8s-master ~]# ku describe svc webapp
Name:              webapp
Namespace:         default
Labels:            <none>
Annotations:       <none>
Selector:          app=webapp
Type:              ClusterIP
IP Family Policy:  SingleStack
IP Families:       IPv4
IP:                10.107.175.37
IPs:               10.107.175.37
Port:              web  8080/TCP
TargetPort:        8080/TCP
Endpoints:         10.244.140.71:8080,10.244.196.135:8080
Port:              management  8005/TCP
TargetPort:        8005/TCP
Endpoints:         10.244.140.71:8005,10.244.196.135:8005
Session Affinity:  None
Events:            <none>

(4)查看创建的service

[root@k8s-master ~]# ku get svc webapp
NAME     TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)             AGE
webapp   ClusterIP   10.107.175.37   <none>        8080/TCP,8005/TCP   96s

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值