Home .NET Docker et les bonnes pratiques avec Visual Studio/.NET Core

Docker et les bonnes pratiques avec Visual Studio/.NET Core

  Nolan VIEIRA Développeur .NET/Angular 45 min 11 mars 2020

Docker dans la pratique

Nous avons vu dans l’article précédent la théorie sur les conteneurs, nous allons maintenant passer à la pratique. L’apprentissage de Docker est relativement simple, mais vous devez le compléter avec Docker Compose pour faire des infrastructures complètes entre les conteneurs.

Docker

Installation

L’installation de Docker va permettre d’avoir les outils nécessaires pour l’utilisation de Docker en local. Vous devez vous inscrire sur le Docker Hub et suivre la procédure d’installation à la fin de l’inscription.

Étape facultative : Installation de Docker avec le WSL2 sur Windows 10 version 2004

La nouvelle version de Windows 10, sortie le 27 Mai 2020 nous permet d’utiliser Docker sur un Linux « natif » sur Windows 10.  Attention, il n’est pas activé nativement, vous allez devoir forcer l’utilisation de la version 2  et installer le dernier noyau Linux pour Windows 10!

Pour faire simple, vous devez :

  • Valider que vous avez un Windows 10 version 2004
  • Activer le WSL depuis un PowerShell en administrateur:
    dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart
    
    dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart
    
    wsl --set-default-version 2
    Activation du WSL2
  • Installer la mise à jour du noyau Linux WSL 2
  • Installer un linux depuis le Microsoft Store : Debian par exemple.
  • Définir le Linux par défaut sur le WSL2:
    wsl --set-default debian
    Définir Debian par défaut
  • Installer Docker Desktop for Windows « normalement »

Vous avez maintenant un Docker Linux sur Windows, l’avantage est considérable : Nous n’utilisons plus Hyper-V et le démarrage du Linux sur Windows est très rapide.

Plus d’information sur les étapes d’installation sur la documentation Docker et sur la documentation Microsoft pour l’utilisation du WSL2.

Interface Docker sur Windows

Depuis peu, Docker nous offre la possibilité d’utiliser une version graphique avec beaucoup de simplicité ! Vous pouvez voir la configuration, la charge, les logs, lancer les conteneurs et ouvrir un terminal simplement.

Exemple simple

Nous allons maintenant faire un test avec la création d’un conteneur Nginx qui n’est autre qu’un serveur Web simple permettant d’héberger des sites.

Dans un terminal, nous allons taper :

docker run -p 8080:80 nginx

Ce qui nous donne :

C:\Users\nolan>docker run -p 8080:80 nginx
Unable to find image 'nginx:latest' locally
latest: Pulling from library/nginx
743f2d6c1f65: Pull complete
6bfc4ec4420a: Pull complete
688a776db95f: Pull complete
Digest: sha256:23b4dcdf0d34d4a129755fc6f52e1c6e23bb34ea011b315d87e193033bcd1b68
Status: Downloaded newer image for nginx:latest  

Vous pouvez regarder le résultat sur http://localhost:8080.

Les arguments seront détaillés plus bas dans l’article. A présent nous allons voir les commandes de Docker.

Les commandes de Docker

Docker pull

La commande docker pull permet de récupérer une image depuis un conteneur d’image Docker, comme le DockerHub.

Attention : les images Docker ne sont pas effacées automatiquement et sont gardées sur votre disque dur.

Tag et sécurité

Vous pouvez demander une version spécifique d’une image Docker sur le hub de docker comme par exemple pour Ngnix :

On peut voir sur la capture ci-dessus, que l’image Docker Nginx propose des versions spécifiques que nous pouvons récupérer avec la commande docker pull ImageDocker:Tag:

docker pull nginx:alpine

La capture ci-dessus ne montre pas l’existence du tag « alpine », mais en cherchant bien sur les tags de l’image Docker nous pouvons la trouver.

Alpine Linux ?

Je vous recommande de prendre les versions d’Alpine Linux. Ce sont des images légères et performantes, qui n’embarquent pas de fioriture, un gage de sécurité. Nous pouvons voir que l’image de Nginx basée sur Alpine fait 8Mb, ce qui est vraiment léger comparé à la version basée sur Debian (50MB). Cependant, les images Docker ne sont pas basées sur Alpine Linux par défaut, mais sur une Debian, vous devez donc bien les chercher.

Par défaut, la commande docker pull prend le tag latest sur le téléchargement des images. Il est toutefois préférable de prendre une version précise car un changement de configuration ou de paramètre de l’image peut casser votre application !

Docker run

Permet de lancer une image Docker.

Syntaxe :

docker run -p 8080:80 nginx

Plus d’information sur les options de docker run sur la documentation officielle

Les Arguments

Port

Option -p pour port.

Nous avons simplement demandé à Docker de lancer l’image nginx (qui est un serveur web) avec une option : -p pour le mot port.

C’est une option indispensable dans Docker. Pour rappel, un conteneur Docker est étanche, nous devons donc définir un port pour communiquer avec.

Le -p de -p 8080:80 signifie -p NotreMachine:ImageDocker.

Nous devons retenir :

  • Une Image Docker peut exposer un ou plusieurs ports, il suffit juste d’ajouter une autre option -p suivi des ports. Vous devez regarder la documentation de votre image pour connaitre quel(s) port(s) elle expose.
  • Nous trouvons souvent des images Docker avec par exemple -p 9000:9000, il n’est pas possible d’utiliser des ports déjà utilisés sur notre machine, faites attention !
  • Il est obligatoire d’avoir un port sur une application Web. Mais il n’est pas obligatoire de définir un port pour une base de données.
Volume

Le -v permet de faire un ancrage physique entre notre machine et l’image Docker de notre conteneur, il permet de faire de la persistance d’information :

  • Le cas le plus simple est -v /var/run/docker.sock:/var/run/docker.sock qui utilise un dossier (ou fichier) physique de notre machine. La notion reste identique sur Docker, -v VotreMachine/Dossier:ImageDocker/Dossier
  • Pour la persistance, nous recommandons de faire -v sonarqube_data:/opt/sonarqube/data, mais la création d’un volume dans Docker est nécessaire : Docker volume create sonarqube_data par exemple.
  • Il n’y a aucune limite dans le nombre d’utilisation de -v

Exemple :

docker run --name my-custom-nginx-container -v /host/path/nginx.conf:/etc/nginx/nginx.conf:ro -d nginx

Le :ro (readonly) à la fin de l’argument du -v permet de définir les droits d’accès en lecture seule sur le dossier (ou fichier) de votre machine.
Plus d’information sur la documentation officielle

Environnement

Le -e permet de donner des informations d’environnement pour l’image Docker, ce qui permet de définir des paramètres. Voici un exemple : -e MSSQL_SA_PASSWORD='<YourStrong!Passw0rd>'.

C’est la seule façon de paramétrer simplement et proprement une application dans une image Docker sans ajouter en dur les informations de configuration. Ce qui permet d’utiliser notre image Docker partout sans contrainte. Nous allons voir un cas d’usage plus bas avec le cas d’une connexion à une base de données.

Les Indispensables

Detach

Le -d (–detach) est une option qui permet de lancer l’image Docker en tâche de fond.

Bien entendu, inutile quand on crée une image Docker, car nous ne pouvons pas voir les retours sur le terminal si une erreur se produit. Donc c’est plus dans un usage avancé lors de la mise en production par exemple.

Nommer un conteneur

L’argument --namepermet de nommer simplement un conteneur pour avoir une administration plus simple avec les commandes du CLI. Dans le cas contraire, un nom aléatoire est donné ce qui n’est pas vraiment bien, surtout si vous avez deux images docker identique de lancé.

Voici un exemple :

docker run --name mon-nginx -d nginx:alpine

Comme vous pouvez le voir sur cette image, si nous ne définissons pas de nom, il va nous en créer un aléatoirement.

Docker build

Vous pouvez tester votre image avec la commande suivante :

docker build --no-cache --force-rm

Il est important d’exécuter cette commande lors de la création d’une image. Docker enregistre des parties en cache pour accélérer le build. Si vous êtes en création d’image pour un projet, il est donc obligatoire de le faire.

le MAN de docker

Vous pouvez obtenir les informations des commandes via l’option --help dans le terminal :

docker run --help
Aide-mémoire

Voici une liste d’actions possibles sur Docker :

Commande Description
attach Attach local standard input, output, and error streams to a running container
build Build an image from a Dockerfile
commit Create a new image from a container’s changes
cp Copy files/folders between a container and the local filesystem
create Create a new container
diff Inspect changes to files or directories on a container’s filesystem
events Get real time events from the server
exec Run a command in a running container
export Export a container’s filesystem as a tar archive
history Show the history of an image
images List images
import Import the contents from a tarball to create a filesystem image
info Display system-wide information
inspect Return low-level information on Docker objects
kill Kill one or more running containers
load Load an image from a tar archive or STDIN
login Log in to a Docker registry
logout Log out from a Docker registry
logs Fetch the logs of a container
pause Pause all processes within one or more containers
port List port mappings or a specific mapping for the container
ps List containers
pull Pull an image or a repository from a registry
push Push an image or a repository to a registry
rename Rename a container
restart Restart one or more containers
rm Remove one or more containers
rmi Remove one or more images
run Run a command in a new container
save Save one or more images to a tar archive (streamed to STDOUT by default)
search Search the Docker Hub for images
start Start one or more stopped containers
stats Display a live stream of container(s) resource usage statistics
stop Stop one or more running containers
tag Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE
top Display the running processes of a container
unpause Unpause all processes within one or more containers
update Update configuration of one or more containers
version Show the Docker version information
wait Block until one or more containers stop, then print their exit codes

 

Docker Compose

Docker Compose est un orchestrateur de conteneur Docker. Il permet de faire des recettes avec des images et de simplifier l’utilisation de Docker. C’est une solution intéressante qui permet de faire une architecture complexe entre divers services en un seul fichier. C’est l’un des outils requis pour utiliser Docker dans un projet.

Mise à niveau (optionnelle)

Le programme d’installation de Docker sur Windows inclut Docker Compose mais pas toujours avec la dernière version, ce qui peut être bloquant si vous souhaitez utiliser ses nouveautés sur votre machine. La team Docker ne propose pas souvent des mises à jour des outils, voici donc une solution pour garder Docker Compose à jour.

Nous pouvons utiliser la dernière version de Docker Compose en téléchargeant la version Windows sur le projet Github Docker Compose : Release.

Remplacez dans le dossier C:\Program Files\Docker\Docker\resources\bin le fichier docker-compose.exe par celui téléchargé.

Docker-compose.yml

Le docker-compose.yml est notre fichier qui permet de faire la configuration et les interactions entre les images du conteneur.

Pour vous montrer les possibilités, nous allons prendre une image Docker qui demande une base de données. Nous allons faire en sorte que les deux images communiquent pour que l’application fonctionne. Voici un exemple avec SonarQube, une application forte utile en entreprise :

version: "3.7"
services:

  db:
    image: postgres:11-alpine
    container_name: postgres_sonarqube
    restart: always
    volumes:
      - db-data:/var/lib/postgresql/data
    environment:
      - POSTGRES_USER=sonar
      - POSTGRES_PASSWORD=sonar
    volumes:
      - postgresql:/var/lib/postgresql
      - postgresql_data:/var/lib/postgresql/data

  sonarqube:
    image: sonarqube:7.7-community
    container_name: sonarqube
    restart: always
    ports:
      - "9010:9000"
    depends_on:
      - db
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - sonarqube_conf:/opt/sonarqube/conf
      - sonarqube_data:/opt/sonarqube/data
      - sonarqube_extensions:/opt/sonarqube/extensions
    environment:
      - sonar.jdbc.username=sonar
      - sonar.jdbc.password=sonar
      - sonar.jdbc.url=jdbc:postgresql://db/sonar

networks:
  default:

volumes:
  postgresql:
  postgresql_data:
  sonarqube_conf:
  sonarqube_data:
  sonarqube_extensions:

Docker-compose up

Pour créer et lancer les images, nous avons besoin de nous trouver dans le même niveau que le fichier docker-compose.yml.

La commande est la suivante :

docker-compose up

Si nous souhaitons exécuter la commande en tâche de fond, nous pouvons ajouter l’option -d

Docker-compose ps

La commande suivante permet de lister les images en cours, la configuration et le statut du conteneur de notre docker-compose.yml.

C’est un bon début pour voir si nous avons un problème de lancement !

docker-compose ps

Nous pouvons aussi retrouver les informations avec la commande docker ps mais cela listera toutes les instances et non celui du fichier docker-compose.yml !

Docker-compose stop

La commande permet de fermer proprement le conteneur de notre docker-compose.yml.

docker-compose stop

Docker-compose down

Pour toute future modification du docker-compose.yml, vous devez préalablement faire un docker-compose down si les modifications sont trop importantes. Vous pouvez ensuite faire un docker-compose up -d.

Cette commande permet de fermer et de supprimer le conteneur, le réseau, les images utilisées et les volumes !

docker-compose down

Docker-compose logs et events

Nous avons deux possibilités pour diagnostiquer un conteneur :

docker-compose logs

Et

docker-compose events

Aide mémoire

Commande Description
build Build or rebuild services
bundle Generate a Docker bundle from the Compose file
config Validate and view the Compose file
create Create services
down Stop and remove containers, networks, images, and volumes
events Receive real time events from containers
exec Execute a command in a running container
help Get help on a command
images List images
kill Kill containers
logs View output from containers
pause Pause services
port Print the public port for a port binding
ps List containers
pull Pull service images
push Push service images
restart Restart services
rm Remove stopped containers
run Run a one-off command
scale Set number of containers for a service
start Start services
stop Stop services
top Display the running processes
unpause Unpause services
up Create and start containers
version Show the Docker-Compose version information

Docker en développement

Création de projet sous Visual Studio 2019

Lors de la création d’un projet avec Visual Studio 2019, vous pouvez ajouter par défaut la prise en charge de Docker sur votre projet :

Les SPA Angular et React.js ne proposent pas par défaut d’activer Docker. Nous pouvons ajouter Docker dans le projet simplement en ajoutant l’orchestrateur Docker Compose :

Nous allons parler de la modification de l’image Docker pour utiliser Node.js et NPM plus bas dans l’article.

Pour rappel, l’ajout de Docker Compose va créer un projet que Visual Studio pourra lancer. C’est la solution la plus simple pour travailler en équipe, car si vous ajoutez simplement le support de Docker, vous serez le seul à pouvoir le lancer sur votre PC. Les autres développeurs n’auront que IIS Express en proposition car la modification n’est pas enregistrée sur un fichier et donc pas de commit possible.

Concernant l’option de support de Docker, je recommande toujours de prendre Linux pour les projets en .NET Core et le futur .NET 5, qui sortira en cette fin d’année. Cela vous fera économiser un coût de licence non négligeable. Pour les projets Legacy sur .NET Framework, vous n’avez pas le choix, c’est du Windows Container.

Extension Docker pour Visual Studio 2019

Il existe une extension officielle Visual Studio Container Tools Extensions développée par Microsoft pour Visual Studio 2019 qui simplifie le management de Docker.

Vous pouvez avoir accès aux conteneurs en cours de lancement et de les arrêter (de force, car parfois Docker en local ne fonctionne pas correctement) ou relancer simplement. Vous avez aussi la possibilité de lister les images Docker en local depuis cet outil, ouvrir un terminal et voir les fichiers rapidement.

Machine arrière ! Certificats SSL droit devant !

La meilleure façon d’apprendre et de retenir c’est en faisant des erreurs ! Vous allez avoir des erreurs sur votre production si vous continuez. Vous avez sans doute laissé activer le SSL sur votre projet lors de la création, mais saviez-vous que toutes les images Docker du Hub ne le sont pas ?

La raison est simple, nous utilisons généralement un outil externe comme Traefik pour la gestion du Proxy et qui permet d’ajouter la gestion dynamique des certificats. Dans le cas contraire, vous allez devoir intégrer un certificat SSL dans l’image Docker que vous avez créé, ce qui n’est pas pratique du tout.

Pourquoi ça fonctionne en local ?

La raison est simple : Il y a un fichier qui surcharge le docker-compose.yml et qui ajoute les certificats locaux dans l’image.

Dans cet exemple, pour que votre application fonctionne, vous allez devoir installer .NET Core et générer des certificats sur le serveur qui exécute les images Docker. Nous allons donc devoir retirer le SSL du projet.

Ne pas utiliser le SSL :

La méthode la plus simple, en début de projet est de simplement désactiver le SSL lors de la création du projet depuis Visual Studio :

Mais il y a des cas où l’option HTTPS est forcée, comme quand vous activez l’option d’authentification par exemple :

Nous allons prendre pour exemple ce cas et désactiver le SSL, car nous allons utiliser cette démo dans cet article pour vous parler de Docker plus en détail. Attention, nous pouvons simplifier l’étape en ajoutant la prise en charge de Docker Compose après la suppression du SSL du projet. Dans cet exemple je ne vais naturellement pas le faire pour vous montrer toutes les modifications à faire si c’est votre cas.

Nous allons modifier 3 fichiers :

{
  "iisSettings": {
    "windowsAuthentication": false,
    "anonymousAuthentication": true,
    "iisExpress": {
      "applicationUrl": "http://localhost:62508",
      //"sslPort": 44339,
      "sslPort": 0
    }
  },
  "profiles": {
    "IIS Express": {
      "commandName": "IISExpress",
      "launchBrowser": true,
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    },
    "Demo": {
      "commandName": "Project",
      "launchBrowser": true,
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      },
      //"applicationUrl": "https://localhost:5001;http://localhost:5000"
      "applicationUrl": "http://localhost:5000"
    },
    "Docker": {
      "commandName": "Docker",
      "launchBrowser": true,
      "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}",
      //"publishAllPorts": true,
      //"useSSL": true
      "publishAllPorts": true
    }
  }
}
Properties/launchSettings.json

Pour information ce fichier permet à Visual Studio Code et Visual Studio 2017/2019 de lancer le(s) projet(s).

Nous allons supprimer la copie du certificat SSL et de l’utilisation du port dans Docker Compose depuis Visual Studio :

version: '3.4'

services:
  demo:
    environment:
      - ASPNETCORE_ENVIRONMENT=Development
#      - ASPNETCORE_URLS=https://+:443;http://+:80
    ports:
      - "80"
#      - "443"
#   volumes:
#      - ${APPDATA}/Microsoft/UserSecrets:/root/.microsoft/usersecrets:ro
#      - ${APPDATA}/ASP.NET/Https:/root/.aspnet/https:ro
docker-compose.override.yml

 

Pour finir, nous allons supprimer l’ouverture du port SSL 443 de l’image Docker :

#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.

FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim AS base
WORKDIR /app
EXPOSE 80
#EXPOSE 443

FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build
WORKDIR /src
COPY ["Demo/Demo.csproj", "Demo/"]
RUN dotnet restore "Demo/Demo.csproj"
COPY . .
WORKDIR "/src/Demo"
RUN dotnet build "Demo.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "Demo.csproj" -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "Demo.dll"]
Dockerfile

Voici une petite vidéo de cette manipulation et des résultats :

 

Création et utilisation de variables d’environnement de Docker dans un projet

Vous avez vu au début de cet article l’utilisation des -e (environnement) pour personnaliser une image Docker. Mais comment faire pour en ajouter nous-même dans notre programme ? Aussi incroyable que cela puisse paraître, cette partie n’est pas détaillée ni même abordée dans la documentation MSDN, mais nous allons en parler ici. En parallèle Docker nous fournit un exemple que vous ne devez absolument pas utiliser (car cela ne vous permet pas de changer la configuration sans refaire une image) sur cette page : Quickstart: Compose and ASP.NET Core with SQL Server

Pour cet exemple, nous allons créer un projet en .Net Core 3.1 MVC avec l’Authentification en local, car nous allons ajouter dynamiquement la configuration de la base de données depuis Docker.

Pour information, le mode HTTPS est activé par défaut, reportez-vous sur la section « Ne pas utiliser le SSL » pour la supprimer.

Nous allons créer un fichier dans le projet du site web qui s’appelle settings.env avec comme contenu suivant :

DB_SERVER=[IP ou Nom de l'image docker]
DB_NAME=[Nom de la base de données]
DB_USER=[Utilisateur]
DB_PASSWORD=[Mot de passe]
settings.env

Nous devons par la suite référencer le fichier settings.env dans le .csproj du site web :

<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>netcoreapp3.1</TargetFramework>
	<!-- ... -->
    <DockerComposeProjectPath>..\docker-compose.dcproj</DockerComposeProjectPath>
    <DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
	
	<!-- Voici la ligne que nous devons ajouter ci-dessous -->
	<DockerfileRunEnvironmentFiles>settings.env</DockerfileRunEnvironmentFiles>
  </PropertyGroup>

	<!-- ... -->
</Project> 
demo.csproj

Maintenant, nous allons ajouter la configuration de Docker Compose, nos variables d’environnement et désactiver le SSL du projet. Vous devez ajouter donc l’orchestrateur Docker Compose (que nous avons vu plus haut, attention de bien vérifier que le SSL est retiré dans le fichier docker-compose.override.yml).

Nous allons ajouter la configuration pour la connexion de la base de données dans le fichier docker-compose.yml avec l’ajout d’une image de Microsoft SQL Server :

version: '3.4'

services:
  demo:
    image: ${DOCKER_REGISTRY-}demo
    build:
      context: .
      dockerfile: Demo/Dockerfile
    depends_on:
      - demo_mssqlserver
    environment:
        DB_SERVER: demo_mssqlserver
        DB_NAME: ma_db_demo
        DB_USER: sa
        DB_PASSWORD: Vi956df12sd02vFYPGsMc3JV3z
  demo_mssqlserver:
    image: microsoft/mssql-server-linux
    container_name: demo_mssqlserver
    environment:
        ACCEPT_EULA: Y
        SA_PASSWORD: Vi956df12sd02vFYPGsMc3JV3z
    ports:
        - "1433:1433"
docker-compose.yml

Il nous manque plus qu’à ajouter une vérification sur le lancement du site pour vérifier de la présence des variables. Pour faire simple dans cette démo, nous allons ajouter dans le fichier Program.cs une vérification simple :

using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
using System;

namespace Demo
{
    public class Program
    {
        public static void Main(string[] args)
        {
            CheckEnvironementVariableDocker();
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                });

        public static void CheckEnvironementVariableDocker()
        {

            if (string.IsNullOrEmpty(Environment.GetEnvironmentVariable("DB_SERVER")))
            {
                throw new Exception("Nous avons besoin d'avoir l'option: -e \"DB_SERVER={IP_or_DockerImageMSSQLName}\"");
            }
            if (string.IsNullOrEmpty(Environment.GetEnvironmentVariable("DB_NAME")))
            {
                throw new Exception("Nous avons besoin d'avoir l'option: -e \"DB_NAME={MyDatabaseName}\"");
            }
            if (string.IsNullOrEmpty(Environment.GetEnvironmentVariable("DB_USER")))
            {
                throw new Exception("Nous avons besoin d'avoir l'option: -e \"DB_USER={MyUser}\"");
            }
            if (string.IsNullOrEmpty(Environment.GetEnvironmentVariable("DB_PASSWORD")))
            {
                throw new Exception("Nous avons besoin d'avoir l'option: -e \"DB_PASSWORD={MyPassword}\"");
            }
        }
    }
}
Program.cs

Pour finir, il nous reste juste à utiliser les variables dans le Startup.cs pour la chaîne de connexion SQL du projet avec Entity Framework :

...
namespace Demo
{
    public class Startup
    {
        ...

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            //services.AddDbContext<ApplicationDbContext>(options =>
            //    options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

            services.AddDbContext<ApplicationDbContext>(options =>
                options.UseSqlServer(@$"Server={Environment.GetEnvironmentVariable("DB_SERVER")};Database={Environment.GetEnvironmentVariable("DB_NAME")};User={Environment.GetEnvironmentVariable("DB_USER")};Password={Environment.GetEnvironmentVariable("DB_PASSWORD")};"));

            ...
        }

        ...
    }
}
Startup.cs

Voici la vidéo qui montre le résultat :

Nous pouvons noter qu’il y a une demande de migration Entity Framework pour créer les tables en base, vous pouvez automatiser cette étape avec la commande suivante :

N’oubliez pas de supprimer le container Docker si vous avez utilisé la persistance de données sur l’image de la base SQL !

Création d’une image Docker

Nous avons vu la création de projet .NET Core avec Docker, cependant nous n’avons pas encore vu la personnalisation des dépendances des images Docker. L’objectif est de comprendre que la personnalisation est importante et simple. Pour ce faire, nous allons utiliser la génération d’un projet de base par Visual Studio : .NET Core SPA Angular

Dockerfile

Le Dockerfile est un fichier qui décrit comment construire l’image de notre projet. Cette image va contenir notre application et l’ensemble des runtimes pour son fonctionnement.

Voici un exemple de construction d’image Docker. Je vais prendre l’image de base de .NET Core runtime et installer Node.js et NPM pour que mon projet .NET Core SPA Angular démarre. Je vais prendre un projet un peu plus complexe avec plusieurs projets pour comprendre quelle est la syntaxe et la logique :

### Création de l'image qui va recevoir notre application + création de l'instance "base"
FROM microsoft/dotnet:3.1-aspnetcore-runtime-alpine AS base

# Installation des outils qui ne sont pas dans l'image de base pour run
RUN apk update && apk upgrade
RUN apk update && apk add nodejs-current npm

# Dossier qui va contenir notre application
WORKDIR /app

# Ports de l'image par défaut, merci de vérifier votre cas dans la documentation 
EXPOSE 80
#EXPOSE 443

### Création de l'image qui vas permet de build la solution + création de l'instance "build"
FROM microsoft/dotnet:3.1-sdk-alpine AS build

# Installation des outils qui ne sont pas dans l'image de base.
# Nous en avons plus car il y a des dépendances dans le build de NodeJs obligatoire!
RUN apk update && apk upgrade
RUN apk update && apk add nodejs-current npm python gcc g++ make git build-base
RUN apk update && apk add --virtual build-dependencies

# On définit le dossier ou on vas stocker l'application pour build
WORKDIR /src

# on copie les csprojet et on fait un restore
COPY ["Boilerplate/Boilerplate.csproj", "Boilerplate/"]
COPY ["Boilerplate.Common/Boilerplate.Common.csproj", "Boilerplate.Common/"]
COPY ["Boilerplate.Models/Boilerplate.Models.csproj", "Boilerplate.Models/"]
COPY ["Boilerplate.Data/Boilerplate.Data.csproj", "Boilerplate.Data/"]
RUN dotnet restore "Boilerplate/Boilerplate.csproj"
# on copie le build
COPY . .
# On défini notre dossier pour la suite des commandes (on entre dans le dossier du projet) et on build
WORKDIR "/src/Boilerplate"
RUN dotnet build "Boilerplate.csproj" -c Release -o /app

# On créer une autre instance et fait une déploiement sur /app 
FROM build AS publish
RUN dotnet publish "Boilerplate.csproj" -c Release -o /app

# On créer la dernière instance
FROM base AS final
WORKDIR /app
# On copie depuis l'instance "publish" le dossier /app dans le dossier /app de l'instance actuel
COPY --from=publish /app .
# On dit c'est quoi comment on start l'application
ENTRYPOINT ["dotnet", "Boilerplate.dll"]
Dockerfile

Comme vous pouvez le voir ci-dessus, il y a plusieurs étapes et utilisation d’image Docker pour créer une image Docker personnalisée. Ici j’ai fait le choix de générer mon application dans une image Docker avec les SDK de .Net Core pour ne pas le faire depuis mon ordinateur. C’est le choix le plus intéressant, car nous pouvons le faire de n’importe où maintenant et surtout nous pouvons l’automatiser simplement sur des outils de déploiement continu.

.dockerignore

Extrêmement important, il permet d’ignorer les dossiers et fichiers inutiles. Le processus de création d’une image vu ci-dessus est le suivant :

  • Nous allons copier le répertoire du projet dans l’image Docker (avec les SDK) pour construire notre application.
  • Pour finir nous allons copier la génération de notre application dans une image Docker (avec les runtimes) pour ensuite l’utiliser normalement.

Il est donc inutile d’ajouter des fichiers non-nécessaire au fonctionnement ou sensible dans une image Docker.
Globalement, nous devons retrouver les mêmes règles que le fichier .gitignore mais avec en plus, tout ce qui est strictement inutile à la compilation de votre application :

**/.classpath
**/.dockerignore
**/.env
**/.git
**/.gitignore
**/.project
**/.settings
**/.toolstarget
**/.vs
**/.vscode
**/*.*proj.user
**/*.dbmdl
**/*.jfm
**/azds.yaml
**/bin
**/charts
**/docker-compose*
**/Dockerfile*
**/node_modules
**/npm-debug.log
**/obj
**/secrets.dev.yaml
**/values.dev.yaml
LICENSE
README.md
.gitignore

Plus d’information sur la documentation officielle

Lire les articles similaires

1 commentaire

V. 19 avril 2022 - 16:11 |

Très intéressant, pour l’installation de Docker ainsi que sa mise en pratique.

Répondre

Laisser un commentaire

Social Share Buttons and Icons powered by Ultimatelysocial