AnUnknownAlias

A list of nonsensical actvities

Setting up a gitlab runner using Ansible

while I was working on a pipeline for testing knock_rs I wanted to write up a quick Ansible playbook to install and configure a gitlab runner. figured I'd write a quick post about it in the process.

Top level

gitlab-runner-setup.yml
---
- hosts: runner
  become: yes

  vars: 
    reg_token: !vault |
      ...
inventory
[runner]
0.0.0.0 Ansible_user=gitlab-runner

A basic setup of a playbook, we have our hosts, in this case read from an inventory file, and become to specify we'll run this as root. In vars we'll store a registration token taken from the projects Settings->CI/CD->Runners->Specific Runners. The token is stored in Ansible vault using a password file not included here. Check out vault here. In the inventory file I've added an ansible_user for connecting through ssh an have masked the ip of the runner to 0.0.0.0.

Our tasks

Our first task is the installation of required dependencies. These are all required to get and install keys and repos for docker, as well as run rust, and ansible on the runner host. I also like to immediately update pip as the version in distro package repos may be outdated.

gitlab-runner-setup.yml
...

  tasks:
  - name: Install dependencies
    apt:
      name:
        - apt-transport-https 
        - ca-certificates 
        - curl 
        - gnupg-agent 
        - software-properties-common
        - build-essential # needed for rust compilation
        - python3-pip # needed for ansible module installs
      state: present
      update-cache: yes

  - name: Immediately update pip
    pip:
      name:
        - pip
      state: latest

  - name: Install pip dependencies
    pip:
      name: 
      - python-gitlab<=1.12.1
      - virtualenv
      - setuptools

With our dependencies met we can grab the gpg key and the repo for docker and install the packages.

gitlab-runner-setup.yml
...

  - name: Install docker gpg key
    apt_key: 
      url: "https://download.docker.com/linux/ubuntu/gpg" 
      id: 9DC858229FC7DD38854AE2D88D81803C0EBFCD88
      state: present

  - name: Add docker repo
    apt_repository:
      repo: "deb [arch=amd64] https://download.docker.com/linux/ubuntu {{ Ansible_distribution_release }} stable"
      state: present
      update_cache: yes

  - name: Install docker
    apt:
      name:
        - docker-ce 
        - docker-ce-cli 
        - containerd.io
      state: present

  - name: Add gitlab-runner user to docker group
    user:
      name: gitlab-runner
      append: yes
      groups: docker

This runner may build rust projects so we'll grab and install rust through rustup and also ansible through pip. Ansible will need some dependencies for interacting with azure, we'll grab those from galaxy and install their requirements.

gitlab-runner-setup.yml
  - name: Install rust
    become_user: gitlab-runner
    args:
      creates: /usr/bin/rustc
    shell:
      curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y

  - name: Install ansible
    pip:
      name:
        - ansible

  - name: Install azure modules from galaxy
    command: |
      ansible-galaxy collection install community.azure && \
      ansible-galaxy collection install azure.azcollection

  - name: Install azure requirements 
    command: |
      cd /home/gitlab-runner/.ansible/collections/ansible_collections/azure/azcollection/; \
      python3 -m pip install -r requirements-azure.txt

The last step is installing a gitlab runner and registering using the token stored above. The runner registration can be repeated for as many runners as you would like, in my case having a docker executor and a shell executor. The shell executor should only be used if you control the runner and know or own all code that will be run with it. It is useful however if your build or test pipeline needs to store sensitive information such as tokens for api access or passwords for a service.

gitlab-runner-setup.yml
...

  - name: Install gitlab runner
    shell: |
      curl -LJO https://gitlab-runner-downloads.s3.amazonaws.com/latest/deb/gitlab-runner_amd64.deb
      dpkg -i gitlab-runner_amd64.deb
    args:
      creates: /usr/bin/gitlab-runner

  - name: Register gitlab docker runner
    command: |
      gitlab-runner register \
      --non-interactive \
      --url "https://gitlab.com/" \
      --registration-token "{{ reg_token }}" \
      --executor "docker" \
      --docker-image alpine:latest \
      --description "docker-runner" \
      --tag-list "azure, docker" \
      --run-untagged="false" \
      --locked="true" \
      --access-level="ref_protected"

  - name: Register gitlab shell runner
    command: |
      gitlab-runner register \
      --non-interactive \
      --url "https://gitlab.com/" \
      --registration-token "{{ reg_token }}" \
      --executor "shell" \
      --description "shell executor" \
      --tag-list "azure, shell, ansible" \
      --run-untagged="false" \
      --locked="true" \
      --access-level="ref_protected"

Full script

gitlab-runner-setup.yml
---
- hosts: runner
  become: yes

  vars: 
    reg_token: !vault |
      ...

  tasks:
  - name: Install dependencies
    apt:
      name:
        - apt-transport-https 
        - ca-certificates 
        - curl 
        - gnupg-agent 
        - software-properties-common
        - build-essential
        - python3-pip
      state: present
      update-cache: yes

  - name: Immediately update pip
    pip:
      name:
        - pip
      state: latest

  - name: Install pip dependencies
    pip:
      name: 
      - python-gitlab<=1.12.1
      - virtualenv
      - setuptools

  - name: Install docker gpg key
    apt_key: 
      url: "https://download.docker.com/linux/ubuntu/gpg" 
      id: 9DC858229FC7DD38854AE2D88D81803C0EBFCD88
      state: present

  - name: Add docker repo
    apt_repository:
      repo: "deb [arch=amd64] https://download.docker.com/linux/ubuntu {{ ansible_distribution_release }} stable"
      state: present
      update_cache: yes

  - name: Install docker
    apt:
      name:
        - docker-ce 
        - docker-ce-cli 
        - containerd.io
      state: present

  - name: Add gitlab-runner user to docker group
    user:
      name: gitlab-runner
      append: yes
      groups: docker

  - name: Install rust
    become_user: gitlab-runner
    args:
      creates: /usr/bin/rustc
    shell:
      curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y

  - name: Install ansible
    pip:
      name:
        - ansible

  - name: Install azure modules from galaxy
    become_user: gitlab-runner
    command: |
      ansible-galaxy collection install community.azure azure.azcollection

  - name: Install azure requirements 
    become_user: gitlab-runner
    command:
      chdir: /home/gitlab-runner/.ansible/collections/ansible_collections/azure/azcollection/
      cmd: python3 -m pip install -r requirements-azure.txt

  - name: Install gitlab runner
    shell: |
      curl -LJO https://gitlab-runner-downloads.s3.amazonaws.com/latest/deb/gitlab-runner_amd64.deb; \
      dpkg -i gitlab-runner_amd64.deb
    args:
      creates: /usr/bin/gitlab-runner
    
  # this is unfortunately the best way I could find to setup these runners
  # ansible does have a gitlab_runner module, but it seems to be only useful if
  # you run/own the gitlab instance. i.e. you don't have permissions to add a
  # runner to gitlab.com, and there is no way to register a runner that is
  # somewhere else. Like hosted on azure. So we'll register them through the
  # commandline and hopefully only run this script once as this doesn't check for
  # instances already running
  - name: Register gitlab docker runner
    command: |
      gitlab-runner register \
      --non-interactive \
      --url "https://gitlab.com/" \
      --registration-token "{{ reg_token }}" \
      --executor "docker" \
      --docker-image alpine:latest \
      --description "docker-runner" \
      --tag-list "azure, docker" \
      --run-untagged="false" \
      --locked="true" \
      --access-level="ref_protected"

  - name: Register gitlab shell runner
    command: |
      gitlab-runner register \
      --non-interactive \
      --url "https://gitlab.com/" \
      --registration-token "{{ reg_token }}" \
      --executor "shell" \
      --description "shell executor" \
      --tag-list "azure, shell, ansible" \
      --run-untagged="false" \
      --locked="true" \
      --access-level="ref_protected"