Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
name: Build
on:
push:
branches:
- master
- develop
pull_request:
types: [opened, synchronize, reopened]
jobs:
docker-build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Build the Docker image
run: cd app && docker build . -t ${{ secrets.IMAGE_NAME }}:$(date +%s)
sonarqube:
name: Sonarqube
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up JDK 11
uses: actions/setup-java@v3
with:
distribution: 'temurin'
java-version: 11
- name: Cache SonarCloud packages
uses: actions/cache@v3
with:
path: ~/.sonar/cache
key: ${{ runner.os }}-sonar
restore-keys: ${{ runner.os }}-sonar
- name: Cache Gradle packages
uses: actions/cache@v3
with:
path: ~/.gradle/caches
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }}
restore-keys: ${{ runner.os }}-gradle
- name: Build and analyze
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
run: ./gradlew build sonarqube --info
64 changes: 52 additions & 12 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,15 +1,55 @@
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib
build
.gradle
.vscode
.idea

# Test binary, built with `go test -c`
*.test
*.log
*.jar
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar

# Output of the go coverage tool, specifically when used with LiteIDE
*.out
# go
vendor
echo
main

# Dependency directories (remove the comment below to include it)
# vendor/
# MAC
.DS_Store

# internal
*internal*

# k8s template output
# go-echo-api-onepod-template.yaml
# go-echo-api-template.yaml
**/go-echo-api-onepod.yaml
**/go-echo-api.yaml

# test
2023*

# GCP
## .sa .readonly-sa
.*sa
## google-github-actions/auth@v1
gha-creds-*.json

# terraform
.terraform
*.tfstate
*.tfstate.*
crash.log
crash.*.log
*.tfvars
*.tfvars.json
override.tf
override.tf.json
*_override.tf
*_override.tf.json
.terraformrc
terraform.rc
*.hcl
198 changes: 197 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,197 @@
# gcp-golang-performance-test
# Performance testing on GKE using labstack eacho application

[![Build](https://github.com/DevSecOpsSamples/gcp-golang-performance-test/actions/workflows/build.yml/badge.svg?branch=master)](https://github.com/DevSecOpsSamples/gcp-golang-performance-test/actions/workflows/build.yml)
[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=DevSecOpsSamples_gcp-golang-performance-test&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=DevSecOpsSamples_gcp-golang-performance-test) [![Lines of Code](https://sonarcloud.io/api/project_badges/measure?project=DevSecOpsSamples_gcp-golang-performance-test&metric=ncloc)](https://sonarcloud.io/summary/new_code?id=DevSecOpsSamples_gcp-golang-performance-test)

Performance testing on GKE using the https://echo.labstack.com application.


## Table of Contents

- [1. Create a GKE cluster](#1-create-a-gke-cluster)
- [2. Deploy two applications for checking the performance per Pod and scaling](#2-deploy-two-applications-for-checking-the-performance-per-pod-and-scaling)
- [2.1. Deploy for performance of one Pod](#21-deploy-for-performance-of-one-pod)
- [2.2. Deploy for Scaling Test](#22-deploy-for-scaling-test)
- [3. Performance Testing](#3-performance-testing)
- [3.1. Install the Taurus](#31-install-the-taurus)
- [3.2. Test for performance of one Pod](#32-test-for-performance-of-one-pod)
- [3.3. Test with auto scaling](#33-test-with-auto-scaling)
- [Cleanup](#6-cleanup)

---

## Prerequisites

### Installation

- [Install the gcloud CLI](https://cloud.google.com/sdk/docs/install)
- [Install kubectl and configure cluster access](https://cloud.google.com/kubernetes-engine/docs/how-to/cluster-access-for-kubectl)
- [Installing and Upgrading for the Taurus ](https://gettaurus.org/install/Installation/)

### Set environment variables

```bash
COMPUTE_ZONE="us-central1"
# replace with your project
PROJECT_ID="sample-project"
```

### Set GCP project

```bash
gcloud config set project ${PROJECT_ID}
gcloud config set compute/zone ${COMPUTE_ZONE}
```

---

## 1. Create a GKE cluster

Create an Autopilot GKE cluster. It may take around 9 minutes.

```bash
gcloud container clusters create-auto sample-cluster --region=${COMPUTE_ZONE}
gcloud container clusters get-credentials sample-cluster
```

## 2. Deploy two applications for checking the performance per Pod and scaling

Build and push to GCR:

```bash
cd app
docker build -t go-echo-api . --platform linux/amd64
docker tag go-echo-api:latest gcr.io/${PROJECT_ID}/go-echo-api:latest

gcloud auth configure-docker
docker push gcr.io/${PROJECT_ID}/go-echo-api:latest
```

```bash
kubectl get namespaces

kubectl create namespace echo-test
```

Two deployments may take around 5 minutes to create a load balancer, including health checking.

## 2.1. Deploy for performance of one Pod

To check request per seconds(RPS) WITHOUT scaling, create and deploy K8s Deployment, Service, HorizontalPodAutoscaler, Ingress, and GKE BackendConfig using the [go-echo-api-onepod-template.yaml](app/go-echo-api-onepod-template.yaml) template file:

```bash
sed -e "s|<project-id>|${PROJECT_ID}|g" go-echo-api-onepod-template.yaml > go-echo-api-onepod.yaml
cat go-echo-api-onepod.yaml

kubectl get namespaces
kubectl apply -f go-echo-api-onepod.yaml -n echo-test --dry-run=client
```

Confirm Pod logs and configuration after deployment:

```bash
kubectl logs -l app=go-echo-api-onepod -n echo-test

kubectl describe pods -n echo-test

kubectl get ingress go-echo-api-onepod-ingress -n echo-test
```

## 2.2. Deploy for Scaling Test

To check request per seconds(RPS) with scaling, create and deploy K8s Deployment, Service, HorizontalPodAutoscaler, Ingress, and GKE BackendConfig using the [go-echo-api-template.yaml](app/go-echo-api-template.yaml) template file:

```bash
sed -e "s|<project-id>|${PROJECT_ID}|g" go-echo-api-template.yaml > go-echo-api.yaml
cat go-echo-api.yaml

kubectl apply -f go-echo-api.yaml -n echo-test --dry-run=client
```

```bash
kubectl apply -f go-echo-api.yaml -n echo-test
```

Confirm Pod logs and configuration after deployment:

```bash
kubectl logs -l app=go-echo-api -n echo-test

kubectl describe pods -n echo-test

kubectl get ingress go-echo-api-ingress -n echo-test
```

Confirm that response of `/` API.

```bash
LB_IP_ADDRESS=$(gcloud compute forwarding-rules list | grep go-echo-api | awk '{ print $2 }')
echo ${LB_IP_ADDRESS}
```

```bash
curl http://${LB_IP_ADDRESS}/
```

## 3. Performance Testing

### 3.1. Install the Taurus

https://gettaurus.org/install/Installation/

```bash
sudo apt-get update -y
sudo apt-get install python3 default-jre-headless python3-tk python3-pip python3-dev libxml2-dev libxslt-dev zlib1g-dev net-tools -y
sudo python3 -m pip install bzt
sudo apt-get install htop -y
```

### 3.2. Test for performance of one Pod

```bash
cd test
# test with 300 threads and connection:close option
bzt echo-bzt-onepod.yaml
```

[test/echo-bzt-onepod.yaml](./test/echo-bzt-onepod.yaml)

```bash
kubectl describe hpa go-echo-api-onepod-hpa -n echo-test

kubectl get hpa go-echo-api-onepod-hpa -n echo-test -w
```

### 3.3. Test with auto scaling

```bash
cd test
# test with 2000 threads and connection:close option
bzt echo-bzt.yaml
```

[test/echo-bzt.yaml](./test/echo-bzt.yaml)

```bash
kubectl describe hpa go-echo-api-hpa -n echo-test

kubectl get hpa go-echo-api-hpa -n echo-test -w
```

## Cleanup

```bash
kubectl scale deployment go-echo-api-onepod -n echo-test --replicas=0
kubectl scale deployment go-echo-api -n echo-test --replicas=0

kubectl delete -f app/go-echo-api-onepod.yaml -n echo-test
kubectl delete -f app/go-echo-api.yaml -n echo-test
```

## References

- https://echo.labstack.com

- [Cloud SDK > Documentation > Reference > gcloud container clusters](https://cloud.google.com/sdk/gcloud/reference/container/clusters)

- [Google Kubernetes Engine (GKE) > Documentation > Guides > GKE Ingress for HTTP(S) Load Balancing](https://cloud.google.com/kubernetes-engine/docs/concepts/ingress)
3 changes: 3 additions & 0 deletions app/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
vendor
echo
main
20 changes: 20 additions & 0 deletions app/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
FROM golang:1.18 AS builder

RUN mkdir /app

COPY ./go.mod /app/
COPY ./go.sum /app/
COPY ./main.go /app/
WORKDIR /app

RUN go install
RUN go build main.go

RUN adduser go
RUN chown go ./main

USER go

EXPOSE 8000

CMD ["./main"]
11 changes: 11 additions & 0 deletions app/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
build:
go build ./...

install:
go install -mod=vendor -v ./...

test:
go test ./...

clean:
go clean ./...
8 changes: 8 additions & 0 deletions app/build-multi-arch.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/bin/bash
set -e

echo "PROJECT_ID: ${PROJECT_ID}"

docker buildx ls
docker buildx create --name builder --use builder
time docker buildx build -t gcr.io/${PROJECT_ID}/go-echo-api:latest . --platform linux/amd64,linux/arm/v7 --push
12 changes: 12 additions & 0 deletions app/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/bin/bash
set -e

echo "PROJECT_ID: ${PROJECT_ID}"

docker build -t go-echo-api . --platform linux/amd64
docker tag go-echo-api:latest gcr.io/${PROJECT_ID}/go-echo-api:latest
docker push gcr.io/${PROJECT_ID}/go-echo-api:latest

# docker run -it -p 8000:8000 go-echo-api:latest

# docker run -it -p 8000:8000 gcr.io/${PROJECT_ID}/go-echo-api:latest
Loading