[PYTHON] Construire un environnement de NGINX + NGINX Unit + MySQL avec Docker

Introduction de Docker

Auparavant, j'ai construit un environnement de NGINX + NGINX Unit + Flask.

Exécutez des applications Web Python avec NGINX + NGINX Unit + Flask

La dernière fois, je l'ai construit avec Vagrant et VirtualBox, mais cette fois je vais le construire avec Docker. Comme précédemment, utilisez NGINX pour le serveur Web, NGINX Unit pour le serveur AP et Flask pour le framework. De plus, cette fois, nous ajouterons MySQL comme base de données et créerons un environnement pour WEB <-> AP <-> DB.

L'image est comme indiqué dans la figure ci-dessous. (À l'origine, le conteneur commence dans l'hôte, mais il est séparé pour plus de clarté)

docker1.png

Nous allons le construire étape par étape, donc si vous voulez voir ce que vous avez fait, veuillez le vérifier sur GitHub.

https://github.com/txkxyx/docker-web

environnement

Nous allons construire dans l'environnement suivant.

--Hôte - OS : macOS Catalina 10.15.3 - Docker : 19.03.5 --Récipient - Python : 3.7.3 - Flask : 1.1.1 - NGINX : 1.17.7 - NGINX Unit : 1.14.0 - MySQL : 8.0.18 - Flask SQLAclchemy : 2.4.1

La structure des répertoires est la suivante.

./web
    |- db                   //Pour DB
    |- nginx                //Pour NGINX
    |- python               //Unité NGINX pour les fichiers source
    |    |- src
    |- docker-compose.yml

Commençons.

Paramètres Dockerfilet et docker-compose

Voici un bref résumé des paramètres utilisés dans Dokerfile et docker-compose.

Paramètres Dockerfile

Consultez la référence officielle de Dockerfile pour plus d'informations.

https://docs.docker.com/engine/reference/builder/

Définir la valeur Aperçu
FROM Spécifiez l'image à utiliser.
WORKDIR Spécifiez le répertoire de travail. Après cette déclaration, le travail est effectué avec le chemin spécifié dans le conteneur.
COPY Copiez le répertoire ou le fichier spécifié de l'hôte vers le conteneur.Conteneur hôtePrécisez dans l'ordre de..dockerignoreLe fichier spécifié dans est exclu.
RUN Exécute la commande spécifiée dans le conteneur actuel. (Commande à exécuter au moment de la construction)
CMD Spécifiez la commande à exécuter au démarrage du conteneur. (Commande à exécuter au démarrage)

paramètres de composition du menu fixe

Voir la référence officielle pour plus de détails.

https://docs.docker.com/compose/compose-file/

Définir la valeur Aperçu
version Version du format de fichier pris en charge par Docker Engine
services Chaque élément qui compose l'application
build Du container pour commencerDockerfileSpécifiez le répertoire où se trouve. Un élément enfant, contexte(Répertoire avec Dockerfile ou URL Github)args(Arguments à transmettre à Dockerfile)Etc. peut être spécifié.
image Spécifiez l'image utilisée par le conteneur à démarrer.
command docker-Commande exécutée lorsque la composition est exécutée
ports Spécifie le port que le conteneur expose.Hôte: ContainerOu spécifiez uniquement le port du conteneur.
expose Spécifiez le port du conteneur qui est exposé uniquement au conteneur à lier. Il ne sera pas publié sur l'hôte.
environment Spécifiez les variables d'environnement du conteneur à démarrer.
volumes Spécifie le répertoire de l'hôte à monter sur le conteneur.hôte:récipientSpécifiez le chemin au format.
container_name Spécifiez le nom du conteneur à démarrer.
depends_on Spécifie les dépendances entre les services. Le nom de service spécifié démarre en premier.

Construire un conteneur DB

Tout d'abord, nous allons construire un conteneur MySQL. L'image ressemble à ceci.

docker2.png

Créez docker-compose.yml.

web/docker-compose.yml


version: "3"

services:
    db:
        image: mysql
        command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
        ports:
            - "33306:3306"
        expose:
            - "3306"
        environment:
            MYSQL_ROOT_PASSWORD: root
            MYSQL_USER: test
            MYSQL_PASSWORD: test
        volumes:
            - ./db/init:/docker-entrypoint-initdb.d
        container_name: app_db

Créez un répertoire ʻinitdans le répertoiredb` et créez createdatabase.sql, comme vous le feriez au démarrage initial du conteneur.

web/db/init/createdatabase.sql


CREATE DATABASE app;
USE app;

CREATE TABLE users(
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(255),
    email VARCHAR(255)
);

INSERT INTO users(name,email) VALUES('sample','[email protected]');
INSERT INTO users(name,email) VALUES('test','[email protected]');
INSERT INTO users(name,email) VALUES('app','[email protected]');

GRANT ALL ON app.* TO test;

Avec les paramètres ci-dessus, démarrez le conteneur MySQL avec docker-compose.

$ docker-compose up
$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                                NAMES
bef9a864276c        mysql               "docker-entrypoint.s…"   4 minutes ago       Up 4 minutes        33060/tcp, 0.0.0.0:33306->3306/tcp   app_db

Si ʻapp_db est affiché dans le résultat de docker ps`, le conteneur a été démarré. Une fois à l'intérieur du conteneur, vérifiez si la base de données a été créée.

$ docker exec -it app_db bash
root@00000000000:/# mysql -u test -p
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| app                |
| information_schema |
+--------------------+
2 rows in set (0.00 sec)
mysql> use app;
mysql> select * from users;
+----+--------+-------------------+
| id | name   | email             |
+----+--------+-------------------+
|  1 | sample | [email protected] |
|  2 | test   | [email protected]     |
|  3 | app    | [email protected]       |
+----+--------+-------------------+
3 rows in set (0.01 sec)

Vous pouvez voir qu'une base de données appelée ʻappa été créée. De plus, vous pouvez voir que la table et les données decreatedatabase.sql` ont été créées. C'est tout pour construire MySQL.

Construire un conteneur AP

Construisez un conteneur en utilisant NGINX Unit comme serveur AP, Python3 comme environnement d'exécution et Flask comme framework. Nous le construirons en nous référant au Document officiel de l'unité NGINX. L'image ressemble à ceci.

docker3.png

Lancement du conteneur NGINX Unit

Tout d'abord, construisez l'environnement de Python3 et Flask à partir de l'image de NGINX Unit. Cela peut être la plus petite unité de l'environnement de développement. Ajoutez Dockerfile au répertoire web / python.

web/python/Dorckerfile


FROM nginx/unit:1.14.0-python3.7

WORKDIR /usr/src/app

COPY src .

RUN apt update && apt install -y python3-pip                               \
    && pip3 install --no-cache-dir -r ./requirements.txt                            \
    && rm -rf /var/lib/apt/lists/* 

CMD ["sleep","infinity"]

À partir du Docker Hub nginx / unit site, utilisez l'image NGINX Unit pour Python 3.7.

Ensuite, créez requirements.txt dans le répertoire web / python / src pour pouvoir installer les bibliothèques en bloc avec pip.

web/python/src/requirements.txt


Flask == 1.1.1
flask-sqlalchemy == 2.4.1
PyMySQL == 0.9.3

Ajoutez les paramètres du conteneur de l'unité NGINX à docker-compose.yml.

docker-compose.yml


version: "3"

services:
    db:
        image: mysql
        ports:
            - "33306:3306"
        expose:
            - "3306"
        environment:
            MYSQL_ROOT_PASSWORD: root
            MYSQL_USER: test
            MYSQL_PASSWORD: test
        volumes:
            - ./db/init:/docker-entrypoint-initdb.d
        container_name: app_db
    #↓ ↓ Addendum
    ap:
        build: ./python
        ports:
            - "8080:8080"
        environment:
            TZ: "Asia/Tokyo"
        container_name: app_ap
        depends_on:
            - db

Le "Dockerfile" créé existe dans le répertoire web / python, spécifiez donc l'emplacement avec build. Le port du serveur doit exposer «8080» à l'hôte. Arrêtez le conteneur Docker en cours d'exécution, puis compilez avec docker-compose build, puis démarrez le conteneur.

$ docker-compose down
$ docker-compose build --no-cache
$ docker-compose up
$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                                NAMES
daf4ddc7c11a        web_ap              "sleep infinity"         41 seconds ago      Up 40 seconds       0.0.0.0:8080->8080/tcp               app_ap
565eb32e6a39        mysql               "docker-entrypoint.s…"   43 seconds ago      Up 41 seconds       33060/tcp, 0.0.0.0:33306->3306/tcp   app_db

Vous pouvez voir que ʻapp_db du conteneur MySQL et ʻapp_ap du conteneur NGINX Unit sont en cours d'exécution. Allez dans le conteneur NGINX Unit et vérifiez si la bibliothèque requirements.txt est installée.

$ docker exec -it app_ap bash
root@00000000000:/# python3 -V
Python 3.7.3
root@00000000000:/# pip3 freeze
Flask==1.1.1
Flask-SQLAlchemy==2.4.1
PyMySQL==0.9.3

En plus des bibliothèques ci-dessus, «SQL Alchemy» et «Jinja2» sont installés. Ceci termine le démarrage du conteneur NGINX Unit. Ensuite, nous allons implémenter Flask.

Implémentation de l'application Flask

Implémentez l'application Flask. Les fichiers et répertoires à créer sont les suivants.

./web
    |- db
    |   |- init
    |       |- createdatabase.sql
    |- nginx  
    |- python
    |   |- src
    |   |   |- app.py ← ajouté
    |   |   |- config.json ← ajouté
    |   |   |- config.py ← ajouté
    |   |   |- run.py ← ajouté
    |   |   |- users.py ← ajouté
    |   |   |- requirements.txt
    |   |   |-modèles ← ajoutés
    |   |       |- list.html ← ajouté
    |   |-Dockerfile ← Mise à jour
    |- docker-compose.yml

Chaque fichier est implémenté comme suit.

config.py

Le premier est «config.py», qui implémente la classe de configuration telle que la destination de la connexion DB. La destination de l'hôte est spécifiée par le nom du conteneur ʻapp_db` du conteneur DB.

web/python/src/config.py



class Config(object):
    '''
    Config Class
    '''
    # DB URL
    SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://test:test@app_db:3306/app?charset=utf8'

app.py

Vient ensuite ʻapp.py, qui lance l'application Flask. Utilisez config.from_object ()pour appeler la classe de configuration de l'application, et utilisezSQLAlchemy ()` pour initialiser l'application Flask afin que SQLAchemy puisse être utilisé.

web/python/src/app.py


from config import Config
from flask import Flask
from flask_sqlalchemy import SQLAlchemy

# Create Flask Application
application = Flask(__name__)

# Set Config Class
application.config.from_object(Config)

# Set DB
db = SQLAlchemy(application)

users.py

Ensuite, créez la classe Model pour la table users. Créez une classe Users qui hérite de la classe db.Model.

web/python/src/users.py


from app import db

class Users(db.Model):
    '''
    Users Table Model
    '''
    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(255))
    email = db.Column(db.String(255))

    def __init__(self,name,email):
        self.name = name
        self.email = email

run.py

Vient ensuite le module de lancement et de routage de l'application Flask run.py. Puisque le fichier modèle est utilisé pour la réponse, spécifiez le fichier modèle et l'objet avec render_template ().

web/python/src/run.py


from app import application
from users import Users
from flask import render_template

@application.route('/list')
def index():
    users = Users.query.order_by(Users.id).all()
    return render_template('list.html', users=users)

if __name__ == '__main__':
    application.run(host='0.0.0.0', port='8080')

list.html

Ensuite, créez un fichier modèle, list.html. Le render_template () passe l'objet ʻusers, donc implémentez-le en utilisant le moteur de template Jinja2`.

web/python/src/templates/list.html


<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Flask Sample</title>
</head>
<body>
    <h1>Flask Sample</h1>
    <table border="1" style="border-collapse: collapse">
        <thead>
            <tr>
                <th >Id</th>
                <th >Name</th>
                <th >EMail</th>
            </tr>
        </thead>
        <tbody>
            {% for user in users %}
                <tr>
                    <td>{{user.id}}</td>
                    <td>{{user.name}}</td>
                    <td>{{user.email}}</td>
                </tr>
            {% endfor %}
        </tbody>
    </table>
</body>
</html>

Dockerfile

Mettez à jour Dockerfile.

web/python/Dorckerfile


FROM nginx/unit:1.14.0-python3.7

WORKDIR /usr/src/app

COPY src .

RUN apt update && apt install -y python3-pip                               \
    && pip3 install --no-cache-dir -r ./requirements.txt                            \
    && rm -rf /var/lib/apt/lists/*
#↓ ↓ Supprimer

config.json

Enfin, ajoutez le fichier de configuration de l'unité NGINX config.json.

web/python/src/config.json


{
  "listeners": {
    "*:8080": {
      "pass": "applications/app"
    }
  },

  "applications": {
    "app": {
      "type": "python",
      "processes": 2,
      "path": "/usr/src/app/",
      "module": "run"
    }
  }
}

C'est tout pour la mise en œuvre.

Construisons puis démarrons le conteneur.

$ docker-compose down
$ docker-compose build --no-cache
$ docker-compose up
$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                                NAMES
daf4ddc7c11a        web_ap              "sleep infinity"         41 seconds ago      Up 40 seconds       0.0.0.0:8080->8080/tcp               app_ap
565eb32e6a39        mysql               "docker-entrypoint.s…"   43 seconds ago      Up 41 seconds       33060/tcp, 0.0.0.0:33306->3306/tcp   app_db

Après avoir démarré le conteneur ʻapp_ap`, accédez au conteneur et définissez le fichier de configuration de l'unité NGINX.

$ docker exec -it app_ap bash
root@00000000000:/# curl -X PUT --data-binary @config.json --unix-socket /var/run/control.unit.sock http://localhost/config
{
	"success": "Reconfiguration done."
}

Dans votre navigateur, allez sur http: // localhost: 8080 / list et l'écran apparaîtra.

docker4.png

Ceci termine la construction du conteneur AP.

Créer un conteneur Web

Enfin, nous allons construire le conteneur NGINX pour le serveur WEB. Cela configurera NGINX <-> NGINX Unit <-> Flask <-> MySQL.

docker1.png

Les fichiers à ajouter ou à mettre à jour sont les suivants.

./web
    |- db
    |   |- init
    |       |- createdatabase.sql
    |- nginx
    |   |-Dockerfile ← ajouté
    |   |- index.html ← ajouté
    |   |- nginx.conf ← ajouté
    |- python
    |   |- src
    |   |   |- __init__.py
    |   |   |- app.py
    |   |   |- config.json
    |   |   |- config.py
    |   |   |- run.py
    |   |   |- users.py
    |   |   |- requirements.txt
    |   |   |- templates
    |   |       |- index.html
    |   |- Dockerfile
    |- docker-compose.yml ← mise à jour

Commencez par créer la page principale ʻindex.html`.

web/nginx/index.html


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Index</title>
</head>
<body>
    <h1>Index</h1>
    <a href="/list">List</a>
</body>
</html>

Ensuite, créez un Dockerfile pour NGINX.

FROM nginx

WORKDIR /var/www/html

COPY ./index.html ./

CMD ["nginx", "-g", "daemon off;","-c","/etc/nginx/nginx.conf"]

Ensuite, créez un fichier de configuration NGINX. À partir du fichier de configuration présenté dans l'article précédent, modifiez l'hôte du serveur AP pour Docker.

nginx.conf


user  nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}


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  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;
    server_tokens off;

    keepalive_timeout  65;

    #gzip  on;

    upstream unit-python {
        server app_ap:8080; # container_Spécifié par son nom
    }
    server {
        listen 80;
        server_name localhost;

        #Afficher la première page
        location  / {
            root /var/www/html;
        }

        # /lister les routes vers le conteneur AP
        location  /list {
            proxy_pass http://unit-python;
            proxy_set_header Host $host;
        }
    }
}

Enfin, mettez à jour docker-compose.

docker-compose.yml


version: "3"

services:
    db:
        image: mysql
        ports:
            - "33306:3306"
        expose:
            - "3306"
        environment:
            MYSQL_ROOT_PASSWORD: root
            MYSQL_USER: test
            MYSQL_PASSWORD: test
        volumes:
            - ./db/init:/docker-entrypoint-initdb.d
        container_name: app_db

    ap:
        build:
            context: ./python
            args:
                project_directory: "/src/"
        #↓ ↓ mise à jour
        expose:
            - "8080"
        volumes:
            - "./python/src:/projects"
        environment:
            TZ: "Asia/Tokyo"
        container_name: app_ap
        depends_on:
            - db
    #↓ ↓ ajouté
    web:
        build: ./nginx
        volumes:
            - ./nginx/nginx.conf:/etc/nginx/nginx.conf
        ports:
            - "80:80"
        environment:
            TZ: "Asia/Tokyo"
        container_name: "app_web"
        depends_on:
            - ap

Construisons puis démarrons le conteneur.

$ docker-compose down
$ docker-compose build --no-cache
$ docker-compose up
$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                                NAMES
5b0f06b89db4        web_web             "nginx -g 'daemon of…"   2 minutes ago       Up 23 seconds       0.0.0.0:80->80/tcp                   app_web
625f3c025a82        web_ap              "/usr/local/bin/dock…"   2 minutes ago       Up 2 minutes        8080/tcp                             app_ap
fe5bf54411a2        mysql               "docker-entrypoint.s…"   2 minutes ago       Up 2 minutes        33060/tcp, 0.0.0.0:33306->3306/tcp   app_db

Après avoir démarré le conteneur app_ap, accédez au conteneur et définissez le fichier de configuration de l'unité NGINX.

$ docker exec -it app_ap bash
root@00000000000:/# curl -X PUT --data-binary @config.json --unix-socket /var/run/control.unit.sock http://localhost/config
{
	"success": "Reconfiguration done."
}

Si vous accédez à http: // localhost: 80 avec un navigateur, la page principale ʻindex.html` sera affichée. (Non accessible sur le port 8080)

docker5.png

Si vous appuyez sur la Liste liée, la liste.html` de l'application Flask s'affichera.

docker6.png

C'est la fin de la construction de NGINX.

Résumé

J'ai pu créer un environnement de NGINX + NGINX Unit + MySQL avec Docker. Tout ce que vous avez à faire est de créer l'application.

Recommended Posts

Construire un environnement de NGINX + NGINX Unit + MySQL avec Docker
Construire un environnement Mysql + Python avec docker
Créez un environnement de développement Django avec Docker! (Docker-compose / Django / postgreSQL / nginx)
Créer un environnement Jupyter Lab (Python) avec Docker
Créer un environnement Python + uWSGI + Nginx avec Docker
[Linux] Créer un environnement Jenkins avec Docker
[Linux] Construction de l'environnement Docker avec Amazon Linux 2
[Python] Créer un environnement de développement Django avec Docker
Créer un environnement de Nginx + uWSGI + Python (Django) avec docker
Construisez un environnement Python + bouteille + MySQL avec Docker sur RaspberryPi3! [Construction facile]
Construisez un environnement Python + bouteille + MySQL avec Docker sur RaspberryPi3! [Essai et erreur]
Créer un environnement python3 avec ubuntu 16.04
Construire un environnement python avec direnv
Créez un environnement de développement avec Poetry Django Docker Pycharm
[Memo] Construire un environnement de développement pour Django + Nuxt.js avec Docker
[Django] Créez rapidement un environnement de développement de conteneur Django (Docker) avec PyCharm
Créer une application Todo avec Django ① Créer un environnement avec Docker
Créez un environnement LAMP avec Vagrant (Linux + Apache + MySQL + PHP)
Construisez FastAPI + uvicorn + nginx avec docker-compose
Créer un environnement go à l'aide de Docker
Créer un fichier deb avec Docker
Créer un environnement Flask avec Dockerfile + docker-compose.yml
Créer un environnement de notebook IPython avec boot2docker
Reconstruisez l'environnement de développement de Django avec Docker! !! !! !!
[Docker] Créer un environnement pour python (Flask) + GraphQL (graphène) + MySQL (sqlalchemy)
(Remarque) Remarques sur la création de l'environnement TensorFlow + Flask + Nginx avec Docker Compose
[DynamoDB] [Docker] Créer un environnement de développement pour DynamoDB et Django avec docker-compose
Apprentissage de l'historique pour participer au développement d'applications d'équipe avec Python ~ Créer un environnement Docker / Django / Nginx / MariaDB ~
Créez facilement un environnement de développement avec Laragon
Connectez-vous à MySQL avec Python dans Docker
Créez un environnement d'API rapide avec docker-compose
Obtenez un environnement local pour DynamoDB avec Docker
Créer un environnement Python avec Anaconda sur Mac
Environnement de lancement avec LineBot + Heroku + Docker + Python
Créez un environnement virtuel pour python avec pyenv
Créez un environnement Python moderne avec Neovim
Construction d'environnement AI / Machine Learning avec Python
Créez un environnement CentOS Linux 8 avec Docker et démarrez Apache HTTP Server
Créez un environnement LAMP sur votre Docker local
Créer un environnement de développement de langage C avec un conteneur
Hello World avec gRPC / go dans l'environnement Docker
Remarque: préparez l'environnement de CmdStanPy avec docker
Créez un environnement WardPress sur AWS avec Pulumi
Conversion de l'environnement Django en Docker (Docker + Django + Gunicorn + nginx) Partie 2
Construire un environnement d'analyse avec Docker (jupyter notebook + PostgreSQL)
Créer un environnement python avec pyenv sur EC2 (ubuntu)
Créer un environnement de développement Python avec Visual Studio Code
Créez un environnement python avec ansible sur centos6
Créer un environnement de construction python3 avec Sublime Text3
Déployer des applications Django sur Ubuntu + Nginx + MySQL (Build)
Créez un environnement Django avec Vagrant en 5 minutes
Démarrez Nginx avec docker sans Nginx dans CentOS8
[Memo] Créez un environnement virtuel avec Pyenv + anaconda