Learning paths / Containers / Docker Compose

Try it: app plus database with Compose

Reading · 15 min · Module 6, lesson 2 of 566 min left in this module

Module 6 · Docker ComposeLesson 2 of 5

Goal: Start a web app and a database with Compose, watch the app's health follow the database, and tear the stack down.

3:38 · captions and chapters · narrated with an AI-generated voice
Transcript

Narration uses an AI-generated voice.

[00:00] Where we're going

By the end of this video, you'll start a web app and its database with one command, and watch the app's health follow the database. Here's the stack, from the Compose file in the last lesson. The web service is built from the app folder, and listens on port three thousand. The db service runs Postgres, on port fifty-four thirty-two. It keeps its files in a volume, called db data. And Compose puts both on one private network, where each service's name is its address.

[00:34] Start the stack

In the compose stack folder, list the files. There's the app, the Compose file, and a deploy file for a later lab. Now start the stack. This builds web from the app folder first. Then it runs everything in the background, so you keep your terminal. Watch the order. Compose creates the network, and the volume. Then web waits, until the database passes its health check. Only then does web start. On your first run, this also downloads Postgres, which takes a minute.

[01:09] Ask the app

So, what's running? List the stack's containers. The database is up and healthy, with port fifty-four thirty-two open only inside the stack. And web is up, with port three thousand published on your machine. Only web publishes a port. You reach the database from web, not from your machine. Now ask the app if it's healthy. Two hundred, okay. And the database is connected.

Here's what that took. Your request reached web, on port three thousand. To answer, web opened a connection to the database, by its name, db, and ran a query. The query worked, so the answer came back, connected.

[01:55] Break it, bring it back

Now let's break it. Stop the database, and ask again. Five oh three, service unavailable. The database is unreachable. Check the web logs. The database check failed, because the name db wasn't found. The app is still up. But it can't do its job, so its health check says so. And that five oh three is what a platform acts on.

Start the database again, and ask once more. Connected. And the app didn't restart. It checks the database on every request, so it recovers as soon as the database is back.

[02:32] Tear it down

When you're done, take the whole stack down. The containers go first. Then the image Compose built for web. Because we asked for volumes too, the db data volume goes, with every row in it. Leave that part out, and your data stays for next time. Postgres itself stays. Compose only pulled that image, so it keeps it.

[02:57] Recap

So that's one file, and one command, for the whole stack. Web and db share a network, and find each other by name. The data lives in a volume. And the health check told the truth, the moment the database went away.

Here's a question to check yourself. When the database stopped, the log said not found, not connection refused. Why? A stopped container leaves the stack's network. So its name stops resolving at all. Next, we'll take this stack from Compose to ComputeSphere. I'll see you there.

You need Docker with Compose (set up in lesson 3.1.1), git and curl.

Check your tools, and curl on Windows

Run docker compose version; any v2 or later works. In Windows PowerShell, type curl.exe wherever this lesson says curl.

No git? Download https://github.com/computesphere-samples/learn/archive/refs/heads/main.zip, unzip it, and open learn-main/labs/compose-stack in a terminal.

  1. Get the sample

    git clone https://github.com/computesphere-samples/learn.git
    cd learn/labs/compose-stack
    ls
    

    Already cloned learn in lesson 3.4.5? Skip the clone: from learn/labs/compose-stack/app, where lesson 3.5.3 left you, run cd ... compose.yaml is the file from the last lesson. The deploy file is for the lab after the next lesson.

    You should seeapp, compose.yaml, compose.deploy.yaml and README.md.

  2. Start the stack

    docker compose up --build -d
    

    --build builds web from ./app first, and -d runs the stack in the background so you keep your terminal. The first run downloads Postgres, which takes a minute.

    Port 3000 is already in use?

    Change "3000:3000" under web in compose.yaml to "3001:3000", run the command again, and use port 3001 below. Only the port on your side changes; the app still listens on 3000 inside its container.

    You should seeContainer compose-stack-db-1 Healthy, then Container compose-stack-web-1 Started.

  3. See what's running

    docker compose ps
    

    Only web publishes a port. The database is reachable from web, not from your machine.

    You should seedb Up (healthy) with 5432/tcp, and web Up with 0.0.0.0:3000->3000/tcp.

  4. Ask the app if it's healthy

    curl -i localhost:3000/healthz
    

    To answer, the app opened a connection to db and ran a query.

    You should seeHTTP/1.1 200 OK and {"status":"ok","database":"connected"}

  5. Stop the database

    docker compose stop db
    curl -i localhost:3000/healthz
    docker compose logs web
    

    The app is still up, but it can't do its job, so its health check says so. That 503 is what a platform acts on.

    Check yourself

    The log says ENOTFOUND db, not connection refused. Why?

    You should seeHTTP/1.1 503 Service Unavailable and {"status":"unhealthy","database":"unreachable"}, then a log line ending database check failed: getaddrinfo ENOTFOUND db.

  6. Bring it back

    docker compose start db
    curl localhost:3000/healthz
    

    The app didn't restart. It checks the database on every request, so it recovers as soon as the database is back.

    You should see{"status":"ok","database":"connected"}

  7. Tear it down

    docker compose down -v --rmi local
    

    down removes the containers and the network. -v also deletes the db-data volume and every row in it; leave it off to keep the data for next time. --rmi local removes the web image Compose built, and keeps postgres:16, which it only pulled.

    You should seeEach container Removed, then Image compose-stack-web:latest Removed, Volume compose-stack_db-data Removed and Network compose-stack_default Removed.