Skip to content

alainpham/business-platform

Repository files navigation

business platform demo

This is a guide to deploy a set of synchronous and asynchronous microservices in spring boot to observed with & Grafana LGTM OSS stack or Grafana Cloud.

architecture diagram

alt text

Env vars

export MAIN_PROJECT_VERSION=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout)
export OTLP_ENDPOINT=$(mvn help:evaluate -Dexpression=otlp.endpoint -q -DforceStdout)
export ACTIVEMQ_ARTEMIS_VERSION=2.33.0
export OTELCOL_VERSION=0.96.0
export K6_VERSION=0.52.0
export KUBE_INGRESS_ROOT_DOMAIN=gkube.duckdns.org


# grafana cloud key
export key=xxxx

#pusher to eu server
export MIMIR_HOST=https://prometheus-prod-24-prod-eu-west-2.grafana.net
export MIMIR_URL=${MIMIR_HOST}/api/prom/push
export MIMIR_USR=xxxx
export MIMIR_KEY=${key}

export LOKI_HOST=https://logs-prod-012.grafana.net
export LOKI_URL=${LOKI_HOST}/loki/api/v1/push
export LOKI_USR=xxxx
export LOKI_KEY=${key}

export TEMPO_URL=tempo-prod-10-prod-eu-west-2.grafana.net:443
export TEMPO_USR=xxxx
export TEMPO_KEY=${key}

# https://github.com/infinityofspace/certbot_dns_duckdns
export CERTBOT_DUCKDNS_VERSION=v1.3
export DUCKDNS_TOKEN=xxxx-xxxx-xxx-xxx-xxxxx
export [email protected]
export WILDCARD_DOMAIN=yourowndomain.duckdns.org

# https://github.com/kubernetes/ingress-nginx/blob/main/deploy/static/provider/baremetal/deploy.yaml
export NGINX_INGRESS_VERSION=1.10.1
export NGINX_INGRESS_KUBE_WEBHOOK_CERTGEN_VERSION=v1.4.1

Build and push to dockerhub

mvn package
mvn package exec:exec@buildpush -f business-hub/pom.xml
mvn package exec:exec@buildpush -f availability-service/pom.xml
mvn package exec:exec@buildpush -f notification-service/pom.xml
mvn package exec:exec@buildpush -f message-consumer/pom.xml

mvn package exec:exec@buildpush -f public-api/pom.xml
mvn package exec:exec@buildpush -f data-batcher/pom.xml

Deploy kube using maven

kubectl delete namespace business-platform
kubectl create ns business-platform
kubectl config set-context --current --namespace=business-platform
export CONTAINER_REGISTRY=apache
export PROJECT_ARTIFACTID=activemq-artemis
export PROJECT_VERSION=${ACTIVEMQ_ARTEMIS_VERSION}

wget -O /tmp/broker.yaml https://raw.githubusercontent.com/alainpham/business-platform/master/broker/broker.envsubst.yaml
envsubst < /tmp/broker.yaml | kubectl apply -n business-platform -f -

envsubst < /tmp/broker.yaml | kubectl delete -n business-platform -f -
mvn exec:exec@kdeploy -f business-hub/pom.xml
mvn exec:exec@kdeploy -f availability-service/pom.xml
mvn exec:exec@kdeploy -f notification-service/pom.xml
APPLICATION_NAME=email mvn exec:exec@kdeploy -f message-consumer/pom.xml
APPLICATION_NAME=sms mvn exec:exec@kdeploy -f message-consumer/pom.xml

mvn exec:exec@kdeploy -f public-api/pom.xml
mvn exec:exec@kdeploy -f data-batcher/pom.xml


mvn exec:exec@kdelete exec:exec@kdeploy -f business-hub/pom.xml
mvn exec:exec@kdelete exec:exec@kdeploy -f availability-service/pom.xml
mvn exec:exec@kdelete exec:exec@kdeploy -f notification-service/pom.xml
APPLICATION_NAME=email mvn exec:exec@kdelete exec:exec@kdeploy -f message-consumer/pom.xml
APPLICATION_NAME=sms mvn exec:exec@kdelete exec:exec@kdeploy -f message-consumer/pom.xml

mvn exec:exec@kdelete  exec:exec@kdeploy -f public-api/pom.xml
mvn exec:exec@kdelete  exec:exec@kdeploy -f data-batcher/pom.xml

Create data source for grafana test data

Create datasource for infinity plugin

Add dashboard on Grafana Cloud

Create an SLO with the following formula

sum by (job) (last_over_time(freshness_worst_seconds[$__interval])) < bool 120

run the demo with docker

Optionally create a dedicated network

docker network create --driver=bridge --subnet=172.20.0.0/16 --gateway=172.20.0.1 mainnet

Launch apps

docker run --rm -d --net mainnet \
    -e ANONYMOUS_LOGIN=true \
    --name activemq-artemis -p 61616:61616 -p 8161:8161 apache/activemq-artemis:${ACTIVEMQ_ARTEMIS_VERSION}

docker run --rm -d --net mainnet \
    -p 8080:8080 \
    -e OTEL_JAVAAGENT_ENABLED="true" \
    --name business-hub alainpham/business-hub:${MAIN_PROJECT_VERSION}
    
docker run --rm -d --net mainnet \
    -e OTEL_JAVAAGENT_ENABLED="true" \
    -e APP_PROCESSING_CPUUSAGE_PERCENTAGE=1 \
    -e APP.PROCESSING.MEMUSAGE_MB=1 \
    --name availability-service alainpham/availability-service:${MAIN_PROJECT_VERSION}
    
docker run --rm -d --net mainnet \
    -e OTEL_JAVAAGENT_ENABLED="true" \
    --name notification-service alainpham/notification-service:${MAIN_PROJECT_VERSION}

docker run --rm -d --net mainnet \
    -e OTEL_JAVAAGENT_ENABLED="true" \
    -e APP_QUEUE="email" \
    -e OTEL_RESOURCE_ATTRIBUTES=service.name=email,service.namespace=email-ns,service.instance.id=email-cnt,service.version=${PROJECT_VERSION} \
    --name email alainpham/message-consumer:${MAIN_PROJECT_VERSION}

docker run --rm -d --net mainnet \
    -e OTEL_JAVAAGENT_ENABLED="true" \
    -e APP_QUEUE="sms" \
    -e OTEL_RESOURCE_ATTRIBUTES=service.name=sms,service.namespace=sms-ns,service.instance.id=sms-cnt,service.version=${PROJECT_VERSION} \
    --name sms alainpham/message-consumer:${MAIN_PROJECT_VERSION}

docker run --rm -d --net mainnet \
    --entrypoint /bin/sh \
    -e BASE_URL="http://business-hub:8080" \
    -v "./k6/script.js:/scripts/script.js:ro" \
    --name k6 grafana/k6:${K6_VERSION} \
    -c "while true; do k6 run /scripts/script.js ;sleep 2m; done"

Stop All

docker stop k6 business-hub availability-service notification-service email sms activemq-artemis

Install and launch Grafana Alloy on Linux Host

ARCH="amd64" GCLOUD_HOSTED_METRICS_URL="${MIMIR_URL}" GCLOUD_HOSTED_METRICS_ID="{MIMIR_USR}" GCLOUD_SCRAPE_INTERVAL="60s" GCLOUD_HOSTED_LOGS_URL="${LOKI_URL}" GCLOUD_HOSTED_LOGS_ID="${LOKI_USR}" GCLOUD_RW_API_KEY="${key}" /bin/sh -c "$(curl -fsSL https://storage.googleapis.com/cloud-onboarding/alloy/scripts/install-linux.sh)"

run demo on kubernetes

The kube deployment yaml files use ingress, to expose application http(s) services to ouside of kubernetes through a loadbalancer type service.

If you want to have clean certificates with valid letsencrypt and a proper domain name follow these optional steps. I use the free duckdns.org dns service.

For this demo to work you this section is optional

this is the architecture we will be building

Generate a domain name and wildcard certificates with Letsencrypt

Go to duckdns.org and create a domain name as in yourowndomain.duckdns.org. You don't need to specify an IP address yet. We will point it to the All applications deployed on kube will be accessible with an url like appname.yourowndomain.duckdns.org

docker run -v "$(pwd)/sensitive/letsencrypt/data:/etc/letsencrypt" -v "$(pwd)/sensitive/letsencrypt/logs:/var/log/letsencrypt" infinityofspace/certbot_dns_duckdns:${CERTBOT_DUCKDNS_VERSION} \
   certonly \
     --non-interactive \
     --agree-tos \
     --email ${EMAIL} \
     --preferred-challenges dns \
     --authenticator dns-duckdns \
     --dns-duckdns-token ${DUCKDNS_TOKEN} \
     --dns-duckdns-propagation-seconds 30 \
     -d "*.${WILDCARD_DOMAIN}"

sudo chown -R ${USER}:${USER} $(pwd)/sensitive/letsencrypt/data

Create ingress router

kubectl create ns ingress-nginx

kubectl -n ingress-nginx create  secret tls nginx-ingress-tls  --key="$(pwd)/sensitive/letsencrypt/data/live/$WILDCARD_DOMAIN/privkey.pem"   --cert="$(pwd)/sensitive/letsencrypt/data/live/$WILDCARD_DOMAIN/fullchain.pem"  --dry-run=client -o yaml | kubectl apply -f -

#ingress with LoadBalancer
wget -O /tmp/ingresslb.yaml https://raw.githubusercontent.com/alainpham/dev-environment/master/workstation-installation/templates/ingress-loadbalancer-notoleration.yaml
envsubst < /tmp/ingresslb.yaml | kubectl -n ingress-nginx apply -f -


# alternative ingress with hostport on non cloud instances
wget -O /tmp/ingress.yaml https://raw.githubusercontent.com/alainpham/dev-environment/master/workstation-installation/templates/ingress-hostport-notoleration.yaml
envsubst < /tmp/ingress.yaml | kubectl -n ingress-nginx apply -f -

Deploy OTEL Collector sending data to Grafana Cloud (option 1)

export CONTAINER_REGISTRY=otel
export PROJECT_ARTIFACTID=opentelemetry-collector-contrib
export PROJECT_VERSION=${OTELCOL_VERSION}

kubectl create ns agents

wget -O /tmp/otelcol.yaml https://raw.githubusercontent.com/alainpham/business-platform/master/otelcol/otelcol.yaml
envsubst < /tmp/otelcol.yaml | kubectl -n agents apply -f -

Deploy PDC agent

wget -O /tmp/pdc.yaml https://raw.githubusercontent.com/alainpham/business-platform/master/pdc/pdc.yaml
kubectl -n agents apply -f pdc/pdc.yaml

Deploy Grafana Alloy to send data to Grafana Cloud (option 2)

helm repo add grafana https://grafana.github.io/helm-charts &&
  helm repo update &&
  helm upgrade --install --atomic --timeout 300s grafana-k8s-monitoring grafana/k8s-monitoring \
    --namespace "agents" --create-namespace --values - <<EOF
cluster:
  name: gkube
externalServices:
  prometheus:
    host: "${MIMIR_HOST}"
    basicAuth:
      username: "${MIMIR_USR}"
      password: "${MIMIR_KEY}"
  loki:
    host: "${LOKI_HOST}"
    basicAuth:
      username: "${LOKI_USR}"
      password: "${LOKI_KEY}"
  tempo:
    host: "${TEMPO_URL}"
    basicAuth:
      username: "${TEMPO_USR}"
      password: "${TEMPO_KEY}"
metrics:
  enabled: true
  cost:
    enabled: true
  node-exporter:
    enabled: true
logs:
  enabled: true
  pod_logs:
    enabled: true
  cluster_events:
    enabled: true
traces:
  enabled: true
receivers:
  grpc:
    enabled: true
  http:
    enabled: true
  zipkin:
    enabled: true
opencost:
  enabled: true
  opencost:
    exporter:
      defaultClusterId: gkube
    prometheus:
      external:
        url: "${MIMIR_HOST}/api/prom"
kube-state-metrics:
  enabled: true
prometheus-node-exporter:
  enabled: true
prometheus-operator-crds:
  enabled: true
alloy: {}
alloy-events: {}
alloy-logs: {}
EOF

start from scratch

kubectl delete namespace business-platform
kubectl create ns business-platform

broker

export CONTAINER_REGISTRY=apache
export PROJECT_ARTIFACTID=activemq-artemis
export PROJECT_VERSION=${ACTIVEMQ_ARTEMIS_VERSION}

kubectl create ns business-platform

wget -O /tmp/broker.yaml https://raw.githubusercontent.com/alainpham/business-platform/master/broker/broker.envsubst.yaml
envsubst < /tmp/broker.yaml | kubectl apply -n business-platform -f -

envsubst < /tmp/broker.yaml | kubectl delete -n business-platform -f -

availability-service

export PROJECT_ARTIFACTID=availability-service
export CONTAINER_REGISTRY=alainpham
export PROJECT_VERSION=${MAIN_PROJECT_VERSION}


wget -O /tmp/availability-service.yaml https://raw.githubusercontent.com/alainpham/business-platform/master/availability-service/src/main/kube/deploy.envsubst.yaml
envsubst < /tmp/availability-service.yaml | kubectl apply -n business-platform -f -

envsubst < /tmp/availability-service.yaml | kubectl delete -n business-platform  -f -

business-hub

export PROJECT_ARTIFACTID=business-hub
export CONTAINER_REGISTRY=alainpham
export PROJECT_VERSION=${MAIN_PROJECT_VERSION}

wget -O /tmp/business-hub.yaml https://raw.githubusercontent.com/alainpham/business-platform/master/business-hub/src/main/kube/deploy.envsubst.yaml
envsubst < /tmp/business-hub.yaml | kubectl apply -n business-platform  -f -

envsubst < /tmp/business-hub.yaml | kubectl delete -n business-platform  -f -

notification-service

export PROJECT_ARTIFACTID=notification-service
export CONTAINER_REGISTRY=alainpham
export PROJECT_VERSION=${MAIN_PROJECT_VERSION}

wget -O /tmp/notification-service.yaml https://raw.githubusercontent.com/alainpham/business-platform/master/notification-service/src/main/kube/deploy.envsubst.yaml
envsubst < /tmp/notification-service.yaml | kubectl apply -n business-platform  -f -

envsubst < /tmp/notification-service.yaml | kubectl delete -n business-platform  -f -

email

export PROJECT_ARTIFACTID=message-consumer
export APPLICATION_NAME=email
export CONTAINER_REGISTRY=alainpham
export PROJECT_VERSION=${MAIN_PROJECT_VERSION}

wget -O /tmp/message-consumer.yaml https://raw.githubusercontent.com/alainpham/business-platform/master/message-consumer/src/main/kube/deploy.envsubst.yaml
envsubst < /tmp/message-consumer.yaml | kubectl apply -n business-platform  -f -

envsubst < /tmp/message-consumer.yaml | kubectl delete -n business-platform  -f -

sms

export PROJECT_ARTIFACTID=message-consumer
export APPLICATION_NAME=sms
export CONTAINER_REGISTRY=alainpham
export PROJECT_VERSION=${MAIN_PROJECT_VERSION}

wget -O /tmp/message-consumer.yaml https://raw.githubusercontent.com/alainpham/business-platform/master/message-consumer/src/main/kube/deploy.envsubst.yaml
envsubst < /tmp/message-consumer.yaml | kubectl apply -n business-platform  -f -

envsubst < /tmp/message-consumer.yaml | kubectl delete -n business-platform  -f -

k6 load testing

export CONTAINER_REGISTRY=grafana
export PROJECT_ARTIFACTID=k6
export PROJECT_VERSION=${K6_VERSION}
export BASE_URL=https://business-hub.${KUBE_INGRESS_ROOT_DOMAIN}

wget -O /tmp/k6.yaml https://raw.githubusercontent.com/alainpham/business-platform/master/k6/k6.yaml
envsubst < /tmp/k6.yaml | kubectl apply -n business-platform  -f -

envsubst < /tmp/k6.yaml | kubectl delete -n business-platform  -f -

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published