k8s之service

实验环境

k8s环境参考: k8s-v1.20.10 二进制部署指导文档

ExternalName

介绍

  • ExternalName ServiceService的特例,它没有selector,也没有定义任何的端口和 Endpoint。 相反地,对于运行在集群外部的服务,它通过返回该外部服务的别名这种方式来提供服务。
  • ExternalName类型的Service用于引入集群外部的服务,它通过externalName 属性指定外部一个服务的地址,然后在集群内部访问此service就可以访问到外部的服务了变现为集群内部提供了服务,且还是只有内部访问外部
  • service FQDN为:<service-name>.<namespace>.svc.cluster.local

应用场景:跨名称空间访问,default名称空间下的client 服务想要访问nginx-ns名称空间下的nginx-svc服务

实例一

​ ExternalName类型的Service用于引入集群外部的服务,它通过externalName 属性指定外部一个服务的地址,然后在集群内部访问此service就可以访问到外部的服务了

# 创建service
[root@k8s-master-1 external]# cat external.yaml
apiVersion: v1
kind: Service
metadata:
  name: external-service
  namespace: default
spec:
  type: ExternalName
  externalName: www.baidu.com   #可写ip | 域名
 
# 测试
[root@k8s-master-1 external]# kubectl run -it busybox --rm --image=busybox:1.28 -- sh
If you don't see a command prompt, try pressing enter.
/ # nslookup external-service.default.svc.cluster.local 10.0.0.10
Server:    10.0.0.10
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local

Name:      external-service.default.svc.cluster.local
Address 1: 220.181.38.149
Address 2: 220.181.38.150

# 即实现了在k8s集群内部访问了www.baidu.com

实例二

实现跨namespace访问

[root@k8s-master-1 external]# cat external.yaml 
apiVersion: v1
kind: Namespace
metadata:
  name: nginx-ns
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-ns
  namespace: nginx-ns
spec:
  selector:
    app: "nginx"
  type: ClusterIP
  ports:
  - name: http
    port: 88
    targetPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
  namespace: nginx-ns
spec:
  replicas: 2
  selector:
    matchLabels:
      app: "nginx"
  template:
    metadata:
      name: nginx
      labels:
        app: "nginx"
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        imagePullPolicy: IfNotPresent
        ports:
        - name: http
          containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: external-service
  namespace: default
spec:
  type: ExternalName
  externalName: nginx-ns.nginx-ns.svc.cluster.local  #当访问external-service.default.svc.cluster.local时,实际上会去访问nginx-ns.nginx-ns.svc.cluster.local
# 应用
[root@k8s-master-1 external]# kubectl apply -f external.yaml 

# 查看pods
[root@k8s-master-1 external]# kubectl get pods -n nginx-ns
NAME                    READY   STATUS    RESTARTS   AGE
nginx-d89c7cdcb-l668x   1/1     Running   0          9s
nginx-d89c7cdcb-l7g98   1/1     Running   0          9s

# 跨namesapce访问
[root@k8s-master-1 external]# kubectl run -it nginx --rm --image=nginx -- sh
If you don't see a command prompt, try pressing enter.
# curl -I external-service.default.svc.cluster.local:88                                     
HTTP/1.1 200 OK
Server: nginx/1.21.3
Date: Thu, 14 Oct 2021 14:22:33 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Tue, 07 Sep 2021 15:21:03 GMT
Connection: keep-alive
ETag: "6137835f-267"
Accept-Ranges: bytes

ClusterIP

介绍

  • ClusterIP的不能设置service.spec.ports.nodePort,不允许,ClusterIP只对集群内提供服务

  • ClusterIP 主要在每个 node 节点使用ipvs/iptables,将发向 ClusterIP对应端口的数据,转发到 kube-proxy 中。然后 kube-proxy 自己内部实现有负载均衡的方法,并可以查询到这个 Service 下对应 pod 的地址和端口,进而把数据转发给对应的 pod 的地址和端口

  • apiserver 用户通过 kubectl命令向 apiserver 发送创建 service 的命令,apiserver 接收到请求后将数据存储到 etcd 中。

  • kube-proxy 在 kubernetes 的每个节点中都有一个叫做 kube-porxy 的进程,这个进程负责感知 service 和 pod 的变化,并将变化的信息写入本地的 ipvs/iptables 规则中

  • ipvs/iptables 使用 NAT 等技术将 VirtualIP 的流量转至 endpoint 中

实例一

# 对应配置文件,如下所示:
[root@k8s-master-1 cluster]# cat deployment-nginx.yaml 
apiVersion: v1
kind: Service
metadata:
  name: cluster-nginx
  namespace: default
spec:
  selector:
    cluster-nginx: "true" 
  type: ClusterIP
  clusterIP: 10.0.0.254
  ports:
  - name: http
    port: 80
    protocol: TCP
    targetPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: cluster-nginx
  namespace: default
spec:
  minReadySeconds: 10
  progressDeadlineSeconds: 600
  replicas: 2
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      cluster-nginx: "true"
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
  template:
    metadata:
      name: cluster-nginx
      labels:
        cluster-nginx: "true"
        app: "nginx"
    spec:
      restartPolicy: Always
      serviceAccountName: default
      containers:
      - name: nginx
        image: nginx:latest
        imagePullPolicy: IfNotPresent
        ports:
        - name: http
          containerPort: 80
# 启动服务
[root@k8s-master-1 cluster]# kubectl apply -f deployment-nginx.yaml

# 查看SVC服务
[root@k8s-master-1 cluster]# kubectl get svc
NAME            TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
cluster-nginx   ClusterIP   10.0.0.254   <none>        80/TCP    2m11s
kubernetes      ClusterIP   10.0.0.1     <none>        443/TCP   9d


# 查看POD服务
[root@k8s-master-1 cluster]# kubectl get pods
NAME                             READY   STATUS    RESTARTS   AGE
cluster-nginx-86d96df9cd-2l5hv   1/1     Running   0          2m25s
cluster-nginx-86d96df9cd-swgtt   1/1     Running   0          2m25s

# pod内通过FQDN访问
[root@k8s-master-1 cluster]# kubectl exec -it cluster-nginx-86d96df9cd-2l5hv -- curl -I cluster-nginx.default.svc.cluster.local
HTTP/1.1 200 OK
Server: nginx/1.21.3
Date: Thu, 14 Oct 2021 12:23:39 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Tue, 07 Sep 2021 15:21:03 GMT
Connection: keep-alive
ETag: "6137835f-267"
Accept-Ranges: bytes

# 通过service IP访问
[root@k8s-master-1 cluster]# curl -I 10.0.0.254:80
HTTP/1.1 200 OK
Server: nginx/1.21.3
Date: Thu, 14 Oct 2021 12:24:56 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Tue, 07 Sep 2021 15:21:03 GMT
Connection: keep-alive
ETag: "6137835f-267"
Accept-Ranges: bytes

# 解析SVC,这里可以看出解析出来的IP是service的IP,而不是后端Pod IP,headless解析出来的是后端POD IP,导致设置port实际上是没有生效的
[root@k8s-master-1 headless]# kubectl run busybox -it --rm --image=busybox:1.28 -- sh
If you don't see a command prompt, try pressing enter.
/ # nslookup cluster-nginx.default.svc.cluster.local
Server:    10.0.0.10
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local

Name:      cluster-nginx.default.svc.cluster.local
Address 1: 10.0.0.254 cluster-nginx.default.svc.cluster.local

NodePort

介绍

  • 如果设置type的值为 “NodePort”,Kubernetes master 将从给定的配置范围内(默认:30000-32767)分配端口,每个Node将从该端口(每个 Node 上的同一端口)代理到Service。该端口将通过Service的spec.ports[].nodePort字段被指定。如果需要指定的端口号,可以配置nodePort的值,系统将分配这个端口,否则调用 API 将会失败(比如,需要关心端口冲突的可能性)。这可以让开发人员自由地安装他们自己的负载均衡器,并配置 Kubernetes 不能完全支持的环境参数,或者直接暴露一个或多个 Node 的IP 地址。需要注意的是,Service 将能通过<NodeIP>:spec.ports[].nodePort和 spec.clusterIp:spec.ports[*].port 而对外可见
  • nodePort 的原理在于在 每个运行了kube-proxy上开了一个端口,将向该端口的流量导入到 kube-proxy,然后由 kube-proxy 进一步到给对应的 pod
  • client -> Node IP:Port -> Service IP:Port -> Pod IP:Container Port

实例一

[root@k8s-master-1 nodeport]# cat deployment-nginx.yaml 
apiVersion: v1
kind: Service
metadata:
  name: cluster-nginx
  namespace: default
spec:
  selector:
    cluster-nginx: "true" 
  type: NodePort
  ports:
  - name: http
    port: 8888
    protocol: TCP
    targetPort: 80
    nodePort: 33333    #这个可以不写,系统分配,30000-32767范围
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: cluster-nginx
  namespace: default
spec:
  minReadySeconds: 10
  progressDeadlineSeconds: 600
  replicas: 2
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      cluster-nginx: "true"
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
  template:
    metadata:
      name: cluster-nginx
      labels:
        cluster-nginx: "true"
        app: "nginx"
    spec:
      restartPolicy: Always
      serviceAccountName: default
      containers:
      - name: nginx
        image: nginx:latest
        imagePullPolicy: IfNotPresent
        ports:
        - name: http
          containerPort: 80
# 查看svc
[root@k8s-master-1 nodeport]# kubectl get svc
NAME            TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)          AGE
cluster-nginx   NodePort    10.0.0.161   <none>        8888:33333/TCP   2m
kubernetes      ClusterIP   10.0.0.1     <none>        443/TCP          9d

# 通过nodeport访问nginx
[root@k8s-master-1 nodeport]# curl -I 192.168.0.10:33333
HTTP/1.1 200 OK
Server: nginx/1.21.3
Date: Thu, 14 Oct 2021 12:33:46 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Tue, 07 Sep 2021 15:21:03 GMT
Connection: keep-alive
ETag: "6137835f-267"
Accept-Ranges: bytes

# 通过service IP访问nginx
[root@k8s-master-1 nodeport]# curl -I 10.0.0.161:8888
HTTP/1.1 200 OK
Server: nginx/1.21.3
Date: Thu, 14 Oct 2021 12:36:28 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Tue, 07 Sep 2021 15:21:03 GMT
Connection: keep-alive
ETag: "6137835f-267"
Accept-Ranges: bytes

# 通过FQDN访问
[root@k8s-master-1 nodeport]# kubectl exec -it cluster-nginx-86d96df9cd-dxwcm -- curl -I cluster-nginx.default.svc.cluster.local:8888
HTTP/1.1 200 OK
Server: nginx/1.21.3
Date: Thu, 14 Oct 2021 12:38:35 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Tue, 07 Sep 2021 15:21:03 GMT
Connection: keep-alive
ETag: "6137835f-267"
Accept-Ranges: bytes

​ kubernetes中的服务之间访问的端口,尽管cluster-nginx容器暴露了80端口,但是集群内其他容器需要通过service:8888端口访问该服务,外部通过nodeport:33333来访问,port和nodeport不会冲突

No-Selector

介绍

Service 抽象了该如何访问 Kubernetes Pod,但也能够抽象其它类型的 backend,例如:

  • 希望在生产环境中使用外部的数据库集群,但测试环境使用自己的数据库。
  • 希望服务指向另一个 Namespace 中或其它集群中的服务。
  • 正在将工作负载转移到 Kubernetes 集群,和运行在 Kubernetes 集群之外的 backend
  • 卸载service时候,会连带把同名的endpoint一起卸载了

实例一

映射外部服务案例:k8s-node-1 上运行mariadb,最后实现访问service,来到达访问mariadb(这里的mariadb可以是集群外的服务)

# 查看yaml文件
[root@k8s-master-1 no-selector]# cat noselect.yaml 
apiVersion: v1
kind: Service
metadata:
  name: mysql
spec:
  type: ClusterIP
  ports:
  - port: 80
    targetPort: 3306
---
apiVersion: v1
kind: Endpoints
metadata:
  name: mysql   #默认创建service时就会生成一个与service名字一样的endpoints,并且会自动去关联
subsets:
- addresses:
  - ip: 192.168.0.11
  ports:
  - port: 3306
 
# 运行
	[root@k8s-master-1 no-selector]# kubectl apply -f noselect.yaml

# 查看service
[root@k8s-master-1 no-selector]# kubectl describe svc mysql
Name:              mysql
Namespace:         default
Labels:            <none>
Annotations:       <none>
Selector:          <none>
Type:              ClusterIP
IP Families:       <none>
IP:                10.0.158.63
IPs:               10.0.158.63
Port:              <unset>  80/TCP
TargetPort:        3306/TCP
Endpoints:         192.168.0.11:3306
Session Affinity:  None
Events:            <none>

# 访问外部mariadb数据库
[root@k8s-master-1 no-selector]# kubectl run mysql -it --rm --image=mysql -- sh
If you don't see a command prompt, try pressing enter.

# mysql -uroot -ppassword -hmysql.default.svc.cluster.local -P80
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 7
Server version: 5.5.68-MariaDB MariaDB Server
Copyright (c) 2000, 2021, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql>   #可以发现集群内部通过service登陆了外部数据库


# 访问流程
	访问Service IP:80 -> 192.168.0.11:3306

Headless

介绍

  • 有时不需要或不想要负载均衡,以及单独的 Service IP。 遇到这种情况,可以通过指定 Cluster IP(spec.clusterIP)的值为 “None” 来创建 Headless Service。(这个service是没有IP)。因为没有ClusterIP,kube-proxy 并不处理此类服务,因为没有load balancing或 proxy 代理设置,在访问服务的时候回返回后端的全部的Pods IP地址,主要用于开发者自己根据pods进行负载均衡器的开发(设置了selector) 或 StatefulSet
  • 这个选项允许开发人员自由寻找他们自己的方式,从而降低与 Kubernetes 系统的耦合性。 应用仍然可以使用一种自注册的模式和适配器,对其它需要发现机制的系统能够很容易地基于这个 API 来构建。对这类 Service 并不会分配 Cluster IP,kube-proxy 不会处理它们,而且平台也不会为它们进行负载均衡和路由DNS如何实现自动配置,依赖于Service是否定义了 selector
  • 不同的pod通过域名进行通信

实例一

含有selector

[root@k8s-master-1 headless]# cat headless-selector.yaml 
apiVersion: v1
kind: Service
metadata:
  name: nginx
spec:
  type: ClusterIP
  clusterIP: None
  selector:
    app: nginx
  ports:
  - port: 88
    targetPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      name: nginx
      labels:
        app: nginx
    spec:
      restartPolicy: Always
      containers:
      - name: nginx
        image: nginx:latest
        imagePullPolicy: IfNotPresent
        ports:
        - name: http
          containerPort: 80
# 查看svc
[root@k8s-master-1 headless]# kubectl get svc
NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.0.0.1     <none>        443/TCP   11h
nginx        ClusterIP   None         <none>        88/TCP    21s
[root@k8s-master-1 headless]# kubectl describe svc nginx
Name:              nginx
Namespace:         default
Labels:            <none>
Annotations:       <none>
Selector:          app=nginx
Type:              ClusterIP
IP Families:       <none>
IP:                None
IPs:               None
Port:              <unset>  88/TCP
TargetPort:        80/TCP
Endpoints:         10.70.2.13:80,10.70.2.14:80
Session Affinity:  None
Events:            <none>

# 运行busybox
[root@k8s-master-1 headless]# kubectl run busybox -it --rm --image=busybox:1.28 -- sh
If you don't see a command prompt, try pressing enter.
/ # nslookup nginx.default.svc.cluster.local
Server:    10.0.0.10
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local

Name:      nginx.default.svc.cluster.local
Address 1: 10.70.2.14 10-70-2-14.nginx.default.svc.cluster.local
Address 2: 10.70.2.13 10-70-2-13.nginx.default.svc.cluster.local

/ # telnet nginx.default.svc.cluster.local 88         这里为啥不能通
telnet: can't connect to remote host (10.70.2.19): Connection refused
/ # telnet nginx.default.svc.cluster.local 80         这里可以通,为啥
^C
Console escape. Commands are:


# 测试访问
[root@k8s-master-1 headless]# kubectl run nginx -it --rm --image=nginx -- sh
If you don't see a command prompt, try pressing enter.

# curl -I nginx.default.svc.cluster.local
HTTP/1.1 200 OK
Server: nginx/1.21.3
Date: Sat, 16 Oct 2021 13:23:36 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Tue, 07 Sep 2021 15:21:03 GMT
Connection: keep-alive
ETag: "6137835f-267"
Accept-Ranges: bytes

# curl -I nginx.default.svc.cluster.local:88
curl: (7) Failed to connect to nginx.default.svc.cluster.local port 88: Connection refused


# 配置 Selector
	对定义selector的Headless Service,Endpoint 控制器在 API 中创建了 Endpoints 记录,并且修改 DNS 配置返回 A 记录(地址),通过这个地址直接到达Service的后端Pod上,`也就是DNS返回的是后端pod的IP,而不是SVC IP,所以才导致访问service:port才会连接不上`

# 不配置 Selector
	对没有定义 selector 的 Headless Service,Endpoint 控制器不会创建Endpoints记录
	
# 我们在容器里面ping FQDN , service解析出的地址是clusterip(正常的clusterIP),headless service 解析出来的地址是 pod ip(无头)

# 通过headless service 可以轻松找到statefulSet 的所有节点。特别是在部署集群的时候,很多服务需要配置节点信息来创建集群,

# statefulSet.spec.serviceName
	当serviceName 配置成与headless service的Name 相同的时候,可以通过 {hostName}.{service-name}.{namespace}.svc.cluster.local 解析出节点IP。hostName 由 {statefulSet name}-{编号} 组成。
# 待确认是否是的
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

旺仔_牛奶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值