DEV Community

Cover image for Deploying a Go backend to a new Kubernetes Cluster in minutes(!)
Marcus Kohlberg for Encore

Posted on

Deploying a Go backend to a new Kubernetes Cluster in minutes(!)

๐Ÿคฏ Setting up and deploying to Kubernetes can be a major pain. Involving many, many, steps, often requiring you to refer to documentation or a tutorial just to get things going.

โœจ Encore: a new type-safe workflow for infrastructure
In this article, we'll be using Encore's Infrastructure SDK 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.

๐Ÿš€ What's on deck:

  • Install Encore
  • Create your backend app from a template
  • Run locally
  • Connect your cloud account
  • Deploy to Kubernetes

๐Ÿ’ฝ 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, we're going to clone a pre-made backend app from Encore's template repo. It's a simple monolith implementing a URL shortener. The app has a REST API and a PostgreSQL database.

Install it by running:

encore app create my-app-name --example=url-shortener
Enter fullscreen mode Exit fullscreen mode

๐Ÿ Running locally

To run the application locally, make sure you have Docker installed and running. This is required to run Encore applications with SQL databases.

Then simply run:

encore run
Enter fullscreen mode Exit fullscreen mode

You should see this:

Image description

๐Ÿงช Try the API

Next, call your endpoint:

curl http://localhost:4000/url -d '{"URL": "https://encore.dev"}'
Enter fullscreen mode Exit fullscreen mode

You should see this:

{
  "ID": "5cJpBVRp",
  "URL": "https://encore.dev"
}
Enter fullscreen mode Exit fullscreen mode

๐Ÿ•น Open the developer dashboard

While encore run is running, open http://localhost:9400/ to view Encore's local developer dashboard.

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.๐Ÿ‘‡

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
}
Enter fullscreen mode Exit fullscreen mode

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 > (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

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

๐Ÿ–ผ 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 this page, you can configure:

  • Which cloud to deploy to (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

Finally, let's make sure the environment we just created is set as the default deployment target:

  • Go to General in the application settings menu
  • Under Primary Environment select the environment you just created and click Update.

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:

$ git add -A .
$ git commit -m 'Initial commit'
$ git push encore
Enter fullscreen mode Exit fullscreen mode

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.๐Ÿ‘ˆ

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 app running in the cloud.

Keep building with these Open Source Encore App Templates.๐Ÿ‘ˆ

If you have questions or want to share your work, join the developers hangout in Encore's community Slack.๐Ÿ‘ˆ

Top comments (0)