Kubernetes 高级特性集锦

1.前言

kubernetes 项目发展至今,社区出现了很多非常优秀的特性,这些特性极大地扩展了Kubernetes的能力。目前很多公司基于Google Kubernetes 和 Docker 打造各自的私有化PaaS平台,这些高级特性往往是PaaS平台需要的,深入了解这些特性能够帮助架构设计人员快速确定技术方案,达到事半功倍的效果。目前很多PaaS平台都通过开放Kubernetes 特性,获得了很好的效果。

2.特性介绍

1)集群联邦

用户在生产环境部署微服务时有一个非常明确的需求,那就是希望服务部署能够跨zone、跨区域、跨集群甚至跨云边界。相对于单个集群的服务部署模式,跨集群服务能够提供按地域分布的服务,支持混合云、多云场景,全面提升服务的高可用等级。服务使用者希望服务无论在集群内部还是外部,都有稳定、一致的连接。

从Kubernetes的角度来说,以前只针对一个集群进行管理即可,加入集群联邦特性之后,就需要一个"集群控制器",通过这个控制器控制各个集群。各个集群在集群控制器中有相应的标识,发送的命令通过集群控制器进行转发。


从上图可以看出,用户通过UI、CLI、API发起的请求,最终汇集到集群联邦控制面板,集群控制面板负责与各个集群进行交互。更为详细信息请查看:

http://blog.kubernetes.io/2016/07/cross-cluster-services.html

2) 有状态应用

众所周知,Pod在Kubernetes中是会发生漂移的。比如节点出现故障,应用会迁移到正常节点。对于无状态应用,这是没有问题的,但是针对有状态应用,这种方式则不可取,因为迁移之后,应用的状态(比如写在节点上的临时文件)不会随着应用迁移,会引起状态不一致的问题。比如Mysql,Mongodb,Zookeeper等引用,必须挂载数据卷并且支持稳定的访问。

无状态的概念,就是只负责运算,不负责任何数据的存储,这样就能很轻松地做到水平扩展。对于无状态应用,如何做到水平扩展呢?谷歌提出了解决方案,Pod负责运行无状态应用,PetSet负责有状态应用。

PetSet 作为运行有状态应用的基础,需要具体以下条件:

* 有唯一的编号

* 在网络上有一个不会改变的标识,k8s是通过域名实现的。pod则是名字后面还有随机数,所以需要有service来做转发

* 每个有状态服务,都需要有自己的卷,这样就能保证数据可靠存储

PetSet.yaml 如下:

# A headless service to create DNS records
apiVersion: v1
kind: Service
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  ports:
  - port: 80
    name: web
  # *.nginx.default.svc.cluster.local
  clusterIP: None
  selector:
    app: nginx
---
apiVersion: apps/v1alpha1
kind: PetSet
metadata:
  name: web
spec:
  serviceName: "nginx"
  replicas: 2
  template:
    metadata:
      labels:
        app: nginx
      annotations:
        pod.alpha.kubernetes.io/initialized: "true"
    spec:
      terminationGracePeriodSeconds: 0
      containers:
      - name: nginx
        image: gcr.io/google_containers/nginx-slim:0.8
        ports:
        - containerPort: 80
          name: web
        volumeMounts:
        - name: www
          mountPath: /usr/share/nginx/html
  volumeClaimTemplates:
  - metadata:
      name: www
      annotations:
        volume.alpha.kubernetes.io/storage-class: anything
    spec:
      accessModes: [ "ReadWriteOnce" ]
      resources:
        requests:
          storage: 1Gi
从yaml中可以看出,Service以PetSet中的Pet作为后端Pod,并且PetSet挂载了持久化存储。同时,PetSet支持以下功能:

* Peer discovery

* PetSet Update

* PetSet 扩容

* 镜像升级

* PetSet删除(仅仅删除PetSet不会删除挂载的持久化存储,如果要在删除PetSet同时删除PVC,需要使用--cascade=false参数)

Kubernetes Petset 官方文档:

http://kubernetes.io/docs/user-guide/petset/

3)Init-Container

在Pod真正运行起来之前,通常有一些初始化的动作需要做,比如初始化本地数据(可能是一些配置)。Pod里面的多个Container(至少一个),在挂载volume之后,并行地进行初始化。

K8S 为了解决Container在运行之前的初始化工作,引入了init-container的概念。一个Init container的定义如下:

apiVersion: v1
kind: Pod
metadata:
  name: kubectl
  annotations:
    pod.alpha.kubernetes.io/init-containers: '[
        {
            "name": "download",
            "image": "busybox",
            "command": [
                "wget", 
            "-O", 
                "/work-dir/kubectl", 
                "http://storage.googleapis.com/kubernetes-release/release/v1.2.4/bin/linux/amd64/kubectl"
            ],
            "volumeMounts": [
                {
                    "name": "workdir",
                    "mountPath": "/work-dir"
                }
            ]
        },
        {
            "name": "chmod",
            "image": "busybox",
            "command": ["chmod", "755", "/work-dir/kubectl"],
            "volumeMounts": [
                {
                    "name": "workdir",
                    "mountPath": "/work-dir"
                }
            ]
        }
    ]'
spec:
  containers:
  - name: kubectl
    image: busybox
    command:
    - /bin/sleep
    - "36000"
    volumeMounts:
    - name: workdir
      mountPath: /usr/local/bin
  dnsPolicy: Default
  volumes:
  - name: workdir
    emptyDir: {}
这里的init container包含两个容器,一个负责下载,另一个负责修改权限。在busybox加载之前完成所有操作,这非常符合init container的设计意图。

这个应用场景是将kubectl容器化处理,首先现在kubectl二进制,然后切换执行权限,一旦Kubectl二进制有版本变更,仅需要升级二进制,重启pod即可。使用方式如下:

kubectl exec -t -i kubectl kubectl version
Client Version: version.Info{Major:"1", Minor:"2", GitVersion:"v1.2.4", GitCommit:"3eed1e3be6848b877ff80a93da3785d9034d0a4f", GitTreeState:"clean"}
Server Version: version.Info{Major:"1", Minor:"3+", GitVersion:"v1.3.0-beta.2", GitCommit:"caf9a4d87700ba034a7b39cced19bd5628ca6aa3", GitTreeState:"clean"}

官方设计文档在此:
https://github.com/kubernetes/kubernetes/blob/master/docs/proposals/container-init.md

4)configmap

应用通常需要很多配置参数,这些配置参数通常都以Container环境变量的形式传入容器内部,能够有一个k8s对象,保存通用的配置参数呢?

k8s提供了configmap对象,这个对象存储了map(key、value)形式的参数。一个configmap定义如下:

kind: ConfigMap
apiVersion: v1
metadata:
  creationTimestamp: 2016-02-18T19:14:38Z
  name: example-config
  namespace: default
data:
  example.property.1: hello
  example.property.2: world
  example.property.file: |-
    property.1=value-1
    property.2=value-2
    property.3=value-3
configmap使用场景如下:

* ConfigMap 作为环境变量使用

configmap:

apiVersion: v1
kind: ConfigMap
metadata:
  name: special-config
  namespace: default
data:
  special.how: very
  special.type: charm
Pod:

apiVersion: v1
kind: Pod
metadata:
  name: dapi-test-pod
spec:
  containers:
    - name: test-container
      image: gcr.io/google_containers/busybox
      command: [ "/bin/sh", "-c", "env" ]
      env:
        - name: SPECIAL_LEVEL_KEY
          valueFrom:
            configMapKeyRef:
              name: special-config
              key: special.how
        - name: SPECIAL_TYPE_KEY
          valueFrom:
            configMapKeyRef:
              name: special-config
              key: special.type
  restartPolicy: Never
* 作为命令行参数

configmap:

apiVersion: v1
kind: ConfigMap
metadata:
  name: special-config
  namespace: default
data:
  special.how: very
  special.type: charm
pod:

apiVersion: v1
kind: Pod
metadata:
  name: dapi-test-pod
spec:
  containers:
    - name: test-container
      image: gcr.io/google_containers/busybox
      command: [ "/bin/sh", "-c", "echo $(SPECIAL_LEVEL_KEY) $(SPECIAL_TYPE_KEY)" ]
      env:
        - name: SPECIAL_LEVEL_KEY
          valueFrom:
            configMapKeyRef:
              name: special-config
              key: special.how
        - name: SPECIAL_TYPE_KEY
          valueFrom:
            configMapKeyRef:
              name: special-config
              key: special.type
  restartPolicy: Never
* 挂载卷

configmap:

apiVersion: v1
kind: ConfigMap
metadata:
  name: special-config
  namespace: default
data:
  special.how: very
  special.type: charm
pod:

apiVersion: v1
kind: Pod
metadata:
  name: dapi-test-pod
spec:
  containers:
    - name: test-container
      image: gcr.io/google_containers/busybox
      command: [ "/bin/sh", "-c", "cat /etc/config/special.how" ]
      volumeMounts:
      - name: config-volume
        mountPath: /etc/config
  volumes:
    - name: config-volume
      configMap:
        name: special-config
  restartPolicy: Never

官方资料在此:http://kubernetes.io/docs/user-guide/configmap/

3. Template

在kubernetes中,创建应用涉及到的对象比较多,通常需要很多参数。用户如果没有模版,每次都需要配置很多参数。在反复创建过程中,效率很低。

K8S 提供了模版能力,开放该能力能够帮助用户快速创建应用。一个应用模版实例如下:

MySql:

https://github.com/openshift/origin/blob/master/examples/db-templates/mysql-persistent-template.json

Jekins:

https://github.com/openshift/origin/blob/master/examples/jenkins/jenkins-persistent-template.json

目前主要使用PodTemplate,里面主要涉及Pod的定义(镜像、挂卷等等)

// PodSpec is a description of a pod
type PodSpec struct {
	Volumes []Volume `json:"volumes"`
	// List of initialization containers belonging to the pod.
	InitContainers []Container `json:"-"`
	// List of containers belonging to the pod.
	Containers    []Container   `json:"containers"`
	RestartPolicy RestartPolicy `json:"restartPolicy,omitempty"`
	// Optional duration in seconds the pod needs to terminate gracefully. May be decreased in delete request.
	// Value must be non-negative integer. The value zero indicates delete immediately.
	// If this value is nil, the default grace period will be used instead.
	// The grace period is the duration in seconds after the processes running in the pod are sent
	// a termination signal and the time when the processes are forcibly halted with a kill signal.
	// Set this value longer than the expected cleanup time for your process.
	TerminationGracePeriodSeconds *int64 `json:"terminationGracePeriodSeconds,omitempty"`
	// Optional duration in seconds relative to the StartTime that the pod may be active on a node
	// before the system actively tries to terminate the pod; value must be positive integer
	ActiveDeadlineSeconds *int64 `json:"activeDeadlineSeconds,omitempty"`
	// Required: Set DNS policy.
	DNSPolicy DNSPolicy `json:"dnsPolicy,omitempty"`
	// NodeSelector is a selector which must be true for the pod to fit on a node
	NodeSelector map[string]string `json:"nodeSelector,omitempty"`

	// ServiceAccountName is the name of the ServiceAccount to use to run this pod
	// The pod will be allowed to use secrets referenced by the ServiceAccount
	ServiceAccountName string `json:"serviceAccountName"`

	// NodeName is a request to schedule this pod onto a specific node.  If it is non-empty,
	// the scheduler simply schedules this pod onto that node, assuming that it fits resource
	// requirements.
	NodeName string `json:"nodeName,omitempty"`
	// SecurityContext holds pod-level security attributes and common container settings.
	// Optional: Defaults to empty.  See type description for default values of each field.
	SecurityContext *PodSecurityContext `json:"securityContext,omitempty"`
	// ImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images used by this PodSpec.
	// If specified, these secrets will be passed to individual puller implementations for them to use.  For example,
	// in the case of docker, only DockerConfig type secrets are honored.
	ImagePullSecrets []LocalObjectReference `json:"imagePullSecrets,omitempty"`
	// Specifies the hostname of the Pod.
	// If not specified, the pod's hostname will be set to a system-defined value.
	Hostname string `json:"hostname,omitempty"`
	// If specified, the fully qualified Pod hostname will be "<hostname>.<subdomain>.<pod namespace>.svc.<cluster domain>".
	// If not specified, the pod will not have a domainname at all.
	Subdomain string `json:"subdomain,omitempty"`
}
3.总结

kubernetes 发展迅速,增加了很多新特性,本篇的总结仅作为开端,后续会介绍其他更多特性。









猜你喜欢

转载自blog.csdn.net/afandaafandaafanda/article/details/53574117