嘗試在 Kubernetes 中構建和自動化部署的新工具

嘗試在 Kubernetes 中構建和自動化部署的新工具

你好! 最近,發布了許多很酷的自動化工具,用於建立 Docker 映像和部署到 Kubernetes。 在這方面,我決定嘗試 GitLab,徹底研究它的功能,當然,也建立了管道。

這項工作的靈感來自於網站 kubernetes.io,它是由生成的 原始碼 自動,對於發送的每個池請求,機器人會自動產生包含您所做更改的網站預覽版本,並提供用於查看的連結。

我嘗試從頭開始建立一個類似的流程,但完全基於 Gitlab CI 和我習慣用來將應用程式部署到 Kubernetes 的免費工具。 今天我終於要告訴你更多關於他們的事了。

本文將討論以下工具:
雨果, 魁北克, 卡尼科, git 密碼 и 亞搏體育app CI 隨著動態環境的創建。

內容

  1. 認識雨果
  2. 準備 Dockerfile
  3. 認識卡尼科
  4. 了解qbec
  5. 嘗試使用 Gitlab-runner 和 Kubernetes-executor
  6. 使用 qbec 部署 Helm 圖表
  7. 介紹 git-crypt
  8. 建立工具箱影像
  9. 我們的第一個管道和按標籤組裝圖像
  10. 部署自動化
  11. 推動掌握時的工件和組裝
  12. 動態環境
  13. 評論應用程序

1. 認識雨果

作為我們專案的一個例子,我們將嘗試建立一個基於 Hugo 的文件發佈網站。 Hugo 是一個靜態內容產生器。

對於那些不熟悉靜態發生器的人,我會告訴你更多關於它們的資訊。 與具有資料庫和一些 PHP 的傳統網站引擎(當使用者要求時動態產生頁面)不同,靜態產生器的設計略有不同。 它們允許您獲取原始程式碼,通常是 Markdown 標記和主題模板中的一組文件,然後將它們編譯成一個完整完成的網站。

也就是說,您將收到一個目錄結構和一組生成的 HTML 文件,您可以簡單地將其上傳到任何廉價託管並獲得可用的網站。

您可以在本地安裝 Hugo 並嘗試:

初始化新站點:

hugo new site docs.example.org

同時 git 儲存庫:

cd docs.example.org
git init

到目前為止,我們的網站是原始的,為了在其上顯示某些內容,我們首先需要連接一個主題;主題只是一組模板和生成我們網站的指定規則。

對於我們將使用的主題 了解,在我看來,它非常適合文件網站。

我要特別注意的是,我們不需要將主題檔案保存在專案儲存庫中;相反,我們可以簡單地使用以下命令連接它 git 子模組:

git submodule add https://github.com/matcornic/hugo-theme-learn themes/learn

因此,我們的儲存庫將僅包含與我們的專案直接相關的文件,並且連接的主題將保留為特定儲存庫的連結以及其中的提交,也就是說,它始終可以從原始來源中拉取,而不必擔心不相容的更改。

讓我們更正一下配置 配置文件:

baseURL = "http://docs.example.org/"
languageCode = "en-us"
title = "My Docs Site"
theme = "learn"

在此階段您可以運行:

hugo server

並在地址 http://localhost:1313/ 查看我們新建立的網站,目錄中所做的所有變更都會自動更新瀏覽器中開啟的頁面,非常方便!

讓我們嘗試建立一個封面頁 內容/_index.md:

# My docs site

## Welcome to the docs!

You will be very smart :-)

新建立的頁面的螢幕截圖

嘗試在 Kubernetes 中構建和自動化部署的新工具

要產生站點,只需運行:

hugo

目錄內容 上市/ 並將成為您的網站。
是的,順便說一下,我們立即將其添加到 的.gitignore:

echo /public > .gitignore

不要忘記提交我們的更改:

git add .
git commit -m "New site created"

2. 準備Dockerfile

是時候定義我們的儲存庫的結構了。 我通常使用類似的東西:

.
├── deploy
│   ├── app1
│   └── app2
└── dockerfiles
    ├── image1
    └── image2

  • dockerfiles/ — 包含包含 Dockerfile 的目錄以及建置 Docker 映像所需的所有內容。
  • 部署/ — 包含用於將我們的應用程式部署到 Kubernetes 的目錄

因此,我們將沿著路徑建立第一個 Dockerfile dockerfiles/網站/Dockerfile

FROM alpine:3.11 as builder
ARG HUGO_VERSION=0.62.0
RUN wget -O- https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_${HUGO_VERSION}_linux-64bit.tar.gz | tar -xz -C /usr/local/bin
ADD . /src
RUN hugo -s /src

FROM alpine:3.11
RUN apk add --no-cache darkhttpd
COPY --from=builder /src/public /var/www
ENTRYPOINT [ "/usr/bin/darkhttpd" ]
CMD [ "/var/www" ]

如您所見,Dockerfile 包含兩個 獲取你的,這個特徵稱為 多階段構建 並允許您從最終的 docker 映像中排除所有不必要的內容。
因此,最終圖像將僅包含 暗httpd (輕量級 HTTP 伺服器)和 上市/ — 我們靜態產生的網站的內容。

不要忘記提交我們的更改:

git add dockerfiles/website
git commit -m "Add Dockerfile for website"

3.認識卡尼科

身為 docker 映像建置者,我決定使用 卡尼科,因為它的操作不需要docker守護進程,並且建置本身可以在任何機器上進行,並且快取可以直接儲存在註冊表中,從而無需擁有成熟的持久性儲存。

要建立映像,只需運行容器即可 卡尼科執行人 並將當前建置上下文傳遞給它;這也可以透過 docker 在本地完成:

docker run -ti --rm 
  -v $PWD:/workspace 
  -v ~/.docker/config.json:/kaniko/.docker/config.json:ro 
  gcr.io/kaniko-project/executor:v0.15.0 
  --cache 
  --dockerfile=dockerfiles/website/Dockerfile 
  --destination=registry.gitlab.com/kvaps/docs.example.org/website:v0.0.1

在哪裡 registry.gitlab.com/kvaps/docs.example.org/website — 您的 docker 映像的名稱;建置後,它將自動啟動到 docker 註冊表中。

參數 - 快取 允許您在 docker 註冊表中快取層;對於給出的範例,它們將保存在 registry.gitlab.com/kvaps/docs.example.org/website/cache,但您可以使用參數指定另一個路徑 --快取儲存庫.

docker-registry 的截圖

嘗試在 Kubernetes 中構建和自動化部署的新工具

4. 了解qbec

魁北克 是一個部署工具,可讓您以聲明方式描述應用程式清單並將其部署到 Kubernetes。 使用 Jsonnet 作為主要語法可以大大簡化跨多個環境的差異描述,並且幾乎完全消除程式碼重複。

當您需要將應用程式部署到具有不同參數的多個叢集並希望在 Git 中以聲明方式描述它們時,尤其如此。

Qbec 還允許您透過向 Helm 圖表傳遞必要的參數來渲染 Helm 圖表,然後以與常規清單相同的方式操作它們,包括您可以對它們應用各種突變,而這反過來又使您無需使用圖表博物館。 也就是說,您可以直接從它們所屬的 git 儲存和渲染圖表。

正如我之前所說,我們將把所有部署儲存在一個目錄中 部署/:

mkdir deploy
cd deploy

讓我們初始化我們的第一個應用程式:

qbec init website
cd website

現在我們的應用程式的結構如下所示:

.
├── components
├── environments
│   ├── base.libsonnet
│   └── default.libsonnet
├── params.libsonnet
└── qbec.yaml

讓我們看一下文件 qbec.yaml:

apiVersion: qbec.io/v1alpha1
kind: App
metadata:
  name: website
spec:
  environments:
    default:
      defaultNamespace: docs
      server: https://kubernetes.example.org:8443
  vars: {}

在這裡我們主要感興趣的是 規範環境,qbec 已經為我們創建了一個預設環境,並從我們目前的 kubeconfig 中取得了伺服器位址和命名空間。
現在當部署到 默認 在環境中,qbec 將始終僅部署到指定的 Kubernetes 叢集和指定的命名空間,也就是說,您不再需要在上下文和命名空間之間切換來執行部署。
如有必要,您可以隨時更新此文件中的設定。

您的所有環境均在中描述 qbec.yaml,並在文件中 params.libsonnet,其中表示從哪裡獲取它們的參數。

接下來我們看到兩個目錄:

  • 組件/ — 我們應用程式的所有清單都將儲存在這裡;它們可以在 jsonnet 和常規 yaml 檔案中進行描述
  • 環境/ - 在這裡我們將描述我們環境的所有變數(參數)。

預設我們有兩個檔案:

  • 環境/base.libsonnet - 它將包含所有環境的通用參數
  • 環境/default.libsonnet — 包含環境覆蓋的參數 默認

讓我們打開 環境/base.libsonnet 並為我們的第一個組件添加參數:

{
  components: {
    website: {
      name: 'example-docs',
      image: 'registry.gitlab.com/kvaps/docs.example.org/website:v0.0.1',
      replicas: 1,
      containerPort: 80,
      servicePort: 80,
      nodeSelector: {},
      tolerations: [],
      ingressClass: 'nginx',
      domain: 'docs.example.org',
    },
  },
}

我們還創建我們的第一個組件 組件/website.jsonnet:

local env = {
  name: std.extVar('qbec.io/env'),
  namespace: std.extVar('qbec.io/defaultNs'),
};
local p = import '../params.libsonnet';
local params = p.components.website;

[
  {
    apiVersion: 'apps/v1',
    kind: 'Deployment',
    metadata: {
      labels: { app: params.name },
      name: params.name,
    },
    spec: {
      replicas: params.replicas,
      selector: {
        matchLabels: {
          app: params.name,
        },
      },
      template: {
        metadata: {
          labels: { app: params.name },
        },
        spec: {
          containers: [
            {
              name: 'darkhttpd',
              image: params.image,
              ports: [
                {
                  containerPort: params.containerPort,
                },
              ],
            },
          ],
          nodeSelector: params.nodeSelector,
          tolerations: params.tolerations,
          imagePullSecrets: [{ name: 'regsecret' }],
        },
      },
    },
  },
  {
    apiVersion: 'v1',
    kind: 'Service',
    metadata: {
      labels: { app: params.name },
      name: params.name,
    },
    spec: {
      selector: {
        app: params.name,
      },
      ports: [
        {
          port: params.servicePort,
          targetPort: params.containerPort,
        },
      ],
    },
  },
  {
    apiVersion: 'extensions/v1beta1',
    kind: 'Ingress',
    metadata: {
      annotations: {
        'kubernetes.io/ingress.class': params.ingressClass,
      },
      labels: { app: params.name },
      name: params.name,
    },
    spec: {
      rules: [
        {
          host: params.domain,
          http: {
            paths: [
              {
                backend: {
                  serviceName: params.name,
                  servicePort: params.servicePort,
                },
              },
            ],
          },
        },
      ],
    },
  },
]

在此文件中,我們同時描述了三個 Kubernetes 實體,它們是: 部署, 服務 и 入口。 如果我們願意,我們可以將它們放入不同的組件中,但在現階段,一個對我們來說就足夠了。

句法 jsonnet 與常規 json 非常相似,原則上,常規 json 已經是有效的 jsonnet,所以首先您可能會更容易使用線上服務,例如 yaml2json 將您常用的 yaml 轉換為 json,或者,如果您的元件不包含任何變量,則可以以常規 yaml 的形式描述它們。

當與 jsonnet 我強烈建議為您的編輯器安裝一個插件

例如,有一個 vim 的插件 vim-jsonnet,開啟語法高亮並自動執行 jsonnet fmt 每次儲存時(需要安裝 jsonnet)。

一切準備就緒,現在我們可以開始部署了:

要查看我們得到了什麼,讓我們運行:

qbec show default

在輸出中,您將看到將套用於預設叢集的渲染 yaml 清單。

太好了,現在申請:

qbec apply default

在輸出中,您將始終看到叢集中將執行的操作,qbec 會要求您輸入同意更改 y 您將能夠確認您的意圖。

我們的應用程式已準備就緒並已部署!

如果您進行更改,您始終可以執行以下操作:

qbec diff default

查看這些變更將如何影響目前部署

不要忘記提交我們的更改:

cd ../..
git add deploy/website
git commit -m "Add deploy for website"

5. 嘗試使用 Kubernetes-executor 來使用 Gitlab-runner

直到最近我只使用常規 gitlab-runner 在具有 shell 或 docker-executor 的預先準備好的機器(LXC 容器)上。 最初,我們在 gitlab 中全域定義了幾個這樣的運行程式。 他們收集了所有專案的 docker 映像。

但實踐表明,這種選擇無論是從實用性還是安全性來看都不是最理想的。 為每個專案甚至每個環境部署單獨的運行程序會更好,在意識形態上也更正確。

幸運的是,這根本不是問題,因為現在我們將部署 gitlab-runner 直接作為我們 Kubernetes 專案的一部分。

Gitlab 提供了一個現成的 Helm Chart,用於將 gitlab-runner 部署到 Kubernetes。 所以你需要做的就是找出 註冊令牌 對於我們的項目 設定 -> CI / CD -> 跑者 並將其傳遞給掌舵:

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

helm install gitlab-runner 
  --set gitlabUrl=https://gitlab.com 
  --set runnerRegistrationToken=yga8y-jdCusVDn_t4Wxc 
  --set rbac.create=true 
  gitlab/gitlab-runner

在哪裡:

  • https://gitlab.com — 您的 Gitlab 伺服器的位址。
  • yga8y-jdCusVDn_t4Wxc — 您的專案的註冊令牌。
  • rbac.create=true — 為運行者提供必要的權限,以便能夠使用 kubernetes-executor 建立 pod 來執行我們的任務。

如果一切都正確完成,您應該會在 部分中看到已註冊的跑步者 運動員,在您的項目設定中。

新增的跑步者的螢幕截圖

嘗試在 Kubernetes 中構建和自動化部署的新工具

真有這麼簡單嗎? - 是的,就是這麼簡單! 不再需要手動註冊跑步者的麻煩,從現在開始,跑步者將自動創建和銷毀。

6. 使用 QBEC 部署 Helm 圖表

既然我們決定考慮 gitlab-runner 作為我們專案的一部分,是時候在我們的 Git 儲存庫中描述它了。

我們可以將其描述為一個單獨的組件 網站,但未來我們計劃部署不同的副本 網站 很多時候,不像 gitlab-runner,每個 Kubernetes 叢集僅部署一次。 因此,讓我們為其初始化一個單獨的應用程式:

cd deploy
qbec init gitlab-runner
cd gitlab-runner

這次我們不會手動描述 Kubernetes 實體,而是採用現成的 Helm 圖表。 qbec 的優點之一是能夠直接從 Git 儲存庫渲染 Helm 圖表。

讓我們使用 git 子模組連接它:

git submodule add https://gitlab.com/gitlab-org/charts/gitlab-runner vendor/gitlab-runner

現在目錄 供應商/gitlab-runner 我們有一個帶有 gitlab-runner 圖表的儲存庫。

以類似的方式,您可以連接其他儲存庫,例如帶有官方圖表的整個儲存庫 https://github.com/helm/charts

讓我們來描述一下這個元件 元件/gitlab-runner.jsonnet:

local env = {
  name: std.extVar('qbec.io/env'),
  namespace: std.extVar('qbec.io/defaultNs'),
};
local p = import '../params.libsonnet';
local params = p.components.gitlabRunner;

std.native('expandHelmTemplate')(
  '../vendor/gitlab-runner',
  params.values,
  {
    nameTemplate: params.name,
    namespace: env.namespace,
    thisFile: std.thisFile,
    verbose: true,
  }
)

第一個參數 展開Helm模板 我們將路徑傳遞給圖表,然後 參數值,我們從環境參數中獲取,然後得到對象

  • 名稱模板 — 發布標題
  • 命名空間 — 命名空間轉移到 helm
  • 這個文件 — 傳遞目前檔案路徑的必要參數
  • 冗長的 - 顯示指令 舵模板 渲染圖表時使用所有參數

現在讓我們來描述一下我們元件的參數 環境/base.libsonnet:

local secrets = import '../secrets/base.libsonnet';

{
  components: {
    gitlabRunner: {
      name: 'gitlab-runner',
      values: {
        gitlabUrl: 'https://gitlab.com/',
        rbac: {
          create: true,
        },
        runnerRegistrationToken: secrets.runnerRegistrationToken,
      },
    },
  },
}

請注意 跑者註冊令牌 我們從外部文件中獲取 秘密/base.libsonnet,讓我們創建它:

{
  runnerRegistrationToken: 'yga8y-jdCusVDn_t4Wxc',
}

讓我們檢查一下是否一切正常:

qbec show default

如果一切正常,那麼我們可以透過 Helm 刪除先前部署的版本:

helm uninstall gitlab-runner

並以相同的方式部署它,但透過 qbec:

qbec apply default

7.git-crypt簡介

Git 加密 是一個允許您為儲存庫設定透明加密的工具。

目前,我們的 gitlab-runner 目錄結構如下所示:

.
├── components
│   ├── gitlab-runner.jsonnet
├── environments
│   ├── base.libsonnet
│   └── default.libsonnet
├── params.libsonnet
├── qbec.yaml
├── secrets
│   └── base.libsonnet
└── vendor
    └── gitlab-runner (submodule)

但是在 Git 中儲存秘密並不安全,不是嗎? 所以我們需要對它們進行正確的加密。

通常,為了一個變量,這並不總是有意義的。 您可以將秘密轉移到 魁北克 並通過 CI 系統的環境變數。
但值得注意的是,還有更複雜的項目可以包含更多秘密;透過環境變數將它們全部傳輸將非常困難。

而且,在這種情況下,我將無法告訴您這樣一個出色的工具 git 密碼.

git 密碼 它還很方便,因為它允許您保存整個秘密歷史記錄,以及比較、合併和解決衝突,就像我們在 Git 中習慣做的那樣。

安裝後第一件事 git 密碼 我們需要為我們的儲存庫產生金鑰:

git crypt init

如果您有 PGP 金鑰,那麼您可以立即將自己新增為該專案的合作者:

git-crypt add-gpg-user [email protected]

這樣,您始終可以使用您的私鑰解密此儲存庫。

如果您沒有 PGP 金鑰並且不希望有它,那麼您可以採用其他方法並匯出專案金鑰:

git crypt export-key /path/to/keyfile

因此,任何擁有出口的人 密鑰檔案 將能夠解密您的儲存庫。

是時候建立我們的第一個秘密了。
讓我提醒您,我們仍在目錄中 部署/gitlab-runner/,我們有一個目錄 秘密/,讓我們加密其中的所有文件,為此我們將創建一個文件 秘密/.gitattributes 包含以下內容:

* filter=git-crypt diff=git-crypt
.gitattributes !filter !diff

從內容可以看出,所有文件都被封鎖了 * 將被驅動通過 git 密碼,除了大多數 .gitattributes

我們可以透過運行來檢查這一點:

git crypt status -e

輸出將是儲存庫中啟用加密的所有檔案的列表

就這樣,現在我們可以安全地提交更改了:

cd ../..
git add .
git commit -m "Add deploy for gitlab-runner"

要阻止存儲庫,只需運行:

git crypt lock

所有加密的文件都會立即變成二進位文件,無法讀取它們。
若要解密儲存庫,請執行:

git crypt unlock

8. 建立工具箱鏡像

工具箱映像是包含我們將用於部署專案的所有工具的映像。 Gitlab 運行程式將使用它將來執行典型的部署任務。

這裡一切都很簡單,讓我們創造一個新的 dockerfiles/工具箱/Dockerfile 包含以下內容:

FROM alpine:3.11

RUN apk add --no-cache git git-crypt

RUN QBEC_VER=0.10.3 
 && wget -O- https://github.com/splunk/qbec/releases/download/v${QBEC_VER}/qbec-linux-amd64.tar.gz 
     | tar -C /tmp -xzf - 
 && mv /tmp/qbec /tmp/jsonnet-qbec /usr/local/bin/

RUN KUBECTL_VER=1.17.0 
 && wget -O /usr/local/bin/kubectl 
      https://storage.googleapis.com/kubernetes-release/release/v${KUBECTL_VER}/bin/linux/amd64/kubectl 
 && chmod +x /usr/local/bin/kubectl

RUN HELM_VER=3.0.2 
 && wget -O- https://get.helm.sh/helm-v${HELM_VER}-linux-amd64.tar.gz 
     | tar -C /tmp -zxf - 
 && mv /tmp/linux-amd64/helm /usr/local/bin/helm

正如您所看到的,在此映像中,我們安裝了用於部署應用程式的所有實用程式。 我們這裡不需要它,除非 Kubectl,但您可能想在管道設定階段使用它。

此外,為了能夠與 Kubernetes 通訊並部署到它,我們需要為 gitlab-runner 產生的 pod 設定角色。

為此,我們使用 gitlab-runner 進入目錄:

cd deploy/gitlab-runner

並新增一個組件 組件/rbac.jsonnet:

local env = {
  name: std.extVar('qbec.io/env'),
  namespace: std.extVar('qbec.io/defaultNs'),
};
local p = import '../params.libsonnet';
local params = p.components.rbac;

[
  {
    apiVersion: 'v1',
    kind: 'ServiceAccount',
    metadata: {
      labels: {
        app: params.name,
      },
      name: params.name,
    },
  },
  {
    apiVersion: 'rbac.authorization.k8s.io/v1',
    kind: 'Role',
    metadata: {
      labels: {
        app: params.name,
      },
      name: params.name,
    },
    rules: [
      {
        apiGroups: [
          '*',
        ],
        resources: [
          '*',
        ],
        verbs: [
          '*',
        ],
      },
    ],
  },
  {
    apiVersion: 'rbac.authorization.k8s.io/v1',
    kind: 'RoleBinding',
    metadata: {
      labels: {
        app: params.name,
      },
      name: params.name,
    },
    roleRef: {
      apiGroup: 'rbac.authorization.k8s.io',
      kind: 'Role',
      name: params.name,
    },
    subjects: [
      {
        kind: 'ServiceAccount',
        name: params.name,
        namespace: env.namespace,
      },
    ],
  },
]

我們還將在中描述新參數 環境/base.libsonnet,現在看起來像這樣:

local secrets = import '../secrets/base.libsonnet';

{
  components: {
    gitlabRunner: {
      name: 'gitlab-runner',
      values: {
        gitlabUrl: 'https://gitlab.com/',
        rbac: {
          create: true,
        },
        runnerRegistrationToken: secrets.runnerRegistrationToken,
        runners: {
          serviceAccountName: $.components.rbac.name,
          image: 'registry.gitlab.com/kvaps/docs.example.org/toolbox:v0.0.1',
        },
      },
    },
    rbac: {
      name: 'gitlab-runner-deploy',
    },
  },
}

請注意 $.components.rbac.name 指的是 名稱 對於組件 紅細胞

讓我們檢查一下發生了什麼變化:

qbec diff default

並將我們的變更應用到 Kubernetes:

qbec apply default

另外,不要忘記將我們的更改提交到 git:

cd ../..
git add dockerfiles/toolbox
git commit -m "Add Dockerfile for toolbox"
git add deploy/gitlab-runner
git commit -m "Configure gitlab-runner to use toolbox"

9. 我們的第一個管道和按標籤組裝圖像

我們將在專案的根目錄中創建 .gitlab-ci.yml 包含以下內容:

.build_docker_image:
  stage: build
  image:
    name: gcr.io/kaniko-project/executor:debug-v0.15.0
    entrypoint: [""]
  before_script:
    - echo "{"auths":{"$CI_REGISTRY":{"username":"$CI_REGISTRY_USER","password":"$CI_REGISTRY_PASSWORD"}}}" > /kaniko/.docker/config.json

build_toolbox:
  extends: .build_docker_image
  script:
    - /kaniko/executor --cache --context $CI_PROJECT_DIR/dockerfiles/toolbox --dockerfile $CI_PROJECT_DIR/dockerfiles/toolbox/Dockerfile --destination $CI_REGISTRY_IMAGE/toolbox:$CI_COMMIT_TAG
  only:
    refs:
      - tags

build_website:
  extends: .build_docker_image
  variables:
    GIT_SUBMODULE_STRATEGY: normal
  script:
    - /kaniko/executor --cache --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/dockerfiles/website/Dockerfile --destination $CI_REGISTRY_IMAGE/website:$CI_COMMIT_TAG
  only:
    refs:
      - tags

請注意我們使用 GIT_SUBMODULE_STRATEGY:正常 對於那些需要在執行之前明確初始化子模組的作業。

不要忘記提交我們的更改:

git add .gitlab-ci.yml
git commit -m "Automate docker build"

我想我們可以放心地稱之為一個版本 v0.0.1 並添加標籤:

git tag v0.0.1

每當我們需要發布新版本時,我們都會新增標籤。 Docker 映像中的標籤將與 Git 標籤綁定。 每次帶有新標籤的推送都會使用該標籤初始化鏡像的建置。

我們開始做吧 git push --標籤,讓我們看看我們的第一個管道:

第一個管道的螢幕截圖

嘗試在 Kubernetes 中構建和自動化部署的新工具

值得注意的是,透過標籤組裝適合建置 docker 映像,但不適合將應用程式部署到 Kubernetes。 由於新標籤可以分配給舊提交,在這種情況下,為它們初始化管道將導致舊版本的部署。

為了解決這個問題,通常將docker映像的建置與標籤綁定在一起,並將應用程式部署到分支 ,其中收集的圖像的版本是硬編碼的。 您可以在此處透過簡單的恢復來初始化回滾 - 分公司。

10. 部署自動化

為了讓 Gitlab-runner 解密我們的秘密,我們需要匯出儲存庫金鑰並將其新增至我們的 CI 環境變數:

git crypt export-key /tmp/docs-repo.key
base64 -w0 /tmp/docs-repo.key; echo

我們將把生成的行保存在 Gitlab 中;為此,我們進入專案設​​定:
設定 -> CI / CD -> 變數

讓我們建立一個新變數:

類別
關鍵

保護
蒙面
範圍

File
GITCRYPT_KEY
<your string>
true (在培訓期間您可以 false)
true
All environments

新增的變數的螢幕截圖

嘗試在 Kubernetes 中構建和自動化部署的新工具

現在讓我們更新我們的 .gitlab-ci.yml 添加到它:

.deploy_qbec_app:
  stage: deploy
  only:
    refs:
      - master

deploy_gitlab_runner:
  extends: .deploy_qbec_app
  variables:
    GIT_SUBMODULE_STRATEGY: normal
  before_script:
    - base64 -d "$GITCRYPT_KEY" | git-crypt unlock -
  script:
    - qbec apply default --root deploy/gitlab-runner --force:k8s-context __incluster__ --wait --yes

deploy_website:
  extends: .deploy_qbec_app
  script:
    - qbec apply default --root deploy/website --force:k8s-context __incluster__ --wait --yes

在這裡,我們為 qbec 啟用了幾個新選項:

  • --根一些/應用程式 — 允許您確定特定應用程式的目錄
  • --force:k8s-context __incluster__ - 這是一個神奇的變量,表示部署將在 gtilab-runner 運行的同一叢集中進行。 這是必要的,因為否則 qbec 會嘗試在您的 kubeconfig 中找到合適的 Kubernetes 伺服器
  • - 等待 — 強制 qbec 等待,直到它建立的資源進入就緒狀態,然後才以成功的退出程式碼退出。
  • -是的 - 簡單地停用互動式 shell 你確定嗎? 部署時。

不要忘記提交我們的更改:

git add .gitlab-ci.yml
git commit -m "Automate deploy"

之後 git push 我們將看到我們的應用程式是如何部署的:

第二條管道的截圖

嘗試在 Kubernetes 中構建和自動化部署的新工具

11. 推到master時的工件和組裝

通常,上述步驟足以建置和交付幾乎任何微服務,但我們不想每次需要更新網站時都會新增標籤。 因此,我們將採取更動態的路線,在 master 分支中設定摘要部署。

這個想法很簡單:現在我們的形象 網站 每次你推入時都會重建 ,然後自動部署到Kubernetes。

讓我們更新這兩個作業 .gitlab-ci.yml:

build_website:
  extends: .build_docker_image
  variables:
    GIT_SUBMODULE_STRATEGY: normal
  script:
    - mkdir -p $CI_PROJECT_DIR/artifacts
    - /kaniko/executor --cache --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/dockerfiles/website/Dockerfile --destination $CI_REGISTRY_IMAGE/website:$CI_COMMIT_REF_NAME --digest-file $CI_PROJECT_DIR/artifacts/website.digest
  artifacts:
    paths:
      - artifacts/
  only:
    refs:
      - master
      - tags

deploy_website:
  extends: .deploy_qbec_app
  script:
    - DIGEST="$(cat artifacts/website.digest)"
    - qbec apply default --root deploy/website --force:k8s-context __incluster__ --wait --yes --vm:ext-str digest="$DIGEST"

請注意我們添加了一個線程 к 裁判 為了工作 建立網站 我們現在使用 $CI_COMMIT_REF_NAME 而不是 $CI_COMMIT_TAG,也就是說,我們擺脫了 Git 中的標籤,現在我們將推送一個帶有初始化管道的提交分支名稱的鏡像。 值得注意的是,這也適用於標籤,這將允許我們在 docker-registry 中保存具有特定版本的網站的快照。

當新版本網站的 docker 標籤名稱可以不變時,我們仍然需要向 Kubernetes 描述這些更改,否則它根本不會從新映像中重新部署應用程序,因為它不會注意到 Kubernetes 中的任何變化。部署清單。

選項 —vm:ext-str 摘要=”$DIGEST” for qbec - 允許您將外部變數傳遞給 jsonnet。 我們希望隨著應用程式的每個版本將其重新部署到叢集中。 我們不能再使用標籤名稱,它現在是不可更改的,因為我們需要綁定到映像的特定版本並在其更改時觸發部署。

在這裡,我們將受益於 Kaniko 將摘要圖像保存到文件的能力(選項 --摘要文件)
然後我們將傳輸這個檔案並在部署時讀取它。

讓我們更新我們的參數 部署/網站/環境/base.libsonnet 現在看起來像這樣:

{
  components: {
    website: {
      name: 'example-docs',
      image: 'registry.gitlab.com/kvaps/docs.example.org/website@' + std.extVar('digest'),
      replicas: 1,
      containerPort: 80,
      servicePort: 80,
      nodeSelector: {},
      tolerations: [],
      ingressClass: 'nginx',
      domain: 'docs.example.org',
    },
  },
}

完成,現在任何提交 初始化 docker 映像的構建 網站,然後部署到Kubernetes。

不要忘記提交我們的更改:

git add .
git commit -m "Configure dynamic build"

我們稍後會檢查 git push 我們應該看到這樣的東西:

master 管道的螢幕截圖

嘗試在 Kubernetes 中構建和自動化部署的新工具

原則上,我們不需要在每次推送時重新部署 gitlab-runner,當然,除非它的配置沒有任何變化,讓我們修復它 .gitlab-ci.yml:

deploy_gitlab_runner:
  extends: .deploy_qbec_app
  variables:
    GIT_SUBMODULE_STRATEGY: normal
  before_script:
    - base64 -d "$GITCRYPT_KEY" | git-crypt unlock -
  script:
    - qbec apply default --root deploy/gitlab-runner --force:k8s-context __incluster__ --wait --yes
  only:
    changes:
      - deploy/gitlab-runner/**/*

變化 將允許您監視變化 部署/gitlab-runner/ 並且只有在有任何情況時才會觸發我們的工作

不要忘記提交我們的更改:

git add .gitlab-ci.yml
git commit -m "Reduce gitlab-runner deploy"

git push,這樣更好:

更新後的管道的螢幕截圖

嘗試在 Kubernetes 中構建和自動化部署的新工具

12. 動態環境

是時候透過動態環境使我們的管道多樣化了。

首先我們來更新一下作業 建立網站 在我們的 .gitlab-ci.yml,從中刪除區塊 僅由,這將強制 Gitlab 在對任何分支的任何提交時觸發它:

build_website:
  extends: .build_docker_image
  variables:
    GIT_SUBMODULE_STRATEGY: normal
  script:
    - mkdir -p $CI_PROJECT_DIR/artifacts
    - /kaniko/executor --cache --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/dockerfiles/website/Dockerfile --destination $CI_REGISTRY_IMAGE/website:$CI_COMMIT_REF_NAME --digest-file $CI_PROJECT_DIR/artifacts/website.digest
  artifacts:
    paths:
      - artifacts/

然後更新作業 部署網站,在那裡添加一個塊 環境:

deploy_website:
  extends: .deploy_qbec_app
  environment:
    name: prod
    url: https://docs.example.org
  script:
    - DIGEST="$(cat artifacts/website.digest)"
    - qbec apply default --root deploy/website --force:k8s-context __incluster__ --wait --yes --vm:ext-str digest="$DIGEST"

這將允許 Gitlab 將作業與 產品 環境並顯示正確的連結。

現在讓我們再新增兩個作業:

deploy_website:
  extends: .deploy_qbec_app
  environment:
    name: prod
    url: https://docs.example.org
  script:
    - DIGEST="$(cat artifacts/website.digest)"
    - qbec apply default --root deploy/website --force:k8s-context __incluster__ --wait --yes --vm:ext-str digest="$DIGEST"

deploy_review:
  extends: .deploy_qbec_app
  environment:
    name: review/$CI_COMMIT_REF_NAME
    url: http://$CI_ENVIRONMENT_SLUG.docs.example.org
    on_stop: stop_review
  script:
    - DIGEST="$(cat artifacts/website.digest)"
    - qbec apply review --root deploy/website --force:k8s-context __incluster__ --wait --yes --vm:ext-str digest="$DIGEST" --vm:ext-str subdomain="$CI_ENVIRONMENT_SLUG" --app-tag "$CI_ENVIRONMENT_SLUG"
  only:
    refs:
    - branches
  except:
    refs:
      - master

stop_review:
  extends: .deploy_qbec_app
  environment:
    name: review/$CI_COMMIT_REF_NAME
    action: stop
  stage: deploy
  before_script:
    - git clone "$CI_REPOSITORY_URL" master
    - cd master
  script:
    - qbec delete review --root deploy/website --force:k8s-context __incluster__ --yes --vm:ext-str digest="$DIGEST" --vm:ext-str subdomain="$CI_ENVIRONMENT_SLUG" --app-tag "$CI_ENVIRONMENT_SLUG"
  variables:
    GIT_STRATEGY: none
  only:
    refs:
    - branches
  except:
    refs:
      - master
  when: manual

它們將在推送到 master 以外的任何分支時啟動,並將部署網站的預覽版本。

我們看到 qbec 的一個新選項: --應用程式標籤 — 它允許您標記應用程式的已部署版本,並且僅在該標記內工作;在 Kubernetes 中建立和銷毀資源時,qbec 將僅對它們進行操作。
這樣我們就不能為每次評審創造一個單獨的環境,而只是重複使用同一個環境。

這裡我們也使用 qbec申請審查, 代替 qbec 應用預設值 - 這正是我們嘗試描述我們的環境差異(審核和預設)的時刻:

讓我們添加 檢討 環境在 部署/網站/qbec.yaml

spec:
  environments:
    review:
      defaultNamespace: docs
      server: https://kubernetes.example.org:8443

然後我們將在中聲明它 部署/網站/params.libsonnet:

local env = std.extVar('qbec.io/env');
local paramsMap = {
  _: import './environments/base.libsonnet',
  default: import './environments/default.libsonnet',
  review: import './environments/review.libsonnet',
};

if std.objectHas(paramsMap, env) then paramsMap[env] else error 'environment ' + env + ' not defined in ' + std.thisFile

並記下它的自訂參數 部署/網站/環境/review.libsonnet:

// this file has the param overrides for the default environment
local base = import './base.libsonnet';
local slug = std.extVar('qbec.io/tag');
local subdomain = std.extVar('subdomain');

base {
  components+: {
    website+: {
      name: 'example-docs-' + slug,
      domain: subdomain + '.docs.example.org',
    },
  },
}

我們也來仔細看看jobu 停止評論,當分支被刪除時會觸發,這樣gitlab就不會嘗試檢查它是否被使用 GIT_STRATEGY:無,稍後我們克隆 - 透過它分支和刪除評論。
這有點令人困惑,但我還沒有找到更漂亮的方法。
另一種選擇是將每個評論部署到酒店名稱空間,該名稱空間始終可以完全拆除。

不要忘記提交我們的更改:

git add .
git commit -m "Enable automatic review"

git push, git checkout -b 測試, git推送原點測試, 查看:

Gitlab 中建立的環境截圖

嘗試在 Kubernetes 中構建和自動化部署的新工具

一切正常嗎? - 太好了,刪除我們的測試分支: git checkout master, git推送原點:測試,我們檢查環境刪除作業是否正常運作。

這裡我想立即澄清,專案中的任何開發人員都可以建立分支,他也可以更改 .gitlab-ci.yml 文件和存取秘密變數。
因此,強烈建議僅允許將它們用於受保護的分支,例如 ,或為每個環境建立一組單獨的變數。

13.審查應用程式

評論應用程序 這是 GitLab 的功能,可讓您為儲存庫中的每個檔案新增一個按鈕,以便在部署的環境中快速查看它。

為了顯示這些按鈕,您需要建立一個文件 .gitlab/route-map.yml 並描述其中的所有路徑轉換;在我們的例子中,它會非常簡單:

# Indices
- source: /content/(.+?)_index.(md|html)/ 
  public: '1'

# Pages
- source: /content/(.+?).(md|html)/ 
  public: '1/'

不要忘記提交我們的更改:

git add .gitlab/
git commit -m "Enable review apps"

git push,並檢查:

“查看應用程式”按鈕的螢幕截圖

嘗試在 Kubernetes 中構建和自動化部署的新工具

工作完成了!

專案來源:

感謝您的關注,希望您喜歡 嘗試在 Kubernetes 中構建和自動化部署的新工具

來源: www.habr.com

添加評論