Kubernetes:Service

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
简介: Kubernetes:Service

Service:将运行在一组 Pods 上的应用程序公开为网络服务(微服务)的抽象方法。

k8s 以 Pod 应用部署的最小单位。k8s 根据调度算法为 Pod 分配运行节点,并随机分配 ip 地址。因此 Pod 的 IP 地址不固定,不方便通过 Pod 的 IP 地址访问服务。因此,k8s 提供了 Service,对后端提供相同服务的一组 Pod 的聚合。

一个 Service 提供一个虚拟的 Cluster IP,后端对应一个或者多个提供服务的 Pod。在集群中访问该 Service 时,采用 Cluster IP 即可,Kube-proxy 负责将发送到 Cluster IP 的请求转发到后端的Pod上。

1、Service 定义

来看一个微服务的定义

apiVersion: v1
 kind: Service
 metadata:
   name: myapp-svc
 spec:
   # service 发布类型
   type: ClusterIP
   # 标签选择器:选择 pod
   selector:
     app: myapp
   # 指定端口数组
   ports:
     # service 端口
   - port: 443
     # 协议
     protocol: TCP
     # 容器端口
     targetPort: 443
     # 端口名称 
     name: https
   - port: 80
     protocol: TCP
     targetPort: 80
     name: http
   - port: 6379
     protocol: TCP
     targetPort: 6379
     name: redis-tcp

微服务暴露端口:443, 80, 6379,k8s 为其分配一个集群 ip: ClusterIP。通过标签选择器选择与其匹配的 Pod,然后将所有更新发布到也称为 myapp-svc 的 Endpoint 对象。

1.1、无选择符的服务

没有选择符的 service 需要手动配置 EndpointSlice(旧版 Endpoints),将服务映射到集群外部的服务或者是集群内其他命名空间下的服务。

例:定义没有选择符的 Service

apiVersion: v1
 kind: Service
 metadata:
   name: notselector-svc
 spec:
   ports:
   - protocol: TCP
     port: 8080
     targetPort: 80

服务没有选择算符,因此不会自动创建相应的 Endpoint 对象。 需要手动添加 Endpoint 对象,将服务手动映射到运行该服务的网络地址和端口:

apiVersion: v1
 kind: Endpoints
 metadata:
   name: notselector-svc
 subsets:
 - addresses:
   - ip: 10.244.1.60
   ports:
   - port: 80
 - addresses:
   # 非集群节点的机器:集群外部服务
   - ip: 192.168.88.131
   ports:
   - port: 80

应用资源

kubectl apply -f notselector-svc.yaml
 kubectl describe -f notselector-svc.yaml
 kubectl apply -f notselector-points.yaml
 kubectl describe -f notselector-points.yaml

在集群节点访问外部服务

curl http://192.168.88.131:80/ping

1.2、Endpoints

Endpoints 定义了网络端点的列表,通常由 Service 引用,定义可以将流量发送到哪些 Pod。推荐用 EndpointSlice API 替换 Endpoints。

2、服务发布类型

type的四种类型

  • ClusterIP:默认值,通过集群内部 ip 暴露服务。该服务只能在集群内部访问。
  • NodePort:通过每个节点上的 IP 和静态端口(NodePort)暴露服务。除了集群内部访问,集群外部可以通过 IP:NodePort访问该服务。
  • ExternalName:将服务映射到 DNS 名称,把集群外部的服务引入到集群内部来使用
  • LoadBalancer:使用云提供商的负载均衡器向外部暴露服务。 将来自外部负载均衡器的流量路由到后端的 pod 上,不再需要内部的负载均衡。

2.1、ClusterIP

定义 clusterIP 类型的服务

apiVersion: v1
 kind: Service
 metadata:
   name: myapp-svc
 spec:
   type: ClusterIP
   ports:
   - port: 443
     protocol: TCP
     targetPort: 443
     name: https
   - port: 80
     protocol: TCP
     targetPort: 80
     name: http
   - port: 6379
     protocol: TCP
     targetPort: 6379
     name: redis-tcp

应用 | 查看服务

kubectl apply -f myapp-svc.yaml
 kubectl get -f myapp-svc.yaml 
 kubectl describe -f myapp-svc.yaml
 kubectl get endpoints

集群 ip 范围在 master 节点初始化配置文件 init.default.yaml 中

networking:
   # 域名
   dnsDomain: cluster.local
   # 服务 ip
   serviceSubnet: 10.96.0.0/12
   # pod ip
   podSubnet: 10.244.0.0/16

测试服务

集群内部创建 pod

# 创建一个 redis pod
 kubectl run redis --image=redis
 # 创建一个带有 curl 工具的 pod
 kubectl run curl --image=radial/busyboxplus:curl -it

测试:集群内部访问服务。

# 访问 curl 容器
 kubectl exec -it curl -- sh
 # 访问集群 service ip
 curl http://10.109.36.83:80/ping
 # 访问集群服务域名
 # 域名形式:服务名.命名空间.服务.dns域名(cluster.local)
 curl http://myapp-svc.default.svc.cluster.local:80/ping
 # 访问 redis 容器
 kubectl exec -it redis -- bash
 # 通过集群IP访问
 redis-cli -h <clusterIP> -p 6379
 # 通过域名访问
 redis-cli -h myapp-svc.default.svc.cluster.local -p 6379

2.2、NodePort

定义 service

apiVersion: v1
 kind: Service
 metadata:
   name: myapp-svc
 spec:
   type: NodePort
   ports:
   - port: 443
     protocol: TCP
     targetPort: 443
     name: https
     nodePort: 30001
   - port: 80
     protocol: TCP
     targetPort: 80
     name: http
   - port: 6379
     protocol: TCP
     targetPort: 6379
     name: redis-tcp
     nodePort: 30002
   selector:
     app: myapp

查看 | 应用服务

kubectl delete svc myapp-svc
 kubectl apply -f myapp-svc.yaml
 kubectl get -f myapp-svc.yaml 
 kubectl describe -f myapp-svc.yaml
 # 显示 svcPort: nodePort。不指定 nodePort,则随机生成
 # 443:30001/TCP, 80:32326/TCP, 6379:30002/TCP

测试服务

  • 通过 serviceIP:port可以集群节点,集群内部容器内访问服务。
  • 通过 DNS 域名,可以在集群内部容器访问服务。
  • 通过 nodeIP:nodePort可以在集群节点、集群内部容器、集群外部访问服务。
# serviceIP:port
 curl http://<clusterIP>:80/ping
 curl http://<podIP>:32326/ping
 # nodeIP:nodePort
 curl http://<nodeIP>:32326ping
 # DNS 域名
 curl http://myapp-svc.default.svc.cluster.local:80/ping

2.3、ExternalName

将服务映射到 DNS 名称,相当于将集群内的服务域名映射到外部域名。使用 CNAME 重定向,无法实现端口映射。

定义服务

apiVersion: v1
 kind: Service
 metadata:
   name: externalname-svc
 spec:
   type: ExternalName
   externalName:

应用服务

kubectl apply -f externalname-svc.yaml
 kubectl get svc
 # 显示:CLUSTER-IP 和 PORT(S) 均为 <none>

测试服务

# 进入集群 curl pod
 kubectl exec -it curl -- sh
 ping externalname-svc.default.svc.cluster.local
 ping www.baidu.com

2.4、loadbalancer

在使用支持外部负载均衡器的云提供商的服务时,云提供商的服务会自动的为 type 值为 LoadBalancer 的 service 创建负载均衡。负载均衡是异步创建的,关于被提供的负载均衡器的信息将会通过 service 的 status.loadBalancer 字段发布出去。

使用云厂商提供的外部负载均衡器,来自外部负载均衡器的流量将直接重定向到后端 Pod 上。不再需要内部负载均衡。

apiVersion: v1
 kind: Service
 metadata:
   name: my-loadbalancer-svc
 spec:
   selector:
     app: myapp
   ports:
     - protocol: TCP
       port: 80
       targetPort: 80
   clusterIP: 10.0.171.239
   type: LoadBalancer
 status:
   loadBalancer:
     ingress:
     - ip: 192.0.2.127

3、无头服务

对于无状态的应用,客户端并不在意其连接的是哪一个 Pod,采用 Service 是没有问题的。但是对于有状态的应用,有时需要客户端根据某种算法选择对应的某一个后端 Pod 提供服务,或是需要连接所有的后端 Pod,例如 redis 服务,这时不需要负载均衡和单独。此时,可以通过指定 clusterIP: None ,来创建无头服务Headless Service

无头 Service 不会分配 ClusterIP,kube-proxy 不会处理它们, 不会进行负载均衡和路由。既不能通过集群 IP 访问,也不能通过 DNS 域名访问。其 DNS 记录返回该服务下的所有 Endpoint。

3.1、有选择符的服务

对于有选择符的无头服务,创建 EndpointSlice 对象,返回 DNS 记录是服务的所有 EndPoint。

例:定义有选择符的无头服务

apiVersion: v1
 kind: Service
 metadata:
   name: myapp-headless-svc
 spec:
   clusterIP: None
   type: ClusterIP
   selector:
     app: myapp
   ports:
   - protocol: TCP
     name: http
     port: 8080
     targetPort: 80

应用服务

kubectl apply -f myapp-headless-svc.yaml
 kubectl describe -f myapp-headless-svc.yaml

测试

# 进入 curl pod
 kubectl exec -it curl -- sh
 # 查询 DNS 记录 
 # serviceName.namespace
 # 列举出所有的端点
 nslookup myapp-headless-svc.default.svc.cluster.local

3.2、无选择符的服务

不会创建 EndpointSlice 对象。 返回 DNS 记录是服务的所有 EndPoint。

例:定义无头无选择服务

apiVersion: v1
 kind: Service
 metadata:
   name: notselector-headless-svc
 spec:
   clusterIP: None
   ports:
   - protocol: TCP
     port: 8080
     targetPort: 80

应用资源

kubectl apply -f notselector-headless-svc.yaml
 kubectl describe svc notselector-headless-svc
 # 显示:Endpoints:<none>

手动创建 Endpoint 对象。

apiVersion: v1
 kind: Endpoints
 metadata:
   name: notselector-headless-svc
 subsets:
 - addresses:
   - ip: 10.244.1.60
   ports:
   - port: 80
 - addresses:
   - ip: 192.168.88.131
   ports:
   - port: 80

测试服务

# 应用资源
 kubectl apply -f notselector-points.yaml
 kubectl describe -f notselector-headless-svc.yaml
 # 查看 dns 记录
 kubectl exec -it curl -- sh
 nslookup notselector-headless-svc.default.svc.cluster.local

4、服务发现

4.1、环境变量

必须先创建 service,才能在创建 Pod 时设定环境变量。

当 Pod 运行在节点上,kubelet 会为每个活跃的 Service 添加一组环境变量。

  • {SVCNAME}_SERVICE_HOST
  • {SVCNAME}_SERVICE_PORT
# 查看 pod 的环境变量
 kubectl exec myapp-deploy-59f8994d89-7gjpd -- printenv | grep SERVICE

4.2、DNS

支持集群的 DNS 服务器监视 Kubernetes API 中的新服务,并为每个服务创建一组 DNS 记录。 如果在整个集群中都启用了 DNS,则所有 Pod 都应该能够通过其 DNS 名称自动解析服务。

# 进入 curl pod
 kubectl exec -it curl -- sh
 # 查询DNS serviceName.namespace
 nslookup myapp-svc.default

5、Service TLS

# 1、自签证书
 openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /tmp/tls.key -out /tmp/tls.crt -subj "/CN=myapp-svc.default.svc.cluster.local/O=my-hello"
 # 或
 openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /tmp/tls.key -out /tmp/tls.crt -subj "/CN=10.109.36.83/O=my-hello"
 # 2、创建 secret
 kubectl create secret tls myhellotls --cert=/tmp/tls.crt --key=/tmp/tls.key
 # 查看 secret
 kubectl get secrets myhellotls -o yaml
 # 部署应用程序,修改 myapp-deployment.yaml
 # spec.template.spec 创建
 volumes:
 - name: myhello-tls-volume
   secret:
     secretName: myhellotls
 # spec.template.containers 创建
 volumeMounts:
   - mountPath: /app/cert
     name: myhello-tls-volume
 # https 访问
 curl https://10.109.36.83/ping --cacert /tmp/tls.crt 
 # 结束测试,删除证书
 rm /tmp/tls.*
相关实践学习
容器服务Serverless版ACK Serverless 快速入门:在线魔方应用部署和监控
通过本实验,您将了解到容器服务Serverless版ACK Serverless 的基本产品能力,即可以实现快速部署一个在线魔方应用,并借助阿里云容器服务成熟的产品生态,实现在线应用的企业级监控,提升应用稳定性。
云原生实践公开课
课程大纲 开篇:如何学习并实践云原生技术 基础篇: 5 步上手 Kubernetes 进阶篇:生产环境下的 K8s 实践 相关的阿里云产品:容器服务&nbsp;ACK 容器服务&nbsp;Kubernetes&nbsp;版(简称&nbsp;ACK)提供高性能可伸缩的容器应用管理能力,支持企业级容器化应用的全生命周期管理。整合阿里云虚拟化、存储、网络和安全能力,打造云端最佳容器化应用运行环境。 了解产品详情:&nbsp;https://www.aliyun.com/product/kubernetes
相关文章
|
2月前
|
存储 运维 Kubernetes
容器服务ACK常见问题之修改service的名字失败如何解决
容器服务ACK(阿里云容器服务 Kubernetes 版)是阿里云提供的一种托管式Kubernetes服务,帮助用户轻松使用Kubernetes进行应用部署、管理和扩展。本汇总收集了容器服务ACK使用中的常见问题及答案,包括集群管理、应用部署、服务访问、网络配置、存储使用、安全保障等方面,旨在帮助用户快速解决使用过程中遇到的难题,提升容器管理和运维效率。
|
5月前
|
Kubernetes 负载均衡 网络协议
k8s学习-Service(概念、模板、创建、外部代理、删除等)
k8s学习-Service(概念、模板、创建、外部代理、删除等)
159 0
|
5月前
|
Kubernetes 负载均衡 网络协议
k8s教程(service篇)-总结(上)
k8s教程(service篇)-总结(上)
76 0
|
1月前
|
Kubernetes 网络协议 应用服务中间件
kubernetes核心技术之Service知识点总结
kubernetes核心技术之Service知识点总结
21 0
|
4月前
|
Kubernetes 负载均衡 算法
kubernetes—Service详解
kubernetes—Service详解
40 0
|
5月前
|
Kubernetes 前端开发 网络协议
云原生|kubernetes|kubernetes中的资源(一)---service详解
云原生|kubernetes|kubernetes中的资源(一)---service详解
182 0
|
5月前
|
Kubernetes 负载均衡 应用服务中间件
k8s学习-CKA真题-负载均衡service
k8s学习-CKA真题-负载均衡service
39 0
|
5月前
|
Kubernetes 负载均衡 容器
k8s(8)Service(服务)
Service(服务)
42 0
|
5月前
|
缓存 Kubernetes 网络协议
k8s教程(service篇)-总结(下)
k8s教程(service篇)-总结(下)
75 0
KUBERNETES04_Service服务ClusterIP、NodePort方式、Ingress域名访问、路径重写、限流操作(五)
KUBERNETES04_Service服务ClusterIP、NodePort方式、Ingress域名访问、路径重写、限流操作(五)
221 0
KUBERNETES04_Service服务ClusterIP、NodePort方式、Ingress域名访问、路径重写、限流操作(五)