
Il y a deux ans, nous avons publiĂ© lâarticle «
GĂ©nĂ©rer des projets avec GitLab CI: un .gitlab-ci.yml pour des centaines dâapplications », et nous allons maintenant parler de la rĂ©solution dâun problĂšme similaire aujourdâhui. Le nouveau matĂ©riel concerne la façon dont vous pouvez crĂ©er des processus CI / CD pour un grand nombre d'applications similaires avec l'avĂšnement d'
include
dans
.gitlab-ci.yml
et l'avĂšnement de werf pour remplacer dapp.
Introduction
Dans les instructions supplémentaires données dans l'article, la situation suivante est prise en compte:
- Il existe une grande application cliente, divisée en plusieurs référentiels.
- Chaque rĂ©fĂ©rentiel est une application distincte qui doit ĂȘtre exĂ©cutĂ©e dans un cluster Kubernetes.
- En tant que systÚme CI, GitLab CI est utilisé.
- Le déploiement (l'infrastructure dans laquelle le code est déployé) est décrit par les graphiques Helm.
- Créez des images et déployez-les dans Kubernetes à l'aide de werf .
Pour plus de simplicité et de commodité (et en hommage à la mode), nous continuerons à appeler ces applications des microservices.
Tous ces microservices sont assemblĂ©s, dĂ©ployĂ©s et lancĂ©s de la mĂȘme maniĂšre , et des paramĂštres spĂ©cifiques sont configurĂ©s Ă l'aide de variables d'environnement.
De toute évidence, la copie de
.gitlab-ci.yml
,
werf.yaml
et
.helm
beaucoup de problĂšmes. AprĂšs tout, toute modification dans CI, le processus d'assemblage ou la description du Helm-chart doit ĂȘtre ajoutĂ©e Ă d'autres rĂ©fĂ©rentiels ...
Connexion de modĂšles dans .gitlab-ci.yml
Avec l'avĂšnement de la directive
include:file
dans GitLab CE (
depuis la version 11.7 ), il est devenu possible de créer un CI commun.
include
lui-mĂȘme est apparu un peu plus tĂŽt (en 11.4), mais il a permis de connecter des modĂšles uniquement Ă partir
d' URL
publiques , ce qui a quelque peu limité sa fonctionnalité. La documentation de GitLab
décrit parfaitement toutes les fonctionnalités et exemples d'utilisation.
Ainsi, il a été possible de refuser de copier
.gitlab-ci.yml
entre les référentiels et de soutenir sa pertinence. Voici un exemple
.gitlab-ci.yml
avec
include
:
include: - project: 'infra/gitlab-ci' ref: 1.0.0 file: base-gitlab-ci.yaml - project: 'infra/gitlab-ci' ref: 1.0.0 file: cleanup.yaml
Nous vous recommandons fortement d'utiliser les noms de branche en
ref
avec prudence . Les inclusions sont calculées au moment de la création du pipeline, de sorte que les modifications de votre CI peuvent automatiquement tomber dans le pipeline de production au moment le plus inopportun. Mais l'
utilisation de balises dans ref
facilite la version de la description des processus CI / CD. Lors de la mise à jour, tout semble aussi transparent que possible et vous pouvez facilement suivre l'historique des modifications dans les versions de pipeline si vous utilisez le contrÎle de version sémantique pour les balises.
Connectez .helm à partir d'un référentiel distinct
Ătant donnĂ© que ces microservices sont dĂ©ployĂ©s et exĂ©cutĂ©s de la mĂȘme maniĂšre, le mĂȘme ensemble de modĂšles Helm est requis. Pour Ă©viter de copier le rĂ©pertoire
.helm
entre les référentiels, nous avons utilisé pour cloner le référentiel dans lequel les modÚles Helm étaient stockés et vérifiés sur la balise souhaitée. Cela ressemblait à ceci:
- git clone https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.example.com/infra/helm.git .helm - cd .helm && git checkout tags/1.0.0 - type multiwerf && source <(multiwerf use 1.0 beta) - type werf && source <(werf ci-env gitlab --tagging-strategy tag-or-branch --verbose) - werf deploy --stages-storage :local
Il y avait aussi des variantes utilisant des sous-modules git, mais tout cela ressemble plus Ă une solution de contournement ...
Et maintenant, avec la récente version de werf, il
a la possibilité de connecter des graphiques à partir de référentiels externes. La prise en charge complÚte des fonctions du gestionnaire de packages a, à son tour, permis de décrire de maniÚre
transparente les dépendances pour le déploiement de l'application.
Séquence d'actions
Revenons à la résolution de notre problÚme avec les microservices. Augmentons notre référentiel pour stocker les graphiques Helm - par exemple,
ChartMuseum . Il se déploie facilement sur un cluster Kubernetes:
helm repo add stable https://kubernetes-charts.storage.googleapis.com helm install stable/chartmuseum --name flant-chartmuseum
Ajouter une entrée:
apiVersion: extensions/v1beta1 kind: Ingress metadata: annotations: kubernetes.io/ingress.class: nginx nginx.ingress.kubernetes.io/force-ssl-redirect: "false" nginx.ingress.kubernetes.io/proxy-body-size: 10m nginx.ingress.kubernetes.io/ssl-redirect: "false" name: chart-museum spec: rules: - host: flant-chartmuseum.example.net http: paths: - backend: serviceName: flant-chartmuseum servicePort: 8080 path: / status: loadBalancer: {}
Le déploiement
flant-chartmuseum
doit remplacer la variable d'environnement
DISABLE_API
par
false
. Sinon (par dĂ©faut), les requĂȘtes de l'API ChartMuseum ne fonctionneront pas et il ne sera pas possible de crĂ©er de nouveaux graphiques.
Nous décrivons maintenant le référentiel dans lequel les graphiques Helm partagés seront stockés. La structure de ses répertoires est la suivante:
. âââ charts â âââ yii2-microservice â âââ Chart.yaml â âââ templates â âââ app.yaml âââ README.md
Chart.yaml
pourrait ressembler Ă ceci:
name: yii2-microservice version: 1.0.4
Le répertoire des
templates
doit contenir toutes les primitives Kubernetes nĂ©cessaires qui seront nĂ©cessaires pour dĂ©ployer l'application sur le cluster. Comme vous l'avez peut-ĂȘtre dĂ©jĂ devinĂ©, dans ce cas, le microservice est une application PHP basĂ©e sur le framework yii2. DĂ©crivons son dĂ©ploiement minimal avec deux conteneurs nginx et php-fpm qui sont construits Ă l'aide de werf:
--- apiVersion: apps/v1 kind: Deployment metadata: name: {{ .Values.global.werf.name }} spec: replicas: 1 revisionHistoryLimit: 3 template: metadata: labels: service: {{ .Values.global.werf.name }} spec: imagePullSecrets: - name: registrysecret containers: - name: backend {{ tuple "backend" . | include "werf_container_image" | indent 8 }} command: [ '/usr/sbin/php-fpm7', "-F" ] ports: - containerPort: 9000 protocol: TCP name: http env: {{ tuple "backend" . | include "werf_container_env" | indent 8 }} - name: frontend command: ['/usr/sbin/nginx'] {{ tuple "frontend" . | include "werf_container_image" | indent 8 }} ports: - containerPort: 80 name: http lifecycle: preStop: exec: command: ["/usr/sbin/nginx", "-s", "quit"] env: {{ tuple "frontend" . | include "werf_container_env" | indent 8 }} --- apiVersion: v1 kind: Service metadata: name: {{ .Values.global.werf.name }} spec: selector: service: {{ .Values.global.werf.name }} ports: - name: http port: 80 protocol: TCP
La variable
.Values.global.werf.name
contient le nom du projet Ă partir du fichier
werf.yaml
, ce qui vous permet d'obtenir les noms de services et de déploiements nécessaires.
Faisons l'automatisation la plus simple pour pousser dans le ChartMuseum de nos graphiques lors de la validation dans la branche principale. Pour ce faire, nous décrivons
.gitlab-ci.yml
:
Build and push to chartmuseum: script: - for i in $(ls charts); do helm package "charts/$i"; done; - for i in $(find . -type f -name "*.tgz" -printf "%f\n"); do curl --data-binary "@$i" http://flant-chartmuseum.example.net/api/charts; done; stage: build environment: name: infra only: - master tags: - my-shell-runner-tag
Les graphiques sont versionnés en changeant la
version
dans
Chart.yaml
. Tous les nouveaux graphiques seront automatiquement ajoutés au ChartMuseum.
Nous allons à la ligne d'arrivée! Dans le référentiel du projet en
.helm/requirements.yaml
écrivons les dépendances du graphique:
dependencies: - name: yii2-microservice version: "1.0.4" repository: "@flant"
... et exécutez dans le répertoire avec le référentiel:
werf helm repo init werf helm repo add flant http://flant-chartmuseum.example.net werf helm dependency update
Nous
.helm/requirements.lock
. Maintenant, pour déployer l'application sur le cluster, il suffit d'exécuter la
werf helm dependency build
avant d'exécuter
werf deploy
.
Pour mettre à jour la description du déploiement de l'application, vous devez maintenant parcourir les référentiels avec des microservices et appliquer de petits correctifs avec des modifications des hachages et des balises dans
requirements.yaml
et
requirements.lock
. Si vous le souhaitez, cette opĂ©ration peut Ă©galement ĂȘtre automatisĂ©e via CI: nous avons dĂ©jĂ dĂ©crit comment procĂ©der dans l'
article mentionné .
Conclusion
J'espÚre que la séquence d'actions décrite pour l'entretien d'applications similaires sera utile aux ingénieurs confrontés à des problÚmes similaires. Et nous serons heureux de partager d'autres recettes pratiques pour utiliser
werf . Par consĂ©quent, si vous rencontrez des difficultĂ©s qui semblent insurmontables ou simplement incomprĂ©hensibles Ă mettre en Ćuvre, n'hĂ©sitez pas Ă contacter
Telegram ou Ă laisser des demandes de futurs documents ici dans les commentaires.
PS
Lisez aussi dans notre blog: