7. 应用配置管理

本文由 CNCF + Alibaba 云原生技术公开课 整理而来

背景

  • 背景问题:

如果想通过一个镜像来启动容器,有时不仅仅只需要一个镜像,其实还有些问题需要解决:

1. 应用的可变配置写到镜像里面是无法接受的,如何加载可变配置?

2. 应用的敏感信息如何存储和使用?

3. 容器如何通过身份认证来访问集群自身,如访问 API Server ?

4. 容器在节点上运行之后,如何配置资源需求?

5. 节点上的容器由于共享内核,如何对它们进行安全管控?

6. 如何在容器启动之前进行前置条件校验?
  • Kubernetes 解决:

在 Kubernetes 里面,这样来解决上面的问题:

可变配置:ConfigMap

敏感信息:Secret

身份认证:ServiceAccount

资源配置:Resources

安全管控:SecurityContext

前置校验:InitContainer

ConfigMap

ConfigMap 是 Kubernetes 的资源对象之一,主要管理容器运行所需的配置文件、环境变量、命令行参数等可变配置。用于解耦容器镜像和可变配置,从而保障工作负载 Pod 的可移植性。

  • ConfigMap 语法:

flannel ConfigMap yaml 文件示例:

apiVersion: v1
kind: ConfigMap
metadata:
  name: flannel
  namespace: kube-system
  labels:
    app: flannel
    tier: node
data:
  cni-conf.json: |
    {
      "name": "cbr0",
      "type": "flannel",
      "delegate": {
        "isDefaultGateway": true
      }
    }
    
  net-conf.json: |
    {
      "Network": "172.27.0.0/16",
      "Backend": {
        "Type": "vxlan"
      }
    }

文件解析:

apiVersion: v1      表示 ConfigMap 的 API 版本是 v1

kind        表示 Kubernetes 资源类型是 ConfigMap

metadata    表示 ConfigMap 的元数据,元数据通常包含 name、namespace、labels、annotations 等

data    表示 ConfigMap 管理的配置文件,每个配置文件是 key:value,其中 key 是文件名,value 是文件内容
  • 使用 ConfigMap

可以通过命令 kubectl apply -f <yaml file> 创建一个 ConfigMap 资源对象。ConfigMap 主要被 Pod 使用,一般用于挂载 Pod 用的配置文件、环境变量、命令行参数等。

Pod 使用 ConfigMap

1. 配置环境变量,通过 valueFrom 指定,其下 ConfigMapKeyRef.name 指定 ConfigMap 的名称,ConfigMapKeyRef.key 是 ConfigMap 中 data 下的 key

2. 配置命令行参数,在 Pod yaml 文件中,containers 下 command 中可以使用 ConfigMap 定义的环境变量

3. 挂载配置文件,ConfigMap 可以被 Pod 挂载,volumes.configMap.name 字段指定 ConfigMap 的名称
  • ConfigMap 注意点:
1. ConfigMap 文件大小。ConfigMap 文件没有大小限制,但是在 etcd 里面,数据的写入是有大小限制的,现在是限制在 1MB 以内;

2. Pod 使用 ConfigMap 时,必须是相同 Namespace 下的 ConfigMap,而且 ConfigMap 需要在 Pod 之前创建好;

3. 当使用 enfFrom 配置环境变量时,如果 ConfigMap 中有些 key 是无效的,则环境变量时不会注入容器,它会被忽略;

4. 只有通过 API Server 创建的 Pod 才能使用 ConfigMap,kubelet 通过 manifest 创建的静态 Pod 无法使用 ConfigMap。

Secret

Secret 是 Kubernetes 的资源对象之一,主要用来存储密码、token等一些敏感信息。其中,敏感信息采用 base64 编码保存。

  • Secret 语法:

mysecret Secret yaml 文件示例:

apiVersion: v1
kind: Secret
metadata:
  name: mysecret
  namespace: kube-system
type: Opaque
data:
  username: YWRtaW4=
  password: MWYyZDFlMwU2N2Rm

文件解析:

apiVersion: v1      表示 Secret 的 API 版本是 v1

kind        表示 Kubernetes 资源类型是 Secret

metadata    表示 Secret 的元数据,元数据通常包含 name、namespace 等

type        表示 Secret 的类型,默认类型是 Opaque

data    表示 Secret 管理的敏感信息,每条敏感信息是 key:value

Secret 常用的类型有 4 种:

Opaque,默认类型,即普通的 Secret 文件

service-account-token,用于 ServiceAccount 身份认证用的 Secret

dockerconfigjson,用于拉取私有仓库镜像

bootstrap.token,用于节点接入集群校验使用
  • 使用 Secret

可以通过命令 kubectl apply -f <yaml file> 创建一个 Secret 资源对象。Secret 主要被 Pod 使用,一般是通过 Volume 形式挂载到容器里的指定目录,然后容器里的业务进程到目录下读取 Secret。在需要访问私有镜像仓库时也是通过 Secret 来实现。

Pod 使用 Secret 是通过 Volume 形式挂载到容器里的指定目录,volumes.secert.secretName 字段指定 Secret 的名称

  • 访问私有镜像库:

Secret 中配置私有镜像仓库的账号密码,创建好之后,将 Podtemplate.spec 部分的 imagePullSecrets.name 指定为 Secret 的名称。

  • Secret 注意点:
1. Secret 文件大小。Secret 文件也没有大小限制,但是由于 etcd 的原因,数据限制在 1MB 以内;

2. Pod 使用 Secret 时,必须是相同 Namespace 下的 Secret,而且 Secret 需要在 Pod 之前创建好;

3. 当读取 Secret 时,不建议使用 list/watch,推荐使用 GET 方法获取需要的 Secret

ServiceAccount

ServiceAccount 用于解决 Pod 在集群里面的身份认证问题,身份认证信息是存在于 Secret 中。

  • ServiceAccount 语法:

default ServiceAccount yaml 文件示例:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: default
  namespace: default
  resourceVersion: "419220122"
  selflink: /api/v1/namespaces/default/serviceaccounts/default
  uid: 320061cb-85da-11e9-909b-06b1d3b258c8
secrets:
- name: default-token-6fn7q

SecretServiceAccount Controller 自动创建:

apiVersion: v1
data:
  ca.crt: LS0tLS1...
  namespace: ZGVmYXVsdA==
  token: ZXlKaGjHY2..
kind: Secret
metadata:
  annotations:
    kubernetes.io/service-account.name: default
    kubernetes.io/service-account.uid: 320061cb-85da-11e9-909b-06b1d3b258c8
  creationTimestamp: 2019-06-03T08:32:59Z
  name: default-token-6fn7q
  namespace: default
  resourceVersion: "419220122"
  selflink: /api/v1/namespaces/default/serviceaccounts/default
  uid: 320061cb-85da-11e9-909b-06b1d3b258c8
type: Opaque

文件解析:

apiVersion: v1      表示 ServiceAccount 的 API 版本是 v1

kind        表示 Kubernetes 资源类型是 ServiceAccount

metadata    表示 ServiceAccount 的元数据,元数据通常包含 name、namespace 等

data    表示 ServiceAccount 使用的 Secret

ServiceAccount 对应的 Secret 中,data 有两块数据,分别是 ca.crttokenca.crt 用于对服务端的校验,token 用于 Pod 的身份认证,它们都是用 base64 编码过的。然后可以看到 metadata 即元信息里,其实是有关联 ServiceAccount 信息的(该 Secret 被哪个 ServiceAccount 使用)。

Pod 访问所属集群的实现原理:

1. Pod 创建时 Admission Controller 会根据指定的 ServiceAccount(默认为 default)把对应的 Secret 挂载到容器中指定的目录(/var/run/secrets/kubernetes.io/serviceaccount)下,这由 Kubernetes 自动实现

2. 当 Pod 访问集群时,可以默认利用 Secret 其中的 token 文件来认证 Pod 的身份,ca.crt 用于校验服务端

3. 默认 token 的认证信息为:
   
   - Group: system:serviceaccounts:[namespace-name]
   - User: system:serviceaccounts:[namespace-name][pod-name]

假如 RBAC 没有配置的话,默认的 Pod 具有资源的 GET 权限,就是可以从所属的 Kubernetes 集群里 GET 数据。如果想要更多的权限,那么就需要自行配置 RBAC


Resource

  • 容器资源配置:

Resource 是对容器的资源配额管理。目前 Kubernetes 内部支持的类型有三种:CPU、内存,以及临时存储。资源配置有 requestlimit 两种类型,分别指定了资源分配的下限和上限。CPU、内存以及临时存储都是在 containers 下的 resources 字段里进行一个声明。

示例:

apiVersion: v1
kind: Pod
metadata:
  name: frontend
spec:
  containers:
  - name: wp
    image: wordpress
    resources:
      requests:
        memory: "64Mi"
        cpu: "250m"
        ephemeral-storage: "2Gi"
      limits:
        memory: "128Mi"
        cpu: "500m"
        ephemeral-storage: "4Gi"
  • Pod 服务质量 QoS 配置:

根据 容器对 CPU 、内存资源的需求,可以对 Pod 的服务质量 QoS 进行一个分类,分别是 GuaranteedBurstableBestEffort

Guaranteed:Pod 里面的每个容器都必须有 CPU 、内存的 request 和 limit 的声明,而且 request 和 limit 必须一致

Burstable:Pod 里面至少有一个容器存在 CPU 、内存的一个 request

BestEffort:只要不是 Guaranteed 和 Burstable,就属于 BestEffort

服务质量是 GuaranteedPod 优先级最高,Burstable 次之,BestEffort 最低。如果节点上资源紧缺,kubelet 会根据服务质量来依次驱逐低优先级的 Pod


SecurityContext

SecurityContext 主要是用于限制容器的行为,保证系统和其它容器的安全。SecurityContext 主要分为 3 个级别:

容器级别,仅对容器生效

Pod 级别,对 Pod 里所有容器生效

集群级别,对集群内所有 Pod 生效

权限和访问控制设置项,目前一共有 7 项:

1. 通过用户 ID 和组 ID 来控制文件访问权限

2. SElinux,通过策略配置来控制用户或进程对文件的访问控制

3. 特权容器

4. Capablilities,它是给特定进程配置一个 privileged 能力

5. AppArmor,通过一些配置文件来控制可执行文件的访问权限,如端口的读写权限

6. 对系统调用的控制

7. 对子进程能否获取比父进程更多权限的限制

这些权限和访问控制设置项最终都是通过内核来达到目的。示例:

apiVersion: v1
kind: Pod
metadata:
  name: security-context-demo
spec:
  securityContext:
    runAsUser: 1000
    runAsGroup: 3000
    fsGroup: 2000
  containers:
  - name: sec-ctx-demo
    image: busybox
    command: ["sh", "-c", "sleep 1h"]
    volumeMounts:
    - name: sec-ctx-vol
      mountPath: /data/demo
    securityContext:
      allowPrivilegeEacalation: false
  volumes:
  - name: sec-ctx-vol
    emptyDir: {
    
    }

InitContainer

InitContainer 用于完成主业务容器所需要的一些辅助工作,将辅助功能从主业务容器解耦。

InitContainerContainer 的区别:

1. InitContainer 会比普通 Container 先启动,并且直到所有的 InitContainer 执行成功后,普通 Container 才会被启动

2. InitContainer 之间是按定义的次序去启动执行的,执行成功一个之后再执行第二个,而普通 Container 是并发启动的

3. InitContainer 执行成功后就结束退出,而普通 Container 可能会一直在执行

猜你喜欢

转载自blog.csdn.net/miss1181248983/article/details/110825136