[K8s]Kubernetes-集群管理
Posted 若水三千
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[K8s]Kubernetes-集群管理相关的知识,希望对你有一定的参考价值。
集群管理
关于创建和管理 Kubernetes 集群的底层细节。
集群管理概述面向任何创建和管理 Kubernetes 集群的读者人群。我们假设你大概了解一些核心的 Kubernetes 概念。
规划集群
查阅安装中的指导,获取如何规划、建立以及配置 Kubernetes 集群的示例。本文所列的文章称为发行版。
说明: 并非所有发行版都是被积极维护的。请选择使用最近 Kubernetes 版本测试过的发行版。
在选择一个指南前,有一些因素需要考虑:
- 你是打算在你的计算机上尝试 Kubernetes,还是要构建一个高可用的多节点集群?请选择最适合你需求的发行版。
- 你正在使用类似 Google Kubernetes Engine 这样的被托管的 Kubernetes 集群,还是管理你自己的集群?
- 你的集群是在本地还是云(IaaS)上?Kubernetes 不能直接支持混合集群。作为代替,你可以建立多个集群。
- 如果你在本地配置 Kubernetes,需要考虑哪种网络模型最适合。
- 你的 Kubernetes 在裸金属硬件上还是虚拟机(VMs)上运行?
- 你是想运行一个集群,还是打算参与开发 Kubernetes 项目代码?如果是后者,请选择一个处于开发状态的发行版。某些发行版只提供二进制发布版,但提供更多的选择。
- 让你自己熟悉运行一个集群所需的组件。
管理集群
-
学习如何管理节点。
-
学习如何设定和管理集群共享的资源配额 。
保护集群
- 生成证书节描述了使用不同的工具链生成证书的步骤。
- Kubernetes 容器环境描述了 Kubernetes 节点上由 Kubelet 管理的容器的环境。
- 控制到 Kubernetes API 的访问描述了如何为用户和 service accounts 建立权限许可。
- 身份认证节阐述了 Kubernetes 中的身份认证功能,包括许多认证选项。
- 鉴权与身份认证不同,用于控制如何处理 HTTP 请求。
- 使用准入控制器阐述了在认证和授权之后拦截到 Kubernetes API 服务的请求的插件。
- 在 Kubernetes 集群中使用 Sysctls 描述了管理员如何使用 sysctl 命令行工具来设置内核参数。
- 审计描述了如何与 Kubernetes 的审计日志交互。
保护 kubelet
- 主控节点通信
- TLS 引导
- Kubelet 认证/授权
可选集群服务
- DNS 集成描述了如何将一个 DNS 名解析到一个 Kubernetes service。
- 记录和监控集群活动阐述了 Kubernetes 的日志如何工作以及怎样实现。
1 - 证书
在使用客户端证书认证的场景下,你可以通过 easyrsa、openssl 或 cfssl 等工具以手工方式生成证书。
easyrsa
easyrsa 支持以手工方式为你的集群生成证书。
-
下载、解压、初始化打过补丁的 easyrsa3。
curl -LO https://storage.googleapis.com/kubernetes-release/easy-rsa/easy-rsa.tar.gz tar xzf easy-rsa.tar.gz cd easy-rsa-master/easyrsa3 ./easyrsa init-pki
-
生成新的证书颁发机构(CA)。参数 --batch 用于设置自动模式;参数 --req-cn 用于设置新的根证书的通用名称(CN)。
./easyrsa --batch "--req-cn=$MASTER_IP@`date +%s`" build-ca nopass
-
生成服务器证书和秘钥。参数 --subject-alt-name 设置 API 服务器的 IP 和 DNS 名称。MASTER_CLUSTER_IP 用于 API 服务器和控制管理器,通常取 CIDR 的第一个 IP,由 --service-cluster-ip-range 的参数提供。参数 --days 用于设置证书的过期时间。下面的示例假定你的默认 DNS 域名为 cluster.local。
./easyrsa --subject-alt-name="IP:$MASTER_IP,"\\ "IP:$MASTER_CLUSTER_IP,"\\ "DNS:kubernetes,"\\ "DNS:kubernetes.default,"\\ "DNS:kubernetes.default.svc,"\\ "DNS:kubernetes.default.svc.cluster,"\\ "DNS:kubernetes.default.svc.cluster.local" \\ --days=10000 \\ build-server-full server nopass
-
拷贝文件 pki/ca.crt、pki/issued/server.crt 和 pki/private/server.key 到你的目录中。
-
在 API 服务器的启动参数中添加以下参数:
--client-ca-file=/yourdirectory/ca.crt --tls-cert-file=/yourdirectory/server.crt --tls-private-key-file=/yourdirectory/server.key
openssl
openssl 支持以手工方式为你的集群生成证书。
-
生成一个 2048 位的 ca.key 文件
openssl genrsa -out ca.key 2048
-
在 ca.key 文件的基础上,生成 ca.crt 文件(用参数 -days 设置证书有效期)
openssl req -x509 -new -nodes -key ca.key -subj "/CN=$MASTER_IP" -days 10000 -out ca.crt
-
生成一个 2048 位的 server.key 文件:
openssl genrsa -out server.key 2048
-
创建一个用于生成证书签名请求(CSR)的配置文件。保存文件(例如:csr.conf)前,记得用真实值替换掉尖括号中的值(例如:<MASTER_IP>)。注意:MASTER_CLUSTER_IP 就像前一小节所述,它的值是 API 服务器的服务集群 IP。下面的例子假定你的默认 DNS 域名为 cluster.local。
[ req ] default_bits = 2048 prompt = no default_md = sha256 req_extensions = req_ext distinguished_name = dn [ dn ] C = <country> ST = <state> L = <city> O = <organization> OU = <organization unit> CN = <MASTER_IP> [ req_ext ] subjectAltName = @alt_names [ alt_names ] DNS.1 = kubernetes DNS.2 = kubernetes.default DNS.3 = kubernetes.default.svc DNS.4 = kubernetes.default.svc.cluster DNS.5 = kubernetes.default.svc.cluster.local IP.1 = <MASTER_IP> IP.2 = <MASTER_CLUSTER_IP> [ v3_ext ] authorityKeyIdentifier=keyid,issuer:always basicConstraints=CA:FALSE keyUsage=keyEncipherment,dataEncipherment extendedKeyUsage=serverAuth,clientAuth subjectAltName=@alt_names
-
基于上面的配置文件生成证书签名请求:
openssl req -new -key server.key -out server.csr -config csr.conf
-
基于 ca.key、ca.crt 和 server.csr 等三个文件生成服务端证书:
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key \\ -CAcreateserial -out server.crt -days 10000 \\ -extensions v3_ext -extfile csr.conf
-
查看证书签名请求:
openssl req -noout -text -in ./server.csr
-
查看证书:
openssl x509 -noout -text -in ./server.crt
最后,为 API 服务器添加相同的启动参数。
cfssl
cfssl 是另一个用于生成证书的工具。
-
下载、解压并准备如下所示的命令行工具。注意:你可能需要根据所用的硬件体系架构和 cfssl 版本调整示例命令。
curl -L https://github.com/cloudflare/cfssl/releases/download/v1.5.0/cfssl_1.5.0_linux_amd64 -o cfssl chmod +x cfssl curl -L https://github.com/cloudflare/cfssl/releases/download/v1.5.0/cfssljson_1.5.0_linux_amd64 -o cfssljson chmod +x cfssljson curl -L https://github.com/cloudflare/cfssl/releases/download/v1.5.0/cfssl-certinfo_1.5.0_linux_amd64 -o cfssl-certinfo chmod +x cfssl-certinfo
-
创建一个目录,用它保存所生成的构件和初始化 cfssl:
mkdir cert cd cert ../cfssl print-defaults config > config.json ../cfssl print-defaults csr > csr.json
-
创建一个 JSON 配置文件来生成 CA 文件,例如:ca-config.json:
"signing": "default": "expiry": "8760h" , "profiles": "kubernetes": "usages": [ "signing", "key encipherment", "server auth", "client auth" ], "expiry": "8760h"
-
创建一个 JSON 配置文件,用于 CA 证书签名请求(CSR),例如:ca-csr.json。确认用你需要的值替换掉尖括号中的值。
"CN": "kubernetes", "key": "algo": "rsa", "size": 2048 , "names":[ "C": "<country>", "ST": "<state>", "L": "<city>", "O": "<organization>", "OU": "<organization unit>" ]
-
生成 CA 秘钥文件(ca-key.pem)和证书文件(ca.pem):
../cfssl gencert -initca ca-csr.json | ../cfssljson -bare ca
-
创建一个 JSON 配置文件,用来为 API 服务器生成秘钥和证书,例如:server-csr.json。确认用你需要的值替换掉尖括号中的值。MASTER_CLUSTER_IP 是为 API 服务器指定的服务集群 IP,就像前面小节描述的那样。以下示例假定你的默认 DSN 域名为cluster.local。
"CN": "kubernetes", "hosts": [ "127.0.0.1", "<MASTER_IP>", "<MASTER_CLUSTER_IP>", "kubernetes", "kubernetes.default", "kubernetes.default.svc", "kubernetes.default.svc.cluster", "kubernetes.default.svc.cluster.local" ], "key": "algo": "rsa", "size": 2048 , "names": [ "C": "<country>", "ST": "<state>", "L": "<city>", "O": "<organization>", "OU": "<organization unit>" ]
-
为 API 服务器生成秘钥和证书,默认会分别存储为server-key.pem 和 server.pem 两个文件。
../cfssl gencert -ca=ca.pem -ca-key=ca-key.pem \\ --config=ca-config.json -profile=kubernetes \\ server-csr.json | ../cfssljson -bare server
分发自签名的 CA 证书
客户端节点可能不认可自签名 CA 证书的有效性。对于非生产环境,或者运行在公司防火墙后的环境,你可以分发自签名的 CA 证书到所有客户节点,并刷新本地列表以使证书生效。
在每一个客户节点,执行以下操作:
sudo cp ca.crt /usr/local/share/ca-certificates/kubernetes.crt
sudo update-ca-certificates
Updating certificates in /etc/ssl/certs...
1 added, 0 removed; done.
Running hooks in /etc/ca-certificates/update.d....
done.
证书 API
你可以通过 certificates.k8s.io API 提供 x509 证书,用来做身份验证,如本文档所述。
2 - 管理资源
你已经部署了应用并通过服务暴露它。然后呢?Kubernetes 提供了一些工具来帮助管理你的应用部署,包括扩缩容和更新。我们将更深入讨论的特性包括配置文件和标签。
组织资源配置
许多应用需要创建多个资源,例如 Deployment 和 Service。可以通过将多个资源组合在同一个文件中(在 YAML 中以 --- 分隔)来简化对它们的管理。例如:
apiVersion: v1
kind: Service
metadata:
name: my-nginx-svc
labels:
app: nginx
spec:
type: LoadBalancer
ports:
- port: 80
selector:
app: nginx
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-nginx
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
可以用创建单个资源相同的方式来创建多个资源:
kubectl apply -f https://k8s.io/examples/application/nginx-app.yaml
service/my-nginx-svc created
deployment.apps/my-nginx created
资源将按照它们在文件中的顺序创建。因此,最好先指定服务,这样在控制器(例如 Deployment)创建 Pod 时能够确保调度器可以将与服务关联的多个 Pod 分散到不同节点。
kubectl create 也接受多个 -f 参数:
kubectl apply -f https://k8s.io/examples/application/nginx/nginx-svc.yaml -f https://k8s.io/examples/application/nginx/nginx-deployment.yaml
还可以指定目录路径,而不用添加多个单独的文件:
kubectl apply -f https://k8s.io/examples/application/nginx/
kubectl 将读取任何后缀为 .yaml、.yml 或者 .json 的文件。
建议的做法是,将同一个微服务或同一应用层相关的资源放到同一个文件中,将同一个应用相关的所有文件按组存放到同一个目录中。如果应用的各层使用 DNS 相互绑定,那么你可以将堆栈的所有组件一起部署。
还可以使用 URL 作为配置源,便于直接使用已经提交到 Github 上的配置文件进行部署:
kubectl apply -f https://raw.githubusercontent.com/kubernetes/website/main/content/zh/examples/application/nginx/nginx-deployment.yaml
deployment.apps/my-nginx created
kubectl 中的批量操作
资源创建并不是 kubectl 可以批量执行的唯一操作。kubectl 还可以从配置文件中提取资源名,以便执行其他操作,特别是删除你之前创建的资源:
kubectl delete -f https://k8s.io/examples/application/nginx-app.yaml
deployment.apps "my-nginx" deleted
service "my-nginx-svc" deleted
在仅有两种资源的情况下,可以使用"资源类型/资源名"的语法在命令行中同时指定这两个资源:
kubectl delete deployments/my-nginx services/my-nginx-svc
对于资源数目较大的情况,你会发现使用 -l 或 --selector 指定筛选器(标签查询)能很容易根据标签筛选资源:
kubectl delete deployment,services -l app=nginx
deployment.apps "my-nginx" deleted
service "my-nginx-svc" deleted
由于 kubectl 用来输出资源名称的语法与其所接受的资源名称语法相同,你可以使用 $() 或 xargs 进行链式操作:
kubectl get $(kubectl create -f docs/concepts/cluster-administration/nginx/ -o name | grep service)
kubectl create -f docs/concepts/cluster-administration/nginx/ -o name | grep service | xargs -i kubectl get
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
my-nginx-svc LoadBalancer 10.0.0.208 <pending> 80/TCP 0s
上面的命令中,我们首先使用 examples/application/nginx/ 下的配置文件创建资源,并使用 -o name 的输出格式(以"资源/名称"的形式打印每个资源)打印所创建的资源。然后,我们通过 grep 来过滤 "service",最后再打印 kubectl get 的内容。
如果你碰巧在某个路径下的多个子路径中组织资源,那么也可以递归地在所有子路径上执行操作,方法是在 --filename,-f 后面指定 --recursive 或者 -R。
例如,假设有一个目录路径为 project/k8s/development,它保存开发环境所需的所有清单,并按资源类型组织:
project/k8s/development
├── configmap
│ └── my-configmap.yaml
├── deployment
│ └── my-deployment.yaml
└── pvc
└── my-pvc.yaml
默认情况下,对 project/k8s/development 执行的批量操作将停止在目录的第一级,而不是处理所有子目录。如果我们试图使用以下命令在此目录中创建资源,则会遇到一个错误:
kubectl apply -f project/k8s/development
error: you must provide one or more resources by argument or filename (.json|.yaml|.yml|stdin)
正确的做法是,在 --filename,-f 后面标明 --recursive 或者 -R 之后:
kubectl apply -f project/k8s/development --recursive
configmap/my-config created
deployment.apps/my-deployment created
persistentvolumeclaim/my-pvc created
--recursive 可以用于接受 --filename,-f 参数的任何操作,例如: kubectl create,get,delete,describe,rollout 等。
有多个 -f 参数出现的时候,--recursive 参数也能正常工作:
kubectl apply -f project/k8s/namespaces -f project/k8s/development --recursive
namespace/development created
namespace/staging created
configmap/my-config created
deployment.apps/my-deployment created
persistentvolumeclaim/my-pvc created
有效地使用标签
到目前为止我们使用的示例中的资源最多使用了一个标签。在许多情况下,应使用多个标签来区分集合。
例如,不同的应用可能会为 app 标签设置不同的值。但是,类似 guestbook 示例这样的多层应用,还需要区分每一层。前端可以带以下标签:
labels:
app: guestbook
tier: frontend
Redis 的主节点和从节点会有不同的 tier 标签,甚至还有一个额外的 role 标签:
labels:
app: guestbook
tier: backend
role: master
以及
labels:
app: guestbook
tier: backend
role: slave
标签允许我们按照标签指定的任何维度对我们的资源进行切片和切块:
kubectl apply -f examples/guestbook/all-in-one/guestbook-all-in-one.yaml
kubectl get pods -Lapp -Ltier -Lrole
NAME READY STATUS RESTARTS AGE APP TIER ROLE
guestbook-fe-4nlpb 1/1 Running 0 1m guestbook frontend <none>
guestbook-fe-ght6d 1/1 Running 0 1m guestbook frontend <none>
guestbook-fe-jpy62 1/1 Running 0 1m guestbook frontend <none>
guestbook-redis-master-5pg3b 1/1 Running 0 1m guestbook backend master
guestbook-redis-slave-2q2yf 1/1 Running 0 1m guestbook backend slave
guestbook-redis-slave-qgazl 1/1 Running 0 1m guestbook backend slave
my-nginx-divi2 1/1 Running 0 29m nginx <none> <none>
my-nginx-o0ef1 1/1 Running 0 29m nginx <none> <none>
kubectl get pods -lapp=guestbook,role=slave
NAME READY STATUS RESTARTS AGE
guestbook-redis-slave-2q2yf 1/1 Running 0 3m
guestbook-redis-slave-qgazl 1/1 Running 0 3m
金丝雀部署(Canary Deployments)
另一个需要多标签的场景是用来区分同一组件的不同版本或者不同配置的多个部署。常见的做法是部署一个使用金丝雀发布来部署新应用版本(在 Pod 模板中通过镜像标签指定),保持新旧版本应用同时运行。这样,新版本在完全发布之前也可以接收实时的生产流量。
例如,你可以使用 track 标签来区分不同的版本。
主要稳定的发行版将有一个 track 标签,其值为 stable:
name: frontend
replicas: 3
...
labels:
app: guestbook
tier: frontend
track: stable
...
image: gb-frontend:v3
然后,你可以创建 guestbook 前端的新版本,让这些版本的 track 标签带有不同的值(即 canary),以便两组 Pod 不会重叠:
name: frontend-canary
replicas: 1
...
labels:
app: guestbook
tier: frontend
track: canary
...
image: gb-frontend:v4
前端服务通过选择标签的公共子集(即忽略 track 标签)来覆盖两组副本,以便流量可以转发到两个应用:
selector:
app: guestbook
tier: frontend
你可以调整 stable 和 canary 版本的副本数量,以确定每个版本将接收实时生产流量的比例(在本例中为 3:1)。一旦有信心,你就可以将新版本应用的 track 标签的值从 canary 替换为 stable,并且将老版本应用删除。
更新标签
有时,现有的 pod 和其它资源需要在创建新资源之前重新标记。这可以用 kubectl label 完成。例如,如果想要将所有 nginx pod 标记为前端层,运行:
kubectl label pods -l app=nginx tier=fe
pod/my-nginx-2035384211-j5fhi labeled
pod/my-nginx-2035384211-u2c7e labeled
pod/my-nginx-2035384211-u3t6x labeled
首先用标签 "app=nginx" 过滤所有的 Pod,然后用 "tier=fe" 标记它们。想要查看你刚才标记的 Pod,请运行:
kubectl get pods -l app=nginx -L tier
NAME READY STATUS RESTARTS AGE TIER
my-nginx-2035384211-j5fhi 1/1 Running 0 23m fe
my-nginx-2035384211-u2c7e 1/1 Running 0 23m fe
my-nginx-2035384211-u3t6x 1/1 Running 0 23m fe
这将输出所有 "app=nginx" 的 Pod,并有一个额外的描述 Pod 的 tier 的标签列(用参数 -L 或者 --label-columns 标明)。
更新注解
有时,你可能希望将注解附加到资源中。注解是 API 客户端(如工具、库等)用于检索的任意非标识元数据。这可以通过 kubectl annotate 来完成。例如:
kubectl annotate pods my-nginx-v4-9gw19 description=\'my frontend running nginx\'
kubectl get pods my-nginx-v4-9gw19 -o yaml
apiVersion: v1
kind: pod
metadata:
annotations:
description: my frontend running nginx
...
扩缩你的应用
当应用上的负载增长或收缩时,使用 kubectl 能够实现应用规模的扩缩。例如,要将 nginx 副本的数量从 3 减少到 1,请执行以下操作:
kubectl scale deployment/my-nginx --replicas=1
deployment.extensions/my-nginx scaled
现在,你的 Deployment 管理的 Pod 只有一个了。
kubectl get pods -l app=nginx
NAME READY STATUS RESTARTS AGE
my-nginx-2035384211-j5fhi 1/1 Running 0 30m
想要让系统自动选择需要 nginx 副本的数量,范围从 1 到 3,请执行以下操作:
kubectl autoscale deployment/my-nginx --min=1 --max=3
horizontalpodautoscaler.autoscaling/my-nginx autoscaled
现在,你的 nginx 副本将根据需要自动地增加或者减少。
就地更新资源
有时,有必要对你所创建的资源进行小范围、无干扰地更新。
kubectl apply
建议在源代码管理中维护一组配置文件(参见配置即代码),这样,它们就可以和应用代码一样进行维护和版本管理。然后,你可以用 kubectl apply 将配置变更应用到集群中。
这个命令将会把推送的版本与以前的版本进行比较,并应用你所做的更改,但是不会自动覆盖任何你没有指定更改的属性。
kubectl apply -f https://k8s.io/examples/application/nginx/nginx-deployment.yaml
deployment.apps/my-nginx configured
注意,kubectl apply 将为资源增加一个额外的注解,以确定自上次调用以来对配置的更改。执行时,kubectl apply 会在以前的配置、提供的输入和资源的当前配置之间找出三方差异,以确定如何修改资源。
目前,新创建的资源是没有这个注解的,所以,第一次调用 kubectl apply 时将使用提供的输入和资源的当前配置双方之间差异进行比较。在第一次调用期间,它无法检测资源创建时属性集的删除情况。因此,kubectl 不会删除它们。
所有后续的 kubectl apply 操作以及其他修改配置的命令,如 kubectl replace 和 kubectl edit,都将更新注解,并允许随后调用的 kubectl apply 使用三方差异进行检查和执行删除。
说明: 想要使用 apply,请始终使用 kubectl apply 或 kubectl create --save-config 创建资源。
kubectl edit
或者,你也可以使用 kubectl edit 更新资源:
kubectl edit deployment/my-nginx
这相当于首先 get 资源,在文本编辑器中编辑它,然后用更新的版本 apply 资源:
kubectl get deployment my-nginx -o yaml > /tmp/nginx.yaml
vi /tmp/nginx.yaml
# do some edit, and then save the file
kubectl apply -f /tmp/nginx.yaml
deployment.apps/my-nginx configured
rm /tmp/nginx.yaml
这使你可以更加容易地进行更重大的更改。请注意,可以使用 EDITOR 或 KUBE_EDITOR 环境变量来指定编辑器。
kubectl patch
你可以使用 kubectl patch 来更新 API 对象。此命令支持 JSON patch、JSON merge patch、以及 strategic merge patch。
破坏性的更新
在某些情况下,你可能需要更新某些初始化后无法更新的资源字段,或者你可能只想立即进行递归更改,例如修复 Deployment 创建的不正常的 Pod。若要更改这些字段,请使用 replace --force,它将删除并重新创建资源。在这种情况下,你可以修改原始配置文件:
kubectl replace -f https://k8s.io/examples/application/nginx/nginx-deployment.yaml --force
deployment.apps/my-nginx deleted
deployment.apps/my-nginx replaced
在不中断服务的情况下更新应用
在某些时候,你最终需要更新已部署的应用,通常都是通过指定新的镜像或镜像标签,如上面的金丝雀发布的场景中所示。kubectl 支持几种更新操作,每种更新操作都适用于不同的场景。
我们将指导你通过 Deployment 如何创建和更新应用。
假设你正运行的是 1.14.2 版本的 nginx:
kubectl create deployment my-nginx --image=nginx:1.14.2
deployment.apps/my-nginx created
要更新到 1.16.1 版本,只需使用我们前面学到的 kubectl 命令将 .spec.template.spec.containers[0].image 从 nginx:1.14.2 修改为 nginx:1.16.1。
kubectl edit deployment/my-nginx
没错,就是这样!Deployment 将在后台逐步更新已经部署的 nginx 应用。它确保在更新过程中,只有一定数量的旧副本被开闭,并且只有一定基于所需 Pod 数量的新副本被创建。
3 - 集群网络系统
集群网络系统是 Kubernetes 的核心部分,但是想要准确了解它的工作原理可是个不小的挑战。下面列出的是网络系统的的四个主要问题:
- 高度耦合的容器间通信:这个已经被 Pods 和 localhost 通信解决了。
- Pod 间通信:这个是本文档的重点要讲述的。
- Pod 和服务间通信:这个已经在服务里讲述过了。
- 外部和服务间通信:这也已经在服务讲述过了。
Kubernetes 的宗旨就是在应用之间共享机器。通常来说,共享机器需要两个应用之间不能使用相同的端口,但是在多个应用开发者之间去大规模地协调端口是件很困难的事情,尤其是还要让用户暴露在他们控制范围之外的集群级别的问题上。
动态分配端口也会给系统带来很多复杂度 - 每个应用都需要设置一个端口的参数,而 API 服务器还需要知道如何将动态端口数值插入到配置模块中,服务也需要知道如何找到对方等等。与其去解决这些问题,Kubernetes 选择了其他不同的方法。
Kubernetes 网络模型
每一个 Pod 都有它自己的IP地址,这就意味着你不需要显式地在每个 Pod 之间创建链接,你几乎不需要处理容器端口到主机端口之间的映射。这将创建一个干净的、向后兼容的模型,在这个模型里,从端口分配、命名、服务发现、负载均衡、应用配置和迁移的角度来看,Pod 可以被视作虚拟机或者物理主机。
Kubernetes 对所有网络设施的实施,都需要满足以下的基本要求(除非有设置一些特定的网络分段策略):
- 节点上的 Pod 可以不通过 NAT 和其他任何节点上的 Pod 通信
- 节点上的代理(比如:系统守护进程、kubelet)可以和节点上的所有Pod通信
备注:仅针对那些支持 Pods 在主机网络中运行的平台(比如:Linux):
- 那些运行在节点的主机网络里的 Pod 可以不通过 NAT 和所有节点上的 Pod 通信
这个模型不仅不复杂,而且还和 Kubernetes 的实现廉价的从虚拟机向容器迁移的初衷相兼容,如果你的工作开始是在虚拟机中运行的,你的虚拟机有一个 IP ,这样就可以和其他的虚拟机进行通信,这是基本相同的模型。
Kubernetes 的 IP 地址存在于 Pod 范围内 - 容器共享它们的网络命名空间 - 包括它们的 IP 地址和 MAC 地址。这就意味着 Pod 内的容器都可以通过 localhost 到达各个端口。这也意味着 Pod 内的容器都需要相互协调端口的使用,但是这和虚拟机中的进程似乎没有什么不同,这也被称为“一个 Pod 一个 IP”模型。
如何实现这一点是正在使用的容器运行时的特定信息。
也可以在 node 本身通过端口去请求你的 Pod(称之为主机端口),但这是一个很特殊的操作。转发方式如何实现也是容器运行时的细节。Pod 自己并不知道这些主机端口是否存在。
如何实现 Kubernetes 的网络模型
有很多种方式可以实现这种网络模型,本文档并不是对各种实现技术的详细研究,但是希望可以作为对各种技术的详细介绍,并且成为你研究的起点。
接下来的网络技术是按照首字母排序,顺序本身并无其他意义。
说明: 本部分链接到提供 Kubernetes 所需功能的第三方项目。Kubernetes 项目作者不负责这些项目。此页面遵循 CNCF 网站指南,按字母顺序列出项目。要将项目添加到此列表中,请在提交更改之前阅读内容指南。
ACI
Cisco Application Centric Infrastructure 提供了一个集成覆盖网络和底层 SDN 的解决方案来支持容器、虚拟机和其他裸机服务器。ACI 为 ACI 提供了容器网络集成。
Antrea
Antrea 项目是一个开源的联网解决方案,旨在成为 Kubernetes 原生的网络解决方案。它利用 Open vSwitch 作为网络数据平面。Open vSwitch 是一个高性能可编程的虚拟交换机,支持 Linux 和 Windows 平台。Open vSwitch 使 Antrea 能够以高性能和高效的方式实现 Kubernetes 的网络策略。借助 Open vSwitch 可编程的特性,Antrea 能够在 Open vSwitch 之上实现广泛的联网、安全功能和服务。
Apstra 的 AOS
AOS 是一个基于意图的网络系统,可以通过一个简单的集成平台创建和管理复杂的数据中心环境。AOS 利用高度可扩展的分布式设计来消除网络中断,同时将成本降至最低。
AOS 参考设计当前支持三层连接的主机,这些主机消除了旧的两层连接的交换问题。这些三层连接的主机可以是 Linux(Debian、Ubuntu、CentOS)系统,它们直接在机架式交换机(TOR)的顶部创建 BGP 邻居关系。AOS 自动执行路由邻接,然后提供对 Kubernetes 部署中常见的路由运行状况注入(RHI)的精细控制。
AOS 具有一组丰富的 REST API 端点,这些端点使 Kubernetes 能够根据应用程序需求快速更改网络策略。进一步的增强功能将用于网络设计的 AOS Graph 模型与工作负载供应集成在一起,从而为私有云和公共云提供端到端管理系统。
AOS 支持使用包括 Cisco、Arista、Dell、Mellanox、HPE 在内的制造商提供的通用供应商设备,以及大量白盒系统和开放网络操作系统,例如 Microsoft SONiC、Dell OPX 和 Cumulus Linux。
想要更详细地了解 AOS 系统是如何工作的可以点击这里:https://www.apstra.com/products/how-it-works/
Kubernetes 的 AWS VPC CNI
AWS VPC CNI 为 Kubernetes 集群提供了集成的 AWS 虚拟私有云(VPC)网络。该 CNI 插件提供了高吞吐量和可用性,低延迟以及最小的网络抖动。此外,用户可以使用现有的 AWS VPC 网络和安全最佳实践来构建 Kubernetes 集群。这包括使用 VPC 流日志、VPC 路由策略和安全组进行网络流量隔离的功能。
使用该 CNI 插件,可使 Kubernetes Pod 拥有与在 VPC 网络上相同的 IP 地址。CNI 将 AWS 弹性网络接口(ENI)分配给每个 Kubernetes 节点,并将每个 ENI 的辅助 IP 范围用于该节点上的 Pod 。CNI 包含用于 ENI 和 IP 地址的预分配的控件,以便加快 Pod 的启动时间,并且能够支持多达 2000 个节点的大型集群。
此外,CNI 可以与用于执行网络策略的 Calico 一起运行。AWS VPC CNI 项目是开源的,请查看 GitHub 上的文档。
Kubernetes 的 Azure CNI
Azure CNI 是一个开源插件,将 Kubernetes Pods 和 Azure 虚拟网络(也称为 VNet)集成在一起,可提供与 VM 相当的网络性能。Pod 可以通过 Express Route 或者站点到站点的 VPN 来连接到对等的 VNet ,也可以从这些网络来直接访问 Pod。Pod 可以访问受服务端点或者受保护链接的 Azure 服务,比如存储和 SQL。你可以使用 VNet 安全策略和路由来筛选 Pod 流量。该插件通过利用在 Kubernetes 节点的网络接口上预分配的辅助 IP 池将 VNet 分配给 Pod。
Azure CNI 可以在 Azure Kubernetes Service (AKS) 中获得。
Big Switch Networks 的 Big Cloud Fabric
Big Cloud Fabric 是一个基于云原生的网络架构,旨在在私有云或者本地环境中运行 Kubernetes。它使用统一的物理和虚拟 SDN,Big Cloud Fabric 解决了固有的容器网络问题,比如负载均衡、可见性、故障排除、安全策略和容器流量监控。
在 Big Cloud Fabric 的虚拟 Pod 多租户架构的帮助下,容器编排系统(比如 Kubernetes、RedHat OpenShift、Mesosphere DC/OS 和 Docker Swarm)将与 VM 本地编排系统(比如 VMware、OpenStack 和 Nutanix)进行本地集成。客户将能够安全地互联任意数量的这些集群,并且在需要时启用他们之间的租户间通信。
在最新的 Magic Quadrant 上,BCF 被 Gartner 认为是非常有远见的。而 BCF 的一条关于 Kubernetes 的本地部署(其中包括 Kubernetes、DC/OS 和在不同地理区域的多个 DC 上运行的 VMware)也在这里被引用。
Calico
Calico 是一个开源的联网及网络安全方案,用于基于容器、虚拟机和本地主机的工作负载。Calico 支持多个数据面,包括:纯 Linux eBPF 的数据面、标准的 Linux 联网数据面以及 Windows HNS 数据面。Calico 在提供完整的联网堆栈的同时,还可与云驱动 CNIs 联合使用,以保证网络策略实施。
Cilium
Cilium 是一个开源软件,用于提供并透明保护应用容器间的网络连接。Cilium 支持 L7/HTTP,可以在 L3-L7 上通过使用与网络分离的基于身份的安全模型寻址来实施网络策略,并且可以与其他 CNI 插件结合使用。
华为的 CNI-Genie
CNI-Genie 是一个 CNI 插件,可以让 Kubernetes 在运行时使用不同的网络模型的实现同时被访问。这包括以 CNI 插件运行的任何实现,比如 Flannel、Calico、Romana、Weave-net。
CNI-Genie 还支持将多个 IP 地址分配给 Pod,每个都来自不同的 CNI 插件。
cni-ipvlan-vpc-k8s
cni-ipvlan-vpc-k8s 包含了一组 CNI 和 IPAM 插件来提供一个简单的、本地主机、低延迟、高吞吐量以及通过使用 Amazon 弹性网络接口(ENI)并使用 Linux 内核的 IPv2 驱动程序以 L2 模式将 AWS 管理的 IP 绑定到 Pod 中,在 Amazon Virtual Private Cloud(VPC)环境中为 Kubernetes 兼容的网络堆栈。
这些插件旨在直接在 VPC 中进行配置和部署,Kubelets 先启动,然后根据需要进行自我配置和扩展它们的 IP 使用率,而无需经常建议复杂的管理覆盖网络、BGP、禁用源/目标检查或调整 VPC 路由表以向每个主机提供每个实例子网的复杂性(每个 VPC 限制为50-100个条目)。简而言之,cni-ipvlan-vpc-k8s 大大降低了在 AWS 中大规模部署 Kubernetes 所需的网络复杂性。
Coil
Coil 是一个为易于集成、提供灵活的出站流量网络而设计的 CNI 插件。与裸机相比,Coil 的额外操作开销低,并允许针对外部网络的出站流量任意定义 NAT 网关。
Contiv
Contiv 为各种使用情况提供了一个可配置网络(使用了 BGP 的本地 L3,使用 vxlan、经典 L2 或 Cisco-SDN/ACI 的覆盖网络)。Contiv 是完全开源的。
Contrail/Tungsten Fabric
Contrail 是基于 Tungsten Fabric 的,真正开放的多云网络虚拟化和策略管理平台。Contrail 和 Tungsten Fabric 与各种编排系统集成在一起,例如 Kubernetes、OpenShift、OpenStack 和 Mesos,并为虚拟机、容器或 Pods 以及裸机工作负载提供了不同的隔离模式。
DANM
DANM 是一个针对在 Kubernetes 集群中运行的电信工作负载的网络解决方案。它由以下几个组件构成:
- 能够配置具有高级功能的 IPVLAN 接口的 CNI 插件
- 一个内置的 IPAM 模块,能够管理多个、群集内的、不连续的 L3 网络,并按请求提供动态、静态或无 IP 分配方案
- CNI 元插件能够通过自己的 CNI 或通过将任务授权给其他任何流行的 CNI 解决方案(例如 SRI-OV 或 Flannel)来实现将多个网络接口连接到容器
- Kubernetes 控制器能够集中管理所有 Kubernetes 主机的 VxLAN 和 VLAN 接口
- 另一个 Kubernetes 控制器扩展了 Kubernetes 的基于服务的服务发现概念,以在 Pod 的所有网络接口上工作
通过这个工具集,DANM 可以提供多个分离的网络接口,可以为 Pod 使用不同的网络后端和高级 IPAM 功能。
Flannel
Flannel 是一个非常简单的能够满足 Kubernetes 所需要的覆盖网络。已经有许多人报告了使用 Flannel 和 Kubernetes 的成功案例。
Google Compute Engine (GCE)
对于 Google Compute Engine 的集群配置脚本,高级路由器用于为每个虚机分配一个子网(默认是 /24 - 254个 IP),绑定到该子网的任何流量都将通过 GCE 网络结构直接路由到虚机。这是除了分配给虚机的“主” IP 地址之外的一个补充,该 IP 地址经过 NAT 转换以用于访问外网。Linux 网桥(称为“cbr0”)被配置为存在于该子网中,并被传递到 Docker 的 --bridge 参数上。
Docker 会以这样的参数启动:
DOCKER_OPTS="--bridge=cbr0 --iptables=false --ip-masq=false"
这个网桥是由 Kubelet(由 --network-plugin=kubenet 参数控制)根据节点的 .spec.podCIDR 参数创建的。
Docker 将会从 cbr-cidr 块分配 IP。容器之间可以通过 cbr0 网桥相互访问,也可以访问节点。这些 IP 都可以在 GCE 的网络中被路由。而 GCE 本身并不知道这些 IP,所以不会对访问外网的流量进行 NAT。为了实现此目的,使用了 iptables 规则来伪装(又称为 SNAT,使数据包看起来好像是来自“节点”本身),将通信绑定到 GCE 项目网络(10.0.0.0/8)之外的 IP。
iptables -t nat -A POSTROUTING ! -d 10.0.0.0/8 -o eth0 -j MASQUERADE
最后,在内核中启用了 IP 转发(因此内核将处理桥接容器的数据包):
sysctl net.ipv4.ip_forward=1
所有这些的结果是所有 Pod 都可以互相访问,并且可以将流量发送到互联网。
Jaguar
Jaguar 是一个基于 OpenDaylight 的 Kubernetes 网络开源解决方案。Jaguar 使用 vxlan 提供覆盖网络,而 Jaguar CNIPlugin 为每个 Pod 提供一个 IP 地址。
k-vswitch
k-vswitch 是一个基于 Open vSwitch 的简易 Kubernetes 网络插件。它利用 Open vSwitch 中现有的功能来提供强大的网络插件,该插件易于操作,高效且安全。
Knitter
Knitter 是一个支持 Kubernetes 中实现多个网络系统的解决方案。它提供了租户管理和网络管理的功能。除了多个网络平面外,Knitter 还包括一组端到端的 NFV 容器网络解决方案,例如为应用程序保留 IP 地址、IP 地址迁移等。
Kube-OVN
Kube-OVN 是一个基于 OVN 的用于企业的 Kubernetes 网络架构。借助于 OVN/OVS,它提供了一些高级覆盖网络功能,例如子网、QoS、静态 IP 分配、流量镜像、网关、基于 openflow 的网络策略和服务代理。
Kube-router
Kube-router 是 Kubernetes 的专用网络解决方案,旨在提供高性能和易操作性。Kube-router 提供了一个基于 Linux LVS/IPVS 的服务代理、一个基于 Linux 内核转发的无覆盖 Pod-to-Pod 网络解决方案和基于 iptables/ipset 的网络策略执行器。
L2 networks and linux bridging
如果你具有一个“哑”的L2网络,例如“裸机”环境中的简单交换机,则应该能够执行与上述 GCE 设置类似的操作。请注意,这些说明仅是非常简单的尝试过-似乎可行,但尚未经过全面测试。如果您使用此技术并完善了流程,请告诉我们。
根据 Lars Kellogg-Stedman 的这份非常不错的“Linux 网桥设备” 使用说明来进行操作。
Multus (a Multi Network plugin)
Multus 是一个多 CNI 插件,使用 Kubernetes 中基于 CRD 的网络对象来支持实现 Kubernetes 多网络系统。
Multus 支持所有参考插件(比如: Flannel、 DHCP、 Macvlan )来实现 CNI 规范和第三方插件(比如: Calico、 Weave、 Cilium、 Contiv)。除此之外,Multus 还支持 SRIOV、DPDK、OVS-DPDK & VPP 的工作负载,以及 Kubernetes 中基于云的本机应用程序和基于 NFV 的应用程序。
NSX-T
VMware NSX-T 是一个网络虚拟化和安全平台。NSX-T 可以为多云及多系统管理程序环境提供网络虚拟化,并专注于具有异构端点和技术堆栈的新兴应用程序框架和体系结构。除了 vSphere 管理程序之外,这些环境还包括其他虚拟机管理程序,例如 KVM、容器和裸机。
NSX-T Container Plug-in (NCP) 提供了 NSX-T 与容器协调器(例如 Kubernetes)之间的结合,以及 NSX-T 与基于容器的 CaaS/PaaS 平台(例如 Pivotal Container Service(PKS)和 OpenShift)之间的集成。
Nuage Networks VCS (Virtualized Cloud Services)
Nuage 提供了一个高度可扩展的基于策略的软件定义网络(SDN)平台。Nuage 使用开源的 Open vSwitch 作为数据平面,以及基于开放标准构建具有丰富功能的 SDN 控制器。
Nuage 平台使用覆盖层在 Kubernetes Pod 和非 Kubernetes 环境(VM 和裸机服务器)之间提供基于策略的无缝联网。Nuage 的策略抽象模型在设计时就考虑到了应用程序,并且可以轻松声明应用程序的细粒度策略。该平台的实时分析引擎可为 Kubernetes 应用程序提供可见性和安全性监控。
OpenVSwitch
OpenVSwitch 是一个较为成熟的解决方案,但同时也增加了构建覆盖网络的复杂性。这也得到了几个网络系统的“大商店”的拥护。
OVN (开放式虚拟网络)
OVN 是一个由 Open vSwitch 社区开发的开源的网络虚拟化解决方案。它允许创建逻辑交换器、逻辑路由、状态 ACL、负载均衡等等来建立不同的虚拟网络拓扑。该项目有一个特定的 Kubernetes 插件和文档 ovn-kubernetes。
Romana
Romana 是一个开源网络和安全自动化解决方案。它可以让你在没有覆盖网络的情况下部署 Kubernetes。Romana 支持 Kubernetes 网络策略,来提供跨网络命名空间的隔离。
Weaveworks 的 Weave Net
Weave Net 是 Kubernetes 及其托管应用程序的弹性且易于使用的网络系统。Weave Net 可以作为 CNI 插件运行或者独立运行。在这两种运行方式里,都不需要任何配置或额外的代码即可运行,并且在两种情况下,网络都为每个 Pod 提供一个 IP 地址 -- 这是 Kubernetes 的标准配置。
4 - Kubernetes 系统组件指标
通过系统组件指标可以更好地了解系统组个内部发生的情况。系统组件指标对于构建仪表板和告警特别有用。
Kubernetes 组件以 Prometheus 格式生成度量值。这种格式是结构化的纯文本,旨在使人和机器都可以阅读。
Kubernetes 中组件的指标
在大多数情况下,可以通过 HTTP 访问组件的 /metrics 端点来获取组件的度量值。对于那些默认情况下不暴露端点的组件,可以使用 --bind-address 标志启用。
这些组件的示例:
- kube-controller-manager
- kube-proxy
- kube-apiserver
- kube-scheduler
- kubelet
在生产环境中,你可能需要配置 Prometheus 服务器或某些其他指标搜集器以定期收集这些指标,并使它们在某种时间序列数据库中可用。
请注意,kubelet 还会在 /metrics/cadvisor,/metrics/resource 和 /metrics/probes 端点中公开度量值。这些度量值的生命周期各不相同。
如果你的集群使用了 RBAC,则读取指标需要通过基于用户、组或 ServiceAccount 的鉴权,要求具有允许访问 /metrics 的 ClusterRole。例如:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: prometheus
rules:
- nonResourceURLs:
- "/metrics"
verbs:
- get
指标生命周期
Alpha 指标 → 稳定的指标 → 弃用的指标 → 隐藏的指标 → 删除的指标
Alpha 指标没有稳定性保证。这些指标可以随时被修改或者删除。
稳定的指标可以保证不会改变。这意味着:
- 稳定的、不包含已弃用(deprecated)签名的指标不会被删除(或重命名)
- 稳定的指标的类型不会被更改
已弃用的指标最终将被删除,不过仍然可用。这类指标包含注解,标明其被废弃的版本。
例如:
-
被弃用之前:
# HELP some_counter this counts things # TYPE some_counter counter some_counter 0
-
被启用之后:
# HELP some_counter (Deprecated since 1.15.0) this counts things # TYPE some_counter counter some_counter 0
隐藏的指标不会再被发布以供抓取,但仍然可用。要使用隐藏指标,请参阅显式隐藏指标节。
删除的指标不再被发布,亦无法使用。
显示隐藏指标
如上所述,管理员可以通过设置可执行文件的命令行参数来启用隐藏指标,如果管理员错过了上一版本中已经弃用的指标的迁移,则可以把这个用作管理员的逃生门。
show-hidden-metrics-for-version 标志接受版本号作为取值,版本号给出你希望显示该发行版本中已弃用的指标。版本表示为 x.y,其中 x 是主要版本,y 是次要版本。补丁程序版本不是必须的,即使指标可能会在补丁程序发行版中弃用,原因是指标弃用策略规定仅针对次要版本。
该参数只能使用前一个次要版本。如果管理员将先前版本设置为 show-hidden-metrics-for-version,则先前版本中隐藏的度量值会再度生成。不允许使用过旧的版本,因为那样会违反指标弃用策略。
以指标 A 为例,此处假设 A 在 1.n 中已弃用。根据指标弃用策略,我们可以得出以下结论:
- 在版本 1.n 中,这个指标已经弃用,且默认情况下可以生成。
- 在版本 1.n+1 中,这个指标默认隐藏,可以通过命令行参数 show-hidden-metrics-for-version=1.n 来再度生成。
- 在版本 1.n+2 中,这个指标就将被从代码中移除,不会再有任何逃生窗口。
如果你要从版本 1.12 升级到 1.13,但仍依赖于 1.12 中弃用的指标 A,则应通过命令行设置隐藏指标:--show-hidden-metrics=1.12,并记住在升级到 1.14 版本之前删除此指标依赖项。
禁用加速器指标
kubelet 通过 cAdvisor 收集加速器指标。为了收集这些指标,对于 NVIDIA GPU 之类的加速器,kubelet 在驱动程序上保持打开状态。这意味着为了执行基础结构更改(例如更新驱动程序),集群管理员需要停止 kubelet 代理。
现在,收集加速器指标的责任属于供应商,而不是 kubelet。供应商必须提供一个收集指标的容器,并将其公开给指标服务(例如 Prometheus)。
DisableAcceleratorUsageMetrics 特性门控禁止由 kubelet 收集的指标。关于何时会在默认情况下启用此功能也有一定规划。
组件指标
kube-controller-manager 指标
控制器管理器指标可提供有关控制器管理器性能和运行状况的重要洞察。这些指标包括通用的 Go 语言运行时指标(例如 go_routine 数量)和控制器特定的度量指标,例如可用于评估集群运行状况的 etcd 请求延迟或云提供商(AWS、GCE、OpenStack)的 API 延迟等。
从 Kubernetes 1.7 版本开始,详细的云提供商指标可用于 GCE、AWS、Vsphere 和 OpenStack 的存储操作。这些指标可用于监控持久卷操作的运行状况。
比如,对于 GCE,这些指标称为:
cloudprovider_gce_api_request_duration_seconds request = "instance_list"
cloudprovider_gce_api_request_duration_seconds request = "disk_insert"
cloudprovider_gce_api_request_duration_seconds request = "disk_delete"
cloudprovider_gce_api_request_duration_seconds request = "attach_disk"
cloudprovider_gce_api_request_duration_seconds request = "detach_disk"
cloudprovider_gce_api_request_duration_seconds request = "list_disk"
kube-scheduler 指标
FEATURE STATE: Kubernetes v1.21 [beta]
调度器会暴露一些可选的指标,报告所有运行中 Pods 所请求的资源和期望的约束值。这些指标可用来构造容量规划监控面板、访问调度约束的当前或历史数据、快速发现因为缺少资源而无法被调度的负载,或者将 Pod 的实际资源用量与其请求值进行比较。
kube-scheduler 组件能够辩识各个 Pod 所配置的资源请求和约束。在 Pod 的资源请求值或者约束值非零时,kube-scheduler 会以度量值时间序列的形式生成报告。该时间序列值包含以下标签:
- 名字空间
- Pod 名称
- Pod 调度所处节点,或者当 Pod 未被调度时用空字符串表示
- 优先级
- 为 Pod 所指派的调度器
- 资源的名称(例如,cpu)
- 资源的单位,如果知道的话(例如,cores)
一旦 Pod 进入完成状态(其 restartPolicy 为 Never 或 OnFailure,且其处于 Succeeded 或 Failed Pod 阶段,或者已经被删除且所有容器都具有终止状态),该时间序列停止报告,因为调度器现在可以调度其它 Pod 来执行。这两个指标称作 kube_pod_resource_request 和 kube_pod_resource_limit。
指标暴露在 HTTP 端点 /metrics/resources,与调度器上的 /metrics 端点一样要求相同的访问授权。你必须使用 --show-hidden-metrics-for-version=1.20 标志才能暴露那些稳定性为 Alpha 的指标。
禁用指标
你可以通过命令行标志 --disabled-metrics 来关闭某指标。在例如某指标会带来性能问题的情况下,这一操作可能是有用的。标志的参数值是一组被禁止的指标(例如:--disabled-metrics=metric1,metric2)。
指标顺序性保证
在 Alpha 阶段,标志只能接受一组映射值作为可以使用的指标标签。每个映射值的格式为<指标名称>,<标签名称>=<可用标签列表>,其中 <可用标签列表> 是一个用逗号分隔的、可接受的标签名的列表。
最终的格式看起来会是这样:--allow-label-value <指标名称>,<标签名称>=\'<可用值1>,<可用值2>...\', <指标名称2>,<标签名称>=\'<可用值1>, <可用值2>...\', ....
下面是一个例子:
--allow-label-value number_count_metric,odd_number=\'1,3,5\', number_count_metric,even_number=\'2,4,6\', date_gauge_metric,weekend=\'Saturday,Sunday\'
5 - 日志架构
应用日志可以让你了解应用内部的运行状况。日志对调试问题和监控集群活动非常有用。大部分现代化应用都有某种日志记录机制。同样容器引擎也被设计成支持日志记录。针对容器化应用,最简单且最广泛采用的日志记录方式就是写入标准输出和标准错误流。
但是,由容器引擎或运行时提供的原生功能通常不足以构成完整的日志记录方案。例如,如果发生容器崩溃、Pod 被逐出或节点宕机等情况,你可能想访问应用日志。在集群中,日志应该具有独立的存储和生命周期,与节点、Pod 或容器的生命周期相独立。这个概念叫集群级的日志。
集群级日志架构需要一个独立的后端用来存储、分析和查询日志。Kubernetes 并不为日志数据提供原生的存储解决方案。相反,有很多现成的日志方案可以集成到 Kubernetes 中。下面各节描述如何在节点上处理和存储日志。
Kubernetes 中的基本日志记录
这里的示例使用包含一个容器的 Pod 规约,每秒钟向标准输出写入数据。
apiVersion: v1
kind: Pod
metadata:
name: counter
spec:
containers:
- name: count
image: busybox
args: [/bin/sh, -c,
\'i=0; while true; do echo "$i: $(date)"; i=$((i+1)); sleep 1; done\']
用下面的命令运行 Pod:
kubectl apply -f https://k8s.io/examples/debug/counter-pod.yaml
输出结果为:
pod/counter created
像下面这样,使用 kubectl logs 命令获取日志:
kubectl logs counter
输出结果为:
0: Mon Jan 1 00:00:00 UTC 2001
1: Mon Jan 1 00:00:01 UTC 2001
2: Mon Jan 1 00:00:02 UTC 2001
...
你可以使用命令 kubectl logs --previous 检索之前容器实例的日志。如果 Pod 中有多个容器,你应该为该命令附加容器名以访问对应容器的日志。
节点级日志记录
容器化应用写入 stdout 和 stderr 的任何数据,都会被容器引擎捕获并被重定向到某个位置。例如,Docker 容器引擎将这两个输出流重定向到某个日志驱动(Logging Driver),该日志驱动在 Kubernetes 中配置为以 JSON 格式写入文件。
说明: Docker JSON 日志驱动将日志的每一行当作一条独立的消息。该日志驱动不直接支持多行消息。你需要在日志代理级别或更高级别处理多行消息。
默认情况下,如果容器重启,kubelet 会保留被终止的容器日志。如果 Pod 在工作节点被驱逐,该 Pod 中所有的容器也会被驱逐,包括容器日志。
节点级日志记录中,需要重点考虑实现日志的轮转,以此来保证日志不会消耗节点上全部可用空间。Kubernetes 并不负责轮转日志,而是通过部署工具建立一个解决问题的方案。例如,在用 kube-up.sh 部署的 Kubernetes 集群中,存在一个 logrotate,每小时运行一次。你也可以设置容器运行时来自动地轮转应用日志。
例如,你可以找到关于 kube-up.sh 为 GCP 环境的 COS 镜像设置日志的详细信息,脚本为 configure-helper 脚本。
当使用某 CRI 容器运行时时,kubelet 要负责对日志进行轮换,并管理日志目录的结构。kubelet 将此信息发送给 CRI 容器运行时,后者将容器日志写入到指定的位置。在 kubelet 配置文件中的两个 kubelet 参数 containerLogMaxSize 和 containerLogMaxFiles 可以用来配置每个日志文件的最大长度和每个容器可以生成的日志文件个数上限。
当运行 kubectl logs 时,节点上的 kubelet 处理该请求并直接读取日志文件,同时在响应中返回日志文件内容。
说明: 如果有外部系统执行日志轮转或者使用了 CRI 容器运行时,那么 kubectl logs 仅可查询到最新的日志内容。比如,对于一个 10MB 大小的文件,通过 logrotate 执行轮转后生成两个文件,一个 10MB 大小,一个为空,kubectl logs 返回最新的日志文件,而该日志文件在这个例子中为空。
系统组件日志
系统组件有两种类型:在容器中运行的和不在容器中运行的。例如:
- 在容器中运行的 kube-scheduler 和 kube-proxy。
- 不在容器中运行的 kubelet 和容器运行时。
在使用 systemd 机制的服务器上,kubelet 和容器容器运行时将日志写入到 journald 中。如果没有 systemd,它们将日志写入到 /var/log 目录下的 .log 文件中。容器中的系统组件通常将日志写到 /var/log 目录,绕过了默认的日志机制。他们使用 klog 日志库。你可以在日志开发文档找到这些组件的日志告警级别约定。
和容器日志类似,/var/log 目录中的系统组件日志也应该被轮转。通过脚本 kube-up.sh 启动的 Kubernetes 集群中,日志被工具 logrotate 执行每日轮转,或者日志大小超过 100MB 时触发轮转。
集群级日志架构
虽然 Kubernetes 没有为集群级日志记录提供原生的解决方案,但你可以考虑几种常见的方法。以下是一些选项:
- 使用在每个节点上运行的节点级日志记录代理。
- 在应用程序的 Pod 中,包含专门记录日志的边车(Sidecar)容器。
- 将日志直接从应用程序中推送到日志记录后端。
使用节点级日志代理
你可以通过在每个节点上使用节点级的日志记录代理来实现群集级日志记录。日志记录代理是一种用于暴露日志或将日志推送到后端的专用工具。通常,日志记录代理程序是一个容器,它可以访问包含该节点上所有应用程序容器的日志文件的目录。
由于日志记录代理必须在每个节点上运行,通常可以用 DaemonSet 的形式运行该代理。节点级日志在每个节点上仅创建一个代理,不需要对节点上的应用做修改。
容器向标准输出和标准错误输出写出数据,但在格式上并不统一。节点级代理收集这些日志并将其进行转发以完成汇总。
使用 sidecar 容器运行日志代理
你可以通过以下方式之一使用边车(Sidecar)容器:
- 边车容器将应用程序日志传送到自己的标准输出。
- 边车容器运行一个日志代理,配置该日志代理以便从应用容器收集日志。
传输数据流的 sidecar 容器
利用边车容器向自己的 stdout 和 stderr 传输流的方式,你就可以利用每个节点上的 kubelet 和日志代理来处理日志。边车容器从文件、套接字或 journald 读取日志。每个边车容器向自己的 stdout 和 stderr 流中输出日志。
这种方法允许你将日志流从应用程序的不同部分分离开,其中一些可能缺乏对写入 stdout 或 stderr 的支持。重定向日志背后的逻辑是最小的,因此它的开销几乎可以忽略不计。另外,因为 stdout、stderr 由 kubelet 处理,你可以使用内置的工具 kubectl logs。
例如,某 Pod 中运行一个容器,该容器向两个文件写不同格式的日志。下面是这个 pod 的配置文件:
apiVersion: v1
kind: Pod
metadata:
name: counter
spec:
containers:
- name: count
image: busybox
args:
- /bin/sh
- -c
- >
i=0;
while true;
do
echo "$i: $(date)" >> /var/log/1.log;
echo "$(date) INFO $i" >> /var/log/2.log;
i=$((i+1));
sleep 1;
done
volumeMounts:
- name: varlog
mountPath: /var/log
volumes:
- name: varlog
emptyDir:
不建议在同一个日志流中写入不同格式的日志条目,即使你成功地将其重定向到容器的 stdout 流。相反,你可以创建两个边车容器。每个边车容器可以从共享卷跟踪特定的日志文件,并将文件内容重定向到各自的 stdout 流。
下面是运行两个边车容器的 Pod 的配置文件:
apiVersion: v1
kind: Pod
metadata:
name: counter
spec:
containers:
- name: count
image: busybox
args:
- /bin/sh
- -c
- >
i=0;
while true;
do
echo "$i: $(date)" >> /var/log/1.log;
echo "$(date) INFO $i" >> /var/log/2.log;
i=$((i+1));
sleep 1;
done
volumeMounts:
- name: varlog
mountPath: /var/log
- name: count-log-1
image: busybox
args: [/bin/sh, -c, \'tail -n+1 -f /var/log/1.log\']
volumeMounts:
- name: varlog
mountPath: /var/log
- name: count-log-2
image: busybox
args: [/bin/sh, -c, \'tail -n+1 -f /var/log/2.log\']
volumeMounts:
- name: varlog
mountPath: /var/log
volumes:
- name: varlog
emptyDir:
现在当你运行这个 Pod 时,你可以运行如下命令分别访问每个日志流:
kubectl logs counter count-log-1
输出为:
0: Mon Jan 1 00:00:00 UTC 2001
1: Mon Jan 1 00:00:01 UTC 2001
2: Mon Jan 1 00:00:02 UTC 2001
...
kubectl logs counter count-log-2
输出为:
Mon Jan 1 00:00:00 UTC 2001 INFO 0
Mon Jan 1 00:00:01 UTC 2001 INFO 1
Mon Jan 1 00:00:02 UTC 2001 INFO 2
...
集群中安装的节点级代理会自动获取这些日志流,而无需进一步配置。如果你愿意,你也可以配置代理程序来解析源容器的日志行。
注意,尽管 CPU 和内存使用率都很低(以多个 CPU 毫核指标排序或者按内存的兆字节排序),向文件写日志然后输出到 stdout 流仍然会成倍地增加磁盘使用率。如果你的应用向单一文件写日志,通常最好设置 /dev/stdout 作为目标路径,而不是使用流式的边车容器方式。
应用本身如果不具备轮转日志文件的功能,可以通过边车容器实现。该方式的一个例子是运行一个小的、定期轮转日志
以上是关于[K8s]Kubernetes-集群管理的主要内容,如果未能解决你的问题,请参考以下文章
k8s之安装 Kubernetes 多集群管理工具 - Kuboard v3
云原生之kubernetes实战kubernetes集群的证书管理
你的薪资的高低取决你对容器集群管理系统Kubernetes(K8S)的理解程度