learning-go

Learn Go by building a REST API and a Command Line Interface (CLI)

Create a Helm chart for the API

Helm is a package manager for Kubernetes. It helps you define, install, and upgrade even the most complex Kubernetes application.

From the Helm introduction video:

Package Management: Tooling that enables someone who has knowledge of an application and a platform to package up an application so that someone else with who has neither extensive knowledge of the application or the way it needs to be run on the platform can use it.

Watch the video linked above before proceeding.

One of the most important concepts in Helm are charts:

Helm uses a packaging format called charts. A chart is a collection of files that describe a related set of Kubernetes resources. A single chart might be used to deploy something simple, like a memcached pod, or something complex, like a full web app stack with HTTP servers, databases, caches, and so on.

To install Helm you can follow the instructions at https://helm.sh/docs/intro/install.

To store the infrastructure related configurations we are going to create a new repository named learning-go-api-iac. Head to GitHub and create one for you. After, clone it to your machine so we can start building a chart for the API.

To create a chart execute the following command:

mkdir charts && cd charts
helm create learning-go-api

After running the following files and directories will be created:

learning-go-api
├── charts                  # A directory containing any charts upon which this chart depends
├── Chart.yaml              # A YAML file containing information about the chart
├── templates               # A directory of templates that, when combined with values,
                            # will generate valid Kubernetes manifest files
│   ├── deployment.yaml     # Template for a deployment (DELETE IF NOT NEEDED)
│   ├── _helpers.tpl        # Helper templates to be used in other templates
│   ├── hpa.yaml            # Template for auto scaling (DELETE IF NOT NEEDED)
│   ├── ingress.yaml        # Template for an ingress (DELETE IF NOT NEEDED)
│   ├── NOTES.txt           # OPTIONAL: A plain text file containing short usage notes
│   ├── serviceaccount.yaml # Template for a service account (DELETE IF NOT NEEDED)
│   ├── service.yaml        # Template for a service (DELETE IF NOT NEEDED)
│   └── tests               # Pod definitions to check the status of the application
└── values.yaml             # The default configuration values for this chart

For the current version of our API we will need to define the following k8s resources:

  1. A Mamespace dedicated to the learning-go-api
  2. A Service exposing the API and load balancing the traffic to pods
  3. A Deployment to manage and scale pods
  4. Several Pods managed by the deployment to run the API containers
  5. A Secret containing the API key to call the backend financial API

The following diagram illustrates all the resources:

k8s

The files generated by the helm create command build a skeleton for most of the resources we need.

But we need to do some clean up and change the generated templates to build this solution.

Clean up

We are not going to use some of the files generated by the helm create command so we can delete them.

rm carts/learning-go-api/templates/ingress.yaml
rm carts/learning-go-api/templates/serviceaccount.yaml
rm carts/learning-go-api/templates/hpa.yaml

Basic configurations

The value.yaml contains configuration values for this chart.

Let's open it and update a couple of things:

  1. The image.repository should be renato0307/learning-go-api
  2. The serviceAccount.create must be set to false
  3. The service.type must be LoadBalancer and the service.port change to 9000
  4. In the resources section uncomment the values

We also need to change the Chart.yaml file and update the following:

  1. appVersion must match the GitHub tag for the learning-go-api, which should be 0.0.3 at this moment.

Create the namespace

All k8s resources will be created under a namespace, to allow the isolation from other resources in the cluster.

The namespace will be named learning-go-api and we can created it by running the following command:

kubectl create ns learning-go-api

Secrets

We are going to use secrets to store the API key for the currency conversion.

First create a file named secrets.yaml with the following contents:

apiVersion: v1
kind: Secret
metadata:
  name: learning-go-api-secrets
type: Opaque
data:
  CURRCONV_API_KEY: <the value of the API key in base64>

Next, create the secret resource by running kubectl apply:

kubectl apply -f secrets.yaml -n learning-go-api

The result should be:

secret/learning-go-api-secrets created

As this contains sensitive information, delete the secrets.yaml file:

rm secrets.yaml

Deployment changes

Open the deployment.yaml and in the containers list, add the CURRCONV_API_KEY environment variable. Additionally also change the container port to be 8080, the default port exposed by Gin.

# ...
containers:
    - name: 
        securityContext:
        image: ":"
        imagePullPolicy: 
        env:                                    # new
        - name: CURRCONV_API_KEY                # new
          valueFrom:                            # new
            secretKeyRef:                       # new
                name: learning-go-api-secrets   # new
                key: CURRCONV_API_KEY           # new
        ports:
            - name: http
              containerPort: 8080               # change
# ...

Install the chart

To install the chart in the cluster run the following command.

This will create a chart named learning-go-api, using the definitions found in carts/learning-go-api, putting all resources in the learning-go-api namespace.

helm install learning-go-api carts/learning-go-api --namespace learning-go-api

To check if everything is OK, list the pods for the learning-go-api namespace:

kubectl -n learning-go-api get pods

You should see something simitar to (the pods must be ready and in the Running status):

NAME                               READY   STATUS    RESTARTS   AGE
learning-go-api-6f7b4d9f79-64cpr   1/1     Running   0          84s

If we get the logs from the pod we should see the requests being made by the liveness and readiness probes:

kubectl -n learning-go-api logs learning-go-api-6f7b4d9f79-64cpr 

The logs are:

...
[GIN] 2021/12/28 - 20:26:44 | 200 |       30.38µs |      10.244.0.1 | GET      "/"
[GIN] 2021/12/28 - 20:26:44 | 200 |       30.89µs |      10.244.0.1 | GET      "/"
[GIN] 2021/12/28 - 20:26:54 | 200 |       36.04µs |      10.244.0.1 | GET      "/"
[GIN] 2021/12/28 - 20:26:54 | 200 |       36.28µs |      10.244.0.1 | GET      "/"
[GIN] 2021/12/28 - 20:27:04 | 200 |      37.859µs |      10.244.0.1 | GET      "/"
[GIN] 2021/12/28 - 20:27:04 | 200 |       15.06µs |      10.244.0.1 | GET      "/"
[GIN] 2021/12/28 - 20:27:14 | 200 |       33.88µs |      10.244.0.1 | GET      "/"
[GIN] 2021/12/28 - 20:27:14 | 200 |        24.8µs |      10.244.0.1 | GET      "/"

Testing the deployed API

The service should also be set up, allowing us to access the API.

You can check it by running:

kubectl -n learning-go-api get svc

You'll be able to see something like:

NAME              TYPE           CLUSTER-IP      EXTERNAL-IP      PORT(S)          AGE
learning-go-api   LoadBalancer   10.96.151.196   172.19.255.200   9000:31144/TCP   21m

Using the EXTERNAL-IP and the PORT you would be able to call the API using httpie:

http 172.19.255.200:9000

The result should be:

HTTP/1.1 200 OK
Content-Length: 51
Content-Type: application/json; charset=utf-8
Date: Wed, 28 Dec 2021 20:45:52 GMT

{
    "message": "Hello, welcome to the learning-go-api"
}

Wrap up

Commit and push everything to GitHub.

Next

The next section is Deploy the API using Flux.