使用 Docker Hub 完美地存储 Helm 图表实战

2023-03-20 09:52:08 浏览数 (1)

Helm[1] 是 Kubernetes 的包管理器。它是一个开源容器编排系统。它通过提供一种简单的方法来定义、安装和升级复杂的 Kubernetes 应用程序,帮助您管理 Kubernetes 应用程序。

使用 Helm,您可以将您的应用程序打包成一个 chart[2],它是描述您的应用程序的一组文件。然后,您可以使用 Helm 在 Kubernetes 集群上安装和管理您的应用程序。Helm 可以轻松地自动安装和管理复杂的应用程序,它提供的许多功能使其成为管理 Kubernetes 应用程序的强大工具。

使用 Helm 的一些好处包括:

  • 简化安装和管理复杂 Kubernetes 应用程序的过程。
  • 使应用程序的部署和管理自动化变得容易。
  • 允许您对应用程序配置进行版本控制。
  • 提供一种通过公共或私人图表存储库与他人共享应用程序的方法。
  • 如有必要,可以轻松回滚到应用程序的先前版本。

总的来说,Helm 是在 Kubernetes 上管理和部署应用程序的有用工具,它可以帮助您简化在 Kubernetes 集群上管理复杂应用程序的过程。

为什么 Docker 支持 Helm Chart?

Docker Hub[3] 是 Docker 提供的流行的托管存储库服务,用于查找容器镜像并与您的团队共享。它是一个容器镜像存储库,用于存储和分发容器镜像,或容器运行时可用的工件。因为容器镜像分发只是应用程序交付过程的起点,这成为我们平台的限制。

现在的应用程序支持许多工件,例如 WebAssembly 模块、OPA Bundle、Helm 图表、SBOM 和自定义工件。因此,Docker Hub 团队必须支持所有这些工件,以便开发人员可以与需要它们的客户共享这些工件,因为这为他们的项目增加了巨大的价值。2022 年 10 月,Docker 宣布[4] Docker Hub 现在可以帮助您分发任何类型的应用程序工件!您现在可以将所有内容保存在一个地方,而无需利用多个注册表。

在此博客中,您将看到 Docker Hub 如何完美地存储 Helm 图表。

1. 创建 Helm 图表

开始使用新图表的最佳方法是使用 helm create 命令搭建一个我们可以构建的示例。使用此命令在新目录中创建一个名为 kubeinfo 的新图表:

代码语言:javascript复制
helm create kubeinfo

2. 查看图表

Helm 将在您的项目中创建一个新目录, kubeinfo 其结构如下所示。让我们浏览我们的新图表以了解它是如何工作的。

代码语言:javascript复制
demo % tree
.
├── Chart.yaml
├── charts
├── templates
│   ├── NOTES.txt
│   ├── _helpers.tpl
│   ├── deployment.yaml
│   ├── hpa.yaml
│   ├── ingress.yaml
│   ├── service.yaml
│   ├── serviceaccount.yaml
│   └── tests
│       └── test-connection.yaml
└── values.yaml

3 directories, 10 files

文件结构中最重要的部分是 template/目录。这是 Helm 查找Services, Deployments和其他 Kubernetes 对象的 YAML 定义的地方。如果您已经有了应用程序的定义,那么所需要做的就是将生成的 YAML 文件替换为您自己的。最终得到的是一个可以使用 helm install 命令部署的 chart。

打开 service.yaml 文件看看它长什么样子:

代码语言:javascript复制
apiVersion: v1
kind: Service
metadata:
  name: {{ include "kubeinfo.fullname" . }}
  labels:
    {{- include "kubeinfo.labels" . | nindent 4 }}
spec:
  type: {{ .Values.service.type }}
  ports:
    - port: {{ .Values.service.port }}
      targetPort: http
      protocol: TCP
      name: http
  selector:
    {{- include "kubeinfo.selectorLabels" . | nindent 4 }}

这是使用模板的基本服务定义。部署图表时,Helm 将生成一个看起来更像有效服务的定义。我们可以试运行 helm 安装并启用调试以检查生成的定义。

请确保在 Helm 目录外运行以下命令。

代码语言:javascript复制
helm install kubeinfo --dry-run --debug ./kubeinfo
install.go:192: [debug] Original chart version: ""
install.go:209: [debug] CHART PATH: /Users/ajeetraina/dec/kubeinfo

NAME: kubeinfo
LAST DEPLOYED: Thu Dec  8 11:02:54 2022
NAMESPACE: default
STATUS: pending-install
REVISION: 1
USER-SUPPLIED VALUES:
{}

COMPUTED VALUES:
affinity: {}
autoscaling:
  enabled: false
  maxReplicas: 100
  minReplicas: 1
  targetCPUUtilizationPercentage: 80
fullnameOverride: ""
image:
  pullPolicy: IfNotPresent
  repository: nginx
  tag: ""
imagePullSecrets: []
ingress:
  annotations: {}
  className: ""
  enabled: false
  hosts:
  - host: chart-example.local
    paths:
    - path: /
      pathType: ImplementationSpecific
  tls: []
nameOverride: ""
nodeSelector: {}
podAnnotations: {}
podSecurityContext: {}
replicaCount: 1
resources: {}
securityContext: {}
service:
  port: 80
  type: ClusterIP
serviceAccount:
  annotations: {}
  create: true
  name: ""
tolerations: []

HOOKS:
---
# Source: kubeinfo/templates/tests/test-connection.yaml
apiVersion: v1
kind: Pod
metadata:
  name: "kubeinfo-test-connection"
  labels:
    helm.sh/chart: kubeinfo-0.1.0
    app.kubernetes.io/name: kubeinfo
    app.kubernetes.io/instance: kubeinfo
    app.kubernetes.io/version: "1.16.0"
    app.kubernetes.io/managed-by: Helm
  annotations:
    "helm.sh/hook": test
spec:
  containers:
    - name: wget
      image: busybox
      command: ['wget']
      args: ['kubeinfo:80']
  restartPolicy: Never
MANIFEST:
---
# Source: kubeinfo/templates/serviceaccount.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: kubeinfo
  labels:
    helm.sh/chart: kubeinfo-0.1.0
    app.kubernetes.io/name: kubeinfo
    app.kubernetes.io/instance: kubeinfo
    app.kubernetes.io/version: "1.16.0"
    app.kubernetes.io/managed-by: Helm
---
# Source: kubeinfo/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
  name: kubeinfo
  labels:
    helm.sh/chart: kubeinfo-0.1.0
    app.kubernetes.io/name: kubeinfo
    app.kubernetes.io/instance: kubeinfo
    app.kubernetes.io/version: "1.16.0"
    app.kubernetes.io/managed-by: Helm
spec:
  type: ClusterIP
  ports:
    - port: 80
      targetPort: http
      protocol: TCP
      name: http
  selector:
    app.kubernetes.io/name: kubeinfo
    app.kubernetes.io/instance: kubeinfo
---
# Source: kubeinfo/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: kubeinfo
  labels:
    helm.sh/chart: kubeinfo-0.1.0
    app.kubernetes.io/name: kubeinfo
    app.kubernetes.io/instance: kubeinfo
    app.kubernetes.io/version: "1.16.0"
    app.kubernetes.io/managed-by: Helm
spec:
  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/name: kubeinfo
      app.kubernetes.io/instance: kubeinfo
  template:
    metadata:
      labels:
        app.kubernetes.io/name: kubeinfo
        app.kubernetes.io/instance: kubeinfo
    spec:
      serviceAccountName: kubeinfo
      securityContext:
        {}
      containers:
        - name: kubeinfo
          securityContext:
            {}
          image: "nginx:1.16.0"
          imagePullPolicy: IfNotPresent
          ports:
            - name: http
              containerPort: 80
              protocol: TCP
          livenessProbe:
            httpGet:
              path: /
              port: http
          readinessProbe:
            httpGet:
              path: /
              port: http
          resources:
            {}

NOTES:
1. Get the application URL by running these commands:
  export POD_NAME=$(kubectl get pods --namespace default -l "app.kubernetes.io/name=kubeinfo,app.kubernetes.io/instance=kubeinfo" -o jsonpath="{.items[0].metadata.name}")
  export CONTAINER_PORT=$(kubectl get pod --namespace default $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}")
  echo "Visit http://127.0.0.1:8080 to use your application"
  kubectl --namespace default port-forward $POD_NAME 8080:$CONTAINER_PORT

3.更改 service.internalPort 的默认值

如果再执行一次试运行,您应该会发现 Service 中的 targetPort 和 Deployment 中的 containerPort 发生了变化。

代码语言:javascript复制
helm install kubeinfo --dry-run --debug ./kubeinfo --set service.internalPort=8080

4.对外暴露

默认情况下,chart 会创建一个 ClusterIP 类型的 Service,因此 NGINX 只会暴露在集群内部。要从外部访问它,我们将改用 NodePort 类型。我们还可以设置 Helm 版本的名称,以便我们可以轻松地引用它。让我们继续使用 helm install 命令部署我们的 NGINX chart:

代码语言:javascript复制
helm install example ./kubeinfo --set service.type=NodePort

3.打包 Helm Chart

完成编辑后,我们需要将 Helm 图表打包为 OCI 图像:

代码语言:javascript复制
helm package kubeinfo
Successfully packaged chart and saved it to: /Users/ajeetraina/dec/kubeinfo-0.1.0.tgz

5.登录到 Docker Hub

代码语言:javascript复制
docker login
Authenticating with existing credentials...
Login Succeeded

Logging in with your password grants your terminal complete access to your account.
For better security, log in with a limited-privilege personal access token. Learn more at https://docs.docker.com/go/access-tokens/

6. 推送到 Docker Hub

代码语言:javascript复制
helm push kubeinfo-0.1.0.tgz  oci://registry-1.docker.io/ajeetraina
Error: server message: insufficient_scope: authorization failed

您可能会遇到错误消息。

修复:建议创建个人访问令牌:Personal Access Token (PAT)。

您可以通过环境变量 export PAT,然后登录,如下所示:

代码语言:javascript复制
echo $REG_PAT | helm registry login registry-1.docker.io -u ajeetraina --password-stdin
Login Succeeded

结论

将 Helm Charts 存储在 Docker Hub 中可以通过 Docker Hub 的标准共享功能改进协作。开发人员现在可以使用 Docker Desktop 的搜索功能在本地构建 Helm chart,然后将其完美地推送到 Docker Hub。

参考资料

[1]

Helm: https://helm.sh/

[2]

chart: https://artifacthub.io/

[3]

Docker Hub: https://www.docker.com/products/docker-hub/

[4]

宣布: https://www.docker.com/blog/announcing-docker-hub-oci-artifacts-support/

- END -

0 人点赞