diff --git a/apis/v1alpha1/cluster_types.go b/apis/v1alpha1/cluster_types.go index b21ae79f7..70a0287ac 100644 --- a/apis/v1alpha1/cluster_types.go +++ b/apis/v1alpha1/cluster_types.go @@ -137,6 +137,9 @@ type CrdbClusterSpec struct { // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Map of nodeSelectors to match when scheduling pods on nodes" // +optional NodeSelector map[string]string `json:"nodeSelector,omitempty"` + // (Optional) HostAliases is an optional list of hosts and IPs that will be injected into the pod's hosts file if specified. + // +optional + HostAliases []corev1.HostAlias `json:"hostAliases,omitempty"` // (Optional) Ingress defines the Ingress configuration used to expose the services using Ingress // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Cockroach Database Ingress" // +optional diff --git a/apis/v1alpha1/zz_generated.deepcopy.go b/apis/v1alpha1/zz_generated.deepcopy.go index 9be602931..9308d0d05 100644 --- a/apis/v1alpha1/zz_generated.deepcopy.go +++ b/apis/v1alpha1/zz_generated.deepcopy.go @@ -209,6 +209,13 @@ func (in *CrdbClusterSpec) DeepCopyInto(out *CrdbClusterSpec) { (*out)[key] = val } } + if in.HostAliases != nil { + in, out := &in.HostAliases, &out.HostAliases + *out = make([]v1.HostAlias, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } if in.Ingress != nil { in, out := &in.Ingress, &out.Ingress *out = new(IngressConfig) diff --git a/config/crd/bases/crdb.cockroachlabs.com_crdbclusters.yaml b/config/crd/bases/crdb.cockroachlabs.com_crdbclusters.yaml index 6bb1d466a..d5aecf83b 100644 --- a/config/crd/bases/crdb.cockroachlabs.com_crdbclusters.yaml +++ b/config/crd/bases/crdb.cockroachlabs.com_crdbclusters.yaml @@ -1525,6 +1525,21 @@ spec: type: string description: (Optional) If specified, the pod's nodeSelector type: object + hostAliases: + description: (Optional) HostAliases is an optional list of hosts and + IPs that will be injected into the pod's hosts file. + items: + properties: + hostnames: + items: + type: string + type: array + ip: + type: string + required: + - ip + type: object + type: array nodeTLSSecret: description: '(Optional) The secret with certificates and a private key for the TLS endpoint on the database port. The standard naming diff --git a/config/manifests/bases/cockroach-operator.clusterserviceversion.yaml b/config/manifests/bases/cockroach-operator.clusterserviceversion.yaml index 27f0e5318..8d8cb72d8 100644 --- a/config/manifests/bases/cockroach-operator.clusterserviceversion.yaml +++ b/config/manifests/bases/cockroach-operator.clusterserviceversion.yaml @@ -116,6 +116,10 @@ spec: - description: (Optional) If specified, the pod's nodeSelector displayName: Map of nodeSelectors to match when scheduling pods on nodes path: nodeSelector + - description: (Optional) HostAliases is an optional list of hosts and IPs + that will be injected into the pod's hosts file. + displayName: Pod Host Aliases + path: hostAliases - description: Number of nodes (pods) in the cluster displayName: Number of nodes path: nodes diff --git a/config/templates/csv.yaml.in b/config/templates/csv.yaml.in index 25a488ded..4ddab29d7 100644 --- a/config/templates/csv.yaml.in +++ b/config/templates/csv.yaml.in @@ -116,6 +116,10 @@ spec: - description: (Optional) If specified, the pod's nodeSelector displayName: Map of nodeSelectors to match when scheduling pods on nodes path: nodeSelector + - description: (Optional) HostAliases is an optional list of hosts and IPs + that will be injected into the pod's hosts file. + displayName: Pod Host Aliases + path: hostAliases - description: Number of nodes (pods) in the cluster displayName: Number of nodes path: nodes diff --git a/config/templates/example.yaml.in b/config/templates/example.yaml.in index 4b9be7b7a..cf8c31567 100644 --- a/config/templates/example.yaml.in +++ b/config/templates/example.yaml.in @@ -69,3 +69,9 @@ spec: # nodeSelectors used to match against # nodeSelector: # worker-pool-name: crdb-workers + + # hostAliases entries are added to /etc/hosts in each CockroachDB pod. + # hostAliases: + # - ip: "10.10.0.10" + # hostnames: + # - "dev.local" diff --git a/examples/example.yaml b/examples/example.yaml index 04a6fa7f3..2cd4937b8 100644 --- a/examples/example.yaml +++ b/examples/example.yaml @@ -68,3 +68,9 @@ spec: # nodeSelectors used to match against # nodeSelector: # worker-pool-name: crdb-workers + + # hostAliases entries are added to /etc/hosts in each CockroachDB pod. + # hostAliases: + # - ip: "10.10.0.10" + # hostnames: + # - "dev.local" diff --git a/install/crds.yaml b/install/crds.yaml index c8cc5e35a..d369c774f 100644 --- a/install/crds.yaml +++ b/install/crds.yaml @@ -1524,6 +1524,21 @@ spec: type: string description: (Optional) If specified, the pod's nodeSelector type: object + hostAliases: + description: (Optional) HostAliases is an optional list of hosts and + IPs that will be injected into the pod's hosts file. + items: + properties: + hostnames: + items: + type: string + type: array + ip: + type: string + required: + - ip + type: object + type: array nodeTLSSecret: description: '(Optional) The secret with certificates and a private key for the TLS endpoint on the database port. The standard naming diff --git a/pkg/resource/statefulset.go b/pkg/resource/statefulset.go index 318393220..a31bdc296 100644 --- a/pkg/resource/statefulset.go +++ b/pkg/resource/statefulset.go @@ -236,6 +236,9 @@ func (b StatefulSetBuilder) makePodTemplate() corev1.PodTemplateSpec { if len(b.Spec().NodeSelector) > 0 { pod.Spec.NodeSelector = b.Spec().NodeSelector } + if len(b.Spec().HostAliases) > 0 { + pod.Spec.HostAliases = b.Spec().HostAliases + } secret := b.GetImagePullSecret() if secret != nil { diff --git a/pkg/resource/testdata/TestStatefulSetBuilder/host_aliases.golden b/pkg/resource/testdata/TestStatefulSetBuilder/host_aliases.golden new file mode 100644 index 000000000..d60e535d5 --- /dev/null +++ b/pkg/resource/testdata/TestStatefulSetBuilder/host_aliases.golden @@ -0,0 +1,117 @@ +apiVersion: apps/v1 +kind: StatefulSet +metadata: + annotations: + crdb.io/containerimage: "" + crdb.io/version: "" + creationTimestamp: null + name: test-cluster +spec: + podManagementPolicy: Parallel + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/component: database + app.kubernetes.io/instance: test-cluster + app.kubernetes.io/name: cockroachdb + serviceName: test-cluster + template: + metadata: + creationTimestamp: null + labels: + app.kubernetes.io/component: database + app.kubernetes.io/instance: test-cluster + app.kubernetes.io/name: cockroachdb + spec: + automountServiceAccountToken: false + hostAliases: + - hostnames: + - dev.local + ip: 10.10.0.10 + terminationGracePeriodSecs: 300 + containers: + - command: + - /bin/bash + - -ecx + - 'exec /cockroach/cockroach.sh start --advertise-host=$(POD_NAME).test-cluster.test-ns + --insecure --http-port=8080 --sql-addr=:26257 --listen-addr=:26258 --log="{sinks: + {stderr: {channels: [OPS, HEALTH], redact: true}}}" --cache $(expr $MEMORY_LIMIT_MIB + / 4)MiB --max-sql-memory $(expr $MEMORY_LIMIT_MIB / 4)MiB --join=test-cluster-0.test-cluster.test-ns:26258' + env: + - name: COCKROACH_CHANNEL + value: kubernetes-operator-gke + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: GOMAXPROCS + valueFrom: + resourceFieldRef: + divisor: "1" + resource: limits.cpu + - name: MEMORY_LIMIT_MIB + valueFrom: + resourceFieldRef: + divisor: 1Mi + resource: limits.memory + image: cockroachdb/cockroach:v21.1.0 + imagePullPolicy: IfNotPresent + lifecycle: + preStop: + exec: + command: + - sh + - -c + - /cockroach/cockroach node drain --insecure || exit 0 + name: db + ports: + - containerPort: 26258 + name: grpc + protocol: TCP + - containerPort: 8080 + name: http + protocol: TCP + - containerPort: 26257 + name: sql + protocol: TCP + readinessProbe: + failureThreshold: 2 + httpGet: + path: /health?ready=1 + port: http + scheme: HTTP + initialDelaySeconds: 10 + periodSeconds: 5 + resources: {} + volumeMounts: + - mountPath: /cockroach/cockroach-data/ + name: datadir + securityContext: + fsGroup: 1000581000 + runAsUser: 1000581000 + serviceAccountName: test-cluster-sa + terminationGracePeriodSeconds: 300 + volumes: + - name: datadir + persistentVolumeClaim: + claimName: "" + updateStrategy: + rollingUpdate: {} + volumeClaimTemplates: + - metadata: + creationTimestamp: null + labels: + app.kubernetes.io/component: database + app.kubernetes.io/instance: test-cluster + app.kubernetes.io/name: cockroachdb + name: datadir + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi + volumeMode: Filesystem + status: {} +status: + replicas: 0 diff --git a/pkg/resource/testdata/TestStatefulSetBuilder/host_aliases_in.yaml b/pkg/resource/testdata/TestStatefulSetBuilder/host_aliases_in.yaml new file mode 100644 index 000000000..930d9a5d4 --- /dev/null +++ b/pkg/resource/testdata/TestStatefulSetBuilder/host_aliases_in.yaml @@ -0,0 +1,44 @@ +# Copyright 2026 The Cockroach Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: crdb.cockroachlabs.com/v1alpha1 +kind: CrdbCluster +metadata: + creationTimestamp: null + name: test-cluster + namespace: test-ns +spec: + terminationGracePeriodSecs: 300 + dataStore: + pvc: + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: "1Gi" + volumeMode: Filesystem + grpcPort: 26258 + hostAliases: + - ip: "10.10.0.10" + hostnames: + - "dev.local" + httpPort: 8080 + image: + name: cockroachdb/cockroach:v21.1.0 + nodes: 1 + topology: + zones: + - locality: "" +status: {}