Skip to main content
Version: v3

odo dev

odo dev is used in order to quickly and effectively iterate through your development process for building an application.

This is inner loop development and allows you to code, build, run and test the application in a continuous workflow.

Running the Command

If you haven't already done so, you must initialize your source code with the odo init command.

Afterwards, run odo dev:

odo dev
Example
$ odo dev
__
/ \__ Developing using the my-nodejs-app Devfile
\__/ \ Namespace: default
/ \__/ odo version: v3.0.0-alpha1
\__/

↪ Running on the cluster in Dev mode
✓ Waiting for Kubernetes resources [3s]
✓ Syncing files into the container [335ms]
✓ Building your application in container on cluster [2s]
✓ Executing the application [1s]

Your application is now running on the cluster
- Forwarding from 127.0.0.1:40001 -> 3000

Watching for changes in the current directory /Users/user/nodejs

[Ctrl+c] - Exit and delete resources from the cluster
[p] - Manually apply local changes to the application on the cluster

In the above example, three things have happened:

  • Your application has been built and deployed to the cluster
  • odo has port-forwarded your application for local accessibility
  • odo will watch for changes in the current directory and rebuild the application when changes are detected

You can press Ctrl-c at any time to terminate the development session. The command can take a few moment to terminate, as it will first delete all resources deployed into the cluster for this session before terminating.

Applying local changes to the application on the cluster

By default, the changes made by the user to the Devfile and source files are applied directly.

The flag --no-watch can be used to change this behaviour: when the user changes the devfile or any source file, the changes won't be applied immediately, but the next time the user presses the p key.

Depending on the local changes, different events can occur on the cluster:

  • if source files are modified, they are pushed to the container running the application, and:
    • if the build command is marked as HotReloadCapable, the application is responsible for building the application with the new changes
    • if the build command is not marked as HotReloadCapable, the build command is executed again
    • if the run command is marked as HotReloadCapable, the application is responsible for applying the new changes
    • if the run command is not marked as HotReloadCapable, the application is stopped, then restarted by odo using the run command again.
  • if the Devfile is modified, the deployment of the application is modified with the new changes. In some circumstances, this may cause the restart of the container running the application and therefore the application itself.

Running an alternative command

Running an alternative build command

By default, odo dev builds the application using the default Build command defined in the Devfile, i.e, the command with a group kind set to build and with isDefault set to true, if any.

Passing the build-command flag allows to override this behavior by running any other command, provided it is in the build group in the Devfile.

For example, given the following excerpt from a Devfile:

- id: my-build
exec:
commandLine: go build main.go
component: tools
workingDir: ${PROJECT_SOURCE}
group:
isDefault: true
kind: build

- id: my-build-with-version
exec:
commandLine: go build -ldflags="-X main.version=v1.0.0" main.go
component: tools
workingDir: ${PROJECT_SOURCE}
group:
kind: build
  • running odo dev will build the application using the default my-build command.
  • running odo dev --build-command my-build-with-version will build the application using the my-build-with-version command:
odo dev --build-command my-build-with-version
Example
$ odo dev --build-command my-build-with-version

__
/ \__ Developing using the my-sample-go Devfile
\__/ \ Namespace: default
/ \__/ odo version: v3.0.0-alpha3
\__/

↪ Running on the cluster in Dev mode
✓ Waiting for Kubernetes resources [39s]
✓ Syncing files into the container [84ms]
✓ Building your application in container on cluster (command: my-build-with-version) [456ms]
• Executing the application (command: run) ...

Your application is now running on the cluster
- Forwarding from 127.0.0.1:40001 -> 8080

Watching for changes in the current directory /path/to/my/sources/go-app

[Ctrl+c] - Exit and delete resources from the cluster
[p] - Manually apply local changes to the application on the cluster

Running an alternative run command

By default, odo dev executes the default Run command defined in the Devfile, i.e, the command with a group kind set to run and its isDefault field set to true.

Passing the run-command flag allows to override this behavior by running any other non-default command, provided it is in the run group in the Devfile.

For example, given the following excerpt from a Devfile:

- id: my-run
exec:
commandLine: mvn spring-boot:run
component: tools
workingDir: ${PROJECT_SOURCE}
group:
isDefault: true
kind: run

- id: my-run-with-postgres
exec:
commandLine: mvn spring-boot:run -Dspring-boot.run.profiles=postgres
component: tools
workingDir: ${PROJECT_SOURCE}
group:
isDefault: false
kind: run
  • running odo dev will run the default my-run command
  • running odo dev --run-command my-run-with-postgres will run the my-run-with-postgres command:
odo dev --run-command my-run-with-postgres
Example
$ odo dev --run-command my-run-with-postgres

__
/ \__ Developing using the my-java-springboot-app Devfile
\__/ \ Namespace: default
/ \__/ odo version: v3.0.0-alpha3
\__/

↪ Running on the cluster in Dev mode
✓ Added storage m2 to my-java-springboot-app
✓ Creating kind ServiceBinding [8ms]
✓ Waiting for Kubernetes resources [39s]
✓ Syncing files into the container [84ms]
✓ Building your application in container on cluster (command: build) [51s]
• Executing the application (command: my-run-with-postgres) ...

Your application is now running on the cluster
- Forwarding from 127.0.0.1:40002 -> 8080

Watching for changes in the current directory /path/to/my/sources/java-springboot-app

[Ctrl+c] - Exit and delete resources from the cluster
[p] - Manually apply local changes to the application on the cluster

Substituting variables

The Devfile can define variables to make the Devfile parameterizable. The Devfile can define values for these variables, and you can override the values for variables from the command line when running odo dev, using the --var and --var-file options.

The --var option is a repeatable option that takes a variable=value pair, where =value is optional. If the =value is omitted, the value is extracted from the environment variable named variable. In this case, if the environment variable with this name is not defined, the value defined into the Devfile will be used.

The --var-file option takes a filename as argument. The file contains a line-separated list of variable=value pairs, with the same behaviour as before.

Note that the values passed with the --var option overrides the values obtained with the --var-file option.

Examples

Considering the Devfile contains this variables field:

variables:
USER: anonymous
DEBUG: false

This command will override the USER Devfile variable with the value of the USER environment variable, if it is defined. It will also override the value of the DEBUG Devfile variable with the true value.

odo dev --var USER --var DEBUG=true

If you create a file config.vars containing:

USER
DEBUG=true

The following command will have the same behaviour as the previous one:

odo dev --var-file config.vars

The following command will override the USER Devfile variable with the john value:

odo dev --var USER=john --var-file config.vars

Using custom port mapping for port forwarding

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.

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.

Supported formats for this flag include:

  1. <LOCAL_PORT>:<CONTAINER_PORT>
  2. <LOCAL_PORT>:<CONTAINER_NAME>:<CONTAINER_PORT> - This format is necessary when multiple container components of a Devfile have the same port number.

The flag accepts a stringArray, so --port-forward flag can be defined multiple times.

If a custom port mapping is not defined for a port, odo will assign a free port in the range of 20001-30001.

odo dev --port-forward <LOCAL_PORT_1>:<CONTAINER_PORT_1> --port-forward <LOCAL_PORT_2>:<CONTAINER_NAME>:<CONTAINER_PORT_2>
Example
$ odo dev --port-forward 3000:runtime:3000 --port-forward 5000:5858 --debug
__
/ \__ Developing using the "my-nodejs-app" Devfile
\__/ \ Namespace: default
/ \__/ odo version: v3.9.0
\__/

⚠ You are using "default" namespace, odo may not work as expected in the default namespace.
⚠ You may set a new namespace by running `odo create namespace <name>`, or set an existing one by running `odo set namespace <name>`

↪ Running on the cluster in Dev mode
• Waiting for Kubernetes resources ...
⚠ Pod is Pending
✓ Pod is Running
✓ Syncing files into the container [152ms]
✓ Building your application in container (command: install) [27s]
• Executing the application (command: debug) ...
✓ Waiting for the application to be ready [1s]
- Forwarding from 127.0.0.1:8000 -> 3000

- Forwarding from 127.0.0.1:5000 -> 5858


↪ Dev mode
Status:
Watching for changes in the current directory /tmp/nodejs-debug-2

Keyboard Commands:
[Ctrl+c] - Exit and delete resources from the cluster
[p] - Manually apply local changes to the application on the cluster

Note that --random-ports flag cannot be used with --port-forward flag.

Using custom address for port forwarding

A custom address can be passed for port forwarding with the help of --address flag. This feature is supported on both podman and cluster. The default value is 127.0.0.1.

odo dev --address <IP_ADDRESS>
Example
$ odo dev --address 127.0.10.3
__
/ \__ Developing using the "my-nodejs-app" Devfile
\__/ \ Namespace: default
/ \__/ odo version: v3.9.0
\__/

⚠ You are using "default" namespace, odo may not work as expected in the default namespace.
⚠ You may set a new namespace by running `odo create namespace <name>`, or set an existing one by running `odo set namespace <name>`

↪ Running on the cluster in Dev mode
• Waiting for Kubernetes resources ...
⚠ Pod is Pending
✓ Pod is Running
✓ Syncing files into the container [123ms]
✓ Building your application in container (command: install) [15s]
• Executing the application (command: run) ...
✓ Waiting for the application to be ready [1s]
- Forwarding from 127.0.10.3:20001 -> 3000


↪ Dev mode
Status:
Watching for changes in the current directory /tmp/nodejs-debug-2

Keyboard Commands:
[Ctrl+c] - Exit and delete resources from the cluster
[p] - Manually apply local changes to the application on the cluster
note

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.

For more information, see the following issues:

  1. Cannot start 2 different Dev sessions on Podman due to conflicting host ports
  2. [MacOS] Cannot run 2 dev sessions simultaneously on cluster

Running on Podman

Instead of deploying the container into a Kubernetes cluster, odo dev can leverage the podman installation on your system to deploy the container.

You need to use the --platform podman flags to run the component using podman instead of a Kubernetes cluster.

odo dev --platform podman
Example

$ odo dev --platform podman
__
/ \__ Developing using the "my-nodejs-app" Devfile
\__/ \ Platform: podman
/ \__/ odo version: v3.7.0
\__/

↪ Running on podman in Dev mode
✓ Deploying pod [4s]
✓ Building your application in container (command: install) [3s]
• Executing the application (command: run) ...
- Forwarding from 127.0.0.1:20001 -> 3000

↪ Dev mode
Status:
Watching for changes in the current directory /path/to/project/nodejs

Keyboard Commands:
[Ctrl+c] - Exit and delete resources from podman
[p] - Manually apply local changes to the application on podman

Passing extra args to Podman or Docker when building images

If the Devfile contains an Image component that is set to be automatically created, or explicitly referenced in another command execution chain), odo will leverage Podman or Docker to build this Image and push it.

Similarly to how odo build-images works, you can set the ODO_IMAGE_BUILD_ARGS environment variable, which is a semicolon-separated list of extra arguments to pass to Podman or Docker when building images. See this section for further details.

ODO_IMAGE_BUILD_ARGS='arg1=value1;arg2=value2;...;argN=valueN' odo dev
Example
$ ODO_IMAGE_BUILD_ARGS='--platform=linux/amd64;--build-arg=MY_ARG=my_value' odo dev

__
/ \__ Developing using the "my-nodejs-app" Devfile
\__/ \ Namespace: default
/ \__/ odo version: v3.10.0
\__/

⚠ You are using "default" namespace, odo may not work as expected in the default namespace.
⚠ You may set a new namespace by running `odo create namespace <name>`, or set an existing one by running `odo set namespace <name>`

↪ Building Image: localhost:5000/nodejs-odo-example
• Building image locally ...
[1/2] STEP 1/4: FROM registry.access.redhat.com/ubi8/nodejs-14:latest
[1/2] STEP 2/4: RUN echo XXX $MY_ARG
--> Using cache cbd3ef1317b96dbef4c9ab3646df49d3770831516c3b5c9f1e15687d67bc8803
--> cbd3ef1317b9
[1/2] STEP 3/4: COPY package*.json ./
--> Using cache de4a08bf2632ef49339beeda4ba50eb6e8a9b7524ffd5717fdcc372c15003b61
--> de4a08bf2632
[1/2] STEP 4/4: RUN npm install --production
--> Using cache 5a37e2783e140582da7ac4e241790e6e2052826c07f46cc0053801f4580e728c
--> 5a37e2783e14
[2/2] STEP 1/6: FROM registry.access.redhat.com/ubi8/nodejs-14-minimal:latest
[2/2] STEP 2/6: COPY --from=0 /opt/app-root/src/node_modules /opt/app-root/src/node_modules
--> Using cache 8779f5d3753baec5961b5ae017d8246b2674eb70f3c5607e4060f6b38e07c182
--> 8779f5d3753b
[2/2] STEP 3/6: COPY . /opt/app-root/src
--> 6ea250968b12
[2/2] STEP 4/6: ENV NODE_ENV production
--> 0bf4dd6605e9
[2/2] STEP 5/6: ENV PORT 3000
--> deea4247dd08
[2/2] STEP 6/6: CMD ["npm", "start"]
[2/2] COMMIT localhost:5000/nodejs-odo-example
--> eebc7c012506
Successfully tagged localhost:5000/nodejs-odo-example:latest
eebc7c01250682bf4e1e9544de1434d5edb90a51cf2d3e96f0faab354918bedb
✓ Building image locally [3s]
• Pushing image to container registry ...
Getting image source signatures
Copying blob 4577dc5a9258 skipped: already exists
Copying blob 6c30129af541 skipped: already exists
Copying blob e48a40635da9 skipped: already exists
Copying blob 1a5c88cd67e6 skipped: already exists
Copying config a4bda6ab2b done
Writing manifest to image destination
Storing signatures
✓ Pushing image to container registry [137ms]
• Waiting for Kubernetes resources ...
⚠ Pod is Pending
✓ Pod is Running
✓ Syncing files into the container [204ms]
✓ Building your application in container (command: install) [15s]
• Executing the application (command: run) ...
✓ Waiting for the application to be ready [1s]
- Forwarding from 127.0.0.1:20001 -> 3000

↪ Dev mode
Status:
Watching for changes in the current directory /path/to/project/nodejs

Keyboard Commands:
[Ctrl+c] - Exit and delete resources from the cluster
[p] - Manually apply local changes to the application on the cluster

Passing extra args to Podman when developing on Podman

When running on Podman, you can set the ODO_CONTAINER_RUN_ARGS environment variable, which is a semicolon-separated list of options to pass to Podman when creating the development session Pod.

You can also set the ODO_CONTAINER_BACKEND_GLOBAL_ARGS environment variable to pass global options to all podman commands executed by odo (including the commands used for building and pushing images).

ODO_CONTAINER_BACKEND_GLOBAL_ARGS='--globalArg1=val1;--globalArg2=val2;...;--globalArgN=valN' \
ODO_CONTAINER_RUN_ARGS='--arg1=value1;--arg2=value2;...;--argN=valueN' \
odo dev --platform=podman
Example
$ ODO_CONTAINER_BACKEND_GLOBAL_ARGS='--root=/tmp/podman/root;--storage-driver=overlay' \
ODO_CONTAINER_RUN_ARGS='--configmap=cm-foo.yml;--quiet' \
odo dev --platform=podman
__
/ \__ Developing using the "my-nodejs-app" Devfile
\__/ \ Platform: podman
/ \__/ odo version: v3.10.0
\__/

↪ Running on podman in Dev mode
✓ Deploying pod [2s]
✓ Building your application in container (command: install) [10s]
• Executing the application (command: run) ...
✓ Waiting for the application to be ready [1s]
- Forwarding from 127.0.0.1:20001 -> 3000

↪ Dev mode
Status:
Watching for changes in the current directory /path/to/project/nodejs

Keyboard Commands:
[Ctrl+c] - Exit and delete resources from podman
[p] - Manually apply local changes to the application on podman

Running with no commands

The --no-commands flag allows to start the Dev Session without implicitly executing any build, run or debug commands.

Specifying this flag will simply create all the resources necessary for the Dev Session, then set up file synchronization and port forwarding. In detail, it will:

  1. eventually build and push any Image Components defined in the Devfile, if they have the autoBuild flag set to true
  2. eventually apply any Kubernetes or OpenShift Components defined in the Devfile, if they have the deployByDefault flag set to true
  3. Start the Dev container(s), taking care of executing any commands that are bound to Devfile lifecycle events, like postStart
  4. Synchronize the local files to the Dev environment
  5. Start the port forwarding logic if needed

This gives users complete control over the Dev session, for example by leveraging the odo run command to manually run any command defined in the Devfile.

Note that this is the default behavior of odo dev if the Devfile does not define any Build, Run or Debug commands. The difference is that if any of those commands is added during the Dev session, a Dev session started via odo dev will automatically pick them up and run them, while a Dev session started via odo dev --no-commands will purposely not run them.

Devfile (Advanced Usage)

Devfile Overview

When odo dev is ran, it first looks in the devfile.yaml for the instructions to be executed, specifically: components and commands.

Each command has a group kind key which correspond to either: build, run, test, or debug.

These instructions make up the development cycle of odo dev.

With the following example devfile.yaml file generated by odo init and selecting nodejs, a container image will be pushed to the cluster, as well as your source code in order to start the development inner loop cycle.

A much more descriptive explanation on each part of a Devfile can be found on the Devfile API reference site.

Below, we'll explain each section of the corresponding Devfile:

metadata

Descriptive registry information with regards to the devfile being used.

metadata:
description: Stack with Node.js 14
displayName: Node.js Runtime
icon: https://nodejs.org/static/images/logos/nodejs-new-pantone-black.svg
language: javascript
name: my-nodejs-app
projectType: nodejs
tags:
- NodeJS
- Express
- ubi8
version: 1.0.1
schemaVersion: 2.0.0

starterProjects

The starter projects available for this devfile, shown when running odo init.

starterProjects:
- git:
remotes:
origin: https://github.com/odo-devfiles/nodejs-ex.git
name: nodejs-starter

commands

The list of commands to be used when running odo dev.

Each command contains what will be ran within the container.

The four groups are: build, run, test and debug.

Build is what is initially ran when deploying to the cluster. It is what builds the command from the sources synced to the container.

Run executes the command after it has been built from sources.

Debug is used instead of Run when running odo dev --debug.

Test executes any tests which are available and part of your application. (This is NOT-YET-IMPLEMENTED in odo)

All of these commands are needed to: build the program, execute the program, debug the application and run any applicable tests.

commands:
- exec:
commandLine: npm install
component: runtime
group:
isDefault: true
kind: build
workingDir: ${PROJECT_SOURCE}
id: install
- exec:
commandLine: npm start
component: runtime
group:
isDefault: true
kind: run
workingDir: ${PROJECT_SOURCE}
id: run
- exec:
commandLine: npm run debug
component: runtime
group:
isDefault: true
kind: debug
workingDir: ${PROJECT_SOURCE}
id: debug
- exec:
commandLine: npm test
component: runtime
group:
isDefault: true
kind: test
workingDir: ${PROJECT_SOURCE}
id: test

components

Components can include containers as well as Kubernetes yaml.

In our example, the nodejs container is being used on port 3000.

components:
- name: runtime
container:
endpoints:
- name: http-3000
targetPort: 3000
image: registry.access.redhat.com/ubi8/nodejs-14:latest
memoryLimit: 1024Mi
mountSources: true

Note that odo will set the container entrypoint to tail -f /dev/null if no command or args fields are explicitly defined for this component in the Devfile. This is a temporary workaround that allows odo to start non-terminating containers in which the Devfile commands will get executed.

Full Example

metadata:
description: Stack with Node.js 14
displayName: Node.js Runtime
icon: https://nodejs.org/static/images/logos/nodejs-new-pantone-black.svg
language: javascript
name: my-nodejs-app
projectType: nodejs
tags:
- NodeJS
- Express
- ubi8
version: 1.0.1
schemaVersion: 2.0.0

starterProjects:
- git:
remotes:
origin: https://github.com/odo-devfiles/nodejs-ex.git
name: nodejs-starter

commands:
- exec:
commandLine: npm install
component: runtime
group:
isDefault: true
kind: build
workingDir: ${PROJECT_SOURCE}
id: install
- exec:
commandLine: npm start
component: runtime
group:
isDefault: true
kind: run
workingDir: ${PROJECT_SOURCE}
id: run
- exec:
commandLine: npm run debug
component: runtime
group:
isDefault: true
kind: debug
workingDir: ${PROJECT_SOURCE}
id: debug
- exec:
commandLine: npm test
component: runtime
group:
isDefault: true
kind: test
workingDir: ${PROJECT_SOURCE}
id: test

components:
- name: runtime
container:
endpoints:
- name: http-3000
targetPort: 3000
image: registry.access.redhat.com/ubi8/nodejs-14:latest
memoryLimit: 1024Mi
mountSources: true

State File

When the command odo dev is executed, the state of the command is saved to the file .odo/devstate.json.

This state file contains the forwarded ports:

{
"forwardedPorts": [
{
"containerName": "runtime",
"localAddress": "127.0.0.1",
"localPort": 40001,
"containerPort": 3000
}
]
}