一文读懂 Service,助你成为 Kubernetes 高手!

什么是 Kubernetes Service

在 Kubernetes 中,Service 是一种抽象的概念,它代表了一组 Pod 的逻辑集合,为 Pod 提供了一个统一的访问地址和端口。Service 可以将 Pod 的 IP 地址和端口号隐藏起来,对外暴露一个稳定的虚拟 IP 地址和端口号,方便外部应用访问。

Service 的作用和用途

Service 具有以下作用和用途:

  • 服务发现: Service 为 Pod 提供了一个统一的访问入口,方便外部应用发现和访问 Pod。

  • 负载均衡: Service 可以将流量分散到多个 Pod 实例上,实现负载均衡。

  • 网络隔离: Service 可以将 Pod 隔离在不同的网络环境中,提高安全性。

  • 动态更新: Service 可以动态更新 Pod 的 IP 地址和端口号,无需修改外部应用的配置。

区分 ClusterIP、NodePort、LoadBalancer 类型的 Service

Service 有三种类型:ClusterIP、NodePort 和 LoadBalancer。

ClusterIP:这种类型的 Service 仅在集群内部可访问,外部应用无法直接访问。

  • 创建 Service 时,Kubernetes 会为 Service 分配一个虚拟 IP 地址,该 IP 地址仅在集群内部可访问。

  • Pod 可以通过 Service 的虚拟 IP 地址和端口号访问其他 Pod。

  • 外部应用无法直接访问 Service 的虚拟 IP 地址和端口号。

NodePort:这种类型的 Service 除了在集群内部可访问之外,还可以通过节点的 IP 地址和 NodePort 端口号从外部访问。

  • 创建 Service 时,Kubernetes 会为 Service 分配一个 NodePort 端口号,该端口号在所有节点上都可用。

  • Pod 可以通过 Service 的 NodePort 端口号访问其他 Pod。

  • 外部应用可以通过节点的 IP 地址和 NodePort 端口号访问 Service。

LoadBalancer:这种类型的 Service 会创建一个负载均衡器,将流量分散到多个 Pod 实例上,并可以通过公网 IP 地址访问。

  • 创建 Service 时,Kubernetes 会创建一个负载均衡器,将流量分散到多个 Pod 实例上。

  • Pod 可以通过 Service 的负载均衡器地址和端口号访问其他 Pod。

  • 外部应用可以通过公网 IP 地址和端口号访问 Service。

选择 Service 类型时,需要考虑以下因素:

  • 应用的访问范围: 如果应用仅在集群内部使用,则可以使用 ClusterIP 类型的 Service。如果应用需要从外部访问,则可以使用 NodePort 或 LoadBalancer 类型的 Service。

  • 负载均衡需求: 如果需要负载均衡,则可以使用 NodePort 或 LoadBalancer 类型的 Service。

  • 成本: LoadBalancer 类型的 Service 需要额外的成本,例如云服务商的负载均衡器费用。

注意:

  • Service 的类型不能动态修改,需要重新创建 Service。

  • LoadBalancer 类型的 Service 需要额外的配置,例如云服务商的负载均衡器配置。

ClusterIP 的工作原理

ClusterIP 类型的 Service 是 Kubernetes 中默认的 Service 类型,它仅在集群内部可访问。

ClusterIP 类型的 Service 工作原理如下:

  1. 创建 Service 时,Kubernetes 会为 Service 分配一个虚拟 IP 地址。

  2. Pod 通过 Service 的虚拟 IP 地址和端口号访问其他 Pod。

  3. Service 将流量转发到相应的 Pod。

内部服务暴露的方式

ClusterIP 类型的 Service 可以通过以下方式暴露内部服务:

  • 通过 Pod 的 IP 地址和端口号直接访问: 这种方式仅适用于在集群内部访问服务。

  • 通过 Service 的虚拟 IP 地址和端口号访问: 这种方式适用于在集群内部和外部访问服务。

注意:

  • 外部应用无法直接访问 ClusterIP 类型的 Service 的虚拟 IP 地址和端口号。

  • 如果需要从外部访问 ClusterIP 类型的 Service,可以使用 NodePort 或 LoadBalancer 类型的 Service。

使用案例:部署内部服务并使用 ClusterIP 暴露

假设 我们有一个名为 my-app 的内部服务,该服务需要在集群内部的所有 Pod 上都可访问。

步骤:

  1. 创建一个 Deployment 来部署 my-app 服务。

apiVersion: apps/v1kind: Deploymentmetadata:  name: my-appspec:  selector:    matchLabels:      app: my-app  template:    metadata:      labels:        app: my-app    spec:      containers:      - name: my-app        image: busybox        command: ["sleep", "3600"]
  • 创建一个 ClusterIP 类型的 Service 来暴露 my-app 服务。

apiVersion: v1kind: Servicemetadata:  name: my-appspec:  selector:    matchLabels:      app: my-app  ports:  - name: http    protocol: TCP    port: 80    targetPort: 80
  • 在集群内部的任何 Pod 上,都可以通过 my-app 的虚拟 IP 地址和端口号访问 my-app 服务。

curl http://my-app.svc.cluster.local:80

NodePort 的工作原理

NodePort 类型的 Service 除了在集群内部可访问之外,还可以通过节点的 IP 地址和 NodePort 端口号从外部访问。

当创建一个 NodePort 类型的 Service 时,Kubernetes 会为 Service 分配一个 NodePort 端口号,该端口号在所有节点上都可用。Pod 可以通过 Service 的 NodePort 端口号访问其他 Pod。外部应用可以通过节点的 IP 地址和 NodePort 端口号访问 Service。

NodePort 类型的 Service 工作原理如下:

  1. 创建 Service 时,Kubernetes 会为 Service 分配一个 NodePort 端口号。

  2. Pod 通过 Service 的 NodePort 端口号访问其他 Pod。

  3. Service 将流量转发到相应的 Pod。

  4. 外部应用通过节点的 IP 地址和 NodePort 端口号访问 Service。

外部访问的方式

NodePort 类型的 Service 可以通过以下方式从外部访问:

  • 通过节点的 IP 地址和 NodePort 端口号直接访问: 这种方式适用于在集群外部的任何地方访问服务。

注意:

  • 外部应用无法直接访问 NodePort 类型的 Service 的虚拟 IP 地址和端口号。

  • 如果需要在集群内部访问 NodePort 类型的 Service,可以使用 Service 的虚拟 IP 地址和端口号访问。

端口范围和冲突解决

NodePort 类型的 Service 使用 30000-32767 端口范围。如果指定的 NodePort 端口号已被占用,Kubernetes 会自动分配一个可用的端口号。

端口冲突解决策略:

  • 随机端口: Kubernetes 会随机分配一个可用的端口号。

  • 指定端口: 您可以指定一个端口号,如果该端口号已被占用,则 Kubernetes 会报错。

推荐使用随机端口策略,因为它可以避免端口冲突问题。

使用案例:创建 NodePort Service 并访问服务

假设 我们有一个名为 my-app 的服务,需要在集群内部和外部都可访问。

步骤:

  • 创建一个 Deployment 来部署 my-app 服务。

apiVersion: apps/v1kind: Deploymentmetadata:  name: my-appspec:  selector:    matchLabels:      app: my-app  template:    metadata:      labels:        app: my-app    spec:      containers:      - name: my-app        image: busybox        command: ["sleep", "3600"]
  • 创建一个 NodePort 类型的 Service 来暴露 my-app 服务。

apiVersion: v1kind: Servicemetadata:  name: my-appspec:  selector:    matchLabels:      app: my-app  ports:  - name: http    protocol: TCP    port: 80    targetPort: 80    nodePort: 30000
  • 在集群内部,可以通过 my-app 的虚拟 IP 地址和端口号访问 my-app 服务。

curl http://my-app.svc.cluster.local:80
  • 在集群外部,可以通过节点的 IP 地址和 NodePort 端口号访问 my-app 服务。

curl http://<node-ip>:30000

LoadBalancer 的工作原理

LoadBalancer 类型的 Service 会创建一个负载均衡器,将流量分散到多个 Pod 实例上。

工作原理:

  1. 创建 Service 时,Kubernetes 会向云服务提供商 (CSP) 的负载均衡器 API 发送请求,创建一个负载均衡器。

  2. 负载均衡器会分配一个外部 IP 地址。

  3. 负载均衡器会将流量转发到 Service 的后端 Pod 实例。

注意:

  • LoadBalancer 类型的 Service 需要额外的成本,例如云服务商的负载均衡器费用。

  • 创建 LoadBalancer 类型的 Service 需要额外的配置,例如云服务提供商的负载均衡器配置。

云服务提供商的负载均衡器

不同的云服务提供商 (CSP) 提供不同的负载均衡器服务。

常见的 CSP 负载均衡器:

  • Amazon Web Services (AWS): Elastic Load Balancing (ELB)

  • Google Cloud Platform (GCP): Cloud Load Balancing

  • Microsoft Azure: Azure Load Balancing

选择 CSP 负载均衡器时,需要考虑以下因素:

  • 负载均衡器的功能

  • 负载均衡器的成本

  • 负载均衡器的可用性

外部 IP 和 DNS 的分配

外部 IP:

  • LoadBalancer 类型的 Service 会分配一个外部 IP 地址,该 IP 地址由 CSP 的负载均衡器提供。

  • 外部 IP 地址可以通过 kubectl get service 命令查看。

DNS:

  • Kubernetes 可以自动为 LoadBalancer 类型的 Service 创建 DNS 记录。

  • DNS 记录可以通过 kubectl get service 命令查看。

注意:

  • 创建 LoadBalancer 类型的 Service 之前,需要确保 CSP 的负载均衡器 API 已经配置好。

  • DNS 记录的解析时间可能需要几分钟。

使用案例:在云上创建 LoadBalancer Service

假设 我们有一个名为 my-app 的服务,需要在互联网上公开访问。

步骤:

  • 创建一个 Deployment 来部署 my-app 服务。

apiVersion: apps/v1kind: Deploymentmetadata:  name: my-appspec:  selector:    matchLabels:      app: my-app  template:    metadata:      labels:        app: my-app    spec:      containers:      - name: my-app        image: busybox        command: ["sleep", "3600"]
  • 创建一个 LoadBalancer 类型的 Service 来暴露 my-app 服务。

apiVersion: v1kind: Servicemetadata:  name: my-appspec:  selector:    matchLabels:      app: my-app  ports:  - name: http    protocol: TCP    port: 80    targetPort: 80  type: LoadBalancer
  1. 等待几分钟,让 DNS 记录解析完成。

  2. 可以通过互联网访问 my-app 服务。

curl http://<external-ip>:80

多端口 Service 的创建

创建多端口 Service:

  • 在 Service 的 spec.ports 字段中,指定多个端口。

示例:

apiVersion: v1kind: Servicemetadata:  name: my-appspec:  selector:    matchLabels:      app: my-app  ports:  - name: http    protocol: TCP    port: 80    targetPort: 80  - name: https    protocol: TCP    port: 443    targetPort: 443

访问多端口 Service:

  • 使用端口号区分不同的端口。

示例:

curl http://my-app.svc.cluster.local:80curl https://my-app.svc.cluster.local:443

Service 的标签选择器

Service 的标签选择器用于指定哪些 Pod 可以被 Service 访问。

示例:​​​​​​​

apiVersion: v1kind: Servicemetadata:  name: my-appspec:  selector:    matchLabels:      app: my-app      tier: frontend

标签选择器支持以下操作符:

  • =: 等于

  • !=: 不等于

  • in: 属于

  • notin: 不属于

  • exists: 存在

  • doesnotexist: 不存在

Kubernetes 中的服务发现机制

Kubernetes 中的服务发现机制允许 Pod 通过域名访问其他 Pod。

两种主要的服务发现机制:

  • DNS: 使用 DNS 将服务名称解析为 Pod 的 IP 地址。

  • Endpoints: 使用 Endpoints 对象将服务名称映射到 Pod 的 IP 地址和端口号。

DNS 服务发现

  • Kubernetes 可以自动为 Service 创建 DNS 记录。

  • Pod 可以通过服务名称解析到 Service 的虚拟 IP 地址。

  • 虚拟 IP 地址由 kube-dns 或 CoreDNS 解析。

Endpoints

  • Endpoints 对象存储了一组 Pod 的 IP 地址和端口号。

  • Service 可以引用 Endpoints 对象。

  • Pod 可以通过 Service 名称解析到 Endpoints 对象中的 Pod 的 IP 地址和端口号。

b. 使用服务名称进行 DNS 解析

Pod 可以通过以下方式使用服务名称进行 DNS 解析:

  • 在 Pod 的 spec.containers.args 字段中,使用服务名称作为参数。

  • 在 Pod 的 spec.containers.env 字段中,使用服务名称作为环境变量。

示例:​​​​​​​

apiVersion: v1kind: Podmetadata:  name: my-appspec:  containers:  - name: my-app    image: busybox    command: ["curl", "http://my-app.svc.cluster.local:80"]

DNS 记录的自动创建

Kubernetes 可以自动为 Service 创建 DNS 记录:

  • 使用 kube-dns 或 CoreDNS 作为 DNS 服务器。

  • 在 Service 的 spec.externalName 字段中,指定一个外部域名。

示例:​​​​​​​

apiVersion: v1kind: Servicemetadata:  name: my-appspec:  selector:    matchLabels:      app: my-app  ports:  - name: http    protocol: TCP    port: 80    targetPort: 80  externalName: www.example.com

使用 Prometheus 监控 Service

Prometheus 是一个开源的监控系统,可以用于监控 Kubernetes 中的服务。

使用 Prometheus 监控 Service 的步骤:

  1. 部署 Prometheus 和 Grafana。

  2. 在 Service 的 spec.annotations 字段中,添加 Prometheus 采集指标的配置。

  3. 在 Grafana 中创建仪表板来展示监控指标。

示例:

1. 部署 Prometheus 和 Grafana:​​​​​​​

# 部署 Prometheuskubectl apply -f https://raw.githubusercontent.com/prometheus/prometheus/master/manifests/prometheus-operator.yaml
# 部署 Grafanakubectl apply -f https://raw.githubusercontent.com/grafana/helm/master/charts/grafana/manifests/grafana.yaml

2. 添加 Prometheus 采集指标的配置:​​​​​​​

apiVersion: v1kind: Servicemetadata:  name: my-appspec:  selector:    matchLabels:      app: my-app  ports:  - name: http    protocol: TCP    port: 80    targetPort: 80  annotations:    prometheus.io/scrape: "true"    prometheus.io/port: "80"

创建 Grafana 仪表板:

  • 登录 Grafana。

  • 点击 "Create" 按钮,创建一个新的仪表板。

  • 选择 "Prometheus" 作为数据源。

  • 添加以下查询语句:

node_cpu_usagenode_memory_usagecontainer_cpu_usagecontainer_memory_usage
  • 点击 "Save" 按钮,保存仪表板。

图片

Kubernetes 提供了多种日志收集和分析工具:

  • Fluentd: 将日志收集到 Elasticsearch、Kibana 等系统中。

  • Elasticsearch: 存储和分析日志。

  • Kibana: 可视化日志。

使用 Fluentd 收集和分析日志的步骤:

  1. 部署 Fluentd。

  2. 在 Fluentd 的配置文件中,指定日志来源和目标。

  3. 在 Kibana 中创建仪表板来展示日志。

示例:

1. 部署 Fluentd:

kubectl apply -f https://raw.githubusercontent.com/fluent/fluentd-kubernetes-daemonset/master/manifests/fluentd-daemonset.yaml

2. 配置 Fluentd:​​​​​​​

# Fluentd 配置文件
<source>  type tail  path /var/log/containers/*.log  pos_file /var/log/fluentd/pos.db</source>
<match kubernetes.**>  @type stdout</match>
<match * >  @type elasticsearch  host elasticsearch  port 9200  index fluentd-kubernetes</match>

创建 Kibana 仪表板:

  • 登录 Kibana。

  • 点击 "Create" 按钮,创建一个新的仪表板。

  • 选择 "Elasticsearch" 作为数据源。

负载均衡算法的选择

Kubernetes 支持以下负载均衡算法:

  • Round Robin: 轮询算法,将流量平均分配到所有 Pod 实例上。

  • Least Connections: 最少连接数算法,将流量分配到连接数最少的 Pod 实例上。

  • IP Hash: IP 哈希算法,根据 Pod 的 IP 地址进行哈希,将流量分配到哈希值相同的 Pod 实例上。

选择负载均衡算法时,需要考虑以下因素:

  • 服务的类型

  • 流量的模式

  • Pod 实例的性能

案例:使用 Round Robin 算法和 Least Connections 算法

场景:

  • HTTP 服务

  • 需要高可用性

配置:​​​​​​​

apiVersion: v1kind: Servicemetadata:  name: my-appspec:  selector:    matchLabels:      app: my-app  ports:  - name: http    protocol: TCP    port: 80    targetPort: 80  type: LoadBalancer  externalIPs:  - <external-ip>  loadBalancerIP: <load-balancer-ip>  sessionAffinity: ClientIP
  • externalIPs 字段用于指定 Service 的外部 IP 地址。

  • loadBalancerIP 字段用于指定 Service 的负载均衡器 IP 地址。

  • sessionAffinity 字段用于指定 Service 的会话亲和性。

案例:使用 Weighted Round Robin 算法

场景:

  • 需要根据 Pod 实例性能进行路由的服务

配置:​​​​​​​

apiVersion: v1kind: Servicemetadata:  name: my-appspec:  selector:    matchLabels:      app: my-app  ports:  - name: http    protocol: TCP    port: 80    targetPort: 80  type: LoadBalancer  externalIPs:  - <external-ip>  loadBalancerIP: <load-balancer-ip>  sessionAffinity: None  externalTrafficPolicy: Local  healthCheckNodePort: 30000  sessionAffinityConfig:    clientIP:      timeoutSeconds: 10800

说明:

  • externalTrafficPolicy 字段用于指定 Service 的外部流量策略。

  • healthCheckNodePort 字段用于指定 Service 的健康检查端口号。

  • sessionAffinityConfig 字段用于配置 Service 的会话亲和性。

调整 Service 的参数和配置

可以调整以下参数和配置来优化服务的性能:

  • replicas: Pod 实例的数量。

  • selector: 选择 Pod 实例的标签。

  • ports: Service 的端口号。

  • externalIPs: Service 的外部 IP 地址。

  • type: Service 的类型。

  • sessionAffinity: 会话亲和性,将来自同一客户端的请求分配到同一个 Pod 实例上。

案例:调整 selector 参数

场景:

  • 需要根据 Pod 实例标签进行路由的服务

配置:​​​​​​​

apiVersion: v1kind: Servicemetadata:  name: my-appspec:  selector:    matchLabels:      app: my-app      tier: frontend  ports:  - name: http    protocol: TCP    port: 80    targetPort: 80  type: LoadBalancer

服务故障排查

常见 Service 故障的诊断方法

1. 检查 Service 的状态:

  • 使用 kubectl get service 命令查看 Service 的状态,确保 Service 处于 Running 状态。

  • 检查 Service 的事件,查看是否有任何错误信息。

2. 检查 Pod 的状态:

  • 使用 kubectl get pods 命令查看 Pod 的状态,确保 Pod 处于 Running 状态。

  • 检查 Pod 的事件,查看是否有任何错误信息。

3. 检查 Endpoints:

  • 使用 kubectl get endpoints 命令查看 Endpoints,确保 Endpoints 包含 Pod 的 IP 地址和端口号。

4. 检查 DNS 解析:

  • 使用 nslookup 命令或 dig 命令查询 Service 的域名,确保解析为 Pod 的 IP 地址。

5. 检查网络连接:

  • 确保 Pod 之间可以相互通信。

  • 确保 Service 可以访问外部服务。

使用 kubectl 命令进行排查

1. 查看 Service 的详细信息:

kubectl describe service <service-name>

2. 查看 Pod 的详细信息:

kubectl describe pod <pod-name>

3. 查看 Endpoints 的详细信息:

kubectl describe endpoints <endpoint-name>

4. 查看 Service 的事件:

kubectl get events -f <service-name>.yaml

5. 查看 Pod 的事件:

kubectl get events -f <pod-name>.yaml

6. 查看网络连接:​​​​​​​

kubectl run -it --rm --restart=Never busybox --image=busybox shping <pod-ip-address>

案例一:Service 无法访问

现象:

  • 使用 kubectl get service 命令查看 Service 的状态,发现 Service 处于 Running 状态。

  • 使用 kubectl get pods 命令查看 Pod 的状态,发现 Pod 处于 Running 状态。

  • 使用 nslookup 命令查询 Service 的域名,发现无法解析为 Pod 的 IP 地址。

诊断:

  • 检查 DNS 配置,确保 DNS 服务器可以解析 Service 的域名。

  • 检查 Pod 的 IP 地址,确保 Pod 的 IP 地址是可用的。

解决方案:

  • 修改 DNS 配置,将 Service 的域名解析为 Pod 的 IP 地址。

案例二:Service 响应延迟高

现象:

  • 使用 kubectl top pod 命令查看 Pod 的资源使用情况,发现 Pod 的 CPU 使用率很高。

诊断:

  • 检查 Pod 的应用程序代码,是否存在性能瓶颈。

  • 检查 Pod 的资源配置,是否需要增加 CPU 或内存资源。

解决方案:

  • 优化应用程序代码,提高性能。

  • 增加 Pod 的 CPU 或内存资源。

通过今天的文章应该已经了解了 Kubernetes Service 的基本概念和使用方法。您可以使用 Service 来管理您的 Pod,并为外部应用提供稳定的访问方式。

后续学习

  • 您还可以阅读以下资源,以了解更多关于 Service 的信息:

    Kubernetes 官方文档 - Service: https://kubernetes.io/docs/concepts/services-networking/service/

关注我,我们一起学习更多知识,带你了解更多职场信息内容.

想要了解更多技术文章请关注公众号“职谷智享”,关注后回复关键字【秒杀】可以领取秒杀系统学习资料

在这里插入图片描述

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值