1. kubernetes 整体架构
kubernetes 由 master 节点和工作节点组成。其中,master 节点的组件有 APIServer,scheduler 和 controller-manager。APIServer 是系统管理指令的统一入口,scheduler 负责调度 Pod 到合适的工作节点上,controller-manager 是一组资源控制器,负责控制管理对应的资源,如 replication 等。工作节点的组件有 kubelet 和 kube-proxy。kubelet 负责创建,管理,维护 pod,kube-proxy 负责将访问 service 的流量转发到对应的 endpoint 上。
kubernetes 的整体架构图如下所示:
了解了整体架构图,那么各个组件是如何协同工作的呢。这里以创建 pod 为例查看各组件的协作流程,流程图如下:
主要有如下几步:
- 用户调用 REST API 请求创建 pod,APIServer 响应 API 请求,并进行一系列验证操作,包括认证,授权和资源配置等,验证通过后,APIServer 调用 etcd 在后台数据库建立 Pod 资源对象。
- scheduler 定期调用 APIServer 的 kubernetes API 接口查看系统中可用的工作节点列表和待调度 Pod,使用调度策略为待调度 Pod 选择合适的工作节点,这个过程称为绑定(bind)。
- 绑定成功后,scheduler 调用 APIServer 在 etcd 中创建 binding 对象,该对象描述了工作节点上绑定运行的所有 pod 信息。
1.1 APIServer 概述
APIServer 作为统一接口,负责管理各组件的通信,是 kubernetes 集群的核心。对资源的增删改查操作都将通过 APIServer 传递到后台 etcd 数据库,使用 curl 工具可以很容易的获取到 APIServer 的 API 响应信息。
1.1.1 Kubernetes APIServer 组件
查看环境上运行的 APIServer:
[root@chunqiu ~ (Master)]# kubectl get pods -o wide -n kube-system | grep api
kube-apiserver-chunqiu-0 1/1 Running 1 70d 172.17.66.2 chunqiu-0 <none> <none>
kube-apiserver-chunqiu-1 1/1 Running 1 70d 172.17.66.3 chunqiu-1 <none> <none>
kube-apiserver-chunqiu-2 1/1 Running 1 70d 172.17.66.4 chunqiu-2 <none> <none>
[root@chunqiu ~ (Master)]# kubectl get service -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
kubernetes ClusterIP 10.254.0.1 <none> 443/TCP 70d <none>
[root@chunqiu ~ (Master)]# kubectl describe service kubernetes
Name: kubernetes
Namespace: default
Labels: component=apiserver
provider=kubernetes
Annotations: <none>
Selector: <none>
Type: ClusterIP
IP: 10.254.0.1
Port: https 443/TCP
TargetPort: 8443/TCP
Endpoints: 172.17.66.2:8443,172.17.66.3:8443,172.17.66.4:8443
Session Affinity: None
Events: <none>
当前环境为 master 和工作节点共用模式,可以看到每台节点上都以 pod 形式运行了 APIServer,并且它们与 kubernetes service 进行了绑定。
集群内的 APIServer 部署知道了,那 APIServer 的配置文件又是怎样的呢?查看组件的配置文件能更好的理解组件的整体结构:
[root@chunqiu ~ (Master)]# kubectl describe pods kube-apiserver-chunqiu-0 -n kube-system
Priority: 2000001000
Priority Class Name: system-node-critical
Status: Running
IP: 172.17.66.2
Containers:
kube-apiserver:
Image: bcmt-registry:5000/k8s.gcr.io/kube-apiserver-amd64:v1.19.5
Port: 8443/TCP
Host Port: 8443/TCP
Command:
/usr/local/bin/kube-apiserver
--default-not-ready-toleration-seconds=180
--default-unreachable-toleration-seconds=180
--bind-address=172.17.66.2
--etcd-servers=https://172.17.66.2:2379
--etcd-cafile=/etc/etcd/ssl/ca.pem
--etcd-certfile=/etc/etcd/ssl/etcd-client.pem
--etcd-keyfile=/etc/etcd/ssl/etcd-client-key.pem
--allow-privileged=true
--service-cluster-ip-range=10.254.0.0/16
--secure-port=8443
--insecure-port=0
--anonymous-auth=false
--authorization-mode=Node,RBAC
--enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount...
--kubelet-certificate-authority=/etc/kubernetes/ssl/ca.pem
--kubelet-client-certificate=/etc/kubernetes/ssl/cluster-admin.pem
--kubelet-client-key=/etc/kubernetes/ssl/cluster-admin-key.pem
...
省略了部分参数,主要配置参数及命令如下:
参数 | 描述 |
---|---|
/usr/local/bin/kube-apiserver | image 中包含的启动 apiserver 命令 |
bind-address | apiserver 安全端口绑定的 ip 地址,用于接受安全连接 |
etcd-servers,etcd-cafile,etcd-certfile,etcd-keyfile | 访问 etcd 需要的信息 |
allow-privileged | 是否运行容器以特权模式运行 |
service-cluster-ip-range | 绑定 service 的 ip 范围(kubernetes service 的 cluster ip 为 10.254.0.1) |
secure-port | 安全端口,通过安全 ip 加安全端口的方式可以访问到 apiserver |
insecure-port | 非安全端口,用于接受非安全连接,0 表示不启用非安全端口 |
enable-admission-plugins | admission controller 的插件 |
kubelet-certificate-authority,kubelet-client-certificate,kubelet-client-key | 访问 apiserver 的认证信息 |
介绍了 APIServer 配置信息,接下来使用 curl 调用 APIServer API 看看请求结果。
1.1.2 Kubernetes API
为了兼容旧版本的同时升级新版本 API,Kubernetes 提供了多版本 API 的支持,每个版本的 API 通过一个版本号路径前缀进行区分,如 /api/v1beta1 等。通过 kubectl api-version 命令可以查看当前 kubernetes 的版本信息:
[root@chunqiu ~ (Master)]# kubectl api-versions | grep v1
networking.k8s.io/v1
networking.k8s.io/v1beta1
...
可以看到资源 networking 包含不同的 APIVersion,其中 v1beta1 表示不建议使用(Deprecated)版本。关于版本发布及管理信息可看这里。
kubernetes 使用 API Groups 对 API 进行标识,API Groups 分为两种:
- Core Groups(核心组)是 Kubernetes 最核心的 API,其特点是没有“组”的概念,例如 “v1” 即表示核心组 apiVersion: v1。
- 具有分组信息的 API,以 /api/$GROUP_NAME/$VERSION/ URL 路径进行标识,如 apiVersion: apps/v1。
关于 API 详细信息可参考这里
以 pod 为例,查看 pod 的基本 API 接口:
资源类型 | 方法 | 说明 | 备注 |
---|---|---|---|
PODS | GET | /api/v1/pods | 获取 pod 列表 |
POST | /api/v1/pods | 创建 pod 列表 | |
GET | /api/v1/namespaces/{namespace}/pods | 获取 Namespace 下的 pod 列表 | |
POST | /api/v1/namespaces/{namespace}/pods | 在 Namespace 下创建 pod | |
DELETE | /api/v1/namespaces/{namespace}/pods/{name} | 删除 Namespace 下的 pod 对象 | |
GET | /api/v1/namespaces/{namespace}/pods/{name} | 获取 Namespace 下的 pod 对象 | |
PATCH | /api/v1/namespaces/{namespace}/pods/{name} | 部分更新某个 Namespace 下的 pod 对象 | |
PUT | /api/v1/namespaces/{namespace}/pods/{name} | 替换某个 Namespace 下的 pod 对象 |
使用 curl 工具 curl pod 的 API:
[root@chunqiu ~ (Master)]# curl https://172.17.66.2:8443/api/v1/namespaces/ci/pods/ --cacert /etc/kubernetes/ssl/ca.pem
--key /etc/kubernetes/ssl/cluster-admin-key.pem --cert /etc/kubernetes/ssl/cluster-admin.pem
{
"kind": "PodList",
"apiVersion": "v1",
"metadata": {
"selfLink": "/api/v1/namespaces/ci/pods/",
"resourceVersion": "42384766"
},
"items": [
{
"metadata": {
"name": "chunqiu-0",
"generateName": "chunqiu-",
"namespace": "ci",
"selfLink": "/api/v1/namespaces/ci/pods/chunqiu-0",
"uid": "36793f0c-9bf9-4bec-b46e-66f5945d3889",
"resourceVersion": "42378305",
"creationTimestamp": "2021-06-09T03:18:00Z",
...
curl 获取到 Namespace ci 下的 pod 列表。类似的,获取 apiVersion: apps/v1 的 statefulset 资源列表如下:
[root@chunqiu ~ (Master)]# curl https://172.17.66.2:8443/apis/apps/v1/namespaces/ci/statefulsets/ --cacert /etc/kubernetes/ssl/ca.pem
--key /etc/kubernetes/ssl/cluster-admin-key.pem --cert /etc/kubernetes/ssl/cluster-admin.pem
{
"kind": "StatefulSetList",
"apiVersion": "apps/v1",
"metadata": {
"selfLink": "/apis/apps/v1/namespaces/ci/statefulsets/",
"resourceVersion": "42392636"
},
"items": [
{
"metadata": {
"name": "chunqiu",
"namespace": "ci",
"selfLink": "/apis/apps/v1/namespaces/ci/statefulsets/chunqiu",
"uid": "0e00ffab-e504-43bf-bcd6-713359a2cfde",
"resourceVersion": "42392038",
"generation": 1,
"creationTimestamp": "2021-06-09T03:40:55Z",
"labels": {
"app.kubernetes.io/managed-by": "Helm"
},
...
对资源对象的操作除了增删改查外,Kubernetes 还提供另外一种资源操作类型 WATCH,WATCH 返回一连串 JSON 对象,该对象记录了某个给定资源对象的变化情况。如对 pod 的 WATCH 操作:
资源类型 | 类型 | 方法 | URL Path | 说明 |
---|---|---|---|---|
PODS | WATCH | GET | /api/v1/watch/pods | 监听所有 pod 变化 |
POST | /api/v1/watch/namespaces/{namespace}/pods | 监听某个 Namespace 下所有 pod 的变化 |
调用 WATCH API 监听 pod 变化情况:
[root@chunqiu ~ (Master)]# curl https://172.17.66.2:8443/api/v1/watch/pods/ --cacert /etc/kubernetes/ssl/ca.pem
--key /etc/kubernetes/ssl/cluster-admin-key.pem --cert /etc/kubernetes/ssl/cluster-admin.pem
{"type":"ADDED","object":{"kind":"Pod","apiVersion":"v1"
...
# 删除 pod
{"type":"MODIFIED","object":{"kind":"Pod","apiVersion":"v1","metadata":{"name":"chunqiu-0","generateName":"chunqiu-...
...
可以看到 WATCH API 始终处于监控当前 pod 变化状态,使用 kubectl 删除某个 pod,WATCH API 监听到该 pod 的变化情况。
1.2 etcd 概述
那么 APIServer 介绍完了吗?并没有,离开 etcd 的 APIServer 是不完整的。介绍 etcd 之前,先看下 APIServer 的拓扑结构:
用户请求通过认证授权之后访问 APIServer,APIServer 会进一步调用 admission controller 对用户请求进行进一步资源审核,审核由多维度资源插件完成(APIServer 配置参数的 enable-admission-plugins 参数定义了所需资源审核插件),通过审核后 APIServer 会根据 REST API 调用在后台 etcd 进行实际的增删改查操作。
Kubernetes 的资源存储路径都以 /registry 开始的:
[root@chunqiu ~ (Master)]# etcdctl --endpoints=https://172.17.66.2:2379 --cacert /etc/etcd/ssl/ca.pem
--key /etc/etcd/ssl/etcd-key.pem --cert /etc/etcd/ssl/etcd.pem get /registry/ --prefix --keys-only=true
/registry/apiextensions.k8s.io/customresourcedefinitions/brhooks.cbur.csf.chunqiu.com
/registry/apiextensions.k8s.io/customresourcedefinitions/brpolices.cbur.bcmt.local
...
构造场景使用 DELETE 方法删除 pod,查看 etcd 中该 pod 的资源变化情况:
- 默认 namespace 下创建 pod,查看 pod 在 etcd 存储情况。
[root@chunqiu ~ (Master)]# kubectl get pods
NAME READY STATUS RESTARTS AGE
etcdtester 0/1 ImagePullBackOff 0 100s
[root@chunqiu ~ (Master)]# etcdctl --endpoints=https://172.17.66.2:2379 --cacert /etc/etcd/ssl/ca.pem
--key /etc/etcd/ssl/etcd-key.pem --cert /etc/etcd/ssl/etcd.pem get /registry/pods/default/etcdtester --prefix --keys-only=true
/registry/pods/default/etcdtester
- 开启 WATCH 监听默认 namespace 下 pod 变化情况。
[root@chunqiu ~ (Master)]# curl https://172.17.66.2:8443/api/v1/watch/namespaces/default/pods/ --cacert /etc/kubernetes/ssl/ca.pem
--key /etc/kubernetes/ssl/cluster-admin-key.pem --cert /etc/kubernetes/ssl/cluster-admin.pem
{"type":"ADDED","object":{"kind":"Pod","apiVersion":"v1","metadata":{"name":"etcdtester"...
- 调用 APIServer 的 DELETE 方法删除 pod,查看 etcd 中 pod 变化情况:
# DELETE pod
[root@chunqiu ~ (Master)]# curl -X DELETE https://172.17.66.2:8443/api/v1/namespaces/default/pods/etcdtester --cacert /etc/kubernetes/ssl/ca.pem
--key /etc/kubernetes/ssl/cluster-admin-key.pem --cert /etc/kubernetes/ssl/cluster-admin.pem
{
"kind": "Pod",
"apiVersion": "v1",
"metadata": {
"name": "etcdtester",
"namespace": "default",
"selfLink": "/api/v1/namespaces/default/pods/etcdtester",
...
# WATCH 监听 pod
[root@chunqiu ~ (Master)]# curl https://172.17.66.2:8443/api/v1/watch/namespaces/default/pods/ --cacert /etc/kubernetes/ssl/ca.pem
--key /etc/kubernetes/ssl/cluster-admin-key.pem --cert /etc/kubernetes/ssl/cluster-admin.pem
{"type":"ADDED","object":{"kind":"Pod","apiVersion":"v1","metadata":{"name":"etcdtester"...
{"type":"MODIFIED","object":{"kind":"Pod","apiVersion":"v1","metadata":{"name":"etcdtester"...
# etcd 查看 pod
[root@chunqiu ~ (Master)]# etcdctl --endpoints=https://172.17.66.2:2379 --cacert /etc/etcd/ssl/ca.pem
--key /etc/etcd/ssl/etcd-key.pem --cert /etc/etcd/ssl/etcd.pem get /registry/pods/default/etcdtester --prefix --keys-only=true
可以看到,删除 pod 后 WATCH 监听到 pod 变化,etcd 更新 pod 资源对象。