Microservices Coffeeshop

MICROSERVICES COFFEESHOP

APIs INTEGRATION AND MONITORING WITH ECLIPSE MICROPROFILE.

1-INIT

export USER=rabreu
export PROJECT_NS=microservices-coffeeshop
export OCP_HOST=mycloud.com

oc login -u $USER https://api.$OCP_HOST.com:6443

oc new-project $PROJECT_NS --description="Expert Extra Recording LAB" --display-name="microservices-coffeeshop"

2-RED HAT REGISTRY SECRET CONFIGURATION

cat > config.json <<EOL
{
        "auths": {
                "registry.redhat.io": {
                        "auth": "YOUR-SECRET-KEY"
                }
        }
}
EOL

2.1- Create a secret with your container credentials

oc delete secret redhat.io -n openshift
oc create secret generic "redhat.io" --from-file=.dockerconfigjson=config.json --type=kubernetes.io/dockerconfigjson -n $PROJECT_NS

oc secrets link default redhat.io --for=pull -n $PROJECT_NS
oc secrets link builder redhat.io -n $PROJECT_NS

3-IMPORT OPENJDK-8-RHEL8 CONTAINER IMAGE

# option1
oc import-image openjdk/openjdk-8-rhel8 --from=registry.redhat.io/openjdk/openjdk-8-rhel8 --confirm -n $PROJECT_NS
oc import-image openjdk/openjdk-8-rhel8 --from=registry.redhat.io/openjdk/openjdk-8-rhel8 --confirm -n openshift
# option2 (working)
oc import-image redhat-openjdk-18/openjdk18-openshift --from=registry.redhat.io/redhat-openjdk-18/openjdk18-openshift --confirm -n openshift

4-NEXUS OSS DEPLOYMENT

oc new-app --docker-image docker.io/sonatype/nexus3:latest

oc rollout pause dc/nexus3

oc patch dc nexus3 -p '{"spec":{"strategy":{"type":"Recreate"}}}'

oc expose svc nexus3

oc set resources dc nexus3 --limits=memory=4Gi,cpu=2 --requests=memory=2Gi,cpu=500m

oc set volume dc/nexus3 --add --overwrite --name=nexus3-volume-1 --mount-path=/nexus-data/ --type persistentVolumeClaim --claim-name=nexus-pvc --claim-size=10Gi

oc set probe dc/nexus3 --liveness --failure-threshold 3 --initial-delay-seconds 60 -- echo ok

oc set probe dc/nexus3 --readiness --failure-threshold 3 --initial-delay-seconds 60 --get-url=http://:8081/

oc rollout resume dc nexus3

NEXUS_POD=$(oc get pods --selector deploymentconfig=nexus3 -n $PROJECT_NS | { read line1 ; read line2 ; echo "$line2" ; } | awk '{print $1;}')

oc exec $NEXUS_POD cat /nexus-data/admin.password
# It will print the password. Something like:
# 33456b65-7e85-4dfc-a063-78b413cf4a47

echo http://$(oc get route -n ${PROJECT_NS} | grep nexus3 | awk '{print $2;}')/

# log into the nexus and change password to admin123 (also enable: Enable anonymous access)
# then, download the shell script bellow:
curl -o setup_nexus3.sh -s https://raw.githubusercontent.com/aelkz/microservices-coffeeshop/master/_configuration/nexus/setup_nexus3.sh

chmod +x setup_nexus3.sh

./setup_nexus3.sh admin admin123 http://$(oc get route -n ${PROJECT_NS} nexus3 --template='{{ .spec.host }}')

oc expose dc nexus3 --port=5000 --name=nexus-registry -n ${PROJECT_NS}

oc create route edge nexus-registry --service=nexus-registry --port=5000 -n ${PROJECT_NS}

OBS.: You might want to add the jboss.org repository and add to maven-group and maven-public repositories on nexus:
See: parent project pom.xml for details on <repositories> tag.

5-NEXUS ENVIRONMENT VARIABLES

# download maven settings.xml file
curl -o maven-settings-template.xml -s https://raw.githubusercontent.com/aelkz/microservices-coffeeshop/master/_configuration/nexus/maven-settings-template.xml

# change mirror url using your nexus openshift route
export MAVEN_URL=http://$(oc get route -n ${PROJECT_NS} nexus3 --template='{{ .spec.host }}')/repository/maven-group/
export MAVEN_URL_RELEASES=http://$(oc get route -n ${PROJECT_NS} nexus3 --template='{{ .spec.host }}')/repository/maven-releases/
export MAVEN_URL_SNAPSHOTS=http://$(oc get route -n ${PROJECT_NS} nexus3 --template='{{ .spec.host }}')/repository/maven-snapshots/

awk -v path="$MAVEN_URL" '/<url>/{sub(/>.*</,">"path"<")}1' maven-settings-template.xml > maven-settings.xml

rm -fr maven-settings-template.xml

6-APPLICATION DEPLOYMENT – PARENT PROJECT

# deploy parent project on nexus
git clone https://github.com/aelkz/microservices-coffeeshop.git

mvn clean package deploy -DnexusReleaseRepoUrl=$MAVEN_URL_RELEASES -DnexusSnapshotRepoUrl=$MAVEN_URL_SNAPSHOTS -s ./maven-settings.xml -e -X -N

7-APPLICATION DEPLOYMENT – BARISTA THORNTAIL APPLICATION

export APP_NAME=barista
export THORNTAIL_APP=$APP_NAME-service
# oc delete all -lapp=$APP_NAME-service -n $PROJECT_NS
# oc delete is $APP_NAME-service -n $PROJECT_NS
# oc delete bc $APP_NAME-service-s2i -n $PROJECT_NS
# oc delete is $APP_NAME-service -n $PROJECT_NS
Prefered Option (using a source strategy build):
oc new-app openjdk18-openshift:latest~https://github.com/aelkz/microservices-coffeeshop.git --name=$THORNTAIL_APP --context-dir=/$APP_NAME-service --build-env='MAVEN_MIRROR_URL='${MAVEN_URL} -e MAVEN_MIRROR_URL=${MAVEN_URL} -n ${PROJECT_NS}

8-CONFIGURE APP RESOURCES

oc tag $APP_NAME-service:1.0 $APP_NAME-service:latest -n ${PROJECT_NS}
oc set resources dc $THORNTAIL_APP --requests=cpu=500m,memory=500Mi --limits=cpu=750m,memory=1Gi -n ${PROJECT_NS}
oc set env dc/$THORNTAIL_APP JAVA_DEBUG=true -n ${PROJECT_NS}
oc set env dc/$THORNTAIL_APP GC_MAX_METASPACE_SIZE=256 -n ${PROJECT_NS}

9-CONFIGURE APP PRODUCTION ENVIRONMENT

oc delete configmap $APP_NAME-config-file -n ${PROJECT_NS}
oc create -f ../_configuration/openshift/$APP_NAME-config/production.yaml -n ${PROJECT_NS}

oc set volume dc/$APP_NAME-service --remove --name=$APP_NAME-config-volume -n ${PROJECT_NS}
oc set volume dc/$APP_NAME-service --add --overwrite --name=$APP_NAME-config-volume -m /app/config -t configmap --configmap-name=$APP_NAME-config-file -n ${PROJECT_NS}

oc set env dc/$APP_NAME-service JAVA_OPTIONS="-server -Djava.net.preferIPv4Stack=true -Dswarm.project.stage=production -Dthorntail.project.stage.file=file:///app/config/$APP_NAME-config.yml"

10-EXPOSE APP ROUTE

oc expose svc/$APP_NAME-service -n ${PROJECT_NS}

TEST!

11-APPLICATION DEPLOYMENT – PRODUCT THORNTAIL APPLICATION

APP_NAME=product
THORNTAIL_APP=$APP_NAME-service
# oc delete all -lapp=$APP_NAME-service -n $PROJECT_NS
# oc delete is $APP_NAME-service -n $PROJECT_NS
# oc delete bc $APP_NAME-service-s2i -n $PROJECT_NS
# oc delete is $APP_NAME-service -n $PROJECT_NS

oc new-app openjdk18-openshift:latest~https://github.com/aelkz/microservices-coffeeshop.git --name=$THORNTAIL_APP --context-dir=/$APP_NAME-service --build-env='MAVEN_MIRROR_URL='${MAVEN_URL} -e MAVEN_MIRROR_URL=${MAVEN_URL} -n ${PROJECT_NS}

oc tag $APP_NAME-service:1.0 $APP_NAME-service:latest -n ${PROJECT_NS}
oc set resources dc $THORNTAIL_APP --requests=cpu=500m,memory=500Mi --limits=cpu=750m,memory=1Gi -n ${PROJECT_NS}
oc set env dc/$THORNTAIL_APP GC_MAX_METASPACE_SIZE=256 -n ${PROJECT_NS}

oc expose svc/$APP_NAME-service -n ${PROJECT_NS}

12-APPLICATION DEPLOYMENT – STORAGE THORNTAIL APPLICATION

APP_NAME=storage
THORNTAIL_APP=$APP_NAME-service
# oc delete all -lapp=$APP_NAME-service -n $PROJECT_NS
# oc delete is $APP_NAME-service -n $PROJECT_NS
# oc delete bc $APP_NAME-service-s2i -n $PROJECT_NS
# oc delete is $APP_NAME-service -n $PROJECT_NS

oc new-app openjdk18-openshift:latest~https://github.com/aelkz/microservices-coffeeshop.git --name=$THORNTAIL_APP --context-dir=/$APP_NAME-service --build-env='MAVEN_MIRROR_URL='${MAVEN_URL} -e MAVEN_MIRROR_URL=${MAVEN_URL} -n ${PROJECT_NS}

oc tag $APP_NAME-service:1.0 $APP_NAME-service:latest -n ${PROJECT_NS}
oc set resources dc $THORNTAIL_APP --requests=cpu=500m,memory=500Mi --limits=cpu=750m,memory=1Gi -n ${PROJECT_NS}
oc set env dc/$THORNTAIL_APP GC_MAX_METASPACE_SIZE=256 -n ${PROJECT_NS}

oc expose svc/$APP_NAME-service -n ${PROJECT_NS}

13-APPLICATION DEPLOYMENT – MAINTENANCE THORNTAIL APPLICATION

APP_NAME=maintenance
THORNTAIL_APP=$APP_NAME-service
# oc delete all -lapp=$APP_NAME-service -n $PROJECT_NS
# oc delete is $APP_NAME-service -n $PROJECT_NS
# oc delete bc $APP_NAME-service-s2i -n $PROJECT_NS
# oc delete is $APP_NAME-service -n $PROJECT_NS

oc new-app openjdk18-openshift:latest~https://github.com/aelkz/microservices-coffeeshop.git --name=$THORNTAIL_APP --context-dir=/$APP_NAME-service --build-env='MAVEN_MIRROR_URL='${MAVEN_URL} -e MAVEN_MIRROR_URL=${MAVEN_URL} -n ${PROJECT_NS}

oc tag $APP_NAME-service:1.0 $APP_NAME-service:latest -n ${PROJECT_NS}
oc set resources dc $THORNTAIL_APP --requests=cpu=500m,memory=500Mi --limits=cpu=750m,memory=1Gi -n ${PROJECT_NS}
oc set env dc/$THORNTAIL_APP GC_MAX_METASPACE_SIZE=256 -n ${PROJECT_NS}

oc expose svc/$APP_NAME-service -n ${PROJECT_NS}

14-APPLICATION DEPLOYMENT – ORDER THORNTAIL APPLICATION

APP_NAME=order
THORNTAIL_APP=$APP_NAME-service
# oc delete all -lapp=$APP_NAME-service -n $PROJECT_NS
# oc delete is $APP_NAME-service -n $PROJECT_NS
# oc delete bc $APP_NAME-service-s2i -n $PROJECT_NS
# oc delete is $APP_NAME-service -n $PROJECT_NS

oc new-app openjdk18-openshift:latest~https://github.com/aelkz/microservices-coffeeshop.git --name=$THORNTAIL_APP --context-dir=/$APP_NAME-service --build-env='MAVEN_MIRROR_URL='${MAVEN_URL} -e MAVEN_MIRROR_URL=${MAVEN_URL} -n ${PROJECT_NS}

oc tag $APP_NAME-service:1.0 $APP_NAME-service:latest -n ${PROJECT_NS}
oc set resources dc $THORNTAIL_APP --requests=cpu=500m,memory=500Mi --limits=cpu=750m,memory=1Gi -n ${PROJECT_NS}
oc set env dc/$THORNTAIL_APP GC_MAX_METASPACE_SIZE=256 -n ${PROJECT_NS}

APP_NAME=order
BARISTA_ROUTE=http://barista-service.${PROJECT_NS}.svc.cluster.local:8080/api/v1
MAINTENANCE_ROUTE=http://maintenance-service.${PROJECT_NS}.svc.cluster.local:8080/api/v1
PRODUCT_ROUTE=http://product-service.${PROJECT_NS}.svc.cluster.local:8080/api/v1
STORAGE_ROUTE=http://storage-service.${PROJECT_NS}.svc.cluster.local:8080/api/v1

echo "
apiVersion: v1
kind: ConfigMap
metadata:
 name: order-config-file
data:
  order-config.yml: |-
    project:
      stage: production
    thorntail:
      logging: INFO
      ajp:
        enable: true
      http:
        port: 8080
      datasources:
        data-sources:
          OrderDS:
            driver-name: h2
            connection-url: jdbc:h2:mem:order;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
            user-name: sa
            password: sa
    greeting:
      message: Hello %s from order-configmap.yml!
    coffeeshop:
      routes:
        barista-service: \""$BARISTA_ROUTE"\"
        maintenance-service: \""$MAINTENANCE_ROUTE\""
        product-service: \""$PRODUCT_ROUTE\""
        storage-service: \""$STORAGE_ROUTE\""
" > production.yaml

oc delete configmap $APP_NAME-config-file -n ${PROJECT_NS}
oc create -f production.yaml -n ${PROJECT_NS}

# oc set volume dc/$APP_NAME-service --remove --name=$APP_NAME-config-volume -n ${PROJECT_NS}
oc set volume dc/$APP_NAME-service --add --overwrite --name=$APP_NAME-config-volume -m /app/config -t configmap --configmap-name=$APP_NAME-config-file -n ${PROJECT_NS}

oc set env dc/$APP_NAME-service JAVA_OPTIONS="-server -Djava.net.preferIPv4Stack=true -Dswarm.project.stage=production -Dthorntail.project.stage.file=file:///app/config/$APP_NAME-config.yml"

oc expose svc/$APP_NAME-service -n ${PROJECT_NS}

15-PROMETHEUS DEPLOYMENT

All microprofile applications enable by default the following endpoints:
http://localhost:8080/metrics (all metrics)
http://localhost:8080/metrics/application (exclusively for application-level metrics)

echo "
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: thorntail-prometheus-monitor
  labels:
    k8s-app: prometheus
  namespace: "$PROJECT_NS"
spec:
  namespaceSelector:
    matchNames:
      - "$PROJECT_NS"
  selector:
    matchLabels:
      monitor: thorntail-app
  endpoints:
    - port: http
      interval: 15s
      path: '/metrics'
"      
echo "
apiVersion: monitoring.coreos.com/v1
kind: Prometheus
metadata:
  name: server
  labels:
    prometheus: k8s
  namespace: "$PROJECT_NS"
spec:
  replicas: 2
  serviceAccountName: prometheus-k8s
  securityContext: {}
  serviceMonitorSelector:
    matchExpressions:
      - key: k8s-app
        operator: Exists
  ruleSelector:
    matchLabels:
      role: prometheus-rulefiles
      prometheus: k8s
  alerting:
    alertmanagers:
      - namespace: "$PROJECT_NS"
        name: alertmanager-main
        port: web
"        

Expose prometheus route:
oc expose svc prometheus-operated -n $PROJECT_NS

16-GRAFANA DEPLOYMENT

Follow these instructions:
https://www.redhat.com/en/blog/custom-grafana-dashboards-red-hat-openshift-container-platform-4
https://github.com/integr8ly/application-monitoring-operator/blob/master/scripts/install.sh
https://medium.com/@zhimin.wen/grafana-dashboard-in-ocp4-2-44468e5390d0
https://operatorhub.io/operator/grafana-operator

Grafana operator template:

echo "
apiVersion: integreatly.org/v1alpha1
kind: Grafana
metadata:
  name: grafana
  namespace: "$PROJECT_NS"
spec:
  ingress:
    enabled: true
  config:
    auth.anonymous:
      enabled: true
    log:
      level: warn
      mode: console
    security:
      admin_password: "123456"
      admin_user: "grafana"
    auth:
      disable_login_form: false
      disable_signout_menu: true
  dashboardLabelSelector:
    - matchExpressions:
        - key: app
          operator: In
          values:
            - grafana
"

You can also deploy the objects manually:

git clone https://github.com/integr8ly/grafana-operator.git
cd grafana-operator
oc create -f deploy/crds -n ${PROJECT_NS}
oc create -f deploy/roles -n ${PROJECT_NS}
oc create -f deploy/cluster_roles -n ${PROJECT_NS}
oc create -f deploy/operator.yaml -n ${PROJECT_NS}

OBS. Grafana can be deployed with a oauth-proxy sidecard.
In order to access grafana, you’ll need access using some service-account and/or cluster admin.

Acquire grafana’s route

echo http://$(oc get route grafana -n ${PROJECT_NS} --template='{{ .spec.host }}')

Acquire prometheus route

echo http://prometheus-operated.$PROJECT_NS.svc.cluster.local:9090

Grafana should be configurated to use the Prometheus datasouce:

URL= http://prometheus-operated.<YOUR-NAMESPACE>.svc.cluster.local:9090
Scrape Interval=5s
Query Timeout=30s

Apply and save. Check if the connection was successful:

APPLY PROMETHEUS LABELS

This will add the prometheus label, to enable scrapping on all services as defined in the step 15.

We will update all services and routes, changing from this:


To this:

oc label svc barista-service monitor=thorntail-app -n $PROJECT_NS
oc patch svc barista-service -p '{"spec":{"ports":[{"name":"http","port":8080,"protocol":"TCP","targetPort":8080}]}}' -n $PROJECT_NS
oc patch route barista-service -p '{"spec":{"port":{"targetPort":"http"}}}' -n $PROJECT_NS

oc label svc maintenance-service monitor=thorntail-app -n $PROJECT_NS
oc patch svc maintenance-service -p '{"spec":{"ports":[{"name":"http","port":8080,"protocol":"TCP","targetPort":8080}]}}' -n $PROJECT_NS
oc patch route maintenance-service -p '{"spec":{"port":{"targetPort":"http"}}}' -n $PROJECT_NS

oc label svc product-service monitor=thorntail-app -n $PROJECT_NS
oc patch svc product-service -p '{"spec":{"ports":[{"name":"http","port":8080,"protocol":"TCP","targetPort":8080}]}}' -n $PROJECT_NS
oc patch route product-service -p '{"spec":{"port":{"targetPort":"http"}}}' -n $PROJECT_NS

oc label svc storage-service monitor=thorntail-app -n $PROJECT_NS
oc patch svc storage-service -p '{"spec":{"ports":[{"name":"http","port":8080,"protocol":"TCP","targetPort":8080}]}}' -n $PROJECT_NS
oc patch route storage-service -p '{"spec":{"port":{"targetPort":"http"}}}' -n $PROJECT_NS

oc label svc order-service monitor=thorntail-app -n $PROJECT_NS
oc patch svc order-service -p '{"spec":{"ports":[{"name":"http","port":8080,"protocol":"TCP","targetPort":8080}]}}' -n $PROJECT_NS
oc patch route order-service -p '{"spec":{"port":{"targetPort":"http"}}}' -n $PROJECT_NS

After this, you can check creation of all service targets on prometheus:

TEST USING REST HTTP CALLS

Open your Rest client application and try to create some records.
You’ll see the final result being updated uppon grafana dashboard.

Leave A Comment