Essayer de nouveaux outils pour créer et automatiser le déploiement dans Kubernetes


Salut RĂ©cemment, de nombreux outils d'automatisation intĂ©ressants ont Ă©tĂ© publiĂ©s Ă  la fois pour la crĂ©ation d'images Docker et pour le dĂ©ploiement sur Kubernetes. À cet Ă©gard, j'ai dĂ©cidĂ© de jouer avec le gitlab, comment Ă©tudier ses capacitĂ©s et, bien sĂ»r, configurer le pipeline.


L'inspiration pour ce travail a été le site kubernetes.io , qui est généré automatiquement à partir des codes sources , et pour chaque pool envoyé, le robot génÚre automatiquement une version d'aperçu du site avec vos modifications et fournit un lien pour la visualisation.


J'ai essayé de créer un processus similaire à partir de zéro, mais entiÚrement basé sur Gitlab CI et des outils gratuits que j'utilisais pour déployer des applications dans Kubernetes. Aujourd'hui, je vais enfin vous en dire plus à leur sujet.


L'article examinera des outils tels que:
Hugo , qbec , kaniko , git-crypt et GitLab CI avec la création d'environnements dynamiques.




Table des matiĂšres


  1. Présentation de Hugo
  2. Préparation de Dockerfile
  3. Connaissance de kaniko
  4. Présentation du qbec
  5. Essayer Gitlab-runner avec Kubernetes-executor
  6. DĂ©ploiement des cartes Helm avec qbec
  7. Présentation de git-crypt
  8. Créer une image de boßte à outils
  9. Notre premier pipeline et assemblage d'images par tags
  10. Automatisation du déploiement
  11. Artefacts et push build dans master
  12. Environnements dynamiques
  13. Examiner les applications



1. Présentation de Hugo


À titre d'exemple de notre projet, nous allons essayer de crĂ©er un site web pour publier de la documentation construite sur Hugo. Hugo est un gĂ©nĂ©rateur de contenu statique.


Pour ceux qui ne connaissent pas les générateurs statiques, je vais vous en dire un peu plus à leur sujet. Contrairement aux moteurs de sites de bases de données classiques et à certains moteurs php qui, lorsqu'ils sont demandés par un utilisateur, génÚrent des pages à la volée, les générateurs statiques sont organisés un peu différemment. Ils vous permettent de prendre la source, en rÚgle générale, il s'agit d'un ensemble de fichiers dans les modÚles de balisage et de thÚme Markdown, puis de les compiler dans un site entiÚrement terminé.


Autrement dit, Ă  la sortie, vous obtiendrez une structure de rĂ©pertoires et un ensemble de fichiers HTML gĂ©nĂ©rĂ©s, qui peuvent ĂȘtre simplement tĂ©lĂ©chargĂ©s sur n'importe quel hĂ©bergement bon marchĂ© et obtenir un site de travail.


Hugo peut ĂȘtre installĂ© localement et l'essayer:


Nous initialisons le nouveau site:


hugo new site docs.example.org 

Et en mĂȘme temps le dĂ©pĂŽt git:


 cd docs.example.org git init 

Jusqu'à présent, notre site est vierge et pour que quelque chose y apparaisse d'abord, nous devons connecter un thÚme, un thÚme - c'est juste un ensemble de modÚles et de rÚgles prédéfinies par lesquelles notre site est généré.


Comme sujet, nous utiliserons Learn , qui, à mon avis, est le mieux adapté pour un site avec de la documentation.


Je voudrais porter une attention particuliÚre au fait que nous n'avons pas besoin d'enregistrer les fichiers de thÚme dans le référentiel de notre projet, nous pouvons simplement le connecter en utilisant le sous - module git :


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

Ainsi, seuls les fichiers directement liĂ©s Ă  notre projet seront dans notre rĂ©fĂ©rentiel, et le sujet connectĂ© restera sous la forme d'un lien vers un rĂ©fĂ©rentiel spĂ©cifique et s'y engagera, c'est-Ă -dire qu'il peut toujours ĂȘtre extrait de la source d'origine et ne pas avoir peur des modifications incompatibles.


Corrigez la configuration config.toml :


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

Déjà à ce stade, vous pouvez exécuter:


 hugo server 

Et sur http: // localhost: 1313 / consultez notre site nouvellement créé, toutes les modifications apportées au répertoire sont automatiquement mises à jour et la page ouverte dans le navigateur est trÚs pratique!


Essayons de créer une page de garde dans content / _index.md :


 # My docs site ## Welcome to the docs! You will be very smart :-) 

Capture d'écran de la page nouvellement créée


Pour générer un site, lancez simplement:


 hugo 

Le contenu du répertoire public / sera votre site.
Oui, au fait, ajoutons-le immédiatement à .gitignore :


 echo /public > .gitignore 

N'oubliez pas de valider nos modifications:


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



2. Préparation du Dockerfile


Il est temps de déterminer la structure de notre référentiel. Habituellement, j'utilise quelque chose comme:


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

  • dockerfiles / - contient des rĂ©pertoires avec Dockerfiles et tout ce dont vous avez besoin pour construire nos images de docker.
  • deploy / - contient des rĂ©pertoires pour dĂ©ployer nos applications sur Kubernetes

Ainsi, nous allons créer notre premier Dockerfile le long du chemin 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" ] 

Comme vous pouvez le voir, le Dockerfile contient deux FROM, cette fonctionnalité est appelée construction en plusieurs étapes et vous permet d'exclure tout ce qui n'est pas nécessaire de l'image Docker finale.
Ainsi, l'image finale ne contiendra que darkhttpd (un serveur HTTP léger) et public / - le contenu de notre site généré statiquement.


N'oubliez pas de valider nos modifications:


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



3. Connaissance de kaniko


En tant que collectionneur d'images docker, j'ai dĂ©cidĂ© d'utiliser kaniko , car il ne nĂ©cessite pas de dĂ©mon docker pour fonctionner, et l'assemblage lui-mĂȘme peut ĂȘtre effectuĂ© sur n'importe quelle machine et stocker le cache directement dans le registre, Ă©liminant le besoin d'avoir un stockage persistant complet .


Pour construire l'image, il suffit de démarrer le conteneur avec kaniko executor et de lui passer le contexte de construction actuel, vous pouvez le faire localement, 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 

Lorsque Registry.gitlab.com/kvaps/docs.example.org/website est le nom de votre image Docker, aprÚs l'assemblage, elle sera automatiquement insérée dans le registre Docker.


Le paramÚtre --cache vous permet de mettre en cache les couches dans le registre docker, pour l'exemple donné, elles seront enregistrées dans Registry.gitlab.com/kvaps/docs.example.org/website/cache , mais vous pouvez spécifier un autre chemin à l'aide du paramÚtre --cache- repo .


Screenshot docker-registry




4. Connaissance du qbec


Qbec est un outil de déploiement qui vous permet de décrire de maniÚre déclarative le manifeste de votre application et de le déployer sur Kubernetes. L'utilisation de Jsonnet comme syntaxe principale vous permet de simplifier considérablement la description des différences pour plusieurs environnements, et élimine également presque complÚtement la répétabilité du code.


Cela peut ĂȘtre particuliĂšrement vrai dans les cas oĂč vous devez dĂ©ployer une application dans plusieurs clusters avec diffĂ©rents paramĂštres et que vous souhaitez les dĂ©crire de maniĂšre dĂ©clarative dans Git.


Qbec vous permet Ă©galement de rendre des graphiques Helm en leur transmettant les paramĂštres nĂ©cessaires et en les faisant ensuite fonctionner ainsi que des manifestes rĂ©guliers, y compris diverses mutations qui peuvent leur ĂȘtre appliquĂ©es, ce qui, Ă  son tour, Ă©limine la nĂ©cessitĂ© d'utiliser le ChartMuseum. Autrement dit, vous pouvez stocker et rendre des graphiques directement Ă  partir de git, oĂč ils ont la place.


Comme je l'ai déjà dit, nous allons stocker tous les déploiements dans le répertoire deploy / :


 mkdir deploy cd deploy 

Initialisons notre premiĂšre application:


 qbec init website cd website 

Maintenant, la structure de notre application ressemble Ă  ceci:


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

regardez le fichier qbec.yaml :


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

Ici, nous nous intéressons principalement aux environnements spécifiques , qbec a déjà créé un environnement par défaut pour nous et a pris l'adresse du serveur, ainsi que l'espace de noms de notre kubeconfig actuel.
Désormais, lors du déploiement dans l'environnement par défaut , qbec ne sera toujours déployé que sur le cluster Kubernetes spécifié et sur l'espace de noms spécifié, c'est-à-dire que vous n'aurez plus à basculer entre les contextes et les espaces de noms pour effectuer un déploiement.
Si nécessaire, vous pouvez toujours mettre à jour les paramÚtres de ce fichier.


Tous vos environnements sont dĂ©crits dans qbec.yaml et dans le fichier params.libsonnet , oĂč il indique oĂč vous devez prendre les paramĂštres pour eux.


Ensuite, nous voyons deux répertoires:


  • composants / - tous les manifestes pour notre application seront stockĂ©s ici, ils peuvent ĂȘtre dĂ©crits Ă  la fois dans jsonnet et dans des fichiers yaml ordinaires
  • environnements / - nous dĂ©crirons ici toutes les variables (paramĂštres) de nos environnements.

Par défaut, nous avons deux fichiers:


  • environnements / base.libsonnet - il contiendra des paramĂštres gĂ©nĂ©raux pour tous les environnements
  • environnements / default.libsonnet - contient les paramĂštres remplacĂ©s pour l'environnement par dĂ©faut

Ouvrons environnement / base.libsonnet et ajoutons-y les paramĂštres de notre premier composant:


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

Nous allons également créer notre premier composant / 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, }, }, ], }, }, ], }, }, ] 

Dans ce fichier, nous avons immédiatement décrit trois entités Kubernetes, à savoir: Déploiement , Service et Ingress . Si vous le souhaitez, nous pourrions les transporter dans différents composants, mais à ce stade, un suffit pour nous.


La syntaxe jsonnet est trĂšs similaire Ă  json standard, en principe json standard est dĂ©jĂ  un jsonnet valide, donc au dĂ©but il pourrait ĂȘtre plus facile d'utiliser des services en ligne comme yaml2json pour convertir votre yaml habituel en json, ou si vos composants ne contiennent aucune variable, alors ils peuvent ĂȘtre dĂ©crits sous forme de yaml ordinaire.


Lorsque vous travaillez avec jsonnet, je recommande fortement d'installer un plugin pour votre Ă©diteur

Par exemple, pour vim, il existe un plugin vim-jsonnet qui active la coloration syntaxique et exécute automatiquement jsonnet fmt chaque fois qu'il est enregistré (nécessite l'installation de jsonnet).

Tout est prĂȘt, nous pouvons maintenant commencer le dĂ©ploiement:


Pour voir ce qui s'est passé, nous allons faire:


 qbec show default 

En sortie, vous verrez des manifestes yaml rendus qui seront appliqués au cluster par défaut.


Ok, appliquez maintenant:


 qbec apply default 

À la sortie, vous verrez toujours ce qui se fera dans votre grappe, qbec vous demandera d'accepter les modifications, en tapant y vous pourrez confirmer vos intentions.


Terminé, maintenant notre application est ancrée!


Si vous apportez des modifications, vous pouvez toujours:


 qbec diff default 

pour voir comment ces changements affecteront le déploiement actuel


N'oubliez pas de valider nos modifications:


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



5. Essayer Gitlab-runner avec Kubernetes-executor


Jusqu'à récemment, je n'utilisais que le gitlab-runner habituel sur une machine pré-préparée (conteneur LXC) avec un shell ou un docker-executor. Initialement, nous avions plusieurs de ces coureurs définis globalement dans notre hitlab. Ils ont collecté des images de docker pour tous les projets.


Mais comme la pratique l'a montrĂ©, cette option n'est pas la plus idĂ©ale, tant en termes de praticitĂ© qu'en termes de sĂ©curitĂ©. Il est beaucoup mieux et idĂ©ologiquement plus correct de dĂ©ployer des coureurs sĂ©parĂ©s pour chaque projet, et mĂȘme pour chaque environnement.


Heureusement, ce n'est pas un problÚme du tout, car nous allons maintenant déployer gitlab-runner directement dans le cadre de notre projet directement sur Kubernetes.


Gitlab fournit un graphique de barre prĂȘt Ă  l'emploi pour le dĂ©ploiement de gitlab-runner dans Kubernetes. Ainsi, tout ce que vous avez Ă  faire est de trouver le jeton d'enregistrement de notre projet dans ParamĂštres -> CI / CD -> Runners et de lui passer la barre:


 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 

OĂč:


  • https://gitlab.com est l'adresse de votre serveur Gitlab.
  • yga8y-jdCusVDn_t4Wxc - jeton d'enregistrement pour votre projet.
  • rbac.create = true - Donne au coureur le nombre de privilĂšges requis pour pouvoir crĂ©er des pods pour effectuer nos tĂąches en utilisant l'exĂ©cuteur kubernetes.

Si tout est fait correctement, vous devriez voir le coureur enregistré dans la section Coureurs , dans les paramÚtres de votre projet.


Capture d'écran du coureur ajouté


C'est aussi simple que ça? - oui, si simple! Plus de tracas avec l'enregistrement manuel des coureurs, désormais les coureurs seront créés et détruits automatiquement.




6. DĂ©ploiement des cartes Helm avec QBEC


Puisque nous avons décidé de considérer gitlab-runner comme faisant partie de notre projet, il est temps de le décrire dans notre référentiel Git.


Nous pourrions le décrire comme un composant distinct du site Web , mais à l'avenir, nous prévoyons de déployer trÚs souvent différentes copies du site Web , contrairement à gitlab-runner , qui ne sera déployé qu'une seule fois pour chaque cluster Kubernetes. Alors initialisons une application distincte pour cela:


 cd deploy qbec init gitlab-runner cd gitlab-runner 

Cette fois, nous ne dĂ©crirons pas les entitĂ©s Kubernetes manuellement, mais prenons un graphique Helm prĂȘt Ă  l'emploi. L'un des avantages de qbec est la possibilitĂ© de rendre les graphiques Helm directement Ă  partir du rĂ©fĂ©rentiel Git.


Branchez-le Ă  l'aide du sous-module git:


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

Maintenant, le répertoire vendor / gitlab-runner contient notre référentiel avec un graphique pour gitlab-runner.


De mĂȘme, vous pouvez connecter d'autres rĂ©fĂ©rentiels, par exemple, l'ensemble du rĂ©fĂ©rentiel avec les graphiques officiels https://github.com/helm/charts

DĂ©crivons le composant 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, } ) 

Le premier argument pour expandHelmTemplate nous passons le chemin vers le graphique, puis params.values , que nous prenons des paramĂštres d'environnement, puis un objet avec


  • nameTemplate - nom de la version
  • namespace - namespace passĂ© Ă  la barre
  • thisFile - paramĂštre obligatoire transmettant le chemin d'accĂšs au fichier actuel
  • verbeux - affiche la commande de modĂšle de barre avec tous les arguments lors du rendu du graphique

Nous allons maintenant décrire les paramÚtres de notre composant dans environnements / base.libsonnet :


 local secrets = import '../secrets/base.libsonnet'; { components: { gitlabRunner: { name: 'gitlab-runner', values: { gitlabUrl: 'https://gitlab.com/', rbac: { create: true, }, runnerRegistrationToken: secrets.runnerRegistrationToken, }, }, }, } 

Faites attention à runnerRegistrationToken que nous prenons du fichier externe secrets / base.libsonnet , créons-le:


 { runnerRegistrationToken: 'yga8y-jdCusVDn_t4Wxc', } 

VĂ©rifiez si tout fonctionne:


 qbec show default 

si tout est en ordre, nous pouvons supprimer notre version antérieure via la version Helm:


 helm uninstall gitlab-runner 

et le déployer, mais déjà via qbec:


 qbec apply default 



7. Présentation de git-crypt


Git-crypt est un outil qui vous permet de configurer un cryptage transparent pour votre référentiel.


Pour le moment, la structure de notre répertoire pour gitlab-runner ressemble à ceci:


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

Mais garder des secrets dans Git n'est pas sûr, n'est-ce pas? Nous devons donc les chiffrer correctement.


Habituellement, pour le bien d'une seule variable, cela n'a pas toujours de sens. Vous pouvez transmettre des secrets Ă  qbec et via les variables d'environnement de votre systĂšme CI.
Mais il convient de noter qu'il existe des projets plus complexes qui peuvent contenir beaucoup plus de secrets; il sera extrĂȘmement difficile de les transfĂ©rer tous via des variables d'environnement.

De plus, dans ce cas, je ne serais pas en mesure de vous parler d'un outil aussi merveilleux que git-crypt .

git-crypt est Ă©galement pratique car il vous permet de sauvegarder l'historique complet des secrets, ainsi que de comparer, de fusionner et de rĂ©soudre les conflits de la mĂȘme maniĂšre que nous le faisions dans le cas de Git.

Tout d'abord, aprÚs avoir installé git-crypt, nous devons générer des clés pour notre référentiel:


 git crypt init 

Si vous avez une clé PGP, vous pouvez immédiatement vous ajouter en tant que collaborateur pour ce projet:


 git-crypt add-gpg-user kvapss@gmail.com 

Ainsi, vous pouvez toujours décrypter ce référentiel à l'aide de votre clé privée.


Si vous n'avez pas de clĂ© PGP et que vous n'ĂȘtes pas attendu, vous pouvez alors aller dans l'autre sens et exporter la clĂ© de projet:


 git crypt export-key /path/to/keyfile 

De cette façon, toute personne possédant un fichier de clés exporté pourra décrypter votre référentiel.


Il est temps de mettre en place notre premier secret.
Permettez-moi de vous rappeler que nous sommes toujours dans le rĂ©pertoire deploy / gitlab-runner / , oĂč nous avons le rĂ©pertoire secrets /, chiffrons tous les fichiers qu'il contient , pour cela nous crĂ©ons le fichier secrets / .gitattributes avec le contenu suivant:


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

Comme vous pouvez le voir dans le contenu, tous les fichiers par mask * seront exĂ©cutĂ©s via git-crypt , Ă  l'exception de .gitattributes lui-mĂȘme


Nous pouvons le vérifier en exécutant:


 git crypt status -e 

À la sortie, nous obtenons une liste de tous les fichiers du rĂ©fĂ©rentiel pour lesquels le cryptage est activĂ©


C'est tout, maintenant nous pouvons valider nos modifications en toute sécurité:


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

Pour bloquer le référentiel, faites simplement:


 git crypt lock 

et puis tous les fichiers cryptés se transforment en quelque chose de binaire, il sera impossible de les lire.
Pour décrypter un référentiel, procédez comme suit:


 git crypt unlock 



8. Créez une image de boßte à outils


Une image de boßte à outils est une telle image avec tous les outils que nous utiliserons pour déployer notre projet. Il sera utilisé par le runner gitlab pour effectuer des tùches de déploiement typiques.


Ici, tout est simple, nous créons un nouveau dockerfiles / toolbox / Dockerfile avec le contenu suivant:


 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 

Comme vous pouvez le voir, dans cette image, nous installons tous les utilitaires que nous avons utilisĂ©s pour dĂ©ployer notre application. Nous n'avons pas besoin de kubectl ici , mais vous voudrez peut-ĂȘtre jouer avec lui lors de la configuration du pipeline.


De plus, afin de pouvoir communiquer avec Kubernetes et y effectuer un déploiement, nous devons configurer le rÎle des pods générés par gitlab-runner.


Pour ce faire, allez dans le répertoire avec gitlab-runner:


 cd deploy/gitlab-runner 

et ajoutez un nouveau composant 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, }, ], }, ] 

Nous décrirons également les nouveaux paramÚtres dans environnements / base.libsonnet , qui ressemble maintenant à ceci:


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

Remarque $ .components.rbac.name fait référence au nom du composant rbac


Vérifions ce qui a changé:


 qbec diff default 

et appliquer nos modifications Ă  Kubernetes:


 qbec apply default 

N'oubliez pas non plus de valider nos modifications dans 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. Notre premier pipeline et assemblage d'images par tags


À la racine du projet, nous crĂ©erons .gitlab-ci.yml avec le contenu suivant:


 .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 

Veuillez noter que nous utilisons GIT_SUBMODULE_STRATEGY: normal pour les travaux oĂč vous devez initialiser explicitement les sous-modules avant l'exĂ©cution.


N'oubliez pas de valider nos modifications:


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

Je pense que vous pouvez l'appeler en toute sécurité la version v0.0.1 et accrocher une balise:


 git tag v0.0.1 

Nous accrocherons les balises chaque fois que nous aurons besoin de publier une nouvelle version. Les balises dans les images Docker seront liées aux balises Git. Chaque poussée avec une nouvelle balise initialisera l'assemblage d'images avec cette balise.


Exécutez git push --tags et regardez notre premier pipeline:


Capture d'Ă©cran du premier pipeline


Il convient de prĂȘter votre attention au fait que l'assemblage par balises convient Ă  l'assemblage d'images Docker, mais ne convient pas au dĂ©ploiement d'une application dans Kubernetes. Étant donnĂ© que de nouvelles balises peuvent Ă©galement ĂȘtre affectĂ©es Ă  d'anciennes validations, dans ce cas, l'initialisation du pipeline pour elles entraĂźnera le dĂ©ploiement de l'ancienne version.

Pour résoudre ce problÚme, généralement l'assemblage d'images docker est attaché à des balises et le déploiement de l'application à la branche principale, dans laquelle les versions des images collectées sont codées en dur. C'est dans ce cas que vous pouvez initialiser la restauration avec une simple balise maßtre de restauration.



10. Automatisation du déploiement


Pour que Gitlab-runner déchiffre nos secrets, nous devons exporter la clé du référentiel et l'ajouter aux variables d'environnement de notre CI:


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

enregistrez la chaßne résultante dans Gitlab, pour cela nous allons aller dans les paramÚtres de notre projet:
ParamĂštres -> CI / CD -> Variables


:


TapezCléValueProtectedMaskedScope
FileGITCRYPT_KEY<your string>true ( false )trueAll environments


.gitlab-ci.yml :


 .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 

qbec:


  • --root some/app —
  • --force:k8s-context __incluster__ — , gtilab-runner. , qbec Kubernetes- kubeconfig
  • --wait — qbec , Ready exit-code.
  • --yes — Are you sure? .

:


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

git push :





11. push master


, . digest master-.


: website push master , Kubernetes.


.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" 

, master refs build_website $CI_COMMIT_REF_NAME $CI_COMMIT_TAG , Git . , , docker-registry.


docker- , Kubernetes, , .


--vm:ext-str digest="$DIGEST" qbec — jsonnet. . , , , .


Kaniko digest ( --digest-file )
.


deploy/website/environments/base.libsonnet :


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

, master docker- website , Kubernetes.


:


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

, git push - :


master


gitlab-runner push, , , , .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/**/* 

changes deploy/gitlab-runner/


:


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

git push , - :





12. Dynamic environments


.


build_website .gitlab-ci.yml , only , Gitlab :


 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/ 

deploy_website , environment :


 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" 

Gitlab prod .


:


 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 

push master preview .


qbec: --app-tag — , Kubernetes qbec .
review, .


qbec apply review , qbec apply default — (review default):


review deploy/website/qbec.yaml


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

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 

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

stop_review , gitlab checkout GIT_STRATEGY: none , master - review .
, .
review , .


:


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

git push , git checkout -b test , git push origin test , :


environments Gitlab


? — , : git checkout master , git push origin :test , environment .


, , .gitlab-ci.yml .
protected-, master , .



13. Review Apps


Review Apps , .


, .gitlab/route-map.yml , :


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

:


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

git push , :


Review App


Job is done!


:



, image

Source: https://habr.com/ru/post/fr481662/


All Articles