Skip to content

Commit 0d0e4d8

Browse files
committed
Initial commit
1 parent 93b4c7b commit 0d0e4d8

19 files changed

Lines changed: 559 additions & 156 deletions
File renamed without changes.

README.md

Lines changed: 32 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,52 @@
1-
# Labspace starter
1+
# Labspace - Compose Quickstart
22

3-
This repository is intended to server as a template to help bootstrap a new Labspace.
3+
An interactive lab that teaches Docker Compose fundamentals by building a multi-container Python Flask and Redis application from scratch. Learners progress from a bare `compose.yaml` through health checks, live development with watch mode, data persistence with volumes, and multi-file Compose configurations.
44

5-
## Instructions
5+
## Learning objectives
66

7-
1. Create a new repository using this repo as the template ([docs here](https://docs.github.com/en/repositories/creating-and-managing-repositories/creating-a-repository-from-a-template)).
7+
This Labspace will teach you the following:
88

9-
**NOTE:** After creating the repo, a GHA workflow will run to do some additional bootstrapping. The bootstrapping workflow file will be removed during bootstrapping.
9+
- Define a multi-service app in a `compose.yaml` file
10+
- Control startup order with health checks and `depends_on`
11+
- Iterate on code quickly using watch mode
12+
- Persist data across container restarts with named volumes
13+
- Compose multi-file configurations with the `include` directive
14+
- Use core debugging commands (`config`, `logs`, `exec`)
1015

11-
2. Clone your newly created repo to your local machine
16+
## Launch the Labspace
1217

13-
3. Start the local development mode:
18+
To launch the Labspace, run the following command:
1419

15-
```bash
16-
# On Mac/Linux
17-
CONTENT_PATH=$PWD docker compose up --watch
20+
```bash
21+
docker compose -f oci://dockersamples/labspace-compose-quickstart up -d
22+
```
1823

19-
# On Windows with PowerShell
20-
$Env:CONTENT_PATH = (Get-Location).Path; docker compose up --watch
21-
```
22-
23-
4. Update the `labspace/labspace.yaml` with your Labspace's title and description
24+
And then open your browser to http://localhost:3030.
2425

25-
5. Write your Labspace! Being in dev mode, your changes should be visible in the interface without a restart. Feel free to edit either on your host machine or in the Labspace itself!
26+
### Using the Docker Desktop extension
2627

27-
Add any supporting application files or resources directly into the Labspace. This repo will be cloned into the Labspace at startup.
28+
If you have the Labspace extension installed (`docker extension install dockersamples/labspace-extension` if not), you can also [click this link](https://open.docker.com/dashboard/extension-tab?extensionId=dockersamples/labspace-extension&location=dockersamples/labspace-compose-quickstart&title=Compose%20Quickstart) to launch the Labspace.
2829

29-
Be sure to check out the [docs](https://github.com/dockersamples/labspace-infra/tree/main/docs) for additional information and guidelines.
30+
## Contributing
3031

32+
If you find something wrong or something that needs to be updated, feel free to submit a PR. If you want to make a larger change, feel free to fork the repo into your own repository.
3133

34+
**Important note:** If you fork it, you will need to update the GHA workflow to point to your own Hub repo.
3235

33-
### Setting up the deployment pipeline
36+
1. Clone this repo
3437

35-
The template repo contains a workflow file to make it easy to publish your Labspace.
38+
2. Start the Labspace in content development mode:
3639

37-
1. Add GitHub Action Secrets in your new repo for the following:
40+
```bash
41+
# On Mac/Linux
42+
CONTENT_PATH=$PWD docker compose up --watch
3843

39-
- `DOCKERHUB_USERNAME` - the username to authenticate to Docker Hub with
40-
- `DOCKERHUB_TOKEN` - a personal or organization access token to use for authentication
44+
# On Windows with PowerShell
45+
$Env:CONTENT_PATH = (Get-Location).Path; docker compose up --watch
46+
```
4147

42-
2. In the `.github/workflows/publish-labspace.yaml.temp` file, update the `DOCKERHUB_REPO` with the name of the Docker Hub repo you want to publish to.
48+
3. Open the Labspace at http://dockerlabs.xyz.
4349

44-
3. Rename the workflow file to remove the `.temp` extension.
50+
4. Make the necessary changes and validate they appear as you expect in the Labspace
4551

46-
```bash
47-
mv .github/workflows/publish-labspace.yaml.temp .github/workflows/publish-labspace.yaml
48-
```
52+
Be sure to check out the [docs](https://github.com/dockersamples/labspace-infra/tree/main/docs) for additional information and guidelines.

compose.override.yaml

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,5 @@ services:
33
environment:
44
PROJECT_CLONE_URL: https://github.com/dockersamples/labspace-compose-quickstart
55

6-
# workspace:
7-
# # Override the default image if desired
8-
# # More details - https://github.com/dockersamples/labspace-infra/blob/main/docs/configuration.md#overriding-the-workspace-image
9-
# image: dockersamples/labspace-workspace-java
10-
11-
# # Override the default ports to publish additional ports you may need
12-
# # More details - https://github.com/dockersamples/labspace-infra/blob/main/docs/configuration.md#overriding-the-workspace-ports
13-
# ports: !override
14-
# - "6274:6274" # Expose the MCP inspector users will launch from inside the Labspace
15-
# - "8080:8080" # The port used by the app
16-
17-
# # Add other environment variables as needed
18-
# environment:
19-
# DANGEROUSLY_OMIT_AUTH: "true" # Skip auth for the MCP Inspector
20-
21-
# Add other models or services your Labspace may need
6+
workspace:
7+
image: dockersamples/labspace-workspace-python

labspace/01-introduction.md

Lines changed: 39 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,49 @@
1-
# Introduction
1+
# Welcome to Docker Compose Quickstart! 🐳
22

3-
👋 Welcome to the **Labspace starter** lab! During this lab, you will learn to do the following:
3+
Docker Compose is a tool for defining and running multi-container applications. Instead of managing each container by hand, you describe your entire application stack in a single `compose.yaml` file and bring everything up with one command.
44

5-
- Learning Objective 1
6-
- Learning Objective 2
7-
- Learning Objective 3
8-
- Learning Objective 4
5+
In this lab, you'll build a **Python Flask web app** backed by **Redis** — a classic multi-container setup. Along the way, you'll learn how to:
96

7+
- Define services in a `compose.yaml` file
8+
- Control startup order with health checks
9+
- Iterate on code quickly with watch mode
10+
- Persist data across container restarts
1011

11-
## 🙋 What is a Labspace again?
12+
## Verify your environment
1213

13-
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis lacinia nisi sit amet auctor accumsan. Maecenas suscipit, libero quis ullamcorper pulvinar, dolor nisl vehicula orci, vel egestas arcu nibh eget enim.
14+
Before diving in, confirm that Docker and Compose are available:
1415

15-
Suspendisse potenti. Pellentesque eleifend eget ante eu egestas.
16+
```bash
17+
docker version
18+
```
1619

17-
Nunc sit amet dapibus erat. Aliquam diam arcu, fringilla hendrerit metus sed, pellentesque fringilla lacus.
20+
```bash
21+
docker compose version
22+
```
1823

19-
Nulla ornare nulla risus. Curabitur ut ipsum euismod, accumsan lorem eu, pretium lorem. Fusce imperdiet fermentum hendrerit.
24+
You should see version information for both. If either command fails, the environment may need a moment to initialize — try again in a few seconds.
2025

26+
## Tour the starter files
2127

28+
The project already contains everything needed to build and run the app. Take a look:
29+
30+
```bash
31+
ls -la
32+
```
33+
34+
| File | Purpose |
35+
|------|---------|
36+
| `app.py` | The Flask web application |
37+
| `requirements.txt` | Python dependencies |
38+
| `Dockerfile` | Instructions to build the container image |
39+
| `.env` | Default environment variable values |
40+
| `.dockerignore` | Files to exclude from the build context |
41+
42+
Open :fileLink[app.py]{path="app.py"} to see the application code. It's a simple hit counter that increments a value in Redis each time someone visits the page, and reports the total back to the browser.
43+
44+
Open :fileLink[Dockerfile]{path="Dockerfile"} to see how the image is built. It starts from the official `python:3.12-alpine` base, installs dependencies, copies the source code, and runs Flask.
45+
46+
> [!NOTE]
47+
> Notice that `.env` is listed in `.dockerignore`. This prevents the `.env` file from being copied into the container image during `docker build` — a good security practice, since `.env` files often contain secrets.
48+
49+
In the next section, you'll connect these pieces together using Docker Compose.

labspace/02-defining-services.md

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
# Defining Services with Compose
2+
3+
A `compose.yaml` file is where you declare every service that makes up your application, along with its configuration: which image to use, which ports to expose, environment variables, and more.
4+
5+
## Creating your Compose stack
6+
7+
Your app needs two services:
8+
9+
- **web** — the Flask app, built from your local `Dockerfile`
10+
- **redis** — the official Redis image for storing the hit count
11+
12+
```mermaid
13+
flowchart LR
14+
web["Flask app<br>(web)"] --> redis["Redis<br>(redis)"]
15+
```
16+
17+
&nbsp;
18+
19+
1. Create a `compose.yaml` file with the following contents:
20+
21+
```yaml save-as=compose.yaml
22+
services:
23+
web:
24+
build: .
25+
ports:
26+
- "${APP_PORT:-8000}:5000"
27+
environment:
28+
- REDIS_HOST=${REDIS_HOST:-redis}
29+
- REDIS_PORT=${REDIS_PORT:-6379}
30+
31+
redis:
32+
image: redis:alpine
33+
```
34+
35+
> [!TIP]
36+
> Compose automatically loads variables from your `.env` file. The `${VAR:-default}` syntax uses the value from `.env` if present, otherwise falls back to the hardcoded default. This lets you override settings without modifying the Compose file.
37+
38+
2. Start the stack using the `docker compose up` command:
39+
40+
```bash
41+
docker compose up --build -d
42+
```
43+
44+
The `--build` flag ensures the `web` image is (re)built from your `Dockerfile` before starting. The `-d` flag runs everything in the background (detached mode).
45+
46+
3. Check that both services are running:
47+
48+
```bash
49+
docker compose ps
50+
```
51+
52+
You should see output similar to the following:
53+
54+
```console no-copy-button no-run-button
55+
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
56+
project-redis-1 redis:alpine "docker-entrypoint.s…" redis 5 seconds ago Up 4 seconds 6379/tcp
57+
project-web-1 project-web "flask run --host=0.…" web 5 seconds ago Up 4 seconds 0.0.0.0:8000->5000/tcp, [::]:8000->5000/tcp
58+
```
59+
60+
4. View the app by opening your browser to :tabLink[http://localhost:8000]{href="http://localhost:8000" title="Flask App" id="app"}
61+
62+
5. Refresh the page a few times — the counter increments with every visit!
63+
64+
## Explore some Compose commands
65+
66+
Check the logs from the web service:
67+
68+
```bash
69+
docker compose logs web
70+
```
71+
72+
Stop and remove the containers (and the default network Compose created):
73+
74+
```bash
75+
docker compose down
76+
```
77+
78+
Run `docker compose ps` again — the containers are gone. The image you built is still cached, so the next startup will be faster.
79+
80+
> [!IMPORTANT]
81+
> Notice that the hit counter resets to 1 when you bring the app back up. Redis stores data inside the container's writable layer, and that layer disappears when the container is removed. You'll fix this with named volumes in a later section.

labspace/02-main-content.md

Lines changed: 0 additions & 68 deletions
This file was deleted.

labspace/03-conclusion.md

Lines changed: 0 additions & 18 deletions
This file was deleted.

labspace/03-health-checks.md

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# Health Checks & Startup Order
2+
3+
Right now, your `web` service starts at roughly the same time as `redis`. But what if Redis isn't ready to accept connections when Flask first tries to connect? The `web` container crashes before it can serve a single request.
4+
5+
This is a **startup race condition**, and it's a common issue in multi-container applications.
6+
7+
## The solution: healthcheck + depends_on
8+
9+
Docker Compose can wait for one service to become *healthy* before starting another. You need two things:
10+
11+
1. A **healthcheck** on `redis` that actively tests whether it's ready to accept connections
12+
2. A `depends_on` condition on `web` that waits until `redis` is healthy
13+
14+
Update your Compose file to add both the `depends_on` and `healthcheck` configurations:
15+
16+
```yaml save-as=compose.yaml highlight=9-11,15-19
17+
services:
18+
web:
19+
build: .
20+
ports:
21+
- "${APP_PORT:-8000}:5000"
22+
environment:
23+
- REDIS_HOST=${REDIS_HOST:-redis}
24+
- REDIS_PORT=${REDIS_PORT:-6379}
25+
depends_on:
26+
redis:
27+
condition: service_healthy
28+
29+
redis:
30+
image: redis:alpine
31+
healthcheck:
32+
test: ["CMD", "redis-cli", "ping"]
33+
interval: 5s
34+
timeout: 5s
35+
retries: 5
36+
```
37+
38+
The healthcheck runs `redis-cli ping` every 5 seconds. Once Redis responds with `PONG`, it's considered healthy — and only then will `web` start.
39+
40+
## See it in action
41+
42+
1. Start the application:
43+
44+
```bash
45+
docker compose up --build -d
46+
```
47+
48+
2. Watch the startup sequence:
49+
50+
```bash
51+
docker compose ps
52+
```
53+
54+
The `redis` service will show `(healthy)` in its status before `web` finishes starting. This guarantees correct startup order every time, regardless of machine speed.
55+
56+
3. Visit the app to confirm everything is working by going to :tabLink[http://localhost:8000]{href="http://localhost:8000" title="Flask App" id="app"}
57+
58+
> [!TIP]
59+
> The `depends_on` field supports three conditions:
60+
>
61+
> - `service_started` — the container has been created (the default)
62+
> - `service_healthy` — the container's healthcheck is passing
63+
> - `service_completed_successfully` — the container exited with code 0 (useful for database migration init containers)

0 commit comments

Comments
 (0)