共计 4118 个字符,预计需要花费 11 分钟才能阅读完成。
本系列的前五篇文章:
本实战练习系列的前五文章:
- 适宜 Kubernetes 初学者的一些实战练习 (一)
- 适宜 Kubernetes 初学者的一些实战练习 (二)
- 适宜 Kubernetes 初学者的一些实战练习 (三)
- 适宜 Kubernetes 初学者的一些实战练习 (四)
- 适宜 Kubernetes 初学者的一些实战练习 (五)
本文持续咱们的 Kubernetes 实战练习之旅。
练习 1:Kubernetes 里 secret 的应用办法介绍
Kubernetes Secret 解决了明码、token、密钥等敏感数据的配置问题,应用 Secret 能够防止把这些敏感数据以明文的模式裸露到镜像或者 Pod Spec 中。
Secret 能够以 Volume 或者环境变量的形式应用。
应用如下命令行创立一个 secret:
kubectl create secret generic admin-access –from-file=./username.txt –from-file=./password.txt
输出文件 username.txt 和 password.txt 须要手动创立,外面别离保护用于测试的用户名和明码。
创立胜利后,发现 secret 的类型为 Opaque
:
实际上,Kubernetes 的 secret 有三种类型:
- Service Account:用来拜访 Kubernetes API,由 Kubernetes 主动创立,并且会主动挂载到 Pod 的 /run/secrets/kubernetes.io/serviceaccount 目录中;
- Opaque:base64 编码格局的 Secret,用来存储明码、密钥等;
- kubernetes.io/dockerconfigjson:用来存储公有 docker registry 的认证信息。
而咱们刚刚创立的 secret 的类型为 Opaque,因而在 kubectl get secrets 的返回后果里,能看到 password 和 username 的值均为 base64 编码:
要在 pod 里生产这个 secret 也很容易,看一个例子:
apiVersion: v1
kind: Pod
metadata:
name: secret-pod
spec:
restartPolicy: Never
volumes:
- name: credentials
secret:
secretName: admin-access
defaultMode: 0440
containers:
- name: secret-container
image: alpine:3.8
command: ["/bin/sh", "-c", "cat /etc/foo/username.txt /etc/foo/password.txt"]
volumeMounts:
- name: credentials
mountPath: "/etc/foo"
readOnly: true
创立 pod,主动执行,通过 log 命令查看 pod 的日志:
发现 /bin/sh 命令被执行了,pod mount 的目录 /etc/foo 下的 username.txt 和 password.txt 通过 cat 命令显示了输入:
练习 2:Kubernetes pod 里一个非凡容器 pause-amd64 的深刻分析
大家在应用 Docker 容器或者 Kubernetes 时, 想必都注意过这个容器:
gcr.io/google_containers/pause-amd64
docker ps
的命令返回的后果:
[root@k8s-minion1 kubernetes]# docker ps |grep pause
c3026adee957 gcr.io/google_containers/pause-amd64:3.0 "/pause" 22 minutes ago Up 22 minutes k8s_POD.d8dbe16c_redis-master-343230949-04glm_default_ce3f60a9-095d-11e7-914b-0a77ecd65f3e_66c108d5
202df18d636e gcr.io/google_containers/pause-amd64:3.0 "/pause" 24 hours ago Up 24 hours k8s_POD.d8dbe16c_kube-proxy-js0z0_kube-system_2866cfc2-0891-11e7-914b-0a77ecd65f3e_c8e1a667
072d3414d33a gcr.io/google_containers/pause-amd64:3.0 "/pause" 24 hours ago Up 24 hours k8s_POD.d8dbe16c_kube-flannel-ds-tsps5_default_2866e3fb-0891-11e7-914b-0a77ecd65f3e_be4b719e
[root@k8s-minion1 kubernetes]#
Kubernetes 的官网解释:
it’s part of the infrastructure. This container is started first in all Pods to setup the network for the Pod.
粗心是:pause-amd64 是 Kubernetes 基础设施的一部分,Kubernetes 治理的所有 pod 里,pause-amd64 容器是第一个启动的,用于实现 Kubernetes 集群里 pod 之间的网络通讯。
对这个非凡容器的技术实现感兴趣的敌人,能够浏览其源代码。
咱们查看这个 pause-amd64 镜像的 dockerfile,发现实现很简略,基于一个空白镜像开始:
FROM scratch
ARG ARCH
ADD bin/pause-${ARCH} /pause
ENTRYPOINT ["/pause"]
ARG 指令用于指定在执行 docker build
命令时传递进去的参数。
这个 pause container
是用 C 语言写的:
在运行的 Kubernetes node 上运行 docker ps
,能发现这些 pause container:
pause container 作为 pod 里其余所有 container 的 parent container,次要有两个职责:
- 是 pod 里其余容器共享 Linux namespace 的根底
- 表演 PID 1 的角色,负责解决僵尸过程
在 Linux 里,当父过程 fork 一个新过程时,子过程会从父过程继承 namespace.
目前 Linux 实现了六种类型的 namespace,每一个 namespace 是包装了一些全局系统资源的形象汇合,这一形象汇合使得在过程的命名空间中能够看到全局系统资源。命名空间的一个总体目标是反对轻量级虚拟化工具 container 的实现,container 机制自身对外提供一组过程,这组过程本人会认为它们就是零碎惟一存在的过程。
在 Linux 里,父过程 fork 的子过程会继承父过程的命名空间。与这种行为相同的一个系统命令就是 unshare:
再来聊聊 pause 容器如何解决僵尸过程的。
Pause 容器内其实就运行了一个非常简单的过程,其逻辑能够从后面提到的 Pause github 仓库上找到:
static void sigdown(int signo) {psignal(signo, "Shutting down, got signal");
exit(0);
}
static void sigreap(int signo) {while (waitpid(-1, NULL, WNOHANG) > 0);
}
int main() {if (getpid() != 1)
/* Not an error because pause sees use outside of infra containers. */
fprintf(stderr, "Warning: pause should be the first process\n");
if (sigaction(SIGINT, &(struct sigaction){.sa_handler = sigdown}, NULL) < 0)
return 1;
if (sigaction(SIGTERM, &(struct sigaction){.sa_handler = sigdown}, NULL) < 0)
return 2;
if (sigaction(SIGCHLD, &(struct sigaction){.sa_handler = sigreap,
.sa_flags = SA_NOCLDSTOP},
NULL) < 0)
return 3;
for (;;)
pause();
fprintf(stderr, "Error: infinite loop terminated\n");
return 42;
}
这个 c 语言实现的过程,外围代码就 28 行:
其中第 24 行里一个有限循环 for(;;)
, 至此大家能看进去 pause 容器名称的由来了吧?
这个有限循环里执行的是一个零碎调用 pause
:
因而 pause 容器大部分工夫都在沉睡,期待有信号将其唤醒。
接管什么信号呢?
一旦收到 SIGCHLD 信号,pause 过程就执行注册的 sigreap 函数。
看下 SIGCHLD 信号的帮忙:
SIGCHLD,在一个过程失常终止或者进行时,将 SIGCHLD 信号发送给其父过程,按零碎默认将疏忽此信号,如果父过程心愿被告知其子系统的这种状态,则应捕获此信号。
pause 过程注册的信号处理函数 sigreap 里,调用另一个零碎调用 waitpid 来取得子过程终止的起因。
总结
本文作为这一系列的第六局部,首先介绍了如何在理论 Kubernetes 我的项目中应用 Secret 来治理 credentials 和 access token 等敏感信息,以此来防止将其以明文的模式裸露到镜像或者 Pod Spec 中的平安问题。接下来通过源代码剖析的模式,分析了作为 Kubernetes 基础设施之一的 pause-amd64 容器的设计和实现原理。
本教程前五个局部的文章链接:
- 适宜 Kubernetes 初学者的一些实战练习 (一)
- 适宜 Kubernetes 初学者的一些实战练习 (二)
- 适宜 Kubernetes 初学者的一些实战练习 (三)
- 适宜 Kubernetes 初学者的一些实战练习 (四)
- 适宜 Kubernetes 初学者的一些实战练习 (五)