Diferență între revizuiri ale paginii „SDPT Lab 6”
(Pagină nouă: = Week 6 Lab Activity: Continuous Integration (CI) with GitLab = == Objective == Today, we automate everything. You will transition from compiling code on your laptop to architect...) |
|||
| (Nu s-au afișat 3 versiuni intermediare efectuate de același utilizator) | |||
| Linia 1: | Linia 1: | ||
| − | = Week 6 Lab Activity: | + | = Week 6 Lab Activity: CI/CD Pipelines & Custom Runners = |
== Objective == | == Objective == | ||
| − | Today, we automate everything. You will transition from compiling code on your laptop to architecting a professional CI pipeline | + | 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 | + | We will accomplish this in six phases: |
# '''Repository Setup:''' Migrating your code to GitLab. | # '''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 <code>main</code> branch. | ||
| + | # '''Cleanup:''' Deregistering and destroying your local runner. | ||
---- | ---- | ||
== Phase 1: Repository Setup == | == Phase 1: Repository Setup == | ||
| − | |||
| − | |||
'''1. Create a Project:''' | '''1. Create a Project:''' | ||
Log into GitLab and create a new blank project named <code>sdpt-smart-oven</code>. Uncheck "Initialize repository with a README". | Log into GitLab and create a new blank project named <code>sdpt-smart-oven</code>. Uncheck "Initialize repository with a README". | ||
| Linia 23: | Linia 23: | ||
git init | git init | ||
git branch -m main | git branch -m main | ||
| − | git remote add origin https://gitlab. | + | git remote add origin https://gitlab.cs.pub.ro/<your-username>/sdpt-smart-oven.git |
git add . | git add . | ||
git commit -m "Initial commit: Oven Controller with CMake and Docker" | git commit -m "Initial commit: Oven Controller with CMake and Docker" | ||
| Linia 31: | Linia 31: | ||
---- | ---- | ||
| − | == Phase 2: | + | == Phase 2: Registering a Local Runner == |
| − | We will | + | GitLab provides shared runners, but embedded systems often require custom hardware or specific toolchains. We will host our own Runner! |
| − | '''Your | + | '''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 <code>local-embedded</code> and click Create. Copy the '''registration token''' it gives you. | |
| − | + | '''2. Start the Runner via Docker:''' | |
| − | # '''Stages:''' Define | + | 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!) |
| + | <syntaxhighlight lang="bash"> | ||
| + | docker run -d --name my-local-runner --restart always -v /var/run/docker.sock:/var/run/docker.sock gitlab/gitlab-runner:latest | ||
| + | </syntaxhighlight> | ||
| + | |||
| + | '''3. Register the Runner:''' | ||
| + | Now, execute the registration command inside the running container: | ||
| + | <syntaxhighlight lang="bash"> | ||
| + | docker exec -it my-local-runner gitlab-runner register | ||
| + | </syntaxhighlight> | ||
| + | * '''GitLab instance URL:''' <code>https://gitlab.cs.pub.ro/</code> | ||
| + | * '''Registration token:''' (Paste your token from step 1) | ||
| + | * '''Description:''' My Laptop Runner | ||
| + | * '''Tags:''' <code>local-embedded</code> | ||
| + | * '''Executor:''' <code>docker</code> | ||
| + | * '''Default image:''' <code>ubuntu:22.04</code> | ||
| + | |||
| + | 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 <code>.gitlab-ci.yml</code> in your project root. | ||
| + | |||
| + | '''Your Challenge (Part 1):''' | ||
| + | # '''Image:''' Set <code>image:</code> to the ARM Docker image you built last week. | ||
| + | # '''Stages:''' Define three stages: <code>build</code>, <code>test</code>, and <code>deploy</code>. | ||
# '''The Build Job:''' Create a job named <code>compile_firmware</code>. | # '''The Build Job:''' Create a job named <code>compile_firmware</code>. | ||
#* Assign it to the <code>build</code> stage. | #* Assign it to the <code>build</code> stage. | ||
| − | #* In the <code>script</code> | + | #* Use <code>tags: [local-embedded]</code> to force this job to run on YOUR laptop's runner. |
| − | # | + | #* In the <code>script</code>, run CMake for <code>aarch64</code> and run <code>make</code>. |
| + | #* Create <code>artifacts</code> to save the <code>build/</code> directory (expire in 1 hour). | ||
| − | Commit and push | + | 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 | + | == Phase 4: The Test Stage & Merge Checks == |
| − | + | '''Your Challenge (Part 2):''' | |
| + | Add a job named <code>verify_logic</code>: | ||
| + | # Stage: <code>test</code> | ||
| + | # Tags: <code>local-embedded</code> | ||
| + | # <code>dependencies:</code> Require the artifacts from <code>compile_firmware</code>. | ||
| + | # <code>script:</code> Navigate to <code>build/</code> and execute tests using QEMU (<code>qemu-aarch64 -L /usr/aarch64-linux-gnu/ ./unit_tests</code>). | ||
| − | ''' | + | '''Test the Block:''' |
| − | + | # Go to GitLab '''Settings''' -> '''Merge Requests''' -> Check "Pipelines must succeed". | |
| − | # | + | # Create a new branch: <code>git checkout -b feature/broken-math</code> |
| − | # | + | # 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 <code>main</code> branch, we want to handle two different types of deployments: an automated OTA release (Pull), and an on-demand Edge deployment (Push). | ||
| − | + | '''Your Challenge (Part 3): Automated OTA Release''' | |
| − | + | Add a job named <code>release_ota_firmware</code>: | |
| + | # Stage: <code>deploy</code> | ||
| + | # Tags: <code>local-embedded</code> | ||
| + | # <code>dependencies:</code> Pull from <code>compile_firmware</code>. | ||
| + | # <code>script:</code> Rename your binary to a release format and simulate cryptographically signing it: | ||
| + | #* <code>mv build/unit_tests build/firmware_v1.bin</code> | ||
| + | #* <code>echo "CRYPTOGRAPHIC_SIGNATURE_OK" >> build/firmware_v1.bin</code> | ||
| + | # '''Rules:''' We ONLY want to release firmware automatically from the main branch! Add a <code>rules:</code> section with <code>- if: '$CI_COMMIT_BRANCH == "main"'</code>. | ||
| + | # '''Artifacts:''' Save <code>build/firmware_v1.bin</code> as an artifact that never expires. | ||
| − | ''' | + | '''Your Challenge (Part 4): On-Demand Push Deployment''' |
| − | + | Sometimes we need to instantly push an update to a specific machine (e.g., a prototype in the lab) without waiting for it to poll. We will simulate an SSH deployment using pipeline variables. | |
| − | |||
| − | ''' | + | Add another job named <code>deploy_to_edge_device</code>: |
| − | + | # Stage: <code>deploy</code> | |
| − | < | + | # Tags: <code>local-embedded</code> |
| − | + | # <code>dependencies:</code> Pull from <code>compile_firmware</code>. | |
| − | </ | + | # '''Rules:''' We want this to be an "On-Demand" job that requires a human to click a play button. Add a <code>rules:</code> section with <code>- when: manual</code>. |
| + | # <code>script:</code> Simulate securely pushing the binary to a specific IP address using an environment variable (<code>$TARGET_IP</code>). Do not hardcode an IP here; we will inject it later! | ||
| + | #* <code>echo "Connecting to Edge Device at $TARGET_IP..."</code> | ||
| + | #* <code>echo "scp build/unit_tests admin@$TARGET_IP:/opt/smart-oven/bin/"</code> | ||
| + | #* <code>echo "Deployment to $TARGET_IP successful!"</code> | ||
| − | ''' | + | '''Test the Deployments:''' |
| − | + | # Push your code to <code>main</code>. | |
| + | # You will see the <code>release_ota_firmware</code> job run automatically. | ||
| + | # The <code>deploy_to_edge_device</code> job will be paused (marked with a "Play" icon). | ||
| + | # Click the Play icon. GitLab will take you to a new screen asking if you want to inject any environment variables. | ||
| + | # Add a variable with the Key <code>TARGET_IP</code> and the Value <code>192.168.1.50</code> (or any dummy IP address you prefer). | ||
| + | # Click "Run job" and check the terminal output to see your variable successfully injected into the simulated SSH command! | ||
| − | + | == Phase 6: Cleanup == | |
| − | + | To prevent your runner from polling GitLab forever and draining your laptop battery, gracefully shut it down and remove it: | |
<syntaxhighlight lang="bash"> | <syntaxhighlight lang="bash"> | ||
| − | + | docker stop my-local-runner | |
| − | + | docker rm my-local-runner | |
</syntaxhighlight> | </syntaxhighlight> | ||
| − | In GitLab, | + | In the GitLab UI, go back to Settings -> CI/CD -> Runners, and delete the offline runner. |
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
---- | ---- | ||
=== Assignment Submission === | === Assignment Submission === | ||
| − | Upload '''ONLY''' your finalized <code>.gitlab-ci.yml</code> to the Moodle VPL assignment. The automated grading server will analyze your YAML syntax to ensure you correctly configured the stages, artifacts, and | + | Upload '''ONLY''' your finalized <code>.gitlab-ci.yml</code> 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. |
Versiunea curentă din 20 aprilie 2026 17:49
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.cs.pub.ro/<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.cs.pub.ro/ - 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 handle two different types of deployments: an automated OTA release (Pull), and an on-demand Edge deployment (Push).
Your Challenge (Part 3): Automated OTA Release
Add a 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 automatically 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.
Your Challenge (Part 4): On-Demand Push Deployment Sometimes we need to instantly push an update to a specific machine (e.g., a prototype in the lab) without waiting for it to poll. We will simulate an SSH deployment using pipeline variables.
Add another job named deploy_to_edge_device:
- Stage:
deploy - Tags:
local-embedded dependencies:Pull fromcompile_firmware.- Rules: We want this to be an "On-Demand" job that requires a human to click a play button. Add a
rules:section with- when: manual. script:Simulate securely pushing the binary to a specific IP address using an environment variable ($TARGET_IP). Do not hardcode an IP here; we will inject it later!echo "Connecting to Edge Device at $TARGET_IP..."echo "scp build/unit_tests admin@$TARGET_IP:/opt/smart-oven/bin/"echo "Deployment to $TARGET_IP successful!"
Test the Deployments:
- Push your code to
main. - You will see the
release_ota_firmwarejob run automatically. - The
deploy_to_edge_devicejob will be paused (marked with a "Play" icon). - Click the Play icon. GitLab will take you to a new screen asking if you want to inject any environment variables.
- Add a variable with the Key
TARGET_IPand the Value192.168.1.50(or any dummy IP address you prefer). - Click "Run job" and check the terminal output to see your variable successfully injected into the simulated SSH command!
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.