Installing TeamCity on Linux using Docker with Perforce support

Here at Borsuk software, we use TeamCity as our CI infrastructure. We also use perforce as our source code repository. We recently migrated our TeamCity infrastructure from Windows only (Windows server and Windows agent) to adding a Linux agent (for .net core functionality) as well to using Linux for the server (reduced Azure bill / allows for more consistent environment with the rest of our infrastructure where we use Docker).

Out of the box, TeamCity provide a docker image which can be used to set up an infrastructure very easily and the installation instructions are very comprehensive. For details, please see:

Unfortunately, as at the time of writing (27-Oct-2019), this set up doesn’t add support for using Perforce. So in order to be able to use Perforce as the source repository, there’s a little bit more work to do.

Background

When it comes to source code, TeamCity has 2 modes of operation, checking out on the server and checking out on the agent. For sheer simplicity (we have 1 server, 1 Windows agent and 1 Linux agent), the approach that we’ve taken is to do the check out on the server to minimise the number of places where we need to configure. This approach isn’t the best option for the highest performance (the server can become a bottleneck) but it does work for us.

When TeamCity interacts with Perforce, it does so through the p4 executable.

Docker images are layered (comes in handy later).

Solution

Given the information above, our approach to adding support is to create a custom Docker image for the TeamCity server which contains for the p4 executable. There are [at least] 2 ways to do this:

  1. Clone the official instructions at https://github.com/JetBrains/teamcity-docker-server and then update to add the p4 executable
  2. Create a new Dockerfile which takes the existing officially built Docker image and adds the p4 executable to it.

We chose option #2 for simplicity’s sake (as we could do this on the machine which actually runs our CI infrastructure over ssh in a rather more simple fashion) and also as it’ll be easier to consume subsequent updates from Jetbrains.

Prerequisites

  • A copy of p4
    • Can be downloaded from www.perforce.com
    • Make sure that it’s executable
  • Docker is installed

Steps

  1. Download a copy of p4
  2. Make sure that it’s executable
  3. Create the following Dockerfile in the same directory where p4 exists
  4. Build the docker file
  5. Run the Docker run command as usual – remembering to use the new name rather than jetbrains/teamcity-server
  6. When the TeamCity server is up and running, it’s necessary to tell TeamCity where to find the p4 executable, this can be done by setting the following internal property – teamcity.perforce.customP4Path. For instructions on how to do this, please see – https://www.jetbrains.com/help/teamcity/configuring-teamcity-server-startup-properties.html . Using the script below, this would mean ‘teamcity.perforce.customP4Path=/perforce/p4
FROM jetbrains/teamcity-server as BASE
RUN mkdir /perforce
COPY p4 /perforce/p4
EXPOSE 8111
CMD ["/run-services.sh"]

Note that when upgrading to use a new version of TeamCity, the following steps should be taken:

  1. Download the updated TC image – docker pull jetbrains/teamcity-server
  2. Stop your existing docker container for the server and rename optionally
  3. Optionally rename your existing image (in case you want to potentially rollback)
  4. Build the above image
  5. Start a new docker container using the new image and the same settings as initially launched – e.g. the mounts, port settings etc.

Note that, depending on the spec of the machine running the server, the initialisation of the server may taken many minutes (we’ve seen up to 20 minutes on our low spec server – Azure B2S). This appears to be disc IO bound and is probably worth us investigating at a later date. Whilst it’s doing this, the other containers that we have running on the machine tend to be fairly unresponsive. Whether this is a problem or not depends on your requirements

Conclusion

With this, we were able to migrate our TeamCity instance from Windows to Linux using Docker with hopefully it being trivially easy to take new versions of TeamCity by simply rebuilding the above Docker image everytime Jetbrains release a new version of the server (note that by using Docker, your TeamCity instance will no longer be automatically updatable from within the app).

Note that if you’re looking for instructions on how to do the migration from Windows to Linux, Jetbrains has a guide online.

If this is useful or if you have suggestions on how to make this better, do let us know in the comments.