Picture showing a roller coaster

Application From Sources to Kubernetes With Waypoint

Find out HashiCorp Waypoint to create a modern workflow to build an application from sources and deploy it to Kubernetes in a single file

Guillaume Vincent
Guillaume Vincent

In October 2020, HashiCorp announced the launch of its new product named Waypoint. It provides a modern workflow to build, deploy and release across platforms. We're going to build a Golang application from sources and deploy it to Kubernetes in a single file!

The build step will detect the source language and compile it using Cloud Native Buildpacks. The result will be a docker image that will be stored securely in a Harbor registry. The configuration of Harbor on a local Kubernetes cluster will be detailed.

Once the build step, Waypoint will reuse this image to deploy and release it into the cluster.

What Is Waypoint?

Waypoint is a CLI tool written in Golang providing cross-platform support :

$ waypoint
Welcome to Waypoint
Docs: https://waypointproject.io
Version: v0.1.5
Usage: waypoint [-version] [-help] [-autocomplete-(un)install] <command> [args]
Common commands
  build        Build a new versioned artifact from source
  deploy       Deploy a pushed artifact
  release      Release a deployment
  up           Perform the build, deploy, and release steps for the app
Other commands
  artifact        Artifact and build management
  config          Application configuration management
  context         Server access configurations
  deployment      Deployment creation and management
  destroy         Delete all the resources created for an app
  docs            Show documentation for components
  exec            Execute a command in the context of a running application instance
  hostname        Application URLs
  init            Initialize and validate a project
  install         Install the Waypoint server to Kubernetes, Nomad, or Docker
  logs            Show log output from the current application deployment
  runner          Runner management
  server          Server management
  token           Authenticate and invite collaborators
  ui              Open the web UI
  version         Prints the version of this Waypoint CLI

It uses a single configuration file containing a common workflow. The content supports HCL (HashiCorp Language) or JSON. By the way if you already use Terraform the learning curve should be reduced for you.

The common workflow contains stages described each one in a stanza. Below you have an example of a build stanza which is also included in an app stanza :

app "foo" {   
  build {    
    use "docker" {}
registry {       
      # ...     
    }
hook {       
      # ...     
    }
  }    
}

We'll use stanzas to cover the following workflow stages :

  • A build stanza to create an artifact from the application source code. There are a lot of supported artifact formats such as container image, VM image, etc… We’ll build a docker image and store it into a remote registry hosted by Harbor.
  • A deploy stanza to stage the created artifact onto the Kubernetes cluster. The application is deployed in deployment but it doesn’t receive traffic yet.
  • A release stanza to enable the deployment to expose the application. The goal is to make ready the application to receive traffic.

The Golang Application

The example application is a simple REST API. Golang is great to create micro-services. Here we use the http standard library to reach this goal :

go.mod is present for Cloud-Native Buildpacks. It will identify the language and build the application without any makefile :

The application source is now ready for delivery :

$ go run main.go
Starting HTTP server on port 8080
$ curl -s http://localhost:8080 | jq
{
  "UserId": 1,
  "Id": 1,
  "Title": "delectus aut autem",
  "Completed": false
}

Configure Harbor Registry

Harbor is an open-source project graduated by the CNCF. It provides a secure way to persist docker images. Waypoint will authenticate to pull and push the artifact with a robot account.

Harbor is available via a Helm chart and has many components whose a web portal. It requires NGINX ingress controller deployed to be accessible :

$ helm install ingress-nginx --namespace staging ingress-nginx/ingress-nginx

After the Helm repository added, we can proceed to the Harbor deployment :

$ helm repo add harbor https://helm.goharbor.io
$ helm install harbor --namespace staging harbor/harbor

Once all the Harbor components ready you can access the portal at https://core.harbor.domain. The username is admin and the password is here.

The Harbor web portal
The Harbor web portal

We create a new project for the application :

New project "foo" in Harbor
New project "foo" in Harbor

We create a robot account in the new fresh project. Waypoint will use these credentials later :

Creation of a robot account for Waypoint in the foo project

The Waypoint Workflow

The common workflow steps are in waypoint.hcl located at the project root directory :

The robot account credentials are in dockerAuth.json. This file is in the .gitignore file for security reasons :

{
    "username": "robot$waypoint",
    "password": "xxxxxxxxxxxxxxx"
}

The Waypoint project needs initialization first :

$ waypoint init
✓ Configuration file appears valid
✓ Connection to Waypoint server was successful
✓ Project "my-awesome-golang-app" and all apps are registered with the server.
✓ Plugins loaded and configured successfully
✓ Authentication requirements appear satisfied.
Project initialized!
You may now call 'waypoint up' to deploy your project or
commands such as 'waypoint build' to perform steps individually.

All the workflow stages are playable using the up argument :

$ waypoint up
» Building...
Creating new buildpack-based image using builder: heroku/buildpacks:18
✓ Creating pack client
✓ Building image
 │ [exporter] Reusing layer 'heroku/go:profile'
 │ [exporter] Adding 1/1 app layer(s)
 │ [exporter] Reusing layer 'launcher'
 │ [exporter] Reusing layer 'config'
 │ [exporter] Adding label 'io.buildpacks.lifecycle.metadata'
 │ [exporter] Adding label 'io.buildpacks.build.metadata'
 │ [exporter] Adding label 'io.buildpacks.project.metadata'
 │ [exporter] *** Images (85ab3ada53c6):
 │ [exporter]       index.docker.io/library/my-awesome-golang-app:latest
 │ [exporter] Adding cache layer 'heroku/go:shim'
✓ Injecting entrypoint binary to image
Generated new Docker image: my-awesome-golang-app:latest
✓ Tagging Docker image: my-awesome-golang-app:latest => core.harbor.domain/foo/my-awesome-golang-app:latest
✓ Pushing Docker image...
 │ 2860c3734ddc: Layer already exists
 │ 459acae8a534: Layer already exists
 │ 761cdf87222e: Layer already exists
 │ 9aa3a9efcd12: Layer already exists
 │ c79bdd8f7423: Layer already exists
 │ fe6d8881187d: Layer already exists
 │ 23135df75b44: Layer already exists
 │ b43408d5f11b: Layer already exists
 │ latest: digest: sha256:e4b943e20f69b7e5f4a839a5b1360e84febb58dd4c20aac2cf642ab09
 │ 50f062e size: 2825
✓ Docker image pushed: core.harbor.domain/foo/my-awesome-golang-app:latest
» Deploying...
✓ Kubernetes client connected to https://kubernetes.docker.internal:6443 with namespace staging
✓ Creating deployment...
✓ Deployment successfully rolled out!
» Releasing...
✓ Kubernetes client connected to https://kubernetes.docker.internal:6443 with namespace staging
✓ Creating service...
✓ Service is ready!
» Pruning old deployments...
  Deployment: 01ERWQ5BQKQSC1MGHYJDZVERT2
✓ Kubernetes client connected to https://kubernetes.docker.internal:6443 with namespace staging
✓ Deleting deployment...
The deploy was successful! A Waypoint deployment URL is shown below. This
can be used internally to check your deployment and is not meant for external
traffic. You can manage this hostname using "waypoint hostname."
Release URL: http://10.111.121.39:80
Deployment URL: https://wildly-hardy-mink--v9.waypoint.run
$ waypoint init
✓ Configuration file appears valid
✓ Connection to Waypoint server was successful
✓ Project "my-awesome-golang-app" and all apps are registered with the server.
✓ Plugins loaded and configured successfully
✓ Authentication requirements appear satisfied.
Project initialized!
You may now call 'waypoint up' to deploy your project or
commands such as 'waypoint build' to perform steps individually.

The application is now running on the local Kubernetes cluster. Configure port-forwarding to access the service :

$ kubectl port-forward service/my-awesome-golang-app --namespace staging 8888:80
Forwarding from 127.0.0.1:8888 -> 8080
Forwarding from [::1]:8888 -> 8080

When requesting the application all is working like a charm :

curl -s http://localhost:8888/ | jq
{
  "UserId": 1,
  "Id": 1,
  "Title": "delectus aut autem",
  "Completed": false
}

Conclusion

Waypoint is a turnkey tool to simplify the workflow and facilitating its adoption. The cloud-native pack integration allows building the application without recipes like makefiles. You build your source and deploy the artifact without having to worry about anything. It is a good deal if you start a new project and you can focus on the essential.

The common configuration file is embeddable in a git repository. This makes Waypoint a good candidate for CI/CD and GitOps purposes. It is promising and reserves good surprises in the future.

Resources

Waypoint by HashiCorp
Install and run Waypoint with this five minute quick start tutorial.
Harbor
Our mission is to be the trusted cloud native repository for Kubernetes
Cloud Native Buildpacks
Cloud Native Buildpacks transform your application source code into images that can run on any cloud.
CI/CDCloud-Native

Guillaume Vincent

DevOps Engineer & AWS Certified Solution Architect. Cloud enthusiast and automation addict