Nous aurons besoin de docker build, docker tag, docker push
tout au long de ce pipeline. Cependant il n’est pas possible de sécuriser l’usage de docker à l’intérieur du cluster Kubernetes car celui ci doit forcément avoir des droits proche de root pour fonctionner quelle que soit la méthode.
En utilisant docker dans un conteneur ou directement dans le cluster nous aurions donc un vecteur d’attaque privilégié pour prendre le contrôle du cluster à partir du déploiement d’images particulières.
Les solutions sont :
Kaniko manque encore un peu de maturité et fonctionne légèrement différemment de docker. Nous utiliserons donc un noeud docker extérieur pour la suite.
Nous allons donc créer un serveur agent docker manuellement pour Jenkins à l’aide de Vagrant. Nous dirons ensuite à Jenkins de s’y connecter en SSH avec l’utilisateur Vagrant pour exécuter son job à l’intérieur. Comme nous avons fait pour le noeud ansible dans le TP4 ansible.
vagrant_docker_agent
dans le dossier tp2_infra_et_app/tp2_infra
et à l’intérieur le fichier Vagrantfile
suivant:Vagrant.configure('2') do |config|
config.ssh.insert_key = false
config.vm.provider :virtualbox do |v|
v.memory = 1024
v.cpus = 1
end
# si le montage du dossier partagé ne fonctionne pas décommentez la ligne suivante
# config.vm.synced_folder ".", "/vagrant", disabled: true
config.vm.define :dockeragent do |dockeragent|
dockeragent.vm.box = 'ubuntu/focal64'
dockeragent.vm.hostname = 'dockeragent'
dockeragent.vm.network :private_network, ip: '10.12.0.11'
dockeragent.vm.provision :shell, privileged: false, inline: <<-SHELL
sudo rm /etc/resolv.conf && echo "nameserver 1.1.1.1" | sudo tee /etc/resolv.conf && sudo chattr +i /etc/resolv.
sudo apt update && sudo apt-get install -y apt-transport-https ca-certificates curl gnupg lsb-release
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io
sudo apt-get install -y openjdk-13-jdk
sudo -u vagrant mkdir -p /home/vagrant/jenkins_agent
SHELL
end
end
Les étapes du provisionning servent à nous assurer un minimum de configuration de ce serveur pour que Jenkins puisse fonctionner et que Docker soit disponible.
vagrant up
. Pour exécuter plusieurs fois les étapes d’installation on pourra utiliser vagrant provision
.Administrer Jenkins > Gérer les noeuds
.Nous avons besoin de nous connecter en SSH au serveur agent. Pour cela il faut créer dans Jenkins un credential
(identifiant) qui lui permettra de se connecter.
Nous allons crée un credential
de type user / clé ssh avec vagrant
et sa clé privée unsecure (c’est une configuration de test, car cette clé et publiquement disponible. En production, il faudrait ajouter un utilisateur et une nouvelle clé ssh “originale” au serveur agent)
Allez voir la configuration des credentials Jenkins : Administrer Jenkins > Manage Credentials > Jenkins > Identifiants globaux > Ajouter des identifiants
.
Complétez le formulaire comme suit (dans Private key > enter directly
collez le texte de la clé privée présent dans ~/.vagrant.d/insecure_private_key
):
Maintenant nous pouvons ajouter l’agent ssh.
Retournez dans la configuration des agents Jenkins : Administrer Jenkins > Gérer les noeuds
.
Créez un nouvel agent comme suit en changeant ansible-agent
par docker-agent
et l’IP 10.10.10.9
par 10.12.0.11
:
Il s’agit généralement soit d’un problème de connexion ssh:
… soit d’un problème d’initialisation du programme agent jenkins sur le serveur agent.
/home/vagrant/jenkins_agent
pour nous)vagrant
dans notre cas. Le dossier a été créé en root on obtient un erreur permission denied.Nous pouvons maintenant builder des images docker avec Jenkins hors de notre cluster k8s.
Nous allons maintenant exécuter les différentes étapes du pipeline mais : - à la main pour valider que chaque étape fonctionne - au même endroit qu’elles le seront lors du pipeline (dans les conteneurs d’un pod kubernetes adapté ou sur le noeud docker selon les étapes).
Comme vu dans le TP2, les tests unitaires nécessitent seulement python et quelques dépendances python pour fonctionner nous pouvons donc les utiliser sans construire d’image.
Idéalement, ces tests unitaires doivent être exécutés avant le moindre build car il est déconseiller des construire ou pousser une image avec des bugs ou failles majeur.e.s, qui pourrait se retrouver utilisée et prendrait de la place dans le dépôt d’image pour rien.
Nous avons donc besoin d’un environnement python temporaire pour exécuter ces tests. Or le principe des agents Jenkins dans Kubernetes sous forme de pods est qu’ils peuvent contenirs plusieurs conteneurs adapté à chaque partie du pipeline.
Pour ce pipeline nous avons besoin de trois principaux outils (mais nous pourrions en ajouter pour contrôler d’autre point de notre logiciel ou déployer différemment):
Notre pod d’exécution avec python et kubectl Kubernetes sera donc comme suit:
apiVersion: v1
kind: Pod
metadata:
name: pod-test-pipeline-manuel
labels:
component: ci
spec:
volumes:
- name: shared-data
emptyDir: {}
containers:
- name: python
image: python:3.9
imagePullPolicy: Always
command: ["cat"]
tty: true
volumeMounts:
- name: shared-data
mountPath: /mount/shared
- name: kubectl
image: tecpi/kubectl-helm
command: ["cat"]
tty: true
volumeMounts:
- name: shared-data
mountPath: /mount/shared
Pour créer ce pod temporaire utilisez par exemple la fonction +
de Lens à côté du terminal.
Rentrez dans le conteneur python avec kubectl exec -it pod-test-pipeline-manuel --container python -- /bin/bash
Allez dans le dossier partagé entre les conteneurs : cd /mount/shared
Il faut d’abord récupérer le code de notre application git clone -b jenkins_application_correction https://github.com/Uptime-Formation/corrections_tp.git jenkins_application_correction
Allez dans le dossier de l’application corrigée : cd jenkins_application_correction
Installez les dépendances python avec pip install -r requirements.txt
Lancez les tests unitaires pytest
comme dans le tp1.
Pour builder l’image beta, allez dans la VM docker agent avec vagrant ssh
Passez en root
pour utiliser docker dans la machine virtuelle avec sudo -i
Reclonez le code comme précédemment git clone -b jenkins_application_correction https://github.com/Uptime-Formation/corrections_tp.git jenkins_application_correction
Allez dans le dossier de l’application avec cd jenkins_application_correction
Lancer la construction de l’image monstericon beta avec docker build -t registry.vagrantk3s.dopl.uk/monstericon:beta .
Poussez l’image sur le dépôt docker push registry.vagrantk3s.dopl.uk/monstericon:beta
Nous allons déployer une version dev de l’application dans notre cluster pour effectuer les tests d’intégration et fonctionnels dessus.
kubectl
avec la commande suivante: kubectl exec -it pod-test-pipeline-manuel --container kubectl -- /bin/bash
Nous avons besoin d’utiliser kubectl pour effectuer un déploiement de test mais il n’est pas encore configuré pour se connecter au cluster. En réalité dans jenkins, kubectl
utilisera automatiquement le serviceAccount
de Jenkins pour se connecter donc les 3 étapes suivant ne seront pas nécessaire:
installer nano
avec apt update && apt install -y nano
éditez la config nano ~/.kube/config
copier le contenu de ~/.kube/config
sur votre machine hote et collez dans nano. Sauvegardez et quittez (Crtl+S puis Ctrl+X)
Lancez kubectl get nodes
pour vérifier la connexion
Retournez dans le dossier de l’application avec cd jenkins_application_correction
.
Créez un namespace beta
: kubectl create namespace beta
Déployez l’application en mode dev avec le tag beta
grace à kubectl apply -k k8s/overlay/dev -n beta
Vérifiez l’état du déploiement avec kubectl -n beta rollout status deployment monstericon
pour voir s’il converge vers l’état fonctionnel (ce qu’on a souvent fait avec Lens jusqu’ici).
Retournez dans le conteneur python et lancez les tests fonctionnels avec : python3 src/test/functionnal_tests.py monstericon-beta.vagrantk3s.dopl.uk
Retournez dans la VM docker et tagguez l’image en registry.vagrantk3s.dopl.uk/monstericon:latest
Poussez l’image latest.
Retournez dans le conteneur kubectl
Redéployer mais cette fois dans le contexte de production (namespace prod
et k8s/overlay/prod
)
Pensez à bien nettoyer, supprimer les images temporaires et les déploiement inutiles
Dans le contexte d’un pipeline Jenkins, le nettoyage doit être lancé même le pipeline échoue ce que nous ferons avec un peu de logique jenkins par la suite.