VictoriaMetrics / VictoriaMetrics/operator
VMCluster: serviceSpec.useAsDefault cannot change vmselect Service from headless to ClusterIP
@AndrewChubatiuk is already working on this.
Since Aug 21, 2026.
- Dominant language
- Go
- Stars
- 589
- Forks
- 229
- Avg merge
- 1d 9h
- Merged PRs (30d)
- 77
Description
What happens
For components whose default Service is headless (vmselect, vmstorage, vmalertmanager), serviceSpec.useAsDefault: true silently keeps clusterIP: None no matter what is supplied in spec. There is no way to turn the main Service into a normal ClusterIP Service.
Why
build.Service re-inherits the default's clusterIP after replacing the spec:
if serviceOverrides.Spec.ClusterIP == "" && serviceOverrides.Spec.Type == svc.Spec.Type {
serviceOverrides.Spec.ClusterIP = svc.Spec.ClusterIP
}
At that point svc.Spec.ClusterIP is already "None", set by the component callback:
svc.Spec.ClusterIP = "None"
svc.Spec.PublishNotReadyAddresses = true
Omitting type in the override is not an escape either, because it is defaulted from the base Service three lines earlier, which then makes the guard's second condition true:
Reproduction
helm install victoria-metrics-operator vm/victoria-metrics-operator --version 0.67.2
Then kubectl apply this file:
apiVersion: operator.victoriametrics.com/v1beta1
kind: VMCluster
metadata:
name: example
namespace: infra
spec:
retentionPeriod: "1"
vmselect:
replicaCount: 1
serviceSpec:
useAsDefault: true
spec:
type: ClusterIP
ports:
- name: http
port: 8481
targetPort: 8481
vmstorage:
replicaCount: 1
Result:
kubectl get svc vmselect-example -o jsonpath='{.spec.clusterIP}'
Expected: an allocated cluster IP.
Actual: None.
Changing useAsDefault to false (and giving the override a distinct metadata.name) produces a second Service that does get a VIP — demonstrating the inconsistency.
Suggested fix
Only inherit the base clusterIP when the user's override is silent about the service shape. Capture whether the user set type before it is defaulted, and skip the inherit if they did:
userSetType := serviceOverrides.Spec.Type != ""
if serviceOverrides.Spec.Type == "" {
serviceOverrides.Spec.Type = svc.Spec.Type
}
if !userSetType && serviceOverrides.Spec.ClusterIP == "" && serviceOverrides.Spec.Type == svc.Spec.Type {
serviceOverrides.Spec.ClusterIP = svc.Spec.ClusterIP
}
That preserves today's behaviour for users who only override ports or labels, while letting an explicit type: ClusterIP mean "allocate a VIP".
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.