44. Kubernetes深入Service-Service端口暴露

释放双眼,带上耳机,听听看~!

Service的地址仅在集群内可以通信,但是我们总需要把我们自己的服务暴露到集群外以供客户端访问,这个时候就需要在集群的边缘添加一层转发机制,来实现集群外部请求流量接入集群的Service资源上。

Kubernetes中的Service共有四种类型:ClusterIP、NodePort、LoadBanlacer和ExternalName。
下面就着重讲解这四种类型的Service。

ClusterIP

通过集群内部IP地址暴露服务,改地址只能够在集群内部访问,无法被集群外部客户端所访问,ClusterIP类型为默认的服务类型。

NodePort

这种类型建立在ClusterIP类型之上,在每个Node节点上的IP和和静态端口暴露服务,因此,它依然会为Service分配集群IP地址,并将地址作为NodePort的路由目标(外部客户端首先会访问Node上的静态端口,然后Node上的静态端口将请求转发至Service的ClusterIP和Port上)。因此,这种类型的Service即可如ClusterIP一样受到集群内部的客户端Pod访问,也可以被集群外部客户端通过 NodeIP:NodePort 访问。

LoadBalancer

这种类型构建在NodePort类型之上,通过云厂商提供的负载均衡器将服务暴露到集群外部,因此LoadBalancer一样具有NodePort和ClusterIP。一个LoadBalancer类型的Service会指向关联至Kubernetes集群外部某个负载均衡设备,该设备通过工作节点之上的NodePort向集群内部发送流量。这种类型的优势在于,能把来自集群外部客户端的请求调度到Node的所有节点或者指定节点的NodePort,而不是依赖于客户端自行决定连接到哪个Node上,从而避免了因客户端指定的节点故障而导致的服务不可用。

ExternalName

这种类型是将Service映射至由ExternalName字段内容指定的主机名来暴露服务,此主机名需要被DNS服务解析至CNAME类型的记录,换言之,此种类型并非定义由Kubernetes集群提供的服务,而是把集群外部的某服务以DNS CNAME记录的方式映射到集群内部,从而让集群内的Pod资源能够访问外部Service的一种实现方式,因此这种类型没有ClusterIP和NodePort,也没有标签选择器用于选择Pod资源,也不会又Endpoints的概念存在。

NodePort类型使用

如果设置type为“NodePort”,在安装部署Kubernetes集群系统时会预留一个端口范围用于NodePort,默认为30000~32767之间的端口。NodePort类型在使用的时候需要使用spec.type属性来指定该类型,Cluster类型由于是默认类型,所以不需要指定。

1.创建NodePort类型资源配置清单

cat NodePort.yaml
apiVersion: v1
kind: Service
metadata:
  name: service-nodeport
spec:
  type: NodePort
  selector:
    type: nodeport
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
    #nodePort: 32345        #这里可以手动指定在Node节点上所监听的端口,但是如果不是为了测试用途,不建议这样做
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deploy
spec:
  replicas: 3
  selector:
    matchLabels:
      type: nodeport
  template:
    metadata:
      labels:
         type: nodeport
    spec:
      containers:
      - name: nginx-proxy
        image: nginx:latest
        ports:
        - containerPort: 80
          name: http

2.创建NodePort类型的Service

kubectl apply -f NodePort.yaml

3.查看资源对象的状态
可以看到如下Service的TYPE已经变为了NodePort类型

kubectl get svc,deploy,pods -o wide
NAME                       TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE    SELECTOR
service/kubernetes         ClusterIP   10.96.0.1       <none>        443/TCP        33d    <none>
service/service-nodeport   NodePort    10.96.239.254   <none>        80:31417/TCP   9m1s   type=nodeport

NAME                           READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS    IMAGES         SELECTOR
deployment.apps/nginx-deploy   3/3     3            3           30s   nginx-proxy   nginx:latest   type=nodeport

NAME                                READY   STATUS    RESTARTS   AGE   IP             NODE         NOMINATED NODE   READINESS GATES
pod/nginx-deploy-84bff99d54-27nkv   1/1     Running   0          30s   10.244.5.140   k8s-node03   <none>           <none>
pod/nginx-deploy-84bff99d54-2kzvg   1/1     Running   0          30s   10.244.2.98    k8s-node02   <none>           <none>
pod/nginx-deploy-84bff99d54-zdf8h   1/1     Running   0          30s   10.244.3.19    k8s-node01   <none>           <none>

4.查看Service的详细信息
如下,NodePort监听TCP的31417端口之上,后端Pod为Endpoints字段

kubectl describe svc service-nodeport
Name:                     service-nodeport
Namespace:                default
Labels:                   <none>
Annotations:              Selector:  type=nodeport
Type:                     NodePort
IP:                       10.96.239.254
Port:                     <unset>  80/TCP
TargetPort:               80/TCP
NodePort:                 <unset>  31417/TCP
Endpoints:                10.244.2.98:80,10.244.3.19:80,10.244.5.140:80
Session Affinity:         None
External Traffic Policy:  Cluster
Events:                   <none>

5.测试访问NodePort类型的Service
从集群外部访问任何Node节点的31417端口

从集群内部访问Service的ClusterIP加Port

6.验证NodePort类型从Node节点接收到请求后将请求调度到Service的ClusterIP:Port

动态查看service的日志,如下

kubectl logs -f svc/service-nodeport

然后打开网页去去访问集群Node的31417端口

kubectl get svc/service-nodeport -o wide
NAME               TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE   SELECTOR
service-nodeport   NodePort   10.96.239.254   <none>        80:31417/TCP   21m   type=nodeport

LoadBalancer类型使用

NodePort类型的Service虽然能够让集群外部访问到,但外部客户端必须要知道NodePort和集群中至少一个节点的IP及端口地址,且选定节点发生故障时,客户端还得自行选择请求访问其它节点,另外集群节点如果是在线下机房使用私有IP的地址VMware等,那么外部的客户端怎么可能访问的到这类私有地址呢?
因此一般还应该在集群之外创建一个具有公网地址的负载均衡器,由它接入外部客户端的请求并调度至集群节点相应的NodePort上。
云计算环境通常提供了一个LBaaS服务,它允许租户动态在自己网络中创建一个负载均衡器设备。那些部署于此环境之上的Kubernetes集群在创建Service资源时可以直接调用此接口按照需要创建出一个软负载均衡器,而且有这种功能的Service资源即为LoadBalancer类型,不过如果Kubernetes部署在逻金属之上,我们也可以手动部署一个负载均衡器(最好有冗余功能),并配置将其请求流量调度至各节点的NodePort之上。

1.LoadBalancer类型的Service配置清单

cat LoadBalancer.yaml
apiVersion: v1
kind: Service
metadata:
  name: loadbalancer-service
spec:
  type: LoadBalancer                        #类型指定为LoadBalancer
  loadBalancerIP: 192.168.31.241            #指定负载均衡器地址(可选)
  selector:
    app: nginx-lb
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
    nodePort: 30808                      #指定Node所监听的端口,在LoadBalancer类型下,个人建议指定
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deploy
spec:
  replicas: 3
  selector:
    matchLabels:
     app: nginx-lb
  template:
    metadata:
      labels:
        app: nginx-lb
    spec:
      containers:
      - name: nginx-proxy
        image: nginx:latest
        ports:
        - containerPort: 80
          name: http

2.创建Service并查看状态

kubectl apply -f LoadBalancer.yaml
kubectl get svc,deploy,pods -o wide
NAME                           TYPE           CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE   SELECTOR
service/kubernetes             ClusterIP      10.96.0.1        <none>        443/TCP        33d   <none>
service/loadbalancer-service   LoadBalancer   10.104.192.216   <pending>     80:30808/TCP   43s   app=nginx-lb

NAME                           READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS    IMAGES         SELECTOR
deployment.apps/nginx-deploy   3/3     3            3           43s   nginx-proxy   nginx:latest   app=nginx-lb

NAME                                READY   STATUS    RESTARTS   AGE   IP             NODE         NOMINATED NODE   READINESS GATES
pod/nginx-deploy-76cf94c6ff-7ghn7   1/1     Running   0          43s   10.244.2.99    k8s-node02   <none>           <none>
pod/nginx-deploy-76cf94c6ff-krpfv   1/1     Running   0          43s   10.244.5.141   k8s-node03   <none>           <none>
pod/nginx-deploy-76cf94c6ff-lznpf   1/1     Running   0          43s   10.244.3.20    k8s-node01   <none>           <none>
kubectl describe svc loadbalancer-service
Name:                     loadbalancer-service
Namespace:                default
Labels:                   <none>
Annotations:              Selector:  app=nginx-lb
Type:                     LoadBalancer
IP:                       10.104.192.216
IP:                       192.168.31.241
Port:                     <unset>  80/TCP
TargetPort:               80/TCP
NodePort:                 <unset>  30808/TCP
Endpoints:                10.244.2.99:80,10.244.3.20:80,10.244.5.141:80
Session Affinity:         None
External Traffic Policy:  Cluster
Events:                   <none>

3.添加均衡器
我这里的负载均衡器就在192.168.31.241上部署一个Nginx来进行对Node上的端口负载均衡进行演示。
192.168.31.241 Nginx配置如下

upstream end-pod {
    server 192.168.31.231:30808 max_fails=6 fail_timeout=60s;
    server 192.168.31.232:30808 max_fails=6 fail_timeout=60s;
    server 192.168.31.233:30808 max_fails=6 fail_timeout=60s;
}

server {
    listen 80;
    server_name localhost;

    location / {
        proxy_pass http://end-pod;
    }
}

4.测试访问
首先动态显示Service的日志,Service也会记录被调度到后端Pod的日志

kubectl logs -f service/loadbalancer-service

打开浏览器访问192.168.31.241负载均衡器的地址

ExternalName类型使用

ExternalName类型的Service用于将外部的服务器发布到集群中来让Pod中的应用程序访问,因此,Service不需要任何标签选择器来关联Pod对象,但必须要使用spec.externalName属性定义一个CNAME记录用于返回外部真正提供服务的主机和别名,而后通过CNAME记录值获取到相关主机的IP地址。

kind: Service
apiVersion: v1
metadata:
  name: my-service
  namespace: default
spec:
  type: ExternalName
  externalName: k8sops.cn

当访问地址 k8sops.cn.default.svc.cluster.local时,集群的 DNS 服务将返回一个值为 k8sops.cn的 CNAME 记录。访问这个服务的工作方式与其它的相同,唯一不同的是重定向发生在 DNS 层,而且不会进行代理或转发。

除了可以直接通过 externalName 指定外部服务的域名之外,我们还可以通过自定义 Endpoints 来创建 Service,前提是 clusterIP=None,名称要和 Service 保持一致,如下所示:

apiVersion: v1
kind: Service
metadata:
  name: etcd-k8s
  namespace: kube-system
  labels:
    k8s-app: etcd
spec:
  type: ClusterIP
  clusterIP: None
  ports:
  - name: port
    port: 2379

---

apiVersion: v1
kind: Endpoints
metadata:
  name: etcd-k8s  # 名称必须和 Service 一致
  namespace: kube-system
  labels:
    k8s-app: etcd
subsets:
- addresses:
  - ip: 10.151.30.57  # Service 将连接重定向到 endpoint
  ports:
  - name: port
    port: 2379   # endpoint 的目标端口

上面这个服务就是将外部的 etcd 服务引入到 Kubernetes 集群中来。

Ops工具

43. Kubernetes深入Service-Service资源创建

2020-6-22 10:27:39

Ops工具

45. Kubernetes深入Service-Service服务发现

2020-6-22 10:32:05

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索