# Docker from Zero to GigaChad

Docker ça faire presque tous ce qu'on veut avec conteneurs.

## Écrire un Dockerfile

Un Dockerfile c'est une _recette_ pour construire une image Docker et ça ressemble à ça:
```Dockerfile
FROM python:3.8

COPY requirements.txt .
RUN pip install -r requirements.txt

COPY main.py main.py

ENTRYPOINT ["python", "main.py"]
```
On reconnait **3** parties essentielles:

### L'image de base
```Dockerfile
FROM python:3.8
``` 
C'est une image de laquelle on s'inspire pour créer la notre, ça nous évite d'avoir à installer python nous même par exemple.

### Un ensemble d'instructions
```Dockerfile
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY main.py main.py
```
Ces instructions s'exécutent lors de la construction de l'image.

Les instructions les plus courantes sont:  
Pour ajouter des fichiers dans l'image:
```Dockerfile
COPY <un fichier/dossier sur mon pc> <un emplacement dans mon image>
COPY --chown=user:group <mon fichier> <ma destination>
```

Pour lancer une commande dans l'image:
```Dockerfile
RUN ma commande
```

### Un entrypoint
C'est la commande qui s'exécutent lorsque le conteneur est démarre à partir de l'image.  
Deux façons possible de l'écrire:  
exec form:

```Dockerfile
ENTRYPOINT ["mon executable", "arg1", "arg2"]
```
C'est la façon préférée de faire.

shell form:
```Dockerfile
ENTRYPOINT ma commande 1 && ma commande 2
```
nécessaire lorsque l'on a plusieurs commande à faire tourner de façon séquentielle.


### Le multi-stage build
Parfois on a pas besoin d'une image différent pour pouvoir build l'application et pour distribuer cette application. On utilise alors un multi-stage build. Voilà un petit exemple.
```Dockerfile
FROM golang:1.16
WORKDIR /go/src/github.com/alexellis/href-counter/
RUN go get -d -v golang.org/x/net/html  
COPY app.go ./
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .

FROM alpine:latest  
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=0 /go/src/github.com/alexellis/href-counter/app ./
CMD ["./app"]  
```
Seul le dernier stage est conservé dans l'image construite.

## Construire une image à partir d'un Dockerfile
Une image se construit à partir d'un Dockerfile et d'un contexte (c'est un dossier qui correspond au **.** que tu as mis dans to Dockerfile). Souvent le contexte c'est `.` et il n'y a pas besoin de spécifier l'emplacement du Dockerfile, si il s'appelle `Dockefile` et est à la racine du contexte. Pour constuire l'image on utilise alors:
```bash
docker build . -t <le nom de mon image>:<tag>
```
Le tag sert à spécifier plusieurs version de la même image, un peu comme des branches sur git.
## Push une image sur un registry
Un registry c'est juste un espace de stockage disponible pour héberger des images Docker.
```bash
# On se log au registry (les identifiants sont sur le bitwarden)
docker login registry.viarezo.fr
# On build l'image avec le nom du registry dedans
docker build . -t registry.viarezo.fr/<nom du projet>/<image>:<tag>
# On push l'image sur le registry
docker push registry.viarezo.fr/<nom du projet>/<image>:<tag>
```
Attention il faut avoir créé le projet au préalable sur le registry, en cochant bien l'option public.

## Faire tourner un conteneur à partir d'une image
Une fois qu'on a construit notre image, on peut l'utiliser pour créer autant de conteneurs que l'on veut:
```bash
docker run <image>
# En forwardant un port
docker run -p <port sur mon pc>:<port dans le conteneur> <image>
# En ajoutant des variables d'environnement
docker run -e FOO=BAR <image>
# Avec un .env
docker run --env-file .env <image>
```

## Gérer les conteneurs qui s'exécutent
```bash
# Voir les conteneurs qui tournent et les informations associées
docker ps
# Stopper un conteneur
docker stop <conteneur>
# Redémarrer un conteneur stoppé
docker start <conteneur>
# Supprimer un conteneur stoppé
docker rm <conteneur>
```

## Débugger un conteneur
```bash
# Voir les logs
docker logs <conteneur>
# Executer une commande dans un conteneur
docker exec -it <conteneur> <commande>
# Récupérer un shell dans un conteneur (attention bash ne marche pas pour les images alpine)
docker exec -it <conteneur> sh/bash
```