10-K8S Basic-Service资源管理(服务发现-四层调度器)

一、Service的基础概念

1.1、为什么需要Service资源

  • Pod对象的动态性会给客户端带来困扰
    • Pod资源对象存在声明周期且不可重现,必要时仅能创建一个新的替代者
    • Pod对象在其控制器进行应用规模伸缩时,同一应用程序的Pod对象会增加或减少
  • Service资源为动态管理的Pod对象添加一个有着股东访问入口的抽象层
    • Service通过标签选择器关联至拥有相关标签的Pod对象
    • 客户端向Service进行请求,而非目标Pod对象

  • 运行在Pod中的应用是向客户端提供服务的守护进程,比如,Nginx、Tomcat、Etcd等。他们都是受控于控制器的资源对象,存在生命周期,我们知道Pod资源对象在资源或非自愿终端后,只能被重构的Pod对象所替代,属于可不再生类组件,而在动态和弹性的管理模式下,Service为该类Pod对象提供了一个固定、统一的访问接口和负载均衡能力。
  • 其实就是说Pod存在生命周期,有销毁,有重建,无法提供一个固定的访问接口给客户端。并且为了同类的Pod都能够实现工作负载的价值,由此Service资源出现了,可以为一类Pod资源对象提供一个固定的访问接口和负载均衡,类似于阿里云的负载均衡或者是LVS的功能。
  • 但是要知道的是,Service和Pod对象的IP地址,一个是虚拟地址,一个是Pod IP地址,都仅仅在集群内部可以进行访问,无法接入集群外部流量,而为了解决该类问题的办法可以是单一的节点上做端口暴漏(hostPort)以及让Pod资源共享工作节点的网络名称空间(hostNetwork)以外,还可以使用NodePort或者是LoadBalacce类型的Service资源,或者是有七层负载均衡能力的Ingress资源。
  • Service是Kunbernetes的核心资源类型之一,Service资源基于标签选择器将一组Pod定义成一个逻辑组合,并通过自己的IP地址和端口代理请求到组内的Pod对象,如图所示,它向客户端隐藏了真实的处理客户请求的Pod资源,使得从客户端上看,就像是由Service直接处理并响应一样,类似于负载均衡器。

image

  • Service对象的IP地址也成为Cluster IP,它位于为Kubernetes集群配置指定专用的IP范围之外,是一种虚拟的IP地址,它在Service对象创建之后保持不变,并且能够被同一集群中的Pod资源所访问,Service端口用于接受客户端请求,并将请求转发至后端的Pod应用的响应端口,这样的代理机制,也称为端口代理,它是基于TCP /IP协议栈的传输层。

1.2、Service的实现模型

  • Node
    • Kube-proxy → Kube-apiserver ← Server object
    • 把Server的定义转换为当前节点上相应的iptables或者ipvs规则
  • Kube-proxy把请求代理至响应端点的方式有三种:userspace(用户空间-基本废除)、iptables、ipvs
    • 在Kubernetes集群中,每一个Node运行一个Kube-proxy进程。kube-proxy负责为Service实现了一种VIP(虚IP)的形式,而不是ExternalName的形式,在Kubernetes v1.0版本,代理完全在userspace,在Kubernetes v1.1版本,新增加了iptables代理,并不是默认的运行模式。从Kubernetes v1.2起,默认的就是iptables代理,在Kubernetesd1.18.0-beta.0中,添加了ipvs代理,在 Kubernetes v1.0 版本,Service 是 “4层”(TCP/UDP over IP)概念。 在 Kubernetes v1.1 版本,新增了 Ingress API(beta 版),用来表示 “7层”(HTTP)服务。
  • kube-proxy 这个组件始终监视着apiserver中有关service的变动信息,获取任何一个与service资源相关的变动状态,通过watch监视,一旦有service资源相关的变动和创建,kube-proxy都要转换为当前节点上的能够实现资源调度规则(例如:iptables、ipvs)

image

1.2.1、userspace代理模式

  • userspace是指Linux操作系统上的 “用户空间”
  • 对于每一个Service对象,kube-proxy会随机打开一个本地端口,任何到达此代理端口的连接请求都将被通过SNAT转发至当前Service资源对象的后端各Pod对象
    • Kubernetes 1.1及之前版本的默认模型
    • 默认调度算法是round-robin
  • Kube-proxy还会为此类的Service对象创建iptables规则以捕获任何到达的ClusterIP和端口的流量

image

  • 这种模式,当客户端Pod请求内核空间的service iptables后,把请求转到给用户空间监听的kube-proxy 的端口,由kube-proxy来处理后,再由kube-proxy将请求转给内核空间的 service ip,再由service iptalbes根据请求转给各节点中的的service pod。
  • 由此可见这个模式有很大的问题,由客户端请求先进入内核空间的,又进去用户空间访问kube-proxy,由kube-proxy封装完成后再进去内核空间的iptables,再根据iptables的规则分发给各节点的用户空间的pod。这样流量从用户空间进出内核带来的性能损耗是不可接受的。在Kubernetes 1.1版本之前,userspace是默认的代理模型。

1.2.2、iptables代理模式

  • 对于每个Service对象,kube-proxy会创建iptables规则直接捕获到达ClusterIP和Port的流量,并将其重定向至当前Service对象的后端Pod资源
  • 对于每个Endpoints对象,Service资源会将其创建iptables规则并关联至挑选的后端Pod资源对象
  • 相对于用户空间模型来说,iptables模型无须将流量在用户空间和内核空间来回切换,因此也就更为高效和可靠

image

1.2.3、ipvs代理模式

  • Kubernetes自1.9-alpha版本引入了ipvs代理模式,自1.11版本开始成为默认设置。客户端IP请求时到达内核空间时,根据ipvs的规则直接分发到各pod上。kube-proxy会监视Kubernetes Service对象和Endpoints,调用netlink接口以相应地创建ipvs规则并定期与Kubernetes Service对象和Endpoints对象同步ipvs规则,以确保ipvs状态与期望一致。访问服务时,流量将被重定向到其中一个后端Pod。

  • 与iptables类似,ipvs基于netfilter 的 hook 功能,但使用哈希表作为底层数据结构并在内核空间中工作。这意味着ipvs可以更快地重定向流量,并且在同步代理规则时具有更好的性能。此外,ipvs为负载均衡算法提供了更多选项,例如:

    • rr:轮询调度
    • lc:最小连接数
    • dh:目标哈希
    • sh:源哈希
    • sed:最短期望延迟
    • nq:不排队调度
  • 注意: ipvs模式假定在运行kube-proxy之前在节点上都已经安装了IPVS内核模块。当kube-proxy以ipvs代理模式启动时,kube-proxy将验证节点上是否安装了IPVS模块,如果未安装,则kube-proxy将回退到iptables代理模式。

image

  • 如果某个服务后端pod发生变化,标签选择器适应的pod有多一个,适应的信息会立即反映到apiserver上,而kube-proxy一定可以watch到etc中的信息变化,而将它立即转为ipvs或者iptables中的规则,这一切都是动态和实时的,删除一个pod也是同样的原理。如图:

image

1.3、Service类型、资源的定义(Service→ Endpoint → Pod)

  • Service类型:
    • ClusterIP : 仅用于集群内部通讯
    • NodePort : 用于为集群外部访问Service后面Pod提供访问接入端口
    • LoadBalancer : 负载均衡器用于对Service做负载均衡调度(K8s外的资源如Nginx、Haproxy最好为云厂商的LBAAS自动创建负载规则)
    • ExternalName : 集群外部的服务引入到集群内部使用

1.3.1、Service资源创建清单

~]# kubectl explain svc
KIND:     Service
VERSION:  v1
 
DESCRIPTION:
     Service is a named abstraction of software service (for example, mysql)
     consisting of local port (for example 3306) that the proxy listens on, and
     the selector that determines which pods will answer requests sent through
     the proxy.
 
FIELDS:
   apiVersion   <string>
     APIVersion defines the versioned schema of this representation of an
     object. Servers should convert recognized schemas to the latest internal
     value, and may reject unrecognized values. More info:
     https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
 
   kind <string>
     Kind is a string value representing the REST resource this object
     represents. Servers may infer this from the endpoint the client submits
     requests to. Cannot be updated. In CamelCase. More info:
     https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
 
   metadata <Object>
     Standard object's metadata. More info:
     https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata
 
   spec <Object>
     Spec defines the behavior of a service.
     https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status
 
   status   <Object>
     Most recently observed status of the service. Populated by the system.
     Read-only. More info:
     https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status
  • 其中重要的4个字段:
    • apiVersion : v1 核心群组的V1版中
    • kind:
    • metadata:
    • spec:
      • clusterIP : Server集群IP 可以自定义,也可以动态分配
      • ports : Server的哪个端口与后端容器端口关联
        • svc.spec.ports (对象列表)
          • port : service自己的哪个端口和pods中的端口对应
          • targetPort : 后端Pods端口
          • name : 每一个ports都可以有自己的名称
          • protocol : 自定端口类型 TCP或者UDP 默认为TCP
    • selector : Service使用标签选择器,关联到哪些pod资源上
    • type :服务类型

  • Service的类型
    • 对一些应用(如 Frontend)的某些部分,可能希望通过外部(Kubernetes 集群外部)IP 地址暴露 Service。
    • Kubernetes ServiceTypes 允许指定一个需要的类型的 Service,默认是 ClusterIP 类型。
    • Type 的取值以及行为如下:
      • ClusterIP:通过集群的内部 IP 暴露服务,选择该值,服务只能够在集群内部可以访问,这也是默认的 ServiceType。
      • NodePort:通过每个 Node 上的 IP 和静态端口(NodePort)暴露服务。NodePort 服务会路由到 ClusterIP 服务,这个 ClusterIP 服务会自动创建。通过请求 :,可以从集群的外部访问一个 NodePort 服务。
      • LoadBalancer:使用云提供商的负载均衡器,可以向外部暴露服务。外部的负载均衡器可以路由到 NodePort 服务和 ClusterIP 服务。
      • ExternalName:通过返回 CNAME 和它的值,可以将服务映射到 externalName 字段的内容(例如, foo.bar.example.com)。 没有任何类型代理被创建,这只有 Kubernetes 1.7 或更高版本的 kube-dns 才支持。

1.3.2、ClusterIP的Service类型演示(默认类型、如果不使用service固定地址的话,无需添加此字段):仅用于集群内部路由

image

  • ClusterIP: 用于为集群内Pod访问时,提供的固定访问地址,默认是自动分配地址,可使用ClusterIP关键字指定固定IP.
  • Service流量到Pod是有中间层的,Service → endpointed(地址+端口) → pod
  • 默认资源记录 (K8s中资源的全局FQDN格式:) : SVC_NAME.NS.NAME.DOMAIN.LTD. (svc.cluster.local.)
    • Service_NAME.NameSpace_NAME.Domain.LTD
    • Domain.LTD.=svc.cluster.local.     #这是默认k8s集群的域名。

1.3.2.1、博客演示一

[root@k8s-master mainfests]# cat redis-svc.yaml
apiVersion: v1
kind: Service
metadata:
  name: redis
  namespace: default
spec:
  selector:  #标签选择器,必须指定pod资源本身的标签
    app: redis
    role: logstor
  type: ClusterIP  #指定服务类型为ClusterIP
  ports:   #指定端口
  - port: 6379  #暴露给服务的端口
  - targetPort: 6379  #容器的端口
[root@k8s-master mainfests]# kubectl apply -f redis-svc.yaml
service/redis created
[root@k8s-master mainfests]# kubectl get svc
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
kubernetes   ClusterIP   10.96.0.1        <none>        443/TCP    36d
redis        ClusterIP   10.107.238.182   <none>        6379/TCP   1m
 
[root@k8s-master mainfests]# kubectl describe svc redis
Name:              redis
Namespace:         default
Labels:            <none>
Annotations:       kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"redis","namespace":"default"},"spec":{"ports":[{"port":6379,"targetPort":6379}...
Selector:          app=redis,role=logstor
Type:              ClusterIP
IP:                10.107.238.182  #service ip
Port:              <unset>  6379/TCP
TargetPort:        6379/TCP
Endpoints:         10.244.1.16:6379  #此处的ip+端口就是pod的ip+端口
Session Affinity:  None
Events:            <none>
 
[root@k8s-master mainfests]# kubectl get pod redis-5b5d6fbbbd-v82pw -o wide
NAME                     READY     STATUS    RESTARTS   AGE       IP            NODE
redis-5b5d6fbbbd-v82pw   1/1       Running   0          20d       10.244.1.16   k8s-node01
 
 
 
 
从上演示可以总结出:service不会直接到pod,service是直接到endpoint资源,就是地址加端口,再由endpoint再关联到pod。
service只要创建完,就会在dns中添加一个资源记录进行解析,添加完成即可进行解析。资源记录的格式为:SVC_NAME.NS_NAME.DOMAIN.LTD.
 
默认的集群service 的A记录:svc.cluster.local.
redis服务创建的A记录:redis.default.svc.cluster.local.

1.3.2.2、总结演示二

1、Deployment控制器下创建pods
chapter5]# cat myapp-deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-deploy
  namespace: prod
spec:
  replicas: 3
  # Deployment匹配的Pod的标签选择器
  selector:
    matchLabels:
      app: myapp
      rel: stable
  template:
    metadata:
      labels:
        app: myapp
        rel: stable
    spec:
      containers:
      - name: myapp
        image: ikubernetes/myapp:v1
        # 容器暴漏的端口
        ports:       
        - containerPort: 80
          name: http
 
 
2、查看此控制器下的pods
    chapter5]# kubectl get pods -n prod --show-labels
        NAME                     READY   STATUS    RESTARTS   AGE     LABELS
        myapp-56c8d75644-6m5vh   1/1     Running   0          5d20h   app=myapp,pod-template-hash=56c8d75644,rel=stable     #Pods的标签很重要,定义Service时匹配Pods的标签
        myapp-56c8d75644-vzsfk   1/1     Running   0          5d20h   app=myapp,pod-template-hash=56c8d75644,rel=stable
        myapp-56c8d75644-xxj5r   1/1     Running   0          5d20h   app=myapp,pod-template-hash=56c8d75644,rel=stable
 
3、为这三个Pod添加一个service (创建Service资源对象清单)
[root@192-168-1-177 basic]# cat service-scv.yml
#service所属的标准资源api版本定义群组
apiVersion: v1
#定义资源的类型为Service
kind: Service
#定义元数据
metadata:
  #定义service的名称
  name: myapp
  #定义service所属的名称空间需要和myapp——pods在同一名称空间
  namespace: prod
  #定义service的标签,可选项
  #  labels:
  #      app: filebeat
#定义service规格
spec:
  # 如果想手动执行ClusterIP地址可以使用ClusterIP,为了避免其他服务也在使用此地址所以尽量不要手动指定
  # clusterIP: 10.97.97.97
  type: ClusterIP  #指定服务类型为ClusterIP
  #ports字段
  ports:
  #此端口的名称
  - name: http
    #Service地址的哪个端口于后端Pods端口映射
    port: 80
    #后端Pods的哪个端口于Service做映射
    targetPort: 80
  #定义Service的标签选择器(仅支持简单的等值标签选择方式),指定pod资源本身的标签(匹配Pods资源的标签名称加入此Service)
  selector:
    app: myapp
    rel: stable
   
 
4、使用声明式接口创建此Service资源
basic]# kubectl apply -f service-scv.yml
    service/myapp created
 
5、查看创建的Service资源
    basic]# kubectl get svc -n prod
            #Service类型  #动态Service集群的地址   #Service映射到后端Pods的地址为80
    NAME    TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
    myapp   ClusterIP   10.2.86.25   <none>        80/TCP    36s
 
6、模拟请求Service 地址
    basic]# curl 10.2.86.25
        Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>
    basic]# curl 10.2.86.25
        Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>
 
7、查看Service资源对象的详细信息
    basic]# kubectl describe svc myapp -n prod
        Name:              myapp
        Namespace:         prod
        Labels:            <none>
        Annotations:       kubectl.kubernetes.io/last-applied-configuration:
                     {"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"myapp","namespace":"prod"},"spec":{"ports":[{"name":"http","port"...
        Selector:          app=myapp,rel=stable
        Type:              ClusterIP
        IP:                10.2.86.25
        Port:              http  80/TCP
        TargetPort:        80/TCP
        Endpoints:         192.168.1.124:80,192.168.1.128:80,192.168.1.40:80   #后端端点地址及IP,实际上为SVC资源配置中的selector标签选择器匹配到的后端Pods的IP + Port
        Session Affinity:  None
        Events:            <none>
 
8、查看端点信息(创建Service自动创建的endpoints)
    basic]# kubectl get endpoints -n prod
        NAME    ENDPOINTS                                           AGE
        myapp   192.168.1.124:80,192.168.1.128:80,192.168.1.40:80   9m44s
    #详细信息
    basic]# kubectl describe endpoints -n prod
        Name:         myapp
        Namespace:    prod
        Labels:       <none>
        Annotations:  endpoints.kubernetes.io/last-change-trigger-time: 2020-03-03T23:08:46+08:00
        Subsets:
          Addresses:          192.168.1.124,192.168.1.128,192.168.1.40
          NotReadyAddresses:  <none>
          Ports:
            Name  Port  Protocol
            ----  ----  --------
            http  80    TCP
 
        Events:  <none>
 
    #输出yaml格式文件详细信息
    basic]# kubectl get endpoints -o yaml -n prod
        apiVersion: v1
        items:
        - apiVersion: v1
          kind: Endpoints
          metadata:
            annotations:
              endpoints.kubernetes.io/last-change-trigger-time: "2020-03-03T23:08:46+08:00"
            creationTimestamp: "2020-03-03T15:08:46Z"
            name: myapp
            namespace: prod
            resourceVersion: "4274514"
            selfLink: /api/v1/namespaces/prod/endpoints/myapp
            uid: c4e6c164-c9f4-4fab-bb6c-9673a995b289
          subsets:
          - addresses:
            - ip: 192.168.1.124
              nodeName: 192.168.1.141
              targetRef:
                kind: Pod
                name: myapp-56c8d75644-xxj5r
                namespace: prod
                resourceVersion: "2655463"
                uid: 7e483d25-a867-4ca5-a2fc-976de819bb74
            - ip: 192.168.1.128
              nodeName: 192.168.1.51
              targetRef:
                kind: Pod
                name: myapp-56c8d75644-6m5vh
                namespace: prod
                resourceVersion: "2655538"
                uid: 50a266a5-2703-4658-b03d-e519dca427a5
            - ip: 192.168.1.40
              nodeName: 192.168.1.247
              targetRef:
                kind: Pod
                name: myapp-56c8d75644-vzsfk
                namespace: prod
                resourceVersion: "2655466"
                uid: fdff13d3-85ba-439a-9f61-c4a60cc8bc3c
            ports:
            - name: http
              port: 80
              protocol: TCP
        kind: List
        metadata:
          resourceVersion: ""
          selfLink: ""
 
 
 
 
# 测试将Deployment控制器下的Pods副本数量调高或者减少,也会实时的反映在Service的Endpoints,Service会自动为自己的标签选择器匹配到的Pods创建端点
 
9、调整Deployment控制器下的Pods副本数量
basic]# cat myapp-deploy.yaml
apiVersion: apps/v1
kind: Deployment
# Deployment的标签
metadata:
  name: myapp-deploy
spec:
  replicas: 6    #之前副本数量为3
  # Deployment匹配的Pod的标签选择器
  selector:
    matchLabels:
      app: myapp
      rel:
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
      - name: myapp
        image: ikubernetes/myapp:v1
        ports:
        - containerPort: 80
          name: http
     
    # kubectl scale调整pod副本数量
    chapter5]# kubectl scale --replicas=3 deployment myapp-deploy -n prod
 
10、再次查看Service详细信息
    basic]# kubectl describe svc myapp -n prod
 
 
11、ClusterIP: 用于为集群内Pod访问时,提供的固定访问地址,默认是自动分配地址,可使用ClusterIP关键字指定固定IP.
    node节点外的服务器是无法通过Service的地址访问的。
    所以ClusterIP 类型的Service 的地址也只能被集群中的Node节点进行访问,即只能被集群内部被路由。
 
12、指定Service资源的清单删除Service
    basic]# kubectl delete -f service-scv.yml
        service "myapp" deleted
 
    basic]# kubectl get svc -n prod
        No resources found in prod namespace.

1.3.3、NodePort的service类型说明及演示: 用于为集群外部访问Service后面Pod提供访问接入端口

image

  • NodePort: 用于为集群外部访问Service后面Pod提供访问接入端口.
    • 这种类型的service工作流程为:
      • Client----->NodeIP:NodePort----->ClusterIP:ServicePort----->PodIP:ContainerPort
basic]# kubectl explain svc.spec.ports
KIND:     Service
VERSION:  v1
 
RESOURCE: ports <[]Object>
 
DESCRIPTION:
     The list of ports that are exposed by this service. More info:
     https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies
 
     ServicePort contains information on service's port.
 
FIELDS:
   name <string>
     The name of this port within the service. This must be a DNS_LABEL. All
     ports within a ServiceSpec must have unique names. When considering the
     endpoints for a Service, this must match the 'name' field in the
     EndpointPort. Optional if only one ServicePort is defined on this service.
 
   nodePort <integer>
     The port on each node on which this service is exposed when type=NodePort
     or LoadBalancer. Usually assigned by the system. If specified, it will be
     allocated to the service if unused or else creation of the service will
     fail. Default is to auto-allocate a port if the ServiceType of this Service
     requires one. More info:
     https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport
 
   port <integer> -required-
     The port that will be exposed by this service.
 
   protocol <string>
     The IP protocol for this port. Supports "TCP", "UDP", and "SCTP". Default
     is TCP.
 
   targetPort   <string>
     Number or name of the port to access on the pods targeted by the service.
     Number must be in the range 1 to 65535. Name must be an IANA_SVC_NAME. If
     this is a string, it will be looked up as a named port in the target Pod's
     container ports. If this is not specified, the value of the 'port' field is
     used (an identity map). This field is ignored for services with
     clusterIP=None, and should be omitted or set equal to the 'port' field.
     More info:
     https://kubernetes.io/docs/concepts/services-networking/service/#defining-a-service
1.3.3.1、博客演示一
  • NodePort即节点Port,通常在部署Kubernetes集群系统时会预留一个端口范围用于NodePort,其范围默认为:30000~32767之间的端口。定义NodePort类型的Service资源时,需要使用.spec.type进行明确指定
[root@k8s-master mainfests]# kubectl get pods --show-labels |grep myapp-deploy
myapp-deploy-69b47bc96d-4hxxw   1/1       Running   0          12m       app=myapp,pod-template-hash=2560367528,release=canary
myapp-deploy-69b47bc96d-95bc4   1/1       Running   0          12m       app=myapp,pod-template-hash=2560367528,release=canary
myapp-deploy-69b47bc96d-hwbzt   1/1       Running   0          12m       app=myapp,pod-template-hash=2560367528,release=canary
myapp-deploy-69b47bc96d-pjv74   1/1       Running   0          12m       app=myapp,pod-template-hash=2560367528,release=canary
myapp-deploy-69b47bc96d-rf7bs   1/1       Running   0          12m       app=myapp,pod-template-hash=2560367528,release=canary
 
[root@k8s-master mainfests]# cat myapp-svc.yaml #为myapp创建service
apiVersion: v1
kind: Service
metadata:
  name: myapp
  namespace: default
spec:
  selector:
    app: myapp
    release: canary
  type: NodePort      #定义Service类型为NodePort
  ports:
  - port: 80          #Service地址的哪个端口于后端Pods端口映射
    targetPort: 80    #后端Pods的哪个端口于Service做映射
    nodePort: 30080
[root@k8s-master mainfests]# kubectl apply -f myapp-svc.yaml
service/myapp created
[root@k8s-master mainfests]# kubectl get svc
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
kubernetes   ClusterIP   10.96.0.1        <none>        443/TCP        36d
myapp        NodePort    10.101.245.119   <none>        80:30080/TCP   5s
redis        ClusterIP   10.107.238.182   <none>        6379/TCP       28m
 
[root@k8s-master mainfests]# while true;do curl http://192.168.56.11:30080/hostname.html;sleep 1;done
myapp-deploy-69b47bc96d-95bc4
myapp-deploy-69b47bc96d-4hxxw
myapp-deploy-69b47bc96d-pjv74
myapp-deploy-69b47bc96d-rf7bs
myapp-deploy-69b47bc96d-95bc4
myapp-deploy-69b47bc96d-rf7bs
myapp-deploy-69b47bc96d-95bc4
myapp-deploy-69b47bc96d-pjv74
myapp-deploy-69b47bc96d-4hxxw
myapp-deploy-69b47bc96d-pjv74
myapp-deploy-69b47bc96d-pjv74
myapp-deploy-69b47bc96d-4hxxw
myapp-deploy-69b47bc96d-pjv74
myapp-deploy-69b47bc96d-pjv74
myapp-deploy-69b47bc96d-pjv74
myapp-deploy-69b47bc96d-95bc4
myapp-deploy-69b47bc96d-hwbzt
 
[root@k8s-master mainfests]# while true;do curl http://192.168.56.11:30080/;sleep 1;done
  Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
  Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
  Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
  Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
  Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
  Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>

1.3.3.2、总结演示二

1、创建Deployment→ Replica Sets → Pods 资源清单
chapter5]# cat deploy-nginx-zhushi.yaml
#Deployment标准资源api版本定义
apiVersion: apps/v1
#定义资源的类型
kind: Deployment
#定义Deployment元数据信息
metadata:
  #Deployment名称
  name: myapp
  #指定Deployment所属的名称空间
  namespace: prod
#Deployment的规格定义
spec:
  #定义期望pod的运行的副本数量
  replicas: 3
  minReadySeconds: 10
  #定义使用更新策略
  strategy:
    #定义滚动更新策略值
    rollingUpdate:
      #允许多一个
      maxSurge: 1
      #允许少一个
      maxUnavailable: 1
    #更新策略为滚动更新
    type: RollingUpdate
  #标签选择器,定义匹配的pod
  selector:
    matchLabels:
      app: myapp
      rel: stable
  #pod的模板以下创建的每一个pod自动使用app:myapp , rel:stable这个标签
  template:
    metadata:
      labels:
        app: myapp
        rel: stable
    spec:
      containers:
      - name: myapp
        image: ikubernetes/myapp:v2
        ports:
        - containerPort: 80
          name: http
        #就绪状态探测
        readinessProbe:
          periodSeconds: 1
          httpGet:
            path: /
            port: http
 
2、创建NodePort类型的Service
basic]# cat service-scv.yml
#service所属的标准资源api版本定义群组
apiVersion: v1
#定义资源的类型为Service
kind: Service
#定义元数据
metadata:
  #定义service的名称
  name: myapp
  #定义service所属的名称空间需要和myapp——pods在同一名称空间
  namespace: prod
  #定义service的标签,可选项
  #  labels:
  #      app: filebeat
#定义service规格
spec:
  #ports字段
  ports:
  #此端口的名称
  - name: http
    #Service地址的哪个端口于后端Pods端口映射
    port: 80
    #后端Pods的哪个端口于Service做映射
    targetPort: 80
    #每一个node节点上都会生成规则默认随机端口30000 ~ 32767  (建议不要自己指定,手动指定存在冲突的可能)
    nodePort: 30080
  #定义Service的标签选择器(仅支持简单的等值标签选择方式),指定pod资源本身的标签(匹配Pods资源的标签名称加入此Service)
  selector:
    app: myapp
    rel: stable
  #定义Service类型为NodePort,默认为ClusterIP
  type: NodePort
 
 
3、使用声明式接口创建Service
    basic]# kubectl apply -f service-scv.yml
        service/myapp created
 
4、查看Service信息
    basic]# kubectl get svc -n prod
                           #地址随机分配
        NAME    TYPE       CLUSTER-IP    EXTERNAL-IP   PORT(S)        AGE
        myapp   NodePort   10.2.52.110   <none>        80:30080/TCP   36s
 
 
    basic]#  kubectl describe svc myapp -n prod
        Name:                     myapp
        Namespace:                prod
        Labels:                   <none>
        Annotations:              kubectl.kubernetes.io/last-applied-configuration:
                            {"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"myapp","namespace":"prod"},"spec":{"ports":[{"name":"http","nodeP...
        Selector:                 app=myapp,rel=stable
        Type:                     NodePort
        IP:                       10.2.52.110
        Port:                     http  80/TCP
        TargetPort:               80/TCP
        NodePort:                 http  30080/TCP
        Endpoints:                192.168.1.124:80,192.168.1.128:80,192.168.1.40:80
        Session Affinity:         None
        External Traffic Policy:  Cluster
        Events:                   <none>
 
5、查看端点信息(创建Service自动创建的endpoints)
    basic]# kubectl get endpoints -n prod
        NAME    ENDPOINTS                                           AGE
        myapp   192.168.1.124:80,192.168.1.128:80,192.168.1.40:80   3m41s
 
 
6、此时通过集群外部访问任意集群节点地址就可以访问到Pods
    basic]# curl NodeIP:30080   
 
    # 访问集群中其中一台node节点的IP+nodePort
    basic]# while : ;do curl 192.168.20.212:30080/hostname.html ;sleep 1 ;done
        myapp-759569c6b6-qkmv6
        myapp-759569c6b6-qkmv6
        myapp-759569c6b6-qkmv6
        myapp-759569c6b6-v57pw
        myapp-759569c6b6-bm5gw
        myapp-759569c6b6-v57pw
        myapp-759569c6b6-24sh8
        myapp-759569c6b6-bm5gw
        myapp-759569c6b6-24sh8
        myapp-759569c6b6-qkmv6
        myapp-759569c6b6-24sh8
        myapp-759569c6b6-xw4jz
        myapp-759569c6b6-v57pw
        myapp-759569c6b6-bm5gw
        myapp-759569c6b6-bm5gw
 
  # 可以此时可以对pod的image进行更新,再次访问可以查看到,多版本并行直至新版本上线

1.3.4、LoadBalancer:的service类型说明及演示:负载均衡器用于对Service做负载均衡调度(K8s外的资源如Nginx、Haproxy最好为云厂商的LBAAS自动创建负载规则)

  • LoadBalancer: 用于当K8s运行在一个云环境内时,若该云环境支持LBaaS,则此类型可自动触发创建一个软件负载均衡器用于对Service做负载均衡调度.
  • 因为外部所有Client都访问一个NodeIP,该节点的压力将会很大, 而LoadBalancer则可解决这个问题。
  • 而且它还直接动态监测后端Node是否被移除或新增了,然后动态更新调度的节点数。
引入 :LoadBalancer类型的Service如何使用?
    1、控制器管理的Pod:如 :Deployment Contaller 管理的Pod
    2、增加NodePort类型的Service,使得集群外部可以访问集群中各Node节点+非标准端口进行访问Pod
        # Client----->NodeIP:NodePort(非标准)----->ClusterIP:ServicePort----->PodIP:ContainerPort
    3、由于客户端访问Node阶段的端口为非标准端口,所以在集群外部需要再增加一个负载均衡使其Client访问的为标准端口;

image

1.3.5、ExternalName:的service类型说明及演示:将集群外部Service引入集群内容提供Pod客户端使用

image

  • ExternalName: 用于将集群外部的服务引入到集群内部,在集群内部可直接访问来获取服务。
    • 它的值必须是 FQDN, 此FQDN为集群内部的FQDN, 即: ServiceName.Namespace.Domain.LTD.
    • 然后CoreDNS接受到该FQDN后,能解析出一个CNAME记录, 该别名记录为真正互联网上的域名.
    • 如: www.test.com, 接着CoreDNS在向互联网上的根域DNS解析该域名,获得其真实互联网IP.
basic]# kubectl explain svc.spec.externalName
KIND:     Service
VERSION:  v1
 
FIELD:    externalName <string>   #定义一个域名,这个域名能够被dns服务器(CoreDNS)解析为外部的IP地址,外部的IP地址就是提供这个服务的端点
 
DESCRIPTION:
     externalName is the external reference that kubedns or equivalent will
     return as a CNAME record for this service. No proxying will be involved.
     Must be a valid RFC-1123 hostname (https://tools.ietf.org/html/rfc1123) and
     requires Type to be ExternalName.

1.3.5.1、引用外部服务器的方式二(无标签选择器的Service,手动创建endpoints资源)

  • Service通过标签选择器关联Pods的主要在于能够自动的为关联到的Pod创建一个endpoints资源

  • 这里的Service定义为无标签选择器,则不会关联Pods,也不会创建endpoints,所以手动创建endpoints并手动将IP地址和端口指向外部资源主机的IP地址,并将这个endpoints作为这个无标签Server的引用者

  • 手动创建endpoints

    • svc.spec.endpoints
      • apiVersion
      • kind
      • metadata
      • subsets 子集
        • addresses 引用外部的地址(多方式如下)
          • hostname 主机名
          • ip 地址
          • nodeName 节点名称(表示哪个node节点持有endpoints)
          • targeRef 表示引用的集群内部的资源
        • ports 引用外部端口
          • name 端口名称
          • port 引用的外部的端口号
          • protacol 端口的协议默认TCP
  • 创建一个无标签选择器selecter的Service,而是直接关联到手动创建的endpoints

1、手动创建endpoints
    basic]#

1.3.6、Headless Service (无头Server) :Service名称直接作用到Pod上

  • 有时不需要或不想要负载均衡,以及单独的 Service IP。 遇到这种情况,可以通过指定 Cluster IP(spec.clusterIP)的值为 "None" 来创建 Headless Service。
  • 这个选项允许开发人员自由寻找他们自己的方式,从而降低与 Kubernetes 系统的耦合性。 应用仍然可以使用一种自注册的模式和适配器,对其它需要发现机制的系统能够很容易地基于这个 API 来构建。
  • 对这类 Service 并不会分配 Cluster IP,kube-proxy 不会处理它们,而且平台也不会为它们进行负载均衡和路由。 DNS 如何实现自动配置,依赖于 Service 是否定义了 selector。

1.3.6.1、博客演示一

(1)编写headless service配置清单
[root@k8s-master mainfests]# cp myapp-svc.yaml myapp-svc-headless.yaml
[root@k8s-master mainfests]# vim myapp-svc-headless.yaml
apiVersion: v1
kind: Service
metadata:
  name: myapp-headless
  namespace: default
spec:
  selector:
    app: myapp
    release: canary
  clusterIP: "None"  #headless的clusterIP值为None
  type: ClusterIP  #无头service服务类型只能是ClusterIP,不写type,默认为clusterip
  ports:
  - port: 80
    targetPort: 80
 
(2)创建headless service
[root@k8s-master mainfests]# kubectl apply -f myapp-svc-headless.yaml
service/myapp-headless created
[root@k8s-master mainfests]# kubectl get svc
NAME             TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
kubernetes       ClusterIP   10.96.0.1        <none>        443/TCP        36d
myapp            NodePort    10.101.245.119   <none>        80:30080/TCP   1h
myapp-headless   ClusterIP   None             <none>        80/TCP         5s
redis            ClusterIP   10.107.238.182   <none>        6379/TCP       2h
 
(3)使用coredns进行解析验证
[root@k8s-master mainfests]# dig -t A myapp-headless.default.svc.cluster.local. @10.96.0.10
 
; <<>> DiG 9.9.4-RedHat-9.9.4-61.el7 <<>> -t A myapp-headless.default.svc.cluster.local. @10.96.0.10
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 62028
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 5, AUTHORITY: 0, ADDITIONAL: 1
 
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;myapp-headless.default.svc.cluster.local. IN A
 
;; ANSWER SECTION:
myapp-headless.default.svc.cluster.local. 5 IN A 10.244.1.18
myapp-headless.default.svc.cluster.local. 5 IN A 10.244.1.19
myapp-headless.default.svc.cluster.local. 5 IN A 10.244.2.15
myapp-headless.default.svc.cluster.local. 5 IN A 10.244.2.16
myapp-headless.default.svc.cluster.local. 5 IN A 10.244.2.17
 
;; Query time: 4 msec
;; SERVER: 10.96.0.10#53(10.96.0.10)
;; WHEN: Thu Sep 27 04:27:15 EDT 2018
;; MSG SIZE  rcvd: 349
 
[root@k8s-master mainfests]# kubectl get svc -n kube-system
NAME       TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)         AGE
kube-dns   ClusterIP   10.96.0.10   <none>        53/UDP,53/TCP   36d
 
[root@k8s-master mainfests]# kubectl get pods -o wide -l app=myapp
NAME                            READY     STATUS    RESTARTS   AGE       IP            NODE
myapp-deploy-69b47bc96d-4hxxw   1/1       Running   0          1h        10.244.1.18   k8s-node01
myapp-deploy-69b47bc96d-95bc4   1/1       Running   0          1h        10.244.2.16   k8s-node02
myapp-deploy-69b47bc96d-hwbzt   1/1       Running   0          1h        10.244.1.19   k8s-node01
myapp-deploy-69b47bc96d-pjv74   1/1       Running   0          1h        10.244.2.15   k8s-node02
myapp-deploy-69b47bc96d-rf7bs   1/1       Running   0          1h        10.244.2.17   k8s-node02
 
(4)对比含有ClusterIP的service解析
[root@k8s-master mainfests]# dig -t A myapp.default.svc.cluster.local. @10.96.0.10
 
; <<>> DiG 9.9.4-RedHat-9.9.4-61.el7 <<>> -t A myapp.default.svc.cluster.local. @10.96.0.10
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 50445
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
 
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;myapp.default.svc.cluster.local. IN    A
 
;; ANSWER SECTION:
myapp.default.svc.cluster.local. 5 IN    A    10.101.245.119
 
;; Query time: 1 msec
;; SERVER: 10.96.0.10#53(10.96.0.10)
;; WHEN: Thu Sep 27 04:31:16 EDT 2018
;; MSG SIZE  rcvd: 107
 
[root@k8s-master mainfests]# kubectl get svc
NAME             TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
kubernetes       ClusterIP   10.96.0.1        <none>        443/TCP        36d
myapp            NodePort    10.101.245.119   <none>        80:30080/TCP   1h
myapp-headless   ClusterIP   None             <none>        80/TCP         11m
redis            ClusterIP   10.107.238.182   <none>        6379/TCP       2h
 
 
#从以上的演示可以看到对比普通的service和headless service,headless service做dns解析是直接解析到pod的,而servcie是解析到ClusterIP的,那么headless有什么用呢???这将在statefulset中应用到,这里暂时仅仅做了解什么是headless service和创建方法

1.3.6.2、总结演示二

1、编写headless Service的配置清单
chapter5]# cat service-svc-headless.yaml
#service所属的标准资源api版本定义群组
apiVersion: v1
#定义资源的类型为Service
kind: Service
#定义元数据
metadata:
  #定义service的名称
  name: myapp
  #定义service所属的名称空间需要和myapp——pods在同一名称空间
  namespace: prod
  #定义service的标签,可选项
  #  labels:
  #      app: filebeat
#定义service规格
spec:
  #定义Service的标签选择器(仅支持简单的等值标签选择方式),指定pod资源本身的标签(匹配Pods资源的标签名称加入此Service)
  selector:
    app: myapp
    rel: stable
  # headless的clusterIP值为None
  clusterIP: "None"
  type: ClusterIP  #无头service服务类型只能是ClusterIP,不写type,默认为clusterip
  ports:
  - port: 80
    targetPort: 80
 
2、声明式方式创建资源
chapter5]# kubectl apply -f service-svc-nodeport.yaml
service/myapp created
 
3、查看创建的Service详细信息
chapter5]# kubectl get svc -n prod
NAME    TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE   
myapp   ClusterIP   None         <none>        80/TCP    50s  # CLUSTER-IP 中无地址,就成为无头Service
 
chapter5]# kubectl describe service myapp -n prod
Name:              myapp
Namespace:         prod
Labels:            <none>
Annotations:       Selector:  app=myapp,rel=stable
Type:              ClusterIP
IP:                None
Port:              <unset>  80/TCP
TargetPort:        80/TCP
Endpoints:         10.244.1.26:80,10.244.1.27:80,10.244.1.28:80 + 3 more... # 使用标签选择器匹配的早已创建好的pod
Session Affinity:  None
Events:            <none>
 
 
 
4、上面详细信息中查看到CLUSTER-IP为None,那么如何访问呢?
    #  只能使用Service的名称进行访问,此时名称就不是Service的地址了,就变成了Pod的地址。
     
    # 连入一个Service所属的Pod进行测试
    chapter5]# kubectl get pods -n prod
     
chapter5]# kubectl exec -it myapp-5c554c56fc-xwv9z -- /bin/sh
Error from server (NotFound): pods "myapp-5c554c56fc-xwv9z" not found
[root@k8s chapter5]# kubectl exec -it -n prod myapp-5c554c56fc-xwv9z -- /bin/sh
/ # cat /etc/resolv.conf
nameserver 10.96.0.10
search prod.svc.cluster.local svc.cluster.local cluster.local node1
options ndots:5
/ # nslookup myapp.prod         # 访问Service地址,其实是直接访问到Pod地址的
nslookup: can't resolve '(null)': Name does not resolve
Name:      myapp.prod
Address 1: 10.244.1.27 myapp-5c554c56fc-xwv9z
Address 2: 10.244.1.26 10-244-1-26.myapp.prod.svc.cluster.local
Address 3: 10.244.1.28 10-244-1-28.myapp.prod.svc.cluster.local
Address 4: 10.244.2.27 10-244-2-27.myapp.prod.svc.cluster.local
Address 5: 10.244.2.29 10-244-2-29.myapp.prod.svc.cluster.local
Address 6: 10.244.2.28 10-244-2-28.myapp.prod.svc.cluster.local
 
/ # wget -O - -q myapp.prod
Hello MyApp | Version: v3 | <a href="hostname.html">Pod Name</a>
/ # wget -O - -q myapp.prod/hostname.html
myapp-5c554c56fc-xwv9z          # 发现未实现调度,而是dns解析缓存
/ # wget -O - -q myapp.prod/hostname.html
myapp-5c554c56fc-xwv9z

1.3.7、Pod的会话保持(svc.spec.sessionAffinity)

  • 会话保持功能的三种实现方式
    • 会话粘性
    • 会话集群
    • 会话服务器
  • Service资源还支持Session affinity(粘性会话)机制,可以将来自同一个客户端的请求始终转发至同一个后端的Pod对象,这意味着它会影响调度算法的流量分发功用,进而降低其负载均衡的效果。因此,当客户端访问Pod中的应用程序时,如果有基于客户端身份保存某些私有信息,并基于这些私有信息追踪用户的活动等一类的需求时,那么应该启用session affinity机制。
  • Service affinity的效果仅仅在一段时间内生效,默认值为10800秒,超出时长,客户端再次访问会重新调度。该机制仅能基于客户端IP地址识别客户端身份,它会将经由同一个NAT服务器进行原地址转换的所有客户端识别为同一个客户端,由此可知,其调度的效果并不理想。Service 资源 通过. spec. sessionAffinity 和. spec. sessionAffinityConfig 两个字段配置粘性会话。 spec. sessionAffinity 字段用于定义要使用的粘性会话的类型,它仅支持使用“ None” 和“ ClientIP” 两种属性值。如下:
[root@k8s-master mainfests]# kubectl explain svc.spec.sessionAffinity
KIND:     Service
VERSION:  v1
 
FIELD:    sessionAffinity <string>
 
DESCRIPTION:
     Supports "ClientIP" and "None". Used to maintain session affinity. Enable      #默认为None,使用调度算法进行调度,不做会话粘性
     client IP based session affinity. Must be ClientIP or None. Defaults to
     None. More info:
     https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies
  • sessionAffinity支持ClientIP和None 两种方式,默认是None(随机调度) ClientIP是来自于同一个客户端的请求调度到同一个pod中
[root@k8s-master mainfests]# vim myapp-svc.yaml
apiVersion: v1
kind: Service
metadata:
  name: myapp-session
  namespace: prod
spec:
  # 用于匹配已经创建的pods的标签选择器
  selector:
    app: myapp
    rel: stable
  sessionAffinity: ClientIP
  type: NodePort
  ports:
  - name: http
    port: 80
    targetPort: 80
    nodePort: 30080
 
[root@k8s-master mainfests]# kubectl apply -f myapp-svc.yaml
service/myapp configured
[root@k8s-master mainfests]# kubectl describe svc myapp
Name:                     myapp
Namespace:                default
Labels:                   <none>
Annotations:              kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"myapp","namespace":"default"},"spec":{"ports":[{"nodePort":30080,"port":80,"ta...
Selector:                 app=myapp,release=canary
Type:                     NodePort
IP:                       10.101.245.119
Port:                     <unset>  80/TCP
TargetPort:               80/TCP
NodePort:                 <unset>  30080/TCP
Endpoints:                10.244.1.18:80,10.244.1.19:80,10.244.2.15:80 + 2 more...
Session Affinity:         ClientIP
External Traffic Policy:  Cluster
Events:                   <none>
 
 
# 访问集群中其中一台node节点的ip+nodePort -->  实现根据ClientIP是来自于同一个客户端的请求调度到同一个pod中
[root@k8s-master mainfests]# while true;do curl http://192.168.56.11:30080/hostname.html;sleep 1;done
myapp-deploy-69b47bc96d-hwbzt
myapp-deploy-69b47bc96d-hwbzt
myapp-deploy-69b47bc96d-hwbzt
myapp-deploy-69b47bc96d-hwbzt
myapp-deploy-69b47bc96d-hwbzt
myapp-deploy-69b47bc96d-hwbzt
myapp-deploy-69b47bc96d-hwbzt
myapp-deploy-69b47bc96d-hwbzt
 
 
 
也可以使用打补丁的方式进行修改yaml内的内容,如下:
    kubectl patch svc myapp -p '{"spec":{"sessionAffinity":"ClusterIP"}}'  #session保持,同一ip访问同一个pod
    kubectl patch svc myapp -p '{"spec":{"sessionAffinity":"None"}}'    #取消session

1.4、Kube-proxy决定了Service如何映射节点的iptables或者ipvs规则(不管是LVS还是iptables规则都为四层的代理)

  • 配置K8s中的服务靠一种资源称为 : ConfigMap (配置映射)
  • 可以在容器外部修改资源的配置映射的定义,定义能够自动注入到相关的应用程序之上,并被Pod加载或使用。

1.4.1、集群初始化完成后修改kube-proxy定义的service节点规则为ipvs(已实验)

1、查看kube-proxy中的配置内容(一旦主节点修改,其他节点的kube-proxy都会被修改,类似于配置中心的感觉、有些资源是支持动态修改)
    ~]# kubectl edit cm kube-proxy -n kube-system
    iptables:                   # iptables
      masqueradeAll: false
      masqueradeBit: null
      minSyncPeriod: 0s
      syncPeriod: 0s
    ipvs:                       # ipvs
      excludeCIDRs: null
      minSyncPeriod: 0s
      scheduler: ""
      strictARP: false
      syncPeriod: 0s
      tcpFinTimeout: 0s
      tcpTimeout: 0s
      udpTimeout: 0s
    kind: KubeProxyConfiguration
    metricsBindAddress: ""
    mode: ""                  # 到底启动那个策略,是在mode中定义的,""表示为iptables
 
 
2、修改Service映射规则为IPVS的前提是各个Node节点已经装载IPVS内核模块  #各个node节点运行此脚本
scripts]# cat ipvs_modeinfo.sh
#!/bin/bash
ipvs_mods_dir="/usr/lib/modules/$(uname -r)/kernel/net/netfilter/ipvs"
for mod in $(ls $ipvs_mods_dir | grep -o "^[^.]*")
do
  /sbin/modinfo -F filename $mod &> /dev/null
  if [[ $? -eq 0 ]];then
     /sbin/modprobe $mod
  fi
done
 
 
 
3、将此脚本放置在集群中每个节点的一下目录下(放置此目录下的意义就是节点每次重启后都会执行此脚本)
[root@k8s ~]# cd /etc/sysconfig/modules/
[root@k8s modules]# ls
[root@k8s modules]# vim ipvs.modules
#!/bin/bash
ipvs_mods_dir="/usr/lib/modules/$(uname -r)/kernel/net/netfilter/ipvs"
for mod in $(ls $ipvs_mods_dir | grep -o "^[^.]*")
do
  /sbin/modinfo -F filename $mod &> /dev/null
  if [[ $? -eq 0 ]];then
     /sbin/modprobe $mod
  fi
done
 
modules]# chmod +x ipvs.modules
modules]# bash ipvs.modules
 
 
modules]# lsmod | grep ip_vs
ip_vs_wlc              12519  0
ip_vs_sed              12519  0
ip_vs_pe_sip           12697  0
nf_conntrack_sip       33860  1 ip_vs_pe_sip
ip_vs_nq               12516  0
ip_vs_lc               12516  0
ip_vs_lblcr            12922  0
ip_vs_lblc             12819  0
ip_vs_ftp              13079  0
ip_vs_dh               12688  0
ip_vs_sh               12688  0
ip_vs_wrr              12697  0
ip_vs_rr               12600  0
ip_vs                 141092  26 ip_vs_dh,ip_vs_lc,ip_vs_nq,ip_vs_rr,ip_vs_sh,ip_vs_ftp,ip_vs_sed,ip_vs_wlc,ip_vs_wrr,ip_vs_pe_sip,ip_vs_lblcr,ip_vs_lblc
nf_nat                 26147  4 ip_vs_ftp,nf_nat_ipv4,xt_nat,nf_nat_masquerade_ipv4
nf_conntrack          111302  8 ip_vs,nf_nat,nf_nat_ipv4,xt_conntrack,nf_nat_masquerade_ipv4,nf_conntrack_netlink,nf_conntrack_sip,nf_conntrack_ipv4
libcrc32c              12644  2 xfs,ip_vs
 
 
4、查看ipvs模块已经装载则可以修改kube-proxy中的配置内容
~]# kubectl edit cm kube-proxy -n kube-system
configmap/kube-proxy edited
    iptables:
      masqueradeAll: false
      masqueradeBit: null
      minSyncPeriod: 0s
      syncPeriod: 0s
    ipvs:
      excludeCIDRs: null
      minSyncPeriod: 0s
      scheduler: ""
      strictARP: false
      syncPeriod: 0s
      tcpFinTimeout: 0s
      tcpTimeout: 0s
      udpTimeout: 0s
    kind: KubeProxyConfiguration
    metricsBindAddress: ""
    mode: "ipvs"                   # 修改为ipvs
 
 
5、验证service的规则是否运行为ipvs规则
    # kube-proxy - pod可能被重构,如果不重构也没问题
    ~]# kubectl get pods -n kube-system
        kube-proxy-4p84s                      1/1     Running   0          18d
        kube-proxy-kxw2v                      1/1     Running   0          17d
        kube-proxy-sptb7                      1/1     Running   0          17d
 
  # 验证service是否运行为ipvs规则并生成策略(任何节点验证都可以)
    ~]# yum install ipvsadm
    ~]# ipvsadm -Ln      # 这里查看也没有生成策略
        IP Virtual Server version 1.2.1 (size=4096)
        Prot LocalAddress:Port Scheduler Flags
        -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
 
 
    # 人为手动的重载一下kube-proxy配置(手动将kube-proxy-pods删除等待自动启动)
     ~]# kubectl get pods -n kube-system --show-labels
        kube-proxy-4p84s                      1/1     Running   0          18d   controller-revision-hash=55877fc8b6,k8s-app=kube-proxy,pod-template-generation=1
        kube-proxy-kxw2v                      1/1     Running   0          17d   controller-revision-hash=55877fc8b6,k8s-app=kube-proxy,pod-template-generation=1
        kube-proxy-sptb7                      1/1     Running   0          17d   controller-revision-hash=55877fc8b6,k8s-app=kube-proxy,pod-template-generation=1
    # 使用标签选择器匹配一类pods删除(删除一组满足标签过滤器条件的pod)
    ~]# kubectl delete pods -l k8s-app=kube-proxy -n kube-system
        pod "kube-proxy-4p84s" deleted
        pod "kube-proxy-kxw2v" deleted
        pod "kube-proxy-sptb7" deleted
    # 可以查看到kube-proxy已经重启启动
    ~]# kubectl get pods -n kube-system --show-labels
        kube-proxy-42r9t                      1/1     Running   0          20s   controller-revision-hash=55877fc8b6,k8s-app=kube-proxy,pod-template-generation=1
        kube-proxy-kprg9                      1/1     Running   0          20s   controller-revision-hash=55877fc8b6,k8s-app=kube-proxy,pod-template-generation=1
        kube-proxy-ltgkv                      1/1     Running   0          20s   controller-revision-hash=55877fc8b6,k8s-app=kube-proxy,pod-template-generation=1              
        kube-system --show-labels
 
    # 此时就可以查看到service生成的ipvs策略
~]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  172.17.0.1:30080(Service地址) rr persistent 10800
  -> 10.244.1.34:80(以下为pod地址)               Masq    1      0          0        
  -> 10.244.1.35:80               Masq    1      0          0        
  -> 10.244.1.36:80               Masq    1      0          0        
  -> 10.244.2.20:80               Masq    1      0          0        
  -> 10.244.2.22:80               Masq    1      0          0        
  -> 10.244.2.23:80               Masq    1      0          0        
TCP  172.17.0.1:31038 rr
  -> 10.244.1.3:80                Masq    1      0          0        
  -> 10.244.1.4:80                Masq    1      0          0        
  -> 10.244.2.4:80                Masq    1      0          0        
TCP  192.168.20.236:30080 rr persistent 10800
  -> 10.244.1.34:80               Masq    1      0          0        
  -> 10.244.1.35:80               Masq    1      0          0        
  -> 10.244.1.36:80               Masq    1      0          0        
  -> 10.244.2.20:80               Masq    1      0          0        
  -> 10.244.2.22:80               Masq    1      0          0        
  -> 10.244.2.23:80               Masq    1      0          0        
TCP  192.168.20.236:31038 rr
  -> 10.244.1.3:80                Masq    1      0          0        
  -> 10.244.1.4:80                Masq    1      0          0        
  -> 10.244.2.4:80                Masq    1      0          0        
TCP  10.96.0.1:443 rr
  -> 192.168.20.236:6443          Masq    1      0          0        
TCP  10.96.0.10:53 rr
  -> 10.244.0.2:53                Masq    1      0          0        
  -> 10.244.0.3:53                Masq    1      0          0        
TCP  10.96.0.10:9153 rr
  -> 10.244.0.2:9153              Masq    1      0          0        
  -> 10.244.0.3:9153              Masq    1      0          0        
TCP  10.104.142.127:80 rr
  -> 10.244.2.3:80                Masq    1      0          0        
TCP  10.105.203.76:80 rr
  -> 10.244.1.3:80                Masq    1      0          0        
  -> 10.244.1.4:80                Masq    1      0          0        
  -> 10.244.2.4:80                Masq    1      0          0        
TCP  10.111.32.118:80 rr persistent 10800
  -> 10.244.1.34:80               Masq    1      0          0        
  -> 10.244.1.35:80               Masq    1      0          0        
  -> 10.244.1.36:80               Masq    1      0          0        
  -> 10.244.2.20:80               Masq    1      0          0        
  -> 10.244.2.22:80               Masq    1      0          0        
  -> 10.244.2.23:80               Masq    1      0          0        
TCP  10.244.0.0:30080 rr persistent 10800
  -> 10.244.1.34:80               Masq    1      0          0        
  -> 10.244.1.35:80               Masq    1      0          0        
  -> 10.244.1.36:80               Masq    1      0          0        
  -> 10.244.2.20:80               Masq    1      0          0        
  -> 10.244.2.22:80               Masq    1      0          0        
  -> 10.244.2.23:80               Masq    1      0          0        
TCP  10.244.0.0:31038 rr
  -> 10.244.1.3:80                Masq    1      0          0        
  -> 10.244.1.4:80                Masq    1      0          0        
  -> 10.244.2.4:80                Masq    1      0          0        
TCP  10.244.0.1:30080 rr persistent 10800
  -> 10.244.1.34:80               Masq    1      0          0        
  -> 10.244.1.35:80               Masq    1      0          0        
  -> 10.244.1.36:80               Masq    1      0          0        
  -> 10.244.2.20:80               Masq    1      0          0        
  -> 10.244.2.22:80               Masq    1      0          0        
  -> 10.244.2.23:80               Masq    1      0          0        
TCP  10.244.0.1:31038 rr
  -> 10.244.1.3:80                Masq    1      0          0        
  -> 10.244.1.4:80                Masq    1      0          0        
  -> 10.244.2.4:80                Masq    1      0          0        
TCP  127.0.0.1:30080 rr persistent 10800
  -> 10.244.1.34:80               Masq    1      0          0        
  -> 10.244.1.35:80               Masq    1      0          0        
  -> 10.244.1.36:80               Masq    1      0          0        
  -> 10.244.2.20:80               Masq    1      0          0        
  -> 10.244.2.22:80               Masq    1      0          0        
  -> 10.244.2.23:80               Masq    1      0          0        
TCP  127.0.0.1:31038 rr
  -> 10.244.1.3:80                Masq    1      0          0        
  -> 10.244.1.4:80                Masq    1      0          0        
  -> 10.244.2.4:80                Masq    1      0          0        
UDP  10.96.0.10:53 rr
  -> 10.244.0.2:53                Masq    1      0          0        
  -> 10.244.0.3:53                Masq    1      0          0 
 
 
6、测试访问已经创建过的service是否正常工作
[root@k8s ~]# kubectl get service -n prod
NAME            TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
myapp-session   NodePort   10.111.32.118   <none>        80:30080/TCP   21h
You have new mail in /var/spool/mail/root
[root@k8s ~]# curl 10.111.32.118
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>
[root@k8s ~]# curl 192.168.20.236
curl: (7) Failed connect to 192.168.20.236:80; Connection refused
[root@k8s ~]# curl 192.168.20.236:30080
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>
You have new mail in /var/spool/mail/root

1.4.2、集群初始化完成前定义的service节点规则为ipvs

Kubernetes技术已经成为了原生云技术的事实标准,它是目前基础软件领域最为热门的分布式调度和管理平台。于是,Kubernetes也几乎成了时下开发工程师和运维工程师必备的技能之一。
 
 
 
一、主机环境预设
 
1、测试环境说明
 
测试使用的Kubernetes集群可由一个master主机及一个以上(建议至少两个)node主机组成,这些主机可以是物理服务器,也可以运行于vmware、virtualbox或kvm等虚拟化平台上的虚拟机,甚至是公有云上的VPS主机。
 
本测试环境将由master01、node01和node02三个独立的主机组成,它们分别拥有4核心的CPU及4G的内存资源,操作系统环境均为CentOS 7.5 1804,域名为ilinux.io。此外,各主机需要预设的系统环境如下:
 
    (1)借助于NTP服务设定各节点时间精确同步;
    (2)通过DNS完成各节点的主机名称解析,测试环境主机数量较少时也可以使用hosts文件进行;
    (3)关闭各节点的iptables或firewalld服务,并确保它们被禁止随系统引导过程启动;
    (4)各节点禁用SELinux;
    (5)各节点禁用所有的Swap设备;
    (6)若要使用ipvs模型的proxy,各节点还需要载入ipvs相关的各模块;
     
2、设定时钟同步
     
    若节点可直接访问互联网,直接启动chronyd系统服务,并设定其随系统引导而启动。
     
        ~]# systemctl start chronyd.service
        ~]# systemctl enable chronyd.service       
     
    不过,建议用户配置使用本地的的时间服务器,在节点数量众多时尤其如此。存在可用的本地时间服务器时,修改节点的/etc/crhony.conf配置文件,并将时间服务器指向相应的主机即可,配置格式如下:
     
        server CHRONY-SERVER-NAME-OR-IP iburst
         
3、主机名称解析
 
    出于简化配置步骤的目的,本测试环境使用hosts文件进行各节点名称解析,文件内容如下所示:
     
    172.20.0.71 master01.ilinux.io master01
    172.20.0.61 node01.ilinux.io node01
    172.20.0.62 node02.ilinux.io node02
     
4、关闭iptables或firewalld服务
 
在CentOS7上,iptables或firewalld服务通常只会安装并启动一种,在不确认具体启动状态的前提下,这里通过同时关闭并禁用二者即可简单达到设定目标。
 
    ~]# systemctl stop firewalld.service
    ~]# systemctl stop iptables.service
    ~]# systemctl disable firewalld.service
    ~]# systemctl disable iptables.service
 
5、关闭并禁用SELinux
 
若当前启用了SELinux,则需要编辑/etc/sysconfig/selinux文件,禁用SELinux,并临时设置其当前状态为permissive:
 
    ~]# sed -i 's@^\(SELINUX=\).*@\1disabled@' /etc/sysconfig/selinux
    ~]# setenforce 0
 
6、禁用Swap设备
 
部署集群时,kubeadm默认会预先检查当前主机是否禁用了Swap设备,并在未禁用时强制终止部署过程。因此,在主机内存资源充裕的条件下,需要禁用所有的Swap设备,否则,就需要在后文的kubeadm init及kubeadm join命令执行时额外使用相关的选项忽略检查错误。
 
关闭Swap设备,需要分两步完成。首先是关闭当前已启用的所有Swap设备:
    ~]# swapoff -a
         
而后编辑/etc/fstab配置文件,注释用于挂载Swap设备的所有行。
     
7、启用ipvs内核模块
 
创建内核模块载入相关的脚本文件/etc/sysconfig/modules/ipvs.modules,设定自动载入的内核模块。文件内容如下:
 
#!/bin/bash
ipvs_mods_dir="/usr/lib/modules/$(uname -r)/kernel/net/netfilter/ipvs"
for mod in $(ls $ipvs_mods_dir | grep -o "^[^.]*"); do
    /sbin/modinfo -F filename $mod  &> /dev/null
    if [ $? -eq 0 ]; then
        /sbin/modprobe $mod
    fi
done
  
修改文件权限,并手动为当前系统加载内核模块:
    ~]# chmod +x /etc/sysconfig/modules/ipvs.modules
    ~]# bash /etc/sysconfig/modules/ipvs.modules 
 
二、安装程序包(在各主机上完成如下设定)
 
1、生成yum仓库配置
         
首先获取docker-ce的配置仓库配置文件:
        ~]# wget https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo -O /etc/yum.repos.d/docker.repo
             
而后手动生成kubernetes的yum仓库配置文件/etc/yum.repos.d/kubernetes.repo,内容如下:
         
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
gpgcheck=1
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
enabled=1
         
2、安装相关的程序包
 
Kubernetes会对经过充分验正的Docker程序版本进行认证,目前认证完成的最高版本是17.03,但docker-ce的最新版本已经高出了几个版本号。管理员可忽略此认证而直接使用最新版本的docker-ce程序,不过,建议根据后面的说明,将安装命令替换为安装17.03版。
  
    ~]# yum install docker-ce
    ~]# yum install kubelet kubeadm kubectl
     
    如果要安装目前经过Kubernetes认证的docker-17版本,可以将上面第一条安装命令替换为如下命令:
    ~]# yum install -y --setopt=obsoletes=0 docker-ce-17.03.2.ce docker-ce-selinux-17.03.2.ce
 
三、启动docker服务(在各节点执行)
 
若要通过默认的k8s.gcr.io镜像仓库获取Kubernetes系统组件的相关镜像,需要配置docker Unit File(/usr/lib/systemd/system/docker.service文件)中的Environment变量,为其定义合用的HTTPS_PROXY,格式如下:
     
    Environment="HTTPS_PROXY=PROTOCOL://HOST:PORT"
    Environment="NO_PROXY=172.20.0.0/16,127.0.0.0/8"
         
另外,docker自1.13版起会自动设置iptables的FORWARD默认策略为DROP,这可能会影响Kubernetes集群依赖的报文转发功能,因此,需要在docker服务启动后,重新将FORWARD链的默认策略设备为ACCEPT,方式是修改/usr/lib/systemd/system/docker.service文件,在"ExecStart=/usr/bin/dockerd"一行之后新增一行如下内容:
    ExecStartPost=/usr/sbin/iptables -P FORWARD ACCEPT
         
重载完成后即可启动docker服务:
    ~]#systemctl daemon-reload       
    ~]# systemctl start docker.service
             
而后设定docker和kubelet随系统引导自动启动:
    ~]# systemctl enable docker kubelet
 
四、初始化主节点(在master01上完成如下操作)
             
1、初始化master节点
 
若未禁用Swap设备,则需要编辑kubelet的配置文件/etc/sysconfig/kubelet,设置其忽略Swap启用的状态错误,内容如下:
    KUBELET_EXTRA_ARGS="--fail-swap-on=false"
     
(可选步骤)而后,在运行初始化命令之前先运行如下命令单独获取相关的镜像文件,而后再运行后面的kubeadm init命令,以便于观察到镜像文件的下载过程。
    ~]# kubeadm config images pull
     
而后即可进行master节点初始化。kubeadm init命令支持两种初始化方式,一是通过命令行选项传递关键的部署设定,另一个是基于yaml格式的专用配置文件,后一种允许用户自定义各个部署参数。下面分别给出了两种实现方式的配置步骤,建议读者采用第二种方式进行。
 
初始化方式一:
 
运行如下命令完成master01节点的初始化:
    ~]# kubeadm init --kubernetes-version=v1.13.3 --pod-network-cidr=10.244.0.0/16 --service-cidr=10.96.0.0/12 --ignore-preflight-errors=Swap
     
命令中的各选项简单说明如下:
    (1) --kubernetes-version选项的版本号用于指定要部署的Kubenretes程序版本,它需要与当前的kubeadm支持的版本保持一致;
    (2) --pod-network-cidr选项用于指定分Pod分配使用的网络地址,它通常应该与要部署使用的网络插件(例如flannel、calico等)的默认设定保持一致,10.244.0.0/16是flannel默认使用的网络;
    (3) --service-cidr用于指定为Service分配使用的网络地址,它由kubernetes管理,默认即为10.96.0.0/12;
    (4) 最后一个选项"--ignore-preflight-errors=Swap"仅应该在未禁用Swap设备的状态下使用。       
 
初始化方式二:
 
kubeadm也可通过配置文件加载配置,以定制更丰富的部署选项。以下是个符合前述命令设定方式的使用示例,不过,它明确定义了kubeProxy的模式为ipvs,并支持通过修改imageRepository的值修改获取系统镜像时使用的镜像仓库。
 
apiVersion: kubeadm.k8s.io/v1alpha2
kind: MasterConfiguration
kubernetesVersion: v1.13.3
api:
  advertiseAddress: 172.20.0.71
  bindPort: 6443
  controlPlaneEndpoint: ""
imageRepository: k8s.gcr.io
kubeProxy:
  config:
    mode: "ipvs"
    ipvs:
      ExcludeCIDRs: null
      minSyncPeriod: 0s
      scheduler: ""
      syncPeriod: 30s   
kubeletConfiguration:
  baseConfig:
    cgroupDriver: cgroupfs
    clusterDNS:
    - 10.96.0.10
    clusterDomain: cluster.local
    failSwapOn: false
    resolvConf: /etc/resolv.conf
    staticPodPath: /etc/kubernetes/manifests
networking:
  dnsDomain: cluster.local
  podSubnet: 10.244.0.0/16
  serviceSubnet: 10.96.0.0/12
   
将上面的内容保存于配置文件中,例如kubeadm-config.yaml,而后执行相应的命令:
     
   ~]# kubeadm init --config kubeadm-config.yaml --ignore-preflight-errors=Swap
 
             
注意:对于Kubernetes系统的新用户来说,无论使用上述哪种方法,命令运行结束后,请记录最后的kubeadm join命令输出的最后提示的操作步骤。下面的内容是需要用户记录的一个命令输出示例,它提示了后续需要的操作步骤:
 
    Your Kubernetes master has initialized successfully!
 
    To start using your cluster, you need to run the following as a regular user:
 
        mkdir -p $HOME/.kube
        sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
        sudo chown $(id -u):$(id -g) $HOME/.kube/config
 
    You should now deploy a pod network to the cluster.
    Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
    https://kubernetes.io/docs/concepts/cluster-administration/addons/
 
    You can now join any number of machines by running the following on each node
    as root:
 
        kubeadm join 172.20.0.71:6443 --token gwxgdg.igg5728t1vt8ahhx --discovery-token-ca-cert-hash sha256:9b63cd1530b50da4733d2e7dace9270782211e25ec2e4bbac395e59adc56a26c
             
另外,kubeadm init命令完整参考指南请移步官方文档。https://kubernetes.io/docs/reference/setup-tools/kubeadm/kubeadm-init/。
            
2、初始化kubectl
 
kubectl是kube-apiserver的命令行客户端程序,实现了除系统部署之外的几乎全部的管理操作,是kubernetes管理员使用最多的命令之一。kubectl需经由API server认证及授权后方能执行相应的管理操作,kubeadm部署的集群为其生成了一个具有管理员权限的认证配置文件/etc/kubernetes/admin.conf,它可由kubectl通过默认的"$HOME/.kube/config"的路径进行加载。当然,用户也可在kubectl命令上使用--kubeconfig选项指定一个别的位置。
 
下面复制认证为Kubernetes系统管理员的配置文件至目标用户(例如当前用户root)的家目录下:
 
    ~]# mkdir ~/.kube
    ~]# cp /etc/kubernetes/admin.conf ~/.kube/config
                 
而后,即可通过kubectl进行客户端命令测试,并借此了解集群组件的当前状态:
    ~]# kubectl get componentstatus
     
一个正常的输出应该类似如下输出结果所示:
    NAME                 STATUS    MESSAGE              ERROR
    controller-manager   Healthy   ok                  
    scheduler            Healthy   ok                  
    etcd-0               Healthy   {"health": "true"}
    
3、添加flannel网络附件
 
Kubernetes系统上Pod网络的实现依赖于第三方插件进行,这类插件有近数十种之多,较为著名的有flannel、calico、canal和kube-router等,简单易用的实现是为CoreOS提供的flannel项目。下面的命令用于在线部署flannel至Kubernetes系统之上:
 
    ~]# kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
     
而后使用如下命令确认其输出结果中Pod的状态为"Running",类似如下所示:
 
    ~]# kubectl get pods -n kube-system -l app=flannel
    NAME                          READY   STATUS    RESTARTS   AGE
    kube-flannel-ds-amd64-wscnz   1/1     Running   0          14m
             
4、验正master节点已经就绪
 
    ~]# kubectl get nodes
     
上述命令应该会得到类似如下输出:   
    NAME                 STATUS   ROLES    AGE    VERSION
    master01.ilinux.io   Ready    master   4m9s   v1.13.3   
 
五、添加节点到集群中(在node01和node02上分别完成如下操作)
 
1、若未禁用Swap设备,编辑kubelet的配置文件/etc/sysconfig/kubelet,设置其忽略Swap启用的状态错误,内容如下:
    KUBELET_EXTRA_ARGS="--fail-swap-on=false"
 
2、将节点加入第二步中创建的master的集群中,要使用主节点初始化过程中记录的kubeadm join命令,并且在未禁用Swap设备的情况下,额外附加"--ignore-preflight-errors=Swap"选项;
 
    ~]# kubeadm join 172.20.0.71:6443 --token gwxgdg.igg5728t1vt8ahhx --discovery-token-ca-cert-hash sha256:9b63cd1530b50da4733d2e7dace9270782211e25ec2e4bbac395e59adc56a26c --ignore-preflight-errors=Swap
    
在每个节点添加完成后,即可通过kubectl验正添加结果。下面的命令及其输出是在node01和node02均添加完成后运行的,其输出结果表明两个Node已经准备就绪。
 
    ~]# kubectl get nodes
    NAME                  STATUS   ROLES    AGE     VERSION
    master01.magedu.com   Ready    master   31m     v1.13.3
    node01.magedu.com     Ready    <none>   3m8s    v1.13.3
    node02.magedu.com     Ready    <none>   2m25s   v1.13.3
 
到此为止,一个master,并附带有两个node的kubernetes集群基础设施已经部署完成,用户随后即可测试其核心功能。例如,下面的命令可将myapp以Pod的形式编排运行于集群之上,并通过在集群外部进行访问:
 
    ~]# kubectl create deployment myapp --image=ikubernetes/myapp:v1
    ~]# kubectl create service nodeport myapp --tcp=80:80
 
而后,使用如下命令了解Service对象myapp使用的NodePort,以便于在集群外部进行访问:
    ~]# kubectl get svc -l app=myapp
    NAME    TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
    myapp   NodePort   10.102.254.75   <none>        80:31257/TCP   2m32s   
     
myapp是一个web应用,因此,用户可以于集群外部通过"http://NodeIP:31257"这个URL访问myapp上的应用,例如于集群外通过浏览器访问"http://172.20.0.61:31257"。
posted @ 2021-06-13 23:09  SRE运维充电站  阅读(2)  评论(0编辑  收藏  举报