kubernetes之使用Preset向pod注入信息

参考:

https://kubernetes.io/docs/concepts/workloads/pods/podpreset/

https://kubernetes.io/docs/tasks/inject-data-application/podpreset/

理解pod  Presets

Pod Preset是一种API资源,用来在创建pod时向其注入运行时需要的额外信息,通过使用label selector确定为pod应用那些Presets。

Preset允许用户创建具有通用性的模板而无需显式提供pod运行时才需要的信息,而模板的使用者只需通过Preset提供pod运行时需要的信息而无需关注pod的实现细节。

Preset如何工作?

Kubernetes为Preset提供了一个允许控制器(admission controller),当创建创建pod的请求到达时,通过这个允入控制器将label selector选中的Preset应用到pod中,具体流程如下:

  1. 检索系统中所有可用的Presets。
  2. 检查所有Preset的label selector是否与当前pod的标签匹配。
  3. 尝试将匹配Preset中的各种资源合并进正在创建的pod。
  4. 如果发生错误,为pod抛出合并Preset失败的异常事件,然后在不合并Preset所提供资源的情况下创建pod(合并失败并没有阻挡pod的创建)。
  5. 如果合并成功,向合并后的结果spec加入到pod的注解中,表示pod被Preset修改了,注册格式如下:
    podpreset.admission.kubernetes.io/podpreset-<pod-preset name>: "<resource version>"

每个pod可以被0到多个Preset匹配,每个Preset可以应用到0到多个pod。当Preset被应用到pod时,kubernetes会修改pod的spec。当注入Env、EnvFrom、VolumeMounts时,kubernetes会修改pod中除init container以外的其它所有container的spec,当注入volume时,修改pod的spec。

为pod禁止掉Preset功能

在某些情况下,不希望所创建的pod被Preset修改,可以在pod的注解中加入如下内容禁止掉此项功能:

podpreset.admission.kubernetes.io/exclude: "true"

允许集群使用Preset功能

  1. 允许API type settings.k8s.io/v1alpha1/podpreset。例如,在运行API server时在--runtime-config选项中包含settings.k8s.io/v1alpha1=true。
  2. 打开Preset的允入控制器,一种方法是在运行API server时--enable-admission-plugins选项中包含Preset值。
  3. 在所使用的namespace下有Preset的定义,先创建后使用。

使用Preset向pod注入信息的示例

示例说明pod的spec如何被Preset修改

首先是简单的pod Preset定义,保存在preset.yaml文件中:

apiVersion: settings.k8s.io/v1alpha1
kind: PodPreset
metadata:
  name: allow-database
spec:
  selector:
    matchLabels:
      role: frontend
  env:
    - name: DB_PORT
      value: "6379"
  volumeMounts:
    - mountPath: /cache
      name: cache-volume
  volumes:
    - name: cache-volume
      emptyDir: {}

创建这个pod Preset:

kubectl create -f https://k8s.io/examples/podpreset/preset.yaml

检察创建的Preset:

$ kubectl get podpreset
NAME             AGE
allow-database   1m

从以上Preset的label selector可以看出,这个Preset会作用到所有相同namespace下拥有role: frontend标签的pod上,以下是一个pod示例:

apiVersion: v1
kind: Pod
metadata:
  name: website
  labels:
    app: website
    role: frontend
spec:
  containers:
    - name: website
      image: nginx
      ports:
        - containerPort: 80

 创建pod:

$ kubectl create -f https://k8s.io/examples/podpreset/pod.yaml

列出运行中的pod:

$ kubectl get pods
NAME      READY     STATUS    RESTARTS   AGE
website   1/1       Running   0          4m

 Preset的允入控制器会将刚才创建的Preset应用到这个pod上,并且修改pod的spec,修改后的结果如下:

apiVersion: v1
kind: Pod
metadata:
  name: website
  labels:
    app: website
    role: frontend
  annotations:
    podpreset.admission.kubernetes.io/podpreset-allow-database: "resource version"
spec:
  containers:
    - name: website
      image: nginx
      volumeMounts:
        - mountPath: /cache
          name: cache-volume
      ports:
        - containerPort: 80
      env:
        - name: DB_PORT
          value: "6379"
  volumes:
    - name: cache-volume
      emptyDir: {}

运行如下命令输出以上内容:

$ kubectl get pod website -o yaml

 使用ConfigMap的Preset示例

本例中Preset向pod模板提供的是ConfigMap类型的资源,ConfigMap中是环境变量。

以下是pod定义:

apiVersion: v1
kind: Pod
metadata:
  name: website
  labels:
    app: website
    role: frontend
spec:
  containers:
    - name: website
      image: nginx
      ports:
        - containerPort: 80

以下是ConfigMap定义:

apiVersion: v1
kind: ConfigMap
metadata:
  name: etcd-env-config
data:
  number_of_members: "1"
  initial_cluster_state: new
  initial_cluster_token: DUMMY_ETCD_INITIAL_CLUSTER_TOKEN
  discovery_token: DUMMY_ETCD_DISCOVERY_TOKEN
  discovery_url: http://etcd_discovery:2379
  etcdctl_peers: http://etcd:2379
  duplicate_key: FROM_CONFIG_MAP
  REPLACE_ME: "a value"

以下是Preset定义:

apiVersion: settings.k8s.io/v1alpha1
kind: PodPreset
metadata:
  name: allow-database
spec:
  selector:
    matchLabels:
      role: frontend
  env:
    - name: DB_PORT
      value: "6379"
    - name: duplicate_key
      value: FROM_ENV
    - name: expansion
      value: $(REPLACE_ME)
  envFrom:
    - configMapRef:
        name: etcd-env-config
  volumeMounts:
    - mountPath: /cache
      name: cache-volume
    - mountPath: /etc/app/config.json
      readOnly: true
      name: secret-volume
  volumes:
    - name: cache-volume
      emptyDir: {}
    - name: secret-volume
      secret:
         secretName: config-details

 以上可以看出Preset已经将定义好的ConfigMap引入其中。

以下内容是Preset被应用到pod上,pod的spec被Preset的允入控制器修改后的内容:

apiVersion: v1
kind: Pod
metadata:
  name: website
  labels:
    app: website
    role: frontend
  annotations:
    podpreset.admission.kubernetes.io/podpreset-allow-database: "resource version"
spec:
  containers:
    - name: website
      image: nginx
      volumeMounts:
        - mountPath: /cache
          name: cache-volume
        - mountPath: /etc/app/config.json
          readOnly: true
          name: secret-volume
      ports:
        - containerPort: 80
      env:
        - name: DB_PORT
          value: "6379"
        - name: duplicate_key
          value: FROM_ENV
        - name: expansion
          value: $(REPLACE_ME)
      envFrom:
        - configMapRef:
            name: etcd-env-config
  volumes:
    - name: cache-volume
      emptyDir: {}
    - name: secret-volume
      secret:
         secretName: config-details

ReplicaSet中仅修改pod spec的Preset示例 

以下是ReplicaSet定义:

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: frontend
spec:
  replicas: 3
  selector:
    matchLabels:
      role: frontend
    matchExpressions:
      - {key: role, operator: In, values: [frontend]}
  template:
    metadata:
      labels:
        app: guestbook
        role: frontend
    spec:
      containers:
      - name: php-redis
        image: gcr.io/google_samples/gb-frontend:v3
        resources:
          requests:
            cpu: 100m
            memory: 100Mi
        env:
          - name: GET_HOSTS_FROM
            value: dns
        ports:
          - containerPort: 80

 以下是Proset的定义:

apiVersion: settings.k8s.io/v1alpha1
kind: PodPreset
metadata:
  name: allow-database
spec:
  selector:
    matchLabels:
      role: frontend
  env:
    - name: DB_PORT
      value: "6379"
  volumeMounts:
    - mountPath: /cache
      name: cache-volume
  volumes:
    - name: cache-volume
      emptyDir: {}

需要注意的是,Preset不会修改ReplicaSet的spec,被修改的是被ReplicaSet控制的pod的spec,被修改后的内容如下:

apiVersion: v1
kind: Pod
metadata:
  name: frontend
  labels:
    app: guestbook
    role: frontend
  annotations:
    podpreset.admission.kubernetes.io/podpreset-allow-database: "resource version"
spec:
  containers:
  - name: php-redis
    image: gcr.io/google_samples/gb-frontend:v3
    resources:
      requests:
        cpu: 100m
        memory: 100Mi
    volumeMounts:
    - mountPath: /cache
      name: cache-volume
    env:
    - name: GET_HOSTS_FROM
      value: dns
    - name: DB_PORT
      value: "6379"
    ports:
    - containerPort: 80
  volumes:
  - name: cache-volume
    emptyDir: {}

pod被多个Preset修改的示例

以下是pod spec:

apiVersion: v1
kind: Pod
metadata:
  name: website
  labels:
    app: website
    role: frontend
spec:
  containers:
    - name: website
      image: nginx
      ports:
        - containerPort: 80

以下是Preset1 spec:

apiVersion: settings.k8s.io/v1alpha1
kind: PodPreset
metadata:
  name: allow-database
spec:
  selector:
    matchLabels:
      role: frontend
  env:
    - name: DB_PORT
      value: "6379"
  volumeMounts:
    - mountPath: /cache
      name: cache-volume
  volumes:
    - name: cache-volume
      emptyDir: {}

以下是Preset2 spec:

apiVersion: settings.k8s.io/v1alpha1
kind: PodPreset
metadata:
  name: proxy
spec:
  selector:
    matchLabels:
      role: frontend
  volumeMounts:
    - mountPath: /etc/proxy/configs
      name: proxy-volume
  volumes:
    - name: proxy-volume
      emptyDir: {}

 被两个Preset修改后的pod spec:

apiVersion: v1
kind: Pod
metadata:
  name: website
  labels:
    app: website
    role: frontend
  annotations:
    podpreset.admission.kubernetes.io/podpreset-allow-database: "resource version"
    podpreset.admission.kubernetes.io/podpreset-proxy: "resource version"
spec:
  containers:
    - name: website
      image: nginx
      volumeMounts:
        - mountPath: /cache
          name: cache-volume
        - mountPath: /etc/proxy/configs
          name: proxy-volume
      ports:
        - containerPort: 80
      env:
        - name: DB_PORT
          value: "6379"
  volumes:
    - name: cache-volume
      emptyDir: {}
    - name: proxy-volume
      emptyDir: {}

合并多个Preset时的冲突示例 

Preset1 spec:

apiVersion: v1
kind: Pod
metadata:
  name: website
  labels:
    app: website
    role: frontend
spec:
  containers:
    - name: website
      image: nginx
      volumeMounts:
        - mountPath: /cache
          name: cache-volume
      ports:
        - containerPort: 80
  volumes:
    - name: cache-volume
      emptyDir: {}

Preset2 spec:

apiVersion: settings.k8s.io/v1alpha1
kind: PodPreset
metadata:
  name: allow-database
spec:
  selector:
    matchLabels:
      role: frontend
  env:
    - name: DB_PORT
      value: "6379"
  volumeMounts:
    - mountPath: /cache
      name: other-volume
  volumes:
    - name: other-volume
      emptyDir: {}

 被冲突Preset修改后的pod spec:

apiVersion: v1
kind: Pod
metadata:
  name: website
  labels:
    app: website
    role: frontend
spec:
  containers:
    - name: website
      image: nginx
      volumeMounts:
        - mountPath: /cache
          name: cache-volume
      ports:
        - containerPort: 80
  volumes:
    - name: cache-volume
      emptyDir: {}

由以上结果看出,冲突的Preset没有起作用,并且会在pod上报出Preset冲突的异常事件,如下:

$ kubectl describe ...
....
Events:
  FirstSeen             LastSeen            Count   From                    SubobjectPath               Reason      Message
  Tue, 07 Feb 2017 16:56:12 -0700   Tue, 07 Feb 2017 16:56:12 -0700 1   {podpreset.admission.kubernetes.io/podpreset-allow-database }    conflict  Conflict on pod preset. Duplicate mountPath /cache.

 删除Preset

$ kubectl delete podpreset allow-database
podpreset "allow-database" deleted

猜你喜欢

转载自blog.csdn.net/dkfajsldfsdfsd/article/details/81097379