Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Docker compose example #7

Merged
merged 1 commit into from
Aug 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -54,5 +54,10 @@ jobs:
docker load --input /tmp/uv-docker-example.tar
docker image ls -a

- name: Test image
run: ./run.sh
- name: Test command line
run: ./run.sh hello

- name: Test Docker compose
run: |
docker compose up --watch -d
docker compose down
6 changes: 4 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,7 @@ RUN uv sync --frozen
# Place executables in the environment at the front of the path
ENV PATH="/app/.venv/bin:$PATH"

# Set the default command to the application
CMD ["hello"]
# Run the FastAPI application by default
# Uses `fastapi dev` to enable hot-reloading when the `watch` sync occurs
# Uses `--host 0.0.0.0` to allow access from outside the container
CMD ["fastapi", "dev", "--host", "0.0.0.0", "src/uv_docker_example"]
31 changes: 23 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,27 @@ A [`run.sh`](./run.sh) utility is provided for quickly building the image and st
This script demonstrates best practices for developing using the container, using bind mounts for
the project and virtual environment directories.

To run the application in the container:
To build and run the web application in the container using `docker run`:

```console
$ ./run.sh
```

To run the application in the container, checking if the environment is up-to-date first:
Then, check out [`http://localhost:8000`](http://localhost:8000) to see the website.

To build and run the web application using Docker compose:

```
docker compose up --watch
```

To run the command-line entrypoint in the container:

```console
$ ./run.sh uv run hello
$ ./run.sh hello
```

To check that the environment is up-to-date:
To check that the environment is up-to-date after image builds:

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

### Docker compose file

The [compose.yml](./compose.yml) file includes a Docker compose definition for the web application.
It includes a [`watch`
directive](https://docs.docker.com/compose/file-watch/#compose-watch-versus-bind-mounts) for Docker
compose, which is a best-practice method for updating the container on local changes.

### Application code

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

### Project definition

The project at [`pyproject.toml`](./pyproject.toml) includes includes Ruff as an example development
dependency and defines a `hello` entrypoint for the application.
The project at [`pyproject.toml`](./pyproject.toml) includes Ruff as an example development
dependency, includes FastAPI as a dependency, and defines a `hello` entrypoint for the application.
25 changes: 25 additions & 0 deletions compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
services:
web:
# Build the image from the Dockerfile in the current directory
build: .

# Host the FastAPI application on port 8000
ports:
- "8000:8000"

develop:
# Create a `watch` configuration to update the appl
# https://docs.docker.com/compose/file-watch/#compose-watch-versus-bind-mounts
watch:
# Sync the working directory with the `/app` directory in the container
- action: sync
path: .
target: /app
# Exclude the project virtual environment — it could be for a
# different platform in the container
ignore:
- .venv/

# Rebuild the image on changes to the `pyproject.toml`
- action: rebuild
path: ./pyproject.toml
5 changes: 4 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.11"
dependencies = []
dependencies = [
"fastapi>=0.112.2",
]

[build-system]
requires = ["hatchling"]
Expand All @@ -16,4 +18,5 @@ hello = "uv_docker_example:hello"
[tool.uv]
dev-dependencies = [
"ruff>=0.6.2",
"fastapi-cli>=0.0.5",
]
2 changes: 2 additions & 0 deletions run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
# --rm Remove the container after exiting
# --volume .:/app Mount the current directory to `/app` so code changes don't require an image rebuild
# --volume /app/.venv Mount the virtual environment separately, so the developer's environment doesn't end up in the container
# --expose Expose the web server port 8000 to the host
# -it $(docker build -q .) Build the image, then use it as a run target
# $@ Pass any arguments to the container

Expand All @@ -22,6 +23,7 @@ docker run \
--rm \
--volume .:/app \
--volume /app/.venv \
--publish 8000:8000 \
$INTERACTIVE \
$(docker build -q .) \
"$@"
12 changes: 11 additions & 1 deletion src/uv_docker_example/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,12 @@
from fastapi import FastAPI

app = FastAPI()


def hello() -> str:
print("Hello from uv-docker-example!")
print("Hello world")


@app.get("/")
async def root():
return "Hello world"
Loading