Kubernetes Storage Classes

本文档介绍了 Kubernetes 中 StorageClass 的概念。建议熟悉  和 Persistent Volume(持久卷)

介绍

StorageClass 为管理员提供了描述他们提供的存储 “class(类)” 的方法。 不同的 class 可能会映射到服务质量等级或备份策略,或由群集管理员确定的任意策略。 Kubernetes 本身不清楚各种 class 代表的什么。这个概念在其他存储系统中有时被称为“配置文件”。

StorageClass 资源

每个 StorageClass 包含 provisioner,parameters 和 reclaimPolicy 字段,当 class 需要动态分配 PersistentVolume 时会使用到。

StorageClass 对象的名称很重要,这是用户请求一个特定的类的方法。 当创建 StorageClass 对象时,管理员设置名称和其他参数,一旦创建了对象就不能对其更新。

管理员可以为没有申请绑定特定 class 的 PVC 指定一个默认的 StorageClass : 更多详情请参阅 PersistentVolumeClaim 章节

kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: standard
provisioner: kubernetes.io/aws-ebs
parameters:
  type: gp2
reclaimPolicy: Retain
mountOptions:
  - debug

Provisioner(存储分配器)

Storage class 有一个分配器,用来决定使用哪个卷插件分配 PV。该字段必须指定。

Volume Plugin Internal Provisioner Config Example
AWSElasticBlockStore AWS
AzureFile Azure File
AzureDisk Azure Disk
CephFS - -
Cinder OpenStack Cinder
FC - -
FlexVolume - -
Flocker -
GCEPersistentDisk GCE
Glusterfs Glusterfs
iSCSI - -
PhotonPersistentDisk -
Quobyte Quobyte
NFS - -
RBD Ceph RBD
VsphereVolume vSphere
PortworxVolume Portworx Volume
ScaleIO ScaleIO
StorageOS StorageOS

您不限于指定此处列出的”内置”分配器(其名称前缀为 kubernetes.io 并打包在 Kubernetes 中)。 您还可以运行和指定外部分配器,这些独立的程序遵循由 Kubernetes 定义的 规范。 外部供应商的作者完全可以自由决定他们的代码保存于何处、打包方式、运行方式、使用的插件(包括Flex)等。 代码仓库 kubernetes-incubator/external-storage 包含一个用于为外部分配器编写功能实现的类库,以及各种社区维护的外部分配器。

例如,NFS 没有内部分配器,但可以使用外部分配器。一些外部分配器列在代码仓库 kubernetes-incubator/external-storage 中。 也有第三方存储供应商提供自己的外部分配器。

回收策略

由 storage class 动态创建的 Persistent Volume 会在的 reclaimPolicy 字段中指定回收策略,可以是 Delete 或者 Retain。如果 StorageClass 对象被创建时没有指定 reclaimPolicy ,它将默认为 Delete。

通过 storage class 手动创建并管理的 Persistent Volume 会使用它们被创建时指定的回收政策。

挂载选项

由 storage class 动态创建的 Persistent Volume 将使用 class 中 mountOptions 字段指定的挂载选项。

如果卷插件不支持安装选项,但指定了安装选项,分配操作将失败。 安装选项在 class 和 PV 上都不会做验证,所以如果安装选项无效,那么这个 PV 就会失败。

参数

Storage class 具有描述属于 storage class 卷的参数。取决于分配器,可以接受不同的参数。 例如,参数 type 的值 io1 和参数 iopsPerGB 特定使用于 EBS。当一个参数被省略时,会使用默认值。

AWS

kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: slow
provisioner: kubernetes.io/aws-ebs
parameters:
  type: io1
  zones: us-east-1d, us-east-1c
  iopsPerGB: "10"
  • type:io1,gp2,sc1,st1。详细信息参见 AWS 文档。默认值:gp2。
  • zone:AWS 区域。如果没有指定 zone 和 zones,通常卷会在 Kubernetes 集群节点所在的活动区域中轮询调度(round-robin)分配。 zone 和 zones 参数不能同时使用。
  • zones:以逗号分隔的 AWS 区域列表。如果没有指定 zone 和 zones,通常卷会在 Kubernetes 集群节点所在的活动区域中轮询调度(round-robin)分配。 zone和zones参数不能同时使用。
  • iopsPerGB:只适用于 io1 卷。每 GiB 每秒 I/O 操作。AWS 卷插件将其与请求卷的大小相乘以计算 IOPS 的容量, 并将其限制在 20000 IOPS(AWS 支持的最高值,请参阅 AWS 文档。 这里需要输入一个字符串,即 "10",而不是 10。
  • encrypted:表示 EBS 卷是否应该被加密。有效值是 "true" 或 "false"。预计需要输入一个字符串,"true",而不是 true。
  • kmsKeyId:可选。加密卷时使用的密钥的完整 Amazon 资源名称。如果没有提供,但 encrypted 值为 true,AWS 生成一个密钥。关于有效的 ARN 值,请参阅 AWS 文档。

GCE

kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: slow
provisioner: kubernetes.io/gce-pd
parameters:
  type: pd-standard
  zones: us-central1-a, us-central1-b
  • type:pd-standard 或者 pd-ssd。默认:pd-standard
  • zone:GCE 区域。如果没有指定 zone 和 zones,通常卷会在 Kubernetes 集群节点所在的活动区域中轮询调度(round-robin)分配。 zone 和 zones 参数不能同时使用。
  • zones:逗号分隔的 GCE 区域列表。如果没有指定 zone 和 zones,通常卷会在 Kubernetes 集群节点所在的活动区域中轮询调度(round-robin)分配。 zone 和 zones 参数不能同时使用。

Glusterfs

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: slow
provisioner: kubernetes.io/glusterfs
parameters:
  resturl: "http://127.0.0.1:8081"
  clusterid: "630372ccdc720a92c681fb928f27b53f"
  restauthenabled: "true"
  restuser: "admin"
  secretNamespace: "default"
  secretName: "heketi-secret"
  gidMin: "40000"
  gidMax: "50000"
  volumetype: "replicate:3"
  • resturl:分配 gluster 卷的需求的 Gluster REST 服务/Heketi 服务 url。 通用格式应该是 IPaddress:Port,这是 GlusterFS 动态分配器的必需参数。 如果 Heketi 服务在 openshift/kubernetes 中安装并暴露为可路由服务,则可以使用类似于 http://heketi-storage-project.cloudapps.mystorage.com 的格式,其中 fqdn 是可解析的 heketi 服务 url。
  • restauthenabled:Gluster REST 服务身份验证布尔值,用于启用对 REST 服务器的身份验证。 如果此值为 ‘true’,则必须填写 restuser 和 restuserkey 或 secretNamespace+ secretName。 此选项已弃用,当在指定 restuser,restuserkey,secretName 或 secretNamespace 时,身份验证被启用。
  • restuser:在 Gluster 可信池中有权创建卷的 Gluster REST服务/Heketi 用户。
  • restuserkey:Gluster REST 服务/Heketi 用户的密码将被用于对 REST 服务器进行身份验证。此参数已弃用,取而代之的是 secretNamespace + secretName。
  • secretNamespace,secretName:Secret 实例的标识,包含与 Gluster REST 服务交互时使用的用户密码。 这些参数是可选的,secretNamespace 和 secretName 都省略是使用空密码。提供的密码必须有 “kubernetes.io/glusterfs” type,例如以这种方式创建:
    kubectl create secret generic heketi-secret \
      --type="kubernetes.io/glusterfs" --from-literal=key='opensesame' \
      --namespace=default
    

    secret 都例子可以在 glusterfs-provisioning-secret.yaml 中找到。

  • clusterid:630372ccdc720a92c681fb928f27b53f 是集群的 ID,当分配卷时,Heketi 将会使用这个文件。 它也可以是一个 clusterid 列表,例如: "8452344e2becec931ece4e33c4674e4e,42982310de6c63381718ccfa6d8cf397"。这个是可选参数。
  • gidMin,gidMax:storage class GID 范围的最小值和最大值。在此范围(gidMin-gidMax)内的唯一值(GID)将用于动态分配卷。 这些是可选的值。如果不指定,卷将被分配一个 2000-2147483647 之间的值,这是 gidMin 和 gidMax 的默认值。
  • volumetype:卷的类型及其参数可以用这个可选值进行配置。如果未声明卷类型,则由分配器决定卷的类型。 例如: ‘Replica volume’: volumetype: replicate:3 其中 ‘3’ 是 replica 数量. ‘Disperse/EC volume’: volumetype: disperse:4:2 其中 ‘4’ 是数据,’2’ 是冗余数量. ‘Distribute volume’: volumetype: none有关可用的卷类型和管理选项,请参阅 管理指南

    更多相关的参考信息,请参阅 如何配置 Heketi

    当动态分配 persistent volume 时,Gluster 插件自动创建一个端点和一个 以 gluster-dynamic- <claimname> 命名的 headless 服务。当 persistent volume claim 删除时,动态端点和服务是自动删除的。

OpenStack Cinder

kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: gold
provisioner: kubernetes.io/cinder
parameters:
  type: fast
  availability: nova
  • type:在 Cinder 中创建的 VolumeType。默认为空。
  • availability:可用区域。如果没有指定,通常卷会在 Kubernetes 集群节点所在的活动区域中轮询调度(round-robin)分配。

vSphere

  1. 使用用户指定的磁盘格式创建一个 StorageClass。
     kind: StorageClass
     apiVersion: storage.k8s.io/v1
     metadata:
       name: fast
     provisioner: kubernetes.io/vsphere-volume
     parameters:
       diskformat: zeroedthick
    

    diskformat: thin, zeroedthick 和 eagerzeroedthick。默认值: "thin"。

  2. 在用户指定的数据存储上创建磁盘格式的 StorageClass。
     kind: StorageClass
     apiVersion: storage.k8s.io/v1
     metadata:
       name: fast
     provisioner: kubernetes.io/vsphere-volume
     parameters:
         diskformat: zeroedthick
         datastore: VSANDatastore
    

    datastore:用户也可以在 StorageClass 中指定数据存储。卷将在 storage class 中指定的数据存储上创建,在这种情况下是 VSANDatastore。 该字段是可选的。如果未指定数据存储,则将在用于初始化 vSphere Cloud Provider 的 vSphere 配置文件中指定的数据存储上创建该卷。

  3. Kubernetes 中的 Storage Policy Management(存储策略管理)
    • 使用现有的 vCenter SPBM 策略vSphere 用于存储管理的最重要特性之一是基于策略的管理。基于存储策略的管理(SPBM)是一个存储策略框架,提供单一的统一控制平面的 跨越广泛的数据服务和存储解决方案。 SPBM 使能 vSphere 管理员克服先期的存储配置挑战,如容量规划,差异化服务等级和管理容量空间。

      SPBM 策略可以在 StorageClass 中使用 storagePolicyName 参数声明。

    • Kubernetes 内的 Virtual SAN 策略支持Vsphere Infrastructure(VI)管理员将能够在动态卷配置期间指定自定义 Virtual SAN 存储功能。 您现在可以定义存储需求,例如性能和可用性,当动态卷供分配时会以存储功能的形式提供。存储功能需求 会转换为 Virtual SAN 策略,然后当 persistent volume(虚拟磁盘)在创建时,会将其推送 到 Virtual SAN 层。虚拟磁盘分布在 Virtual SAN 数据存储中以满足要求。

      更多有关 persistent volume 管理的存储策略的详细信息, 您可以参考 Storage Policy Based Management for dynamic provisioning of volumes

有几个 vSphere 例子 供您在 Kubernetes for vSphere 中尝试进行 persistent volume 管理。

Ceph RBD

kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: fast
provisioner: kubernetes.io/rbd
parameters:
  monitors: 10.16.153.105:6789
  adminId: kube
  adminSecretName: ceph-secret
  adminSecretNamespace: kube-system
  pool: kube
  userId: kube
  userSecretName: ceph-secret-user
  fsType: ext4
  imageFormat: "2"
  imageFeatures: "layering"
  • monitors:Ceph monitor,逗号分隔。该参数是必需的。
  • adminId:Ceph 客户端 ID,用于在池(ceph pool)中创建映像。 默认是 “admin”。
  • adminSecretNamespace:adminSecret 的 namespace。默认是 “default”。
  • adminSecret:adminId 的 Secret 名称。该参数是必需的。 提供的 secret 必须有值为 “kubernetes.io/rbd” 的 type 参数。
  • pool: Ceph RBD 池. 默认是 “rbd”。
  • userId:Ceph 客户端 ID,用于映射 RBD 镜像(RBD image)。默认与 adminId 相同。
  • userSecretName:用于映射 RBD 镜像的 userId 的 Ceph Secret 的名字。 它必须与 PVC 存在于相同的 namespace 中。该参数是必需的。 提供的 secret 必须具有值为 “kubernetes.io/rbd” 的 type 参数,例如以这样的方式创建:
    kubectl create secret generic ceph-secret --type="kubernetes.io/rbd" \
      --from-literal=key='QVFEQ1pMdFhPUnQrSmhBQUFYaERWNHJsZ3BsMmNjcDR6RFZST0E9PQ==' \
      --namespace=kube-system
    
  • fsType:Kubernetes 支持的 fsType。默认:"ext4"。
  • imageFormat:Ceph RBD 镜像格式,”1” 或者 “2”。默认值是 “1”。
  • imageFeatures:这个参数是可选的,只能在你将 imageFormat 设置为 “2” 才使用。 目前支持的功能只是 layering。 默认是 ““,没有功能打开。

Quobyte

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
   name: slow
provisioner: kubernetes.io/quobyte
parameters:
    quobyteAPIServer: "http://138.68.74.142:7860"
    registry: "138.68.74.142:7861"
    adminSecretName: "quobyte-admin-secret"
    adminSecretNamespace: "kube-system"
    user: "root"
    group: "root"
    quobyteConfig: "BASE"
    quobyteTenant: "DEFAULT"
  • quobyteAPIServer:Quobyte API 服务器的格式是 "http(s)://api-server:7860"
  • registry:用于挂载卷的 Quobyte registry。你可以指定 registry 为 <host>:<port> 或者如果你想指定多个 registry,你只需要在他们之间添加逗号,例如 <host1>:<port>,<host2>:<port>,<host3>:<port>。 主机可以是一个 IP 地址,或者如果您有正在运行的DNS,您也可以提供 DNS 名称。
  • adminSecretNamespace:adminSecretName的 namespace。 默认值是 “default”。
  • adminSecretName:保存关于 Quobyte 用户和密码的 secret,用于对 API 服务器进行身份验证。 提供的 secret 必须有值为 “kubernetes.io/quobyte” 的 type 参数,例如以这种方式创建:
    kubectl create secret generic quobyte-admin-secret \
      --type="kubernetes.io/quobyte" --from-literal=key='opensesame' \
      --namespace=kube-system
    
  • user:对这个用户映射的所有访问权限。默认是 “root”。
  • group:对这个组映射的所有访问权限。默认是 “nfsnobody”。
  • quobyteConfig:使用指定的配置来创建卷。您可以创建一个新的配置,或者,可以修改 Web console 或 quobyte CLI 中现有的配置。默认是 “BASE”。
  • quobyteTenant:使用指定的租户 ID 创建/删除卷。这个 Quobyte 租户必须已经于 Quobyte。 默认是 “DEFAULT”。

Azure 磁盘

Azure Unmanaged Disk Storage Class(非托管磁盘存储类)

kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: slow
provisioner: kubernetes.io/azure-disk
parameters:
  skuName: Standard_LRS
  location: eastus
  storageAccount: azure_storage_account_name
  • skuName:Azure 存储帐户 Sku 层。默认为空。
  • location:Azure 存储帐户位置。默认为空。
  • storageAccount:Azure 存储帐户名称。如果提供存储帐户,它必须位于与集群相同的资源组中,并且 location 是被忽略的。 如果未提供存储帐户,则会在与群集相同的资源组中创建新的存储帐户。

新的 Azure 磁盘 Storage Class(从 v1.7.2 开始)

kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: slow
provisioner: kubernetes.io/azure-disk
parameters:
  storageaccounttype: Standard_LRS
  kind: Shared
  • storageaccounttype:Azure 存储帐户 Sku 层。默认为空。
  • kind:可能的值是 shared(默认),dedicated 和 managed。 当 kind 的值是 shared 时,所有非托管磁盘都在集群的同一个资源组中的几个共享存储帐户中创建。 当 kind 的值是 dedicated 时,将为在集群的同一个资源组中新的非托管磁盘创建新的专用存储帐户。
  • Premium VM 可以同时添加 Standard_LRS 和 Premium_LRS 磁盘,而 Standard 虚拟机只能添加 Standard_LRS 磁盘。
  • 托管虚拟机只能连接托管磁盘,非托管虚拟机只能连接非托管磁盘。

Azure 文件

kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: azurefile
provisioner: kubernetes.io/azure-file
parameters:
  skuName: Standard_LRS
  location: eastus
  storageAccount: azure_storage_account_name
  • skuName:Azure 存储帐户 Sku 层。默认为空。
  • location:Azure 存储帐户位置。默认为空。
  • storageAccount:Azure 存储帐户名称。默认为空。 如果不提供存储帐户,会搜索所有与资源相关的存储帐户,以找到一个匹配 skuName 和 location 的账号。 如果提供存储帐户,它必须存在于与集群相同的资源组中,skuName 和 location 会被忽略。

During provision, a secret is created for mounting credentials. If the cluster has enabled both RBAC and Controller Roles, add the create permission of resource secret for clusterrolesystem:controller:persistent-volume-binder. 在分配期间,为挂载凭证创建一个 secret。如果集群同时启用了 RBAC 和 Controller Roles, 为 system:controller:persistent-volume-binder 的 clusterrole 添加 secret 资源的 create 权限。

Portworx 卷

kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: portworx-io-priority-high
provisioner: kubernetes.io/portworx-volume
parameters:
  repl: "1"
  snap_interval:   "70"
  io_priority:  "high"

  • fs:选择的文件系统:[none/xfs/ext4](默认:ext4)。
  • block_size:以 Kbytes 为单位的块大小(默认值:32)。
  • repl:同步副本数量,以复制因子 [1..3](默认值:1)的形式提供。 这里需要填写字符串,即,"1" 而不是 1。
  • io_priority:决定是否从更高性能或者较低优先级存储创建卷 [high/medium/low](默认值:low)。
  • snap_interval:触发快照的时钟/时间间隔(分钟)。快照是基于与先前快照的增量变化,0 是禁用快照(默认:0)。 这里需要填写字符串,即,是 "70" 而不是 70。
  • aggregation_level:指定卷分配到的块数量,0 表示一个非聚合卷(默认:0)。 这里需要填写字符串,即,是 "0" 而不是 0。
  • ephemeral:指定卷在卸载后进行清理还是持久化。 emptyDir 的使用场景可以将这个值设置为 true , persistent volumes 的使用场景可以将这个值设置为 false(例如 Cassandra 这样的数据库)[true/false](默认为 false)。 这里需要填写字符串,即,是 "true" 而不是 true。

ScaleIO

kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: slow
provisioner: kubernetes.io/scaleio
parameters:
  gateway: https://192.168.99.200:443/api
  system: scaleio
  protectionDomain: pd0
  storagePool: sp1
  storageMode: ThinProvisioned
  secretRef: sio-secret
  readOnly: false
  fsType: xfs
  • provisioner:属性设置为 kubernetes.io/scaleio
  • gateway 到 ScaleIO API 网关的地址(必需)
  • system:ScaleIO 系统的名称(必需)
  • protectionDomain:ScaleIO 保护域的名称(必需)
  • storagePool:卷存储池的名称(必需)
  • storageMode:存储提供模式:ThinProvisioned(默认)或 ThickProvisioned
  • secretRef:对已配置的 Secret 对象的引用(必需)
  • readOnly:指定挂载卷的访问模式(默认为 false)

*fsType:卷的文件系统(默认是 ext4)

ScaleIO Kubernetes 卷插件需要配置一个 Secret 对象。 secret 必须用 kubernetes.io/scaleio 类型创建,并与引用它的 PVC 所属的名称空间使用相同的值 如下面的命令所示:

kubectl create secret generic sio-secret --type="kubernetes.io/scaleio" \
--from-literal=username=sioadmin --from-literal=password=d2NABDNjMA== \
--namespace=default

StorageOS

kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: fast
provisioner: kubernetes.io/storageos
parameters:
  pool: default
  description: Kubernetes volume
  fsType: ext4
  adminSecretNamespace: default
  adminSecretName: storageos-secret
  • pool:分配卷的 StorageOS 分布式容量池的名称。如果未指定,则使用通常存在的 default 池。
  • description:分配给动态创建的卷的描述。所有卷描述对于 storage class 都是相同的, 但不同的 storage class 可以使用不同的描述,以区分不同的使用场景。 默认为 Kubernetas volume。
  • fsType:请求的默认文件系统类型。请注意,在 StorageOS 中用户定义的规则可以覆盖此值。默认为 ext4
  • adminSecretNamespace:API 配置 secret 所在的命名空间。如果设置了 adminSecretName,则是必需的。
  • adminSecretName:用于获取 StorageOS API 凭证的 secret 名称。如果未指定,则将尝试默认值。

StorageOS Kubernetes 卷插件可以使用一个 Secret 对象来指定一个用于访问 StorageOS API 的端点和凭据。 只有当默认值已被更改,这才是必须的。 secret 必须使用 kubernetes.io/storageos 类型创建,如以下命令:

kubectl create secret generic storageos-secret \
--type="kubernetes.io/storageos" \
--from-literal=apiAddress=tcp://localhost:5705 \
--from-literal=apiUsername=storageos \
--from-literal=apiPassword=storageos \
--namespace=default

用于动态分配卷的 Secret 可以在任何名称空间中创建,并用 adminSecretNamespace 参数引用。 预先配置的卷使用的 Secret 必须在与引用它的 PVC 在相同的名称空间中。

作者:zhangqx2010 / 原文链接

K8S中文社区微信公众号

通过 rkt 运行 Kubernetes

本文档描述如何使用 rkt 作为容器运行时(runtime)来运行 Kubernetes。

注意:本文档描述如何使用所谓的 “rktnetes”。在以后,Kubernetes 将通过容器运行时接口(CRI)来支持 rkt 运行时(runtime)。目前 rkt shim for the CRI 仍处于实验阶段,不过如果需要使用仍然可以在 kubeadm reference 中找到教程。

前提

  • Systemd 必须安装并且启用。Kubernetes V1.3 要求的 systemd 最低版本是219。Systemd 是用来监控和管理 node 上的 pod 的。
  • 安装最新版的 rkt。要求的 rkt 最低版本是 v1.13.0CoreOS Linux alpha channel 附带了一个最新的 rkt 发布版本,如果必要的话您可以通过 在 CoreOS 上更新 rkt 更新 rkt。
  • rkt API service 必须运行在 node 上。
  • 你需要安装 kubelet 在 node 上,并且建议运行 kube-proxy 在所有 node 上。本文档描述如何设置 kubelet 的参数使其能够使用 rkt 作为运行时(runtime)。

rktnetes 中的 pod 网络

Kubernetes 的 CNI 网络

你可以通过适当地设置 kubelet 的 --network-plugin 和 --network-plugin-dir 参数来让 Kubernetes pod 使用常用的 Container Network Interface(CNI)网络插件。通过这种方法,rkt 可以在不了解网络细节的情况下通过提供的子网来连接 pod。

kubenet:Google Compute Engine(GCE)网络

您能够通过配置 kubelet 的参数 --network-plugin=kubenet 来选择使用 kubenet 插件。该插件目前只支持GCE环境。当使用 kubenet,Kubernetes CNI 将会创建并且管理网络,同时提供一个网桥设备给 rkt 使其能够连接到 GCE 网络。

rkt contained 网络

相对于将网络交给 Kubernetes,rkt 也能通过其自身的 contained 网络 在一个网桥设备提供的子网上直接配置网络连接,如 flannel SDN,或者其它的 CNI 插件。以这种方式配置,rkt 通过查找它的 配置目录,通常位于 /etc/rkt/net.d,来发现 CNI 配置并且调用合适的插件来创建 pod 网络。

通过网桥实现 rkt contained 网络

rkt 默认使用 contained 网络,所以你可以把 kubelet 的 --network-plugin 参数置空让其使用这个默认网络。任意的 CNI 插件都能支持 contained 网络。通过 contained 网络,rkt 将尝试把 pod 连接到一个名为 rkt.kubernetes.io 的网络,所以提供支持的 CNI 配置必须使用这个名称。

如果使用 contained 网络,需要在 rkt 网络配置目录下创建一个网络配置文件,该文件定义如何在您的环境中创建 rkt.kubernetes.io 网络。如下示例展示如何通过 bridge CNI 插件创建一个网桥设备:

$ cat <<EOF >/etc/rkt/net.d/k8s_network_example.conf
{
  "name": "rkt.kubernetes.io",
  "type": "bridge",
  "bridge": "mybridge",
  "mtu": 1460,
  "addIf": "true",
  "isGateway": true,
  "ipMasq": true,
  "ipam": {
    "type": "host-local",
    "subnet": "10.22.0.0/16",
    "gateway": "10.22.0.1",
    "routes": [
      { "dst": "0.0.0.0/0" }
    ]
  }
}
EOF

通过 flannel 实现 rkt contained 网络

目前推荐通过 Kubernetes CNI 的支持来操作 flannel,不过您也可以通过配置 flannel 插件目录来为 rkt 的 contained 网络提供子网。如下提供一个 CNI/flannel 配置文件的示例:

$ cat <<EOF >/etc/rkt/net.d/k8s_flannel_example.conf
{
    "name": "rkt.kubernetes.io",
    "type": "flannel",
    "delegate": {
        "isDefaultGateway": true
    }
}
EOF

如果需要查看更多关于 flannel 的配置信息,请参阅 CNI/flannel README

Contained 网络的注意事项:

  • 对于创建的 CNI 配置文件,其中的网络名称必须为 rkt.kubernetes.io。
  • 向下兼容的 API 和环境变量替换将不包含 pod IP 地址。
  • 尽管提供了 /etc/hostname, 但是 /etc/hosts 文件将不会包含 pod 自己的 hostname。

运行 rktnetes

通过 rkt 运行时(runtime)来运行一个本地的 Kubernetes 集群

如果需要使用 rkt 来作为本地 Kubernetes 集群的容器运行时(container runtime),需要为 kubelet 设置如下参数:

  • --container-runtime=rkt 设置 node 的容器运行时(container runtime)为 rkt。
  • --rkt-api-endpoint=HOST:PORT 设置 rkt API service 的 endpoint。默认为:localhost:15441。
  • --rkt-path=PATH_TO_RKT_BINARY 设置 rkt 二进制的目录。非必填项。如果不设置该参数,则在 $PATH 中查找 rkt。
  • –rkt-stage1-image=STAGE1 设置 stage1 镜像的名字,例如 coreos.com/rkt/stage1-coreos。非必填项。如果不设置,则使用默认的 Linux 内核软件隔离器 stage1。

如果您是使用 hack/local-up-cluster.sh 脚本来启动集群,您可以通过编辑 CONTAINER_RUNTIME,RKT_PATH,和 RKT_STAGE1_IMAGE 环境变量来设置上面这些参数。如果 rkt 已经正确的配置在您的 $PATH中,那么RKT_PATH和RKT_STAGE1_IMAGE` 就都不是必填项。

$ export CONTAINER_RUNTIME=rkt
$ export RKT_PATH=<rkt_binary_path>
$ export RKT_STAGE1_IMAGE=<stage1-name>

现在可以使用 local-up-cluster.sh 脚本来启动集群了:

$ hack/local-up-cluster.sh

同时,我们也尝试在 minikube 中将 rkt 作为容器运行时(container runtime)。

在 Google Compute Engine(GCE)上启动 rktnetes 集群

本节概述如何使用 kube-up 脚本在 GCE 上启动 CoreOS/rkt 集群。

首先需要指定 OS distribution,GCE distributor 的 master project,和 Kubernetes 的 master 和 node 的示例镜像。然后设置 KUBE_CONTAINER_RUNTIME 为 rkt:

$ export KUBE_OS_DISTRIBUTION=coreos
$ export KUBE_GCE_MASTER_PROJECT=coreos-cloud
$ export KUBE_GCE_MASTER_IMAGE=<image_id>
$ export KUBE_GCE_NODE_PROJECT=coreos-cloud
$ export KUBE_GCE_NODE_IMAGE=<image_id>
$ export KUBE_CONTAINER_RUNTIME=rkt

或者,通过设置 KUBE_RKT_VERSION 来指定 rkt 版本:

$ export KUBE_RKT_VERSION=1.13.0

或者,通过设置 KUBE_RKT_STAGE1_IMAGE 来为容器运行时(container runtime)选择另一个 stage1 isolator

$ export KUBE_RKT_STAGE1_IMAGE=<stage1-name>

然后您就可以通过以下命令启动集群:

$ cluster/kube-up.sh

在 AWS 上启动一个 rktnetes 集群

在 AWS 上目前还不支持 kube-up 脚本。不过,我们建议遵循 Kubernetes on AWS guide 在 AWS 上启动一个 CoreOS Kubernetes 集群,然后按照上述配置来设置 kubelet 的选项。

在集群中部署应用

创建集群之后,您就可以开始部署应用了。您可以在 deploy a simple nginx web server 找到一个介绍示例。请注意,您并不需要修改该示例来让其运行在 “rktnetes” 集群上。更多示例可以参阅 Kubernetes examples directory

通过可互换的 stage1 镜像实现模块化隔离

rkt 在一个可互换的隔离环境中运行容器。这个功能被称作 stage1 镜像。目前支持三种 rkt stage1 镜像:

  • 默认使用 systemd-nspawn stage1。通过 Linux kernel namespaces 和 cgroups 来隔离运行态的容器,该行为类似于默认的容器运行时(container runtime)。
  • KVM stage1,在一个 KVM hypervisor-managed 的虚拟机中运行容器。在 Kubernetes v1.3 版本中仍处于实验状态。
  • fly stage1,仅通过 chroot 来隔离容器,从而为需要特殊权限的应用程序提供主机级别的 mount 和网络命名空间权限。

除了上述的三个 stage1 镜像,您也可以根据您自己特定的隔离需求来 [创建您自己的镜像]https://coreos.com/rkt/docs/latest/devel/stage1-implementors-guide.html)。如果不配置,那么将默认使用 default stage1。目前有两种方法来选择不同的 stage1;通过 node 或者通过 pod:

  • 设置 kubelet 的 --rkt-stage1-image 参数来告知 kubelet 为其 node 上的所有 pod 使用哪个 stage1 镜像。例如,--rkt-stage1-image=coreos/rkt/stage1-coreos 将会选择默认的 systemd-nspawn stage1。
  • 设置 rkt.alpha.kubernetes.io/stage1-name-override 注解来覆盖 stage1,stage1 用来执行一个指定的容器。这将允许在同一个集群或者节点上混合使用不同的容器隔离机制。例如,以下的 pod manifest (缩减版)将使用 fly stage1 来运行 pod,从而让它的应用 – 这里就是 kubelet – 能够访问宿主机的命名空间:
apiVersion: v1
kind: Pod
metadata:
  name: kubelet
  namespace: kube-system
  labels:
    k8s-app: kubelet
  annotations:
    rkt.alpha.kubernetes.io/stage1-name-override: coreos.com/rkt/stage1-fly
spec:
  containers:
  - name: kubelet
    image: quay.io/coreos/hyperkube:v1.3.0-beta.2_coreos.0
    command:
    - kubelet
    - --api-servers=127.0.0.1:8080
    - --config=/etc/kubernetes/manifests
    - --allow-privileged
    - --kubeconfig=/etc/kubernetes/kubeconfig
    securityContext:
      privileged: true
[...]

使用不同 stage1 镜像的注意事项

设置 stage1 注解将会潜在的赋予 pod 以 root 权限。所以,pod 的 securityContext 中的 privileged 必须设置为 true。

使用 KVM stage1 时需要配套使用 rkt 的 contained network,因为 CNI 插件驱动目前还没完全支持 hypervisor-based 运行时(runtime)。

rkt 和 Docker 之间已知的问题和差异

rkt 和默认节点容器引擎具有非常不同的设计,就像 rkt 的本地 ACI 和 Docker 的容器镜像格式一样。从一个容器引擎切换到另一个时,用户可能会遇到不同的行为。更多信息请参阅 in the Kubernetes rkt notes

故障排除

以下是一些基于 rkt 容器引擎的 Kubernetes 的故障排除的提示:

检查 rkt 的 pod 状态

如果想要检查正在运行的 pod 的状态,可以使用 rkt 的子命令 rkt listrkt status,和 rkt image list。更多关于 rkt 子命令的信息可参阅 rkt commands documentation

检查 journal 日志

可以在 node 上使用 journalctl 命令来检查 pod 的日志。Pod 是作为 systemd 单元来进行管理和命名的。Pod 的单元名称是通过把 k8s_ 前缀和 pod 的 UUID 串联起来形成的,格式类似于 k8s_${RKT_UUID}。用 rkt list 命令找到 pod 的 UUID 来组成它的服务名,然后使用 journalctl 命令查看日志:

$ sudo journalctl -u k8s_ad623346

日志输出级别

默认情况下,日志级别为2。如果想要查看更多和 rkt 相关的日志信息,可以设置级别为4或更高级别。对于一个本地集群,设置环境变量:LOG_LEVEL=4 即可。

检查 Kubernetes 的事件和日志。

Kubernetes 提供了多种工具以进行问题排查和检测。更多信息可参阅 in the app troubleshooting guide

译者:tianshapjq / 原文链接

K8S中文社区微信公众号

云控制器管理器的基础概念

云控制器管理器

云控制器管理器(CCM)的概念(不要与二进制混淆)最初提出的目的是使得云供应商特定代码和 Kubernetes 核心代码相互独立。 云控制器管理器能够与其他管理组件(如 Kubernetes 控制器管理器、API 服务器、调度器等)一起运行, 也能够以 Kubernetes 插件的形式启动,在这种情况下,它运行在 Kubernetes 之上。

云控制器管理器的设计基于一种插件机制,这种插件机制使得新的云提供商通过使用插件能够很容易地与 Kubernetes 集成。 目前已经有计划在 Kubernetes 中(采用 CCM)集成新的云供应商,并将已有云供应商从旧模型迁移到新的 CCM 模型。

本文讨论了云控制器管理器背后的概念,并详细介绍了它的相关功能。

以下是没有引入云控制器管理器的 Kubernetes 集群架构:

Pre CCM Kube Arch

设计

在上面的图中,Kubernetes 和云提供商通过几个不同的组件集成:

  • Kubelet
  • Kubernetes 控制器管理器
  • Kubernetes API 服务器

CCM 将前面三个组件中所有依赖云服务的逻辑进行合并,形成单一的云服务集成点,引入 CCM 的新架构如下所示:

CCM Kube Arch

CCM 的组件

CCM 将 Kubernetes 控制器管理器(KCM)的一部分功能剥离,并作为独立的进程运行。 具体地说,它将 KCM 中依赖云服务的控制器剥离,KCM 中存在以下依赖云服务的控制器:

  • 节点控制器
  • 卷控制器
  • 路由控制器
  • 服务控制器

在 1.8 版本中, CCM 当前运行上述列表中的以下控制器:

  • 节点控制器
  • 路由控制器
  • 服务控制器

此外,CCM 运行另一个名为 PersistentVolumeLabels 的控制器。 该控制器负责为 GCP 和 AWS 云中创建的 PersistentVolume 设置区域(zone)和地域(region)标签。

注意: 经过深入考虑,我们没有选择将卷控制器作为 CCM 的一部分。 由于(将卷控制器移至 CCM)涉及到的复杂性和已有的对供应商特定的卷逻辑进行抽象的成果,我们决定不将卷控制器移到 CCM 中。

最初计划使用 CCM 支持卷的目的是使用 Flex volume 支持插件式卷。 然而,社区计划采用名为 CSI 的成果来取代 Flex (两者为竞争关系)。

考虑到这些动态,我们决定采取一种临时措施,直到 CSI 就绪。

云供应商工作组(wg-cloud-provider)正致力于使用 CCM 支持 PersistentVolume。 参考 kubernetes/kubernetes#52371.

CCM 的功能

CCM 的功能继承于 Kubernetes 中依赖云供应商的组件。 本节基于 CCM 的功能来源组件展开描述。

1. Kubernetes 控制器管理器

CCM 的功能大部分来自 KCM。 如前一节所述,CCM 运行以下控制回路:

  • 节点控制器
  • 路由控制器
  • 服务控制器
  • PersistentVolumeLabel 控制器

节点控制器

节点控制器负责从云提供商获取集群中运行的节点信息,并用该信息对节点进行初始化。节点控制器执行以下功能:

  1. 以云服务特定的区域/地域标签初始化节点。
  2. 以云服务特定的实例详细信息(如类型、规格)初始化节点。
  3. 获取节点的网络地址和 hostname。
  4. 检查云服务,查看节点是否已从云服务中删除,以防止节点无法响应。 如果节点已从云服务中删除,删除 Kubernetes 中的节点对象。

路由控制器

路由控制器负责在云服务中适当地配置路由,以便 Kubernetes 中不同节点上的容器间能够互相通信。 路由控制器只适用于谷歌计算引擎集群。

服务控制器

服务控制器负责监听服务创建、更新和删除事件。 基于当前 Kubernetes 中的服务状态,配置云负载均衡器(如 ELB 或 Google LB) 来反映 Kubernetes 中的服务状态。 此外,服务控制器保证云负载均衡器的服务后端是最新的。

PersistentVolumeLabel 控制器

在用户创建 AWS EBS 或 GCE PD 卷时,PersistentVolumeLabel 控制器为其设置标签。 这使得用户不必手动为这些卷设置标签。

这些标签对 pod 调度来说是必不可少的,因为这些卷只有在它们所在的地域/区域中才能正常工作,因此任何使用这些卷的 pod 都需要被调度到同样的地域/区域中。

PersistentVolumeLabel 控制器是专门为 CCM 创建的,换句话说,CCM 出现之前该控制器并不存在。 我们创建该控制器,是为了将 Kubernetes API 服务器中为 PV 设置标签的逻辑(通过准入控制器)移到 CCM 中。 该逻辑并不运行在 KCM 中。

2. Kubelet

节点控制器中包含了 kubelet 中依赖云服务的功能。 引入 CCM 之前, kubelet 负责以特定云服务的详细信息(如 IP 地址、 地域/区域标签和实例类型信息)对节点进行初始化。 引入 CCM 后,该初始化操作从 kubelet 移到了 CCM 中。

在这个新的模型中,kubelet 执行初始化节点时不感知特定云服务信息。 然而,它为新创建的节点添加 taint,使得节点处于不可调度的状态,直到 CCM 以特定云服务的信息对节点进行初始化后,才移除该 taint。

3. Kubernets API 服务器

如前面的章节所述,PersistentVolumeLabel 控制器将 Kubernetes API 服务器中依赖云服务的功能移到了 CCM 中。

插件机制

云控制器管理器使用 Go 接口,容许接入任何云服务的实现。 具体地说,它使用 这里 定义的 CloudProvider 接口。

上面强调的四种共享控制器的实现以及共享 cloudprovider 接口相关的一些框架,会保留在 Kubernetes 核心代码中, 但特定云供应商的实现将在核心代码之外,并实现核心代码中定义的接口。

更多插件开发相关的信息,参见 开发云控制器管理器.

授权

本节分解描述 CCM 执行操作所需要的对各种 API 对象的访问权限。

节点控制器

节点控制器只作用于节点对象。 它需要对节点对象的全部访问权限:获取、列举、创建、更新、打补丁(patch)、监视(watch)和删除

v1/Node:

  • Get
  • List
  • Create
  • Update
  • Patch
  • Watch

路由控制器

路由控制器监听节点对象的创建,并适当地配置路由。 它需要节点对象的获取权限。

v1/Node:

  • Get

服务控制器

服务控制器监听服务对象的创建、更新和删除事件,然后适当地为那些服务配置端点(endpoint)。

为访问服务,服务控制器需要列举和监视权限。为更新服务,它需要打补丁和更新权限。

为给服务设置端点,它需要创建、列举、获取、监视和更新的权限。 v1/Service:

  • List
  • Get
  • Watch
  • Patch
  • Update

PersistentVolumeLabel 控制器

PersistentVolumeLabel 控制器监听 PersistentVolume (PV) 创建事件,并对其进行更新。 该控制器需要 PV 对象的列举、监视、 获取和更新权限。

v1/PersistentVolume:

  • Get
  • List
  • Watch
  • Update

其他

CCM 的核心实现需要事件对象的创建权限,同时为保证安全操作,需要创建服务账户(ServiceAccount)的权限。

v1/Event:

  • Create
  • Patch
  • Update

v1/ServiceAccount:

  • Create

CCM 的 RBAC ClusterRole 形如:

apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
  name: cloud-controller-manager
rules:
- apiGroups:
  - ""
  resources:
  - events
  verbs:
  - create
  - patch
  - update
- apiGroups:
  - ""
  resources:
  - nodes
  verbs:
  - '*'
- apiGroups:
  - ""
  resources:
  - nodes/status
  verbs:
  - patch
- apiGroups:
  - ""
  resources:
  - services
  verbs:
  - list
  - patch
  - update
  - watch
- apiGroups:
  - ""
  resources:
  - serviceaccounts
  verbs:
  - create
- apiGroups:
  - ""
  resources:
  - persistentvolumes
  verbs:
  - get
  - list
  - update
  - watch
- apiGroups:
  - ""
  resources:
  - endpoints
  verbs:
  - create
  - get
  - list
  - watch
  - update

云供应商实现

以下云供应商已经实现了针对其自身云服务的 CCM:

集群管理

配置和运行 CCM 的完整说明详见 这里

译者:lichuqiang / 原文链接

K8S中文社区微信公众号

Windows Server 容器

Kubernetes v1.5引入了对Windows Server容器的支持。在版本1.5中,Kubernetes控制面板(API服务器,调度器,控制管理器等)仍然运行在Linux上,但是kubelet和kube-proxy可以运行在Windows Server上。

注意: 在Kubernetes 1.5中,Kubernetes中的Windows Server容器还属于Alpha功能。

前提条件

在Kubernetes v1.5中,Windows Server容器对Kubernetes的支持使用如下方法:

  1. Kubernetes控制面板还是运行在已有的Linux基础设施(v1.5及以后的版本)上
  2. 在Linux节点上搭建Kubenet网络插件
  3. Windows Server 2016 (RTM版本10.0.14393或之后的)
  4. 对Windows Server节点而言,需要Docker 版本 v1.12.2-cs2-ws-beta或之后的(Linux节点和Kubernetes控制面板可以运行在任何支持Docker版本的Kubernetes上)

网络

网络是通过L3路由实现的。由于第三方的网络插件(比如 flannel,calico等)本身在Windows Server上无法工作,它只能依赖于内嵌在Windows和Linux操作系统中的已有技术。在这个L3网络方法中,集群中的节点都选择使用/16的子网,每个工作节点选择/24的子网。在给定工作节点上的所有pod都会连接到/24的子网。这样,在同一个节点上的所有pod就能相互通信。为了激活运行在不同节点上的pod之间的网络,它使用了内嵌在Window server 2016 和Linux内的路由功能。

Linux

以上网络方法在Linux上已经使用网桥接口实现,网桥接口本质上是在节点上创建了一个本地私有网络。与Windows方面一样,为了使用“公开”NIC发送数据包,必须创建到所有其他节点CIDR的路由。

Windows

每个Windows server节点都必须做如下配置:

  1. 每个Windows Server节点都都必须要有两块NIC(虚拟网络适配器) - 这两种Windows容器网络模式(传输层和L2网桥)使用一个外部Hyper-V虚拟交换机。这意味着其中有一个NIC完全分配给该网桥,这也是为什么还需要创建一个NIC。
  2. 创建传输层容器网络 - 这是一个手工配置步骤,会在下面的Route Setup章节中介绍
  3. 启用RRAS(路由)Windows功能 - 允许同一台机器上两个NIC之间的路由,并能“截获”目标地址是运行在该节点上的POD的数据包。要启用该功能,打开“服务器管理”,点击“角色”,“添加角色”,点击“下一步”,选择“网络策略和访问服务”,点击“路由和远程访问服务”,并选择底下的复选框。
  4. 通过“公开”NIC将 - 这些路由添加到内嵌的路由表中,请参考下面的Route Setup章节

以下图表显示了在Windows Server上搭建Kubernetes的网络配置

在Kubernetes上搭建Windows server 容器

要在Kubernetes上运行Windows Server容器,你需要配置你的主机机器和Windows上的Kubernetes节点组件,并为在不同的节点上Pod之间的通信搭建路由。

主机配置

Windows主机配置

  1. Windows Server容器要运行Windows Server 2016 和 Docker v1.12。参考这个博客发表的搭建方法:https://msdn.microsoft.com/en-us/virtualization/windowscontainers/quick_start/quick_start_windows_server
  2. 对Windows DNS的支持最近刚并到docker master中,目前在稳定的docker发布版中还不支持。要使用DNS,你可以从master中构建docker,或从【docker master】(https://master.dockerproject.org/)中下载二进制。
  3. 从https://hub.docker.com/r/apprenda/pause中拖拽apprenda/pause镜像
  4. 启用RRAS(路由) Windows功能
  5. 在PowerShell窗口下运行New-VMSwitch -Name KubeProxySwitch -SwitchType Internal命令来安装类型为‘Internal’的VMSwitch。这会创建一个新的名为vEthernet (KubeProxySwitch)的网络接口。kube-proxy会使用这个接口来添加Service IP。

Linux 主机配置

  1. Linux主机必须根据他们各自发行版的文档和你准备使用的Kubernetes的版本需求来配置。
  2. 安装CNI网络插件。

组件配置

要求

  • Git
  • Go 1.7.1+
  • make (如果使用的是Linux 或 MacOS)
  • 关键注解和其他依赖关系都列在【这里】(https://git.k8s.io/community/contributors/devel/development.md#building-kubernetes-on-a-local-osshell-environment)

kubelet

要构建kubelet,运行:

  1. cd $GOPATH/src/k8s.io/kubernetes
  2. 构建 kubelet
    1. Linux/MacOS: KUBE_BUILD_PLATFORMS=windows/amd64 make WHAT=cmd/kubelet
    2. Windows: go build cmd/kubelet/kubelet.go

kube-proxy

要投建kube-proxy,运行:

  1. cd $GOPATH/src/k8s.io/kubernetes
  2. 构建 kube-proxy
    1. Linux/MacOS: KUBE_BUILD_PLATFORMS=windows/amd64 make WHAT=cmd/kube-proxy
    2. Windows: go build cmd/kube-proxy/proxy.go

路由配置

如下实例配置是假设你有一个Linux和两个Windows Server 2016 节点,以及集群CIDR 192.168.0.0/16。

Hostname Routable IP address Pod CIDR
Lin01 <IP of Lin01 host> 192.168.0.0/24
Win01 <IP of Win01 host> 192.168.1.0/24
Win02 <IP of Win02 host> 192.168.2.0/24

Lin01

ip route add 192.168.1.0/24 via <IP of Win01 host>
ip route add 192.168.2.0/24 via <IP of Win02 host>

Win01

docker network create -d transparent --gateway 192.168.1.1 --subnet 192.168.1.0/24 <network name>

# 创建了一个适配器名为"vEthernet (HNSTransparent)"的网桥。将它的IP地址设置为传输层网络网关
netsh interface ipv4 set address "vEthernet (HNSTransparent)" addr=192.168.1.1
route add 192.168.0.0 mask 255.255.255.0 192.168.0.1 if <Interface Id of the Routable Ethernet Adapter> -p
route add 192.168.2.0 mask 255.255.255.0 192.168.2.1 if <Interface Id of the Routable Ethernet Adapter> -p

Win02

docker network create -d transparent --gateway 192.168.2.1 --subnet 192.168.2.0/24 <network name>

# 创建了一个适配器名为"vEthernet (HNSTransparent)"的网桥。将它的IP地址设置为传输层网络网关
netsh interface ipv4 set address "vEthernet (HNSTransparent)" addr=192.168.2.1
route add 192.168.0.0 mask 255.255.255.0 192.168.0.1 if <Interface Id of the Routable Ethernet Adapter> -p
route add 192.168.1.0 mask 255.255.255.0 192.168.1.1 if <Interface Id of the Routable Ethernet Adapter> -p

启动集群

要启动你的集群,你需要将基于Linux的Kubernetes控制面板和基于Windows Server的Kubernetes节点组件都启动。

启动基于Linux的Kubernetes控制面板

你可以使用喜欢的方式在Linux上启动Kubernetes集群。请注意,该集群的CIDR可能需要更新。

启动Windows节点组件

要在你的Windows节点上启动kubelet: 在PowerShell窗口下运行以下命令。需要注意的是,如果节点重启或进程退出了,你需要重新运行以下命令来重启kubelet

  1. 将环境变量CONTAINER_NETWORK的值设置为docker容器网络 $env:CONTAINER_NETWORK = "<docker network>"
  2. 使用如下命令运行可执行文件 kubelet kubelet.exe --hostname-override=<ip address/hostname of the windows node> --pod-infra-container-image="apprenda/pause" --resolv-conf="" --api_servers=<api server location>

要在你的Windows节点上启动kube-proxy: 使用管理员权限在PowerShell窗口里运行以下命令。需要注意的是,如果节点重启或进程退出了,你需要重新运行以下命令来重启kube-proxy。 .\proxy.exe --v=3 --proxy-mode=userspace --hostname-override=<ip address/hostname of the windows node> --master=<api server location> --bind-address=<ip address of the windows node>

在Windows上调度pod

由于你的集群中既有Linux也有Windows节点,为了能将pod调度到Windows节点上,你必须显示地设置nodeSelector限制条件。你必须把nodeSelector的标签beta.kubernetes.io/os的值设置为windows;请看下面的例子:

{
  "apiVersion": "v1",
  "kind": "Pod",
  "metadata": {
    "name": "iis",
    "labels": {
      "name": "iis"
    }
  },
  "spec": {
    "containers": [
      {
        "name": "iis",
        "image": "microsoft/iis",
        "ports": [
          {
            "containerPort": 80
          }
        ]
      }
    ],
    "nodeSelector": {
      "beta.kubernetes.io/os": "windows"
    }
  }
}

已知限制:

  1. Windows系统没有网络命名空间,因此目前只支持一个pod上只有一个容器。
  2. 由于Windows Server容器的一个问题,Secrets目前不可用。该问题在【这里】描述(https://github.com/docker/docker/issues/28401)。
  3. ConfigMaps目前还没有实现。
  4. kube-proxy的实现使用了netsh portproxy,由于netsh portproxy`只支持TCP,因此只有在客户端使用TCP来重试DNS查询的时候,DNS才会有用。

译者:yybuxiu04 / 原文链接

K8S中文社区微信公众号

Kubernetes 重新配置活动集群中节点的 Kubelet

FEATURE STATE: Kubernetes v1.8 alpha

1.8 版本的 Kubernetes 中包含了一个新的 动态 Kubelet 配置(Dynamic Kubelet Configuration) alpha 功能。该功能可以让您通过顶级 Kubernetes 概念(first-class Kubernetes concepts)改变活动集群中的 Kubelet 的配置。特别的,该功能还允许通过 ConfigMaps 配置单个节点的 Kubelet。

警告: 所有的 Kubelet 配置参数都可以动态修改,但并不是所有的修改都安全。此功能适用于对配置更改会如何影响行为有深刻理解的系统专家。当前没有一个文件列出“对修改安全”的配置域,但我们计划在此功能从 alpha 阶段毕业时添加这个文件。

Before you begin

  • 有一个活动的 Kubernetes 集群,Master 和 Node 均运行 1.8 或更高版本。Kubernetes 打开了 DynamicKubeletConfig 特性开关(feature gate)并设置 Kubelet 的 --dynamic-config-dir 参数为节点上的一个可写目录。必须设置此参数以启用动态 Kubelet 配置。
  • kubectl 命令行工具也必须为 1.8 或更高版本,并能和集群正常通信。

重新配置集群活动节点上的 Kubelet

基本工作流程概览

配置活动集群中的 kubelet 的基本工作流程如下:

  1. 编写一个包含 Kubelet 配置的 YAML 或 JSON 格式的配置文件。
  2. 用 ConfigMap 包装该文件并保存至 Kubernetes 控制平面。
  3. 更新 Kubelet 对应的节点对象以使用此 ConfigMap。

每个 Kubelet 都会监控各自节点对象上的配置引用。当这个引用发生改变时,Kubelet 将下载新的配置并退出。为了使这个功能正常工作,您必须运行一个进程管理器(例如 systemd),以便在 Kubelet 退出时自动对其进行重启。当 Kubelet 重新启动后,它将开始使用新的配置。

新的配置将完全覆盖旧配置;新配置中没有指定的字段将使用典型的默认值。某些 CLI 配置项没有与之关联的配置字段,也不会被新的配置所影响。这些字段在 KubeletFlags 结构体中进行了定义,请参考 这个文件

节点 Kubelet 配置的状态通过节点状态中的 ConfigOK 状态进行报告。一旦使用新的 ConfigMap 对节点进行了升级,您就可以通过观察这个状态确认节点是否正在使用预期的配置。您可以在文章末尾找到描述所有可能状态的表格。

本文描述了通过 kubectl edit 编辑节点的方法。除此之外还有其它修改节点 spec 的方式,例如 kubectl patch 可用于通过脚本配置的工作流程。

本文仅仅介绍了单个节点使用各种 ConfigMap 的场景。这也适用于多个节点使用相同 ConfigMap 的场景。

Node Authorizer 变通方案

Node Authorizer 不会在意哪个 ConfigMap 分配给了哪个节点。如果您目前正在使用 Node authorizer,节点的 Kubelet 将不能自动获得下载各自 ConfigMap 的权限。

本文使用的临时变通方案是为每个 ConfigMap 手动创建 RBAC Role 和 RoleBinding。在动态 Kubelet 配置功能从 alpha 阶段毕业之前,我们将对 Node Authorizer 进行扩展,所以您永远不必在生产环境中这样做。

生成包含当前配置的文件

动态 Kubelet 配置功能允许您对整个配置对象进行覆盖,而不只是单个字段的替换。这种更为简单的模式使得追踪配置值的来源及调试问题变得更加容易。但是,随之而来的问题是您必须知道现存的配置,以确保只对需要的配置字段进行了修改。

将来,Kubelet 将使用磁盘上的文件进行引导(请参考 通过配置文件设置 Kubelet 参数),您可以简单的通过编辑这个文件的副本(作为最佳实践,应该对其进行版本控制)来创建第一个 Kubelet ConfigMap。然而当前 Kubelet 仍然使用命令行参数启动。幸运的是,您可以通过一个脏技巧(dirty trick)生成包含节点当前配置的文件。这个技巧需要通过 kubectl proxy 访问 Kubelet 服务的 configz endpoint。在目前的实现中,这个 endpoint 仅用于辅助调试,这就是为何这是一个脏技巧。改进这个 endpoint 的工作正在进行当中,未来这个操作将变得不是那么 “脏”。这个技巧还要求您的机器安装了 jq 命令行工具,用于对 endpoint 回复的 JSON 响应进行拆包和编辑。

执行下列步骤以生成配置文件:

  1. 选择一个需要重新配置的节点。我们将使用 NODE_NAME 指代这个节点的名字。
  2. 通过 kubectl proxy --port=8001 & 命令在后台启动 kubectl proxy。
  3. 运行下列命令以从 configz endpoint 下载并解包配置。
$ export NODE_NAME=the-name-of-the-node-you-are-reconfiguring
$ curl -sSL http://localhost:8001/api/v1/proxy/nodes/${NODE_NAME}/configz | jq '.kubeletconfig|.kind="KubeletConfiguration"|.apiVersion="kubeletconfig/v1alpha1"' > kubelet_configz_${NODE_NAME}

请注意,我们需要手动为下载的对象添加 kind 和 apiVersion,因为 configz endpoint 没有报告这些值。这是计划在将来进行修复的限制之一。

编辑配置文件

使用文本编辑器改变前面步骤生成的 kubelet_configz_${NODE_NAME} 文件中的某个参数。例如,QPS 参数 eventRecordQPS 是一个不错的选择。

推送配置文件至控制平面

使用下列命令推送编辑后的配置文件至控制平面:

$ kubectl -n kube-system create configmap my-node-config --from-file=kubelet=kubelet_configz_${NODE_NAME} --append-hash -o yaml

您应该看到类似的响应:

apiVersion: v1
data:
  kubelet: |
    {...}
kind: ConfigMap
metadata:
  creationTimestamp: 2017-09-14T20:23:33Z
  name: my-node-config-gkt4c2m4b2
  namespace: kube-system
  resourceVersion: "119980"
  selfLink: /api/v1/namespaces/kube-system/configmaps/my-node-config-gkt4c2m4b2
  uid: 946d785e-998a-11e7-a8dd-42010a800006

请注意,ConfigMap 的 kubelet 键下必须存在配置数据。

我们在 kube-system namespace 中创建这个 ConfigMap,这种选择是恰当的,因为这个 ConfigMap 用于配置 Kubernetes 的系统组件之一 —— Kubelet。

--append-hash 选项将 ConfigMap 内容的短校验和添加到其名称后面。这将为 edit->push 工作流程带来便利,因为它将自动的、确切的为新的 ConfigMap 生成新的名称。

我们使用 -o yaml 输出格式,以便创建的时候输出 name、namespace 和 uid。在后续步骤中我们将需要这些值。我们将使用 CONFIG_MAP_NAME 指代 name,使用 CONFIG_MAP_UID 指代 uid。

授权节点读取新的 ConfigMap

现在您已经创建了一个新的 ConfigMap,您需要授权节点对其进行读取。首先使用下列命令为新的 ConfigMap 创建一个 Role:

$ export CONFIG_MAP_NAME=name-from-previous-output
$ kubectl -n kube-system create role ${CONFIG_MAP_NAME}-reader --verb=get --resource=configmap --resource-name=${CONFIG_MAP_NAME}

接下来,创建一个 RoleBinding 以将节点和新的 Role 进行关联:

$ kubectl -n kube-system create rolebinding ${CONFIG_MAP_NAME}-reader --role=${CONFIG_MAP_NAME}-reader --user=system:node:${NODE_NAME}

一旦将来 Node Authorizer 可以自动进行该工作时,您就可以跳过这个步骤。

设置节点使用新的配置

使用下列命令编辑节点的引用,使其指向新的 ConfigMap。

kubectl edit node ${NODE_NAME}

使用编辑器,在 spec 下添加如下 YAML:

configSource:
    configMapRef:
        name: CONFIG_MAP_NAME
        namespace: kube-system
        uid: CONFIG_MAP_UID

请确保指定了 name、namespace 和 uid 三个配置。

观察节点是否开始使用新的配置

通过 kubectl get node ${NODE_NAME} -o yaml 命令获取节点信息,并在 status.conditions 下查找 ConfigOK 状态。如果 Kubelet 已经开始使用新的配置,您应该能看到类似 Using current (UID: CONFIG_MAP_UID) 的信息。

方便起见,您可以使用下面的命令(使用 jq)筛选 ConfigOK 状态。

$ kubectl get no ${NODE_NAME} -o json | jq '.status.conditions|map(select(.type=="ConfigOK"))'
[
  {
    "lastHeartbeatTime": "2017-09-20T18:08:29Z",
    "lastTransitionTime": "2017-09-20T18:08:17Z",
    "message": "using current (UID: \"2ebc8d1a-9e2a-11e7-a8dd-42010a800006\")",
    "reason": "passing all checks",
    "status": "True",
    "type": "ConfigOK"
  }
]

如果出现问题,您可能会看到几种不同错误状态之一,详情请参阅下面的 ConfigOK Conditions 表格。当这个情况发生时,请检查 Kubelet 日志以获取详细信息。

再次编辑配置文件

如果想要再次改变配置,我们可以简单的重复上述步骤。请尝试编辑 kubelet 文件,为前面修改过的参数设置一个新的值。

推送重新编辑过的配置到控制平面

使用下列命令生成新的 ConfigMap 来推送新配置到控制平面:

$ kubectl create configmap my-node-config --namespace=kube-system --from-file=kubelet=kubelet_configz_${NODE_NAME} --append-hash -o yaml

由于我们改变了内容,这个新的 ConfigMap 会获得一个新的名字。我们将使用 NEW_CONFIG_MAP_NAME 指代新的名字,使用 NEW_CONFIG_MAP_UID 指代新的 uid。

授权节点读取新的 ConfigMap

现在您已经创建了一个新的 ConfigMap,您需要授权节点来对其进行读取。首先,使用下列命令为新的 ConfigMap 创建一个 Role:

$ export NEW_CONFIG_MAP_NAME=name-from-previous-output
$ kubectl -n kube-system create role ${NEW_CONFIG_MAP_NAME}-reader --verb=get --resource=configmap --resource-name=${NEW_CONFIG_MAP_NAME}

接下来,创建一个 RoleBinding 以对节点和新的 Role 进行关联:

$ kubectl -n kube-system create rolebinding ${NEW_CONFIG_MAP_NAME}-reader --role=${NEW_CONFIG_MAP_NAME}-reader --user=system:node:${NODE_NAME}

一旦将来 Node Authorizer 可以自动进行该工作时,您就可以跳过这个步骤。

配置节点使用新的配置

再次使用 kubectl edit node ${NODE_NAME} 命令编辑节点的 spec.configSource。新的 spec.configSource 应该和下面类似,请替换 name 和 uid 为实际值:

configSource:
    configMapRef:
        name: NEW_CONFIG_MAP_NAME
        namespace: kube-system
        uid: NEW_CONFIG_MAP_UID

观察 Kubelet 是否正在使用新的配置

再一次使用 kubectl get node ${NODE_NAME} -o yaml 获取节点信息并在 status.conditions 字段下查看 ConfigOK 状态。当 Kubelet 开始使用新的配置时,您应该可以看见类似 Using current (UID: NEW_CONFIG_MAP_UID) 的信息。

取消对节点读取旧 ConfigMap 的授权

一旦知道了节点已经在使用新的配置并且确信没有引起任何问题时,最好取消对节点读取旧 ConfigMap 的授权。执行下列命令以删除 RoleBinding 和 Role:

$ kubectl -n kube-system delete rolebinding ${CONFIG_MAP_NAME}-reader
$ kubectl -n kube-system delete role ${CONFIG_MAP_NAME}-reader

请注意,这样做并不一定能防止节点读取旧配置,因为它可能会在一段不定的时间内在本地缓存旧 ConfigMap。

你还可以选择删除旧 ConfigMap:

$ kubectl -n kube-system delete configmap ${CONFIG_MAP_NAME}

一旦将来 Node Authorizer 可以自动进行该工作时,您就可以跳过这个步骤。

重置节点以使用本地默认配置

最后,如果希望重置节点并使用启动时的配置,只需要简单的使用 kubectl edit node ${NODE_NAME} 命令编辑节点并去除 spec.configSource 子字段。

观察节点是否正在使用本地默认配置

在去除了这个子字段之后,您应该最终能够观察到 ConfigOK 状态的信息变为 using current (default) 或者 using current (init)(这取决于节点是如何配置的)。

取消对节点读取旧 ConfigMap 的授权

一旦知道了节点已经在使用新的配置并且确信没有引起任何问题时,最好取消对节点读取旧 ConfigMap 的授权。执行下列命令以删除 RoleBinding 和 Role:

$ kubectl -n kube-system delete rolebinding ${NEW_CONFIG_MAP_NAME}-reader
$ kubectl -n kube-system delete role ${NEW_CONFIG_MAP_NAME}-reader

请注意,这样做并不一定能防止节点读取旧配置,因为它可能会在一段不定的时间内在本地缓存旧 ConfigMap。

你还可以选择删除旧 ConfigMap:

$ kubectl -n kube-system delete configmap ${NEW_CONFIG_MAP_NAME}

一旦将来 Node Authorizer 可以自动进行该工作时,您就可以跳过这个步骤。

Kubectl Patch 示例

如上所述,存在多种改变节点配置源的方式。这是一个使用 kubectl patch 命令的示例:

kubectl patch node ${NODE_NAME} -p "{\"spec\":{\"configSource\":{\"configMapRef\":{\"name\":\"${CONFIG_MAP_NAME}\",\"namespace\":\"kube-system\",\"uid\":\"${CONFIG_MAP_UID}\"}}}}"

理解 ConfigOK 状态

下面的表格列举了您在启用了动态 Kubelet 配置的集群中可能遇到的几种 ConfigOK 节点状态。如果您观察到状态为 status=False,请检查 Kubelet 日志并搜索消息或原因的文本,以获取更多关于错误的详细信息。

Possible Messages Possible Reasons Status
using current (default) current is set to the local default, and no init config was provided True
using current (init) current is set to the local default, and an init config was provided True
using current (UID: CURRENT_CONFIG_MAP_UID) passing all checks True
using last-known-good (default)
  • failed to load current (UID: CURRENT_CONFIG_MAP_UID)
  • failed to parse current (UID: CURRENT_CONFIG_MAP_UID)
  • failed to validate current (UID: CURRENT_CONFIG_MAP_UID)
False
using last-known-good (init)
  • failed to load current (UID: CURRENT_CONFIG_MAP_UID)
  • failed to parse current (UID: CURRENT_CONFIG_MAP_UID)
  • failed to validate current (UID: CURRENT_CONFIG_MAP_UID)
False
using last-known-good (UID: LAST_KNOWN_GOOD_CONFIG_MAP_UID)
  • failed to load current (UID: CURRENT_CONFIG_MAP_UID)
  • failed to parse current (UID: CURRENT_CONFIG_MAP_UID)
  • failed to validate current (UID: CURRENT_CONFIG_MAP_UID)
False
The reasons in the next column could potentially appear for any of the above messages.

This condition indicates that the Kubelet is having trouble reconciling `spec.configSource`, and thus no change to the in-use configuration has occurred.

The "failed to sync" reasons are specific to the failure that occurred, and the next column does not necessarily contain all possible failure reasons.

failed to sync, reason:

  • failed to read Node from informer object cache
  • failed to reset to local (default or init) config
  • invalid NodeConfigSource, exactly one subfield must be non-nil, but all were nil
  • invalid ObjectReference, all of UID, Name, and Namespace must be specified
  • invalid ObjectReference, UID SOME_UID does not match UID of downloaded ConfigMap SOME_OTHER_UID
  • failed to determine whether object with UID SOME_UID was already checkpointed
  • failed to download ConfigMap with name SOME_NAME from namespace SOME_NAMESPACE
  • failed to save config checkpoint for object with UID SOME_UID
  • failed to set current config checkpoint to default
  • failed to set current config checkpoint to object with UID SOME_UID

译者:xiaosuiba / 原文链接

K8S中文社区微信公众号

Kubernetes 对 DaemonSet 执行回滚

Before you begin

  • DaemonSet 滚动升级历史和 DaemonSet 回滚特性仅在 Kubernetes 1.7 及以后版本的 kubectl 中支持。
  • 确保您了解如何 对 DaemonSet 执行滚动升级

对 DaemonSet 执行回滚

步骤 1: 找到想要 DaemonSet 回滚到的历史版本(revision)

如果只想回滚到最后一个版本,可以跳过这一步。

列出 DaemonSet 的所有版本:

kubectl rollout history daemonset <daemonset-name>

该命令返回 DaemonSet 版本列表:

daemonsets "<daemonset-name>"
REVISION        CHANGE-CAUSE
1               ...
2               ...
...
  • 在创建时,DaemonSet 的变化原因从 kubernetes.io/change-cause 注解(annotation)复制到其版本中。 用户可以在 kubectl 中指定 --record=true ,将执行的命令记录在变化原因注解中。

执行以下命令,来查看指定版本的详细信息:

kubectl rollout history daemonset <daemonset-name> --revision=1

该命令返回相应版本的详细信息:

daemonsets "<daemonset-name>" with revision #1
Pod Template:
Labels:       foo=bar
Containers:
app:
 Image:       ...
 Port:        ...
 Environment: ...
 Mounts:      ...
Volumes:       ...

步骤 2: 回滚到指定版本

# 在 --to-revision 中指定您从步骤 1 中获取的版本序号
kubectl rollout undo daemonset <daemonset-name> --to-revision=<revision>

如果成功,命令会返回:

daemonset "<daemonset-name>" rolled back

如果 --to-revision 参数未指定,将选中最近的版本。

步骤 3: 观察 DaemonSet 回滚进度

kubectl rollout undo daemonset 向服务器表明启动 DaemonSet 回滚。 真正的回滚是在服务器端异步完成的。

执行以下命令,来观察 DaemonSet 回滚进度:

kubectl rollout status ds/<daemonset-name> 

回滚完成时,输出形如:

daemonset "<daemonset-name>" successfully rolled out

理解 DaemonSet 版本

在前面的 kubectl rollout history 步骤中,您获得了一个版本列表,每个版本都存储在名为 ControllerRevision 的资源中。 ControllerRevision 仅在 Kubernetes 1.7 及以后的版本中可用。

查找原始的版本资源,来查看每个版本中存储了什么内容:

kubectl get controllerrevision -l <daemonset-selector-key>=<daemonset-selector-value>

该命令返回 ControllerRevisions 列表:

NAME                               CONTROLLER                     REVISION   AGE
<daemonset-name>-<revision-hash>   DaemonSet/<daemonset-name>     1          1h
<daemonset-name>-<revision-hash>   DaemonSet/<daemonset-name>     2          1h

每个 ControllerRevision 中存储了相应 DaemonSet 版本的注解和模板。

kubectl rollout undo 采用特定 ControllerRevision ,并用 ControllerRevision 中存储的模板代替 DaemonSet 的模板。 kubectl rollout undo 相当于通过其他命令(如 kubectl edit 或 kubectl apply)将 DaemonSet 模板更新至先前的版本。

注意 DaemonSet 版本只会向前滚动。 也就是说,回滚完成后,所回滚到的 ControllerRevision 版本号 (.revision 字段) 会增加。 例如,如果用户在系统中有版本 1 和版本 2,并从版本 2 回滚到版本 1 ,带有 .revision: 1 的ControllerRevision 将变为 .revision: 3。

故障排除

译者:lichuqiang / 原文链接

K8S中文社区微信公众号