Live Workshop: How to Measure ROI of Developer Experience
Register now!

Develop and Deploy a Grails application in Okteto Cloud

Microservice-based applications make our applications more scalable. But they also make it harder to setup local development environments. You need to run several services that you are not familiar with, with a variety of different runtimes. And you probably need to switch your development environment between different projects. Not to mention that running all these services can eat up all of your computer's available resources.

In this blog post, I’ll show you how to develop a Hello World application, how to kubernetize it and how to deploy it into Okteto Cloud without having to install anything locally. We will use Grails as our programming language, but the guide applies to any Spring Boot application. And yes, you won't need to install grails, the JVM, Docker or Kubernetes locally 😍.

Create your development environment

Okteto Cloud is a development platform for Kubernetes applications. You can create development environments in Kubernetes, deploy containers, pods, deployments, etc... and code from your favorite local IDE while Okteto takes care of synchronizing the files to your remote development environment to instantly update your application. It's by far the fastest development experience I've ever tried.

Okteto creates your remote development environments using the okteto.yml file. This file declares the deployment target, the docker image used as the development runtime, the working directory and other information required to activate your development environment with Okteto (more information about the okteto.yml file is available here).

Create a local folder for your Grails application and add the following okteto.yml file to it:

name: hello-world
image: okteto/grails:latest
command: [ "bash" ]
volumes:
  - /home/gradle/.gradle
forward:
  - 8080:8080
  - 5005:5005
resources:
  limits:
    cpu: 1

This file will instruct Okteto to use a okteto/grails:latest container as your development environment runtime and to expose two ports in your machine localhost interface. Port 8080 to access the application and 5005 to debug it remotely. Once you have your okteto manifest ready you will create your remote development environment in Okteto Cloud by executing the command below:

$ okteto up
Deployment test doesn't exist in namespace jagedn. Do you want to create a new one? [y/n]: y

 ✓  Development environment activated
 ✓  Files synchronized
    Namespace: jagedn
    Name:      test
    Forward:   5005 -> 5005
               8080 -> 8080

Welcome to your development environment. Happy coding!
okteto>

If you haven’t done it yet, install the Okteto CLI by following this guide and configure access to your Okteto Cloud namespace by following these steps.

If all it’s ok, you are now in a remote shell session, with all the tools you need already preinstalled 💥.

Creating the app

Your remote development environment has all the tools you need to create, build and run the application. To create a Hello world application execute the following command on the remote shell:

okteto> grails create-app --profile web --inplace
Resolving dependencies...
| Application created at /okteto

Okteto synchronizes files in both directions, which means that the files created by grails create-app will automatically appear in your local machine. Create the file grails-app/controllers/grails4/TestController.groovy in your favorite local IDE, make some changes to it, and save it:

package grails4

class TestController {

    def index() {
        println "into the controller"
        render "Hello World"
    }
}

Run the application with the following command:

okteto> ./gradlew bootRun
Downloading https://services.gradle.org/distributions/gradle-5.1.1-bin.zip
.................................................................................

Welcome to Gradle 5.1.1!

Here are the highlights of this release:
 - Control which dependencies can be retrieved from which repositories
 - Production-ready configuration avoidance APIs

For more details see https://docs.gradle.org/5.1.1/release-notes.html

Starting a Gradle Daemon (subsequent builds will be faster)

> Task :bootRun
....
Grails application running at http://localhost:8080 in environment: development
<==========---> 83% EXECUTING [1m 45s]
> IDLE
> :bootRun

You can now access the application at http://localhost:8080/test (this port is being automatically forwarded by okteto up to the remote development environment). You can also use the public HTTPs endpoint created by Okteto Cloud for a true end-to-end experience.

Okteto Cloud uses your GitHub username as your personal namespace, and it is also used to create automatic HTTPs endpoints for your applications. Since my GitHub username is jagedn my application hello-world will be accessible at hello-world-jagedn.cloud.okteto.net/test

Go back to your local IDE and update the response message in TestController. Once you modify your code, refresh your browser and see how your changes are applied immediately 😎. This is possible thanks to Grails' hot reloading capabilities and Okteto's file synchronization.

Remote debugging

To be able to debug the (remote) application we need to configure gradle to run with debug flags. Add the flags below to the bootRun task in your build.gradle file:

bootRun {
    jvmArgs(
        '-Dspring.output.ansi.enabled=always',
        '-noverify',
        '-XX:TieredStopAtLevel=1',
        '-Xmx1024m',
        '-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005'
    )
    sourceResources sourceSets.main
    String springProfilesActive = 'spring.profiles.active'
    systemProperty springProfilesActive, System.getProperty(springProfilesActive)
}

Go ahead and restart the application in the remote shell:

$ ./gradlew bootRun

and connect your IDE to it using a remote debug configuration on http://localhost:5005 (forwarded by okteto up to the remote debugger). You will be able to halt the execution at your breakpoints, inspect requests, the available variables, etc.

Dockerize

Now it's time to deploy your application. Close your remote development environment by exiting the remote shell with Ctrl + C + Ctrl + D and execute the following command from your local terminal:

$ okteto down
$ okteto down
 ✓  Development environment deactivated

Your remote development environment is now deactivated. The first step is to dockerize your application and push your application docker image to Docker Hub.

Start by creating the following Dockerfile in the root folder of your application:

# syntax = docker/dockerfile:experimental
FROM gradle:latest as builder

WORKDIR /app
COPY . .
RUN --mount=type=cache,target=/home/gradle/.gradle /app/gradlew bootJar

FROM adoptopenjdk/openjdk11-openj9:jdk-11.0.1.13-alpine-slim

WORKDIR /app
COPY --from=builder /app/build/libs/*.jar application.jar

CMD ["sh", "-c","java -Djava.security.egd=file:/dev/./urandom -jar /app/application.jar"]

We could build and push the docker image using the traditional docker way:

$ docker build -t jagedn/grails-test .
$ docker push jagedn/grails-test

But instead, we are going to use the Okteto CLI to remotely build and push your image (note that you will need to use your DockerHub user instead of jagedn). This way we don't need to install docker locally:

$ okteto build -t jagedn/grails-test .

Kubernetize (Go live)

To deploy your application wee need to create Kubernetes manifests. Create the file k8s.yml in the root folder of your application with this content:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-world
  labels:
    app: hello-world
spec:
  replicas: 1
  selector:
    matchLabels:
      app: hello-world
  template:
    metadata:
      name: hello-world
      labels:
        app: hello-world
    spec:
      containers:
      - image: jagedn/grails-test
        name: api
        resources:
          limits:
            cpu: 1

---

apiVersion: v1
kind: Service
metadata:
  name: hello-world
  labels:
    app: hello-world
  annotations:
    dev.okteto.com/auto-ingress: "true"
spec:
  type: ClusterIP
  ports:
    - port: 8080
      protocol: TCP
      targetPort: 8080
  selector:
    app: hello-world

In this file you instruct Kubernetes to deploy your application and, at the same time, we configure a service to expose your application to the world:

If you don't have kubectl installed follow this guide.

$ kubectl apply -f k8s.yml
deployment.apps/test hello-world
service/test hello-world

And finally, the production version of your Kubernetes application will be available in about half a minute at https://hello-world-jagedn.cloud.okteto.net/test (remember to replace jagedn by your GitHub Username).

Conclusions

Although this example is a simple app, when you’re working in a more complex solution you soon realize you need to work as close to how it will look in production. You can (you must) write a lot of tests but you can’t mock all services or typical situations that happen in a cluster. Okteto lets you develop close to the production architecture.

Another advantage you’ll gain working directly in a Kubernetes cluster is that you’ll need to define your YAML files in early stages keeping your focus on it, detecting your requirements at the same time you are working in the solution.

Last but not least, with the generous Okteto Cloud free tier of 4 CPUs and 8GB per namespace, you can use Okteto Cloud to put your idea in production in a short time as I did, migrating all my Telegram Bots from Google AppEngine and Heroku to Okteto Cloud. It was great.

Jorge Aguilera is a Principal Software Architect at Puravida Software, where he builds software for self-service devices like ATMs and Sales Kiosks. In his free time, he likes to dabble with Kubernetes, build Telegram Bots, and speak at different meetups and conferences.

Jorge AguileraPrincipal Software Architect View all posts

Automate Provisioning Any Dev Resource on Any Cloud Provider With Pulumi and Okteto

The Value It is common in today's landscape to build microservices-based applications that leverage resources like RDS databases, storage buckets, etc...

October 19, 2023
Avatar of Arsh SharmaAvatar of Arsh SharmaArsh Sharma

How Developers Can Seamlessly Collaborate When Building Microservice Apps

Building microservices based applications is inherently challenging. Given the multitude of components involved, it is unrealistic to expect any individual...

October 10, 2023
Avatar of Arsh SharmaAvatar of Arsh SharmaArsh Sharma