Deploying a Go backend to a new Kubernetes Cluster in minutes(!)
Marcus Kohlberg
Posted on November 6, 2023
๐คฏ 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
๐ 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
You should see this:
๐งช Try the API
Next, call your endpoint:
curl http://localhost:4000/url -d '{"URL": "https://encore.dev"}'
You should see this:
{
"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.
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
}
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.
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.
๐ผ 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.๐พ
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
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.๐
Posted on November 6, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.