Skip to content

Commit 010e963

Browse files
valaparthvirm3l
andauthored
Use custom address for port forwarding (#6766)
* Custom address for port forwarding Signed-off-by: Parthvi Vala <[email protected]> * Add integration tests Signed-off-by: Parthvi Vala <[email protected]> * Use private variables for custom address and ports Signed-off-by: Parthvi Vala <[email protected]> * Update pkg/util/util.go Co-authored-by: Armel Soro <[email protected]> * Assign custom address to HostIP for podman Signed-off-by: Parthvi Vala <[email protected]> * Add validation for free port when --port-forward is provided in the Validate() method, add integration test for running parallel dev sessions on same platform, same port and different addresses Signed-off-by: Parthvi Vala <[email protected]> * Fix unit test failure Signed-off-by: Parthvi Vala <[email protected]> * Attempt at fixing windows failure Signed-off-by: Parthvi Vala <[email protected]> * Add documentation Signed-off-by: Parthvi Vala <[email protected]> * Use default value for --address flag Signed-off-by: Parthvi Vala <[email protected]> * Changes from review Co-authored-by: Armel Soro <[email protected]> Signed-off-by: Parthvi Vala <[email protected]> --------- Signed-off-by: Parthvi Vala <[email protected]> Co-authored-by: Armel Soro <[email protected]> Co-authored-by: Armel Soro <[email protected]>
1 parent 191ee6f commit 010e963

File tree

23 files changed

+898
-284
lines changed

23 files changed

+898
-284
lines changed

docs/website/docs/command-reference/dev.md

+108
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,114 @@ The following command will override the `USER` Devfile variable with the `john`
244244
odo dev --var USER=john --var-file config.vars
245245
```
246246

247+
248+
### Using custom port mapping for port forwarding
249+
Custom local ports can be passed for port forwarding with the help of the `--port-forward` flag. This feature is supported on both podman and cluster.
250+
251+
This feature can be helpful when you want to provide consistent and predictable port numbers and avoid being assigned a potentially different port number every time `odo dev` is run.
252+
253+
Supported formats for this flag include:
254+
1. `<LOCAL_PORT>:<CONTAINER_PORT>`
255+
2. `<LOCAL_PORT>:<CONTAINER_NAME>:<CONTAINER_PORT>` - This format is necessary when multiple container components of a Devfile have the same port number.
256+
257+
The flag accepts a stringArray, so `--port-forward` flag can be defined multiple times.
258+
259+
If a custom port mapping is not defined for a port, `odo` will assign a free port in the range of 20001-30001.
260+
261+
```shell
262+
odo dev --port-forward <LOCAL_PORT_1>:<CONTAINER_PORT_1> --port-forward <LOCAL_PORT_2>:<CONTAINER_NAME>:<CONTAINER_PORT_2>
263+
```
264+
265+
<details>
266+
<summary>Example</summary>
267+
268+
```shell
269+
$ odo dev --port-forward 3000:runtime:3000 --port-forward 5000:5858 --debug
270+
__
271+
/ \__ Developing using the "my-nodejs-app" Devfile
272+
\__/ \ Namespace: default
273+
/ \__/ odo version: v3.9.0
274+
\__/
275+
276+
⚠ You are using "default" namespace, odo may not work as expected in the default namespace.
277+
⚠ You may set a new namespace by running `odo create namespace <name>`, or set an existing one by running `odo set namespace <name>`
278+
279+
↪ Running on the cluster in Dev mode
280+
• Waiting for Kubernetes resources ...
281+
⚠ Pod is Pending
282+
✓ Pod is Running
283+
✓ Syncing files into the container [152ms]
284+
✓ Building your application in container (command: install) [27s]
285+
• Executing the application (command: debug) ...
286+
✓ Waiting for the application to be ready [1s]
287+
- Forwarding from 127.0.0.1:8000 -> 3000
288+
289+
- Forwarding from 127.0.0.1:5000 -> 5858
290+
291+
292+
↪ Dev mode
293+
Status:
294+
Watching for changes in the current directory /tmp/nodejs-debug-2
295+
296+
Keyboard Commands:
297+
[Ctrl+c] - Exit and delete resources from the cluster
298+
[p] - Manually apply local changes to the application on the cluster
299+
```
300+
</details>
301+
302+
Note that `--random-ports` flag cannot be used with `--port-forward` flag.
303+
304+
### Using custom address for port forwarding
305+
A custom address can be passed for port forwarding with the help of `--address` flag. This feature is supported on both podman and cluster.
306+
The default value is 127.0.0.1.
307+
308+
```shell
309+
odo dev --address <IP_ADDRESS>
310+
```
311+
312+
<details>
313+
<summary>Example</summary>
314+
315+
```shell
316+
$ odo dev --address 127.0.10.3
317+
__
318+
/ \__ Developing using the "my-nodejs-app" Devfile
319+
\__/ \ Namespace: default
320+
/ \__/ odo version: v3.9.0
321+
\__/
322+
323+
⚠ You are using "default" namespace, odo may not work as expected in the default namespace.
324+
⚠ You may set a new namespace by running `odo create namespace <name>`, or set an existing one by running `odo set namespace <name>`
325+
326+
↪ Running on the cluster in Dev mode
327+
• Waiting for Kubernetes resources ...
328+
⚠ Pod is Pending
329+
✓ Pod is Running
330+
✓ Syncing files into the container [123ms]
331+
✓ Building your application in container (command: install) [15s]
332+
• Executing the application (command: run) ...
333+
✓ Waiting for the application to be ready [1s]
334+
- Forwarding from 127.0.10.3:20001 -> 3000
335+
336+
337+
↪ Dev mode
338+
Status:
339+
Watching for changes in the current directory /tmp/nodejs-debug-2
340+
341+
Keyboard Commands:
342+
[Ctrl+c] - Exit and delete resources from the cluster
343+
[p] - Manually apply local changes to the application on the cluster
344+
```
345+
</details>
346+
347+
:::note
348+
If you are on macOS and using a Cluster platform, you may not be able to run multiple Dev sessions in parallel on address 0.0.0.0 without defining a custom port mapping, or using a different or default address.
349+
350+
For more information, see the following issues:
351+
1. [Cannot start 2 different Dev sessions on Podman due to conflicting host ports](https://github.com/redhat-developer/odo/issues/6612)
352+
2. [[MacOS] Cannot run 2 dev sessions simultaneously on cluster](https://github.com/redhat-developer/odo/issues/6744)
353+
:::
354+
247355
### Running on Podman
248356
249357
Instead of deploying the container into a Kubernetes cluster, `odo dev` can leverage the podman installation on your system to deploy the container.

pkg/dev/interface.go

+2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ type StartOptions struct {
2222
RandomPorts bool
2323
// CustomForwardedPorts define custom ports for port forwarding
2424
CustomForwardedPorts []api.ForwardedPort
25+
// CustomAddress defines a custom local address for port forwarding; default value is 127.0.0.1
26+
CustomAddress string
2527
// if WatchFiles is set, files changes will trigger a new sync to the container
2628
WatchFiles bool
2729
// IgnoreLocalhost indicates whether to proceed with port-forwarding regardless of any container ports being bound to the container loopback interface.

pkg/dev/kubedev/innerloop.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ func (o *DevClient) innerloop(ctx context.Context, parameters common.PushParamet
180180
fmt.Fprintln(log.GetStdout())
181181
}
182182

183-
err = o.portForwardClient.StartPortForwarding(ctx, parameters.Devfile, componentName, parameters.StartOptions.Debug, parameters.StartOptions.RandomPorts, log.GetStdout(), parameters.StartOptions.ErrOut, parameters.StartOptions.CustomForwardedPorts)
183+
err = o.portForwardClient.StartPortForwarding(ctx, parameters.Devfile, componentName, parameters.StartOptions.Debug, parameters.StartOptions.RandomPorts, log.GetStdout(), parameters.StartOptions.ErrOut, parameters.StartOptions.CustomForwardedPorts, parameters.StartOptions.CustomAddress)
184184
if err != nil {
185185
return common.NewErrPortForward(err)
186186
}

pkg/dev/podmandev/pod.go

+17-8
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ func createPodFromComponent(
4242
randomPorts bool,
4343
customForwardedPorts []api.ForwardedPort,
4444
usedPorts []int,
45+
customAddress string,
4546
) (*corev1.Pod, []api.ForwardedPort, error) {
4647
var (
4748
appName = odocontext.GetApplication(ctx)
@@ -60,7 +61,7 @@ func createPodFromComponent(
6061
}
6162

6263
var fwPorts []api.ForwardedPort
63-
fwPorts, err = getPortMapping(*devfileObj, debug, randomPorts, usedPorts, customForwardedPorts)
64+
fwPorts, err = getPortMapping(*devfileObj, debug, randomPorts, usedPorts, customForwardedPorts, customAddress)
6465
if err != nil {
6566
return nil, nil, err
6667
}
@@ -112,7 +113,7 @@ func createPodFromComponent(
112113
return nil, nil, err
113114
}
114115

115-
containers = addHostPorts(withHelperContainer, containers, fwPorts)
116+
containers = addHostPorts(withHelperContainer, containers, fwPorts, customAddress)
116117

117118
pod := corev1.Pod{
118119
Spec: corev1.PodSpec{
@@ -142,7 +143,10 @@ func createPodFromComponent(
142143
return &pod, fwPorts, nil
143144
}
144145

145-
func addHostPorts(withHelperContainer bool, containers []corev1.Container, fwPorts []api.ForwardedPort) []corev1.Container {
146+
func addHostPorts(withHelperContainer bool, containers []corev1.Container, fwPorts []api.ForwardedPort, customAddress string) []corev1.Container {
147+
if customAddress == "" {
148+
customAddress = "127.0.0.1"
149+
}
146150
if withHelperContainer {
147151
// A side helper container is added and will be responsible for redirecting the traffic,
148152
// so it can work even if the application is listening on the container loopback interface.
@@ -164,6 +168,7 @@ func addHostPorts(withHelperContainer bool, containers []corev1.Container, fwPor
164168
Name: fwPort.PortName,
165169
ContainerPort: int32(fwPort.LocalPort),
166170
HostPort: int32(fwPort.LocalPort),
171+
HostIP: customAddress,
167172
})
168173
}
169174
containers = append(containers, pfHelperContainer)
@@ -176,6 +181,7 @@ func addHostPorts(withHelperContainer bool, containers []corev1.Container, fwPor
176181
for _, fwPort := range fwPorts {
177182
if containers[i].Name == fwPort.ContainerName && int(p.ContainerPort) == fwPort.ContainerPort {
178183
p.HostPort = int32(fwPort.LocalPort)
184+
p.HostIP = customAddress
179185
containerPorts = append(containerPorts, p)
180186
break
181187
}
@@ -191,7 +197,10 @@ func getVolumeName(volume string, componentName string, appName string) string {
191197
return volume + "-" + componentName + "-" + appName
192198
}
193199

194-
func getPortMapping(devfileObj parser.DevfileObj, debug bool, randomPorts bool, usedPorts []int, definedPorts []api.ForwardedPort) ([]api.ForwardedPort, error) {
200+
func getPortMapping(devfileObj parser.DevfileObj, debug bool, randomPorts bool, usedPorts []int, definedPorts []api.ForwardedPort, address string) ([]api.ForwardedPort, error) {
201+
if address == "" {
202+
address = "127.0.0.1"
203+
}
195204
containerComponents, err := devfileObj.Data.GetComponents(common.DevfileOptions{
196205
ComponentOptions: common.ComponentOptions{ComponentType: v1alpha2.ContainerComponentType},
197206
})
@@ -268,7 +277,7 @@ func getPortMapping(devfileObj parser.DevfileObj, debug bool, randomPorts bool,
268277
freePort = getCustomLocalPort(ep.TargetPort, containerName)
269278
if freePort == 0 {
270279
for {
271-
freePort, err = util.NextFreePort(startPort, endPort, usedPorts)
280+
freePort, err = util.NextFreePort(startPort, endPort, usedPorts, address)
272281
if err != nil {
273282
klog.Infof("%s", err)
274283
continue
@@ -290,15 +299,15 @@ func getPortMapping(devfileObj parser.DevfileObj, debug bool, randomPorts bool,
290299
rand.Seed(time.Now().UnixNano()) // #nosec
291300
for {
292301
freePort = rand.Intn(endPort-startPort+1) + startPort // #nosec
293-
if !isPortUsedInContainer(freePort) && util.IsPortFree(freePort) {
302+
if !isPortUsedInContainer(freePort) && util.IsPortFree(freePort, address) {
294303
break
295304
}
296305
time.Sleep(100 * time.Millisecond)
297306
}
298307
}
299308
} else {
300309
for {
301-
freePort, err = util.NextFreePort(startPort, endPort, usedPorts)
310+
freePort, err = util.NextFreePort(startPort, endPort, usedPorts, address)
302311
if err != nil {
303312
klog.Infof("%s", err)
304313
continue epLoop
@@ -316,7 +325,7 @@ func getPortMapping(devfileObj parser.DevfileObj, debug bool, randomPorts bool,
316325
PortName: portName,
317326
IsDebug: isDebugPort,
318327
ContainerName: containerName,
319-
LocalAddress: "127.0.0.1",
328+
LocalAddress: address,
320329
LocalPort: freePort,
321330
ContainerPort: ep.TargetPort,
322331
Exposure: string(ep.Exposure),

0 commit comments

Comments
 (0)