This article shows you how to use Docker Compose to complete Python Web application development. The application uses the Flask framework and has a click counter in Redis that provides a practical example of how Docker Compose can be applied to a web development scenario. Highlight the key operations that Docker Compose can perform.
You need to install the latest version of Docker Compose first, and have a basic understanding of Docker concept and how Docker works. First create a directory for the project:
mkdir composetest
cd composetest
Create a file named app.py in the project and paste the following command:
import time
import redis
from flask import Flask
app = Flask(__name__)
cache = redis.Redis(host='redis', port=6379)
def get_hit_count():
retries = 5
while True:
try:
return cache.incr('hits')
except redis.exceptions.ConnectionError as exc:
if retries == 0:
raise exc
retries -= 1
time.sleep(0.5)
@app.route('/')
def hello():
count = get_hit_count()
return 'Hello World! I have been seen {} times.\n'.format(count)
The redis default port 6379 is used.
Create another file called requirements.txt in the project directory and add the following command:
flask
Redis
Create a Dockerfile and paste the following code:
# syntax=docker/dockerfile:1
FROM python:3.10-alpine
WORKDIR /code
ENV FLASK_APP=app.py
ENV FLASK_RUN_HOST=0.0.0.0
RUN apk add --no-cache gcc musl-dev linux-headers
COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt
EXPOSE 5000
COPY . .
CMD ["flask", "run", "--debug"]
Note whether the Dockerfile file extension is.txt. Some editors may automatically attach this file extension, causing an error when running the application.
Define the service in the Compose file. Compose simplifies control of the entire application stack, making it easy to manage services, networks and volumes in a single, easy-to-understand YAML configuration file. Create a file called compose.yaml in your project directory and add the following:
services:
web:
build: .
ports:
- "8000:5000"
redis:
image: "redis:alpine"
The Compose file defines two services: web and redis. The web server uses an image Dockerfile built from the current directory. Then bind the container to the host on open port 800. The default port 5000 of the FIask Web server is used. The redis service uses a public image extracted from the Docker Hub registry.
With a single command, you can configure files and start all services. Build and run your application with Compose. From the directory, start the application docker compose up by running it.
docker compose up
Creating network "composetest_default" with the default driver
Creating composetest_web_1 ...
Creating composetest_redis_1 ...
Creating composetest_web_1
Creating composetest_redis_1 ... done
Attaching to composetest_web_1, composetest_redis_1
web_1 | * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
redis_1 | 1:C 17 Aug 22:11:10.480 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
redis_1 | 1:C 17 Aug 22:11:10.480 # Redis version=4.0.1, bits=64, commit=00000000, modified=0, pid=1, just started
redis_1 | 1:C 17 Aug 22:11:10.480 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf
web_1 | * Restarting with stat
redis_1 | 1:M 17 Aug 22:11:10.483 * Running mode=standalone, port=6379.
redis_1 | 1:M 17 Aug 22:11:10.483 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
web_1 | * Debugger is active!
redis_1 | 1:M 17 Aug 22:11:10.483 # Server initialized
redis_1 | 1:M 17 Aug 22:11:10.483 # WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled.
web_1 | * Debugger PIN: 330-787-903
redis_1 | 1:M 17 Aug 22:11:10.483 * Ready to accept connections
Compose pulls the Redis image, builds the image for the code, and starts the definition service. In these cases, the code is statically copied into the image at build time.
To see the application running, type http://localhost:8000/ directly in your browser.
If that doesn't work out, you can always try http://127.0.0.1:8000.
You should see a message in your browser:
Hello World! I have been seen 1 times.
Refresh the page and this number increases:
Hello World! I have been seen 2 times.
Switch to another terminal window and type docker image ls to list the local image, which should return redis and web
docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
composetest_web latest e2c21aa48cc1 4 minutes ago 93.8MB
python 3.4-alpine 84e6077c7ab6 7 days ago 82.5MB
redis alpine 9d8fa9aa0e5b 3 weeks ago 27.5MB
Images can be inspected using docker inspect <tag or id>. Stopping the application can be done either by running docker compose down in the project directory in the second terminal, or by hitting CTRL+C to start the original terminal of the application.
Edit the file watch to use in the compose.yaml project directory so that you can preview the running Compose service, which automatically updates as you edit and save your code:
services:
web:
build: .
ports:
- "8000:5000"
develop:
watch:
- action: sync
path: .
target: /code
redis:
image: "redis:alpine"
In the project directory, type docker compose watch or docker compose up --watch to build and start the application and file monitoring mode.
docker compose watch
[+] Running 2/2
a œ” Container docs-redis-1 Created 0.0 s
a œ” Container docs-web-1 Recreated 0.1 s
Attaching to redis-1, web-1
A ¦ ¿ watch enabled
... Check the Hello World message in your web browser again, and then refresh to see the count increments.
Change the greeting app.py and save it. For example, Hello World! Message changed to Hello from Docker! :
return 'Hello from Docker! I have been