Kubernetes 工作负载-高级配置介绍

我们再深入浅出的了解一下 Pod,Pod 只是一个逻辑概念,Kubernetes 真正处理的,还是宿主机操作系统上 Linux 容器的 NameSpace 和 Cgroups,而并不存在一个所谓的 Pod 的边界或者隔离环境。Pod 是一组共享了某些资源的容器,Pod 里的所有容器共享的是一个 Network NameSpace,并且可以声明共享同一个 Volume。在 Kubernetes 里,Pod 的实现需要使用一个中间容器,这个容器叫做 Infra 容器(Infra 容器(k8s.gcr.io/pause)占用极少的资源,它的镜像时用汇编语言编写的,永远处于“暂停”状态的容器)。在 Pod 中 Infra 容器永远都是第一个被创建的容器,而其他用户自定义的容器,则通过 join Network NameSpace 的方式,与 Infra 容器关联在一起。对于同一个 Pod 里面的所有用户容器,它们的进出流量都是通过 Infra 容器完成的。凡是调度、网络、存储、以及安全相关的属性,基本上都是 Pod 级别的。

1. 数据卷

Container 中的文件在磁盘上是临时存放的,这给 Container 中运行的较重要的应用程序带来一些问题:

  • 一是当容器崩溃时文件丢失;
  • 二是同一 Pod 中运行的多个容器无法共享文件;

Kubernetes 的数据卷(Volume)便是为了解决上述问题的。数据卷有很多种类型,以下几种为常用的卷类型。

1.1 主机路径(hostPath)

hostPath 允许将节点(宿主机)上的文件系统挂载到 Pod 中的容器里面去,如果 Pod 需要使用节点上的文件,可以使用该类型。需要注意的是,默认调度策略下 Pod 在重建时,可能会调度到集群中的其它节点上,此时因调度的节点不同,所以无法获取"先前节点"上所保存的数据。

apiVersion: v1
kind: Pod
metadata:
  name: test-pd
spec:
  containers:
  - image: k8s.gcr.io/test-webserver
    name: test-pd
    volumeMounts:
    - mountPath: /test-pd
      name: test-volume
      readOnly: true
  volumes:
  - name: test-volume
    hostPath:
      # 宿主上目录位置
      path: /data
      # 此字段为可选
      type: Directory

1.2 临时路径(emptyDir)

emptyDir 可以让 Pod 中的所有容器共享同一文件系统,常用于作为临时目录、或缓存使用。它会在 Pod 被分配到节点上时被创建,并跟随 Pod 的生命中后期,即该该 Pod 一直运行,卷就会一直存在,当它被删除时卷也会同时删除。

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

1.3 配置项(configMap)

configMap 卷提供了向 Pod 注入 ConfigMap(配置)数据的方法。 ConfigMap 对象中存储的每条数据都会以一个个文件形式保存在指定的容器挂载路径中,此时你可以在容器中读取这些配置数据。

apiVersion: v1
kind: Pod
metadata:
  name: configmap-vol-demo
spec:
  containers:
    - name: nginx
      image: nginx
      volumeMounts:
        - name: config-vol
          mountPath: /etc/config
          readOnly: true
  volumes:
    - configMap:
        defaultMode: 420
        name: lytest
      name: config-vol

1.4 密钥(secret)

secret 卷用来给 Pod 传递敏感信息(例如密码)。你可以将 Secret 存储在 Kubernetes API 服务器上,然后以文件的形式挂在到 Pod 中,无需直接与 Kubernetes 耦合。

apiVersion: v1
kind: Pod
metadata:
  name: secret-vol-demo
spec:
  containers:
    - name: nginx
      image: nginx
      volumeMounts:
        - name: secret-vol
          mountPath: /etc/secret
          readOnly: true
  volumes:
    - secret:
        defaultMode: 420
        secretName: ly-secret
      name: secret-vol

1.5 存储声明(PVC)

...待补充

2. 节点选择

节点选择的作用是用来控制 Pod 的调度的,它是通过 Pod 的 spec.nodeSelector 字段来控制的。

自动分配

默认选项,在该模式下将由 Kubernetes 根据各节点的运行时状态自动分配。

指定节点

Pod 的 spec.nodeName 字段属性可以让其仅调度到指定节点。在 OpenKube 中我们在创建工作负载时通过指定节点来进行配置。

匹配节点

除了指定调度节点外,Kubernetes 还支持通过配置 spec.nodeSelector 字段来匹配节点的标签,从而决定是否将 Pod 调度到该节点上。在 OpenKube 中我们在创建工作负载时通过匹配节点来进行配置。

3. 升级策略

工作负载的 .spec.strategy 字段值用于指定新 Pod 替换旧 Pod 的策略配置。不同的工作负载类型所支持的策略有所不同:

Deployment

  • 滚动升级(RollingUpdate):滚动升级将逐步用新版本的实例替换旧版本的实例,升级的过程中,业务流量会同时负载均衡分布到新老的实例上,因此业务不会中断。它支持以下选项来控制滚动更新过程:
    • 最大峰值(maxSurge):用来指定可以创建的超出期望 Pod 个数的 Pod 数量。此值可以是绝对数(例如 5)或所需 Pods 的百分比(例如 10%)。 如果最大不可用副本数为 0,则此值不能为 0。百分比值会通过向上取整转换为绝对数。 此字段的默认值为 25%。
    • 最大不可用副本数(maxUnavailable):用来指定更新过程中不可用的 Pod 的个数上限。该值可以是绝对数字(例如 5),也可以是所需 Pod 的百分比(例如 10%)。百分比值会转换成绝对数并去除小数部分。 如果最大超出副本数为 0,则此值不能为 0。 默认值为 25%。
  • 替换升级(Recreate):该策略会在创建新版本的 Pod 之前,"杀死"所有现有的 Pod。

StatefulSet

  • 滚动升级(RollingUpdate):滚动升级会删除和重建 StatefulSet 中的每个 Pod, 它将按照与 Pod 终止相同的顺序(从最大序号到最小序号)进行,每次更新一个 Pod。 它会等到被更新的 Pod 进入 RunningReady 状态,然后再更新其前身。它支持以下选项来控制滚动更新过程:

    • 分区(partition):在大多数情况下,你不需要使用分区,但如果你希望进行阶段更新,执行金丝雀或分阶段上线,那么可以配置分区序号。当 StatefulSet 被更新时,所有序号大于等于该分区序号的 Pod 都会被更新,所有小于该分区号的 Pod 都不会更新(即使它们被删除后重建)。
  • 删除容器时更新(OnDelete):在该策略下控制器将不会自动更新 StatefulSet 的 Pod,必须手动删除 Pod 以便让控制器创建新的 Pod。

DaemonSet

  • 滚动升级(RollingUpdate):与 Deployment 滚动更新策略效果一样。

    • 最大不可用副本数(maxUnavailable):与 Deployment 滚动更新策略的最大不可用副本数作用相同。
    • 最小就绪时间(maxUnavailable):用于指定新创建的 Pod 在没有任意容器崩溃情况下的最小就绪时间, 只有超出这个时间 Pod 才被视为可用(默认值为 0,Pod 在准备就绪后立即将被视为可用)。但其本身并不属于更新策略的配置,它可作用于所有类型的工作负载,只是由于产品设计的原因将其置于此处。
  • 删除容器时更新(OnDelete):在该策略下控制器将不会自动更新 DaemonSet 的 Pod,必须手动删除 Pod 以便让控制器创建新的 Pod。

4. 自动伸缩

自动伸缩(Horizontal Pod Autoscaler)可以根据 CPU 利用率自动扩缩 ReplicationController、 Deployment、ReplicaSet 或 StatefulSet 中的 Pod 数量 。

5. 容忍

可以通过 Pod 的 spec.tolerations 字段来添加了容忍,允许其部署在匹配特定污点的节点上。可以使用两种操作符来匹配污点,分别是:

  • Exists:与污点信息完全匹配(即与污点的 key-value 值相等)
tolerations:
- key: "key1"
  operator: "Equal"
  value: "value1"
  effect: "NoExecute"
  tolerationSeconds: 3600
  • Equal:判断污点信息存在性(与污点的 key 值相等)
tolerations:
- key: "key2"
  operator: "Exists"
  effect: "NoSchedule"
  tolerationSeconds: 3600

在实践中,某些有着特殊硬件的节点需要专用于运行一类有着此类硬件资源需求的 Pod 对象时,例如,那些有着 SSD 或 GPU 的设备,酒应该为其添加污点信息以排除其他的 Pod 对象。

6. 亲和性

待完善

一般情况下我们部署的 Pod 是通过集群自动调度选择某个节点的,默认情况下调度器考虑的是资源足够,并且负载尽量平均。但是有的时候我们需要能够更加细粒度的去控制 Pod 的调度,比如我们希望服务的 Pod 尽量跑在一些带有特定标签的节点上,或希望能某些服务的 Pod 调度到同样的节点上,这就需要用到 Kubernetes 里面的一个概念 --- 亲和性(Affinity)。

亲和性有又分为节点亲和性和应用亲和性两种类型,每种类型又支持两种策略:

  • 软策略:尽量满足调度要求,若无匹配的节点,则会忽略这条规则,继续完成调度过程。
  • 硬策略:即必须满足我的要求,如果没有满足条件的节点的话,就不断重试直到满足条件为止。

6.1 节点亲和性(nodeAffinity)

节点亲和性(nodeAffinity )是通过匹配节点的标签来决定是否调度到该节点**,但相比节点选择( nodeSelector )更加灵活,它可以进行一些简单的逻辑组合,不只是简单的相等匹配。

6.2 应用亲和性(podAffinity)/ 应用反亲和性(podAntiAffinity)

节点亲和性是从 Pod 和 Node 的关系角度进行匹配,而应用亲和性(podAffinity )与应用反亲和性(podAntiAffinity )是从 Pod 与 Pod 方面,即应用与应用的角度去考虑。它会基于已在节点上运行 Pod 的标签(LabelSelector)来约束 Pod 可以调度到的节点,并且也是基于命名空间限定的,而不是节点上的标签。

例如,因为服务 A 和服务 B 需要在同一节点上协同工作;或是我们希望系统数据服务 C 和数据服务 D 尽量分开,部署到不同节点上,以免主机或机房出问题时,不会导致应用完全不可用,等等这些场景下就需要用到应用亲和性了。

7. 终止等待时间

可以通过 spec.terminationGracePeriodSeconds 字段来设置终止等待时间,该配置的作用是当集群向 Pod 发送 SIGTERM 信号后,等待结束的时间。当超过该时间后,集群会强制结束该 Pod。因此该时间是 Kubernetes 集群给你程序预留的最后缓冲时间,来处理关闭之前的操作。

8. 主机别名

Kubernetes 中不同服务之间可以通过 "service-name" 域名来相互访问,这是通过集群中的 CoreDNS 组件来完成域名解析工作的。但当我们想在 Pod 上增加一些域名解析时,可以通过 Pod 的 spec.hostAliases 字段往 /etc/hosts 文件中添加域名解析(集群需 1.7.x 及以上版本)。

apiVersion: v1
kind: Pod
metadata:
  name: test
spec:
  hostAliases:
  – ip: "10.1.2.2"
    hostnames:
    – "mc.local"
    – "rabbitmq.local"
  containers:
  – name: cathosts
    image: busybox
...

9. DNS 策略与配置

我们可以通过 Pod 声明中的 spec.dnsPolicy 字段来设置 DNS 策略,目前支持以下类型:

  • (继承节点)Default:Pod 从运行所在的节点继承名称解析配置,即将宿主机的 /etc/resolv.conf 内容挂载到容器中。
  • (集群优先)ClusterFirst:默认策略,会预先把 kube-dns(或 CoreDNS)的信息当作预设参数写入到该 Pod 内的 DNS 设置。
  • (宿主机与 Kubernetes 共存)ClusterFirstWithHostNet:集群 DNS 优先,并伴随着使用宿主机 DNS 网络设置。
  • (无策略)None:不使用任何预设的 DNS 配置,此时必须通过 spec.dnsConfig 字段来配置 DNS 信息。

默认 DNS 策略为 ClusterFirst

在 OpenKube 中 DNS 策略设置目前仅支持 ClusterFirst 与 ClusterFirstWithHostNet 两种类型。除了采用策略预设的配置,Pod 的 spec.dnsConfig 字段可以让用户对 Pod 的 DNS 设置进行更多控制,该字段是可选的,它可以与任何 dnsPolicy 设置一起使用。 但是当 Pod 的 dnsPolicy 设置为 "None" 时,必须指定 dnsConfig 字段。

用户可以在 dnsConfig 字段中指定以下属性:

  • nameservers:将用作于 Pod 的 DNS 服务器的 IP 地址列表(最多可以指定 3 个 IP 地址),当 Pod 的 dnsPolicy 设置为 "None" 时, 列表必须至少包含一个 IP 地址,否则此属性是可选的。 所列出的服务器将合并到从指定的 DNS 策略生成的基本名称服务器,并删除重复的地址。
  • searches:用于在 Pod 中查找主机名的 DNS 搜索域的列表(最多允许 6 个搜索域)。此属性是可选的, 指定此属性时,所提供的列表将合并到根据所选 DNS 策略生成的基本搜索域名中。 重复的域名将被删除。
  • options:可选的对象列表,其中每个对象可能具有 name 属性(必需)和 value 属性(可选)。 此属性中的内容将合并到从指定的 DNS 策略生成的选项,重复的条目将被删除。
apiVersion: v1
kind: Pod
metadata:
  namespace: default
  name: dns-example
spec:
  containers:
    - name: test
      image: nginx
  dnsPolicy: "ClusterFirst"
  dnsConfig:
    nameservers:
      - 1.2.3.4
    searches:
      - ns1.svc.cluster-domain.example
      - my.dns.search.suffix
    options:
      - name: ndots
        value: "2"

10. 宿主机配置

NameSpace 是 Linux 内核用于隔离资源的机制,通过 NameSpace 可以让一些进程只能看到与自己相关的一部分资源,而不受其它进程影响。其实现方式是把一个或多个进程的相关资源指定在同一个 NameSpace 中。

容器本质上是把系统中为同一个业务目标服务的相关进程合成一组,放在同一个叫 Namespace 空间中。同一个 Namespace 中的进程能够互相通信,在这个 Namespace 中可以拥有自己独立的主机名、进程 ID 系统、IPC、网络、文件系统、用户等等资源。在某种程度上,实现了一个简单的虚拟:让一个主机上可以同时运行多个互不感知的系统。

10.1 是否使用主机 IPC

Pod 声明文件的 spec.hostIPC 字段值表示是否使用主机 PID。若选择"是",此时 Pod 中所有的容器会与宿主机处于同一个 IPC NameSpace 空间中,可直接与宿主机进程进行通信。

10.2 是否使用主机 PID

Pod 声明文件的 spec.hostPID 字段值表示是否使用主机 PID。若选择"是",此时 Pod 中所有的容器会与宿主机处于同一个 PID NameSpace 空间中 。当我们在 Pod 中的容器执行 ps -aux 命令时,可以查看到宿主机里正在运行的所有进程。

10.3 是否使用主机网络

Pod 声明文件的 spec.hostNetwork 字段值表示是否使用主机网络。若选择"是",Pod 中所有的容器会直接使用宿主机的网络,即它们与宿主机处于同一个 NET NameSpace。

10.4 是否共享进程命名空间

Pod 声明文件的 spec.shareProcessNamespace 字段值表示是否共享进程命名空间。若选择 "是" 时,Pod 里的每个容器的进程,对于所有容器来说都是可见的,即它们共享了同一个 PID Namespace。

11. 安全上下文

默认情况下,工作负载会以 root 用户运行容器(可通过在容器中执行 ps -aux 命令查看 USER 列信息),但在某些场景下这会带来安全问题,此时我们需要控制容器中运行的用户与权限,避免以超级用户身份运行容器。

安全上下文(Security Context)定义 Pod 或 Container 的特权与访问设置。目前 OpenKube 支持在创建工作负载时对安全上下文进行以下配置。

11.1 以非 root 用户身份运行

默认情况下,是否以非 root 用户身份运行的单选框值为"否",此时 Pod 声明文件中的 spec.securityContext.runAsNonRoot 字段值为 false,表示以 root 身份运行容器。但当我们要以指定用户运行容器时,应勾选"是"(即字段值为 true)。

除此之外,还需要配置 spec.securityContext.runAsUserspec.securityContext.runAsGroup 字段,即分别设置运行容器的用户 ID主用户组 ID。例如我们设置以 ID 为 1 的用户运行容器,其用户组 ID 为 2

那么如何确认我们所指定的用户与用户组是否生效呢?可以在容器中执行 whoami 命令获取当前用户名,与用户详情配置文件 /etc/passwd 信息进行比较来确认当前用户。而用户组可以通过 group 命令获取当前用户组,与用户组详情文件 /etc/group 信息进行比较。

fsGroup

该配置项为 Pod 声明中的 spec.fsGroup 字段,用于指定卷的附加用户组 ID。

补充用户组

该配置项为 Pod 声明中的 spec.supplementalGroups 字段,一个用户可以加入很多组,但是其中只有一个是主组,而配置项用于指定额外的用户组 ID。

11.2 配置内核参数

sysctl 参数位于 /proc/sys 目录下,它们是系统运行时的内核参数。Kubernetes 支持我们在 Pod 的声明文件中去配置内核参数。这些配置将会影响容器运行时的系统环境,例如设置联网功能,IP 转发以及源路由检查等。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,098评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,213评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,960评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,519评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,512评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,533评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,914评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,804评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,563评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,644评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,350评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,933评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,908评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,146评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,847评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,361评论 2 342

推荐阅读更多精彩内容