📖 Lecture — From Commit to Container: CI/CD for Your Capstone
For six weeks you've been assembling a toolbox: containers, cloud deployment, model serving, fine-tuning, agents, RAG, security, and cost management. This week is about the glue that holds a real production system together — the pipeline that takes your code from a local commit to a running, versioned artifact without you manually typing deploy commands at midnight. That glue is CI/CD, and by the end of this lecture you'll understand exactly what it is, why it's structured the way it is, and how to build one for your capstone. CI, CD, and CD — three overlapping terms, one letter apart. "CI/CD" is often said as if it's one thing, but it actually describes a spectrum of automation, and precision here matters for your capstone architecture decisions.
- Continuous Integration (CI) is the practice of merging code into a shared repository frequently — multiple times a day on a healthy team. Every merge automatically triggers a build plus a suite of unit and integration tests. The goal is to catch integration problems (two people's changes conflicting, a regression slipping in) within minutes of the merge, not weeks later when it's expensive to untangle.
- Continuous Delivery takes CI one step further: it automates the release process — packaging, versioning, staging deployment — so that the software is always in a releasable state. A human still clicks the button to actually push to production.
- Continuous Deployment removes that last human gate. Every change that passes the automated pipeline is deployed to production automatically, with no manual approval step.
For a solo capstone project, you'll typically land on Continuous Delivery or a light form of Continuous Deployment: your pipeline will automatically build, test, and push a container image, and you decide (manually or via a merge to main) when that image actually goes live. The canonical pipeline: four stages plus a feedback loop. Regardless of which flavor of CI/CD you're running, nearly every pipeline decomposes into the same stages:
| Stage |
What happens |
Capstone example |
| Source |
A commit or pull request triggers the pipeline |
Push to main or open a PR on GitHub |
| Build |
Code is compiled/packaged into a runnable artifact |
docker build produces your capstone's container image |
| Test |
Automated checks verify correctness |
Linting, unit tests, integration tests run against the build |
| Deploy |
The artifact is released to an environment |
Image is pushed to GHCR (and optionally deployed to your cloud target from AIINFRA 302) |
| Monitor (feedback loop) |
Runtime behavior is observed and fed back |
Logs/metrics from your serving endpoint inform the next commit |
Notice that "Monitor" feeds back into "Source" — a production incident or a cost spike you observe (FinOps, from AIINFRA 302) becomes the next commit that starts the loop over. This is why CI/CD is drawn as a loop, not a line. Best practices that make pipelines actually work:
- Commit small and often. Large, infrequent commits produce large, hard-to-diagnose failures. Small commits isolate blame quickly.
- Automate testing to catch regressions. A pipeline that only builds but never tests is just a build server — it will happily ship a broken image. Tests are what make the pipeline trustworthy enough to automate the next stage.
- Provision infrastructure via Infrastructure as Code (IaC). Whatever you configured by hand in AIINFRA 301/302 (a server, a registry, a deployment target) should be reproducible from a file in your repo, not from memory of which buttons you clicked.
- Build security checks into the pipeline itself (DevSecOps). Don't treat security as a separate audit that happens after deployment — dependency scanning, secret scanning, and image scanning belong in the pipeline as gates, right alongside your unit tests.
Secrets: the part that goes wrong most often. Your pipeline needs credentials — to push to GHCR, to deploy to a cloud provider. There are two safe patterns:
- Repository Secrets (GitHub Settings → Secrets and variables → Actions) for static values like a registry token. These are encrypted at rest, injected as environment variables at runtime, and automatically masked in logs. They are never written into the workflow YAML itself — the YAML only references
${{ secrets.MY_SECRET }}. - OpenID Connect (OIDC) for cloud-provider authentication. Instead of storing a long-lived cloud access key as a secret, your workflow requests a short-lived, automatically-expiring token from the cloud provider at run time, scoped to exactly the permissions it needs. This is the modern best practice for anything deploying to AWS, Azure, or GCP, because there is no standing credential to leak in the first place.
Correcting three common misconceptions:
- "I'll just paste my API key into the workflow file to get it working, and clean it up later." Never hardcode secrets in pipeline configs. Once a credential is committed to version control, it is compromised — even if you delete it in a later commit, it lives in git history forever. Always use the CI's native secret store (or a dedicated secrets manager) from the very first commit.
- "One big pipeline that runs everything in order is simpler to maintain." A monolithic, serial pipeline kills fast feedback. If lint, unit tests, integration tests, and deploy all run one after another in a single job, a developer waits 20+ minutes to learn their typo failed linting. Break the pipeline into independent stages/jobs that can fail fast and, where possible, run in parallel. Teams whose pipelines finish in under 10 minutes deploy far more often, because the feedback loop is fast enough to stay in flow.
- "Testing is a manual QA step, and there should be one person who owns the pipeline." Relying on manual testing and a single pipeline owner does not scale, even on a team of one. Automate the tests so they run identically every time, and treat pipeline health (a broken
ci.yml) as a first-class bug — not someone else's problem, and not something you'll "get to eventually."
By the end of this week, your capstone will have a green pipeline badge, a versioned image sitting in GHCR, and zero credentials sitting in plain text anywhere in your repo. That's a meaningful, resume-worthy milestone — most junior engineers have never built one of these from scratch.