Create Instance

Create an Instance

Install Docker

taken from https://docs.docker.com/engine/installation/linux/docker-ce/ubuntu/#install-using-the-repository

sudo apt-get remove docker docker-engine docker.io
sudo apt-get update
sudo apt-get install     linux-image-extra-$(uname -r)     linux-image-extra-virtual
sudo apt-get update
sudo apt-get install     apt-transport-https     ca-certificates     curl     software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
curl -fsSL https://download.docker.com/linux/ubuntu/gpg
sudo apt-key fingerprint 0EBFCD88
echo $(lsb_release -cs)
sudo add-apt-repository    "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
   $(lsb_release -cs) \
   stable"
sudo apt-get update
apt-cache madison docker-ce
sudo apt-get install docker-ce=17.03.2~ce-0~ubuntu-xenial
sudo docker run hello-world

mounting data disk

one thing I noticed is that this did not work well with the container optimized image provided by google (chromeos). It kept unmounting the disk after each shutdown. below is taken from : https://cloud.google.com/compute/docs/disks/add-persistent-disk

sudo lsblk
NAME   MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
sdb      8:16   0  200G  0 disk 
sda      8:0    0   10G  0 disk 
└─sda1   8:1    0   10G  0 part /

sdb is the mounted drive. now to format it.

sudo mkfs.ext4 -m 0 -F -E lazy_itable_init=0,lazy_journal_init=0,discard /dev/sdb
mke2fs 1.42.13 (17-May-2015)
/dev/sdb contains a ext4 file system
  last mounted on Tue Sep  5 20:30:57 2017
Discarding device blocks: done                            
Creating filesystem with 52428800 4k blocks and 13107200 inodes
Filesystem UUID: c38706b2-deb6-428c-a924-304018171052
Superblock backups stored on blocks: 
  32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208, 
  4096000, 7962624, 11239424, 20480000, 23887872

Allocating group tables: done                            
Writing inode tables: done                            
Creating journal (32768 blocks): done
Writing superblocks and filesystem accounting information: done     

now to mount it and change fstab so that on startup you will remount the drive.

sudo mkdir -p /mnt/disks/teamcity_data
sudo mount -o discard,defaults /dev/sdb /mnt/disks/teamcity_data
sudo chmod a+w /mnt/disks/teamcity_data/
sudo cp /etc/fstab /etc/fstab.backup
sudo blkid /dev/sdb
/dev/sdb: UUID="c38706b2-deb6-428c-a924-304018171052" TYPE="ext4"

echo UUID=`sudo blkid -s UUID -o value /dev/sdb` /mnt/disks/teamcity_data ext4 discard,defaults,nofail 0 2 | sudo tee -a /etc/fstab
UUID=c38706b2-deb6-428c-a924-304018171052 /mnt/disks/teamcity_data ext4 discard,defaults,nofail 0 2

cat /etc/fstab
LABEL=cloudimg-rootfs /  ext4 defaults  0 0
UUID=c38706b2-deb6-428c-a924-304018171052 /mnt/disks/teamcity_data ext4 discard,defaults,nofail 0 2

Run TeamCity Server from Instance

docker will create the datadir and logs directories in the mounted /mnt/disks/teamcity_data directory. Once you run this command keep the terminal window open so you can get the authentication token for the web portal super user login.

sudo docker run -it --name teamcity-server-instance \
  -v /mnt/disks/teamcity_data/datadir:/data/teamcity_server/datadir \
  -v /mnt/disks/teamcity_data/logs:/opt/teamcity/logs \
  -p 80:8111 \
  jetbrains/teamcity-server

Web Portal

Go to your ip address for this machine (if you didn’t allow http traffic in your vm instance this won’t work). Click proceed at the first window and accept the default TeamCity HSQLDB database from the dropdown if you haven’t setup a database for your TeamCity Server instance.

Accept your license agreement and then select “Login as Super user” Super user Login

You click “Login as Super user” and in the terminal output from your above docker run command you’ll see the following:

[2017-09-05 21:56:49,815]   INFO -   jetbrains.buildServer.SERVER - Super user authentication token: "104771920120677263962". To login as Super user use an empty username and this token as a password on the login page. 

Your number in the quotes will allow you to login as admin.

Running a TeamCity Agent

From the same instance we’ve installed TeamCity we’re going to run a TeamCity agent. mounting /var/run/docker.sock allows for docker-in-docker running of test containers. :

sudo docker run -it -e SERVER_URL="http://teamcity.yourfancyurl.io/" \
  -e AGENT_NAME=agent-1 \
  -v /home/davidraleigh/agent-1:/data/teamcity_agent/conf \
  -v /var/run/docker.sock:/var/run/docker.sock \
  --name="teamcity-agent-1" \
  jetbrains/teamcity-agent

When you go to the Agents->Unauthorized tab in TeamCity, you’ll see a list of agents (at this point it should only show the one agent you just started). Your agent may take a little while to download all the latest libraries from TeamCity. Once it has downloaded all the necessary libraries it will say Connected in green as you see in this below image. Click the hyperlink to the left that says Unauthorized and then you will be able to approve your agent’s being associated with TeamCity. Once it says Connected

Docker in Docker testing

I created a Test project with a temp build that wasn’t associated with any VCS. It had only one Command Line build step:

docker run hello-world

This should run and give you a set of results in the Build Log that looks like:

[22:44:48]Step 1/1: Command Line (4s)
[22:44:48][Step 1/1] Starting: /opt/buildagent/temp/agentTmp/custom_script7130264888871250564
[22:44:48][Step 1/1] in directory: /opt/buildagent/work/2b35ac7e0452d98f
[22:44:49][Step 1/1] Unable to find image 'hello-world:latest' locally
[22:44:50][Step 1/1] latest: Pulling from library/hello-world
[22:44:50][Step 1/1] b04784fba78d: Pulling fs layer
[22:44:51][Step 1/1] b04784fba78d: Verifying Checksum
[22:44:51][Step 1/1] b04784fba78d: Download complete
[22:44:51][Step 1/1] b04784fba78d: Pull complete
[22:44:51][Step 1/1] Digest: sha256:f3b3b28a45160805bb16542c9531888519430e9e6d6ffc09d72261b0d26ff74f
[22:44:51][Step 1/1] Status: Downloaded newer image for hello-world:latest
[22:44:51][Step 1/1] 
[22:44:51][Step 1/1] Hello from Docker!
[22:44:51][Step 1/1] This message shows that your installation appears to be working correctly.
[22:44:51][Step 1/1] 
[22:44:51][Step 1/1] To generate this message, Docker took the following steps:
[22:44:51][Step 1/1]  1. The Docker client contacted the Docker daemon.
[22:44:51][Step 1/1]  2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
[22:44:51][Step 1/1]  3. The Docker daemon created a new container from that image which runs the
[22:44:51][Step 1/1]     executable that produces the output you are currently reading.
[22:44:51][Step 1/1]  4. The Docker daemon streamed that output to the Docker client, which sent it
[22:44:51][Step 1/1]     to your terminal.
[22:44:51][Step 1/1] 
[22:44:51][Step 1/1] To try something more ambitious, you can run an Ubuntu container with:
[22:44:51][Step 1/1]  $ docker run -it ubuntu bash
[22:44:51][Step 1/1] 
[22:44:51][Step 1/1] Share images, automate workflows, and more with a free Docker ID:
[22:44:51][Step 1/1]  https://cloud.docker.com/
[22:44:51][Step 1/1] 
[22:44:51][Step 1/1] For more examples and ideas, visit:
[22:44:51][Step 1/1]  https://docs.docker.com/engine/userguide/
[22:44:51][Step 1/1] 
[22:44:51][Step 1/1] Process exited with code 0

Updating TeamCity Server or TeamCity Agent

If you need to update your server it’s a breeze. SSH into your GCP instance and do the following.

Server:

sudo docker stop teamcity-server-instance
sudo docker rm teamcity-server-instance
sudo docker pull jetbrains/teamcity-server:latest
sudo docker run -it --name teamcity-server-instance \
  -v /mnt/disks/teamcity_data/datadir:/data/teamcity_server/datadir \
  -v /mnt/disks/teamcity_data/logs:/opt/teamcity/logs \
  -p 80:8111 \
  jetbrains/teamcity-server:latest

Agent:

sudo docker stop teamcity-agent-1
sudo docker rm teamcity-agent-1
sudo docker pull jetbrains/teamcity-agent:latest
sudo docker run -it -e SERVER_URL="http://teamcity.yourfancyurl.io/" \
  -e AGENT_NAME=agent-1 \
  -v /home/davidraleigh/agent-1:/data/teamcity_agent/conf \
  -v /var/run/docker.sock:/var/run/docker.sock \
  --name="teamcity-agent-1" \
  jetbrains/teamcity-agent:latest

Since all of your server’s data is stored on the mounted disks you don’t need to worry about deleting your containers.

Using an Agent that Has GCP Gcloud Permissions

Using this Docker file: https://raw.githubusercontent.com/GoogleCloudPlatform/cloud-sdk-docker/ad2078cacf943d005069f48f23c36a8a4aa4dadb/Dockerfile

We can create a Dockerfile for TeamCity Agent that inherits also gets all the benefits of inheriting instance permissions. This way all we need to do when pulling, pushing and building images from gcr.io is use the gcloud docker -a command first.

Here is the Dockerfile I created using the above GCP Dockerfile:

FROM jetbrains/teamcity-agent

ENV CLOUD_SDK_VERSION 168.0.0

ARG INSTALL_COMPONENTS
RUN apt-get update -qqy && apt-get install -qqy \
        curl \
        gcc \
        python-dev \
        python-setuptools \
        apt-transport-https \
        lsb-release \
        openssh-client \
        git \
    && easy_install -U pip && \
    pip install -U crcmod && \
    export CLOUD_SDK_REPO="cloud-sdk-$(lsb_release -c -s)" && \
    echo "deb https://packages.cloud.google.com/apt $CLOUD_SDK_REPO main" > /etc/apt/sources.list.d/google-cloud-sdk.list && \
    curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add - && \
    apt-get update && apt-get install -y google-cloud-sdk=${CLOUD_SDK_VERSION}-0 $INSTALL_COMPONENTS && \
    gcloud config set core/disable_usage_reporting true && \
    gcloud config set component_manager/disable_update_check true && \
    gcloud config set metrics/environment github_docker_image
VOLUME ["/root/.config"]

Now instead of using the jetbrains/teamcity-agent image I use this custom image for my agents.

Deleting GCP Instance and Installing on new GCP Instance

Sometimes we need to delete a GCP instance and get a new VM. Here are the instructions to start your server up again without losing any of your information:

After SSH’ing into your instance you need to mount the drive. Do NOT Format the drive!!! Up above we formatted the drive to prepare it for it’s first use, but if you do that now you’ll lose all of your CI information

sudo lsblk
sudo mkdir -p /mnt/disks/teamcity_data
sudo mount -o discard,defaults /dev/sdb /mnt/disks/teamcity_data
sudo chmod a+w /mnt/disks/teamcity_data/
sudo cp /etc/fstab /etc/fstab.backup
echo UUID=`sudo blkid -s UUID -o value /dev/sdb` /mnt/disks/teamcity_data ext4 discard,defaults,nofail 0 2 | sudo tee -a /etc/fstab

Calling cat /etc/fstab you should see something like this:

LABEL=cloudimg-rootfs	/	 ext4	defaults	0 0
UUID=c38706b2-deb6-428c-a924-304018171052 /mnt/disks/teamcity_data ext4 discard,defaults,nofail 0 2

Now use docker to startup your teamcity server that mounts the directory with all your previous instance’s information:

sudo docker run -it --name teamcity-server-instance \
  -v /mnt/disks/teamcity_data/datadir:/data/teamcity_server/datadir \
  -v /mnt/disks/teamcity_data/logs:/opt/teamcity/logs \
  -p 80:8111 \
  jetbrains/teamcity-server

and start the teamcity agent:

sudo docker run -it -e SERVER_URL="http://teamcity.echoparklabs.io/" \
  -e AGENT_NAME=agent-1 \
  -v /home/davidraleigh/agent-1:/data/teamcity_agent/conf \
  -v /var/run/docker.sock:/var/run/docker.sock \
  --name="teamcity-agent-1" \
  jetbrains/teamcity-agent