前言
大家好,我是秋意零。
在上一篇中,我们介绍了 Pod 的生命周期以及区分 Pod 字段的层次级别,相信你对此有了充分的认识。
今天,我们还会接着以 Pod 展开,说说它的 “服务对象”,一听就知道是对 Pod 提供服务的对象,接下来就一起来看看, “服务对象” 是否有趣吧!!
哦!对了最近搞了一个扣扣群,旨在技术交流、博客互助,希望各位大佬多多支持!在我主页推广区域,如图:
文章底部推广区域,如图:
👿 简介
- 🏠 个人主页: 秋意零
- 🧑 个人介绍:在校期间参与众多云计算相关比赛,如:🌟 “省赛”、“国赛”,并斩获多项奖项荣誉证书
- 🎉 目前状况:24 届毕业生,拿到一家私有云(IAAS)公司 offer,暑假开始实习
- 🔥 账号:各个平台, 秋意零 账号创作者、 云社区 创建者
- 💕欢迎大家:欢迎大家一起学习云计算,走向年薪 30 万
系列文章目录
【探索Kubernetes|容器基础进阶篇 系列1】容器的本质是进程
【探索 Kubernetes|容器基础进阶篇 系列 2】容器资源限制利器
【探索 Kubernetes|容器基础进阶篇 系列 3】容器进程的文件系统
【探索 Kubernetes|容器基础进阶篇 系列 4】理解现代云原生时代的引擎
【探索 Kubernetes|集群搭建篇 系列 5】简化 Kubernetes 的部署,深入解析其工作流程
更多点击专栏查看:深入探索 Kubernetes
文章目录
- 前言
- 系列文章目录
- 一、Pod 服务对象
- 二、Secret
- 小结
- 三、ConfigMap
- 四、Downward API
- 可用字段
- 小结
- 五、ServiceAccountToken
- 总结
正文开始:
- 快速上船,马上开始掌舵了(Kubernetes),距离开船还有 3s,2s,1s…
一、Pod 服务对象
早在 【探索 Kubernetes|容器基础进阶篇 系列 4】理解现代云原生时代的引擎 (七、Kubernetes 全景图) 这篇中,就简单介绍过 “服务对象” ;而下图中,所说的 “编排对象” 将在后面详细展开。如下图所示:
首先,需要声明的是,目前介绍的 “服务对象”,仅仅是通过 Pod 的 Volume 字段来展开说明的。为什么呢?
- 像 Secret、ConfigMap、Downward API、ServiceAccountToken 这四种 Projected Volume 是今天主角,也就是通过 Volume 字段挂载(投射)进 Pod 从而进行服务的。这种 Volume,存在的意义不是为了存放容器里的数据,也不是用来进行容器和宿主机之间的数据交换。这些特殊 Volume 的作用,是为容器提供预先定义好的数据。所以,从容器的角度来看,这些 Volume 里的信息就是仿佛是被 Kubernetes“投射”(Project)进入容器当中的。这正是 Projected Volume 的含义。
- 而像 Service、Horizontal Pod Autoscaler 就是通过其它指标字段对 Pod 进行服务的。
二、Secret
Sercret 是将 Pod 要访问的加密数据,存在在 Etcd 数据库中。之后,Pod 通过挂载 Volume 卷的方式,访问到这些 Secret 里存放的信息。
Secret 使用方法:
想象一个这样的场景,使用 Kubernetes 部署一个 Mysql 服务,Mysql 容器初始化时需要指定 root 密码,因为我们一般使用 YAML 方式部署,这样方便管理容器服务对象。这时我们需要在 YAML 文件中通过环境变量的方式,初始化 Mysql 用户和密码,但是这样就容易暴露这样的明文用户和密码信息。这时就需要使用 Secret 映射给这个 Mysql 使用对应的认证信息。
1.首先需要给明文用户和密码加密
因为我们 Secret 也是 YAML 方式部署,不过在企业中,这种信息一般是管理人员为运维人员创建。运维人员使用这样一个 Secret 即可。
这里使用 base64 方式转码,并不安全,因为 base64 仅仅是经过了转码,而并没有被加密。在真正的生产环境中,你需要在 Kubernetes 中开启 Secret 的加密插件,增强数据的安全性。
# 加密方式
[root@master01 ~]# echo -n "root" | base64
cm9vdA==
[root@master01 ~]# echo -n "000000" | base64
MDAwMDAw
# 解密方式
[root@master01 ~]# echo -n "cm9vdA==" | base64 -d
admin
[root@master01 ~]# echo -n "MDAwMDAw" | base64 -d
000000
2.创建 Secret
将加密过后的用户和密码信息,填写到 Secret 中。data 字段下,以 Key-Value 的格式保存了两份 Secret 数据。其中,“user” 就是第一份数据的 Key,“pass” 是第二份数据的 Key。
user 是用户 key 而 cm9vdA== 是用户 value(用户名)
pass 是用户 key 而 MDAwMDAw 是用户 value(用户密码)
[root@master01 yaml]# cat > secret-my.yaml << EOF
apiVersion: v1
kind: Secret
metadata:
name: mysecret
type: Opaque # 默认类型
data:
user: cm9vdA==
pass: MDAwMDAw
EOF
# 部署 Secret
[root@master01 yaml]# kubectl apply -f secret-my.yaml
secret/mysecret created
# 记住 Secret 的名称(这里叫:mysecret),待会会使用。
[root@master01 yaml]# kubectl get secret
NAME TYPE DATA AGE
mysecret Opaque 2 9s
3.创建 Pod(Mysql)
可以使用 kubectl create secret generic
命令创建或者 YAML
文件创建。
- 3.1.将 Secret 导入到环境变量中
apiVersion: v1
kind: Pod
metadata:
name: mysql-pod
spec:
containers:
- name: mysql-container
image: mysql:5.7
imagePullPolicy: IfNotPresent
ports:
- containerPort: 3306
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mysecret
key: pass
进入容器验证,环境变量是否和 Secret 中保存的值一致。
[root@master01 yaml]# kubectl exec -it mysql-pod -- /bin/bash
root@mysql-pod:/# env |grep MYSQL_ROOT_PASSWORD
MYSQL_ROOT_PASSWORD=000000
- 3.2.将 Secret 挂载到 projected Voluem 中
apiVersion: v1
kind: Pod
metadata:
name: busybox-pod
spec:
containers:
- name: busybox-container
image: busybox
imagePullPolicy: IfNotPresent
args:
- sleep
- "3600"
volumeMounts:
- name: busybox-secrets
mountPath: /var/secrets/busybox
readOnly: true
volumes:
- name: busybox-secrets
projected:
sources:
- secret:
name: mysecret
进入容器验证,挂载的目录的值是否和 Secret 中保存的值一致。
- 注意:使用 Voluem 挂载方式时,是将 Secret 中的 key 作为目录名称,value 作为目录中的值 。
[root@master01 yaml]# kubectl exec -it busybox-pod -- /bin/sh
# 查看使用 Secret 挂载进容器中的目录
/ # ls /var/secrets/busybox
pass user
# 查看值
/ # cat /var/secrets/busybox/user
admin
/ # cat /var/secrets/busybox/pass
000000/ #
小结
通过挂载方式进入到容器里的 Secret,一旦其对应的 Etcd 里的数据被更新,这些 Volume 里的文件内容,同样也会被更新。其实,这是 kubelet 组件在定时维护这些 Volume。
不过,这个更新会有一定延时。所以在编写应用程序时,在发起数据库连接的代码处写好重试和超时的逻辑,绝对是个好习惯。
三、ConfigMap
ConfigMap 与 Secret 类似,区别就是 ConfigMap 保存的是不需要加密的、应用所需的配置文件信息。
ConfigMap 的用法几乎与 Secret 完全相同,可以使用 kubectl create configmap
从文件或者目录创建 ConfigMap,也可以直接编写 ConfigMap 对象的 YAML 文件。
[root@master01 yaml]# cat test-db.text
database.host=localhost
database.port=3306
database.username=admin
database.password=secret
# 从 test-db.text 文件中,创建 configmap。
[root@master01 yaml]# kubectl create configmap my-config --from-file=test-db.text
configmap/my-config created
查看 configmap 中 data 数据信息,可以看到是和 test-db.text 配置文件中一致的,后期也是可以通过环境变量和 Voluem 卷的方式使用(同上述 Secret)。
[root@master01 yaml]# kubectl get configmap my-config -o yaml
例:
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
containers:
- name: my-container
image: my-image
env:
- name: DATABASE_HOST
valueFrom:
configMapKeyRef:
name: my-config
key: database.host
- name: DATABASE_PORT
valueFrom:
configMapKeyRef:
name: my-config
key: database.port
- name: DATABASE_USERNAME
valueFrom:
configMapKeyRef:
name: my-config
key: database.username
- name: DATABASE_PASSWORD
valueFrom:
configMapKeyRef:
name: my-config
key: database.password
四、Downward API
Downward API 是一种特性,它允许容器在运行时获取关于自身和它所在 Pod 的一些元数据信息。这些信息可以作为环境变量或卷挂载提供给容器使用。
如果按照 Downward(下载)这个单词意思理解就是: 将 Pod 或容器自身的元数据信息下载到是运行状态的容器中使用。
Downward API 提供了以下作用:
总的来说,Downward API 提供了一种在容器运行时获取 Pod 和容器自身元数据的机制,使容器能够动态获取并使用这些信息。这对于编写灵活且适应性强的应用程序非常有用,并能够在 Kubernetes 环境中提供更多的自动化和配置选项。
可用字段
只有部分 Kubernetes API 字段可以通过 Downward API 使用。
- fieldRef:传递 Pod 级字段的信息
- resourceFieldRef:传递 Container 级字段的信息
1.可通过 fieldRef
获得的信息
metadata.name
:Pod 的名称metadata.namespace
:Pod 的命名空间metadata.uid
:Pod 的唯一 ID- …
2.可通过 resourceFieldRef
获得的信息
limits.cpu
:容器的 CPU 限制值requests.cpu
:容器的 CPU 请求值requests.memory
:容器的内存请求值limits.memory
:容器的内存限制值- …
Kubernetes 官网:更多可用字段信息
举个例子:
我们定义了一个 Pod 名为 projected-buxybox,并创建了一个名为 app 的容器。我们使用了一个 Projected Volume,并将其挂载到了 /etc/config 目录下。 并使用 fieldRef 来获取 Pod 的元数据信息,使用 resourceFieldRef 来获取容器的元数据信息。
items.path
:定义元数据信息的目录是什么。fieldRef.fieldPath
:定义 Pod 元数据信息的值是什么。resourceFieldRef.resource
:定义 容器 元数据信息的值是什么。
apiVersion: v1
kind: Pod
metadata:
name: projected-buxybox
spec:
containers:
- name: app
image: busybox
imagePullPolicy: IfNotPresent
args:
- sleep
- "3600"
resources:
limits:
cpu: "2"
requests:
cpu: "1"
volumeMounts:
- name: config-volume
mountPath: /etc/config
volumes:
- name: config-volume
projected:
sources:
- downwardAPI:
items:
- path: "pod_name"
fieldRef:
fieldPath: metadata.name
- path: "pod_namespace"
fieldRef:
fieldPath: metadata.namespace
- path: "cpu_limits"
resourceFieldRef:
containerName: app
resource: limits.cpu
- path: "cpu_request"
resourceFieldRef:
containerName: app
resource: requests.cpu
验证:部署 Pod ,并查看 /etc/config 目录下,获取的值是否正确。
[root@master01 yaml]# kubectl apply -f projected-buxybox-pod.yaml
[root@master01 yaml]# kubectl get -f projected-buxybox-pod.yaml
NAME READY STATUS RESTARTS AGE
projected-buxybox 1/1 Running 0 3m11s
[root@master01 yaml]# kubectl exec -it projected-buxybox -- /bin/sh
/ # ls /etc/config/
cpu_limits cpu_request pod_name pod_namespace
/ # cat /etc/config/cpu_limits
2
/ # cat /etc/config/cpu_request
1
/ # cat /etc/config/pod_name
projected-buxybox
/ # cat /etc/config/pod_namespace
default
小结
注意:Downward API 能够获取到的信息,一定是 Pod 里的容器进程启动之前就能够确定下来的信息。而如果你想要获取 Pod 容器运行后才会出现的信息,比如,容器进程的 PID,那就肯定不能使用 Downward API 了,而应该考虑在 Pod 里定义一个 sidecar 容器。
Secret、ConfigMap,以及 Downward API 这三种 Projected Volume 定义的信息,大多还可以通过环境变量的方式出现在容器里。但是,通过环境变量获取这些信息的方式,不具备自动更新的能力。所以,一般情况下,我都建议你使用 Volume 文件的方式获取这些信息。
五、ServiceAccountToken
如果我有一个 Pod,而且在 Pod 中安装 Kubernetes 的 Clinet,想实现可以从容器里直接访问并且操作这个 Kubernetes 的 API ?这种方式是可行的,不过,你首先要解决 API Server 的授权问题,这就需要 ServiceAccount 服务对象了。
1.Service Account 是什么?
- Service Account(服务账号)是 Kubernetes 中用于身份验证和授权的实体,进行权限分配的对象。它是为 Pod 提供访问 Kubernetes API 的身份凭据。每个 Service Account 都有一个唯一的名称和对应的身份令牌(Token)。
- Service Account 可以与 Pod 关联,使 Pod 具有与 Kubernetes API 进行交互的权限。它允许 Pod 在运行时进行身份验证,并根据其配置的权限来执行操作,例如创建、更新或删除资源。
比如,Service Account A,可以只被允许对 Kubernetes API 进行 GET 操作,而 Service Account B,则可以有 Kubernetes API 的所有操作权限。
2.ServiceAccountToken 是什么?
像上述这样的权限分配操作,实际上是通过一种它所绑定的一个 ServiceAccountToken。任何运行在 Kubernetes 集群上的应用,都必须使用这个 ServiceAccountToken 里保存的授权信息,也就是 Token,才能访问 kube-apiserver。
另外,为了方便使用,Kubernetes 已经为你提供了一个默认“服务账户”(default Service Account)。如图:
并且,任何一个运行在 Kubernetes 里的 Pod,都可以直接使用这个默认的 Service Account,而无需显示地声明挂载它,因为是默认自动挂载(可以设置不挂载,默认挂载)靠 Projected Volume 机制实现。
你可以查看任意一个运行中的 Pod,你会发现一个 类型为 Projected 并且包含来自多个源的注入数据的卷(Service Account 的身份令牌),然后自动挂载在每个容器的一个固定目录上 /var/run/secrets/kubernetes.io/serviceaccount
,容器可以通过该路径访问令牌,并将其用于与 Kubernetes API 的安全通信。
这里提供了两种查看方式,如下图:
kubectl describe pod mysql-pod
下图我们可以看到,这个 Projected 包含来自多个源的注入数据的卷,使用了 ServiceAccountToken、ConfigMap、DownwardAPI。
kubectl get pod -o yaml mysql-pod
所以 Pod 中的容器应用,就可以直接使用这个目录下的授权信息和文件与 kube-apiserver 访问, Projected 目录下的内容,如图所示:
这种把 Kubernetes 客户端以容器的方式运行在集群里,然后使用 default Service Account 自动授权的方式,被称作 “InClusterConfig”(内部集群配置),也是我最推荐的进行 Kubernetes API 编程的授权方式。
除了默认的 ServiceAccount 还可以自定义 ServiceAccount 来对应不同的权限设置。这样 Pod 在使用这个 Service Account 对应的 ServiceAccountToken 时权限就更加灵活。
总结
今天,介绍了 Pod 的 Volume 的 Projected 服务对象。
你还应该认真体会一下 Kubernetes “一切皆对象” 的设计思想:比如,应用是 Pod 对象,应用的配置是 ConfigMap 对象,应用要访问的密码则是 Secret 对象。
最后:技术交流、博客互助,点击下方或主页推广加入哦!!