Get Started
Get Started
本节代码参见compose-test
1. Prerequisites
首先安装 Docker Compose
,
$ pacman -S docker-compose
2. Setup
Define the application dependencies
Create a directory for the proejct:
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)
Create a file
app.py
: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)
In this example,
redis
is the hostname of the redis container on the application’s network. We use the default port for Redis,6379
.Handling transient errors
Note the way the
get_hit_count
function is written. This basic retry loop lets us attempt our request multiple times if the redis service is not available. This is useful at startup while the application comes online, but also makes our application more resilient if the Redis service needs to be restarted anytime during the app’s lifetime. In a cluster, this also helps handling momentary connection drops between nodes.Create file
requirements.txt
:flask redis
3. Create a Dockerfile
Write a Dockerfile that builds a Docker image. The imge contains all the dependencies the Python application requires, including Python iteself.
In project directory, create a file Dockerfile
:
FROM python:3.7-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"]
This tells Docker to:
- Build an image starting with Python 3.7 image
- Set the working directory to
/code
(会自动创建) - Set environment variables used by the
flask
command - Install gcc and other dependencies
- Copy
requirements.txt
and install the Python dependencies - Add metadata to the image to describe that the container is listening on port 5000
- Copy the current directory
.
in the project to the workdir.
in the image - Set the default command for the container to
flask run
4. Define services in a Compose file
Create a file docker-compose.yml
version: "3.9"
services:
web:
build: .
ports:
- "5000:5000"
redis:
image: "redis:alpine"
This Compose file defines two services: web
and redis
4.1 Web service
The web
service uses an image that’s build from the Dockerfile
in the current directory. It then binds the container and the host machine to the exposed port 5000 (the default port for the flask web server)
4.2 Redis service
The redis
service uses a public Redis imges redis:alpine
5. Build and run your app with Compose
From the project directory, start up app by running
docker compose up
$ docker compose up
Compose pull a Redis iamge, builds an image for you code, and starts the services you defined. In this case, the code is statically copied into the image at build time
Use curl to test
$ curl http://localhost:5000/ Hello World! I have been seen 3 times.
Switch to another terminal window, and type
docker image ls
$ docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE docker-compose-get-started_web latest da30493291c0 About an hour ago 183MB python 3.7-alpine a1034fd13493 2 weeks ago 41.8MB redis alpine 3900abf41552 2 weeks ago 32.4MB
Stop the application, either by running
docker-compose down
from within your project directory in the second terminal, or by hitting CTRL+C in the original terminal where you started the app$ docker compose down [+] Running 3/3 ⠿ Container docker-compose-get-started-web-1 Removed 10.3s ⠿ Container docker-compose-get-started-redis-1 Removed 0.2s ⠿ Network docker-compose-get-started_default Removed 0.1s
可以看到使用 docker compose down
之后会将 container
和 network
删除,若使用 CTRL+C 只会删除容器而网络将不会被删除
6. Edit the Compose file to add a bind mount
Edit docker-compose.yml
ito add a bind mount for the web
service:
version: "3.9"
services:
web:
build: .
ports:
- "5000:5000"
volumes:
- .:/code
environment:
FLASK_ENV: development
redis:
image: "redis:alpine"
The volumes
key mounts the project directory on the host to /code
inside the container, allowing you to modify the code on the fly, without having to rebuild the image. The environment
key sets the FLASK_NEW
environment variable, which tells flask run
to run in development mode and reload the code on change. This mode should only be used in development
7. Re-build and run the app with Compose
From project directory, run docker compose up
$ docker compose up
8. Update the application
Because the application code is now mounted into the container using a volume, you can make changes to its code and see the changes instantly, without having to rebuild the image.
Change the greeting in app.py
and save it. For example, change the Hello World!
message to Hello from Docker!
:
return 'Hello from Docker! I have been seen {} times.\n'.format(count)
$ curl 'http://localhost:5000'
Hello from Docker! I have been seen 1 times.
9. Experiment with some other commands
You can pass the -d
flag (detached
mode ) to docker compose up
and use docker compose ps
to see what is currently running:
$ docker compose up -d
# ...
$ docker compose ps
NAME COMMAND SERVICE STATUS PORTS
docker-compose-get-started-redis-1 "docker-entrypoint.s…" redis running 6379/tcp
docker-compose-get-started-web-1 "flask run" web running 0.0.0.0:5000->5000/tcp, :::5000->5000/tcp
The docker compose run
command allows you to run one-off commands for your services. For example, to see what environment variables are available to the web
service
$ docker compose run web env
If you started Compose with docker compose up -d
, stop your services once you’ve finished with them
$ docker compose stop
You can bring everything down, removing the containers entirely, with the down
command. Pass --volumes
to also remove the data volume used by the Redis container
$ docker compose down --volumes