-
Notifications
You must be signed in to change notification settings - Fork 865
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Feat: add container-ports trait for hostPort and hostIP (#6187)
* Feat: add container-ports trait for hostPort and hostIP Signed-off-by: wuzhongjian <wuzhongjian_yewu@cmss.chinamobile.com> * Feat: add container-ports trait for hostPort and hostIP Signed-off-by: wuzhongjian <wuzhongjian_yewu@cmss.chinamobile.com> * Feat: add container-ports trait for hostPort and hostIP Signed-off-by: wuzhongjian <wuzhongjian_yewu@cmss.chinamobile.com> * Feat: add container-ports trait for hostPort and hostIP Signed-off-by: wuzhongjian <wuzhongjian_yewu@cmss.chinamobile.com> * Feat: add container-ports trait for hostPort and hostIP Signed-off-by: wuzhongjian <wuzhongjian_yewu@cmss.chinamobile.com> --------- Signed-off-by: wuzhongjian <wuzhongjian_yewu@cmss.chinamobile.com>
- Loading branch information
Showing
3 changed files
with
307 additions
and
0 deletions.
There are no files selected for viewing
139 changes: 139 additions & 0 deletions
139
charts/vela-core/templates/defwithtemplate/container-ports.yaml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
# Code generated by KubeVela templates. DO NOT EDIT. Please edit the original cue file. | ||
# Definition source cue file: vela-templates/definitions/internal/container-ports.cue | ||
apiVersion: core.oam.dev/v1beta1 | ||
kind: TraitDefinition | ||
metadata: | ||
annotations: | ||
definition.oam.dev/description: Expose on the host and bind the external port to host to enable web traffic for your component. | ||
name: container-ports | ||
namespace: {{ include "systemDefinitionNamespace" . }} | ||
spec: | ||
appliesToWorkloads: | ||
- deployments.apps | ||
- statefulsets.apps | ||
- daemonsets.apps | ||
- jobs.batch | ||
podDisruptive: true | ||
schematic: | ||
cue: | ||
template: | | ||
import ( | ||
"strconv" | ||
"strings" | ||
) | ||
#PatchParams: { | ||
// +usage=Specify the name of the target container, if not set, use the component name | ||
containerName: *"" | string | ||
// +usage=Specify ports you want customer traffic sent to | ||
ports: *[] | [...{ | ||
// +usage=Number of port to expose on the pod's IP address | ||
containerPort: int | ||
// +usage=Protocol for port. Must be UDP, TCP, or SCTP | ||
protocol: *"TCP" | "UDP" | "SCTP" | ||
// +usage=Number of port to expose on the host | ||
hostPort?: int | ||
// +usage=What host IP to bind the external port to. | ||
hostIP?: string | ||
}] | ||
} | ||
PatchContainer: { | ||
_params: #PatchParams | ||
name: _params.containerName | ||
_baseContainers: context.output.spec.template.spec.containers | ||
_matchContainers_: [ for _container_ in _baseContainers if _container_.name == name {_container_}] | ||
_baseContainer: *_|_ | {...} | ||
if len(_matchContainers_) == 0 { | ||
err: "container \(name) not found" | ||
} | ||
if len(_matchContainers_) > 0 { | ||
_baseContainer: _matchContainers_[0] | ||
_basePorts: _baseContainer.ports | ||
if _basePorts == _|_ { | ||
// +patchStrategy=replace | ||
ports: [ for port in _params.ports { | ||
containerPort: port.containerPort | ||
protocol: port.protocol | ||
if port.hostPort != _|_ { | ||
hostPort: port.hostPort | ||
} | ||
if port.hostIP != _|_ { | ||
hostIP: port.hostIP | ||
} | ||
}] | ||
} | ||
if _basePorts != _|_ { | ||
_basePortsMap: {for _basePort in _basePorts {(strings.ToLower(_basePort.protocol) + strconv.FormatInt(_basePort.containerPort, 10)): _basePort}} | ||
_portsMap: {for port in _params.ports {(strings.ToLower(port.protocol) + strconv.FormatInt(port.containerPort, 10)): port}} | ||
// +patchStrategy=replace | ||
ports: [ for portVar in _basePorts { | ||
containerPort: portVar.containerPort | ||
protocol: portVar.protocol | ||
_uniqueKey: strings.ToLower(portVar.protocol) + strconv.FormatInt(portVar.containerPort, 10) | ||
if _portsMap[_uniqueKey] != _|_ { | ||
if _portsMap[_uniqueKey].hostPort != _|_ { | ||
hostPort: _portsMap[_uniqueKey].hostPort | ||
} | ||
if _portsMap[_uniqueKey].hostIP != _|_ { | ||
hostIP: _portsMap[_uniqueKey].hostIP | ||
} | ||
} | ||
if _portsMap[_uniqueKey] == _|_ { | ||
if portVar.name != _|_ { | ||
name: portVar.name | ||
} | ||
} | ||
}] + [ for port in _params.ports if _basePortsMap[strings.ToLower(port.protocol)+strconv.FormatInt(port.containerPort, 10)] == _|_ { | ||
if port.containerPort != _|_ { | ||
containerPort: port.containerPort | ||
} | ||
if port.protocol != _|_ { | ||
protocol: port.protocol | ||
} | ||
if port.hostPort != _|_ { | ||
hostPort: port.hostPort | ||
} | ||
if port.hostIP != _|_ { | ||
hostIP: port.hostIP | ||
} | ||
}] | ||
} | ||
} | ||
} | ||
patch: spec: template: spec: { | ||
if parameter.containers == _|_ { | ||
// +patchKey=name | ||
containers: [{ | ||
PatchContainer & {_params: { | ||
if parameter.containerName == "" { | ||
containerName: context.name | ||
} | ||
if parameter.containerName != "" { | ||
containerName: parameter.containerName | ||
} | ||
ports: parameter.ports | ||
}} | ||
}] | ||
} | ||
if parameter.containers != _|_ { | ||
// +patchKey=name | ||
containers: [ for c in parameter.containers { | ||
if c.containerName == "" { | ||
err: "container name must be set for containers" | ||
} | ||
if c.containerName != "" { | ||
PatchContainer & {_params: c} | ||
} | ||
}] | ||
} | ||
} | ||
parameter: *#PatchParams | close({ | ||
// +usage=Specify the container ports for multiple containers | ||
containers: [...#PatchParams] | ||
}) | ||
errs: [ for c in patch.spec.template.spec.containers if c.err != _|_ {c.err}] | ||
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
It's used to define Pod networks directly. hostPort routes the container's port directly to the port on the scheduled node, so that you can access the Pod through the host's IP plus hostPort. | ||
Don't specify a hostPort for a Pod unless it is absolutely necessary(run `DaemonSet` service). When you bind a Pod to a hostPort, it limits the number of places the Pod can be scheduled, because each <hostIP, hostPort, protocol> combination must be unique. If you don't specify the hostIP and protocol explicitly, Kubernetes will use 0.0.0.0 as the default hostIP and TCP as the default protocol. | ||
If you explicitly need to expose a Pod's port on the node, consider using `expose` or `gateway` trait, or exposeType and ports parameter of `webservice` component before resorting to `container-ports` trait. | ||
```yaml | ||
apiVersion: core.oam.dev/v1beta1 | ||
kind: Application | ||
metadata: | ||
name: busybox | ||
spec: | ||
components: | ||
- name: busybox | ||
type: webservice | ||
properties: | ||
cpu: "0.5" | ||
exposeType: ClusterIP | ||
image: busybox | ||
memory: 1024Mi | ||
ports: | ||
- expose: false | ||
port: 80 | ||
protocol: TCP | ||
- expose: false | ||
port: 801 | ||
protocol: TCP | ||
traits: | ||
- type: container-ports | ||
properties: | ||
# you can use container-ports to control multiple containers by filling `containers` | ||
# NOTE: in containers, you must set the container name for each container | ||
containers: | ||
- containerName: busybox | ||
ports: | ||
- containerPort: 80 | ||
protocol: TCP | ||
hostPort: 8080 | ||
``` |
132 changes: 132 additions & 0 deletions
132
vela-templates/definitions/internal/trait/container-ports.cue
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
import ( | ||
"strconv" | ||
"strings" | ||
) | ||
|
||
"container-ports": { | ||
type: "trait" | ||
annotations: {} | ||
labels: {} | ||
description: "Expose on the host and bind the external port to host to enable web traffic for your component." | ||
attributes: { | ||
podDisruptive: true | ||
appliesToWorkloads: ["deployments.apps", "statefulsets.apps", "daemonsets.apps", "jobs.batch"] | ||
} | ||
} | ||
|
||
template: { | ||
#PatchParams: { | ||
// +usage=Specify the name of the target container, if not set, use the component name | ||
containerName: *"" | string | ||
// +usage=Specify ports you want customer traffic sent to | ||
ports: *[] | [...{ | ||
// +usage=Number of port to expose on the pod's IP address | ||
containerPort: int | ||
// +usage=Protocol for port. Must be UDP, TCP, or SCTP | ||
protocol: *"TCP" | "UDP" | "SCTP" | ||
// +usage=Number of port to expose on the host | ||
hostPort?: int | ||
// +usage=What host IP to bind the external port to. | ||
hostIP?: string | ||
}] | ||
} | ||
|
||
PatchContainer: { | ||
_params: #PatchParams | ||
name: _params.containerName | ||
_baseContainers: context.output.spec.template.spec.containers | ||
_matchContainers_: [ for _container_ in _baseContainers if _container_.name == name {_container_}] | ||
_baseContainer: *_|_ | {...} | ||
if len(_matchContainers_) == 0 { | ||
err: "container \(name) not found" | ||
} | ||
if len(_matchContainers_) > 0 { | ||
_baseContainer: _matchContainers_[0] | ||
_basePorts: _baseContainer.ports | ||
if _basePorts == _|_ { | ||
// +patchStrategy=replace | ||
ports: [ for port in _params.ports { | ||
containerPort: port.containerPort | ||
protocol: port.protocol | ||
if port.hostPort != _|_ { | ||
hostPort: port.hostPort | ||
} | ||
if port.hostIP != _|_ { | ||
hostIP: port.hostIP | ||
} | ||
}] | ||
} | ||
if _basePorts != _|_ { | ||
_basePortsMap: {for _basePort in _basePorts {(strings.ToLower(_basePort.protocol) + strconv.FormatInt(_basePort.containerPort, 10)): _basePort}} | ||
_portsMap: {for port in _params.ports {(strings.ToLower(port.protocol) + strconv.FormatInt(port.containerPort, 10)): port}} | ||
// +patchStrategy=replace | ||
ports: [ for portVar in _basePorts { | ||
containerPort: portVar.containerPort | ||
protocol: portVar.protocol | ||
_uniqueKey: strings.ToLower(portVar.protocol) + strconv.FormatInt(portVar.containerPort, 10) | ||
if _portsMap[_uniqueKey] != _|_ { | ||
if _portsMap[_uniqueKey].hostPort != _|_ { | ||
hostPort: _portsMap[_uniqueKey].hostPort | ||
} | ||
if _portsMap[_uniqueKey].hostIP != _|_ { | ||
hostIP: _portsMap[_uniqueKey].hostIP | ||
} | ||
} | ||
if _portsMap[_uniqueKey] == _|_ { | ||
if portVar.name != _|_ { | ||
name: portVar.name | ||
} | ||
} | ||
}] + [ for port in _params.ports if _basePortsMap[strings.ToLower(port.protocol)+strconv.FormatInt(port.containerPort, 10)] == _|_ { | ||
if port.containerPort != _|_ { | ||
containerPort: port.containerPort | ||
} | ||
if port.protocol != _|_ { | ||
protocol: port.protocol | ||
} | ||
if port.hostPort != _|_ { | ||
hostPort: port.hostPort | ||
} | ||
if port.hostIP != _|_ { | ||
hostIP: port.hostIP | ||
} | ||
}] | ||
} | ||
} | ||
} | ||
|
||
patch: spec: template: spec: { | ||
if parameter.containers == _|_ { | ||
// +patchKey=name | ||
containers: [{ | ||
PatchContainer & {_params: { | ||
if parameter.containerName == "" { | ||
containerName: context.name | ||
} | ||
if parameter.containerName != "" { | ||
containerName: parameter.containerName | ||
} | ||
ports: parameter.ports | ||
}} | ||
}] | ||
} | ||
if parameter.containers != _|_ { | ||
// +patchKey=name | ||
containers: [ for c in parameter.containers { | ||
if c.containerName == "" { | ||
err: "container name must be set for containers" | ||
} | ||
if c.containerName != "" { | ||
PatchContainer & {_params: c} | ||
} | ||
}] | ||
} | ||
} | ||
|
||
parameter: *#PatchParams | close({ | ||
// +usage=Specify the container ports for multiple containers | ||
containers: [...#PatchParams] | ||
}) | ||
|
||
errs: [ for c in patch.spec.template.spec.containers if c.err != _|_ {c.err}] | ||
} |