This post brought to you by Thumbtack Engineering and the letters C and I.
How to package the TeamCity build agent for Debian/Ubuntu
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.
fpm if you don’t have it already.
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
Make the agent scripts executable
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.
systemd service file
Create a file named
teamcity-build-agent.service and put this in it.
Description=TeamCity build agent
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
systemd is too cool for
Build a package with
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
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
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
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
conf/buildAgent.properties, including at least
system, as well as
backup directories that I’ve only seen in log output. They should be writable by the
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
logs is used by
agent.sh for both logging and a PID file, but that can be changed by setting the
PID_FILE environment variables in the service file.
More extra credit: there’s no easy way to specify file ownership in an
.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
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.