Kubernetes学习-相关概念

Kubernetes架构图

上图可以看到如下组件,使用特别的图标表示Service和Label:

    • Pod
    • Container(容器)
    • Label(label)(标签)
    • Replication Controller(复制控制器)
    • Service(enter image description here)(服务)
    • Node(节点)
    • Kubernetes Master(Kubernetes主节点)

Pod

  Pod 是Kubernetes的基本操作单元,也是应用运行的载体。整个Kubernetes系统都是围绕着Pod展开的,比如如何部署运行Pod、如何保证Pod的数量、如何访问Pod等。另外,Pod是一个或多个机关容器的集合,提供了一种容器的组合的模型。

 Pod(上图绿色方框)安排在节点上,包含一组容器和卷。同一个Pod里的容器共享同一个网络命名空间,可以使用localhost互相通信。Pod是短暂的,不是持续性实体。

    • Pod是短暂的,pod重建的时候数据会丢失对于需要持久化的数据,因为Kubernetes支持的概念,故可以使用持久化的卷类型。这样就能持久化容器数据使其能够跨重启而存在。
    • 创建Pod时可以手动创建单个Pod,也可以使用Replication Controller使用Pod模板创建出多份拷贝。
    • Pod是短暂的,那么重启时IP地址可能会改变,那么怎么才能从前端容器正确可靠地指向后台容器呢?这时可以使用Service。

   Pods提供两种共享资源:网络和存储。
网络:
  每个Pod被分配一个独立的IP地址,Pod中的每个容器共享网络命名空间,包括IP地址和网络端口。
  Pod内的容器可以使用localhost相互通信。
  当Pod中的容器与Pod 外部通信时,他们必须协调如何使用共享网络资源(如端口)。
存储:
  Pod可以指定一组共享存储volumes。
  Pod中的所有容器都可以访问共享volumes,允许这些容器共享数据。
  volumes 还用于Pod中的数据持久化,以防其中一个容器需要重新启动而丢失数据。

 

  • 基本操作

  创建  kubectl create -f xxx.yaml

  查询  kubectl get pod yourPodName  kubectl describe pod yourPodName

  删除  kubectl delete pod yourPodName

  更新  kubectl replace /path/to/yourNewYaml.yaml

  •  Pod与容器

  在Docker中,容器是最小的处理单元,增删改查的对象是容器,容器是一种虚拟化技术,容器之间是隔离的,隔离是基于Linux Namespace实现的。而在Kubernetes中,Pod包含一个或者多个相关的容器,Pod可以认为是容器的一种延伸扩展,一个Pod也是一个隔离体,而Pod内部包含的一组容器又是共享的(包括PID、Network、IPC、UTS)。除此之外,Pod中的容器可以访问共同的数据卷来实现文件系统的共享。

  • Pod与Controller

  Controller可以创建和管理多个Pod,提供副本管理、滚动升级和集群级别的自愈能力。如果一个Node故障,Controller就能自动将该节点上的Pod调度到其他健康的Node上。

  • 镜像

  在kubernetes中,镜像的下载策略为:

    Always:每次都下载最新的镜像

    Never:只使用本地镜像,从不下载

    IfNotPresent:只有当本地没有的时候才下载镜像

  Pod被分配到Node之后会根据镜像下载策略进行镜像下载,可以根据自身集群的特点来决定采用何种下载策略。无论何种策略,都要确保Node上有正确的镜像可用。

  •  其他

  通过yaml文件,可以在Pod中设置:

    启动命令,如:spec-->containers-->command;

    环境变量,如:spec-->containers-->env-->name/value;

    端口桥接,如:spec-->containers-->ports-->containerPort/protocol/hostIP/hostPort(使用hostPort时需要注意端口冲突的问题,不过Kubernetes在调度Pod的时候会检查宿主机端口是否冲突,比如当两个Pod均要求绑定宿主机的80端口,Kubernetes将会将这两个Pod分别调度到不同的机器上);

    Host网络,一些特殊场景下,容器必须要以host方式进行网络设置(如接收物理机网络才能够接收到的组播流),在Pod中也支持host网络的设置,如:spec-->hostNetwork=true;

    数据持久化,如:spec-->containers-->volumeMounts-->mountPath;

    重启策略,当Pod中的容器终止退出后,重启容器的策略。这里的所谓Pod的重启,实际上的做法是容器的重建,之前容器中的数据将会丢失,如果需要持久化数据,那么需要使用数据卷进行持久化设置。Pod支持三种重启策略:Always(默认策略,当容器终止退出后,总是重启容器)、OnFailure(当容器终止且异常退出时,重启)、Never(从不重启);

  •  Pod生命周期

  Pod被分配到一个Node上之后,就不会离开这个Node,直到被删除。当某个Pod失败,首先会被Kubernetes清理掉,之后ReplicationController将会在其它机器上(或本机)重建Pod,重建之后Pod的ID发生了变化,那将会是一个新的Pod。所以,Kubernetes中Pod的迁移,实际指的是在新Node上重建Pod。

 

Replication Controller

  Replication Controller确保任意时间都有指定数量的Pod“副本”在运行。如果为某个Pod创建了Replication Controller并且指定3个副本,它会创建3个Pod,并且持续监控它们。如果某个Pod不响应,那么Replication Controller会替换它。

  当创建Replication Controller时,需要指定两个东西:

    1. Pod模板:用来创建Pod副本的模板
    2. Label:Replication Controller需要监控的Pod的标签。RC与Pod的关联是通过Label来实现的。

  使用过程:

  1.   rc.yaml文件

 

apiVersion: v1
kind: ReplicationController
metadata:      #设置rc的元数据
  name: frontend
  labels:
    name: frontend
spec:
  replicas: 3    #设置Pod的具体数量
  selector:    #通过selector来匹配相应的Pod的label
    name: frontend
  template:    #设置Pod的模板
    metadata:
     labels:
       name: frontend
    spec:
     containers:
     - name: frontend
       image: kubeguide/guestbook-php-frontend:latest
    imagePullPolicy: IfNotPresent     #镜像拉取策略,分为Always,Never,IfNotPresent,默认是Always env : - name : GET_HOSTS_FROM value : env ports: - containerPort: 80

yaml字段的含义: 
spec.replicas:副本数量3 
spec.selector:RC通过spec.selector来筛选要控制的Pod 
spec.template:这里写Pod的定义(但不需要apiVersion和kind) 
spec.template.metadata.labels:Pod的label,可以看到这个label与spec.selector相同

这个文件的意思: 
定义一个RC对象,它的名字是frontend(metadata.name:frontend),保证有3个Pod运行(spec.replicas:3),Pod的镜像是kubeguide/guestbook-php-frontend:latest(spec.template.spec.containers.image:kubeguide/guestbook-php-frontend:latest)

  1. 关键在于spec.selector与spec.template.metadata.labels,这两个字段必须相同,否则下一步创建RC会失败。(也可以不写spec.selector,这样默认与spec.template.metadata.labels相同)

RC的常用操作命令:

    通过kubectl创建RC

    # kubectl create -f rc.yaml

    查看RC具体信息

    # kubectl describe rc frontend

    通过RC修改Pod副本数量(需要修改yaml文件的spec.replicas字段到目标值,然后替换旧的yaml文件)

    # kubectl replace -f rc.yaml

    或

    # kubect edit replicationcontroller frontend

    对RC使用滚动升级,来发布新功能或修复BUG

    # kubectl rolling-update frontend --image=kubeguide/guestbook-php-frontend:latest

    当Pod中只有一个容器时,通过–image参数指定新的Tag完成滚动升级,但如果有多个容器或其他字段修改时,需要指定yaml文件

     # kubectl rolling-update frontend -f FILE.yaml

    如果在升级过程中出现问题(如发现配置错误、长时间无响应),可以使用CTRL+C退出,再进行回滚

     # kubectl rolling-update frontend --image=kubeguide/guestbook-php-frontend:latest --rollback

     但如果升级完成后出现问题(比如新版本程序出core),此命令就无能为力了。我们需要使用同样方法,利用原来的镜像,“升级”为旧版本。

 

Deployment

  更加方便的管理Pod和Replica Set

  k8s是一个高速发展的项目,在新的版本中,官方推荐使用Replica Set和Deployment来代替RC。那么它们优势在哪里,我们来看一看:

  • RC只支持基于等式的selector(env=dev或environment!=qa),但Replica Set还支持新的,基于集合的selector(version in (v1.0, v2.0)或env notin (dev, qa)),这对复杂的运维管理很方便。

  • 使用Deployment升级Pod,只需要定义Pod的最终状态,k8s会为你执行必要的操作,虽然能够使用命令# kubectl rolling-update完成升级,但它是在客户端与服务端多次交互控制RC完成的,所以REST API中并没有rolling-update的接口,这为定制自己的管理系统带来了一些麻烦。

  • Deployment拥有更加灵活强大的升级、回滚功能。

目前,Replica Set与RC的区别只是支持的selector不同,后续肯定会加入更多功能。Deployment使用了Replica Set,它是更高一层的概念。除非用户需要自定义升级功能或根本不需要升级Pod,在一般情况下,我们推荐使用Deployment而不直接使用Replica Set。

  Deployment的一些基础命令。

$ kubectl describe deployments  #查询详细信息,获取升级进度
$ kubectl rollout pause deployment/nginx-deployment2  #暂停升级
$ kubectl rollout resume deployment/nginx-deployment2  #继续升级
$ kubectl rollout undo deployment/nginx-deployment2  #升级回滚
$ kubectl scale deployment nginx-deployment --replicas 10  #弹性伸缩Pod数量
 

  使用子命令create,创建Deployment

  # kubectl create -f deployment.yaml --record

  注意–record参数,使用此参数将记录后续创建对象的操作,方便管理与问题追溯

  使用子命令edit,编辑spec.replicas/spec.template.spec.container.image字段,完成deployment的扩缩容与滚动升级(这要比子命令rolling-update速度快很多)

  # kubectl edit deployment hello-deployment

  使用rollout history命令,查看Deployment的历史信息

  # kubectl rollout history deployment hello-deployment

  上面提到RC在rolling-update升级成功后不能直接回滚,而使用Deployment却可以回滚到上一版本,但要加上–revision参数,指定版本号

  # kubectl rollout history deployment hello-deployment --revision=2

  使用rollout undo回滚到上一版本

  # kubectl rollout undo deployment hello-deployment 

  使用–to-revision可以回滚到指定版本

  # kubectl rollout undo deployment hello-deployment --to-revision=2

 

Volume

    在Docker中,容器中的数据是临时的,当容器被销毁时,其中的数据将会丢失。如果需要持久化数据,需要使用Docker数据卷挂载宿主机上的文件或者目录到容器中。Docker中有docker Volume的概念,Docker的Volume只是磁盘中的一个目录,生命周期不受管理。当然Docker现在也提供Volume将数据持久化存储,但支持功能比较少(例如,对于Docker 1.7,每个容器只允许挂载一个Volume,并且不能将参数传递给Volume)。
    在Kubernetes中,当Pod重建的时候,数据也会丢失,Kubernetes也是通过数据卷挂载来提供Pod数据的持久化的。Kubernetes数据卷是对Docker数据卷的扩展,Kubernetes数据卷是Pod级别的,可以用来实现Pod中容器的文件共享。Kubernetes Volume具有明确的生命周期 - 与pod相同。因此,Volume的生命周期比Pod中运行的任何容器要持久,在容器重新启动时可以保留数据,当然,当Pod被删除不存在时,Volume也将消失。注意,Kubernetes支持许多类型的Volume,Pod可以同时使用任意类型/数量的Volume。
    要使用Volume,pod需要指定Volume的类型和内容(spec.volumes字段),和映射到容器的位置(spec.containers.volumeMounts字段)。
    容器中的进程可以看到Docker image和volumes组成的文件系统。Docker image处于文件系统架构的root,任何volume都映射在镜像的特定路径上。Volume不能映射到其他volume上,或者硬链接到其他volume。容器中的每个容器必须堵路地指定他们要映射的volume。

  Kubernetes支持Volume类型有:

  • emptyDir
  • hostPath
  • gcePersistentDisk
  • awsElasticBlockStore
  • nfs
  • iscsi
  • fc (fibre channel)
  • flocker
  • glusterfs
  • rbd
  • cephfs
  • gitRepo
  • secret
  • persistentVolumeClaim
  • downwardAPI
  • projected
  • azureFileVolume
  • azureDisk
  • vsphereVolume
  • Quobyte
  • PortworxVolume
  • ScaleIO
  • StorageOS
  • local

  emptyDir

  使用emptyDir,当Pod分配到Node上时,将会创建emptyDir,并且只要Node上的Pod一直运行,Volume就会一直存。当Pod(不管任何原因)从Node上被删除时,emptyDir也同时会删除,存储的数据也将永久删除。注:删除容器不影响emptyDir。

  从名称就可以看出,它的初始内容为空。同一个pod中所有容器可以读和写emptyDir中的相同文件。

emptyDir的用途:

  • 临时空间,例如用于某些应用程序运行时所需的临时目录,且无需永久保存;
  • 长时间任务的中间过程CheckPoint临时保存目录;
  • 一个容器需要从另一个容器中获取数据的目录(多容器共享目录)

示例:

apiVersion: v1
kind: Pod
metadata:
  name: test-pd
spec:
  containers:
  - image: gcr.io/google_containers/test-webserver
    name: test-container
    volumeMounts:
    - mountPath: /cache
      name: cache-volume
  volumes:
  - name: cache-volume
    emptyDir: {}

  hostPath

  hostPath允许挂载Node上的文件系统到Pod里面去。如果Pod需要使用Node上的文件,可以使用hostPath。

hostPath通常应用于:

  • 容器应用程序生成的日志文件需要永久保存,可以使用宿主机的高速文件系统进行存储;
  • 需要访问宿主机上Docker引擎内部数据结构的容器应用,可以通过定义hostpath为宿主机/var/lib/docker目录,使得容器内部应用可以直接访问Docker的文件系统。

使用此类型的Volume时需注意:

  在不同Node上具有相同配置的Pod可能会因为宿主机上的目录和文件不用而导致对Volume上目录和文件的访问结果不一致

示例

apiVersion: v1
kind: Pod
metadata:
  name: test-pd
spec:
  containers:
  - image: gcr.io/google_containers/test-webserver
    name: test-container
    volumeMounts:
    - mountPath: /test-pd  #容器路径
      name: test-volume
  volumes:
  - name: test-volume
    hostPath:
      # directory location on host
      path: /data      #宿主机路径

  gcePersistentDisk

  gcePersistentDisk可以挂载GCE上的永久磁盘到容器,需要Kubernetes运行在GCE的VM中。与emptyDir不同,Pod删除时,gcePersistentDisk被删除,但Persistent Disk 的内容任然存在。这就意味着gcePersistentDisk能够允许我们提前对数据进行处理,而且这些数据可以在Pod之间“切换”。

提示:使用gcePersistentDisk,必须用gcloud或使用GCE API或UI 创建PD

创建PD

使用GCE PD与pod之前,需要创建它

gcloud compute disks create --size=500GB --zone=us-central1-a my-data-disk

示例

apiVersion: v1
kind: Pod
metadata:
  name: test-pd
spec:
  containers:
  - image: gcr.io/google_containers/test-webserver
    name: test-container
    volumeMounts:
    - mountPath: /test-pd
      name: test-volume
  volumes:
  - name: test-volume
    # This GCE PD must already exist.
    gcePersistentDisk:
      pdName: my-data-disk
      fsType: ext4

  awsElasticBlockStore

  awsElasticBlockStore可以挂载AWS上的EBS盘到容器,需要Kubernetes运行在AWS的EC2上。与emptyDir Pod被删除情况不同,Volume仅被卸载,内容将被保留。这就意味着awsElasticBlockStore能够允许我们提前对数据进行处理,而且这些数据可以在Pod之间“切换”。

提示:必须使用aws ec2 create-volumeAWS API 创建EBS Volume,然后才能使用。

创建EBS Volume

在使用EBS Volume与pod之前,需要创建它。

aws ec2 create-volume --availability-zone eu-west-1a --size 10 --volume-type gp2

AWS EBS配置示例

apiVersion: v1
kind: Pod
metadata:
  name: test-ebs
spec:
  containers:
  - image: gcr.io/google_containers/test-webserver
    name: test-container
    volumeMounts:
    - mountPath: /test-ebs
      name: test-volume
  volumes:
  - name: test-volume
    # This AWS EBS volume must already exist.
    awsElasticBlockStore:
      volumeID: <volume-id>
      fsType: ext4

  NFS

  NFS 是Network File System的缩写,即网络文件系统。Kubernetes中通过简单地配置就可以挂载NFS到Pod中,而NFS中的数据是可以永久保存的,同时NFS支持同时写操作。Pod被删除时,Volume被卸载,内容被保留。这就意味着NFS能够允许我们提前对数据进行处理,而且这些数据可以在Pod之间相互传递。

  iSCSI

  iscsi允许将现有的iscsi磁盘挂载到我们的pod中,和emptyDir不同的是,删除Pod时会被删除,但Volume只是被卸载,内容被保留,这就意味着iscsi能够允许我们提前对数据进行处理,而且这些数据可以在Pod之间“切换”。

  flocker

  Flocker是一个开源的容器集群数据卷管理器。它提供各种存储后端支持的数据卷的管理和编排。

  glusterfs

  glusterfs,允许将Glusterfs(一个开源网络文件系统)Volume安装到pod中。不同于emptyDir,Pod被删除时,Volume只是被卸载,内容被保留。味着glusterfs能够允许我们提前对数据进行处理,而且这些数据可以在Pod之间“切换”。

  RBD

  RBD允许Rados Block Device格式的磁盘挂载到Pod中,同样的,当pod被删除的时候,rbd也仅仅是被卸载,内容保留,rbd能够允许我们提前对数据进行处理,而且这些数据可以在Pod之间“切换”。

  cephfs

  cephfs Volume可以将已经存在的CephFS Volume挂载到pod中,与emptyDir特点不同,pod被删除的时,cephfs仅被被卸载,内容保留。cephfs能够允许我们提前对数据进行处理,而且这些数据可以在Pod之间“切换”。

提示:可以使用自己的Ceph服务器运行导出,然后在使用cephfs。

  gitRepo

  gitRepo volume将git代码下拉到指定的容器路径中。

示例:

apiVersion: v1
kind: Pod
metadata:
  name: server
spec:
  containers:
  - image: nginx
    name: nginx
    volumeMounts:
    - mountPath: /mypath
      name: git-volume
  volumes:
  - name: git-volume
    gitRepo:
      repository: "git@somewhere:me/my-git-repository.git"
      revision: "22f1d8406d464b0c0874075539c1f2e96c253775"

  secret

  secret volume用于将敏感信息(如密码)传递给pod。可以将secrets存储在Kubernetes API中,使用的时候以文件的形式挂载到pod中,而不用连接api。 secret volume由tmpfs(RAM支持的文件系统)支持。      

  persistentVolumeClaim

  persistentVolumeClaim用来挂载持久化磁盘的。PersistentVolumes是用户在不知道特定云环境的细节的情况下,实现持久化存储(如GCE PersistentDisk或iSCSI卷)的一种方式。

  downwardAPI

  通过环境变量的方式告诉容器Pod的信息

  projected

  Projected volume将多个Volume源映射到同一个目录

目前,可以支持以下类型的卷源:

  • secret
  • downwardAPI
  • configMap

所有卷源都要求与pod在同一命名空间中。

示例

apiVersion: v1
kind: Pod
metadata:
  name: volume-test
spec:
  containers:
  - name: container-test
    image: busybox
    volumeMounts:
    - name: all-in-one
      mountPath: "/projected-volume"
      readOnly: true
  volumes:
  - name: all-in-one
    projected:
      sources:
      - secret:
          name: mysecret
          items:
            - key: username
              path: my-group/my-username
      - downwardAPI:
          items:
            - path: "labels"
              fieldRef:
                fieldPath: metadata.labels
            - path: "cpu_limit"
              resourceFieldRef:
                containerName: container-test
                resource: limits.cpu
      - configMap:
          name: myconfigmap
          items:
            - key: config
              path: my-group/my-config

apiVersion: v1
kind: Pod
metadata:
  name: volume-test
spec:
  containers:
  - name: container-test
    image: busybox
    volumeMounts:
    - name: all-in-one
      mountPath: "/projected-volume"
      readOnly: true
  volumes:
  - name: all-in-one
    projected:
      sources:
      - secret:
          name: mysecret
          items:
            - key: username
              path: my-group/my-username
      - secret:
          name: mysecret2
          items:
            - key: password
              path: my-group/my-password
              mode: 511

  FlexVolume

  alpha功能

  AzureFileVolume

  AzureFileVolume用于将Microsoft Azure文件卷(SMB 2.1和3.0)挂载到Pod中。

  AzureDiskVolume

  Azure是微软提供的公有云服务,如果使用Azure上面的虚拟机来作为Kubernetes集群使用时,那么可以通过AzureDisk这种类型的卷插件来挂载Azure提供的数据磁盘。

  vsphereVolume

  需要条件:配置了vSphere Cloud Provider的Kubernetes。

  vsphereVolume用于将vSphere VMDK Volume挂载到Pod中。卸载卷后,内容将被保留。它同时支持VMFS和VSAN数据存储。

  重要提示:使用POD之前,必须使用以下方法创建VMDK。

  创建一个VMDK卷

  • 使用vmkfstools创建。先将ssh接入ESX,然后使用以下命令创建vmdk
vmkfstools -c 2G /vmfs/volumes/DatastoreName/volumes/myDisk.vmdk
  • 使用vmware-vdiskmanager创建
shell vmware-vdiskmanager -c -t 0 -s 40GB -a lsilogic myDisk.vmdk

示例

apiVersion: v1
kind: Pod
metadata:
  name: test-vmdk
spec:
  containers:
  - image: gcr.io/google_containers/test-webserver
    name: test-container
    volumeMounts:
    - mountPath: /test-vmdk
      name: test-volume
  volumes:
  - name: test-volume
    # This VMDK volume must already exist.
    vsphereVolume:
      volumePath: "[DatastoreName] volumes/myDisk"
      fsType: ext4

  Quobyte

  在kubernetes中使用Quobyte存储,需要提前部署Quobyte软件,要求必须是1.3以及更高版本,并且在kubernetes管理的节点上面部署Quobyte客户端。

  PortworxVolume

  Portworx能把你的服务器容量进行蓄积(pool),将你的服务器或者云实例变成一个聚合的高可用的计算和存储节点。

  PortworxVolume可以通过Kubernetes动态创建,也可以在Kubernetes pod中预先配置和引用。示例:

apiVersion: v1
kind: Pod
metadata:
  name: test-portworx-volume-pod
spec:
  containers:
  - image: gcr.io/google_containers/test-webserver
    name: test-container
    volumeMounts:
    - mountPath: /mnt
      name: pxvol
  volumes:
  - name: pxvol
    # This Portworx volume must already exist.
    portworxVolume:
      volumeID: "pxvol"
      fsType: "<fs-type>"

  ScaleIO

  ScaleIO是一种基于软件的存储平台(虚拟SAN),可以使用现有硬件来创建可扩展共享块网络存储的集群。ScaleIO卷插件允许部署的pod访问现有的ScaleIO卷(或者可以为持久卷声明动态配置新卷,请参阅 Scaleio Persistent Volumes)。

示例:

apiVersion: v1
kind: Pod
metadata:
  name: pod-0
spec:
  containers:
  - image: gcr.io/google_containers/test-webserver
    name: pod-0
    volumeMounts:
    - mountPath: /test-pd
      name: vol-0
  volumes:
  - name: vol-0
    scaleIO:
      gateway: https://localhost:443/api
      system: scaleio
      volumeName: vol-0
      secretRef:
        name: sio-secret
      fsType: xfs

  StorageOS

  StorageOS是一家英国的初创公司,给无状态容器提供简单的自动块存储、状态来运行数据库和其他需要企业级存储功能,但避免随之而来的复杂性、刚性以及成本。

核心:是StorageOS向容器提供块存储,可通过文件系统访问。

StorageOS容器需要64位Linux,没有额外的依赖关系,提供免费开发许可证。

安装说明,请参阅StorageOS文档

apiVersion: v1
kind: Pod
metadata:
  labels:
    name: redis
    role: master
  name: test-storageos-redis
spec:
  containers:
    - name: master
      image: kubernetes/redis:v1
      env:
        - name: MASTER
          value: "true"
      ports:
        - containerPort: 6379
      volumeMounts:
        - mountPath: /redis-master-data
          name: redis-data
  volumes:
    - name: redis-data
      storageos:
        # The `redis-vol01` volume must already exist within StorageOS in the `default` namespace.
        volumeName: redis-vol01
        fsType: ext4

有关动态配置和持久卷声明的更多信息,请参阅StorageOS示例

  Local

  目前处于 Kubernetes 1.7中的 alpha 级别。

Local 是Kubernetes集群中每个节点的本地存储(如磁盘,分区或目录),在Kubernetes1.7中kubelet可以支持对kube-reserved和system-reserved指定本地存储资源。

通过上面的这个新特性可以看出来,Local Storage同HostPath的区别在于对Pod的调度上,使用Local Storage可以由Kubernetes自动的对Pod进行调度,而是用HostPath只能人工手动调度Pod,因为Kubernetes已经知道了每个节点上kube-reserved和system-reserved设置的本地存储限制。

示例:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: example-pv
  annotations:
        "volume.alpha.kubernetes.io/node-affinity": '{
            "requiredDuringSchedulingIgnoredDuringExecution": {
                "nodeSelectorTerms": [
                    { "matchExpressions": [
                        { "key": "kubernetes.io/hostname",
                          "operator": "In",
                          "values": ["example-node"]
                        }
                    ]}
                 ]}
              }'
spec:
    capacity:
      storage: 100Gi
    accessModes:
    - ReadWriteOnce
    persistentVolumeReclaimPolicy: Delete
    storageClassName: local-storage
    local:
      path: /mnt/disks/ssd1

请注意,本地PersistentVolume需要手动清理和删除。

有关local卷类型的详细信息,请参阅 Local Persistent Storage user guide

  Using subPath

  有时,可以在一个pod中,将同一个卷共享,使其有多个用处。volumeMounts.subPath特性可以用来指定卷中的一个子目录,而不是直接使用卷的根目录。

以下是使用单个共享卷的LAMP堆栈(Linux Apache Mysql PHP)的pod的示例。HTML内容映射到其html文件夹,数据库将存储在mysql文件夹中:

apiVersion: v1
kind: Pod
metadata:
  name: my-lamp-site
spec:
    containers:
    - name: mysql
      image: mysql
      volumeMounts:
      - mountPath: /var/lib/mysql
        name: site-data
        subPath: mysql
    - name: php
      image: php
      volumeMounts:
      - mountPath: /var/www/html
        name: site-data
        subPath: html
    volumes:
    - name: site-data
      persistentVolumeClaim:
        claimName: my-lamp-site-data

  Resources

  emptyDir Volume的存储介质(Disk,SSD等)取决于kubelet根目录(如/var/lib/kubelet)所处文件系统的存储介质。不限制emptyDir或hostPath Volume使用的空间大小,不对容器或Pod的资源隔离。

 

Service

  Service是定义一系列Pod以及访问这些Pod的策略的一层抽象因为Service是抽象的,所以在图表里通常看不到它们的存在。

  Service通过Label找到Pod组。当你在Service的yaml文件中定义了该Service的selector中的label为app:my-web,那么这个Service会将Pod-->metadata-->labeks中label为app:my-web的Pod作为分发请求的后端。当Pod发生变化时(增加、减少、重建等),Service会及时更新。这样一来,Service就可以作为Pod的访问入口,起到代理服务器的作用,而对于访问者来说,通过Service进行访问,无需直接感知Pod。

   Service的目标是提供一种桥梁, 它会为访问者提供一个固定访问地址,用于在访问时重定向到相应的后端,这使得非 Kubernetes原生应用程序,在无须为Kubemces编写特定代码的前提下,轻松访问后端。

  需要注意的是,Kubernetes分配给Service的固定IP是一个虚拟IP,并不是一个真实的IP,在外部是无法寻址的。真实的系统实现上,Kubernetes是通过Kube-proxy组件来实现的虚拟IP路由及转发。所以在之前集群部署的环节上,我们在每个Node上均部署了Proxy这个组件,从而实现了Kubernetes层级的虚拟转发网络。有一个特别类型的Kubernetes Service,称为'LoadBalancer',作为外部负载均衡器使用,在一定数量的Pod之间均衡流量。比如,对于负载均衡Web流量很有用。


  现在,假定有2个后台Pod,并且定义后台Service的名称为‘backend-service’,lable选择器为(tier=backend, app=myapp)。backend-service 的Service会完成如下两件重要的事情:

    • 会为Service创建一个本地集群的DNS入口,因此前端Pod只需要DNS查找主机名为 ‘backend-service’,就能够解析出前端应用程序可用的IP地址。
    • 现在前端已经得到了后台服务的IP地址,但是它应该访问2个后台Pod的哪一个呢?Service在这2个后台Pod之间提供透明的负载均衡,会将请求分发给其中的任意一个。通过每个Node上运行的代理(kube-proxy)完成。

 

  Service代理外部服务

    Service不仅可以代理Pod,还可以代理任意其他后端,比如运行在Kubernetes外部Mysql、Oracle等。这是通过定义两个同名的service和endPoints来实现的。示例如下:

redis-service.yaml

apiVersion: v1
kind: Service
metadata:
  name: redis-service
spec:
  ports:
  - port: 6379
    targetPort: 6379
    protocol: TCP

redis-endpoints.yaml

apiVersion: v1
kind: Endpoints
metadata:
  name: redis-service
subsets:
  - addresses:
    - ip: 10.0.251.145
    ports:
    - port: 6379
      protocol: TCP

基于文件创建完Service和Endpoints之后,在Kubernetes的Service中即可查询到自定义的Endpoints。

[root@k8s-master demon]# kubectl describe service redis-service
Name:            redis-service
Namespace:        default
Labels:            <none>
Selector:        <none>
Type:            ClusterIP
IP:            10.254.52.88
Port:            <unset>    6379/TCP
Endpoints:        10.0.251.145:6379
Session Affinity:    None
No events.
[root@k8s-master demon]# etcdctl get /skydns/sky/default/redis-service
{"host":"10.254.52.88","priority":10,"weight":10,"ttl":30,"targetstrip":0}

 

  Service内部负载均衡

    当Service的Endpoints包含多个IP的时候,及服务代理存在多个后端,将进行请求的负载均衡。默认的负载均衡策略是轮训或者随机(有kube-proxy的模式决定)。同时,Service上通过设置Service-->spec-->sessionAffinity=ClientIP,来实现基于源IP地址的会话保持。

  发布Service

    Service的虚拟IP是由Kubernetes虚拟出来的内部网络,外部是无法寻址到的。但是有些服务又需要被外部访问到,例如web前段。这时候就需要加一层网络转发,即外网到内网的转发。Kubernetes提供了NodePort、LoadBalancer、Ingress三种方式。

  • NodePort,在之前的Guestbook示例中,已经延时了NodePort的用法。NodePort的原理是,Kubernetes会在每一个Node上暴露出一个端口:nodePort,外部网络可以通过(任一Node)[NodeIP]:[NodePort]访问到后端的Service。
  • LoadBalancer,在NodePort基础上,Kubernetes可以请求底层云平台创建一个负载均衡器,将每个Node作为后端,进行服务分发。该模式需要底层云平台(例如GCE)支持。
  • Ingress,是一种HTTP方式的路由转发机制,由Ingress Controller和HTTP代理服务器组合而成。Ingress Controller实时监控Kubernetes API,实时更新HTTP代理服务器的转发规则。HTTP代理服务器有GCE Load-Balancer、HaProxy、Nginx等开源方案。

   servicede 自发性机制

    Kubernetes中有一个很重要的服务自发现特性。一旦一个service被创建,该service的service IP和service port等信息都可以被注入到pod中供它们使用。Kubernetes主要支持两种service发现 机制:环境变量和DNS。

   环境变量方式

    Kubernetes创建Pod时会自动添加所有可用的service环境变量到该Pod中,如有需要.这些环境变量就被注入Pod内的容器里。需要注意的是,环境变量的注入只发送在Pod创建时,且不会被自动更新。这个特点暗含了service和访问该service的Pod的创建时间的先后顺序,即任何想要访问service的pod都需要在service已经存在后创建,否则与service相关的环境变量就无法注入该Pod的容器中,这样先创建的容器就无法发现后创建的service。

   DNS方式

    Kubernetes集群现在支持增加一个可选的组件——DNS服务器。这个DNS服务器使用Kubernetes的watchAPI,不间断的监测新的service的创建并为每个service新建一个DNS记录。如果DNS在整个集群范围内都可用,那么所有的Pod都能够自动解析service的域名。

  多个service如何避免地址和端口冲突

    此处设计思想是,Kubernetes通过为每个service分配一个唯一的ClusterIP,所以当使用ClusterIP:port的组合访问一个service的时候,不管port是什么,这个组合是一定不会发生重复的。另一方面,kube-proxy为每个service真正打开的是一个绝对不会重复的随机端口,用户在service描述文件中指定的访问端口会被映射到这个随机端口上。这就是为什么用户可以在创建service时随意指定访问端口。

  service目前存在的不足

    Kubernetes使用iptables和kube-proxy解析service的人口地址,在中小规模的集群中运行良好,但是当service的数量超过一定规模时,仍然有一些小问题。首当其冲的便是service环境变量泛滥,以及service与使用service的pod两者创建时间先后的制约关系。目前来看,很多使用者在使用Kubernetes时往往会开发一套自己的Router组件来替代service,以便更好地掌控和定制这部分功能。

 

posted @ 2018-05-16 10:31  山人是我师  阅读(596)  评论(0编辑  收藏  举报