Skip to content

emr02/tp-devops

 
 

Repository files navigation

TP1

Database

FROM postgres:14.1-alpine

ENV POSTGRES_DB=db \
    POSTGRES_USER=usr \
    POSTGRES_PASSWORD=pwd

COPY ./initdb /docker-entrypoint-initdb.d/
  • FROM définit l'image de base du conteneur, dans ce cas, PostgreSQL.
  • COPY transfère un fichier depuis la machine hôte vers un répertoire spécifique du conteneur Docker.
  • ENV sert à définir des variables d'environnement au sein du conteneur Docker.
# Create network, communication entre 2 conteneurs, il faut créer un réseau commun

docker network create app-network
# To restart admirer

docker run -d --name adminer --network app-network -p 8090:8080 adminer
# Build docker image

docker build -t mypostgres .
# Run the PostgreSQL Container with Volume

docker run -p 5432:5432 --net=app-network --name mypostgres -v data:/var/lib/postgresql/data mypostgres

-p exposer les ports du conteneur sur la machine hôte.  
--name sert à attribuer un nom au conteneur.  
-v gère les volumes pour la persistance des données, sinon si container détruit, données conservées
#Run Adminer

docker run -p "8090:8080" --net=app-network --name=adminer -d adminer

1-1 Why should we run the container with a flag -e to give the environment variables?

Utiliser l'option -e pour passer des variables d'environnement lors de l'exécution est plus sûr que de les écrire directement dans le Dockerfile. Cela évite de stocker des informations sensibles, comme des mots de passe, en clair dans le fichier, ce qui pourrait poser un risque si le Dockerfile est partagé ou enregistré dans un gestionnaire de versions.

1-2 Why do we need a volume to be attached to our postgres container?

Attacher un volume au conteneur PostgreSQL garantit que les données de la base de données sont stockées de manière persistante sur la machine hôte. Ainsi, même si le conteneur est détruit ou recréé, les données restent intactes et peuvent être réutilisées par la nouvelle instance du conteneur.

1-3 Document your database container essentials: commands and Dockerfile.

Done

Backend API (1-4)

Build

# Build
FROM maven:3.9.9-amazoncorretto-21 AS myapp-build
ENV MYAPP_HOME=/opt/myapp 
WORKDIR $MYAPP_HOME
COPY /simpleapi/pom.xml .
COPY /simpleapi/src ./src
RUN mvn package -DskipTests

# Run
FROM amazoncorretto:21
ENV MYAPP_HOME=/opt/myapp 
WORKDIR $MYAPP_HOME
COPY --from=myapp-build $MYAPP_HOME/target/*.jar $MYAPP_HOME/myapp.jar

ENTRYPOINT ["java", "-jar", "myapp.jar"]

Un build multistage permet d'utiliser plusieurs instructions FROM dans un seul Dockerfile. Chaque instruction FROM démarre une nouvelle étape, et nous pouvons sélectionner les artefacts à copier d'une étape à l'autre. Le build contient le JDK nécessaire pour compiler l'application avec Maven Le run contient uniquement le JRE, suffisant pour éxecuter l'application déjà compilée, rendant l'image plus légère. La première étape génère les artefacts nécessaires, tandis que la seconde étape ne copie que les artefacts essentiels dans l'image finale, l'image finale sera plus petite et performante.

Explication du Dockerfile

1. Phase de Build

FROM maven:3.9.9-amazoncorretto-21 AS myapp-build

Utilise Maven et le JDK Amazon Corretto pour compiler l'application.

WORKDIR /opt/myapp
COPY /simpleapi/pom.xml .
COPY /simpleapi/src ./src
RUN mvn package -DskipTests

Définit le répertoire de travail, copie le code source et compile l'application en un fichier JAR.

2. Phase d'Exécution

FROM amazoncorretto:21

Utilise l'image JRE Amazon Corretto pour l'exécution de l'application.

COPY --from=myapp-build /opt/myapp/target/*.jar /opt/myapp/myapp.jar
ENTRYPOINT ["java", "-jar", "myapp.jar"]

Copie le JAR compilé et exécute l'application avec java -jar.


Cette approche sépare la construction (avec JDK) et l'exécution (avec JRE) pour une image finale plus légère et optimisée.

Http server

1-5 Why do we need a reverse proxy?

Un reverse proxy est utilisé pour rediriger les requêtes des clients vers un ou plusieurs serveurs backend, en agissant comme un intermédiaire. Avantages : sécurité en masquant le serveur backend, gestion du SSL/TLS etc .. Dans notre cas, il redirige les requêtes HTTP vers l'application backend de manière simple.

# database
docker build -t mypostgres .
docker run -p 5432:5432 --net=app-network --name mypostgres -v data:/var/lib/postgresql/data mypostgres

# API
docker build -t simple-api-student .
docker run -p 8080:8080 --net=app-network --name simple-api-student simple-api-student

# Server, 8040 car port 80:80 ne marchait vraiment pas
docker build -t simple-http-server .
docker run -p 8040:80 --net=app-network --name simple-http-server -d simple-http-server

# To check
docker stats simple-http-server
docker inspect simple-http-server
docker logs simple-http-server

Dockerfile :

FROM httpd:2.4

COPY httpd.conf /usr/local/apache2/conf/httpd.conf
COPY ./index.html /usr/local/apache2/htdocs/

httpd.conf que on a récupéré avec :

docker cp simple-http-server:/usr/local/apache2/conf/httpd.conf ./httpd.conf
<VirtualHost *:80>
ProxyPreserveHost On
ProxyPass / http://simple-api-student:8080/
ProxyPassReverse / http://simple-api-student:8080/
</VirtualHost>
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so

Avantages de l'utilisation de docker cp pour récupérer httpd.conf :

  • Personnalisation : Ajuster la configuration selon les besoins.
  • Cohérence : Configuration par défaut qui fonctionne, puis y apporter des modifications.
  • Contrôle de version : Garder le fichier de configuration personnalisé, avec le Dockerfile et autres fichiers.

Link application

1-6 Why is docker-compose so important?

Docker-compose est important car il permet de gérer plusieurs conteneurs Docker avec une seule commande. Il simplifie le déploiement et l'organisation d'applications utilisant plusieurs conteneurs, en facilitant le démarrage, l'arrêt et la gestion des services d'une application. Cela permet de gagner du temps et d'assurer que la configuration est fiable et peut être reproduite facilement.


1-8 Document docker-compose most important commands.

  • Démarrer les conteneurs :

    docker-compose up
  • Démarrer les conteneurs en mode détaché (en arrière-plan) :

    docker-compose up -d
  • Arrêter et supprimer les conteneurs :

    docker-compose down
  • Mettre en pause les conteneurs :

    docker-compose pause
  • Reprendre les conteneurs mis en pause :

    docker-compose unpause
  • Voir les logs des conteneurs :

    docker-compose logs
  • Construire les images :

    docker-compose build

1-8 Document your docker-compose file.

Voici un exemple de structure de fichier docker-compose.yml :

version: '3.7'

services:
  backend:
    build:
      context: ./backend_api/app2
      dockerfile: Dockerfile
    container_name: simple-api-student
    networks:
      - app-network
    depends_on:
      - database

  database:
    build:
      context: ./postgres
      dockerfile: Dockerfile
    container_name: mypostgres
    networks:
      - app-network
    volumes:
      - ./data:/var/lib/postgresql/data

  httpd:
    build:
      context: ./http_server
      dockerfile: Dockerfile
    container_name: simple-http-server
    networks:
      - app-network
    ports:
      - 8040:80

networks:
  app-network:

services

  1. backend :

    • Construit l'image à partir de ./backend_api/app2 avec le Dockerfile.
    • Dépend de database et utilise le réseau app-network.
  2. database :

    • Construit l'image à partir de ./postgres.
    • Utilise un volume pour persister les données dans ./data et se connecte au réseau app-network.
  3. httpd :

    • Construit l'image à partir de ./http_server.
    • Expose le port 8040 local vers le port 80 du conteneur et utilise le réseau app-network.

networks

networks:
  app-network:

Crée un réseau app-network pour que tous les services puissent communiquer entre eux.

En résumé, ce fichier configure un backend, une base de données PostgreSQL et un serveur HTTP, tous connectés via un réseau privé.


Publish

1-9 Document your publication commands and published images in dockerhub.

# Se connecter à Docker Hub :
docker login

#Taguer votre image :
docker tag mypostgres wanoni/my-database:1.0

# Pousser l'image vers Docker Hub :
docker push wanoni/my-database:1.0

# de même avec api et server

1-10 Why do we put our images into an online repo?

Mettre nos images dans un dépôt en ligne comme Docker Hub permet de les partager facilement avec d'autres, de les sauvegarder, d'y accéder à distance et de gérer les versions. C'est essentiel pour collaborer et déployer de manière efficace.

TP2 : Github Actions

2-1 What are testcontainers?

They simply are java libraries that allow you to run a bunch of docker containers while testing. Here we use the postgresql container to attach to our application while testing.

2-2 Document your Github Actions configurations.

Github Action :

  1. pour tester le backend à chaque commit sur la branch main
  2. le publier
## Bonus: split pipelines (Optional)

Build : On teste le backend sur le merge sur main
```yml
name: Test Backend

on:
  push:
    branches:
      - main
      - develop
  pull_request:

jobs:
  test-backend: 
    runs-on: ubuntu-22.04
    steps:
      # Checkout your GitHub code using actions/checkout@v4
      - uses: actions/checkout@v4

      # Set up JDK 21 using actions/setup-java@v3
      - name: Set up JDK 21
        uses: actions/setup-java@v3
        with:
          distribution: 'corretto'
          java-version: '21'

      # Build and test the project using Maven
      - name: Build and test with Maven
        run: mvn -B verify sonar:sonar -Dsonar.projectKey=devops-project12345 -Dsonar.organization=devops-sonar123 -Dsonar.host.url=https://sonarcloud.io -Dsonar.token=${{ secrets.SONAR_TOKEN }}
        working-directory: simple-api

Deploy : on publie

name: Build and Push Docker Image

on:
  workflow_run:
    workflows: ["Test Backend"]
    types:
      - completed
    branches: 
      - main

jobs:
  build-and-push-docker-image:
    if: github.event.workflow_run.conclusion == 'success' &&
      github.event.workflow_run.head_branch == 'main' # Ensure deploy only runs for main
    runs-on: ubuntu-22.04

    steps:
      # Checkout the code
      - name: Checkout code
        uses: actions/checkout@v4

      # Log in to Docker Hub using the provided credentials
      - name: Login to DockerHub
        run: docker login -u ${{ secrets.DOCKERHUB_USERNAME }} -p ${{ secrets.DOCKERHUB_TOKEN }}

      # Build the Docker image for the backend and push it to Docker Hub
      - name: Build image and push backend
        uses: docker/build-push-action@v3
        with:
          # Relative path to the place where source code with Dockerfile is located
          context: ./simple-api
          # Note: tags have to be all lower-case
          tags: ${{ secrets.DOCKERHUB_USERNAME }}/tp-devops-simple-api:latest
          # Build on feature branches, push only on main branch
          push: ${{ github.ref == 'refs/heads/main' }}

      # Build the Docker image for the database and push it to Docker Hub
      - name: Build image and push database
        uses: docker/build-push-action@v3
        with:
          context: ./database
          tags: ${{ secrets.DOCKERHUB_USERNAME }}/tp-devops-database:latest
          # Build on feature branches, push only on main branch
          push: ${{ github.ref == 'refs/heads/main' }}

      # Build the Docker image for the HTTP server and push it to Docker Hub
      - name: Build image and push httpd
        uses: docker/build-push-action@v3
        with:
          context: ./http-server
          tags: ${{ secrets.DOCKERHUB_USERNAME }}/tp-devops-httpd:latest
          # Build on feature branches, push only on main branch
          push: ${{ github.ref == 'refs/heads/main' }}

      # Build the Docker image for the front-end and push it to Docker Hub
      - name: Build image and push frontend
        uses: docker/build-push-action@v3
        with:
          context: ./devops-front
          tags: ${{ secrets.DOCKERHUB_USERNAME }}/tp-devops-front:latest
          # Build on feature branches, push only on main branch
          push: ${{ github.ref == 'refs/heads/main' }}

2-3 For what purpose do we need to push docker images?

On pousse des images Docker pour simplifier le déploiement, rendre l’application accessible depuis n’importe quel serveur ou cloud et automatiser les mises à jour sans configuration complexe.

2-4 Document your quality gate configuration

mvn -B verify sonar:sonar -Dsonar.projectKey=devops-project12345 -Dsonar.organization=devops-sonar123 -Dsonar.host.url=https://sonarcloud.io -Dsonar.token=${{ secrets.SONAR_TOKEN }}

Cette commande exécute Maven pour tester et analyser le code avec SonarCloud :

Décomposition :

  1. mvn -B → Exécute Maven en mode "batch" (évite les interactions utilisateur).
  2. verify → Compile et teste le projet pour vérifier son bon fonctionnement.
  3. sonar:sonar → Lance l'analyse du code avec SonarCloud (vérification de la qualité du code, détection de bugs, etc.).
  4. -Dsonar.projectKey=devops-project12345 → Identifie le projet dans SonarCloud.
  5. -Dsonar.organization=devops-sonar123 → Spécifie l'organisation SonarCloud associée.
  6. -Dsonar.host.url=https://sonarcloud.io → Indique l’URL du serveur SonarCloud.
  7. -Dsonar.token=${{ secrets.SONAR_TOKEN }} → Utilise un jeton secret pour s’authentifier et envoyer les résultats sur SonarCloud.

En résumé :

Cette commande compile, teste et envoie l'analyse du code à SonarCloud pour évaluer sa qualité.

TP3

Connexion en ssh :

chmod 400 id_rsa
ssh -i id_rsa [email protected]

add dans /etc/ansible/hosts , le dns doit marcher

emre.elma.takima.cloud

3-1 Document your inventory and base commands

Inventories/setup.yml :

# Définition de l'inventaire Ansible
all:
  vars:
    # Utilisateur SSH pour se connecter aux hôtes
    ansible_user: admin
    # Chemin vers la clé privée SSH pour l'authentification
    ansible_ssh_private_key_file: /home/wind/id_rsa
  children:
    # Groupe d'hôtes de production
    prod:
      # Liste des hôtes dans le groupe de production
      hosts:
        emre.elma.takima.cloud:

Commande ansible :

# To ping 
ansible all -i ansible/inventories/setup.yml -m ping

# request your server to get your OS distribution
ansible all -i ansible/inventories/setup.yml -m setup -a "filter=ansible_distribution*"

# Install Apache into your instance to make it a webserver
$ ansible all -m apt -a "name=apache2 state=present" --private-key=id_rsa -u admin --become

# remove Apache
ansible all -i ansible/inventories/setup.yml -m apt -a "name=apache2 state=absent" --become
# Execute playbook, --syntex-check pour check avant de lancer
ansible-playbook -i ansible/inventories/setup.yml ansible/playbook.yml

Advanced Playbook

3-2 Document your playbook

Playbook avec toutes les tâches dans playbook.yml

- hosts: all
  gather_facts: true
  become: true

  roles:
    - docker

  tasks:
    # Install prerequisites for Docker
    - name: Install required packages
      apt:
        name:
          - apt-transport-https
          - ca-certificates
          - curl
          - gnupg
          - lsb-release
          - python3-venv
        state: latest
        update_cache: yes

    # Add Docker’s official GPG key
    - name: Add Docker GPG key
      apt_key:
        url: https://download.docker.com/linux/debian/gpg
        state: present

    # Set up the Docker stable repository
    - name: Add Docker APT repository
      apt_repository:
        repo: "deb [arch=amd64] https://download.docker.com/linux/debian {{ ansible_facts['distribution_release'] }} stable"
        state: present
        update_cache: yes

    # Install Docker
    - name: Install Docker
      apt:
        name: docker-ce
        state: present

    # Install Python3 and pip3
    - name: Install Python3 and pip3
      apt:
        name:
          - python3
          - python3-pip
        state: present

    # Create a virtual environment for Python packages
    - name: Create a virtual environment for Docker SDK
      command: python3 -m venv /opt/docker_venv
      args:
        creates: /opt/docker_venv  # Only runs if this directory doesn’t exist

    # Install Docker SDK for Python in the virtual environment
    - name: Install Docker SDK for Python in virtual environment
      command: /opt/docker_venv/bin/pip install docker

    # Ensure Docker is running
    - name: Make sure Docker is running
      service:
        name: docker
        state: started
      tags: docker

Notre playbook d'installation de docker est sympa et tout mais il sera plus propre à avoir à un endroit précis, dans un rôle par exemple. On ne garde que handlers et tasks. Ajout du front aussi

On crée :

ansible-galaxy init ansible/roles/copy_env_file
ansible-galaxy init ansible/roles/create_network
ansible-galaxy init ansible/roles/launch_database
ansible-galaxy init ansible/roles/launch_app
ansible-galaxy init ansible/roles/launch_proxy
ansible-galaxy init ansible/roles/launch_front

3-3 Document your docker_container tasks configuration La configuration est similaire, par exemple, rôle pour launch-proxy :

# tasks file for ansible/roles/launch_proxy

- name: Launch Proxy Container
  community.docker.docker_container:
    # Nom du conteneur Docker
    name: http-server
    # Image Docker à utiliser pour le conteneur
    image: wanoni/tp-devops-httpd:latest
    # Toujours tirer la dernière version de l'image
    pull: yes
    # Réseaux Docker auxquels le conteneur sera connecté
    networks:
      - name: app-database-network
      - name: app-front-network
    # Ports à exposer sur le conteneur
    ports:
      - "80:80"
      - "8080:8080"

httpd.conf à modifier pour le front

# Écoute sur le port 8080
Listen 8080

# Configuration du VirtualHost pour le port 8080
<VirtualHost *:8080>
    # Préserve l'hôte d'origine dans les requêtes proxy
    ProxyPreserveHost On

    # Redirige les requêtes vers le backend simple-api sur le port 8080
    ProxyPass / http://simple-api:8080/
    ProxyPassReverse / http://simple-api:8080/
</VirtualHost>

# Configuration du VirtualHost pour le port 80
<VirtualHost *:80>
    # Préserve l'hôte d'origine dans les requêtes proxy
    ProxyPreserveHost On

    # Redirige les requêtes vers le frontend sur le port 80
    ProxyPass / http://front:80/
    ProxyPassReverse / http://front:80/
</VirtualHost>

# Charge le module proxy pour Apache
LoadModule proxy_module modules/mod_proxy.so

# Charge le module proxy_http pour Apache
LoadModule proxy_http_module modules/mod_proxy_http.so

On aura notre app et le front sur http://emre.elma.takima.cloud/departments

Continuous Deployment

test-nackend.yml se lance en 1er. Une fois fini, build-push.yml se lance. Et finalement, deploy-production se lance

# Nom du workflow
name: Deploy

# Déclencheurs du workflow
on:
  workflow_run:
    workflows: ["Build and Push Docker Image"]  # Ce workflow s'exécute après la complétion du workflow "Build and Push Docker Image"
    types:
     - completed
    branches:
     - main  # Ce workflow s'exécute uniquement sur la branche "main"
  pull_request:  # Ce workflow s'exécute également lors de la création de pull requests

# Définition des jobs
jobs:
  deploy:
    runs-on: ubuntu-latest  # Le job s'exécute sur une machine virtuelle Ubuntu

    steps:
      - name: Checkout
        uses: actions/checkout@v2  # Cette étape utilise l'action checkout pour récupérer le code source du dépôt

      - name: Configure SSH
        env:
          ANSIBLE_PRIVATE_KEY: ${{ secrets.RSA_PRIVATE_KEY }}  # Utilisation de la clé privée SSH stockée dans les secrets GitHub
        run: |
          echo "${ANSIBLE_PRIVATE_KEY}" > private_key.pem  # Écriture de la clé privée dans un fichier
          chmod 400 private_key.pem  # Modification des permissions du fichier pour qu'il soit lisible uniquement par le propriétaire
          mkdir -p ~/.ssh  # Création du répertoire .ssh s'il n'existe pas
          ssh-keyscan -t rsa,dsa emre.elma.takima.cloud >> ~/.ssh/known_hosts  # Ajout de l'hôte distant à la liste des hôtes connus
          mv private_key.pem ~/.ssh/id_rsa  # Déplacement de la clé privée dans le répertoire .ssh

      - name: Run Ansible Playbook
        env:
          ENV: ${{ secrets.ENV }}  # Utilisation de la variable d'environnement stockée dans les secrets GitHub
        run: |
          echo "${ENV}" > env  # Écriture de la variable d'environnement dans un fichier
          chmod 400 env  # Modification des permissions du fichier pour qu'il soit lisible uniquement par le propriétaire
          ansible-playbook -i ansible/inventories/setup.yml ansible/playbook.yml  # Exécution du playbook Ansible pour déployer l'application

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Java 84.9%
  • Vue 7.2%
  • Dockerfile 3.6%
  • JavaScript 3.0%
  • HTML 1.3%