Új eszközöket tesztelünk a Kubernetes beállításához és automatizált telepítéséhez

Új eszközöket tesztelünk a Kubernetes beállításához és automatizált telepítéséhez

Helló! Az utóbbi időben sok nagyszerű automatizálási eszköz jelent meg, mind a Docker-képek felépítésére, mind a Kubernetesbe való telepítésre. Ennek kapcsán úgy döntöttem, hogy játszadozom a GitLabbal, alaposan megismerem a lehetőségeit, és természetesen beállítom a folyamatot.

Ennek a munkának az inspirációja a következő weboldal volt kubernetes.io, amely automatikusan generálódik a forráskódokból , és minden beérkező pull requesthez a robot automatikusan generál egy preview verziót az Ön módosításaival, és linket biztosít a megtekintéshez.

Megpróbáltam egy hasonló folyamatot felépíteni a nulláról, de teljesen a GitLab CI-n és az általam használt szabad eszközökön alapulva, amelyeket a Kubernetes alkalmazások telepítéséhez szoktam használni. Ma végre részletesebben is beszámolok róluk.

A cikkben a következő eszközöket vizsgáljuk meg:
Hugo, qbec, kaniko, git-crypt és GitLab CI dinamikus környezetek létrehozásához.

Tartalom

  1. Ismerkedés a Hugóval
  2. Dockerfile előkészítése
  3. Ismerkedés a kanikóval
  4. Ismerkedés a qbécel
  5. GitLab-futtató tesztelése Kubernetes-végrehajtóval
  6. Helm-diagramok telepítése qbécel
  7. Ismerkedés a git-cryptel
  8. Toolbox-kép létrehozása
  9. Első folyamatunk és a képek építése címkék szerint
  10. A telepítés automatizálása
  11. Artefaktumok és építés push esetén a master-hez
  12. Dinamikus környezetek
  13. Felülvizsgálati alkalmazások

1. Ismerkedés a Hugóval

Példaként a projektünkhöz egy dokumentációs weboldalt próbálunk létrehozni, amely a Hugóra épül. A Hugo egy statikus tartalomgenerátor.

Azok számára, akik nem ismerik a statikus generátorokat, egy kicsit részletesebben bemutatom őket. A hagyományos adatbázis-alapú webes motorokkal és PHP-vel ellentétben, amelyek a felhasználói kérések alapján valós időben generálják az oldalakat, a statikus generátorok kicsit másképp működnek. Lehetővé teszik az alapfájlok, általában Markdown formátumban lévő fájlok és téma sablonok felhasználását, majd ezekből egy kész weboldal kialakítását.

Ezért a kibocsátáskor egy könyvtárszerkezetet és számos generált HTML-fájlt fog kapni, amelyeket egyszerűen feltölthet bármely olcsó webhosztra, és működő weboldalt kaphat.

A Hugót helyileg telepítheti, és kipróbálhatja a működését:

Új webhelyet indítunk:

hugo new site docs.example.org

És egyúttal git-repo-t is:

cd docs.example.org
git init

A weboldalunk még érintetlen, és ahhoz, hogy valami megjelenjen rajta, először aktiválnunk kell a sablont, a sablon csupán egy template-ek és a generálási szabályok halmaza, amely alapján a weboldalunk létrejön.

Sablonként a következőt fogjuk használni: Learn, amely véleményem szerint a legjobban illik a dokumentációs weboldalhoz.

Külön figyelmet érdemel, hogy nem szükséges a sablon fájljait a projektünk tárolójában megőrizni, ehelyett egyszerűen csatlakoztathatjuk azt a következő parancs használatával: git submodule:

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

Így a tárolónkban csak a projekthez kapcsolódó fájlok fognak szerepelni, a csatlakoztatott sablon pedig hivatkozásként marad egy adott tárolóra és annak egy commitjára, tehát bármikor lehúzhatjuk az eredeti forrásból, és nem kell félni az inkompatibilis változtatásoktól.

Javítsuk a konfigurációt: config.toml:

baseURL = "http://docs.example.org/"
languageCode = "hu-hu"
title = "Dokumentációs Weboldalam"
theme = "learn"

Ezen a ponton már elindíthatjuk:

hugo server

És a következő címen http://localhost:1313/ ellenőrizhetjük az éppen most létrehozott weboldalunkat, az összes változtatás automatikusan frissíti a böngészőben megnyitott oldalt, ami nagyon kényelmes!

Próbáljunk létrehozni egy címoldalt a következőben: content/_index.md:

# My docs site

## Welcome to the docs!

You will be very smart :-)

A nemrég létrehozott oldal képernyőképe

Új eszközöket tesztelünk a Kubernetes beállításához és automatizált telepítéséhez

A weboldal generálásához elegendő elindítani:

hugo

A könyvtár tartalma public/ lesz a weboldalad.
Igen, és azonnal vegyük fel a .gitignore:

echo /public > .gitignore

Ne felejtsük el elkötelezni a változtatásainkat:

git add .
git commit -m "Új weboldal létrehozva"

2. Dockerfile előkészítése

Itt az ideje meghatározni a tárolónk struktúráját. Általában valami ilyesmit használok:

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

  • dockerfiles/ — olyan könyvtárakat tartalmaz, amelyek Dockerfile-okat és mindent, ami szükséges a docker-képeink összeállításához.
  • deploy/ — olyan könyvtárakat tartalmaz, amelyek a Kubernetesben alkalmazásaink telepítésére szolgálnak.

Így az első Dockerfile-unkat itt fogjuk létrehozni: dockerfiles/website/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" ]

Ahogy észreveheted, a Dockerfile két FROM, ez a képesség úgynevezett multi-stage build és lehetővé teszi, hogy a végleges docker képből eltávolítsuk az összes felesleges dolgot.
Így a végleges képünk csak a következőket fogja tartalmazni: darkhttpd (könnyűsúlyú HTTP-szerver) és public/ — a statikusan generált weboldalunk tartalma.

Ne felejtsük el elkötelezni a változtatásainkat:

git add dockerfiles/website
git commit -m "Dockerfile hozzáadása a weboldalhoz"

3. Ismerkedés a kaniko-val

Docker képek készítőjeként a kaniko-t választottam kaniko, mivel működéséhez nem szükséges a docker daemon, a build pedig bármilyen gépen végezhető, és a cache közvetlenül a registryben tárolható, így megszabadulunk a teljes értékű persistent tároló meglétének szükségességétől.

A kép építéséhez elegendő elindítani egy konténert a következővel: kaniko executor és megadni neki a jelenlegi build kontextust, ezt akár lokálisan, a docker-en keresztül is megtehetjük:

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

Ahol registry.gitlab.com/kvaps/docs.example.org/website — a docker kép neve, a build után automatikusan feltöltésre kerül a docker registry-be.

A parameter —cache lehetővé teszi a rétegek cache-elését a docker registry-ben, a fenti példához tartozóan a következőkben fognak tárolódni: registry.gitlab.com/kvaps/docs.example.org/website/cache, de megadhat másik útvonalat is a —cache-repo.

docker-registry képernyőképe

Új eszközöket tesztelünk a Kubernetes beállításához és automatizált telepítéséhez

4. Ismerkedés a qbec-el

Qbec — egy telepítési eszköz, amely lehetővé teszi az alkalmazásod nyilatkozatainak deklaratív leírását és azok Kubernetes-be való telepítését. A Jsonnet használata mint fő szintaxis jelentősen egyszerűsíti a különbségek leírását több környezet között, és szinte teljesen megszabadít a kód ismétlésétől.

Ez különösen fontos lehet, amikor az alkalmazást több klaszterbe kell telepíteni különböző paraméterekkel, és szeretnéd ezeket deklaratívan leírni a Git-ben.

A Qbec emellett lehetővé teszi a Helm-chartok renderelését, szükséges paraméterek átadásával, és később ezekkel úgy bánhatsz, mint a hagyományos nyilatkozatokkal, beleértve különböző mutációk rájuk vonatkoztatását, ami lehetővé teszi, hogy ne kelljen ChartMuseum-ot használnod. Tehát a chartokat közvetlenül git-ből tárolhatod és renderelheted, ahol a legjobban illeszkednek.

Ahogy korábban mondtam, minden telepítést a deploy/:

mkdir deploy
cd deploy

direktóriumban fogunk tárolni.

Lássuk, hogyan inicializálhatjuk az első alkalmazásunkat:

Jelenleg az alkalmazásunk struktúrája így néz ki:

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

nézzük meg a fájlt qbec.yaml:

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

Itt elsősorban az érdekes számunkra spec.environments, a qbec már létrehozta számunkra az alapértelmezett környezetet és átvette a szerver címét, valamint a névteret a jelenlegi kubeconfig-ból.
Most a telepítés során alapértelmezett környezetben a qbec mindig csak a megadott Kubernetes klaszterre és a megadott névtérbe fog telepíteni, így többé nem kell váltogatnia a kontextusok és névterek között a telepítés végrehajtásához.
Szükség esetén mindig frissítheti a beállításokat ebben a fájlban.

Minden környezetét a következő fájlokban találja: qbec.yaml, és a fájlban params.libsonnet, ahol megtalálhatók az ezekhez szükséges paraméterek.

Továbbá két könyvtárat látunk:

  • components/ ─ itt tároljuk az alkalmazásunk összes manifesztjét, amelyek jsonnet és hagyományos yaml fájlok formájában is létezhetnek
  • environments/ ─ itt írjuk le az összes változót (paramétert) a környezetünk számára.

Alapértelmezés szerint két fájl áll rendelkezésünkre:

  • environments/base.libsonnet ─ ez tartalmazza az összes környezetre vonatkozó közös paramétert
  • environments/default.libsonnet ─ ez tartalmazza a környezetre felülírt paramétereket alapértelmezett

Nyissuk meg environments/base.libsonnet és adjuk hozzá az első komponensünkhöz szükséges paramétereket:

{
  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',
    },
  },
}

Hozzuk létre az első komponensünket is components/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,
                },
              },
            ],
          },
        },
      ],
    },
  },
]

Ebben a fájlban három Kubernetes-entitást írtunk le: Deployment, Service és Ingress. Ha szeretnénk, kivehetjük őket külön komponensekbe, de ezen a ponton elég, ha egyben tartjuk őket.

Szintaxis jsonnet nagyon hasonlít a sima json-re, gyakorlatilag a sima json már érvényes jsonnet, így az első időszakban könnyebb lehet az online szolgáltatások használata, mint például yaml2json , hogy a megszokott yaml-t json-ra konvertálja, vagy ha a komponensek nem tartalmaznak változókat, akkor azokat sima yaml-ként is leírhatjuk.

A jsonnet használata során nagyon ajánlom, hogy telepítsen egy plugint a szerkesztőjéhez.

Például a vimhez van egy plugin vim-jsonnet, amely szintaxis kiemelést biztosít, és automatikusan futtatja a jsonnet fmt minden mentéskor (az jsonnet telepítése szükséges).

Minden kész, most kezdhetjük a telepítést:

Ahhoz, hogy megnézzük, mit értünk el, futtassuk:

qbec show default

A kimenetben a renderelt yaml-manifesztusokat fogja látni, amelyeket a default klaszterhez fognak alkalmazni.

Tökéletes, most alkalmazzuk:

qbec apply default

A kimenetben mindig láthatja, hogy mit hajtanak végre az Ön klaszterében, a qbec megkéri, hogy fogadja el a változtatásokat az alábbi beírásával: y megerősítheti a szándékait.

Most már az alkalmazásunk telepítve van!

Ha módosításokat végez, mindig futtathatja:

qbec diff default

hogy lássa, hogyan hatnak ezek a módosítások a jelenlegi telepítésre

Ne felejtsük el elkötelezni a változtatásainkat:

cd ..\..
git add deploy\website
git commit -m "Weboldal telepítése"

5. Gitlab-runner kipróbálása Kubernetes-executorral

A közelmúltig csak a hagyományos gitlab-runner-t használtam egy előkészített gépen (LXC-konténer) shell- vagy docker-executorral. Eredetileg több ilyen futtatót állítottunk be globálisan a gitlabunkban. Ezek gyűjtötték a docker-képeket minden projekthez.

De a gyakorlat azt mutatta, hogy ez a megoldás nem a legjobb, sem a praktikusság, sem a biztonság szempontjából. Sokkal jobb és ideológiailag helyesebb külön telepített futtatókat biztosítani minden projekthez, vagy akár minden környezethez.

Szerencsére ez egyáltalán nem probléma, mivel most közvetlenül a projektünk részeként fogunk telepíteni gitlab-runner-t használtam Kubernetesbe.

A Gitlab kész helm-chartot biztosít a gitlab-runner Kubernetesbe való telepítéséhez. Így minden, amire szüksége van, az az, hogy megtudja a regisztrációs tokent a projektünkhöz, Beállítások —> CI / CD —> Futtatók és átadja a helmnek:

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

Ahol:

  • https://gitlab.com — a Gitlab-szervere címe.
  • yga8y-jdCusVDn_t4Wxc — a projektünk számára szóló regisztrációs token.
  • rbac.create=true — biztosítja a futtatónak a szükséges jogokat ahhoz, hogy podokat hozzon létre a feladataink végrehajtásához a kubernetes-executor segítségével.

Ha minden helyesen van beállítva, látnia kell a regisztrált futtatót a Futtatókszekcióban, a projekt beállításaiban.

A hozzáadott futtató képernyőképe

Új eszközöket tesztelünk a Kubernetes beállításához és automatizált telepítéséhez

Úgy könnyű? — igen, tényleg! Többé nincs szükség a futtatók manuális regisztrálására, innentől a futtatók automatikusan létrejönnek és megszűnnek.

6. Helm-chartok telepítése QBEC-vel

Mivel úgy döntöttünk, hogy ezt gitlab-runner-t használtam projektrésznek számítjuk, itt az ideje, hogy ezt leírjuk a Git-tárolónkban.

Leírhattuk volna külön komponensként website, de a jövőben gyakran tervezünk különböző másolatokat telepíteni website ellentétben azzal, gitlab-runner-t használtamamelyet csak egyszer telepítenek minden Kubernetes klaszterre. Szóval indítsunk el egy külön alkalmazást erre:

cd deploy
qbec init gitlab-runner
cd gitlab-runner

Ezúttal nem fogjuk kézzel leírni a Kubernetes-entitásokat, hanem egy elkészített Helm-chartot fogunk használni. A qbec egyik előnye, hogy lehetőséget ad a Helm-chartok közvetlenül a Git-tárhelyből való renderelésére.

Csatlakoztassuk a git submodule segítségével:

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

Most a könyvtár vendor/gitlab-runner tartalmaz egy repót a gitlab-runner chartjával.

Hasonló módon más repókat is csatlakoztathatunk, például az összes hivatalos chart repóját. https://github.com/helm/charts

Írjuk le a komponenst components/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,
  }
)

Az első argumentumként az expandHelmTemplate függvénynek átadjuk a chart elérhetőségét, majd a params.values, amelyeket a környezeti paraméterekből veszünk, ezután következik egy objektum a

  • nameTemplate -el, amely a kiadás neve
  • namespace — a Helmnek átadott névtér
  • thisFile — kötelező paraméter, amely az aktuális fájl elérhetőségét adja meg
  • verbose — megmutatja a parancsot helm template minden argumentummal a chart renderelésekor

Most írjuk le a paramétereket a komponensünkhöz a environments/base.libsonnet:

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

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

Figyeljünk arra, hogy runnerRegistrationToken külső fájlból vettük, secrets/base.libsonnet— létrehozunk egyet:

{
  runnerRegistrationToken: 'yga8y-jdCusVDn_t4Wxc',
}

Ellenőrizzük, hogy minden rendben működik-e:

qbec show default

ha minden a helyén van, akkor eltávolíthatjuk a korábban Helm segítségével telepített kiadást:

helm uninstall gitlab-runner

és újra telepíthetjük, de már qbec használatával:

qbec apply default

7. Ismerkedés a git-crypt-tel

A Git-crypt — egy eszköz, amely lehetővé teszi a titkosított tárolás konfigurálását a repónk számára.

Jelenleg a gitlab-runner könyvtárunk struktúrája így néz ki:

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

De nem biztonságos titkokat tárolni a Git-ben, nem igaz? Szóval, megfelelően titkosítani kell őket.

Általában egyetlen változó esetén ez nem mindig éri meg. Titkokat adhat át qbec és a CI-rendszerének környezeti változóin keresztül is.
De meg kell jegyezni, hogy léteznek bonyolultabb projektek is, amelyek sokkal több titkot tartalmazhatnak, és azokat környezeti változókon keresztül átadni rendkívül nehézkes lenne.

Ráadásul ilyen esetben nem tudnám elmondani neked erről a csodálatos eszközről, mint például git-crypt.

git-crypt ami abban is hasznos, hogy megőrzi az összes titok történetét, valamint összehasonlíthatjuk, összevonhatjuk és megoldhatjuk a konfliktusokat, ahogy azt a Git esetében is megszoktuk.

Első lépésként telepítés után git-crypt generálnunk kell a kulcsokat a repónkhoz:

git crypt init

Ha van PGP-kulcsod, azonnal hozzáteheted magad, mint együttműködő a projekthez:

git-crypt add-gpg-user kvapss@gmail.com

Így mindig dekódolni tudod ezt a repót a privát kulcsoddal.

Ha viszont nincs PGP-kulcsod és nem is várható, akkor más úton is járhatsz, és exportálhatod a projekt kulcsát:

git crypt export-key /path/to/keyfile

Így bárki, aki rendelkezik az exportált keyfile dekódolni tudja a repódat.

Itt az idő beállítani az első titkunkat.
Emlékeztetek, még mindig a deploy/gitlab-runner/dokumentumban vagyunk, ahol van egy secrets/dokumentumunk, most titkosítsuk az összes fájlt benne, ehhez hozzunk létre egy fájlt secrets/.gitattributes a következő tartalommal:

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

Ahogy a tartalomból látható, az összes fájl a megadott mintának megfelelően * át fog futni a git-crypt, kivéve magát a .gitattributes

Ezt ellenőrizhetjük azzal, hogy futtatjuk:

git crypt status -e

A kimenetben megkapjuk az összes fájl listáját a repóban, amelyekhez engedélyezett a titkosítás.

Ennyi, most már nyugodtan elkötelezhetjük a változtatásainkat:

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

A repó zárolásához elegendő végrehajtani:

git crypt lock

és azonnal minden titkosított fájl bináris tárgyakká alakul, amelyeket lehetetlen lesz elolvasni.
A repó dekódolásához futtasd:

git crypt unlock

8. Hozzunk létre toolbox képet.

A toolbox kép olyan kép, amely az összes eszközt tartalmazza, amelyet a projektünk telepítéséhez fogunk használni. Ez a GitLab-Runner által lesz felhasználva a standard telepítési feladatok végrehajtásához.

Itt minden egyszerű, hozzunk létre egy új dockerfiles/toolbox/Dockerfile a következő tartalommal:

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

Ahogy láthatod, ebben a képen telepítjük az összes olyan segédprogramot, amelyet az alkalmazásunk telepítéséhez használtunk. Itt talán csak kubectl, de lehet, hogy kedved támadna kipróbálni a pipeline beállításának fázisában.

A Kuberneteshez való kapcsolódás és a telepítések végrehajtása érdekében szerepkört kell beállítanunk a gitlab-runner által generált podokhoz.

Ehhez lépjünk a gitlab-runner könyvtárba:

cd deploy/gitlab-runner

és adjuk hozzá az új komponenst components/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,
      },
    ],
  },
]

Ugyanakkor írjuk körül az új paramétereket itt: environments/base.libsonnet, ami most így néz ki:

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',
    },
  },
}

Figyeljünk arra, hogy $.components.rbac.name utal a name komponensre rbac

Nézzük meg, mi változott:

qbec diff default

és alkalmazzuk a változtatásainkat a Kubernetesben:

qbec apply default

Ne felejtsd el elkötelezni a változtatásainkat a gitben sem:

cd ../..
git add dockerfiles/toolbox
git commit -m "Dockerfile hozzáadása a toolboxhoz"
git add deploy/gitlab-runner
git commit -m "A gitlab-runner konfigurálása a toolbox használatára"

9. Az első pipeline-unk és képkészítés címkék alapján

A projekt gyökérkönyvtárában létrehozunk .gitlab-ci.yml a következő tartalommal:

.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

Kérjük, vegye figyelembe, hogy GIT_SUBMODULE_STRATEGY: normal azokhoz a feladatokhoz, ahol a szubmodulokat kifejezetten inicializálni kell a végrehajtás előtt.

Ne felejtsük el elkötelezni a változtatásainkat:

git add .gitlab-ci.yml
git commit -m "Automatizálja a docker build folyamatot"

Azt hiszem, ezt bátran nevezhetjük verziónak v0.0.1 és beállíthatjuk a taget:

git tag v0.0.1

A tageket minden alkalommal beállítjuk, amikor új verziót kell kiadnunk. A Docker képek tagei a Git tagekhez lesznek hozzárendelve. Minden új tag push aktiválja a képek építését ezzel a taggel.

Futtassuk git push —tags, és nézzük meg az első pipeline-unkat:

Az első pipeline képernyőképe

Új eszközöket tesztelünk a Kubernetes beállításához és automatizált telepítéséhez

Érdemes megjegyezni, hogy a tagek szerinti építés alkalmas Docker képek építésére, de nem megfelelő az alkalmazás Kubernetesbe való telepítésére. Mivel új tagek régi commitokhoz is rendelhetők, ez esetben a pipeline inicializálása a régi verzió telepítéséhez vezet.

E problémát általában úgy oldják meg, hogy a Docker képek építését a tagekhez, míg az alkalmazás telepítését a branchoz rendelik master, amelyben a beépített képek verziói találhatók. Csak ebben az esetben tudja egyszerű revert-tel inicializálni a rollback-et master-ág.

10. A telepítés automatizálása

Ahhoz, hogy a Gitlab-runner képes legyen dekódolni titkainkat, szükségünk lesz a repo kulcsának exportálására, és annak beállítására a CI környezeti változói között:

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

A kapott szöveget a Gitlabban kell elmentenünk, ehhez lépjünk a projektünk beállításaiba:
Beállítások —> CI / CD —> Változók

És hozzunk létre egy új változót:

Típus
Kulcs
Érték
Védett
Maszkos
Hatókör

Fájl
GITCRYPT_KEY

igaz (a képzés idejére akár hamis)
igaz
Minden környezet

A hozzáadott változó képernyőképe

Új eszközöket tesztelünk a Kubernetes beállításához és automatizált telepítéséhez

Most frissítsük a .gitlab-ci.yml hozzáadva:

.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

Itt több új lehetőséget használtunk a qbec számára:

Ne felejtsük el elkötelezni a változtatásainkat:

git add .gitlab-ci.yml
git commit -m "Automatizált telepítés"

És után git push látni fogjuk, hogyan települtek az alkalmazásaink:

A második pipeline képernyőfelvétele

Új eszközöket tesztelünk a Kubernetes beállításához és automatizált telepítéséhez

11. Artefaktumok és összesítés a master be push közben

Általában a fent leírt lépések elegendőek szinte bármilyen mikroszolgáltatás összesítéséhez és szállításához, de nem akarjuk minden alkalommal címkét felrakni, amikor frissítenünk kell a weboldalt. Ezért dinamikusabb megoldásra térünk át, és beállítjuk a telepítést a digest alapján a master ágon.

Az ötlet egyszerű: most a képek újraépítésre kerülnek minden push esetén a website de ezt követően automatikusan telepítjük a Kubernetes-be. masterFrissítsük a két feladatunkat a

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 - tagsdeploy_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" .gitlab-ci.yml:

Figyeljen, hogy hozzáadtuk az ágat

a master refs a feladathoz build_website és most a $CI_COMMIT_REF_NAME helyett $CI_COMMIT_TAG , vagyis leválunk a git címkékről, és most a commit ági nevével készítjük el a képet, amely elindította a pipeline-t. Érdemes megemlíteni, hogy ez a címkékkel is működni fog, lehetővé téve számunkra, hogy snapshots-t készítsünk a weboldalról meghatározott verzióval a docker-registry-ben., azaz leválasztjuk a címkéket a Git-ről, és mostantól a pipeline-t inicializáló commit ága nevét fogjuk push-olni. Érdemes megjegyezni, hogy ez a címkákra is vonatkozni fog, ami lehetővé teszi számunkra, hogy különböző verziókkal rendelkező webhely snapshotokat tároljunk a docker-registry-ben.

Amikor a docker-tág neve az új verzió számára állandó lehet, továbbra is le kell írnunk a változásokat a Kubernetes számára, különben egyszerűen nem fogja újradeployálni az alkalmazást az új képből, mivel nem fog észlelni semmilyen változást a telepítési manifesztben.

Opció —vm:ext-str digest="$DIGEST" a qbec-hez — lehetővé teszi, hogy egy külső változót átadjunk a jsonnetnek. Azt szeretnénk, hogy alkalmazásunk minden kiadásával újradeployálódjon a klaszterben. Az állandó tág név használatára itt már nincs lehetőségünk, mivel meg kell kötnünk egy konkrét verziót és aktiválnunk kell a telepítést ennek megváltoztatásakor.

Itt segít nekünk a Kaniko lehetősége, hogy a kép digest-jét fájlba mentse (opció —digest-file)
Ezt a fájlt átadjuk az alkalmazás telepítésének pillanatában és elolvassuk.

Frissítjük a paramétereket a deploy/website/environments/base.libsonnet ami most így fog kinézni:

{
  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',
    },
  },
}

Kész, most bármilyen elkötelezés a master elkezdi a docker-kép összeállítását a website, majd pedig annak telepítését a Kubernetes-be.

Ne felejtsük el elkötelezni a változtatásainkat:

git add .
git commit -m "Dinamikus építés konfigurálása"

Ellenőrizzük, miután git push látni kell valami ilyesmit:

Képernyőkép a master pipeline-ról

Új eszközöket tesztelünk a Kubernetes beállításához és automatizált telepítéséhez

Elvileg nincs szükségünk a gitlab-runner újradeployálására minden push-nál, hacsak, természetesen, nem történt változás a konfigurációjában, javítsuk ki ezt a .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/**/*

változások lehetővé teszi a változások nyomon követését a deploy/gitlab-runner/ és csak akkor aktiválja a munkánkat, ha vannak ilyenek

Ne felejtsük el elkötelezni a változtatásainkat:

git add .gitlab-ci.yml
git commit -m "Csökkentett gitlab-runner telepítés"

git push, így már jobb:

Képernyőkép a frissített pipeline-ról

Új eszközöket tesztelünk a Kubernetes beállításához és automatizált telepítéséhez

12. Dinamikus környezetek

Itt az ideje, hogy változatosabbá tegyük a pipeline-unkat dinamikus környezetekkel.

Először frissítsük a munkát és most a a .gitlab-ci.yml, eltávolítva belőle a only, amely arra kényszeríti a Gitlabot, hogy bármely elkötelezéskor aktiválja azt bármely ágon:

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/

Ezután frissítjük a munkát deploy_website, hozzáadunk egy blokkot környezet:

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"

Ez lehetővé teszi a Gitlab számára, hogy társítsa a feladatot a prod környezettel, és helyes linket jelenítsen meg róla.

Most adjunk hozzá még két feladatot:

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

Ezek a feladatok minden branchen történő push esetén elindulnak, kivéve a mastert, és előnézeti verziót fognak telepíteni a weboldalból.

Új opciót látunk a qbec számára: —app-tag — ez lehetővé teszi a telepített alkalmazásverziók címkézését, és csak ezen címkék belül működik. A Kubernetesben a qbec csak velük fog dolgozni az erőforrások létrehozásakor és megszüntetésekor.
Így nem kell külön környezetet létrehoznunk minden egyes áttekintéshez, hanem egyszerűen újra felhasználhatjuk ugyanazt.

Itt szintén használjuk a qbec apply review, a helyett qbec apply default — most próbáljuk leírni a különbségeket a környezetek között (review és default):

Adjunk hozzá egy review környezetet a deploy/website/qbec.yaml

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

Aztán bejelentjük a deploy/website/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

És felvesszük az egyedi paramétereket számára a következő fájlba: deploy/website/environments/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',
    },
  },
}

Nézzük meg részletesebben a stop_review, amely akkor aktiválódik, amikor egy branchet törölnek, és hogy a gitlab ne próbáljon checkout-ot végezni rajta, ezért használjuk a GIT_STRATEGY: none, később klónozunk. master-ágat és rajta keresztül eltávolítjuk a review-t.
Kicsit macerás, de eddig nem találtam szebb módszert.
Alternatív megoldás lehet minden review telepítése egy külön névtérbe, amit teljesen törölni lehet.

Ne felejtsük el elkötelezni a változtatásainkat:

git add .
git commit -m "Automatikus review engedélyezése"

git push, git checkout -b test, git push origin test, ellenőrizzük:

Képernyőkép a létrehozott környezetekről a Gitlab-ban

Új eszközöket tesztelünk a Kubernetes beállításához és automatizált telepítéséhez

Minden működik? — remek, töröljük a teszt ágat: git checkout master, git push origin :test, ellenőrizzük, hogy a környezet törlésére vonatkozó feladatok hiba nélkül futottak-e le.

Itt szeretném pontosítani, hogy ágakat bármely fejlesztő létrehozhat a projektben, az is megváltoztathatja .gitlab-ci.yml a fájlt, és hozzáférést kaphat a titkos változókhoz.
Ezért erősen ajánlott azok használatát csak védett ágakra korlátozni, például a master, vagy létrehozni egy külön változó készletet minden egyes környezethez.

13. Review Apps

Felülvizsgálati alkalmazások ez egy lehetőség a GitLabban, ami lehetővé teszi, hogy minden fájlhoz a repository-ban hozzáadjunk egy gombot az gyors megtekintéshez a telepített környezetben.

Ahhoz, hogy ezek a gombok megjelenjenek, létre kell hozni egy fájlt .gitlab/route-map.yml és le kell írni benne az összes útvonal-transzformációt, a mi esetünkben ez nagyon egyszerű lesz:

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

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

Ne felejtsük el elkötelezni a változtatásainkat:

git add .gitlab/
git commit -m "Review appok engedélyezése"

git push, és ellenőrizzük:

Képernyőkép a Review App gombbal

Új eszközöket tesztelünk a Kubernetes beállításához és automatizált telepítéséhez

A feladat kész!

A projekt forrásai:

Köszönöm a figyelmet, remélem tetszett nektek Új eszközöket tesztelünk a Kubernetes beállításához és automatizált telepítéséhez

Forrás: habr.com

Megbízható hosting vásárlása weboldalak számára, DDoS védelemmel, VPS VDS szerverek. 🔥 Megbízható webtárhely vásárlása DDoS védelemmel, VPS VDS szerverek | ProHoster