feat(cluster): add default container registry field to advanced config

Surface the top-level system_default_container_registry as a dedicated
input (both Docker and K8s), coerce blank to null, and drop its
redundant worker_config YAML hint.
This commit is contained in:
Yuxing Deng
2026-05-29 23:11:46 +08:00
committed by jialin
parent 1b6466ae78
commit f62e0ba372
8 changed files with 46 additions and 5 deletions
+3
View File
@@ -162,6 +162,9 @@ export default {
'clusters.volume.configMap.name': 'ConfigMap Name',
'clusters.volume.configMap.optional': 'Optional',
'clusters.volume.add': 'Add Volume Mount',
'clusters.systemDefaultContainerRegistry.title': 'Default Container Registry',
'clusters.systemDefaultContainerRegistry.tip':
'Default registry used to resolve GPUStack images for this cluster. Falls back to the server default when unset.',
'clusters.k8sOptions.title': 'K8s Deployment Options',
'clusters.imageCredentials.title': 'Image Credentials',
'clusters.imageCredentials.add': 'Add Credential',
+3
View File
@@ -162,6 +162,9 @@ export default {
'clusters.volume.configMap.name': 'ConfigMap Name',
'clusters.volume.configMap.optional': 'Optional',
'clusters.volume.add': 'Add Volume Mount',
'clusters.systemDefaultContainerRegistry.title': 'Default Container Registry',
'clusters.systemDefaultContainerRegistry.tip':
'Default registry used to resolve GPUStack images for this cluster. Falls back to the server default when unset.',
'clusters.k8sOptions.title': 'K8s Deployment Options',
'clusters.imageCredentials.title': 'Image Credentials',
'clusters.imageCredentials.add': 'Add Credential',
+3
View File
@@ -163,6 +163,9 @@ export default {
'clusters.volume.configMap.name': 'ConfigMap Name',
'clusters.volume.configMap.optional': 'Optional',
'clusters.volume.add': 'Add Volume Mount',
'clusters.systemDefaultContainerRegistry.title': 'Default Container Registry',
'clusters.systemDefaultContainerRegistry.tip':
'Default registry used to resolve GPUStack images for this cluster. Falls back to the server default when unset.',
'clusters.k8sOptions.title': 'K8s Deployment Options',
'clusters.imageCredentials.title': 'Image Credentials',
'clusters.imageCredentials.add': 'Add Credential',
+3
View File
@@ -163,6 +163,9 @@ export default {
'clusters.volume.configMap.name': 'ConfigMap Name',
'clusters.volume.configMap.optional': 'Optional',
'clusters.volume.add': 'Add Volume Mount',
'clusters.systemDefaultContainerRegistry.title': 'Default Container Registry',
'clusters.systemDefaultContainerRegistry.tip':
'Default registry used to resolve GPUStack images for this cluster. Falls back to the server default when unset.',
'clusters.k8sOptions.title': 'K8s Deployment Options',
'clusters.imageCredentials.title': 'Image Credentials',
'clusters.imageCredentials.add': 'Add Credential',
+3
View File
@@ -155,6 +155,9 @@ export default {
'clusters.volume.configMap.name': '配置名称',
'clusters.volume.configMap.optional': '可选',
'clusters.volume.add': '添加卷挂载',
'clusters.systemDefaultContainerRegistry.title': '默认容器镜像仓库',
'clusters.systemDefaultContainerRegistry.tip':
'用于解析该集群 GPUStack 镜像的默认镜像仓库。未设置时回退到服务端默认值。',
'clusters.k8sOptions.title': 'K8s 部署选项',
'clusters.imageCredentials.title': '镜像仓库凭证',
'clusters.imageCredentials.add': '添加凭证',
@@ -64,8 +64,18 @@ const ClusterForm: React.FC<AddModalProps> = forwardRef(
// "no auth". Coerce empty form values to null before sending so a blank
// input is unambiguous rather than an empty string that defeats fallbacks.
const normalizeOutgoing = (values: any): any => {
const opts = values?.k8s_options;
if (!opts) return values;
const base: any = { ...values };
// Top-level cluster field shared by Docker and K8s. Trim then coerce a
// blank input to null so clearing it on edit (or a whitespace-only
// value) falls back to the server default rather than persisting an
// empty string.
if (base.system_default_container_registry !== undefined) {
base.system_default_container_registry =
base.system_default_container_registry?.trim() || null;
}
const opts = base.k8s_options;
if (!opts) return base;
const next: any = { ...opts };
@@ -90,7 +100,7 @@ const ClusterForm: React.FC<AddModalProps> = forwardRef(
};
}
return { ...values, k8s_options: next };
return { ...base, k8s_options: next };
};
const handleOnFinish = (_values: FormData) => {
@@ -9,7 +9,6 @@ export const dockerConfig = `# This is a template for worker_config.
# ========= container & image ===========
# system_default_container_registry: "docker.io"
# image_name_override: "gpustack/gpustack:dev"
# image_repo: "gpustack/gpustack"
@@ -53,7 +52,6 @@ export const kubernetesConfig = `# This is a template for worker_config.
# ========= container & image ===========
# system_default_container_registry: "docker.io"
# image_name_override: "gpustack/gpustack:dev"
# image_repo: "gpustack/gpustack"
@@ -88,6 +88,24 @@ const ClusterAdvanceConfig: React.FC<{
>
<CInput.TextArea required={false} trim={false}></CInput.TextArea>
</Form.Item>
{/* Default container registry used to resolve images for this cluster.
A top-level cluster field shared by both Docker and Kubernetes
providers (the backend hoists any legacy worker_config value onto
this column). */}
<Form.Item<FormData>
name="system_default_container_registry"
style={{ marginBottom: 16 }}
>
<CInput.Input
label={intl.formatMessage({
id: 'clusters.systemDefaultContainerRegistry.title'
})}
description={intl.formatMessage({
id: 'clusters.systemDefaultContainerRegistry.tip'
})}
placeholder="docker.io"
></CInput.Input>
</Form.Item>
<Title>
{intl.formatMessage({ id: 'clusters.create.workerConfig' })}
</Title>