Skip to main content

odo v3-alpha1 Released

ยท 10 min read

v3-alpha1 of odo has been released!

odo is a tool that aims to simplify the life of developers working on cloud-native applications.

Thanks to the emergence of the Devfile open standard, which has been accepted as a CNCF Sandbox project (January 2022), odo v3 is now entirely based on this open standard.

The goal of the Devfile standard is to define the structure of applications and how developers can work on them.

A single Devfile defines the smallest building block of an application, that a developer can: build, run, test, debug and deploy. In a cloud-native environment, we generally talk about a micro-service.

Firstly, the Devfile describes the container that is needed to be deployed on a cluster during the development phases, along with the commands to execute on this container to build, run, test and debug the program, assuming the sources have been synchronized into the container.

Secondly, the Devfile provides the instructions to build the container image ready for production, along with the Kubernetes resources to deploy to the cluster.

An example of a Devfileโ€‹

To illustrate, here is a simple yet complete Devfile, usable for a Node.js micro-service:

schemaVersion: 2.2.0
metadata:
description: Stack with NodeJS 12
displayName: NodeJS Runtime
language: nodejs
name: my-nodejs-app
projectType: nodejs
variables:
CONTAINER_IMAGE: quay.io/phmartin/myimage
components:
- name: runtime
container:
endpoints:
- name: http-3000
targetPort: 3000
- name: debug-5858
targetPort: 5858
image: registry.access.redhat.com/ubi8/nodejs-14:latest
memoryLimit: 1024Mi
mountSources: true
sourceMapping: /project
- name: outerloop-build
image:
dockerfile:
buildContext: ${PROJECT_ROOT}
rootRequired: false
uri: ./Dockerfile
imageName: "{{CONTAINER_IMAGE}}"
- name: outerloop-deployment
kubernetes:
inlined: |
kind: Deployment
apiVersion: apps/v1
metadata:
name: my-node
spec:
replicas: 1
selector:
matchLabels:
app: node-app
template:
metadata:
labels:
app: node-app
spec:
containers:
- name: my-node
image: {{CONTAINER_IMAGE}}
ports:
- name: http
containerPort: 3001
protocol: TCP
resources:
limits:
memory: "1024Mi"
cpu: "500m"
- name: outerloop-service
kubernetes:
inlined: |
apiVersion: v1
kind: Service
metadata:
name: svc
spec:
ports:
- name: "3000"
port: 3000
protocol: TCP
targetPort: 3000
selector:
app: node-app
type: ClusterIP
commands:
- id: install
exec:
commandLine: npm install
component: runtime
group:
isDefault: true
kind: build
workingDir: /project
- id: run
exec:
commandLine: npm start
component: runtime
group:
isDefault: true
kind: run
workingDir: /project
- id: debug
exec:
commandLine: npm run debug
component: runtime
group:
isDefault: true
kind: debug
workingDir: /project
- id: test
exec:
commandLine: npm test
component: runtime
group:
isDefault: true
kind: test
workingDir: /project
- id: deploy
composite:
commands:
- build-image
- k8s-deployment
- k8s-service
group:
isDefault: true
kind: deploy
- id: build-image
apply:
component: outerloop-build
- id: k8s-deployment
apply:
component: outerloop-deployment
- id: k8s-service
apply:
component: outerloop-service
starterProjects:
- name: nodejs-starter
git:
remotes:
origin: https://github.com/odo-devfiles/nodejs-ex.git

The runtime component defines the container that will be deployed to support the program in development. Specifically, it will use the image registry.access.redhat.com/ubi8/nodejs-14:latest, and sources should be placed in the /project directory of the container. Two endpoints are also defined, one to access the micro-service, the other to help the debugger attach to the process, during debugging sessions.

The commands install, run, debug and test indicate which commands to execute to respectively build, execute, debug and test the application. For example, the npm install command will be executed in the container to build the application, then npm start will be executed to start the application.

To deploy the micro-service, the component outerloop-build indicates how to build the production image (by using ./Dockerfile, and creating an image whose name is defined by the variable CONTAINER_IMAGE defined at the beginning of the devfile). Then, two other components outerloop-deployment and outerloop-service define the Kubernetes resources to deploy to the cluster. Note that the first one defines a Deployment that will help deploy a container using the image built with the previous outerloop-build component. And, the second outerloop-service component will help expose the deployment created by outerloop-deployment component.

The starterProjects section at the end of the Devfile indicates a list of starter projects, that can be downloaded to have an example of program deployable with this Devfile.

Devfile registryโ€‹

We can see through the previous example that a Devfile is generic enough, with only a few specific values, like the endpoints and the image names. A Devfile written for a specific language and framework can be used by most of the programs written using this language and framework, with minimum personalization.

A Devfile registry is available at https://registry.devfile.io, containing Devfiles for a large variety of languages and frameworks, and you can deploy your own registry to make accessible your own Devfiles.

Introducing odo v3โ€‹

You can find the instructions to install odo v3-alpha1 from this release page. The binaries are accessible here.

Initializing a projectโ€‹

The odo init command is the first command to use, before starting to use odo with your project. The goal of this first step is to get a suitable Devfile for your project.

odo init will search for Devfiles in the Devfile registries. By default, odo is configured to access only one Devfile registry (the one specified above), and you can modify the Devfile registries odo is accessing using the command odo preference registry.

This odo init command offers two modes, either interactive, or manual. The interactive mode will help you discover the appropriate Devfile. To use the interactive mode, you just need to enter odo init in your command line.

If you execute this command from a directory containing sources, odo will try to recognize the language and framework you are using, will search into the Devfile registries that you have configured for the most appropriate Devfile, and give you the choice to use it, or to search for another one.

$ odo init
__
/ \__ Initializing new component
\__/ \ Files: Source code detected, a Devfile will be determined based upon source code autodetection
/ \__/ odo version: v3.0.0-alpha1
\__/

Interactive mode enabled, please answer the following questions:
Based on the files in the current directory odo detected
Language: javascript
Project type: nodejs
The devfile "nodejs" from the registry "DefaultDevfileRegistry" will be downloaded.
? Is this correct? (Y/n)

If you answer No here, or if you run the odo init command from an empty directory, odo init will help you choose the appropriate Devfile. The command will also help you make some personalization on the Devfile, by personalizing the endpoints and the environment variables for the container that will be deployed during the development phase.

? Select language: javascript
? Select project type: Node.js Runtime
โœ“ Downloading devfile "nodejs" from registry "DefaultDevfileRegistry" [961ms]
Current component configuration:
Container "runtime":
Opened ports:
- 3000
Environment variables:
? Select container for which you want to change configuration? NONE - configuration is correct
? Enter component name: my-nodejs-app

Your new component 'my-nodejs-app' is ready in the current directory.
To start editing your component, use 'odo dev' and open this folder in your favorite IDE.
Changes will be directly reflected on the cluster.

Finally, if you start the odo init command from an empty directory, it will give you the choice to download one of the starter projects listed in the Devfile.

The development phaseโ€‹

Now that a Devfile is present in the current directory, you can run your application in the development mode, using the odo dev command. This command will create a Deployment in the cluster that will help start a container as defined in the Devfile. Then, the sources present in the current directory will be synchronized into the container, and the commands to build and run the application will be executed from inside the container.

At the same time, a port-forwarding will be done for each endpoint defined in the Devfile, so you can access the container ports through local ports in your development machine.

Finally, odo will watch for changes in the current directory. When files are modified, added or deleted, odo will synchronize the changes to the container, and will restart the build and run commands from inside the container.

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

โ†ช Deploying to the cluster in developer mode
โœ“ Waiting for Kubernetes resources [6s]
โœ“ Syncing files into the container [439ms]
โœ“ Building your application in container on cluster [3s]
โœ“ Executing the application [1s]

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

Watching for changes in the current directory /home/phmartin/Documents/tests/devto-deploy
Press Ctrl+c to exit `odo dev` and delete resources from the cluster

To be able to debug the application, you will need to run the odo dev --debug command instead.

When you have finished the development session, you just need to hit Ctrl-c to stop the odo dev command. The command won't terminate immediately, as it will delete the resources it has deployed on the cluster before exiting.

The deployment phaseโ€‹

When you are satisfied with your program, you may want to deploy it. The first step would be to build the container image using a Dockerfile, instead of using a generic image as during the development phase. The second step would be to deploy personalized resources, instead of the Deployment used during the development phase.

At the time of this blog post, no Devfile within the default Devfile registry contains instructions for the deployment phase. By using the Devfile provided as an example above, the command odo deploy will build the container image using the Dockerfile present in the directory, and then deploy a personalized Deployment using the container image and a Service into the cluster.

$ odo deploy
__
/ \__ Deploying the application using my-nodejs-app Devfile
\__/ \ Namespace: prj2
/ \__/ odo version: v3.0.0-alpha1
\__/

โ†ช Building & Pushing Container: quay.io/phmartin/myimage
โ€ข Building image locally ...
STEP 1/7: FROM docker.io/library/node:17
STEP 2/7: WORKDIR /usr/src/app
[...]
STEP 7/7: CMD [ "node", "server.js" ]
COMMIT quay.io/phmartin/myimage
โœ“ Building image locally [6s]
โ€ข Pushing image to container registry ...
[...]
Writing manifest to image destination
Storing signatures
โœ“ Pushing image to container registry [8s]

โ†ช Deploying Kubernetes Component: my-node
โœ“ Searching resource in cluster
โœ“ Creating kind Deployment [50ms]

โ†ช Deploying Kubernetes Component: svc
โœ“ Searching resource in cluster
โœ“ Creating kind Service [57ms]

Your Devfile has been successfully deployed

At any moment, you can check if a component has been deployed by using the odo list command.

$ odo list
โœ“ Listing components from namespace 'prj2' [61ms]
NAME PROJECT TYPE RUNNING IN MANAGED
* my-nodejs-app nodejs Deploy odo

When you are done with this application or if you want to undeploy it to work on development mode again, you can use the odo delete component to undeploy the component from the cluster.

$ odo delete component
Searching resources to delete, please wait...
This will delete "my-nodejs-app" from the namespace "prj2".
โ€ข The component contains the following resources that will get deleted:
- Deployment: my-node
- Service: svc
? Are you sure you want to delete "my-nodejs-app" and all its resources? Yes
The component "my-nodejs-app" is successfully deleted from namespace "prj2"

Demoโ€‹