Que cela soit pour mettre en place des infras sur Azure, des scripts ou des modules ou mêmes des fichiers bat, l’admin aujourd’hui est obligé de stocker et de gérer du code. Git c’est largement imposé dans le monde des développeurs pour la gestion non seulement du code source mais aussi pour la gestion du projet. Le monde des OPS reste encore largement hermétique à cela.
Souvent les scripts sont encore stockés sur un partage de fichiers lorsqu’ils doivent être partagé. Au mieux la version finale est placée dans un git sans pour autant que l’on utilise toutes les possibilités de l’outils. Il est fréquent de voir des personnes avancées n’utiliser que quelques commandes sur Git.
Ce post se propose de revenir sur les concepts utilisés dans Git et de les appliquer à la collaboration entre Admin sur des projets de scripts, de module PS ou d’infra as code.
Commençons ! Dans un répertoire, on ajoute 5 dossiers, les quatre premiers correspondent à quatre admins et le dernier deviendra un repository centrale.
mkdir olivier,lucien,maurice,alexandre,remote
On rentre dans le répertoire olivier et on y ajoute une configuration git.
cd olivier
git init
Ce que nous venons de faire, c’est de créer l’espace de travail d’Olivier, le dossier olivier, c’est ici que l’on mettra nos fichiers et nos scripts.
La command git init, initialise le repository. Dans l’explorer Windows, en affichant les fichiers et les dossiers cachés, vous devriez voir un répertoire nommé .git. Ce répertoire sert à la configuration de Git est stocke deux éléments.
- Le staging area
- Le local repository
Le premier peut être vus comme un entrepôt provisoire pour les donner que l’on voudrait ajouter à un Commit . Le Second permet de stocker les diffèrent commits et donc l’historique de notre code.
Créons le fichier dsc\web.dsc.ps1
new-item -name dsc -ItemType Directory
new-item -path "dsc\web.dsc.ps1" -ItemType file
Nous avons créé un premier script dans notre espace de travail
Voyons ce qu’il se passe pour git. Pour cela il faut utiliser git status
git status
On branch master
No commits yet
Untracked files:
(use "git add <file>..." to include in what will be committed)
dsc/
nothing added to commit but untracked files present (use "git add" to track)
Cela indique que git voit un ou plusieurs fichiers, qui ne sont ni en staging ni dans le repository local.
Pour pouvoir le mettre en staging
Git add dsc\web.dsc.ps1
Git status
On branch master
No commits yet
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: dsc/web.dsc.ps1
Le fichier est maintenant dans l’espace de staging
Si l’on modifie le fichier pour integrer une configuration.
Configuration iisdeploy {
Import-DscResource -Module xPSDesiredStateConfiguration
Node localhost {
WindowsFeature IIS
{
Ensure = 'Present'
Name = 'Web-Server'
}
}
}
git status
On branch master
No commits yet
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: dsc/web.dsc.ps1
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: dsc/web.dsc.ps1
La création du fichier est bien enregistrée dans le staging area mais l’ajout du code non.
On peut s’en rendre compte en utilisant un git diff
git diff dsc\web.dsc.ps1
diff --git a/dsc/web.dsc.ps1 b/dsc/web.dsc.ps1
index bc2a057..adf793d 100644
--- a/dsc/web.dsc.ps1
+++ b/dsc/web.dsc.ps1
@@ -1 +1,14 @@
\ No newline at end of file
+Configuration iisdeploy {
+ Import-DscResource -Module xPSDesiredStateConfiguration
+ Import-DscResource -Module xWebAdministration
+
+ Node localhost {
+
+ WindowsFeature IIS
+ {
+ Ensure = 'Present'
+ Name = 'Web-Server'
+ }
+
+ }
+}
\ No newline at end of file
On voit bien l’ajout des lignes de code symbolisé par le signe + et la couleur verte. Les suppressions sont-elles symbolisées par un signe – et une couleur rouge
new-item -path "dsc\README.md " -ItemType file
Et un texte explicatif
Set-Content -Path dsc\README.md -Value "# DSC Configuration"
Nous avons une première étape de travail, l’ajout d’un squelette de configuration DSC.
Nous pouvons faire un commit. Un commit permet d’inclure les éléments que nous avons en staging dans le repository local.
git commit -m "Add DSC Folder and web config"
[master (root-commit) ef8cf6b] Add DSC Folder and web config
1 file changed, 1 insertion(+)
create mode 100644 dsc/web.dsc.ps1
Plusieurs informations ici. Notre commit ne concerne que les éléments en staging. Le fichier README.md et les modifications n’ont pas été pris en compte. Nous devons faire l’ajout des modifications
Pour ce faire nous pouvons utiliser git add –all mais attention c’est à double tranchant car dans ce cas toutes les modifications sont enregistrées y compris celles qui n’ont pas de rapport entre elle.
git add –-all
git commit -m "Add DSC Folder and web config"
[master 89c5c6d] Add DSC Folder and web config
2 files changed, 15 insertions(+), 1 deletion(-)
create mode 100644 dsc/README.md
Autre point nous avons ajouter un message avec -m. Ce message n’est pas obligatoire, mais il permet d’indiquer la raison du commit, quel changement il contient. Et comme on vient de la voir, le message peut être le même sur plusieurs commit.
Si l’on fait un git log
git log
commit 89c5c6d9cf024051fc52b6c926800188e4b02ba5 (HEAD -> master)
Author: Olivier Miossec <oliviermiossec@hotmail.fr>
Date: Sun Jun 16 16:04:58 2019 +0200
Add DSC Folder and web config
commit ef8cf6bdd8b99709d6fe6bff8f80efce2dd68500
Author: Olivier Miossec <oliviermiossec@hotmail.fr>
Date: Sun Jun 16 15:59:50 2019 +0200
Add DSC Folder and web config
On retrouve la liste de nos commits, avec leur ID et leur message (d’où leur importance) et l’on trouve aussi l’information (HEAD -> master).
HEAD est par contre un marqueur qui indique où se trouve, dans quelle branche et sur quel commit, se situe le repository.
Nous venons donc de voir les différences entre espace de travail, espace de staging et repository local. Nous avons aussi une notion de ce qu’est HEAD et de la branche principale nommée master.
Nous venons aussi de voir qu’un Commit correspond à un ensemble de fichiers et de modification qui dans l’idéal correspondent à une étape d’un projet.
Git est un outil de collaboration. Cela veut dire qu’en plus d’avoir un repository local, celui que nous venons de manipuler, il est possible d’avoir un repository en ligne où peuvent travailler plusieurs personnes.
Le repository dans le dossier olivier, ne dispose pas de repository remote Git remote –v ne renvois rien et avec
git remote get-url origin
On obtient l’erreur : fatal: No such remote ‘origin’
Origin peut être compris ici comme un synonyme de remote, du repository original.
C’est normal car nous avons uniquement créer un repository local
Pour créer un remote repository, on se déplace dans le répertoire remote créer lors de la première étape. On y ajoute alors une configuration git spécifique.
git init --bare TeamRemoteWork.git
La commande configure un nouveau repository mais si l’on regarde à l’intérieur de ce nouveau dossier on remarque qu’il ne comprend les données git.
Si l’on revient dans le dossier olivier, on peut maintenant ajouter un remote
git remote add origin C:\work\psworkshop\git\remote\TeamRemoteWork.git
La commande git remote –v nous renvois alors les informations
origin C:\work\psworkshop\git\remote\TeamRemoteWork.git (fetch)
origin C:\work\psworkshop\git\remote\TeamRemoteWork.git (push)
La configuration comprend en plus de l’espace de travail, de l’espace de staging et du repository local, un remote repository.
Ce dernier est le point où l’ensemble d’une equipe partage leur commits. Git remove -v renvois deux endpoint disponible suivit de deux opérations Fetch et Push.
Push est l’action d’envoyer les données du repository local vers le repository en remote.
git push origin master
Counting objects: 9, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (9/9), 783 bytes | 130.00 KiB/s, done.
Total 9 (delta 0), reused 0 (delta 0)
To C:\work\psworkshop\git\remote\TeamRemoteWork.git
* [new branch] master -> master
Git Push a simplement fusionner, ou merger, le repository local dans le remote repository. Les commits sont ainsi disponible depuis pour toute personne voulant contribuer au projet
Maintenant plaçons nous dans le répertoire lucien. Lucien veut lui aussi travailler sur le projet DSC et souhaite enrichir le code d’Olivier. Pour cela il doit obtenir une copie du remote repository.
git clone C:\work\psworkshop\git\remote\TeamRemoteWork.git
Cloning into 'TeamRemoteWork'...
done.
Ce que fait git clone, c’est de copier le remote repository en local et d’en faire un repository local et en même temps cela ajout un espace de staging et un espace de travail.
Si l’on regarde à l’interieur du dossier teamremotework on y retrouve notre dossier DSC et un dossier .git
Lucien souhaite corriger deux choses dans ce qui a été fait dans DSC
La première est que l’on souhaite pouvoir utiliser DSC en local mais aussi avec Azure Automation. Dans ce cas il faut que le nom de la configuration corresponde au nom du fichier.
La seconde est de pouvoir aussi effectuer des configurations sur des serveurs linux
Pour la première action
Rename-Item -Path .\dsc\web.dsc.ps1 -NewName iisdeploy.ps1
Pour la seconde on ajoute le fichier ubutunApache.ps1
configuration ubutunApache {
Import-DSCResource -module "nx"
Node localhost {
$requiredPackages = @("apache2","php","php-mysql","mariadb","mariadb-server")
$enabledServices = @("httpd","mariadb")
#Ensure packages are installed
ForEach ($package in $requiredPackages){
nxPackage $Package{
Ensure = "Present"
Name = $Package
PackageManager = "apt"
}
}
#Ensure daemons are enabled
ForEach ($service in $enabledServices){
nxService $service{
Enabled = $true
Name = $service
Controller = "SystemD"
State = "running"
}
}
}
}
Nous pouvons le rajouter les modifications dans le repos local
git add dsc\ubutunApache.ps1
git add dsc\iisdeploy.ps1
si l’on fait un git status
On branch master
Your branch is up to date with 'origin/master'.
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
new file: dsc/iisdeploy.ps1
new file: dsc/ubutunApache.ps1
Changes not staged for commit:
(use "git add/rm <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
deleted: dsc/web.dsc.ps1
Git par default ne tient pas compte du renomage du fichier web.dsc.ps1 il faut donc l’ajouter
git add dsc\web.dsc.ps1
On branch master
Your branch is up to date with 'origin/master'.
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
renamed: dsc/web.dsc.ps1 -> dsc/iisdeploy.ps1
new file: dsc/ubutunApache.ps1
on peut effectuer un commit et le renvoyer vers le repos central
git commit -m "Add Support for Azure and Apache 2 on Ubuntu"
git push origin master
Dès lors ce repos local est synchronisé avec le repository remote. Mais ce n’est pas le cas de notre premier repos celui nommé olivier.
Si l’on revient vers ce dernier, git log n’indique rien
Git Pull, est une des solutions. Git Pull permet de merger les commits du repos remote dans le repos local et d’agir (ajout/suppresion/modification) sur l’espace de travail.
git pull origin master
* branch master -> FETCH_HEAD
Updating 89c5c6d..d9f7ac3
Fast-forward
dsc/{web.dsc.ps1 => iisdeploy.ps1} | 0
dsc/ubutunApache.ps1 | 28 ++++++++++++++++++++++++++++
2 files changed, 28 insertions(+)
rename dsc/{web.dsc.ps1 => iisdeploy.ps1} (100%)
create mode 100644 dsc/ubutunApache.ps1
Le git log intégre maintenant l’ensemble des commits
commit d9f7ac3c9c02a7f3efdbf78f7e7278ea0c966ff4 (HEAD -> master, origin/master)
Author:
Date: Sun Jun 16 18:29:01 2019 +0200
Add Support for Azure and Apache 2 on Ubuntu
commit 89c5c6d9cf024051fc52b6c926800188e4b02ba5
Author:
Date: Sun Jun 16 16:04:58 2019 +0200
Add DSC Folder and web config
commit ef8cf6bdd8b99709d6fe6bff8f80efce2dd68500
Author:
Date: Sun Jun 16 15:59:50 2019 +0200
Add DSC Folder and web config
Durant tout ce temps, Alexandre, clone aussi le remote repository mais n’y fait rien
Maurice ne travaille pas sur le projet DSC. Mais il est chargé de lancer un projet de déploiement à partir d’ARM Template. Autre chose, il travaille sous linux.
Maurice ajoute donc un dossier ARM avec un fichier README.md à l’interieur.
Il commit son travail et exécute un Push
Dès lors comment les autres membres de l’equipe peuvent-ils vérifier que leur repository local est bien à jour.
Cela peut se faire en utilisant un fetch, qui permet de récupérer les changements en remote.
git fetch origin
git diff master origin/master
commit e4f4bd7b7d368d0c3a10266640b9dc2200b7250f (origin/master, origin/HEAD)
Author: Maurice <olivier@omiossec.work>
Date: Sun Jun 16 20:26:18 2019 +0200
Add ARM Project
Ici l’on peut voir ce qu’il se passe au niveau de notre remote repository
Mais on se rend compte de plusieurs choses ici.
-
On a rajouté un peu de tout dans le repos central, y compris des choses non terminées
-
Plusieurs personnes ont travaillé sur le même fichier ce qui pourrait créer un conflit s’il avait merger en même temps
C’est ici que l’on doit introduire le concept de branch. Nous avons déjà vu cela lorsque nous avons parlé de master. Une branch est une façon de s’éloigner du travail en cours. C’est une sorte d’univers parallèle où les modifications qui sont faite ne concernent que la branche dans laquelle nous travaillons.
On peut avoir plusieurs stratégies pour ces branches, mais toutes ces stratégies s’accordent sur une chose, la branch master doit rester le plus proche possible de la production, the single source of true, comme pourrait le dire les anglophones.
La branche master peut par exemple service dans une chaine de CI/CD avec Azure DevOps et déclencher des modifications lors d’un commit.
L’une des possibilités de gérer les branches est de créer une branche commune pour chaque nouvelle fonctionnalité, ici une branche ARM et un autre pour DSC et de les merger une fois considérer comme complète.
Dans le même temps si plusieurs développeurs souhaitent travailler sur une même feature, il est d’usage que chacun puisse avoir leur propre branche en local afin d’éviter les complications.
Ainsi à partir du remote repository, nous avons une branche master, correspondant à la prod, plusieurs branches correspondant à nos features et d’autres correspondant au travail des différents acteurs.
Commençons par créer deux branches pour de nouvelles feature, terraform-azure et ps-module-log
sur le repos d’Olivier
git branch terraform-azure
puis
git branch ps-module log
En faisant un git branch –a on peut lister les branches en local et en remote
* master
ps-module-log
terraform-azure
Remotes/origin/master
Ici l’on voit un *, cela correspond à notre HEAD qui est toujours placé sur master
On voit aussi que notre remote n’a pas d’autre branche que master
Pour changer de branche
Git checkout ps-module-log
Git branche –a nous donne alors
master
* ps-module-log
terraform-azure
Remotes/origin/master
Créons un nouveau fichier
new-item -Name module-log -Type Directory
new-item -Path module-log\README.md -ItemType File
Ajoutons les changements et effectuons un commit
git add module-log\README.md
git commit -m "New Feature Module Log"
Tentons un push pour envoyer les modifications
git push origin ps-module-log
Counting objects: 4, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (4/4), 329 bytes | 23.00 KiB/s, done.
Total 4 (delta 0), reused 0 (delta 0)
To C:\work\psworkshop\git\remote\TeamRemoteWork.git
* [new branch] ps-module-log -> ps-module-log
git branch –a
master
* ps-module-log
terraform-azure
remotes/origin/master
remotes/origin/ps-module-log
Maintenant Lucien souhaite aussi pouvoir récupérer les branches pour travailler sur ps-module-log
git fetch origin
git branch -a
* master
remotes/origin/HEAD -> origin/master
remotes/origin/master
remotes/origin/ps-module-log
On voit donc qu’il ne dispose pas en local de la branche ps-module-log . Pour changer cela
Git checkout ps-module-log
Git branch –a
master
* ps-module-log
remotes/origin/HEAD -> origin/master
remotes/origin/master
remotes/origin/ps-module-log
Maintenant Lucien veut pouvoir créer une branche locale pour y mettre son développement
Pour cela on doit faire un git branch et un checkout, mais il est possible d’avoir les deux même commandes en une seule
Git checkout –b dev-lucien-ps-module-log
Switched to a new branch 'dev-lucien-ps-module-log'
* dev-lucien-ps-module-log
master
ps-module-log
remotes/origin/HEAD -> origin/master
remotes/origin/master
remotes/origin/ps-module-log
Nous avons donc une branche locale qui dérive d’une branche remote. On ajoute une ligne dans \module-log\README.md On peut alors faire un commit.
git add .\module-log\README.md
git commit –m "Dev on Ps Module"
Cependant le but n’est pas d’envoyer cette branche en remote mais de la fusionner avec la branche ps-module-log
Pour cela on se place sur la branch ps-module-log
git checkout ps-module-log
Switched to branch 'ps-module-log'
Your branch is up to date with 'origin/ps-module-log'.
Puis
git merge dev-lucien-ps-module-log
Updating 55b8015..239dbe2
Fast-forward
module-log/README.md | 1 +
1 file changed, 1 insertion(+)
Supprimons la branche de dev
git branch -d dev-lucien-ps-module-log
Il est alors possible d’envoyer les changements vers le remote repository
git push origin ps-module-log
Counting objects: 4, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (4/4), 348 bytes | 69.00 KiB/s, done.
Total 4 (delta 0), reused 0 (delta 0)
To C:\work\psworkshop\git\remote\TeamRemoteWork.git
55b8015..239dbe2 ps-module-log -> ps-module-log
C’est ici les bases pour utiliser Git en tant que Ops, il y a bien d’autres options, mais les concepts expliqués ici doivent vous permettre d’avancer dans votre trajet vers le DevOps et l’Infra as Code.
Petite explication sur les prénoms proposés ici, ont une petite explication, ce sont ceux qui existent sur mon état civil (oui que 4).