Until API made with Flask + MySQL is converted to Docker

this is?

I want to create an API. I want to make it with Flask + MySQL. And I want to make it Docker. Make a note of this procedure. I personally don't know how to make it Docker, so I will concentrate on this.

things to do

  1. Create a simple API with Flask alone.
  2. Convert 1 to Docker.
  3. Prepare MySQL.
  4. Allow Flask and MySQL to work together with docker-compose.

1. Create a simple API with Flask alone.

First, create a simple API because anything is fine. This time, I decided to make a list that returns only the data that meets the conditions from the member list (provisional).

From the file below, create a feature where prefecture returns a list of mail_addresses that match the parameters of the request.

{personal_info.csv}


mail_address,sex,age,name,prefecture
[email protected],male,18,itirou,tokyo
[email protected],male,23,zirou,osaka
[email protected],male,31,saburou,tokyo
[email protected],female,29,itiko,tokyo
[email protected],mail,11,shirou,osaka
[email protected],female,42,fumiko,tokyo

The code using Flask is here.

It's super easy, run app.py, add? Pref = xxx to http://127.0.0.1:5000/, and mail_address matching pref = xxx will be returned in the list.

スクリーンショット 2020-01-02 20.43.38.png スクリーンショット 2020-01-02 20.43.26.png スクリーンショット 2020-01-02 20.43.51.png

Next, make this API Docker.

2. Convert 1 to Docker.

"Making Docker" aims to create a Docker file, docker build to create a Docker image, and execute app.py in the container with docker run to create a state where API requests are thrown.

A Dockerfile describes the operation of "specifying the base image, describing the settings of the container to be created, and executing the command in the container" for the container you want to create.

2-1 Specify the base image

I just want to be able to run flask in python, so I'll base it on a python image.

2-2 Describe the container settings

To run the flask code, you need the following:

--Place local source code and data in a container. --Install the required libraries.

2-3 Execute the command in the container.

Execute the created app.py.

The Dockerfile created with these 2-1 to 2-3 in mind is as follows.

# 2-1 Specify the base image
FROM python:3.6  
# 2-2 Describe the container settings
ARG work_dir=/work  #Creating variables to handle in Dockerfile
ADD pure_flask $work_dir/pure_flask  #the code/work/Copy to(Note that when copying a directory, you must write the directory name on the right side.)

WORKDIR $work_dir/pure_flask  #  cd work_directory image

RUN pip install -r requirements.txt  # requirements.Install the required libraries with txt
# 2-3 Execute the command in the container
CMD ["python", "/work/pure_flask/app.py"]   #There is basically only one CMD in the Dockerfile.

requirements.txt is super easy to describe only flask.

{requirements.txt}


flask

Execute docker build -t flask: ver1 . in the directory containing the Dockerfile in this state. The above command. Refers to building an image using the Dockerfile in the current directory.

Then run docker run -it -d -p 5000: 5000 flask: ver1. -d points to background execution, -p 5000: 5000 points to local port 5000 and port forwarding on container port 5000.

In this state, if you check with a browser at localhost: 5000 on the local machine, you can check the return of the API.

スクリーンショット 2020-01-03 11.01.41.png

By the way, in this state, docker ps and docker images are as follows. If nothing is displayed with docker ps, it may be an error, so you may understand the reason by doing docker logs [container ID] using the container ID displayed with docker ps -a. ..

$ docker ps
> CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
> dc371c597cef        flask:ver1          "python /work/pure_f…"   9 minutes ago       Up 9 minutes        0.0.0.0:5000->5000/tcp   quizzical_margulis
$ docker images
> REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
> flask               ver1                b4cda0e56563        9 minutes ago       923MB
> python              3.6                 138869855e44        5 days ago          913MB

Safely, 1. I was able to confirm the same operation on Docker as I made a simple API with Flask alone.

Next, get ready to use MySQL.

3. Prepare MySQL.

MySQL is also prepared with Docker. This time, I will also use Docker-compose.yaml at the same time.

Docker-compose.yaml is similar to Dockerfile, but for describing the linkage of multiple containers. Since DB is supposed to be connected, I think it is natural to write it in Docker-compose.

3-1 Specify the base image

I want to use MySQL, so I will base it on the image of MySQL.

3-2 Describe the container settings

Initialize the MySQL configuration file and database.

3-3 Execute the command in the container.

Start a MySQL process.

The Dockerfile is below.

# 3-1 Specifying the base image
FROM mysql:5.7

# 3-2 Describe the container settings
COPY conf.d/mysql.cnf /etc/mysql/conf.d/mysql.cnf  #Set of character code settings
COPY initdb.d/init.sql /docker-entrypoint-initdb.d/init.sql  #Set of SQL files for initialization

The config file and init.sql copied in the Dockerfile are as follows.

{mysql.cnf}


[mysqld]
character-set-server=utf8

[mysql]
default-character-set=utf8

[client]
default-character-set=utf8

{init.sql}


CREATE TABLE `personal_info` (
    mail_address VARCHAR(100) NOT NULL,
    sex VARCHAR(6) NOT NULL,
    age INT NOT NULL,
    name VARCHAR(50) NOT NULL,
    prefecture VARCHAR(50) NOT NULL,
    createdAt DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updatedAt DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    PRIMARY KEY (mail_address)
);

INSERT INTO `personal_info` (mail_address, sex, age, name, prefecture, createdAt, updatedAt)
VALUES
('[email protected]', 'male',   18, 'ichirou1' , 'tokyo', current_timestamp(), current_timestamp()),
('[email protected]', 'male',   23, 'zirou2', 'osaka', current_timestamp(), current_timestamp()),
('[email protected]', 'male',   31, 'saburou', 'tokyo', current_timestamp(), current_timestamp()),
('[email protected]', 'female', 29, 'itiko', 'tokyo', current_timestamp(), current_timestamp()),
('[email protected]', 'mail',   11, 'shirou', 'osaka', current_timestamp(), current_timestamp()),
('[email protected]', 'female', 42, 'fumiko', 'tokyo', current_timestamp(), current_timestamp());

docker-compose.yaml is below.

version: '3'  # docker-compose.Description version of yaml
services:  
  db:  
    build: mysql  #Specify Dockerfile under mysql directory
    container_name: db_server  #The name of the Docker container
    ports:
      - '3306:3306'  #Specify port forwarding
    environment:  #Setting environment variables
      MYSQL_ROOT_PASSWORD: pass  #MySQL root user password
      MYSQL_DATABASE: testdb     #MySQL schema
      TZ: Asia/Tokyo             #Specifying the time zone
    volumes:  #Volume mount for persisting MySQL data
      - db-data/:/var/lib/mysql
    # 3-3 Execute the command in the container
    command: mysqld  #Executing the mysqld command
volumes:
  db-data:

Once you have done the above, start the db container with docker-compose up -d. After that, log in with docker exec -it [container ID] / bin / bash, enter the password from mysql -u root -p to check the table, and if the contents of init.sql are included, it's OK. ..

[Remarks] tips around mysql

If the data is not saved in the volume for persisting the MySQL data, check the volume with docker volume ls on the Docker host, delete it, and then docker-compose up -d.

Copy init.sql to /docker-entrypoint-initdb.d/.

Next, connect flask and MySQL.

4. Allow Flask and MySQL to work together with docker-compose.

Combine the two Docker containers created in 2 and 4. All you need to do to combine them is:

--Flask is also included in docker-compose.yaml. --Allow a connection from flask to MySQL (network). --Allows a connection from flask to MySQL (code).

4-1 flask also put in docker-compose.yaml

Below is the flask container added to MySQL docker-compose.yaml.

version: '3'
services:
  api:
    build: python
    container_name: api_server
    ports:
      - "5000:5000"
    tty: yes
    environment:
      TZ: Asia/Tokyo
      FLASK_APP: app.py
    depends_on:  #The api server starts after the db server is up and running
      - db
    networks:  #Common network specification for connecting api and db
      - app_net
  db:
    build: mysql
    container_name: db_server
    ports:
      - '3306:3306'
    environment:
      MYSQL_ROOT_PASSWORD: pass
      MYSQL_DATABASE: testdb
      TZ: Asia/Tokyo
    volumes:
      - ./db-data:/var/lib/mysql
    command: mysqld
    networks:
      - app_net
volumes:
  db-data:
networks:
  app_net:
    driver: bridge

Describe api as the same hierarchy as db in the hierarchy directly under services.

4-2 Allow connection from flask to MySQL (network).

When starting two containers and connecting between them, it is necessary to handle the two containers on the same network. Add the following to each service in docker-compose.yaml of 4-1.

networks:
      - app_net

This allows you to specify which network each container will use. It means that the two are on the same network. Then, write the following in the top level hierarchy of docker-compose.yaml.

networks:
  app_net:
    driver: bridge

This means creating a docker network, and specifying to create a driver with the bridge specification. Now that the api and db containers are on the same network, you can connect from the api to the db.

4-3 --Allows a connection from flask to MySQL (code).

Fix code and module on flask side. There seem to be various ways to connect to MySQL from python, but this time I used mysqlclient.

Install mysqlclient with pip install mysqlclient and connect with the following code to use it.

import MySQLdb

conn = MySQLdb.connect(user='root', passwd='pass', host='db_server', db='testdb')
cur = conn.cursor()
sql = "select * from personal_info;"
cur.execute(sql)
rows = cur.fetchall()

Tuples are returned to these rows, and tuples with the length of the number of records can be obtained.

{Image of rows.}


(
 (Value in the first column of the first record,Value in the second column of the first record, ...), 
 (Value in the first column of the second record,Value in the second column of the second record, ...),
 (Value in the first column of the third record,Value in the second column of the third record, ...)
)

An image that receives this with python, stores it in a list, and returns it with json.

The modified source is here. Please refer to this for the directory structure and the location of the Dockerfile.

After that, since the number of modules I want to handle with python has increased, add mysqlclient to requirements.txt.

That's it. After starting everything with docker-compose up -d, you can check the result by entering http://0.0.0.0:5000/?pref=osaka etc. locally.

that's all.

Recommended Posts

Until API made with Flask + MySQL is converted to Docker
[With image diagram] Nginx + gunicorn + Flask converted to Docker [Part 2]
[With image diagram] Nginx + gunicorn + Flask converted to Docker [Part 1]
Connect to MySQL with Python within Docker
Output log to console with Flask + Nginx on Docker
Try to make RESTful API with MVC using Flask 1.0.2
How to deploy a web app made with Flask to Heroku
API with Flask + uWSGI + Nginx
SNS Flask (Ajax) made with Flask
I made LINE-bot with Python + Flask + ngrok + LINE Messaging API
From environment construction to deployment for flask + Heroku with Docker
Rubyist tried to make a simple API with Python + bottle + MySQL
A story about adding a REST API to a daemon made with Python
Python script written in PyTorch is converted to exe with PyInstaller
SNS Flask (Model) edition made with Flask
SNS Python basics made with Flask
Until you start Jupyter with Docker
Creating a Flask server with Docker
Persist Flask API server with forever
Build Mysql + Python environment with docker
SNS made with Flask Flask (Blueprint, bcrypt)
Application development with Docker + Python + Flask
Connect to MySQL using Flask SQLAlchemy
I made a music bot using discord.py and Google Drive API (tested with Docker → deployed to Heroku)
Environment maintenance made with Docker (I want to post-process GrADS in Python
Connect to Docker's MySQL container from Flask
Simple Slack API client made with Python
Send CSS compressed to Gzip with Flask
Send data to DRF API with Vue.js
[Python] Quickly create an API with Flask
Serverless face recognition API made with Python
Create a web service with Docker + Flask
Launch Flask application with Docker on Heroku
How to install python3 with docker centos
Create an API to convert PDF files to TIF images with FastAPI and Docker
I tried to automate internal operations with Docker, Python and Twitter API + bonus
Three things I was addicted to when using Python and MySQL with Docker
Build a flask app made with tensorflow and dlib to work on centos7