I'm constantly in awe and amazed by Docker's capabilities (specifically docker-compose). After you install Docker engine, you simply run: ```docker docker-compose up -d ``` And you can have a full stack application running, with a consistent runtime and development dependencies, regardless of what operating system or environment you work in. When you use or develop software across different platforms and devices (at one point I had [[05-22_Mindless Consumption|8 different devices]] across Windows / Mac), Docker is a godsend. ## Development Patterns One of the patterns I follow now is to have a base Dockerfile that installs all the drivers and dependencies that I need `Dockerfile` ```docker FROM python:3.12-slim RUN ... WORKDIR /app ``` Build the container image ```bash docker build -t base . ``` And then use that image in downstream applications. If you need to extend the base image with additional packages: ```docker FROM base COPY requirements.txt RUN uv pip install -r requirements.txt COPY . . ``` > [!TIP] > To prevent Docker from caching frequently changing files, place the last line of code at the bottom of the Dockerfile. > > What `COPY . . ` does is that it copies all files and folders on your host system into the container filesystem, and your files and folders are likely to keep changing as you develop your project. Otherwise you can simply use the base image without specifying a build context in docker-compose.yml ```docker services: <service_name>: image: base ```