本文转载自Rancher Labs

在 Kubernetes 中,Service(服务)始终用于将网络访问流量转发到一个或一组 Pod。服务会根据标签选择对应的 Pod;当为该服务发起网络请求时,它会在集群内找到所有与 Service selector 相匹配的 Pod,从中选择一个,并将请求转发过去。
Kubernetes 服务vs Deployment
在 K8S 中,我们应该如何区分 Deployment 和 Service?
Deployment 主要负责确保一组 Pod 在集群中持续运行
Service 主要负责为一组 Pod 提供稳定的网络访问能力
在 K8S 集群中,理论上我们可以只使用 Deployment,而不创建 Service,这样同样能够让多个相同的 Pod 保持运行。同时,Deployment 的副本数量可以灵活扩缩容,既能增加也能减少,Pod 也可以被复制创建。不过在 Kubernetes 里,虽然单个 Pod 可以通过网络被直接访问,但由于 Pod 可能会被重建、替换或调度到其他节点,持续跟踪这些 Pod 并不容易。
实际上,我们也可以只使用某一种 Service 类型,而不依赖 Deployment。这样做时,通常只会面向已有的单个 Pod 提供访问,而不会像 Deployment 那样统一管理和创建多个 Pod。不过,更常见也更推荐的方式是:让 Service 根据分配给 Pod 的标签进行筛选,再把网络请求准确地路由到匹配的 Pod 上。
我们如何发现 Kubernetes 服务?
在 Kubernetes 中,服务发现通常有两种方式:
DNS 类型。集群中会添加 DNS Server,用于监听 Kubernetes API,并为每个新建服务创建 DNS record set。当整个集群启用 DNS 后,所有 Pod 通常都可以自动解析服务名称。
ENV 变量。在这种服务发现方式中,当一个 Pod 运行在节点上时,kubelet 会为每个 active 服务注入对应的环境变量。
ClusterIP、NodePort 和 LoadBalancer 是什么?
Service 规范中的 type 属性决定了服务如何对外暴露。常见类型包括 ClusterIP、NodePort 和 LoadBalancer。
ClusterIP—默认类型。该服务只能在 Kubernetes 集群内部访问。NodePort—该类型使服务可以通过集群中每个节点上的固定端口进行访问。LoadBalancer—服务可通过云厂商提供的负载均衡器能力从集群外部访问。阿里云、AWS、Azure 等平台都支持这种方式。
如何创建一个服务
借助 Deployment kind,并通过一个 “Hello World” 应用示例,可以帮助你更直观地理解如何在 Kubernetes 中创建服务。
整体操作流程是:当我们确认应用已经成功部署并处于运行状态后,再创建一个 Service(ClusterIP 类型)来访问 Kubernetes 中的应用程序。
现在,让我们先创建一个正在运行的 Deployment。
“kubectl run hello-world –replicas=3 –labels=”run=load-balancer-example” –image=gcr.io/google-samples/node-hello:1.0 –port=8080”.这里,这条命令会在 Kubernetes 中创建一个包含三个应用副本的 Deployment。
接下来,
run "kubectl get deployment hello-world" so see that the deployment is running.
Now we can check the replicaset and pods that the deployment created.
$ kubectl get deployments hello-world
NAME DESIRED CURRENT UP-TO-DATE A VAILABLE AGE
hello-world 3 3 3 3 76s应用程序现在已经运行。如果你想访问这个新创建的应用,我们需要创建一个 ClusterIP 类型的服务:
创建服务对应的 YAML manifest 并应用,或
使用
kubectl expose命令,这通常是更简单的选择,因为它无需手动编写 YAML 文件即可快速创建一个 Service。
$ kubectl expose deployment hello-world --type=ClusterIP --name=example-service
service "example-service" exposed这里,我们创建了一个名为 example-service、类型为 ClusterIP 的 Kubernetes 服务。
接下来,我们就可以访问应用程序了:
run “kubectl get service example-service” to get our port number.然后,我们需要执行port-forward命令。由于当前服务类型是 ClusterIP,只能在集群内部访问,因此必须通过端口转发,将集群中的服务端口映射到本地端口,才能从本地访问应用。
当然,我们也可以使用其他服务类型,例如 LoadBalancer。这样会在 AWS 或 GCP 中创建一个负载均衡器(LB),之后便可以通过该 LB 分配的 DNS 地址和端口号从外部访问应用程序。
$ kubectl get service example-service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
example-service ClusterIP 100.20.167.76 8080/TCP 1h
$ kubectl port-forward service/example-service 8080:8080
Forwarding from 127.0.0.1:8080 -> 8080 现在,我们可以在工作站浏览器中打开 https://localhost:8080,并且应该会看到:
Hello Kubernetes!Kubernetes 服务 NodePort YAML 示例
下面这个 YAML 示例创建了一个可接收外部网络请求的 Service。在这里,我们指定了带有具体值的 NodePort,因此该服务会映射到集群中每个节点的对应端口上。

下面是一个 YAML 示例,它展示了如何在 Kubernetes 中使用 NodePort 服务类型。
kind: Service
apiVersion: v1
metadata:
name: hostname-service
spec:
# Expose the service on a static port on each node
# so that we can access the service from outside the cluster
type: NodePort
# When the node receives a request on the static port (30163)
# "select pods with the label 'app' set to 'echo-hostname'"
# and forward the request to one of them
selector:
app: echo-hostname
ports:
# Three types of ports for a service
# nodePort - a static port assigned on each the node
# port - port exposed internally in the cluster
# targetPort - the container port to send requests to
- nodePort: 30163
port: 8080
targetPort: 80