도커스웜에서 운영되던 teamcity를 쿠버네티스로 이관한 과정을 정리한다.
적절한 helm chart 가 없어 직접 배포했다.
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: teamcity-server
namespace: teamcity
spec:
serviceName: 'teamcity'
replicas: 1
selector:
matchLabels:
app: teamcity-server
template:
metadata:
labels:
app: teamcity-server
spec:
initContainers:
- name: volume-permissions
image: busybox
command: ['sh', '-c', 'chown -R 1000:1000 /data/teamcity_server/datadir']
volumeMounts:
- name: teamcity-data
mountPath: /data/teamcity_server/datadir
containers:
- name: teamcity-server
image: jetbrains/teamcity-server:2024.07.1
ports:
- containerPort: 8111
env:
- name: TEAMCITY_SERVER_MEM_OPTS
value: '-Xmx6g'
resources:
requests:
memory: '4Gi'
cpu: '4000m'
limits:
memory: '8Gi'
cpu: '8000m'
volumeMounts:
- name: teamcity-data
mountPath: /data/teamcity_server/datadir
volumeClaimTemplates:
- metadata:
name: teamcity-data
spec:
accessModes: ['ReadWriteOnce']
resources:
requests:
storage: 20Gi
서버 pod 에는 데이터베이스 외에도, 데이터베이스에 대한 연결 정보나 플러그인그 외 다른 데이터들도 저장된다. 재시작 시 다시 인스톨러를 보고싶지 않다면 위 정보를 stateful 하게 관리해야한다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: teamcity-agent
namespace: teamcity
spec:
replicas: 3
selector:
matchLabels:
app: teamcity-agent
template:
metadata:
labels:
app: teamcity-agent
spec:
containers:
# agent 의 build runner 로 docker 를 사용하고있다. dind 컨테이너를 사용해 Docker 데몬을 실행하고, TeamCity 에이전트 컨테이너에서 이 데몬에 연결한다.
- name: dind
image: docker:20.10-dind
securityContext:
privileged: true
# 기본적으로 2376 에 TLS를 사용하는 Docker 데몬이 실행되지만, TeamCity 에이전트는 TLS를 사용하지 않으므로 2375 포트를 사용하게 명시해야한다.
command: ['dockerd', '-H', 'tcp://0.0.0.0:2375', '-H', 'unix:///var/run/docker.sock']
env:
- name: DOCKER_DRIVER
value: overlay2
volumeMounts:
- name: dind-storage
mountPath: /var/lib/docker
- name: teamcity-agent
image: jetbrains/teamcity-agent:2024.07.1
env:
- name: SERVER_URL
value: 'teamcity-server.teamcity.svc.cluster.local:8111'
- name: AGENT_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: DOCKER_HOST
value: 'tcp://localhost:2375' # DinD 컨테이너의 Docker 데몬에 연결
resources:
requests:
cpu: '2000m'
memory: '2Gi'
limits:
cpu: '4000m'
memory: '4Gi'
volumeMounts:
- name: dind-storage
mountPath: /var/lib/docker
volumes:
- name: dind-storage
emptyDir: {}
팀시티 Professional(무료) 라이센스 에서는 최대 3개의 agent 까지 사용할 수 있다.
jetbrains 에서 제공하는 teamcity-agent 이미지에는 docker 가 설치되어 있지 않다.
따라서 docker 를 사용해 빌드해야 하는 경우 에러가 발생하며 이를 해결하기 위해 아래 방법들을 두고 고민했다.
추후 팀시티 버전 업그레이드 시 커스텀 이미지를 새로 만들어야 하는데 귀찮을 것 같아 dind 컨테이너를 함께 배포하는 2번 방법을 선택했다.
위 agent yaml 에 따라 dind 컨테이너 설정을 조금 수정해서 사용해야한다.
팀시티 서버에서 에이전트는 수동으로 할당해줘야 한다.
최초 실행 시 agent pod 이 배포되어 있음에도 상단 메뉴에 Agents 0 를 확인할 수 있다.


Unauthorized agents 를 모두 수동으로 pool 에 할당해줄 수 있다.

위와같이 할당이 끝났다면 agent 가 정상적으로 작업을 수행할 수 있다.
기존 환경에선 RDS 를 사용하고 있었다. 하지만 해당 RDS 인스턴스의 자원이 거의 사용되지 않고 있었고, 온프레미스 환경의 쿠버네티스를 사용하고 있기 때문에 RDS → K8s 로 DB 를 이전했다.
teamcity server 에 접근하면 아래 인스톨러가 실행된다.

Restore from backup 선택 시 기존 backup 파일을 사용해 복구할 수 있다.
단, source database(RDB) 에서 target database(in K8s) 로 마이그레이션 하는 기능은 제공되지 않는다.

Administration → Backup 에서 데이터를 백업할 수 있다.

백업한 데이터를 업로드하고 Proceed 버튼을 누르면 target database 설정을 할 수 있다.

만약 지정한 데이터베이스가 비어있지 않은 경우 아래 에러와 함께 Restore 가 수행되지 않는다.
Found a TeamCity schema when expected an empty database

복구가 끝나면 서버가 재시작되고 서비스를 이용할 수 있다.

인스톨러 초기 화면에서 Restore from backup 가 아니라 Proceed 로 진행할 수 있다.

데이터베이스 정보를 입력하고 진행하면

초기화 기다리고

라이센스 동의하면

관리자 계정을 생성하고 서비스를 이용할 수 있다.