Initial commit: Turbo Mothership bare metal management cluster

- k0s bootstrap with Cilium and OpenEBS
- ArgoCD apps for infra, CAPI, Tinkerbell, and Netris
- Ansible playbooks for virtual baremetal lab and Netris switches
- CAPI provider manifests for k0smotron and Tinkerbell
This commit is contained in:
Pavel Basov
2025-12-15 19:59:58 +01:00
commit df9937f0c3
39 changed files with 1961 additions and 0 deletions

113
bootstrap/README.md Normal file
View File

@@ -0,0 +1,113 @@
# Bootstrap
Bootstrap chart for cluster initialization. Deploys all required infrastructure components in a single Helm release.
## Requirements
- 1-3 nodes
- External DNS for ingress access
- Internet access
## Components
The bootstrap umbrella chart (`charts/bootstrap/`) includes:
| Component | Description |
|-----------|-------------|
| Cilium | CNI for networking |
| ingress-nginx | Ingress controller |
| cert-manager | TLS certificate management |
| sealed-secrets | Encrypted secrets for GitOps |
| ArgoCD | GitOps continuous delivery |
| OpenEBS | Container storage (hostpath) |
Additional resources created:
- ClusterIssuer (Let's Encrypt)
- StorageClass (local-storage)
## Kubernetes
Install [k0s](https://k0sproject.io/) as the Kubernetes distribution:
```sh
curl -sSf https://get.k0s.sh | sudo sh
sudo k0s install controller --enable-worker --no-taints --config ./k0s.yaml
sudo k0s start
```
Verify and get kubeconfig:
```sh
sudo k0s status
k0s kubeconfig admin create > ~/.kube/config
```
## Bootstrap Installation
```sh
cd charts/bootstrap
# Download dependencies
helm dependency update
# Review what will be installed
helm template bootstrap . --namespace bootstrap | less
# Install
helm upgrade -i bootstrap . --namespace bootstrap --create-namespace
```
## Sealed Secrets
[Sealed Secrets](https://github.com/bitnami-labs/sealed-secrets) enables GitOps management of secrets using asymmetric encryption.
### Usage
```sh
# Create a secret (do not commit)
kubectl create secret generic my-secret \
--from-literal=password=supersecret \
--dry-run=client -o yaml > plaintext.yaml
# Seal it
kubeseal < plaintext.yaml > sealed-secret.yaml
# Delete plaintext
rm plaintext.yaml
# Apply sealed secret
kubectl apply -f sealed-secret.yaml
```
## ArgoCD
Available at https://argo.turbo.weystrom.dev
Get initial admin password:
```sh
kubectl -n bootstrap get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d
```
## Configuration
Edit `charts/bootstrap/values.yaml` to customize components. Each subchart is configured under its own key:
```yaml
cilium:
enabled: true
ingress-nginx:
enabled: true
controller:
service:
externalIPs:
- 1.2.3.4
cert-manager:
enabled: true
# ... etc
```
To disable a component, set `enabled: false`.

View File

@@ -0,0 +1,18 @@
# Patterns to ignore when building packages.
.DS_Store
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
*.swp
*.bak
*.tmp
*.orig
*~
.project
.idea/
*.tmproj
.vscode/

View File

@@ -0,0 +1,15 @@
dependencies:
- name: ingress-nginx
repository: https://kubernetes.github.io/ingress-nginx
version: 4.14.1
- name: cert-manager
repository: https://charts.jetstack.io
version: v1.19.2
- name: sealed-secrets
repository: https://bitnami-labs.github.io/sealed-secrets
version: 2.17.9
- name: argo-cd
repository: https://argoproj.github.io/argo-helm
version: 9.1.6
digest: sha256:dae2d89a79210646255cfbd3d045717b9db40aaf0c9e180d64829b1306659cd0
generated: "2025-12-15T17:29:55.279201521+01:00"

View File

@@ -0,0 +1,27 @@
apiVersion: v2
name: turbo-mothership-bootstrap
description: Umbrella chart for cluster bootstrap components
type: application
version: 0.1.0
appVersion: "1.0.0"
dependencies:
- name: ingress-nginx
version: "4.14.1"
repository: https://kubernetes.github.io/ingress-nginx
condition: ingress-nginx.enabled
- name: cert-manager
version: "1.19.2"
repository: https://charts.jetstack.io
condition: cert-manager.enabled
- name: sealed-secrets
version: "2.17.9"
repository: https://bitnami-labs.github.io/sealed-secrets
condition: sealed-secrets.enabled
- name: argo-cd
version: "9.1.6"
repository: https://argoproj.github.io/argo-helm
condition: argo-cd.enabled

View File

@@ -0,0 +1,19 @@
{{- if .Values.clusterIssuer.enabled }}
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: {{ .Values.clusterIssuer.name }}
annotations:
"helm.sh/hook": post-install,post-upgrade
"helm.sh/hook-weight": "10"
spec:
acme:
server: {{ .Values.clusterIssuer.server }}
email: {{ .Values.clusterIssuer.email }}
privateKeySecretRef:
name: {{ .Values.clusterIssuer.name }}
solvers:
- http01:
ingress:
ingressClassName: nginx
{{- end }}

View File

@@ -0,0 +1,41 @@
{{- if index .Values "ingress-nginx" "enabled" }}
---
apiVersion: v1
kind: Namespace
metadata:
name: {{ index .Values "ingress-nginx" "namespaceOverride" | default "ingress-nginx" }}
labels:
app.kubernetes.io/managed-by: Helm
annotations:
meta.helm.sh/release-name: {{ .Release.Name }}
meta.helm.sh/release-namespace: {{ .Release.Namespace }}
"helm.sh/resource-policy": keep
{{- end }}
{{- if index .Values "cert-manager" "enabled" }}
---
apiVersion: v1
kind: Namespace
metadata:
name: {{ index .Values "cert-manager" "namespace" | default "cert-manager" }}
labels:
app.kubernetes.io/managed-by: Helm
annotations:
meta.helm.sh/release-name: {{ .Release.Name }}
meta.helm.sh/release-namespace: {{ .Release.Namespace }}
"helm.sh/resource-policy": keep
{{- end }}
{{- if index .Values "argo-cd" "enabled" }}
---
apiVersion: v1
kind: Namespace
metadata:
name: {{ index .Values "argo-cd" "namespaceOverride" | default "argocd" }}
labels:
app.kubernetes.io/managed-by: Helm
annotations:
meta.helm.sh/release-name: {{ .Release.Name }}
meta.helm.sh/release-namespace: {{ .Release.Namespace }}
"helm.sh/resource-policy": keep
{{- end }}

View File

@@ -0,0 +1,87 @@
# Bootstrap umbrella chart values
# Each subchart is configured under its own key
# NOTE: Cilium CNI is installed via k0s config (k0s.yaml)
# ------------------------------------------------------------------------------
# Ingress NGINX (ingress-nginx)
# ------------------------------------------------------------------------------
ingress-nginx:
enabled: true
fullnameOverride: turbo-ingress
namespaceOverride: ingress-nginx
controller:
admissionWebhooks:
enabled: false
service:
externalIPs:
- 65.109.94.180
type: ClusterIP
# ------------------------------------------------------------------------------
# Cert Manager (cert-manager)
# ------------------------------------------------------------------------------
cert-manager:
enabled: true
fullnameOverride: turbo-certmgr
namespace: cert-manager
crds:
enabled: true
ingressShim:
defaultIssuerName: letsencrypt-prod
defaultIssuerKind: ClusterIssuer
defaultIssuerGroup: cert-manager.io
# ------------------------------------------------------------------------------
# Sealed Secrets (kube-system)
# ------------------------------------------------------------------------------
sealed-secrets:
enabled: true
fullnameOverride: turbo-sealedsecrets
# ------------------------------------------------------------------------------
# Argo CD (argocd)
# ------------------------------------------------------------------------------
argo-cd:
enabled: true
fullnameOverride: turbo-argocd
global:
domain: argo.turbo.weystrom.dev
namespaceOverride: argocd
configs:
params:
server.insecure: true
cm:
admin.enabled: true
server:
ingress:
enabled: true
ingressClassName: nginx
annotations:
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
cert-manager.io/cluster-issuer: "letsencrypt-prod"
extraTls:
- hosts:
- argo.turbo.weystrom.dev
secretName: argocd-ingress-http
ingressGrpc:
enabled: true
ingressClassName: nginx
hostname: argo-grpc.turbo.weystrom.dev
annotations:
nginx.ingress.kubernetes.io/backend-protocol: "GRPC"
cert-manager.io/cluster-issuer: "letsencrypt-prod"
extraTls:
- hosts:
- argo-grpc.turbo.weystrom.dev
secretName: argocd-ingress-grpc
# ------------------------------------------------------------------------------
# Raw manifests configuration
# ------------------------------------------------------------------------------
# NOTE: OpenEBS is installed via k0s config (k0s.yaml)
clusterIssuer:
enabled: true
name: letsencrypt-prod
email: mail@weystrom.dev
server: https://acme-v02.api.letsencrypt.org/directory

101
bootstrap/k0s.yaml Normal file
View File

@@ -0,0 +1,101 @@
apiVersion: k0s.k0sproject.io/v1beta1
kind: ClusterConfig
metadata:
name: k0s
namespace: kube-system
spec:
api:
address: 65.109.94.180
ca:
certificatesExpireAfter: 8760h0m0s
expiresAfter: 87600h0m0s
k0sApiPort: 9443
port: 6443
sans:
- 65.109.94.180
- 2a01:4f9:3051:48ca::2
controllerManager: {}
extensions:
helm:
concurrencyLevel: 5
repositories:
- name: cilium
url: https://helm.cilium.io/
- name: openebs
url: https://openebs.github.io/openebs
charts:
- name: cilium
chartname: cilium/cilium
version: "1.18.4"
namespace: kube-system
order: 1
values: |
cluster:
name: local
k8sServiceHost: 65.109.94.180
k8sServicePort: 6443
kubeProxyReplacement: true
operator:
replicas: 1
routingMode: tunnel
tunnelProtocol: vxlan
- name: openebs
chartname: openebs/openebs
version: "4.2.0"
namespace: openebs
order: 2
values: |
localpv-provisioner:
localpv:
basePath: /var/openebs/local
engines:
replicated:
mayastor:
enabled: false
local:
zfs:
enabled: false
rawfile:
enabled: false
lvm:
enabled: false
loki:
enabled: false
minio:
enabled: false
alloy:
enabled: false
installConfig:
users:
etcdUser: etcd
kineUser: kube-apiserver
konnectivityUser: konnectivity-server
kubeAPIserverUser: kube-apiserver
kubeSchedulerUser: kube-scheduler
network:
clusterDomain: cluster.local
dualStack:
enabled: true
IPv6podCIDR: fd00::/108
IPv6serviceCIDR: fd01::/108
kubeProxy:
disabled: true
nodeLocalLoadBalancing:
enabled: false
envoyProxy:
apiServerBindPort: 7443
konnectivityServerBindPort: 7132
type: EnvoyProxy
podCIDR: 10.240.0.0/16
provider: custom
serviceCIDR: 10.99.0.0/12
scheduler: {}
storage:
etcd:
ca:
certificatesExpireAfter: 8760h0m0s
expiresAfter: 87600h0m0s
peerAddress: 127.0.0.1
type: etcd
telemetry:
enabled: false