Déploiement continu avec CircleCI - Partie 2

La première partie permettait de découvrir les concepts de base de CircleCI et comment les mettre en application. Dans cette partie on va voir comment aller plus loin en utilisant les différents moyens permettant de partager de l'information entre les jobs.
État des lieux
version: 2.1
jobs:
build:
docker:
- image: circleci/node:11.10.1
steps:
- checkout
- run: yarn install
- run: yarn build
lint:
docker:
- image: circleci/node:11.10.1
steps:
- checkout
- run: yarn install
- run: yarn lint
test:
docker:
- image: circleci/node:11.10.1
steps:
- checkout
- run: yarn install
- run: yarn test:unit
deploy:
docker:
- image: circleci/node:11.10.1
steps:
- checkout
- run: yarn install
- run: yarn build
- run: yarn firebase deploy --token "$FIREBASE_TOKEN" --only hosting
workflows:
version: 2
integration:
jobs:
- build
- lint
- test
- deploy:
requires:
- build
- lint
- test
filters:
branches:
only: master
Notre configuration fonctionne mais on voit que l'on se répète. Chacun des jobs contient ces lignes :
docker:
- image: circleci/node:11.10.1
steps:
- checkout
- run: yarn install
Les deux premières lignes, celles de la configuration de l'environnement d'exécution, sont juste une répétition au sein du fichier de configuration, elles n'ont pas d'impact sur les performances. Mais par soucis de maintenabilité on utilisera les executors et les commands pour factoriser ces fragments.
Deuxième problème, chaque job est obligé de réinstaller les dépendances car ils exécutent leurs instructions dans un environnement isolé. Pour pallier ce problème on va installer les dépendances, les stocker en cache pour qu'elles puissent être partagées par les jobs d'un workflow. Les dépendances mises en cache pourront aussi être utilisées par les jobs futurs.
Le dernier problème est la nécessité de devoir re-construire l'application de production dans le job de déploiement alors que cette étape a été réalisée par le job de build. Encore une fois le problème vient du fait que les jobs sont isolés. Par défaut le job de déploiement ne peut pas lire ce qui a été généré par le job de build. On utilisera les workspaces pour résoudre ce souci.
Cacher les dépendances
Pour utiliser le cache on va définir un nouveau job chargé d'installer nos dépendances :
install:
docker:
- image: circleci/node:11.10.1
steps:
- checkout
- restore_cache:
key: v1-dependencies-{{ checksum "yarn.lock" }}
- run: yarn install
- save_cache:
key: v1-dependencies-{{ checksum "yarn.lock" }}
paths:
- ./node_modules
- : restore le cache pour une clé donnée
restore_cache
- : clé de restauration du cache
key
- : sauvegarde des fichiers en cache
save_cache
- : clé de stockage du cache
key
- : les élements à stocker, ici les node_modules
paths
Cette étape tente de restaurer le cache contenant les
node_modules
NB : la clé de cache contient un hash de notre fichier
yarn.lock
On peut mettre à jour les autres jobs de notre configuration pour qu'ils utilisent le cache :
version: 2
jobs:
install:
docker:
- image: circleci/node:11.10.1
steps:
- checkout
- restore_cache:
key: v1-dependencies-{{ checksum "yarn.lock" }}
- run: yarn install
- save_cache:
key: v1-dependencies-{{ checksum "yarn.lock" }}
paths:
- ./node_modules
build:
docker:
- image: circleci/node:11.10.1
steps:
- checkout
- restore_cache:
key: v1-dependencies-{{ checksum "yarn.lock" }}
- run: yarn build
# autres jobs...
workflows:
version: 2
integration:
jobs:
- install
- build:
requires:
- install
- lint:
requires:
- install
- test:
requires:
- install
- deploy:
requires:
- build
- lint
- test
filters:
branches:
only: master
Désormais on installe une seule fois les dépendances que l'on partage entre les différents jobs. On n'oublie pas de préciser que chacun des jobs requiert que le job install ait été complété.
Avec du cache on gagne environ 20s sur le processus de déploiement.
Les workspaces
Un workspace est un espace qui permet à un job de partager des données avec un job lui succédant. Dans notre cas on va construire l'application dans le job de
build
deploy
build:
docker:
- image: circleci/node:11.10.1
steps:
- checkout
- restore_cache:
key: v1-dependencies-{{ checksum "yarn.lock" }}
- run: yarn build
- persist_to_workspace:
root: ~/project
paths:
- ./dist
- : indique que l'on veut écrire dans le workspace
persist_to_workspace
- : le dossier dans lequel on doit aller chercher l'information, par défaut
root
~/project
- : liste des chemins des fichiers/dossiers à écrire dans le workspace
paths
deploy:
docker:
- image: circleci/node:11.10.1
steps:
- checkout
- restore_cache:
key: v1-dependencies-{{ checksum "yarn.lock" }}
- attach_workspace:
at: ~/project
- run: yarn firebase deploy --token "$FIREBASE_TOKEN" --only hosting
En utilisant les workspaces en complément du cache on est parvenu à gagner une trentaine de secondes par rapport à la configuration de la première partie 🎉.
🍒 sur le 🍰 : les executors et les commandes
Ici on peaufine notre configuration afin d'éviter un maximum les répétitions dans notre fichier de configuration. Les
commands
executors
commands:
checkout_and_restore_cache:
steps:
- checkout
- restore_cache:
key: v1-dependencies-{{ checksum "yarn.lock" }}
executors:
node:
docker:
- image: circleci/node:11.10.1
On peut mettre à jour nos jobs :
install:
executor: node
steps:
- checkout_and_restore_cache
- run: yarn install
- save_cache:
key: v1-dependencies-{{ checksum "yarn.lock" }}
paths:
- ./node_modules
La configuration finale
version: 2.1
commands:
checkout_and_restore_cache:
steps:
- checkout
- restore_cache:
key: v1-dependencies-{{ checksum "yarn.lock" }}
executors:
node:
docker:
- image: circleci/node:11.10.1
jobs:
install:
executor: node
steps:
- checkout_and_restore_cache
- run: yarn install
- save_cache:
key: v1-dependencies-{{ checksum "yarn.lock" }}
paths:
- ./node_modules
build:
executor: node
steps:
- checkout_and_restore_cache
- run: yarn build
- persist_to_workspace:
root: ~/project
paths:
- dist/*
lint:
executor: node
steps:
- checkout_and_restore_cache
- run: yarn lint
test:
executor: node
steps:
- checkout_and_restore_cache
- run: yarn test:unit
deploy:
executor: node
steps:
- checkout_and_restore_cache
- attach_workspace:
at: ~/project
- run: yarn firebase deploy --token "$FIREBASE_TOKEN" --only hosting
workflows:
version: 2
integration:
jobs:
- install
- build:
requires:
- install
- lint:
requires:
- install
- test:
requires:
- install
- deploy:
requires:
- build
- lint
- test
filters:
branches:
only: master
Conclusion
On a enfin une configuration de bogass 😎 Performante grâce à l'utilisation du cache et des workspaces, maintenable grâce aux commandes et aux executors, sympathique grâce aux pommes.
Merci de m'avoir lu.