Kubernetes应用程序开发认证(CKAD)学习指南-第3章 配置
第3章 配置
本章涵盖了用于配置Pod的高级概念。本章将通过一个具体的用例讨论所有相关的Kubernetes原语及其用途。
如前一章所示,使用环境变量控制运行时行为是常见的做法。通过为各个容器定义环境变量,导致必须处理一系列环境变量,这很快就会变得单调乏味,特别是当您希望在一组Pods中重用其中一些键-值对时。ConfigMaps和Secrets有助于集中配置数据,可以注入到容器中。
此外,本章还讨论了安全和资源消耗问题。可以定义安全上下文来定义特权和访问控制设置。每个命名空间都可以限制Pods可用的CPU和内存等资源数量。在本章的最后,您将了解如何创建和检查一个ResourceQuota,以及如何为一个Pod设置最小和最大资源边界。最后,我们将讨论为Pod分配服务帐户所需的配置。
请注意 本章将采用卷(Volume)的概念。如果您不熟悉Kubernetes的持久存储选项,请参考第8章获取更多信息。 |
本章涵盖以下概念:
- ConfigMap
- Secret
- Volume
- 安全上下文
- 资源的边界
- ResourceQuota
- 服务帐户
定义和使用配置数据
持续交付的基本原则之一是为单个SCM提交只构建一次二进制工件。二进制工件应该存储在二进制存储库中—例如,在商业产品JFrog工件中。如果需要将工件部署到目标环境,那么自动化流程将下载该工件。典型的目标运行时环境包括staging或生产环境。如果您要在每个环境中重新构建工件,那么只构建一次工件的方法可以防止意外的错误,并在将软件交付给客户时提高整体的信心水平。每个环境所需的配置数据都可以注入到运行时环境中。环境变量可以帮助完成这个任务,但是还有其他选项。
让我们在容器运行时环境(如Docker)之间架起桥梁。这里应该应用构建一次工件的相同概念。在我们的例子中,二进制工件是一个容器镜像。您不会希望为不同的运行时环境重新生成镜像。
Kubernetes用两个原语来定义配置数据:ConfigMap和Secret。这两个原语都与Pod的生命周期完全解耦,这使您能够更改它们的配置数据值,而不必重新部署Pod。本质上,ConfigMap和Secrets存储一组键-值对。这些键-值对可以作为环境变量注入到容器中,也可以作为卷挂载。图3-1展示了一个示例Pod,使用ConfigMap中的数据作为卷挂载,而Secret作为环境变量。
ConfigMap和Secret之间的区别是什么?它们在用途和结构上几乎是相同的,尽管Secret更适合存储敏感数据,如密码、API密钥或SSL证书,因为它们存储用Base64编码的值。我还要提一下Secret的安全方面。Base64只对值进行编码,但不加密。因此,任何了解其value的人都可以迅速解码。Secret只分发给实际需要访问它的运行Pods的节点。此外,Secret存储在内存中,而不会写入物理存储器。
图3-1 使用配置数据
创建一个ConfigMap
可以使用命令创建一个ConfigMap:kubectl create configmap。作为命令的一部分,必须提供一个强制的命令行flag,该flag指向数据来源。Kubernetes提供了四个不同的选项:
- 字面值,它是纯文本形式的键-值对。
- 包含键-值对并期望它们为环境变量的文件。
- 包含任意内容的文件。
- 包含一个或多个文件的目录。
下面的命令显示运行中的所有选项。文件和目录使用相同的命令行选项 --from-file。稍后,我们将介绍如何在ConfigMap中解析和存储这些键-值对。
字面值
$ kubectl create configmap db-config --from-literal=db=staging
configmap/db-config created
带有环境变量的单个文件
$ kubectl create configmap db-config --from-env-file=config.env
configmap/db-config created
单个文件
$ kubectl create configmap db-config --from-file=config.txt
configmap/db-config created
包含文件的目录
$ kubectl create configmap db-config --from-file=app-config
configmap/db-config created
另外,也可以声明式创建ConfigMap。假设你决定将键值对定义为字面值;YAML表示形式可以像例3-1中所示的那样。
例3-1 ConfigMap YAML清单
apiVersion: v1
kind: ConfigMap
metadata:
name: backend-config
data:
database_url: jdbc:postgresql://localhost/test
使用ConfigMap作为环境变量
一旦创建了ConfigMap,它就可以被同一个命名空间中的一个或多个Pods使用。这里,我们将探索如何将ConfigMap的键值对注入为环境变量。例3-2中显示的Pod,定义引用名为backend-config的ConfigMap,并在envFrom.configMapRef的帮助下将键值对作为环境变量注入。
3-2示例 将ConfigMap键-值对注入到容器中
apiVersion: v1
kind: Pod
metadata:
name: configured-pod
spec:
containers:
name: app
envFrom:
name: backend-config
需要指出的是,属性envFrom不会自动格式化key,以符合环境变量使用的典型约定(全部为大写字母,单词由下划线分隔)。该属性只是按原样使用key。在创建Pod之后,你可以通过在容器中执行远程Unix命令env来检查注入的环境变量:
$ kubectl exec configured-pod -- env
...
database_url=jdbc:postgresql://localhost/test
user=fred
...
有时,键值对不符合环境变量的典型命名约定,或者不能在不影响正在运行的服务的情况下进行更改。您可以使用valueFrom属性重新定义用于将环境变量注入到Pod中的键。例3-3将关键字database_url转换为DATABASE_URL,关键字user转换为USERNAME。
例3-3 为ConfigMap项重新分配环境变量键
apiVersion: v1
kind: Pod
metadata:
name: configured-pod
spec:
containers:
name: app
env:
valueFrom:
configMapKeyRef:
name: backend-config
key: database_url
valueFrom:
configMapKeyRef:
name: backend-config
key: user
容器可用的最终环境变量现在遵循环境变量的命名约定:
$ kubectl exec configured-pod -- env
...
DATABASE_URL=jdbc:postgresql://localhost/test
USERNAME=fred
...
将ConfigMap挂载为卷
大多数编程语言都可以解析和使用环境变量来控制应用程序的运行时行为。特别是在处理一系列配置数据时,最好从容器的文件系统中访问键-值对。
ConfigMap可以挂载为卷。然后,应用程序将从具有预期挂载路径的文件系统中读取这些键-值对。Kubernetes将ConfigMap中的每个键表示为一个文件。该值成为文件的内容。听起来很复杂?让我们看一看例3-4。
例3-4 将ConfigMap挂载为卷
apiVersion: v1
kind: Pod
metadata:
name: configured-pod
spec:
containers:
name: app
volumeMounts:
mountPath: /etc/config
volumes:
configMap:
name: backend-config
在例3-4所示的YAML清单中,我想指出最重要的构建块。volumes属性指定要使用的卷。正如在代码片段中看到的,它指向ConfigMap的名称。卷的名称与使用volumeMounts属性添加挂载路径相关。这里,我们指向挂载路径/etc/config。
要验证预期的行为,请打开一个交互式shell。如下终端输出所示,该目录包含database_url和user文件。这些文件名对应于ConfigMap的键。文件内容表示它们在ConfigMap中对应的值:
$ kubectl exec -it configured-pod -- /bin/sh
# ls -1 /etc/config
database_url
user
# cat /etc/config/database_url
jdbc:postgresql://localhost/test
# cat /etc/config/user
fred
创建一个Secret
您可以使用命令创建一个Secret:kubectl create Secret。与创建ConfigMap的命令类似,必须提供额外的子命令和配置选项。必须在Kubernetes资源类型secret之后拼写子命令。您可以选择表3-1所示的选项之一。
表3-1 创建Secret的选项
选项 |
描述 |
generic |
从文件、目录或字面值创建一个Secret。 |
docker-registry |
创建一个带Docker注册中心的Secret。 |
tls |
创建一个TLS Secret |
在大多数情况下,你可能会处理通用类型,它提供了和kubectl create configmap一样的命令行选项来指向配置数据的源:
- 字面值,它是纯文本形式的键-值对。
- 包含键-值对并期望它们为环境变量的文件。
- 包含任意内容的文件。
- 包含一个或多个文件的目录。
让我们看一些用命令行创建Secret类型的例子。输入命令的所有值都将以Base64编码存储在内部。例如,值s3cre!变成czNjcmUh。
字面值
secret/db-creds created
包含环境变量的文件
$ kubectl create secret generic db-creds --from-env-file=secret.env
secret/db-creds created
SSH密钥文件
$ kubectl create secret generic ssh-key --from-file=id_rsa=~/.ssh/id_rsa
secret/db-creds created
当然,可以采用声明式方法,但是有一点需要注意。当使用Opaque类型时,您必须自己对配置数据值进行base64编码。如何做到呢?对值进行编码和解码的一种方法是Unix命令行工具base64。另外,你也可以使用像Base64 Encode这样的网站。使用命令行工具的示例如下:
czNjcmUh
现在,您可以在data部分下使用相应的键插入值,如示例3-5所示。
例子3-5 使用base64编码值的Secret
apiVersion: v1
kind: Secret
metadata:
name: db-creds
type: Opaque
data:
pwd: czNjcmUh
有关可分配给Secret的其他类型(不需要显式的base64编码),请参阅Kubernetes文档。kubernetes.io/basic-auth类型就是一个例子,表示基本身份验证所需的凭据。
使用一个Secret作为环境变量
使用Secret的键-值对作为容器中的环境变量,其工作方式与使用ConfigMap几乎完全相同。只有一个区别:不是使用envFrom.configMapRef,而是使用envFrom.secretRef。如3-6所示。
例3-6 将Secret的键值对注入到容器中
apiVersion: v1
kind: Pod
metadata:
name: configured-pod
spec:
containers:
name: app
envFrom:
name: db-creds
容器将环境变量解码,使之可用,理解这一点很重要。反过来,在容器中运行的应用程序不必实现base64解码逻辑:
将Secret挂载为卷
在实践中,您会经常看到Secret作为卷挂载,特别是在使SSH私钥对容器可用的上下文中。例3-7假设您已经使用密钥id_rsa创建了一个名为ssh-key的Secret。首先,通过使用secret.secretName,将其指向Secret的名称来创建卷。注意引用该名称的属性与ConfigMap不同;对于Secret,它叫做secretName。接下来,通过卷的名称挂载卷,并提供一个挂载路径。
例3-7 Secret作为卷挂载
apiVersion: v1
kind: Pod
metadata:
name: configured-pod
spec:
containers:
name: app
volumeMounts:
mountPath: /var/app
readOnly: true
volumes:
secret:
secretName: ssh-key
作为卷挂载的Secrets将以base64解码的形式公开其值。你可以很容易地验证这个值,打开一个交互式shell,将/var/app/id_rsa文件的内容打印到标准输出:
$ kubectl exec -it configured-pod -- /bin/sh
# ls -1 /var/app
id_rsa
# cat /var/app/id_rsa
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-128-CBC,8734C9153079F2E8497C8075289EBBF1
...
-----END RSA PRIVATE KEY-----
理解Security上下文
Docker images可以定义安全相关指令,减少运行容器的攻击向量。默认情况下,容器以root权限运行,提供对所有进程和容器文件系统的最高访问权限。作为一个最佳实践,您应该以这样一种方式创建相应的Dockerfile,即容器将在用户指令的帮助下以一个用户ID而不是0运行。还有许多其他方法可以在容器级别上保护容器,但我们在这里不再详细讨论。
Kubernetes作为容器编排引擎,可以应用额外的配置来提高容器安全性。您可以通过定义安全上下文来实现这一点。安全上下文定义Pod或容器的权限和访问控制设置。下面列出了一些例子:
- 用于运行Pod和/或容器的用户ID。
- 应该用于文件系统访问的组ID。
- 授予容器内运行的进程root用户的某些特权,但不是全部。
安全上下文不是Kubernetes原语。它被建模为Pod规范中的指令securityContext下的一组属性。Pod级别上定义的安全设置适用于在Pod中运行的所有容器;但是,容器级别的设置优先级高。有关pod级安全属性的更多信息,请参阅PodSecurityContext API。容器级安全属性可以在SecurityContext API中找到。
为了使功能更加透明,让我们来看一个用例。有些镜像,比如开源反向代理服务器NGINX的镜像,必须在root用户下运行。假设您想强制容器不能作为root用户运行,这是一个合理的安全策略。例3-8中显示的YAML清单专门为一个容器定义了安全配置。如果要在Pod中运行其他容器,那么runAsNonRoot设置不会对它们产生任何影响。
例3-8 在容器级别上设置安全上下文
apiVersion: v1
kind: Pod
metadata:
name: non-root
spec:
containers:
name: secured-container
securityContext:
runAsNonRoot: true
你会看到Kubernetes做了它的工作;然而,镜像是不兼容的。因此,在启动过程中容器失败,状态为CreateContainerConfigError:
$ kubectl create -f container-root-user.yaml
pod/non-root created
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
non-root 0/1 CreateContainerConfigError 0 7s
$ kubectl describe pod/non-root
...
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled <unknown> default-scheduler Successfully assigned \
default/non-root to minikube
Normal Pulling 18s kubelet, minikube Pulling image "nginx:1.18.0"
Normal Pulled 14s kubelet, minikube Successfully pulled image \
"nginx:1.18.0"
Warning Failed 0s (x3 over 14s) kubelet, minikube Error: container has \
runAsNonRoot and image \
will run as root
还有其他的NGINX镜像,它们不需要在root用户下运行。一个例子是bitnami/nginx。仔细查看生成镜像的Dockerfile,会发现容器以用户ID 1001运行。用runAsNonRoot指令启动容器就可以了。
在Kubernetes中运行的容器还有许多其他的安全限制。例如,您可能想要为文件和目录设置访问控制。假设,无论何时在文件系统上创建一个文件,该文件的所有者应该是任意组ID 3500。示例3-9中显示的YAML清单将Pod级别上的安全上下文设置分配为spec属性的直接子属性。
例3-9 在Pod级别上设置安全上下文
apiVersion: v1
kind: Pod
metadata:
name: fs-secured
spec:
securityContext:
fsGroup: 3500
containers:
name: secured-container
volumeMounts:
mountPath: /data/app
volumes:
您可以很容易地验证设置文件系统组ID的效果。打开到容器的交互式shell,导航到挂载的卷,并创建一个新文件。检查文件的所有权将显示自动分配给它的组ID 3500:
$ kubectl create -f pod-file-system-group.yaml
pod/fs-secured created
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
fs-secured 1/1 Running 0 24s
$ kubectl exec -it fs-secured -- /bin/sh
# cd /data/app
# touch logs.txt
# ls -l
-rw-r--r-- 1 root 3500 0 Jul 9 01:41 logs.txt
理解资源的边界
命名空间不强制限制CPU、内存或磁盘空间等计算资源的任何配额,也不限制可以创建的Kubernetes对象的数量。因此,Kubernetes对象可以无限制地消耗资源,直到达到最大可用容量为止。在云环境中,只要您支付账单,资源就会按需供应。我想我们都同意这种方法不能很好地扩展。
请注意
Kubernetes以millicores为单位度量CPU资源,以字节为单位度量内存资源。这就是为什么您可能会看到资源定义为600m或100Mib。要深入了解这些资源单位,有必要交叉参考官方文档中的“Kubernetes中的资源单位”一节。 |
创建一个ResourceQuota
Kubernetes原语ResourceQuota建立每个命名空间可用的最大资源数量。一旦设置,Kubernetes调度器将负责执行这些规则。下面的列表可以让你了解可以定义的规则:
- 为可以为创建特定类型的对象数量设置上限(例如,最多3个pod)。
- 限制计算资源的总和(例如,3gib的RAM)。
- 期待一个Pod的服务质量(QoS)类(例如,尽最大努力表明Pod必须不做任何内存或CPU限制或请求)。
创建ResourceQuota对象通常是Kubernetes管理员的任务,但是定义和创建这样的对象相对容易。首先,创建quota用到的命名空间:
$ kubectl create namespace team-awesome
namespace/team-awesome created
$ kubectl get namespace
NAME STATUS AGE
team-awesome Active 23s
接下来,在YAML中定义ResourceQuota。为了演示ResourceQuota的功能,可以向名称空间添加约束,如例3-10所示:
- 将pod的数量限制为2个。
- 定义一个Pod请求的最小资源为1个CPU和1024m RAM。
- 定义一个Pod使用的最大资源为4个cpu和4096m RAM。
例3-10 用资源配额定义资源限制
apiVersion: v1
kind: ResourceQuota
metadata:
name: awesome-quota
spec:
hard:
pods: 2
现在可以为命名空间创建ResourceQuota了。创建后,该对象提供了一个方便的表概述,用于比较已使用的资源和通过description命令由ResourceQuota spec设置的限制:
$ kubectl create -f awesome-quota.yaml --namespace=team-awesome
resourcequota/awesome-quota created
$ kubectl describe resourcequota awesome-quota --namespace=team-awesome
Name: awesome-quota
Namespace: team-awesome
Resource Used Hard
-------- ---- ----
limits.cpu 0 4
limits.memory 0 4096m
pods 0 2
requests.cpu 0 1
requests.memory 0 1024m
探索ResourceQuota的实施
有了命名空间的配额规则--太棒了,我们希望看到它的实际执行情况。我们将首先创建超过最大数量(即两个)的pod。为了测试这一点,我们可以创建任意定义的pod。例如,我们使用一个在容器中运行镜像nginx:1.18.0的基本定义,如例3-11所示。
示例3-11 一个不需要资源的pod
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
name: nginx
根据这个YAML定义,让我们创建一个Pod,看看会发生什么。事实上,Kubernetes会拒绝创建对象,并输出如下错误消息:
$ kubectl create -f nginx-pod.yaml --namespace=team-awesome
Error from server (Forbidden): error when creating "nginx-pod.yaml": \
pods "nginx" is forbidden: failed quota: awesome-quota: must specify \
limits.cpu,limits.memory,requests.cpu,requests.memory
因为我们为命名空间中的对象定义了最小和最大的资源需求,所以我们必须确保YAML清单实际上定义了它们。通过更新resources下的指令来修改初始定义,如例3-12所示。
例3-12 有资源需求的pod
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
name: nginx
resources:
requests:
cpu: "0.5"
memory: "512m"
limits:
cpu: "1"
memory: "1024m"
我们应该能够用这个清单创建两个唯一命名的pod,因为总的资源需求仍然符合ResourceQuota中定义的边界:
$ kubectl create -f nginx-pod1.yaml --namespace=team-awesome
pod/nginx1 created
$ kubectl create -f nginx-pod2.yaml --namespace=team-awesome
pod/nginx2 created
$ kubectl describe resourcequota awesome-quota --namespace=team-awesome
Name: awesome-quota
Namespace: team-awesome
Resource Used Hard
-------- ---- ----
limits.cpu 2 4
limits.memory 2048m 4096m
pods 2 2
requests.cpu 1 1
requests.memory 1024m 1024m
您可以想象,如果我们尝试创建另一个定义为nginx1和nginx2的Pod,将会发生什么。它失败的原因有两个。首先,我们不允许在名称空间中创建第三个Pod,因为最大数量被设置为两个。而且,我们会超过规定的最大请求限额。cpu和requests.memory。下面的错误信息为我们提供了这样的信息:
$ kubectl create -f nginx-pod3.yaml --namespace=team-awesome
Error from server (Forbidden): error when creating "nginx-pod3.yaml": \
pods "nginx3" is forbidden: exceeded quota: awesome-quota, requested: \
pods=1,requests.cpu=500m,requests.memory=512m, used: pods=2,requests.cpu=1, \
requests.memory=1024m, limited: pods=2,requests.cpu=1,requests.memory=1024m
理解服务帐户
我们一直在使用kubectl可执行文件对Kubernetes集群运行操作。在底层,它的实现通过对公开的端点进行HTTP调用来调用API服务器。在Pod中运行的一些应用程序可能还必须与API服务器通信。例如,应用程序可能要求特定的集群节点信息或可用的命名空间。
pod使用服务帐户通过身份验证令牌与API服务器进行身份验证。Kubernetes管理员通过基于角色的访问控制(RBAC)将规则分配给服务帐户,以授权对特定资源和操作的访问。我们不会深入研究RBAC的概念,因为CKAD课程没有涵盖这个主题。您可以在Kubernetes文档中阅读更多有关它的内容。概述如图3-2所示。
图3-2 使用服务帐户与API服务器通信
到目前为止,我们还没有为Pod定义服务帐户。如果没有明确分配,Pod将使用默认的服务帐户。默认的服务帐户与未经认证的用户具有相同的权限。这意味着Pod不能查看或修改集群状态,也不能列出或修改它的任何资源。
可以使用子命令serviceaccounts查询可用的服务帐户。你应该只会看到列出的默认服务帐户:
$ kubectl get serviceaccounts
NAME SECRETS AGE
default 1 25d
Kubernetes使用Secret原语为身份验证令牌建模。很容易识别服务帐户的相应Secret。检索服务帐户的YAML表示,并查看属性secrets。在Secret中,可以找到当前命名空间、集群证书和身份验证令牌的base64编码值:
$ kubectl get serviceaccount default -o yaml | grep -A 1 secrets:
secrets:
- name: default-token-bf8rh
$ kubectl get secret default-token-bf8rh -o yaml
apiVersion: v1
data:
ca.crt: LS0tLS1CRUdJTiB...0FURS0tLS0tCg==
namespace: ZGVmYXVsdA==
token: ZXlKaGJHY2lPaUp...ThzU0poeFMxR013
kind: Secret
...
您将在spec部分中发现任何活动Pod对象都指示其分配的服务帐户。下面的命令在终端中呈现该值:
apiVersion: v1
kind: Pod
metadata:
...
spec:
serviceAccountName: default
...
创建和分配自定义服务帐户
您很可能想要向在Pod中运行的应用程序授予某些权限。为此,需要创建一个自定义服务帐户,并将相关权限绑定到它。在很大程度上,这是Kubernetes管理员的工作;但是,从应用程序开发人员的角度对这个过程有一个基本的了解是很好的。
要创建一个新的服务帐户,可以简单地使用create命令:
serviceaccount/custom created
现在,有两种方式将服务帐户分配给Pod。你可以编辑YAML清单并像上面所示的那样添加serviceAccountName属性,或者你可以在创建Pod时使用--serviceaccount标志和run命令:
$ kubectl run nginx --image=nginx --restart=Never --serviceaccount=custom
pod/nginx created
$ kubectl get pod nginx -o yaml
apiVersion: v1
kind: Pod
metadata:
...
spec:
serviceAccountName: custom
...
总结
Kubernetes为pod和容器提供高级配置选项。这些选项中的许多都以原语的形式表示,而其他选项只是与前一章的YAML配置混合在一起。本章讨论了配置ConfigMaps, Secrets, Security上下文、资源需求和服务帐户等主题,这些对于致力于操作安全、可维护和大小合适的云本地应用程序的应用程序开发人员来说都是重要的概念。
将配置耦合到容器镜像很容易成为维护的噩梦。与在构建镜像时硬编码环境变量或将配置文件嵌入为指令相比,在启动容器时注入这些信息要容易得多。在Kubernetes中,该功能由原语configmap和Secrets实现。这两个概念都定义了解耦的配置数据,这些数据可以作为环境变量注入到Pods中,也可以作为卷安装。ConfigMaps以明文元组的形式包含键-值对。这个原语非常适合于不敏感的、未加密的配置信息,如连接到其他微服务或用户名的url。Secrets建立在configmap的基础上,用于存储敏感数据,如密码或API密钥。Secrets的清单与ConfigMap的清单非常相似;但是,data部分中的所有值都是用Base64编码的。请记住,Base64编码不是一种加密机制——每个访问该值的人都可以轻松地对其进行解码。因此,不建议将Secrets作为代码检入到版本控制存储库中。
默认情况下,容器以root用户的权限运行。这意味着对文件系统的完全访问和运行任何进程的能力,使恶意攻击者有可能破坏安全性。可以通过为Pod或容器定义安全上下文来抵消这种风险。例如,可以指定容器只能作为非root用户运行。一定要记住,容器级定义优先于pod级安全上下文。
ResourceQuota定义命名空间可用的计算资源(例如CPU、RAM和磁盘空间),以防止运行它的Pods无限制地消耗它。还可以限制允许创建的资源类型的数量。因此,Pods必须通过声明它们的最小和最大资源期望来在这些资源边界内工作。Kubernetes调度程序将在对象创建时检查这些边界。
最后,服务帐户为需要与API服务器通信的Pod定义权限。每个pod都使用一个服务帐户。如果没有定义,Kubernetes将自动分配默认的服务帐户。默认的服务帐户使用未经身份验证的用户的特权。可以创建一个自定义服务帐户,以便进行更细粒度的控制。为Pod分配自定义服务帐户与使用spec.serviceAccountName定义它一样简单。
考试要点
知道如何创建和使用configmap和secret
重要的是要理解这两个原语之间的复杂差异,并实践如何命令式地和声明式地创建这些对象。创建对象的最快方法是使用create configmap和create secret命令。虽然赋值字面键值对很简单,但将文件和目录作为数据源会带来微妙的含义。熟悉Kubernetes在清单中引用信息的方式。作为一种交叉检查,检查配置数据的正确性通过进入容器shell:作为环境变量注入和作为容量安装。请记住,在从YAML清单创建secret时,只需要提供base64编码的值。命令式创建流程自动执行转换。
尝试使用可用于安全上下文的选项
Kubernetes的用户文档和API文档是探索安全上下文选项的一个很好的起点。您将发现posecuritycontext和SecurityContext的可用选项有重叠。如果在Pod级别上定义,这些选项可以通过在容器级别上指定不同的值来覆盖。在处理由安全上下文选项解决的不同用例时,通过运行允许或不允许的操作来验证它们的结果。
理解资源的边界
ResourceQuota为存在于命名空间中的对象定义资源边界。最常用的边界适用于计算资源。练习定义它们并理解它们对Pods创建的影响。了解列出ResourceQuota的硬需求和当前使用的资源的命令是很重要的。你会发现ResourceQuota提供了其他选项。更详细地发现它们,以便更广泛地接触该主题。
了解如何创建和分配自定义服务帐户
应用程序开发人员不必每天创建定制服务帐户——这是Kubernetes管理员的工作。尽管如此,理解服务帐户的背景以及这个概念如何与RBAC联系在一起还是很有帮助的。对于考试,请练习创建服务帐户,并了解如何将其分配给Pod。您不需要理解RBAC方面,因为它超出了考试的范围。
Sample ExercisesSolutions to these exercises are available in the Appendix.
- Create a directory with the name config. Within the directory, create two files. The first file should be named db.txt and contain the key-value pair password=mypwd. The second file is named ext-service.txt and should define the key-value pair api_key=LmLHbYhsgWZwNifiqaRorH8T.
- Create a Secret named ext-service-secret that uses the directory as data source and inspect the YAML representation of the object.
- Create a Pod named consumer with the image nginx and mount the Secret as a Volume with the mount path /var/app. Open an interactive shell and inspect the values of the Secret.
- Use the declarative approach to create a ConfigMap named ext-service-configmap. Feed in the key-value pairs api_endpoint=https://myapp.com/api and username=bot as literals.
- Inject the ConfigMap values into the existing Pod as environment variables. Ensure that the keys conform to typical naming conventions of environment variables.
-
Open an interactive shell and inspect the values of the ConfigMap.
-
Define a security context on the container level of a new Pod named security-context-demo that uses the image alpine. The security context adds the Linux capability CAP_SYS_TIME to the container. Explain if the value of this security context can be redefined in a Pod-level security context.
-
Define a ResourceQuota for the namespace project-firebird. The rules should constrain the count of Secret objects within the namespace to 1.
-
Create as many Secret objects within the namespace until the maximum number enforced by the ResourceQuota has been reached.
-
Create a new Service Account named monitoring and assign it to a new Pod with an image of your choosing. Open an interactive shell and locate the authentication token of the assigned Service Account.