mirror of
https://github.com/clastix/kamaji.git
synced 2026-02-22 22:03:51 +00:00
Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2571086ff3 | ||
|
|
cd9d92296b | ||
|
|
f24ff618a9 | ||
|
|
4bf39149ec | ||
|
|
045c5bbd7c | ||
|
|
6eb3171817 | ||
|
|
289bad540c | ||
|
|
ac06447706 | ||
|
|
95de31d697 | ||
|
|
0037b4941c | ||
|
|
c251f57f06 | ||
|
|
129cb0e6fe | ||
|
|
73e0618ad3 | ||
|
|
6c2634b5e9 | ||
|
|
dac670113f | ||
|
|
c8039cdf5c | ||
|
|
a7cfc9a898 | ||
|
|
0f1a4f28de | ||
|
|
40f57466e2 |
2
Makefile
2
Makefile
@@ -3,7 +3,7 @@
|
||||
# To re-generate a bundle for another specific version without changing the standard setup, you can:
|
||||
# - use the VERSION as arg of the bundle target (e.g make bundle VERSION=0.0.2)
|
||||
# - use environment variables to overwrite this value (e.g export VERSION=0.0.2)
|
||||
VERSION ?= 0.3.4
|
||||
VERSION ?= 0.3.6
|
||||
|
||||
# CHANNELS define the bundle channels used in the bundle.
|
||||
# Add a new line here if you would like to change its default config. (E.g CHANNELS = "candidate,fast,stable")
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
- **High-density Control Plane:** place multiple control planes on the same infrastructure, instead of having dedicated machines for each control plane.
|
||||
- **Strong Multi-tenancy:** leave users to access the control plane with admin permissions while keeping them isolated at the infrastructure level.
|
||||
- **Kubernetes Inception:** use Kubernetes to manage Kubernetes with automation, high-availability, fault tolerance, and autoscaling out of the box.
|
||||
- **Bring Your Own Device:** keep the control plane isolated from data plane. Worke nodes can join and run consistently everywhere: cloud, edge, and data-center.
|
||||
- **Bring Your Own Device:** keep the control plane isolated from data plane. Worker nodes can join and run consistently everywhere: cloud, edge, and data-center.
|
||||
- **Full CNCF compliant:** all clusters are built with upstream Kubernetes binaries, resulting in full CNCF compliant Kubernetes clusters.
|
||||
|
||||
## Roadmap
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
apiVersion: v2
|
||||
appVersion: v0.3.4
|
||||
appVersion: v0.3.6
|
||||
description: Kamaji is a Kubernetes Control Plane Manager.
|
||||
home: https://github.com/clastix/kamaji
|
||||
icon: https://github.com/clastix/kamaji/raw/master/assets/logo-colored.png
|
||||
@@ -15,8 +15,8 @@ name: kamaji
|
||||
sources:
|
||||
- https://github.com/clastix/kamaji
|
||||
type: application
|
||||
version: 0.12.5
|
||||
version: 0.13.1
|
||||
annotations:
|
||||
catalog.cattle.io/certified: partner
|
||||
catalog.cattle.io/release-name: kamaji
|
||||
catalog.cattle.io/display-name: Kamaji
|
||||
catalog.cattle.io/display-name: Kamaji
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# kamaji
|
||||
|
||||
  
|
||||
  
|
||||
|
||||
Kamaji is a Kubernetes Control Plane Manager.
|
||||
|
||||
@@ -73,8 +73,9 @@ Here the values you can override:
|
||||
| datastore.basicAuth.usernameSecret.name | string | `nil` | The name of the Secret containing the username used to connect to the relational database. |
|
||||
| datastore.basicAuth.usernameSecret.namespace | string | `nil` | The namespace of the Secret containing the username used to connect to the relational database. |
|
||||
| datastore.driver | string | `"etcd"` | (string) The Kamaji Datastore driver, supported: etcd, MySQL, PostgreSQL (defaults=etcd). |
|
||||
| datastore.enabled | bool | `true` | (bool) Enable the Kamaji Datastore creation (default=true) |
|
||||
| datastore.endpoints | list | `[]` | (array) List of endpoints of the selected Datastore. When letting the Chart install the etcd datastore, this field is populated automatically. |
|
||||
| datastore.nameOverride | string | `nil` | The Datastore name override, if empty defaults to `default` |
|
||||
| datastore.nameOverride | string | `nil` | The Datastore name override, if empty and enabled=true defaults to `default`, if enabled=false, this is the name of the Datastore to connect to. |
|
||||
| datastore.tlsConfig.certificateAuthority.certificate.keyPath | string | `nil` | Key of the Secret which contains the content of the certificate. |
|
||||
| datastore.tlsConfig.certificateAuthority.certificate.name | string | `nil` | Name of the Secret containing the CA required to establish the mandatory SSL/TLS connection to the datastore. |
|
||||
| datastore.tlsConfig.certificateAuthority.certificate.namespace | string | `nil` | Namespace of the Secret containing the CA required to establish the mandatory SSL/TLS connection to the datastore. |
|
||||
@@ -100,10 +101,11 @@ Here the values you can override:
|
||||
| etcd.persistence.accessModes[0] | string | `"ReadWriteOnce"` | |
|
||||
| etcd.persistence.customAnnotations | object | `{}` | The custom annotations to add to the PVC |
|
||||
| etcd.persistence.size | string | `"10Gi"` | |
|
||||
| etcd.persistence.storageClass | string | `""` | |
|
||||
| etcd.persistence.storageClassName | string | `""` | |
|
||||
| etcd.port | int | `2379` | The client request port. |
|
||||
| etcd.serviceAccount.create | bool | `true` | Create a ServiceAccount, required to install and provision the etcd backing storage (default: true) |
|
||||
| etcd.serviceAccount.name | string | `""` | Define the ServiceAccount name to use during the setup and provision of the etcd backing storage (default: "") |
|
||||
| etcd.tolerations | list | `[]` | (array) Kubernetes affinity rules to apply to Kamaji etcd pods |
|
||||
| extraArgs | list | `[]` | A list of extra arguments to add to the kamaji controller default ones |
|
||||
| fullnameOverride | string | `""` | |
|
||||
| healthProbeBindAddress | string | `":8081"` | The address the probe endpoint binds to. (default ":8081") |
|
||||
|
||||
@@ -2,7 +2,11 @@
|
||||
Create a default fully qualified datastore name.
|
||||
*/}}
|
||||
{{- define "datastore.fullname" -}}
|
||||
{{- if .Values.datastore.enabled }}
|
||||
{{- default "default" .Values.datastore.nameOverride | trunc 63 | trimSuffix "-" }}
|
||||
{{- else }}
|
||||
{{- required "A valid .Values.datastore.nameOverride required!" .Values.datastore.nameOverride }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
{{- if .Values.datastore.enabled}}
|
||||
apiVersion: kamaji.clastix.io/v1alpha1
|
||||
kind: DataStore
|
||||
metadata:
|
||||
@@ -24,3 +25,4 @@ spec:
|
||||
{{- include "datastore.certificateAuthority" . | indent 6 }}
|
||||
clientCertificate:
|
||||
{{- include "datastore.clientCertificate" . | indent 6 }}
|
||||
{{- end}}
|
||||
|
||||
@@ -30,11 +30,15 @@ spec:
|
||||
- bash
|
||||
- -c
|
||||
- |-
|
||||
etcdctl member list -w table &&
|
||||
etcdctl user add --no-password=true root &&
|
||||
etcdctl role add root &&
|
||||
etcdctl user grant-role root root &&
|
||||
etcdctl auth enable
|
||||
etcdctl member list -w table
|
||||
if etcdctl user get root &>/dev/null; then
|
||||
echo "User already exists, nothing to do"
|
||||
else
|
||||
etcdctl user add --no-password=true root &&
|
||||
etcdctl role add root &&
|
||||
etcdctl user grant-role root root &&
|
||||
etcdctl auth enable
|
||||
fi
|
||||
env:
|
||||
- name: ETCDCTL_ENDPOINTS
|
||||
value: https://etcd-0.{{ include "etcd.serviceName" . }}.{{ .Release.Namespace }}.svc.cluster.local:2379
|
||||
|
||||
@@ -37,13 +37,21 @@ spec:
|
||||
containers:
|
||||
- name: kubectl
|
||||
image: {{ printf "clastix/kubectl:%s" (include "etcd.jobsTagKubeVersion" .) }}
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- |-
|
||||
kubectl --namespace={{ .Release.Namespace }} delete secret --ignore-not-found=true {{ include "etcd.caSecretName" . }} {{ include "etcd.clientSecretName" . }} &&
|
||||
kubectl --namespace={{ .Release.Namespace }} create secret generic {{ include "etcd.caSecretName" . }} --from-file=/certs/ca.crt --from-file=/certs/ca.key --from-file=/certs/peer-key.pem --from-file=/certs/peer.pem --from-file=/certs/server-key.pem --from-file=/certs/server.pem &&
|
||||
kubectl --namespace={{ .Release.Namespace }} create secret tls {{ include "etcd.clientSecretName" . }} --key=/certs/root-client-key.pem --cert=/certs/root-client.pem
|
||||
command: ["/bin/sh", "-c"]
|
||||
args:
|
||||
- |
|
||||
if kubectl get secret {{ include "etcd.caSecretName" . }} --namespace={{ .Release.Namespace }} &>/dev/null; then
|
||||
echo "Secret {{ include "etcd.caSecretName" . }} already exists"
|
||||
else
|
||||
echo "Creating secret {{ include "etcd.caSecretName" . }}"
|
||||
kubectl --namespace={{ .Release.Namespace }} create secret generic {{ include "etcd.caSecretName" . }} --from-file=/certs/ca.crt --from-file=/certs/ca.key --from-file=/certs/peer-key.pem --from-file=/certs/peer.pem --from-file=/certs/server-key.pem --from-file=/certs/server.pem
|
||||
fi
|
||||
if kubectl get secret {{ include "etcd.clientSecretName" . }} --namespace={{ .Release.Namespace }} &>/dev/null; then
|
||||
echo "Secret {{ include "etcd.clientSecretName" . }} already exists"
|
||||
else
|
||||
echo "Creating secret {{ include "etcd.clientSecretName" . }}"
|
||||
kubectl --namespace={{ .Release.Namespace }} create secret tls {{ include "etcd.clientSecretName" . }} --key=/certs/root-client-key.pem --cert=/certs/root-client.pem
|
||||
fi
|
||||
volumeMounts:
|
||||
- mountPath: /certs
|
||||
name: certs
|
||||
|
||||
@@ -15,6 +15,7 @@ rules:
|
||||
resources:
|
||||
- secrets
|
||||
verbs:
|
||||
- get
|
||||
- delete
|
||||
resourceNames:
|
||||
- {{ include "etcd.caSecretName" . }}
|
||||
|
||||
@@ -22,6 +22,10 @@ spec:
|
||||
- name: certs
|
||||
secret:
|
||||
secretName: {{ include "etcd.caSecretName" . }}
|
||||
{{- with .Values.etcd.tolerations }}
|
||||
tolerations:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
containers:
|
||||
- name: etcd
|
||||
image: {{ .Values.etcd.image.repository }}:{{ .Values.etcd.image.tag | default "v3.5.4" }}
|
||||
|
||||
@@ -54,12 +54,15 @@ etcd:
|
||||
name: ""
|
||||
persistence:
|
||||
size: 10Gi
|
||||
storageClass: ""
|
||||
storageClassName: ""
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
# -- The custom annotations to add to the PVC
|
||||
customAnnotations: {}
|
||||
# volumeType: local
|
||||
|
||||
# -- (array) Kubernetes affinity rules to apply to Kamaji etcd pods
|
||||
tolerations: []
|
||||
|
||||
overrides:
|
||||
caSecret:
|
||||
@@ -157,7 +160,9 @@ loggingDevel:
|
||||
enable: false
|
||||
|
||||
datastore:
|
||||
# -- (string) The Datastore name override, if empty defaults to `default`
|
||||
# -- (bool) Enable the Kamaji Datastore creation (default=true)
|
||||
enabled: true
|
||||
# -- (string) The Datastore name override, if empty and enabled=true defaults to `default`, if enabled=false, this is the name of the Datastore to connect to.
|
||||
nameOverride:
|
||||
# -- (string) The Kamaji Datastore driver, supported: etcd, MySQL, PostgreSQL (defaults=etcd).
|
||||
driver: etcd
|
||||
|
||||
@@ -5093,7 +5093,7 @@ spec:
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: spec.serviceAccountName
|
||||
image: clastix/kamaji:v0.3.4
|
||||
image: clastix/kamaji:v0.3.6
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
|
||||
@@ -13,4 +13,4 @@ kind: Kustomization
|
||||
images:
|
||||
- name: controller
|
||||
newName: clastix/kamaji
|
||||
newTag: v0.3.4
|
||||
newTag: v0.3.6
|
||||
|
||||
@@ -5,6 +5,7 @@ package finalizers
|
||||
|
||||
const (
|
||||
// DatastoreFinalizer is using a wrong name, since it's related to the underlying datastore.
|
||||
DatastoreFinalizer = "finalizer.kamaji.clastix.io"
|
||||
SootFinalizer = "finalizer.kamaji.clastix.io/soot"
|
||||
DatastoreFinalizer = "finalizer.kamaji.clastix.io"
|
||||
DatastoreSecretFinalizer = "finalizer.kamaji.clastix.io/datastore-secret"
|
||||
SootFinalizer = "finalizer.kamaji.clastix.io/soot"
|
||||
)
|
||||
|
||||
@@ -40,6 +40,7 @@ type GroupDeletableResourceBuilderConfiguration struct {
|
||||
tcpReconcilerConfig TenantControlPlaneReconcilerConfig
|
||||
tenantControlPlane kamajiv1alpha1.TenantControlPlane
|
||||
connection datastore.Connection
|
||||
dataStore kamajiv1alpha1.DataStore
|
||||
}
|
||||
|
||||
// GetResources returns a list of resources that will be used to provide tenant control planes
|
||||
@@ -60,6 +61,11 @@ func GetDeletableResources(tcp *kamajiv1alpha1.TenantControlPlane, config GroupD
|
||||
Client: config.client,
|
||||
Connection: config.connection,
|
||||
})
|
||||
res = append(res, &ds.Config{
|
||||
Client: config.client,
|
||||
ConnString: config.connection.GetConnectionString(),
|
||||
DataStore: config.dataStore,
|
||||
})
|
||||
}
|
||||
|
||||
return res
|
||||
|
||||
@@ -145,6 +145,7 @@ func (r *TenantControlPlaneReconciler) Reconcile(ctx context.Context, req ctrl.R
|
||||
tcpReconcilerConfig: r.Config,
|
||||
tenantControlPlane: *tenantControlPlane,
|
||||
connection: dsConnection,
|
||||
dataStore: *ds,
|
||||
}
|
||||
|
||||
for _, resource := range GetDeletableResources(tenantControlPlane, groupDeletableResourceBuilderConfiguration) {
|
||||
|
||||
@@ -86,6 +86,21 @@ helm install kamaji clastix/kamaji -n kamaji-system --create-namespace
|
||||
!!! note "A managed datastore is highly recommended in production"
|
||||
The [kamaji-etcd](https://github.com/clastix/kamaji-etcd) project provides the code to setup a multi-tenant `etcd` running as StatefulSet made of three replicas. Optionally, Kamaji offers support for a more robust storage system, as `MySQL` or `PostgreSQL` compatible database, thanks to the native [kine](https://github.com/k3s-io/kine) integration.
|
||||
|
||||
Now you should end up with a working Kamaji instance, including the default `datastore`:
|
||||
|
||||
```bash
|
||||
kubectl -n kamaji-system get pods
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
etcd-0 1/1 Running 0 50s
|
||||
etcd-1 1/1 Running 0 60s
|
||||
etcd-2 1/1 Running 0 90s
|
||||
kamaji-7949578bfb-lj44p 1/1 Running 0 12s
|
||||
```
|
||||
|
||||
> An unsuccessful first installation could fail for several reasons, such as missing a `StorageClass`, or even for a trivial `Ctrl+C` during the installation phase.
|
||||
>
|
||||
> See the [Cleanup](#cleanup) section before to retry an aborted installation.
|
||||
|
||||
## Create Tenant Cluster
|
||||
|
||||
### Tenant Control Plane
|
||||
@@ -319,7 +334,8 @@ tenant-00-worker-02 Ready <none> 2m32s v1.25.0
|
||||
```
|
||||
|
||||
## Cleanup
|
||||
Remove the worker nodes joined the tenant control plane
|
||||
### Delete a Tenant Cluster
|
||||
First, remove the worker nodes joined the tenant control plane
|
||||
|
||||
```bash
|
||||
kubectl --kubeconfig=${TENANT_NAMESPACE}-${TENANT_NAME}.kubeconfig delete nodes --all
|
||||
@@ -337,10 +353,37 @@ for i in "${!HOSTS[@]}"; do
|
||||
done
|
||||
```
|
||||
|
||||
Delete the tenant control plane from kamaji
|
||||
Delete the tenant control plane from Kamaji
|
||||
|
||||
```bash
|
||||
kubectl delete -f ${TENANT_NAMESPACE}-${TENANT_NAME}-tcp.yaml
|
||||
```
|
||||
|
||||
### Uninstall Kamaji
|
||||
Uninstall the Kamaji controller by removing the Helm release
|
||||
|
||||
```bash
|
||||
helm uninstall kamaji -n kamaji-system
|
||||
```
|
||||
|
||||
The default datastore installed three `etcd` replicas with persistent volumes, so remove the `PersistentVolumeClaims` resources:
|
||||
|
||||
```bash
|
||||
kubectl -n kamaji-system delete pvc --all
|
||||
```
|
||||
|
||||
Also delete the custom resources:
|
||||
|
||||
```bash
|
||||
kubectl delete crd tenantcontrolplanes.kamaji.clastix.io
|
||||
kubectl delete crd datastores.kamaji.clastix.io
|
||||
```
|
||||
|
||||
In case of a broken installation, manually remove the hooks installed by Kamaji:
|
||||
|
||||
```bash
|
||||
kubectl delete ValidatingWebhookConfiguration kamaji-validating-webhook-configuration
|
||||
kubectl delete MutatingWebhookConfiguration kamaji-mutating-webhook-configuration
|
||||
```
|
||||
|
||||
That's all folks!
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 152 KiB After Width: | Height: | Size: 163 KiB |
@@ -12,3 +12,5 @@ In Kamaji, there are different components that might require independent version
|
||||
| v0.3.2 | v1.22+ | [v1.21.0 .. v1.27.3] |
|
||||
| v0.3.3 | v1.22+ | [v1.21.0 .. v1.27.3] |
|
||||
| v0.3.4 | v1.22+ | [v1.21.0 .. v1.28.1] |
|
||||
| v0.3.5 | v1.22+ | [v1.21.0 .. v1.28.1] |
|
||||
| v0.3.5 | v1.22+ | [v1.21.0 .. v1.28.1] |
|
||||
|
||||
@@ -43,7 +43,7 @@ func (d *Migrate) Define(ctx context.Context, tenantControlPlane *kamajiv1alpha1
|
||||
|
||||
d.job = &batchv1.Job{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: fmt.Sprintf("migrate-%s-%s", tenantControlPlane.GetNamespace(), tenantControlPlane.GetName()),
|
||||
Name: fmt.Sprintf("migrate-%s", tenantControlPlane.UID),
|
||||
Namespace: d.KamajiNamespace,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -9,13 +9,18 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/pkg/errors"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
kubeerrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
|
||||
|
||||
kamajiv1alpha1 "github.com/clastix/kamaji/api/v1alpha1"
|
||||
"github.com/clastix/kamaji/controllers/finalizers"
|
||||
"github.com/clastix/kamaji/internal/utilities"
|
||||
)
|
||||
|
||||
@@ -62,6 +67,30 @@ func (r *Config) CreateOrUpdate(ctx context.Context, tenantControlPlane *kamajiv
|
||||
return utilities.CreateOrUpdateWithConflict(ctx, r.Client, r.resource, r.mutate(ctx, tenantControlPlane))
|
||||
}
|
||||
|
||||
func (r *Config) Delete(ctx context.Context, tenantControlPlane *kamajiv1alpha1.TenantControlPlane) error {
|
||||
secret := r.resource.DeepCopy()
|
||||
|
||||
if err := r.Client.Get(ctx, types.NamespacedName{Name: r.resource.Name, Namespace: r.resource.Namespace}, secret); err != nil {
|
||||
if kubeerrors.IsNotFound(err) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return errors.Wrap(err, "cannot retrieve the DataStore Secret for removal")
|
||||
}
|
||||
|
||||
secret.SetFinalizers(nil)
|
||||
|
||||
if err := r.Client.Update(ctx, secret); err != nil {
|
||||
if kubeerrors.IsNotFound(err) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return errors.Wrap(err, "cannot remove DataStore Secret finalizers")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Config) GetName() string {
|
||||
return "datastore-config"
|
||||
}
|
||||
@@ -100,6 +129,10 @@ func (r *Config) mutate(_ context.Context, tenantControlPlane *kamajiv1alpha1.Te
|
||||
return []byte(strings.ReplaceAll(fmt.Sprintf("%s_%s", tenantControlPlane.GetNamespace(), tenantControlPlane.GetName()), "-", "_"))
|
||||
}
|
||||
|
||||
finalizersList := sets.New[string](r.resource.GetFinalizers()...)
|
||||
finalizersList.Insert(finalizers.DatastoreSecretFinalizer)
|
||||
r.resource.SetFinalizers(finalizersList.UnsortedList())
|
||||
|
||||
r.resource.Data = map[string][]byte{
|
||||
"DB_CONNECTION_STRING": []byte(r.ConnString),
|
||||
"DB_SCHEMA": coalesceFn(tenantControlPlane.Status.Storage.Setup.Schema),
|
||||
|
||||
@@ -4,5 +4,5 @@
|
||||
package upgrade
|
||||
|
||||
const (
|
||||
KubeadmVersion = "v1.28.1"
|
||||
KubeadmVersion = "v1.28.2"
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user