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.
---
- hosts: runner
become: yes
vars:
reg_token: !vault |
...
[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 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.
...
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.
...
- 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.
- 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.
...
- 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"
---
- 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"