GNU/Linux >> Tutoriels Linux >  >> Panels >> Docker

Comment déployer des microservices avec Docker

Qu'est-ce qu'un microservice ?

Les microservices sont une architecture de plus en plus populaire pour la création d'applications à grande échelle. Plutôt que d'utiliser une seule base de code monolithique, les applications sont décomposées en un ensemble de composants plus petits appelés microservices. Cette approche offre plusieurs avantages, notamment la possibilité de mettre à l'échelle des microservices individuels, de faciliter la compréhension et le test de la base de code, et de permettre l'utilisation de différents langages de programmation, bases de données et autres outils pour chaque microservice.

Docker est un excellent outil pour gérer et déployer des microservices. Chaque microservice peut être subdivisé en processus exécutés dans des conteneurs Docker distincts, qui peuvent être spécifiés avec les fichiers de configuration Dockerfiles et Docker Compose. Combiné à un outil de provisionnement tel que Kubernetes, chaque microservice peut ensuite être facilement déployé, mis à l'échelle et développé en collaboration par une équipe de développeurs. La spécification d'un environnement de cette manière permet également de lier facilement des microservices pour former une application plus grande.

Ce guide explique comment créer et déployer un exemple de microservice à l'aide de Docker et Docker Compose.

Avant de commencer

  1. Si vous ne l'avez pas déjà fait, créez un compte Linode et une instance de calcul. Consultez nos guides Premiers pas avec Linode et Création d'une instance de calcul.

  2. Suivez notre guide Configuration et sécurisation d'une instance de calcul pour mettre à jour votre système. Vous pouvez également définir le fuseau horaire, configurer votre nom d'hôte, créer un compte utilisateur limité et renforcer l'accès SSH.

Remarque Ce guide est écrit pour un utilisateur non root. Les commandes qui nécessitent des privilèges élevés sont préfixées par sudo . Si vous n'êtes pas familier avec le sudo commande, vous pouvez consulter notreGuide des utilisateurs et des groupes.

Installer Docker

Pour installer Docker CE (Community Edition), suivez les instructions de l'un des guides ci-dessous :

  • Installation et utilisation de Docker sur Ubuntu et Debian

  • Installation et utilisation de Docker sur CentOS et Fedora

Pour obtenir des instructions complètes sur encore plus de distributions Linux, consultez la section Install Docker Engine de la documentation officielle de Docker.

Installer Docker Compose

  1. Téléchargez la dernière version de Docker Compose. Consultez la page des versions et remplacez 1.25.4 dans la commande ci-dessous avec la version marquée comme Dernière version :

     sudo curl -L https://github.com/docker/compose/releases/download/1.25.4/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
    
  2. Définir les autorisations de fichier :

     sudo chmod +x /usr/local/bin/docker-compose
    

Préparer l'environnement

Cette section utilise Dockerfiles pour configurer les images Docker. Pour plus d'informations sur la syntaxe et les meilleures pratiques de Dockerfile, consultez notre guide How To Use Dockerfiles et le guide Docker's Dockerfile Best Practices.

  1. Créez un répertoire pour le microservice :

     mkdir flask-microservice
    
  2. Créez une structure de répertoires pour les composants du microservice dans le nouveau répertoire :

     cd flask-microservice
     mkdir nginx postgres web
    

NGINX

  1. Dans le nouveau nginx sous-répertoire, créez un Dockerfile pour l'image NGINX :

    Fichier :nginx /Dockerfile
    1
    2
    
    from nginx:alpine
    COPY nginx.conf /etc/nginx/nginx.conf
  2. Créez le nginx.conf référencé dans le Dockerfile :

    Fichier :/ nginx/nginx.conf
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    
    user  nginx;
    worker_processes 1;
    error_log  /dev/stdout info;
    error_log off;
    pid        /var/run/nginx.pid;
    
    events {
        worker_connections  1024;
        use epoll;
        multi_accept on;
    }
    
    http {
        include       /etc/nginx/mime.types;
        default_type  application/octet-stream;
    
        log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                          '$status $body_bytes_sent "$http_referer" '
                          '"$http_user_agent" "$http_x_forwarded_for"';
    
        access_log  /dev/stdout main;
        access_log off;
        keepalive_timeout 65;
        keepalive_requests 100000;
        tcp_nopush on;
        tcp_nodelay on;
    
        server {
            listen 80;
            proxy_pass_header Server;
    
            location / {
                proxy_set_header Host $host;
                proxy_set_header X-Real-IP $remote_addr;
    
                # app comes from /etc/hosts, Docker added it for us!
                proxy_pass http://flaskapp:8000/;
            }
        }
    }

PostgreSQL

L'image PostgreSQL pour ce microservice utilisera le postgresql officiel image sur Docker Hub, aucun Dockerfile n'est donc nécessaire.

Dans le postgres sous-répertoire, créez un init.sql fichier :

Fichier :postgres /init.sql
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
SET statement_timeout = 0;
SET lock_timeout = 0;
SET idle_in_transaction_session_timeout = 0;
SET client_encoding = 'UTF8';
SET standard_conforming_strings = on;
SET check_function_bodies = false;
SET client_min_messages = warning;
SET row_security = off;
CREATE EXTENSION IF NOT EXISTS plpgsql WITH SCHEMA pg_catalog;
COMMENT ON EXTENSION plpgsql IS 'PL/pgSQL procedural language';
SET search_path = public, pg_catalog;
SET default_tablespace = '';
SET default_with_oids = false;
CREATE TABLE visitors (
    site_id integer,
    site_name text,
    visitor_count integer
);

ALTER TABLE visitors OWNER TO postgres;
COPY visitors (site_id, site_name, visitor_count) FROM stdin;
1 	linodeexample.com  	0
\.
Attention À la ligne 22 de init.sql , assurez-vous que votre éditeur de texte ne convertit pas les tabulations en espaces. L'application ne fonctionnera pas sans onglets entre les entrées de cette ligne.

Web

Le web l'image contiendra un exemple d'application Flask. Ajoutez les fichiers suivants au web répertoire pour préparer l'application :

  1. Créez un .python-version fichier pour spécifier l'utilisation de Python 3.6 :

     echo "3.6.0" >> web/.python-version
    
  2. Créer un Dockerfile pour le web image :

    Fichier :Web /Dockerfile
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    
    from python:3.6.2-slim
    RUN groupadd flaskgroup && useradd -m -g flaskgroup -s /bin/bash flask
    RUN echo "flask ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers
    RUN mkdir -p /home/flask/app/web
    WORKDIR /home/flask/app/web
    COPY requirements.txt /home/flask/app/web
    RUN pip install --no-cache-dir -r requirements.txt
    RUN chown -R flask:flaskgroup /home/flask
    USER flask
    ENTRYPOINT ["/usr/local/bin/gunicorn", "--bind", ":8000", "linode:app", "--reload", "--workers", "16"]
  3. Créez web/linode.py et ajoutez l'exemple de script d'application :

    Fichier :Web /linode.py
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    
    from flask import Flask
    import logging
    import psycopg2
    import redis
    import sys
    
    app = Flask(__name__)
    cache = redis.StrictRedis(host='redis', port=6379)
    
    # Configure Logging
    app.logger.addHandler(logging.StreamHandler(sys.stdout))
    app.logger.setLevel(logging.DEBUG)
    
    def PgFetch(query, method):
    
        # Connect to an existing database
        conn = psycopg2.connect("host='postgres' dbname='linode' user='postgres' password='linode123'")
    
        # Open a cursor to perform database operations
        cur = conn.cursor()
    
        # Query the database and obtain data as Python objects
        dbquery = cur.execute(query)
    
        if method == 'GET':
            result = cur.fetchone()
        else:
            result = ""
    
        # Make the changes to the database persistent
        conn.commit()
    
        # Close communication with the database
        cur.close()
        conn.close()
        return result
    
    @app.route('/')
    def hello_world():
        if cache.exists('visitor_count'):
            cache.incr('visitor_count')
            count = (cache.get('visitor_count')).decode('utf-8')
            update = PgFetch("UPDATE visitors set visitor_count = " + count + " where site_id = 1;", "POST")
        else:
            cache_refresh = PgFetch("SELECT visitor_count FROM visitors where site_id = 1;", "GET")
            count = int(cache_refresh[0])
            cache.set('visitor_count', count)
            cache.incr('visitor_count')
            count = (cache.get('visitor_count')).decode('utf-8')
        return 'Hello Linode!  This page has been viewed %s time(s).' % count
    
    @app.route('/resetcounter')
    def resetcounter():
        cache.delete('visitor_count')
        PgFetch("UPDATE visitors set visitor_count = 0 where site_id = 1;", "POST")
        app.logger.debug("reset visitor count")
        return "Successfully deleted redis and postgres counters"
  4. Ajouter un requirements.txt fichier avec les dépendances Python requises :

    Fichier :Web /requirements.txt
    1
    2
    3
    4
    
    flask
    gunicorn
    psycopg2-binary
    redis

Docker Compose

Docker Compose sera utilisé pour définir les connexions entre les conteneurs et leurs paramètres de configuration.

Créez un docker-compose.yml fichier dans le flask-microservice répertoire et ajoutez ce qui suit :

Fichier :menu fixe -compose.yml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
version: '3'
services:
 # Define the Flask web application
 flaskapp:

   # Build the Dockerfile that is in the web directory
   build: ./web

   # Always restart the container regardless of the exit status; try and restart the container indefinitely
   restart: always

   # Expose port 8000 to other containers (not to the host of the machine)
   expose:
     - "8000"

   # Mount the web directory within the container at /home/flask/app/web
   volumes:
     - ./web:/home/flask/app/web

   # Don't create this container until the redis and postgres containers (below) have been created
   depends_on:
     - redis
     - postgres

   # Link the redis and postgres containers together so they can talk to one another
   links:
     - redis
     - postgres

   # Pass environment variables to the flask container (this debug level lets you see more useful information)
   environment:
     FLASK_DEBUG: 1

   # Deploy with three replicas in the case one of the containers fails (only in Docker Swarm)
   deploy:
     mode: replicated
     replicas: 3

 # Define the redis Docker container
 redis:

   # use the redis:alpine image: https://hub.docker.com/_/redis/
   image: redis:alpine
   restart: always
   deploy:
     mode: replicated
     replicas: 3

 # Define the redis NGINX forward proxy container
 nginx:

   # build the nginx Dockerfile: http://bit.ly/2kuYaIv
   build: nginx/
   restart: always

   # Expose port 80 to the host machine
   ports:
     - "80:80"
   deploy:
     mode: replicated
     replicas: 3

   # The Flask application needs to be available for NGINX to make successful proxy requests
   depends_on:
     - flaskapp

 # Define the postgres database
 postgres:
   restart: always
   # Use the postgres alpine image: https://hub.docker.com/_/postgres/
   image: postgres:alpine

   # Mount an initialization script and the persistent postgresql data volume
   volumes:
     - ./postgres/init.sql:/docker-entrypoint-initdb.d/init.sql
     - ./postgres/data:/var/lib/postgresql/data

   # Pass postgres environment variables
   environment:
     POSTGRES_PASSWORD: linode123
     POSTGRES_DB: linode

   # Expose port 5432 to other Docker containers
   expose:
     - "5432"

Tester le microservice

  1. Utilisez Docker Compose pour créer toutes les images et démarrer le microservice :

    cd flask-microservice/ && docker-compose up
    

    Vous devriez voir tous les services démarrer dans votre terminal.

  2. Ouvrez une nouvelle fenêtre de terminal et faites une demande à l'exemple d'application :

    curl localhost
    
    Hello Linode! This page has been viewed 1 time(s).
  3. Réinitialisez le compteur d'accès à la page :

    curl localhost/resetcounter
    
    Successfully deleted redis and postgres counters
  4. Revenez à la fenêtre du terminal où Docker Compose a été lancé pour afficher le journal de sortie standard :

    flaskapp_1  | DEBUG in linode [/home/flask/app/web/linode.py:56]:
    flaskapp_1  | reset visitor count

Utilisation de conteneurs en production :bonnes pratiques

Les conteneurs utilisés dans l'exemple de microservice sont destinés à démontrer les meilleures pratiques suivantes pour l'utilisation de conteneurs en production :

Les conteneurs doivent être :

  1. Éphémère  :Il devrait être facile d'arrêter, de détruire, de reconstruire et de redéployer des conteneurs avec un minimum d'installation et de configuration.

    Le microservice Flask en est un parfait exemple. L'ensemble du microservice peut être activé ou désactivé à l'aide de Docker Compose. Aucune configuration supplémentaire n'est nécessaire après l'exécution des conteneurs, ce qui facilite la modification de l'application.

  2. Jetable :Idéalement, tout conteneur unique dans une application plus grande devrait pouvoir échouer sans affecter les performances de l'application. Utilisation d'un restart: on-failure option dans le docker-compose.yml file, en plus d'avoir un nombre de réplicas, permet à certains conteneurs de l'exemple de microservice d'échouer correctement tout en continuant à servir l'application Web, sans dégradation pour l'utilisateur final.

    Remarque La directive de nombre de répliques ne sera effective que lorsque cette configuration sera déployée dans le cadre d'un Docker Swarm, qui n'est pas couvert dans ce guide.
  3. Démarrage rapide :Éviter les étapes d'installation supplémentaires dans le fichier Docker, supprimer les dépendances inutiles et créer une image cible pouvant être réutilisée sont trois des étapes les plus importantes pour créer une application Web dont le temps d'initialisation est rapide dans Docker. L'exemple d'application utilise des Dockerfiles courts, concis et prédéfinis afin de minimiser le temps d'initialisation.

  4. Arrêt rapide :Valide qu'un docker kill --signal=SIGINT {APPNAME} arrête l'application gracieusement. Ceci, associé à une condition de redémarrage et à une condition de réplique, garantira que lorsque les conteneurs échouent, ils seront remis en ligne efficacement.

  5. Léger :utilisez le plus petit conteneur de base qui fournit tous les utilitaires nécessaires pour créer et exécuter votre application. De nombreuses images Docker sont basées sur Alpine Linux, une distribution Linux légère et simple qui ne prend que 5 Mo dans une image Docker. L'utilisation d'une petite distribution permet d'économiser le réseau et les frais généraux opérationnels, et augmente considérablement les performances du conteneur. L'exemple d'application utilise des images alpines, le cas échéant (NGINX, Redis et PostgreSQL), et une image de base python-slim pour l'application Gunicorn / Flask.

  6. Apatride  :Comme ils sont éphémères, les conteneurs ne doivent généralement pas conserver leur état. L'état d'une application doit être stocké dans un volume de données distinct et persistant, comme c'est le cas avec le magasin de données PostgreSQL du microservice. Le magasin clé-valeur Redis conserve les données dans un conteneur, mais ces données ne sont pas critiques pour l'application ; le magasin Redis reviendra automatiquement à la base de données si le conteneur n'est pas en mesure de répondre.

  7. Portable :toutes les dépendances d'une application nécessaires à l'exécution du conteneur doivent être disponibles localement. Toutes les dépendances et les scripts de démarrage de l'exemple de microservice sont stockés dans le répertoire de chaque composant. Ceux-ci peuvent être vérifiés dans le contrôle de version, ce qui facilite le partage et le déploiement de l'application.

  8. Modulaire :Chaque conteneur doit avoir une responsabilité et un processus. Dans ce microservice, chacun des principaux processus (NGINX, Python, Redis et PostgreSQL) est déployé dans un conteneur séparé.

  9. Journalisation  :Tous les conteneurs doivent se connecter à STDOUT . Cette uniformité facilite la visualisation des journaux de tous les processus dans un seul flux.

  10. Résilient :L'exemple d'application redémarre ses conteneurs s'ils sont fermés pour une raison quelconque. Cela permet de donner à votre application dockerisée une disponibilité et des performances élevées, même pendant les périodes de maintenance.

Plus d'informations

Vous pouvez consulter les ressources suivantes pour plus d'informations sur ce sujet. Bien que ceux-ci soient fournis dans l'espoir qu'ils seront utiles, veuillez noter que nous ne pouvons pas garantir l'exactitude ou l'actualité des documents hébergés en externe.

  • Référentiel Github pour un exemple de microservice
  • Utiliser des conteneurs pour créer une architecture de microservices

Docker
  1. Comment déployer un serveur DNS dynamique avec Docker sur Debian 10

  2. Comment déployer Modsecurity avec Nginx sur Ubuntu 20.04 LTS

  3. Comment installer Jenkins avec Docker

  4. Comment déployer des applications avec Rancher

  5. Comment déployer un conteneur nginx avec Docker sur Linode

Comment déployer Pi-Hole sur Debian 11

Comment déployer des piles Docker Compose sur Kubernetes avec Kompose

Comment déployer CouchDB en tant que cluster avec Docker

Comment déployer Rocket Chat avec Nginx sur Ubuntu 18.04

Comment déployer une application PHP avec Nginx et MySQL à l'aide de Docker et Docker Compose

Comment déployer l'application Laravel avec Nginx sur Ubuntu ?