# Lab: The Containerized SDLC


Build a real Node.js API, then apply containers at every stage of the software
development lifecycle. You'll write a Compose file for local development,
integration tests using Testcontainers, a CI/CD pipeline, and Kubernetes
manifests — using the same container image throughout.

## Launch the lab













<ol>
<li>
<p>Start the labspace:</p>
<div
  data-pagefind-ignore
  x-data
  x-ref="root"
  class="group mt-2 mb-4 flex w-full scroll-mt-2 flex-col items-start gap-4 rounded bg-gray-50 p-2 outline outline-1 outline-offset-[-1px] outline-gray-200 dark:bg-gray-900 dark:outline-gray-800"
>
  
  <div class="relative w-full">
    
    
    <div class="syntax-light dark:syntax-dark not-prose w-full">
      <button
        x-data="{ code: 'JCBkb2NrZXIgY29tcG9zZSAtcCBsYWJzcGFjZSAtZiBvY2k6Ly9kb2NrZXJzYW1wbGVzL2xhYnNwYWNlLWNvbnRhaW5lcml6ZWQtc2RsYyB1cCAtZA==', copying: false }"
        class="
          top-1
         absolute right-2 z-10 text-gray-300 dark:text-gray-500"
        title="copy"
        @click="window.navigator.clipboard.writeText(atob(code).replaceAll(/^[\$>]\s+/gm, ''));
      copying = true;
      setTimeout(() => copying = false, 2000);"
      >
        <span
          :class="{ 'group-hover:block' : !copying }"
          class="icon-svg hidden"
          ><svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 -960 960 960"><path d="M300-200q-24 0-42-18t-18-42v-560q0-24 18-42t42-18h440q24 0 42 18t18 42v560q0 24-18 42t-42 18H300ZM180-80q-24 0-42-18t-18-42v-590q0-13 8.5-21.5T150-760q13 0 21.5 8.5T180-730v590h470q13 0 21.5 8.5T680-110q0 13-8.5 21.5T650-80H180Z"/></svg></span
        >
        <span :class="{ 'group-hover:block' : copying }" class="icon-svg hidden"
          ><svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 -960 960 960"><path d="m421-389-98-98q-9-9-22-9t-23 10q-9 9-9 22t9 22l122 123q9 9 21 9t21-9l239-239q10-10 10-23t-10-23q-10-9-23.5-8.5T635-603L421-389Zm59 309q-82 0-155-31.5t-127.5-86Q143-252 111.5-325T80-480q0-83 31.5-156t86-127Q252-817 325-848.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 82-31.5 155T763-197.5q-54 54.5-127 86T480-80Z"/></svg></span
        >
      </button>
      
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> docker compose -p labspace -f oci://dockersamples/labspace-containerized-sdlc up -d
</span></span></code></pre></div>
      
    </div>
  </div>
</div>
</li>
<li>
<p>Open your browser to <a class="link" href="http://dockerlabs.xyz" rel="noopener">http://dockerlabs.xyz</a>.</p>
</li>
<li>
<p>When you're done, tear down the labspace:</p>
<div
  data-pagefind-ignore
  x-data
  x-ref="root"
  class="group mt-2 mb-4 flex w-full scroll-mt-2 flex-col items-start gap-4 rounded bg-gray-50 p-2 outline outline-1 outline-offset-[-1px] outline-gray-200 dark:bg-gray-900 dark:outline-gray-800"
>
  
  <div class="relative w-full">
    
    
    <div class="syntax-light dark:syntax-dark not-prose w-full">
      <button
        x-data="{ code: 'JCBkb2NrZXIgY29tcG9zZSAtcCBsYWJzcGFjZSBkb3du', copying: false }"
        class="
          top-1
         absolute right-2 z-10 text-gray-300 dark:text-gray-500"
        title="copy"
        @click="window.navigator.clipboard.writeText(atob(code).replaceAll(/^[\$>]\s+/gm, ''));
      copying = true;
      setTimeout(() => copying = false, 2000);"
      >
        <span
          :class="{ 'group-hover:block' : !copying }"
          class="icon-svg hidden"
          ><svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 -960 960 960"><path d="M300-200q-24 0-42-18t-18-42v-560q0-24 18-42t42-18h440q24 0 42 18t18 42v560q0 24-18 42t-42 18H300ZM180-80q-24 0-42-18t-18-42v-590q0-13 8.5-21.5T150-760q13 0 21.5 8.5T180-730v590h470q13 0 21.5 8.5T680-110q0 13-8.5 21.5T650-80H180Z"/></svg></span
        >
        <span :class="{ 'group-hover:block' : copying }" class="icon-svg hidden"
          ><svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 -960 960 960"><path d="m421-389-98-98q-9-9-22-9t-23 10q-9 9-9 22t9 22l122 123q9 9 21 9t21-9l239-239q10-10 10-23t-10-23q-10-9-23.5-8.5T635-603L421-389Zm59 309q-82 0-155-31.5t-127.5-86Q143-252 111.5-325T80-480q0-83 31.5-156t86-127Q252-817 325-848.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 82-31.5 155T763-197.5q-54 54.5-127 86T480-80Z"/></svg></span
        >
      </button>
      
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> docker compose -p labspace down
</span></span></code></pre></div>
      
    </div>
  </div>
</div>
</li>
</ol>



## What you'll learn

By the end of this Labspace, you will have completed the following:

- Set up a containerized local development environment with Docker Compose and Compose Watch
- Write integration tests that spin up a real database using Testcontainers
- Build a CI/CD pipeline that tests, builds, and pushes a container image automatically
- Write Kubernetes manifests and deploy a live application to a k3s cluster
- Configure the pipeline to cause an automatic deployment on every push to `main`

## Modules

| #   | Module                                    | Description                                                              |
| --- | ----------------------------------------- | ------------------------------------------------------------------------ |
| 1   | Introduction: Meet the App                | Tour the TaskFlow API and understand the SDLC journey ahead              |
| 2   | Local Dev with Docker Compose             | Write a `compose.yaml` to provision a local database and visualizer      |
| 3   | Containerizing Your Dev Environment       | Add the app to Compose with hot-reloading via Compose Watch              |
| 4   | Integration Testing with Testcontainers   | Write self-contained tests that start a real PostgreSQL container        |
| 5   | Continuous Integration with Gitea Actions | Build a pipeline that tests, builds, and pushes a container image        |
| 6   | Deploying to Kubernetes                   | Write manifests and deploy to a live k3s cluster with automated rollouts |
| 7   | The Containerized SDLC: A Recap           | Review the portability, consistency, and reproducibility gains           |

