Kubernetes 为Service 创建的CLusterIP 地址是对后端Pod列表的一层抽象,对于集群外部来说并没有意义,但有许多Service 是需要对集群外部提供服务的,Kubernetes提供了多种机制将Service 是暴露出去,供集群外部的客户端访问。这可以通过Service 资源对象的类型字段“type” 进行设置。
目前Service的类型如下:
(1)ClusterIP : Kubernetes 默认会自动设置Service 的 虚拟IP地址,仅可被集群内部的客户端应用访问,当然,用户也可手工指定一个ClusterIP 地址,不过需要确保该IP 在Kubernetes集群设置的ClusterIP 地址范围内(通过kube-apiserver服务的启动参数–service-cluster-ip-range设置),并且没有被其他Service 使用。
(2)NodePort: 将Service 的端口号映射到每个Node的一个端口号上,这样集群中的任意Node 都可以作为Service 的访问入口地址,即NodeIP:NodePort。
(3)LoadBalancer: 将Service 映射到一个已存在的负载均衡的IP 地址上,通常在公有云环境中使用。
(4)ExternalName: 将Service 映射为一个外部域名地址,通过externalName 字段进行设置。
1. NodePort类型
下面的例子设置Service的类型为NodePort,并且设置具体nodePort端口号为30002:
# webapp-svc-nodeport.yaml
apiVersion: v1
kind: Service
metadata:
name: webapp
spec:
type: NodePort
ports:
- port: 8080
targetPort: 8080
nodePort: 8081 -> 30002 # 这里我报错了,如下
selector:
app: webapp
创建:
[root@k8s-master ~]# kubectl create -f webapp-svc-nodeport.yaml
The Service "webapp" is invalid: spec.ports[0].nodePort: Invalid value: 8081: provided port is not in the valid range. The range of valid ports is 30000-32767
这是什么错误呢,是因为端口号受限了。
解决的办法:
#编辑 kube-apiserver.yaml文件
vim /etc/kubernetes/manifests/kube-apiserver.yaml
#找到 --service-cluster-ip-range 这一行,在这一行的下一行增加 如下内容
- --service-node-port-range=1-65535
#最后 重启 kubelet
systemctl daemon-reload
systemctl restart kubelet
这里说明一下,我换了一个端口号,将8081 改成30002
[root@k8s-master ~]# kubectl create -f webapp-svc-nodeport.yaml
service/webapp created
r然后就可以通过任意一个node 的IP 地址和NodePort. 30002 端口号访问服务:
[root@k8s-master ~]# curl 172.16.185.161:30002
<!DOCTYPE html>
<html lang="en">
.....
[root@k8s-node-1 ~]# curl 172.16.185.162:30002
<!DOCTYPE html>
<html lang="en">
.....
[root@k8s-node-2 ~]# curl 172.16.185.163:30002
<!DOCTYPE html>
<html lang="en">
.....
在默认情况下,Node的kube-proxy 会在全部网卡(0.0.0.0)上绑定NodePort 端口号。
在很多数据中心环境中,一台主机会配置多块网卡,作用各不相同(例如存在业务网卡和管理网卡等)。从Kubernetes 1.10 版本开始,kube-proxy 可以通过设置特定的IP 地址将NodePort 绑定到特定的网卡上,而无须绑定再全部网卡上,其设置方式为配置启动参数,“–nodeport-addresses”,指定需要绑定的网卡IP地址,多个地址之间使用逗号分隔。例如仅在10.0.0.0和192.168.18.0 对应的网卡上绑定NodePort 端口号,对其他IP 地址对应的网卡不会进行绑定,配置如下:
--nodeport-addresses=10.0.0.0/8,192.168.18.0/24
另外,如果用户在Service 定义中不设置具体的nodePort 端口号,则Kubernetes 会自动分配一个NodePort 范围内的可用端口号。
2. LoadBalancer类型
通常在公有云环境中设置Service 的类型为“LoadBalancer” ,可以将Service 映射到公有云提供的某个负载均衡器的IP地址,客户端通过负载均衡器的IP 和 Servcie 的端口号就可以访问到具体的服务,无须再通过kube-proxy提供的负载均衡机制进行流量转发。公有云提供的LoadBalancer 可以直接将流量转发到后端Pod 上,而负载分发机制依赖于公有云服务商的具体实现。
下面的例子设置Service 的类型为LoadBalancer:
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
type: LoadBalancer
selector:
app: MyApp
ports:
- ptotocol: TCP
port: 80
targetPort: 9376
clusterIP: 10.1.10.125
[root@k8s-master ~]# kubectl create -f loadBalancer.yaml
service/my-service created
[root@k8s-master ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
my-service LoadBalancer 10.1.10.125 <pending> 80:30357/TCP 10m
可以看到的是状态一直都是 pending。
我们先查看详情有没有报错:
[root@k8s-master ~]# kubectl describe svc my-service
Name: my-service
Namespace: default
Labels: <none>
Annotations: <none>
Selector: app=MyApp
Type: LoadBalancer
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.1.10.125
IPs: 10.1.10.125
Port: <unset> 80/TCP
TargetPort: 9376/TCP
NodePort: <unset> 30357/TCP
Endpoints: <none>
Session Affinity: None
External Traffic Policy: Cluster
Events: <none>
问题原因:
查看了官方文档,自己搭建的k8s集群 (公有云环境除外),是没有LB能力的。
3.ExternalName 类型
ExternalName类型的服务用于将集群外的服务定义为Kubernetes 的集群的Service,并且通过externalName 字段指定外部服务的地址,可以使用域名或IP 格式,集群内的客户端应用通过访问这个Service 就能访问外部服务了。这种类型Service 没有后端Pod,所以无须设置Label Selector ,例如:
apiVersion: v1
kind: Service
metadata:
name: my-service
namespace: prod
spec:
type: ExternalName
externalName: my.database.example.com
在本例中设置的服务名为my-service,所在namspace 为prod ,客户端访问服务地址my-service.prod.svc.cluster.local时,系统将自动指向外部域名my.database.example.com。