Skip to content

Execution: Jenkins vs. GitLab CI vs. GitHub Actions

s How a platform handles the execution of a job—the "where" and "how"—is arguably the most critical factor for security, performance, and cost.

The terminology here is the most confusing part, as they all use similar words (like "runner") to mean slightly different things.

Let's demystify Agents vs. Runners and, most importantly, the Executors.

The Core Concept: Controller and Worker

All three platforms use a Controller/Worker model (sometimes called Master/Slave, though that term is deprecated).

  • Controller (Jenkins Controller, GitLab.com, GitHub.com): This is the "brain." It holds the pipeline configuration, manages the UI, and tells workers what to do.

  • Worker (Jenkins Agent, GitLab Runner, GitHub Runner): This is the "muscle." It's a machine waiting for jobs from the controller. When it gets a job, it executes the script and reports the results back.

The real difference lies in how these workers are provisioned, managed, and how they isolate jobs.

Here is a detailed breakdown of each platform's approach.


1. Jenkins: The "Do It Yourself" Model

With Jenkins, you are responsible for everything. The Controller (Jenkins server) just manages the jobs; you must provide and connect the "Agents" (the workers).

  • Terminology: The worker is called an Agent (formerly "Slave").

  • Management:

    • Static/Permanent Agents: This is the traditional method. You set up a VM or bare-metal machine, install the agent software (agent.jar), and permanently connect it to the Jenkins Controller (via SSH or JNLP). It sits idle, waiting for jobs.

    • Dynamic/Ephemeral Agents: This is the modern, cloud-native approach. You use a plugin (like the Kubernetes plugin or EC2 plugin) that allows Jenkins to spin up a new agent for each job (e.g., a new pod in Kubernetes) and then destroy it when the job is done.

  • Job Environment (The "Executor"):

    • An "Executor" in Jenkins is just a thread on an agent. A single, powerful agent machine might be configured with 10 executors, meaning it can run 10 jobs in parallel on the same machine.

    • Isolation is weak by default. If 10 jobs are running on one agent, they all share the same filesystem, environment variables, and resources. Job A could accidentally break Job B.

    • To fix this, you run your steps inside a Docker container using docker.image('...').inside { ... } in your Jenkinsfile. This provides container-level isolation, but the agent itself is still persistent.

Key Takeaway: Jenkins is the most flexible but has the highest management overhead. You build your own fleet of workers. Security and isolation are your responsibility and are typically achieved via plugins (like Docker or Kubernetes).


2. GitLab: The "Executor" Model

GitLab provides a clear distinction between the "Runner" (the worker process) and the "Executor" (how the job runs).

  • Terminology: The worker is called a GitLab Runner. This is a single Go binary (an application) that you install on a machine.

  • Management:

    • GitLab-Hosted (SaaS): GitLab provides a managed fleet of runners you can use (with a free quota). You don't manage them, but you have less control.

    • Self-Managed: You install the GitLab Runner application on your own VM, bare-metal machine, or in a Kubernetes cluster. You then "register" this runner with your GitLab instance (self-hosted or .com) using a token.

  • Job Environment (The "Executor"):

    This is GitLab's killer feature. When you configure your self-managed runner, you choose its Executor. The executor defines the technology used to run the job.

    • shell Executor: Runs the job script directly on the host machine. It's fast but has very poor security and isolation, just like a basic Jenkins agent.

    • docker Executor: The most popular. For each job, it spins up a new, clean Docker container based on the image: you defined in your .gitlab-ci.yml. This provides excellent isolation, as each job gets its own containerized environment and is destroyed afterward.

    • kubernetes Executor: The most scalable. The runner (living in your cluster) will create a new Kubernetes Pod for each job. This is the gold standard for dynamic, isolated, and autoscaling build agents.

Key Takeaway: GitLab provides the "Runner" application, and you provide the infrastructure. Its power comes from the built-in Executor concept, which makes it trivial to get perfect, container-based job isolation without complex plugin management.


3. GitHub Actions: The "Ephemeral VM" Model

GitHub combines the ease of a managed service with the power of self-hosting.

  • Terminology: The worker is simply called a Runner.

  • Management:

    • GitHub-Hosted: This is the default. When your job runs on ubuntu-latest, GitHub spins up a brand new, clean Virtual Machine for you. It runs your one job and is then immediately destroyed. This provides the strongest isolation of all the managed offerings. You can also pay for "Larger Runners" (more powerful VMs).

    • Self-Hosted: You install the runner application (a small binary) on your own machine (VM, bare-metal, etc.). This machine then connects to GitHub and polls for jobs. This is exactly like GitLab's shell executor: the runner runs jobs directly on the host, so isolation is your responsibility.

  • Job Environment (The "Executor"):

    • GitHub-Hosted: The environment is the ephemeral VM (Ubuntu, Windows, or macOS) with thousands of tools pre-installed. You can also run jobs inside a Docker container using container: in your workflow file.

    • Self-Hosted: The environment is the host machine. You are responsible for cleaning up files, managing dependencies, and preventing jobs from conflicting.

    • The "Kubernetes" Option: The modern way to autoscale self-hosted runners is using the Actions Runner Controller (ARC). This is a Kubernetes operator (similar to GitLab's Kubernetes executor) that automatically scales pods (each containing a runner) up and down based on demand.

Key Takeaway: GitHub-hosted runners offer the simplest and most secure experience by giving every job a fresh VM. Self-hosted runners are simple but insecure by default, requiring you to implement your own isolation or use the advanced Kubernetes (ARC) setup.


At-a-Glance Comparison

FeatureJenkinsGitLab CI/CDGitHub Actions
Worker NameAgentRunnerRunner
Managed Option?No. (Must use a 3rd-party cloud provider).Yes. GitLab-hosted runners (managed fleet).Yes. GitHub-hosted runners (ephemeral VMs).
Self-Hosted Option?Yes. This is the primary model.Yes. A core feature.Yes. A core feature.
Job Isolation (Default)Very Weak. Jobs share the agent's filesystem (via Executors/threads).Strong. (If using docker executor).Strongest. (If using GitHub-hosted VMs).
Job Isolation (Advanced)Strong. Achieved via docker.image().inside or the Kubernetes Plugin.Strongest. Built-in via docker or kubernetes executors.Strong. (If using self-hosted with the Actions Runner Controller).
ScalingManual/Plugin-Driven. You must configure autoscaling via plugins (e.g., Kubernetes, EC2).Built-in. The Runner has native autoscaling logic for Docker and Kubernetes.Built-in. (For GitHub-hosted). For self-hosted, you use the Actions Runner Controller (ARC).
Primary ConceptStatic Agents with Executors (threads). Isolation is a plugin's job.A Runner (app) that uses an Executor (technology) to run a job.An Ephemeral VM (hosted) or a Static Runner (app) (self-hosted).

Managing Secrets

These are the primary drivers for choosing one platform over another: security (how it protects your keys) and cost (how you pay for it).


Part 1: Security & Secret Management

This is where the platforms show their biggest philosophical differences. The modern "gold standard" is moving away from storing static secrets (like API keys) and toward "passwordless" authentication using temporary tokens (like OIDC).

1. Jenkins

  • Native Secrets: Jenkins uses the Credentials Plugin, a robust, built-in system.

    • What it is: A central, secure store inside your Jenkins controller for credentials.3

    • Types: It can store "Secret text" (API keys), "Username with password," "SSH private keys," and "Secret files" (like a kubeconfig or JSON key file).

    • How it works: You "bind" these credentials to an environment variable in your Jenkinsfile. The credential itself is never printed to the log (just a **** mask).

    • Scoping: You can define credentials globally, or restrict them to specific folders or pipelines.

  • External Vaults (OIDC/Passwordless): This is not a native feature.

    • How it works: You must install and configure plugins for each vault you want to talk to.

    • Examples:

      • HashiCorp Vault: You typically use the HashiCorp Vault Plugin. 7This plugin authenticates to Vault (often using a method called AppRole), retrieves secrets, and injects them as variables.

      • Cloud Vaults: You need separate plugins like the AWS Secrets Manager Credentials Provider or Azure Key Vault Plugin.

    • The Bottom Line: It's powerful and can do anything, but it's 100% plugin-managed. You are responsible for configuring and maintaining this security layer.

2. GitLab CI/CD

  • Native Secrets: GitLab uses CI/CD Variables stored at the project, group, or instance level.

    • Key Features:

      • Masked: If you mark a variable as "Masked," GitLab will hide its value in all job logs. It has strict requirements (e.g., must be a single line) to prevent accidental unmasking.

      • Protected: This is the critical feature. A "Protected" variable is only injected into jobs running on protected branches or tags (like main or v1.0). This is the perfect way to stop a developer's feature-branch pipeline from accessing production deployment keys.

      • File Type: You can store an entire file (like a JSON key) as a File variable, and GitLab will write it to a temporary file on the runner.

  • External Vaults (OIDC/Passwordless): This is a native, first-class feature (available in Premium/Ultimate tiers).

    • How it works: GitLab CI can generate a unique, short-lived OIDC token ($CI_JOB_JWT_V2) for every single job.

    • You configure your external vault (HashiCorp Vault, AWS, GCP, Azure) to trust your GitLab instance as an identity provider.

    • Your .gitlab-ci.yml script can then present this token to the vault, which verifies it and issues a temporary access token in return.

    • The Bottom Line: This is the modern, secure standard. No static API keys are stored in GitLab. You grant access based on job attributes (e.g., "only jobs from the main branch on my-project can access prod secrets").

3. GitHub Actions

  • Native Secrets: GitHub has a powerful, multi-layered system for Encrypted Secrets.

    • Scoping (3 Levels):

      1. Repository-level: Available to all workflows in that repo.

      2. Organization-level: Share secrets (like a company-wide scanner key) across multiple repositories.

      3. Environment-level: This is the most powerful feature. You create an "Environment" (e.g., production), add secrets to it, and then add protection rules.

    • Environment Protection Rules: You can require a manual approval from a specific team (DevOps-Admins) before a workflow job using that environment's secrets is allowed to run. You can also restrict it to protected branches.

  • External Vaults (OIDC/Passwordless): This is also a native, first-class feature (and it's free).

    • How it works: Identical in concept to GitLab. GitHub's OIDC provider issues a unique JWT for every workflow run.

    • You configure your cloud (AWS, Azure, GCP) or HashiCorp Vault to trust GitHub.

    • In your workflow, you add a permissions: block to get an id-token: write and then use an official action (like aws-actions/configure-aws-credentials) to exchange that token for temporary cloud credentials.

    • The Bottom Line: Extremely secure and considered a best practice. It completely eliminates the need for long-lived cloud API keys in GitHub Secrets.


Part 2: Pricing & Hosting Models

This is all about the SaaS vs. Self-Hosted trade-off.

1. Jenkins

  • Hosting: Almost exclusively Self-Hosted. You must provide and manage the infrastructure for the Jenkins Controller and all its Agents.

  • SaaS Option: There is no official "Jenkins SaaS." The closest thing is CloudBees, which is a commercial, enterprise-grade version of Jenkins that you can pay for.

  • Pricing (The "Free" Trap):

    • Software Cost: $0. Jenkins is open-source and free.

    • Real Cost (Total Cost of Ownership - TCO): This is very high. You are paying for:

      • Infrastructure: The servers (VMs) for the Controller and all build Agents (which can be a large, auto-scaling fleet).

      • Maintenance: A dedicated engineer or team to update Jenkins, manage plugins, fix security vulnerabilities, and back up data.

      • Management: The time your team spends configuring jobs, plugins, and agents instead of building your product.

    • In short: You trade a software license fee for infrastructure and high operational overhead.

2. GitLab CI/CD

  • Hosting: Both SaaS (GitLab.com) and Self-Managed (you run it on your own servers).

  • Pricing (SaaS - GitLab.com):

    • Free: Very generous. Includes 400 CI/CD minutes per month.

    • Premium ($29/user/month): The sweet spot. Includes 10,000 CI/CD minutes. This tier adds OIDC support, protected variables, and other key DevOps features.

    • Ultimate ($99/user/month): Adds advanced security scanning (SAST, DAST, dependency scanning) directly into the pipeline.

  • Pricing (Self-Managed):

    • Core (Free): You can self-host the free, open-source version. This includes CI/CD! You must provide your own Runners, but the CI/CD features are all there. This is a very common choice.

    • Premium & Ultimate: You pay the same per-user price as SaaS, but you host it all. You do not get any included build minutes because you are using your own runners.

    • In short: GitLab gives you the most flexibility. You can start for free on their SaaS, pay to scale, or host the entire thing (including a free version) yourself.

3. GitHub Actions

  • Hosting: Primarily SaaS (GitHub.com). A Self-Hosted runner option is available.

  • Pricing (SaaS - GitHub.com):

    • Free (Public Repos): Completely free. Unlimited CI/CD minutes on GitHub-hosted runners. This is why it dominates open-source.

    • Free (Private Repos): Includes 2,000 CI/CD minutes per month.

    • Team ($4/user/month): Includes 3,000 CI/CD minutes per month.

    • Enterprise ($21/user/month): Includes 50,000 CI/CD minutes per month.

  • The Overage Model:

    • After you use your free minutes, you pay per-minute. The rate depends on the OS.

    • (e.g., Linux: ~$0.008/min, Windows: ~$0.016/min, macOS: ~$0.08/min).

    • This also applies to "Larger Runners" (more CPU/RAM), which are billed at a higher per-minute rate.

  • Self-Hosted Runners:

    • Using your own self-hosted runners (your own VMs/servers) is 100% free. You pay nothing to GitHub for CI/CD minutes, but you pay for your own infrastructure (just like with Jenkins).

    • In short: GitHub is the undisputed king of open-source. For private work, it has a "pay-as-you-go" feel. You can control costs by providing your own runners.


Summary: Which Should You Choose?

  • Choose Jenkins if: You have a complex, mature, multi-cloud environment and you must host everything yourself. You already have a dedicated DevOps/SRE team with the expertise (and budget) to manage and secure the entire platform.

  • Choose GitLab CI/CD if: You want a single, all-in-one platform for your entire lifecycle (code, issues, registry, CI/CD). You value the flexibility of starting on SaaS and having a clear path to a self-hosted (even free) version later.

  • Choose GitHub Actions if: Your world revolves around GitHub. You want the best-in-class, event-driven automation and the easiest, most secure SaaS experience (especially with OIDC). The vast marketplace and free tier for public repos are huge draws.