Stage 5 · Platform
Building Pipelines
Jobs and Runners
Hosted runners, self-hosted runners, Kubernetes executors, containers, and privileged build isolation.
Hosted Runners
GitHub provides hosted runners with common development tools pre-installed. Each workflow run gets a fresh virtual machine. GitHub offers Ubuntu, Windows, and macOS runners. GitLab provides shared runners with Linux-based environments.
| Platform | Free Tier | Linux Specs | Storage |
|---|---|---|---|
| GitHub Actions | 2,000 min/month | 2 cores, 7 GB RAM | 14 GB SSD |
| GitLab CI | 400 min/month (SaaS) | Shared, variable | Variable |
Hosted runners are ideal for most workloads. They require zero maintenance, automatically update, and scale on demand. The main limitation is build time limits and potential queue delays during peak usage.
Self-Hosted Runners
Self-hosted runners run on your own infrastructure. They give you control over hardware, networking, and software. Use them when you need access to internal services, specialized hardware, or when hosted runner costs become prohibitive.
# On your runner machine:
# 1. Download the runner
curl -o actions-runner-linux-x64-2.311.0.tar.gz -L \
https://github.com/actions/runner/releases/download/v2.311.0/actions-runner-linux-x64-2.311.0.tar.gz
# 2. Extract
tar xzf actions-runner-linux-x64-2.311.0.tar.gz
# 3. Configure
./config.sh --url https://github.com/myorg/myrepo --token $RUNNER_TOKEN
# 4. Install and run
sudo ./svc.sh install
sudo ./svc.sh start
# Workflow targeting self-hosted runner:
# jobs:
# build:
# runs-on: self-hostedSelf-hosted runners need a registration token from GitHub. The token is single-use — each runner gets a unique identity. For organizations, use runner groups to manage access across repositories.
Kubernetes Executor
The Kubernetes executor runs each job in a separate Pod. Jobs are isolated at the container level, and pods are destroyed after the job completes. This provides clean environments, automatic scaling, and resource limits per job.
# /etc/gitlab-runner/config.toml
concurrent = 10
check_interval = 3
[[runners]]
name = "kubernetes-runner"
url = "https://gitlab.com"
token = "TOKEN"
executor = "kubernetes"
[runners.kubernetes]
namespace = "gitlab-ci"
image = "node:20"
poll_timeout = 600
cpu_request = "500m"
memory_request = "1Gi"
cpu_limit = "2"
memory_limit = "4Gi"
service_cpu_request = "100m"
service_memory_request = "256Mi"
helper_cpu_request = "100m"
helper_memory_request = "256Mi"
[[runners.kubernetes.volumes.pvc]]
name = "cache-volume"
mount_path = "/cache"
read_only = falseEach job runs in a fresh Pod with the specified resource limits. The cache volume persists across jobs on the same node. Resource requests and limits prevent runaway jobs from consuming cluster resources.
Container Jobs
Container jobs run each job in a Docker container. GitHub Actions uses containers: to define the job container. GitLab CI uses the image keyword. Containers provide isolation and reproducibility — the same container runs on any machine.
jobs:
integration-test:
runs-on: ubuntu-latest
container:
image: node:20
options: --cpus 2 --memory 4g
env:
NODE_ENV: test
services:
postgres:
image: postgres:16
env:
POSTGRES_PASSWORD: testpass
POSTGRES_DB: testdb
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
redis:
image: redis:7
ports:
- 6379:6379
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm test -- --integration
env:
DATABASE_URL: postgres://postgres:testpass@postgres:5432/testdb
REDIS_URL: redis://redis:6379The job runs inside a Node.js container with 2 CPUs and 4GB memory. Postgres and Redis run as sidecar containers. Service containers are accessible by their name (postgres, redis) within the job container.
Runner Security
Self-hosted runners execute arbitrary code from pull requests. A malicious PR can run commands on your runner machine, access your network, and steal credentials. Security measures include ephemeral runners, network isolation, and scoped tokens.
- Use ephemeral runners — destroy the runner after each job so it cannot be reused by malicious code.
- Run on isolated networks — self-hosted runners should not have access to production systems.
- Scope tokens minimally — give runners only the permissions they need for their jobs.
- Enable runner audit logs — track which jobs ran on which runners with what commands.
- Use container isolation — run jobs in containers to limit filesystem and network access.
Scaling Runners
As pipeline usage grows, you need more runners. Scaling strategies include auto-scaling groups, Kubernetes pod autoscaling, and runner fleets. The goal is to minimize queue time while controlling costs.
Track runner utilization to right-size your fleet. If runners are idle most of the time, reduce the count. If jobs queue for minutes, add more runners. GitHub provides runner usage reports in the Actions settings. GitLab provides runner analytics in the Admin Area.
Mark this lesson complete to store local progress and unlock a cleaner resume path the next time you visit.