Skip to main content

Onboard Your Project to Raftt in 10 minutes

What is Raftt?

Raftt helps you have fast dev iterations. With Raftt it takes just seconds to see your code changes applied in your dev env on your Kubernetes cluster.

Raftt can work in two different modes -

  1. Connect-mode - to be used if you already have a dev env deployed on K8s and wish to enhance its dev experience using Raftt.
  2. Orchestration-mode - to be used if you want Raftt to be responsible for spawning and destroying ephemeral dev envs that also have Raftt's dev experience.

If you wish to experience developing with Raftt using a sample project, you can try one of our tutorials - the connect-mode tutorial or the orchestration-mode one. Going through the tutorials isn't required before using this guide.

Overview

This guide explains how to onboard your existing project to Raftt in connect-mode and includes the following steps -

  1. Installing Raftt's CLI tool and IDE Plugin
  2. Connecting Raftt to your dev env
  3. Inspecting the env using Raftt's IDE plugin
  4. Converting one of your workload's into dev-mode to allow fast iterations
  5. Configure run/debug configurations to allow interactive debugging of the workload's main process.

Prerequisites

This guide shows how to enhance the development experience of existing K8s envs using Raftt in connect-mode. To successfully go through this guide you first need to meet the following prerequisites -

  1. Install Raftt's CLI tool and IDE plugin (see here for instructions).
  2. Clone the repo of the workload you wish to develop to your local machine.
  3. Deploy the environment you wish to develop as a namespace in a K8s cluster, local or remote.
  4. Install kubectl locally with sufficient permissions (see here for installation guides).
    1. If your Kube-context doesn't have enough permissions, you can use tools like minikube to create a local Kubernetes cluster to deploy your env, and then connect with Raftt.

Connecting to the Env

In this section, we'll add Raftt's environment controller to the namespace that contains your dev environment. Take the following steps -

  1. Make sure your current working directory is the repo of the service you wish to develop.
  2. Make sure your Kubernetes context is correct
kubectl config get-contexts
  1. Setup Raftt's initial configuration
raftt setup --direct

This command creates Raftt's basic configuration. The --direct flag determines that you're working in connect-mode. The command creates two files in your repo root -

  • raftt.yml - raftt's basic configuration file
  • env.raftt - the file that contains the definition of all the changes to resources when entering dev-mode (more on that later). For now it's an almost empty template that will be filled later.
  1. Connect to your dev env
raftt connect <NAMESPACE>

You will be prompted to log in to Raftt using one of several third-party services (Google, GitHub, etc.).

This command adds Raftt's env controller - a deployment called sandcastle, to the namespace. The environment controller now waits for Raftt commands.

You can now inspect your workloads using raftt status, raftt sh and raftt logs commands.

Env inspection in the IDE

Once connected to the environment you can inspect it and execute commands from your IDE using Raftt's plugin.

The Raftt plugin is accessible from the navigation bar at the bottom of the IDE window. You can see the different workloads and their status, and use the different action buttons to execute Raftt commands.

JetBrains IDE Plugin

Devifying the First Workload

The raftt dev command

This command gets resources into dev-mode, or "devifies" them. Devifying a resource means it is redeployed with modifications that make it much easier to develop. Try to run

raftt dev <workload_name>

and see that it's now in dev-mode, so you can stop and restart the main process without taking the whole workload down - use

raftt stop <workload_name>

and

raftt restart <workload_name>

respectively.

In the next sections we'll configure additional changes that will help accelerating your dev velocity.

What is a .raftt file

The .raftt file defines how Raftt will convert resources into dev-mode (using raftt dev), or rebuild them (using raftt rebuild). It is written in Starlark - a Python-like scripting language.

The namespace_resources() function

There are several methods for importing the initial resource definitions. The most useful one for connect-mode is namespace_resources() - a function that returns an object containing the definitions of the resources currently deployed in your namespace.

This line was already added to your env.raftt file when you ran raftt setup --direct

resources = namespace_resources()
Important

Keep the call to deploy(resources) at the end of your .raftt file - modifications to the resources object won't be applied if there's no later call to deploy(resources).

Mounting the source code

To allow hot reloading, the source code needs to be mounted (and hence continually synced) into the workload.

For example, to mount the code located in the src/payments dir in your repo to the /src dir in your payments deployment add the following line to your env.raftt file -

resources.deployments["payments"].mount(repo_volume().subpath("src/payments"), "/src")

For interpreted languages this (and raftt restart) is enough for hot reloading. For compiled languages, you'll need to configure how to compile your code.

Compiling your code

For compiled languages, you'll want to compile the binary before restarting the main process. The compilation process is performed on one of your env's workloads. In some cases, you can compile on the workload on which the code eventually runs, but it may not be possible for many reasons. In such a case, you'd want to add an additional workload dedicated for compiling the code.
To do so, define the builder workload in your .raftt file -

# Import the definitions from a pre-defined yml (see below for more details)
builder_resources = k8s_manifests("./k8s_manifests/builder.yml")
# Fetch the builder deployment from the imported Resources object
builder = builder_resources.deployments["builder"]
# Mount the repo to the container root
builder.mount(repo_volume(), "/src")
# Mark builder to be deploy upon connection to the env
deploy_on_connect(builder)

The specification of builder.yml depends on the language used and on the specific requirements for compiling your code. Here are a few examples for builder.yml files that should work in most cases -

apiVersion: apps/v1
kind: Deployment
metadata:
name: builder
spec:
selector:
matchLabels:
app: builder
template:
metadata:
labels:
app: builder
spec:
containers:
- name: builder
image: golang:latest
Important

At the end of the compilation the artifacts must be located in the workload that runs them. The best way to do it is to have a shared volume between the builder and the workload. See here for instructions on how to do it.

After adding the workload in which you can compile your code, you need to configure when and how to trigger the compilation. There are several possible ways to do it, we'll describe three of them -

  1. Trigger the build directly using
raftt sh builder -- <build_command>
  1. Configure automatic build on any source code change (see below)
  2. Configure a pre-launch task in your IDE to run before every run/debug session (see below)

After configuring any of these methods, you can enjoy fast iterations from code change to seeing the change in the cluster, without rebuilding and redeploying any images.

File watching hooks

Raftt lets you define file watching hooks that trigger the execution of predefined actions on predefined workloads. Common use cases of such hooks are -

  1. Automatic compilation on any code change
  2. Automatically installing the dependencies on any change to the dependencies file

The following snippet defines a hook for each use case -

register_hook(
on=events.OnFileChanged(
workload=payments,
patterns="/src/**/*.ts"
),
do=actions.CMD(
workload=builder,
cmd=["npm", "build"]
)
)

register_hook(
on=events.OnFileChanged(
workload=payments,
patterns="/src/**/package.json"
),
do=actions.CMD(
workload=payments,
cmd=["npm", "install"]
)
)

Debug/run configurations

Raftt lets you interactively debug the workloads in your cluster. It currently supports debugging Python, Go, JavaScript (including TypeScript) and Java-based languages using VS Code and JetBrains IDEs.

Raftt debug/run configuration are almost identical to those used for local debugging. To get more information on creating these configurations, see our debugging docs.

Pre-launch tasks

For compiled languages, you'll want to rebuild the binary before launching a run/debug session. To do this you can define a task that will be executed before re-launching the main process. This is defined in the IDE.

Assuming Raftt's plugin is already installed, you can add a new before launch task of the type Run on Raftt workload in which you can define what build command to run and on which workload.

before launch task

The command can run on any workload of your choice, not just on the one running the binary.

Port Mapping

In some cases, when developing, you'd want to map a remote port to localhost. This can be defined in the .raftt file and the mapping will occur once the workload is in dev-mode.

For example to map port 27017 from your mongodb StatefulSet to your local port 27017, add the following line to your .raftt file -

resources.statefulsets["mongodb"].map_port(local=27017, remote=27017)

Conclusion and Next Steps

In this guide you went through configuring Raftt to develop one of your workloads. You can now enjoy dev iterations that take seconds instead of minutes, or much more, and enjoy interactive debugging directly in your cluster.

Now you can onboard the rest of your environment to have the great Raftt dev experience for all of your workloads.

You're welcome to join our Slack community or contact us for any further questions and enquiries.