Article Image
Article Image

Jetbrains released docker images for Teamcity (although not “official” as per the docker hub). I need to document the process internally, so I might as well turn it into an article and share it with everyone.

Using separate data container gives you much more flexibility in how you upgrade, test, or backup the services. You then have a pure service that you can kill restart throw away and upgrade without worrying about the configuration. The configuration will be provided by the long-live data container instead. you don’t need to backup the service. only the data container associated to it, etc…

We’ll have 4 pieces :

  1. Teamcity server : official image
  2. Teamcity data
  3. Postgres instance : official image
  4. Postgres data

Let’s start with the data containers

We’ll use an empty image to create empty data containers : tianon/true (If you want to know more, I prefer this reasoning, using an empty image to this one that uses the same base image as the app, but maybe I’m wrong, let me know :))

docker create -v /teamcity --name teamcity-data tianon/true echo 'teamcity data'
docker create -v /postgres --name postgres-data tianon/true echo 'postgres data'

That gives you a container with nothing but 1 folder named /teamcity or /postgres. you can take a peak at it by doing the following :

C:\> docker run -it --rm --volumes-from teamcity-data ubuntu ls
bin   core  etc   lib    media  opt   root  sbin  sys       tmp  var
boot  dev   home  lib64  mnt    proc  run   srv   *teamcity*  usr

We map the volumes from our newly created teamcity-data container into a new ubuntu container and we run ls. we can see the teamcity folder, mounted from our teamcity-data container.


Postgres is quite straight forward. We will start the postgres container, and take the volume from our postgres-data container :

docker run --volumes-from postgres-data \
  --name tc-postgres \
  -e POSTGRES_PASSWORD=<password_here> \
  -e PGDATA=/postgres/pgdata postgres

The postgres image uses some environment variables during setup to define the password and the data folder for our db. The user is postgres by default. That’s what is provided after the -e parameter.

And that’s about it. Now we get :

C:\> docker ps
CONTAINER ID     IMAGE       COMMAND                  CREATED       STATUS       PORTS       NAMES
7f43642f2c2e     postgres    "/docker-entrypoint.s"   2 hours ago   Up 2 hours   5432/tcp    tc-postgres

Teamcity server

Restoring backup

I took a backup of our existing teamcity, from the teamcity UI, and unzipped it on my local machine :

C:\teamcityupgrade> ls

    Directory: C:\teamcityupgrade

Mode                LastWriteTime         Length Name
----                -------------         ------ ----
d-----       2016-07-22  01:05 PM                teamcity
-a----       2016-07-22  01:01 PM      124890616

C:\teamcityupgrade> ls .\teamcity\

    Directory: C:\teamcityupgrade\teamcity

Mode                LastWriteTime         Length Name
----                -------------         ------ ----
d-----       2016-07-22  01:01 PM                config
d-----       2016-07-22  01:01 PM                lib
d-----       2016-07-22  01:01 PM                metadata
d-----       2016-07-22  01:01 PM                plugins
d-----       2016-07-22  01:01 PM                system
-a----       2016-07-22  10:56 AM              6 charset
-a----       2016-07-22  10:56 AM            681
-a----       2016-07-22  10:56 AM             87 version.txt

We’ll want to restore the database, and you can do that with the script from Teamcity. That’s in the TC container. Let’s see what we need :

  1. Use the volumes from our teamcity-data container
  2. Tell teamcity to use our volume folder (env variable)
  3. link it to postgres
  4. restore backup
  5. run teamcity

We’ll start with the db restore. We will bash into a teamcity container to get access to the script. we call the container restore-tc.
The script needs the file, an empty config folder, the zipped backup file and a connection to postgres :

docker run -it --name restore-tc --rm \
  --link tc-postgres \ # gives us a connection to postgres
  --volumes-from teamcity-data \ # gives us the config folder
  jetbrains/teamcity-server /bin/bash

Then we will copy the backup and the and the driver libraries into the container. We’ll use docker cp to do that :

So from another console, we run :

 docker cp C:\teamcityupgrade\ restore-tc:/

We edit the to connect to our postgres, and copy it too :


Note the url uses the postgres container name. This works thanks to the link parameter in the previous command. Then we copy it over :

docker cp C:\teamcityupgrade\teamcity\config\ restore-tc:/

And finally the jdbc drivers for postgres:

 docker cp C:\teamcityupgrade\teamcity\lib\jdbc\ restore-tc:/teamcity/jdbc/

Now, to restore the database, let’s go back to the bash console inside our restore-tc container and run the script (documentation):

:/# /opt/teamcity/bin/ restore \
    -A /teamcity/ \
    -F / \
    -T /

Voilà, backup is restored!

Running Teamcity

We could keep that container and run it from there, but we can also kill it and start a new one with about the same parameter, and without the /bin/bash. all the config data is in the teamcity-data data container now. so we exit the restore-tc container (we started it with –rm so it will be stopped and removed).

What we want :

  1. data from the teamcity-data (where we restored the config)
  2. tell teamcity to use the /teamcity folder as data folder
  3. use db from postgres-tc (we also just restored it)
  4. port exposed
  5. run as daemon

To run it, the full command will be :

docker run -d --name teamcity \
   -p80:8111 \
   -e TEAMCITY_DATA_PATH=/teamcity \
   --link tc-postgres \
   --volumes-from teamcity-data \

Aaand… it works (I mapped it to port 8111 in my test) :)

it works!

Blog Logo

Stéphane Erbrech



Stéphane Erbrech - Blog

Saving keystrokes

Back to Overview