Nije ark probearje foar it bouwen en automatisearjen fan ynset yn Kubernetes

Nije ark probearje foar it bouwen en automatisearjen fan ynset yn Kubernetes

Hallo! Koartlyn binne in protte koele automatisearring-ark frijjûn sawol foar it bouwen fan Docker-ôfbyldings as foar ynset nei Kubernetes. Yn dit ferbân besleat ik om mei GitLab te boartsjen, har mooglikheden yngeand te studearjen en, fansels, de pipeline op te setten.

Dit wurk is ynspirearre troch de webside kubernetes.io, dat wurdt generearre út boarne koades automatysk, en foar eltse pool fersyk ferstjoerd, de robot generearret automatysk in foarbyld ferzje fan de side mei jo feroarings en jout in keppeling foar besjen.

Ik besocht in ferlykber proses fanôf it begjin te bouwen, mar folslein boud op Gitlab CI en fergese ark dy't ik wend bin te brûken om applikaasjes nei Kubernetes yn te setten. Hjoed sil ik jo einlings mear oer har fertelle.

It artikel sil ark besprekke lykas:
hugo, qbec, kaniko, git-krypt и GitLab CI mei it skeppen fan dynamyske omjouwings.

Ynhâld

  1. Moetsje Hugo
  2. De Dockerfile tariede
  3. Learje mei kaniko
  4. Learje mei qbec
  5. Gitlab-runner besykje mei Kubernetes-útfierder
  6. It ynsetten fan Helm charts mei qbec
  7. Yntroduksje fan git-crypt
  8. It meitsjen fan in toolbox-ôfbylding
  9. Us earste pipeline en gearstalling fan ôfbyldings troch tags
  10. Ynset automatisearring
  11. Artefakten en gearstalling by triuwe nei master
  12. Dynamyske omjouwings
  13. Besjoch Apps

1. Hugo kennen leare

As foarbyld fan ús projekt sille wy besykje om in dokumintaasje-publisearjende side te meitsjen boud op Hugo. Hugo is in statyske ynhâldgenerator.

Foar dyjingen dy't net bekend binne mei statyske generators, sil ik jo in bytsje mear oer har fertelle. Oars as konvinsjonele websidemotoren mei in databank en wat PHP, dy't, as frege troch in brûker, siden op 'e flecht generearje, wurde statyske generators in bytsje oars ûntwurpen. Se tastean jo te nimmen boarnen, meastal in set fan triemmen yn Markdown markup en tema sjabloanen, dan kompilearje se yn in folslein klear webside.

Dat is, as gefolch krije jo in mapstruktuer en in set generearre HTML-bestannen, dy't jo gewoan kinne uploade nei elke goedkeap hosting en in wurkjende webside krije.

Jo kinne Hugo lokaal ynstallearje en it útprobearje:

Inisjalisearjen fan in nije side:

hugo new site docs.example.org

En tagelyk it git repository:

cd docs.example.org
git init

Oant no ta is ús side ûnreplik en om der wat op te ferskinen, moatte wy earst in tema ferbine; in tema is gewoan in set sjabloanen en spesifisearre regels wêrmei ús side wurdt generearre.

Foar it tema sille wy brûke Leare, dy't neffens my perfekt geskikt is foar in dokumintaasjeside.

Ik wol spesjaal omtinken jaan oan it feit dat wy de temabestannen net hoege te bewarjen yn ús projektrepository; ynstee kinne wy ​​it gewoan ferbine mei git submodule:

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

Sa sil ús repository allinich bestannen befetsje dy't direkt relatearre binne oan ús projekt, en it ferbûne tema sil bliuwe as in keppeling nei in spesifyk repository en in commit dêryn, dat is, it kin altyd út 'e orizjinele boarne helle wurde en net bang wêze foar ynkompatibele feroarings.

Litte wy de konfiguraasje korrigearje config.toml:

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

Al op dit stadium kinne jo rinne:

hugo server

En op it adres http://localhost:1313/ kontrolearje ús nij oanmakke webside, alle wizigingen makke yn 'e map fernije automatysk de iepen side yn' e browser, heul handich!

Litte wy besykje in omslach te meitsjen yn ynhâld/_index.md:

# My docs site

## Welcome to the docs!

You will be very smart :-)

Skermôfbylding fan 'e nij oanmakke side

Nije ark probearje foar it bouwen en automatisearjen fan ynset yn Kubernetes

Om in side te generearjen, útfiere gewoan:

hugo

Directory ynhâld iepenbier/ en sil jo webside wêze.
Ja, trouwens, litte wy it daliks oanmeitsje .gitignore:

echo /public > .gitignore

Ferjit net ús wizigingen yn te fieren:

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

2. De Dockerfile tariede

It is tiid om de struktuer fan ús repository te definiearjen. Ik brûk normaal sa'n ding as:

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

  • dockerfiles/ - befetsje mappen mei Dockerfiles en alles wat nedich is foar it bouwen fan ús Docker-ôfbyldings.
  • ynsette/ - befettet mappen foar it ynsetten fan ús applikaasjes nei Kubernetes

Sa sille wy ús earste Dockerfile lâns it paad oanmeitsje 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" ]

Sa't jo sjen kinne, befettet de Dockerfile twa FAN, dizze funksje hjit multi-stage build en lit jo alles net nedich útslute fan 'e definitive dockerôfbylding.
Sa sil de definitive ôfbylding allinich befetsje tsjuster httpd (lichtgewicht HTTP-tsjinner) en iepenbier/ - de ynhâld fan ús statysk oanmakke webside.

Ferjit net ús wizigingen yn te fieren:

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

3. Kennis te meitsjen mei kaniko

As docker-ôfbyldingsbouwer besleat ik te brûken kaniko, om't syn operaasje gjin docker-daemon fereasket, en de bou sels kin wurde útfierd op elke masine en de cache kin direkt yn 'e registraasje opslein wurde, wêrtroch't de needsaak om in folsleine persistente opslach te hawwen elimineert.

Om it byld te bouwen, rinne gewoan de kontener mei kaniko eksekuteur en trochjaan it de hjoeddeistige bouwkontekst; dit kin ek lokaal dien wurde, fia 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

Wêr registry.gitlab.com/kvaps/docs.example.org/website - de namme fan jo dockerôfbylding; nei it bouwen sil it automatysk wurde lansearre yn it docker-register.

Parameter --cache lit jo lagen yn it docker-register yn cache; foar it opjûne foarbyld sille se wurde bewarre yn registry.gitlab.com/kvaps/docs.example.org/website/cache, mar jo kinne opjaan in oar paad mei help fan de parameter --cache-repo.

Skermôfbylding fan docker-registry

Nije ark probearje foar it bouwen en automatisearjen fan ynset yn Kubernetes

4. Yn 'e kunde komme mei qbec

Qbec is in ynset ark wêrmei jo deklaratyf beskriuwe jo applikaasje manifestaasjes en ynsette se nei Kubernetes. It brûken fan Jsonnet as de haadsyntaksis lit jo de beskriuwing fan ferskillen oer meardere omjouwings sterk ferienfâldigje, en elimineert ek koade werhelling hast folslein.

Dit kin benammen wier wêze yn gefallen wêr't jo in applikaasje moatte ynsette op ferskate klusters mei ferskate parameters en se deklaratyf beskriuwe wolle yn Git.

Qbec lit jo ek Helm-diagrammen werjaan troch se de nedige parameters troch te jaan en se dan op deselde manier te betsjinjen as gewoane manifesten, ynklusyf jo kinne ferskate mutaasjes op har tapasse, en dit, op syn beurt, lit jo de needsaak kwytreitsje brûke ChartMuseum. Dat is, jo kinne charts direkt opslaan en werjaan fan git, wêr't se hearre.

Lykas ik earder sei, sille wy alle ynset yn in map opslaan ynsette/:

mkdir deploy
cd deploy

Litte wy ús earste applikaasje inisjalisearje:

qbec init website
cd website

No sjocht de struktuer fan ús applikaasje der sa út:

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

litte wy nei it bestân sjen qbec.yaml:

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

Hjir binne wy ​​foaral ynteressearre yn spec.omjouwings, qbec hat al in standertomjouwing foar ús makke en naam it serveradres, lykas nammeromte fan ús hjoeddeistige kubeconfig.
No by it ynsetten nei standert omjouwing, qbec sil altyd ynsette allinnich nei de oantsjutte Kubernetes kluster en oan de oantsjutte nammeromte, dat is, jo net mear te wikseljen tusken konteksten en nammeromten foar in útfiere in ynset.
As it nedich is, kinne jo de ynstellings yn dit bestân altyd bywurkje.

Al jo omjouwings wurde beskreaun yn qbec.yaml, en yn de triem params.libsonnet, wêr't it seit wêr't de parameters foar har te krijen binne.

Folgjende sjogge wy twa mappen:

  • komponinten/ - alle manifesten foar ús applikaasje sille hjir wurde opslein; se kinne wurde beskreaun sawol yn jsonnet as reguliere yaml-bestannen
  • omjouwings/ - hjir sille wy alle fariabelen (parameters) foar ús omjouwings beskriuwe.

Standert hawwe wy twa triemmen:

  • environments/base.libsonnet - it sil mienskiplike parameters befetsje foar alle omjouwings
  • environments/default.libsonnet - befettet parameters oerskreaun foar it miljeu standert

lit ús iepenje environments/base.libsonnet en foegje parameters ta foar ús earste komponint dêr:

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

Litte wy ek ús earste komponint oanmeitsje komponinten/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,
                },
              },
            ],
          },
        },
      ],
    },
  },
]

Yn dit bestân hawwe wy trije Kubernetes-entiteiten tagelyk beskreaun, dit binne: Deployment, Betsjinning и Ingress. As wy woene, koenen wy se yn ferskate komponinten pleatse, mar op dit stadium sil ien foar ús genôch wêze.

syntaksis jsonnet is heul gelyk oan gewoane json, yn prinsipe is gewoane json al jildich jsonnet, dus it kin earst makliker wêze foar jo om online tsjinsten te brûken lykas yaml2json om jo gewoane yaml yn json te konvertearjen, of, as jo komponinten gjin fariabelen befetsje, dan kinne se wurde beskreaun yn 'e foarm fan reguliere yaml.

By it wurkjen mei jsonnet Ik riede tige oan om in plugin te ynstallearjen foar jo bewurker

Bygelyks, der is in plugin foar vim vim-jsonnet, dy't syntaksis markearring ynskeakelt en automatysk útfiert jsonnet fmt eltse kear as jo bewarje (fereasket jsonnet ynstallearre).

Alles is klear, no kinne wy ​​begjinne te ynsetten:

Om te sjen wat wy hawwe, litte wy rinne:

qbec show default

By de útfier sille jo werjûn yaml-manifesten sjen dy't sille wurde tapast op it standertkluster.

Geweldich, jilde no:

qbec apply default

By de útfier sille jo altyd sjen wat der dien wurdt yn jo kluster, qbec sil jo freegje om yn te stimmen mei de wizigingen troch te typen y do silst wêze kinne om te befêstigjen dyn bedoelingen.

Us applikaasje is klear en ynset!

As jo ​​​​wizigingen meitsje, kinne jo altyd dwaan:

qbec diff default

om te sjen hoe't dizze feroarings de hjoeddeistige ynset beynfloedzje

Ferjit net ús wizigingen yn te fieren:

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

5. Besykje Gitlab-runner mei Kubernetes-útfierder

Oant koartlyn brûkte ik gewoan gewoan gitlab-runner op in pre-tariede masine (LXC container) mei shell of docker-útfierder. Yn it earstoan hiene wy ​​ferskate sokke runners wrâldwiid definieare yn ús gitlab. Se sammele docker-ôfbyldings foar alle projekten.

Mar as praktyk hat sjen litten, dizze opsje is net de meast ideaal, sawol yn termen fan praktykens en feiligens. It is folle better en ideologysk korrekter om foar elk projekt, of sels foar elke omjouwing, aparte runners yn te setten.

Gelokkich is dit hielendal gjin probleem, want no sille wy ynsette gitlab-runner direkt as ûnderdiel fan ús projekt rjochts yn Kubernetes.

Gitlab leveret in klear makke helmkaart foar it ynsetten fan gitlab-runner nei Kubernetes. Dat alles wat jo hoege te dwaan is útfine registraasje token foar ús projekt yn Ynstellings -> CI / CD -> Runners en jou it oan it roer:

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

Wêr:

  • https://gitlab.com - it adres fan jo Gitlab-tsjinner.
  • yga8y-jdCusVDn_t4Wxc - registraasjetoken foar jo projekt.
  • rbac.create=wier - jout de runner de nedige hoemannichte privileezjes om pods te meitsjen om ús taken út te fieren mei kubernetes-executor.

As alles goed is dien, moatte jo in registrearre rinner sjen yn 'e seksje Runners, yn jo projektynstellingen.

Skermprint fan de tafoege runner

Nije ark probearje foar it bouwen en automatisearjen fan ynset yn Kubernetes

Is it sa ienfâldich? - ja, sa ienfâldich is it! Gjin gedoe mear mei it manuell registrearjen fan runners, fan no ôf wurde runners automatysk oanmakke en ferneatige.

6. Ynsette Helm charts mei QBEC

Sûnt wy besletten om te beskôgje gitlab-runner diel fan ús projekt, it is tiid om it te beskriuwen yn ús Git-repository.

Wy kinne it omskriuwe as in aparte komponint website, mar yn 'e takomst planje wy ferskate eksimplaren yn te setten website hiel faak, oars as gitlab-runner, dy't mar ien kear per Kubernetes-kluster ynset wurde sil. Litte wy dus in aparte applikaasje foar inisjalisearje:

cd deploy
qbec init gitlab-runner
cd gitlab-runner

Dizze kear sille wy Kubernetes-entiteiten net manuell beskriuwe, mar sille in klear makke Helm-diagram nimme. Ien fan 'e foardielen fan qbec is de mooglikheid om Helm-diagrammen direkt út in Git-repository te werjaan.

Litte wy it ferbine mei git submodule:

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

No de map ferkeaper/gitlab-runner Wy hawwe in repository mei in diagram foar gitlab-runner.

Op in fergelykbere manier kinne jo oare repositories ferbine, bygelyks it heule repository mei offisjele charts https://github.com/helm/charts

Litte wy de komponint beskriuwe komponinten/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,
  }
)

It earste argumint oan expandHelmTemplate wy passe it paad nei de kaart, dan params.values, dy't wy nimme fan 'e omjouwingsparameters, dan komt it objekt mei

  • nammeTemplate - release namme
  • nammeromte - nammeromte oerdroegen oan roer
  • dizze triem - in fereaske parameter dy't it paad trochjaan nei it aktuele bestân
  • verbose - toant it kommando helm sjabloan mei alle arguminten by it werjaan fan de grafyk

Litte wy no de parameters beskriuwe foar ús komponint yn 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,
      },
    },
  },
}

Wês oandacht runnerRegistrationToken wy nimme út in eksterne triem secrets/base.libsonnet, litte wy it oanmeitsje:

{
  runnerRegistrationToken: 'yga8y-jdCusVDn_t4Wxc',
}

Litte wy kontrolearje as alles wurket:

qbec show default

as alles yn oarder is, dan kinne wy ​​ús earder ynsetten release wiskje fia Helm:

helm uninstall gitlab-runner

en ynsette it op deselde manier, mar fia qbec:

qbec apply default

7. Ynlieding ta git-krypt

Git-krypt is in ark wêrmei jo transparante fersifering ynstelle kinne foar jo repository.

Op it stuit sjocht ús mapstruktuer foar gitlab-runner der sa út:

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

Mar it opslaan fan geheimen yn Git is net feilich, is it? Dat wy moatte se goed fersiferje.

Meastentiids hat dit om 'e wille fan ien fariabele net altyd sin. Jo kinne oerdrage geheimen oan qbec en troch de omjouwingsfariabelen fan jo CI-systeem.
Mar it is de muoite wurdich op te merken dat d'r ek mear komplekse projekten binne dy't folle mear geheimen kinne befetsje; it oerdragen fan se allegear fia omjouwingsfariabelen sil ekstreem lestich wêze.

Boppedat soe ik yn dit gefal net kinne fertelle oer sa'n prachtich ark as git-krypt.

git-krypt It is ek handich om't it jo de heule skiednis fan geheimen kinne bewarje, lykas konflikten fergelykje, gearfoegje en oplosse op deselde manier as wy wend binne te dwaan yn it gefal fan Git.

Earste ding nei ynstallaasje git-krypt wy moatte kaaien generearje foar ús repository:

git crypt init

As jo ​​​​in PGP-kaai hawwe, dan kinne jo josels direkt tafoegje as meiwurker foar dit projekt:

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

Op dizze manier kinne jo dizze repository altyd ûntsiferje mei jo privee kaai.

As jo ​​​​gjin PGP-kaai hawwe en it net ferwachtsje, dan kinne jo de oare manier gean en de projektkaai eksportearje:

git crypt export-key /path/to/keyfile

Sa, elkenien dy't hat in eksportearre keyfile sil jo repository kinne ûntsiferje.

It is tiid om ús earste geheim op te stellen.
Lit my jo herinnerje dat wy noch yn 'e map binne deploy/gitlab-runner/, wêr't wy in map hawwe geheimen/, lit ús alle bestannen dêryn fersiferje, dêrfoar meitsje wy in bestân geheimen/.gitattributes mei de folgjende ynhâld:

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

Lykas út 'e ynhâld kin wurde sjoen, binne alle bestannen maskere * sil trochriden wurde git-krypt, útsein foar de measte .gitattributes

Wy kinne dit kontrolearje troch te rinnen:

git crypt status -e

De útfier sil in list wêze fan alle bestannen yn it repository wêrfoar fersifering ynskeakele is

Dat is alles, no kinne wy ​​ús wizigingen feilich dwaan:

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

Om in repository te blokkearjen, útfiere gewoan:

git crypt lock

en daliks sille alle fersifere bestannen yn binêr wat feroarje, it sil ûnmooglik wêze om se te lêzen.
Om it repository te ûntsiferjen, útfiere:

git crypt unlock

8. Meitsje in arkôfbylding

In toolbox-ôfbylding is in ôfbylding mei alle ark dy't wy sille brûke om ús projekt yn te setten. It sil brûkt wurde troch de Gitlab runner om typyske ynsettaken út te fieren.

Alles is hjir ienfâldich, litte wy in nije meitsje dockerfiles/toolbox/Dockerfile mei de folgjende ynhâld:

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

Sa't jo sjen kinne, yn dizze ôfbylding ynstallearje wy alle nutsbedriuwen dy't wy brûkten om ús applikaasje yn te setten. Wy hawwe it hjir net nedich, útsein as kubectl, mar jo wolle der miskien mei boartsje yn 'e pipeline-ynstellingsfaze.

Ek, om te kinnen kommunisearje mei Kubernetes en dêryn ynsette, moatte wy in rol konfigurearje foar de pods generearre troch gitlab-runner.

Om dit te dwaan, litte wy nei de map gean mei gitlab-runner:

cd deploy/gitlab-runner

en foegje in nije komponint ta komponinten/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,
      },
    ],
  },
]

Wy sille ek beskriuwe de nije parameters yn environments/base.libsonnet, dy't der no sa útsjocht:

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

Wês oandacht $.components.rbac.name ferwiist nei namme foar komponint rbac

Litte wy kontrolearje wat feroare is:

qbec diff default

en tapasse ús wizigingen op Kubernetes:

qbec apply default

Ferjit ek net om ús wizigingen yn git yn te setten:

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. Us earste pipeline en gearstalling fan bylden troch tags

Oan 'e woartel fan it projekt sille wy meitsje .gitlab-ci.yml mei de folgjende ynhâld:

.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

Tink derom dat wy brûke GIT_SUBMODULE_STRATEGY: normaal foar dy banen dêr't jo moatte eksplisyt inisjalisearje submodules foar útfiering.

Ferjit net ús wizigingen yn te fieren:

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

Ik tink dat wy dit feilich in ferzje neame kinne v0.0.1 en foegje de tag ta:

git tag v0.0.1

Wy sille tags tafoegje as wy in nije ferzje moatte frijjaan. Tags yn Docker-ôfbyldings sille wurde bûn oan Git-tags. Elke druk mei in nije tag sil de bou fan ôfbyldings mei dizze tag inisjalisearje.

Litte wy it dwaan git push --tags, en lit ús nei ús earste pipeline sjen:

Skermprint fan 'e earste pipeline

Nije ark probearje foar it bouwen en automatisearjen fan ynset yn Kubernetes

It is de muoite wurdich om jo oandacht te tekenjen op it feit dat assemblage troch tags geskikt is foar it bouwen fan dockerôfbyldings, mar net geskikt is foar it ynsetten fan in applikaasje nei Kubernetes. Sûnt nije tags kinne wurde tawiisd oan âlde commits, yn dit gefal sil it inisjalisearjen fan 'e pipeline foar har liede ta de ynset fan' e âlde ferzje.

Om dit probleem op te lossen, wurdt normaal de bou fan dockerôfbyldings bûn oan tags, en de ynset fan 'e applikaasje nei in branch master, wêryn ferzjes fan 'e sammele ôfbyldings hurdkodearre binne. Dit is wêr't jo weromrol kinne inisjalisearje mei in ienfâldige weromsette master-tûken.

10. Automatisearring fan ynset

Om Gitlab-runner ús geheimen te ûntsiferjen, moatte wy de repository-kaai eksportearje en tafoegje oan ús CI-omjouwingsfariabelen:

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

Wy sille de resultearjende rigel opslaan yn Gitlab; om dit te dwaan, litte wy nei ús projektynstellingen gean:
Ynstellings -> CI / CD -> Fariabelen

En lit ús in nije fariabele oanmeitsje:

Type
Kaai
Wearde
beskerme
masked
Scope

File
GITCRYPT_KEY
<your string>
true (by de training kinne jo false)
true
All environments

Skermprint fan de tafoege fariabele

Nije ark probearje foar it bouwen en automatisearjen fan ynset yn Kubernetes

No litte wy ús bywurkje .gitlab-ci.yml taheakke oan it:

.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

Hjir hawwe wy ferskate nije opsjes ynskeakele foar qbec:

  • --root guon/app - lit jo de map fan in spesifike applikaasje bepale
  • --force:k8s-kontekst __incluster__ - dit is in magyske fariabele dy't seit dat de ynset sil plakfine yn itselde kluster wêryn gtilab-runner rint. Dit is nedich om't oars qbec sil besykje in geskikte Kubernetes-tsjinner te finen yn jo kubeconfig
  • --wachtsje - twingt qbec om te wachtsjen oant de middels dy't it skept yn 'e Ready-status geane en pas dan útgean mei in suksesfolle útgongskoade.
  • -Ja - Skeakelt gewoan de ynteraktive shell út Bisto wis? wannear ynset.

Ferjit net ús wizigingen yn te fieren:

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

En nei git druk wy sille sjen hoe't ús applikaasjes binne ynset:

Skermprint fan 'e twadde pipeline

Nije ark probearje foar it bouwen en automatisearjen fan ynset yn Kubernetes

11. Artefakten en gearkomste doe't triuwe te master

Typysk binne de hjirboppe beskreaune stappen genôch om hast elke mikrotsjinst te bouwen en te leverjen, mar wy wolle net elke kear in tag tafoegje as wy de side moatte bywurkje. Dêrom sille wy in mear dynamyske rûte nimme en in digest-ynset ynstelle yn 'e mastertûke.

It idee is simpel: no it byld fan ús website sil wurde ferboud eltse kear as jo triuwe yn master, en dan automatysk ynsette nei Kubernetes.

Litte wy dizze twa banen bywurkje yn ús .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"

Tink derom dat wy in thread tafoege hawwe master к refs foar banen build_webside en wy brûke no $CI_COMMIT_REF_NAME вместо $CI_COMMIT_TAG, dat is, wy binne ûntbûn fan tags yn Git en no sille wy in ôfbylding drukke mei de namme fan 'e commit-tûke dy't de pipeline inisjalisearre. It is de muoite wurdich op te merken dat dit ek sil wurkje mei tags, wêrtroch't wy snapshots fan in side mei in spesifike ferzje kinne bewarje yn it docker-register.

As de namme fan 'e docker-tag foar in nije ferzje fan' e side net feroare wurde kin, moatte wy de wizigingen yn Kubernetes noch beskriuwe, oars sil it de applikaasje gewoan net opnij ynsette fan 'e nije ôfbylding, om't it gjin feroaringen sil fernimme yn' e ynset manifest.

Opsje —vm:ext-str digest="$DIGEST" foar qbec - kinne jo trochjaan in eksterne fariabele oan jsonnet. Wy wolle dat it opnij ynset wurdt yn it kluster mei elke release fan ús applikaasje. Wy kinne de tagnamme net mear brûke, dy't no ûnferoarlik wêze kin, om't wy moatte wurde bûn oan in spesifike ferzje fan 'e ôfbylding en de ynset trigger as it feroaret.

Hjir sille wy wurde holpen troch Kaniko's fermogen om in digestôfbylding op te slaan yn in bestân (opsje --digest-bestân)
Dan sille wy dit bestân oerdrage en lêze op it momint fan ynset.

Litte wy de parameters foar ús bywurkje deploy/website/environments/base.libsonnet dat sil der no sa útsjen:

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

Dien, no elke commit yn master inisjalisearret de bou fan 'e dockerôfbylding foar website, en ynsette it dan nei Kubernetes.

Ferjit net ús wizigingen yn te fieren:

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

Wy sille letter kontrolearje git druk wy moatte sa'n ding sjen:

Skermprint fan 'e pipeline foar master

Nije ark probearje foar it bouwen en automatisearjen fan ynset yn Kubernetes

Yn prinsipe hoege wy gitlab-runner net mei elke druk opnij yn te setten, útsein as, fansels, neat feroare is yn syn konfiguraasje, litte wy it reparearje yn .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/**/*

feroarings sil tastean jo tafersjoch te hâlden feroarings yn deploy/gitlab-runner/ en sil ús baan allinich trigger as d'r ien binne

Ferjit net ús wizigingen yn te fieren:

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

git druk, dat is better:

Skermprint fan de bywurke pipeline

Nije ark probearje foar it bouwen en automatisearjen fan ynset yn Kubernetes

12. Dynamyske omjouwings

It is tiid om ús pipeline te diversifiëren mei dynamyske omjouwings.

Lit ús earst de baan bywurkje build_webside yn ús .gitlab-ci.yml, it fuortsmiten fan it blok út it allinnich, dy't Gitlab twingt om it te triggerjen op elke commit nei elke branch:

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/

Dan bywurkje de baan deploy_website, foegje dêr in blok ta miljeu:

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"

Dit sil Gitlab de baan kinne assosjearje mei produksje omjouwing en werjaan de juste keppeling nei it.

Litte wy no noch twa banen tafoegje:

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

Se wurde lansearre by push nei alle tûken útsein master en sille de foarbyldferzje fan 'e side ynsette.

Wy sjogge in nije opsje foar qbec: --app-tag - it lit jo ynsette ferzjes fan 'e applikaasje taggje en allinich binnen dizze tag wurkje; by it meitsjen en ferneatigjen fan boarnen yn Kubernetes, sil qbec allinich mei har operearje.
Op dizze manier kinne wy ​​net in aparte omjouwing meitsje foar elke resinsje, mar deselde ien gewoan opnij brûke.

Hjir brûke wy ek qbec tapasse resinsje, yn plak fan qbec tapasse standert - dit is krekt it momint dat wy sille besykje de ferskillen foar ús omjouwings te beskriuwen (resinsje en standert):

Litte wy tafoegje resinsje miljeu yn deploy/website/qbec.yaml

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

Dan sille wy it yn ferklearje 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

En skriuw de oanpaste parameters dêrfoar yn 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',
    },
  },
}

Lit ús ek ris efkes nei jobu sjen stop_review, it sil wurde aktivearre as de tûke wurdt wiske en sadat gitlab net besiket te kontrolearjen wurdt it brûkt GIT_STRATEGY: gjin, letter klone wy master-takke en wiskje resinsje troch it.
It is in bytsje betiizjend, mar ik haw noch net fûn in moaier manier.
In alternative opsje soe wêze om elke resinsje yn te setten op in hotelnammeromte, dy't altyd hielendal ôfbrutsen wurde kin.

Ferjit net ús wizigingen yn te fieren:

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

git druk, git checkout -b test, git push oarsprong test, kontrolearje:

Skermôfbylding fan makke omjouwings yn Gitlab

Nije ark probearje foar it bouwen en automatisearjen fan ynset yn Kubernetes

Alles wurket? - geweldich, wiskje ús testtûke: git kassa master, git push oarsprong: test, wy kontrolearje dat de omjouwing wiskjen banen wurke sûnder flaters.

Hjir wol ik fuortendaliks dúdlik meitsje dat elke ûntwikkelder yn in projekt tûken kin meitsje, hy kin ek feroarje .gitlab-ci.yml triem en tagong geheime fariabelen.
Dêrom wurdt it sterk oanrikkemandearre om har gebrûk allinich te tastean foar beskerme tûken, bygelyks yn master, of meitsje in aparte set fan fariabelen foar elke omjouwing.

13. Resinsje Apps

Besjoch Apps Dit is in GitLab-funksje wêrmei jo in knop kinne tafoegje foar elk bestân yn 'e repository om it fluch te besjen yn in ynset omjouwing.

Om dizze knoppen te ferskinen, moatte jo in bestân oanmeitsje .gitlab/route-map.yml en beskriuw alle paadtransformaasjes dêryn; yn ús gefal sil it heul ienfâldich wêze:

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

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

Ferjit net ús wizigingen yn te fieren:

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

git druk, en kontrolearje:

Skermôfbylding fan 'e knop Review App

Nije ark probearje foar it bouwen en automatisearjen fan ynset yn Kubernetes

Job is dien!

Projekt boarnen:

Tankewol foar jo oandacht, ik hoopje dat jo it leuk fine Nije ark probearje foar it bouwen en automatisearjen fan ynset yn Kubernetes

Boarne: www.habr.com

Add a comment