[K8S – Helm]近期开发Helm包的一些理解 – 202503

相比于一开始作为Web前端工程师入职公司,现在我的工作内容已经远远超出了当时的范畴,JAVA的后端开发到Linux单机、K8S云原生的运维,最近是go开发一些项目需要的Agent应用。

而在将公司项目开发的Agent应用通过Helm安装到客户正式环境集群时,遇到了要求标明资源限制和镜像拉取凭证的问题,我将在这篇文章里讲讲我对这两个问题的理解。

集群要求标明资源限制

相比于普通的Web应用,由于项目Agent应用的特殊性:
- 部分时候需要在集群Node上执行一些资源消耗性的破坏性任务
- 以及各类任务Pod的动态创建
基于以上原因,未配置部分工作负载的limit和requests。

而使用helm将Agent应用安装到客户提供的集群后,查询却没有发现相应的Pod被创建,而Deployment是存在的。
在排除helm包内容缺失的问题后,需要使用kubectl describe replicaset查询具体Pod未被创建的原因,发现存在如下内容:

Error creating: pods "xxx" is forbidden: failed quota: xxx: must specify limits.cpu, limits.memory, requests.cpu, requests.memory

也就是需要给Pod配置requests和limit,才允许被创建。了解到命名空间配置了ResourceQuota来限制整个命名空间可以使用的CPU和内存资源。在Pod未配置limit和requests时,由于无法计算资源是否会超出限制,因此会被拒绝创建。

后续采用LimitRange的default和defaultRequest,来自动设置Pod资源在未填写limit和requests时的默认值,能够保证在不移除ResourceQuota资源限制的情况下,设置一个资源可使用的默认值,这样Pod就能够创建成功了:

apiVersion: v1
kind: LimitRange
metadata:
  name: my-limitrange
  namespace: my-namespace
spec:
  limits:
  - type: Container
    default:
      cpu: "500m"
      memory: "512Mi"
    defaultRequest:
      cpu: "200m"
      memory: "256Mi"

但是这样也存在弊端,原本设计的消耗资源的破坏性任务可能无法达到需要的效果,后续还需要和客户进一步的沟通,不过好在大部分功能还是能够符合需求的。

进一步的,可以在对应应用的values.yaml将其配置为开关,在对应集群有资源限制需求时开启--set limitRange.enabled=true,并可以再helm install时传入--set limitRange.defaltLimit.cpu='500m'调整默认的资源配额:

limitRange:
  enabled: false
  defaultLimit:
    cpu: "500m"
    memory: "512Mi"
  defaultRequest:
    cpu: "200m"
    memory: "256Mi"
{{- if .Values.limitRange.enabled }}
apiVersion: v1
kind: LimitRange
metadata:
  name: xxx-limitrange
  namespace: {{ .Release.Namespace | quote }}
spec:
  limits:
  - type: Container
    default:
      cpu: {{ .Values.limitRange.defaultLimit.cpu | quote }}
      memory: {{ .Values.limitRange.defaultLimit.memory | quote }}
    defaultRequest:
      cpu: {{ .Values.limitRange.defaultRequest.cpu | quote }}
      memory: {{ .Values.limitRange.defaultRequest.memory | quote }}
{{- end }}

这里的quota是一个内置的函数表示将内容使用引号包裹成字符串。

镜像拉取凭证的设计

由于需要将应用镜像提前上传到客户环境的镜像仓库,但有些客户的环境又不便于将仓库项目设置为公共项目,应用在创建Pod时需要使用镜像拉取凭证才能从私有仓库拉取镜像,因此需要针对镜像拉取凭证处理。

拉取凭证的创建可以通过kubectl执行命令创建

kubectl create secret docker-registry my-registry-secret \
  --docker-server=<DOCKER_REGISTRY_URL> \
  --docker-username=<DOCKER_USERNAME> \
  --docker-password=<DOCKER_PASSWORD> \
  --docker-email=<DOCKER_EMAIL>

也可以将配置合并到应用helm包,先在values.yaml下创建关于镜像仓库的配置:

image:
  repository: harbor.xxx.com
  appProject: project-name
  secret:
    # 1.拉取镜像不需要secret,create和enable都改为false;
    # 2.拉取镜像需要我们自己创建secret,create和enable都改为true;
    # 3.拉取镜像使用客户提供的secret,create改为false,enable改为true,name改成客户提供的secret名称;
    imagePull:
      create: true
      enable: true
      username: natuki
      password: mypassword
      email: [email protected]
      # 镜像拉取secret名称
      name: image-pull-secret

创建如下的secret.yaml文件用于根据values.yaml配置生成镜像拉取凭证

{{- if .Values.image.secret.imagePull.create }}
apiVersion: v1
kind: Secret
metadata:
  name: {{ .Values.image.secret.imagePull.name }}
  namespace: {{ .Release.Namespace }}
type: kubernetes.io/dockerconfigjson
data:
  .dockerconfigjson: |
    {
      "auths": {
        "{{ .Values.image.repository }}": {
          "username": "{{ .Values.image.secret.imagePull.username }}",
          "password": "{{ .Values.image.secret.imagePull.password }}",
          "email": "{{ .Values.image.secret.imagePull.email }}",
          "auth": "{{ .Values.image.secret.imagePull.username | cat \":\" .Values.image.secret.imagePull.password | b64enc }}"
        }
      }
    }
{{- end }}

在应用相关的服务账号rbac.yaml配置里添加如下配置引用镜像拉取凭证,这样和服务账号关联的Pod就会使用该凭证拉取镜像:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: my-service-account
{{- if .Values.global.secret.imagePull.enable }}
imagePullSecrets:
  - name: {{ .Values.global.secret.imagePull.name }}
{{- end }}

发布者

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注