The fastest way to deploy a Go app to Kubernetes
Tags: go, devops, kubernetes, tutorial
Published: 2023-11-20 13:12:27

**😰 Setting up a Kubernetes cluster can be a major time investment.** Going from zero to deploy will normally involve many steps, requiring you to refer to documentation and several guides — just to get things stood up in a relatively secure way.

**✨ Encore: a new type-safe workflow for infrastructure**
In this article, we'll be using [Encore](https://encore.dev)'s [Infrastructure SDK](https://encore.dev/docs/primitives) to declaratively define the infrastructure our Go backend needs, and then use Encore to automatically provision our Kubernetes cluster along with other infrastructure, directly in our cloud account.

Your code will be deployable to both GCP and AWS, and Encore will provision your cluster using either GKE or EKS Fargate, depending on which cloud you choose.🙋‍♂️

If you prefer, you can also deploy using serverless compute instances, without changing a line of code. This is great for setting up test environments that are cheap and easy to run.💸

**🚀 What's on deck:**
- Install Encore
- Create your backend app from a template
- Run locally
- Connect your cloud account
- Deploy to Kubernetes

_Don't feel like building right now? Watch the video instead:_
[How to deploy a Go backend to Kubernetes](https://www.youtube.com/watch?v=NnNCKLiyNRY)

## 💽 Install Encore

Install the Encore CLI to run your local environment:
- **macOS:** `brew install encoredev/tap/encore`
- **Linux:** `curl -L https://encore.dev/install.sh | bash`
- **Windows:** `iwr https://encore.dev/install.ps1 | iex`

## 🔨 Create your app

To keep things simple as we explain how Encore works, we're going to clone a pre-made app from Encore's [template repo](https://encore.dev/templates). It's a simple monolith implementing a URL shortener. The app has a REST API and a PostgreSQL database.

Install it by running:

```bash
encore app create my-app-name --example=url-shortener
```

## 🏁 Running locally

To run the application locally, make sure you have [Docker](https://docker.com) installed and running. This is required to run Encore applications with SQL databases.

Then simply run:

```bash
encore run
```

You should see this:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zzumjxut8v9n9ltb89k3.png)

## 🧪 Try the API

Next, call your endpoint:

```shell
curl http://localhost:4000/url -d '{"URL": "https://encore.dev"}'
```

You should see this:

```bash
{
  "ID": "5cJpBVRp",
  "URL": "https://encore.dev"
}
```

## 🕹 Open the developer dashboard

While `encore run` is running, open <http://localhost:9400/> to view Encore's [local developer dashboard](https://encore.dev/docs/observability/dev-dash).

Here you can see API documentation, use the API via an API explorer, and see traces using Encore's built-in distributed tracing.

## 🧐 Take a look a the code

This app is now running locally, without any manual work to set up a local Kubernetes instance, and we're about to deploy it to our cloud account. So how does it work?

Let's take a look at the code.👇

```go
package url

import (
	"context"
	"crypto/rand"
	"encoding/base64"

	"encore.dev/storage/sqldb"
)

type URL struct {
	ID  string // short-form URL id
	URL string // complete URL, in long form
}

type ShortenParams struct {
	URL string // the URL to shorten
}

// Shorten shortens a URL.
//
//encore:api public method=POST path=/url
func Shorten(ctx context.Context, p *ShortenParams) (*URL, error) {
	id, err := generateID()
	if err != nil {
		return nil, err
	} else if err := insert(ctx, id, p.URL); err != nil {
		return nil, err
	}
	return &URL{ID: id, URL: p.URL}, nil
}

// Get retrieves the original URL for the id.
//
//encore:api public method=GET path=/url/:id
func Get(ctx context.Context, id string) (*URL, error) {
	u := &URL{ID: id}
	err := sqldb.QueryRow(ctx, `
		SELECT original_url FROM url
		WHERE id = $1
	`, id).Scan(&u.URL)
	return u, err
}

type ListResponse struct {
	URLs []*URL
}

// List retrieves all URLs.
//
//encore:api public method=GET path=/url
func List(ctx context.Context) (*ListResponse, error) {
	rows, err := sqldb.Query(ctx, `
		SELECT id, original_url FROM url
	`)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	urls := []*URL{}
	for rows.Next() {
		var u URL
		if err := rows.Scan(&u.ID, &u.URL); err != nil {
			return nil, err
		}
		urls = append(urls, &u)
	}

	if err := rows.Err(); err != nil {
		return nil, err
	}
	return &ListResponse{URLs: urls}, nil
}

// generateID generates a random short ID.
func generateID() (string, error) {
	var data [6]byte // 6 bytes of entropy
	if _, err := rand.Read(data[:]); err != nil {
		return "", err
	}
	return base64.RawURLEncoding.EncodeToString(data[:]), nil
}

// insert inserts a URL into the database.
func insert(ctx context.Context, id, url string) error {
	_, err := sqldb.Exec(ctx, `
		INSERT INTO url (id, original_url)
		VALUES ($1, $2)
	`, id, url)
	return err
}
```

As you can see there's no Kubernetes configuration or other infrastructure config. It's all Go code, and almost only business logic.

We've simply defined an API endpoint by using the `//encore:api` annotation and have imported the `encore.dev/storage/sqldb` package.

At compile time, Encore parses the code to understand what the infrastructure requirements are to run the application and then generates the boilerplate code necessary.

When running locally, the CLI takes care of setting up local versions of the infrastructure, and in the cloud Encore provisions the cloud services you need based on your configuration options when you create an environment. Now, let's go ahead and do just that!

## ⛅️ Connect your cloud account

First, we need to connect a cloud account to Encore. Do this by the [Cloud Dashboard](https://app.encore.dev) **> (Select your app) > App Settings > Integrations > Connect Cloud**.

### AWS

If you are using AWS, follow the instructions on the page to create an IAM Role, and then connect the role with Encore.

For your security, make sure to check `Require external ID` and specify the external ID provided in the instructions.

![Connect AWS](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xup3ys66ri9pdidcdi2m.png)

### GCP

If you are using GCP, follow the instructions on the screen to create a GCP Service Account for your Encore application.

Note: You need to have a GCP `Organization account` to be able to create service accounts.

![Connect GPC](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gb2gvav894otf846leol.png)

## 🖼 Create Environment

Once you've connected your account, it's time to create a new environment. Do this by going to the **Environments** page in Encore's Cloud Dashboard and clicking **Create Environment**.

From here you can set up your new environment:
- Select **Type** as `Production`.
- Select **Deployment Trigger** as `Branch Push` and set the branch name to your git default (e.g. `main`, or run `git branch` in your app's root folder if you're unsure).
- Select the **Cloud** to use (Select the one you connect your account for).
- **Region** (Select the one you prefer).
- **Compute instance** (Select Kubernetes).
- **Process allocation** (Select `All processes in one service`).

Then click **Create** to save your environment.💾

![Create environment](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/28e37rfryou2j93d0xqx.png)

Now we're ready to deploy!✨

## 🚀 Deploy to Kubernetes

Before pushing the button, remember: Encore will provision a real-live Kubernetes cluster in your account, along with best practices security measures. This means deploying will incur a cost on your account.🤑

To deploy your app and create a new Kubernetes cluster, simply run:

```shell
$ git add -A .
$ git commit -m 'Initial commit'
$ git push encore
```

Encore will now build and test your app, provision the needed infrastructure, including a Kubernetes cluster and database cluster, and deploy your application to the cloud.🚀

After triggering the deployment, you will see a URL where you can view its progress in Encore's [Cloud Dashboard](https://app.encore.dev).👈

It will look something like: `https://app.encore.dev/$APP_ID/deploys/...`

From there you can also see metrics, traces, and connect your GitHub account.

🎉*Now you have a fully-fledged Go backend running in Kubernetes, well done!*

Note: _If you want to keep costs in check, you should delete all the resources created if you don't want to keep using your new cluster. This is easy to do from your cloud provider's console._

### 🍰 Great job - you're done!

You now have the start of a scalable Go backend running in Kubernetes.

Keep building with these Open Source Encore [App Templates](https://encore.dev/templates).👈

If you have questions or want to share your work, join the developers hangout in [Encore's community Slack](https://encore.dev/slack).👈