DEV Community

Cover image for CI/CD on Local Gitlab server| Setup GitLab Runner | Self-hosted GitLab

CI/CD on Local Gitlab server| Setup GitLab Runner | Self-hosted GitLab

Hello again! In Part 1 of Git on Localhost | Self-hosted GitLab series, we successfully installed our own self-hosted GitLab server in localhost using Docker. You may have even gone ahead, created your first project, and added a .gitlab-ci.yml file, only to see your pipeline get "stuck" with a pending status.

If not, try setting up a project from your project list:

Note: If you already setup a project and a pipeline to your local server, then skip the setup part & directly move to the next part.

⚠ Though its a part 2 article, but I mistakenly wrote 'part 3' in the Cover image! Sorry for that! 🙏🏻

first create a repository with a name Go CI Test,then add some code there from your pc:

New Project

cd project_folder
git init --initial-branch=main
git remote add origin http://localhost:8080/root/ci-test.git
git add .
git commit -m "add: test CI"
git push --set-upstream origin main
Enter fullscreen mode Exit fullscreen mode

Project Init

now create a file name .gitlab-ci.yml in the root folder and add some demo CI/CD code:

stages:
  - test

dummy_test_job:
  stage: test
  script:
    - echo "Running dummy test..."
    - exit 0 
Enter fullscreen mode Exit fullscreen mode

local setup

An Error Occured! pipeline cant run!

This is expected! We've built the "brain" (the GitLab server), but we haven't given it any "hands" to do the work. This is where the GitLab Runner comes in.


In this article, we'll install and register our own local runner—also using Docker—to pick up those pending jobs and bring our CI/CD pipelines to life.

What is a GitLab Runner and Why Do We Need One?

A GitLab Runner is a separate application that executes the CI/CD jobs specified in your GitLab projects.

  • On GitLab.com, your jobs run on a shared fleet of runners managed by GitLab.

  • On our self-hosted server, we are in a private environment. The GitLab server knows what to do (from .gitlab-ci.yml) but has no one to delegate the task to.

We must provide our own Runner. This runner will poll our GitLab server, ask "Are there any jobs for me?", and if so, execute them. We'll use the Docker executor, which means our runner will spin up a fresh, clean Docker container for every single job, providing a perfectly isolated and reproducible build environment.


Installation Process

As we did in Part 1, we will use Docker to keep our setup clean and containerized.

Caution: Before we start, make sure Docker is running on your machine along with the gitlab container.

Step 0: Create a Docker Network

To allow our gitlab container and our new gitlab-runner container to communicate with each other by name, we should create a dedicated Docker network.

  1. First, create the network:
docker network create gitlab-network
Enter fullscreen mode Exit fullscreen mode

You can verify it exists with docker network ls command.

Network List

  1. Next, connect your existing gitlab container (from Part 1) to this network:
docker network connect gitlab-network gitlab
Enter fullscreen mode Exit fullscreen mode

This allows the runner to find the server at the hostname gitlab.

Step 1: Pull the GitLab Runner Docker Image

Open your terminal and pull the latest official image for the runner:

docker pull gitlab/gitlab-runner:latest
Enter fullscreen mode Exit fullscreen mode

Step 2: Start the Runner Container

Now we'll launch the runner container. This command creates a persistent volume for the runner's configuration and mounts the host's Docker socket so the runner can launch other containers.

For Linux / macOS: (This assumes you want to store the config in /code/gitlab-runner/config, similar to Part 1)

docker run -d \
    --name gitlab-runner \
    --restart always \
    --network gitlab-network \
    -v /code/gitlab-runner/config:/etc/gitlab-runner \
    -v /var/run/docker.sock:/var/run/docker.sock \
    gitlab/gitlab-runner:
Enter fullscreen mode Exit fullscreen mode

For Windows (using PowerShell): (This assumes you're using the D:\code\ path from Part 1)

docker run -d --name gitlab-runner --restart always --network gitlab-network -v D:\code\gitlab-runner\config:/etc/gitlab-runner -v //var/run/docker.sock:/var/run/docker.sock gitlab/gitlab-runner:
Enter fullscreen mode Exit fullscreen mode

Command Breakdown:

  • --name gitlab-runner: A recognizable name for our container.

  • --restart always: Ensures the runner restarts if you reboot your machine.

  • --network gitlab-network: Connects the runner to the same network as our GitLab server.

  • -v /code/gitlab-runner/config:/etc/gitlab-runner: Persistent Config. This maps a folder on your host machine to the config folder inside the container. This is critical so your runner doesn't forget its registration if you update or restart the container.

  • -v /var/run/docker.sock:/var/run/docker.sock: The Docker Socket. This is the magic. It gives the runner permission to use your host machine's Docker daemon. This is how the runner can spin up new containers (e.g., golang:1.21 or node:18) to run your jobs. (Note for Windows: the //var/run/docker.sock path is correct).

Step 3: Register the Runner

Our runner container is running, but it's not authenticated with our server. We need to "register" it.

  1. Find Your Registration Token:
  • Log into your local GitLab server (http://localhost:8080) as the root user.

  • Click the Admin Area (wrench icon) in the top navigation bar.

  • In the left sidebar, go to CI/CD > Runners.

  • Click the "Register an instance runner" button.

    Create New Instance Runner

    Runner creation Page

  • Copy the registration token displayed. It will start with glrt...

runner auth

  1. Run the Interactive Registration Command: We will execute a command inside our running gitlab-runner container:
docker exec -it gitlab-runner gitlab-runner register
Enter fullscreen mode Exit fullscreen mode
  1. Answer the Prompts: This will start an interactive setup.

Runner Register Cli
Here are the answers you should provide:

  • Enter the GitLab instance URL:

    http://gitlab (We use http://gitlab instead of localhost because both containers are on the gitlab-network and can find each other by their container names. 8080 is the port we exposed in Part 1.)

  • Enter the registration token:

    [PASTE_THE_TOKEN_YOU_COPIED]

  • Enter a description for the runner:

    'My Local Docker Runner (or whatever you want to write)' (This is just a friendly name you'll see in the UI.)

  • Enter tags for the runner (comma-separated):

    docker, local (Tags are very important. This allows you to "tag" your jobs in .gitlab-ci.yml to ensure they run on the correct runner.)

  • Enter an optional maintenance note:

    (Just press Enter to leave this blank.)

  • Enter the executor:

    docker (This is the most important setting. It tells the runner to use Docker to run jobs.)

  • Enter the default Docker image:

    alpine:latest (This is a fallback image to use if a job in your .gitlab-ci.yml doesn't specify its own image:.)

The registration is now complete!

Step 4: Verify Your Runner

Go back to your GitLab browser window (the Admin Area > Runners page) and refresh.

You should now see your new runner listed, with a green circle indicating it is online and ready for jobs.

New Runner Online

Optional: You can manually verify that the runner is available to pick up jobs.

docker exec -it gitlab-runner gitlab-runner run
Enter fullscreen mode Exit fullscreen mode

Now, go back to that "pending" pipeline (or push a new commit to trigger one). You will see it get picked up by your new runner and finally switch to "running" and then "passed"!


Conclusion

Congratulations! You now have a complete, end-to-end CI/CD setup on your local machine. You have the Local GitLab Server to manage your code and pipelines, and a GitLab Runner to execute the work.

Hope this tutorial series helps you setup your own local version control!
Next what you can do is deploy this to your server and can access from anywhere!

Enjoy your own Private gitlab!

Top comments (0)