Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 20 additions & 15 deletions api/v1alpha1/hyperbytedbcluster_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,15 @@ type HyperbytedbClusterSpec struct {
// +kubebuilder:default=1
Replicas *int32 `json:"replicas,omitempty"`

// +kubebuilder:default="hyperbytedb:latest"
// Container image reference. When set with a tag (contains ':'), used as-is.
// When set without a tag, treated as the repository and combined with Version.
// When empty, defaults to hyperbytedb:{Version} or hyperbytedb:latest.
// +optional
Image string `json:"image,omitempty"`

// Application version. Drives the container image tag for hyperbytedb and
// hyperbytedb-proxy (e.g. version "0.8.3" → hyperbytedb:v0.8.3). Changing
// this field triggers a rolling upgrade.
// +optional
Version string `json:"version,omitempty"`

Expand Down Expand Up @@ -169,6 +175,12 @@ type CertManagerIssuerRef struct {
type StorageSpec struct {
// +optional
VolumeClaimTemplate *PersistentVolumeClaimSpec `json:"volumeClaimTemplate,omitempty"`

// WAL encoding format: "bincode" (default) or "arrow_ipc".
// +optional
// +kubebuilder:validation:Enum=bincode;arrow_ipc
// +kubebuilder:default="bincode"
WALFormat string `json:"walFormat,omitempty"`
}

type PersistentVolumeClaimSpec struct {
Expand Down Expand Up @@ -204,6 +216,11 @@ type FlushSpec struct {
// +optional
// +kubebuilder:validation:Minimum=0
WALBatchDelayUs int64 `json:"walBatchDelayUs,omitempty"`

// Keep chDB-ready Arrow batches in an in-memory WAL cache for zero-copy flush.
// +optional
// +kubebuilder:default=true
ArrowWALEnabled *bool `json:"arrowWALEnabled,omitempty"`
}

type ChDBSpec struct {
Expand Down Expand Up @@ -235,18 +252,6 @@ type LoggingSpec struct {
// +kubebuilder:default="text"
// +kubebuilder:validation:Enum=text;json
Format string `json:"format,omitempty"`

// Emit per-phase performance logs (write/query/flush). Off by default.
// +optional
DetailedTrace *bool `json:"detailedTrace,omitempty"`

// OTLP HTTP endpoint for trace export (e.g. http://alloy-logs:4318).
// +optional
OtlpEndpoint string `json:"otlpEndpoint,omitempty"`

// Fraction of traces exported to OTLP (0.0–1.0). Default 1.0 when OTLP is set.
// +optional
OtlpSampleRatio string `json:"otlpSampleRatio,omitempty"`
}

type ClusterTuningSpec struct {
Expand Down Expand Up @@ -447,7 +452,7 @@ type ProxySpec struct {
// When false, the operator does not create or reconcile any proxy
// resources. Existing proxy Deployment/Service (if any) are left alone
// so they can be cleaned up out-of-band.
// +kubebuilder:default=false
// +kubebuilder:default=true
Enabled bool `json:"enabled"`

// +kubebuilder:default="hyperbytedb-proxy:latest"
Expand Down Expand Up @@ -479,7 +484,7 @@ type ProxySpec struct {
// request with 503. Bigger values mean rolling restarts are smoother but
// individual stuck requests sit longer.
// +optional
// +kubebuilder:default=10
// +kubebuilder:default=30
// +kubebuilder:validation:Minimum=0
HoldTimeoutSecs int32 `json:"holdTimeoutSecs,omitempty"`

Expand Down
10 changes: 6 additions & 4 deletions api/v1alpha1/hyperbytedbcluster_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,6 @@ func (w *HyperbytedbClusterWebhook) Default(_ context.Context, obj *HyperbytedbC
obj.Spec.Replicas = ptr.To(int32(1))
}

if obj.Spec.Image == "" {
obj.Spec.Image = "hyperbytedb:latest"
}

if obj.Spec.Server.Port == 0 {
obj.Spec.Server.Port = 8086
}
Expand Down Expand Up @@ -84,6 +80,12 @@ func (w *HyperbytedbClusterWebhook) Default(_ context.Context, obj *HyperbytedbC
obj.Spec.Retention.Interval = "60s"
}

// hyperbytedb-proxy is enabled by default for health-aware routing during
// rolling upgrades. Opt out with spec.proxy.enabled=false.
if obj.Spec.Proxy == nil {
obj.Spec.Proxy = &ProxySpec{Enabled: true}
}

return nil
}

Expand Down
14 changes: 7 additions & 7 deletions api/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -3137,6 +3137,11 @@ spec:
type: object
flush:
properties:
arrowWALEnabled:
default: true
description: Keep chDB-ready Arrow batches in an in-memory WAL
cache for zero-copy flush.
type: boolean
intervalSecs:
default: 10
format: int32
Expand Down Expand Up @@ -3189,7 +3194,10 @@ spec:
type: integer
type: object
image:
default: hyperbytedb:latest
description: |-
Container image reference. When set with a tag (contains ':'), used as-is.
When set without a tag, treated as the repository and combined with Version.
When empty, defaults to hyperbytedb:{Version} or hyperbytedb:latest.
type: string
imagePullPolicy:
description: PullPolicy describes a policy for if/when to pull a container
Expand All @@ -3215,10 +3223,6 @@ spec:
type: array
logging:
properties:
detailedTrace:
description: Emit per-phase performance logs (write/query/flush).
Off by default.
type: boolean
format:
default: text
enum:
Expand All @@ -3234,13 +3238,6 @@ spec:
- warn
- error
type: string
otlpEndpoint:
description: OTLP HTTP endpoint for trace export (e.g. http://alloy-logs:4318).
type: string
otlpSampleRatio:
description: Fraction of traces exported to OTLP (0.0–1.0). Default
1.0 when OTLP is set.
type: string
type: object
monitoring:
properties:
Expand Down Expand Up @@ -3271,7 +3268,7 @@ spec:
returning errors to clients.
properties:
enabled:
default: false
default: true
description: |-
When false, the operator does not create or reconcile any proxy
resources. Existing proxy Deployment/Service (if any) are left alone
Expand All @@ -3283,7 +3280,7 @@ spec:
Set to `/health/ready` for the deeper chDB-aware readiness check.
type: string
holdTimeoutSecs:
default: 10
default: 30
description: |-
How long the proxy waits for a backend to come back before failing a
request with 503. Bigger values mean rolling restarts are smoother but
Expand Down Expand Up @@ -3609,6 +3606,13 @@ spec:
storageClassName:
type: string
type: object
walFormat:
default: bincode
description: 'WAL encoding format: "bincode" (default) or "arrow_ipc".'
enum:
- bincode
- arrow_ipc
type: string
type: object
tolerations:
items:
Expand Down Expand Up @@ -3823,6 +3827,10 @@ spec:
type: object
type: array
version:
description: |-
Application version. Drives the container image tag for hyperbytedb and
hyperbytedb-proxy (e.g. version "0.8.3" → hyperbytedb:v0.8.3). Changing
this field triggers a rolling upgrade.
type: string
type: object
status:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@ spec:
logging:
level: info
format: json
otlpEndpoint: http://alloy-logs:4318
otlpSampleRatio: "0.1"
cardinality:
maxTagValuesPerMeasurement: 100000
maxMeasurementsPerDatabase: 10000
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
---
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
Expand Down Expand Up @@ -3189,7 +3190,10 @@ spec:
type: integer
type: object
image:
default: hyperbytedb:latest
description: |-
Container image reference. When set with a tag (contains ':'), used as-is.
When set without a tag, treated as the repository and combined with Version.
When empty, defaults to hyperbytedb:{Version} or hyperbytedb:latest.
type: string
imagePullPolicy:
description: PullPolicy describes a policy for if/when to pull a container
Expand Down Expand Up @@ -3271,7 +3275,7 @@ spec:
returning errors to clients.
properties:
enabled:
default: false
default: true
description: |-
When false, the operator does not create or reconcile any proxy
resources. Existing proxy Deployment/Service (if any) are left alone
Expand All @@ -3283,7 +3287,7 @@ spec:
Set to `/health/ready` for the deeper chDB-aware readiness check.
type: string
holdTimeoutSecs:
default: 10
default: 30
description: |-
How long the proxy waits for a backend to come back before failing a
request with 503. Bigger values mean rolling restarts are smoother but
Expand Down Expand Up @@ -3823,6 +3827,10 @@ spec:
type: object
type: array
version:
description: |-
Application version. Drives the container image tag for hyperbytedb and
hyperbytedb-proxy (e.g. version "0.8.3" → hyperbytedb:v0.8.3). Changing
this field triggers a rolling upgrade.
type: string
type: object
status:
Expand Down
5 changes: 1 addition & 4 deletions internal/controller/hyperbytedbbackup_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,10 +207,7 @@ func (r *HyperbytedbBackupReconciler) reconcileCronJob(ctx context.Context, back
}

func (r *HyperbytedbBackupReconciler) buildBackupJob(backup *hyperbytedbv1alpha1.HyperbytedbBackup, cluster *hyperbytedbv1alpha1.HyperbytedbCluster, name string) *batchv1.Job {
image := cluster.Spec.Image
if image == "" {
image = "hyperbytedb:latest"
}
image := hyperbytedb.ResolveHyperbytedbImage(cluster)

s3 := backup.Spec.Destination.S3
s3Path := r.buildBackupS3Path(backup)
Expand Down
30 changes: 23 additions & 7 deletions internal/controller/hyperbytedbcluster_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -216,9 +216,8 @@ func (r *HyperbytedbClusterReconciler) Reconcile(ctx context.Context, req ctrl.R
log.Error(err, "Failed to reconcile HPA")
}

// 11b. Proxy (optional). When disabled (default) we don't reconcile —
// any pre-existing proxy resources are left intact so users can clean
// them up out-of-band.
// 11b. Proxy (optional). Enabled by default; set spec.proxy.enabled=false
// to skip reconciliation.
if hyperbytedb.ProxyEnabled(cluster) {
if err := r.reconcileProxy(ctx, cluster); err != nil {
log.Error(err, "Failed to reconcile proxy")
Expand Down Expand Up @@ -527,7 +526,10 @@ func (r *HyperbytedbClusterReconciler) reconcilePDB(ctx context.Context, cluster

pdbName := cluster.Name + "-pdb"

if replicas < 3 {
// Single-node clusters don't need a PDB. For 2+ replicas keep at least
// N-1 pods available during voluntary disruption so rolling upgrades and
// node drains never take the whole cluster offline at once.
if replicas < 2 {
existing := &policyv1.PodDisruptionBudget{}
err := r.Get(ctx, types.NamespacedName{Name: pdbName, Namespace: cluster.Namespace}, existing)
if apierrors.IsNotFound(err) {
Expand Down Expand Up @@ -990,6 +992,15 @@ func (r *HyperbytedbClusterReconciler) updateStatus(ctx context.Context, cluster
cluster.Status.ReadyReplicas = sts.ReadyReplicas
cluster.Status.ConfigHash = configHash

rollingUpgrade := false
curSTS := &appsv1.StatefulSet{}
if err := r.Get(ctx, types.NamespacedName{
Name: hyperbytedb.StatefulSetName(cluster), Namespace: cluster.Namespace,
}, curSTS); err == nil {
rollingUpgrade = curSTS.Status.UpdateRevision != "" &&
curSTS.Status.UpdateRevision != curSTS.Status.CurrentRevision
}

if sts.ReadyReplicas == sts.SpecReplicas && sts.SpecReplicas > 0 {
cluster.Status.Phase = hyperbytedbv1alpha1.ClusterPhaseRunning
meta.SetStatusCondition(&cluster.Status.Conditions, metav1.Condition{
Expand All @@ -1000,9 +1011,14 @@ func (r *HyperbytedbClusterReconciler) updateStatus(ctx context.Context, cluster
LastTransitionTime: metav1.Now(),
})
} else {
if cluster.Status.Phase != hyperbytedbv1alpha1.ClusterPhaseFailed &&
cluster.Status.Phase != hyperbytedbv1alpha1.ClusterPhaseScaling &&
cluster.Status.Phase != hyperbytedbv1alpha1.ClusterPhaseUpgrading {
switch {
case cluster.Status.Phase == hyperbytedbv1alpha1.ClusterPhaseFailed:
// preserve
case cluster.Status.Phase == hyperbytedbv1alpha1.ClusterPhaseScaling:
// preserve
case rollingUpgrade:
cluster.Status.Phase = hyperbytedbv1alpha1.ClusterPhaseUpgrading
default:
cluster.Status.Phase = hyperbytedbv1alpha1.ClusterPhaseInitializing
}
meta.SetStatusCondition(&cluster.Status.Conditions, metav1.Condition{
Expand Down
5 changes: 1 addition & 4 deletions internal/controller/hyperbytedbrestore_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -246,10 +246,7 @@ func (r *HyperbytedbRestoreReconciler) buildRestoreJob(
s3Source *hyperbytedbv1alpha1.S3BackupSpec,
ordinal int32,
) *batchv1.Job {
image := cluster.Spec.Image
if image == "" {
image = "hyperbytedb:latest"
}
image := hyperbytedb.ResolveHyperbytedbImage(cluster)

s3Path := s3Source.Bucket
if s3Source.Prefix != "" {
Expand Down
4 changes: 3 additions & 1 deletion internal/hyperbytedb/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,9 @@ func (c *Client) DrainNode(ctx context.Context, host string, port int32) error {
return err
}
defer func() { _ = resp.Body.Close() }()
if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusNoContent {
if resp.StatusCode != http.StatusOK &&
resp.StatusCode != http.StatusNoContent &&
resp.StatusCode != http.StatusAccepted {
respBody, _ := io.ReadAll(resp.Body)
return fmt.Errorf("drain returned %d: %s", resp.StatusCode, string(respBody))
}
Expand Down
Loading
Loading