本月早些时候,我使用 kubernetes 和 Flux 构建并部署了我的第一个 GitOps 持续交付管道。在整个过程中,我发现自己在阅读大量过时且令人困惑的文档,因此在到达另一边后,我想写下我所采取的步骤的演练,希望其他开发人员可以更轻松地度过.

堆栈:

AWS EKS用于 kubernetes 集群

HelmOperator byFlux用于 GitOps

Terraform+Cloudformation用于基础设施

我部署到集群的应用程序是一个 GraphQL API,它存在于 AWS ECR 上的 docker 映像中,但这可以适应任何 docker 容器或其他容器化构建。

由于有很多很好的资源可以创建特定于您使用的任何服务(AWS、Google GKE 等)的 kubernetes 集群,因此我将假设您有一个想要的现有集群来开始本演练将映像部署到。

第1步:GitHub

您将需要一个专用的 GitHub 存储库来执行此过程。在这里您将提交所有以下配置(您的 helm 图表、helm 版本等),并且它应该与您用于构建您正在部署的应用程序的任何存储库分开。

第 2 步:设置 Fluxcd

按照的说明安装 Helm和Fluxctl

然后,使用 helm 安装 Fluxcd 图表:

helm repo add fluxcd https://charts.fluxcd.io

在您的集群上创建一个命名空间,以供与通量相关的 pod 生存:

我使用了“fluxcd”,但您可以选择任何对您有意义的命名空间

kubectl create ns fluxcd

创建您的通量 pod(GitHub 存储库 + 分支将来自第 1 步):

helm upgrade -i flux fluxcd/flux --wait \
  --namespace fluxcd \
  --set git.url=git@github.com:<GITHUB REPO> \
  --set git.branch=<BRANCH>

如果您的存储库是私有的,您还需要添加 knownhosts 标志:

--set-file ssh.known_hosts=$known_hosts_path

指向您的 knownhosts 所在的路径,通常在 ~/.ssh 目录中。

第三步:Helm Operator

helm operator 是一个控制器,它与 Flux 协同工作,并允许您创建将部署映像的 HelmReleases,并在 Flux 检测到更改时将映像更新到最新版本。

将 Helm Operator 应用到您的集群:

kubectl apply -f https://raw.githubusercontent.com/fluxcd/helm-operator/master/deploy/flux-helm-release-crd.yaml

创建 helmRelease pod:

helm upgrade -i helm-operator fluxcd/helm-operator --wait \
  --namespace fluxcd \
  --set helm.versions=v3

检索 SSH 密钥:

fluxctl identity --k8s-fwd-ns fluxcd

并将其添加到部署密钥下的 github 存储库中。

您将希望授予此密钥写入权限,以便 Flux 在检测到图像的新版本时更新您的 helmReleases。

第 4 步:HelmReleases

现在助焊剂已全部设置好,是时候开始制作好东西了。正如我之前提到的,HelmReleases 是 Flux 用于部署映像的 yaml 文件。

apiVersion: helm.fluxcd.io/v1
kind: HelmRelease
metadata:
  name: <app name -- name of the application you're deploying>
  namespace: default
  annotations:
    flux.weave.works/automated: "true"
    flux.weave.works/tag.chart-image: glob:dev-*
spec:
  releaseName: <app name>
  helmVersion: v3
  chart:
    git: <github repo from step 1>
    path: <the directory where your charts live -- ex. charts/app-name >
    ref: <github branch set in step 2>
  values:
    image: <image endpoint of your application>
    replicaCount: 1
    hpa:
      enabled: true
      maxReplicas: 3
      cpu: 1
    extraEnvs:
      ## This is where you can add any public env variables
      username: oliver_2020
      dbServer: 11.0.1.213 
    envFrom:
      secretRef:
        ## The Secret Name for private env variables (more on that later)
        name: mysecrets

您拥有的每个 HelmRelease 都需要一个相应的 Helm Chart。 Helm 有一些很棒的文档关于构建自定义 Helm 图表 + 模板,但我会添加基础知识。

第 5 步:Helm 图表

如果 Kubernetes 是领航员,Helm 就是方向盘。大多数 Helm Charts 包含以下组件:

Chart.yaml 文件几乎就像掌舵图的“标题页”。它由图表名称和版本信息组成。

apiVersion: v1
kind: application
description: A Super Awesome GraphQL API
name: graphql
version: 1.0.0

values.yaml 文件用于定义图表所需的所有变量。

image: <image endpoint of your application>
    replicaCount: 1
    hpa:
      enabled: true
      maxReplicas: 3
      cpu: 1
    extraEnvs:
      username: oliver_2020

这些变量然后被各种模板文件使用。

一个常见的模板文件是部署模板:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ .Release.Name }}
  labels:
    app: {{ template "app.name" . }}
    chart: {{ template "app.chart" . }}
    release: {{ .Release.Name }}
    heritage: {{ .Release.Service }}
spec:
  replicas: {{ .Values.replicaCount }}
  selector:
    matchLabels:
      app: {{ template "app.name" . }}
      release: {{ .Release.Name }}
  template:
    metadata:
      labels:
        app: {{ template "app.name" . }}
        release: {{ .Release.Name }}
      annotations:
        prometheus.io/scrape: 'true'
    spec:
      containers:
        - name: {{ .Chart.Name }}
          image: "{{ .Values.image }}"
          imagePullPolicy: {{ .Values.imagePullPolicy }}
          env:
            - name: publicEnvKey
              value: {{ .Values.extraEnv.key | quote }}
            - name: secretEnvKey
              valueFrom:
                secretKeyRef:
                  key: dbPassword
                  name: mysecrets
          resources:
{{ toYaml .Values.resources | indent 12 }}
    {{- with .Values.nodeSelector }}
      nodeSelector:
{{ toYaml . | indent 8 }}
    {{- end }}
    {{- with .Values.affinity }}
      affinity:
{{ toYaml . | indent 8 }}
    {{- end }}
    {{- with .Values.tolerations }}
      tolerations:
{{ toYaml . | indent 8 }}
    {{- end }}
      volumes:
      - name: data
        emptyDir: {}

您将可以使用模板语法访问整个图表中定义的变量

.价值观

。发布

。图表

但是,如果您需要更改值的结构,例如删除或添加连字符,则可以添加 helper.tpl 文件。模板助手对于生成时间戳等值也很有用,将它放在你的 values.yaml 文件中是没有意义的,因为它并不是图表的真正组成部分。

第 6 步:模板助手

变量在帮助文件中使用define操作定义

{{- define "mychart.labels" }}
  labels:
    generator: helm
    date: {{ now | htmlDate }}
{{- end }}

然后,您可以使用template操作在任何模板文件中调用此值

{{ template "mychart.labels" }}

模板引擎会将其读取为当前日期。

有关声明自定义值的完整参考,请参阅 helm命名模板指南

第7步:密封的秘密

如果您有任何要使用的私有环境变量,最好将它们存储在一个秘密中。 Kubernetes 有一种存储机密的本机方式,但值只是 base64 编码,这不是最安全的策略,所以我一直在使用一个名为seal-secrets的工具,它允许您创建 SealedSecrets 资源,然后您可以将其存储在其中GitHub,因为它们只能由创建它们的控制器解密。

SealedSecret 资源如下所示:

apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
  name: mysecrets
  namespace: default
spec:
  encryptedData:
    dbPassword: AgBy3i4OJSWK+PiTySYZZA9rO43cGDEq.....

并且可以通过秘密名称在您的 helmRelease 中引用

envFrom:
      secretRef:
        name: mysecrets

首先,安装 Stable 存储库:

helm repo add stable https://kubernetes-charts.storage.googleapis.com/

更新 Helm 存储库:

helm repo update

然后从稳定的存储库安装密封的秘密:

helm install --namespace kube-system stable/sealed-secrets --generate-name

安装后,您可以将 seal-secrets 控制器应用于您的集群:

kubectl apply -f https://github.com/bitnami-labs/sealed-secrets/releases/download/v0.9.6/controller.yaml

然后使用生成的密封秘密 pod 名称获取生成的公钥(可以提交到 GitHub):

kubeseal --fetch-cert \
  --controller-namespace=kube-system \
  --controller-name=sealed-secrets-230493143 \
  > pub-cert.pem

您可以使用kubectl get pods -n kube-system获取 pod 名称

步骤 8:创建 SealedSecret 资源

要创建 Secret,您将首先使用 kubectl 生成它,然后使用 kubeseal 对其进行加密

kubectl -n <env namespace> create secret generic <secretname> \
--from-literal=<key>=<value> \
--from-literal=<key>=<value> \
--dry-run \
-o json > <secretname>.json

试运行标志将创建具有 base64 加密值的 json 文件,但不会在您的集群上创建实际的 kubernetes 机密。

要使用 kubeseal 对其进行加密,您将传递上一步中公钥的位置、您刚刚创建的 json 文件的名称以及您要用于秘密的文件名

kubeseal --format=yaml --cert=pub-cert.pem < secretname.json > secretname.yaml

此过程将生成一个自定义 SealedSecret 资源,其中包含只能由创建它的控制器解封的加密凭据。

拥有 SealedSecret 资源后,您可以删除或 .gitignore 生成的 json 文件。当您提交 pub-cert 文件和新的 SealedSecrets 资源到 GitHub 时,flux 会将密钥应用到您的集群,然后控制器会将其解封为本地 kubernetes 密钥以供集群读取。

第 9 步:推送到 Git

一旦你的 helm 发布和相应的 helm 图表都设置好了,你可以继续从第 1 步将你的提交推送到 GitHub 存储库。

一旦您的提交被合并或推送到您在步骤 2 中指定的分支,flux 将获取更改并部署您的第一个掌舵版本。

Flux 通常需要一两分钟才能同步,但您可以手动强制同步

fluxctl sync --k8s-fwd-ns fluxcd

fluxcd替换为您在步骤 2 中为通量 pod 选择的任何命名空间。

步骤 10. 故障排除

如果您推送了提交,等待通量同步,但仍然没有看到带有 helm 版本中 app-name 的 pod,那么您可以通过几种方法进行故障排除。

获取具有kubectl get pods --all-namespaces的所有 pod 的列表并复制通量 pod 的名称。然后运行kubectl logs <fluxpodname> -n fluxcd

您应该能够看到 Flux 尝试克隆 repo 的日志,并轮询更新,并可以检查任何错误。

另一种策略是kubectl get hr,它将获取所有 helm 发布实例,并且通常会显示发布在部署过程中的位置以及出现的任何错误。

最后,我总是发现描述资源并确保它们按预期配置很有帮助。您可以使用kubectl describe <resourcetype> <resourcename>描述任何 Kubernetes 资源


结论

这只是为您的 Kubernetes 管道配置持续交付管道的众多方法之一。 Flux 是一个很棒的工具,因为它可以很好地与 Helm 集成,并且是一种自动化部署过程的相对直接的方式。 Helm 最近更新到版本 3,并且对 Helm v3 的通量支持仍处于 beta 模式,因此有些令人困惑/过时的文档,但 Weaveworks 的团队在他们的 slack 频道https://cloud-native.slack .com/,希望本演练也能帮助解决一些复杂问题。

有问题、反馈、宠物照片吗?不要犹豫,在下面发表评论并快乐编码!

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐