不论什么样的应用，基本都有配置文件，在企业中，大部分会用到配置中心，比如apollo、nacos等，也有一些公司直接使用Kubernetes自带的配置管理，主要有： Secret ConfigMap Secret如果把配置信息保存在Secret中，其会被加密存放到Etcd中，Pod可以通过以下两种种方式使用它： 通过环境变量的方式 通过挂载的方式 指定拉取镜像的Secret 一般情况下，通过Secret保存的配置信息都是敏感信息，比如数据库的账号密码、认证服务的账号密码等，且Secret不宜过大，因为如果使用大的Secret，则将大量占用API Server和kubelet的内存。创建Secret的方式主要有两种： 使用YAML文件创建 使用kubectl命令创建 使用YAML文件创建使用YAML文件创建，就要熟悉Secret的配置详情，可以通过kubectl explain secret去查看。其主要字段有apiVersion，data，kind，metadata，type。比如创建一个简单的Secret如下：apiVersion: v1 kind: Secret metadata: name: my-secret-volume type: Opaque data: user: cm9vdA== password: UEBzc1cwcmQ= 其中apiVersion、kind和metadata是常用字段，这里就不赘述了。type表示secret的类型，主要有以下几种： Qpaque：可以定义任意数据 kubernetes.io/service-account-token：配置ServiceAccount Token kubernetes.io/dockercfg：配置docker认证文件 kubernetes.io/dockerconfigjson：配置docker认证文件 kubernetes.io/basic-auth：配置基础认证 kubernetes.io/ssh-auth：配置ssh认证 kubernetes.io/tls：配置TLS证书 bootstrap.kubernetes.io/token：配置bootstrap token 如果在创建Secret的时候没有指定类型，默认使用Qpaque类型。另外data的数据的值是需要base64转码。使用kubectl命令创建在使用kubectl创建的时候，如果不熟悉子命令信息，可以通过kubectl explain secret查看。我们使用以下命令创建一个Secret：$ kubectl create secret generic secret-auth-test --from-literal=username=joker --from-literal=password=123 创建完成后，可以看到username和password的值被自动加密了，如下：$ kubectl get secrets secret-auth-test -oyaml apiVersion: v1 data: password: MTIz username: am9rZXI= kind: Secret metadata: creationTimestamp: "2022-07-25T07:44:18Z" name: secret-auth-test namespace: default resourceVersion: "652834" uid: ff1b756a-6b38-4b68-a47c-c51988729b68 type: Opaque 除了直接在命令行输入数据，还可以从文件创建，如下：$ echo -n 'admin' > ./username.txt $ echo -n '1f2d1e2e67df' > ./password.txt 然后通过--from-file引入文件，如下：$ kubectl create secret generic db-user-pass \ --from-file=./username.txt \ --from-file=./password.txt 创建后的secret值都是加密的，如果要获取明文信息，通过以下命令即可：$ kubectl get secret db-user-pass -o jsonpath='{.data.password}' | base64 --decode 默认情况下，secret是使用base64加密的，所以解密可以直接使用base64解密。Secret只是一个静态资源，最终，我们是想使用它，在实际中，主要通过以下方式使用： 通过环境变量的方式 通过挂载的方式 指定拉取镜像的Secret 我们在上面创建了secret-auth-test的Secret，下面分别使用以上三种方式进行使用。通过环境变量使用Secret在Pod的对象中，有spec.containers.env.valueFrom.secretKeyRef字段，该字段可以用来引用Secret字段，如下：apiVersion: v1 kind: Pod metadata: name: secret-env-pod spec: containers: - name: mycontainer image: redis env: - name: SECRET_USERNAME valueFrom: secretKeyRef: name: secret-auth-test key: username - name: SECRET_PASSWORD valueFrom: secretKeyRef: name: secret-auth-test key: password 这样就会把Secret里的信息注入到容器环境变量里，应用可以直接通过读取环境变量来使用。通过挂载的方式使用Secret可以使用挂载的方式，将Secret以文件的形式挂载到容器中，如下：apiVersion: v1 kind: Pod metadata: name: mypod spec: containers: - name: mypod image: redis volumeMounts: - name: foo mountPath: "/etc/foo" readOnly: true volumes: - name: foo secret: secretName: secret-auth-test 这样就会把数据挂载到/etc/foo这个目录里，如下：$ kubectl exec -it mypod -- /bin/sh # ls -l /etc/foo total 0 lrwxrwxrwx 1 root root 15 Jul 25 08:30 password -> ..data/password lrwxrwxrwx 1 root root 15 Jul 25 08:30 username -> ..data/username 如果Secret里有多个键值，还可以只挂载某一个数据，如下：apiVersion: v1 kind: Pod metadata: name: mypod spec: containers: - name: mypod image: redis volumeMounts: - name: foo mountPath: "/etc/foo" readOnly: true volumes: - name: foo secret: secretName: secret-auth-test items: - key: username path: my-group/my-username 上面指定volumes.secret.items.path用来指定username的子目录，如下：$ kubectl exec -it mypod-password -- /bin/bash root@mypod-password:/data# cat /etc/foo/my-group/my-username joker 除此之外，还可以指定权限，如下：apiVersion: v1 kind: Pod metadata: name: mypod spec: containers: - name: mypod image: redis volumeMounts: - name: foo mountPath: "/etc/foo" volumes: - name: foo secret: secretName: secret-auth-test defaultMode: 0400 然后可以看到被挂载的Secret的权限如下：$ kubectl exec -it mypod-permision -- /bin/bash root@mypod-permision:/etc/foo# ls -l total 0 lrwxrwxrwx 1 root root 15 Jul 25 08:38 password -> ..data/password lrwxrwxrwx 1 root root 15 Jul 25 08:38 username -> ..data/username root@mypod-permision:/etc/foo# ls ..data/password -l -r-------- 1 root root 3 Jul 25 08:38 ..data/password 注意：我们进/etc/foo目录直接使用ls -l查看到的权限是777，但是仔细的人可以发现其实质是一个链接文件，我们真正要看的权限是被链接的文件，也就是上面的..data/password。在拉取镜像的时候使用Secret我们在前面列举了很多YAML文件，都没有配置imagePullSecret，主要是那些镜像都是Dockerhub官方的镜像，对外是公开的。然而，在实际的生产中，不会将自己公司的镜像对外公开，这非常的不安全。如果镜像仓库加密了，在下载镜像的时候要docker login，在Kubernetes中，也免不了该操作。为此，Kubernetes提供了imagePullSecret字段，该字段用来指定拉取镜像的Secret，这个Secret会保存镜像仓库的认证信息。（1）首先创建镜像认证信息的Secretkubectl create secret \ docker-registry pull-registry-secret \ --docker-server=registry.test.cn \ --docker-username=ops \ --docker-password=ops123123 \ （2）在Pod中使用apiVersion: v1 kind: Pod metadata: name: mypod spec: imagePullSecrets: - name: pull-registry-secret containers: - name: mypod image: redis volumeMounts: - name: foo mountPath: "/etc/foo" volumes: - name: foo secret: secretName: secret-auth-test defaultMode: 0400 这样就可以拉取私有仓库里的镜像了。综上，我们可以通过Secret保管其他系统的敏感信息（比如数据库的用户名和密码），并以Mount的方式将Secret挂载到Container中，然后通过访问目录中文件的方式获取该敏感信息。当Pod被API Server创建时，API Server不会校验该Pod引用的Secret是否存在。一旦这个Pod被调度，则kubelet将试着获取Secret的值。如果Secret不存在或暂时无法连接到API Server，则kubelet按一定的时间间隔定期重试获取该Secret，并发送一个Event来解释Pod没有启动的原因。一旦Secret被Pod获取，则kubelet将创建并挂载包含Secret的Volume。只有所有Volume都挂载成功，Pod中的Container才会被启动。在kubelet启动Pod中的Container后，Container中和Secret相关的Volume将不会被改变，即使Secret本身被修改。为了使用更新后的Secret，必须删除旧Pod，并重新创建一个新Pod。ConfigMapConfigMap和Serect类似，不同之处在于ConfigMap保存的数据信息是不需要加密的，比如一些应用的配置信息，其他的用法和Secret一样。同样，我们可以使用两种方式来创建ConfigMap: 通过命令行方式，也就是kubectl create configmap； 通过YAML文件方式； 通过命令创建ConfigMap如果不熟悉ConfigMap对象的字段，可以通过kubectl explain configmap来查看，如果想查看创建configmap的示例，可以通过kubectl create configmap -h查看，如下：Examples: # Create a new config map named my-config based on folder bar kubectl create configmap my-config --from-file=path/to/bar # Create a new config map named my-config with specified keys instead of file basenames on disk kubectl create configmap my-config --from-file=key1=/path/to/bar/file1.txt --from-file=key2=/path/to/bar/file2.txt # Create a new config map named my-config with key1=config1 and key2=config2 kubectl create configmap my-config --from-literal=key1=config1 --from-literal=key2=config2 # Create a new config map named my-config from the key=value pairs in the file kubectl create configmap my-config --from-file=path/to/bar # Create a new config map named my-config from an env file kubectl create configmap my-config --from-env-file=path/to/foo.env --from-env-file=path/to/bar.env 从上面可以看出，创建ConfigMap可以从给定一个目录来创建。例如，我们定义了如下一些配置文件：$ mkdir configmap-demo $ cd configmap-demo $ ll total 8 -rw-r--r-- 1 root root 25 Sep 6 17:07 mysqld.conf -rw-r--r-- 1 root root 25 Sep 6 17:07 redis.conf $ cat mysqld.conf host=127.0.0.1 port=3306 $ cat redis.conf host=127.0.0.1 port=6379 然后使用一下命令来进行创建：$ kubectl create configmap my-configmap --from-file=../configmap-demo/ 然后通过一下命令查看创建完的configmap：$ kubectl get cm NAME DATA AGE kube-root-ca.crt 1 21d my-configmap 2 9s $ kubectl describe cm my-configmap Name: my-configmap Namespace: default Labels: <none> Annotations: <none> Data ==== mysqld.conf: ---- host=127.0.0.1 port=3306 redis.conf: ---- host=127.0.0.1 port=6379 BinaryData ==== Events: <none> 我们可以看到两个key对应的是文件的名字，value对应的是文件的内容。如果要看键值的话可以通过如下命令查看：$ kubectl get configmap my-configmap -o yaml apiVersion: v1 data: mysqld.conf: | host=127.0.0.1 port=3306 redis.conf: | host=127.0.0.1 port=6379 kind: ConfigMap metadata: creationTimestamp: "2022-07-25T09:20:43Z" name: my-configmap namespace: default resourceVersion: "667706" uid: 46cb52e9-0936-4934-9628-ac20efcfd893 当然，我们还可以通过文件来创建一个configmap，比如我们定义一个如下的配置文件：$ cat nginx.conf user nobody; worker_processes 1; error_log logs/error.log; error_log logs/error.log notice; error_log logs/error.log info; pid logs/nginx.pid; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log logs/access.log main; sendfile on; tcp_nopush on; keepalive_timeout 65; gzip on; server { listen 80; server_name localhost; location / { root html; index index.html index.htm; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } } } 然后通过如下命令创建一个nginx的configmap：$ kubectl create configmap nginx-configmap --from-file=nginx.conf 查看创建后的信息：$ kubectl get configmap nginx-configmap -o yaml apiVersion: v1 data: nginx.conf: | user nobody; worker_processes 1; error_log logs/error.log; error_log logs/error.log notice; error_log logs/error.log info; pid logs/nginx.pid; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log logs/access.log main; sendfile on; tcp_nopush on; keepalive_timeout 65; gzip on; server { listen 80; server_name localhost; location / { root html; index index.html index.htm; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } } } kind: ConfigMap metadata: creationTimestamp: "2022-07-25T09:24:29Z" name: nginx-configmap namespace: default resourceVersion: "668283" uid: a025da28-6817-4605-8daf-375b676282c1 注：在一条命令中--from-file可以指定多次。另外，通过帮助文档我们可以看到我们还可以直接使用字符串进行创建，通过--from-literal参数传递配置信息，同样的，这个参数可以使用多次，格式如下：$ kubectl create configmap my-cm-daemo --from-literal=db.host=localhost --from-literal=db.port=3306 通过YAML创建ConfigMap通过YAML文件创建就比较简单，我们可以参考上面输出的yaml信息，比如定义如下一个YAML文件：apiVersion: v1 kind: ConfigMap metadata: name: my-cm-daemon2 labels: app: cm-daemon data: redis.conf: | host=127.0.0.1 port=6379 然后创建即可。ConfigMap中的配置数据可以通过如下方式进行使用： 设置环境变量值 在数据卷中创建config文件 通过环境变量使用ConfigMap我们直接通过在pod.spec.containers.env.valueFrom.configMapKeyRef中引用ConfigMap即可，如下：apiVersion: v1 kind: Pod metadata: name: env-configmap labels: app: env-configmap-mysql spec: containers: - name: test-configmap image: busybox command: - "/bin/sh" - "-c" - "env" env: - name: DB_HOST valueFrom: configMapKeyRef: name: my-cm-daemo key: db.host - name: DB_PORT valueFrom: configMapKeyRef: name: my-cm-daemo key: db.port envFrom: - configMapRef: name: my-cm-daemo 创建后，可以通过日志查看环境变量输出，如下：$ kubectl logs env-configmap | grep DB DB_PORT=3306 DB_HOST=localhost 通过数据卷使用ConfigMap基本原理和Secret一样。在这里，通过指定pod.spec.volumes.configMap.name来指定ConfigMap，然后挂载到容器里，如下：apiVersion: v1 kind: Pod metadata: name: volume-configmap-test spec: containers: - name: volume-configmap-test image: busybox command: [ "/bin/sh", "-c", "cat /etc/config/redis.conf" ] volumeMounts: - name: config-volume mountPath: /etc/config volumes: - name: config-volume configMap: name: my-configmap 我们可以通过日志查看ConfigMap是否挂载进去了。$ kubectl logs volume-configmap-test host=127.0.0.1 port=6379 我们也可以在ConfigMap值被映射的数据卷里去控制路径，如下：apiVersion: v1 kind: Pod metadata: name: volume-path-configmap spec: containers: - name: volume-path-configmap-test image: busybox command: [ "/bin/sh","-c","cat /etc/config/path/to/msyqld.conf" ] volumeMounts: - name: config-volume mountPath: /etc/config volumes: - name: config-volume configMap: name: my-configmap items: - key: mysqld.conf path: path/to/msyqld.conf 另外，当ConfigMap以数据卷的形式挂载进Pod的时，这时更新ConfigMap（或删掉重建ConfigMap），Pod内挂载的配置信息会热更新。虽然配置信息更新，应用到底能不能使用，主要还是依赖应用是否也会热更新。ConfigMap在实际中用的还是比较多，主要都是一些应用的配置文件，比如Nginx配置文件，MySQL配置文件，这类配置文件如果想放到私有的配置中心需要额外花费更多的精力，而放到ConfigMap，则方便很多，而且多数都以挂载的方式放进容器里。
1、简述ETCD及其特点?etcd是一个分布式的、高可用的、一致的key-value存储数据库，基于Go语言实现，主要用于共享配置和服务发现。特点：完全复制：集群中的每个节点都可以使用完整的存档高可用性：Etcd可用于避免硬件的单点故障或网络问题一致性：每次读取都会返回跨多主机的最新写入简单：包括一个定义良好、面向用户的API（gRPC）安全：实现了带有可选的客户端证书身份验证的自动化TLS快速：每秒10000次写入的基准速度可靠：使用Raft算法实现了强一致、高可用的服务存储目录2、简述ETCD适应的场景?服务发现：服务发现要解决的也是分布式系统中最常见的问题之一，即在同一个分布式集群中的进程或服务，要如何才能找到对方并建立连接。本质上来说，服务发现就是想要了解集群中是否有进程在监听udp或tcp端口，并且通过名字就可以查找和连接。消息发布与订阅：在分布式系统中，最实用对的一种组件间的通信方式：消息发布与订阅。构建一个配置共享中心，数据提供者在这个配置中心发布消息，而消息使用者订阅他们关心的主题，一旦主题有消息发布，就会实时通知订阅者。达成集中式管理与动态更新。应用中用到的一些配置信息放到etcd上进行集中管理。负载均衡：分布式系统中，为了保证服务的高可用以及数据的一致性，通常都会把数据和服务部署多份，以此达到对等服务，即使其中的某一个服务失效了，也不影响使用。etcd本身分布式架构存储的信息访问支持负载均衡。分布式通知与协调：通过注册与异步通知机制，实现分布式环境下不同系统之间的通知与协调，从而对数据变更做到实时处理。分布式锁：因为etcd使用Raft算法保持了数据的强一致性，某次操作存储到集群中的值必然是全局一致的，所以很容易实现分布式锁。锁服务有两种使用方式，一是保持独占，二是控制时序。分布式队列：分布式队列的常规用法与场景五中所描述的分布式锁的控制时序用法类似，即创建一个先进先出的队列，保证顺序。集群监控与Leader精选：通过etcd来进行监控实现起来非常简单并且实时性强。3、简述什么是Kubernetes?kubernetes，简称K8s，是一个开源的，用于管理云平台中多个主机上的容器化的应用，Kubernetes的目标是让部署容器化的应用简单并且高效,Kubernetes提供了应用部署，规划，更新，维护的一种机制。4、简述Kubernetes和Docker的关系?Docker开源的容器引擎，一种更加轻量级的虚拟化技术。Kubernetes，容器管理工具，用来管理容器pod的集合，它可以实现容器集群的自动化部署、自动扩缩容、维护等功能。5、简述Kubernetes中什么是Minikube、Kubectl、Kubelet?Minikube 是一种可以在本地轻松运行一个单节点 Kubernetes 群集的工具。Kubectl 是一个命令行工具，可以使用该工具控制Kubernetes集群管理器，如检查群集资源，创建、删除和更新组件，查看应用程序。Kubelet 是一个代理服务，它在每个节点上运行，并使从服务器与主服务器通信。6、简述Kubernetes常见的部署方式?kubeadm：也是推荐的一种部署方式；二进制minikube：在本地轻松运行一个单节点 Kubernetes 群集的工具。7、简述Kubernetes如何实现集群管理?在集群管理方面，Kubernetes将集群中的机器划分为一个Master节点和一群工作节点Node。其中，在Master节点运行着集群管理相关的一组进程kube-apiserver、kube-controller-manager和kube-scheduler，这些进程实现了整个集群的资源管理、Pod调度、弹性伸缩、安全控制、系统监控和纠错等管理能力，并且都是全自动完成的。8、简述Kubernetes的优势、适应场景及其特点?Kubernetes作为一个完备的分布式系统支撑平台，其主要优势：容器编排轻量级开源弹性伸缩负载均衡Kubernetes常见场景：快速部署应用快速扩展应用无缝对接新的应用功能节省资源，优化硬件资源的使用Kubernetes相关特点：可移植: 支持公有云、私有云、混合云、多重云（multi-cloud）。可扩展: 模块化,、插件化、可挂载、可组合。自动化: 自动部署、自动重启、自动复制、自动伸缩/扩展。9、简述Kubernetes的缺点或当前的不足之处?安装过程和配置相对困难复杂。管理服务相对繁琐。运行和编译需要很多时间。它比其他替代品更昂贵。对于简单的应用程序来说，可能不需要涉及Kubernetes即可满足。10、简述Kubernetes相关基础概念?master：k8s集群的管理节点，负责管理集群，提供集群的资源数据访问入口。拥有Etcd存储服务（可选），运行Api Server进程，Controller Manager服务进程及Scheduler服务进程。node（worker）：Node（worker）是Kubernetes集群架构中运行Pod的服务节点，是Kubernetes集群操作的单元，用来承载被分配Pod的运行，是Pod运行的宿主机。运行docker eninge服务，守护进程kunelet及负载均衡器kube-proxy。pod：运行于Node节点上，若干相关容器的组合。Pod内包含的容器运行在同一宿主机上，使用相同的网络命名空间、IP地址和端口，能够通过localhost进行通信。Pod是Kurbernetes进行创建、调度和管理的最小单位，它提供了比容器更高层次的抽象，使得部署和管理更加灵活。一个Pod可以包含一个容器或者多个相关容器。label：Kubernetes中的Label实质是一系列的Key/Value键值对，其中key与value可自定义。Label可以附加到各种资源对象上，如Node、Pod、Service、RC等。一个资源对象可以定义任意数量的Label，同一个Label也可以被添加到任意数量的资源对象上去。Kubernetes通过Label Selector（标签选择器）查询和筛选资源对象。Replication Controller：Replication Controller用来管理Pod的副本，保证集群中存在指定数量的Pod副本。集群中副本的数量大于指定数量，则会停止指定数量之外的多余容器数量。反之，则会启动少于指定数量个数的容器，保证数量不变。Replication Controller是实现弹性伸缩、动态扩容和滚动升级的核心。Deployment：Deployment在内部使用了RS来实现目的，Deployment相当于RC的一次升级，其最大的特色为可以随时获知当前Pod的部署进度。HPA（Horizontal Pod Autoscaler）：Pod的横向自动扩容，也是Kubernetes的一种资源，通过追踪分析RC控制的所有Pod目标的负载变化情况，来确定是否需要针对性的调整Pod副本数量。Service：Service定义了Pod的逻辑集合和访问该集合的策略，是真实服务的抽象。Service提供了一个统一的服务访问入口以及服务代理和发现机制，关联多个相同Label的Pod，用户不需要了解后台Pod是如何运行。Volume：Volume是Pod中能够被多个容器访问的共享目录，Kubernetes中的Volume是定义在Pod上，可以被一个或多个Pod中的容器挂载到某个目录下。Namespace：Namespace用于实现多租户的资源隔离，可将集群内部的资源对象分配到不同的Namespace中，形成逻辑上的不同项目、小组或用户组，便于不同的Namespace在共享使用整个集群的资源的同时还能被分别管理。11、简述Kubernetes集群相关组件?Kubernetes Master控制组件，调度管理整个系统（集群），包含如下组件:Kubernetes API Server：作为Kubernetes系统的入口，其封装了核心对象的增删改查操作，以RESTful API接口方式提供给外部客户和内部组件调用，集群内各个功能模块之间数据交互和通信的中心枢纽。Kubernetes Scheduler：为新建立的Pod进行节点(node)选择(即分配机器)，负责集群的资源调度。Kubernetes Controller：负责执行各种控制器，目前已经提供了很多控制器来保证Kubernetes的正常运行。Replication Controller：管理维护Replication Controller，关联Replication Controller和Pod，保证Replication Controller定义的副本数量与实际运行Pod数量一致。Node Controller：管理维护Node，定期检查Node的健康状态，标识出(失效 | 未失效)的Node节点。Namespace Controller：管理维护Namespace，定期清理无效的Namespace，包括Namesapce下的API对象，比如Pod、Service等。Service Controller：管理维护Service，提供负载以及服务代理。EndPoints Controller：管理维护Endpoints，关联Service和Pod，创建Endpoints为Service的后端，当Pod发生变化时，实时更新Endpoints。Service Account Controller：管理维护Service Account，为每个Namespace创建默认的Service Account，同时为Service Account创建Service Account Secret。Persistent Volume Controller：管理维护Persistent Volume和Persistent Volume Claim，为新的Persistent Volume Claim分配Persistent Volume进行绑定，为释放的Persistent Volume执行清理回收。Daemon Set Controller：管理维护Daemon Set，负责创建Daemon Pod，保证指定的Node上正常的运行Daemon Pod。Deployment Controller：管理维护Deployment，关联Deployment和Replication Controller，保证运行指定数量的Pod。当Deployment更新时，控制实现Replication Controller和Pod的更新。Job Controller：管理维护Job，为Jod创建一次性任务Pod，保证完成Job指定完成的任务数目Pod Autoscaler Controller：实现Pod的自动伸缩，定时获取监控数据，进行策略匹配，当满足条件时执行Pod的伸缩动作。12、简述Kubernetes RC的机制?Replication Controller用来管理Pod的副本，保证集群中存在指定数量的Pod副本。当定义了RC并提交至Kubernetes集群中之后，Master节点上的Controller Manager组件获悉，并同时巡检系统中当前存活的目标Pod，并确保目标Pod实例的数量刚好等于此RC的期望值，若存在过多的Pod副本在运行，系统会停止一些Pod，反之则自动创建一些Pod。13、简述kube-proxy作用?kube-proxy 运行在所有节点上，它监听 apiserver 中 service 和 endpoint 的变化情况，创建路由规则以提供服务 IP 和负载均衡功能。简单理解此进程是Service的透明代理兼负载均衡器，其核心功能是将到某个Service的访问请求转发到后端的多个Pod实例上。14、简述kube-proxy iptables原理?Kubernetes从1.2版本开始，将iptables作为kube-proxy的默认模式。iptables模式下的kube-proxy不再起到Proxy的作用，其核心功能：通过API Server的Watch接口实时跟踪Service与Endpoint的变更信息，并更新对应的iptables规则，Client的请求流量则通过iptables的NAT机制“直接路由”到目标Pod。15、简述kube-proxy ipvs原理?IPVS在Kubernetes1.11中升级为GA稳定版。IPVS则专门用于高性能负载均衡，并使用更高效的数据结构（Hash表），允许几乎无限的规模扩张，因此被kube-proxy采纳为最新模式。在IPVS模式下，使用iptables的扩展ipset，而不是直接调用iptables来生成规则链。iptables规则链是一个线性的数据结构，ipset则引入了带索引的数据结构，因此当规则很多时，也可以很高效地查找和匹配。可以将ipset简单理解为一个IP（段）的集合，这个集合的内容可以是IP地址、IP网段、端口等，iptables可以直接添加规则对这个“可变的集合”进行操作，这样做的好处在于可以大大减少iptables规则的数量，从而减少性能损耗。16、简述kube-proxy ipvs和iptables的异同?iptables与IPVS都是基于Netfilter实现的，但因为定位不同，二者有着本质的差别：iptables是为防火墙而设计的；IPVS则专门用于高性能负载均衡，并使用更高效的数据结构（Hash表），允许几乎无限的规模扩张。与iptables相比，IPVS拥有以下明显优势：为大型集群提供了更好的可扩展性和性能；支持比iptables更复杂的复制均衡算法（最小负载、最少连接、加权等）；支持服务器健康检查和连接重试等功能；可以动态修改ipset的集合，即使iptables的规则正在使用这个集合。17、简述Kubernetes中什么是静态Pod?静态pod是由kubelet进行管理的仅存在于特定Node的Pod上，他们不能通过API Server进行管理，无法与ReplicationController、Deployment或者DaemonSet进行关联，并且kubelet无法对他们进行健康检查。静态Pod总是由kubelet进行创建，并且总是在kubelet所在的Node上运行。18、简述Kubernetes中Pod可能位于的状态?Pending：API Server已经创建该Pod，且Pod内还有一个或多个容器的镜像没有创建，包括正在下载镜像的过程。Running：Pod内所有容器均已创建，且至少有一个容器处于运行状态、正在启动状态或正在重启状态。Succeeded：Pod内所有容器均成功执行退出，且不会重启。Failed：Pod内所有容器均已退出，但至少有一个容器退出为失败状态。Unknown：由于某种原因无法获取该Pod状态，可能由于网络通信不畅导致。19、简述Kubernetes创建一个Pod的主要流程?客户端提交Pod的配置信息（可以是yaml文件定义的信息）到kube-apiserver。Apiserver收到指令后，通知给controller-manager创建一个资源对象。Controller-manager通过api-server将pod的配置信息存储到ETCD数据中心中。Kube-scheduler检测到pod信息会开始调度预选，会先过滤掉不符合Pod资源配置要求的节点，然后开始调度调优，主要是挑选出更适合运行pod的节点，然后将pod的资源配置单发送到node节点上的kubelet组件上。Kubelet根据scheduler发来的资源配置单运行pod，运行成功后，将pod的运行信息返回给scheduler，scheduler将返回的pod运行状况的信息存储到etcd数据中心。20、简述Kubernetes中Pod的重启策略?Pod重启策略（RestartPolicy）应用于Pod内的所有容器，并且仅在Pod所处的Node上由kubelet进行判断和重启操作。当某个容器异常退出或者健康检查失败时，kubelet将根据RestartPolicy的设置来进行相应操作。Pod的重启策略包括Always、OnFailure和Never，默认值为Always。Always：当容器失效时，由kubelet自动重启该容器；OnFailure：当容器终止运行且退出码不为0时，由kubelet自动重启该容器；Never：不论容器运行状态如何，kubelet都不会重启该容器。同时Pod的重启策略与控制方式关联，当前可用于管理Pod的控制器包括ReplicationController、Job、DaemonSet及直接管理kubelet管理（静态Pod）。不同控制器的重启策略限制如下：RC和DaemonSet：必须设置为Always，需要保证该容器持续运行；Job：OnFailure或Never，确保容器执行完成后不再重启；kubelet：在Pod失效时重启，不论将RestartPolicy设置为何值，也不会对Pod进行健康检查。21、简述Kubernetes中Pod的健康检查方式?LivenessProbe探针：用于判断容器是否存活（running状态），如果LivenessProbe探针探测到容器不健康，则kubelet将杀掉该容器，并根据容器的重启策略做相应处理。若一个容器不包含LivenessProbe探针，kubelet认为该容器的LivenessProbe探针返回值用于是“Success”。ReadineeProbe探针：用于判断容器是否启动完成（ready状态）。如果ReadinessProbe探针探测到失败，则Pod的状态将被修改。Endpoint Controller将从Service的Endpoint中删除包含该容器所在Pod的Eenpoint。startupProbe探针：启动检查机制，应用一些启动缓慢的业务，避免业务长时间启动而被上面两类探针kill掉。22、简述Kubernetes Pod的LivenessProbe探针的常见方式?ExecAction：在容器内执行一个命令，若返回码为0，则表明容器健康。TCPSocketAction：通过容器的IP地址和端口号执行TCP检查，若能建立TCP连接，则表明容器健康。HTTPGetAction：通过容器的IP地址、端口号及路径调用HTTP Get方法，若响应的状态码大于等于200且小于400，则表明容器健康。23、简述Kubernetes Pod的常见调度方式?Deployment或RC：该调度策略主要功能就是自动部署一个容器应用的多份副本，以及持续监控副本的数量，在集群内始终维持用户指定的副本数量。NodeSelector：定向调度，当需要手动指定将Pod调度到特定Node上，可以通过Node的标签（Label）和Pod的nodeSelector属性相匹配。NodeAffinity亲和性调度：亲和性调度机制极大的扩展了Pod的调度能力，目前有两种节点亲和力表达：requiredDuringSchedulingIgnoredDuringExecution：硬规则，必须满足指定的规则，调度器才可以调度Pod至Node上（类似nodeSelector，语法不同）。preferredDuringSchedulingIgnoredDuringExecution：软规则，优先调度至满足的Node的节点，但不强求，多个优先级规则还可以设置权重值。Taints和Tolerations（污点和容忍）：Taint：使Node拒绝特定Pod运行；Toleration：为Pod的属性，表示Pod能容忍（运行）标注了Taint的Node。24、简述Kubernetes初始化容器（init container）?init container的运行方式与应用容器不同，它们必须先于应用容器执行完成，当设置了多个init container时，将按顺序逐个运行，并且只有前一个init container运行成功后才能运行后一个init container。当所有init container都成功运行后，Kubernetes才会初始化Pod的各种信息，并开始创建和运行应用容器。25、简述Kubernetes deployment升级过程?初始创建Deployment时，系统创建了一个ReplicaSet，并按用户的需求创建了对应数量的Pod副本。当更新Deployment时，系统创建了一个新的ReplicaSet，并将其副本数量扩展到1，然后将旧ReplicaSet缩减为2。之后，系统继续按照相同的更新策略对新旧两个ReplicaSet进行逐个调整。最后，新的ReplicaSet运行了对应个新版本Pod副本，旧的ReplicaSet副本数量则缩减为0。26、简述Kubernetes deployment升级策略?在Deployment的定义中，可以通过spec.strategy指定Pod更新的策略，目前支持两种策略：Recreate（重建）和RollingUpdate（滚动更新），默认值为RollingUpdate。Recreate：设置spec.strategy.type=Recreate，表示Deployment在更新Pod时，会先杀掉所有正在运行的Pod，然后创建新的Pod。RollingUpdate：设置spec.strategy.type=RollingUpdate，表示Deployment会以滚动更新的方式来逐个更新Pod。同时，可以通过设置spec.strategy.rollingUpdate下的两个参数（maxUnavailable和maxSurge）来控制滚动更新的过程。27、简述Kubernetes DaemonSet类型的资源特性?DaemonSet资源对象会在每个Kubernetes集群中的节点上运行，并且每个节点只能运行一个pod，这是它和deployment资源对象的最大也是唯一的区别。因此，在定义yaml文件中，不支持定义replicas。它的一般使用场景如下：在去做每个节点的日志收集工作。监控每个节点的的运行状态。28、简述Kubernetes自动扩容机制?Kubernetes使用Horizontal Pod Autoscaler（HPA）的控制器实现基于CPU使用率进行自动Pod扩缩容的功能。HPA控制器周期性地监测目标Pod的资源性能指标，并与HPA资源对象中的扩缩容条件进行对比，在满足条件时对Pod副本数量进行调整。29、简述Kubernetes Service类型?通过创建Service，可以为一组具有相同功能的容器应用提供一个统一的入口地址，并且将请求负载分发到后端的各个容器应用上。其主要类型有：ClusterIP：虚拟的服务IP地址，该地址用于Kubernetes集群内部的Pod访问，在Node上kube-proxy通过设置的iptables规则进行转发；NodePort：使用宿主机的端口，使能够访问各Node的外部客户端通过Node的IP地址和端口号就能访问服务；LoadBalancer：使用外接负载均衡器完成到服务的负载分发，需要在spec.status.loadBalancer字段指定外部负载均衡器的IP地址，通常用于公有云。30、简述Kubernetes Service分发后端的策略?Service负载分发的策略有：RoundRobin和SessionAffinityRoundRobin：默认为轮询模式，即轮询将请求转发到后端的各个Pod上。SessionAffinity：基于客户端IP地址进行会话保持的模式，即第1次将某个客户端发起的请求转发到后端的某个Pod上，之后从相同的客户端发起的请求都将被转发到后端相同的Pod上。31、简述Kubernetes Headless Service?在某些应用场景中，若需要人为指定负载均衡器，不使用Service提供的默认负载均衡的功能，或者应用程序希望知道属于同组服务的其他实例。Kubernetes提供了Headless Service来实现这种功能，即不为Service设置ClusterIP（入口IP地址），仅通过Label Selector将后端的Pod列表返回给调用的客户端。32、简述Kubernetes外部如何访问集群内的服务?映射Pod到物理机：将Pod端口号映射到宿主机，即在Pod中采用hostPort方式，以使客户端应用能够通过物理机访问容器应用。映射Service到物理机：将Service端口号映射到宿主机，即在Service中采用nodePort方式，以使客户端应用能够通过物理机访问容器应用。映射Sercie到LoadBalancer：通过设置LoadBalancer映射到云服务商提供的LoadBalancer地址。这种用法仅用于在公有云服务提供商的云平台上设置Service的场景。33、简述Kubernetes ingress?Kubernetes的Ingress资源对象，用于将不同URL的访问请求转发到后端不同的Service，以实现HTTP层的业务路由机制。Kubernetes使用了Ingress策略和Ingress Controller，两者结合并实现了一个完整的Ingress负载均衡器。使用Ingress进行负载分发时，Ingress Controller基于Ingress规则将客户端请求直接转发到Service对应的后端Endpoint（Pod）上，从而跳过kube-proxy的转发功能，kube-proxy不再起作用，全过程为：ingress controller + ingress 规则 ----> services。同时当Ingress Controller提供的是对外服务，则实际上实现的是边缘路由器的功能。34、简述Kubernetes镜像的下载策略?K8s的镜像下载策略有三种：Always、Never、IFNotPresent。Always：镜像标签为latest时，总是从指定的仓库中获取镜像。Never：禁止从仓库中下载镜像，也就是说只能使用本地镜像。IfNotPresent：仅当本地没有对应镜像时，才从目标仓库中下载。默认的镜像下载策略是：当镜像标签是latest时，默认策略是Always；当镜像标签是自定义时（也就是标签不是latest），那么默认策略是IfNotPresent。35、简述Kubernetes的负载均衡器?负载均衡器是暴露服务的最常见和标准方式之一。根据工作环境使用两种类型的负载均衡器，即内部负载均衡器或外部负载均衡器。内部负载均衡器自动平衡负载并使用所需配置分配容器，而外部负载均衡器将流量从外部负载引导至后端容器。36、简述Kubernetes各模块如何与API Server通信?Kubernetes API Server作为集群的核心，负责集群各功能模块之间的通信。集群内的各个功能模块通过API Server将信息存入etcd，当需要获取和操作这些数据时，则通过API Server提供的REST接口（用GET、LIST或WATCH方法）来实现，从而实现各模块之间的信息交互。如kubelet进程与API Server的交互：每个Node上的kubelet每隔一个时间周期，就会调用一次API Server的REST接口报告自身状态，API Server在接收到这些信息后，会将节点状态信息更新到etcd中。如kube-controller-manager进程与API Server的交互：kube-controller-manager中的Node Controller模块通过API Server提供的Watch接口实时监控Node的信息，并做相应处理。如kube-scheduler进程与API Server的交互：Scheduler通过API Server的Watch接口监听到新建Pod副本的信息后，会检索所有符合该Pod要求的Node列表，开始执行Pod调度逻辑，在调度成功后将Pod绑定到目标节点上。37、简述Kubernetes Scheduler作用及实现原理?Kubernetes Scheduler是负责Pod调度的重要功能模块，Kubernetes Scheduler在整个系统中承担了“承上启下”的重要功能，“承上”是指它负责接收Controller Manager创建的新Pod，为其调度至目标Node；“启下”是指调度完成后，目标Node上的kubelet服务进程接管后继工作，负责Pod接下来生命周期。Kubernetes Scheduler的作用是将待调度的Pod（API新创建的Pod、Controller Manager为补足副本而创建的Pod等）按照特定的调度算法和调度策略绑定（Binding）到集群中某个合适的Node上，并将绑定信息写入etcd中。在整个调度过程中涉及三个对象，分别是待调度Pod列表、可用Node列表，以及调度算法和策略。Kubernetes Scheduler通过调度算法调度为待调度Pod列表中的每个Pod从Node列表中选择一个最适合的Node来实现Pod的调度。随后，目标节点上的kubelet通过API Server监听到Kubernetes Scheduler产生的Pod绑定事件，然后获取对应的Pod清单，下载Image镜像并启动容器。38、简述Kubernetes Scheduler使用哪两种算法将Pod绑定到worker节点?预选（Predicates）：输入是所有节点，输出是满足预选条件的节点。kube-scheduler根据预选策略过滤掉不满足策略的Nodes。如果某节点的资源不足或者不满足预选策略的条件则无法通过预选。如“Node的label必须与Pod的Selector一致”。优选（Priorities）：输入是预选阶段筛选出的节点，优选会根据优先策略为通过预选的Nodes进行打分排名，选择得分最高的Node。例如，资源越富裕、负载越小的Node可能具有越高的排名。39、简述Kubernetes kubelet的作用?在Kubernetes集群中，在每个Node（又称Worker）上都会启动一个kubelet服务进程。该进程用于处理Master下发到本节点的任务，管理Pod及Pod中的容器。每个kubelet进程都会在API Server上注册节点自身的信息，定期向Master汇报节点资源的使用情况，并通过cAdvisor监控容器和节点资源。40、简述Kubernetes kubelet监控Worker节点资源是使用什么组件来实现的?kubelet使用cAdvisor对worker节点资源进行监控。在 Kubernetes 系统中，cAdvisor 已被默认集成到 kubelet 组件内，当 kubelet 服务启动时，它会自动启动 cAdvisor 服务，然后 cAdvisor 会实时采集所在节点的性能指标及在节点上运行的容器的性能指标。41、简述Kubernetes如何保证集群的安全性?Kubernetes通过一系列机制来实现集群的安全控制，主要有如下不同的维度：基础设施方面：保证容器与其所在宿主机的隔离；权限方面：最小权限原则：合理限制所有组件的权限，确保组件只执行它被授权的行为，通过限制单个组件的能力来限制它的权限范围。用户权限：划分普通用户和管理员的角色。集群方面：API Server的认证授权：Kubernetes集群中所有资源的访问和变更都是通过Kubernetes API Server来实现的，因此需要建议采用更安全的HTTPS或Token来识别和认证客户端身份（Authentication），以及随后访问权限的授权（Authorization）环节。API Server的授权管理：通过授权策略来决定一个API调用是否合法。对合法用户进行授权并且随后在用户访问时进行鉴权，建议采用更安全的RBAC方式来提升集群安全授权。敏感数据引入Secret机制：对于集群敏感数据建议使用Secret方式进行保护。AdmissionControl（准入机制）：对kubernetes api的请求过程中，顺序为：先经过认证 & 授权，然后执行准入操作，最后对目标对象进行操作。42、简述Kubernetes准入机制?在对集群进行请求时，每个准入控制代码都按照一定顺序执行。如果有一个准入控制拒绝了此次请求，那么整个请求的结果将会立即返回，并提示用户相应的error信息。准入控制（AdmissionControl）准入控制本质上为一段准入代码，在对kubernetes api的请求过程中，顺序为：先经过认证 & 授权，然后执行准入操作，最后对目标对象进行操作。常用组件（控制代码）如下：AlwaysAdmit：允许所有请求AlwaysDeny：禁止所有请求，多用于测试环境。ServiceAccount：它将serviceAccounts实现了自动化，它会辅助serviceAccount做一些事情，比如如果pod没有serviceAccount属性，它会自动添加一个default，并确保pod的serviceAccount始终存在。LimitRanger：观察所有的请求，确保没有违反已经定义好的约束条件，这些条件定义在namespace中LimitRange对象中。NamespaceExists：观察所有的请求，如果请求尝试创建一个不存在的namespace，则这个请求被拒绝。43、简述Kubernetes RBAC及其特点（优势）?RBAC是基于角色的访问控制，是一种基于个人用户的角色来管理对计算机或网络资源的访问的方法。相对于其他授权模式，RBAC具有如下优势：对集群中的资源和非资源权限均有完整的覆盖。整个RBAC完全由几个API对象完成， 同其他API对象一样， 可以用kubectl或API进行操作。可以在运行时进行调整，无须重新启动API Server。44、简述Kubernetes Secret作用?Secret对象，主要作用是保管私密数据，比如密码、OAuth Tokens、SSH Keys等信息。将这些私密信息放在Secret对象中比直接放在Pod或Docker Image中更安全，也更便于使用和分发。45、简述Kubernetes Secret有哪些使用方式?创建完secret之后，可通过如下三种方式使用：在创建Pod时，通过为Pod指定Service Account来自动使用该Secret。通过挂载该Secret到Pod来使用它。在Docker镜像下载时使用，通过指定Pod的spc.ImagePullSecrets来引用它。46、简述Kubernetes PodSecurityPolicy机制?Kubernetes PodSecurityPolicy是为了更精细地控制Pod对资源的使用方式以及提升安全策略。在开启PodSecurityPolicy准入控制器后，Kubernetes默认不允许创建任何Pod，需要创建PodSecurityPolicy策略和相应的RBAC授权策略（Authorizing Policies），Pod才能创建成功。47、简述Kubernetes PodSecurityPolicy机制能实现哪些安全策略?在PodSecurityPolicy对象中可以设置不同字段来控制Pod运行时的各种安全策略，常见的有：特权模式：privileged是否允许Pod以特权模式运行。宿主机资源：控制Pod对宿主机资源的控制，如hostPID：是否允许Pod共享宿主机的进程空间。用户和组：设置运行容器的用户ID（范围）或组（范围）。提升权限：AllowPrivilegeEscalation：设置容器内的子进程是否可以提升权限，通常在设置非root用户（MustRunAsNonRoot）时进行设置。SELinux：进行SELinux的相关配置。48、简述Kubernetes网络模型?Kubernetes网络模型中每个Pod都拥有一个独立的IP地址，并假定所有Pod都在一个可以直接连通的、扁平的网络空间中。所以不管它们是否运行在同一个Node（宿主机）中，都要求它们可以直接通过对方的IP进行访问。设计这个原则的原因是，用户不需要额外考虑如何建立Pod之间的连接，也不需要考虑如何将容器端口映射到主机端口等问题。同时为每个Pod都设置一个IP地址的模型使得同一个Pod内的不同容器会共享同一个网络命名空间，也就是同一个Linux网络协议栈。这就意味着同一个Pod内的容器可以通过localhost来连接对方的端口。在Kubernetes的集群里，IP是以Pod为单位进行分配的。一个Pod内部的所有容器共享一个网络堆栈（相当于一个网络命名空间，它们的IP地址、网络设备、配置等都是共享的）。49、简述Kubernetes CNI模型?CNI提供了一种应用容器的插件化网络解决方案，定义对容器网络进行操作和配置的规范，通过插件的形式对CNI接口进行实现。CNI仅关注在创建容器时分配网络资源，和在销毁容器时删除网络资源。在CNI模型中只涉及两个概念：容器和网络。容器（Container）：是拥有独立Linux网络命名空间的环境，例如使用Docker或rkt创建的容器。容器需要拥有自己的Linux网络命名空间，这是加入网络的必要条件。网络（Network）：表示可以互连的一组实体，这些实体拥有各自独立、唯一的IP地址，可以是容器、物理机或者其他网络设备（比如路由器）等。对容器网络的设置和操作都通过插件（Plugin）进行具体实现，CNI插件包括两种类型：CNI Plugin和IPAM（IP Address Management）Plugin。CNI Plugin负责为容器配置网络资源，IPAM Plugin负责对容器的IP地址进行分配和管理。IPAM Plugin作为CNI Plugin的一部分，与CNI Plugin协同工作。50、简述Kubernetes网络策略?为实现细粒度的容器间网络访问隔离策略，Kubernetes引入Network Policy。Network Policy的主要功能是对Pod间的网络通信进行限制和准入控制，设置允许访问或禁止访问的客户端Pod列表。Network Policy定义网络策略，配合策略控制器（Policy Controller）进行策略的实现。51、简述Kubernetes网络策略原理?Network Policy的工作原理主要为：policy controller需要实现一个API Listener，监听用户设置的Network Policy定义，并将网络访问规则通过各Node的Agent进行实际设置（Agent则需要通过CNI网络插件实现）。52、简述Kubernetes中flannel的作用?Flannel可以用于Kubernetes底层网络的实现，主要作用有：它能协助Kubernetes，给每一个Node上的Docker容器都分配互相不冲突的IP地址。它能在这些IP地址之间建立一个覆盖网络（Overlay Network），通过这个覆盖网络，将数据包原封不动地传递到目标容器内。53、简述Kubernetes Calico网络组件实现原理?Calico是一个基于BGP的纯三层的网络方案，与OpenStack、Kubernetes、AWS、GCE等云平台都能够良好地集成。Calico在每个计算节点都利用Linux Kernel实现了一个高效的vRouter来负责数据转发。每个vRouter都通过BGP协议把在本节点上运行的容器的路由信息向整个Calico网络广播，并自动设置到达其他节点的路由转发规则。Calico保证所有容器之间的数据流量都是通过IP路由的方式完成互联互通的。Calico节点组网时可以直接利用数据中心的网络结构（L2或者L3），不需要额外的NAT、隧道或者Overlay Network，没有额外的封包解包，能够节约CPU运算，提高网络效率。54、简述Kubernetes共享存储的作用?Kubernetes对于有状态的容器应用或者对数据需要持久化的应用，因此需要更加可靠的存储来保存应用产生的重要数据，以便容器应用在重建之后仍然可以使用之前的数据。因此需要使用共享存储。55、简述Kubernetes数据持久化的方式有哪些?Kubernetes通过数据持久化来持久化保存重要数据，常见的方式有：EmptyDir（空目录）：没有指定要挂载宿主机上的某个目录，直接由Pod内保部映射到宿主机上。类似于docker中的manager volume。场景：只需要临时将数据保存在磁盘上，比如在合并/排序算法中；作为两个容器的共享存储。特性：同个pod里面的不同容器，共享同一个持久化目录，当pod节点删除时，volume的数据也会被删除。emptyDir的数据持久化的生命周期和使用的pod一致，一般是作为临时存储使用。Hostpath：将宿主机上已存在的目录或文件挂载到容器内部。类似于docker中的bind mount挂载方式。特性：增加了pod与节点之间的耦合。PersistentVolume（简称PV）：如基于NFS服务的PV，也可以基于GFS的PV。它的作用是统一数据持久化目录，方便管理。56、简述Kubernetes PV和PVC?PV是对底层网络共享存储的抽象，将共享存储定义为一种“资源”。PVC则是用户对存储资源的一个“申请”。57、简述Kubernetes PV生命周期内的阶段?某个PV在生命周期中可能处于以下4个阶段（Phaes）之一。Available：可用状态，还未与某个PVC绑定。Bound：已与某个PVC绑定。Released：绑定的PVC已经删除，资源已释放，但没有被集群回收。Failed：自动资源回收失败。58、简述Kubernetes所支持的存储供应模式?Kubernetes支持两种资源的存储供应模式：静态模式（Static）和动态模式（Dynamic）。静态模式：集群管理员手工创建许多PV，在定义PV时需要将后端存储的特性进行设置。动态模式：集群管理员无须手工创建PV，而是通过StorageClass的设置对后端存储进行描述，标记为某种类型。此时要求PVC对存储的类型进行声明，系统将自动完成PV的创建及与PVC的绑定。59、简述Kubernetes CSI模型?Kubernetes CSI是Kubernetes推出与容器对接的存储接口标准，存储提供方只需要基于标准接口进行存储插件的实现，就能使用Kubernetes的原生存储机制为容器提供存储服务。CSI使得存储提供方的代码能和Kubernetes代码彻底解耦，部署也与Kubernetes核心组件分离，显然，存储插件的开发由提供方自行维护，就能为Kubernetes用户提供更多的存储功能，也更加安全可靠。CSI包括CSI Controller和CSI Node：CSI Controller的主要功能是提供存储服务视角对存储资源和存储卷进行管理和操作。CSI Node的主要功能是对主机（Node）上的Volume进行管理和操作。60、简述Kubernetes Worker节点加入集群的过程?通常需要对Worker节点进行扩容，从而将应用系统进行水平扩展。主要过程如下：在该Node上安装Docker、kubelet和kube-proxy服务； 然后配置kubelet和kubeproxy的启动参数，将Master URL指定为当前Kubernetes集群Master的地址，最后启动这些服务；通过kubelet默认的自动注册机制，新的Worker将会自动加入现有的Kubernetes集群中； Kubernetes Master在接受了新Worker的注册之后，会自动将其纳入当前集群的调度范围。61、简述Kubernetes Pod如何实现对节点的资源控制?Kubernetes集群里的节点提供的资源主要是计算资源，计算资源是可计量的能被申请、分配和使用的基础资源。当前Kubernetes集群中的计算资源主要包括CPU、GPU及Memory。CPU与Memory是被Pod使用的，因此在配置Pod时可以通过参数CPU Request及Memory Request为其中的每个容器指定所需使用的CPU与Memory量，Kubernetes会根据Request的值去查找有足够资源的Node来调度此Pod。通常，一个程序所使用的CPU与Memory是一个动态的量，确切地说，是一个范围，跟它的负载密切相关：负载增加时，CPU和Memory的使用量也会增加。62、简述Kubernetes Requests和Limits如何影响Pod的调度?当一个Pod创建成功时，Kubernetes调度器（Scheduler）会为该Pod选择一个节点来执行。对于每种计算资源（CPU和Memory）而言，每个节点都有一个能用于运行Pod的最大容量值。调度器在调度时，首先要确保调度后该节点上所有Pod的CPU和内存的Requests总和，不超过该节点能提供给Pod使用的CPU和Memory的最大容量值。63、简述Kubernetes Metric Service?在Kubernetes从1.10版本后采用Metrics Server作为默认的性能数据采集和监控，主要用于提供核心指标（Core Metrics），包括Node、Pod的CPU和内存使用指标。对其他自定义指标（Custom Metrics）的监控则由Prometheus等组件来完成。64、简述Kubernetes中，如何使用EFK实现日志的统一管理在Kubernetes集群环境中，通常一个完整的应用或服务涉及组件过多，建议对日志系统进行集中化管理，通常采用EFK实现。EFK是 Elasticsearch、Fluentd 和 Kibana 的组合，其各组件功能如下：Elasticsearch：是一个搜索引擎，负责存储日志并提供查询接口；Fluentd：负责从 Kubernetes 搜集日志，每个node节点上面的fluentd监控并收集该节点上面的系统日志，并将处理过后的日志信息发送给Elasticsearch；Kibana：提供了一个 Web GUI，用户可以浏览和搜索存储在 Elasticsearch 中的日志。通过在每台node上部署一个以DaemonSet方式运行的fluentd来收集每台node上的日志。Fluentd将docker日志目录/var/lib/docker/containers和/var/log目录挂载到Pod中，然后Pod会在node节点的/var/log/pods目录中创建新的目录，可以区别不同的容器日志输出，该目录下有一个日志文件链接到/var/lib/docker/contianers目录下的容器日志输出。65、简述Kubernetes如何进行优雅的节点关机维护?由于Kubernetes节点运行大量Pod，因此在进行关机维护之前，建议先使用kubectl drain将该节点的Pod进行驱逐，然后进行关机维护。66、简述Kubernetes集群联邦?Kubernetes集群联邦可以将多个Kubernetes集群作为一个集群进行管理。因此，可以在一个数据中心/云中创建多个Kubernetes集群，并使用集群联邦在一个地方控制/管理所有集群。67、简述Helm及其优势?Helm 是 Kubernetes 的软件包管理工具。类似 Ubuntu 中使用的apt、Centos中使用的yum 或者Python中的 pip 一样。Helm能够将一组K8S资源打包统一管理, 是查找、共享和使用为Kubernetes构建的软件的最佳方式。 Helm中通常每个包称为一个Chart，一个Chart是一个目录（一般情况下会将目录进行打包压缩，形成name-version.tgz格式的单一文件，方便传输和存储）。Helm优势在 Kubernetes中部署一个可以使用的应用，需要涉及到很多的 Kubernetes 资源的共同协作。使用helm则具有如下优势：统一管理、配置和更新这些分散的 k8s 的应用资源文件；分发和复用一套应用模板；将应用的一系列资源当做一个软件包管理。对于应用发布者而言，可以通过 Helm 打包应用、管理应用依赖关系、管理应用版本并发布应用到软件仓库。对于使用者而言，使用 Helm 后不用需要编写复杂的应用部署文件，可以以简单的方式在 Kubernetes 上查找、安装、升级、回滚、卸载应用程序。68、标签与标签选择器的作用是什么?标签可以附加在kubernetes任何资源对象之上的键值型数据，常用于标签选择器的匹配度检查，从而完成资源筛选标签选择器用于表达标签的查询条件或选择标准，Kubernetes API目前支持两个选择器：基于等值关系（equality-based）的标签选项器以及基于集合关系（set-based）的标签选择器。69、考虑一家拥有分布式系统的跨国公司，拥有大量数据中心，虚拟机和许多从事各种任务的员工。您认为这样公司如何以与Kubernetes一致的方式管理所有任务?正如我们所有人都知道IT部门推出了数千个容器，其任务在分布式系统中遍布全球众多节点。在这种情况下，公司可以使用能够为基于云的应用程序提供敏捷性，横向扩展功能和DevOps实践的东西。因此，该公司可以使用Kubernetes来定制他们的调度架构并支持多种容器格式。这使得容器任务之间的亲和性成为可能，从而提供更高的效率，并为各种容器网络解决方案和容器存储提供广泛支持。70、考虑一种情况，即公司希望通过维持最低成本来提高其效率和技术运营速度。您认为公司将如何实现这一目标?公司可以通过构建CI/CD管道来实现DevOps方法，但是这里可能出现的一个问题是配置可能需要一段时间才能启动并运行。因此，在实施CI/CD管道之后，公司的下一步应该是在云环境中工作。一旦他们开始处理云环境，他们就可以在集群上安排容器，并可以在Kubernetes的帮助下进行协调。这种方法将有助于公司缩短部署时间，并在各种环境中加快速度。71、假设一家公司想要修改它的部署方法，并希望建立一个更具可扩展性和响应性的平台。您如何看待这家公司能够实现这一目标以满足客户需求?为了给数百万客户提供他们期望的数字体验，公司需要一个可扩展且响应迅速的平台，以便他们能够快速地将数据发送到客户网站。现在，要做到这一点，公司应该从他们的私有数据中心（如果他们使用任何）转移到任何云环境，如AWS。不仅如此，他们还应该实现微服务架构，以便他们可以开始使用Docker容器。一旦他们准备好基础框架，他们就可以开始使用最好的编排平台，即Kubernetes。这将使团队能够自主地构建应用程序并快速交付它们。72、考虑一家拥有非常分散的系统的跨国公司，期待解决整体代码库问题。您认为公司如何解决他们的问题?那么，为了解决这个问题，我们可以将他们的单片代码库转移到微服务设计，然后每个微服务都可以被视为一个容器。因此，所有这些容器都可以在Kubernetes的帮助下进行部署和协调。73、我们所有人都知道，从单片到微服务的转变解决了开发方面的问题，但却增加了部署方面的问题。公司如何解决部署方面的问题?团队可以试验容器编排平台，例如Kubernetes，并在数据中心运行。因此，通过这种方式，公司可以生成模板化应用程序，在五分钟内部署它，并在此时将实际实例集中在暂存环境中。这种Kubernetes项目将有数十个并行运行的微服务，以提高生产率，即使节点出现故障，也可以立即重新安排，而不会影响性能。74、考虑一家拼车公司希望通过同时扩展其平台来增加服务器数量,公司如何有效地实现这种资源分配?这个问题的解决方案就是Kubernetes。Kubernetes确保资源得到有效优化，并且只使用特定应用程序所需的那些资源。因此，通过使用最佳容器编排工具，公司可以有效地实现资源分配。75、您认为公司如何处理服务器及其安装?公司可以采用集装箱化的概念。一旦他们将所有应用程序部署到容器中，他们就可以使用Kubernetes进行编排，并使用像Prometheus这样的容器监视工具来监视容器中的操作。因此，利用容器的这种使用，在数据中心中为它们提供更好的容量规划，因为它们现在将受到更少的限制，因为服务和它们运行的硬件之间存在抽象。76、考虑一种情况，公司希望向具有各种环境的客户提供所有必需的分发。您认为他们如何以动态的方式实现这一关键目标?该公司可以使用Docker环境，组建一个横截面团队，使用Kubernetes构建Web应用程序。这种框架将帮助公司实现在最短的时间内将所需产品投入生产的目标。因此，在这样的机器运行的情况下，公司可以向所有具有各种环境的客户发放电子邮件。77、假设公司希望在不同的云基础架构上运行各种工作负载，从裸机到公共云。公司将如何在不同界面的存在下实现这一目标?该公司可以将其基础设施分解为微服务，然后采用Kubernetes。这将使公司在不同的云基础架构上运行各种工作负载。78、什么是Google容器引擎?Google Container Engine（GKE）是Docker容器和集群的开源管理平台。这个基于 Kubernetes的引擎仅支持在Google的公共云服务中运行的群集。79、您如何看待公司从单—服务转向微服务并部署其服务容器?由于公司的目标是从单一应用程序转向微服务，它们最终可以逐个构建，并行构建，只需在后台切换配置。然后他们可以将这些内置微服务放在Kubernetes平台上。因此，他们可以从一次或两次迁移服务开始，并监控它们以确保一切运行稳定。一旦他们觉得一切顺利，他们就可以将其余的应用程序迁移到他们的Kubernetes集群中。80、什么是Headless Service？Headless Service类似于“普通”服务，但没有群集IP。此服务使您可以直接访问pod，而无需通过代理访问它。
前言一般来说大家都用etcd备份恢复k8s集群，但是有时候我们可能不小心删掉了一个namespace，假设这个ns里面有上百个服务，瞬间没了，怎么办？当然了，可以用CI/CD系统发布，但是时间会花费很久，这时候，vmvare的Velero出现了。velero可以帮助我们：灾备场景，提供备份恢复k8s集群的能力迁移场景，提供拷贝集群资源到其他集群的能力（复制同步开发，测试，生产环境的集群配置，简化环境配置）下面我就介绍一下如何使用 Velero 完成备份和迁移。Velero 地址：https://github.com/vmware-tanzu/veleroACK 插件地址：https://github.com/AliyunContainerService/velero-plugin下载 Velero 客户端Velero 由客户端和服务端组成，服务器部署在目标 k8s 集群上，而客户端则是运行在本地的命令行工具。前往 Velero 的 Release 页面 下载客户端，直接在 GitHub 上下载即可解压 release 包将 release 包中的二进制文件 velero 移动到 $PATH 中的某个目录下执行 velero -h 测试部署velero-plugin插件拉取代码git clone https://github.com/AliyunContainerService/velero-plugin 配置修改#修改`install/credentials-velero`文件，将新建用户中获得的`AccessKeyID`和`AccessKeySecret`填入，这里的 OSS EndPoint 为之前 OSS 的访问域名 ALIBABA_CLOUD_ACCESS_KEY_ID=<ALIBABA_CLOUD_ACCESS_KEY_ID> ALIBABA_CLOUD_ACCESS_KEY_SECRET=<ALIBABA_CLOUD_ACCESS_KEY_SECRET> ALIBABA_CLOUD_OSS_ENDPOINT=<ALIBABA_CLOUD_OSS_ENDPOINT> #修改 `install/01-velero.yaml`，将 OSS 配置填入： --- apiVersion: v1 kind: ServiceAccount metadata: namespace: velero name: velero --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: labels: component: velero name: velero roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: cluster-admin subjects: - kind: ServiceAccount name: velero namespace: velero --- apiVersion: velero.io/v1 kind: BackupStorageLocation metadata: labels: component: velero name: default namespace: velero spec: config: region: cn-beijing objectStorage: bucket: k8s-backup-test prefix: test provider: alibabacloud --- apiVersion: velero.io/v1 kind: VolumeSnapshotLocation metadata: labels: component: velero name: default namespace: velero spec: config: region: cn-beijing provider: alibabacloud --- apiVersion: extensions/v1beta1 kind: Deployment metadata: name: velero namespace: velero spec: replicas: 1 selector: matchLabels: deploy: velero template: metadata: annotations: prometheus.io/path: /metrics prometheus.io/port: "8085" prometheus.io/scrape: "true" labels: component: velero deploy: velero spec: serviceAccountName: velero containers: - name: velero # sync from velero/velero:v1.2.0 image: registry.cn-hangzhou.aliyuncs.com/acs/velero:v1.2.0 imagePullPolicy: IfNotPresent command: - /velero args: - server - --default-volume-snapshot-locations=alibabacloud:default env: - name: VELERO_SCRATCH_DIR value: /scratch - name: ALIBABA_CLOUD_CREDENTIALS_FILE value: /credentials/cloud volumeMounts: - mountPath: /plugins name: plugins - mountPath: /scratch name: scratch - mountPath: /credentials name: cloud-credentials initContainers: - image: registry.cn-hangzhou.aliyuncs.com/acs/velero-plugin-alibabacloud:v1.2-991b590 imagePullPolicy: IfNotPresent name: velero-plugin-alibabacloud volumeMounts: - mountPath: /target name: plugins volumes: - emptyDir: {} name: plugins - emptyDir: {} name: scratch - name: cloud-credentials secret: secretName: cloud-credentials k8s 部署 Velero 服务# 新建 namespace kubectl create namespace velero # 部署 credentials-velero 的 secret kubectl create secret generic cloud-credentials --namespace velero --from-file cloud=install/credentials-velero # 部署 CRD kubectl apply -f install/00-crds.yaml # 部署 Velero kubectl apply -f install/01-velero.yaml 备份测试这里，我们将使用velero备份一个集群内相关的resource，并在当该集群出现一些故障或误操作的时候，能够快速恢复集群resource， 首先我们用下面的yaml来部署：--- apiVersion: v1 kind: Namespace metadata: name: nginx-example labels: app: nginx --- apiVersion: apps/v1beta1 kind: Deployment metadata: name: nginx-deployment namespace: nginx-example spec: replicas: 2 template: metadata: labels: app: nginx spec: containers: - image: nginx:1.7.9 name: nginx ports: - containerPort: 80 --- apiVersion: v1 kind: Service metadata: labels: app: nginx name: my-nginx namespace: nginx-example spec: ports: - port: 80 targetPort: 80 selector: app: nginx 我们可以全量备份，也可以只备份需要备份的一个namespace，本处只备份一个namespace：nginx-example[rsync@velero-plugin]$ kubectl get pods -n nginx-example NAME READY STATUS RESTARTS AGE nginx-deployment-5c689d88bb-f8vsx 1/1 Running 0 6m31s nginx-deployment-5c689d88bb-rt2zk 1/1 Running 0 6m32s [rsync@velero]$ cd velero-v1.4.0-linux-amd64/ [rsync@velero-v1.4.0-linux-amd64]$ ll total 56472 drwxrwxr-x 4 rsync rsync 4096 Jun 1 15:02 examples -rw-r--r-- 1 rsync rsync 10255 Dec 10 01:08 LICENSE -rwxr-xr-x 1 rsync rsync 57810814 May 27 04:33 velero [rsync@velero-v1.4.0-linux-amd64]$ ./velero backup create nginx-backup --include-namespaces nginx-example --wait Backup request "nginx-backup" submitted successfully. Waiting for backup to complete. You may safely press ctrl-c to stop waiting - your backup will continue in the background. . Backup completed with status: Completed. You may check for more information using the commands `velero backup describe nginx-backup` and `velero backup logs nginx-backup`. 删除ns[rsync@velero-v1.4.0-linux-amd64]$ kubectl delete namespaces nginx-example namespace "nginx-example" deleted [rsync@velero-v1.4.0-linux-amd64]$ kubectl get pods -n nginx-example No resources found. 恢复[rsync@velero-v1.4.0-linux-amd64]$ ./velero restore create --from-backup nginx-backup --wait Restore request "nginx-backup-20200603180922" submitted successfully. Waiting for restore to complete. You may safely press ctrl-c to stop waiting - your restore will continue in the background. Restore completed with status: Completed. You may check for more information using the commands `velero restore describe nginx-backup-20200603180922` and `velero restore logs nginx-backup-20200603180922`. [rsync@velero-v1.4.0-linux-amd64]$ kubectl get pods -n nginx-example NAME READY STATUS RESTARTS AGE nginx-deployment-5c689d88bb-f8vsx 1/1 Running 0 5s nginx-deployment-5c689d88bb-rt2zk 0/1 ContainerCreating 0 5s 可以看到已经恢复了 另外迁移和备份恢复也是一样的，下面看一个特殊的，再部署一个项目，之后恢复会不会删掉新部署的项目。新建了一个tomcat容器[rsync@tomcat-test]$ kubectl get pods -n nginx-example NAME READY STATUS RESTARTS AGE nginx-deployment-5c689d88bb-f8vsx 1/1 Running 0 65m nginx-deployment-5c689d88bb-rt2zk 1/1 Running 0 65m tomcat-test-sy-677ff78f6b-rc5vq 1/1 Running 0 7s restore 一下[rsync@velero-v1.4.0-linux-amd64]$ ./velero restore create --from-backup nginx-backup Restore request "nginx-backup-20200603191726" submitted successfully. Run `velero restore describe nginx-backup-20200603191726` or `velero restore logs nginx-backup-20200603191726` for more details. [rsync@velero-v1.4.0-linux-amd64]$ kubectl get pods -n nginx-example NAME READY STATUS RESTARTS AGE nginx-deployment-5c689d88bb-f8vsx 1/1 Running 0 68m nginx-deployment-5c689d88bb-rt2zk 1/1 Running 0 68m tomcat-test-sy-677ff78f6b-rc5vq 1/1 Running 0 2m33s 可以看到没有覆盖 删除nginx的deployment，在restore[rsync@velero-v1.4.0-linux-amd64]$ kubectl delete deployment nginx-deployment -n nginx-example deployment.extensions "nginx-deployment" deleted [rsync@velero-v1.4.0-linux-amd64]$ kubectl get pods -n nginx-example NAME READY STATUS RESTARTS AGE tomcat-test-sy-677ff78f6b-rc5vq 1/1 Running 0 4m18s [rsync@velero-v1.4.0-linux-amd64]$ ./velero restore create --from-backup nginx-backup Restore request "nginx-backup-20200603191949" submitted successfully. Run `velero restore describe nginx-backup-20200603191949` or `velero restore logs nginx-backup-20200603191949` for more details. [rsync@velero-v1.4.0-linux-amd64]$ kubectl get pods -n nginx-example NAME READY STATUS RESTARTS AGE nginx-deployment-5c689d88bb-f8vsx 1/1 Running 0 2s nginx-deployment-5c689d88bb-rt2zk 0/1 ContainerCreating 0 2s tomcat-test-sy-677ff78f6b-rc5vq 1/1 Running 0 4m49s 可以看到，对我们的tomcat项目是没影响的。 结论：velero恢复不是直接覆盖，而是会恢复当前集群中不存在的resource，已有的resource不会回滚到之前的版本，如需要回滚，需在restore之前提前删除现有的resource。高级用法可以设置一个周期性定时备份# 每日1点进行备份 velero create schedule <SCHEDULE NAME> --schedule="0 1 * * *" # 每日1点进行备份，备份保留48小时 velero create schedule <SCHEDULE NAME> --schedule="0 1 * * *" --ttl 48h # 每6小时进行一次备份 velero create schedule <SCHEDULE NAME> --schedule="@every 6h" # 每日对 web namespace 进行一次备份 velero create schedule <SCHEDULE NAME> --schedule="@every 24h" --include-namespaces web 定时备份的名称为：`<SCHEDULE NAME>-<TIMESTAMP>`，恢复命令为：`velero restore create --from-backup <SCHEDULE NAME>-<TIMESTAMP>`。 如需备份恢复持久卷，备份如下：velero backup create nginx-backup-volume --snapshot-volumes --include-namespaces nginx-example 该备份会在集群所在region给云盘创建快照（当前还不支持NAS和OSS存储），快照恢复云盘只能在同region完成。恢复命令如下：velero restore create --from-backup nginx-backup-volume --restore-volumes 删除备份方法一，通过命令直接删除velero delete backups default-backup 方法二，设置备份自动过期，在创建备份时，加上TTL参数velero backup create <BACKUP-NAME> --ttl <DURATION> 还可为资源添加指定标签，添加标签的资源在备份的时候被排除。# 添加标签 kubectl label -n <ITEM_NAMESPACE> <RESOURCE>/<NAME> velero.io/exclude-from-backup=true # 为 default namespace 添加标签 kubectl label -n default namespace/default velero.io/exclude-from-backup=true 参考链接https://yq.aliyun.com/articles/705007?spm=a2c4e.11163080.searchblog.140.1a8b2ec1TYJPbF 院长技术
基于自定义指标除了基于 CPU 和内存来进行自动扩缩容之外，我们还可以根据自定义的监控指标来进行。这个我们就需要使用 Prometheus Adapter，Prometheus 用于监控应用的负载和集群本身的各种指标，Prometheus Adapter 可以帮我们使用 Prometheus 收集的指标并使用它们来制定扩展策略，这些指标都是通过 APIServer 暴露的，而且 HPA 资源对象也可以很轻易的直接使用。下面来看具体怎么实现的！部署应用首先，我们部署一个示例应用，在该应用程序上测试 Prometheus 指标自动缩放，资源清单文件如下所示：（podinfo.yaml）--- apiVersion: apps/v1 kind: Deployment metadata: name: podinfo spec: selector: matchLabels: app: podinfo replicas: 1 template: metadata: labels: app: podinfo annotations: prometheus.io/scrape: 'true' spec: containers: - name: podinfod image: stefanprodan/podinfo:0.0.1 imagePullPolicy: Always command: - ./podinfo - -port=9898 - -logtostderr=true - -v=2 volumeMounts: - name: metadata mountPath: /etc/podinfod/metadata readOnly: true ports: - containerPort: 9898 protocol: TCP readinessProbe: httpGet: path: /readyz port: 9898 initialDelaySeconds: 1 periodSeconds: 2 failureThreshold: 1 livenessProbe: httpGet: path: /healthz port: 9898 initialDelaySeconds: 1 periodSeconds: 3 failureThreshold: 2 resources: requests: memory: "32Mi" cpu: "1m" limits: memory: "256Mi" cpu: "100m" volumes: - name: metadata downwardAPI: items: - path: "labels" fieldRef: fieldPath: metadata.labels - path: "annotations" fieldRef: fieldPath: metadata.annotations --- apiVersion: v1 kind: Service metadata: name: podinfo labels: app: podinfo spec: type: NodePort ports: - port: 9898 targetPort: 9898 nodePort: 31198 protocol: TCP selector: app: podinfo 接下来我们将 Prometheus-Adapter 安装到集群中，这里选用helm安装，当然也可以直接yaml文件安装。Prometheus-Adapter规则Prometheus-Adapter 规则大致 可以分为以下几个部分：seriesQuery：查询 Prometheus 的语句，通过这个查询语句查询到的所有指标都可以用于 HPA seriesFilters：查询到的指标可能会存在不需要的，可以通过它过滤掉。 resources：通过 seriesQuery 查询到的只是指标，如果需要查询某个 Pod 的指标，肯定要将它的名称和所在的命名空间作为指标的标签进行查询，resources 就是将指标的标签和 k8s 的资源类型关联起来，最常用的就是 pod 和 namespace。有两种添加标签的方式，一种是 overrides，另一种是 template。 overrides：它会将指标中的标签和 k8s 资源关联起来。上面示例中就是将指标中的 pod 和 namespace 标签和 k8s 中的 pod 和 namespace 关联起来，因为 pod 和 namespace 都属于核心 api 组，所以不需要指定 api 组。当我们查询某个 pod 的指标时，它会自动将 pod 的名称和名称空间作为标签加入到查询条件中。比如 pod: {group: "apps", resource: "deployment"} 这么写表示的就是将指标中 podinfo 这个标签和 apps 这个 api 组中的 deployment 资源关联起来； template：通过 go 模板的形式。比如template: "kube_<<.Group>>_<<.Resource>>" 这么写表示，假如 <<.Group>> 为 apps，<<.Resource>> 为 deployment，那么它就是将指标中 kube_apps_deployment 标签和 deployment 资源关联起来。 name：用来给指标重命名的，之所以要给指标重命名是因为有些指标是只增的，比如以 total 结尾的指标。这些指标拿来做 HPA 是没有意义的，我们一般计算它的速率，以速率作为值，那么此时的名称就不能以 total 结尾了，所以要进行重命名。 matches：通过正则表达式来匹配指标名，可以进行分组 as：默认值为 $1，也就是第一个分组。as 为空就是使用默认值的意思。 metricsQuery：这就是 Prometheus 的查询语句了，前面的 seriesQuery 查询是获得 HPA 指标。当我们要查某个指标的值时就要通过它指定的查询语句进行了。可以看到查询语句使用了速率和分组，这就是解决上面提到的只增指标的问题。 Series：表示指标名称 LabelMatchers：附加的标签，目前只有 pod 和 namespace 两种，因此我们要在之前使用 resources 进行关联 GroupBy：就是 pod 名称，同样需要使用 resources 进行关联。 安装我们新建 hpa-prome-adapter-values.yaml 文件覆盖默认的 Values 值 ，安装Prometheus-Adapter，我用的helm2文件如下：rules: default: false custom: - seriesQuery: 'http_requests_total' resources: overrides: kubernetes_namespace: resource: namespace kubernetes_pod_name: resource: pod name: matches: "^(.*)_total" as: "${1}_per_second" metricsQuery: (sum(rate(<<.Series>>{<<.LabelMatchers>>}[1m])) by (<<.GroupBy>>)) prometheus: url: http://prometheus-clusterip.monitor.svc.cluster.local 安装helm repo add apphub https://apphub.aliyuncs.com/ helm install --name prome-adapter --namespace monitor -f hpa-prome-adapter-values.yaml apphub/prometheus-adapter 等一小会儿，安装完成后，可以使用下面的命令来检测是否生效了：[root@prometheus]# kubectl get --raw="/apis/custom.metrics.k8s.io/v1beta1" | jq { "kind": "APIResourceList", "apiVersion": "v1", "groupVersion": "custom.metrics.k8s.io/v1beta1", "resources": [ { "name": "namespaces/http_requests_per_second", "singularName": "", "namespaced": false, "kind": "MetricValueList", "verbs": [ "get" ] }, { "name": "pods/http_requests_per_second", "singularName": "", "namespaced": true, "kind": "MetricValueList", "verbs": [ "get" ] } ] } 我们可以看到 http_requests_per_second 指标可用。 现在，让我们检查该指标的当前值：[root@prometheus]# kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1/namespaces/default/pods/*/http_requests_per_second" | jq . { "kind": "MetricValueList", "apiVersion": "custom.metrics.k8s.io/v1beta1", "metadata": { "selfLink": "/apis/custom.metrics.k8s.io/v1beta1/namespaces/default/pods/%2A/http_requests_per_second" }, "items": [ { "describedObject": { "kind": "Pod", "namespace": "default", "name": "podinfo-5cdc457c8b-99xtw", "apiVersion": "/v1" }, "metricName": "http_requests_per_second", "timestamp": "2020-06-02T12:01:01Z", "value": "888m", "selector": null }, { "describedObject": { "kind": "Pod", "namespace": "default", "name": "podinfo-5cdc457c8b-b7pfz", "apiVersion": "/v1" }, "metricName": "http_requests_per_second", "timestamp": "2020-06-02T12:01:01Z", "value": "888m", "selector": null } ] } 下面部署hpa对象apiVersion: autoscaling/v2beta1 kind: HorizontalPodAutoscaler metadata: name: podinfo spec: scaleTargetRef: apiVersion: extensions/v1beta1 kind: Deployment name: podinfo minReplicas: 2 maxReplicas: 5 metrics: - type: Pods pods: metricName: http_requests_per_second targetAverageValue: 3 部署之后，可见：[root@prometheus-adapter]# kubectl get hpa NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE podinfo Deployment/podinfo 911m/10 2 5 2 70s [root@prometheus-adapter]# kubectl describe hpa Name: podinfo Namespace: default Labels: <none> Annotations: kubectl.kubernetes.io/last-applied-configuration: {"apiVersion":"autoscaling/v2beta1","kind":"HorizontalPodAutoscaler","metadata":{"annotations":{},"name":"podinfo","namespace":"default"},... CreationTimestamp: Tue, 02 Jun 2020 17:53:14 +0800 Reference: Deployment/podinfo Metrics: ( current / target ) "http_requests_per_second" on pods: 911m / 10 Min replicas: 2 Max replicas: 5 Deployment pods: 2 current / 2 desired Conditions: Type Status Reason Message ---- ------ ------ ------- AbleToScale True ScaleDownStabilized recent recommendations were higher than current one, applying the highest recent recommendation ScalingActive True ValidMetricFound the HPA was able to successfully calculate a replica count from pods metric http_requests_per_second 做一个ab压测：ab -n 2000 -c 5 http://sy.test.com:31198/ 观察下hpa变化：Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal SuccessfulRescale 9m29s horizontal-pod-autoscaler New size: 3; reason: pods metric http_requests_per_second above target Normal SuccessfulRescale 9m18s horizontal-pod-autoscaler New size: 4; reason: pods metric http_requests_per_second above target Normal SuccessfulRescale 3m34s horizontal-pod-autoscaler New size: 3; reason: All metrics below target Normal SuccessfulRescale 3m4s horizontal-pod-autoscaler New size: 2; reason: All metrics below target 发现触发扩容动作了，副本到了4，并且压测结束后，过了5分钟左右，又恢复到最小值2个。参考链接:https://github.com/directxman12/k8s-prometheus-adapter院长技术
https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands 入口导航在线命令查询入口