Purple white and red flowers.
Our garden is growing. We've raised a Series A funding round.
Read more here

Setting up and deploying your first Garden module

Anna Mager
Anna Mager
March 4, 2022

Many businesses are now established and operated on the cloud. Unfortunately, cloud developers spend much too much time waiting for testing and setting up environments rather than developing. Garden not only accelerates development, we also healthily disrupt the way cloud native development is built and maintained. Garden is an end-to-end cloud native development and testing platform. This blog post will introduce you to Garden and get your first Garden project up and running.

The transition to modern application architectures

Before we start looking at what Garden is and what it brings to the table, let's take a quick step back and look at how we used to build applications.

So-called legacy applications employ a monolithic architecture where the application is typically a single indivisible unit, comprised of the user interface, business logic, data interface, and a database. Monolithic applications are usually complex systems, with a steeper learning curve and a lot of dependencies. They take time to build and release to the market, and don’t fare well with rapid scalability. Errors in these types of applications can be time consuming to fix, and for this reason, monolithic applications are cumbersome to manage and run effectively. Granted, there are benefits to this approach to building applications, but the industry has largely transitioned to a more modern approach.

A diagram of a monolith showing UI, Business Logic, Data interface, and a Database

Modern applications break up the parts of a hypothetical monolithic architecture into a microservices architecture. In this way, we get separation of concern, dividing the application into a collection of smaller independent units that carry out individual application processes as separate services, each with its own logic, database, etc. An application produced in this way is modular rather than tightly coupled, and therefore less complex to manage.

A diagram showing microservices with the UI connecting through an API gateway to three microservices, each with their own database

The cloud-native microservices developer experience

Although microservices have a number of benefits over monolithic applications, it would be inaccurate to suggest this new approach is a developer’s cure-all. Indeed, some of the problems that plague monolithic architecture remain prevalent in microservices.

The developer experience in a cloud-native microservices architecture can get quite frustrating. Frustrations can come in the form of containers, Kubernetes clusters, environments, or other closely related concepts. One particular pain point around microservices is the continuous integration and deployment (CI/CD) pipeline.

Less than ideal CI/CD experience

Let's take a look at an example of a typical microservices workflow: We have the development loop, which consists of editing code in an IDE. Development deploys to a local environment, and when that's finished we push to Git, putting our code into the CI pipeline. We effectively build and test our application as we go, with dedicated application testing usually occurring later on in the process.

The main problem with this system is that you are working in a local development environment. These environments are difficult to maintain – sometimes you need to have extra tooling to get them running, and that may not always be feasible. This may be true, for example, if you’re developing in a restricted IT environment, or if the project is too dependency-heavy, or if it's simply a lot of code. The local environment in such circumstances may not be implemented in the same way as it is in the production environment.

The need to configure tooling multiple times between the different stages and environments can produce discrepancies that are annoying and tedious to debug. Add a number of individual pipelines to the mix, and problems can be exacerbated.

Integration, compliance, security, or end-to-end testing takes place late in the development process. This means that feedback comes late in the process too. This lengthy feedback loop can be unproductive, and it ultimately means less time is spent on actual development. A delayed feedback loop isn’t by any means a train wreck, but can be frustrating when you have already merged your code.

Improving the developer experience

This is where Garden comes in. Garden Core is an open-source automation platform for cloud development and testing, essentially a hybrid between GitHub actions and a development tool that you configure once and run anywhere.

Garden allows you to configure every component in your project, identify its dependencies, and specify how it is built, deployed, and tested. Garden has the added benefit of cacheable testing and shared environments.

Keep reading part 2 to see how Garden works.

Setting up and deploying your first Garden module: Part 2

Garden is an open-source automation platform for cloud development and testing, essentially a hybrid between GitHub actions and a development tool that you configure once and run anywhere.

Garden allows you to configure every component in your project, identify its dependencies, and specify how it is built, deployed, and tested. Components and configurations are aggregated into Garden’s stack graph.

A screenshot of the Garden UI showing a stack graph with build, deploy, run, and test steps

The stack graph – visualized on the Garden dashboard – is a simple UI that also maps containers to source files and configurations. Source files are hashed to create a version identifier. If you change any file or configuration, the version allows Garden to concisely figure out which parts of the graph need to be redeployed without having to redeploy the whole project.Garden also has the added benefit of cacheable testing and shared environments.

Let’s take a look at what Garden is capable of by working through an example.

Using Garden

We'll "gardenify" a simple demo project, consisting of a backend written in Go. The backend sends a message to the frontend when it is called from the frontend. Both the frontend and backend have Dockerfiles.

We'll start off by installing the Garden CLI. Refer to this guide.

Once installation is complete, run the following commands on your terminal (in an appropriate folder) to clone our repo and CD into the demo project:

Initialize the Garden project

Garden is a CLI tool, so it uses commands run on the terminal. Let's initialize the Garden project with: <span class="p-color-bg">garden create project</span>.

This generates a <span class="p-color-bg">project.garden.yml</span> file. This file is the entry point to our application. You can open the file and delete the commented lines to get a clearer view of the configuration. Yes, there's a bit of YAML, but it’s not like the 20 levels of indentation you sometimes get in Kubernetes manifests!

The Garden project essentially glues together all the different modules. Modules in Garden can be containers, services, tests, or any tasks. Garden allows for a variety of module types to be used, which you can also specify how to build. We'll keep it light for now and create simplified modules from our frontend and backend services.

Create modules

Let's create the frontend module with the following commands:

This generates a <span class="p-color-bg">garden.yml</span> config for our frontend service. Open the config file and append this to the end:

The generated config file has enough to get Garden to build the module, but it isn’t complete. For Garden to deploy the module, we append the above code to configure the required services. We name our service and declare the service’s listening port in the container (8080), and <span class="p-color-bg">healthCheck</span> to ensure our service does run – you can skip the health check if you want to get your build done quicker and you are certain that the service will run. We also declare the traffic <span class="p-color-bg">ingress</span> routes and – for the frontend specifically – a runtime dependency to the backend service.

Note that the Garden YAML configs can be distributed in much the same way as the system is. Garden will automatically look for these, so there’s no need to have a single monolithic config file specifying the module locations. The module configs allow every part of a project to describe itself and what it depends on.

Now, let's do the same for the backend service. Run these commands:

Once again, open the generated <span class="p-color-bg">garden.yml</span> config file and append the following to it:

This config is similar to our frontend service with the exception of the <span class="p-color-bg">ports</span> and <span class="p-color-bg">variables</span> section. The service port declaration simply maps the service’s port (80) to the container’s 8080 port. At the top we declare an <span class="p-color-bg">ingressPath</span> variable and then use it in the <span class="p-color-bg">ingresses</span> section (<span class="p-color-bg">path: ${var.ingressPath}</span>). You can define and then use variables as you would in any programming language. Variables are always called with the <span class="p-color-bg">${var.<variable_name>}</span> syntax. This brings us to Garden's templating syntax.

A note on using templates and variables

Garden has a powerful templating syntax that supports complex conditionals, loops, ternaries, and more. Template strings can also be used to differentiate any environment you're working in. For instance, <span class="p-color-bg">$[local.username]</span> can be used if you want to share a Garden config with other people, allowing each person to have their own specific namespace.

Variables work as you would expect in any programming language. Garden is modular in this regard too, and variables can be placed globally in a separate file to keep configs clean.

Connect to Kubernetes

Now let's connect to a Kubernetes cluster. Keeping things simple for now, install Docker for desktop by following this guide.

After installing Docker, make sure that you have enabled the “Kubernetes” option in the settings.

Deploy your Garden project

Now we can deploy and test the project. The <span class="p-color-bg">garden deploy</span> command deploys and tests the whole project without further interaction from the user. Try running this command now.

Note: It isn't imperative to run <span class="p-color-bg">garden build</span> before deploying the project. The command <span class="p-color-bg">garden deploy</span> has this functionality built-in. We can however run the build command first if we want to specify any build arguments.

Since Garden is a CLI tool, the commands remain the same whether on development or CI pipelines; for instance, <span class="p-color-bg">garden deploy</span> and <span class="p-color-bg">garden test</span> will always function in the same way.

Test your Garden project

Let's test our project by using the test command: <span class="p-color-bg">garden test</span>.

Our test completes successfully, but you may notice that there aren't any tests specified in either of our modules. The test then automatically passes, but let's go back into our modules and change this.

Open the <span class="p-color-bg">garden.yml</span> file in the frontend directory and append the following:

Here we’ve specified a unit and integration test to run as you normally would in a CI pipeline.

Now let's run <span class="p-color-bg">garden deploy</span> again to redeploy the project, since we’ve changed a config file.

How Garden uses caching to optimize builds

You may have noticed that Garden deploys the project a little quicker this time. Garden generates a hash version based on the source file and config attached to it. Garden checks this hash every time you deploy, to prevent unnecessary wait times rebuilding, deploying, and testing modules and configurations that have no changes.

If you're sharing infrastructure with Garden, you get a cache that is shared between all instances of the project. Garden makes smart use of image layer caching and caches test results. This cache lives in a shared namespace on the remote Kubernetes cluster – we’ll get to shared environments in a bit. Once again, with templating, each dev gets their own namespace. The main idea is: If something is built once, it doesn't have to be built again.

Garden allows you to use the same cluster for development and testing, resulting in less time spent waiting and debugging CI, because you have the same tools, configs and caching across environments.

Now let's run:

Garden’s CLI should report that our unit and integration tests have passed this time.

A quick note on shared environments

We have done this whole development and testing process in one environment! However, keep in mind that we’ve used a local environment. With Garden you can use remote Kubernetes environments, which opens further possibilities. This includes benefits such as collaborating on shared preview environments and being able to run Garden in your CI pipelines, considerably speeding up your workflows. More to come on this!

A modern tool for modern architecture

It all comes down to this: Why retest modules if your tests are the same in your local and CI environments? Frankly, it’s tedious. Garden eliminates the need for retesting altogether.

Garden is a modern cloud native development and CI pipeline tool; effectively meeting the needs of both. With Garden, you're able to deploy any environment and easily configure a production-like environment, enabling quality feedback early in the development process. You can run tests in the project’s namespace, and feasibly write them too.

Our platform is helping keep developers focused and productive. We don’t believe a developer’s time should be wasted on a loop of constant Git commits, checks, waiting for tests, context switching, and – sometimes – slowly losing their sanity. The less time spent waiting on CI pipelines and debugging low-value plumbing work, the more we’re able to stay focused and in the flow, being productive. A modern tool for happy developers!

previous arrow
newt arrow