SDPT Lab 6
Week 6 Lab Activity: CI/CD Pipelines & Custom Runners
Objective
Today, we automate everything. You will transition from compiling code on your laptop to architecting a professional CI/CD pipeline.
We will accomplish this in six phases:
- Repository Setup: Migrating your code to GitLab.
- Infrastructure: Spinning up and registering your own local GitLab Runner via Docker.
- Continuous Integration (Build): Writing your first CI job and generating Artifacts.
- Continuous Integration (Test): Consuming Artifacts and testing via QEMU.
- Continuous Deployment (CD): Creating a simulated OTA firmware release restricted to the
mainbranch. - Cleanup: Deregistering and destroying your local runner.
Phase 1: Repository Setup
1. Create a Project:
Log into GitLab and create a new blank project named sdpt-smart-oven. Uncheck "Initialize repository with a README".
2. Push Your Code: Open your terminal on your laptop, navigate to your Week 5 project folder, and push your code to this new repository.
git init
git branch -m main
git remote add origin https://gitlab.com/<your-username>/sdpt-smart-oven.git
git add .
git commit -m "Initial commit: Oven Controller with CMake and Docker"
git push -u origin main
Phase 2: Registering a Local Runner
GitLab provides shared runners, but embedded systems often require custom hardware or specific toolchains. We will host our own Runner!
1. Get Your Registration Token:
In your GitLab project, go to Settings -> CI/CD. Expand the Runners section. Under "Project runners", click "New project runner". Add the tag local-embedded and click Create. Copy the registration token it gives you.
2. Start the Runner via Docker: On your laptop terminal, run a background Docker container to act as your runner. (We mount the Docker socket so the runner can spawn its own containers!)
docker run -d --name my-local-runner --restart always -v /var/run/docker.sock:/var/run/docker.sock gitlab/gitlab-runner:latest
3. Register the Runner: Now, execute the registration command inside the running container:
docker exec -it my-local-runner gitlab-runner register
- GitLab instance URL:
https://gitlab.com/ - Registration token: (Paste your token from step 1)
- Description: My Laptop Runner
- Tags:
local-embedded - Executor:
docker - Default image:
ubuntu:22.04
Refresh your GitLab Runners page. You should see a green circle indicating your local runner is alive and listening for jobs!
Phase 3: The Build Stage & Artifacts
We will now tell your Runner how to build our code. Create a file named exactly .gitlab-ci.yml in your project root.
Your Challenge (Part 1):
- Image: Set
image:to the ARM Docker image you built last week. - Stages: Define three stages:
build,test, anddeploy. - The Build Job: Create a job named
compile_firmware.- Assign it to the
buildstage. - Use
tags: [local-embedded]to force this job to run on YOUR laptop's runner. - In the
script, run CMake foraarch64and runmake. - Create
artifactsto save thebuild/directory (expire in 1 hour).
- Assign it to the
Commit and push. Watch the pipeline in GitLab. Your laptop's fan might spin up because *your* Docker daemon is doing the heavy lifting!
Phase 4: The Test Stage & Merge Checks
Your Challenge (Part 2):
Add a job named verify_logic:
- Stage:
test - Tags:
local-embedded dependencies:Require the artifacts fromcompile_firmware.script:Navigate tobuild/and execute tests using QEMU (qemu-aarch64 -L /usr/aarch64-linux-gnu/ ./unit_tests).
Test the Block:
- Go to GitLab Settings -> Merge Requests -> Check "Pipelines must succeed".
- Create a new branch:
git checkout -b feature/broken-math - Break an assertion in your C++ tests and push the branch.
- Open a Merge Request. Watch the test stage fail and observe the Merge button physically lock you out! Fix the code, push again, and Merge it.
Phase 5: Continuous Deployment (CD)
Once the code hits the main branch, we want to automatically package it for an Over-The-Air (OTA) firmware update.
Your Challenge (Part 3):
Add a final job named release_ota_firmware:
- Stage:
deploy - Tags:
local-embedded dependencies:Pull fromcompile_firmware.script:Rename your binary to a release format and simulate cryptographically signing it:mv build/unit_tests build/firmware_v1.binecho "CRYPTOGRAPHIC_SIGNATURE_OK" >> build/firmware_v1.bin
- Rules: We ONLY want to release firmware from the main branch! Add a
rules:section with- if: '$CI_COMMIT_BRANCH == "main"'. - Artifacts: Save
build/firmware_v1.binas an artifact that never expires.
Push to main. You should see a 3-stage pipeline complete successfully. You can now download your final "signed" firmware directly from the GitLab UI!
Phase 6: Cleanup
To prevent your runner from polling GitLab forever and draining your laptop battery, gracefully shut it down and remove it:
docker stop my-local-runner
docker rm my-local-runner
In the GitLab UI, go back to Settings -> CI/CD -> Runners, and delete the offline runner.
Assignment Submission
Upload ONLY your finalized .gitlab-ci.yml to the Moodle VPL assignment. The automated grading server will analyze your YAML syntax to ensure you correctly configured the stages, artifacts, custom runner routing, and deployment rules.