Docker -- Part Two
Posted on Wed 02 January 2019 in linux
In the first part of the Docker series the basic concepts as well as the installation of the Docker Community Edition (CE) has been discussed.
In the next step, a basic docker image is created that should run a simple web application built on the Python micro-framework Flask.
Prerequisites
Before diving into the creation of the Docker image, first, the minimal Flask web application will be discussed:
To resolve the dependencies of the web application, a requirements.txt
file
is specified that contains the Python modules that are required to run the web
application. It just contains the web framework
Flask itself plus the
Gunicorn (Green Unicorn) a Python-based WSGI
HTTP server.
Flask==1.0.2
gunicorn==19.9.0
Then, the web application itself (myapp.py
) is defined that just returns
'Hello World' when calling the corresponding root URL /
:
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
return "Hello World!"
Apart from this create a wsgi.py
file with the following content is created:
from myapp import app
if __name__ == "__main__":
app.run()
The wsgi.py
can later on easily be called by the gunicorn
WSGI server.
Creating a Dockerfile
Though, there are a couple of pre-defined Docker images that already include a ready-to-use Python environment, here a completely new Docker image is created from scratch that is based on Alpine Linux, a lightweight Linux distribution. This allows, on the one hand, the creation of a fully customizable Docker image and, on the other hand, the required image size can be reduced, in comparison to Debian- or Ubuntu-based Docker images.
FROM alpine:3.8
MAINTAINER Your Name <your.name@example.com>
ENV APP_PATH /myapp
WORKDIR ${APP_PATH}
COPY . ${APP_PATH}
RUN apk update \
&& apk add --no-cache python3 \
&& pip3 install --no-cache-dir --upgrade pip \
&& pip3 install --no-cache-dir -r requirements.txt
EXPOSE 8000
CMD ["gunicorn", "-b 0.0.0.0:8000", "-w 4", "wsgi:app"]
FROM
-- defines the parent Docker image, the newly created image should be based on. Particularly, if multiple instances of the image should be initiated, make sure to choose a small lightweight base image.MAINTAINER
-- defines the maintainer of the image. This is just the contact information of the creator of theDockerfile
.ENV
-- defines environment variables that can be referenced in later commands in the Dockerfile. The environment variables can later on be overridden when adding the argument-e "env_var_name=another_value"
to thedocker
command. This allows an easy adoption of the Docker image.WORKDIR
-- sets the working directory for all following commands, includingRUN
,CMD
,ENTRYPOINT
,COPY
andADD
. The working directory will automatically be created, if it is not existing yet.COPY
-- copies the current directory content to the application path.RUN
-- specifies which commands should be executed in the image. EachRUN
call will create a new layer in the image so that it is recommended to combine the commands in a singleRUN
line to reduce the number of layers.EXPOSE
-- make container port available to the outside world. This information is relevant for the Docker host to access the port of a container.CMD
-- command that is executed in the working directory. Here, the web application is started usinggunicorn
.
Build the prepared Docker image as follows:
docker build -t myapp .
The Dockerfile
in the specified directory (here: .
) is used to create the
Docker image. Make sure to provide a tag using the -t
argument to label the
image with a unique name.
After the successful creation of the container, the image can be run as Docker container as follows:
docker run -p 8000:8080 myapp
The exposed port 8000
of the container will be made available on the Docker
host's port 8080
.
To test if the container is running correctly, point your browser to http://127.0.0.1:8080/.
As a result, a Docker image of approximately 62 MB was created, providing a lightweight way to easily setup a web application.