首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >【Enjoy Kubernetes】2. 每位开发人员都应该了解的17 个Kubernetes最佳实践

【Enjoy Kubernetes】2. 每位开发人员都应该了解的17 个Kubernetes最佳实践

原创
作者头像
于顾而言SASE
发布2024-12-27 16:56:47
发布2024-12-27 16:56:47
34700
代码可运行
举报
文章被收录于专栏:golang与云原生golang与云原生
运行总次数:0
代码可运行

在本文中,我将介绍一些在使用Kubernetes(K8s)时使用的最佳实践。

作为最流行的容器编排系统,K8s是现代云工程师应该掌握的一项技能。K8s是一个众所周知的复杂系统,因此了解您应该做什么,不应该做什么,这会对您的部署如虎添翼。

这些建议涵盖了应用程序开发、治理和集群配置这三个广泛的类别中的常见问题。

1. Use namespaces

在K8s中,命名空间对于组织对象、在集群内创建逻辑分区以及出于安全目的是非常重要的。默认情况下,K8s集群中有三个命名空间,分别是default、kube-public和kube-system。

命名空间主要是起到一个隔离作用:

  • 多租户环境
  • 环境分离
  • 实施基于角色的访问控制

RBAC可以用于控制对特定命名空间的访问,以限制组的访问权限,控制可能发生的任何错误的影响范围,例如,开发人员组可能只能访问名为dev的命名空间,并且无法访问生产命名空间。限制不同团队对不同命名空间的访问能力可以避免重复工作或资源冲突。

  • 测试

还可以针对命名空间配置LimitRange对象,以定义部署在命名空间中的容器的标准大小。ResourceQuotas也可以用于限制命名空间内所有容器的总资源消耗。网络策略可以用于针对命名空间限制Pod之间的流量。

1.1. 常用命令

那namespace的相关操作有哪些呢?

代码语言:javascript
代码运行次数:0
运行
复制
# View existing namespaces
kubectl get namespaces
代码语言:javascript
代码运行次数:0
运行
复制
# List the pods contained in a namespace
kubectl get pods --namespace ingress-nginx

# Note the short format for namespace can be used (-n)
kubectl get pods -n ingress-nginx
代码语言:javascript
代码运行次数:0
运行
复制
# Create a new namespace called jacks-blog
kubectl create namespace jacks-blog

# Delete a namespace called jacks-blog
kubectl delete namespace jacks-blog
代码语言:javascript
代码运行次数:0
运行
复制
# Describe a namespace
kubectl describe namespace nginx-ingress

1.2. 最佳实践

  1. 为特定用例创建命名空间,例如环境分离、多租户RBAC、测试等。通过查看命名空间名称,您应该能够轻松地识别其目的 。 同时, 您应该避免使用以kube-为前缀的命名空间,因为此前缀保留用于Kubernetes系统命名空间。
  2. 在命名空间级别实施资源配额和限制是必要的,以确保资源对CPU和内存有限制,避免超载集群。
  3. 实施基于角色的访问控制是一种最佳实践,使用最小权限访问方法对于每个IT工具或产品都是必要的,Kubernetes也不例外。您需要为您的命名空间创建角色和角色绑定,并确保只有授权用户可以访问它们。
  4. 实施网络策略类似于安全组/网络访问控制列表规则。通过网络策略,您可以控制Pod之间的通信,并限制不需要互动的服务之间的连接。
  5. 利用监控和日志记录作为集群的一部分进行配置,并基于命名空间特定指标设置警报。这有助于监视集群的健康状况并检测异常,同时让您有机会及时解决这些问题。

2. Use readiness and liveness probes

就绪探针和存活探针本质上是健康检查的一种类型。这些是K8s中要利用的另一个非常重要的概念。

就绪探针确保只有在Pod准备好提供请求时,请求才会被定向到该Pod。如果它尚未准备就绪,请求将被定向到其他地方。对于每个容器定义就绪探针非常重要,因为在K8s中没有为这些设置默认值。

例如,如果一个Pod需要20秒才能启动,并且缺少就绪探针,那么在启动期间定向到该Pod的任何流量都会导致失败。就绪探针应该是独立的,不考虑对其他服务的任何依赖,比如后端数据库或缓存服务。

存活探针测试应用程序是否正在运行,以标记其为健康状态。例如,可以测试Web应用程序的特定路径以确保其响应。如果未响应,Pod将不会被标记为健康,探针失败将导致kubelet启动一个新的Pod,然后再次进行测试。这种类型的探针用作在进程变得无响应时的恢复机制。

2.1. 常用命令

代码语言:javascript
代码运行次数:0
运行
复制
apiVersion: v1
kind: Pod
metadata:
  labels:
    test: liveness
  name: liveness-exec
spec:
  containers:
  - name: liveness
    image: registry.k8s.io/liveness:0.1
    ports:
    - containerPort: 8080
    livenessProbe:
      exec:
        command:
        - cat
        - /usr/share/liveness/html/index.html
      initialDelaySeconds: 5
      periodSeconds: 5

如果文件不存在,pod将会被杀死后重启

代码语言:javascript
代码运行次数:0
运行
复制
apiVersion: v1
kind: Pod
metadata:
  name: liveness
  labels:
    app: liveness-tcp
spec:
  containers:
  - name: liveness
    image: registry.k8s.io/liveness:0.1
    ports:
    - containerPort: 8080
    livenessProbe:
      tcpSocket:
        port: 8080
      initialDelaySeconds: 5
      periodSeconds: 5

kubelet将尝试与改特定port建立socket如果失败,pod将会被杀死后重启

代码语言:javascript
代码运行次数:0
运行
复制
apiVersion: v1
kind: Pod
metadata:
  labels:
    test: liveness
  name: liveness-http
spec:
  containers:
  - name: liveness
    image: registry.k8s.io/liveness:0.1
    livenessProbe:
      httpGet:
        path: /health
        port: 8080
        httpHeaders:
        - name: Custom-Header
          value: ItsAlive
      initialDelaySeconds: 5
      periodSeconds: 5

which will send an HTTP GET request on port 8080 to the /health path. If a code between 200–400 is returned, the probe is considered successful.

代码语言:javascript
代码运行次数:0
运行
复制
apiVersion: v1
kind: Pod
metadata:
  labels:
    test: liveness
  name: liveness-gRPC
spec:
  containers:
  - name: liveness
    image: registry.k8s.io/liveness:0.1
    ports:
    - containerPort: 2379
    livenessProbe:
      grpc:
        port: 2379
      initialDelaySeconds: 5
      periodSeconds: 5

用grpc协议检测2379是否打开

2.2. 最佳实践

  1. 保持存活探针简单和轻量。如果配置错误,探针可能会影响应用程序性能,如果它们运行得太频繁或导致容器长时间处于不健康状态。一些容器不需要探针,因为它们执行简单操作并快速终止,因此应避免不必要的探针配置。
  2. 如果存活探针完成所需时间过长,Kubernetes可能会认为应用程序未运行并重新启动它,即使实际上它仍在运行,因此建议设置一个现实和适当的超时值。检查探针的命令、API请求或gRPC调用实际完成所需的时间,然后设置一个带有小额外时间缓冲的值。
  3. 如果存活探针失败了特定次数,Kubernetes将重新启动应用程序。为存活探针设置一个失败阈值,以避免不必要地重新启动应用程序。
  4. 检查探针之后应用的容器重启策略是否已应用。这意味着您的容器需要restartPolicy: Always(默认值)或restartPolicy: OnFailure,这样Kubernetes就可以在探针失败后重新启动它们。使用Never策略将使容器保持在失败状态。
  5. 使用kubectl命令行工具测试您的探针,并确保它们已正确配置。 为您的应用程序选择适当的探针类型。例如,对于Web应用程序,使用HTTP探针,而对于数据库,则更适合使用TCP探针。探针的命令或HTTP请求的目标通常应独立于您的主要应用程序,以便即使在失败条件下也能完成运行。

3. Use autoscaling

在适当的情况下,可以使用自动缩放来动态调整Pod的数量(水平Pod自动缩放器)、Pod消耗的资源量(垂直自动缩放器)或集群中的节点数量(集群自动缩放器),具体取决于资源的需求。

水平Pod自动缩放器还可以根据CPU需求来调整replication controller, replica set, or statefulset的规模。

使用缩放也带来一些挑战,比如不要将持久数据存储在容器的本地文件系统中,因为这会阻止水平自动缩放。相反,可以使用PersistentVolume。。

当集群上存在高度变化的工作负载,可能根据需求在不同时间需要不同数量的资源时,集群自动缩放器就非常有用。自动删除未使用的节点也是节省成本的好方法。

具体pvc的操作如下:

  1. 先检查你集群的存储类型
代码语言:javascript
代码运行次数:0
运行
复制
$ kubectl get storageclass
NAME                 PROVISIONER                RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
standard (default)   k8s.io/minikube-hostpath   Delete          Immediate           false                  7d2h

这个就是主机存储
  1. 创建pv
代码语言:javascript
代码运行次数:0
运行
复制
apiVersion: v1
kind: PersistentVolume
metadata:
  name: demo-pv
spec:
  accessModes:
    - ReadWriteOnce
  capacity:
    storage: 1Gi
  storageClassName: standard
  hostPath:
    path: /tmp/demo-pv

$ kubectl apply -f pv.yaml
persistentvolume/demo-pv created

$ kubectl get pv
NAME      CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
demo-pv   1Gi        RWO            Retain           Available           standard                113s
  1. 创建pvc
代码语言:javascript
代码运行次数:0
运行
复制
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-dynamic
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
  storageClassName: standard


$ kubectl apply -f pvc-dynamic.yaml
persistentvolumeclaim/pvc-dynamic created

$ kubectl get pv
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                 STORAGECLASS   REASON   AGE
demo-pv                                    1Gi        RWO            Retain           Bound    default/demo-pvc      standard                33m
pvc-fd022049-eabf-415c-937a-94927c84ef6f   1Gi        RWO            Delete           Bound    default/pvc-dynamic   standard                

#Dynamically created PVs default to using the Delete retention policy. This means the PV is automatically deleted when the PVC is destroyed.
  1. pod中使用pvc
代码语言:javascript
代码运行次数:0
运行
复制
apiVersion: v1
kind: Pod
metadata:
  name: pvc-pod
spec:
  containers:
    - name: pvc-pod-container
      image: nginx:latest
      volumeMounts:
        - mountPath: /data
          name: data
  volumes:
    - name: data
      persistentVolumeClaim:
        claimName: pvc-dynamic

pvc存储是独立于pod的

使用RBAC保护存储资源。配置集群的RBAC授权策略,以帮助保护您的PV和PVC免受意外或恶意更改和删除。

始终为您的持久卷(PV)指定存储类。没有存储类的PV将使用集群中的默认存储类,如果值发生更改或未设置,可能会导致不可预测的行为。

4. Use resource requests and limits

资源请求和限制(容器中可使用的资源的最小和最大量)应设置以避免容器在没有分配所需资源的情况下启动,或者集群耗尽可用资源。

没有限制,Pod可能会使用超过所需资源的资源,导致总可用资源减少,这可能会影响集群上的其他应用程序。节点可能会崩溃,并且调度器可能无法正确放置新的Pod。

如果没有请求,如果无法为应用程序分配足够的资源,则在尝试启动或执行时可能会失败。

资源请求和限制定义了以毫核和mebibytes为单位的CPU和内存量。请注意,如果您的进程超过内存限制,进程将被终止,因此在所有情况下设置这个值可能并不总是合适。如果您的容器超过CPU限制,进程将被限制。

5. Deploy your pods as part of a Deployment, DaemonSet, ReplicaSet, or StatefulSet across nodes.

单个Pod永远不应该单独运行。为了提高容错性,它们应始终作为部署(Deployment)、守护进程集(DaemonSet)、副本集(ReplicaSet)或有状态集(StatefulSet)的一部分。然后,可以使用部署中的反亲和规则在节点之间部署Pod,以避免所有Pod在单个节点上运行,这可能会导致宕机时间。

6. Use multiple nodes

在单个节点上运行K8s如果您想构建容错性并不是一个好主意。您的集群应该使用多个节点,以便工作负载可以在它们之间分配。

7. RBAC

角色(Role):角色是一组权限集合,允许用户对一组定义的Kubernetes资源类型(如Pod、部署和命名空间)执行特定操作(动词,例如“get”、“create”和“delete”)。角色是有命名空间的对象;它们授予的权限仅适用于角色所属的命名空间内。

集群角色(ClusterRole):集群角色与角色类似,但是它们是用于集群级资源的非命名空间替代方案。您需要使用集群角色来控制对不属于任何命名空间的对象(如节点)的访问。集群角色还允许您全局地访问跨所有命名空间的有命名空间资源,例如集群中的每个Pod。

角色绑定(RoleBinding):角色绑定表示您的角色与用户或服务账户之间的关联。角色绑定允许您引用一个角色,然后将这些权限授予一个或多个用户(称为主体)。

集群角色绑定(ClusterRoleBinding):集群角色绑定类似于角色绑定,但是针对的是集群角色资源而不是角色。

在您的K8s集群中使用RBAC对于正确保护您的系统至关重要。用户、组和服务账户可以被分配权限来执行特定命名空间(Role)或整个集群(ClusterRole)上的许可操作。每个角色可以有多个权限。为了将定义的角色与用户、组或服务账户联系起来,将使用RoleBinding或ClusterRoleBinding对象。

RBAC角色应该设置为遵循最小权限原则,即只授予所需的权限。例如,管理员组可能对所有资源具有访问权限,而您的运维组可能可以部署但无法读取机密信息。

7.1. 常用命令

  1. 打开RBAC开关
代码语言:javascript
代码运行次数:0
运行
复制
$ kubectl api-versions | grep rbac
rbac.authorization.k8s.io/v1

To manually enable RBAC support, you must start the Kubernetes API server with the --authorization-mode=RBAC flag set:

代码语言:javascript
代码运行次数:0
运行
复制
$ kube-apiserver --authorization-mode=RBAC
  1. 创建服务账户
代码语言:javascript
代码运行次数:0
运行
复制
$ kubectl create serviceaccount demo-user
serviceaccount/demo-user created

创建认证token

代码语言:javascript
代码运行次数:0
运行
复制
$ TOKEN=$(kubectl create token demo-user)

kube config文件添加认证

代码语言:javascript
代码运行次数:0
运行
复制
$ kubectl config set-credentials demo-user --token=$TOKEN
User "demo-user" set.

设置context

代码语言:javascript
代码运行次数:0
运行
复制
$ kubectl config set-context demo-user-context --cluster=default --user=demo-user
Context "demo-user-context" created.

检查当前context,方便后续切回

代码语言:javascript
代码运行次数:0
运行
复制
$ kubectl config current-context
default
  1. 创建角色
代码语言:javascript
代码运行次数:0
运行
复制
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: demo-role
  namespace: default
rules:
  - apiGroups:
      - ""
    resources:
      - pods
    verbs:
      - get
      - list
      - create
      - update
      
$ kubectl apply -f role.yaml
role.rbac.authorization.k8s.io/demo-role created
  1. 角色绑定
代码语言:javascript
代码运行次数:0
运行
复制
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: demo-role-binding
  namespace: default
roleRef: # 啥角色
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: demo-role
subjects: # 绑定了哪些用户
  - namespace: default
    kind: ServiceAccount
    name: demo-user
    
$ kubectl apply -f rolebinding.yaml
rolebinding.rbac.authorization.k8s.io/demo-role-binding created

7.2. 最佳实践

  • 始终启用RBAC 在每个生产Kubernetes集群中都应启用RBAC。限制默认管理员帐户的使用;相反,确保每个用户、应用程序和集成都有自己的身份和独立角色。
  • 保持角色精确 角色应尽可能精确,只包含执行它们代表的任务所需的最小权限集。尝试为用户分配多个小角色,而不是一个难以维护的大角色。这样可以保持您的攻击面小,减少与被入侵账户相关的风险。
  • 理解角色与集群角色的区别 您创建的大多数RBAC规则应为角色。这些提供了对各个命名空间内权限的狭窄范围限定。如果要分配对集群级资源(如节点)的访问权限,则需要使用集群角色,但对于诸如Pod之类的有命名空间资源,应谨慎使用它们——它们将提供对所有命名空间中的所有资源的访问权限。
  • 定期审查并删除未使用的角色 您应定期审计角色、角色绑定、集群角色和集群角色绑定,并删除任何不再使用的内容。这可以防止过度授予特权的账户仍然存在,并且可以更轻松地查看谁可以访问不同的资源。
  • 避免在角色中使用通配符 角色允许您在其资源和动词字段中使用*通配符。这是危险的,因为这意味着用户将自动获得对集群中添加的任何新资源类型的访问权限,除了当前存在的资源。

8. Host your Kubernetes cluster externally (use a cloud service)

在自己的硬件上托管K8s集群可能是一个复杂的任务。云服务提供K8s集群作为平台即服务(PaaS),如Azure上的AKS(Azure Kubernetes Service)或亚马逊网络服务上的EKS(Amazon Elastic Kubernetes Service)。利用这一点意味着基础设施将由您的云提供商管理,以及围绕扩展您的集群的任务,如添加和移除节点,可以更容易地实现,从而使您的工程师可以专注于管理K8s集群本身上运行的内容。

9. Upgrade your kubernetes version

除了引入新功能外,新的K8s版本还包括漏洞和安全修复程序,这使得在集群上运行最新版本的K8s至关重要。对于较旧版本的支持可能不如较新版本。

然而,迁移到新版本应该谨慎对待,因为某些功能可能会被弃用,同时还会添加新功能。此外,在升级之前,应检查在您的集群上运行的应用程序是否与新的目标版本兼容。

10. Monitor your cluster resources and audit policy logs

监控K8s控制平面中的组件对于控制资源消耗至关重要。控制平面是K8s的核心,这些组件使系统保持运行,因此对于正确的K8s操作至关重要。Kubernetes API、kubelet、etcd、controller-manager、kube-proxy和kube-dns构成了控制平面。

控制平面组件可以输出以Prometheus最常见的K8s监控工具可以使用的格式的指标。

应该使用自动化监控工具,而不是手动管理警报。

在启动kube-apiserver时可以打开K8s中的审计日志,以便使用您选择的工具进行更深入的调查。审计日志将详细记录对K8s API的所有请求,并应定期检查是否存在可能在集群上造成问题的问题。Kubernetes集群的默认策略在audit-policy.yaml文件中定义,可以根据需要进行修改。

可以使用日志聚合工具(例如Azure Monitor)将日志从AKS发送到日志分析工作区,以便将来使用Kusto查询进行详细调查。在AWS中,可以使用Cloudwatch。第三方工具还提供更深入的监控功能,如Dynatrace和Datadog。

最后,应该为日志设定一个明确的保留期限,通常为30-45天。

11. Use a version control system

K8s配置文件应该在版本控制系统(VCS)中进行控制。这样可以带来一系列好处,包括增强安全性,启用更改审计跟踪,并提高集群的稳定性。应该为所做的任何更改设置批准门,以便团队可以在将更改提交到主分支之前进行同行审查。

12. Use a git-based workflow (GitOps)

成功部署K8s需要考虑团队使用的工作流程。使用基于git的工作流程通过CI/CD(持续集成/持续交付)管道的自动化,可以提高应用程序部署效率和速度。CI/CD还将提供部署的审计跟踪。Git应该是所有自动化的唯一真相来源,并将实现K8s集群的统一管理。您还可以考虑使用专用的基础设施交付平台,如Spacelift,该平台最近引入了对Kubernetes的支持。

13. Reduce the size of your containers

较小的镜像大小将有助于加快构建和部署速度,并减少容器在K8s集群中消耗的资源量。应尽可能删除不必要的软件包,并优先选择小型操作系统分发镜像,如Alpine。较小的镜像可以比较大的镜像更快地拉取,并且占用更少的存储空间。

遵循这种方法还将提供安全性方面的好处,因为恶意行为者的攻击向量将更少。

14. Organize your objects with labels

K8s标签是附加到对象的键值对,以便组织您的集群资源。标签应该是有意义的元数据,提供一种跟踪K8s系统中不同组件交互方式的机制。

官方K8s文档中推荐的Pod标签包括名称、实例、版本、组件、部分和管理者。

标签也可以类似于在云环境中在资源上使用标记,以跟踪与业务相关的事物,如对象所有权和对象应属于的环境。

此外,建议使用标签详细说明安全要求,包括保密性和合规性。

15. Use network policies

应该使用网络策略来限制K8s集群中对象之间的流量。默认情况下,所有容器都可以在网络中互相通信,如果恶意行为者访问容器,则会导致安全风险,允许它们遍历集群中的对象。网络策略可以控制IP和端口级别的流量,类似于云平台中安全组的概念,以限制对资源的访问。通常,默认情况下应拒绝所有流量,然后应设置允许规则以允许所需流量。

16. Use a firewall

除了使用网络策略在K8s集群中限制内部流量外,还应该在K8s集群前放置防火墙,以限制外部世界对API服务器的请求。应该将IP地址列入白名单,并限制开放端口。

17. Use declarative configuration

声明性配置涉及在YAML或JSON文件中指定资源的期望状态,然后使用诸如kubectl apply之类的工具将这些配置应用于您的集群。

您描述资源应该是什么样子,而不是发出命令来实现特定状态。声明性配置是幂等的,这意味着多次应用相同的配置会产生相同的期望状态。

Reference

https://spacelift.io/blog/kubernetes-best-practices

https://spacelift.io/blog/kubernetes-namespaces

https://spacelift.io/blog/kuber

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. Use namespaces
  • 1.1. 常用命令
  • 1.2. 最佳实践
  • 2. Use readiness and liveness probes
  • 2.1. 常用命令
  • 2.2. 最佳实践
  • 3. Use autoscaling
  • 4. Use resource requests and limits
  • 5. Deploy your pods as part of a Deployment, DaemonSet, ReplicaSet, or StatefulSet across nodes.
  • 6. Use multiple nodes
  • 7. RBAC
  • 7.1. 常用命令
  • 7.2. 最佳实践
  • 8. Host your Kubernetes cluster externally (use a cloud service)
  • 9. Upgrade your kubernetes version
  • 10. Monitor your cluster resources and audit policy logs
  • 11. Use a version control system
  • 12. Use a git-based workflow (GitOps)
  • 13. Reduce the size of your containers
  • 14. Organize your objects with labels
  • 15. Use network policies
  • 16. Use a firewall
  • 17. Use declarative configuration
  • Reference
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档