Pré-requis
- Avoir installé
Docker - Avoir installé
Docker Compose
Configuration du projet
- Créer un répertoire
gitserverpour le projet, et à l'intérieur de celui-ci deux sous-répertoires :repos(pour conserver les dépôtsgithors du conteneurDocker) etetc(pour certains fichiers de configuration) :
$ cd ~/docker
# -p, --parents créer les répertoires parents nécessaires, sans erreur s'ils existent
$ mkdir -p gitserver/{repos,etc}
- Dans le répertoire
etc, on trouvera un fichier de configuration pourgit(git.conf) et un script permettant la création de dépôts (create-repo.sh) ; - À la racine du répertoire
gitserver, on trouve également deux fichiers : unDockerfile(gitserver.Dockerfile) pour fabriquer le conteneurDocker, et un fichieryamlpourDocker Compose(docker-compose.yaml) ; - L'ensemble de la structure du répertoire
gitserverest donc organisée comme suit :
Le fichier gitserver.Dockerfile
# 20.04 LTS (Focal Fossa, 23 avril 2020) FROM ubuntu:20.04 RUN apt update 2>/dev/null # Debian, Ubuntu et leurs clones utilisent le système de configuration des paquets de Debian appelé "debconf". # debconf peut présenter à l'utilisateur différentes interfaces en fonction de la variable d'environnement "DEBIAN_FRONTEND" : # - non interactif : Vous utilisez ce mode lorsque vous avez besoin d'une interaction nulle lors de l'installation ou de la # mise à niveau du système via apt. Il accepte la réponse par défaut pour toutes les questions. Il peut envoyer un message # d'erreur à l'utilisateur root, mais c'est tout. Sinon, il est totalement silencieux et humble, un frontal parfait pour # les installations automatiques. On peut utiliser ce mode dans les fichiers Docker, les scripts shell, le script cloud-init, etc. ENV DEBIAN_FRONTEND=noninteractive # -y, --yes, --assume-yes : Répondre automatiquement oui aux questions - Présume « oui » comme réponse # à toutes les questions et s'exécute de manière non interactive # -q, --quiet : Mode silencieux - Cette commande produit une sortie destinée à l'enregistrement # dans un fichier-journal en omettant les indicateurs de progression. # vim n'est pas indispensable pour un serveur git, on l'installe par commodité. RUN apt install -q -y git apache2 apache2-utils vim 2>/dev/null RUN a2enmod env cgi alias rewrite RUN mkdir /var/www/git # -R, --recursive => opérer récursivement sur les fichiers et répertoires # -f, --silent, --quiet => supprimer la plupart des messages d'erreur # -v, --verbose => afficher un diagnostic pour chaque fichier traité RUN chown -Rfv www-data:www-data /var/www/git COPY ./etc/git.conf /etc/apache2/sites-available/git.conf COPY ./etc/git-create-repo.sh /usr/bin/mkrepo RUN chmod +x /usr/bin/mkrepo RUN a2dissite 000-default.conf RUN a2ensite git.conf # utile pour la commande "git send-pack" RUN git config --system http.receivepack true # utile pour les commandes "git fetch-pack" et "git ls-remote" RUN git config --system http.uploadpack true ENV APACHE_RUN_USER=www-data ENV APACHE_RUN_GROUP=www-data ENV APACHE_LOG_DIR=/var/log/apache2 ENV APACHE_LOCK_DIR=/var/lock/apache2 ENV APACHE_PID_FILE=/var/run/apache2.pid # "-D FOREGROUND" : indique que le serveur Apache doit être lancé au premier plan (foreground) CMD /usr/sbin/apache2ctl -D FOREGROUND EXPOSE 80/tcp
Rappel sur les instructions dans un fichier Dockerfile
ENV
ENV <key>=<value>
- L'instruction
ENVdéfinit la variable d'environnement<key>à la valeur<value>. Cette valeur sera dans l'environnement pour toutes les instructions suivantes de l'étape de construction et peut être remplacée en ligne dans de nombreuses autres. La valeur sera interprétée pour d'autres variables d'environnement, donc les caractères 'quote' et 'doublequote' seront supprimés s'ils ne sont pas échappés. Comme pour l'analyse de la ligne de commande, les guillemets et les barres obliques inversées peuvent être utilisés pour inclure des espaces dans les valeurs. - Pour faciliter l'exécution de nouveaux logiciels, vous pouvez utiliser
ENVpour mettre à jour la variable d'environnementPATHpour les logiciels installés par votre conteneur. Par exemple,ENV PATH=/usr/local/nginx/bin:$PATHgarantit queCMD ["nginx"]fonctionne. - L'instruction
ENVest également utile pour fournir les variables d'environnement requises spécifiques aux services que vous souhaitez conteneuriser, commePGDATAdePostgres. - Enfin,
ENVpeut également être utilisée pour définir les numéros de version les plus courants afin de faciliter la maintenance des changements de version, comme le montre l'exemple suivant :
RUN
RUN a 2 formes :
# (forme shell, la commande est exécutée dans un shell, qui par défaut est /bin/sh -c sous Linux ou cmd /S /C sous Windows) RUN <command> # (forme exec) RUN ["executable", "param1", "param2"]
- L'instruction
RUNexécute toutes les commandes dans un nouveau calque (layer) par-dessus l'image actuelle et valide les résultats. L'image validée résultante sera utilisée pour l'étape suivante du fichierDocker. - La superposition des instructions
RUNet la génération de commits sont conformes aux concepts fondamentaux deDocker, où les commits sont peu coûteux et où les conteneurs peuvent être créés à partir de n'importe quel point de l'historique d'une image, un peu comme le contrôle des sources. - La forme
execpermet d'éviter le mélange de chaînes de caractères shell et d'exécuter des commandes à l'aide d'une image de base qui ne contient pas l'exécutable shell spécifié. - Le shell par défaut de la forme shell peut être modifié à l'aide de la commande
SHELL.
COPY
COPY a deux formes :
COPY [--chown=<user>:<group>] <src>... <dest> # Cette dernière forme est requise pour les chemins contenant des espaces. COPY [--chown=<user>:<group>] ["<src>",... "<dest>"]
Remarque : La fonctionnalité --chown est uniquement prise en charge sur les Dockerfiles utilisés pour construire des conteneurs Linux, et ne fonctionnera pas sur les conteneurs Windows. Étant donné que les concepts de propriété des utilisateurs et des groupes ne se traduisent pas entre Linux et Windows, l'utilisation de /etc/passwd et /etc/group pour traduire les noms d'utilisateurs et de groupes en identifiants limite cette fonctionnalité aux conteneurs basés sur le système d'exploitation Linux.
- L'instruction
COPYcopie de nouveaux fichiers ou répertoires depuis<src>et les ajoute au système de fichiers du conteneur au chemin<dest>. - Plusieurs ressources
<src>peuvent être spécifiées mais les chemins des fichiers et des répertoires seront interprétés comme relatifs à la source du contexte de la construction. - Chaque
<src>peut contenir des caractères génériques et la correspondance sera effectuée en utilisant les règlesfilepath.MatchdeGo. Par exemple : - Pour ajouter tous les fichiers commençant par "
hom" :
COPY hom* /mydir/
Le <dest> est un chemin absolu, ou un chemin relatif à WORKDIR, dans lequel la source sera copiée à l'intérieur du conteneur de destination.
L'exemple ci-dessous utilise un chemin relatif, et ajoute "test.txt" à <WORKDIR>/relativeDir/ :
COPY test.txt relativeDir/
Alors que cet exemple utilise un chemin absolu, et ajoute "test.txt" à /absoluteDir/
COPY test.txt /absoluteDir/
CMD
L'instruction CMD a trois formes :
# (forme exec, c'est la forme préférée) CMD ["executable", "param1", "param2"] # (comme paramètres par défaut de ENTRYPOINT) CMD ["param1", "param2"] # (forme shell) CMD command param1 param2
- Il ne peut y avoir qu'une seule instruction
CMDdans unDockerfile. Si vous listez plus d'uneCMD, seule la dernière prendra effet. - L'objectif principal d'une
CMDest de fournir des valeurs par défaut pour un conteneur en cours d'exécution. Ces valeurs par défaut peuvent inclure un exécutable, ou omettre l'exécutable, auquel cas vous devez également spécifier une instructionENTRYPOINT. - Si la
CMDest utilisée pour fournir des arguments par défaut pour l'instructionENTRYPOINT, les instructionsCMDetENTRYPOINTdoivent être spécifiées avec le format de tableauJSON. - Note : La forme
execest analysé comme un tableauJSON, ce qui signifie que vous devez utiliser des guillemets doubles (") autour des mots et non des guillemets simples ('). - Contrairement à la forme
shell, la formeexecn'invoque pas un shell de commande. Cela signifie que le traitement normal du shell ne se produit pas. Par exemple,CMD [ "echo", "$HOME" ]ne fera pas de substitution de variable sur$HOME. Si vous voulez un traitement de l'interpréteur de commandes, utilisez le formulaire de l'interpréteur de commandes ou exécutez directement un interpréteur de commandes, par exemple :CMD [ "sh", "-c", "echo $HOME" ]. Lorsque vous utilisez la forme exec et que vous exécutez directement un interpréteur de commandes, comme dans le cas de la forme shell, c'est l'interpréteur de commandes qui effectue l'expansion des variables d'environnement, et nondocker. - Lorsqu'elle est utilisée dans les formes
shellouexec, l'instructionCMDdéfinit la commande à exécuter lors de l'exécution de l'image. - Si vous utilisez la forme
shellde l'instructionCMD, alors la<commande>sera exécutée dans/bin/sh -c:
FROM ubuntu CMD echo "Ceci est un test." | wc -
- Note : Ne confondez pas
RUNetCMD.RUNexécute réellement une commande et commite le résultat ;CMDn'exécute rien au moment du build du conteneur, mais spécifie la commande prévue pour l'image.
EXPOSE
EXPOSE <port> [<port>/<protocole>...]
- L'instruction
EXPOSEinformeDockerque le conteneur écoute sur les ports réseau spécifiés au moment de l'exécution. Vous pouvez spécifier si le port écoute surTCPouUDP, et la valeur par défaut estTCPsi le protocole n'est pas spécifié. - L'instruction
EXPOSEne publie pas réellement le port. Elle fonctionne comme un type de documentation entre la personne qui construit l'image et la personne qui exécute le conteneur, sur les ports qui sont destinés à être publiés. Pour publier réellement le port lors de l'exécution du conteneur, utilisez l'indicateur-psurdocker runpour publier et mapper un ou plusieurs ports, ou l'indicateur-Ppour publier tous les ports exposés et les mapper sur des ports d'ordre supérieur. - Par défaut,
EXPOSEsupposeTCP. Vous pouvez également spécifierUDP:
EXPOSE 80/udp
- Pour exposer à la fois sur
TCPetUDP, incluez deux lignes :
EXPOSE 80/tcp EXPOSE 80/udp
Le fichier git.conf
Il s'agit du fichier de configuration Apache pour Git :
<VirtualHost *:80>
ServerAdmin webmaster@localhost
SetEnv GIT_PROJECT_ROOT /var/www/git
SetEnv GIT_HTTP_EXPORT_ALL
ScriptAlias / /usr/lib/git-core/git-http-backend/
Alias / /var/www/git
<Directory /usr/lib/git-core>
Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
AllowOverride None
Require all granted
</Directory>
DocumentRoot /var/www/html
<Directory /var/www>
Options Indexes FollowSymLinks MultiViews
AllowOverride None
Require all granted
</Directory>
ErrorLog ${APACHE_LOG_DIR}/error.log
LogLevel warn
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
Le fichier git-create-repo.sh
Il s'agit d'un script shelle permettant de créer des dépôts git :
#!/bin/bash
GIT_DIR="/var/www/git"
REPO_NAME=$1
mkdir -p "${GIT_DIR}/${REPO_NAME}.git"
cd "${GIT_DIR}/${REPO_NAME}.git"
git init --bare &> /dev/null
touch git-daemon-export-ok
cp hooks/post-update.sample hooks/post-update
git update-server-info
chown -Rf www-data:www-data "${GIT_DIR}/${REPO_NAME}.git"
echo "Git repository '${REPO_NAME}' created in ${GIT_DIR}/${REPO_NAME}.git"
Le fichier docker-compose.yaml
version: "3.7" services: git-server: container_name: mygitserver build: dockerfile: gitserver.Dockerfile context: . restart: always ports: - "8083:80" volumes: - ./repos:/var/www/git image: mygit:1.0
Construction de l'image Docker du serveur Git HTTP
Maintenant, pour construire l'image Docker du serveur Git HTTP, exécutez la commande suivante :
$ cd ~/docker/gitserver/ $ docker-compose build
La construction d'une image Docker personnalisée peut prendre un certain temps, au cours duquel les différentes étapes s'affichent à l'écran. Pour chaque instruction dans le Dockerfile, une couche supplémentaire (layer) identifiée par un SHA est créée :
Step 17/21 : ENV APACHE_LOG_DIR=/var/log/apache2 ---> Running in c7c9b4bd44fb Removing intermediate container c7c9b4bd44fb ---> dda2038e2201 Step 18/21 : ENV APACHE_LOCK_DIR=/var/lock/apache2 ---> Running in 512dc0df848a Removing intermediate container 512dc0df848a ---> 2a447b6cac80 Step 19/21 : ENV APACHE_PID_FILE=/var/run/apache2.pid ---> Running in 620f784fabb2 Removing intermediate container 620f784fabb2 ---> 1a3f6fb72b4b Step 20/21 : CMD /usr/sbin/apache2ctl -D FOREGROUND ---> Running in 03ac0213f831 Removing intermediate container 03ac0213f831 ---> 522b910c75a6 Step 21/21 : EXPOSE 80/tcp ---> Running in 469313f32983 Removing intermediate container 469313f32983 ---> f9fea6dae724 Successfully built f9fea6dae724 Successfully tagged mygit:1.0
À ce stade, l'image Docker devrait être construite :
gitserver $ docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE mygit 1.0 3bcaaedcae89 7 seconds ago 255MB
Chaque fois que vous apportez une modification à l'un des fichiers gitserver.Dockerfile, etc/git.conf, etc/git-create-repo.sh, vous devez reconstruire l'image Docker à l'aide de la commande docker-compose build.
Démarrage du serveur HTTP Git
Pour démarrer le service git-server, exécutez la commande suivante :
# -d, --detach => Mode détaché : Exécuter les conteneurs en arrière-plan $ docker-compose up -d
Le service git-server devrait démarrer en arrière-plan :
gitserver $ docker-compose up --detach Creating mygitserver ... done
Pour voir comment les ports sont mappés, exécutez la commande docker-compose ps :
# Comme vous pouvez le constater, pour le conteneur mygitserver, le port 8083 de l'hôte Docker est mappé au port 80 du conteneur TCP. gitserver $ docker-compose ps Name Command State Ports ------------------------------------------------------------------------------------------- mygitserver /bin/sh -c /usr/sbin/apach ... Up 0.0.0.0:8083->80/tcp,:::8083->80/tcp
On peut également utiliser la commande docker container ls :
gitserver $ docker container ls CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 28b6bf8ae48c mygit:1.0 "/bin/sh -c '/usr/sb…" 2 minutes ago Up 2 minutes 0.0.0.0:8083->80/tcp, :::8083->80/tcp mygitserver
Si l'on souhaite rentrer dans le conteneur, on peut exécuter la commande suivante :
# --interactive , -i Keep STDIN open even if not attached # --tty , -t Allocate a pseudo-TTY gitserver $ docker exec -it mygitserver "/bin/bash" root@28b6bf8ae48c:/#
Utilisation du serveur Git
Pour créer un nouveau dépôt Git nommé fooproject sur le conteneur du serveur Git HTTP, exécutez la commande suivante :
gitserver $ docker-compose exec git-server mkrepo fooproject Git repository 'fooproject' created in /var/www/git/fooproject.git
Si vous voulez accéder au serveur HTTP Git à partir d'autres ordinateurs sur votre réseau, vous devez connaître l'adresse IP de votre hôte Docker. Pour trouver cette adresse IP, nous utilisons la commande suivante :
$ ip address
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: enp3s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
link/ether 2c:f0:5d:61:ab:c7 brd ff:ff:ff:ff:ff:ff
inet 192.168.0.39/24 brd 192.168.0.255 scope global dynamic noprefixroute enp3s0
valid_lft 41559sec preferred_lft 41559sec
inet6 2a01:e0a:2b0:2d90:a760:f1ab:695:cbd2/64 scope global temporary dynamic
valid_lft 86253sec preferred_lft 62740sec
inet6 2a01:e0a:2b0:2d90:95ba:4209:fb9f:8f43/64 scope global dynamic mngtmpaddr noprefixroute
valid_lft 86253sec preferred_lft 86253sec
inet6 fe80::a64f:56af:74aa:d13f/64 scope link noprefixroute
valid_lft forever preferred_lft forever
3: wlp4s0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether 3c:7c:3f:49:26:6a brd ff:ff:ff:ff:ff:ff
4: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:3a:2a:58:83 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
valid_lft forever preferred_lft forever
inet6 fe80::42:3aff:fe2a:5883/64 scope link
valid_lft forever preferred_lft forever
Dans le cas précédent, l'adresse IP de l'hôte Docker est 172.17.0.1.
Nous pouvons maintenant accéder aux dépôts Git sur le serveur en utilisant l'URL http://<docker-host-IP>:8083/<reponame>.git :
$ cd ~ # <docker-host-IP> est l'adresse IP de votre hôte Docker. # <reponame> est le nom du dépôt Git dans le serveur HTTP Git. # Pour cloner le dépôt Git "fooproject" à partir du serveur : $ git clone http://172.17.0.1:8083/fooproject.git Clonage dans 'fooproject'... warning: Vous semblez avoir cloné un dépôt vide.
Comme vous pouvez le voir, le référentiel est cloné avec succès. Mais il est actuellement vide. Un nouveau répertoire fooproject/ a été créé.
Arrêter le serveur HTTP Git
Pour arrêter le service git-server, exécutez la commande suivante :
gitserver $ docker-compose down
Le service git-server doit maintenant être arrêté.