Build a development environment for Django + MySQL + nginx with Docker Compose

Operating environment and history

--Host environment - macOS Catalina 10.15.6 - VirtualBox 6.1.14 --Guest environment - Ubuntu Server 20.04.1 LTS - Docker 19.03.13 - Docker Compose 1.27.3

So, in order to develop a web application, I would like to build a mass-docker development environment ** Django + MySQL + nginx with Docker.

Directory structure

The initial directory structure is as follows.

app
├── docker-compose.yml
├── mysql
│   ├── Dockerfile
│   └── init.d
│       └── init.sql
├── nginx
│   ├── conf
│   │   └── app_nginx.conf
│   └── uwsgi_params
└── python
    ├── .dockerignore
    ├── Dockerfile
    └── requirements.txt

From this state

By the way, the following is an example of creating an application called "app" with Django. Replace it with the name of the application you want to create.

docker-compose.yml finally looks like this

Let's write the result first. After trial and error, googled and reading books, and fighting ruthless error messages, I finally arrived at docker-compose.yml. Looking back on the long journey, the inner corner of my eyes gets hot.

docker-compose.yml


version: '3.7'

services:
  python:
    build:
      context: ./python
      dockerfile: Dockerfile
    command: uwsgi --socket :8001 --module app.wsgi --py-autoreload 1 --logto /tmp/uwsgi.log
    restart: unless-stopped
    container_name: Django
    networks:
      - django_net
    volumes:
      - ./src:/code
      - ./static:/static
    expose:
      - "8001"
    depends_on:
      - db

  db:
    build:
      context: ./mysql
      dockerfile: Dockerfile
    restart: unless-stopped
    container_name: MySQL
    networks:
      - django_net
    ports:
      - "3306:3306"
    environment:
      MYSQL_ROOT_PASSWORD: "*******"
      TZ: "Asia/Tokyo"
    volumes:
      - app.db.volume:/var/lib/mysql
      - ./mysql/init.d:/docker-entrypont-initdb.d

  nginx:
    image: nginx:1.17
    restart: unless-stopped
    container_name: nginx
    networks:
      - django_net
    ports:
      - "80:80"
    volumes:
      - ./nginx/conf:/etc/nginx/conf.d
      - ./nginx/uwsgi_params:/etc/nginx/uwsgi_params
      - ./static:/static
    depends_on:
      - python

networks:
  django_net:
    driver: bridge

volumes:
  app.db.volume:
    name: app.db.volume

If you abbreviate the composition appropriately, it looks like this. 図1.png

Django settings

Anyway, from Django's settings. Edit `` `Dockerfile``` directly under the "python" directory as follows.

./python/Dockerfile


FROM python:3.8.5
WORKDIR /code
ADD requirements.txt /code/
RUN pip install --upgrade pip && pip install -r requirements.txt
ADD . /code/

First, create a working directory named `code``` and move to it. Add requirements.txt``` to that directory, then install the required packages with `` pip, and finally add `code``` to the container.

So, the packages to install with `pip``` are listed in` requirements.txt``` as follows. This time, you'll need Django itself, uWSGI for socket communication with nginx, and mysqlclient for connecting to MySQL.

:./python/requirements.txt


Django==2.2.12
uwsgi==2.0.18
mysqlclient==1.4.6

By the way, let's also edit .dockerignore. It would be a problem if extra files were put in the container.

:./python/.dockerignore


**/__pycache__
**/.DS_Store
**/.Thumbs.db
**/.git
**/.gitignore

Based on the settings so far, if you set Django in docker-compose.yml, it will be as follows.

docker-compose.yml (excerpt)


python:
  build:
    context: ./python        # docker-compose.Relative path to Dockerfile from yml
    dockerfile: Dockerfile   #Explicit specification that the setting is written in "Dockerfile"
  command: uwsgi --socket :8001 --module app.wsgi --py-autoreload 1 --logto /tmp/uwsgi.log
  restart: unless-stopped    #If the container stops abnormally, restart it
  container_name: Django     #Define container name
  networks:
    - django_net             #Network name "django_Specify "net"
  volumes:
    - ./src:/code            # ./In src/mount code
    - ./static:/static       # ./static/Mount static
  expose:
    - "8001"     #Keep port 8001 open for uwsgi to socket communicate with nginx
  depends_on:
    - db

Setting up uWSGI is confusing, but if you keep the `app.wsgi``` part as `[Django project name] .wsgi```, the rest is magical.

MySQL settings

To be honest, I'm not sure about the MySQL settings. Mostly, I hate RDBs at a level where I can't write queries satisfactorily.

As a result of examining various manuals, it seems that this is a best practice. I don't know.

./mysql/Dockerfile


FROM mysql:5.7
COPY init.d/* /docker-entrypoint-initdb.d/

sql:./mysql/init.d/init.sql


CREATE DATABASE IF NOT EXISTS app_db CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
CREATE USER IF NOT EXISTS 'app_user'@'%' IDENTIFIED BY '[password]';
GRANT ALL PRIVILEGES ON app_db.* TO 'app_user'@'%';
FLUSH PRIVILEGES;

By the way, the app.db (database name) created by the above ``` init.sql``` is required for the setting of `settings.py``` described later. ,So I will not forget.

Based on this setting, if you configure MySQL with `` `docker-compose.yml```, it will look like this:

docker-compose.yml (excerpt)


db:
  build:
    context: ./mysql         # docker-compose.Relative path to Dockerfile from yml
    dockerfile: Dockerfile   #Explicit specification that the setting is written in "Dockerfile"
  restart: unless-stopped    #If the container stops abnormally, restart it
  container_name: MySQL      #Define container name
  networks:
    - django_net             #Network name "django_Specify "net"
  ports:
    - "3306:3306"            #Specify the port number to communicate
  environment:
    MYSQL_ROOT_PASSWORD: "*******"  #Set root password in environment variable
    TZ: "Asia/Tokyo"                #Set the time zone with an environment variable
  volumes:
    - app.db.volume:/var/lib/mysql   #Database volume "app".db.Save to "volume"
    - ./mysql/init.d:/docker-entrypont-initdb.d

Since we decided to save the database to a volume named "app.db.volume", set "volumes".

docker-compose.yml (excerpt)


volumes:
  app.db.volume:
    name: app.db.volume

nginx settings

I'm not sure about the uWSGI settings either. To be honest, I didn't feel like investigating uWSGI. sorry.

It seems that you should set the parameters appropriately as follows. I don't know.

./nginx/uwsgi_params


uwsgi_param  QUERY_STRING       $query_string;
uwsgi_param  REQUEST_METHOD     $request_method;
uwsgi_param  CONTENT_TYPE       $content_type;
uwsgi_param  CONTENT_LENGTH     $content_length;

uwsgi_param  REQUEST_URI        $request_uri;
uwsgi_param  PATH_INFO          $document_uri;
uwsgi_param  DOCUMENT_ROOT      $document_root;
uwsgi_param  SERVER_PROTOCOL    $server_protocol;
uwsgi_param  REQUEST_SCHEME     $scheme;
uwsgi_param  HTTPS              $https if_not_empty;

uwsgi_param  REMOTE_ADDR        $remote_addr;
uwsgi_param  REMOTE_PORT        $remote_port;
uwsgi_param  SERVER_PORT        $server_port;
uwsgi_param  SERVER_NAME        $server_name;

So, it is the setting of nginx, but first you need to open port 8001 for socket communication with uWSGI.

Also, set the listening port of nginx. My setting is number 80, but this is the setting of the virtual machine that runs the container, Set the data flowing through number 80 of the guest (virtual machine) to flow to number 8081 of the host. Is.

Now, if you access "127.0.0.1:8081" on the host browser, you can see the web application that runs on the guest.

conf:./nginx/conf/app_nginx.conf


upstream django {
  ip_hash;
  server python:8001;  #A port for uWSGI to communicate with Django and nginx
}

server {
  listen      80;      #Standby port
  server_name 127.0.0.1;
  charset     utf-8;

  location /static {
    alias /static;
  }
  
  client_max_body_size 75M;
  
  location / {
    uwsgi_pass  django;
    include     /etc/nginx/uwsgi_params;
  }
}

server_tokens off;

Based on this setting, setting nginx in docker-compose.yml gives: Similar to Django's settings, we've mounted `./static``` on` / static```, so static content that Django doesn't handle can be returned with nginx.

docker-compose.yml (excerpt)


nginx:
  image: nginx:1.17         #Get the image of nginx properly
  restart: unless-stopped   #If the container stops abnormally, restart it
  container_name: nginx     #Define container name
  networks:
    - django_net            #Network name "django_Specify "net"
  ports:
    - "80:80"               #Specify the port number to communicate
  volumes:
    - ./nginx/conf:/etc/nginx/conf.d
    - ./nginx/uwsgi_params:/etc/nginx/uwsgi_params
    - ./static:/static      # ./static/Mount static
  depends_on:
    - python

Also, I said that I will use "django_net" so far, but I have not set it at all, so don't forget to set the "networks" item as well.

docker-compose.yml (excerpt)


networks:
  django_net:
    driver: bridge

Django project settings

By the way, all the settings of Docker are completed. All you have to do now is leave the Django console settings.

Let's start the project first.

$ docker-compose run python django-admin.py startproject app .

If you look inside `src``` and `static``` after hitting this command, you should see various files for Django.

Then edit ./src/app/settings.py.

python:./src/app/settings.py


DATABASES = {
    'default': {
        # 'ENGINE': 'django.db.backends.sqlite3',    #Comment out
        'ENGINE': 'django.db.backends.mysql',        #add to
        # 'NAME': os.path.join(BASE_DIR, 'app_db'),  #Comment out
        'NAME': 'app_db',    # init.Confirm that it is the same as the database name that was CREATE by sql
        'USER': 'app_user',  #add to
        'PASSWORD': '*****', #Add (same as the password specified in the environment variable)
        'PORT': '3306',      #add to
        'HOST': 'db',        #add to
    }
}

STATIC_URL = '/static/'   #add to
STATIC_ROOT = '/static/'  #add to

...(Omitted)

LANGUAGE_CODE = 'ja'      #Edit
TIME_ZONE = 'Asia/Tokyo'  #Edit

All you have to do is hit the familiar Django commands with docker-compose.

$ docker-compose run python ./manage.py migrate          #DB migration
$ docker-compose run python ./manage.py createsuperuser  #Administrator settings
$ docker-compose run python ./manage.py collectstatic    #Copy static files

Start and stop the container

Now, let's move the container. Get out, Django!

$ docker-compose up -d

And when I access 127.0.0.1:8081 from the host browser ... スクリーンショット 2020-10-27 21.26.10.png I did it! !! **Hello! Docker! Hello! Django! ** **

To stop the container, do stop.

$ docker-compose stop

Ruthless error messages

By the way, if you put it together in an article like this, it seems to be misunderstood as if I set it as crispy, so I will write down how many twists and turns I went through.

First of all, this error message.

ERROR: The Compose file './docker-compose.yml' is invalid because:
services.pithon.volumes contains an invalid type, it should be an array

I was angry and angry about what was wrong with this, but I couldn't find a direct solution.

Suddenly, I noticed that "it should be array" (it should be an array, but it shouldn't be) is the point, and when I examined the YAML syntax ... Express the array by. Please put a half-width space after "-" "](https://magazine.rubyist.net/articles/0009/0009-YAML.html#%E9%85%8D % E5% 88% 97) is stated.

If you look closely, here,

volumes:
  - ./src:/code

But,

volumes:
  -./src:/code  # 「-There is no half-width space after

It was like this. ** It took me 2 hours to notice this **.

** This fucking calculator! !! Are you a relative's annoying man! !! ** ** This is done because there was only one half-width space. I can't do it anymore. In the first place, I don't like the name "Yamuru". Is it Korean food (that's Namul)?

Then this error message.

Unsupported config option for services.nginx: 'deponds_on'

As you can see from a closer look, `depends_on``` is correct, not `deponds_on```. It's a stupid misspelling, but ** it took me two hours to notice this **.

** This fucking calculator! !! Give back my precious time in life! !! ** ** I don't care about face recognition with deep learning, and I want a smart calculator that gently corrects this kind of human error.

Yes, this error message as well.

ERROR: Service 'nginx' depends on service 'python' which is undefined.

The reason I got this error was because I mistyped `python``` as `pithon``` (see the first error message). ** It took me an hour to notice this **.

** This fucking calculator! !! Your head is a happy set! !! ** ** I'm surprised at the development like a two-frame cartoon, but the cause is in the Dvorak layout, y and i are next to each other. It seems.

Look forward to next time

Now, do you understand how much I hate computers, why I decided to major in machine learning in graduate school, and why both researchers and engineers quit (a story completely different from the purpose of this article).

** It's just right to play as a toy, but I don't feel like making it a job **. In short, he is incompetent by any means. I'm really thankful to you.

At the end, it was a very heart-warming punch line, but next time I would like to create a production environment on AWS. stay tuned.

Recommended Posts

Build a development environment for Django + MySQL + nginx with Docker Compose
Build a simple Docker Compose + Django development environment
Build a PureScript development environment with Docker
Build a Wordpress development environment with Docker
Build a simple Docker + Django development environment
Build a SPA for Laravel 6.2 / Vue.js / Nginx / Mysql / Redis with Docker
Procedure for building a Rails application development environment with Docker [Rails, MySQL, Docker]
Build a development environment for Docker + Rails6 + Postgresql
Build a WordPress development environment quickly with Docker
React + Django + Nginx + MySQL environment construction with Docker
Build a development environment for Docker, java, vscode
[Copy and paste] Build a Laravel development environment with Docker Compose Part 2
Build a local development environment for Rails tutorials with Docker (Rails 6 + PostgreSQL + Webpack)
[Copy and paste] Build a Laravel development environment with Docker Compose Participation
Build a Node.js environment with Docker
Build Rails environment with Docker Compose
Build a web application development environment that uses Java, MySQL, and Redis with Docker CE for Windows
Rails application development environment construction with Docker [Docker, Rails, Puma, Nginx, MySQL]
Build a local development environment for Open Distro for Elasticsearch with multiple nodes using Docker
How to quit Docker for Mac and build a Docker development environment with Ubuntu + Vagrant
Create Rails 6 + MySQL environment with Docker compose
Build a Laravel / Docker environment with VSCode devcontainer
[Win10] Build a JSF development environment with NetBeans
[First team development ②] Build an environment with Docker
Create a Spring Boot development environment with docker
Build a Java development environment with VS Code
Build debug environment on container --Build local development environment for Rails tutorial with Docker-
Creating a java web application development environment with docker for mac part1
I tried to build a Firebase application development environment with Docker in 2020
How to build a Ruby on Rails development environment with Docker (Rails 6.x)
Build a development environment on AWS EC2 with CentOS7 + Nginx + pm2 + Nuxt.js
How to build a Ruby on Rails development environment with Docker (Rails 5.x)
Template: Build a Ruby / Rails development environment with a Docker container (Ubuntu version)
Create a java web application development environment with docker for mac part2
Template: Build a Ruby / Rails development environment with a Docker container (Mac version)
Building an environment for WordPress, MySQL and phpMyAdmin with Docker Compose on EC2
How to build docker environment with Gradle for intelliJ
Easily build a Vue.js environment with Docker + Vue CLI
[Note] Build a Python3 environment with Docker in EC2
Build docker environment with WSL
Build Java development environment with WSL2 Docker VS Code
Build a development environment to create Ruby on Jets + React apps with Docker
Build Rails (API) x MySQL x Nuxt.js environment with Docker
[Environment construction] Build a Java development environment with VS Code!
Try to build a Java development environment using Docker
[2021] Build a Docker + Vagrant environment for using React / TypeScript
Until you build a Nuxt.js development environment with Docker and touch it with VS Code
[Rails] [Docker] Copy and paste is OK! How to build a Rails development environment with Docker
I made a development environment with rails6 + docker + postgreSQL + Materialize.
How to build [TypeScript + Vue + Express + MySQL] environment with Docker ~ Express ~
Build a "Spring Thorough Introduction" development environment with IntelliJ IDEA
How to build Rails, Postgres, ElasticSearch development environment with Docker
Build a Node-RED environment with Docker to move and understand
I tried to create a padrino development environment with Docker
Rails + MySQL environment construction with Docker
Create a Vue3 environment with Docker!
Node.js environment construction with Docker Compose
Build a Tomcat 8.5 environment with Pleiades 4.8
Environment construction with Docker for beginners
Build PlantUML environment with VSCode + Docker
Build environment with vue.js + rails + docker