
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 , amely automatikusan generálódik a , é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
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 initA 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: , 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 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

A weboldal generálásához elegendő elindítani:
hugoA könyvtár tartalma public/ lesz a weboldalad.
Igen, és azonnal vegyük fel a .gitignore:
echo /public > .gitignoreNe 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 é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 , 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.1Ahol 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

4. Ismerkedés a qbec-el
— 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 deploydirektó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.yamlné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 defaultA kimenetben a renderelt yaml-manifesztusokat fogja látni, amelyeket a default klaszterhez fognak alkalmazni.
Tökéletes, most alkalmazzuk:
qbec apply defaultA 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 defaulthogy 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-runnerAhol:
- — 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

Ú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-runnerEzú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-runnerMost 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.
Í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 defaultha 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 default7. Ismerkedés a git-crypt-tel
— 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 initHa 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 !diffAhogy 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 -eA 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 unlock8. 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/helmAhogy 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 defaultNe 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:
- tagsKé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.1A 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

É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; echoA 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

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 --yesItt több új lehetőséget használtunk a qbec számára:
- —root some/app — lehetővé teszi a konkrét alkalmazás könyvtárának meghatározását
- —force:k8s-context __incluster__ — ez egy varázslatos változó, amely megmondja, hogy a telepítés abban a klaszterben történik, ahol a gitlab-runner fut. Ezt meg kell tenni, mivel különben a qbec megpróbálja megtalálni a megfelelő Kubernetes szervert a kubeconfig fájlban
- —wait — arra kényszeríti a qbec-et, hogy várja meg, amíg az általa létrehozott erőforrások készen állnak, és csak utána fejeződik be sikeres exit-kóddal.
- —yes — egyszerűen letiltja az interaktív shell-t Biztos vagy benne? a telepítés során.
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

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 ágata 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

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

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: manualEzek 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:8443Aztá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

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
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

A feladat kész!
A projekt forrásai:
- a Gitlab-on:
- a GitHub-on:
Köszönöm a figyelmet, remélem tetszett nektek ![]()
Forrás: habr.com
