Skip to content

Commit

Permalink
[SPD-6446] adding k8s example for node app (#11)
Browse files Browse the repository at this point in the history
  • Loading branch information
kenahrens authored Nov 14, 2023
1 parent f46875a commit fd605ba
Show file tree
Hide file tree
Showing 30 changed files with 403 additions and 35 deletions.
1 change: 1 addition & 0 deletions .github/workflows/main.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,4 @@ jobs:
run: |
gcloud auth configure-docker
cd java && make docker-multi
cd ../node && make docker-multi
2 changes: 1 addition & 1 deletion java/Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
VERSION?=1.0.3
VERSION?=1.0.4
REGISTRY?=gcr.io/speedscale-demos/java-server:${VERSION}
NAMESPACE?=default

Expand Down
2 changes: 1 addition & 1 deletion java/client/client
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ random-sleep () {

i=0
while true; do
if [[ $((i % 100)) == 0 ]]; then
if [[ $((i % 5)) == 0 ]]; then
login
rsaToken
fi
Expand Down
2 changes: 1 addition & 1 deletion java/manifest.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ spec:
spec:
containers:
- name: java-server
image: gcr.io/speedscale-demos/java-server:1.0.3
image: gcr.io/speedscale-demos/java-server:1.0.4
imagePullPolicy: Always
readinessProbe:
httpGet:
Expand Down
8 changes: 8 additions & 0 deletions node/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
VERSION?=1.0.4
REGISTRY?=gcr.io/speedscale-demos/node-server:${VERSION}
NAMESPACE?=default

.PHONY: docker-multi
docker-multi:
@echo "Building and pushing multi-arch Docker image"
@docker buildx build --push --platform linux/amd64,linux/arm64 --tag ${REGISTRY} .
14 changes: 8 additions & 6 deletions node/README.md
Original file line number Diff line number Diff line change
@@ -1,28 +1,30 @@
# Great App: demo-node
# Great App: node-server

This app has a couple of different endpoints:
* `/` returns a generic response
* `/nasa` will get the NASA picture of the day (as JSON)
* `/events` reads some GitHub events
* `/space` will call the SpaceX launches API
* `/nasa` will get the NASA picture of the day (as JSON)
* `/bin` calls `httpbin`

![demo-node](img/demo-node.png)
![node-server](img/node-server.png)

After you get the application running on your machine, you're going to capture traffic with Speedscale like so:

![demo-node-capture](img/demo-node-capture.png)
![node-server-capture](img/node-server-capture.png)

And once you're able to process the traffic properly, you are going to replay the tests and mocks like so which lets you run numerous different scenarios and isolate yourself from the backend dependencies.

![demo-node-replay](img/demo-node-replay.png)
![node-server-replay](img/node-server-replay.png)

## Choose Your Adventure

The next step is to get the application working in your environment. You can choose what kind of environment you want to work with and follow the specific instructions:

* [Kubernetes](docs-k8s.md) - choose this if you have a `kubernetes` cluster and want to run everything inside k8s
* [Local Environment](docs-local.md) - choose this if you have `nodejs` installed and want to run everything locally
* [Docker Environment](docs-docker.md) - choose this if you have `docker` installed and want to run everything in containers
* **Something Else??** - if you are want to see instructions for a different environment, open up an [issue](https://github.com/speedscale/demo-node/issues) on this project and let us know
* **Something Else??** - if you are want to see instructions for a different environment, open up an [issue](https://github.com/speedscale/node-server/issues) on this project and let us know

## Other Questions??

Expand Down
62 changes: 62 additions & 0 deletions node/client/client
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#!/usr/bin/env bash

set -eou pipefail

SERVER_URL=${SERVER_URL:-"localhost:3000"}
loginToken=""
rsaToken=""

echo $SERVER_URL

RED='\033[0;31m'
BLUE='\033[0;34m'
NC='\033[0m'

login() {
echo -e "${RED}Getting login token ${NC}"
loginToken=$(curl -s -X POST -H "Content-Type: application/json" -d '{"username": "admin", "password": "pass" }' "${SERVER_URL}/login" | jq -r .access_token)
echo -e "${RED}Login token is ${loginToken}${NC}"
echo
}

home() {
echo -e "${BLUE}Getting unauthenticated home ${NC}"
curl -s -X GET "${SERVER_URL}/"
echo
echo
}

space() {
echo -e "${BLUE}Getting SpaceX ${NC}"
curl -s -X GET -H "Authorization: Bearer ${loginToken}" "${SERVER_URL}/space"
echo
echo
}

events() {
echo -e "${BLUE}Getting GitHub Events ${NC}"
curl -s -X GET -H "Authorization: Bearer ${loginToken}" "${SERVER_URL}/events"
echo
echo
}

random-sleep () {
sleep $(( RANDOM % 3 ))
}

i=0
while true; do
if [[ $((i % 5)) == 0 ]]; then
login
fi

home
random-sleep

space
random-sleep

events
random-sleep
i=$((i+1))
done
6 changes: 3 additions & 3 deletions node/compose-replay-test.yaml
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
services:
demo-node:
node-server:
environment:
- GLOBAL_AGENT_HTTP_PROXY=http://host.docker.internal:4140
- GLOBAL_AGENT_HTTPS_PROXY=http://host.docker.internal:4140
- export GLOBAL_AGENT_NO_PROXY=*127.0.0.1:12557
- NODE_EXTRA_CA_CERTS=/etc/ssl/speedscale/tls.crt
image: demo-node:latest
image: node-server:latest
ports:
- 3000:3000
volumes:
Expand Down Expand Up @@ -47,7 +47,7 @@ services:
- PROXY_TYPE=dual
- PROXY_PROTOCOL=tcp:http
- ENABLE_API=false
- APP_POD_NAME=demo-node
- APP_POD_NAME=node-server
- APP_POD_NAMESPACE=${USER}
- COLLECTION_MODE=discard
### settings you may want to change ###
Expand Down
4 changes: 2 additions & 2 deletions node/compose-speedscale.yaml
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
services:
demo-node:
node-server:
environment:
- GLOBAL_AGENT_HTTP_PROXY=http://host.docker.internal:4140
- GLOBAL_AGENT_HTTPS_PROXY=http://host.docker.internal:4140
- export GLOBAL_AGENT_NO_PROXY=*127.0.0.1:12557
- NODE_EXTRA_CA_CERTS=/etc/ssl/speedscale/tls.crt
image: demo-node:latest
image: node-server:latest
ports:
- 3000:3000
volumes:
Expand Down
4 changes: 2 additions & 2 deletions node/compose.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
services:
demo-node:
image: demo-node:latest
node-server:
image: node-server:latest
ports:
- 3000:3000
24 changes: 12 additions & 12 deletions node/docs-docker.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Pre-requisites:
First you need to build the docker image:

```
docker build . -t demo-node:latest
docker build . -t node-server:latest
```

Then you can run it using `docker compose`. Make sure you use `docker compose` NOT `docker-compose` which is legacy and no longer supported. There is an example file which will start the listener on port 3000.
Expand All @@ -20,10 +20,10 @@ docker compose up
If the output looks like this then it's working:

```
demo-node-demo-node-1 | > demo-node@1.0.0 start
demo-node-demo-node-1 | > node index.js
demo-node-demo-node-1 |
demo-node-demo-node-1 | demo-node listening on port 3000
node-server-node-server-1 | > node-server@1.0.0 start
node-server-node-server-1 | > node index.js
node-server-node-server-1 |
node-server-node-server-1 | node-server listening on port 3000
```

## Send Test Transactions
Expand Down Expand Up @@ -83,7 +83,7 @@ Choose one:
[q] Quit
▸ What would you like to do? [q]: 1
▸ What is the name of your service? [MY_SERVICE]: demo-node
▸ What is the name of your service? [MY_SERVICE]: node-server
▸ What port does your service listen on locally? [8080]: 3000
```
Expand All @@ -94,17 +94,17 @@ This will create a file `speedscale-docker-capture.yaml` which runs the capture
yq '. *= load("speedscale-docker-capture.yaml")' compose-speedscale.yaml > compose-capture-merged.yaml
```

The resulting file should look like this with 3 sections for `demo-node` along with `forwarder` and `goproxy` which are the Speedscale containers.
The resulting file should look like this with 3 sections for `node-server` along with `forwarder` and `goproxy` which are the Speedscale containers.

```
services:
demo-node:
node-server:
environment:
- GLOBAL_AGENT_HTTP_PROXY=http://host.docker.internal:4140
- GLOBAL_AGENT_HTTPS_PROXY=http://host.docker.internal:4140
- export GLOBAL_AGENT_NO_PROXY=*127.0.0.1:12557
- NODE_EXTRA_CA_CERTS=/etc/ssl/speedscale/tls.crt
image: demo-node:latest
image: node-server:latest
ports:
- 3000:3000
volumes:
Expand Down Expand Up @@ -148,7 +148,7 @@ Now you are going to replay that snapshot on your own machine using `docker`. Yo
```
[2] Docker
[3] Replay recorded traffic from a Snapshot against my service locally
Choose your service: `demo-node`
Choose your service: `node-server`
Choose your test config: `standard`
Which snapshot ID should be used? (the one you created earlier)
What port does your service listen on locally? [8080]: 3000
Expand All @@ -161,13 +161,13 @@ This will create `speedscale-docker-replay.yaml` which runs the replay component
yq '. *= load("speedscale-docker-replay.yaml")' compose-speedscale.yaml > compose-replay-merged.yaml
```

The resulting file should look like this with 3 sections for `demo-node` along with `generator`, `goproxy`, `redis` and `responder` which are the Speedscale containers. You can run it like this:
The resulting file should look like this with 3 sections for `node-server` along with `generator`, `goproxy`, `redis` and `responder` which are the Speedscale containers. You can run it like this:

```
docker compose --file compose-replay-merged.yaml up
```

When you see the log message `demo-node-generator-1 exited with code 0` then the generator has completed, and you can turn down all the conatiners. Now you should see a Report in the [Speedscale Reports](https://app.speedscale.com/reports) list. It should have an 87.5% success rate like this.
When you see the log message `node-server-generator-1 exited with code 0` then the generator has completed, and you can turn down all the conatiners. Now you should see a Report in the [Speedscale Reports](https://app.speedscale.com/reports) list. It should have an 87.5% success rate like this.

![Speedscale Report](img/spd-report-summary.png)

Expand Down
58 changes: 58 additions & 0 deletions node/docs-k8s.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Kubernetes Workflow

Pre-requisites:
* You need to install the [Speedscale helm chart](https://github.com/speedscale/operator-helm) first.

## Install and Run the App

First you need to deploy the manifests:

```
kubectl apply -k .
```

It should spin up 2 deployments (each with 1 pod), 1 service and 1 configmap. You can check the status of the pods with this:

```
kubectl get pods
```

If the output looks like this then it's working:

```
NAME READY STATUS RESTARTS AGE
node-client-68f7c4fdcf-w5spx 1/1 Running 0 16s
node-server-b8997bcdf-gn772 1/1 Running 0 16s
```

## Capture

You can add your service through the [Add a new service wizard](https://app.speedscale.com/?popupId=addNewKubernetes).

![add-new-service-1](img/spd-add-new-service-1.png)

After you select your cluster and click next, you can see your namespaces. This demo is installed in the `default` namespace, you should see the workloads:

![add-new-service-2](img/spd-add-new-service-2.png)

For the TLS settings, select the very first radio button `Attempt to decode TLS outbound` and this will work automatically for this NodeJS app!

![add-new-service-3](img/spd-add-new-service-3.png)

The operator will automatically install the sidecar on your workload and you should get all green checkmarks:

![add-new-service-4](img/spd-add-new-service-4.png)

Now you should be able to see the data in Speedscale traffic viewer.

## Replay

The first step to replay is to [create a snapshot](https://docs.speedscale.com/guides/creating-a-snapshot/). After a few minutes you should see the data like this in your traffic viewer:

![traffic-viewer-k8s](img/spd-traffic-viewer-k8s.png)

The next step is to click the `Replay` and follow the workflow using all the default values. Select your cluster and the `default` namespace. For the test report select the `Regression (1x traffic, with service mocks)` option and `Replay exactly as recorded`. This will kick off service mocks to mock out the SpaceX and GitHub API calls, and then replay the inbound traffic as a regression test case. After the test completes you should see a report.

![report-k8s](img/spd-report-summary-k8s.png)

Now try to run with some different test configs to try out performance testing, chaos, or other types of tests!
6 changes: 3 additions & 3 deletions node/docs-local.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ npm start
If the log looks like this it's working:

```
> demo-node@1.0.0 start
> node-server@1.0.0 start
> node index.js
demo-node listening on port 3000
node-server listening on port 3000
```

## Send Test Transactions
Expand Down Expand Up @@ -54,7 +54,7 @@ speedctl create certs -o ~/.speedscale/certs
To quickly capture on your own local machine, you can capture the inbound and outbound traffic using `speedctl` with this command:

```
speedctl capture demo-node 3000
speedctl capture node-server 3000
```

Now you need to configure your application to use the proxy, this is from the [Speedscale Proxy Docs](https://docs.speedscale.com/setup/sidecar/proxy-modes/#configuring-your-application-proxy-server).
Expand Down
Binary file removed node/img/demo-node-capture.png
Binary file not shown.
Binary file removed node/img/demo-node-replay.png
Binary file not shown.
Binary file removed node/img/demo-node.png
Binary file not shown.
Binary file added node/img/node-server-capture.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added node/img/node-server-replay.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added node/img/node-server.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added node/img/spd-add-new-service-1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added node/img/spd-add-new-service-2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added node/img/spd-add-new-service-3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added node/img/spd-add-new-service-4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added node/img/spd-report-summary-k8s.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added node/img/spd-traffic-viewer-k8s.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
26 changes: 25 additions & 1 deletion node/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ import 'global-agent/bootstrap.js';
import got from 'got';
import express from 'express';
import morgan from 'morgan';
import jwt from 'jsonwebtoken';

const app = express()
app.use(express.json())
app.use(morgan('tiny'))
const port = 3000

Expand Down Expand Up @@ -37,6 +39,15 @@ app.get('/healthz', (req, res) => {
res.send(body);
})

app.post('/login', (req, res) => {
var token = jwt.sign({ user: req.body.username }, 'shhhhh');
const body = {
'access_token': token,
'ts': new Date().toISOString()
}
res.send(body);
})

app.get('/nasa', async (req, res) => {
try {
const url = 'https://api.nasa.gov/planetary/apod'
Expand All @@ -55,6 +66,19 @@ app.get('/nasa', async (req, res) => {
}
})

app.get('/space', async (req, res) => {
try {
const url = 'https://api.spacexdata.com/v5/launches/latest';
const data = await got(url).json()
res.send(data)
} catch (err) {
const msg = makeError(err)
console.error(msg)
res.status(500)
res.send(msg)
}
})

app.get('/events', async (req, res) => {
try {
const url = 'https://api.github.com/orgs/speedscale/events';
Expand Down Expand Up @@ -87,6 +111,6 @@ app.get('/bin', async (req, res) => {
})

app.listen(port, () => {
console.log(`demo-node listening on port ${port}`)
console.log(`node-server listening on port ${port}`)
})

Loading

0 comments on commit fd605ba

Please sign in to comment.