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
93 changes: 93 additions & 0 deletions api/v1alpha1/hyperbytedbcluster_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,12 @@ type HyperbytedbClusterSpec struct {
// +optional
Failover *FailoverSpec `json:"failover,omitempty"`

// Proxy deploys a stateless `hyperbytedb-proxy` Deployment in front of the
// StatefulSet to absorb rolling restarts and drain events without
// returning errors to clients.
// +optional
Proxy *ProxySpec `json:"proxy,omitempty"`

// +optional
PodAnnotations map[string]string `json:"podAnnotations,omitempty"`

Expand Down Expand Up @@ -470,6 +476,93 @@ type FailoverSpec struct {
FailoverTimeoutSecs int32 `json:"failoverTimeoutSecs,omitempty"`
}

// ProxySpec configures the optional `hyperbytedb-proxy` reverse proxy that
// sits in front of the StatefulSet. The proxy is health-aware: it routes
// only to Active backends and holds requests briefly while a rolling
// restart cycles through pods, so clients (Grafana, Telegraf, etc.) never
// observe transient 503s.
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
Enabled bool `json:"enabled"`

// +kubebuilder:default="hyperbytedb-proxy:latest"
Image string `json:"image,omitempty"`

// +optional
ImagePullPolicy corev1.PullPolicy `json:"imagePullPolicy,omitempty"`

// +optional
ImagePullSecrets []corev1.LocalObjectReference `json:"imagePullSecrets,omitempty"`

// +kubebuilder:default=2
// +kubebuilder:validation:Minimum=1
Replicas *int32 `json:"replicas,omitempty"`

// Port the proxy Service exposes. Defaults to the cluster server port so
// existing clients can re-target the Service name with no port change.
// +optional
// +kubebuilder:validation:Minimum=1
// +kubebuilder:validation:Maximum=65535
Port int32 `json:"port,omitempty"`

// HTTP path used for backend health probes. Defaults to `/health`.
// Set to `/health/ready` for the deeper chDB-aware readiness check.
// +optional
HealthPath string `json:"healthPath,omitempty"`

// 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
// individual stuck requests sit longer.
// +optional
// +kubebuilder:default=10
// +kubebuilder:validation:Minimum=0
HoldTimeoutSecs int32 `json:"holdTimeoutSecs,omitempty"`

// Cap on per-backend retries for one request. 0 disables retries.
// +optional
// +kubebuilder:default=2
// +kubebuilder:validation:Minimum=0
MaxRetries int32 `json:"maxRetries,omitempty"`

// How long the proxy keeps serving in-flight requests after SIGTERM
// before exiting. Should comfortably exceed the longest expected query.
// +optional
// +kubebuilder:default=30
// +kubebuilder:validation:Minimum=1
ShutdownGraceSecs int32 `json:"shutdownGraceSecs,omitempty"`

// Per-request budget the proxy allows for the upstream call. Defaults
// to ~ServerSpec.RequestTimeoutSecs.
// +optional
// +kubebuilder:validation:Minimum=1
RequestTimeoutSecs int32 `json:"requestTimeoutSecs,omitempty"`

// +optional
Resources corev1.ResourceRequirements `json:"resources,omitempty"`

// Type of the proxy Service. Defaults to ClusterIP. Set NodePort/
// LoadBalancer to expose externally.
// +optional
// +kubebuilder:validation:Enum=ClusterIP;NodePort;LoadBalancer
ServiceType corev1.ServiceType `json:"serviceType,omitempty"`

// Explicit nodePort when ServiceType=NodePort. Required for kind clusters
// that pre-map a host port to a fixed nodePort.
// +optional
// +kubebuilder:validation:Minimum=30000
// +kubebuilder:validation:Maximum=32767
NodePort int32 `json:"nodePort,omitempty"`

// +optional
PodAnnotations map[string]string `json:"podAnnotations,omitempty"`

// +optional
PodLabels map[string]string `json:"podLabels,omitempty"`
}

// ClusterPhase represents the lifecycle phase of the cluster.
// +kubebuilder:validation:Enum=Pending;Initializing;Running;Scaling;Upgrading;Failed
type ClusterPhase string
Expand Down
45 changes: 45 additions & 0 deletions api/v1alpha1/zz_generated.deepcopy.go

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

175 changes: 175 additions & 0 deletions config/crd/bases/hyperbytedb.hyperbytedb.io_hyperbytedbclusters.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3309,6 +3309,181 @@ spec:
additionalProperties:
type: string
type: object
proxy:
description: |-
Proxy deploys a stateless `hyperbytedb-proxy` Deployment in front of the
StatefulSet to absorb rolling restarts and drain events without
returning errors to clients.
properties:
enabled:
default: false
description: |-
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.
type: boolean
healthPath:
description: |-
HTTP path used for backend health probes. Defaults to `/health`.
Set to `/health/ready` for the deeper chDB-aware readiness check.
type: string
holdTimeoutSecs:
default: 10
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
individual stuck requests sit longer.
format: int32
minimum: 0
type: integer
image:
default: hyperbytedb-proxy:latest
type: string
imagePullPolicy:
description: PullPolicy describes a policy for if/when to pull
a container image
type: string
imagePullSecrets:
items:
description: |-
LocalObjectReference contains enough information to let you locate the
referenced object inside the same namespace.
properties:
name:
default: ""
description: |-
Name of the referent.
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
type: string
type: object
x-kubernetes-map-type: atomic
type: array
maxRetries:
default: 2
description: Cap on per-backend retries for one request. 0 disables
retries.
format: int32
minimum: 0
type: integer
nodePort:
description: |-
Explicit nodePort when ServiceType=NodePort. Required for kind clusters
that pre-map a host port to a fixed nodePort.
format: int32
maximum: 32767
minimum: 30000
type: integer
podAnnotations:
additionalProperties:
type: string
type: object
podLabels:
additionalProperties:
type: string
type: object
port:
description: |-
Port the proxy Service exposes. Defaults to the cluster server port so
existing clients can re-target the Service name with no port change.
format: int32
maximum: 65535
minimum: 1
type: integer
replicas:
default: 2
format: int32
minimum: 1
type: integer
requestTimeoutSecs:
description: |-
Per-request budget the proxy allows for the upstream call. Defaults
to ~ServerSpec.RequestTimeoutSecs.
format: int32
minimum: 1
type: integer
resources:
description: ResourceRequirements describes the compute resource
requirements.
properties:
claims:
description: |-
Claims lists the names of resources, defined in spec.resourceClaims,
that are used by this container.

This field depends on the
DynamicResourceAllocation feature gate.

This field is immutable. It can only be set for containers.
items:
description: ResourceClaim references one entry in PodSpec.ResourceClaims.
properties:
name:
description: |-
Name must match the name of one entry in pod.spec.resourceClaims of
the Pod where this field is used. It makes that resource available
inside a container.
type: string
request:
description: |-
Request is the name chosen for a request in the referenced claim.
If empty, everything from the claim is made available, otherwise
only the result of this request.
type: string
required:
- name
type: object
type: array
x-kubernetes-list-map-keys:
- name
x-kubernetes-list-type: map
limits:
additionalProperties:
anyOf:
- type: integer
- type: string
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
x-kubernetes-int-or-string: true
description: |-
Limits describes the maximum amount of compute resources allowed.
More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
type: object
requests:
additionalProperties:
anyOf:
- type: integer
- type: string
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
x-kubernetes-int-or-string: true
description: |-
Requests describes the minimum amount of compute resources required.
If Requests is omitted for a container, it defaults to Limits if that is explicitly specified,
otherwise to an implementation-defined value. Requests cannot exceed Limits.
More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
type: object
type: object
serviceType:
description: |-
Type of the proxy Service. Defaults to ClusterIP. Set NodePort/
LoadBalancer to expose externally.
enum:
- ClusterIP
- NodePort
- LoadBalancer
type: string
shutdownGraceSecs:
default: 30
description: |-
How long the proxy keeps serving in-flight requests after SIGTERM
before exiting. Should comfortably exceed the longest expected query.
format: int32
minimum: 1
type: integer
required:
- enabled
type: object
rateLimit:
description: RateLimitSpec controls per-endpoint request rate limiting.
properties:
Expand Down
1 change: 1 addition & 0 deletions config/rbac/role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ rules:
- apiGroups:
- apps
resources:
- deployments
- statefulsets
verbs:
- create
Expand Down
Loading
Loading