kubernetes 服务是一种为一组功能相同的 pod 提供单一不变的接入点的资源。当服务存在时,它的 IP 地址和端口不会改变。客户端通过 IP 地址和端口号建立连接,这些连接会被路由到提供该服务的任意一个 pod 上。通过这种方式,客户端不需要知道每个单独的提供服务的 pod 的地址,这样这些 pod 就可以在集群中随时被创建或移除。
创建服务
通过 kubectl expose 快速创建
kubectl expose rc yx-nginx
执行此命令,就是会根据 rc 控制器 yx-nginx 创建一个同名的 service。
通过 yaml 配置文件创建
apiVersion: v1
kind: Service
metadata:
## 服务名称
name: yx-nginx
spec:
ports:
## 服务访问端口
- port: 8000
## 目标 pod 访问端口
targetPort: 80
selector:
## 具有 app=nginx 标签的 pod 都属于该服务
app: nginx
创建了一个名叫 yx-nginx 的服务,它将在端口 8000 接受请求并将连接路由到具有 app=nginx 标签的 pod 的 80 端口上。
kubectl create -f test-nginx-service.yaml
列出命名空间下所有服务资源
kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 3d20h
yx-nginx ClusterIP 10.109.90.148 <none> 8000/TCP 18h
列表显示分配给服务的 IP 地址是 10.109.90.148。因为只是集群的 iP 地址,只能在集群内部可以被访问。
配置服务上的会话亲和性
如果多次请求同一个服务,每次调用执行应该在不同的 pod 上。因为在默认情况下, Kubernetes 采用 RoundRobin 模式对客户端请求进行负载分发。
如果希望特定客户端产生的所有请求每次都指向同一个 pod,可以设置服务的sessionAffinity 属性为ClientIP,默认值为 None。
apiVersion: v1
kind: Service
metadata:
## 服务名称
name: yx-nginx
spec:
sessionAffinity: ClientIP
ports:
## 服务访问端口
- port: 8000
## 目标 pod 访问端口
targetPort: 80
selector:
## 具有 app=nginx 标签的 pod 都属于该服务
app: nginx
同一个服务暴露多个端口
创建的服务可以暴露一个端口,也可以暴露多个端口。比如,你的 pod 监昕两个端口,比如 HTTP 监听 80 端口、 HTTPS 监听 443 端口,可以使用一个服务从端口 80 和 443 转发至 pod 端口 80 和 443。在这种情况下,无须创建两个不同的服务。通过一个集群 IP,使用一个服务就可以将多个端口全部暴露出来。
在创建一个有多个端口的服务的时候,必须给每个端口指定名字。
apiVersion: v1
kind: Service
metadata:
## 服务名称
name: yx-nginx
spec:
ports:
- name: http
port: 80
targetPort: 80
- name: https
port: 443
targetPort: 443
selector:
## 具有 app=nginx 标签的 pod 都属于该服务
app: nginx
标签选择器应用于整个服务,不能对每个端口做单独的配置。如果不同的 pod 有不同的端口映射关系,需要创建两个服务。
使用命名的端口
我们可以在定义 pod 端口的时候给端口命名,然后在服务 spec 中按名称引入端口。
apiVersion: v1
kind: Pod
metadata:
name: test-nginx ##pod名称
spec:
containers: ## pod里运行那些容器
- image: nginx ## 镜像名称
name: test ## 容器名称
ports:
- name: http
containerPort: 80
- name: https
containerPort: 443
apiVersion: v1
kind: Service
metadata:
## 服务名称
name: yx-nginx
spec:
ports:
- name: http
port: 80
targetPort: http
- name: https
port: 443
targetPort: https
selector:
## 具有 app=nginx 标签的 pod 都属于该服务
app: nginx
为什么要采用命名端口的方式?最大的好处就是即使更换端口号也无须更改服务 spec。你的 pod 现在对 http 服务用的是 80,但是假设过段时间你决定将端口更换为 8080 呢?
如果你采用了命名的端口,仅仅需要做的就是改变 spec pod 中的端口号(当然你的端口号的名称没有改变)。在你的 pod 向新端口更新时,根据 pod 收到的连接 (80 端口在旧的 pod 上、 8080 端口在新的 pod 上 ),用户连接将会转发到对应的端口。
连接集群外部的服务
通过 Kubernetes 服务特性暴露外部服务的情况。不要让服务将连接重定向到集群中的 pod,而是让它重定向到外部 IP 和端口。
这样做可以让你充分利用服务负载平衡和服务发现。在集群中运行的客户端 pod 可以像连接到内部服务一样连接到外部服务 。
介绍服务 endpoint
服务并不是和 pod 直接相连的。相反,有一种资源介于两者之间,它就是 Endpoint 资源。
$ kubectl describe svc yx-nginx
Name: yx-nginx
Namespace: default
Labels: <none>
Annotations: <none>
Selector: app=nginx
Type: ClusterIP
IP: 10.108.146.21
Port: <unset> 80/TCP
TargetPort: 80/TCP
Endpoints: 100.108.201.68:80,100.73.43.204:80,100.98.112.72:80
Session Affinity: None
Events: <none>
Endpoint 资源就是暴露一个服务的 IP 地址和端口的列表,Endpoint 资源和其他 Kubernetes 资源一样,所以可以使用 kubectl info 来获取它的基本信息。
$ kubectl get endpoints yx-nginx
NAME ENDPOINTS AGE
yx-nginx 100.73.43.204:80,100.73.43.205:80,100.73.43.206:80 23h
尽管在 spec 服务中定义了 pod 选择器,但在重定向传入连接时不会直接使用它。相反,选择器用于构建 IP 和端口列表,然后存储在 Endpoint 资源中。 当客户端连接到服务时,服务代理选择这些 IP 和端口对中的一个,并将传入连接重定向到在该 位置监昕的服务器。
手动配置服务的 endpoint
服务的 endpoint 与服务解稍后,可以分别手动配置和更新它们。
如果创建了不包含 pod 选择器的服务,Kubernetes 将不会创建 Endpoint 资源(毕竟,缺少选择器,将不会知道服务中包含哪些 pod )。这样就需要创建 Endpoint 资源来指定该服务的 endpoint 列表。
创建没有选择器的服务
apiVersion: v1
kind: Service
metadata:
## 服务名称
name: manual-endponit-service
spec:
ports:
## 服务访问端口
- port: 80
定义一个名为 manual-endponit-service 的服务, 它将接收端口 80 上的传入连接。并没有为服务定义一个 pod 选择器 。
为没有选择器的服务创建 Endpoint 资源
Endpoint 是一个单独的资源并不是服务的一个属性。由于创建的服务中并不包 含选择器,相关的 Endpoints 资源并没有自动创建,所以必须手动创建。
apiVersion: v1
kind: Endpoints
metadata:
## endpoint 的名称必须和服务名称一致
name: manual-endponit-service
subsets:
- addresses:
- ip: 192.168.0.239
ports:
- port: 8090
Endpoint 对象需要与服务具有相同的名称,并包含该服务的目标 IP 地址和端口列表。服务和 Endpoint 资源都发布到服务器后,这样服务就可以像具有 pod 选择器那样的服务正常使用。在服务创建后创建的容器将包含服务的环境变量,并且与其 ip : port 对的所有连接都将在服务端点之间进行负载均衡。
将服务暴露给外部访问
上面只讨论了集群内服务如何被 pod 使用;但是,还需要向外部公开某些服务。例如前端 web 服务器,以便外部客户端可以访问它们。
有几种方式可以在外部访问服务 :
- 将服务的类型设置成 NodePort:每个集群节点都会在节点上打开一个端口,对于 NodePort 服务,每个集群节点在节点本身上打开一个端口,并将在该端口上接收到的流量重定向到基础服务。该服务仅在内部集群 IP 和端口上才可访问,但也可通过所有节点上的专用端口访问。
- 将服务的类型设置成 LoadBalance:NodePort 类型的一种扩展,这使得 服务可以通过一个专用的负载均衡器来访问,这是由 Kubernetes 中正在运行的云基础设施提供的。负载均衡器将流量重定向到跨所有节点的节点端口。 客户端通过负载均衡器的 IP 连接到服务。
- 创建一个 Ingress 资源,这是一个完全不同的机制,通过一个 IP 地址公开多个服务,它运行在 HTTP 层( 网络协议第 7 层)上,因此可以提供比工作在第 4 层的服务更多的功能。
创建 NodePort 类型的服务
apiVersion: v1
kind: Service
metadata:
## 服务名称
name: yx-nginx-nodeport
spec:
type: NodePort
ports:
## 服务访问端口
- port: 8000
## 目标 pod 访问端口
targetPort: 80
## 集群节点端口,通过该端口访问服务,如果不设置,kubernetes 会随机一个端口
nodePort: 30123
selector:
## 具有 app=nginx 标签的 pod 都属于该服务
app: nginx
将类型设置为 NodePort 并指定该服务应该绑定到的所有集群节点的节点端口。指定端口不是强制性的。如果忽略它,Kubernetes 将选择一个随机端口。
创建 LoadBalance 负载均衡器服务
kubernetes 集群通常支持从云基础架构自动提供负载平衡器。所有需要做的就是设置服务的类型为 LoadBadancer 而不是 NodePort。负载均衡器拥有自己独一无二的可公开访问的 IP 地址, 可以通过负载均衡器的 IP 地址访问服务。
如果 kubernetes 在不支持 LoadBadancer 服务的环境中运行,则不会调 配负载平衡器,但该服务仍将表现得像一个 NodePort 服务。这是因为 LoadBadancer 服务是 Node Port 服务的扩展
apiVersion: v1
kind: Service
metadata:
## 服务名称
name: yx-nginx-loadbalancer
spec:
type: LoadBalancer
ports:
## 服务访问端口
- port: 8000
## 目标 pod 访问端口
targetPort: 80
nodePort: 30124
selector:
## 具有 app=nginx 标签的 pod 都属于该服务
app: nginx
了解外部连接的特性
防止不必要的网络跳数
当外部客户端通过节点端口连接到服务时,随机选择的 pod 并不一定在接收连接的同一节点上运行。可能需要额外的网络跳转才能到达 pod,但这种行为并不符合期望。
可以通过将服务配置为仅将外部通信重定向到接收连接的节点上运行的 pod 来阻止此额外跳数。这是通过在服务的 spec 部分中设置 externalTrafficPolicy 字段来完成:
spec:
externalTrafficPolicy: Local
如果服务定义包含此设置,并且通过服务的节点端口打开外部连接,则服务代理将选择本地运行的 pod。如果没有本地 pod 存在,则连接将挂起。因此,需要确保负载平衡器将连接转发给至少具有一个 pod 的节点。
网友评论