Skip to main content

Command Palette

Search for a command to run...

Test your apps in Docker or Kubernetes locally

Updated
5 min read
Test your apps in Docker or Kubernetes locally

Today I’m going to talk about a few things that happen to me pretty often, which is that developers don’t like to test their changes more than some basic examples or only in to write box way, no one likes testing neither use Linux (which is the OS where most of the production apps run) so their development environment is far different from what apps are supposed to work with. Let’s talk about a few things, one of them which is import for everyone is SDLC.

Software Development Life Cycle

So, coding is an important part of the SDLC or the product itself but pushing your code to the repository is neither the end nor the beginning, there are a lot (really a lot) of things happening previously and after that!

Graph took from [HERE](https://www.geeksforgeeks.org/software-development-life-cycle-sdlc/)

Lightbox

So it’s significant to understand the complete SDLC, why? Because one of the final aspects of it is the deployment! And the deployment is totally dominated by the Linux OS.

But people don’t use Linux in the personal or working computers, not as much as Windows, so that creates us a problem where developers try their apps on Windows then push their code and end up uploading that code to a Linux machine. So here if there is an error because the OS works differently.

How we can solve it?

One of the many solutions for these is something that is quite popular in the recent decade and is containers, I’m not going to explain what they are or how they're work, but rather why we should use them at least for local development, even if your server doesn’t run another OS.

Proposal #1: Docker

Using the docker engine we can build what is called Dockerfiles here is an example of a Golang app running GIN a web framework.

# DEV
FROM golang:alpine3.20 AS build

WORKDIR /app
COPY . /app
RUN go mod download
RUN GOARCH=amd64 go build -o ./bin/InfobaeAPI ./src/main.go

# PROD
FROM alpine:3.20

RUN addgroup -S appgroup && adduser -S infobae -G appgroup
WORKDIR /app
COPY --from=build /app/bin/InfobaeAPI /app/bin/InfobaeAPI
ENV GIN_MODE=release

USER infobae
ENV PORT=3000
EXPOSE ${PORT}
ENTRYPOINT ["/app/bin/InfobaeAPI"]

If our apps communicate with other components, or we just want to have an easier read of the panorama (or just type less) we can create a compose.yml

services:
  infobae:
    container_name: infobae
    ## https://hackernoon.com/how-to-harden-your-docker-containers-using-seccomp-security-profile-81153ucz
    security_opt:
      - no-new-privileges
      - seccomp=./security/seccomp.json
      - apparmor=./security/non-root.profile
    restart: unless-stopped
    cap_add:
      - CHOWN
      - NET_BIND_SERVICE
    cap_drop: ["ALL"]
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "${PORT}:3000"

In this example, I’m creating a service with a unique container that has some security constraints.

This container is going to build in an operating system called alpine which is a minimal operating system often used for work fulls that don’t need that many things.

With docker compose up -d while having the compose and Dokerfile in hand, we can create a docker container that will run our app with the base OS and our app.

The end result is something like this where I see my app running, if my machine was a windows one, and I wanted to try how it works in a Linux environment, this was a success (at least for runtime apps, read something about build time just in case)

This workflow is valid in simple environments where Kubernetes is not into mind. Next we are going to cover the Kubernetes part.

Proposal 2: Minikube

Post used as reference [HERE](https://www.digitalocean.com/community/tutorials/how-to-use-minikube-for-local-kubernetes-development-and-testing)

In some workflows there are Kubernetes clusters with are part of the entire infrastructure, so testing docker would be fine since the container itself is part of the pods which is the smallest components in the Kubernetes ecosystem, but maybe we want to try more components of it, that’s why building a local cluster can be handy.

But you may be thinking, building a local cluster won’t be hard for a developer? Is not even part of their job, well kinda. Their job is to make the app work no matter what, so testing locally in a real scenario would be ideal for them. Lucky enough, there are solutions like Minikube which creates clusters for local development quite easily.

Now let’s get into practice, In my case I used Kompose to convert the compose.yml into Kubernetes manifestos, with a command like this kompose -f compose.yml convert I got this file

apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    kompose.cmd: kompose -f docker-compose.yml convert
    kompose.version: 1.34.0 (HEAD)
  labels:
    io.kompose.service: infobae
  name: infobae
spec:
  replicas: 1
  selector:
    matchLabels:
      io.kompose.service: infobae
  template:
    metadata:
      annotations:
        kompose.cmd: kompose -f docker-compose.yml convert
        kompose.version: 1.34.0 (HEAD)
      labels:
        io.kompose.service: infobae
    spec:
      containers:
        - image: dyallo/infobae_api
          name: infobae-dev
          ports:
            - containerPort: 3000
              protocol: TCP
          securityContext:
            allowPrivilegeEscalation: false
            capabilities:
              add:
                - CHOWN
                - NET_BIND_SERVICE
              drop:
                - ALL
      restartPolicy: Always

And this one too

apiVersion: v1
kind: Service
metadata:
  annotations:
    kompose.cmd: kompose -f docker-compose.yml convert
    kompose.version: 1.34.0 (HEAD)
  labels:
    io.kompose.service: infobae
  name: infobae
spec:
  ports:
    - name: "5000"
      port: 5000
      targetPort: 3000
  selector:
    io.kompose.service: infobae
  type: NodePort

Now using kubectl we can do something like kubectl -f apply . and apply all changes of the manifestos we created before with kompose

Here I make sure that the cluster is running with minikube start, apply the manifestos with kubectl apply -f ./kubernetes, check that the service is running kubectl get services grab the IP from the cluster since I’m using NodeIP in the service with minikube ip and curl the app (since is an API).

Conclusion

It is always necessary to test (also with testing!) your apps before publishing into the server, do not be satisfied only by running things like npm run dev or npm run build your OS is not always the same as the server! Learn more about what happens before and after you start coding.

Don’t be a code monkey.

More from this blog

J

jd-apprentice - blog

29 posts

🧰 devops | 💻 tech | 📚 linux | 💖 anime