Provant noves eines per crear i automatitzar el desplegament a Kubernetes

Provant noves eines per crear i automatitzar el desplegament a Kubernetes

Hola! Darrerament s'han llançat moltes eines d'automatització interessants tant per crear imatges de Docker com per desplegar-les a Kubernetes. En aquest sentit, vaig decidir jugar amb Gitlab, com estudiar les seves capacitats i, per descomptat, configurar un pipeline.

Aquest lloc es va inspirar en kubernetes.io, que es genera a partir de codis font automàticament, i per a cada sol·licitud d'extracció enviada, el robot genera automàticament una versió prèvia del lloc amb els vostres canvis i proporciona un enllaç per visualitzar-lo.

Vaig intentar crear un procés similar des de zero, però totalment basat en Gitlab CI i eines gratuïtes que solia utilitzar per desplegar aplicacions a Kubernetes. Avui per fi us explicaré més coses sobre ells.

L'article tractarà eines com ara:
Hugo, qbec, kaniko, git-crypt и GitLab CI amb la creació d'entorns dinàmics.

Contingut

  1. Conèixer l'Hugo
  2. Preparant el Dockerfile
  3. Coneixement del kaniko
  4. Introducció al qbec
  5. Provant Gitlab-runner amb Kubernetes-executor
  6. Desplegueu els gràfics Helm amb qbec
  7. Introducció a git-crypt
  8. Creeu una imatge de caixa d'eines
  9. El nostre primer pipeline i muntatge d'imatges per etiquetes
  10. Desplegar l'automatització
  11. Artefactes i muntatge en empènyer per dominar
  12. Entorns dinàmics
  13. Revisa les aplicacions

1. Conèixer l'Hugo

Com a exemple del nostre projecte, intentarem crear un lloc de publicació de documentació basat en Hugo. Hugo és un generador de contingut estàtic.

Per a aquells que no estiguin familiaritzats amb els generadors estàtics, us explicaré una mica més sobre ells. A diferència dels motors de llocs habituals amb una base de dades i algun tipus de php, que, quan ho sol·licita l'usuari, generen pàgines sobre la marxa, els generadors estàtics s'organitzen una mica diferent. Us permeten agafar el codi font, normalment un conjunt de fitxers en plantilles de marques i temes de Markdown, i després compilar-los en un lloc completament acabat.

És a dir, a la sortida obtindreu una estructura de directoris i un conjunt de fitxers html generats que simplement podeu carregar a qualsevol allotjament barat i obtenir un lloc de treball.

Podeu instal·lar Hugo localment i provar-ho:

Inicialització del nou lloc:

hugo new site docs.example.org

I al mateix temps el repositori git:

cd docs.example.org
git init

Fins ara, el nostre lloc és impecable i perquè hi aparegui alguna cosa, primer hem de connectar un tema, un tema és només un conjunt de plantilles i establir regles amb les quals es genera el nostre lloc.

Com a tema utilitzarem Aprèn, que, al meu entendre, és el més adequat per a un lloc amb documentació.

M'agradaria prestar especial atenció al fet que no necessitem desar els fitxers del tema al repositori del nostre projecte, sinó que simplement podem connectar-lo mitjançant submòdul git:

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

Així, només els fitxers relacionats directament amb el nostre projecte estaran al nostre repositori, i el tema connectat romandrà com a enllaç a un repositori específic i commit en ell, és a dir, sempre es pot extreure de la font original i no tenir por. de canvis incompatibles.

Arreglem la configuració config.toml:

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

Ja en aquesta fase, podeu executar:

hugo server

I a l'adreça http://localhost:1313/ comproveu el nostre lloc de nova creació, tots els canvis fets al directori actualitzen automàticament la pàgina oberta al navegador, molt convenient!

Intentem crear una pàgina de títol content/_index.md:

# My docs site

## Welcome to the docs!

You will be very smart :-)

Captura de pantalla de la pàgina acabada de crear

Provant noves eines per crear i automatitzar el desplegament a Kubernetes

Per generar un lloc, només cal que executeu:

hugo

Contingut del directori públic/ i serà el teu lloc.
Sí, per cert, introduïm-ho de seguida .gitignore:

echo /public > .gitignore

No us oblideu de comprometre els nostres canvis:

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

2. Preparació del Dockerfile

És hora de definir l'estructura del nostre repositori. Normalment faig servir alguna cosa com:

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

  • Dockerfiles/ - conté directoris amb Dockerfiles i tot el necessari per crear les nostres imatges Docker.
  • desplegar/ - conté directoris per desplegar les nostres aplicacions a Kubernetes

Per tant, crearem el nostre primer Dockerfile al llarg del camí 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" ]

Com podeu veure, el Dockerfile en conté dos DES DE, aquesta possibilitat s'anomena construcció en diverses etapes i us permet excloure tot el que no sigui necessari de la imatge final del docker.
Per tant, la imatge final només contindrà foschttpd (servidor HTTP lleuger) i públic/ - el contingut del nostre lloc generat estàticament.

No us oblideu de comprometre els nostres canvis:

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

3. Conèixer kaniko

Com a creador d'imatges docker, vaig decidir utilitzar-lo kaniko, ja que el seu funcionament no requereix la presència d'un dimoni docker, i el propi muntatge es pot dur a terme en qualsevol màquina i emmagatzemar la memòria cau directament al registre, eliminant així la necessitat de tenir un emmagatzematge persistent complet.

Per crear la imatge, només cal que executeu el contenidor amb marmessor kaniko i passeu-li el context de construcció actual, podeu fer-ho localment, mitjançant 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

On registry.gitlab.com/kvaps/docs.example.org/website - el nom de la vostra imatge docker, després de crear-la, s'iniciarà automàticament al registre docker.

Paràmetre --caché us permet emmagatzemar capes a la memòria cau al registre docker, per a l'exemple donat, s'emmagatzemaran registry.gitlab.com/kvaps/docs.example.org/website/cache, però podeu especificar un altre camí amb el paràmetre --cache-repo.

Captura de pantalla de docker-registry

Provant noves eines per crear i automatitzar el desplegament a Kubernetes

4. Introducció al qbec

Qbec és una eina de desplegament que us permet descriure de manera declarativa els manifestos de l'aplicació i desplegar-los a Kubernetes. L'ús de Jsonnet com a sintaxi principal fa que sigui molt fàcil descriure les diferències per a diversos entorns i elimina gairebé completament la repetició del codi.

Això pot ser especialment cert en els casos en què necessiteu desplegar una aplicació en diversos clústers amb diferents paràmetres i voleu descriure'ls de manera declarativa a Git.

Qbec també us permet renderitzar gràfics Helm passant-los els paràmetres necessaris i després operar-hi de la mateixa manera que els manifests habituals, inclosa la possibilitat d'aplicar-hi diverses mutacions, i això, al seu torn, elimina la necessitat d'utilitzar ChartMuseum. És a dir, podeu emmagatzemar i representar gràfics directament des de git, on pertanyen.

Com he dit abans, emmagatzemarem tots els desplegaments al directori desplegar/:

mkdir deploy
cd deploy

Inicialitzem la nostra primera aplicació:

qbec init website
cd website

Ara l'estructura de la nostra aplicació és la següent:

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

mira l'arxiu qbec.yaml:

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

Aquí ens interessa principalment entorns específics, qbec ja ens ha creat l'entorn predeterminat i ha pres l'adreça del servidor i l'espai de noms del nostre kubeconfig actual.
Ara quan es desplega a defecte entorn, qbec sempre es desplegarà només al clúster de Kubernetes especificat i a l'espai de noms especificat, és a dir, ja no haureu de canviar entre contextos i espais de noms per implementar-lo.
Si cal, sempre podeu actualitzar la configuració d'aquest fitxer.

Tots els vostres entorns es descriuen a qbec.yaml, i a l'arxiu params.libsonnet, que diu on cal agafar els paràmetres per a ells.

A continuació veiem dos directoris:

  • components / - Tots els manifests de la nostra aplicació s'emmagatzemaran aquí, es poden descriure tant en jsonnet com en fitxers yaml habituals
  • entorns/ - aquí descriurem totes les variables (paràmetres) dels nostres entorns.

Per defecte tenim dos fitxers:

  • ambients/base.libsonnet - contindrà paràmetres comuns per a tots els entorns
  • ambients/default.libsonnet - conté paràmetres redefinits per al medi ambient defecte

anem a obrir ambients/base.libsonnet i afegiu-hi paràmetres per al nostre primer component:

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

Creem també el nostre primer component components/website.jsonnet:

local env = {
  name: std.extVar('qbec.io/env'),
  namespace: std.extVar('qbec.io/defaultNs'),
};
local p = import '../params.libsonnet';
local params = p.components.website;

[
  {
    apiVersion: 'apps/v1',
    kind: 'Deployment',
    metadata: {
      labels: { app: params.name },
      name: params.name,
    },
    spec: {
      replicas: params.replicas,
      selector: {
        matchLabels: {
          app: params.name,
        },
      },
      template: {
        metadata: {
          labels: { app: params.name },
        },
        spec: {
          containers: [
            {
              name: 'darkhttpd',
              image: params.image,
              ports: [
                {
                  containerPort: params.containerPort,
                },
              ],
            },
          ],
          nodeSelector: params.nodeSelector,
          tolerations: params.tolerations,
          imagePullSecrets: [{ name: 'regsecret' }],
        },
      },
    },
  },
  {
    apiVersion: 'v1',
    kind: 'Service',
    metadata: {
      labels: { app: params.name },
      name: params.name,
    },
    spec: {
      selector: {
        app: params.name,
      },
      ports: [
        {
          port: params.servicePort,
          targetPort: params.containerPort,
        },
      ],
    },
  },
  {
    apiVersion: 'extensions/v1beta1',
    kind: 'Ingress',
    metadata: {
      annotations: {
        'kubernetes.io/ingress.class': params.ingressClass,
      },
      labels: { app: params.name },
      name: params.name,
    },
    spec: {
      rules: [
        {
          host: params.domain,
          http: {
            paths: [
              {
                backend: {
                  serviceName: params.name,
                  servicePort: params.servicePort,
                },
              },
            ],
          },
        },
      ],
    },
  },
]

En aquest fitxer, vam descriure tres entitats de Kubernetes alhora, aquestes són: Desplegament, servei и Ingrés. Si ho desitgem, podríem moure'ls en diferents components, però en aquesta fase, n'hi ha prou amb un.

sintaxi jsonnet molt semblant al json normal, en principi, el json normal ja és un jsonnet vàlid, de manera que al principi us pot ser més fàcil utilitzar serveis en línia com ara yaml2json per convertir el vostre yaml habitual a json, o si els vostres components no contenen cap variable, es poden descriure en forma de yaml normal.

Quan es treballa amb jsonnet Us recomano molt que instal·leu un connector per al vostre editor

Per exemple, hi ha un connector per a vim vim-jsonnet, que activa el ressaltat de sintaxi i s'executa automàticament jsonnet fmt en cada desat (requereix que s'instal·li jsonnet).

Ja està tot a punt, ara podem començar el desplegament:

Per veure què tenim, anem a executar:

qbec show default

A la sortida, veureu els manifests yaml renderitzats que s'aplicaran al clúster predeterminat.

Genial, ara aplica:

qbec apply default

La sortida sempre us mostrarà què es farà al vostre clúster, qbec us demanarà que accepteu els canvis escrivint y pots confirmar les teves intencions.

Fet ara la nostra aplicació està desplegada!

Si es fan canvis, sempre podeu executar:

qbec diff default

per veure com afectaran aquests canvis al desplegament actual

No us oblideu de comprometre els nostres canvis:

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

5. Proveu Gitlab-runner amb Kubernetes-executor

Fins fa poc, només he utilitzat habitualment gitlab-runner en una màquina prèviament preparada (contenidor LXC) amb un executor de shell o docker. Inicialment, teníem diversos d'aquests corredors definits globalment al nostre gitlab. Van crear imatges docker per a tots els projectes.

Però com ha demostrat la pràctica, aquesta opció no és la més ideal, tant pel que fa a la pràctica com a la seguretat. És molt millor i ideològicament correcte tenir corredors separats desplegats per a cada projecte, i fins i tot per a cada entorn.

Afortunadament, això no és cap problema, ja que ara el desplegarem gitlab-runner directament com a part del nostre projecte a Kubernetes.

Gitlab proporciona un gràfic de timó ja preparat per desplegar gitlab-runner a Kubernetes. Així que tot el que necessites saber és testimoni de registre pel nostre projecte a Configuració -> CI / CD -> Corredors i passa-ho al timó:

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

On:

  • https://gitlab.com és l'adreça del vostre servidor de Gitlab.
  • yga8y-jdCusVDn_t4Wxc - testimoni de registre del vostre projecte.
  • rbac.create=true - dóna al corredor el nombre de privilegis necessaris per poder crear pods per realitzar les nostres tasques amb kubernetes-executor.

Si tot està fet correctament, hauríeu de veure el corredor inscrit a la secció Runners, a la configuració del projecte.

Captura de pantalla del corredor afegit

Provant noves eines per crear i automatitzar el desplegament a Kubernetes

És tan senzill? -Sí, així de senzill! No més problemes amb el registre manual dels corredors, a partir d'ara els corredors es crearan i es destruiran automàticament.

6. Desplegueu els gràfics Helm amb QBEC

Ja que hem decidit considerar gitlab-runner part del nostre projecte, és hora de descriure-ho al nostre repositori Git.

Podríem descriure-ho com un component independent , però en el futur tenim previst desplegar diferents còpies molt sovint, a diferència gitlab-runner, que només es desplegarà una vegada per clúster de Kubernetes. Així que inicialitzem una aplicació independent per a això:

cd deploy
qbec init gitlab-runner
cd gitlab-runner

Aquesta vegada no descriurem les entitats de Kubernetes manualment, sinó que farem un gràfic Helm ja fet. Un dels avantatges de qbec és la capacitat de representar gràfics Helm directament des d'un repositori Git.

Activem-lo mitjançant el submòdul git:

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

Ara el directori venedor/gitlab-runner conté el nostre dipòsit amb un gràfic per a gitlab-runner.

Altres repositoris es poden connectar de manera similar, per exemple, tot el repositori amb gràfics oficials https://github.com/helm/charts

Anem a descriure el component 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,
  }
)

El primer argument a expandHelmTemplate passem el camí a la carta, doncs paràmetres.valors, que prenem dels paràmetres de l'entorn, després ve l'objecte

  • nameTemplate - nom de la publicació
  • espai de noms - L'espai de noms va passar al timó
  • aquest fitxer - un paràmetre obligatori que passa la ruta al fitxer actual
  • detallada - Mostra l'ordre plantilla de timó amb tots els arguments en representar un gràfic

Ara anem a descriure els paràmetres del nostre component a ambients/base.libsonnet:

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

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

Preste atenció runnerRegistrationToken obtenim d'un fitxer extern secrets/base.libsonnet, anem a crear-lo:

{
  runnerRegistrationToken: 'yga8y-jdCusVDn_t4Wxc',
}

Comprovem si tot funciona:

qbec show default

si tot està en ordre, podem eliminar el nostre desplegat anterior mitjançant el llançament de Helm:

helm uninstall gitlab-runner

i desplegar-lo, però mitjançant qbec:

qbec apply default

7. Introducció a git-crypt

git-crypt és una eina que us permet configurar un xifratge transparent per al vostre dipòsit.

De moment, la nostra estructura de directoris per a gitlab-runner té aquest aspecte:

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

Però emmagatzemar secrets a Git no és segur, oi? Per tant, hem de xifrar-los correctament.

En general, pel bé d'una variable, no sempre té sentit. Podeu transferir secrets a qbec i mitjançant les variables d'entorn del vostre sistema CI.
Però val la pena assenyalar que també hi ha projectes més complexos que poden contenir molts més secrets, serà extremadament difícil passar-los tots per variables d'entorn.

A més, en aquest cas, no podria parlar-vos d'una eina tan meravellosa com git-crypt.

git-crypt També és convenient perquè permet desar tot l'historial de secrets, així com comparar, fusionar i resoldre conflictes de la mateixa manera que ho fèiem en el cas de Git.

Primer després de la instal·lació git-crypt hem de generar claus per al nostre repositori:

git crypt init

Si teniu una clau PGP, podeu afegir-vos immediatament com a col·laborador d'aquest projecte:

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

D'aquesta manera, sempre podeu desxifrar aquest repositori amb la vostra clau privada.

Si no teniu una clau PGP i no s'espera que la tingui, podeu anar a l'altre costat i exportar la clau del projecte:

git crypt export-key /path/to/keyfile

Així, qualsevol que posseeixi un exportat fitxer de claus podrà desxifrar el vostre repositori.

És hora d'establir el nostre primer secret.
Us recordo que encara estem al directori desplegar/gitlab-runner/on tenim un directori secrets/, xifrem tots els fitxers que hi ha, per a això crearem un fitxer secrets/.gitattributes amb contingut com aquest:

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

Com es pot veure pel contingut, tots els fitxers per màscara * travessarà git-crypt, amb l'excepció del .gitattributes

Això ho podem comprovar executant:

git crypt status -e

A la sortida, obtenim una llista de tots els fitxers del dipòsit per als quals el xifratge està habilitat

Això és tot, ara podem confirmar els nostres canvis amb seguretat:

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

Per bloquejar el repositori, n'hi ha prou amb executar:

git crypt lock

i immediatament tots els fitxers xifrats es convertiran en una cosa binari, serà impossible llegir-los.
Per desxifrar el repositori, executeu:

git crypt unlock

8. Creeu una imatge de caixa d'eines

Una imatge de caixa d'eines és una imatge amb totes les eines que utilitzarem per desplegar el nostre projecte. El corredor de gitlab l'utilitzarà per realitzar tasques de desplegament típiques.

Aquí tot és senzill, en creem un de nou dockerfiles/toolbox/Dockerfile amb contingut com aquest:

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

Com podeu veure, en aquesta imatge instal·lem totes les utilitats que hem utilitzat per desplegar la nostra aplicació. No necessitem aquí tret que kubectl, però potser voldreu jugar-hi quan configureu el pipeline.

A més, per poder comunicar-nos amb Kubernetes i desplegar-hi, hem de configurar un rol per als pods generats per gitlab-runner.

Per fer-ho, aneu al directori amb gitlab-runner'om:

cd deploy/gitlab-runner

i afegir un nou component 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,
      },
    ],
  },
]

També descrivim els nous paràmetres a ambients/base.libsonnet, que ara té aquest aspecte:

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

Preste atenció $.components.rbac.name es refereix a nom per component rbac

Comprovem què ha canviat:

qbec diff default

i apliqueu els nostres canvis a Kubernetes:

qbec apply default

A més, no oblideu confirmar els nostres canvis a 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. El nostre primer pipeline i muntatge d'imatges per tags

A l'arrel del projecte crearem .gitlab-ci.yml amb contingut com aquest:

.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

Tingueu en compte que estem utilitzant GIT_SUBMODULE_STRATEGY: normal per a aquells treballs en què necessiteu inicialitzar explícitament els submòduls abans de l'execució.

No us oblideu de comprometre els nostres canvis:

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

Crec que pots anomenar-ho una versió amb seguretat v0.0.1 i afegeix una etiqueta:

git tag v0.0.1

Penjarem les etiquetes sempre que hàgim de llançar una nova versió. Les etiquetes de les imatges de Docker s'assignaran a les etiquetes de Git. Cada empenta amb una etiqueta nova inicialitzarà una creació d'imatge amb aquesta etiqueta.

Fem-ho git push --tags, i mireu el nostre primer pipeline:

Captura de pantalla del primer pipeline

Provant noves eines per crear i automatitzar el desplegament a Kubernetes

Val la pena assenyalar que les compilacions basades en etiquetes són bones per crear imatges de Docker, però no per desplegar una aplicació a Kubernetes. Atès que també es poden assignar etiquetes noves a commits antigues, en aquest cas, la inicialització de la canalització per a elles comportarà el desplegament de la versió antiga.

Per resoldre aquest problema, la creació d'imatges docker normalment està lligada a etiquetes i el desplegament de l'aplicació a la branca mestre, en què les versions de les imatges recollides estan codificades. És en aquest cas que podeu inicialitzar el rollback amb una inversió senzilla mestre-branques.

10. Desplega l'automatització

Per tal que Gitlab-runner desxifra els nostres secrets, hem d'exportar la clau del repositori i afegir-la a les nostres variables d'entorn CI:

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

guardarem la cadena resultant a Gitlab, per a això anirem a la configuració del nostre projecte:
Configuració —> CI / CD —> Variables

I creeu una nova variable:

Tipus
Clau
Valor
Protegit
emmascarat
abast

File
GITCRYPT_KEY
<your string>
true (en el moment de l'entrenament, pots false)
true
All environments

Captura de pantalla de la variable afegida

Provant noves eines per crear i automatitzar el desplegament a Kubernetes

Ara actualitzem el nostre .gitlab-ci.yml afegint-hi:

.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

Aquí hem habilitat algunes opcions noves per a qbec:

  • --root some/app - permet definir el directori d'una aplicació específica
  • --force:k8s-context __incluster__ - aquesta és una variable màgica que diu que el desplegament es produirà al mateix clúster en què s'està executant gtilab-runner. Això és necessari, en cas contrari qbec intentarà trobar un servidor Kubernetes adequat al vostre kubeconfig
  • - espera - obliga qbec a esperar fins que els recursos que crea entren a l'estat Preparat i només aleshores es completa amb un codi de sortida satisfactori.
  • -sí - només desactiva l'intèrpret d'ordres interactiu Estàs segur? durant el desplegament.

No us oblideu de comprometre els nostres canvis:

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

I després git push veurem com s'han desplegat les nostres aplicacions:

Captura de pantalla del segon gasoducte

Provant noves eines per crear i automatitzar el desplegament a Kubernetes

11. Artefactes i muntatge en empènyer per dominar

Normalment, els passos anteriors són suficients per crear i oferir gairebé qualsevol microservei, però no volem afegir una etiqueta cada vegada que necessitem actualitzar el lloc. Per tant, anirem d'una manera més dinàmica i establirem un desplegament de resum a la branca mestra.

La idea és senzilla: ara la imatge del nostre es reconstruirà cada vegada que premeu mestre, i després es desplega automàticament a Kubernetes.

Actualitzem aquestes dues feines al nostre .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"

Tingueu en compte que hem afegit una sucursal mestre к ref per feina build_website i ara fem servir $CI_COMMIT_REF_NAME en comptes de $CI_COMMIT_TAG, és a dir, desfer-nos de les etiquetes a Git i ara empènyer la imatge amb el nom de la branca de commit que va inicialitzar el vostre pipeline. Val la pena assenyalar que això també funcionarà amb etiquetes, que ens permetran desar instantànies del lloc amb una versió específica al registre docker.

Quan el nom de l'etiqueta docker per a la nova versió del lloc no es pot canviar, encara hem de descriure els canvis per a Kubernetes, en cas contrari, simplement no tornarà a desplegar l'aplicació des de la nova imatge, ja que no notarà cap canvi a la imatge. manifest de desplegament.

Opció --vm:ext-str digest="$DIGEST" per qbec: us permet passar una variable externa a jsonnet. Volem que la nostra aplicació es torni a desplegar al clúster amb cada llançament. Ja no podem utilitzar el nom de l'etiqueta, que ara no es pot canviar, ja que hem d'enllaçar a una versió específica de la imatge i activar el desplegament quan canviï.

Aquí, la capacitat de Kaniko per desar el resum de la imatge en un fitxer ens ajudarà (opció --digest-file)
Després transferirem aquest fitxer i el llegirem en el moment del desplegament.

Actualitzem els paràmetres del nostre deploy/website/environments/base.libsonnet que ara quedarà així:

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

Fet, ara qualsevol es compromet mestre inicialitza la creació de la imatge de Docker per , i després implementeu-lo a Kubernetes.

No us oblideu de comprometre els nostres canvis:

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

Comproveu-ho després git push hauríem de veure alguna cosa com això:

Captura de pantalla de Pipeline per al mestre

Provant noves eines per crear i automatitzar el desplegament a Kubernetes

En principi, no necessitem tornar a desplegar gitlab-runner amb cada empenta, tret que, per descomptat, no hagi canviat res en la seva configuració, arreglem-ho a .gitlab-ci.yml:

deploy_gitlab_runner:
  extends: .deploy_qbec_app
  variables:
    GIT_SUBMODULE_STRATEGY: normal
  before_script:
    - base64 -d "$GITCRYPT_KEY" | git-crypt unlock -
  script:
    - qbec apply default --root deploy/gitlab-runner --force:k8s-context __incluster__ --wait --yes
  only:
    changes:
      - deploy/gitlab-runner/**/*

canvis farà un seguiment dels canvis desplegar/gitlab-runner/ i activarà la nostra feina només si n'hi ha

No us oblideu de comprometre els nostres canvis:

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

git push, això està millor:

Captura de pantalla de la canalització actualitzada

Provant noves eines per crear i automatitzar el desplegament a Kubernetes

12. Entorns dinàmics

És hora de diversificar la nostra cartera amb entorns dinàmics.

Primer, actualitzem la feina build_website en el nostre .gitlab-ci.yml, eliminant-ne el bloc només, que obligarà a Gitlab a activar-lo en qualsevol confirmació a qualsevol branca:

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/

A continuació, actualitzeu la feina lloc web_deploy, afegiu-hi un bloc medi ambient:

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"

Això permetrà a Gitlab associar la feina amb producció entorn i mostrar-hi l'enllaç correcte.

Ara afegim dos treballs més:

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

S'activaran mitjançant push a qualsevol branca excepte la mestra i desplegaran una versió de vista prèvia del lloc.

Veiem una nova opció per a qbec: --etiqueta-aplicació - us permet etiquetar les versions desplegades de l'aplicació i treballar només dins d'aquesta etiqueta; quan creeu i destruïu recursos a Kubernetes, qbec només operarà amb ells.
Per tant, no podem crear un entorn independent per a cada revisió, sinó simplement reutilitzar el mateix.

Aquí també fem servir qbec aplica revisió, en lloc de qbec aplica per defecte - aquest és exactament el moment en què intentarem descriure les diferències per als nostres entorns (revisió i per defecte):

Afegim revisar entorn en deploy/website/qbec.yaml

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

Llavors ho declarem a deploy/website/params.libsonnet:

local env = std.extVar('qbec.io/env');
local paramsMap = {
  _: import './environments/base.libsonnet',
  default: import './environments/default.libsonnet',
  review: import './environments/review.libsonnet',
};

if std.objectHas(paramsMap, env) then paramsMap[env] else error 'environment ' + env + ' not defined in ' + std.thisFile

I escriu-hi paràmetres personalitzats 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',
    },
  },
}

Mirem també de prop la feina stop_review, s'activarà quan s'elimini la branca i s'utilitza perquè gitlab no intenti pagar-hi GIT_STRATEGY: cap, més tard clonem mestre-ramificar i eliminar la revisió a través d'ella.
Una mica confús, però encara no he trobat una manera més bonica.
Una opció alternativa seria desplegar cada revisió a l'espai de noms d'un hotel, que sempre es pot enderrocar en la seva totalitat.

No us oblideu de comprometre els nostres canvis:

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

git push, prova git checkout -b, prova d'origen git push, comproveu:

Captura de pantalla dels entorns creats a Gitlab

Provant noves eines per crear i automatitzar el desplegament a Kubernetes

Tot funciona? - Genial, suprimiu la nostra branca de prova: git checkout master, git push origin :test, comprovem que els treballs per esborrar l'entorn van funcionar sense errors.

Aquí de seguida vull aclarir que qualsevol desenvolupador del projecte pot crear branques, també pot canviar .gitlab-ci.yml fitxer i accedir a variables secretes.
Per tant, és molt recomanable permetre el seu ús només per a branques protegides, per exemple a mestre, o creeu un conjunt separat de variables per a cada entorn.

13 Revisió d'aplicacions

Revisa les aplicacions aquesta és una característica de gitlab que us permet afegir un botó per a cada fitxer del repositori per visualitzar-lo ràpidament a l'entorn desplegat.

Perquè apareguin aquests botons, heu de crear un fitxer .gitlab/route-map.yml i descriu-hi totes les transformacions dels camins, en el nostre cas serà molt senzill:

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

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

No us oblideu de comprometre els nostres canvis:

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

git push, i comproveu:

Captura de pantalla del botó Revisa l'aplicació

Provant noves eines per crear i automatitzar el desplegament a Kubernetes

La feina està feta!

Fonts del projecte:

Gràcies per la vostra atenció, espero que us hagi agradat Provant noves eines per crear i automatitzar el desplegament a Kubernetes

Font: www.habr.com

Afegeix comentari