Comment décrire un job 100 gitlab en 100 lignes sur Jsonnet

Dans la suite de l' article précédent sur les outils de déploiement dans Kubernetes, je veux vous expliquer comment vous pouvez utiliser Jsonnet pour simplifier la description du travail dans votre .gitlab-ci.yml



Étant donnĂ©


Il existe un monorepa dans lequel:


  • 10 Dockerfiles
  • 30 dĂ©ploiements dĂ©crits
  • 3 environnements: dĂ©veloppement , mise en scĂšne et production

DĂ©fi


Configurer un pipeline:


  • La construction d'images Docker doit ĂȘtre effectuĂ©e en ajoutant une balise git avec une version.
  • Chaque opĂ©ration de dĂ©ploiement doit ĂȘtre effectuĂ©e lors de la transmission Ă  la branche environnement et uniquement en modifiant les fichiers dans un rĂ©pertoire spĂ©cifique
  • Chaque environnement possĂšde son propre gitlab-runner avec une balise distincte qui effectue uniquement le dĂ©ploiement dans son environnement.
  • Toutes les applications ne doivent pas ĂȘtre dĂ©ployĂ©es dans chacun des environnements; nous devons dĂ©crire le pipeline afin de pouvoir faire des exceptions.
  • Certains dĂ©ploiements utilisent le sous-module git et doivent ĂȘtre dĂ©marrĂ©s avec la variable dĂ©finie GIT_SUBMODULE_STRATEGY=normal

Décrire tout cela peut sembler un véritable enfer, mais nous ne désespérons pas et armés de Jsonnet, nous le ferons facilement et naturellement.


Solution


gitlab-ci.yml a des capacités intégrées pour réduire la description des travaux répétés, par exemple, vous pouvez utiliser étend ou inclure , mais il ne fournit pas de modÚles à part entiÚre, ce qui ne nous permet pas de décrire les plus concis et efficaces.


Pour résoudre ce problÚme, je suggÚre d'utiliser jsonnet, qui vous permet de vous débarrasser presque complÚtement de la répétition de code lors de la description des structures de données.


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

Regardons la structure de notre référentiel:


 . ├── deploy │  ├── analyse │  ├── basin │  ├── brush │  ├── copper │  ├── dinner │  ├── dirty │  ├── drab │  ├── drunk │  ├── education │  ├── fanatical │  ├── faulty │  ├── guarantee │  ├── guitar │  ├── hall │  ├── harmonious │  ├── history │  ├── iron │  ├── maniacal │  ├── mist │  ├── nine │  ├── pleasant │  ├── polish │  ├── receipt │  ├── shop │  ├── smelly │  ├── solid │  ├── stroke │  ├── thunder │  ├── ultra │  └── yarn └── dockerfiles ├── dinner ├── drunk ├── fanatical ├── guarantee ├── guitar ├── harmonious ├── shop ├── smelly ├── thunder └── yarn 

Les images Docker seront construites en utilisant kaniko


Le déploiement des applications sur le cluster se fera à l'aide de qbec . Chaque application est décrite pour trois environnements différents, pour appliquer des modifications au cluster, il suffit d'effectuer:


 qbec apply <environment> --root deploy/<app> --yes 

oĂč:


  • <app> - le nom de notre application
  • <environment> est l'un de nos environnements: dĂ©veloppement , mise en scĂšne ou prod .

En fin de compte, nos emplois devraient ressembler Ă  ceci:


Assemblage:


 build:{{ image }}: stage: build tags: - build image: name: gcr.io/kaniko-project/executor:debug entrypoint: [""] script: - echo "{\"auths\":{\"$CI_REGISTRY\":{\"username\":\"$CI_REGISTRY_USER\",\"password\":\"$CI_REGISTRY_PASSWORD\"}}}" > /kaniko/.docker/config.json - /kaniko/executor --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/dockerfiles/{{ image }}/Dockerfile --destination $CI_REGISTRY_IMAGE/{{ image }}:$CI_COMMIT_TAG only: refs: - tags 

Au lieu de {{ image }} , le nom de répertoire des dockerfiles sera remplacé


DĂ©ployer:


 deploy:{{ environment }}:{{ app }}: stage: deploy tags: - {{ environment }} script: - qbec apply {{ environment }} --root deploy/{{ app }} --force:k8s-context __incluster__ --wait --yes only: changes: - deploy/{{ app }}/**/* refs: - {{ environment }} 

Au lieu de {{ app }} , le nom de répertoire de deploy sera remplacé,
et au lieu de {{ environment }} - le nom de l'environnement dans lequel vous souhaitez vous déployer.


Décrivons les prototypes de nos travaux en tant qu'objets dans une lib / jobs.jsonnet séparée


 { //    docker- dockerImage(name):: { tags: ['build'], stage: 'build', image: { name: 'gcr.io/kaniko-project/executor:debug-v0.15.0', entrypoint: [''], }, script: [ 'echo "{\\"auths\\":{\\"$CI_REGISTRY\\":{\\"username\\":\\"$CI_REGISTRY_USER\\",\\"password\\":\\"$CI_REGISTRY_PASSWORD\\"}}}" > /kaniko/.docker/config.json', '/kaniko/executor --cache --context $CI_PROJECT_DIR/dockerfiles/' + name + ' --dockerfile $CI_PROJECT_DIR/dockerfiles/' + name + '/Dockerfile --destination $CI_REGISTRY_IMAGE/' + name + ':$CI_COMMIT_TAG --build-arg VERSION=$CI_COMMIT_TAG', ], }, //    qbec- qbecApp(name): { stage: 'deploy', script: [ 'qbec apply $CI_COMMIT_REF_NAME --root deploy/' + name + ' --force:k8s-context __incluster__ --wait --yes', ], only: { changes: [ 'deploy/' + name + '/**/*', ], }, }, } 

Veuillez noter que je n'ai délibérément pas spécifié de refs et de tags pour rendre notre bibliothÚque plus flexible et vous démontrer pleinement les capacités de jsonnet, nous les ajouterons plus tard à partir du fichier principal.


Nous allons maintenant décrire notre .gitlab-ci.jsonnet :


 //    local jobs = import 'lib/jobs.libsonnet'; //    local ref(x) = { only+: { refs: [x] } }; local tag(x) = { tags: [x] }; local submodule(x) = { variables+: { GIT_SUBMODULE_STRATEGY: x } }; { // C docker- ['build:' + x]: jobs.dockerImage(x) + tag('build') + ref('tags') for x in [ 'dinner', 'drunk', 'fanatical', 'guarantee', 'guitar', 'harmonious', 'shop', 'smelly', 'thunder', 'yarn', ] } + { //         'prod' ['deploy:prod:' + x]: jobs.qbecApp(x) + tag('prod') + ref('prod') for x in [ 'dinner', 'hall', ] } + { //   git-submodule ['deploy:' + env + ':' + app]: jobs.qbecApp(app) + tag(env) + ref(env) + submodule('normal') for env in ['devel', 'stage', 'prod'] for app in [ 'brush', 'fanatical', 'history', 'shop', ] } + { //    ['deploy:' + env + ':' + app]: jobs.qbecApp(app) + tag(env) + ref(env) for env in ['devel', 'stage', 'prod'] for app in [ 'analyse', 'basin', 'copper', 'dirty', 'drab', 'drunk', 'education', 'faulty', 'guarantee', 'guitar', 'harmonious', 'iron', 'maniacal', 'mist', 'nine', 'pleasant', 'polish', 'receipt', 'smelly', 'solid', 'stroke', 'thunder', 'ultra', 'yarn', ] } 

Faites attention aux fonctions ref , tag et submodule au début du fichier; elles vous permettent de créer un objet prioritaire.


Une petite explication: utiliser " +: " au lieu de " : " pour remplacer les objets vous permet d'ajouter une valeur Ă  un objet ou une liste existant.


Par exemple " : " pour les références :


 local job = { script: ['echo 123'], only: { refs: ['tags'] }, }; local ref(x) = { only+: { refs: [x] } }; job + ref('prod') 

retournera:


 { "only": { "refs": [ "prod" ] }, "script": [ "echo 123" ] } 

Et voici le « +: » pour les références :


 local job = { script: ['echo 123'], only: { refs: ['tags'] }, }; local ref(x) = { only+: { refs+: [x] } }; job + ref('prod') 

retournera:


 { "only": { "refs": [ "prod", "tags" ] }, "script": [ "echo 123" ] } 

Comme vous pouvez le voir, l'utilisation de Jsonnet vous permet de dĂ©crire et de fusionner trĂšs efficacement vos objets, en sortie, vous obtenez toujours du JSON prĂȘt Ă  l'emploi, que nous pouvons immĂ©diatement Ă©crire dans notre fichier .gitlab-ci.yml :


 jsonnet .gitlab-ci.jsonnet > .gitlab-ci.yml 

VĂ©rifiez le nombre de lignes:


 # wc -l .gitlab-ci.jsonnet lib/jobs.libsonnet .gitlab-ci.yml 77 .gitlab-ci.jsonnet 24 lib/jobs.libsonnet 1710 .gitlab-ci.yml 

À mon avis, c'est trùs bien!


Vous pouvez voir plus d'exemples et sentir Jsonnet directement sur le site officiel: jsonnet.org
Si vous, comme moi, comme Jsonnet, rejoignez notre groupe dans le télégramme t.me/jsonnet_ru

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


All Articles