Skip to content

LAB : Setup Repo privé avec Harbor#

Présentation#

Objectifs:#

  • Mise en place d'un repository privé d'hébergement d'images Docker avec Harbor
  • Configuration des credentials de communication entre Jenkins et Harbor
  • Test push image depuis Jenkins vers Harbor

Prérequis#

  • Connaissance de Docker et GIT
  • Instance docker fonctionnel
  • Editeur de code
  • Utilitaire installé sur la machine: git
  • Avoir un proxy nginx fonctionnel (voir lab deploy reverse proxy sur la section 03-conteneurisation)
  • Avoir un jenkins de fonctionnel voir lab du stage 6 Jenkins sur Docker
  • Avoir un repo Github hébergeant de façon privé le code springboot-react-app, voir lab du stage 6 Pipeline Jenkins avec Docker

Déroulement du Lab#

Etape 1 : Mise en place de Harbor#

Dans cette étape, on va mettre en place et configurer Harbor

  • Télécharger et décompresser la dernière version de Harbor depuis le repo officiel sur Github
wget https://github.com/goharbor/harbor/releases/download/v2.12.2/harbor-online-installer-v2.12.2.tgz
tar xzvf harbor-online-installer-v2.12.2.tgz
  • Se rendre dans le dossier de configuration de harbor et configurer le fichier harbor.yml
cd harbor
mv harbor.yml.tmpl harbor.yml
vi harbor.yml
  • Ouvrir le fichier et effectuer les changements ci-dessous :

--> Changer le hostname par registry.lcf.io --> Modifier le port d'écoute de http à 8081
--> commenter les lignes relatives à https

On doit se retrouver avec ce contenu ci-dessous :

# Configuration file of Harbor

# The IP address or hostname to access admin UI and registry service.
# DO NOT use localhost or 127.0.0.1, because Harbor needs to be accessed by external clients.
hostname: registry.lcf.io

# http related config
http:
  # port for http, default is 80. If https enabled, this port will redirect to https port
    port: 8081

# https related config
#https:
  # https port for harbor, default is 443
  #  port: 443
  # The path of cert and key files for nginx
  #  certificate: /your/certificate/path
   #private_key: /your/private/key/path
  # enable strong ssl ciphers (default: false)
  # strong_ssl_ciphers: false

--> Ensuite dans le meme fichier, rechercher la ligne contenant l'instruction external_url, le décommenter et lui mettre la valeur http://registry.lcf.io. Ceci nous permettra d'utiliser notre propre proxy et configurer notre url d'accès à Harbor

# Uncomment external_url if you want to enable external proxy
# And when it enabled the hostname will no longer used
external_url: http://registry.lcf.io

Etape 2 : Lancement des services Harbor#

On va maintenant lancer la préparation pour que harbor puisse télécharger les images et dépendances nécessaires ainsi que les fichiers de configuration necessaires selon ce qui est défini dans le fichier harbor.yml

  • Lancer cette commande dans le meme répertoire harbor
sudo ./prepare --with-trivy
  • Lancer l'installation avec la commande ci-dessous :
sudo ./install.sh --with-trivy
  • Afin de pouvoir utiliser notre proxy, il faudra modifier le fichier docker-compose.yml de harbor pour mettre son nginx dans le meme network frontend que celui de notre proxy. Pour cela faire ces modifications ci-dessous :

--> Rajouter ces lignes dans le bloc networks à la fin du fichier :

  frontend:
    external: true

--> rajouter le network frontend au niveau du service proxy

    networks:
      - harbor
      - frontend

A la fin on aura ce contenu de notre fichier docker-compose.yml (vous pourrez mettre ce contenu à la place du contenu existant)

services:
  log:
    image: goharbor/harbor-log:v2.12.2
    container_name: harbor-log
    restart: always
    cap_drop:
      - ALL
    cap_add:
      - CHOWN
      - DAC_OVERRIDE
      - SETGID
      - SETUID
    volumes:
      - /var/log/harbor/:/var/log/docker/:z
      - type: bind
        source: ./common/config/log/logrotate.conf
        target: /etc/logrotate.d/logrotate.conf
      - type: bind
        source: ./common/config/log/rsyslog_docker.conf
        target: /etc/rsyslog.d/rsyslog_docker.conf
    ports:
      - 127.0.0.1:1514:10514
    networks:
      - harbor
  registry:
    image: goharbor/registry-photon:v2.12.2
    container_name: registry
    restart: always
    cap_drop:
      - ALL
    cap_add:
      - CHOWN
      - SETGID
      - SETUID
    volumes:
      - /data/registry:/storage:z
      - ./common/config/registry/:/etc/registry/:z
      - type: bind
        source: /data/secret/registry/root.crt
        target: /etc/registry/root.crt
      - type: bind
        source: ./common/config/shared/trust-certificates
        target: /harbor_cust_cert
    networks:
      - harbor
    depends_on:
      - log
    logging:
      driver: "syslog"
      options:
        syslog-address: "tcp://localhost:1514"
        tag: "registry"
  registryctl:
    image: goharbor/harbor-registryctl:v2.12.2
    container_name: registryctl
    env_file:
      - ./common/config/registryctl/env
    restart: always
    cap_drop:
      - ALL
    cap_add:
      - CHOWN
      - SETGID
      - SETUID
    volumes:
      - /data/registry:/storage:z
      - ./common/config/registry/:/etc/registry/:z
      - type: bind
        source: ./common/config/registryctl/config.yml
        target: /etc/registryctl/config.yml
      - type: bind
        source: ./common/config/shared/trust-certificates
        target: /harbor_cust_cert
    networks:
      - harbor
    depends_on:
      - log
    logging:
      driver: "syslog"
      options:
        syslog-address: "tcp://localhost:1514"
        tag: "registryctl"
  postgresql:
    image: goharbor/harbor-db:v2.12.2
    container_name: harbor-db
    restart: always
    cap_drop:
      - ALL
    cap_add:
      - CHOWN
      - DAC_OVERRIDE
      - SETGID
      - SETUID
    volumes:
      - /data/database:/var/lib/postgresql/data:z
    networks:
      harbor:
    env_file:
      - ./common/config/db/env
    depends_on:
      - log
    logging:
      driver: "syslog"
      options:
        syslog-address: "tcp://localhost:1514"
        tag: "postgresql"
    shm_size: '1gb'
  core:
    image: goharbor/harbor-core:v2.12.2
    container_name: harbor-core
    env_file:
      - ./common/config/core/env
    restart: always
    cap_drop:
      - ALL
    cap_add:
      - SETGID
      - SETUID
    volumes:
      - /data/ca_download/:/etc/core/ca/:z
      - /data/:/data/:z
      - ./common/config/core/certificates/:/etc/core/certificates/:z
      - type: bind
        source: ./common/config/core/app.conf
        target: /etc/core/app.conf
      - type: bind
        source: /data/secret/core/private_key.pem
        target: /etc/core/private_key.pem
      - type: bind
        source: /data/secret/keys/secretkey
        target: /etc/core/key
      - type: bind
        source: ./common/config/shared/trust-certificates
        target: /harbor_cust_cert
    networks:
      harbor:
    depends_on:
      - log
      - registry
      - redis
      - postgresql
    logging:
      driver: "syslog"
      options:
        syslog-address: "tcp://localhost:1514"
        tag: "core"
  portal:
    image: goharbor/harbor-portal:v2.12.2
    container_name: harbor-portal
    restart: always
    cap_drop:
      - ALL
    cap_add:
      - CHOWN
      - SETGID
      - SETUID
      - NET_BIND_SERVICE
    volumes:
      - type: bind
        source: ./common/config/portal/nginx.conf
        target: /etc/nginx/nginx.conf
    networks:
      - harbor
    depends_on:
      - log
    logging:
      driver: "syslog"
      options:
        syslog-address: "tcp://localhost:1514"
        tag: "portal"

  jobservice:
    image: goharbor/harbor-jobservice:v2.12.2
    container_name: harbor-jobservice
    env_file:
      - ./common/config/jobservice/env
    restart: always
    cap_drop:
      - ALL
    cap_add:
      - CHOWN
      - SETGID
      - SETUID
    volumes:
      - /data/job_logs:/var/log/jobs:z
      - type: bind
        source: ./common/config/jobservice/config.yml
        target: /etc/jobservice/config.yml
      - type: bind
        source: ./common/config/shared/trust-certificates
        target: /harbor_cust_cert
    networks:
      - harbor
    depends_on:
      - core
    logging:
      driver: "syslog"
      options:
        syslog-address: "tcp://localhost:1514"
        tag: "jobservice"
  redis:
    image: goharbor/redis-photon:v2.12.2
    container_name: redis
    restart: always
    cap_drop:
      - ALL
    cap_add:
      - CHOWN
      - SETGID
      - SETUID
    volumes:
      - /data/redis:/var/lib/redis
    networks:
      harbor:
    depends_on:
      - log
    logging:
      driver: "syslog"
      options:
        syslog-address: "tcp://localhost:1514"
        tag: "redis"
  proxy:
    image: goharbor/nginx-photon:v2.12.2
    container_name: nginx
    restart: always
    cap_drop:
      - ALL
    cap_add:
      - CHOWN
      - SETGID
      - SETUID
      - NET_BIND_SERVICE
    volumes:
      - ./common/config/nginx:/etc/nginx:z
      - type: bind
        source: ./common/config/shared/trust-certificates
        target: /harbor_cust_cert
    networks:
      - harbor
      - frontend
    ports:
      - 8081:8080
    depends_on:
      - registry
      - core
      - portal
      - log
    logging:
      driver: "syslog"
      options:
        syslog-address: "tcp://localhost:1514"
        tag: "proxy"
  trivy-adapter:
    container_name: trivy-adapter
    image: goharbor/trivy-adapter-photon:v2.12.2
    restart: always
    cap_drop:
      - ALL
    depends_on:
      - log
      - redis
    networks:
      - harbor
    volumes:
      - type: bind
        source: /data/trivy-adapter/trivy
        target: /home/scanner/.cache/trivy
      - type: bind
        source: /data/trivy-adapter/reports
        target: /home/scanner/.cache/reports
      - type: bind
        source: ./common/config/shared/trust-certificates
        target: /harbor_cust_cert
    logging:
      driver: "syslog"
      options:
        syslog-address: "tcp://localhost:1514"
        tag: "trivy-adapter"
    env_file:
      ./common/config/trivy-adapter/env
networks:
  harbor:
    external: false
  frontend:
    external: true
  • Redémarrer les services Harbor:
docker compose up -d
  • Vérifier que les services ont bien démarré :
docker ps

Etape 3 : Mise à jour de la configuration du proxy#

Le répertoire lecloudfacile-devops-labs/nginx-proxy/conf.d/harbor contient un exemple de configuration du proxy pour la gestion des requêtes entrantes en ce qui concerne l'application harbor. Nous pourrons la copier dans le répertoire lecloudfacile-devops-labs/nginx-proxy/conf.d avec la bonne extension .conf

cd lecloudfacile-devops-labs/nginx-proxy/
cp conf.d/jenkins/harbor.scratch.conf.template conf.d/harbor.conf

N.B : Vous pourrez faire un git pull pour récupèrer les dernières mises à jour du repo github si tel n'est pas déjà le cas

Il faudra ensuite recharger la configuration du proxy pour prendre en compte les modifications apportées.

docker exec -ti proxy nginx -s reload

Enfin, modifier le fichier /etc/hosts pour rajouter notre url d'accès à harbor : registry.lcf.io

127.0.0.1       registry.lcf.io quality.lcf.io jenkins.lcf.io localhost app.moodboard.xyz adminer.moodboard.xyz api.moodboard.xyz

Etape 4 : Accès au service Harbor#

Ouvrir un navigateur et taper l'adresse suivante : http://registry.lcf.io

Les identifiants d'accès par défaut sont :
- login : admin
- Mot de passe : Harbor12345

Etape 5 : Configuration du projet#

Dans cette étape on va créer un projet pour héberger de façon privé nos images springboot précèdemment pushé sur DockerHub lors du lab Pipeline Jenkins avec Docker du Stage 6

  • Cliquer sur New project pour créer de nouveaux projets

  • Créer un projet avec comme nom moodboard

  • Activer le scan automatique avec trivy sur l'ensemble du projet

Se rendre sur le projet moodboard

Puis se rendre dans configuration, cocher Automatically scan images on push et cliquer sur Save tout en bas.
Ceci permettra d'avoir un scan sécurité automatisé à chaque fois qu'on va pousser des images sur ce projet.

Etape 5 : Push d'images depuis Jenkins#

Dans cette étape, on va créer un pipeline jenkins permettant de pusher des images vers Harbor

  • Créer un credential avec les identifiants de connexion à harbor

Se rendre sur la page d'administration de jenkins --> Credentials --> Global --> Add Credentials --> créer un credential de type Username with password avec les informations ci-dessous :

-> Renseigner le nom d'utilisateur admin dans le champs Nom d'utilisateur

--> Renseigner Harbor12345dans le champs Mot de passe

--> Dans le champ ID, renseigner token-harbor

--> Dans le champ Description, renseigner Identifiant de connexion à Harbor

--> Enfin cliquer sur Create

  • Création d'un pipeline Jenkins

Créer un nouveau job jenkins de type pipeline avec comme nom build-springboot-harbor

Ci-dessous le contenu du pipeline :

pipeline {
    agent any

    stages {
        stage('clone Project') {
            steps {
        // Clone le repo Github pour récumèrer le code source
                git branch: 'main', url: 'https://github.com/wingufactory/lecloudfacile-devops-labs.git'
            }
        }
        stage('Build Docker Image') {
            steps {
        // Construction de l'image Docker pour le backend
                sh 'docker build -t moodboard-backend-app:1.0.0 springboot-react-app/moodboard-backend'

                // Construction de l'image Docker pour le frontend
                sh 'docker build -t moodboard-frontend-app:1.0.0 springboot-react-app/moodboard-frontend'
            }
        }

        stage('Tag Docker Image') {
            steps {
                // Tag des images Docker avec les noms de dépôt sur Docker Hub
                sh 'docker image tag moodboard-frontend-app:1.0.0 registry.lcf.io/moodboard/moodboard-frontend-app:1.0.0'
                sh 'docker image tag moodboard-backend-app:1.0.0 registry.lcf.io/moodboard/moodboard-backend-app:1.0.0'
            }
        }

        stage('Push to DockerHub') {
            steps {
                echo "Pushing image to Harbor..."

                // Utilisation des identifiants Jenkins pour se connecter à Docker Hub
                withCredentials([usernamePassword(credentialsId: "token-harbor", usernameVariable: "DOCKER_USER", passwordVariable: "DOCKER_PASSWORD")]) {
                    // Connexion et push des images Docker vers Docker Hub
                    sh """
                        echo "$DOCKER_PASSWORD" | docker login registry.lcf.io -u "$DOCKER_USER" --password-stdin
                        docker push registry.lcf.io/moodboard/moodboard-frontend-app:1.0.0
                        docker push registry.lcf.io/moodboard/moodboard-backend-app:1.0.0
                    """
                }
            }
        }
    }
}
  • Executer le pipeline

Etape 6 : Vérification#

Se rendre sur harbor, puis dans le projet moodboard, on pourra constater les deux images poussés : backend et frontend

On peut constater également que les images ont été automatiquement scannées avec trivy