TeamCity On-Premises 2024.03 Help

多节点设置以实现高可用性

TeamCity 服务器可以配置为使用多个节点(或服务器)以实现高可用性和灵活的负载分配。 可以设置一个 TeamCity 节点群集,其中每个节点负责不同的任务,如处理来自构建的数据或从 VCS 仓库收集更改。 或者,保持一个主节点来进行所有的工作,以及一个提供只读接口的次要节点。 如果主节点发生故障,所有的数据处理都可以在最短的停机时间内切换到次级节点。

由于多节点设置的主要用例是实现高可用性(HA),因此本文重点讲述如何配置一个 HA 集群。 然而,您可以对任何具有多个 TeamCity 节点的设置使用相同的方法:例如,分散到多台机器之间的负载。

主节点对比辅助节点

TeamCity 集群可以有一个 主节点 和多个 次要节点。 主节点是首选节点,且默认情况下,它接收所有进来的 HTTP 请求。 它还执行关键的后台任务,例如启动构建。 次要节点主要充当备份服务器,这是故障转移所必需的。 为了更好的负载分配和性能优化,还可以授予 额外的责任

使用两个节点的 TeamCity 设置

高可用性设置

前提条件

一个基本的 HA 配置必须包括以下组件:

  • 专用数据库服务器:来自受支持的数据库列表的外部数据库服务器。

  • 专用于 TeamCity 数据目录的服务器:例如,通过网络使用 NFS 或 SMB 共享 数据目录 给节点。

  • 至少需要两台用于 TeamCity 节点的服务器,并且装有共享数据目录:两台服务器应具有相同或可比的硬件。 否则,如果辅助节点性能较差,您可能会在发生故障切换时体验到显著的性能下降。

  • TeamCity 节点上的本地存储:安装 TeamCity 和存储日志和本地缓存所必需的。 为了估计缓存的大小,请查看您当前安装中 <TeamCity 数据目录>/系统/缓存 目录的大小。

  • 专用的反向 HTTP 代理服务器

对于高可用性设置,所需的服务器机器的最小数量为5台:一个数据库,一个网络存储服务器,两个 TeamCity 节点,以及一个用于反向 HTTP 代理的服务器。 更简单的负载均衡解决方案可能只需要较少的机器就能实现。

共享数据目录

主要的 TeamCity 节点和次要节点必须能够访问并共享相同的 TeamCity 数据目录

这是一些关于设置共享数据目录的主要建议:

  • 对于高可用性设置,将其储存在一个单独且性能良好的机器上,以便在主节点宕机时仍可访问。

  • 所有 TeamCity 节点的机器都应能够以读/写模式访问它。

  • 典型的数据目录挂载选项是 SMB 和 NFS。 TeamCity 使用数据目录作为常规文件系统,因此应支持所有基本的文件系统操作。

  • I/O 操作计数或 I/O 容量限制不应受存储或挂载选项的限制。

  • 请务必查阅您的存储解决方案的性能指南。 例如,增加服务器与存储之间网络连接的 MTU 通常会提高 artifact 的传输速度。

  • 禁用数据目录挂载上的网络客户端缓存

    • 所有节点都能及时看到共享数据目录的当前状态非常重要。 如果情况并非如此,很可能会导致不稳定的行为和频繁的构建日志损坏。

    • 如果 TeamCity 节点在使用 SMB 协议共享数据目录的 Windows 上运行,请确保在所有 TeamCity 节点上将此文章中提到的所有注册表键设置为 0。

    • 如果数据目录是通过 NFS 共享的,确保所有节点在其挂载设置中都有以下选项: lookupcache=positive

所需的 JVM 选项

TeamCity 服务器节点要求您配置以下 JVM 选项:

teamcity.server.nodeId=<node_ID>

TeamCity 节点的唯一标识符,用于 UI 和配置文件中。

teamcity.server.rootURL=<node_root_URL>

TeamCity 节点的根 URL,通常呈现的形式为 http://<node_hostname>。 这个 URL 用于节点间通信,应配置防火墙以允许从一个节点到另一个节点的此 URL 的连接。

teamcity.data.path=<TeamCity数据目录>

(可选) 至共享 TeamCity Data Directory 的挂载点路径。

teamcity.node.data.path=<节点特定的数据目录>

到节点特定的 TeamCity 数据目录的路径,该目录是每个节点上用于节点特定配置和缓存的本地存储。

teamcity.server.responsibilities=<responsibilities_list>

(可选) 用逗号分隔的 责任 列表,用于分配给此节点。

JVM 选项可以使用 TEAMCITY_SERVER_OPTS 环境变量进行配置,其值是以空格分隔的设置列表,格式为 -D < JVMOption > = < Value >

配置 HA 设置

这一部分依赖于以下假设:

现在,我们可以进行从单服务器设置过渡到高可用性集群设置的操作。

要配置由两个节点组成的 TeamCity 集群,请遵循以下步骤:

  1. 请检查安装在两个节点上的 TeamCity 服务器的版本是否相同,并且与 Data Directory 的版本相符。

  2. 为每个节点选择一个 ID :例如,基于主机名的短 ID。

  3. 在每个节点上创建 TEAMCITY_SERVER_OPTS 环境变量。 这个变量应具有以下参数:

    -Dteamcity.server.nodeId=<node_ID> -Dteamcity.server.rootURL=<node_root_URL> -Dteamcity.data.path=<TeamCity Data Directory> -Dteamcity.node.data.path=<Node-specific Data Directory>
  4. 使用 常规 TeamCity 脚本 或通过 TeamCity 服务来启动两个节点。

  5. 在任一服务器上打开 TeamCity Administration | Nodes Configuration页面,并为您想设为主要的节点启用Main TeamCity node 负责人权限。

  6. 继续进行 配置反向 HTTP 代理

代理配置

反向 HTTP 代理充当 TeamCity 用户和 构建代理 的单一端点。 这也是为整个集群配置 HTTPS 连接设置的好地方。

当与 TeamCity 一起使用时,代理服务器也充当传入请求的负载均衡器。 它可以确定应将请求发送到何处,并将其路由到相应的上游服务器。 在这篇文章中,我们为最受欢迎的代理服务器:NGINX,NGINX Plus和HAProxy提供了代理配置的示例。

defaults mode http timeout connect 240s timeout client 1200s timeout server 1200s frontend http-in bind *:80 stats enable stats uri /healthz default_backend web_endpoint option httplog log /dev/log local0 info # Uncomment if logging to stdout is desired (e.g. when running in a containerized environment) #log stdout local0 info option http-buffer-request declare capture request len 40000000 http-request capture req.body id 0 capture request header user-agent len 150 capture request header Host len 15 capture cookie X-TeamCity-Node-Id-Cookie= len 100 http-request add-header X-TeamCity-Proxy "type=haproxy; version=2023.05" http-request set-header X-Forwarded-Host %[req.hdr(Host)] acl node_id_cookie_found req.cook(X-TeamCity-Node-Id-Cookie) -m found acl browser req.hdr(User-Agent) -m sub Mozilla default_backend clients_not_supporting_cookies use_backend clients_with_node_id_cookie if node_id_cookie_found use_backend clients_supporting_cookies if browser backend clients_with_node_id_cookie # this backend handles the clients that provided the "X-TeamCity-Node-Id-Cookie" cookie # clients that do so are TeamCity agents and browsers handling HTTP requests asking to switch to a specific node cookie X-TeamCity-Node-Id-Cookie http-request disable-l7-retry if METH_POST METH_PUT METH_DELETE retry-on empty-response conn-failure response-timeout 502 503 504 retries 5 option httpchk GET /healthCheck/ready default-server check fall 6 inter 10000 downinter 5000 server NODE1 {node1_hostname} cookie {node1_id} server NODE2 {node2_hostname} cookie {node2_id} backend clients_supporting_cookies # this backend is for the browsers without "X-TeamCity-Node-Id-Cookie" # these requests will be served in a round-robin manner to a healthy server balance roundrobin option redispatch cookie TCSESSIONID prefix nocache http-request disable-l7-retry if METH_POST METH_PUT METH_DELETE option httpchk http-check connect http-check send meth GET uri /healthCheck/preferredNodeStatus http-check expect status 200 default-server check fall 6 inter 10000 downinter 5000 on-marked-down shutdown-sessions server NODE1 {node1_hostname} cookie n1 weight 50 server NODE2 {node1_hostname} cookie n2 weight 50 backend clients_not_supporting_cookies # for compatibiity reasons requests from non browser clients are always # routed to a single node (the first healthy) balance first option redispatch http-request disable-l7-retry if METH_POST METH_PUT METH_DELETE option httpchk http-check connect http-check send meth GET uri /healthCheck/preferredNodeStatus http-check expect status 200 default-server check fall 6 inter 10000 downinter 5000 on-marked-down shutdown-sessions server NODE1 {node1_hostname} server NODE2 {node2_hostname}
events { worker_connections 10000; } http { upstream round_robin { zone round_robin 1m; server {node1_hostname}; server {node2_hostname}; sticky cookie X-TeamCity-RoundRobin-Cookie path=/; } upstream first_available { zone first_available 1m; server {node1_hostname} weight=100; server {node2_hostname} weight=1; } upstream sticky_route { zone sticky_route 1m; server {node1_hostname} route={node1_id}; server {node2_hostname} route={node2_id}; sticky route $node_id; } map $http_user_agent $browser { default 0; "~*Mozilla*" 1; } map $http_cookie $node_id_cookie { default 0; "~*X-TeamCity-Node-Id-Cookie" 1; } map "$browser$node_id_cookie" $backend { 00 @clients_not_supporting_cookies; 10 @clients_supporting_cookies; 01 @clients_with_node_id_cookie; 11 @clients_with_node_id_cookie; } map $http_cookie $node_id { default ''; "~*X-TeamCity-Node-Id-Cookie=(?<node_name>[^;]+)" $node_name; } map $http_upgrade $connection_upgrade { # WebSocket support default upgrade; '' ''; } proxy_read_timeout 1200; proxy_connect_timeout 240; client_max_body_size 0; # maximum size of an HTTP request. 0 allows uploading large artifacts to TeamCity server { listen 80; server_name {proxy_server_hostname}; status_zone status_page; set $proxy_header_host $host; set $proxy_descr "type=nginx_plus; version=2023.05"; location / { try_files /dev/null $backend; } location @clients_with_node_id_cookie { # this backend handles the clients which provided the cookie with name "X-TeamCity-Node-Id-Cookie" # such clients are TeamCity agents and browsers handling HTTP requests asking to switch to a specific node proxy_pass http://sticky_route; health_check uri=/healthCheck/ready; proxy_next_upstream error timeout http_503 http_502 non_idempotent; proxy_intercept_errors on; proxy_set_header Host $host:$server_port; proxy_redirect off; proxy_set_header X-TeamCity-Proxy $proxy_descr; proxy_set_header X-Forwarded-Host $http_host; # necessary for proper absolute redirects and TeamCity CSRF check proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header Upgrade $http_upgrade; # WebSocket support proxy_set_header Connection $connection_upgrade; # WebSocket support } location @clients_supporting_cookies { # this backend is for the browsers without "X-TeamCity-Node-Id-Cookie" # these requests will be served in a round-robin manner to a healthy server proxy_pass http://round_robin; health_check uri=/healthCheck/preferredNodeStatus; proxy_next_upstream error timeout http_503 http_502 non_idempotent; proxy_intercept_errors on; proxy_set_header Host $host:$server_port; proxy_redirect off; proxy_set_header X-TeamCity-Proxy $proxy_descr; proxy_set_header X-Forwarded-Host $http_host; # necessary for proper absolute redirects and TeamCity CSRF check proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header Upgrade $http_upgrade; # WebSocket support proxy_set_header Connection $connection_upgrade; # WebSocket support } location @clients_not_supporting_cookies { # for compatibiity reasons requests from non browser clients are always # routed to a single node (the first healthy) proxy_pass http://first_available; health_check uri=/healthCheck/preferredNodeStatus; proxy_next_upstream error timeout http_503 http_502 non_idempotent; proxy_intercept_errors on; proxy_set_header Host $host:$server_port; proxy_redirect off; proxy_set_header X-TeamCity-Proxy $proxy_descr; proxy_set_header X-Forwarded-Host $http_host; # necessary for proper absolute redirects and TeamCity CSRF check proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header Upgrade $http_upgrade; # WebSocket support proxy_set_header Connection $connection_upgrade; # WebSocket support } } }
events { worker_connections 10000; } http { upstream {main_node_id} { server {main_node_hostname}; server {secondary_node_hostname} backup; } upstream {secondary_node_id} { server {secondary_node_hostname}; server {main_node_hostname} backup; } upstream web_requests { server {main_node_hostname}; server {secondary_node_hostname} backup; } map $http_cookie $backend_cookie { default "{main_node_id}"; "~*X-TeamCity-Node-Id-Cookie=(?<node_name>[^;]+)" $node_name; } map $http_user_agent $is_agent { default @users; "~*TeamCity Agent*" @agents; } map $http_upgrade $connection_upgrade { # WebSocket support default upgrade; '' ''; } proxy_read_timeout 1200; proxy_connect_timeout 240; client_max_body_size 0; # maximum size of an HTTP request. 0 allows uploading large artifacts to TeamCity server { listen 80; server_name {proxy_server_hostname}; set $proxy_header_host $host; set $proxy_descr "type=nginx; version=2023.05"; location / { try_files /dev/null $is_agent; } location @agents { proxy_pass http://$backend_cookie; proxy_next_upstream error timeout http_503 non_idempotent; proxy_intercept_errors on; proxy_set_header Host $host:$server_port; proxy_redirect off; proxy_set_header X-TeamCity-Proxy $proxy_descr; proxy_set_header X-Forwarded-Host $http_host; # necessary for proper absolute redirects and TeamCity CSRF check proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header Upgrade $http_upgrade; # WebSocket support proxy_set_header Connection $connection_upgrade; # WebSocket support } location @users { proxy_pass http://web_requests; proxy_next_upstream error timeout http_503 non_idempotent; proxy_intercept_errors on; proxy_set_header Host $host:$server_port; proxy_redirect off; proxy_set_header X-TeamCity-Proxy $proxy_descr; proxy_set_header X-Forwarded-Host $http_host; # necessary for proper absolute redirects and TeamCity CSRF check proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header Upgrade $http_upgrade; # WebSocket support proxy_set_header Connection $connection_upgrade; # WebSocket support } } }

选择正确的代理服务器

TeamCity 可以与不同类型的代理服务器一起工作。 然而,HAProxyNGINX Plus 更为可取,因为这些服务器支持主动健康检查和粘性会话。 这些特性对于用户请求在不同节点(由 TeamCity 2023.05+ 支持)之间的 round-robin 来说是至关重要的。

相比之下,常规的 NGINX 代理使用标准模块,缺乏这些功能并且不能用于配置轮询。

另外,常规的 NGINX 要求您在配置文件中明确区分主节点和辅助节点(主节点应该在列表中的首位)。 此要求强制您在主节点将其职责转移给次要节点时(例如,在故障转移的情况下),手动更新节点角色。 HAProxy 和 NGINX Plus 服务器在同一情境下不需要您手动更新配置文件。

最后,HAProxyNGINX Plus 代理服务器的配置文件更易于维护,尤其是在向集群中添加新节点时。

将代理版本与服务器匹配

上述示例中的 代理配置 设定了一个特殊的 X-TeamCity-Proxy 头部。 这个标题通知 TeamCity,请求是通过正确配置的代理传递的。

X-TeamCity-Proxy 标题还定义了代理配置的一个版本。 如果此版本与当前的 TeamCity 版本不兼容,TeamCity 会显示 代理配置版本不匹配 健康报告。 请检查您的代理设置,确保它们与 代理配置 部分中所示的配置类似。

轮询

从2023.05版本开始,配置有处理 UI 动作和负载均衡用户请求责任的主要 TeamCity 节点和每个辅助节点都参与轮询。

代理将第一个浏览器请求随机路由到任何参与的节点。 随后的 HTTP 请求将被发送到同一节点(粘性会话)。 此行为将用户请求产生的负载分布到不同的节点中,可能允许 TeamCity 处理更多的同时 HTTP 请求。 此外,轮询在故障转移发生或计划节点重启的情况下,有助于提升用户体验。 例如,如果需要重新启动单个节点,只有分配给该节点的用户会受到影响。 一旦代理服务器检测到节点不再可用,所有这些用户将会被分配到其他节点。

如果一个请求必须由特定的节点处理,而不是随机分配给任何节点,那么请在 TeamCity UI 底部使用节点选择器,或者在请求查询字符串中添加 __nodeId=<节点的id> 请求参数。

要将节点添加到或从轮询列表中删除,请更改 处理 UI 操作和负载均衡用户请求 责任的状态。 不需要更改代理配置。

域隔离代理配置

域隔离模式要求配置一个专用域来存储工件。 请确保在您的 DNS 中添加一个新的记录,将此域名指向代理地址:例如,可能是一个指向代理 URL 的 CNAME 记录。

故障转移

在发生故障切换的情况下,当主节点由于崩溃或维护而无法使用时,可以将 Main TeamCity node 的责任赋予次级节点,并暂时或永久地作为主节点运行。

每个二级节点都会跟踪当前主节点的活动,如果主节点在数分钟(默认为3分钟)内无活动,将会显示对应的健康报告。 主 Main TeamCity Node 的责任可以通过 TeamCity UI 或 REST API 重新分配给另一个节点。 然而,如果这种不活动状态并非计划中的(也就是说,主节点已经崩溃),那么,确认在非活动节点上没有剩余的 TeamCity 服务器进程在运行就显得非常重要。 如果您检测到此类进程,需要在重新分配 Main TeamCity node 责任之前停止它们。

如果您使用标准的 NGINX 代理服务器,请在 反向代理配置中更新节点 ID 和主机名,然后在切换 Main TeamCity Node 负责人后重新加载代理服务器配置。 HAProxy 和 NGINX Plus 代理服务器不需要手动更新配置。

总的来说,如果发生故障转移,请遵循以下步骤:

  1. 在次要节点上等待有关主节点不可用的服务器健康报告。

  2. 确保主节点已停止。

  3. Main node 的责任切换到次级节点上。

  4. (如果使用的是常规 NGINX)更新反向代理配置中的主节点 ID,并重新加载配置。

通过 REST API 监控和管理节点

从 TeamCity 2022.10 开始,您可以使用 REST API 来检查节点状态和重新分配节点职责。

要获取所有在线节点的列表,请使用:

GET /app/rest/server/nodes?locator=state:online

要将 Main node 的责任分配给次级节点,请使用:

PUT /app/rest/server/nodes/id:<node id>/enabledResponsibilities/MAIN_NODE

与 curl 的相同示例:

curl \ -X PUT \ -H "Content-Type: text/plain" \ -H "Origin: <host>:<port>" \ --data-raw "true" \ --header “Authorization: Bearer <token-value>” \ "https://<host>:<port>/app/rest/server/nodes/id:<node id>/enabledResponsibilities/MAIN_NODE"
GET /app/rest/server/nodes/id:<node id>/effectiveResponsibilities

节点配置

认证和许可证

主节点和辅助节点在同一许可证下运行。

次级节点使用与主节点相同的认证设置。 然而,用户在被路由到次级节点后可能会被要求再次登录。 这种情况发生在两种情况下:(1)用户在登录屏幕上没有选择记住我选项,和(2)SSO 认证未配置。

全局设置

次级节点使用与主节点相同的全局设置(路径到工件,版本控制设置等)。

责任

默认情况下,新启动的辅助节点提供只读用户界面,并且不执行任何后台活动。 您可以在 Administration | Server Administration | Nodes Configuration 中为每个次要节点分配以下额外的职责:

为了让用户能够执行构建和代理上的最常见操作,启用 处理 UI 操作和负载均衡用户请求 责任。

您可以随时启用和禁用节点的责任。

在辅助节点上处理构建产生的数据

可以使用一个或多个次要节点来处理来自 TeamCity 代理的流量。 这允许将相关负载移至主 TeamCity 节点之外的单独机器上,当处理数百个并发且活跃记录的构建时,将会提升 TeamCity 的性能。

一般来说,除非您有超过400个代理连接到单个节点,否则您不需要为运行构建使用单独的节点。 使用辅助节点可以显著增加设置能处理的代理数量。

一旦您第一次将辅助节点分配给处理构建产生的数据的责任,所有新启动的构建都将被路由到这个节点。 现有的运行构建将继续在主节点上执行。 当您禁用责任时,只有新启动的构建将切换到主节点。 已在辅助节点上运行的构建将会继续在那里运行。
如果您为这个职责分配了多个辅助节点,那么构建将在这些节点之间均等分配。

在次要节点上轮询 VCS 仓库

最初,只有主 TeamCity 节点会轮询 VCS 仓库以查找新的提交。 在多个节点上启用 VCS Repositories Polling 责任可以分散这种可能较慢的活动,并减少启动新构建的延迟。

在您的主节点上配置的提交钩子不需要任何更改,在将 VCS 轮询委托给次要节点后仍然可以正常工作。

在次要节点上处理触发器

在配置了许多构建代理的设置中,主节点的大量 CPU 被分配用于不断处理构建触发器。 通过启用一个或多个辅助节点的 Processing build trigger 责任,您可以在主节点和负责的辅助节点之间分配触发处理任务和 CPU 负载。 TeamCity 会自动分发触发器,但您可以查看当前分配给每个节点的触发器是什么。

处理用户界面操作和负载均衡用户请求

这项责任负责允许用户在辅助节点上进行操作。 当主节点关闭或进行维护时,它尤其有用。

启用此责任还会将节点添加到参与 round-robin 的节点列表中。

主节点责任

您可以将一个辅助节点分配给 Main TeamCity node 的责任。 这个责任默认由当前主节点承担,但如果此节点变得无法使用,该责任则会变得空缺。 在您将任何次要节点指定给这个责任后,它将变成主节点,并且额外接收 处理用户界面操作和负载均衡用户请求 的责任。 所有正在运行的构建将在不中断的情况下继续其操作。 如果您的设置中配置了 代理,构建代理将无缝地重新连接到新的主节点。
当先前的主节点再次启动时,它将变为次节点,因为主 TeamCity 节点的责任已被另一个节点占据。 如有必要,您可以重复上述步骤,以在这些节点之间切换角色。

在命令行上设置责任

您可以使用以下的 JVM 选项来定义服务器的责任:

teamcity.server.responsibilities=<responsibilities_list>

在服务器的环境中,将 JVM 选项添加到 TEAMCITY_SERVER_OPTS 环境变量中,将责任指定为逗号分隔的列表。 例如:

-Dteamcity.server.responsibilities=CAN_PROCESS_BUILD_MESSAGES,CAN_CHECK_FOR_CHANGES,CAN_PROCESS_BUILD_TRIGGERS,CAN_PROCESS_USER_DATA_MODIFICATION_REQUESTS

以下职责可以被启用:

标识符

责任

CAN_PROCESS_BUILD_MESSAGES

处理构建产生的数据

CAN_CHECK_FOR_CHANGES

VCS 仓库轮询

CAN_PROCESS_BUILD_TRIGGERS

处理构建触发器

CAN_PROCESS_USER_DATA_MODIFICATION_REQUESTS

处理 UI 操作和负载均衡用户请求

MAIN_NODE

主要的 TeamCity 节点

请注意,当服务器的职责在命令行上设置时,适用以下限制:

  • 无法从命令行指定 要处理的构建的最大百分比 或分配给每个节点的 触发器。 这些责任设置只能通过用户界面或 REST API 来获取。

  • 如果启用了 CAN_PROCESS_USER_DATA_MODIFICATION_REQUESTS 责任,则您可以使用 UI 或 REST API 编辑服务器的责任,但只有在您直接连接到服务器时才可以。 此外,这些更改仅为临时性(节点重启时,它们将被重置)。

内部属性

所有 TeamCity 节点都依赖于共享的内部属性,这些属性存储在 共享数据目录中,以及特定属性,存储在节点特定的数据目录中。 节点特定的属性具有更高的优先级,并在发生冲突时覆盖通用值。

要在给定的次级节点上禁用任何常见属性,请使用以下语法进行传递: -<property_name>

次要节点内存设置

次级节点需要与主节点相同的内存设置。 如果您已经为主节点配置了 TEAMCITY_SERVER_MEM_OPTS 环境变量,请确保为次节点使用相同的变量。 如果您的主节点使用了64位的JVM,那么次节点也必须使用64位的JVM。

环境变量

以下环境变量可用于配置 TeamCity 服务器节点:

变量

描述

TEAMCITY_DATA_PATH

指向共享的 TeamCity Data Directory 的路径。

TEAMCITY_SERVER_OPTS

(必需) 服务器 JVM 选项(参见 必需的 JVM 选项)。

TEAMCITY_SERVER_MEM_OPTS

服务器 JVM 内存选项(请参阅 JVM 选项)。

管理节点

项目导入

您只能将项目导入到主节点。 次级节点将在运行时检测到导入的数据,无需重新启动。

清理

TeamCity 清理任务可以在任何 TeamCity 节点上进行调度,但只在主节点上执行。 在多节点配置中,就像在单个节点配置中一样,任务可以在辅助节点处理他们的操作时运行。

使用插件

辅助节点可以访问主节点上启用的所有插件。 它还会监视新上传的插件。 如果次级节点检测到插件已上传至主节点,它将在其 Administration | Plugins 页面上显示相应的通知。 如果插件支持,您无需重新启动辅助节点,可以在运行时重新加载——相应的提示将显示在用户界面中。

自动添加辅助节点

您可以通过利用 TeamCity 服务器 环境变量,以最少的手动干预(例如,在脚本中)启动一个二级节点的实例,这些环境变量提供了二级节点的基本配置。

为了以适合自动化的方式创建一个二级节点,请遵循以下步骤:

  1. 准备 TeamCity 服务器软件,可以通过下载并安装分发包,或者拉取适当的 Docker 镜像。 确保 TeamCity 软件的版本与在其他节点上运行的版本相同。

  2. 挂载共享的 TeamCity 数据目录(例如,使用 NFS 或 SMB)。

  3. 通过设置 TEAMCITY_DATA_PATH 环境变量,提供到共享 TeamCity Data Directory 的路径。

  4. 通过设置 TEAMCITY_SERVER_OPTS 环境变量并以空格分隔的 JVM 选项列表,为节点提供 JVM 选项,如下:

    TEAMCITY_SERVER_OPTS = -Dteamcity.server.nodeId=<node_ID> -Dteamcity.server.rootURL=<node_URL> -Dteamcity.node.data.path=<Node-specific Data Directory> -Dteamcity.server.responsibilities=<responsibilities_list>

    Where:

    • <node_ID> 是节点的唯一 ID,应专门为此节点生成。

    • <node_URL> 是次级节点根网址,应该能从主节点访问。

    • <Node-specific Data Directory> 是指向特定节点的 TeamCity 数据目录的路径。

    • <responsibilities_list> 是在此节点上启用的责任列表,各项责任间以逗号分隔。

  5. 如有需要,可通过设置 TEAMCITY_SERVER_MEM_OPTS 环境变量来指定 JVM 内存选项。

  6. 使用 常规 TeamCity 脚本 启动 TeamCity 服务器,或使用 TeamCity 服务,或运行 TeamCity 服务器 docker 容器。

升级/降级

建议主 TeamCity 节点和所有次要节点使用相同的版本。 在某些情况下,主节点和次节点可能在短时间内运行不同的版本,例如,在主节点的次要升级期间。 当次要节点和主节点的版本不同时,相应的健康报告将在两个节点上显示。

升级到次版本(一个错误修复版本)时,主节点和辅助节点应该无故障地运行,因为 TeamCity 数据格式保持不变。 您可以升级主 TeamCity 节点,然后再手动或使用 自动更新来升级次要节点 升级 TeamCity 服务器和代理

将主节点升级到主要版本时,其 TeamCity 数据格式会发生变化。 因此,一旦新版本的主节点启动,辅助节点会检测到主节点的数据格式已经发生变化,并切换到只读模式。 副节点可能需要一些时间才能变成只读模式。 在此期间,主节点将等待,直到确保所有其他节点不再更改数据。

要将多节点设置中的节点升级到 TeamCity 的主要版本,请按照以下步骤操作:

  1. 升级 主要的 TeamCity 节点。 升级笔记的过程与更新独立服务器的过程相同。

  2. 请确认所有内容都运行正常,且代理程序正在连接到主节点(代理程序将把本应路由到次级节点的数据重新路由至主节点)。

  3. 将 TeamCity 在次级节点上升级到相同的版本。

要在多节点设置中对 downgrade 节点进行操作,请遵循以下步骤:

  1. 关闭主节点和次要节点。

  2. 从备份中恢复数据(仅在升级过程中更改了数据格式时)。

  3. 将主节点上的 TeamCity 软件降级。

  4. 启动主要的 TeamCity 节点并验证所有内容是否正常运行。

  5. 将副节点上的 TeamCity 软件降级到与主节点相同的版本。

  6. 启动次级节点。

TeamCity 代理将自动执行升级/降级。

开始/停止

任何 TeamCity 节点都可以使用常规的 TeamCity 脚本 ( teamcity-server.batteamcity-server.sh )或 Windows 服务来启动/停止。 环境变量 [ TEAMCITY_DATA_PATH]、 [ TEAMCITY_SERVER_MEM_OPTS] 和 [ TEAMCITY_SERVER_OPTS] 由所有类型的节点支持。

所有节点都采用相同的方法来记录事件。 您可以在 <TeamCity 安装目录>/logs/teamcity-server.log 文件中检查启动的状态。 或者,您可以在浏览器中打开 <node root URL> ,查看 TeamCity 启动界面。

次要节点,以及主要节点,可以在构建运行时停止或重新启动。 他们将继续在代理上运行,要么会被代理重新分配给另一个节点,要么等待他们的指定节点再次启动。

备份/恢复

您可以在任何具有 处理 UI 动作和负载均衡用户请求 职责的节点上从 TeamCity UI 启动备份。 您也可以在任何节点上 从命令行 启动备份。 在备份运行期间,所有其他节点不允许调度清理、导入项目或启动另一个备份进程。

恢复操作可以在任何节点上执行,但前提是使用 TeamCity 数据库和数据目录的所有节点都已停止。

多节点设置健康报告

请参阅专用文章中的相关报告。

常见问题

无法从 Windows 服务访问数据目录

请注意,如果 TeamCity 作为 Windows 上的一项服务在运行,它可能无法通过映射的网络驱动器访问 TeamCity 数据目录。 这是因为 Windows 服务不能处理映射的网络驱动器,且 TeamCity 不支持 UNC 格式( \\host\directory )作为数据目录路径。 为了解决这个问题,您可以使用 mklink ,因为它允许在网络驱动器上创建符号链接:

mklink /d "C:\<path to mount point>" "\\<host>\<shared directory name>\"

确保您的操作系统中已启用远程到本地的符号链接求值:

fsutil behavior query SymlinkEvaluation

要启用它们,请使用以下命令:

fsutil behavior set SymlinkEvaluation R2L:1
最后修改日期: 16日 7月 2024年