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
34 changes: 33 additions & 1 deletion apis/apps/v1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -252,10 +252,42 @@ type ComponentNetwork struct {
// +optional
DNSPolicy *corev1.DNSPolicy `json:"dnsPolicy,omitempty"`

// Specifies the DNS parameters of a pod.
// Specifies the DNS parameters of the pod.
//
// +optional
DNSConfig *corev1.PodDNSConfig `json:"dnsConfig,omitempty"`

// HostPorts specifies the mapping of container ports to host ports.
// The behavior varies based on the HostNetwork setting:
//
// 1. When HostNetwork is enabled:
// - If this field is empty: All ports are automatically allocated by the host-port manager.
// - If this field is specified:
// a) Mappings for all ports defined in `cmpd.spec.hostNetwork` are MANDATORY.
// b) Mappings for kbagent ports ("http", "streaming") are OPTIONAL.
// You can explicitly map them here, or leave them omitted to be allocated by the host-port manager.
//
// 2. When HostNetwork is disabled:
// It allows optional mapping for container ports to host ports.
// - Mappings are restricted to ports defined in `cmpd.spec.runtime.containers.ports`.
// - Any specified container ports not present in the runtime definition will be ignored.
//
// +optional
HostPorts []HostPort `json:"hostPorts,omitempty"`
}

type HostPort struct {
// The name of the container port.
//
// +kubebuilder:validation:Required
Name string `json:"name"`

// The port number of the host port.
//
// +kubebuilder:validation:Minimum=1
// +kubebuilder:validation:Maximum=65535
// +kubebuilder:validation:Required
Port int32 `json:"port"`
}

type Service struct {
Expand Down
20 changes: 20 additions & 0 deletions apis/apps/v1/zz_generated.deepcopy.go

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

2 changes: 1 addition & 1 deletion cmd/manager/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -417,7 +417,7 @@ func main() {
client = multiClusterMgr.GetClient()
}

if err := intctrlutil.InitHostPortManager(mgr.GetClient()); err != nil {
if err := intctrlutil.InitDefaultHostPortManager(mgr.GetClient()); err != nil {
setupLog.Error(err, "unable to init port manager")
os.Exit(1)
}
Expand Down
72 changes: 70 additions & 2 deletions config/crd/bases/apps.kubeblocks.io_clusters.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2709,7 +2709,7 @@ spec:
description: Defines the network configuration for the Component.
properties:
dnsConfig:
description: Specifies the DNS parameters of a pod.
description: Specifies the DNS parameters of the pod.
properties:
nameservers:
description: |-
Expand Down Expand Up @@ -2774,6 +2774,40 @@ spec:
description: Host networking requested for this pod. Use
the host's network namespace.
type: boolean
hostPorts:
description: |-
HostPorts specifies the mapping of container ports to host ports.
The behavior varies based on the HostNetwork setting:


1. When HostNetwork is enabled:
- If this field is empty: All ports are automatically allocated by the host-port manager.
- If this field is specified:
a) Mappings for all ports defined in `cmpd.spec.hostNetwork` are MANDATORY.
b) Mappings for kbagent ports ("http", "streaming") are OPTIONAL.
You can explicitly map them here, or leave them omitted to be allocated by the host-port manager.


2. When HostNetwork is disabled:
It allows optional mapping for container ports to host ports.
- Mappings are restricted to ports defined in `cmpd.spec.runtime.containers.ports`.
- Any specified container ports not present in the runtime definition will be ignored.
items:
properties:
name:
description: The name of the container port.
type: string
port:
description: The port number of the host port.
format: int32
maximum: 65535
minimum: 1
type: integer
required:
- name
- port
type: object
type: array
type: object
offlineInstances:
description: |-
Expand Down Expand Up @@ -13959,7 +13993,7 @@ spec:
description: Defines the network configuration for the Component.
properties:
dnsConfig:
description: Specifies the DNS parameters of a pod.
description: Specifies the DNS parameters of the pod.
properties:
nameservers:
description: |-
Expand Down Expand Up @@ -14024,6 +14058,40 @@ spec:
description: Host networking requested for this pod.
Use the host's network namespace.
type: boolean
hostPorts:
description: |-
HostPorts specifies the mapping of container ports to host ports.
The behavior varies based on the HostNetwork setting:


1. When HostNetwork is enabled:
- If this field is empty: All ports are automatically allocated by the host-port manager.
- If this field is specified:
a) Mappings for all ports defined in `cmpd.spec.hostNetwork` are MANDATORY.
b) Mappings for kbagent ports ("http", "streaming") are OPTIONAL.
You can explicitly map them here, or leave them omitted to be allocated by the host-port manager.


2. When HostNetwork is disabled:
It allows optional mapping for container ports to host ports.
- Mappings are restricted to ports defined in `cmpd.spec.runtime.containers.ports`.
- Any specified container ports not present in the runtime definition will be ignored.
items:
properties:
name:
description: The name of the container port.
type: string
port:
description: The port number of the host port.
format: int32
maximum: 65535
minimum: 1
type: integer
required:
- name
- port
type: object
type: array
type: object
offlineInstances:
description: |-
Expand Down
36 changes: 35 additions & 1 deletion config/crd/bases/apps.kubeblocks.io_components.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2488,7 +2488,7 @@ spec:
description: Defines the network configuration for the Component.
properties:
dnsConfig:
description: Specifies the DNS parameters of a pod.
description: Specifies the DNS parameters of the pod.
properties:
nameservers:
description: |-
Expand Down Expand Up @@ -2553,6 +2553,40 @@ spec:
description: Host networking requested for this pod. Use the host's
network namespace.
type: boolean
hostPorts:
description: |-
HostPorts specifies the mapping of container ports to host ports.
The behavior varies based on the HostNetwork setting:


1. When HostNetwork is enabled:
- If this field is empty: All ports are automatically allocated by the host-port manager.
- If this field is specified:
a) Mappings for all ports defined in `cmpd.spec.hostNetwork` are MANDATORY.
b) Mappings for kbagent ports ("http", "streaming") are OPTIONAL.
You can explicitly map them here, or leave them omitted to be allocated by the host-port manager.


2. When HostNetwork is disabled:
It allows optional mapping for container ports to host ports.
- Mappings are restricted to ports defined in `cmpd.spec.runtime.containers.ports`.
- Any specified container ports not present in the runtime definition will be ignored.
items:
properties:
name:
description: The name of the container port.
type: string
port:
description: The port number of the host port.
format: int32
maximum: 65535
minimum: 1
type: integer
required:
- name
- port
type: object
type: array
type: object
offlineInstances:
description: |-
Expand Down
2 changes: 1 addition & 1 deletion controllers/apps/cluster/suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ var _ = BeforeSuite(func() {
viper.SetDefault("HOST_PORT_CM_NAME", "kubeblocks-host-ports")
viper.SetDefault(constant.EnableRBACManager, true)

err = intctrlutil.InitHostPortManager(k8sClient)
err = intctrlutil.InitDefaultHostPortManager(k8sClient)
Expect(err).ToNot(HaveOccurred())

err = (&apps.ClusterDefinitionReconciler{
Expand Down
2 changes: 2 additions & 0 deletions controllers/apps/component/component_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,8 @@ func (r *ComponentReconciler) Reconcile(ctx context.Context, req ctrl.Request) (
&componentMonitorContainerTransformer{},
// allocate ports for host-network component
&componentHostNetworkTransformer{},
// map for container ports to host ports
&componentHostPortTransformer{},
// handle component services
&componentServiceTransformer{},
// handle component system accounts
Expand Down
2 changes: 1 addition & 1 deletion controllers/apps/component/suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ var _ = BeforeSuite(func() {
viper.SetDefault("HOST_PORT_CM_NAME", "kubeblocks-host-ports")
viper.SetDefault(constant.EnableRBACManager, true)

err = intctrlutil.InitHostPortManager(k8sClient)
err = intctrlutil.InitDefaultHostPortManager(k8sClient)
Expect(err).ToNot(HaveOccurred())

err = (&apps.ComponentDefinitionReconciler{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ func (t *componentDeletionTransformer) deleteCompResources(transCtx *componentTr
}

// release the allocated host-network ports for the component
pm := intctrlutil.GetPortManager()
pm := intctrlutil.GetPortManager(comp.Spec.Network)
if err = pm.ReleaseByPrefix(comp.Name); err != nil {
return intctrlutil.NewRequeueError(time.Second*1, fmt.Sprintf("release host ports for component %s error: %s", comp.Name, err.Error()))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,18 +43,18 @@ func (t *componentHostNetworkTransformer) Transform(ctx graph.TransformContext,
}

synthesizedComp := transCtx.SynthesizeComponent
ports, err := allocateHostPorts(synthesizedComp)
ports, err := t.allocateHostPorts(synthesizedComp)
if err != nil {
return err
}

comp := transCtx.Component
updateObjectsWithAllocatedPorts(synthesizedComp, comp, ports)
t.updateObjectsWithAllocatedPorts(synthesizedComp, comp, ports)

return nil
}

func allocateHostPorts(synthesizedComp *component.SynthesizedComponent) (map[string]map[string]int32, error) {
func (t *componentHostNetworkTransformer) allocateHostPorts(synthesizedComp *component.SynthesizedComponent) (map[string]map[string]int32, error) {
ports := map[string]map[string]bool{}
for _, c := range synthesizedComp.HostNetwork.ContainerPorts {
for _, p := range c.Ports {
Expand All @@ -65,18 +65,18 @@ func allocateHostPorts(synthesizedComp *component.SynthesizedComponent) (map[str
}
}

pm := intctrlutil.GetPortManager()
pm := intctrlutil.GetPortManager(synthesizedComp.Network)
needAllocate := func(c string, p string) bool {
containerPorts, ok := ports[c]
if !ok {
return false
}
return containerPorts[p]
}
return allocateHostPortsWithFunc(pm, synthesizedComp, needAllocate)
return t.allocateHostPortsWithFunc(pm, synthesizedComp, needAllocate)
}

func allocateHostPortsWithFunc(pm *intctrlutil.PortManager, synthesizedComp *component.SynthesizedComponent,
func (t *componentHostNetworkTransformer) allocateHostPortsWithFunc(pm intctrlutil.PortManager, synthesizedComp *component.SynthesizedComponent,
needAllocate func(string, string) bool) (map[string]map[string]int32, error) {
ports := map[string]map[string]int32{}
insert := func(c, pk string, pv int32) {
Expand All @@ -87,7 +87,7 @@ func allocateHostPortsWithFunc(pm *intctrlutil.PortManager, synthesizedComp *com
}
for _, c := range synthesizedComp.PodSpec.Containers {
for _, p := range c.Ports {
portKey := intctrlutil.BuildHostPortName(synthesizedComp.ClusterName, synthesizedComp.Name, c.Name, p.Name)
portKey := pm.PortKey(synthesizedComp.ClusterName, synthesizedComp.Name, c.Name, p.Name)
if needAllocate(c.Name, p.Name) {
port, err := pm.AllocatePort(portKey)
if err != nil {
Expand All @@ -104,7 +104,7 @@ func allocateHostPortsWithFunc(pm *intctrlutil.PortManager, synthesizedComp *com
return ports, nil
}

func updateObjectsWithAllocatedPorts(synthesizedComp *component.SynthesizedComponent,
func (t *componentHostNetworkTransformer) updateObjectsWithAllocatedPorts(synthesizedComp *component.SynthesizedComponent,
comp *appsv1.Component, ports map[string]map[string]int32) {
synthesizedComp.PodSpec.HostNetwork = true
if comp.Spec.Network != nil && comp.Spec.Network.DNSPolicy != nil {
Expand Down
58 changes: 58 additions & 0 deletions controllers/apps/component/transformer_component_hostport.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
Copyright (C) 2022-2025 ApeCloud Co., Ltd

This file is part of KubeBlocks project

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package component

import (
"github.com/apecloud/kubeblocks/pkg/controller/graph"
)

type componentHostPortTransformer struct{}

var _ graph.Transformer = &componentHostPortTransformer{}

func (t *componentHostPortTransformer) Transform(ctx graph.TransformContext, dag *graph.DAG) error {
transCtx, _ := ctx.(*componentTransformContext)
if isCompDeleting(transCtx.ComponentOrig) {
return nil
}

synthesizedComp := transCtx.SynthesizeComponent
if synthesizedComp == nil ||
synthesizedComp.PodSpec.HostNetwork ||
synthesizedComp.Network == nil ||
synthesizedComp.Network.HostNetwork {
return nil
}

ports := map[string]int32{}
for _, hostPort := range synthesizedComp.Network.HostPorts {
ports[hostPort.Name] = hostPort.Port
}
if len(ports) > 0 {
for i, c := range synthesizedComp.PodSpec.Containers {
for j, p := range c.Ports {
if hostPort, ok := ports[p.Name]; ok {
synthesizedComp.PodSpec.Containers[i].Ports[j].HostPort = hostPort
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will the HostPort allocated here be conflict with the ports automatically allocated by portmanager?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be guaranteed by the user. Either turn off the default port manager or assign a separate port range to it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok. Another question. What if two containers have defined ports with a same name?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

K8s requires that each named port in a Pod must have a unique name.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be guaranteed by the user. Either turn off the default port manager or assign a separate port range to it.

It looks like when using hostNetwork, ports defined in hostPorts spec also won't be managed by portmanager?

}
}
}
}
return nil
}
Loading
Loading