Skip to content

Commit

Permalink
Merge pull request #7 from morka17/ft/eks
Browse files Browse the repository at this point in the history
update readme
  • Loading branch information
morka17 committed Jul 12, 2023
2 parents feaf889 + 2b5a7a2 commit 679b12b
Show file tree
Hide file tree
Showing 13 changed files with 467 additions and 45 deletions.
58 changes: 35 additions & 23 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
@@ -1,43 +1,55 @@
# # This workflow will build a golang project
# # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-go

# name: Deploy to production
# name: Deploy to production

# on:
# push:
# branches: [ "main" ]

# branches: [ release ]

# jobs:

# build:
# deploy:
# name: Build image
# runs-on: ubuntu-latest

# steps:
# - name: Check out code
# uses: actions/checkout@v3

# - name: Configure AWS credentials
# uses: aws-actions/configure-aws-credentials@v2
# - name: Check out code
# uses: actions/checkout@v2

# - name: Install kubectl
# uses: azure/setup-kubectl@v1
# with:
# version: 'v1.21.3'
# id: install

# - name: Configure AWS credentials
# uses: aws-actions/configure-aws-credentials@v1
# with:
# aws-access-key-id: ${{secrets.AWS_ACCESS_KEY_ID}}
# aws-secret-access-key: ${{secrets.AWS_SECRET_ACCESS_KEY}}
# aws-region: us-east-1
# aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
# aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
# aws-region: eu-west-1

# - name: Login to Amazon ECR Private
# - name: Login to Amazon ECR
# id: login-ecr
# uses: aws-actions/amazon-ecr-login@v1

# - name: Load secrets and save to app.env
# run: aws secretsmanager get-secret-value --secret-id shiny-bank --query SecretString --output text | jq -r 'to_entries|map("\(.key)=\(.value)")|.[]' > app.env

# run: aws secretsmanager get-secret-value --secret-id shiny_bank --query SecretString --output text | jq -r 'to_entries|map("\(.key)=\(.value)")|.[]' > app.env

# - name: Build, tag, and push docker image to Amazon ECR
# - name: Build, tag, and push image to Amazon ECR
# env:
# REGISTRY: ${{ steps.login-ecr.outputs.registry }}
# REPOSITORY: shinybank
# ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
# ECR_REPOSITORY: shinybank
# IMAGE_TAG: ${{ github.sha }}
# run: |
# docker build -t $REGISTRY/$REPOSITORY:$IMAGE_TAG .
# docker push $REGISTRY/$REPOSITORY:$IMAGE_TAG
# docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG -t $ECR_REGISTRY/$ECR_REPOSITORY:latest .
# docker push -a $ECR_REGISTRY/$ECR_REPOSITORY

# - name: Update kube config
# run: aws eks update-kubeconfig --name shiny-bank --region eu-west-2

# - name: Deploy image to Amazon EKS
# run: |
# kubectl apply -f eks/aws-auth.yaml
# kubectl apply -f eks/deployment.yaml
# kubectl apply -f eks/service.yaml
# kubectl apply -f eks/issuer.yaml
# kubectl apply -f eks/ingress.yaml
11 changes: 11 additions & 0 deletions eks/aws-auth.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: aws-auth
namespace: kube-system
data:
mapUsers: |
- userarn: arn
username: github-ci
groups:
- system:masters
22 changes: 22 additions & 0 deletions eks/deployment.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: shiny-bank-api-deployment
labels:
app: shiny-bank-api
spec:
replicas: 2
selector:
matchLabels:
app: shiny-bank-api
template:
metadata:
labels:
app: shiny-bank-api
spec:
containers:
- name: shiny-bank-api
image: <Image>
imagePullPolicy: Always
ports:
- containerPort: 8080
33 changes: 33 additions & 0 deletions eks/ingress.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
name: nginx
spec:
controller: k8s.io/ingress-nginx
---

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: shiny-bank-ingress
annotations:
cert-manager.io/cluster-issuer: letsencrypt
spec:
ingressClassName: nginx
rules:
- host: "api.shiny-bank.org"
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: shiny-bank-api-service
port:
number: 80

tls:
- hosts:
- api.shiny-bank.org
secretName: shiny-bank-api-cert

16 changes: 16 additions & 0 deletions eks/issuer.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt
spec:
acme:
email: techschool.guru@gmail.com
server: https://acme-v02.api.letsencrypt.org/directory
privateKeySecretRef:
# Secret resource that will be used to store the account's private key.
name: letsencrypt-account-private-key
# Add a single challenge solver, HTTP01 using nginx
solvers:
- http01:
ingress:
class: nginx
14 changes: 14 additions & 0 deletions eks/service.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
apiVersion: v1
kind: Service
metadata:
name: shiny-bank-api-service
spec:
selector:
app: shiny-bank-api
ports:
- protocol: TCP
port: 80
targetPort: 8080
type: ClusterIP


62 changes: 60 additions & 2 deletions readme.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,63 @@

### Postgres

# To Run this project

```json
Docker compose up
```



# OVERVIEW OF THIS PROJECT
### Here are some of the things that I have dene in this project:
> - I've done a lot of work on the database layer. This is important, as the database is the foundation of any application.
>- I've also implemented a number of security features, such as JWT and PASETO tokens, authentication middleware, and authorization rules. This is important for ensuring the security of your application.
>- I've used a number of different technologies, such as Go, Postgres, Gin, gRPC, Swagger, and Redis. This shows my expertise with a wide range of technologies and can use them to build a production-ready application
>- I've also automated a number of tasks, such as building and pushing Docker images, deploying to Kubernetes, and issuing TLS certificates. This shows that I'm using modern DevOps practices to build and deploy your application.

# Project breakdown
1. Designed a database schema and generated SQL code using diagram.io
2. Implemented migrations
3. Generated CRUD code for Golang using SQL for Postgres
4. Efficiently handled database transaction locks and deadlocks
5. Came up with an efficient strategy for deadlock avoidance in Golang
6. Set up Github Actions for Golang + Postgres to run automated tests
7. Implemented a RESTful HTTP API using Gin
8. Ran a mock database for testing the HTTP API in Go and achieved 100%
9. test coverage
10. Implemented a transfer money API with a custom parameters validator
11. Implemented a JWT and PASETO token
12. Implemented a user session manager with refresh token
13. Built a minimal Golang Docker image using a multi-stage Dockerfile
14. Introduced gRPC to the project
15. Defined a gRPC API and generated Go code from protobuf
16. Implemented the Golang gRPC server for the API
17. Integrated the gRPC API to create and manage users
18. Made the API compatible with both HTTP and gRPC requests
19. Automated the generation and serving of Swagger documentation from the
20. Go server using OpenAPI
21. Implemented a validator for gRPC parameters and sent friendly error messages
22. Added authorization to protect the gRPC API
23. Implemented structured logging for the C APIs
24. Implemented a HTTP logger middleware
25. Integrated a background worker with Redis and asynq for the email server
26. Handled all possible errors and printed logs for Asynq
27. Implemented the send and verification email with Gomail
28. Wrote tests for the gRPC API that requires authentication
29. Implemented automatic building and pushing of the Docker image to AWS ECR with Github Actions
30. Created a Postgres database on AWS RDS
31. Stored and retrieved production secrets with AWS Secrets Manager
32. Created an EKS cluster on AWS
33. Deployed the API_BANK to a Kubernetes cluster on AWS EKS
34. Registered a domain and set up a record in Route53
35. Used ingress to route traffic to different services in Kubernetes
36. Implemented an automatic issuance of TLS certificates in Kubernetes with Let'sencrypt
37. Finally, automated deployment to the internet (EKS) with Github Actions



<!-- ### Postgres
### Create a migration
Expand Down Expand Up @@ -38,4 +96,4 @@ migrate create -ext sql -dir db/migration -seq init_schema
https://dbdocs.io/joshuamorka4/shiny_bank_project?schema=public&view=relationships&table=accounts
### Mock Database
### Mock Database -->
6 changes: 3 additions & 3 deletions src/db/sqlc/store_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ func TestTransferTx(t *testing.T) {
account2 := CreateRandomAccount(t)

// Run n concurrent transfer transactions
n := 2
n := 5
amount := int64(10)

errs := make(chan error)
Expand Down Expand Up @@ -139,13 +139,13 @@ func TestTransferTxDeadlock(t *testing.T) {
}

go func() {
transResult, err := store.TransferTx(context.Background(), TransferTxParams{
_, err := store.TransferTx(context.Background(), TransferTxParams{
FromAccountID: fromAccountID,
ToAccountID: toAccountID,
Amount: amount,
})

fmt.Printf("fromAccountID: %v ToAccountID: %v\n", transResult.FromAccount.Balance, transResult.ToAccount.Balance)


errs <- err
}()
Expand Down
1 change: 1 addition & 0 deletions src/gapi/authoration.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const (
func (server *Server) authorizeUser(ctx context.Context) (*token.Payload, error) {
md, ok := metadata.FromIncomingContext(ctx)
if !ok {

return nil, fmt.Errorf("missing metadata")
}

Expand Down
21 changes: 21 additions & 0 deletions src/gapi/main_test.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
package gapi

import (
"context"
"fmt"
"testing"
"time"

db "github.com/morka17/shiny_bank/v1/src/db/sqlc"
"github.com/morka17/shiny_bank/v1/src/token"
"github.com/morka17/shiny_bank/v1/src/utils"
"github.com/morka17/shiny_bank/v1/src/worker"
"github.com/stretchr/testify/assert"
"google.golang.org/grpc/metadata"
)

func newTestServer(t *testing.T, store db.Store, taskDistributor worker.TaskDistributor) *Server {
Expand All @@ -21,3 +25,20 @@ func newTestServer(t *testing.T, store db.Store, taskDistributor worker.TaskDist

return server
}


func newContextWithBearer(t *testing.T, tokenMaker token.Maker, username string, duration time.Duration) context.Context {

accessToken, _, err := tokenMaker.CreateToken(username, duration)
assert.NoError(t, err)

bearerToken := fmt.Sprintf("%s %s", authorizationBearer, accessToken)
md := metadata.MD{
authorization: []string{
bearerToken,
},
}
return metadata.NewIncomingContext(context.Background(), md)


}
4 changes: 4 additions & 0 deletions src/gapi/rpc_update_user.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package gapi
import (
"context"
"database/sql"
"log"
"time"

"google.golang.org/genproto/googleapis/rpc/errdetails"
Expand All @@ -16,6 +17,9 @@ import (
)

func (server *Server) UpdateUser(ctx context.Context, req *pb.UpdateUserRequest) (*pb.UpdateUserResponse, error) {
if ctx == nil {
log.Panic("NIl context")
}
authPayload, err := server.authorizeUser(ctx)
if err != nil {
return nil, unauthenticatedError(err)
Expand Down
Loading

0 comments on commit 679b12b

Please sign in to comment.