PHASE 15 OF 15

Advanced Topics

Full pipeline design, matrix builds, conditional steps, clean-up policies, server backup and restore, JVM tuning, Docker agents, Kotlin DSL versioned settings, and the upgrade procedure

Pipeline DesignMatrix BuildsBackupJVM TuningDocker Agents
1

Full CI/CD Pipeline Design

A production-ready Java microservice pipeline integrating everything from Phases 1–14:

// Full pipeline: user-service microservice 1. Compile Maven: clean compile Trigger: VCS (all branches + PRs) Build feature: Commit Status Publisher → GitHub 2. Unit Tests // parallel with Integration Tests Maven: test Build feature: JaCoCo coverage Failure condition: coverage < 80% 3. Integration Tests // parallel with Unit Tests Maven: verify -P integration Shared resource: integration-test-db (exclusive) ▼ (both must pass) 4. All-Tests (Composite) No steps — aggregates Unit + Integration GitHub branch protection requires this to pass ▼ (only on main branch) 5. Package Maven: package -DskipTests File Content Replacer: inject build.number Artifacts: target/user-service-*.jar Docker build + push to registry 6. Deploy Staging // auto: on Package pass on main SSH: deploy script on staging server Smoke test step ▼ (manual trigger) 7. Deploy Production // prompt: confirm + env + version SSH: deploy script on prod servers Rollback step (executes on failure)
Design principles applied
  • Compile once, test in parallel — avoids redundant builds
  • Composite build as GitHub gate — one status check covers the full pipeline
  • Package only on main branch — feature branches build and test but don't produce artifacts
  • Staging is automated; production is manual with prompt confirmation
  • All stages use snapshot dependency on Compile — guaranteed same revision throughout
2

Matrix Builds

TeamCity doesn't have a native matrix syntax like GitHub Actions, but you can achieve matrix builds by creating one build configuration per combination and grouping them under a composite.

Pattern: test against multiple JDK versions
# Create one build config per JDK version using templates:
# Template: Maven-Test-Template
#   Parameter: jdk.version (required)
#   Agent requirement: java.version starts with %jdk.version%
#   Maven goals: test
#   Artifact: target/surefire-reports/**/* => test-reports/%jdk.version%

# Apply template to create:
# Test-JDK8   → jdk.version=1.8
# Test-JDK11  → jdk.version=11
# Test-JDK17  → jdk.version=17

# Composite: All-Java-Tests
# Snapshot deps on: Compile, Test-JDK8, Test-JDK11, Test-JDK17
Pattern: test against multiple OS
# Similar approach with agent requirements on OS:
# Test-Linux   → agent requirement: teamcity.agent.os.name=Linux
# Test-Windows → agent requirement: teamcity.agent.os.name=Windows
3

Conditional Build Steps

TeamCity 2017.2 doesn't have native "if/else" step conditions based on parameter values. Use these patterns instead:

Pattern 1: Shell conditional in Command Line step
#!/bin/bash
# Only deploy if on main branch
if [ "%teamcity.build.branch%" = "refs/heads/main" ]; then
  echo "Main branch — deploying..."
  ./deploy.sh --env=staging
else
  echo "Feature branch — skipping deploy"
fi
Pattern 2: Separate build configs per scenario
# Instead of conditional steps, use build chain:
# BuildAndTest → runs on all branches
# Deploy       → runs only on main (trigger with branch filter: +refs/heads/main)

# VCS trigger on Deploy config:
# Branch filter: +refs/heads/main (only triggers on main)
Pattern 3: Parameter-driven skip
#!/bin/bash
# Check if skip flag is set
if [ "%run.integration.tests%" = "false" ]; then
  echo "##teamcity[buildStatus status='SUCCESS' text='Integration tests skipped']"
  exit 0
fi

# Run integration tests
mvn verify -P integration
4

Clean-Up Policies

Without clean-up policies, the TeamCity data directory grows indefinitely. Set policies at server and project levels.

Server-level clean-up

Administration → Server Administration → Clean-up Settings:

  • Run clean-up at: 02:00 daily (avoid peak hours)
  • Maximum duration: 60 minutes
Project-level clean-up rules

Administration → <Project> → Clean-up Rules → Add rule:

KeepWhat is deleted
Last N buildsEverything older than the N most recent builds
Builds for last N daysBuilds older than N days
Last N successful buildsFailed builds beyond the last N successes
# Recommended rules for an active service build config:
# Keep: last 30 builds (full history including logs + artifacts)
# Keep: last 100 builds (history only, no artifacts)
# Keep: pinned builds indefinitely (don't delete release builds)

# This keeps recent builds with artifacts for debugging,
# and longer history for trend analysis, without infinite disk growth.
GOTCHA — Pinned builds are never cleaned up

Pinning a build exempts it from all clean-up rules. If your release process auto-pins every successful build, you'll accumulate hundreds of pinned builds and clean-up will never free any disk space. Only pin builds that represent actual releases — unpin test/staging builds after validation.

5

Server Backup & Restore

Creating a backup
  1. Go to Administration → Server Administration → Backup.
  2. Select what to include: configuration, database, build logs, artifacts. For a minimal config backup: include configuration + database only.
  3. Click Start Backup. The backup ZIP is created in <Data Dir>/backup/.
Scheduled backups

TeamCity can create backups on a schedule. Enable in Administration → Backup → Enable scheduled backups. Set time and what to include. Copy backup ZIPs to off-server storage (S3, NFS).

Restore procedure
# 1. Stop the TeamCity server
systemctl stop teamcity

# 2. Run maintainDB restore tool
cd /opt/teamcity/bin
./maintainDB.sh restore \
  -F /var/lib/teamcity/backup/TeamCity_Backup_20260612_0200.zip \
  -T /var/lib/teamcity   # data directory

# 3. Start the server
systemctl start teamcity

# The maintainDB tool restores: database schema, data, and config files
BACKUP SCHEDULE RECOMMENDATION

Daily database + config backup (no build logs/artifacts — too large). Weekly full backup (database + config + artifacts). Keep 30 days of daily backups and 6 months of weekly backups on off-server storage. Test your restore procedure quarterly — a backup you've never restored is an untested backup.

6

JVM Performance Tuning

# TeamCity server JVM settings
# Linux: /opt/teamcity/bin/teamcity-server.sh
# Windows: set TEAMCITY_SERVER_OPTS in registry or service wrapper

export TEAMCITY_SERVER_MEM_OPTS="\
  -Xms1g \
  -Xmx8g \
  -XX:MaxMetaspaceSize=512m \
  -XX:+UseG1GC \
  -XX:MaxGCPauseMillis=200 \
  -XX:G1HeapRegionSize=16m \
  -XX:InitiatingHeapOccupancyPercent=45"

# TeamCity agent JVM settings
# conf/buildAgent.properties:
# JAVA_OPTS=-Xmx512m

# Monitoring GC:
# Add to server opts: -Xloggc:/var/log/teamcity-gc.log -XX:+PrintGCDateStamps
Team sizeRecommended -XmxNotes
1–5 developers, <20 builds/day2gDefault 750m is too small even for dev
5–20 developers, <100 builds/day4gMost small teams
20–100 developers, <500 builds/day8gMedium teams
100+ developers, 500+ builds/day16g+Consider separate artifact storage
7

Docker Build Agents

Run TeamCity agents inside Docker containers for isolated, disposable build environments.

# Pull official TeamCity agent image
docker pull jetbrains/teamcity-agent:2017.2.2

# Run a TeamCity agent container
docker run -d \
  --name tc-agent-1 \
  -e SERVER_URL="http://YOUR_TC_SERVER:8111" \
  -e AGENT_NAME="Docker-Agent-01" \
  -v tc-agent-1-work:/opt/buildagent/work \
  -v tc-agent-1-system:/opt/buildagent/system \
  jetbrains/teamcity-agent:2017.2.2
Docker agent with Docker-in-Docker
# Mount the host Docker socket for Docker builds inside the agent
docker run -d \
  --name tc-agent-docker \
  -e SERVER_URL="http://YOUR_TC_SERVER:8111" \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v tc-agent-docker-work:/opt/buildagent/work \
  --privileged \
  jetbrains/teamcity-agent:2017.2.2
GOTCHA — Agent version must match server

Use the agent image tag that matches your server version: jetbrains/teamcity-agent:2017.2.2. Using latest may pull a newer agent that is incompatible with an older server. Pin the image tag and update it deliberately when upgrading the server.

8

Versioned Settings: Kotlin DSL in Depth

A complete Kotlin DSL example for a project with one build configuration, demonstrating the key DSL elements:

// .teamcity/settings.kts
import jetbrains.buildServer.configs.kotlin.v2019_2.*
import jetbrains.buildServer.configs.kotlin.v2019_2.buildFeatures.commitStatusPublisher
import jetbrains.buildServer.configs.kotlin.v2019_2.buildSteps.maven
import jetbrains.buildServer.configs.kotlin.v2019_2.triggers.vcs
import jetbrains.buildServer.configs.kotlin.v2019_2.vcs.GitVcsRoot

version = "2017.2"

project {
  vcsRoot(MyGitHubRepo)
  buildType(Build)
}

object MyGitHubRepo : GitVcsRoot({
  name = "GitHub — myorg/user-service"
  url = "https://github.com/myorg/user-service.git"
  branch = "refs/heads/main"
  branchSpec = "+:refs/heads/*\n+:refs/pull/*/head"
  authMethod = password {
    userName = "myorg-ci-bot"
    password = "credentialsJSON:token-id"   // stored in TeamCity credentials store
  }
})

object Build : BuildType({
  name = "Build"
  vcs { root(MyGitHubRepo) }

  artifactRules = "target/user-service-*.jar => artifacts"

  steps {
    maven {
      name = "Compile and Test"
      goals = "clean verify"
      mavenVersion = defaultProvidedVersion()
      jvmArgs = "-Xmx512m"
    }
  }

  triggers {
    vcs {
      branchFilter = "+:refs/heads/*\n+:refs/pull/*/head"
      quietPeriodMode = USE_DEFAULT
    }
  }

  features {
    commitStatusPublisher {
      publisher = github {
        githubUrl = "https://api.github.com"
        authType = personalToken {
          token = "credentialsJSON:github-status-token"
        }
      }
    }
  }

  failureConditions {
    executionTimeoutMin = 30
    testFailure(true)
  }
})
9

Upgrading TeamCity

In-place upgrade procedure for TeamCity 2017.2.2 to a newer version:

  1. Take a full backup (Section 15.5) — this is your rollback plan.
  2. Read the upgrade notes for your target version in the JetBrains documentation — some upgrades require manual steps.
  3. Download the new TeamCity distribution.
  4. Stop the TeamCity server: systemctl stop teamcity
  5. Run the new installer or extract the tar.gz over the existing installation.
  6. Start the server: systemctl start teamcity
  7. TeamCity automatically runs the database migration on first start. This may take several minutes.
  8. Verify: open the UI, check Administration → Server Info for the new version number.
  9. Agents auto-upgrade to the new version within 5–10 minutes.
GOTCHA — Don't skip major versions

If upgrading more than 2–3 major versions (e.g., 2017.2 → 2022.10), upgrade in steps. Skipping too many versions can cause database migration failures because migration scripts are cumulative. Recommended: upgrade one major version at a time, verify, then continue.

10

High Availability Limitations in 2017.2

TeamCity 2017.2 does not support multi-server active-active clustering. A single server is the only supported architecture. For high availability:

  • Database HA: use MySQL/PostgreSQL with replication. If the TC server machine fails, point a new server at the same database + data directory.
  • Data directory on shared storage: NFS or SAN mount so a replacement server can access existing artifacts and config.
  • VM snapshots: take nightly VM snapshots of the TC server machine — fast rollback in 15–30 minutes.
  • Multi-node clustering: available in TeamCity 2018.2+. If you need active-active HA, upgrade to a newer TeamCity version.
11

Real-World: Java Microservice Full Pipeline

Combining everything in this guide into a complete production build configuration set for a Java Spring Boot microservice:

// user-service — complete pipeline configuration summary // VCS Root: GitHub (SSH deploy key), branch spec: all branches + PRs Parameters: env.NEXUS_URL, env.DOCKER_REGISTRY, app.version (= 1.0.{build.counter}) Template: SpringBoot-CI-Template (shared with other services) // Build Configs: 1. Compile Maven: clean compile | Trigger: VCS all branches + PRs 2. Unit-Tests Maven: test | JaCoCo coverage | Fail if coverage < 75% 3. IT-Tests Maven: verify -P it | Shared Resource: test-db (exclusive) 4. All-Tests Composite: deps on Unit + IT | GitHub branch protection gate 5. Package Maven: package -DskipTests | Docker build+push | Artifacts: jar 6. Deploy-Staging SSH deploy + smoke test | Trigger: Finish Build on Package (main only) 7. Deploy-Prod SSH deploy | Manual trigger | Prompt: environment + confirm // All configs: Commit Status Publisher → GitHub Package+: Docker Support build feature Notifications: Email on First Failure + Fixed, branch filter: main only Clean-up: Keep last 30 builds; keep pinned; clean artifacts after 7 days

You've Completed All 15 Phases!

Finish with the Appendix — top 20 gotchas, parameter cheat sheet, branch spec reference, REST API quick-reference, and TeamCity vs Jenkins comparison.

Appendix & Reference → Back to Hub