Tag Archives: ci

How to package the TeamCity build agent for Debian/Ubuntu

This post brought to you by Thumbtack Engineering and the letters C and I.

How to package the TeamCity build agent for Debian/Ubuntu

We’ll use fpm to package the TeamCity 9 build agent for Debian 8 (“Jessie”) or Ubuntu Linux, including a systemd service file to start it automatically.

First, read the TeamCity 9 docs for “Setting up and Running Additional Build Agents”.

Get the TeamCity build agent

Download TeamCity 9 from JetBrains. I’m going to be using TeamCity 9.0.3. You can also get a version of the agent matched to your TeamCity install by going to the Agents tab and clicking “Install Build Agents” in the upper right.

Install fpm if you don’t have it already.

Unzip TeamCity-9.0.3.tar.gz and find the buildAgent directory. This is where all of the agent’s code and config files live. Since TeamCity wasn’t written with the FHS in mind, we’ll put it in /opt/TeamCity/buildAgent.

Make the agent scripts executable

Run chmod +x buildAgent/bin/*.sh. You won’t need to run them on the system you’re using for packaging, but fpm preserves the executable flag when it creates a package.

Create a systemd service file

Create a file named teamcity-build-agent.service and put this in it.

[Unit]
Description=TeamCity build agent

[Service]
User=teamcity
ExecStart=/opt/TeamCity/buildAgent/bin/agent.sh run

[Install]
WantedBy=multi-user.target

The run argument keeps the startup script from forking so that systemd can manage the process itself. The User section should be changed to reflect whatever user you plan on running TeamCity as. (See the systemd.exec man page for more process control options.)

This file will eventually be copied to /lib/systemd/system/teamcity-build-agent.service, because systemd is too cool for /etc.

Build a package with fpm

fpm has some usage examples on its wiki. We’re going to use the -s dir input type to take a directory and the -t deb output type to generate a Debian .deb package.

fpm
-s dir
-t deb
--name teamcity-build-agent
--version 9.0.3
--architecture all
--depends java6-runtime-headless
buildAgent=/opt/TeamCity/
teamcity-build-agent.service=/lib/systemd/system/teamcity-build-agent.service

This fpm invocation tells it thje package name and version, that the agent doesn’t care what architecture you’re using but requires Java 6, and that everything should go under /opt/TeamCity, except for the service file, which goes where systemd is expecting it.

You should now have a file named teamcity-build-agent_9.0.3_all.deb.

Create a user

Before installing the package on your target machine, run sudo adduser teamcity --system --group --home /opt/TeamCity, or add something equivalent to your configuration manager if that’s where you manage users. (I’ll be using Puppet to manage users on production machines that will have this package). The --group option creates a teamcity group along with the teamcity user, so that you can then add other users to the teamcity group if they need to look at TeamCity builds or configuration.

For extra credit, you could create and destroy the user in preinstall/postremove scripts.

Install the package

Copy the file to your target machine and run sudo dpkg -i teamcity-build-agent_9.0.3_all.deb.

Configure the package

Copy /opt/TeamCity/buildAgent/conf/buildAgent.dist.properties to /opt/TeamCity/buildAgent/conf/buildAgent.properties. Edit serverUrl to point it at your TeamCity server. You may also want to set name to something recognizable, or the agent will default to your hostname. If you’re using Puppet, this is a good file to templatize.

Create writable directories

You’ll need to create the directories named in bin/agent.sh and conf/buildAgent.properties, including at least logs, work, temp, and system, as well as update and backup directories that I’ve only seen in log output. They should be writable by the teamcity user.

sudo install -d -o teamcity -g teamcity -m ug=rwx /opt/TeamCity/buildAgent/logs
sudo install -d -o teamcity -g teamcity -m ug=rwx /opt/TeamCity/buildAgent/work
sudo install -d -o teamcity -g teamcity -m ug=rwx /opt/TeamCity/buildAgent/temp
sudo install -d -o teamcity -g teamcity -m ug=rwx /opt/TeamCity/buildAgent/system
sudo install -d -o teamcity -g teamcity -m ug=rwx /opt/TeamCity/buildAgent/update
sudo install -d -o teamcity -g teamcity -m ug=rwx /opt/TeamCity/buildAgent/backup

Alternatively, you can map them to more FHS-friendly locations in /tmp and /var. logs is used by agent.sh for both logging and a PID file, but that can be changed by setting the LOG_DIR and PID_FILE environment variables in the service file.

More extra credit: there’s no easy way to specify file ownership in an fpm-generated .deb package. This is a known issue. This is not a limitation of the .deb format itself, which, broadly speaking, is a pair of tarballs. Solve this problem and your package can create those writable directories itself.

Start the agent

Run sudo systemctl start teamcity-build-agent. You can also run sudo systemctl status teamcity-build-agent to see if it started successfully.

Talking in both directions

Communication between a TeamCity server and a TeamCity agent is two-way. Agent→server connections can and should use HTTPS, but server→agent connections don’t yet support encryption.

You’ll need to make sure the agent can reach the server (outbound on on whatever port you used in the serverUrl section of the agent config file), and the server can likewise reach the agent (inbound on the port specified in ownPort and the IP address specified in ownAddress, if you’ve bound your agent to a specific IP). The inbound port is 9090 by default, and again, it’s not encrypted, so you’ll need to use a VPN, SSH tunnel, or equivalent between the server and agent.

Advertisements
Tagged , , , , , ,