Installing Gentoo Build Publisher

In my article from 14 months ago when I introduced Gentoo Build Publisher I wrote "Next time I will write about how one can install one's own gbp instance." Well that didn't happen. It's not that I couldn't document it, but I first wanted to make installing GBP easy. I struggled a lot with making it easy before finally conceding that... installing Gentoo Build Publisher ain't easy. But then it occurred to me that the audience here are Gentoo users, people who install and maintain Gentoo Linux, and that ain't easy either. So why delay any further, the Gentoo Build Publisher Install Guide is here! The current install follows, but this guide is expected to change over time so always consult the source repo for the latest documentation.

This document provides step-by-step instructions on how to install Gentoo Build Publisher (GBP). This document presumes a little familiarity with Gentoo, or else why would you be reading it ;-). You should at least be familiar with the Gentoo Handbook.

This documents how to install Gentoo Build Publisher (GBP) on a single Gentoo virtual machine (or physical machine if you have one to spare). There are other ways of installing Gentoo Build Publisher (bare metal, containers, multiple machines, distros other than Gentoo, etc.) however installing on a single virtual machine is the easiest to document.

Install Gentoo on a virtual machine.

The first step is to install Gentoo on a virtual machine. There is nothing special about doing this for GBP. Either testing or stable branches should suffice. From now on we assume it's being installed on an amd64-based virtual machine, but other hardware types may work as well. A typical Handbook-style installation should suffice.

Your virtual machines should be connected to a network which is accessible from all the machines it will publish for.

On resource requirements

As the primary purpose of GBP is to store lots of files, the GBP instance should have adequate storage. How much is needed depends on the usual "how much space do I need for Gentoo" factors, as well as how many machine types it will be hosting and how often builds are made. For reference a by the (this) book GBP instance with a single build from a single machine takes up about 9.1G of storage on the root filesystem. By contrast, my "real" GBP instance, which currently hosts 340 builds from 20 different machine types set me back 133G on (the equivalent of) /home/gbp/. However read here about how GBP stores multiple builds of a machine efficiently.

As for how much RAM your instance needs that all depends on what packages are being built, how many parallel builds, threads, etc. Also if Jenkins is configured for 4 workers and they're building 4 machines at the same time, multiply that by 4. A single-machine instance however should need no more memory than building locally on the target machine.

This Installation Document Requires systemd

I've thought about documenting installation using OpenRC since there is a bit of... politics regarding systemd. But the truth of the matter is all of my systems are running on systemd, and I just don't have the time/interest to figure out how to get it working on OpenRC or other init systems. However if you know how to get GBP up and running with your favorite init system then feel free to add to this document via a pull request.

Install required packages

Install the required Gentoo packages:

# unmask jenkins-bin if in the stable tree
echo dev-util/jenkins-bin >> /etc/portage/package.accept_keywords/gbp
emerge --verbose --ask --noreplace \
    app-admin/sudo \
    app-containers/buildah \
    app-containers/runc \
    dev-db/postgresql \
    dev-lang/python:3.10 \
    dev-util/jenkins-bin \
    dev-vcs/git \
    net-misc/rabbitmq-server \
    net-misc/rsync \
    www-servers/nginx

Optional packages

Optional: install pigz for a speedier gzip on multi-core systems.

echo app-arch/pigz symlink >> /etc/portage/package.accept_keywords/gbp
emerge --verbose --ask app-arch/pigz

Configure Jenkins

Give the Jenkins user subordinate uids and gids for using rootless containers.

loginctl enable-linger jenkins
usermod --add-subuids 100000-165535 --add-subgids 100000-165535 jenkins

Start the Jenkins service.

systemctl enable --now jenkins

Note the initial password stored in /var/lib/jenkins/home/secrets/initialAdminPassword. Point a web browser at port 8080 of your virtual machine, e.g. http://10.10.100.12:8080/ and enter the password given in the file.

After entering the password, select the button to "Install suggested plugins". Continue through the wizard filling out the forms. When finished click the "Start using Jenkins" button.

Click on "Manage Jenkins", "Manage Plugins". Click on the "Available" tab and enter "CopyArtifact". Select the CopyArtifact plugin and click "Install without restart".

Create a Jenkins API key

From the top bar in the Jenkins UI, click on your user/name. Then from the left menu click "Configure". Under "API Token" click the "Add new Token" button. Give it the name "gbp" then click "Generate". "Copy the token now, because it cannot be recovered in the future." Click the "Save" button.

Configure PostgreSQL

Configure PostgreSQL and start the service.

emerge --config postgresql
systemctl enable --now postgresql-14.service

NOTE: If a version of PostgreSQL other than 14 was installed, replace the 14 the major version number that was installed.

Create the role for gbp.

psql -U postgres -d template1 -c "CREATE USER gbp CREATEDB;"

Create the gbp database.

psql -U postgres -d template1 -c "CREATE DATABASE gbp OWNER gbp;"

Create user for GBP

Create a user under which the GBP-specific services will run.

useradd -c "Gentoo Build Publisher" gbp
passwd --lock gbp

Install Gentoo Build Publisher

Install the Python packages in the gbp user's home directory.

cd /home/gbp
sudo -u gbp -H git clone https://github.com/enku/gentoo-build-publisher.git
sudo -u gbp -H python3.10 -m venv .
sudo -u gbp -H ./bin/pip install -e ./gentoo-build-publisher
sudo -u gbp -H ./bin/pip install gunicorn psycopg2

Create the Django project

As GBP is a Django app, it requires a Django project to run.

sudo -u gbp -H ./bin/django-admin startproject djangoproject .

Now make some changes to the project's settings file.

$EDITOR djangoproject/settings.py

For the ALLOWED_HOST setting, use either the virtual machine's (static) IP address or the hostname you'll be using to access the system from a web browser plus "localhost". For example:

ALLOWED_HOSTS = ['10.10.100.12', 'localhost']

or

ALLOWED_HOSTS = ['gbpbox', 'localhost']

If you are unsure yet how it will be accessed via HTTP(s), use the wildcard, '*' for now:

ALLOWED_HOSTS = ['*']

Add the following to the list of INSTALLED_APPS:

* `'ariadne_django'`
* `'gentoo_build_publisher'`

Change the value of ROOT_URLCONF to 'gentoo_build_publisher.urls'.

Change the DATABASES setting to the following:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'gbp',
        'HOST': 'localhost',
        'USER': 'gbp',
        'CONN_MAX_AGE': None,
    }
}

Add the following to the end of the settings.py and save:

CELERY_BROKER_URL = 'pyamqp://guest@127.0.0.1//'
CELERY_BROKER_POOL_LIMIT = 0
STATIC_ROOT = '/home/gbp/share/static_media'

Create Celery app

Create a the file /home/gbp/djangoproject/celery.py. There is already a copy in the gentoo-build-publisher repo.

cp /home/gbp/gentoo-build-publisher/contrib/deployment/celery.py /home/gbp/djangoproject/celery.py
chown gbp:gbp /home/gbp/djangoproject/celery.py

Create the configuration file

Copy the file gentoo-build-publisher.conf file over from the repo.

cp /home/gbp/gentoo-build-publisher/contrib/deployment/gentoo-build-publisher.conf /etc/gentoo-build-publisher.conf
chown gbp:gbp /etc/gentoo-build-publisher.conf
chmod 0600 /etc/gentoo-build-publisher.conf

Open /etc/gentoo-build-publisher.conf with a text editor. Change BUILD_PUBLISHER_JENKINS_USER value to the username you created in Jenkins and the BUILD_PUBLISHER_JENKINS_API_KEY value to the API key you copied when configuring Jenkins. You did remember to copy that API key, right?

Install systemd unit files

The gbp service requires a web app service and worker service. Systemd unit files exist for these in the gentoo-build-publisher repo.

mkdir -p /usr/local/lib/systemd/system
cp /home/gbp/gentoo-build-publisher/contrib/deployment/*.service /usr/local/lib/systemd/system
systemctl daemon-reload

Install the gbp CLI

NOTE: This is a temporary method until gbpcli is packaged.

Install the shiv package.

sudo -u gbp -H /home/gbp/bin/pip install shiv

Use shiv to create a gbp "binary".

/home/gbp/bin/shiv -o /usr/local/bin/gbp -e gbpcli:main git+https://github.com/enku/gbpcli

Configure nginx

Copy the contrib/deployment/nginx.conf nginx configuration file.

cp /home/gbp/gentoo-build-publisher/contrib/deployment/nginx.conf /etc/nginx/nginx.conf

Edit /etc/nginx/nginx.conf if needed.

Configure rsyncd

cp /home/gbp/gentoo-build-publisher/contrib/deployment/rsyncd.conf /etc/rsyncd.conf
systemctl enable --now rsyncd

Start services

Enable and start all the related services:

systemctl enable --now rabbitmq
systemctl enable --now gentoo-build-publisher-wsgi
systemctl enable --now gentoo-build-publisher-worker

Create Jenkins jobs

Let's go back to Jenkins. Go back to your virtual machine in a browser on port 8080.

I prefer having all my Gentoo stuff in a separate folder. From the Dashboard click the "New Item" link in the upper left. Give it the name "Gentoo", click the "Folder" type and confirm. On the next page, click "Save".

Create a job for the Gentoo repo

In the Jenkins UI, under the Gentoo folder create another folder called "repos". Under the repos folder create a new item. Call it "gentoo". Make it of type "Freestyle project" and confirm. In the next page, configure the "gentoo" project. Select "git" for Source Code Management. For the repository URL enter "https://anongit.gentoo.org/git/repo/gentoo.git". Under "Additional Behaviors" add "Advanced clone behaviours", then click on the "Shallow clone" checkbox. For Build Triggers set it to build periodically on a schedule of once per day ("@daily"). For Build Steps add an "Execute Shell" step with the following script content:

artifact="${JOB_BASE_NAME}"-repo.tar.gz
date -R -u > ./metadata/timestamp.chk
python -c 'import json, os, sys; json.dump({"source": os.environ["GIT_URL"], "commit": os.environ["GIT_COMMIT"], "build": int(os.environ["BUILD_ID"])}, sys.stdout)' > ./metadata/build.json
rm -f "${artifact}"
mkdir -p "${WORKSPACE_TMP}"
tar cf "${WORKSPACE_TMP}"/"${artifact}" -I 'gzip -9' --exclude-vcs --exclude-vcs-ignores .
mv "${WORKSPACE_TMP}"/"${artifact}" .

For Post-build Actions add "Archive the artifacts". Enter "*-repo.tar.gz" for Files to archive.

Click Save.

Now that we have a Gentoo repo job. Let's give it a whirl. Click on the "Build Now" link on the left. The job should start running, pulling (cloning, since it's the first time), the official Gentoo repo and then creating an artifact. This artifact can then be used for machine builds.

Create a machine job

In the Jenkins UI navigate over to the "Dashboard > Gentoo" folder. Click on "New Item". For the name call it "base". For type choose "Pipeline" and confirm. Click on "Do not allow concurrent builds". Under "Build Triggers", click on "Build after other projects are built". For "Projects to watch" enter "repos/gentoo". Under "Pipeline" select "Pipeline script from SCM" from the dropdown. For "SCM" select "Git". Under "Repository URL" enter "https://github.com/enku/gbp-machines.git". Click "Save".

Now that we have a machine build job, let's give it a whirl. Click on the "Build Now" link on the left. After a few moments, if all goes successfully, you should have your first completed build pushed to GBP. Go to the GBP dashboard in a browser (The hostname/IP of your virtual machine at port 80).

Now we should be able to publish the build which will make it available to install.

gbp publish base 1