DEV Community

Cover image for Deploying a Go-based app to AKS using Kubestack
s1ntaxe770r
s1ntaxe770r

Posted on

Deploying a Go-based app to AKS using Kubestack

In this post, I would be showing you how to deploy a golang application to Kubernetes using Kubestack. Kubestack is a Gitops automation built on Terraform to reduce the risk of deploying and increasing development speed. That being said I would not be covering how to set up kubestack but rather how to deploy Kubernetes manifests using Kubestack, for more info on how to up a working Kubestack pipeline check out the getting started guide over here.

Now let's dive in.

Setup

Once you have your kubestack pipeline set up your folder structure should look something like this

    .
    ├── Dockerfile
    ├── Dockerfile.loc
    ├── README.md
    ├── aks_zero_cluster.tf
    ├── aks_zero_ingress.tf
    ├── aks_zero_providers.tf
    ├── manifests
    └── versions.tf
Enter fullscreen mode Exit fullscreen mode

to deploy our Kubernetes manifest we would be making use of a cluster service module. Cluster service modules in Kubestack allows Terraform to interact directly with Kubernetes through Terraform, this covers things like deploying and creating namespaces, creating deployments..etc.

Open up ask-zero_cluster.tf and add the following lines

    ...

    module "custom_manifests" {
      providers = {
        kustomization = kustomization.aks_zero
      }
      source  = "kbst.xyz/catalog/custom-manifests/kustomization"
      version = "0.1.0"
      configuration = {
        apps = {
          namespace = "apps-${terraform.workspace}"
          resources = [
                "${path.root}/manifests/apps/namespace.yaml",
            "${path.root}/manifests/apps/deployment.yaml",
            "${path.root}/manifests/apps/service.yaml",
            "${path.root}/manifests/apps/ingress.yaml"
          ]
          common_labels = {
            "env" = terraform.workspace
          }
        }
        ops = {}
        loc = {}
      }
    }
Enter fullscreen mode Exit fullscreen mode

Here we initialize the custom manifest cluster service module and tell kustomize to use the existing aks_zero module using.

     providers = {
        kustomization = kustomization.aks_zero
      }
Enter fullscreen mode Exit fullscreen mode

The configuration block is where the magic happens, first, we specify we declare what workspace we want our resources to be deployed to using


     apps = {
          namespace = "apps-${terraform.workspace}"
          resources = [
                "${path.root}/manifests/apps/namespace.yaml",
            "${path.root}/manifests/apps/deployment.yaml",
            "${path.root}/manifests/apps/service.yaml",
            "${path.root}/manifests/apps/ingress.yaml"
          ]
          common_labels = {
            "env" = terraform.workspace
          }
        }
Enter fullscreen mode Exit fullscreen mode

Next, we declare what namespace the manifests should be deployed to using namespace = "apps${terraform.workspace}" which would translate to apps-ops or apps-apps depending on your current workspace, next the resources block tells terraform to look in manifests folder in the current directory for the manifests we want to deploy. Now that we have the cluster module set up let's create the manifests.
Run the following commands:

mkdir manifests/apps && cd manifests/apps && touch deployment.yaml service.yaml ingress.yaml
Enter fullscreen mode Exit fullscreen mode

Now populate the files with the following code.

# manifests/apps/namespace.yaml
---
apiVersion: v1
kind: Namespace
metadata:
  name: apps-apps

---
apiVersion: v1
kind: Namespace
metadata:
  name: apps-ops
Enter fullscreen mode Exit fullscreen mode

Note: since this is a fresh Kubernetes cluster I have included a manifest for a namespace as kubestack would deploy the resources in the order specified in the module so the namespace apps-apps would need to exist first.

#manifests/apps/deployment.yaml
--------
apiVersion: apps/v1
kind: Deployment
metadata:
  name: ping-api
spec:
  selector:
    matchLabels:
      app: ping-api
  template:
    metadata:
      labels:
        app: ping-api
    spec:
      containers:
      - name: ping-api
        image: ghcr.io/s1ntaxe770r/evil-ekow:latest
        resources:
          limits:
            memory: "128Mi"
            cpu: "500m"
        ports:
        - containerPort: 8080
        env:
          - name: REDIS_CACHE_HOST
            value: "redis-svc"
          - name: REDIS_PORT
            value: "6379"

--------
apiVersion: apps/v1
kind: Deployment
metadata:
  name: redis
spec:
  selector:
    matchLabels:
      app: redis
  template:
    metadata:
      labels:
        app: redis
    spec:
      containers:
      - name: redis
        image: redis:alpine
        resources:
          limits:
            memory: "128Mi"
            cpu: "500m"
        ports:
        - containerPort: 6379

# manifests/apps/service.yaml
--
apiVersion: v1
kind: Service
metadata:
  name: redis-svc
spec:
  selector:
    app: redis
  ports:
  - port: 6379
    targetPort: 6379

--------
apiVersion: v1
kind: Service
metadata:
  name: ping-svc
spec:
  selector:
    app: ping-api
  ports:
  - port: 80
    targetPort: 8080
# manifests/apps/ingress.yaml
--------
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: myingress
  labels:
    name: myingress
spec:
  rules:
  - host: prod.evil.corp
    http:
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          service:
            name: ping-svc
            port:
              number: 80
Enter fullscreen mode Exit fullscreen mode

The above manifests will deploy a version of an API that uses Redis to store key-value pairs. You can check the source code out here.

Next, you can test out these changes locally by running kbst apply local, if all looks good you should be able to tag and deploy like this:

$ git tag apps-deploy-1
$ git push origin apps-deploy-1
Enter fullscreen mode Exit fullscreen mode

Accessing your deployment

Because I don't have a valid domain at the time of writing I would be using my ingress controller external IP to access the deployment, however, if you have your domain properly configured pls refer to this portion of the
Kubestack documentation.

First, grab your ingress controller\'s external IP using:

$  kubectl get ingresses -A
Enter fullscreen mode Exit fullscreen mode

Next, create the following entry in /etc/hosts

10.10.20.5   prod.evil.corp
Enter fullscreen mode Exit fullscreen mode

be sure to change the IP to your ingress controllers external IP ,now you should be able to access the swagger docs at
http://prod.evil.corp

evil-corp

Conclusion

In this post, I covered how to deploy your Kubernetes manifests using Kubestack on Azure do note that this is not limited to azure as Kubetack also supports GKE and AWS at the time of writing this post, so be sure to check out the
documentation for any provider-specific steps. Now go forth and git deploying 😄

Discussion (0)