Go Dev Guide and Sample Apps

Overview

In this developer guide, we are going to cover hosting a Go application on App Platform. We will cover steps to hosting, common pitfalls, and more so that you can optimally host your Go application on App Platform. If you come across something that isn’t covered in this guide, ask a community question.

Before You Start

For this guide, we make the assumption that you already have a Go app.

To deploy a Go app on App Platform, you will need:

  1. A DigitalOcean account
  2. A Go app located in one of the following:
    1. GitHub or GitLab
    2. A public DockerHub repository
    3. A DigitalOcean Container Registry

If you’re just learning App Platform, we have a sample Go app you can fork on GitHub.

Questions About Your App

Creating an app for the first time is easily done by clicking Create App in the DigitalOcean cloud control panel. Before creating an apps, it’s good to consider what things you will need to locate, build, and configure your app at both build and run time.

Some things to consider before creation:

  • If your app is not in the root of your Git repository, what is the path?
  • What configurations need to be done to startup successfully?
  • Does your app expect any external dependencies? (such as a database or third party API)
  • Can the configurations you need be added via environment variables?
  • Does your app need any special build arguments?
  • Does your app need any special run arguments?
  • What port does your app’s http server listen on?
    • Is it configurable via the $PORT environment variable?

The Ways App Platform Works

App Platform supports two methods of build apps:

Buildpacks inspect your code and create a plan to build and run your code. When you give App Platform access to your code base, it checks your code to determine what language it is using, and if the language is supported, uses a buildpack to build, run, and deploy your code. Build packs are usually the most user-accessible way to deploy apps on App Platform.

heroku-buildpack-go is utilized as the buildpack for detecting and building your Golang applications.

Creating Go Applications in App Platform

When creating an app, App Platform scans the app source code in the App Platform detection service which will determine the language/framework for building your application.

App Platform looks for any of the following files to detect a Go application:

go.mod
Gopkg.toml
Godeps/Godeps.json
vendor/vendor.json
glide.yaml

If any of the above are found, App Platform will walk you through deploying your application. Providing one of the above files is the simplest and fastest way to deploy a Go app to App Platform.

If none of the above are found, App Platform will default to Dockerfile builds if a dockerfile is found in the root of the project directory.

Go Version

The version in your go.mod file is automatically detected and used as the version to build your application:

module github.com/digitalocean/sample-golang

go 1.16
...

Limitations

Deploying Go with a Dockerfile

Using a Dockerfile to build a Go app is a flexible way to optimize the build image that will be used to deploy the app. By placing a Dockerfile in the root of the directory or specifying the path to a dockerfile in the app spec, App Platform will detect the Go app as a dockerfile based app.

One of the advantages of a Dockerfile based build is the image can be cut down really small with multi-stage builds. For example, digitalocean/sample-dockerfile uses multi-stage build so the final container image only contains updated CA certificates and the compiled Go binary:

# This is a standard Dockerfile for building a Go app.
# It is a multi-stage build: the first stage compiles the Go source into a binary, and
#   the second stage copies only the binary into an alpine base.

# -- Stage 1 -- #
# Compile the app.
FROM golang:1.12-alpine as builder
WORKDIR /app
# The build context is set to the directory where the repo is cloned.
# This will copy all files in the repo to /app inside the container.
# If your app requires the build context to be set to a subdirectory inside the repo, you
#   can use the source_dir app spec option, see: <https://www.digitalocean.com/docs/app-platform/references/app-specification-reference/>
COPY . .
RUN go build -mod=vendor -o bin/hello

# -- Stage 2 -- #
# Create the final environment with the compiled binary.
FROM alpine
# Install any required dependencies.
RUN apk --no-cache add ca-certificates
WORKDIR /root/
# Copy the binary from the builder stage and set it as the default command.
COPY --from=builder /app/bin/hello /usr/local/bin/
CMD ["hello"]

Configuring App Platform for Go Applications

The process for creating an App Platform app involves four steps:

  1. Selecting the code base (repository) to pull the code from
  2. Configuring the detected service, such as environment variables and HTTP routes
  3. Selecting the app’s name and the region it will reside in
  4. Selecting the app’s instance type and size

You can add more configurations, services, static sites, and databases after the initial creation if needed.

1. Selecting the Code Base

App Platform has native integration with GitHub and GitLab. App Platform also supports public pre-built images hosted in Docker Hub and DigitalOcean Container Registry.

After authenticating with GitHub or GitLab, you can select repositories and their respective branches to deploy from. You can also indicate if changes to this branch should be auto-deployed by App Platform.

2. Configuring the Detected Service

During this step, App Platform scans the code base and detects the language and framework. If the source is not located in the root directory, the option to specify a sub-directory is provided after the first scan attempt. Once the Go app is detected, you can specify the following configurations:

  • Environment variables
  • The default HTTP port
  • Subroutes
  • Database
  • Build and run commands

You can create more complex configuration after creation by modifying the app’s configuration in the control panel or by editing the app’s spec.

Environment Variables

Environment Variables are included at both run and build time by default and you can customize them in the app spec later if needed. We recommend using the Encrypt option for secrets, such as CA certificates or SSH keys, that should not be visible after creation. This feature encrypts the value in the app spec. The secret is bound to the app and is only decrypted before injection into the app.

Typically you need environment variables for:

  • Database credentials
  • 3rd-party services credentials

HTTP Port

HTTP Port is the port that an app is expecting traffic on. If your app uses the PORT environment variable, you can leave this as is, otherwise you can change it to match the port that is set in your app. App Platform automatically receives traffic on port 80 and 443 and forwards it to this port. If you set a PORT environment variable during your app’s configuration in the control panel, it overwrites the PORT environment variable in your app.

HTTP Request Route

The HTTP Request Route defines the subpath that you can access this component from. If this is the only component in the app, then the request route will be the domain’s root /. If your app has multiple public-facing components, you can define a route for each component. For example, if your app contains a frontend static site that connects to a backend API, the static site’s request route can be the domain’s root / and the Go API can be available at /api.

Database

During this step, you can attach a database. App Platform offers a low cost PostgreSQL development database you can add to the app as a an additional component. You can also attach existing databases created using the Database service.

Your app can connect the app to a dev database by adding a bind variable (DATABASE_URL=${db.DATABASE_URL}) to the app’s environment variables.

Build and Run Commands

App Platform automatically detects build and run commands. If you have special arguments, you can add them in the app’s Build Command and Run Command sections.

In some cases, you can also run startup scripts before starting your Go app to get the environment ready for production.

Typically in a Go application, you’ll see:

  • Build: npm run build
  • Run: npm start

3. Selecting a Name and Region

App names are used within a provided domain with a random five character string appended. Most apps eventually use a custom domain like example.com instead of the provided domain. The domain provided by DigitalOcean is good for testing, though.

When you pick a region, we recommend picking one that is close to your users to minimize latency.

4. Specifying Instance Type and Size

Lastly, you can pick your app’s hosting plan. We recommend Basic plans for simple, low traffic apps and apps early in their development. You can upgrade to a Pro tier plan at any time. Upgrading your plan does not cause any downtime. The Starter tier is reserved for deploying and hosting static websites.

Most apps can be deployed on either Basic or Pro tiers. The Pro tier provides more bandwidth and build minutes, access to dedicated CPU instances, per-minute metrics, and horizontal scaling.

Go apps cannot be static sites, so you will be using Basic and Pro tier apps.

🚀 Houston, we have lift off! 🚀

After clicking the Launch button, the configured app builds, deploys, and is provided a domain. You can find details about the deployment in the Deployments` tab.

Common Pitfalls

HTTP Port configuration

Some apps set the listening port using the PORT environment variable, while others are hardcoded. In the scenario that an app uses PORT to determine the HTTP server port, the HTTP Port field in app’s Settings tab overwrites any PORT environment variables that are set in the app.

If an app’s HTTP port is hardcoded, the HTTP Port for that component needs to be changed in the Settings tab to match the app’s value.

HTTP Serving on localhost vs 0.0.0.0

HTTP servers explicitly running on localhost or 127.0.0.1 creates a common issue. This is problematic because localhost is an alias for 127.0.0.1, which is a local loopback interface that is not externally exposed to the current environment.

HTTP servers should not include an address specifying 0.0.0.0 explicitly, or using the process.env.PORT.

Private dependencies

If your Go app uses private dependencies that are not accessible with the same account used to access the apps, a personal access token can be injected by setting an environment variable with the key of GO_GIT_CRED__HTTPS__GITHUB__COM and the value of a GitHub personal access token. Note, this has only been tested with GitHub. More details can be found here.

App Operations

Security

App Platform offers a number of features that can be used to secure your app:

  • Encrypted Environment Variables: Encrypts environment variables, which binds them to the app and makes them immutable. They are injected at both build and run time events.

  • Database Trusted Sources:: Limits connections to your database to specified IP addresses or resources in your DigitalOcean account.

  • HTTPS Encryption: Ensures all traffic is encrypted over the wire and redirects all HTTP traffic to HTTPS.

Insights

The Insights tab in the DigitalOcean Apps dashboard shows metrics for all of an apps components. Alongside seeing CPU and memory usage, Insights tracks restart counts, bandwidth, and latency metrics.

Alerts and Notifications

App Platform offers app alerts and metrics monitoring via email and Slack integration. You can set alerts that will trigger based on resource usage or failed deployments.

Scaling

You can scale your app vertically or horizontally depending on what tier your app is being hosted on. App’s on a *Pro tier plan can be scaled horizontally by adding more load-balanced containers. Apps on a Basic tier can be scaled vertically, which increases the CPU and memory allocated to each container instance.

Jobs, Workers, and Internal Services

You can add several different types of useful components to your app as it grows in scope. Here’s brief overview of each:

  • Workers: Run server-side code and can’t be accessed externally from the internet. Because workers can can not accept HTTP requests, they are only suitable for doing background tasks, such as queue processing or video encoding.

  • Internal Services: are similar to services but expose ports internally. A service can expose external and internal ports.

  • Jobs: One off operations that you can schedule to run before or after a deployment, or after a deploy fails. Jobs are great for starting database migrations or executing code on a failed deployment.

Logs

Runtime logs contain the live logs for the app’s components that support logging. These logs include standard output and errors. You can access the runtime logs from the Runtime Logs tab.

In addition runtime logs, we also provide build and deployment logs for each of your app’s components. You can access build and deployment logs from the Deployments tab in the app’s dashboard. Here you can find the build and deployment logs for each of your components for a specific deployment.

App Platform also supports log forwarding. You can forward your app runtime logs to external log management providers, like Papertrail and Datadog.

Troubleshooting Your App

Build Issues

App Platform preserves logs and posts them under the deployment. You can see both the App Platform logs and your build logs as they happen and use them to troubleshoot build issues.

Deployment Issues

Deployment logs occur after a build has been successful. At this point, the container image of the app created by App Platform is being pulled from a private container registry and deployed to an App Platform cluster.

Live Apps Issues

Debugging a live app offers a few more tools than the simple log offering of builds and deployments. Not only are the live logs available under the Runtime Logs tab, you can also access component instances through the console.

Continuous Integration/Continuous Deployment (CI/CD)

App Platform works well with CI/CD settings in different scenarios. You can use auto-deployment to continuously deploy changes to your app to see if they work. You can also disable auto-deploy and use GitHub Actions to deploy when certain conditions are met.

You can turn off auto-deployment and only trigger a build after tests are done, or on a new version release, or ad-hoc. Some common paths are:

  • Triggering a deploy on version release
  • Running tests before deployment
  • Build a Docker image and pushing that to DigitalOcean Container Registry or Docker Hub, then setting that image to be used for deployment
  • Waiting for multiple repositories (for multiple components) to be done before deployments are triggered

All of these scenarios and more are possible.

GitHub Actions

App Platform has a GitHub Action called app_action that you can use to trigger deployments on specific types of changes to your repo, including new commits on a branch, releases, tags, and merges. It also supports dynamically updating app specs to pull specific Docker image versions.

doctl (CLI)

You can perform App Platform operation in almost any CI/CD environment using the doctl command-line tool. See the doctl reference page for a full list of commands that you can use to manage App Platform.

See Troubleshoot Your App for more troubleshooting techniques for App Platform.

Sample Apps

Manage Go apps in DigitalOcean App Platform.