Skip to content

Commit e635a6b

Browse files
committed
Add Docker compose example
1 parent fe0075e commit e635a6b

File tree

8 files changed

+531
-15
lines changed

8 files changed

+531
-15
lines changed

.github/workflows/ci.yaml

+9-2
Original file line numberDiff line numberDiff line change
@@ -54,5 +54,12 @@ jobs:
5454
docker load --input /tmp/uv-docker-example.tar
5555
docker image ls -a
5656
57-
- name: Test image
58-
run: ./run.sh
57+
- name: Test command line
58+
run: ./run.sh hello
59+
60+
- name: Test Docker compose
61+
run: |
62+
docker compose up --watch -d
63+
# Test the server
64+
curl -f http://localhost:8000
65+
docker compose down

Dockerfile

+4-2
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,7 @@ RUN uv sync --frozen
1919
# Place executables in the environment at the front of the path
2020
ENV PATH="/app/.venv/bin:$PATH"
2121

22-
# Set the default command to the application
23-
CMD ["hello"]
22+
# Run the FastAPI application by default
23+
# Uses `fastapi dev` to enable hot-reloading when the `watch` sync occurs
24+
# Uses `--host 0.0.0.0` to allow access from outside the container
25+
CMD ["fastapi", "dev", "--host", "0.0.0.0", "src/uv_docker_example"]

README.md

+23-8
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,27 @@ A [`run.sh`](./run.sh) utility is provided for quickly building the image and st
1111
This script demonstrates best practices for developing using the container, using bind mounts for
1212
the project and virtual environment directories.
1313

14-
To run the application in the container:
14+
To build and run the web application in the container using `docker run`:
1515

1616
```console
1717
$ ./run.sh
1818
```
1919

20-
To run the application in the container, checking if the environment is up-to-date first:
20+
Then, check out [`http://localhost:8000`](http://localhost:8000) to see the website.
21+
22+
To build and run the web application using Docker compose:
23+
24+
```
25+
docker compose up --watch
26+
```
27+
28+
To run the command-line entrypoint in the container:
2129

2230
```console
23-
$ ./run.sh uv run hello
31+
$ ./run.sh hello
2432
```
2533

26-
To check that the environment is up-to-date:
34+
To check that the environment is up-to-date after image builds:
2735

2836
```console
2937
$ ./run.sh uv sync --frozen
@@ -63,13 +71,20 @@ mounts during container runs.
6371
The [`run.sh`](./run.sh) script includes an example of invoking `docker run` for local development,
6472
mounting the source code for the project into the container so that edits are reflected immediately.
6573

74+
### Docker compose file
75+
76+
The [compose.yml](./compose.yml) file includes a Docker compose definition for the web application.
77+
It includes a [`watch`
78+
directive](https://docs.docker.com/compose/file-watch/#compose-watch-versus-bind-mounts) for Docker
79+
compose, which is a best-practice method for updating the container on local changes.
80+
6681
### Application code
6782

6883
The Python application code for the project is at
69-
[`src/uv_docker_example/__init__.py`](./src/uv_docker_example/__init__.py)it just prints hello
70-
world.
84+
[`src/uv_docker_example/__init__.py`](./src/uv_docker_example/__init__.py)there's a command line
85+
entrypoint and a basic FastAPI application — both of which just display "hello world" output.
7186

7287
### Project definition
7388

74-
The project at [`pyproject.toml`](./pyproject.toml) includes includes Ruff as an example development
75-
dependency and defines a `hello` entrypoint for the application.
89+
The project at [`pyproject.toml`](./pyproject.toml) includes Ruff as an example development
90+
dependency, includes FastAPI as a dependency, and defines a `hello` entrypoint for the application.

compose.yml

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
services:
2+
web:
3+
# Build the image from the Dockerfile in the current directory
4+
build: .
5+
# Host the FastAPI application on port 8000
6+
ports:
7+
- "8000:8000"
8+
# Create a `watch` configuration to update the appl
9+
# https://docs.docker.com/compose/file-watch/#compose-watch-versus-bind-mounts
10+
develop:
11+
watch:
12+
# Sync the working directory with the `/app` directory in the container
13+
- action: sync
14+
path: .
15+
target: /app
16+
# Exclude the project virtual environment — it could be for a
17+
# different platform in the container
18+
ignore:
19+
- .venv/
20+
# Rebuild the image on changes to the `pyproject.toml`
21+
- action: rebuild
22+
path: ./pyproject.toml

pyproject.toml

+4-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ version = "0.1.0"
44
description = "Add your description here"
55
readme = "README.md"
66
requires-python = ">=3.11"
7-
dependencies = []
7+
dependencies = [
8+
"fastapi>=0.112.2",
9+
]
810

911
[build-system]
1012
requires = ["hatchling"]
@@ -16,4 +18,5 @@ hello = "uv_docker_example:hello"
1618
[tool.uv]
1719
dev-dependencies = [
1820
"ruff>=0.6.2",
21+
"fastapi-cli>=0.0.5",
1922
]

run.sh

+2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
# --rm Remove the container after exiting
1010
# --volume .:/app Mount the current directory to `/app` so code changes don't require an image rebuild
1111
# --volume /app/.venv Mount the virtual environment separately, so the developer's environment doesn't end up in the container
12+
# --expose Expose the web server port 8000 to the host
1213
# -it $(docker build -q .) Build the image, then use it as a run target
1314
# $@ Pass any arguments to the container
1415

@@ -22,6 +23,7 @@ docker run \
2223
--rm \
2324
--volume .:/app \
2425
--volume /app/.venv \
26+
--publish 8000:8000 \
2527
$INTERACTIVE \
2628
$(docker build -q .) \
2729
"$@"

src/uv_docker_example/__init__.py

+11-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,12 @@
1+
from fastapi import FastAPI
2+
3+
app = FastAPI()
4+
5+
16
def hello() -> str:
2-
print("Hello from uv-docker-example!")
7+
print("Hello world")
8+
9+
10+
@app.get("/")
11+
async def root():
12+
return "Hello world"

0 commit comments

Comments
 (0)