Provante novajn ilojn por konstrui kaj aŭtomatigi deplojon en Kubernetes

Provante novajn ilojn por konstrui kaj aŭtomatigi deplojon en Kubernetes

Saluton! Lastatempe, multaj bonegaj aŭtomatigaj iloj estis publikigitaj kaj por konstrui Docker-bildojn kaj por disfaldi al Kubernetes. Ĉi-rilate, mi decidis ludi kun GitLab, ĝisfunde studi ĝiajn kapablojn kaj, kompreneble, agordi la dukton.

Ĉi tiu verko estis inspirita de la retejo kubernetes.io, kiu estas generita de fontkodoj aŭtomate, kaj por ĉiu naĝejo sendita, la roboto aŭtomate generas antaŭrigardan version de la retejo kun viaj ŝanĝoj kaj provizas ligilon por vidi.

Mi provis konstrui similan procezon de nulo, sed tute konstruita sur Gitlab CI kaj senpagaj iloj, kiujn mi kutimas uzi por disfaldi aplikaĵojn al Kubernetes. Hodiaŭ mi finfine rakontos al vi pli pri ili.

La artikolo diskutos pri iloj kiel:
Hugo, qbec, kaniko, git-crypt и GitLab CI kun la kreado de dinamikaj medioj.

Enhavo

  1. Renkontu Hugo'n
  2. Preparante la Dockerfile
  3. Konatiĝi kun kaniko
  4. Konatiĝi kun qbec
  5. Provante Gitlab-runner kun Kubernetes-executor
  6. Deplojante Helm-diagramojn kun qbec
  7. Enkonduko de git-crypt
  8. Kreante bildon de ilkesto
  9. Nia unua dukto kaj aro de bildoj per etikedoj
  10. Deploja aŭtomatigo
  11. Artefaktoj kaj asembleo kiam puŝado por majstri
  12. Dinamikaj medioj
  13. Revizii Apojn

1. Konatiĝi kun Hugo

Kiel ekzemplo de nia projekto, ni provos krei dokumentaran eldonejon konstruitan sur Hugo. Hugo estas statika enhavo-generatoro.

Por tiuj, kiuj ne konas statikajn generatorojn, mi rakontos al vi iom pli pri ili. Male al konvenciaj retejo-motoroj kun datumbazo kaj iom da PHP, kiuj, kiam petotaj de uzanto, generas paĝojn sur la flugo, statikaj generatoroj estas desegnitaj iomete alimaniere. Ili permesas al vi preni fontojn, kutime aron da dosieroj en Markdown-markado kaj temoŝablonoj, poste kompili ilin en tute finitan retejon.

Tio estas, kiel rezulto, vi ricevos dosierujon kaj aron de generitaj HTML-dosieroj, kiujn vi povas simple alŝuti al iu ajn malmultekosta gastigado kaj akiri funkciantan retejon.

Vi povas instali Hugo-on loke kaj provi ĝin:

Komencante novan retejon:

hugo new site docs.example.org

Kaj samtempe la git-deponejo:

cd docs.example.org
git init

Ĝis nun, nia retejo estas pura kaj por ke io aperu sur ĝi, ni unue devas konekti temon; temo estas nur aro da ŝablonoj kaj specifitaj reguloj per kiuj nia retejo estas generita.

Por la temo ni uzos lerni, kiu laŭ mi perfekte taŭgas por dokumenta retejo.

Mi ŝatus prunti specialan atenton al la fakto, ke ni ne bezonas konservi la temdosierojn en nia projekta deponejo; anstataŭe, ni povas simple konekti ĝin uzante git-submodulo:

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

Tiel, nia deponejo enhavos nur dosierojn rekte rilatajn al nia projekto, kaj la ligita temo restos kiel ligilo al specifa deponejo kaj kompromiso en ĝi, tio estas, ĝi ĉiam povas esti tirita de la origina fonto kaj ne timi. nekongruaj ŝanĝoj.

Ni korektu la agordon agordo.toml:

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

Jam en ĉi tiu etapo vi povas kuri:

hugo server

Kaj ĉe la adreso http://localhost:1313/ kontrolu nian nove kreitan retejon, ĉiuj ŝanĝoj faritaj en la dosierujo aŭtomate ĝisdatigas la malfermitan paĝon en la retumilo, tre oportune!

Ni provu krei kovrilpaĝon en enhavo/_index.md:

# My docs site

## Welcome to the docs!

You will be very smart :-)

Ekrankopio de la nove kreita paĝo

Provante novajn ilojn por konstrui kaj aŭtomatigi deplojon en Kubernetes

Por generi retejon, simple rulu:

hugo

Dosierujo enhavo publika/ kaj estos via retejo.
Jes, cetere, ni tuj aldonu ĝin .gitignore:

echo /public > .gitignore

Ne forgesu fari niajn ŝanĝojn:

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

2. Preparante la Dockerfile

Estas tempo por difini la strukturon de nia deponejo. Mi kutime uzas ion kiel:

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

  • dockerfiles/ — enhavas dosierujojn kun Dockerfiles kaj ĉion necesan por konstrui niajn Docker-bildojn.
  • deploji/ — enhavas dosierujojn por disfaldi niajn aplikaĵojn al Kubernetes

Tiel, ni kreos nian unuan Dockerfile laŭ la vojo dockerfiles/retejo/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" ]

Kiel vi povas vidi, la Dockerfile enhavas du FROM, ĉi tiu funkcio nomiĝas plurŝtupa konstruo kaj permesas al vi ekskludi ĉion nenecesan de la fina docker-bildo.
Tiel, la fina bildo nur enhavos mallumohttpd (malpeza HTTP-servilo) kaj publika/ — la enhavo de nia statike generita retejo.

Ne forgesu fari niajn ŝanĝojn:

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

3. Konatiĝi kun kaniko

Kiel docker-bildkonstruanto, mi decidis uzi kaniko, ĉar ĝia funkciado ne postulas docker-demonon, kaj la konstruo mem povas esti farita sur iu ajn maŝino kaj la kaŝmemoro povas esti stokita rekte en la registro, tiel forigante la bezonon havi plenkreskan konstantan stokadon.

Por konstrui la bildon, simple rulu la ujon per kaniko executor kaj transdonu al ĝi la nunan konstruan kuntekston; ĉi tio ankaŭ povas esti farita loke, per 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

Kie registry.gitlab.com/kvaps/docs.example.org/website — la nomo de via docker-bildo; post konstruado, ĝi estos aŭtomate lanĉita en la docker-registro.

Parametro --kaŝaĵo permesas vin konservi tavolojn en la docker-registro; por la ekzemplo donita, ili estos konservitaj enen registry.gitlab.com/kvaps/docs.example.org/website/cache, sed vi povas specifi alian vojon uzante la parametron --cache-repo.

Ekrankopio de docker-registry

Provante novajn ilojn por konstrui kaj aŭtomatigi deplojon en Kubernetes

4. Konatiĝi kun qbec

Qbec estas disfalda ilo, kiu permesas vin deklare priskribi viajn aplikaĵajn manifestojn kaj disfaldi ilin al Kubernetes. Uzante Jsonnet kiel la ĉefan sintakson ebligas al vi multe simpligi la priskribon de diferencoj tra pluraj medioj, kaj ankaŭ preskaŭ tute forigas kodan ripeton.

Ĉi tio povas esti precipe vera en kazoj kie vi devas deploji aplikaĵon al pluraj aretoj kun malsamaj parametroj kaj volas deklare priskribi ilin en Git.

Qbec ankaŭ ebligas al vi bildigi Helm-diagramojn pasante al ili la necesajn parametrojn kaj poste funkcii ilin sammaniere kiel regulaj manifestoj, inkluzive de vi povas apliki diversajn mutaciojn al ili, kaj ĉi tio, siavice, ebligas vin forigi la bezonon. uzu ChartMuseum. Tio estas, vi povas stoki kaj redoni diagramojn rekte de git, kie ili apartenas.

Kiel mi diris pli frue, ni stokos ĉiujn deplojojn en la dosierujo deploji/:

mkdir deploy
cd deploy

Ni pravigu nian unuan aplikaĵon:

qbec init website
cd website

Nun la strukturo de nia aplikaĵo aspektas jene:

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

ni rigardu la dosieron qbec.yaml:

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

Ĉi tie ni ĉefe interesiĝas spec.medioj, qbec jam kreis defaŭltan medion por ni kaj prenis la servilan adreson, same kiel nomspacon de nia nuna kubeconfig.
Nun kiam deplojiĝas al defaŭlte medio, qbec ĉiam disfaldiĝos nur al la specifita Kubernetes-areo kaj al la specifita nomspaco, tio estas, vi ne plu devas ŝanĝi inter kuntekstoj kaj nomspacoj por plenumi disfaldiĝon.
Se necese, vi ĉiam povas ĝisdatigi la agordojn en ĉi tiu dosiero.

Ĉiuj viaj medioj estas priskribitaj en qbec.yaml, kaj en la dosiero params.libsonnet, kie ĝi diras kie akiri la parametrojn por ili.

Poste ni vidas du dosierujojn:

  • komponantoj / — ĉiuj manifestoj por nia aplikaĵo estos konservitaj ĉi tie; ili povas esti priskribitaj kaj en jsonnet kaj regulaj yaml-dosieroj
  • medioj/ — ĉi tie ni priskribos ĉiujn variablojn (parametrojn) por niaj medioj.

Defaŭlte ni havas du dosierojn:

  • medioj/bazo.libsonnet - ĝi enhavos komunajn parametrojn por ĉiuj medioj
  • medioj/default.libsonnet — enhavas parametrojn anstataŭitajn por la medio defaŭlte

ni malfermu medioj/bazo.libsonnet kaj aldonu parametrojn por nia unua komponanto tie:

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

Ni kreu ankaŭ nian unuan komponanton komponantoj/retejo.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,
                },
              },
            ],
          },
        },
      ],
    },
  },
]

En ĉi tiu dosiero ni priskribis tri Kubernetes-entaĵojn samtempe, ĉi tiuj estas: deplojo, servo и Ingreso. Se ni volus, ni povus meti ilin en malsamajn komponantojn, sed en ĉi tiu etapo unu sufiĉos por ni.

sintakso jsonnet estas tre simila al regula json, principe, regula json jam validas jsonnet, do komence eble estos pli facile por vi uzi retajn servojn kiel yaml2json por konverti vian kutiman yaml en json, aŭ, se viaj komponantoj ne enhavas ajnajn variablojn, tiam ili povas esti priskribitaj en la formo de regula yaml.

Laborante kun jsonnet Mi tre rekomendas instali kromprogramon por via redaktilo

Ekzemple, ekzistas kromaĵo por vim vim-jsonnet, kiu ŝaltas sintakson reliefigon kaj aŭtomate efektivigas jsonnet fmt ĉiufoje kiam vi konservas (postulas jsonnet instalita).

Ĉio estas preta, nun ni povas komenci deploji:

Por vidi kion ni ricevis, ni kuru:

qbec show default

Ĉe la eligo, vi vidos prezentitajn yaml-manifestojn, kiuj estos aplikitaj al la defaŭlta areto.

Bonege, nun apliku:

qbec apply default

Ĉe la eligo vi ĉiam vidos, kio estos farita en via areto, qbec petos vin konsenti pri la ŝanĝoj tajpante y vi povos konfirmi viajn intencojn.

Nia aplikaĵo estas preta kaj deplojita!

Se vi faras ŝanĝojn, vi ĉiam povas fari:

qbec diff default

por vidi kiel ĉi tiuj ŝanĝoj influos la nunan deplojon

Ne forgesu fari niajn ŝanĝojn:

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

5. Provante Gitlab-runner kun Kubernetes-executor

Ĝis antaŭ nelonge mi nur uzis regulan gitlab-kuristo sur antaŭpreparita maŝino (LXC-ujo) kun ŝelo aŭ docker-ekzekutoro. Komence, ni havis plurajn tiajn kuristojn tutmonde difinitajn en nia gitlab. Ili kolektis docker-bildojn por ĉiuj projektoj.

Sed kiel la praktiko montris, ĉi tiu opcio ne estas la plej ideala, kaj laŭ praktikeco kaj sekureco. Estas multe pli bone kaj ideologie pli ĝuste havi apartajn kuristojn deplojitaj por ĉiu projekto, aŭ eĉ por ĉiu medio.

Feliĉe, ĉi tio tute ne estas problemo, ĉar nun ni disfaldiĝos gitlab-kuristo rekte kiel parto de nia projekto ĝuste en Kubernetes.

Gitlab disponigas pretan stirilan diagramon por deploji gitlab-runner al Kubernetes. Do ĉio, kion vi devas fari, estas ekscii registra ĵetono por nia projekto en Agordoj -> CI / KD -> Kuriloj kaj pasigu ĝin al stirilo:

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

Kie:

  • https://gitlab.com — la adreso de via Gitlab-servilo.
  • yga8y-jdCusVDn_t4Wxc — registriĝo por via projekto.
  • rbac.create=true — provizas al la kuristo la necesan kvanton da privilegioj por povi krei podojn por plenumi niajn taskojn per kubernetes-executor.

Se ĉio estas farita ĝuste, vi devus vidi registritan kuriston en la sekcio Koridoroj, en viaj projektaj agordoj.

Ekrankopio de la aldonita kuristo

Provante novajn ilojn por konstrui kaj aŭtomatigi deplojon en Kubernetes

Ĉu tiel simple? - Jes, ĝi estas tiel simpla! Ne plu ĝenas registri kuristojn permane, de nun kuristoj estos aŭtomate kreitaj kaj detruitaj.

6. Deploji Helm-leterojn kun QBEC

Ĉar ni decidis konsideri gitlab-kuristo parto de nia projekto, estas tempo priskribi ĝin en nia Git-deponejo.

Ni povus priskribi ĝin kiel apartan komponanton retejo, sed estonte ni planas disfaldi malsamajn kopiojn retejo tre ofte, male al gitlab-kuristo, kiu estos deplojita nur unufoje per Kubernetes-areto. Do ni pravigu apartan aplikaĵon por ĝi:

cd deploy
qbec init gitlab-runner
cd gitlab-runner

Ĉi-foje ni ne priskribos Kubernetes-entaĵojn permane, sed prenos pretan Helm-diagramon. Unu el la avantaĝoj de qbec estas la kapablo redoni Helm-diagramojn rekte de Git-deponejo.

Ni konektu ĝin per git-submodulo:

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

Nun la dosierujo vendisto/gitlab-kuristo Ni havas deponejon kun diagramo por gitlab-runner.

Simile, vi povas konekti aliajn deponejojn, ekzemple la tutan deponejon kun oficialaj leteroj https://github.com/helm/charts

Ni priskribu la komponanton 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,
  }
)

La unua argumento al vastigi HelmTemplate ni pasas la vojon al la diagramo, do params.valoroj, kiun ni prenas el la medio-parametroj, tiam venas la objekto kun

  • nomo Ŝablono — eldonnomo
  • nomspaco — nomspaco transdonita al helmo
  • ĉi tiu dosiero — bezonata parametro, kiu pasas la vojon al la nuna dosiero
  • multvorta - montras la komandon stirila ŝablono kun ĉiuj argumentoj dum la bildigo de la diagramo

Nun ni priskribu la parametrojn por nia komponanto en medioj/bazo.libsonnet:

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

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

Atentu runnerRegistrationToken ni prenas el ekstera dosiero secrets/base.libsonnet, ni kreu ĝin:

{
  runnerRegistrationToken: 'yga8y-jdCusVDn_t4Wxc',
}

Ni kontrolu ĉu ĉio funkcias:

qbec show default

se ĉio estas en ordo, tiam ni povas forigi nian antaŭe deplojitan eldonon per Helm:

helm uninstall gitlab-runner

kaj deploji ĝin same, sed per qbec:

qbec apply default

7. Enkonduko al git-crypt

Git-kripto estas ilo, kiu ebligas al vi agordi travideblan ĉifradon por via deponejo.

Nuntempe, nia dosierujo-strukturo por gitlab-runner aspektas jene:

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

Sed konservi sekretojn en Git ne estas sekura, ĉu? Do ni devas ĉifri ilin ĝuste.

Kutime, pro unu variablo, ĉi tio ne ĉiam havas sencon. Vi povas transdoni sekretojn al qbec kaj tra la mediovariabloj de via CI-sistemo.
Sed indas noti, ke ekzistas ankaŭ pli kompleksaj projektoj, kiuj povas enhavi multajn pli da sekretoj; transdoni ilin ĉiujn per medio-variabloj estos ege malfacila.

Cetere, ĉi-kaze mi ne povus rakonti al vi pri tia mirinda ilo kiel git-crypt.

git-crypt Ĝi ankaŭ estas oportuna ĉar ĝi permesas vin konservi la tutan historion de sekretoj, kaj ankaŭ kompari, kunfandi kaj solvi konfliktojn same kiel ni kutimas fari en la kazo de Git.

Unua afero post instalado git-crypt ni devas generi ŝlosilojn por nia deponejo:

git crypt init

Se vi havas PGP-ŝlosilon, vi povas tuj aldoni vin kiel kunlaboranton por ĉi tiu projekto:

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

Tiel vi ĉiam povas deĉifri ĉi tiun deponejon uzante vian privatan ŝlosilon.

Se vi ne havas PGP-ŝlosilon kaj ne atendas ĝin, tiam vi povas iri la alian vojon kaj eksporti la projekt-ŝlosilon:

git crypt export-key /path/to/keyfile

Tiel, ĉiu, kiu havas eksportitan ŝlosildosiero povos malĉifri vian deponejon.

Estas tempo starigi nian unuan sekreton.
Mi memorigu vin, ke ni ankoraŭ estas en la dosierujo deploy/gitlab-runner/, kie ni havas dosierujon sekretoj/, ni ĉifri ĉiujn dosierojn en ĝi, por tio ni kreos dosieron sekretoj/.gitattributes kun la sekva enhavo:

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

Kiel videblas el la enhavo, ĉiuj dosieroj estas maskitaj * estos pelita tra git-crypt, krom la plej granda parto .gitattributes

Ni povas kontroli ĉi tion rulante:

git crypt status -e

La eligo estos listo de ĉiuj dosieroj en la deponejo por kiuj ĉifrado estas ebligita

Jen ĉio, nun ni povas sekure fari niajn ŝanĝojn:

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

Por bloki deponejon, simple rulu:

git crypt lock

kaj tuj ĉiuj ĉifritaj dosieroj fariĝos binara io, estos neeble legi ilin.
Por deĉifri la deponejon, rulu:

git crypt unlock

8. Kreu ilokeston bildon

Bildo de ilujo estas bildo kun ĉiuj iloj, kiujn ni uzos por disfaldi nian projekton. Ĝi estos uzata de la Gitlab-kuristo por plenumi tipajn deplojajn taskojn.

Ĉio estas simpla ĉi tie, ni kreu novan dockerfiles/ilokesto/Dockerfile kun la sekva enhavo:

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

Kiel vi povas vidi, en ĉi tiu bildo ni instalas ĉiujn ilojn, kiujn ni uzis por disfaldi nian aplikaĵon. Ni ne bezonas ĝin ĉi tie krom se kubectl, sed vi eble volas ludi kun ĝi dum la fazo de aranĝo de dukto.

Ankaŭ, por povi komuniki kun Kubernetes kaj disfaldi al ĝi, ni devas agordi rolon por la podoj generitaj de gitlab-runner.

Por fari tion, ni iru al la dosierujo kun gitlab-runner:

cd deploy/gitlab-runner

kaj aldonu novan komponanton 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,
      },
    ],
  },
]

Ni ankaŭ priskribos la novajn parametrojn en medioj/bazo.libsonnet, kiu nun aspektas jene:

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

Atentu $.components.rbac.name rilatas al nomo por komponanto rbac

Ni kontrolu, kio ŝanĝiĝis:

qbec diff default

kaj apliki niajn ŝanĝojn al Kubernetes:

qbec apply default

Ankaŭ, ne forgesu fari niajn ŝanĝojn al git:

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

9. Nia unua dukto kaj aro de bildoj per etikedoj

Ĉe la radiko de la projekto ni kreos .gitlab-ci.yml kun la sekva enhavo:

.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

Bonvolu noti, ke ni uzas GIT_SUBMODULE_STRATEGY: normala por tiuj laboroj, kie vi devas eksplicite pravalorigi submodulojn antaŭ ekzekuto.

Ne forgesu fari niajn ŝanĝojn:

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

Mi pensas, ke ni sekure povas nomi tion versio v0.0.1 kaj aldonu la etikedon:

git tag v0.0.1

Ni aldonos etikedojn kiam ajn ni bezonos publikigi novan version. Etikedoj en Docker-bildoj estos ligitaj al Git-etikedoj. Ĉiu puŝo kun nova etikedo pravalorigos la konstruon de bildoj kun ĉi tiu etikedo.

Ni faru ĝin git push --tags, kaj ni rigardu nian unuan dukton:

Ekrankopio de la unua dukto

Provante novajn ilojn por konstrui kaj aŭtomatigi deplojon en Kubernetes

Indas atentigi vin pri la fakto, ke kunigo per etikedoj taŭgas por konstrui docker-bildojn, sed ne taŭgas por disfaldi aplikaĵon al Kubernetes. Ĉar novaj etikedoj povas esti asignitaj al malnovaj komits, en ĉi tiu kazo, pravalorigi la dukton por ili kondukos al la deplojo de la malnova versio.

Por solvi ĉi tiun problemon, kutime la konstruo de docker-bildoj estas ligita al etikedoj, kaj la deplojo de la aplikaĵo al branĉo. majstro, en kiu versioj de la kolektitaj bildoj estas malmolkodigitaj. Jen kie vi povas pravalorigi retrovon per simpla reverto majstro-branĉoj.

10. Aŭtomatigo de deplojo

Por ke Gitlab-runner malĉifri niajn sekretojn, ni devos eksporti la deponejan ŝlosilon kaj aldoni ĝin al niaj CI-mediaj variabloj:

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

Ni konservos la rezultan linion en Gitlab; por fari tion, ni iru al niaj projektaj agordoj:
Agordoj -> CI / KD -> Variabloj

Kaj ni kreu novan variablon:

tipo
ŝlosilo
valoro
Protektata
Maskita
amplekso

File
GITCRYPT_KEY
<your string>
true (dum la trejnado vi povas false)
true
All environments

Ekrankopio de la aldonita variablo

Provante novajn ilojn por konstrui kaj aŭtomatigi deplojon en Kubernetes

Nun ni ĝisdatigu nian .gitlab-ci.yml aldonante al ĝi:

.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

Ĉi tie ni ebligis plurajn novajn eblojn por qbec:

  • --radikigi iun/apon — permesas vin determini la dosierujon de specifa aplikaĵo
  • --force:k8s-context __incluster__ - ĉi tio estas magia variablo, kiu diras, ke la deplojo okazos en la sama areto en kiu funkcias gtilab-runner. Ĉi tio estas necesa ĉar alie qbec provos trovi taŭgan Kubernetes-servilon en via kubeconfig
  • --atendu — devigas qbec atendi ĝis la rimedoj, kiujn ĝi kreas, iros en la staton Preta kaj nur tiam eliri kun sukcesa elirkodo.
  • —jes - simple malŝaltas la interagan ŝelon Ĉu vi certas? kiam deplojita.

Ne forgesu fari niajn ŝanĝojn:

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

Kaj poste git push ni vidos kiel niaj aplikoj estis deplojitaj:

Ekrankopio de la dua dukto

Provante novajn ilojn por konstrui kaj aŭtomatigi deplojon en Kubernetes

11. Artefaktoj kaj asembleo kiam puŝas al majstro

Kutime, la paŝoj priskribitaj supre sufiĉas por konstrui kaj liveri preskaŭ ajnan mikroservon, sed ni ne volas aldoni etikedon ĉiufoje kiam ni bezonas ĝisdatigi la retejon. Sekve, ni prenos pli dinamikan vojon kaj starigos digestan deplojon en la majstra branĉo.

La ideo estas simpla: nun la bildo de nia retejo estos rekonstruita ĉiufoje kiam vi enpuŝos majstro, kaj poste aŭtomate disfaldu al Kubernetes.

Ni ĝisdatigu ĉi tiujn du laborpostenojn en nia .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"

Bonvolu noti, ke ni aldonis fadenon majstro к ref por laboroj konstrui_retejo kaj ni nun uzas $CI_COMMIT_REF_NAME anstataŭ $CI_COMMIT_TAG, tio estas, ni estas malligitaj de etikedoj en Git kaj nun ni puŝos bildon kun la nomo de la kommit-branĉo, kiu pravigis la dukto. Indas noti, ke ĉi tio ankaŭ funkcios kun etikedoj, kiuj permesos al ni konservi momentfotojn de retejo kun specifa versio en la docker-registro.

Kiam la nomo de la docker-etikedo por nova versio de la retejo povas esti senŝanĝa, ni ankoraŭ devas priskribi la ŝanĝojn al Kubernetes, alie ĝi simple ne redeplojos la aplikaĵon de la nova bildo, ĉar ĝi ne rimarkos ajnajn ŝanĝojn en la manifesto de deplojo.

Opcio —vm:ext-str digest="$DIGEST" por qbec - permesas vin transdoni eksteran variablon al jsonnet. Ni volas, ke ĝi estu redeplojita en la areto kun ĉiu eldono de nia aplikaĵo. Ni ne plu povas uzi la etikednomon, kiu nun povas esti neŝanĝebla, ĉar ni devas esti ligitaj al specifa versio de la bildo kaj ekigi la deplojon kiam ĝi ŝanĝiĝas.

Ĉi tie ni helpos la kapablo de Kaniko konservi digestan bildon al dosiero (opcio --digest-dosiero)
Tiam ni translokigos ĉi tiun dosieron kaj legos ĝin en la momento de deplojo.

Ni ĝisdatigu la parametrojn por nia deploy/website/environments/base.libsonnet kiu nun aspektos jene:

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

Farita, nun ajna kompromiso en majstro pravigigas la konstruon de la docker-bildo por retejo, kaj poste deploji ĝin al Kubernetes.

Ne forgesu fari niajn ŝanĝojn:

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

Ni kontrolos poste git push ni devus vidi ion tian:

Ekrankopio de la dukto por majstro

Provante novajn ilojn por konstrui kaj aŭtomatigi deplojon en Kubernetes

Principe, ni ne bezonas redeploji gitlab-runner per ĉiu puŝo, krom se, kompreneble, nenio ŝanĝiĝis en ĝia agordo, ni riparu ĝin en .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/**/*

ŝanĝoj permesos al vi kontroli ŝanĝojn en deploy/gitlab-runner/ kaj ekigos nian laboron nur se ekzistas

Ne forgesu fari niajn ŝanĝojn:

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

git push, tio estas pli bona:

Ekrankopio de la ĝisdatigita dukto

Provante novajn ilojn por konstrui kaj aŭtomatigi deplojon en Kubernetes

12. Dinamikaj medioj

Estas tempo diversigi nian dukton kun dinamikaj medioj.

Unue, ni ĝisdatigu la laboron konstrui_retejo en nia .gitlab-ci.yml, forigante la blokon de ĝi nur, kiu devigos Gitlab-on ekigi ĝin sur ajna kompromiso al iu branĉo:

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/

Poste ĝisdatigu la laboron deploji_retejo, aldonu blokon tie medio:

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"

Ĉi tio permesos al Gitlab asocii la laboron kun prod medio kaj montru la ĝustan ligon al ĝi.

Nun ni aldonu du pliajn laborojn:

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

Ili estos lanĉitaj post puŝado al iuj branĉoj krom majstro kaj deplojos la antaŭrigardan version de la retejo.

Ni vidas novan opcion por qbec: --app-tag — ĝi permesas vin etikedi deplojitajn versiojn de la aplikaĵo kaj labori nur ene de ĉi tiu etikedo; kreante kaj detruante rimedojn en Kubernetes, qbec funkcios nur kun ili.
Tiel ni ne povas krei apartan medion por ĉiu recenzo, sed simple reuzi la saman.

Ĉi tie ni ankaŭ uzas qbec apliki revizion, anstataŭ qbec apliki defaŭlton - jen ĝuste la momento, kiam ni provos priskribi la diferencojn por niaj medioj (revizio kaj defaŭlta):

Ni aldonu revizio medio en deploy/retejo/qbec.yaml

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

Tiam ni deklaros ĝin en 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

Kaj skribu la kutimajn parametrojn por ĝi 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',
    },
  },
}

Ni ankaŭ rigardu pli proksime al jobu halt_revizio, ĝi estos ekigita kiam la branĉo estas forigita kaj por ke gitlab ne provu elĉerpi, ĝi estas uzata GIT_STRATEGY: neniu, poste ni klonas majstro-branĉu kaj forigu recenzon per ĝi.
Ĝi estas iom konfuza, sed mi ankoraŭ ne trovis pli belan manieron.
Alternativa opcio estus deploji ĉiun revizion al hotela nomspaco, kiu ĉiam povas esti disfaligita tute.

Ne forgesu fari niajn ŝanĝojn:

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

git push, git checkout -b testo, git push origintesto, kontrolu:

Ekrankopio de kreitaj medioj en Gitlab

Provante novajn ilojn por konstrui kaj aŭtomatigi deplojon en Kubernetes

Ĉu ĉio funkcias? - bonege, forigu nian testbranĉon: git checkout master, git push origin :test, ni kontrolas, ke la medio-forigo-laboroj funkciis sen eraroj.

Ĉi tie mi ŝatus tuj klarigi, ke ĉiu programisto en projekto povas krei branĉojn, li ankaŭ povas ŝanĝi .gitlab-ci.yml dosiero kaj aliri sekretajn variablojn.
Tial, estas forte rekomendite permesi ilian uzon nur por protektitaj branĉoj, ekzemple en majstro, aŭ kreu apartan aron de variabloj por ĉiu medio.

13. Revizii Apojn

Revizii Apojn Ĉi tio estas funkcio de GitLab, kiu ebligas al vi aldoni butonon por ĉiu dosiero en la deponejo por rapide vidi ĝin en deplojita medio.

Por ke ĉi tiuj butonoj aperu, vi devas krei dosieron .gitlab/route-map.yml kaj priskribu ĉiujn vojtransformojn en ĝi; en nia kazo ĝi estos tre simpla:

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

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

Ne forgesu fari niajn ŝanĝojn:

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

git push, kaj kontrolu:

Ekrankopio de la butono Revizia App

Provante novajn ilojn por konstrui kaj aŭtomatigi deplojon en Kubernetes

Ijob estas finita!

Projektfontoj:

Dankon pro via atento, mi esperas ke vi ŝatis ĝin Provante novajn ilojn por konstrui kaj aŭtomatigi deplojon en Kubernetes

fonto: www.habr.com

Aldoni komenton