Everything you need to manage and deploy your next gaming project - TeamCity, Youtrack and Perforce
I now manage all of my projects with TeamCity and Youtrack, here's why
Its been a while since I’ve shared what stacks I’m using for my developing pipeline. Currently I’m very happy with using TeamCity for testing and deployments, Youtrack for project management as well as keeping documentation for a project and for game related development, Perforce as a SCM.
If you’ve been following my posts you already know how much I like to utilize these 3 pieces of software. This post was just meant to be a quick guide on how to set them up via docker containers and use nginx to expose them to the internet.
Quick overview
TeamCity
Used for CICD related deployments. Now a days you don’t have to host your own CICD solutions. TeamCity has a cloud version, Github actions, Gitlab, Bitbucket pretty much every SCM provider has their own CICD tool. The main version I use TeamCity is for Unreal Engine deployments. The engine is big and bulky and does not play well with cloud tools. A typical docker image of the engine is around 125GB, ideally you’d want to host your own agents for this. Now you could just use a cloud based option and host your own agent as well, I like to utilize my NAS for that since I already have it running, why pay extra to do cloud hosting.
Back on topic, I find having hosted agents that you can log into better to work with for complex and/or longer pipelines. Just offers easier troubleshooting which is why I prefer to host my own. I do work alone and if I did scale, I may move to a cloud option.
Out of the box, TeamCity is just ready to be used. It is the best option out of all of the providers I’ve used for the easier onboarding of several projects
Youtrack
Similar to most other project management tools, this pretty much does what the rest does. Relating to TeamCity, I am a big fan of Jetbrains products and use Youtrack since its part of their suite. Since most of these project management tools do the same thing, I mostly look for aesthetics, speed and ease of use. Youtrack does all 3 of these well and just like TeamCity, it is fast and easy to setup and integrate. They also provide top notch documentation
Perforce
Not much to add here, in my opinion its the only useable SCM for game projects(projects with lots of binaries). You can use git LFS, it just doesn’t work well and is no where near as performant as Perforce.
Setup
I use docker compose to set up my infrastructure. Keeps it easy and portable if I ever need to swap anything around. One thing to note, TeamCity depends on a sql server. I do have a mysql container in this docker compose. If you have sql server running you can just point that config to TeamCity.
version: "3"
services:
mysql:
image: mysql:8.0-oracle
container_name: mysql
command: --innodb_flush_log_at_trx_commit=2
environment:
- TZ=${TZ}
- PUID=${PUID}
- PGID=${PGID}
- MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
- MYSQL_USER=${MYSQL_USER}
- MYSQL_PASSWORD=${MYSQL_PASSWORD}
volumes:
- ${CONFIG_PATH}/mysql:/var/lib/mysql
ports:
- 3306:3306
labels:
com.centurylinklabs.watchtower.enable: true
restart: unless-stopped
deploy:
restart_policy:
condition: on-failure
youtrack:
container_name: youtrack
platform: linux/amd64
image: jetbrains/youtrack:2022.3.65372
ports:
- 7112:8080
volumes:
- ${CONFIG_PATH}/youtrack/data:/opt/youtrack/data
- ${CONFIG_PATH}/youtrack/conf:/opt/youtrack/conf
- ${CONFIG_PATH}/youtrack/logs:/opt/youtrack/logs
- ${CONFIG_PATH}/youtrack/backups:/opt/youtrack/backups
environment:
- TZ=${TZ}
- PUID=${PUID}
- PGID=${PGID}
restart: unless-stopped
deploy:
restart_policy:
condition: on-failure
teamcity:
container_name: teamcity
platform: linux/amd64
image: jetbrains/teamcity-server
depends_on:
- mysql
ports:
- 8111:8111
volumes:
- ${CONFIG_PATH}/teamcity/data:/data/teamcity_server/datadir
- ${CONFIG_PATH}/teamcity/logs:/opt/teamcity/logs
environment:
- TZ=${TZ}
- PUID=${PUID}
- PGID=${PGID}
restart: unless-stopped
deploy:
restart_policy:
condition: on-failure
perforce:
container_name: perforce
platform: linux/amd64
image: hawkmothstudio/helix-p4d
environment:
- P4PORT=${P4PORT}
- P4USER=${P4USER}
- P4PASSWD=${P4PASSWD}
ports:
- 1666:1666
volumes:
- ${CONFIG_PATH}/perforce:/data
restart: unless-stopped
deploy:
restart_policy:
condition: on-failure
You can run docker-compose up and pass along the variables with it. Here’s each env variable you need to specify
CONFIGPATH - root path of all of the containers. In my case I use /volume1/docker TZ - Linux time zone. ex. America/NewYork PUID - user id to run the containers under PGID - group id to run the containers under MYSQLPASSWORD - your mysql user password (can be omitted if you delete the mysql deployment) MYSQLROOTPASSWORD - your mysql root password (can be omitted if you delete the mysql deployment) MYSQLUSER - your mysql user P4PORT - Port(address) to run perforce under. ssl:0.0.0.0:1666 will turn ssl on and listen on every ip under port 1666 P4PASSWD - password for the perforce server P4USER - user for the perforce server
Nginx
This is a little out of scope of this posts since Nginx is a beast of its own. To expose the Youtrack and TeamCity servers I use the LinuxServer Nginx image here - https://github.com/linuxserver/docker-swag#migrating-from-the-old-linuxserverletsencrypt-image. This image takes care of ssl and the proxy. I will however share my proxy-conf that you can use with this image or your own if you already have one
TeamCity
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name teamcity.*;
include /config/nginx/ssl.conf;
client_max_body_size 0;
location / {
include /config/nginx/proxy.conf;
include /config/nginx/resolver.conf;
set $upstream_app 192.168.50.227;
set $upstream_port 8111;
set $upstream_proto http;
proxy_pass $upstream_proto://$upstream_app:$upstream_port;
}
}
Youtrack
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name youtrack.*;
include /config/nginx/ssl.conf;
client_max_body_size 0;
add_header Strict-Transport-Security max-age=31536000;
location / {
include /config/nginx/proxy.conf;
include /config/nginx/resolver.conf;
set $upstream_app 192.168.50.227;
set $upstream_port 7112;
set $upstream_proto http;
proxy_pass $upstream_proto://$upstream_app:$upstream_port;
}
location /contextPath/ {
include /config/nginx/proxy.conf;
include /config/nginx/resolver.conf;
proxy_set_header X-Forwarded-Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
client_max_body_size 10m;
set $upstream_app 192.168.50.227;
set $upstream_port 7112;
set $upstream_proto http;
proxy_pass $upstream_proto://$upstream_app:$upstream_port/contextPath;
}
location /contextPath/api/eventSourceBus {
include /config/nginx/proxy.conf;
include /config/nginx/resolver.conf;
proxy_cache off;
proxy_buffering off;
proxy_set_header Connection '';
chunked_transfer_encoding off;
proxy_set_header X-Forwarded-Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
set $upstream_app 192.168.50.227;
set $upstream_port 7112;
set $upstream_proto http;
proxy_pass $upstream_proto://$upstream_app:$upstream_port/contextPath/api/eventSourceBus;
}
}