Kubenetes-CKA-和-CKAD-认证备考指南-一-

106 阅读15分钟

Kubenetes CKA 和 CKAD 认证备考指南(一)

原文:Kubernetes: Preparing for the CKA and CKAD Certifications

协议:CC BY-NC-SA 4.0

一、使用 Kubernetes 创建集群

在本章中,您将在 Google Cloud 中的虚拟机上部署一个 Kubernetes 集群。

调配计算资源

您将安装一个控制面板集群。为此,您将需要一个用于控制器的虚拟机和几个(这里是两个)用于工作者的虚拟机。

集群中所有机器之间的完全网络连接是必要的。为此,您将创建一个虚拟私有云(VPC)来托管集群,并定义一个子网来获取主机地址。

从 Google Cloud 控制台,创建一个新项目my-project;,然后从本地终端登录并设置当前区域、区域和项目(您也可以从 Google Cloud Shell 工作并跳过登录步骤):

$ gcloud auth login
[...]

$ gcloud config set compute/region us-west1
Updated property [compute/region].

$ gcloud config set compute/zone us-west1-c
Updated property [compute/zone].

$ gcloud config set project my-project
Updated property [core/project].

创建专用虚拟私有云(VPC):

$ gcloud compute networks create kubernetes-cluster --subnet-mode custom
Created [https://www.googleapis.com/compute/v1/projects/my-project/global/networks/kubernetes-cluster].

kubernetes-cluster VPC 中创建子网:

$ gcloud compute networks subnets create kubernetes \
  --network kubernetes-cluster \
  --range 10.240.0.0/24
Created [https://www.googleapis.com/compute/v1/projects/my-project/regions/us-west1/subnetworks/kubernetes].

为内部通信创建防火墙规则:

$ gcloud compute firewall-rules create \
  kubernetes-cluster-allow-internal \
  --allow tcp,udp,icmp \
  --network kubernetes-cluster \
  --source-ranges 10.240.0.0/24,10.244.0.0/16
Created [https://www.googleapis.com/compute/v1/projects/my-project/global/firewalls/kubernetes-cluster-allow-internal].

为外部通信创建防火墙规则:

$ gcloud compute firewall-rules create \
  kubernetes-cluster-allow-external \
  --allow tcp:22,tcp:6443,icmp \
  --network kubernetes-cluster \
  --source-ranges 0.0.0.0/0
Created [https://www.googleapis.com/compute/v1/projects/my-project/global/firewalls/kubernetes-cluster-allow-external].

为控制器保留一个公共 IP 地址:

$ gcloud compute addresses create kubernetes-controller \
  --region $(gcloud config get-value compute/region)
Created [https://www.googleapis.com/compute/v1/projects/my-project/regions/us-west1/addresses/kubernetes-controller].
$ PUBLIC_IP=$(gcloud compute addresses describe kubernetes-controller \
    --region $(gcloud config get-value compute/region) \
    --format 'value(address)')

为控制器创建一个虚拟机:

$ gcloud compute instances create controller \
    --async \
    --boot-disk-size 200GB \
    --can-ip-forward \
    --image-family ubuntu-1804-lts \
    --image-project ubuntu-os-cloud \
    --machine-type n1-standard-1 \
    --private-network-ip 10.240.0.10 \
    --scopes compute-rw,storage-ro,service-management,service-control, logging-write, monitoring \
    --subnet kubernetes \
    --address $PUBLIC_IP
Instance creation in progress for [controller]: [...]

为员工创建虚拟机:

$ for i in 0 1; do \
  gcloud compute instances create worker-${i} \
    --async \
    --boot-disk-size 200GB \
    --can-ip-forward \
    --image-family ubuntu-1804-lts \
    --image-project ubuntu-os-cloud \
    --machine-type n1-standard-1 \
    --private-network-ip 10.240.0.2${i} \
    --scopes compute-rw,storage-ro,service-management,service-control,logging-write, monitoring \
    --subnet kubernetes; \
done
Instance creation in progress for [worker-0]: [...]

Instance creation in progress for [worker-1]: [...]

在主机上安装 Docker

对控制器和每个工人重复这些步骤。

连接到主机(这里是控制器):

$ gcloud compute ssh controller

安装 Docker 服务:

# Install packages to allow apt to use a repository over HTTPS
$ sudo apt-get update && sudo apt-get install -y \
  apt-transport-https ca-certificates curl software-properties-common

# Add Docker's official GPG key
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

# Add Docker apt repository
$ sudo add-apt-repository \
  "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) \
  stable"

# List available versions of Docker
$ apt-cache madison docker-ce

# Install Docker CE, for example version 5:19.03.12~3-0
$ sudo apt-get update && sudo apt-get install -y \
  docker-ce=5:19.03.12~3-0~ubuntu-bionic \
  docker-ce-cli=5:19.03.12~3-0~ubuntu-bionic

$ sudo apt-mark hold containerd.io docker-ce docker-ce-cli

# Setup daemon
$ cat <<EOF | sudo tee /etc/docker/daemon.json
{
  "exec-opts": ["native.cgroupdriver=systemd"],
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100m"
  },
  "storage-driver": "overlay2"
}
EOF

$ sudo mkdir -p /etc/systemd/system/docker.service.d

# Restart docker
$ sudo systemctl daemon-reload
$ sudo systemctl restart docker
$ sudo systemctl enable docker

在主机上安装 kubeadm、kubelet 和 kubectl

对控制器和每个工人重复这些步骤。

连接到主机(这里是控制器):

$ gcloud compute ssh controller

安装kubelet , kubeadm ,kubectl:

# Add GPG key
$ curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -

# Add Kubernetes apt repository
$ cat <<EOF | sudo tee /etc/apt/sources.list.d/kubernetes.list
deb https://apt.kubernetes.io/ kubernetes-xenial main
EOF

# Get Kubernetes apt repository data
$ sudo apt-get update

# List available versions of kubeadm
$ apt-cache madison kubeadm

# Install selected version (here 1.18.6-00)
$ sudo apt-get install -y kubelet=1.18.6-00 kubeadm=1.18.6-00 kubectl=1.18.6-00
$ sudo apt-mark hold kubelet kubeadm kubectl

初始化控制面板节点

仅在控制器上运行这些步骤。

初始化集群(这需要几分钟时间):

$ gcloud config set compute/zone us-west1-c # or your selected zone
Updated property [compute/zone].
$ KUBERNETES_PUBLIC_ADDRESS=$(gcloud compute instances describe controller \
  --zone $(gcloud config get-value compute/zone) \
  --format='get(networkInterfaces[0].accessConfigs[0].natIP)')
$ sudo kubeadm init \
  --pod-network-cidr=10.244.0.0/16 \
  --ignore-preflight-errors=NumCPU \
  --apiserver-cert-extra-sans=$KUBERNETES_PUBLIC_ADDRESS

初始化结束时,会有一条消息向您发出一条命令,让您将工作者加入集群(这条命令以kubeadm join开头)。请复制此命令以备后用。

将安装生成的 kubeconfig 文件保存在您的主目录中。它将授予您对集群的管理员权限:

$ mkdir -p $HOME/.kube

$ sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config

$ sudo chown $(id -u):$(id -g) $HOME/.kube/config

$ kubectl get nodes
NAME         STATUS      ROLES    AGE     VERSION
Controller   NotReady    master   1m14s   v1.18.6

安装calico Pod 网络插件:

$ kubectl apply -f https://docs.projectcalico.org/manifests/calico.yaml

等到安装结束。所有的吊舱都应该有一个运行状态:

$ kubectl get pods -A

当所有的吊舱都运行时,主节点应该就绪:

$ kubectl get nodes
NAME         STATUS  ROLES    AGE     VERSION
Controller   Ready   master   2m23s   v1.18.6

加入工人队伍

对每个工人重复这些步骤。

在控制器上运行kubeadm init后,运行您保存的命令:

$ sudo kubeadm join 10.240.0.10:6443 --token <token> \
  --discovery-token-ca-cert-hash sha256:<hash>

如果您没有保存命令,您必须获得令牌和散列。在控制器上,运行:

$ kubeadm token list
TOKEN                     TTL   EXPIRES
abcdef.ghijklmnopqrstuv   23h   2020-01-19T08:25:27Z

令牌在 24 小时后过期。如果您的过期,您可以创建一个新的:

$ kubeadm token create
bcdefg.hijklmnopqrstuvw

要获得hash值,您可以在控制器上运行以下命令:

$ openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | \
   openssl rsa -pubin -outform der 2>/dev/null | \
   openssl dgst -sha256 -hex | sed 's/^.* //'
8cb2de97839780a412b93877f8507ad6c94f73add17d5d7058e91741c9d5ec78

二、控制面板组件

Kubernetes 控制面板由以下部分组成

  • API 服务器kube-apiserver,Kubernetes 控制面板的前端

  • 键值存储etcd,所有集群数据的后备存储

  • 调度器kube-scheduler,它为新的 pod 选择运行的节点

  • 控制器管理器kube-controller-manager,它嵌入了所有控制器,包括节点控制器、复制控制器、端点控制器以及服务帐户和令牌控制器。

在每个节点上,运行的组件有

  • kubelet,确保受节点影响的 pod 正常运行

  • kube-proxy,维护节点上的网络规则,以满足Service需求

探索控制面板服务

kubelet服务作为 Unix 服务运行,它的状态和日志可以通过使用传统的systemd命令行工具来访问:

$ systemctl status kubelet
[...]
$ journalctl -u kubelet
[...]

其他服务运行在 Kubernetes 集群中,并且在kube-system名称空间中可见。您可以使用kubectl describe命令获得状态,使用kubectl logs命令获得日志:

$ kubectl get pods -n kube-system
etcd-controller
kube-apiserver-controller
kube-controller-manager-controller
kube-proxy-123456
kube-proxy-789012
kube-proxy-abcdef
kube-scheduler-controller

$ kubectl describe pods -n kube-system etcd-controller
[...]
$ kubectl logs -n kube-system etcd-controller
[...]

你可能想知道是什么魔力使 Kubernetes 控制飞机在 Kubernetes 本身中运行。这要归功于静态 Pod 特性,使用它可以直接给kubelet服务提供 Pod 定义。您可以在控制器的以下目录中找到 pod 的清单:

$ gcloud compute ssh controller
Welcome to controller

$ ls /etc/kubernetes/manifests/
etcd.yaml
kube-apiserver.yaml
kube-controller-manager.yaml
kube-scheduler.yaml

三、访问集群

在前面的章节中,您已经在 Kubernetes 主机上安装了kubectl,并从这些主机上使用它。使用kubectl命令的通常方式是将其安装在您的开发机器上。

在本章中,你将看到如何在你的机器上安装kubectl以及如何配置它来访问你在第一章中安装的集群。

在您的开发机器上安装 kubectl

根据您在开发计算机上运行的操作系统,请遵循以下指令之一:

Linux 操作系统

$ curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.18.6/bin/linux/amd64/kubectl

$ chmod +x ./kubectl

$ sudo mv ./kubectl /usr/local/bin/kubectl

# Test it is working correctly

$ kubectl version --client --short
Client Version: v1.18.6

苹果

$ curl -LO https://storage.googleapis.com/kubernetes

-release/release/v1.18.6/bin/darwin/amd64/kubectl
$ chmod +x ./kubectl
$ sudo mv ./kubectl /usr/local/bin/kubectl
# Test it is working correctly
$ kubectl version --client --short
Client Version: v1.18.6

Windows 操作系统

$ curl -LO https://storage.googleapis.com/kubernetes

-release/release/v1.18.6/bin/windows/amd64/kubectl.exe
# Move the binary into your PATH,
$ kubectl version --client --short
Client Version: v1.18.6

从开发机器访问集群

获取新集群的 kubeconfig 文件:

$ gcloud compute scp controller:~/.kube/config kubeconfig

在文件中更新 IP 地址以访问群集:

$ KUBERNETES_PUBLIC_ADDRESS=$(gcloud compute instances describe controller \
  --zone $(gcloud config get-value compute/zone) \
  --format='get(networkInterfaces[0].accessConfigs[0].natIP)')
$ sed -i "s/10.240.0.10/$KUBERNETES_PUBLIC_ADDRESS/" kubeconfig

如果您还没有 kubeconfig 文件,您可以将其复制到$HOME/.kube/config:

$ mv -i kubeconfig $HOME/.kube/config

如果您已经有一个 kubeconfig 文件,您可以将这个新文件与现有文件合并。首先,检查kubeconfig文件:

apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: <...>
    server: https://<ip>:6443
  name: kubernetes
contexts:
- context:
    cluster: kubernetes
    user: kubernetes-admin
  name: kubernetes-admin@kubernetes
current-context: kubernetes-admin@kubernetes
kind: Config
preferences: {}
users:
    - name: kubernetes-admin
      user:
        client-certificate-data: <...>
        client-key-data: <...>

您可以看到这个文件定义了一个名为kubernetes的集群、一个名为kubernetes-admin的用户和一个上下文kubernetes-admin@kubernetes

这些名称非常通用(如果您用 kubeadm 创建了几个集群,所有的 kubeconfig 文件都会用相同的名称定义这些元素)。我们将首先用更具体的内容替换它们:

$ sed -i 's/kubernetes/cka/' kubeconfig

然后,我们可以将这个文件与现有的$HOME/.kube/config文件合并:

$ KUBECONFIG=$HOME/.kube/config:kubeconfig \
  kubectl config view --merge --flatten > config \
  && mv config $HOME/.kube/config

最后,您可以将当前上下文切换到cka-admin@kubernetes:

$ kubectl config use-context cka-admin@kubernetes
Switched to context "cka-admin@kubernetes".

四、Kubernetes 资源

Kubernetes 以声明的方式工作:您在 Kubernetes API 的帮助下创建资源,这些对象存储在 etcd 存储中,控制器工作以确保您在这些对象中声明的内容正确地部署在您的基础设施中。

大部分资源由三部分组成:元数据、规范状态

规范是您提供给集群的规范**。这是控制器将检查以知道该做什么的内容。**

状态代表基础设施中资源的当前状态,由控制器观察。这是您将检查的内容,以了解资源在基础结构中是如何部署的。

元数据包含其他信息,比如资源的名称、它所属的名称空间、标签、注释等等。

命名空间

一些资源(称为命名空间资源)属于一个namespace。名称空间是一个逻辑分隔,资源的名称在名称空间中必须是唯一的。

RBAC 授权使用名称空间来基于资源的名称空间定义授权。

您可以使用以下命令创建新的名称空间:

$ kubectl create namespace my-ns
namespace/my-ns created

然后,在运行kubectl命令时,可以用标志--namespace指定命令操作的名称空间,或者用--all-namespaces(简称-A)指定命令在所有名称空间中操作。

您也可以指定想要使用的默认名称空间,使用:

$ kubectl config set-context \
   --current --namespace=my-ns
Context "minikube" modified.

标签和选择器

任何数量的键值对(命名标签)都可以附加到任何资源上。这些标签主要由 Kubernetes 的组件和工具使用,通过属性(由标签具体化)而不是名称来选择资源:

  • 许多kubectl命令接受一个--selector(简称-l)标志,该标志允许通过标签选择资源:

  • 将流量路由到 pod 的服务使用标签选择器选择 pod:

$ kubectl get pods -l app=nginx -A

  • 负责维持给定数量的 Pod 的部署使用标签选择器来查找它所负责的 Pod(参见第五章“Pod 控制器”一节):
apiVersion: v1
kind: Service
metadata:
  name: nginx
spec:
  selector:
    # distribute traffic to all pods with this label
    app: nginx
  ports:
  - port: 80

  • 您可以使用标签选择器选择要在其上部署 Pod 的节点的属性(参见第九章“使用标签选择器在特定节点上调度 Pod”一节)。
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  selector:
    # the pods managed by the Deployment
    # are the ones with this label
    matchLabels:
      app: nginx
  template:
    metadata:
      # pods created by the Deployment
      # will have this label
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx
        name: nginx

释文

注释是附加到资源上的元数据,通常用于工具和 Kubernetes 扩展,但是还没有集成到 spec 部分中。您可以通过强制方式向资源添加注释:

$ kubectl annotate deployments.apps nginx \
   mytool/mem-size=1G
deployment.apps/nginx annotated

或者以声明的方式:

apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    mytool/mem-size: 1G
  name: nginx
[...]

五、工作负载

POD 是库伯内特集群架构的杰作。

Kubernetes 的基本目标是帮助您管理您的容器。Pod 是 Kubernetes 集群中可部署的最小部分,包含一个或多个容器。

kubectl命令行,您可以像运行以下命令一样简单地运行包含容器的 Pod:

$ kubectl run nginx --image=nginx
pod/nginx created

通过将--dry-run=client -o yaml添加到命令中,您可以看到创建相同 Pod 所需编写的 YAML 模板:

$ kubectl run nginx --image=nginx --dry-run=client -o yaml
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: nginx
  name: nginx
spec:
  containers:
  - image: nginx
    name: nginx
    resources: {}
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}

或者,您可以通过仅保留必填字段来大大简化模板:

-- simple.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - name: nginx
    image: nginx

现在,您可以使用以下模板启动 Pod:

$ kubectl apply -f simple.yaml
pod/nginx created

如果你不太挑剔的话,创建的 Pod 已经准备好了。否则,Pod 会提供一个很长的字段列表,使其更适合生产。这些都是字段。

在 specs 的下面

以下是 Pod 规格字段的分类:

  • 容器字段将更精确地定义和参数化 Pod 的每个容器,无论它是普通容器(containers)还是初始化容器(initContainers)。imagePullSecrets字段将帮助从私人注册处下载容器映像。

  • 字段(volumes)将定义容器能够挂载和共享的卷列表。

  • 调度字段将帮助您定义部署 Pod 的最合适的节点,方法是通过标签选择节点(nodeSelector)、直接指定节点名(nodeName)、使用affinitytolerations、选择特定的调度程序(schedulerName)以及要求特定的运行时类(runtimeClassName)。它们还将被用于确定一个 Pod 相对于其他 Pod 的优先级(priorityClassNamepriority)。

  • 生命周期字段将帮助定义一个 Pod 是否应该在终止(restartPolicy)后重启,并微调终止 Pod 的容器中运行的进程被终止(terminationGracePeriodSeconds)或正在运行的 Pod 如果尚未终止将停止(activeDeadlineSeconds)的时间段。它们还有助于定义 Pod 的就绪状态(readinessGates)。

  • 主机名和名称解析字段将帮助定义 Pod 的主机名(hostname和部分 FQDN ( subdomain),在容器(hostAliases)的 /etc/hosts 文件中添加主机,微调容器(dnsConfig)的 /etc/resolv.conf 文件,并定义 DNS 配置的策略(dnsPolicy)。

  • 主机名称空间字段将帮助指示 Pod 是否必须为网络(hostNetwork)、PID(hostPID)和 IPC ( hostIPC)使用主机名称空间,以及容器是否将共享相同的(非主机)进程名称空间(shareProcessNamespace)。

  • 服务帐户字段将有助于通过影响特定服务帐户(serviceAccountName)或通过automountServiceAccountToken禁用默认服务帐户的自动装载来赋予 Pod 特定权限。

  • 安全上下文字段(securityContext)有助于在 Pod 级别定义各种安全属性和通用容器设置。

容器规格

Pod 定义的一个重要部分是它将包含的容器的定义。

我们可以将容器字段分成两部分。第一部分包含与容器运行时相关的字段(映像、入口点、端口、环境变量和卷);第二部分包含将由 Kubernetes 系统处理的字段。

与容器运行时相关的字段如下:

  • 映像字段定义了容器的映像(image)和拉映像的策略(imagePullPolicy)。

  • 入口点字段定义了入口点的命令(command)和参数(args)及其工作目录(workingDir)。

  • 端口字段(ports)定义了从容器中暴露的端口列表。

  • 环境变量字段帮助定义将直接(env)或通过引用配置图或秘密值(envFrom)在容器中导出的环境变量。

  • 字段定义要装入容器的卷,无论它们是文件系统卷(volumeMounts)还是原始块卷(volumeDevices)。

与 Kubernetes 相关的字段如下:

  • 资源字段(resources)帮助定义容器的资源需求和限制。

  • 生命周期字段帮助定义生命周期事件(lifecycle)的处理程序,参数化终止消息(terminationMessagePathterminationMessagePolicy),并定义探测器来检查容器的活性(livenessProbe和就绪(readinessProbe)。

  • 安全上下文字段帮助在容器级别定义各种安全属性和通用容器设置。

  • 调试字段是非常专业的字段,主要用于调试目的(stdinstdinOncetty)。

Pod 控制器

POD,虽然是库伯内特建筑的杰作,但很少单独使用。您通常会使用一个控制器来运行带有一些特定策略的 Pod。

不同的控制器处理盒如下:

  • ReplicaSet:确保指定数量的 Pod 副本在任何给定时间运行。

  • Deployment:启用 pod 和副本集的声明性更新。

  • 管理 pod 和副本集的更新,照顾有状态的资源。

  • DaemonSet:确保所有或部分节点运行一个 Pod 的副本。

  • 启动 pod 并确保它们完成。

  • CronJob:根据时间表创建作业。

在 Kubernetes 中,所有控制器都遵循协调循环的原则:控制器持续观察一些感兴趣的对象,以便能够检测集群的实际状态(运行到集群中的对象)是否满足控制器负责的不同对象的规格,并相应地调整集群。

让我们仔细看看复制集和部署控制器是如何工作的。

复制集控制器

副本集的字段如下:

  • replicas表示您想要多少个所选 POD 的复制品。

  • selector定义您想要 ReplicaSet 控制器管理的 Pods。

  • template是当控制器检测到副本数量不足时,用于创建新 pod 的模板。

  • minReadySeconds表示控制器在 Pod 启动后等待的秒数,不认为 Pod 准备就绪。

复制集控制器持续地观察带有用selector指定的标签的容器。在任何给定的时间,如果带有这些标签的实际运行吊舱的数量

  • 大于请求的replicas,一些 pod 将被终止以满足副本的数量。请注意,终止的 pod 不一定是由 ReplicaSet 控制器创建的 pod。

  • 低于请求的replicas,将使用指定的 Pod template创建新的 Pod,以满足副本的数量。注意,为了避免 ReplicaSet 控制器在循环中创建 Pod,指定的template必须创建一个可由指定的selector选择的 Pod(这就是为什么您必须在selector.matchLabelstemplate.metadata.labels字段中设置相同的标签)。

注意到

  • 副本集的selector字段是不可变的。

  • 更改副本集的template不会立即生效。它将影响在这个变化之后将被创造的荚。

  • 更改replicas字段将立即触发 pod 的创建或终止。

部署控制器

部署的字段如下:

  • replicas表示请求的副本数量。

  • selector定义您希望部署控制器管理的单元。

  • template是 pod 所需的模板。

  • minReadySeconds表示控制器在 Pod 启动后等待的秒数,不认为 Pod 准备就绪。

  • strategy是在改变先前和当前激活的ReplicaSetsreplicas时应用的策略。

  • revisionHistoryLimit是为将来使用而保留的ReplicaSets的编号。

  • paused表示部署是否处于活动状态。

  • progressDeadlineSeconds

部署控制器永久地观察带有请求selector的复制集。其中包括

  • 如果具有所请求的template的副本集存在,控制器将确保该副本集的副本数量等于所请求的replicas(通过使用所请求的strategy),并且minReadySeconds等于所请求的数量。

  • 如果不存在具有所请求的template的副本集,控制器将用所请求的replicasselectortemplateminReadySeconds创建一个新的副本集。

  • 对于具有不匹配template的复制集,控制器将确保replicas的数量被设置为零(通过使用请求的strategy)。

注意到

  • 部署的selector字段是不可变的。

  • 更改部署的template字段将立即

    • 如果不存在具有所请求的selectortemplate的副本集,则触发新副本集的创建

    • 或者用所请求的replicas更新与所请求的selectortemplate相匹配的现有数据库(使用strategy

    • 或者将其他复制集的replicas的数量设置为零

  • 更改部署的replicasminReadySeconds字段将会立即更新相应副本集(具有所请求的template的副本集)的相应值。

使用这种方法,部署控制器管理一系列的副本集,每个副本集对应 Pod 模板的一个修订版。活动副本集是副本数量为正数的副本集,其他修订版的副本数量设置为零。

这样,通过将 Pod 模板从一个版本切换到另一个版本,您可以从一个版本切换到另一个版本(例如,用于回滚)。

更新和回滚

让我们首先在Deployment的帮助下部署 nginx 服务器的映像:

$ kubectl create deployment nginx --image=nginx:1.10
deployment.apps/nginx created

命令kubectl rollout提供了几个子命令来处理部署。

子命令status给出了部署的状态:

$ kubectl rollout status deployment nginx
deployment "nginx" successfully rolled out

history子命令为我们提供了部署的修订历史。这是部署的第一个版本:

$ kubectl rollout history deployment nginx
deployment.apps/nginx
REVISION  CHANGE-CAUSE
1         <none>

我们现在将更新nginx的映像以使用1.11版本。一种方法是使用kubectl set image命令:

$ kubectl set image deployment nginx nginx=nginx:1.11
deployment.extensions/nginx image updated

通过history子命令,我们可以看到部署处于其第二个版本:

$ kubectl rollout history deployment nginx
deployment.apps/nginx
REVISION  CHANGE-CAUSE
1         <none>
2         <none>

默认情况下,change-cause为空。它可以包含用于制作卷展栏的命令,或者通过使用--record标志

$ kubectl set image deployment nginx nginx=nginx:1.12 --record
deployment.apps/nginx image updated
$ kubectl rollout history deployment nginx
deployment.apps/nginx
REVISION  CHANGE-CAUSE
1         <none>
2         <none>
3         kubectl set image deployment nginx nginx=nginx:1.12 --record=true

或者通过设置卷展栏后的kubernetes.io/change-cause注释:

$ kubectl set image deployment nginx nginx=nginx:1.13
deployment.apps/nginx image updated
$ kubectl annotate deployment nginx \
  kubernetes.io/change-cause="update to revision 1.13" \
  --record=false --overwrite=true
$ kubectl rollout history deployment nginx
deployment.apps/nginx
REVISION  CHANGE-CAUSE
1         <none>
2         <none>
3         kubectl set image deployment nginx nginx=nginx:1.12 --record=true
4         update to revision 1.13

还可以编辑部署的规范:

$ kubectl edit deployment nginx

在您喜欢的编辑器打开后,您可以,例如,添加一个环境变量FOO=bar到容器的规范中:

[...]
    spec:
      containers:
      - image: nginx:1.13
        env:
      - name: FOO
        value: bar
[...]

保存模板并退出编辑器后,新的修订版将被部署。让我们验证新 Pod 是否包含此环境变量:

$ kubectl describe pod -l app=nginx
[...]
    Environment:
      FOO:  bar
[...]

让我们为该版本设置一个变更原因,并查看历史记录:

$ kubectl annotate deployment nginx \
  kubernetes.io/change-cause="add FOO environment variable" \
  --record=false --overwrite=true
$ kubectl rollout history deployment nginx
deployment.apps/nginx
REVISION  CHANGE-CAUSE
1         <none>
2         <none>
3         kubectl set image deployment nginx nginx=nginx:1.12 --record=true
4         update to revision 1.13
5         add FOO environment variable

现在让我们用undo子命令回滚上一次的卷展栏:

$ kubectl rollout undo deployment nginx
deployment.apps/nginx rolled back
$ kubectl rollout history deployment nginx
deployment.apps/nginx
REVISION  CHANGE-CAUSE
1         <none>
2         <none>
3         kubectl set image deployment nginx nginx=nginx:1.12 --record=true
5         add FOO envvar
6         update to revision 1.13

我们看到我们切换回了第四个版本(它在列表中消失了,并被重命名为第六个修订版)。

也可以回滚到特定的版本,例如,再次使用nginx:1.12映像:

$ kubectl rollout undo deployment nginx --to-revision=3
deployment.apps/nginx rolled back
$ kubectl rollout history deployment nginx
deployment.apps/nginx
REVISION  CHANGE-CAUSE
1         <none>
2         <none>
5         add FOO envvar
6         update to revision 1.13
7         kubectl set image deployment nginx nginx=nginx:1.12 --record=true

最后,您可以验证每个修订都有一个ReplicaSet:

$ kubectl get replicaset
NAME               DESIRED CURRENT READY AGE
nginx-65c8969d67   0       0       0     58m
nginx-68b47b4d58   0       0       0     62m
nginx-7856959c59   1       1       1     62m
nginx-84c7fd7848   0       0       0     62m
nginx-857df58577   0       0       0     62m

部署策略

您已经在“部署控制器”一节中看到,当改变旧的和新的副本集的副本数量时,部署控制器提供了不同的策略

再造战略

最简单的策略是 Recreate 策略:在这种情况下,旧的副本集将被缩小到零,当该副本集的所有单元停止时,新的副本集将被扩大到所请求的副本数。

一些后果如下:

  • 将有一个小的停机时间,旧的吊舱停止,新的吊舱开始。

  • 并行运行以前的和新的 pod 不需要额外的资源。

  • 新旧版本不会同时运行。

滚动更新策略

RollingUpdate 策略是一种更高级的策略,也是创建部署时的默认策略。

该策略的目标是在不停机的情况下从以前的版本更新到新版本。

该策略将缩小和扩大复制集的可能性与通过服务公开 pod 的可能性结合起来。

你将在第十章中看到传统上通过服务访问 pod。服务资源声明了一个端点列表,这些端点是通过该服务公开的 pod 列表。当服务的端点没有准备好服务请求时,pod 被从服务的端点移除,当服务的端点准备好服务请求时,pod 被添加。

Pod 的就绪状态由为其容器声明的就绪探测器的状态决定。如果您没有为您的容器声明就绪探测器,那么风险在于,在它们真正就绪之前,会检测到这些容器就绪,并且当它们仍处于启动阶段时,会向它们发送流量。

在滚动更新期间,部署控制器一方面将

  • 增加新版本副本的数量

    当副本准备好时,它将被端点控制器添加到服务端点。

另一方面

  • 将旧版本的副本标记为未就绪,因此它们将由端点控制器从服务端点中移除

  • 阻止这些复制品

根据流量和可用资源,您可能希望先增加新版本副本的数量,然后停止旧副本,或者相反,先停止旧副本,然后启动新版本副本。

为此,部署strategy字段的字段maxSurgemaxUnavailable分别指示除了和少于预期数量的副本之外可以存在多少副本。根据这些值,部署控制器要么首先启动新版本,要么首先停止旧版本。

运行作业

作业和 CronJob 控制器帮助您运行 pod,直到它们按照基于时间的计划完成。

作业控制器

作业控制器并行运行一个或多个 pod,并等待特定数量的 pod 成功终止。

运行一个 Pod 直到完成

最简单的情况是运行一个 Pod 直到它完成。在这种情况下,您必须用spec.template声明要运行的 Pod 的模板,作业控制器将从该模板启动一个 Pod。

如果过了一段时间,Pod 成功终止(这意味着所有容器都以零状态退出),则该作业被标记为已完成。

但是如果 Pod 错误退出,新的 Pod 将重新启动,直到 Pod 成功或出现给定数量的错误。重试次数由spec.backoffLimit的值决定。

下面是一个将运行至完成的作业示例:

apiVersion: batch/v1
kind: Job
metadata:
  name: a-job
spec:
  template:
    spec:
      containers:
      - name: a-job
        image: bash
        command: ["bash", "-c", "sleep 1; exit 0" ]
      restartPolicy: Never

几秒钟后,您会看到 Pod 状态为Completed,作业状态为succeeded:

$ kubectl get pods
NAME          READY   STATUS     RESTARTS   AGE
a-job-sgd8r   0/1     Completed  0          8s

$ kubectl get jobs
NAME    COMPLETIONS   DURATION   AGE
a-job   1/1           4s         60s

$ kubectl get jobs a-job -o yaml
[...]
status:
  completionTime: "2020-08-15T09:19:07Z"
  conditions:
  - lastProbeTime: "2020-08-15T09:19:07Z"
    lastTransitionTime: "2020-08-15T09:19:07Z"
    status: "True"
    type: Complete
  startTime: "2020-08-15T09:19:03Z"
  succeeded: 1

现在,这是一个经常失败的工作的例子:

apiVersion: batch/v1
kind: Job
metadata:
  name: a-job-failing
spec:
  template:
    spec:
      containers:
      - name: a-job-failing
        image: bash
        command: ["bash", "-c", "sleep 1; exit 1" ]
      restartPolicy: Never
  backoffLimit: 3

过了一会儿,您可以看到启动了四个单元(一次加三次重试),所有这些单元都失败了,作业被标记为失败:

$ kubectl get pods
NAME                  READY   STATUS   RESTARTS   AGE
a-job-failing-92qsj   0/1     Error    0          2m19s
a-job-failing-c5w9x   0/1     Error    0          2m5s
a-job-failing-g4bp9   0/1     Error    0          105s
a-job-failing-nwm4q   0/1     Error    0          2m15s

$ kubectl get jobs a-job-failing -o yaml
[...]
status:
  conditions:
  - lastProbeTime: "2020-08-15T09:26:14Z"
    lastTransitionTime: "2020-08-15T09:26:14Z"
    message: Job has reached the specified backoff limit

    reason: BackoffLimitExceeded
    status: "True"
    type: Failed
  failed: 4
  startTime: "2020-08-15T09:25:00Z"

运行几个 pod,直到一个完成

如果您指定了与spec.parallelism并行运行的 pod 的数量,并且没有在spec.completions中定义完成的数量,作业控制器将并行运行这个数量的 pod,直到一个成功。

在第一个 Pod 成功之前的时间内,失败的 Pod 将由其他 Pod 替换。一旦一个 Pod 成功,控制器将等待其他 Pod 终止(错误或成功),并将作业标记为成功。

在此示例中,并行运行四个 pod,随机退出错误或成功,您可以检查控制器如何操作:

apiVersion: batch/v1
kind: Job
metadata:
  name: a-job
spec:
  template:
    spec:
      containers:
      - name: a-job
        image: bash
        command: ["bash", "-c", "sleep $((RANDOM/1024+1)); exit $((RANDOM/16384))" ]
  restartPolicy: Never

parallelism: 4

$ kubectl apply -f job-parallel.yaml && kubectl get pods -w
job.batch/a-job created
NAME         READY  STATUS             RESTARTS AGE
a-job-aaaaa  0/1    ContainerCreating  0        2s
a-job-bbbbb  0/1    ContainerCreating  0        2s
a-job-ccccc  0/1    ContainerCreating  0        2s
a-job-ddddd  0/1    ContainerCreating  0        3s
a-job-aaaaa  1/1    Running            0        5s
a-job-bbbbb  1/1    Running            0        6s
a-job-ccccc  1/1    Running            0        7s
a-job-ddddd  1/1    Running            0        8s
a-job-bbbbb  0/1    Error              0        12s b fails
a-job-BBBBB  0/1    Pending            0        0s B replaces b
a-job-BBBBB  0/1    ContainerCreating  0        0s
a-job-BBBBB  1/1    Running            0        3s
a-job-aaaaa  0/1    Error              0        19s a fails
a-job-AAAAA  0/1    Pending            0        0s A replaces a
a-job-AAAAA  0/1    ContainerCreating  0        0s
a-job-ddddd  0/1    Completed          0        22s d succeeds
a-job-AAAAA  1/1    Running            0        3s
a-job-AAAAA  0/1    Error              0        6s A fails, not replaced
a-job-ccccc  0/1    Error              0        29s c fails, not replaced

a-job-BBBBB  0/1    Completed          0        36s B succeeds

运行几个单元,直到几个单元完成

您可以使用spec.completions指定您希望成功的 pod 数量,使用spec.parallelism指定并行运行的 pod 的最大数量。

在所有情况下,并行运行的 pod 数量永远不会高于仍待完成的完成数量。例如,如果您指定一个4completions和一个parallelism为 6,控制器将首先启动四个吊舱(因为还有四个完成任务要完成)。当第一个 Pod 成功时,还剩下三个完成,如果已经有三个 Pod 在运行,控制器将不会启动新的 Pod。

在这个例子中,让我们检查一下控制器对于 4 的parallelism和 4 的completions是如何工作的:

apiVersion: batch/v1
kind: Job
metadata:
  name: a-job
spec:
  template: spec:
    containers:
    - name: a-job
      image: bash
      command: ["bash", "-c", "sleep $((RANDOM/1024+1)); exit $((RANDOM/16384))" ]
    restartPolicy: Never
  parallelism: 4
  completions: 4

$ kubectl apply -f job-parallel.yaml && kubectl get pods -w
job.batch/a-job created

NAME         READY  STATUS              RESTARTS  AGE
a-job-aaa01  0/1    ContainerCreating   0         1s
a-job-bbb01  0/1    ContainerCreating   0         1s
a-job-ccc01  0/1    ContainerCreating   0         1s
a-job-ddd01  0/1    ContainerCreating   0         1s
a-job-ccc01  1/1    Running             0         5s
a-job-bbb01  1/1    Running             0         5s
a-job-aaa01  1/1    Running             0         7s
a-job-ddd01  1/1    Running             0         9s
a-job-ccc01  0/1    Completed           0         11s c1 succeeds
a-job-ddd01  0/1    Completed           0         13s d1 succeeds
a-job-aaa01  0/1    Completed           0         17s a1 succeeds
a-job-bbb01  0/1    Error               0         28s b1 fails, replaced by b2
a-job-bbb02  0/1     Pending            0         0s
a-job-bbb02  0/1     ContainerCreating  0         0s
a-job-bbb02  1/1     Running            0         4s
a-job-bbb02  0/1     Error              0         30s b2 fails, replaced by b3

a-job-bbb03  0/1     Pending            0         0s
a-job-bbb03  0/1     ContainerCreating  0         0s
a-job-bbb03  1/1     Running            0         3s
a-job-bbb03   0/1     Completed         0         12s b3 succeeds

CronJob 控制器

CronJob 控制器允许您按照基于时间的计划运行作业。

创建CronJob模板时,两个必需的规范字段如下:

  • jobTemplate是您想要按基于时间的计划运行的作业的模板。

  • schedule是运行作业的时间规范,采用 Cron 格式。

concurrencyPolicy表示当前一个任务仍在运行时如何处理新任务。可能的值是Allow允许几个并发作业,Forbid如果前一个作业仍在运行则跳过新作业,Replace在运行新作业之前首先取消前一个作业。

如果您想暂时挂起一个特定的 CronJob,而不删除它,那么suspend布尔值非常有用。

计划格式

计划信息由五部分组成,代表执行作业的时间:

  • 分钟(0–59)

  • 小时(0–23)

  • 一个月中的第几天(1–31)

  • 月份(1–12)

  • 一周中的某一天(0–周日至 6–周六)

如果您不想限制在某个特定字段,可以使用星号*

符号*/n可用于每 n 个时间间隔运行一次作业,其中n是一个数字。

您可以用逗号分隔值来指定几个时间间隔。

示例:

  • 10 2 * * *将在每天凌晨 2:10 运行作业。

  • 将在每周日凌晨 3:30 运行该作业。

  • */15 7,8,9 * * *将在上午 7 点到 10 点(不包括)之间每 15 分钟运行一次作业。

六、配置应用

可以用不同的方式配置应用:

  • 通过向命令传递参数

  • 通过定义环境变量

  • 使用配置文件

命令的参数

我们在第五章“容器规范”一节中已经看到,我们可以用容器规范的Args字段来定义命令的参数。

不能通过使用kubectl命令runcreate来强制定义命令的参数。

根据映像的定义,您可能还必须指定Command值(尤其是当 Dockerfile 没有定义ENTRYPOINT而只定义了一个CMD)。

您必须在定义容器的模板中指定参数:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx

        name: nginx
        command: ["nginx"]
        args: ["-g", "daemon off; worker_priority 10;"]

环境变量

可以为容器定义环境变量,方法是直接声明它们的值,或者从ConfigMapsSecrets或所创建对象的字段(部署等)中引用它们的值。

直接声明值

以声明的形式

以声明方式,您可以将环境变量添加到容器的定义中:

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx
  name: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx
        name: nginx
        env:
        - name: VAR1
          value: "value1"
        - name: VAR2
          value: "value2"

以命令的形式

强制性地,使用kubectl run命令,您可以从命令行定义环境变量:

$ kubectl run nginx --image=nginx \
  --env VAR1=value1 \
  --env VAR2=value2
pod/nginx created

请注意,不推荐使用用于创建部署的kubectl run命令的变体,而推荐使用kubectl create deployment命令。不幸的是,这个命令不接受--env旗。您可以在创建部署后使用kubectl set env命令添加环境变量:

$ kubectl create deployment nginx --image=nginx
deployment.apps/nginx created
$ kubectl set env deployment nginx \
  --env VAR1=value1 \
  --env VAR2=value2
deployment.apps/nginx env updated

从配置映射和机密中引用特定值

以声明的形式

以声明方式,当声明环境变量时,您可以指示应该从 ConfigMap 或 Secret 中逐个提取值:

apiVersion: v1
kind: ConfigMap
metadata:
  name: vars
data:
  var1: value1
  var2: value2
---

apiVersion: v1
kind: Secret
metadata:
  name: passwords
stringData:
  pass1: foo
---

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx
  name: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx
        name: nginx
        env:
        - name: VAR1
          valueFrom:
            configMapKeyRef:
                key: var1
                name: vars
        - name: VAR2
          valueFrom:
            configMapKeyRef:
                key: var2
                name: vars
        - name: PASS1
          valueFrom:
            secretKeyRef:
                key: pass1
                name: passwords

请注意,如果在引用的配置映射或机密中找不到引用的密钥,部署的创建将会失败。如果您想要创建部署,即使值不存在(在这种情况下,相应的环境变量将不会被定义),您可以使用optional字段:

- name: PASS2
  valueFrom:
    secretKeyRef:
        key: pass2
        name: passwords
        optional: true

以命令的形式

强制性地,您也可以使用带有--fromkeys标志的kubectl set env命令。在本例中,您只引用了 ConfigMap 和 Secret 中定义的一些密钥:

$ kubectl create configmap vars \
  --from-literal=var1=value1 \
  --from-literal=var2=value2 \
  --from-literal=var3=value3
configmap/vars created
$ kubectl create secret generic passwords \
  --from-literal=pass1=foo \
  --from-literal=pass2=bar
secret/passwords created
$ kubectl create deployment nginx --image=nginx
deployment.apps/nginx created
$ kubectl set env deployment nginx \
  --from=configmap/vars \
  --keys="var1,var2"
deployment.apps/nginx env updated
$ kubectl set env deployment nginx \
  --from=secret/passwords \
  --keys="pass1"
deployment.apps/nginx env updated

引用配置映射和机密中的所有值

以声明的形式

您还可以将配置映射或机密的所有条目作为环境变量注入(在这种情况下,您还可以使用optional字段来指示操作应该成功,即使所引用的配置映射或机密不存在):

apiVersion: v1
kind: ConfigMap
metadata:
  name: vars
data:
  var1: value1
  var2: value2
---

apiVersion: v1
kind: Secret
metadata:
  name: passwords
stringData:
  pass1: foo
---

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx

  name: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app:  nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx
        name: nginx
        envFrom:
        - configMapRef:
            name: vars
        - secretRef:
            name: passwords

        - secretRef:
            name: notfound
            optional: true

以命令的形式

强制性地,您也可以使用带有--from标志的kubectl set env命令:

$ kubectl create configmap vars \
  --from-literal=var1=value1 \
  --from-literal=var2=value2
configmap/vars created
$ kubectl create secret generic passwords \
  --from-literal=pass1=foo
secret/passwords created
$ kubectl create deployment nginx --image=nginx
deployment.apps/nginx created
$ kubectl set env deployment nginx \
  --from=configmap/vars
deployment.apps/nginx env updated
$ kubectl set env deployment nginx \
  --from=secret/passwords
deployment.apps/nginx env updated

从 Pod 字段引用值

以声明方式,可以引用 Pod 的某些字段的值:

  • metadata.name

  • 元数据.命名空间

  • 元数据. uid

  • 规格节点名称

  • 服务帐户规格 Name

  • status.hostIP

  • status.podIP

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx
  name: nginx

spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx
        name: nginx
        env:
        - name: POD_NAME
          valueFrom:
            fieldRef:
                fieldPath: metadata.name
        - name: POD_NAMESPACE
          valueFrom:
            fieldRef:
                fieldPath: metadata.namespace
        - name: POD_UID
          valueFrom:
            fieldRef:
                fieldPath: metadata.uid
        - name:   POD_NODENAME
          valueFrom:
            fieldRef:
                fieldPath: spec.nodeName
        - name: POD_SERVICEACCOUNTNAME
          valueFrom:
            fieldRef:
                fieldPath: spec.serviceAccountName
        - name: POD_HOSTIP
          valueFrom:
            fieldRef:
                fieldPath: status.hostIP
        - name: POD_PODIP
          valueFrom:
            fieldRef:
                fieldPath: status.podIP

应用此模板后,您可以将环境变量的值检查到容器中:

$ kubectl exec -it nginx-xxxxxxxxxx-yyyyy bash -- -c "env | grep POD_"

从容器资源字段引用值

以声明方式,可以引用容器的资源请求和限制的值。您可以使用divisor字段将该值除以给定的除数:

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx
  name: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx
        name: nginx

        resources:
          requests:
            cpu: "500m"
            memory: "500Mi"
          limits:
            cpu: "1"
            memory: "1Gi"
        env:
        - name: M_CPU_REQUEST
          valueFrom:
            resourceFieldRef:
                resource: requests.cpu
                divisor: "0.001"
        - name: MEMORY_REQUEST
          valueFrom:
            resourceFieldRef:
                resource: requests.memory
        - name:  M_CPU_LIMIT
          valueFrom:
            resourceFieldRef:
                resource: limits.cpu
                divisor: "0.001"
        - name: MEMORY_LIMIT
          valueFrom:
            resourceFieldRef:
                resource: limits.memory

变量将获得以下值:

M_CPU_REQUEST=500
MEMORY_REQUEST=524288000
M_CPU_LIMIT=1000
MEMORY_LIMIT=1073741824

来自配置映射的配置文件

可以在容器文件系统中挂载 ConfigMap 内容。挂载的配置映射的每个键/值将是一个文件名及其在挂载目录中的内容。

例如,您可以以声明形式创建此配置映射:

apiVersion: v1
kind: ConfigMap
metadata:
  name: config
data:
  nginx.conf: |
    server {
      location / {
        root /data/www;
      }

      locatioimg/ {
        root /data;
      }
    }

或以命令的形式:

$ cat > nginx.conf <<EOF
server {
    location / {
        root /data/www;
    }

    locatioimg/ {
        root /data;
    }
}
EOF
$ kubectl create configmap config --from-file=nginx.conf
configmap/config created

然后,您可以在容器中挂载配置映射:

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx
  name: nginx
spec:
  replicas:  1
  selector:
    matchLabels:
      app: nginx
    template:
      metadata:
        labels:
          app: nginx
      spec:
        volumes:
        - name: config-volume
          configMap: config
        containers:
        - image: nginx
          name: nginx
          volumeMounts:
          - name: config-volume
            mountPath: /etc/nginx/conf.d/

最后,容器中的文件/etc/nginx/conf.d/nginx.conf将包含 ConfigMap 的nginx.conf键的值。

来自 Secret 的配置文件

同样,也可以挂载秘密的内容。首先,以声明的形式创建一个秘密

apiVersion: v1
kind: Secret
metadata:
  name: passwords
stringData:
  password: foobar

或祈使句:

$ kubectl create secret generic passwords \
  --from-literal=password=foobar
secret/passwords created

然后在容器中装入秘密:

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx
  name: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx

  template:
    metadata:
      labels:
        app: nginx
    spec:
      volumes:
      - name: passwords-volume
        secret:
          secretName: passwords
          containers:
          - image: nginx
            name: nginx
            volumeMounts:
            - name: passwords-volume
              mountPath: /etc/passwords

最后,容器中的文件/etc/passwords/password将包含 foobar。

Pod 字段中的配置文件

以声明方式,可以装入包含 Pod 值的文件的卷:

  • metadata.name

  • 元数据.命名空间

  • 元数据. uid

  • 元数据.标签

  • 元数据.注释

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx
  name: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx
        name: nginx
        volumeMounts:
        - name: pod-info
          mountPath: /pod
          readOnly: true
      volumes:
        - name: pod-info
          downwardAPI:
            items:
            - path: metadata/name
              fieldRef:
                fieldPath: metadata.name
            - path: metadata/namespace
              fieldRef:
                fieldPath: metadata.namespace
            - path: metadata/uid
              fieldRef:
                fieldPath: metadata.uid
            - path: metadata/labels
              fieldRef:
                fieldPath: metadata.labels
            - path: metadata/annotations
              fieldRef:
                fieldPath: metadata.annotations

因此,在容器中,您可以在/pod/metadata中找到文件:

$ kubectl exec nginx-xxxxxxxxxx-yyyyy bash -- -c \
  'for i in /pod/metadata/*; do echo $i; cat -n $i; echo ; done'
/pod/metadata/annotations
     1  kubernetes.io/config.seen="2020-01-11T17:21:40.497901295Z"
     2  kubernetes.io/config.source="api"
/pod/metadata/labels
     1  app="nginx"
     2  pod-template-hash="789ccf5b7b"
/pod/metadata/name
     1  nginx-xxxxxxxxxx-yyyyy
/pod/metadata/namespace
     1  default
/pod/metadata/uid
     1  631d01b2-eb1c-49dc-8c06-06d244f74ed4

容器资源字段中的配置文件

以声明的方式,可以用包含资源请求值和容器限制的文件来挂载卷。您可以使用divisor字段将该值除以给定的除数:

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx
  name: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx
        name: nginx
        resources:
          requests:
            cpu: "500m"
            memory: "500Mi"
          limits:
            cpu: "1"
            memory: "1Gi"
        volumeMounts:
        - name: resources-info
          mountPath: /resources
          readOnly: true
      volumes:
        - name: resources-info
          downwardAPI:
            items:
            - path: limits/cpu
              resourceFieldRef:
                resource: limits.cpu
                divisor: "0.001"
                containerName: nginx
            - path: limits/memory
              resourceFieldRef:
                resource: limits.memory
                containerName: nginx
            - path: requests/cpu
              resourceFieldRef:
                resource: requests.cpu
                divisor: "0.001"
                containerName: nginx
            - path: requests/memory
              resourceFieldRef:
                resource: requests.memory
                containerName: nginx

因此,在容器中,您可以在/resources中找到文件:

$ kubectl exec nginx-85d7c97f64-9knh9 bash -- -c \
  'for i in /resources/*/*; do echo $i; cat -n $i; echo ; done'
/resources/limits/cpu
     1  1000
/resources/limits/memory
     1  1073741824
/resources/requests/cpu

     1  500
/resources/requests/memory
     1  524288000

不同来源的配置文件

可以使用包含配置映射、机密、Pod 字段和容器资源字段混合信息的文件来装载卷。

与前面示例的主要区别在于,这里可以在同一目录中混合来自这些不同来源的值:

apiVersion: v1
kind: ConfigMap
metadata:
  name: values
data:
  cpu: "4000"
  memory: "17179869184"
---

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx
  name: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx
        name: nginx

        resources:
          requests:
            cpu: "500m"
            memory: "500Mi"
          limits:
            cpu: "1"
            memory: "1Gi"
        volumeMounts:
        - name: config
          mountPath: /config
          readOnly: true
      volumes:
        - name: config
          projected:
            sources:
            - configMap:
                name: values
                items:
                - key: cpu
                  path: cpu/value
                - key: memory
                  path: memory/value
            - downwardAPI:
                items:
                - path: cpu/limits
                  resourceFieldRef:
                    resource: limits.cpu
                    divisor: "0.001"
                    containerName: nginx
                - path: memory/limits
                  resourceFieldRef:
                    resource: limits.memory
                    containerName: nginx
                - path: cpu/requests
                  resourceFieldRef:
                    resource: requests.cpu
                    divisor: "0.001"
                    containerName: nginx
                - path: memory/requests
                  resourceFieldRef:
                    resource: requests.memory
                    containerName: nginx

因此,在容器中,您可以在/config中找到文件:

$ kubectl exec nginx-7d797b5788-xzw79 bash -- -c \
  'for i in /config/*/*; do echo $i; cat -n $i; echo ; done'
/config/cpu/limits
     1  1000
/config/cpu/requests
     1  500
/config/cpu/value
     1  4000
/config/memory/limits
     1  1073741824
/config/memory/requests
     1  524288000
/config/memory/value
     1  17179869184