Kubernetes CI/CD Cluster – VM Design & IP Plan
Scope Legend
AC CI/CD VM Inputs
Shared ARC Controller Inputs
Generic Organization and Repository Inputs
Computed Shared Values
https://ac-cicd-api.aspireclan.com192.168.8.60192.168.8.0/22192.168.8.1arc-systems/arcarc-runners-<app-short-form>-<environment>Multi-GitHub Organization Design
- Kubernetes cluster, API VIP, and load balancer
- Control-plane VMs and environment worker VMs
- ARC controller at
arc-systems/arc - Runner namespace prefix and worker workload label
- Harbor server, reverse proxy, TLS endpoint, and base networking
- Environment worker capacity, monitoring, and cluster upgrades
- Unique app short form and GitHub organization name
- GitHub App, installation ID, private key, and repository access
- Runner namespaces for each required environment
- GitHub App and Harbor secrets inside those namespaces
- One Harbor project and separate CI/runtime robot accounts
- Organization working folder and scoped checklist state
- Service / app name and GitHub repository URL
- Runner scale-set name, Helm release, and values file
- Application image repository and workflow runner reference
- Repository-level Harbor secrets and variables for GitHub Free
- Repository-specific build and deployment settings
Current Organization-Derived Values
| Value | Generated result | Scope |
|---|---|---|
| GitHub organization | <github-organization> | Per GitHub organization |
| App short form | <app-short-form> | Per GitHub organization and globally unique in this cluster |
| Target environment | <environment> | Per organization deployment |
| Target runner namespace | arc-runners-<app-short-form>-<environment> | Per organization and environment |
| GitHub App secret | <app-short-form>-arc-ghapp-secret | Per organization namespace |
| Harbor pull secret | <app-short-form>-harbor-regcred | Per organization namespace |
| Harbor CI credentials secret | <app-short-form>-harbor-credentials | Per organization namespace |
| Harbor project | <app-short-form>-ci-cd | Per product / GitHub organization |
| ARC working folder | ~/arc/<app-short-form> | Per organization |
| Harbor CI robot | Pull + Push | Per organization; used by GitHub Actions / ARC runners |
| Harbor runtime robot | Pull only | Per organization; used by Kubernetes imagePullSecrets |
Isolation Boundary by Layer
| Layer | Shared or Isolated | Design |
|---|---|---|
| Load balancer and API VIP | SHARED | One endpoint for the Kubernetes control plane. |
| Kubernetes control planes | SHARED | One highly available cluster for all CI/CD runner scale sets. |
| ARC controller | SHARED | One controller at arc-systems/arc. |
| Environment worker VMs | SHARED BY ENVIRONMENT | Dev runners share dev workers, QA runners share QA workers, and prod runners share prod workers. |
| Runner namespaces | PER ORGANIZATION | arc-runners-<app-short-form>-<environment> |
| GitHub Apps and Kubernetes secrets | PER ORGANIZATION | Each GitHub organization uses its own GitHub App and namespace-scoped secrets. |
| Harbor project and robots | PER ORGANIZATION | One project per product with separate CI and runtime credentials. |
| Runner scale-set Helm releases | PER REPOSITORY | Each private repository uses a unique release and runner scale-set name. |
Repository-Level Runner Resources
| Repository-level value | Generated result |
|---|---|
| Service / App Name | <service-name> |
| GitHub repository URL | https://github.com/<github-organization>/<service-name> |
| Runner scale-set / Helm release | <service-name>-<environment>-arc |
| Runner values file | ~/arc/<app-short-form>/<service-name>-<environment>-values.yaml |
| Harbor image repository | harbor.aspireclan.com/<app-short-form>-ci-cd/<service-name>:<tag> |
| Repository-level Actions secrets | HARBOR_USERNAME, HARBOR_PASSWORD |
| Repository-level Actions variables | HARBOR_REGISTRY, HARBOR_PROJECT |
- Create a separate runner scale-set release for each repository and environment.
- Grant the organization GitHub App access only to the required private repositories.
- On GitHub Free, configure
HARBOR_USERNAMEandHARBOR_PASSWORDas repository secrets. - Configure
HARBOR_REGISTRYandHARBOR_PROJECTas repository variables. - Do not depend on organization-level or environment-level Actions secrets or variables for private repositories.
- Keep the organization namespace and Harbor project shared across repositories in the same product organization.
Final VM Plan
Create the Kubernetes API VIP and load balancer plan
COMMON · NO CHANGE NEEDEDUse the following API endpoint for the kubeadm control-plane endpoint and future kubeconfig access.
ac-cicd-api.aspireclan.com192.168.8.60https://ac-cicd-api.aspireclan.comCreate the load balancer VM
COMMON · NO CHANGE NEEDEDac-cicd-lb-01ac-cicd-lb-01.aspireclan.com192.168.8.611 vCPU / 2 GB / 20 GBCreate the control plane VMs
COMMON · NO CHANGE NEEDED| VM Name | FQDN | IP | vCPU | RAM | Disk | CI/CD Responsibility |
|---|---|---|---|---|---|---|
| ac-cicd-cp-01 | ac-cicd-cp-01.aspireclan.com | 192.168.8.62 | 2 | 8 GB | 100 GB | Shared Kubernetes control plane and ARC controller placement |
| ac-cicd-cp-02 | ac-cicd-cp-02.aspireclan.com | 192.168.8.63 | 2 | 8 GB | 100 GB | Shared Kubernetes control plane |
| ac-cicd-cp-03 | ac-cicd-cp-03.aspireclan.com | 192.168.8.64 | 2 | 8 GB | 100 GB | Shared Kubernetes control plane |
Create the worker VMs
COMMON · NO CHANGE NEEDED| VM Name | FQDN | IP | vCPU | RAM | Disk | Role | Expected Labels |
|---|---|---|---|---|---|---|---|
| ac-cicd-prod-wk-01 | ac-cicd-prod-wk-01.aspireclan.com | 192.168.8.71 | 8 | 24 GB | 250 GB | Shared prod ARC runner worker | env=prod workload=arc-runner |
| ac-cicd-prod-wk-02 | ac-cicd-prod-wk-02.aspireclan.com | 192.168.8.72 | 8 | 24 GB | 250 GB | Shared prod ARC runner worker | env=prod workload=arc-runner |
| ac-cicd-qa-wk-01 | ac-cicd-qa-wk-01.aspireclan.com | 192.168.8.81 | 8 | 24 GB | 250 GB | Shared QA ARC runner worker | env=qa workload=arc-runner |
| ac-cicd-dev-wk-01 | ac-cicd-dev-wk-01.aspireclan.com | 192.168.8.91 | 8 | 24 GB | 250 GB | Shared dev ARC runner worker | env=dev workload=arc-runner |
Runner Worker Placement
Apply environment and workload labels to the shared worker nodes. Do not assign an application or GitHub organization label in the default design because runner scale sets from different GitHub organizations intentionally share the worker pool for their environment.
kubectl label node ac-cicd-prod-wk-01 env=prod workload=arc-runner --overwrite
kubectl label node ac-cicd-prod-wk-02 env=prod workload=arc-runner --overwrite
kubectl label node ac-cicd-qa-wk-01 env=qa workload=arc-runner --overwrite
kubectl label node ac-cicd-dev-wk-01 env=dev workload=arc-runner --overwritekubectl get nodes -L env,workloadmaxRunners values for the same environment must be planned against the combined capacity of that environment's worker nodes. Add another worker VM before increasing concurrency beyond safe shared capacity.When Dedicated Organization Worker VMs Become Appropriate
Keep the shared environment worker model initially. Add dedicated organization workers only when one of these conditions appears:
- A product needs hard compute isolation beyond namespace and secret isolation.
- One organization's builds regularly exhaust shared CPU, memory, disk, or Docker capacity.
- A product requires different operating-system, tooling, network, or compliance controls.
- Production release workloads need a dedicated failure or maintenance boundary.
A future dedicated worker can use labels such as env=<environment>, workload=arc-runner, and app=<app-short-form>. Only then should the matching runner values add an application-specific node selector and toleration.
DNS Plan
Create the internal DNS records
COMMON · NO CHANGE NEEDEDAdd internal DNS records for all nodes and for the Kubernetes API VIP.
# Cluster API VIP
192.168.8.60 ac-cicd-api.aspireclan.com
# Load balancer
192.168.8.61 ac-cicd-lb-01.aspireclan.com
# Control planes
192.168.8.62 ac-cicd-cp-01.aspireclan.com
192.168.8.63 ac-cicd-cp-02.aspireclan.com
192.168.8.64 ac-cicd-cp-03.aspireclan.com
# Shared environment workers
192.168.8.71 ac-cicd-prod-wk-01.aspireclan.com
192.168.8.72 ac-cicd-prod-wk-02.aspireclan.com
192.168.8.81 ac-cicd-qa-wk-01.aspireclan.com
192.168.8.91 ac-cicd-dev-wk-01.aspireclan.comKubeadm Endpoint
Use the control-plane endpoint during cluster initialization
COMMON · NO CHANGE NEEDEDkubeadm init \
--control-plane-endpoint "ac-cicd-api.aspireclan.com:443" \
--upload-certsProxmox Notes
Use consistent VM settings in Proxmox
COMMON · NO CHANGE NEEDED- OS: Ubuntu Server 24.04 LTS
- CPU Type: host
- Machine Type: q35
- Disk Controller: VirtIO SCSI single
- NIC Model: VirtIO
- Enable QEMU Guest Agent
- Disable swap in guest after OS install
- Keep worker VM names environment-based, not GitHub-organization-based, while workers are shared.
Create VMs in this order
COMMON · NO CHANGE NEEDED- ac-cicd-lb-01
- ac-cicd-cp-01
- ac-cicd-cp-02
- ac-cicd-cp-03
- ac-cicd-prod-wk-01
- ac-cicd-prod-wk-02
- ac-cicd-qa-wk-01
- ac-cicd-dev-wk-01
Organization Isolation Rules
- One Kubernetes cluster and one ARC controller
- API VIP, load balancer, control planes, and environment workers
- Runner namespace prefix and worker placement labels
- Cluster operations, upgrades, and shared-capacity monitoring
- App short form and GitHub organization
- GitHub App, installation, private key, and repository permissions
- Runner namespace:
arc-runners-<app-short-form>-<environment> - GitHub App and Harbor namespace secrets
- Harbor project and separate CI/runtime robot accounts
- Organization working folder and scoped checklist state
- Operate exactly one shared ARC controller unless a future security boundary requires another cluster.
- Never reuse a GitHub App secret name or runner namespace across app short forms.
- Use one GitHub App per GitHub organization and grant only the required private repositories.
- Generate namespaces as
arc-runners-<app-short-form>-<environment>. - Keep Harbor pull and CI credentials secrets inside the matching runner namespace.
- Use one Harbor project per product/GitHub organization by default.
- Plan total runner concurrency against shared worker capacity, not namespace count.
Repository-Specific Rules
- Use the Service / App Name in the Helm release and runner scale-set name.
- Create a separate values file per repository and environment.
- Limit GitHub App repository access to only the private repositories that require runners.
- Configure GitHub Free private-repository Actions secrets and variables at repository scope.
- Use
HARBOR_USERNAMEandHARBOR_PASSWORDas repository secrets. - Use
HARBOR_REGISTRYandHARBOR_PROJECTas repository variables. - Do not create separate worker VMs or Harbor projects per repository unless a stronger boundary is required.
Quick Reference
Shared Values
https://ac-cicd-api.aspireclan.com192.168.8.1192.168.8.0/22arc-systems/arcCurrent GitHub Organization Values
<github-organization><app-short-form><environment>arc-runners-<app-short-form>-<environment><app-short-form>-arc-ghapp-secret<app-short-form>-ci-cd<app-short-form>-harbor-regcred<app-short-form>-harbor-credentialsCurrent Repository Values
<service-name>https://github.com/<github-organization>/<service-name><service-name>-<environment>-arc~/arc/<app-short-form>/<service-name>-<environment>-values.yamlharbor.aspireclan.com/<app-short-form>-ci-cd/<service-name>:<tag>Shared Proxmox Portal
Proxmox portal:
https://pve.aspireclan.com