Running TeamCity in Kubernetes has always been possible, but it often required knowing your way around both systems pretty well.
TeamCity is flexible and easy to tune, and Kubernetes provides excellent tools for running applications at scale. However, bringing the two together smoothly wasn’t always straightforward.
The new TeamCity Operator is designed to change that. It uses custom resources to automate the management of your TeamCity server life cycle. For example, it allows you to automatically deploy new servers and perform zero-downtime upgrades (see the Kubernetes documentation for more details).
Although the TeamCity Operator was originally designed to support internal use cases, interest from users running sizable Kubernetes-based installations encouraged us to make it open source. It’s now publicly available and ready for you to explore.
Why an operator?
The most common way to deploy applications to Kubernetes is through Helm charts. Helm works well for many services, but it has limitations when it comes to applications that require orchestrated, stateful operations, such as controlled upgrades, multi-node setups, or zero-downtime updates.
TeamCity fits squarely into this category. Its life cycle is complex and nuanced. Updates require sequencing, certain states must be preserved, and there are moments when two versions must temporarily coexist.
| TeamCity Operator | TeamCity Helm charts |
| Go application | Collection of templated YAML files |
| Single object that controls everything needed for TeamCity | No control over the life cycle |
| Minimal need to think about dependencies in Kubernetes | Updateable fields in objects only |
Kubernetes operators exist precisely for these cases. An operator is an application that runs inside a cluster and encodes expert knowledge about how to deploy, upgrade, and maintain a particular system. Instead of asking you to understand every nuance of TeamCity’s Kubernetes behavior, the TeamCity Operator takes on that work.
How it works
The TeamCity Operator introduces a new Kubernetes custom resource that represents a TeamCity installation. When you apply it to the cluster, the TeamCity Operator inspects this object and turns it into a fully configured, running TeamCity instance.
In practice, this means the TeamCity Operator:
- Creates and configures the necessary StatefulSets.
- Ensures the startup and shutdown sequences are executed correctly.
- Applies changes to the TeamCity installation based on updates to the custom resource specification.
- Manages upgrades, including optional zero-downtime ones.
- Coordinates the main and secondary nodes in multi-node setups.
The TeamCity Operator continuously watches the Kubernetes API for changes. When you update the TeamCity custom resource spec (for example, by changing the version or resource settings), the TeamCity Operator reconciles the actual state with the desired one.
In other words, you declare what TeamCity should look like, and the TeamCity Operator makes your vision a reality.
Example: Deploying a TeamCity main node with an external database
To give you a concrete idea of how the TeamCity Operator is used in practice, here is an example of deploying a standalone TeamCity main node that connects to an external database.
This example demonstrates how database configuration is passed via a Kubernetes Secret and how the TeamCity custom resource defines the main node, resources, and storage.
apiVersion: v1
data:
connectionProperties.password: DB_PASSWORD
connectionProperties.user: DB_USER
connectionUrl: DB_CONNECTION_STRING # format jdbc:mysql://DB_HOST:DB_PORT/SCHEMA_NAME
kind: Secret
metadata:
name: database-properties
---
apiVersion: jetbrains.com/v1beta1
kind: TeamCity
metadata:
name: teamcity-with-database
namespace: default
finalizers:
- "teamcity.jetbrains.com/finalizer"
spec:
image: jetbrains/teamcity-server
databaseSecret:
secret: database-properties
mainNode:
name: main-node
spec:
env:
AWS_DEFAULT_REGION: "eu-west-1"
requests:
cpu: "900m"
memory: "1512Mi"
dataDirVolumeClaim:
name: teamcity-data-dir
volumeMount:
name: teamcity-data-dir
mountPath: /storage
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
Built-in life cycle management
We’ve spent years refining the life cycle of a TeamCity server (startup, updates, and clean shutdown) for TeamCity Cloud. The new operator brings these practices to self-hosted users.
For upgrades, the TeamCity Operator can perform a quick update with downtime or run an orchestrated, zero-downtime upgrade process, keeping at least one TeamCity node available while switching versions behind the scenes
These workflows go far beyond what a Helm chart can reliably encode.
Configuration as code with the TeamCity Operator, Terraform, and the Kotlin DSL
The TeamCity Operator is focused on life cycle and cluster-level configuration. It gives you a running TeamCity instance but intentionally leaves higher-level configuration to other tools.
You can combine it with:
- The Terraform Provider for TeamCity for managing server-level settings, cleanup rules, VCS roots, project templates, and other global configuration elements.
- The Kotlin DSL or YAML for per-project build configurations.
Together, these create a complete and consistent code-driven setup:
- The TeamCity Operator installs, scales, upgrades, and tears down TeamCity.
- Terraform configures global server behavior.
- The Kotlin DSL or YAML defines the builds themselves.
This allows you to manage every part of TeamCity with code and keep the configuration fully version-controlled.
Why use the TeamCity Operator?
To put it simply, the TeamCity Operator offers a hassle-free way to run TeamCity in Kubernetes.
It gives you:
- A minimal starting manifest for quick setups.
- An extended manifest for more advanced installations.
- An automated life cycle that reduces the risk of misconfiguration.
- Consistent behavior across environments.
- A path toward a fully code-driven, reproducible CI/CD infrastructure.
If you’re running TeamCity as part of your CI/CD setup (especially in a Kubernetes-heavy environment), the TeamCity Operator helps take some of the pressure off. It reduces your day-to-day workload and makes long-term maintenance much easier.
What’s next
We’re preparing official documentation to accompany the TeamCity Operator. In the meantime, you can explore the GitHub repository, which includes solid documentation in the README.
For now, the GitHub repository includes examples and technical notes, and we’ll expand them over time. We also plan to publish migration guides and usage examples, particularly around combining the TeamCity Operator with Terraform and the Kotlin DSL.
You’ll also see the TeamCity Operator featured at industry events such as KubeCon, where our engineers will be available to give a walk-through of the design and answer questions.








