In this article we will create a Go application which will accept http requests and interact with Postgresql database. Then we will deploy the app together with the database to a Kubernetes cluster. In order to run the code, Docker registry and Kubernetes cluster must be available to you. If not, you can slightly amend the code in order to run it locally. You can follow it step by step or get the source from: https://github.com/marukhno/go-demo-app

Our application is going to provide four methods which can be called with the following sample requests:

curl -X GET "http://HOST:PORT/ping"
curl -X GET "http://HOST:PORT/ticker?ticker=TSLA"
curl -X POST -d '{"ticker":"AAPL", "price":"140.00"}' "http://HOST:PORT/order"
curl -X GET "http://HOST:PORT/order?id=1"

/order methods will interact with the database.

Swagger file is available on: https://github.com/marukhno/go-demo-app/blob/main/swagger.yaml

The article includes steps to:
1. Create a new Go module
2. Prepare and run a database
3. Developing an application
4. Testing an application

1. Create a new Go module

mkdir go-demo-app && cd go-demo-app
git init
git remote add origin https://github.com/marukhno/go-demo-app.git
go mod init github.com/marukhno/go-demo-app

2. Prepare and run a database

From go-demo-app folder create a directory for the database files. Let's call it initdb:
mkdir initdb && cd initdb

Create init.sql script with initial sql to create an empty table for our service.
vi init.sql

CREATE TABLE orders (
    id SERIAL PRIMARY KEY,
    ticker varchar(100) NOT NULL,
    price NUMERIC(12, 2),
    created timestamp
);

Create a Dockerfile from postgres image. Copy init.sql script to /docker-entrypoint-initdb.d/
vi Dockerfile

FROM postgres:13.1
ENV POSTGRES_USER docker
ENV POSTGRES_DB docker
ENV POSTGRES_PASSWORD passw0rd
VOLUME /var/lib/postgresql/data
COPY init.sql /docker-entrypoint-initdb.d/

Build an image for our database. Use you docker registry as a tag.
docker build --tag=YOUR_REGISTRY_HOST:YOUR_REGISTRY_PORT/go-demo-app-postgres:1.0.0 .

Push the image to your registry
docker push YOUR_REGISTRY_HOST:YOUR_REGISTRY_PORT/go-demo-app-postgres:1.0.0

Prepare Deployment and Service to run the database in Kubernetes
In this example I will run a pod without persistent volume. If you need to make the data persistent mount a volume for /var/lib/postgresql/data.
vi go-demo-app-postgres-install.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: go-demo-app-postgres
spec:
  replicas: 1
  selector:
    matchLabels:
      app: go-demo-app-postgres
  template:
    metadata:
      labels:
        app: go-demo-app-postgres
    spec:
      containers:
        - name: go-demo-postgres
          image: YOUR_REGISTRY_HOST:YOUR_REGISTRY_PORT/go-demo-app-postgres:1.0.0
          resources:
            limits:
              memory: "2Gi"
              cpu: "1000m"
          ports:
            - containerPort: 5432
---
apiVersion: v1
kind: Service
metadata:
  name: go-demo-app-postgres
spec:
  selector:
    app: go-demo-app-postgres
  ports:
    - protocol: TCP
      port: 5432
      targetPort: 5432

Apply the Deployment
kubectl apply -f go-demo-app-postgres-install.yaml -n NAMESPACE

Validate that the database pod has started
kubectl get po -n NAMESPACE | grep go-demo-app

3. Developing an application

Lets add models to use in our code
vi models.go
The code is available here: https://github.com/marukhno/go-demo-app/blob/main/models.go

Now we create functions to handle communication with the database.
vi db.go
The code is available here: https://github.com/marukhno/go-demo-app/blob/main/db.go

And develop the main function
vi main.go
The code is available here: https://github.com/marukhno/go-demo-app/blob/main/main.go

Optionally, we can add some tests for our function. We will override enviroment variables to test the code locally. This require a database running and available externally.
vi main_test.go
The code is available here: https://github.com/marukhno/go-demo-app/blob/main/main_test.go

Prepare a Dockerfile for our application
vi Dockerfile

FROM golang:1.16.0
WORKDIR /app

COPY go.mod go.sum ./
RUN go mod download

COPY db.go ./db.go
COPY models.go ./models.go
COPY main.go ./main.go

RUN go build -o main .
EXPOSE 8080

CMD ["./main"]

Build an image for the application
docker build --tag=YOUR_REGISTRY_HOST:YOUR_REGISTRY_PORT/go-demo-app:1.0.0 .

Push the image to your registry
docker push YOUR_REGISTRY_HOST:YOUR_REGISTRY_PORT/go-demo-app:1.0.0

Prepare Deployment and Service to run and expose the app. Prepare Secret to keep database credentials.
Where:
go-demo-app-postgres - a name of the Service we created for the database
go-demo-app-db-secret - a name of the Secret
username and passwod - base64 encoded credentials to access the database
vi go-demo-app-install.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: go-demo-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: go-demo-app
  template:
    metadata:
      labels:
        app: go-demo-app
    spec:
      containers:
        - name: go-demo-app
          image: YOUR_REGISTRY_HOST:YOUR_REGISTRY_PORT/go-demo-app:1.0.0
          env:
            - name: DATABASE_URL
              value: "go-demo-app-postgres:5432/docker"
            - name: DB_USERNAME
              valueFrom:
                secretKeyRef:
                  name: go-demo-app-db-secret
                  key: username
            - name: DB_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: go-demo-app-db-secret
                  key: password
          resources:
            limits:
              memory: "2Gi"
              cpu: "1000m"
          ports:
            - containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
  name: go-demo-app
spec:
  type: NodePort
  selector:
    app: go-demo-app
  ports:
    - port: 8080
      targetPort: 8080
---
apiVersion: v1
kind: Secret
metadata:
  name: go-demo-app-db-secret
data:
  username: ZG9ja2Vy
  password: cGFzc3cwcmQ=

Apply the Deployment
kubectl apply -f go-demo-app-install.yaml -n NAMESPACE

4. Testing an application

Optionally, run go test: go test -v
Be sure you configured the environment for this test.

optional local test

Now let's test the app deployed in the Kubernetes.
First of all, lets find out the NodePort for our service:
kubectl get svc -n NAMESPACE | grep go-demo-app

NodePort for our service

We can use curl to make a few calls.

curl -s -X GET v101:30629/ping
curl -s X GET "v101:30629/ticker?ticker=TSLA"
curl -s X POST -d '{"ticker":"AAPL", "price":"150.45"}' v101:30629/order
curl -s X GET "v101:30629/order?id=2"
testing the app's endpoints with curl

Another way is to import service's swagger file to a testing tool like Postman.
The swagger can be found here: https://github.com/marukhno/go-demo-app/blob/main/swagger.yaml

testing the app's endpoint with Postman