一、什么是 Kubernetes 中的服务?
在 Kubernetes 环境中,你可以有数百个(如果不是数千个)短暂的 pod。无论是因为节点被缩减、Pod 副本被缩减,还是 Pod 被重新调度到新节点,Pod 的 IP 地址都无法保证。Pod IP 地址是在调度到特定节点之后和引导之前分配的。
鉴于我们处于云原生环境中,我们希望能够水平扩展 Pod。因此,跟踪我们所有应用程序的所有IP地址将非常困难。Kubernetes 有一种资源类型,可以解决不断变化的 pod IP 问题,称为服务。Kubernetes 服务允许您创建单个常量 IP 地址,其中包含一组包含相同服务的 Pod 的 IP 地址。这非常有用,因为服务 IP 保持静态,而 Pod IP 可以不断更改。您永远不必担心没有正确的IP地址。
二、服务如何运作?
服务如何工作?如何配置?
让我们首先创建一个包含三个 Nginx pod 实例的部署。
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nginx
name: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
spec:
containers:
- image: nginx
name: nginx
应用部署清单后,我们可以看到有三个 nginx 实例与 IP 一起运行。另外,请注意我们为这些 Pod 分配的标签。这对于服务如何监视这些 Pod 至关重要。10.244.242.66, 10.244.242.67, 10.244.230,199
app=nginx
$ kubectl get pods -owide --show-labels
NAME READY STATUS RESTARTS AGE IP NODE LABELS
nginx-8f458dc5b-6vcxt 1/1 Running 0 2m27s 10.244.242.66 nodepool-a-95e9c8e86208 app=nginx,pod-template-hash=8f458dc5b
nginx-8f458dc5b-ktvtf 1/1 Running 0 2m27s 10.244.242.67 nodepool-a-95e9c8e86208 app=nginx,pod-template-hash=8f458dc5b
nginx-8f458dc5b-mlkwd 1/1 Running 0 2m27s 10.244.230.199 nodepool-a-11aa1dc199fa app=nginx,pod-template-hash=8f458dc5b
现在,让我们定义我们的服务清单,下面定义服务清单,其中包含所定义内容的细分。
apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
app: nginx
spec:
selector:
app: nginx
type: ClusterIP
ports:
- name: 80-80
port: 80
protocol: TCP
targetPort: 80
当我们开始分解这个清单时,我们注意到这种清单是。接下来,元数据部分应该很熟悉,因为它与其他 Kubernetes 资源上的元数据字段相同。规范部分定义了我们的服务将如何以及与什么交互。Service
菲尔德。在此字段中,您可以定义希望此服务监视的容器。这是通过标签匹配完成的。您会注意到这有一个定义。如果您还记得,这些是我们在部署清单中为 Pod 定义的标签。通过此选择器定义,我们声明任何带有标签的 Pod 都将成为此服务的一部分。selector
selector
app: nginx
app=nginx
接下来,我们有字段。这定义了我们希望这是什么样的服务。稍后我们将更深入地介绍服务类型,但我们现在刚刚将其定义为 a。type
ClusterIP
最后,我们有领域。在这里,我们定义流量流经服务的方式和位置。请注意,此字段包含一个数组,以便您可以定义多个条目。ports
让我们分解端口中的每个字段:
- 名称:可以为给定端口条目分配特定名称。
- 端口:这是服务将侦听的端口。
- 目标端口:这是服务将请求转发到的端口。这应该与 Pod 正在侦听的端口匹配。
- 协议:您希望服务侦听并与之交互的特定协议。
现在,我们已经基本了解了服务清单的功能以及它如何与 Pod 交互,接下来我们将部署清单并检查服务。
$ k get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 90m
nginx ClusterIP 10.108.176.62 <none> 80/TCP 18m
$ kubectl describe svc nginx
Name: nginx
Namespace: default
Labels: app=nginx
Annotations: <none>
Selector: app=nginx
Type: ClusterIP
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.108.176.62
IPs: 10.108.176.62
Port: 80-80 80/TCP
TargetPort: 80/TCP
Endpoints: 10.244.230.199:80,10.244.242.66:80,10.244.242.67:80
Session Affinity: None
Events: <none>
描述命令中的所有内容都应与清单定义保持一致,但两个字段和除外。IP
Endpoints
该字段定义服务的 IP 地址。这是可用于访问服务后面的 Pod 的静态 IP。IP
该字段定义当前分配给此服务的容器 IP。您注意到这些 IP 来自我们的 Nginx 部署。Endpoints
在我们继续讨论其他服务类型之前,让我们展示如何缩减 Nginx 部署,并查看服务将如何处理此更改。
$ kubectl scale deployment/nginx --replicas 1
deployment.apps/nginx scaled
$ kubectl get pods -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-8f458dc5b-mlkwd 1/1 Running 0 43m 10.244.230.199 nodepool-a-11aa1dc199fa <none> <none>
$ kubectl describe service nginx | grep Endpoints
Endpoints: 10.244.230.199:80
$ kubectl scale deployment/nginx --replicas 5
deployment.apps/nginx scaled
$ kubectl get pods -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-8f458dc5b-9pmhb 1/1 Running 0 108s 10.244.242.69 nodepool-a-95e9c8e86208 <none> <none>
nginx-8f458dc5b-mlkwd 1/1 Running 0 47m 10.244.230.199 nodepool-a-11aa1dc199fa <none> <none>
nginx-8f458dc5b-r2pcp 1/1 Running 0 108s 10.244.242.70 nodepool-a-95e9c8e86208 <none> <none>
nginx-8f458dc5b-vgwv6 1/1 Running 0 108s 10.244.242.68 nodepool-a-95e9c8e86208 <none> <none>
nginx-8f458dc5b-x6thl 1/1 Running 0 108s 10.244.230.200 nodepool-a-11aa1dc199fa <none> <none>
$ kubectl describe service nginx | grep Endpoints
Endpoints: 10.244.230.199:80,10.244.230.200:80,10.244.242.68:80 + 2 more...
您可以看到,向上和向下扩展 Pod 会立即反映在服务中,允许单个静态 IP 访问 Pod。
三、服务类型
在服务资源中,有三种不同的类型。它们如下:
- 集群IP
- 节点端口
- 负载均衡器
这些都有自己的行为和特定的用例,因此知道何时使用每个非常重要。在以下部分中,我们将对其中的每一个进行更深入的探讨。
3.1、集群 IP
集群 IP 是最基本的“服务类型。它将创建一个静态 IP 地址,该地址位于与 Pod IP 范围不同的子网上,并通过标签选择器监控一组 Pod。
ClusterIP 允许 Pod 之间轻松通信,因为 Pod 可以向静态 IP 发送请求,也可以使用 Kubernetes DNS 发送请求。在我们部署的前面的示例中,DNS 应该是。使用 ClusterIP 存在一些限制。最大的问题是没有办法向外界公开这项服务。这是服务类型应该使用的地方。{service-name}.{namespace}
nginx.default
nodePort
loadBalancer
3.2、节点端口
该服务建立在类型之上。它通过在工作节点上打开端口来转发流量,从而向外界公开。这意味着,如果您有 50 个工作器节点,则每个工作器节点都将侦听分配的端口,即使 Pod 不存在于该工作节点上也是如此。NodePort
ClusterIP
ClusterIP
要创建服务,唯一的区别是定义NodePort
Type
NodePort
kind: Service
metadata:
labels:
app: nginx
name: nginx
spec:
ports:
- name: 80-80
port: 80
protocol: TCP
targetPort: 80
# nodePort: 30001
selector:
app: nginx
type: NodePort
您可能会注意到它被注释掉了。这是因为如果您不定义该部分,Kubernetes 将自动从该范围内分配一个随机端口。如果要定义特定端口,则必须从此范围完成。nodePort
nodePort
ports
30000-32767
部署 NodePort 服务清单并让我们对其进行审核。
$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 135m
nginx NodePort 10.98.246.253 <none> 80:30828/TCP 5s
$ kubectl describe svc nginx
Name: nginx
Namespace: default
Labels: app=nginx
Annotations: <none>
Selector: app=nginx
Type: NodePort
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.98.246.253
IPs: 10.98.246.253
Port: 80-80 80/TCP
TargetPort: 80/TCP
NodePort: 80-80 30828/TCP
Endpoints: 10.244.230.199:80,10.244.230.200:80,10.244.242.68:80 + 2 more...
Session Affinity: None
External Traffic Policy: Cluster
Events: <none>
在这里,我们看到一个名为值的新字段。这是分配给此服务的端口和协议。现在,如果我们要使用该端口向任何工作节点 IP 地址发送请求,则请求将发送到服务,然后服务将发送到我们的 Pod。NodePort
30828/TCP
$ kubectl get nodes -owide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
nodepool-a-11aa1dc199fa Ready <none> 140m v1.24.4 10.1.96.5 45.77.152.173 Debian GNU/Linux 10 (buster) 4.19.0-22-amd64 containerd://1.6.8
nodepool-a-95e9c8e86208 Ready <none> 140m v1.24.4 10.1.96.4 140.82.44.105 Debian GNU/Linux 10 (buster) 4.19.0-22-amd64 containerd://1.6.8
$ curl 140.82.44.105:30828
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
$ curl 45.77.152.173:30828
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
虽然这是向外界公开我们的服务的有用方法,但它不能很好地扩展。在高度自动扩展的 Kubernetes 集群中,工作节点可能是短暂的,因为它们可能不断上下旋转。这使我们陷入了与pod类似的问题,我们可以在其中找出IP是什么,但这并不意味着它们将永远存在。如果您的服务需要静态外部 IP 地址,则服务类型将满足该需求。LoadBalancer
3.3、负载均衡器
与 how’s 构建在 ‘, the’s 服务构建在 –使用服务时,每个工作节点继续具有分配给特定服务的唯一端口。但是,现在部署并配置了 L4 以路由到特定的工作器节点和端口。高级请求流如下所示:将请求发送到负载均衡器,负载均衡器转发到特定节点端口上的工作节点,然后传递到特定服务,最后发送到 Pod。NodePort
ClusterIP
LoadBalancer
NodePort
LoadBalancer
如果需要,配置服务会更加复杂。一个非常简单的配置可以如下所示,只是将字段更改为。LoadBalancer
type
LoadBalancer
apiVersion: v1
kind: Service
metadata:
labels:
app: nginx
name: nginx
spec:
ports:
- name: 80-80
port: 80
protocol: TCP
targetPort: 80
selector:
app: nginx
type: LoadBalancer
例如,如果您希望更改负载均衡器以强制 SSL 重定向、配置防火墙规则、使用 HTTPS 而不是 HTTP 或使用不同的平衡算法,则需要在您的服务上定义。Annotations
下面是一个这样的例子。LoadBalancer
apiVersion: v1
kind: Service
metadata:
annotations:
service.beta.kubernetes.io/vultr-loadbalancer-protocol: "http"
service.beta.kubernetes.io/vultr-loadbalancer-https-ports: "443"
# You will need to have created a TLS Secret and pass in the name as the value
service.beta.kubernetes.io/vultr-loadbalancer-ssl: "ssl-secret"
service.beta.kubernetes.io/vultr-loadbalancer-algorithm: "least_connections"
service.beta.kubernetes.io/vultr-loadbalancer-ssl-redirect: "true"
service.beta.kubernetes.io/vultr-loadbalancer-firewall-rules: "0.0.0.0/80;0.0.0.0/443"
labels:
app: nginx
name: nginx
spec:
ports:
- port: 80
name: "http"
- port: 443
name: "https"
selector:
app: nginx
type: LoadBalancer
有关更多详细信息,请参阅可与 Vultr 负载均衡器一起使用的所有可用注释列表。
当您第一次部署您的服务时,您将看到该部分是LoadBalancer
EXTERNAL-IP
pending
$ portfolio [talk-postman] âš¡ k get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 150m
nginx LoadBalancer 10.103.252.120 <pending> 80:30092/TCP 4s
$ portfolio [talk-postman] âš¡ kubectl describe service nginx
Name: nginx
Namespace: default
Labels: app=nginx
Annotations: <none>
Selector: app=nginx
Type: LoadBalancer
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.103.252.120
IPs: 10.103.252.120
Port: 80-80 80/TCP
TargetPort: 80/TCP
NodePort: 80-80 30092/TCP
Endpoints: 10.244.230.199:80,10.244.230.200:80,10.244.242.68:80 + 2 more...
Session Affinity: None
External Traffic Policy: Cluster
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal EnsuringLoadBalancer 8s (x4 over 44s) service-controller Ensuring load balancer
Warning SyncLoadBalancerFailed 8s (x4 over 44s) service-controller Error syncing load balancer: failed to ensure load balancer: load-balancer is not yet active - current status: pending
您注意到,这里 Kubernetes 已经部署了一个 Vultr 负载均衡器,并且正在进行持续通信,以检查负载均衡器是否已被配置并分配了 IP。
一旦 Vultr 负载均衡器已配置并准备好用于流量,您将在字段中看到分配的 IP 地址,并且 LB 已得到保证”。这意味着 Kubernetes 现在可以控制相应地监控和更新负载均衡器。另外,请注意,分配了一个唯一的节点端口。EXTERNAL-IP
$ portfolio [talk-postman] âš¡ k get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 154m
nginx LoadBalancer 10.103.252.120 45.63.15.140 80:30092/TCP 4m9s
$ kubectl describe service nginx
Name: nginx
Namespace: default
Labels: app=nginx
Annotations: <none>
Selector: app=nginx
Type: LoadBalancer
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.103.252.120
IPs: 10.103.252.120
LoadBalancer Ingress: 45.63.15.140
Port: 80-80 80/TCP
TargetPort: 80/TCP
NodePort: 80-80 30092/TCP
Endpoints: 10.244.230.199:80,10.244.230.200:80,10.244.242.68:80 + 2 more...
Session Affinity: None
External Traffic Policy: Cluster
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning SyncLoadBalancerFailed 2m21s (x5 over 3m37s) service-controller Error syncing load balancer: failed to ensure load balancer: load-balancer is not yet active - current status: pending
Normal EnsuringLoadBalancer 61s (x6 over 3m37s) service-controller Ensuring load balancer
Normal EnsuredLoadBalancer 60s service-controller Ensured load balancer
要验证我们的 Vultr 负载均衡器是否正常工作,我们可以向负载均衡器公共 IP 地址发送请求。EXTERNAL-IP
$ curl 45.63.15.140
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
您可以将服务类型视为一个绝佳的解决方案。但是,它们有一个缺点;不能定义任何类型的 URL 路径,这不允许灵活性或将其路由到多个服务。该服务绑定到单个服务,因此如果要从群集中公开另一个应用程序,则需要部署另一个 Vultr 负载均衡器,如果您有多个应用程序,这可能会迅速增加成本。LoadBalancer
LoadBalancer
这个问题的解决方案不是另一种服务类型,而是调用不同的 Kubernetes 资源。ingress
3.4、入口
Anresource是一种更灵活的方法来定义外部世界要访问的服务。这里最大的卖点之一是您可以定义单个入口资源,并将此路由路由到您定义的子域、端口或 URL 路径下的所有服务。它们还提供了大量其他功能,例如速率限制、身份验证、自动 TLS、加权路由等等。所有这些都可以使用单个负载均衡器完成,因为 theresource 与服务类型一起工作,唯一的区别是部署负载均衡器充当代理将所有流量发送到 theresource,它充当集群中的 L7 负载均衡器。ingress
Ingress
LoadBalancer
Ingress
这里唯一需要注意的是,Kubernetes没有内部入口控制器。那里有各种入口控制器,都具有不同类型的功能。最终,这取决于您的需求和愿望,然后再决定安装哪个入口控制器。有关配置指南,请参阅入口控制器的文档。
一些更流行的入口控制器是:
- 使者入口
- 大使边缘堆栈
- 入口 nginx
四、总结
虽然这篇文章可能会让你很好地理解不同类型的 Kubernetes 服务和入口控制器,但这只是划伤了服务。这些服务还有更多配置选项和一些免费功能,例如网络策略。请查看下面列出的一些链接以获取更多信息。