ProHoster > Bloc > Administració > 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.
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:
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
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:
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:
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
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:
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:
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ó:
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
É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.
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:
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:
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:
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:
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ó.
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
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:
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.
I després git push veurem com s'han desplegat les nostres aplicacions:
Captura de pantalla del segon gasoducte
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:
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í:
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
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:
Captura de pantalla de la canalització actualitzada
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:
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):
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.
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: