GitLab CI/CD Pipeline


This article provides details on my use of the GitLab Runners in order to deploy websites and then automatically build, tag, and push images to my local docker repository.

Runner Installation

I’ve been using Jenkins for most of my work but as someone who continually learns, I’m also looking at other tools to see how they work. In this case because where I was working, we were going to install a local GitLab server as such I want to dig into GitLab Runners.

We’ll need to create servers for the Runners in each of the environments. In addition, for security reasons, I’ll want separate Runners that have access to my remote server in Florida.

Configuration wise, I’ll have one Runner in Dev, QA, and Stage and two Runners in Production, one for local environments and one for access to the remote server, and two Runners in my Home environment, same with one for local installations and one for the remote server. What my Runners will do is mainly deploy websites (only my Llamas website is set up right now) to my Tool servers and remote server.

Each Runner server will have 2 CPUs, 4 Gigs of RAM, and 140 Gigs of disk.

Installation itself is simple enough. You retrieve the appropriate binary from the gitlab-runner site and install it.

rpm -ivh gitlab-runner_amd64.rpm

You will need to then register the runner with gitlab. You’ll need to get the registration token from the gitlab. Click on the ‘pancake icon’, Admin, CI/CD, Runners, and click the Register an instance runner drop down to get a Registration token. With that, you can register the runner.

gitlab-runner register --url http://lnmt1cuomgitlab.internal.pri/ \
--registration-token [registration token] \
--name \
--tag-list "development,docker" --executor shell

I do have multiple gitlab-runner servers. This one is the development one that also processes containers. Other gitlab-runner servers test code or push code to various target servers.

GitLab CI/CD File

Now within your application, you can set up your pipeline to process your project on this new gitlab-runner. You do this in the .gitlab-ci.yml file. For this example, I’m again using my Llamas band website in part because it builds containers plus pushes out to two web sites so there’s some processing that needs to be done for each step. Let’s check out this process.

Test Stage

In the Test Stage, the gitlab-runner server has various testing tools installed. In this specific case, I’m testing my php scripts to make sure they all at least pass a lint test. There are other tests I have installed or can install to test other features of my projects. Note that I will use the CI_PROJECT_DIR for every command to make sure I’m working in the right directory.

- test
stage: test
- |
for i in $(find "${CI_PROJECT_DIR}" -type f -name *.php -print)
php -l ${i}

Docker Stage

In this section, I’m building the container, retagging it to be loaded to my local registry, and then pushing it to the registry. But only if the site’s been tagged. I only tag when I’m actually releasing a site version. So if no tag for this push, the build is skipped. I do push it out to the separate docker server though. I do keep all binary information on the two dev servers, bldr0cuomdev1 and ndld1cuomdev1 in the /opt/static directory structure. And unlike the other stages, there is no need to clear out the .git files and directories as they aren’t part of the llamas directory so won’t be in the container.

- docker
stage: deploy-docker
- env
- /usr/bin/rsync -av --rsync-path=/usr/bin/rsync unixsvc@ndld1cuomdev1.home.internal.pri:/opt/static/llamas/ "${CI_PROJECT_DIR}"/llamas/
- |
if [[ ! -z ${CI_COMMIT_TAG} ]]
podman-compose build
podman tag localhost/llamas_webapp:latest${CI_COMMIT_TAG}
podman push${CI_COMMIT_TAG}
- rm -rf "${CI_PROJECT_DIR}"/.git
- rm -f "${CI_PROJECT_DIR}"/.gitlab-ci.yml
- /usr/bin/rsync -av --delete --no-perms --no-owner --no-group --omit-dir-times --rsync-path=/usr/bin/rsync "${CI_PROJECT_DIR}"/

Local Stage

The next stage cleans up the git and docker information and moves the website from the llamas directory down to the documentroot. Then the site is pushed out to the local web server for review.

- home
stage: deploy-local
- /usr/bin/rsync -av --rsync-path=/usr/bin/rsync unixsvc@ndld1cuomdev1.home.internal.pri:/opt/static/llamas/ "${CI_PROJECT_DIR}"/llamas/
- rm -f "${CI_PROJECT_DIR}"/000-default.conf
- rm -f "${CI_PROJECT_DIR}"/docker-compose.yaml
- rm -f "${CI_PROJECT_DIR}"/Dockerfile.development
- rm -f "${CI_PROJECT_DIR}"/
- rm -rf "${CI_PROJECT_DIR}"/.git
- rm -f "${CI_PROJECT_DIR}"/.gitlab-ci.yml
- mv "${CI_PROJECT_DIR}"/llamas/* "${CI_PROJECT_DIR}"/
- rmdir "${CI_PROJECT_DIR}"/llamas
- /usr/bin/rsync -av --delete --no-perms --no-owner --no-group --omit-dir-times --rsync-path=/usr/bin/rsync "${CI_PROJECT_DIR}"/ unixsvc@ndld1cuomtool11.home.internal.pri:/var/www/html/llamas/

Remote Stage

The last stage pushes the website out to my remote server. As it’s effectively the same as the local stage, there’s no need to duplicate the listing.


This is actually at the top of the .gitlab-ci.yml file and lists the steps involved in the pipeline build. If any of these stages fails, the process stops until it’s resolved. You can monitor the status in gitlab by going to the project and clicking on CI/CD. The most recent job and stages will be listed. Click on the stage to see the output of the task.

- test
- deploy-docker
- deploy-local
- deploy-remote

Podman Issue

Well, when running the pipeline with a change and a tag, gitlab-runner is unable to build the image. Basically when run from gitlab, gitlab-runner isn’t actually logged in so there’s an error:

$ podman-compose build
['podman', '--version', '']
using podman version: 4.2.0
podman build -t llamas_webapp -f ././Dockerfile.development .
Error: error creating tmpdir: mkdir /run/user/984: permission denied
exit code: 125

See when someone logs in, a socket is created in /run/user with the user id. But the gitlab-runner account isn’t actually logging in. So the uid 984 isn’t being created. I manually created it and was able to successfully use podman-compose but waiting a short time and the uid is removed by linux and rebooting caused it to disappear as well.

I did eventually find an article (linked below) where the person having the problem finally got an answer. Heck, I didn’t even know there was a loginctl command.

loginctl enable-linger gitlab-runner

From the man page:

Enable/disable user lingering for one or more users. If enabled for a specific user, a user manager is spawned for the user at boot and kept around after logouts. This allows users who are not logged in to run long-running services. Takes one or more user names or numeric UIDs as argument. If no argument is specified, enables/disables lingering for the user of the session of the caller.

And it worked! Now to add that to the ansible script and give it a try.


This entry was posted in CI/CD, Computers, Docker, Git, Kubernetes and tagged , , , , . Bookmark the permalink.

One Response to GitLab CI/CD Pipeline

  1. Pingback: Kubernetes Index | Motorcycle Touring

Leave a Reply

Your email address will not be published. Required fields are marked *