Back to rankings

learning-cloud-native-go/myapp

Go

πŸš€ Dockerized Go API application with DB migrations, GitOps and Kubernetes Kustomize based CD

golangdockermicroservicegokubernetesapiargocddistrolessistiokustomizeschema-migrations
Star Growth
Stars
1.1k
Forks
79
Weekly Growth
β€”
Issues
1
5001k
Oct 2019Jan 2022Apr 2024Jul 2026
ArtifactsGo Modulesgo get github.com/learning-cloud-native-go/myapp
README

buymeacoffee

Learning Cloud Native Go - myapp

πŸ”‹ Batteries Included

  • Use of Go linters, Docker, Docker Compose, Alpine development images, and Distroless production images.
  • Use of GORM CLI to generate Go generics-based database repositories.
  • Use of Goose to build a DB migration CLI with embedded migrations.
  • Use of Validator.v10 to validate forms via Go generics-based, fail-fast validation middleware.
  • Use of Zerolog to generate request logs and centralized Syslog logging.
  • Use of Swag.v2 to generate OpenAPI v3 specifications.
  • Use of GitHub Actions to run linters and tests, and to build and push production images to the registry.
  • Use of GitOps with ArgoCD to automate declarative environment orchestration and application lifecycle management.
Environment Go 1.26 Image Size Postgres v18 Image Size
Development 800 MB 300MB
Production 30 MB

πŸ“Ÿ Available Commands

$ just
πŸš€MYAPP
    help                    # List available commands
    install                 # Install development tools
    go-run cmd="app"        # Run a specific cmd (defaults to app)
    go-run-migrate cmd="up" # Run database migrations (defaults to up)
    build                   # Run docker compose build
    up cmd=""               # Run docker compose up
    down                    # Run docker compose down
    lint                    # Run lints using gofumpt, go vet, staticcheck and govulncheck
    test                    # Run tests
    gen                     # Run go generate for all packages
    gen-openapi             # Generate openapi v3 specification using swag v2
    gen-gorm-repos          # Generate gorm repositories using gorm cli

πŸ›¬ Endpoints

Name HTTP Method Route
Health GET /livez
List Books GET /v1/books
Create Book POST /v1/books
Read Book GET /v1/books/{id}
Update Book PUT /v1/books/{id}
Delete Book DELETE /v1/books/{id}

πŸ—„οΈ Database Design

Column Name Datatype Not Null Primary Key
id UUID βœ… βœ…
title TEXT βœ…
author TEXT βœ…
published_date DATE βœ…
image_url TEXT
description TEXT
created_at TIMESTAMP βœ…
updated_at TIMESTAMP βœ…

⛔️ Form Validation

{
  "errors": {
    "title": "This is a required field",
    "author": "This can only contain alphabetic and space characters",
    "published_date": "This must be a valid date",
    "image_url": "This must be a valid URL"
  }
}

πŸ“ Request Logs and Centralized Syslog Logging

db-1  | 2018-01-10 01:00:00.000 +08 [1] LOG:  database system is ready to accept connections
Container myapp-db-1 Healthy
app-1  | 2018/01/10 01:00:00 OK   00001_create_books_table.sql (2.21ms)
app-1  | 2018/01/10 01:00:00 goose: successfully migrated database to version: 1
app-1  |
app-1  | {"level":"info","time":"2018-01-10T02:00:00+08:00","message":"Starting server :8080"}
app-1  |
app-1  | [7.218ms] [rows:1] INSERT INTO books (id, created_at, updated_at, title, author, published_date, image_url, description) VALUES ('38ba23d1-9565-40ed-b781-aacd2f84018d', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, 'Death Note', 'Light Yagami', '2006-10-04 00:00:00', 'https://static.wikia.nocookie.net/deathnote/images/9/94/A_Death_Note.jpg', 'A supernatural volume dropped into the human world by the Shinigami Ryuk') RETURNING *
app-1  | {"level":"info","request_id":"d5mq7oi6hkls7397s43g","received_time":"2018-01-10T03:00:00+08:00","method":"POST","url":"/v1/books","header_size":135,"body_size":0,"agent":"yaak","referer":"","proto":"HTTP/1.1","remote_ip":"192.168.65.1","server_ip":"172.19.0.3","status":201,"resp_header_size":47,"resp_body_size":296,"latency":8.307,"time":"2018-01-10T03:00:00+08:00"}
app-1  | {"level":"info","request_id":"d5mq7oi6hkls7397s43g","id":"38ba23d1-9565-40ed-b781-aacd2f84018d","time":"2018-01-10T03:00:00+08:00","message":"new book created"}
app-1  |
app-1  | [2.541ms] [rows:1] SELECT * FROM books WHERE id = '38ba23d1-9565-40ed-b781-aacd2f84018d'
app-1  | {"level":"info","request_id":"d5mqa6a6hkls7397s44g","received_time":"2018-01-10T04:00:00+08:00","method":"GET","url":"/v1/books/38ba23d1-9565-40ed-b781-aacd2f84018d","header_size":82,"body_size":0,"agent":"yaak","referer":"","proto":"HTTP/1.1","remote_ip":"192.168.65.1","server_ip":"172.19.0.3","status":200,"resp_header_size":47,"resp_body_size":296,"latency":2.674625,"time":"2018-01-10T04:00:00+08:00"}
app-1  |
app-1  | [3.744ms] [rows:1] UPDATE books SET updated_at=CURRENT_TIMESTAMP, title='Death Note', author='Misa Amane', published_date='2004-11-04 00:00:00', image_url='https://static.wikia.nocookie.net/deathnote/images/9/94/A_Death_Note.jpg', description='Light Yagami''s buried notebook' WHERE id = '38ba23d1-9565-40ed-b781-aacd2f84018d' RETURNING *
app-1  | {"level":"info","request_id":"d5mqesa6hkls7397s45g","id":"38ba23d1-9565-40ed-b781-aacd2f84018d","time":"2018-01-10T05:00:00+08:00","message":"book updated"}
app-1  | {"level":"info","request_id":"d5mqesa6hkls7397s45g","received_time":"2018-01-10T05:00:00+08:00","method":"PUT","url":"/v1/books/38ba23d1-9565-40ed-b781-aacd2f84018d","header_size":135,"body_size":0,"agent":"yaak","referer":"","proto":"HTTP/1.1","remote_ip":"192.168.65.1","server_ip":"172.19.0.3","status":200,"resp_header_size":47,"resp_body_size":252,"latency":4.018875,"time":"2018-01-10T05:00:00+08:00"}
app-1  |
app-1  | [3.035ms] [rows:1] DELETE FROM books WHERE id = '38ba23d1-9565-40ed-b781-aacd2f84018d' RETURNING true
app-1  | {"level":"info","request_id":"d5mqfgi6hkls7397s460","received_time":"2018-01-10T06:00:00+08:00","method":"DELETE","url":"/v1/books/38ba23d1-9565-40ed-b781-aacd2f84018d","header_size":82,"body_size":0,"agent":"yaak","referer":"","proto":"HTTP/1.1","remote_ip":"192.168.65.1","server_ip":"172.19.0.3","status":200,"resp_header_size":47,"resp_body_size":0,"latency":3.265,"time":"2018-01-10T06:00:00+08:00"}
app-1  | {"level":"info","request_id":"d5mqfgi6hkls7397s460","id":"38ba23d1-9565-40ed-b781-aacd2f84018d","time":"2018-01-10T06:00:00+08:00","message":"book deleted"}
app-1  |
app-1  | [2.573ms] [rows:1] SELECT * FROM books LIMIT 10 OFFSET 0
app-1  | {"level":"info","request_id":"d5mq9gi6hkls7397s440","received_time":"2018-01-10T07:00:00+08:00","method":"GET","url":"/v1/books","header_size":82,"body_size":0,"agent":"yaak","referer":"","proto":"HTTP/1.1","remote_ip":"192.168.65.1","server_ip":"172.19.0.3","status":200,"resp_header_size":47,"resp_body_size":298,"latency":2.926916,"time":"2018-01-10T07:00:00+08:00"}
app-1  |
app-1  |
app-1  | [1.661ms] [rows:0] DELETE FROM books WHERE id = '38ba23d1-9565-40ed-b781-aacd2f84018d' RETURNING true
app-1  | {"level":"info","request_id":"d5mrj8ppsdvs73dkfct0","received_time":"2018-02-01T01:00:00+08:00","method":"DELETE","url":"/v1/books/38ba23d1-9565-40ed-b781-aacd2f84018d","header_size":82,"body_size":0,"agent":"yaak","referer":"","proto":"HTTP/1.1","remote_ip":"192.168.65.1","server_ip":"172.19.0.3","status":404,"resp_header_size":47,"resp_body_size":0,"latency":1.80125,"time":"2018-02-01T01:00:00+08:00"}
app-1  | [1.384ms] [rows:0] UPDATE books SET updated_at=CURRENT_TIMESTAMP, title='Death Note', author='Misa Amane', published_date='2004-11-04 00:00:00', image_url='https://static.wikia.nocookie.net/deathnote/images/9/94/A_Death_Note.jpg', description='Light Yagami''s buried notebook' WHERE id = '38ba23d1-9565-40ed-b781-aacd2f84018d' RETURNING *
app-1  | {"level":"info","request_id":"d5mqjmhqvtmc73foh3dg","received_time":"2018-02-02T08:00:00:00","method":"PUT","url":"/v1/books/38ba23d1-9565-40ed-b781-aacd2f84018d","header_size":135,"body_size":0,"agent":"yaak","referer":"","proto":"HTTP/1.1","remote_ip":"192.168.65.1","server_ip":"172.19.0.3","status":404,"resp_header_size":47,"resp_body_size":0,"latency":1.576,"time":"2018-02-02T08:00:00+08:00"}

// πŸ’― Real logs collected locally but with few rearrangements to make it easier to read.

πŸ—‚οΈ Project Folder Structure

β”œβ”€β”€ compose.yml
β”œβ”€β”€ Dockerfile
β”‚
β”œβ”€β”€ openapi-v3.yaml
β”‚
β”œβ”€β”€ app
β”‚   β”œβ”€β”€ book
β”‚   β”‚   β”œβ”€β”€ bookrepo      # πŸ’‘generated with gorm-cli via the interface in book/repository.go
β”‚   β”‚   β”‚   └── repository.go
β”‚   β”‚   β”œβ”€β”€ form_util.go
β”‚   β”‚   β”œβ”€β”€ handler.go
β”‚   β”‚   └── repository.go
β”‚   └── router
β”‚       └── router.go
β”œβ”€β”€ form    # πŸ’‘Form validation middleware rely on this and pkg folder only
β”‚   └── book.go
β”œβ”€β”€ model
β”‚   └── book.go
β”‚
β”œβ”€β”€ config
β”‚   └── config.go
β”‚
β”œβ”€β”€ cmd   # πŸ’‘Entrypoint for app and migrate executables
β”‚   β”œβ”€β”€ app
β”‚   β”‚   └── main.go
β”‚   └── migrate
β”‚       β”œβ”€β”€ main.go
β”‚       └── migrations
β”‚           └── 00001_create_books_table.sql
β”‚
└── pkg (middleware, logger, validator, ctxutil, paramsutil, errors)

πŸ—οΈ ArgoCD and Kustomize

ArgoCD and Kustomize based cloud native IaC & GitOps setup.

πŸ’‘ Consider moving to a Hub-and-Spoke architecture for Argo CD, combined with a separate repository strategy.

└── k8s
    β”‚
    β”œβ”€β”€ bootstrap
    β”‚   β”œβ”€β”€ argocd
    β”‚   └── argocd-config
    β”‚       β”œβ”€β”€ clusters
    β”‚       β”œβ”€β”€ projects
    β”‚       └── applications
    β”‚
    β”œβ”€β”€ platform
    β”‚   β”œβ”€β”€ metrics-server
    β”‚   β”œβ”€β”€ gateway-api
    β”‚   β”œβ”€β”€ istio-ambient
    β”‚   └── cloudnative-pg
    β”‚
    β”œβ”€β”€ components
    β”‚   └── myapp-db
    β”œβ”€β”€ services
    β”‚   β”œβ”€β”€ base
    β”‚   β”‚   └── myapp
    β”‚   └── overlays
    β”‚       β”œβ”€β”€ dev
    β”‚       β”œβ”€β”€ prod
    β”‚       └── stage
    β”‚
    └── gateways

πŸ’‘ Sample Kind Dev Cluster

kind create cluster --name dev
kubectl apply -k k8s/bootstrap/argocd
kubectl apply -k k8s/bootstrap/argocd-config
kubectl apply -k k8s/platform/istio-ambient
kubectl apply -k k8s/platform/gateway-api
kubectl apply -k k8s/gateways
kubectl port-forward svc/shared-gateway-dev-istio -n istio-ingress 8081:8081 # πŸ’‘ Shared Dev Gateway
curl -X GET 'localhost:8081/myapp/v1/books' --header 'Accept: application/json'

kubectl port-forward svc/argocd-server -n argocd 8080:443 # πŸ’‘ ArgoCD Dashboard(admin/password)
Related repositories
practical-tutorials/project-based-learning

Curated list of project-based tutorials

PythonPyPIMIT Licensetutorialproject
274.6k35.4k
avelino/awesome-go

A curated list of awesome Go frameworks, libraries and software

GoGo ModulesMIT Licensegolanggolang-library
awesome-go.com
178.8k13.4k
ollama/ollama

Get up and running with Kimi-K2.6, GLM-5.2, MiniMax, DeepSeek, gpt-oss, Qwen, Gemma and other models.

GoGo ModulesMIT Licensellamallm
ollama.com
176.6k17.1k
golang/go

The Go programming language

GoGo ModulesBSD 3-Clause "New" or "Revised" Licenseprogramming-languagelanguage
go.dev
135.3k19.3k
caddyserver/caddy

Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS

GoGo ModulesApache License 2.0goweb-server
caddyserver.com
74.2k4.8k
unionlabs/union

The trust-minimized, zero-knowledge bridging protocol, designed for censorship resistance, extremely high security, and usage in decentralized finance.

Rustcrates.ioApache License 2.0blockchaincosmos
union.build
73.9k3.9k
moby/moby

The Moby Project - a collaborative project for the container ecosystem to assemble container-based systems

GoGo ModulesApache License 2.0dockercontainers
mobyproject.org
71.9k19k
nektos/act

Run your GitHub Actions locally πŸš€

GoGo ModulesMIT Licensegithub-actionsgolang
nektosact.com
71.2k2k
traefik/traefik

The Cloud Native Application Proxy

GoGo ModulesMIT Licensemicroservicedocker
traefik.io
64.1k6.1k
santifer/career-ops

Open-source AI job search: scan job portals, evaluate listings with a structured A-F rubric into a 1.0-5.0 score, tailor your CV, track applications β€” runs locally in your AI coding CLI (Claude Code, Codex, OpenCode, Antigravity…)

JavaScriptnpmMIT Licenseai-agentanthropic
career-ops.org
60.9k12k
pocketbase/pocketbase

Open Source realtime backend in 1 file

GoGo ModulesMIT Licenseauthenticationbackend
pocketbase.io
60.1k3.6k
rclone/rclone

"rsync for cloud storage" - Google Drive, S3, Dropbox, Backblaze B2, One Drive, Swift, Hubic, Wasabi, Google Cloud Storage, Azure Blob, Azure Files, Yandex Files

GoGo ModulesMIT Licensegolanggo
rclone.org
58.6k5.2k