Pruvate novi strumenti per custruisce è automatizà a implementazione in Kubernetes

Pruvate novi strumenti per custruisce è automatizà a implementazione in Kubernetes

Bonghjornu! Recentemente, assai strumenti di automatizazione cool sò stati liberati sia per a custruzzione di l'imaghjini Docker sia per l'implementazione in Kubernetes. In questu sensu, aghju decisu di ghjucà cù GitLab, studià bè e so capacità è, sicuru, stabilisce u pipeline.

Stu travagliu hè statu inspiratu da u situ web kubernetes.io, chì hè generatu da codici fonte automaticamente, è per ogni dumanda di piscina mandata, u robot genera automaticamente una versione di vista previa di u situ cù i vostri cambiamenti è furnisce un ligame per a visualizazione.

Aghju pruvatu à custruisce un prucessu simili da zero, ma cumpletamente custruitu nantu à Gitlab CI è strumenti gratuiti chì sò abituatu à aduprà per implementà applicazioni in Kubernetes. Oghje vi dicu infine di più nantu à elli.

L'articulu discuterà strumenti cum'è:
Hugo, qbec, canicu, git-crypt и GitLab CI cù a creazione di ambienti dinamichi.

Cuntenuti

  1. Scuntrà Hugo
  2. Preparazione di u Dockerfile
  3. Cunniscite u kaniko
  4. Amparate à cunnosce qbec
  5. Pruvate Gitlab-runner cù Kubernetes-executor
  6. Implementazione di i grafici Helm cù qbec
  7. Presentazione di git-crypt
  8. Creazione di l'imagine di u toolbox
  9. U nostru primu pipeline è assemblea d'imaghjini per tag
  10. Automatizazione di implementazione
  11. Artefatti è assemblea quandu spinghje à maestru
  12. Ambienti dinamichi
  13. Review Apps

1. Cunniscite à Hugo

Cum'è un esempiu di u nostru prughjettu, avemu da pruvà à creà un situ di publicazione di ducumentazione custruitu nantu à Hugo. Hugo hè un generatore di cuntenutu staticu.

Per quelli chì ùn sò micca familiarizati cù i generatori statici, vi dicu un pocu più nantu à elli. A cuntrariu di i mutori di u situ web cunvinziunali cù una basa di dati è qualchì PHP, chì, quandu esse dumandati da un utilizatore, generanu pagine nantu à a mosca, i generatori statici sò designati un pocu diffirenti. Permettenu di piglià fonti, di solitu un inseme di fugliali in Markdown markup è mudelli di temi, poi compilali in un situ web cumpletamente finitu.

Questu hè, in u risultatu, riceverete una struttura di repertoriu è un inseme di fugliali HTML generati, chì pudete simpricimenti caricate à qualsiasi hosting economicu è uttene un situ web di travagliu.

Pudete installà Hugo in u locu è pruvate:

Inizializza un novu situ:

hugo new site docs.example.org

È à u listessu tempu u repository git:

cd docs.example.org
git init

Finu a ora, u nostru situ hè pristine è per chì qualcosa apparisce nantu à questu, avemu prima bisognu di cunnette un tema; un tema hè solu un inseme di mudelli è regule specificate per quale u nostru situ hè generatu.

Per u tema avemu aduprà Scuole, chì, in my opinion, hè perfettamente adattatu per un situ di documentazione.

Vogliu prestà una attenzione particulari à u fattu chì ùn avemu micca bisognu di salvà i fugliali tematichi in u nostru repository di u prughjettu; invece, pudemu simpliciamente cunnette cù l'usu. sottumodulu git:

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

Cusì, u nostru repository cuntene solu i fugliali direttamente ligati à u nostru prughjettu, è u tema cunnessu restarà cum'è un ligame à un repository specificu è un impegnu in questu, vale à dì, pò sempre esse tiratu da a fonte originale è ùn avè micca paura di cambiamenti incompatibili.

Correggemu a cunfigurazione config.toml:

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

Dighjà in questa fase pudete eseguisce:

hugo server

È à l'indirizzu http://localhost:1313/ verificate u nostru situ web appena creatu, tutti i cambiamenti fatti in u cartulare aghjurnà automaticamente a pagina aperta in u navigatore, assai convenientu!

Pruvemu di creà una pagina di copertina cuntenutu/_index.md:

# My docs site

## Welcome to the docs!

You will be very smart :-)

Screenshot di a nova pagina creata

Pruvate novi strumenti per custruisce è automatizà a implementazione in Kubernetes

Per generà un situ, basta eseguite:

hugo

U cuntenutu di u repertoriu publicu/ è serà u vostru situ web.
Iè, per via, aghjustemu immediatamente .gitignore:

echo /public > .gitignore

Ùn vi scurdate di fà i nostri cambiamenti:

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

2. Preparazione di u Dockerfile

Hè ora di definisce a struttura di u nostru repository. Di solitu aduprà qualcosa cum'è:

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

  • dockerfiles/ - cuntene cartulari cù Dockerfiles è tuttu ciò chì hè necessariu per custruisce e nostre imagine Docker.
  • implementà/ - cuntene cartulari per implementà e nostre applicazioni in Kubernetes

Cusì, creeremu u nostru primu Dockerfile longu u percorsu 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" ]

Comu pudete vede, u Dockerfile cuntene dui FROM, sta opportunità hè chjamata custruzzione in più tappe è vi permette di escludiri tuttu ciò chì ùn hè micca necessariu da l'imagine finale di Docker.
Cusì, l'imaghjini finali cuntene solu scuruhttpd (servitore HTTP ligeru) è publicu/ - u cuntenutu di u nostru situ web generatu staticamente.

Ùn vi scurdate di fà i nostri cambiamenti:

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

3. Cunniscite u kaniko

Cum'è un docker image builder, aghju decisu di utilizà canicu, Siccomu u so funziunamentu ùn hà micca bisognu di un daemon docker, è a custruzzione stessu pò esse realizatu in ogni macchina è a cache pò esse guardata direttamente in u registru, eliminendu cusì a necessità di avè un almacenamentu persistente cumpletu.

Per custruisce l'imaghjini, basta eseguite u cuntinuu cù esecutore kaniko è trasmette u cuntestu di custruzzione attuale; questu pò ancu esse fattu in u locu, via 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

Induve registry.gitlab.com/kvaps/docs.example.org/website - u nome di a vostra imagine docker; dopu a custruzzione, serà lanciata automaticamente in u registru docker.

Parameter --cache permette di cache strati in u registru docker; per l'esempiu datu, seranu salvati in registry.gitlab.com/kvaps/docs.example.org/website/cache, ma pudete specificà un altru percorsu utilizendu u paràmetru --cache-repo.

Screenshot di docker-registry

Pruvate novi strumenti per custruisce è automatizà a implementazione in Kubernetes

4. Cunniscite qbec

Qbec hè un strumentu di implementazione chì vi permette di discrive in modu dichjarazione i vostri manifesti di l'applicazione è di implementà in Kubernetes. Utilizà Jsonnet cum'è a sintassi principale permette di simplificà assai a descrizzione di e differenze in parechje ambienti, è ancu elimina quasi completamente a ripetizione di codice.

Questu pò esse soprattuttu veru in i casi induve avete bisognu di implementà una applicazione à parechji clusters cù diversi paràmetri è vulete descriverà in modu dichjarazione in Git.

Qbec permette ancu di rende i grafici Helm passendu i paràmetri necessarii è poi operanu in u listessu modu cum'è manifesti regulare, cumpresu pudete applicà diverse mutazioni à elli, è questu, à u turnu, permette di caccià a necessità di aduprà ChartMuseum. Questu hè, pudete almacenà è rende i grafici direttamente da git, induve appartenenu.

Cumu l'aghju dettu prima, almacenaremu tutte e implementazioni in un repertoriu implementà/:

mkdir deploy
cd deploy

Inizialemu a nostra prima applicazione:

qbec init website
cd website

Avà a struttura di a nostra applicazione pare cusì:

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

fighjemu u schedariu qbec.yaml:

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

Quì ci interessa principalmente spec.ambienti, qbec hà digià creatu un ambiente predeterminatu per noi è hà pigliatu l'indirizzu di u servitore, è ancu u spaziu di nomi da u nostru kubeconfig attuale.
Avà quandu si sparghje à automaticamente ambiente, qbec sempre implementà solu à u cluster Kubernetes specificatu è à u spaziu di nome specificatu, vale à dì, ùn avete più bisognu di cambià trà cuntesti è spazii di nomi per fà una implementazione.
Se necessariu, pudete sempre aghjurnà i paràmetri in stu schedariu.

Tutti i vostri ambienti sò descritti in qbec.yaml, è in u schedariu params.libsonnet, induve dice induve uttene i paràmetri per elli.

Dopu vedemu dui cartulari:

  • cumpunenti/ - tutti i manifesti per a nostra applicazione seranu guardati quì; ponu esse descritti sia in i fugliali jsonnet sia regularmente yaml
  • ambienti/ - quì descriveremu tutte e variàbili (parametri) per i nostri ambienti.

Per difettu avemu dui schedari:

  • ambienti/base.libsonnet - cuntene paràmetri cumuni per tutti l'ambienti
  • ambienti/default.libsonnet - cuntene parametri annullati per l'ambiente automaticamente

apremu ambienti/base.libsonnet è aghjunghje parametri per u nostru primu cumpunente quì:

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

Creemu ancu u nostru primu cumpunente cumpunenti/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,
                },
              },
            ],
          },
        },
      ],
    },
  },
]

In questu schedariu avemu descrittu trè entità Kubernetes à una volta, queste sò: Mudellu, Service и Ingress. Se vulemu, pudemu mette in diverse cumpunenti, ma in questu stadiu unu serà abbastanza per noi.

fuori jsonnet hè assai simili à json regulare, in principiu, json regulare hè digià validu jsonnet, cusì in prima pò esse più faciule per voi di utilizà servizii in linea cum'è yaml2json per cunvertisce u vostru yaml abituale in json, o, se i vostri cumpunenti ùn cuntenenu micca variàbili, ponu esse discrittu in a forma di yaml regulare.

Quandu travaglia cun jsonnet Vi cunsigliu assai di installà un plugin per u vostru editore

Per esempiu, ci hè un plugin per vim vim-jsonnet, chì attiva l'evidenziazione di sintassi è eseguisce automaticamente jsonnet fmt ogni volta chì salvate (necessita installatu jsonnet).

Tuttu hè prontu, avà pudemu cumincià à implementà:

Per vede ciò chì avemu, corremu:

qbec show default

À l'output, vi vede manifesti yaml renditi chì saranu appiicati à u cluster predeterminatu.

Grande, avà applica:

qbec apply default

À l'output, sempre vede ciò chì serà fattu in u vostru cluster, qbec vi dumandarà d'accettà i cambiamenti scrivendu. y sarete capaci di cunfirmà e vostre intenzioni.

A nostra applicazione hè pronta è implementata!

Se fate cambiamenti, pudete sempre fà:

qbec diff default

per vede cumu questi cambiamenti affettanu a implementazione attuale

Ùn vi scurdate di fà i nostri cambiamenti:

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

5. Pruvate Gitlab-runner cù Kubernetes-executor

Finu à pocu tempu aghju utilizatu solu regularmente gitlab-runner nantu à una macchina pre-preparata (container LXC) cù shell o docker-executor. Inizialmente, avemu avutu parechji tali corridori definiti globalmente in u nostru gitlab. Anu cullatu imagine docker per tutti i prughjetti.

Ma cum'è a pratica hà dimustratu, sta opzione ùn hè micca u più ideale, in quantu à praticità è sicurità. Hè assai megliu è ideologicamente più currettu per avè corridori separati disposti per ogni prughjettu, o ancu per ogni ambiente.

Fortunatamente, questu ùn hè micca un prublema in tuttu, postu chì avà avemu da implementà gitlab-runner direttamente cum'è parte di u nostru prughjettu ghjustu in Kubernetes.

Gitlab furnisce un graficu di timone prontu per implementà gitlab-runner à Kubernetes. Allora tuttu ciò chì avete da fà hè di scopre gettone di registrazione per u nostru prughjettu in Settings -> CI / CD -> Runners è passa à u timone :

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

Dove:

  • https://gitlab.com - l'indirizzu di u vostru servitore Gitlab.
  • yga8y-jdCusVDn_t4Wxc - token di registrazione per u vostru prughjettu.
  • rbac.create=true - furnisce u corridore cù a quantità necessaria di privileggi per pudè creà pods per eseguisce i nostri compiti cù kubernetes-executor.

Se tuttu hè fattu bè, duvete vede un corridore registratu in a sezione Runners, in i paràmetri di u vostru prughjettu.

Screenshot di u corridore aghjuntu

Pruvate novi strumenti per custruisce è automatizà a implementazione in Kubernetes

Hè cusì simplice? - Iè, hè cusì simplice ! Ùn ci hè più fastidiu cù a registrazione di i corridori manualmente, da avà i corridori seranu creati è distrutti automaticamente.

6. Deploy Helm charts cù QBEC

Dapoi avemu decisu di cunsiderà gitlab-runner parte di u nostru prughjettu, hè ora di discrìvilu in u nostru repository Git.

Puderemu discrive cum'è un cumpunente separatu situ, ma in u futuru avemu pensatu à implementà diverse copie situ assai spessu, à u cuntrariu gitlab-runner, chì serà implementatu solu una volta per cluster Kubernetes. Allora iniziali una applicazione separata per questu:

cd deploy
qbec init gitlab-runner
cd gitlab-runner

Questa volta ùn descriveremu micca e entità Kubernetes manualmente, ma piglià un graficu Helm prontu. Unu di i vantaghji di qbec hè a capacità di rende Helm charts direttamente da un repository Git.

Cunnetteremu cù u sottumodulu git:

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

Avà u cartulare venditore/gitlab-runner Avemu un repository cù un graficu per gitlab-runner.

In un modu simili, pudete cunnette altri repositori, per esempiu, u repositoriu tutale cù charts ufficiali https://github.com/helm/charts

Descrivimu u cumpunente cumpunenti/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,
  }
)

U primu argumentu à expandHelmTemplate passemu u percorsu à a carta, allora paràmetri.valori, chì pigliamu da i paràmetri di l'ambiente, dopu vene l'ughjettu cù

  • name Template - Titulu di liberazione
  • namespace - namespace trasferitu à helm
  • stu File - un paràmetru necessariu chì passa u percorsu à u schedariu attuale
  • verbosu - mostra u cumandamentu mudellu di timone cù tutti l'argumenti quandu rende u graficu

Avà descrivimu i paràmetri per u nostru cumpunente in ambienti/base.libsonnet:

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

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

Attenti runnerRegistrationToken pigliemu da un schedariu esternu secrets/base.libsonnet, creemu :

{
  runnerRegistrationToken: 'yga8y-jdCusVDn_t4Wxc',
}

Cuntrollamu se tuttu funziona:

qbec show default

se tuttu hè in ordine, allora pudemu sguassà a nostra liberazione implementata prima via Helm:

helm uninstall gitlab-runner

è implementà u listessu modu, ma attraversu qbec:

qbec apply default

7. Introduzione à git-crypt

Git-crypt hè un strumentu chì vi permette di stabilisce una criptografia trasparente per u vostru repository.

À u mumentu, a nostra struttura di cartulare per gitlab-runner pare cusì:

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

Ma almacenà i sicreti in Git ùn hè micca sicuru, hè? Allora avemu bisognu di criptà bè.

Di solitu, per una variabile, questu ùn hè micca sempre sensu. Pudete trasfiriri sicreti à qbec è attraversu e variabili di l'ambiente di u vostru sistema CI.
Ma vale a pena nutà chì ci sò ancu prughjetti più cumplessi chì ponu cuntene assai più sicreti; trasferimentu tutti attraversu variabili di l'ambiente serà estremamente difficiule.

In più, in stu casu, ùn saria in gradu di dì à voi circa un tali strumentu maravigghiusu comu git-crypt.

git-crypt Hè ancu cunvene chì permette di salvà tutta a storia di i sicreti, è ancu di paragunà, fusione è risolve i cunflitti in u listessu modu chì avemu abituatu à fà in u casu di Git.

Prima cosa dopu a stallazione git-crypt avemu bisognu di generà chjave per u nostru repository:

git crypt init

Se tenete una chjave PGP, pudete aghjunghje immediatamente cum'è cullaburatore per stu prughjettu:

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

Questu modu pudete sempre decriptà stu repository utilizendu a vostra chjave privata.

Se ùn avete micca una chjave PGP è ùn l'aspittà micca, pudete andà in l'altru modu è esportà a chjave di u prughjettu:

git crypt export-key /path/to/keyfile

Cusì, qualchissia chì hà un esportatu keyfile puderà decifrare u vostru repository.

Hè ora di stabilisce u nostru primu sicretu.
Lasciami ricurdà chì simu sempre in u cartulare deploy/gitlab-runner/, induve avemu un annuariu sicreti/, Criptemu tutti i schedari in questu, per questu avemu da creà un schedariu secrets/.gitattributes cù u seguenti cuntenutu:

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

Comu pò esse vistu da u cuntenutu, tutti i schedari sò mascati * sarà guidatu à traversu git-crypt, fora di u più .gitattributes

Pudemu verificà questu eseguendu:

git crypt status -e

L'output serà una lista di tutti i schedari in u repository per quale a criptografia hè attivata

Hè tuttu, avà pudemu cummette in modu sicuru i nostri cambiamenti:

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

Per bluccà un repository, basta à eseguisce:

git crypt lock

è subitu tutti i schedarii criptati diventeranu in qualcosa binariu, serà impussibile di leghje.
Per decrypt u repository, eseguite:

git crypt unlock

8. Crià una imagine toolbox

Una maghjina di toolbox hè una maghjina cù tutti l'arnesi chì useremu per implementà u nostru prughjettu. Serà utilizatu da u corridore Gitlab per eseguisce attività tipiche di implementazione.

Tuttu hè simplice quì, creamu un novu dockerfiles/toolbox/Dockerfile cù u seguenti cuntenutu:

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

Comu pudete vede, in questa imagine installemu tutte e utilità chì avemu usatu per implementà a nostra applicazione. Ùn avemu micca bisognu quì, salvu kubectl, ma pudete vulete ghjucà cun ellu durante a fase di setup pipeline.

Inoltre, per pudè cumunicà cù Kubernetes è implementà à questu, avemu bisognu di cunfigurà un rolu per i pods generati da gitlab-runner.

Per fà questu, andemu à u cartulare cù gitlab-runner:

cd deploy/gitlab-runner

è aghjunghje un novu cumpunente cumpunenti/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,
      },
    ],
  },
]

Descriveremu ancu i novi paràmetri in ambienti/base.libsonnet, chì avà pare cusì:

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

Attenti $.components.rbac.name si riferisce à Cognome per cumpunenti rbac

Cuntrollamu ciò chì hè cambiatu:

qbec diff default

è applicà i nostri cambiamenti à Kubernetes:

qbec apply default

Inoltre, ùn vi scurdate di fà i nostri cambiamenti à 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. U nostru primu pipeline è assemblea d'imaghjini per tag

À a radica di u prugettu avemu da creà .gitlab-ci.yml cù u seguenti cuntenutu:

.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

Per piacè nutate chì usemu GIT_SUBMODULE_STRATEGY: normale per quelli travaglii induve avete bisognu di inizializà esplicitamente i submoduli prima di l'esekzione.

Ùn vi scurdate di fà i nostri cambiamenti:

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

Pensu chì pudemu chjamà in modu sicuru una versione v0.0.1 è aghjunghje l'etichetta:

git tag v0.0.1

Aggiungeremu tags ogni volta chì avemu bisognu di liberà una nova versione. I tag in l'imaghjini di Docker seranu ligati à i tags Git. Ogni spinta cù una nova tag inizializzarà a custruzione di l'imaghjini cù questa tag.

Facemu git push --tags, è fighjemu a nostra prima pipeline:

Screenshot di u primu pipeline

Pruvate novi strumenti per custruisce è automatizà a implementazione in Kubernetes

Vale a pena attirà a vostra attenzione à u fattu chì l'assemblea per tags hè adattatu per custruisce l'imaghjini docker, ma ùn hè micca adattatu per implementà una applicazione à Kubernetes. Siccomu i novi tag ponu esse attribuiti à i vechji commits, in questu casu, l'inizializazione di u pipeline per elli porta à a implementazione di a versione antica.

Per risolve stu prublema, di solitu a custruzzione di l'imaghjini docker hè ligata à i tags, è l'implementazione di l'applicazione in una filiera. Maestru, in quale versioni di l'imaghjini cullate sò hardcoded. Questu hè induve pudete inizializà u rollback cun un revert simplice Maestru- rami.

10. Automatizazione di implementazione

Per chì Gitlab-runner decifra i nostri sicreti, avemu bisognu di esportà a chjave di repository è aghjunghje à e nostre variabili di l'ambiente CI:

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

Salvemu a linea risultante in Gitlab; per fà questu, andemu à i nostri paràmetri di prughjettu:
Settings -> CI / CD -> Variables

È creemu una nova variabile:

Type
Key
Value
Protetta
Paradossu di l '
aghjalesi

File
GITCRYPT_KEY
<your string>
true (durante a furmazione pudete false)
true
All environments

Screenshot di a variabile aghjuntu

Pruvate novi strumenti per custruisce è automatizà a implementazione in Kubernetes

Avà aghjurnà u nostru .gitlab-ci.yml aghjunghjendu à questu:

.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

Quì avemu attivatu parechje opzioni novi per qbec:

  • --root some/app - permette di determinà u repertoriu di una applicazione specifica
  • --force:k8s-context __incluster__ - Questa hè una variabile magica chì dice chì a implementazione serà in u stessu cluster in quale gtilab-runner hè in esecuzione. Questu hè necessariu perchè altrimenti qbec pruverà à truvà un servitore Kubernetes adattatu in u vostru kubeconfig.
  • -- aspetta - forza qbec à aspittà finu à chì i risorsi chì crea entranu in u statu Ready è solu dopu esce cù un exit-code successu.
  • -Iè - disattiva solu a cunchiglia interattiva Sì sicuru? quandu hè dispostu.

Ùn vi scurdate di fà i nostri cambiamenti:

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

È dopu git push videremu cumu e nostre applicazioni sò state implementate:

Screenshot di a seconda pipeline

Pruvate novi strumenti per custruisce è automatizà a implementazione in Kubernetes

11. Artifacts è assemblea quandu pushing to master

Di genere, i passi descritti sopra sò abbastanza per custruisce è furnisce quasi ogni microserviziu, ma ùn vulemu aghjunghje una tag ogni volta chì avemu bisognu di aghjurnà u situ. Dunque, avemu da piglià una strada più dinamica è stallate una implementazione di digest in u ramu maestru.

L'idea hè simplice: avà l'imaghjini di u nostru situ serà ricustruita ogni volta chì vi spinghje Maestru, e poi implementate automaticamente in Kubernetes.

Aghjurnà sti dui travaglii in u nostru .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"

Per piacè nutate chì avemu aghjustatu un filu Maestru к rif per i travaglii build_site è avemu avà aduprà $CI_COMMIT_REF_NAME invece di $CI_COMMIT_TAG, vale à dì, simu slegati da e tags in Git è avà spinghjemu una maghjina cù u nome di u ramu commit chì hà inizializatu u pipeline. Hè da nutà chì questu travaglià ancu cù tags, chì ci permettenu di salvà snapshots di un situ cù una versione specifica in u docker-registry.

Quandu u nome di l'etiqueta docker per una nova versione di u situ pò esse invariatu, avemu sempre à discrìviri i cambiamenti à Kubernetes, altrimenti ùn simpricimenti ùn rimetterà micca l'applicazione da a nova maghjina, postu chì ùn hà micca avvistu micca cambiamenti in l'imaghjini. manifestu di implementazione.

Opzione —vm:ext-str digest="$DIGEST" per qbec - permette di passà una variabile esterna à jsonnet. Vulemu chì sia ridistribuitu in u cluster cù ogni liberazione di a nostra applicazione. Ùn pudemu più usà u nome di tag, chì avà pò esse immutabile, postu chì avemu bisognu à esse ligatu à una versione specifica di l'imaghjini è attivà a implementazione quandu cambia.

Quì seremu aiutati da l'abilità di Kaniko per salvà una maghjina digest in un schedariu (opzione --digest-file)
Allora avemu da trasfiriri stu schedariu è leghje lu à u mumentu di a distribuzione.

Aghjurnà i paràmetri per i nostri deploy/website/environments/base.libsonnet chì avà sarà cusì cusì:

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

Fattu, avà ogni impegnu in Maestru inizializza a creazione di l'imaghjini docker per situ, è dopu implementà à Kubernetes.

Ùn vi scurdate di fà i nostri cambiamenti:

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

Avemu da verificà dopu git push duvemu vede qualcosa cum'è questu:

Screenshot di u pipeline per u maestru

Pruvate novi strumenti per custruisce è automatizà a implementazione in Kubernetes

In principiu, ùn avemu micca bisognu di ripiglià gitlab-runner cù ogni spinta, salvu chì, sicuru, nunda hà cambiatu in a so cunfigurazione, correggemu in .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/**/*

Cambiamenti vi permetterà di monitorà i cambiamenti in deploy/gitlab-runner/ è attivarà u nostru travagliu solu s'ellu ci hè

Ùn vi scurdate di fà i nostri cambiamenti:

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

git push, hè megliu:

Screenshot di u pipeline aghjurnatu

Pruvate novi strumenti per custruisce è automatizà a implementazione in Kubernetes

12. Ambienti dinamichi

Hè ora di diversificà a nostra pipeline cù ambienti dinamichi.

Prima, aghjurnemu u travagliu build_site in u nostru .gitlab-ci.yml, cacciendu u bloccu da ellu solu, chì furzà Gitlab à attivallu nantu à qualsiasi cummit à qualsiasi 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/

Allora aghjurnà u travagliu deploy_website, aghjunghje un bloccu quì ambiente:

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"

Questu permetterà à Gitlab di associà u travagliu cù prod ambiente è mostra u ligame currettu à questu.

Avà aghjustemu dui travaglii più:

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

Seranu lanciati nantu à u spinu à qualsiasi rami eccettu u maestru è implementaranu a versione di anteprima di u situ.

Avemu vistu una nova opzione per qbec: --app-tag - vi permette di taggà e versioni implementate di l'applicazione è travaglià solu in questa tag; quandu creanu è distrugge risorse in Kubernetes, qbec operarà solu cun elli.
In questu modu ùn pudemu micca creà un ambiente separatu per ogni rivista, ma simpricimenti reutilizà u stessu.

Quì avemu ancu aduprà qbec applica rivista, invece di qbec applica predefinitu - questu hè esattamente u mumentu quandu avemu da pruvà à discriva e differenze per i nostri ambienti (revisione è predeterminatu):

Aghjunghjemu recensione ambiente in deploy/website/qbec.yaml

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

Allora a dichjarà in 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

È scrivite i paràmetri persunalizati per questu 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',
    },
  },
}

Fighjemu ancu più attente à jobu stop_review, serà attivatu quandu u ramu hè sguassatu è cusì chì gitlab ùn prova micca di checkout hè utilizatu GIT_STRATEGY: nimu, dopu avemu clone Maestru-branch è sguassà rivista attraversu lu.
Hè un pocu cunfusu, ma ùn aghju micca trovu un modu più bellu.
Una opzione alternativa seria di implementà ogni rivista in un spaziu di nomi di hotel, chì pò sempre esse demolitu sanu.

Ùn vi scurdate di fà i nostri cambiamenti:

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

git push, git checkout -b test, test d'origine git push, verificate :

Screenshot di ambienti creati in Gitlab

Pruvate novi strumenti per custruisce è automatizà a implementazione in Kubernetes

Tuttu travaglia? - grande, sguassate u nostru ramu di prova: git checkout master, git push origine :test, avemu verificatu chì i travaglii di eliminazione di l'ambiente anu travagliatu senza errore.

Quì vogliu chjarificà immediatamente chì qualsiasi sviluppatore in un prughjettu pò creà rami, pò ancu cambià .gitlab-ci.yml file è accede à variàbili secreti.
Per quessa, hè assai cunsigliatu per permette u so usu solu per rami prutetti, per esempiu in Maestru, o crea un settore separatu di variàbili per ogni ambiente.

13. Review Apps

Review Apps Questa hè una funzione di GitLab chì permette di aghjunghje un buttone per ogni schedariu in u repositoriu per vede rapidamente in un ambiente implementatu.

Per vede sti buttoni, avete bisognu di creà un schedariu .gitlab/route-map.yml è descrive tutte e trasfurmazioni di a strada in questu; in u nostru casu serà assai simplice:

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

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

Ùn vi scurdate di fà i nostri cambiamenti:

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

git push, è verificate:

Screenshot di u buttone Review App

Pruvate novi strumenti per custruisce è automatizà a implementazione in Kubernetes

U travagliu hè fattu!

Fonti di prughjettu:

Grazie per a vostra attenzione, spergu chì vi piacia Pruvate novi strumenti per custruisce è automatizà a implementazione in Kubernetes

Source: www.habr.com

Add a comment