Pod
概述
Pod 是一组并置的容器,代表了 Kubernetes 中的基本构建模块。在实际应用中,我们不会直接使用 Pod 这种类型的模块,而是使用更高级的 ReplicationController、ReplicaSet、Deployment 这些资源。但是为了更好地理解 Kubernetes 的运行机制,我们还是要了解一下 Pod 的运行机制。
以下是 Pod 的一些关键知识点:
- Pod 用于将多个密切相关的进程(容器)绑定在一起,并作为一个单元进行管理(如将 Sidecar 与微服务绑定在一起)。Pod 可以包含多个容器,也可以只包含一个容器。
- 当一个 Pod 包含多个容器时,这些容器总是运行于同一个工作节点(Node)上。
- 每个 Pod 都有独立的 IP 地址(内部地址),Pod 与 Pod 之间都能像在无 NAT 的平坦网络中一样相互通信,就像局域网(LAN)上的计算机一样。
- 扩容时,Pod 将作为最小的基础单元。
原理
Kubernetes 通过配置容器来让一个 Pod 内的所有容器共享相同的 Linux 命名空间(Network、UTS),从而让容器共享一些资源。因此每个进程注意不能绑定相同的端口号,否则会导致端口冲突。
准备工作
为了学习接下来的东西,需要先创建一个容器镜像。我们在本地机器(或另一台服务器上面),完成一个镜像的创建工作。镜像内容如下:
kubia
├── app.js
└── Dockerfile
- app.js
const http = require('http');
const os = require('os');
console.log("Kubernetes server starting...");
var handler = function(request, response) {
console.log("Received request from " + request.connection.remoteAddress);
response.writeHead(200);
response.end("You've hit " + os.hostname() + "\n");
}
var www = http.createServer(handler);
www.listen(8080);
- Dockerfile
FROM node:18
ADD app.js /app.js
ENTRYPOINT ["node", "app.js"]
然后使用以下命令构建镜像并推送到 Registry。
# 在 kubia 目录下,构建容器镜像
$ docker build -t deploy.cluster.k8s/kubia:1.0.0 .
# 推送到 Registry 供 Kubernetes 集群使用
$ docker push deploy.cluster.k8s/kubia:1.0.0
基础声明
创建 kubia-manual.yaml 文件,用于 Pod 的声明,内容如下:
apiVersion: v1
kind: Pod
metadata:
name: kubia-manual # Pod 的名称
labels: # 为 Pod 添加两个标签
creation_method: manual
env: prod
spec:
containers: # 容器所用的镜像
- image: cluster.k8s/kubia
name: kubia
ports:
- containerPort: 8080
protocol: TCP
命令
创建 Pod
# 从 yaml 文件创建 Pod
$ kubectl create -f kubia-manual.yaml
# 得到运行中的 Pod 的完整 yaml 格式的定义
$ kubectl get po kubia-manual -o yaml
# 得到运行中的 Pod 的完整 json 格式的定义
$ kubectl get po kubia-manual -o json
查看 Pod
# 查看 Pod 列表
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
kubia-manual 1/1 Running 0 26s
# 查看 Pod 列表(显示其标签)
$ kubectl get po --show-labels
NAME READY STATUS RESTARTS AGE LABELS
kubia-manual 1/1 Running 0 2s creation_method=manual,env=prod
# 根据标签筛选 Pod
$ kubectl get po -l creation_method=manual
NAME READY STATUS RESTARTS AGE
kubia-manual 1/1 Running 0 101s
# 查看应用程序日志
$ kubectl logs kubia-manual
# 如果 Pod 中包含多个容器,则必须要指定容器
$ kubectl logs kubia-manual -c kubia
访问 Pod
由于创建 Pod 时,Kubernetes 可能会随机挑选一个合适的节点去创建 Pod 实例,因此我们没有办法直接到找到该容器所在的节点并访问它。如果要访问 Pod,可以用创建 service,以方便在外部访问该 Pod。由于后面有一章节专门介绍 service,因此这里不打算使用 service,而是使用 Kubernetes 提供的端口转发功能。
# 将本地的 8888 端口的请求转发到名为 kubia-manual 的 Pod 的 8080 端口
# 注意,本命令在启动后会一直阻塞到使用 ctrl + c 中断
$ kubectl port-forward kubia-manual 8888:8080
Forwarding from 127.0.0.1:8888 -> 8080
另起一个终端窗口,通过 curl 访问 Pod。
$ curl localhost:8888
You've hit kubia-manual
下图可以用于表示上面的端口转发的过程:
将 Pod 调度到特定节点
Kubernetes 对运行在其上的应用程序隐藏实时的基础加构,因此我们不应该特别告诉 Kubernetes 必须将 Pod 调度到哪个节点上,而是告诉 Kubernetes 该 Pod 需要什么资源/特性,再由 Kuberntes 自行决定部署到哪个节点上。
这种情况下,一般使用标签(Label)及选择器(Selector)来完成该功能。
apiVersion: v1
kind: Pod
metadata:
name: kubia-manual # Pod 的名称
spec:
nodeSelector: # 节点选择器要求 Kubernetes 只将 Pod 部署到包含标签 gpu=true 的节点上
gpu: "true"
containers: # 容器所用的镜像
- image: cluster.k8s/kubia
name: kubia
ports:
- containerPort: 8080
protocol: TCP
命名空间
通过命名空间,可以将 Pod 对象分割成完全独立且不重叠的组。命名空间是一种和其他资源一样的 Kubernetes 资源,因此可以通过将 YAML 文件提交到 Kubernetes API 服务器来创建资源。
- custom-namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
name: custom-namespace
然后就可以通过 kubectl create -f custom-namespace.yaml
命令提交文件到 Kubernetes API 服务器。也可以使用 kubectl create namespace custom-namespace
命令快速创建命名空间。
如果想在指定的命名空间中创建资源,可以选择在 metadata 字段中添加一个 namespace: custom-namespace 属性,也可以在使用 kubectl create 命令创建资源时指定命名空间:
$ kubectl create -f kubia-manual.yaml -n custom-namespace
在查询、操作资源时,如果不指定命名空间,kubectl 将在当前上下文中配置的默认命名空间中执行操作。可以通过以下命令切换当前默认的命名空间
$ kubectl config set-context $(kubectl config current-context) --namespace custom-namespace
提示,如果嫌弃上面的命令太长了,可以通过设置别名
alias kdc='kubectl config set-context $(kubectl config current-context) --namespace
。然后就可以使用kcd custom-namespace
在命令行里切换命名空间了。
在指定的 Pod 下面执行命令
$ kubectl exec kubia-7nog1 -- curl -s http://10.111.249.153
停止和删除 Pod
# 根据名称删除 Pod
$ kubectl delete po kubia-manual
# 根据标签选择器删除 Pod
$ kubectl elete po -l creation_method=manual
# 通过删除整个命名空间来删除 Pod
$ kubectl delete ns custom-namespace
# 删除命名空间中所有的 Pod,但保留命名空间
$ kubectl kubect delete po -all