feat(infra): add POP2-HC-32C-64G CPU compile pool for 4x faster builds
Split runners into CPU (compile/build/deploy) and GPU (training): - CPU runner: tags kapsule,rust,docker → ci-compile-cpu (32 vCPU, 64GB) - GPU runner: tags kapsule,gpu → ci-compile (L4) or ci-training (L40S) Changes: - Add ci-compile-cpu Terraform pool (POP2-HC-32C-64G, autoscale 0-1) - Set CARGO_BUILD_JOBS=30 to use all CPUs for Rust compilation - Increase CPU request to 28000m/31000m (was 7000m/7800m on L4) - Add docker tag to deploy/infra jobs for explicit CPU runner routing - Update CI header with new pool routing documentation Cost: EUR 0.85/h (vs EUR 1.1/h for L4) — cheaper AND 4x faster compile Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,12 +1,14 @@
|
||||
# GitLab CI/CD — Foxhunt
|
||||
# Compile: ci-compile pool (L4, CUDA 8.9) | Training: ci-training pool (L40S, 48GB VRAM)
|
||||
# Two runners: CPU (compile/build/deploy) and GPU (training)
|
||||
# CI builder image: CUDA 12.4 + Rust 1.89 + protoc + sccache (hosted on Scaleway CR)
|
||||
# Service images: pushed to Scaleway Container Registry (Kaniko)
|
||||
# Note: .gitlab-ci.yml itself is NOT in changes: filters — CI-only edits skip build
|
||||
#
|
||||
# Node pool routing: Runner default nodeSelector pool=ci-compile.
|
||||
# Override via KUBERNETES_NODE_SELECTOR_pool: "pool=<pool-name>" (k=v format required)
|
||||
# Pools: ci-compile (L4 GPU), ci-training (L40S GPU), services (DEV1-M), gitlab (GP1-XS)
|
||||
# Runner routing (by tags):
|
||||
# kapsule,rust,docker → CPU runner → ci-compile-cpu pool (POP2-HC-32C-64G, 32 vCPU)
|
||||
# kapsule,gpu → GPU runner → ci-compile (L4) or ci-training (L40S)
|
||||
# Override nodeSelector: KUBERNETES_NODE_SELECTOR_pool: "pool=<name>" (k=v format)
|
||||
# Pools: ci-compile-cpu (POP2-HC), ci-compile (L4), ci-training (L40S), services, gitlab
|
||||
|
||||
# Ensure pipeline is always created — individual job rules handle filtering.
|
||||
# Without this, GitLab CE may silently drop push pipelines when changes:
|
||||
@@ -151,8 +153,7 @@ build-infra-runner:
|
||||
|
||||
# Base template for Rust jobs — pre-baked CI builder from Scaleway CR
|
||||
# Image pre-exists in SCR; rebuild via build-ci-builder when Dockerfile changes
|
||||
# Runs on pool=ci-compile (L4: 24GB VRAM, CUDA CC 89) by default (runner nodeSelector)
|
||||
# Training jobs override via KUBERNETES_NODE_SELECTOR_pool: ci-training (L40S: 48GB VRAM)
|
||||
# Runs on ci-compile-cpu pool (POP2-HC-32C-64G: 32 vCPU, 64GB RAM) via CPU runner
|
||||
.rust-base:
|
||||
image: ${CI_BUILDER_IMAGE}
|
||||
tags:
|
||||
@@ -162,11 +163,12 @@ build-infra-runner:
|
||||
# Compile uses CUDA stubs from ci-builder image — no nvidia runtime needed.
|
||||
# L4 GPU = compute capability 8.9 → candle-kernels generates sm_89 PTX
|
||||
CUDA_COMPUTE_CAP: "89"
|
||||
# Give compile pods all available CPU for fast Rust compilation
|
||||
KUBERNETES_CPU_REQUEST: "7000m"
|
||||
KUBERNETES_CPU_LIMIT: "7800m"
|
||||
KUBERNETES_MEMORY_REQUEST: "16Gi"
|
||||
KUBERNETES_MEMORY_LIMIT: "80Gi"
|
||||
# Use all 32 vCPUs on POP2-HC for maximum Rust compilation parallelism
|
||||
CARGO_BUILD_JOBS: "30"
|
||||
KUBERNETES_CPU_REQUEST: "28000m"
|
||||
KUBERNETES_CPU_LIMIT: "31000m"
|
||||
KUBERNETES_MEMORY_REQUEST: "24Gi"
|
||||
KUBERNETES_MEMORY_LIMIT: "56Gi"
|
||||
before_script:
|
||||
# Mold linker fallback — .cargo/config.toml uses -fuse-ld=mold via clang.
|
||||
# clang's -fuse-ld=mold searches for "ld.mold" (not "mold") in its linker paths.
|
||||
@@ -1154,6 +1156,7 @@ infra-plan:
|
||||
image: ${INFRA_RUNNER_IMAGE}
|
||||
tags:
|
||||
- kapsule
|
||||
- docker
|
||||
needs: []
|
||||
rules:
|
||||
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
||||
@@ -1186,6 +1189,7 @@ infra-apply:
|
||||
image: ${INFRA_RUNNER_IMAGE}
|
||||
tags:
|
||||
- kapsule
|
||||
- docker
|
||||
needs:
|
||||
- job: infra-plan
|
||||
optional: true
|
||||
@@ -1214,6 +1218,7 @@ infra-drift-check:
|
||||
image: ${INFRA_RUNNER_IMAGE}
|
||||
tags:
|
||||
- kapsule
|
||||
- docker
|
||||
needs: []
|
||||
rules:
|
||||
- if: $CI_PIPELINE_SOURCE == "schedule" && $DRIFT_CHECK == "true"
|
||||
@@ -1253,9 +1258,9 @@ deploy:
|
||||
image: ${INFRA_RUNNER_IMAGE}
|
||||
tags:
|
||||
- kapsule
|
||||
- docker
|
||||
variables:
|
||||
# Deploy runs on ci-compile (nvidia runtime required by runner default).
|
||||
# 200m CPU fits alongside compile since deploy runs in a later stage.
|
||||
# Deploy runs on CPU compile pool (lightweight kubectl apply)
|
||||
KUBERNETES_CPU_REQUEST: "200m"
|
||||
KUBERNETES_CPU_LIMIT: "500m"
|
||||
KUBERNETES_MEMORY_REQUEST: "256Mi"
|
||||
|
||||
@@ -21,6 +21,11 @@ inputs = {
|
||||
ci_compile_type = "L4-1-24G"
|
||||
ci_compile_max_size = 1
|
||||
|
||||
# CPU compile pool (POP2-HC for cargo check/build — 32 vCPU, no GPU)
|
||||
enable_ci_compile_cpu_pool = true
|
||||
ci_compile_cpu_type = "POP2-HC-32C-64G"
|
||||
ci_compile_cpu_max_size = 1
|
||||
|
||||
# CI training pool (L40S for hyperopt + training — 48GB VRAM, CUDA CC 89)
|
||||
enable_ci_training_pool = true
|
||||
ci_training_type = "L40S-1-48G"
|
||||
|
||||
@@ -109,6 +109,25 @@ resource "scaleway_k8s_pool" "ci_training" {
|
||||
}
|
||||
}
|
||||
|
||||
# CPU compile pool (POP2-HC — high CPU, no GPU, for cargo check/build)
|
||||
resource "scaleway_k8s_pool" "ci_compile_cpu" {
|
||||
count = var.enable_ci_compile_cpu_pool ? 1 : 0
|
||||
cluster_id = scaleway_k8s_cluster.foxhunt.id
|
||||
name = "ci-compile-cpu"
|
||||
node_type = var.ci_compile_cpu_type
|
||||
size = 1
|
||||
min_size = 0
|
||||
max_size = var.ci_compile_cpu_max_size
|
||||
autoscaling = true
|
||||
autohealing = true
|
||||
public_ip_disabled = var.public_ip_disabled
|
||||
region = var.region
|
||||
|
||||
lifecycle {
|
||||
ignore_changes = [size]
|
||||
}
|
||||
}
|
||||
|
||||
# CPU pool for remote development (DevPod — autoscales to zero)
|
||||
resource "scaleway_k8s_pool" "dev" {
|
||||
count = var.enable_dev_pool ? 1 : 0
|
||||
|
||||
@@ -29,6 +29,11 @@ output "ci_compile_pool_id" {
|
||||
value = var.enable_ci_compile_pool ? scaleway_k8s_pool.ci_compile[0].id : ""
|
||||
}
|
||||
|
||||
output "ci_compile_cpu_pool_id" {
|
||||
description = "ID of the CPU compile node pool (POP2-HC)"
|
||||
value = var.enable_ci_compile_cpu_pool ? scaleway_k8s_pool.ci_compile_cpu[0].id : ""
|
||||
}
|
||||
|
||||
output "ci_training_pool_id" {
|
||||
description = "ID of the CI training node pool (L40S)"
|
||||
value = var.enable_ci_training_pool ? scaleway_k8s_pool.ci_training[0].id : ""
|
||||
|
||||
@@ -75,6 +75,24 @@ variable "ci_training_max_size" {
|
||||
default = 1
|
||||
}
|
||||
|
||||
variable "enable_ci_compile_cpu_pool" {
|
||||
description = "Create high-CPU node pool for CI compilation (no GPU needed)"
|
||||
type = bool
|
||||
default = false
|
||||
}
|
||||
|
||||
variable "ci_compile_cpu_type" {
|
||||
description = "Instance type for the CPU compile pool (high CPU, no GPU)"
|
||||
type = string
|
||||
default = "POP2-HC-32C-64G"
|
||||
}
|
||||
|
||||
variable "ci_compile_cpu_max_size" {
|
||||
description = "Maximum number of nodes in the CPU compile pool"
|
||||
type = number
|
||||
default = 1
|
||||
}
|
||||
|
||||
variable "enable_dev_pool" {
|
||||
description = "Create CPU node pool for remote development (DevPod)"
|
||||
type = bool
|
||||
|
||||
Reference in New Issue
Block a user