There are several ways to run a WEB application created with ** Django ** in a ** development / production environment **. Recently, ** Kubernetes ** has become popular and there are many occasions when applications are containerized.
This article describes how to create a ** Docker container ** with a ** Django application ** in a ** development / production environment **.
The environment used in this article is ** CentOS7 **, ** Docker **, ** Django2 series **.
As long as ** Docker ** works, ** Docker container ** works, so there is no problem even if the OS is Windows.
The Docker file used for the development environment is as follows.
This Docker file is based on ** debian: 10 ** and has ** Python ** installed from source code. There is also a ** official Python ** Docker image, so it's okay to use it, but it's configured like this for study.
FROM debian:10
# Install Python3.7.7
WORKDIR /work
ADD ./Python-3.7.7.tar.xz .
WORKDIR Python-3.7.7
RUN apt-get update && apt-get install -y \
gcc \
libbz2-dev \
libssl-dev \
libffi-dev \
libsqlite3-dev \
make \
tk-dev \
zlib1g-dev \
apache2-dev \
python3-dev \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
RUN ./configure --enable-shared && \
make && \
make install && \
make distclean && \
./configure && \
make && \
make altbininstall
# Install with pip
COPY ./requirements.txt .
RUN pip3 install --upgrade pip setuptools
RUN pip3 install --upgrade wheel
RUN pip3 install -r requirements.txt
# Deploy App
WORKDIR /
ADD ./deployfiles.tar.xz .
WORKDIR /myapp
CMD ["python3", "manage.py", "runserver", "0.0.0.0:80"]
FROM debian:10
First, when writing a ** Docker ** file, specify what to use as a ** base **. Here, ** debian: 10 ** is specified.
# Install Python3.7.7
WORKDIR /work
ADD ./Python-3.7.7.tar.xz .
WORKDIR Python-3.7.7
Next is the installation of ** Python **.
** [WORKDIR] 7 ** is a syntax that moves the current directory of the OS. If ** WORKDIR / work ** is specified, a directory called ** work ** will be created directly under the root directory (/) ** (** it will be created if there is no specified directory **), and that is the current. It will be a directory.
** ADD ** can be ** copied / expanded ** to the path on the Docker container by setting the path on the ADD host OS to the path ** on the Docker container. I can do it. ** Unlike [ADD is COPY] 5 **, you can ** decompress compressed files **. Therefore, files such as ** tar ** and ** xz ** should be copied onto ** Docker container ** using ** ADD **.
RUN apt-get update && apt-get install -y \
gcc \
libbz2-dev \
libssl-dev \
libffi-dev \
libsqlite3-dev \
make \
tk-dev \
zlib1g-dev \
apache2-dev \
python3-dev \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
** [RUN] 3 ** can execute commands on the Docker container. I'm using apt-get to install the dependent packages needed to install ** Python **.
** apt-get clean **, ** rm -rf / var / lib / apt / lists / \ *** are running to remove unnecessary caches and files. By removing this, you can keep the ** capacity of the created ** Docker image ** small **.
RUN ./configure --enable-shared && \
make && \
make install && \
make distclean && \
./configure && \
make && \
make altbininstall
The rest are **. / Configure **, ** make **, ** make install **. There are about 4 extra lines, but I've added them to handle errors.
*** I think it's a combination problem **, but when I ran it I had to do this. Maybe it's unnecessary.
# Install with pip
COPY ./requirements.txt .
RUN pip3 install --upgrade pip setuptools
RUN pip3 install --upgrade wheel
RUN pip3 install -r requirements.txt
After installing ** Python **, install the ** Python ** package. Here, use the ** pip ** command to install the packages listed in ** requirements.txt **.
** [COPY is similar to ADD] 5 **, ** COPY Path on host OS Path on Docker container ** Copy files on host OS to path on Docker container I can do it. This is literally just a copy.
After that, upgrade ** pip ** with ** [RUN] 3 ** and install the ** Python ** package based on ** requirements.txt **.
# Deploy App
WORKDIR /
ADD ./deployfiles.tar.xz .
WORKDIR /myapp
CMD ["python3", "manage.py", "runserver", "0.0.0.0:80"]
Finally, add your application ** to the Docker container **.
** deployfiles.tar.xz ** is a compressed directory called ** myapp **, with ** manage.py ** directly under ** myapp **.
** [CMD] 4 ** is the syntax to set the command to be executed when the ** Docker container ** starts. This can be described like a list format of ** Python **, and each element is joined with a single-byte space. In other words, the command looks like this:
CMD ["python3", "manage.py", "runserver", "0.0.0.0:80"]
↓
python3 manage.py runserver 0.0.0.0:80
To build the ** Docker image **, run the following command.
docker build -t test/myapp .
The ** -t ** option is used to tag ** Docker images **. Tagging makes it easier to manage.
At the end of the command, put the path of the ** Docker file **. Here, ** current directory (.) ** is specified.
By default, the file named ** Dockerfile ** is searched from the specified path, so the file name created above is set to ** Dockerfile **.
To check the created image, execute the following command.
docker image ls
To start the ** Docker container ** from the ** Docker image **, run the following command.
docker run --name myapp -d -p 80:80 -v /work/db.sqlite3:/myapp/db.sqlite3 test/myapp:latest
The ** --name ** option names the ** Docker container **. This is useful later if you want to stop, start or delete this ** Docker container **. The name will be unique, so if you give it a name, you can stop, start, or delete it just by specifying the name. If there is no name, specify the container ID.
The ** -d ** option runs the container in ** background **. If you don't add this, the standard output of ** Docker container ** will be displayed on the console. You can exit with ** Ctrl + c **. In most cases, I think it will run in the background, so I'll add it.
The **-p ** option associates the ** host OS port ** with the ** Docker container port **. ** Host OS port: Docker container port **. This time, we're publishing the ** Django ** process using ** port 80 ** of the Docker container, so specify 80.
The ** -v ** option associates the ** host OS volume (Docker volume or file path on the host OS) ** with the ** Docker container file path **. The container does not hold any data when it exits. Therefore, the data you want to keep must be stored externally. ** Recommended is Docker volume **, but because of the development environment ** Save data to the file path of the OS on the host **. Here, ** db.sqlite3 ** is linked from ** host OS ** to ** Docker container **.
** test / myapp ** is the specification of the underlying ** Docker image **. ** latest ** is the version name and will be ** latest ** if you don't specify anything when you build the ** Docker image **. You can check it by referring to the ** TAG ** column output by ** docker image ls **.
To check if it has started normally, execute the following command.
docker ps
If the ** STATUS ** column is ** UP **, it has started normally.
If nothing is output, add ** -a ** to check the stopped process. If you want to check the log of ** Docker container **, execute the following command.
docker logs [Container name or container ID]
Check the error and take corrective action.
Access the public port number of the IP address on the ** host OS ** running ** Docker **.
The ** Docker file ** used for the production environment is as follows.
Unlike the development environment, you cannot start a process with ** python3 manage.py runserver **. It is more stable to run on ** Apache ** etc.
I'm using ** httpd: 2.4 ** as the base here. [** Official Docker image ** of Apache Web Server **] 1.
In order to run ** Django ** on ** Apache **, you need to include a module called ** [mod_wsgi] 2 ** in ** Apache **. Therefore, ** Python ** and ** [mod_wsgi] 2 ** are installed.
FROM httpd:2.4
# Install Python3.7.7
WORKDIR /work
ADD ./Python-3.7.7.tar.xz .
WORKDIR Python-3.7.7
RUN apt-get update && apt-get install -y \
gcc \
libbz2-dev \
libssl-dev \
libffi-dev \
libsqlite3-dev \
make \
tk-dev \
zlib1g-dev \
apache2-dev \
python3-dev \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
RUN ./configure --enable-shared && \
make && \
make install && \
make distclean && \
./configure && \
make && \
make altbininstall
# Install with pip
COPY ./requirements.txt .
RUN pip3 install --upgrade pip setuptools
RUN pip3 install --upgrade wheel
RUN pip3 install -r requirements.txt
# install ModWsgi
WORKDIR /work
ADD ./mod_wsgi-4.7.1.tar.gz .
WORKDIR mod_wsgi-4.7.1
RUN ./configure \
--with-apxs=/usr/local/apache2/bin/apxs \
--with-python=/usr/local/bin/python3.7 && \
make && \
make install
# Set Apache
WORKDIR /usr/local/apache2/conf
COPY ./httpd.conf .
COPY ./server.crt .
COPY ./server.key .
COPY ./wsgi.conf ./extra
COPY ./httpd-ssl.conf ./extra
FROM httpd:2.4
** [httpd: 2.4] 1 ** is specified as the base.
# Install Python3.7.7
WORKDIR /work
ADD ./Python-3.7.7.tar.xz .
WORKDIR Python-3.7.7
RUN apt-get update && apt-get install -y \
gcc \
libbz2-dev \
libssl-dev \
libffi-dev \
libsqlite3-dev \
make \
tk-dev \
zlib1g-dev \
apache2-dev \
python3-dev \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
RUN ./configure --enable-shared && \
make && \
make install && \
make distclean && \
./configure && \
make && \
make altbininstall
Install ** Python ** as you would in the development environment.
# Install with pip
COPY ./requirements.txt .
RUN pip3 install --upgrade pip setuptools
RUN pip3 install --upgrade wheel
RUN pip3 install -r requirements.txt
Install the ** Python ** package based on ** requirements.txt ** with ** pip ** as in the development environment.
# install ModWsgi
WORKDIR /work
ADD ./mod_wsgi-4.7.1.tar.gz .
WORKDIR mod_wsgi-4.7.1
RUN ./configure \
--with-apxs=/usr/local/apache2/bin/apxs \
--with-python=/usr/local/bin/python3.7 && \
make && \
make install
Install ** [mod_wsgi] 2 ** to get ** Django ** working on ** Apache **.
# Set Apache
WORKDIR /usr/local/apache2/conf
COPY ./httpd.conf .
COPY ./server.crt .
COPY ./server.key .
COPY ./wsgi.conf ./extra
COPY ./httpd-ssl.conf ./extra
Finally, copy the ** Apache ** various ** config ** files and ** certificate related ** files.
Similar to the development environment.
To create ** [Docker Volume] 10 **, execute the following command.
docker volume create --name volume-name
** [Docker Volume] 10 ** is created with the name specified by **-name **. This volume is associated with ** Docker container **.
** [Docker Volume] 10 ** has a different lifespan than ** Docker Container **. Even if the ** Docker container ** disappears, ** [Docker volume] 10 ** will continue to exist, so data can be persisted.
To start the ** Docker container ** from the ** Docker image **, run the following command.
docker run --name myapp -d -p 443:443 -v volume-name:/myapp test/myapp
Only the ** -v ** option is different from the development environment. Here, ** [Docker volume] 10 ** is specified instead of ** file path ** on the host OS. ** [Docker volume] 10 ** named ** volume-name ** is associated with ** / myapp ** on ** Docker container **. This will save the data on ** / myapp ** to ** [Docker Volume] 10 **.
Similar to the development environment.
Recommended Posts