- Go version 1.21.9 or higher installed
- Docker installed
- Terraform - Never mind if you don't have it, we have done it for you
- SonarQube - https://sonarqube.werockstar.dev/
- ArgoCD - https://argocd.werockstar.dev/
- Health Check:
GET: api/v1/health
- Group 1
- Group 2
- Group 3
- Group 4
- Group 5
sequenceDiagram
Mobile App ->> HongJot API: Upload Image to S3 Bucket
activate Mobile App
HongJot API ->> S3 Bucket: Store Image
HongJot API ->> Mobile App: success
deactivate Mobile App
S3 Bucket ->> Lambda Function: (Event Trigger)
Lambda Function ->> Amazon Textract: Extract Text from Image
Amazon Textract ->> Lambda Function: Slip Expense info
Lambda Function ->> HongJot API: Send Slip Expense info
HongJot API ->> PostgreSQL Database: Store Expense info
Mobile App ->> HongJot API: Get Expense Summary (Spender Requests Summary) Retrieve Expense Summary
activate Mobile App
HongJot API ->> PostgreSQL Database: Get Expense Summary Data
PostgreSQL Database ->> HongJot API: Return Summary Data
HongJot API ->> Mobile App: Show Expense Summary Data
deactivate Mobile App
We have created the infrastructure by using Terraform. The infrastructure consists of the following:
Kubernetes Cluster (EKS)
- Managed Kubernetes ServicePostgreSQL (RDS)
- Relational Database (Managed Service)SonarQube
- Static Code Analysis- Github (see
.github/workflows
directory)- Github Action
- Github Container Registry
- ArgoCD - Continuous Delivery
- Cloudflare - DNS Management
- Create IAM account for
Terraform
- Authenticate with AWS
- Option 1:
aws configure
- Configure your AWS credentials with keypair - Option 2: Set environment variable
export AWS_ACCESS_KEY_ID=<KEY>
export AWS_SECRET_ACCESS_KEY=<SECRET>
- Option 1:
- Provision the infrastructure (ESK, RDS (Postgres), SonarQube, ArgoCD, Cloudflare, VPC)
cd infra/iac
terraform init
terraform apply
Terraform
will requirecloudflare
API key, you can get it from theCloudflare
dashboard- Option 1: Enter API token on Terraform prompt
- Option 2: Export environment variable that provide for Terraform
RDS
username, password, and database name- Option 1: Enter the value on Terraform prompt
- Option 2: Export environment variable that provide for Terraform
- And then Terraform will do things for you
- Waiting and enjoy your coffee
- Importantly, you need to destroy resources because it's not free 💰
terraform destroy
- Note: You can see the README.md in the
infra
directory for more information
- Fork
workshop-summer
repository and name it asworkshop-summer-<GROUP_NO>-<BATCH_NO>
(e.g.workshop-summer-group-1-b2
) - Enable Github Actions in the repository
- Replace the
<GROUP_NO>
pattern viaauto-replace-group.sh
- Setup project on
SonarQube
manually- Create project on
SonarQube
with the same name as the repository - Generate SonarQube token and create secret on Github named as
SONAR_TOKEN
- Add
SONAR_HOST_URL
secret on Github with the value of https://sonarqube.werockstar.dev
- Create project on
- Commit and push the changes to the repository
- View the
Github Actions
and see the workflow running - Observe analysis result on
SonarQube
dashboard
- Go to ArgoCD dashboard https://argocd.werockstar.dev/
- Setup GitOps สำหรับ Development
- กด
+ New App
แล้วใส่ข้อมูลดังนี้ - Application Name:
<GROUP_NO>-<BATCH_NO>-dev
(e.g.group-1-b2-dev
) - Project Name:
default
- SYNC POLICY:
Automatic
- Repository URL:
https://github.com/<your-github>/workshop-summer-<GROUP_NO>-<BATCH_NO>
- Revision:
main
- Path:
infra/gitops/dev
- Cluster URL:
https://kubernetes.default.svc
- กด
Create
มุมบนซ้าย - ภาวะณา
- กด
- Setup GitOps สำหรับ Production env
- กด
+ New App
แล้วใส่ข้อมูลดังนี้ - Application Name:
<GROUP_NO>-<BATCH_NO>-prod
(e.g.group-1-b2-prod
) - Project Name:
default
- SYNC POLICY:
Automatic
- Repository URL:
https://github.com/<your-github>/workshop-summer-<GROUP_NO>-<BATCH_NO>
- Revision:
main
- Path:
infra/gitops/prod
- Cluster URL:
https://kubernetes.default.svc
- กด
Create
มุมบนซ้าย
- กด
ใน Repository นี้เราใช้ Makefile ในการทำงานได้ ดังนั้นสามารถสั่งรันง่ายๆ ผ่าน make
ได้เลย
1.เริ่มต้นลองสั่งติดตั้ง dependencies ของ Go มาก่อน
go mod tidy
2.จากนั้น set environment variable โดยสร้าง file ใหม่ชื่อ .env
แล้ว copy content จาก .env.template
มา แล้วเปลี่ยน db:5432
เป็น localhost:5432
ENV=LOCAL
LOCAL_DATABASE_POSTGRES_URI=postgres://postgres:password@localhost:5432/hongjot?sslmode=disable
LOCAL_SERVER_PORT=8080
# Features Flags
LOCAL_ENABLE_CREATE_SPENDER=false
3.Export environment variable ด้วยเครื่องมืออย่าง direnv หรือจะใช้คำสั่งนี้ก็ได้
# Using source (.)
source .env
# or using export
export $(cat .env)
4.สร้าง PostgreSQL บน local machine ผ่าน docker-compose
ด้วยคำสั่ง
docker-compose up -d
5.จากนั้นสั่งรันได้เลย
make run
หรือถ้าใครใช้ Makefile ไม่ได้ก็ใช้คำสั่งตรงก็ได้ โดยเข้าไปดูแต่ละคำสั่งใน makefile
ได้เลย
go run main.go
เมื่อ Server ทำงานได้ควรจะสามารถเรียกจาก http://localhost:8080/api/v1/health ได้
make health
Checking the health of the server...
curl http://localhost:8080/api/v1/health
{"message":"api is ready and connected to database","status":"ok"}
โปรเจกนี้มี 2 ระดับคือ unit
, integration
รันได้ดังนี้
make test
Run ผ่าน Docker
make test-it-docker
Run ตรง
make test-it
หมายเหตุ: ตอนเขียน integration test ต้องตั้งชื่อเป็น format Test...IT
ไม่งั้นตอน run มันจะข้ามไป
pre-commit คือ framework ที่ใช้ run script (hooks) ก่อน commit หรือ push ผ่าน Git โดยให้ทำการติดตั้งตามคู่มือ จากนั้น run คำสั่ง
make setup-pre-commit
ทีนี้เวลาเรา commit หรือ push มันก็จะไป run คำสั่งต่าง ๆ ที่จะดักปัญหาก่อนไม่ให้ CI/CD pipeline ของเราพังนั่นเอง
Project นี้เราใช้ goose เป็น database migration tool โดย database script จะเก็บไว้อยู่ที่ directory migration
ตอนที่เราสร้าง script ใหม่ก็สามารถ run คำสั่ง
make new-migration name=0X_name_with_underscore
หรือจะสร้างโดย copy file จาก template ชื่อ 00_example.sql.template
แล้วสร้าง file ใหม่โดยต้องตั้งชื่อเป็น 0X_<script_name_with_underscore>.sql
ก็ได้
Migration file ใหม่ที่ได้จะอยู่ที่ directory migration
ที่มีใส่ content ดังนี้
-- +goose Up
-- +goose StatementBegin
SELECT 'up SQL query';
-- +goose StatementEnd
-- +goose Down
-- +goose StatementBegin
SELECT 'down SQL query';
-- +goose StatementEnd
จากนั้นก็ทำการเขียน SQL statement ที่ต้องการ
เวลาเรา run server ขึ้นมามันจะทำการ apply migration ให้อัตโนมัติ แต่ในส่วนของ integration test ต้องเขียน apply และ rollback ด้วย ประมาณนี้
import (
"database/sql"
"testing"
"github.com/KKGo-Software-engineering/workshop-summer/config"
"github.com/KKGo-Software-engineering/workshop-summer/migration"
_ "github.com/lib/pq"
)
func TestSomethingIT(t *testing.T) {
t.Run("create spender succesfully when feature toggle is enable", func(t *testing.T) {
sql, err := getTestDatabaseFromConfig()
if err != nil {
t.Error(err)
}
migration.ApplyMigrations(sql)
defer migration.RollbackMigrations(sql)
// เขียน test ต่อได้เลย
})
}
func getTestDatabaseFromConfig() (*sql.DB, error) {
cfg := config.Parse("DOCKER")
sql, err := sql.Open("postgres", cfg.PostgresURI())
if err != nil {
return nil, err
}
return sql, nil
}