{"id":16515075,"url":"https://github.com/ebullient/monster-combat","last_synced_at":"2025-03-16T19:30:42.189Z","repository":{"id":37807439,"uuid":"212815257","full_name":"ebullient/monster-combat","owner":"ebullient","description":"D\u0026D monster fighting + micrometer metrics","archived":true,"fork":false,"pushed_at":"2025-01-13T13:59:07.000Z","size":2636,"stargazers_count":35,"open_issues_count":0,"forks_count":12,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-03-08T18:09:40.672Z","etag":null,"topics":["hacktoberfest"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ebullient.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"custom":"https://www.buymeacoffee.com/ebullient"}},"created_at":"2019-10-04T12:56:28.000Z","updated_at":"2025-01-13T13:59:10.000Z","dependencies_parsed_at":"2023-11-20T16:29:05.344Z","dependency_job_id":"5fd3364d-1970-435d-80d4-91ae2925698b","html_url":"https://github.com/ebullient/monster-combat","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ebullient%2Fmonster-combat","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ebullient%2Fmonster-combat/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ebullient%2Fmonster-combat/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ebullient%2Fmonster-combat/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ebullient","download_url":"https://codeload.github.com/ebullient/monster-combat/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243919867,"owners_count":20368956,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["hacktoberfest"],"created_at":"2024-10-11T16:15:05.260Z","updated_at":"2025-03-16T19:30:41.747Z","avatar_url":"https://github.com/ebullient.png","language":"Java","funding_links":["https://www.buymeacoffee.com/ebullient"],"categories":[],"sub_categories":[],"readme":"# Monster Combat\n\nTLDR; This application had a few purposes:\n\n1. to teach me, a rookie Dungeon Master, how D\u0026D combat rules work (specifically, [D\u0026D 5e](https://www.dndbeyond.com/sources/basic-rules/combat))\n2. to explore usage and capabilities of metrics libraries, starting with [Micrometer](https://micrometer.io)\n3. to mess with metrics and spring boot applications with Kubernetes, Prometheus, and Grafana.\n\nYou can read more here [Monsters in combat: exploring application metrics with D\u0026D](https://jaxenter.com/metrics-dnd-173311.html)\n\nAdditional Notes:\n\n* The Spring application also uses WebFlux (no Tomcat).\n* The Quarkus application uses the micrometer core library\n\nOne injectable class, `CombatMetrics.java` in the core library, defines metrics gathered\nusing micrometer. This class is used by both the Spring and Quarkus-micrometer applications\nto collect custom metrics. I wanted metrics definitions to be easy to find, and easy to change.\nThis choice means I'm not making extensive use of annotation-based configurations, but I\nthink the result is clear and concise, and much less invasive than annotations would have been.\n\n## Prerequisites\n\n* [Docker](https://docs.docker.com/install/)\n* Java 11\n\n## Getting started\n\nObtain the source for this repository:\n\n* HTTPS: git clone https://github.com/ebullient/monster-combat.git\n* SSH: git clone git@github.com:ebullient/monster-combat.git\n\nStart with:\n\n```bash\ncd monster-combat           # cd into the project directory\nexport MONSTER_DIR=${PWD}   # for future reference\n```\n\n## Just the jar files\n\nIt is possible to run (and measure) this app using jars or native binaries alone.\n\n```bash\n# Use the mc.sh script to build jars (--native is optional)\n./mc.sh jars --native\n\n# OR:\n# 1. Build jars (clean is optional)\n./mvnw clean package\n\n# 2. build platform-native images (with GraalVM) .. not containerized (windows-specific, mac-specific, etc)\n./mvnw install -Dnative\n```\n\n## Container images\n\nJVM-mode and Native mode containers need to be\n\n```bash\n# Use the mc.sh script to build images (--native is optional)\n./mc.sh images --native\n\n# OR:\n# 1. Create jvm-mode containers (skipping tests)\n./mvnw clean package -Dimages -DskipTests\n\n# 2. Create native container images (skipping tests)\n./mvnw clean package -Dimages -DskipTests -Dnative\n```\n\nNB: There may be issues on windows, and there is some known weirdness on Mac M1\n\n## Measuring all the things!\n\nGet your system up and running using either\n\n* [Docker compose](#lazy-bones-quick-and-dirty-with-docker-compose) or\n* [Kubernetes](#general-bring-up-instructions-for-kubernetes)\n\nOnce you have your system configured and running, you can use `client.sh` script to keep a steady stream of\nrequests hitting an endpoint of your choosing.\n\nHopefully, it will all work fine. If it doesn't, come find me in the [gameontext slack](https://gameontext.org/slackin)\nand let me know. Or open an issue. That works, too.\n\n## Lazy bones: quick and dirty with docker-compose\n\nThis application is all about application metrics. The surrounding environment doesn't matter much.\n\nIf you're lazy, or on a constrained system, docker-compose will work fine to start all the bits.\nNote: I'm lazy, so this is the method I use the most often.\n\nSee below for notes on adding native images to the mix:\n\n```bash\n# go to docker-compose directory\ncd deploy/dc\n\n# start all services (prom, grafana, spring, quarkus, quarkus-mpmetrics)\ndocker-compose up -d\n```\n\nAlternately, use `mc.sh` to manage some of these operations for you:\n\n```bash\n# start services using docker compose\n./mc.sh dc up -d\n```\n\nThe `mc.sh` script looks for some flags (like `--native` or `--format`) to add options to maven commands,\nbut otherwise hands all remaining command line arguments to invoked commands.\nIn the case of `dc`, `mc.sh` will execute the docker-compose command with explicitly specified\ndocker-compose files, which can save a lot of typing once you add native images to the mix.\n\nYou should then be able to do the following and get something interesting in return:\n\n```bash\n# Start traffic to the /any endpoint for all of the running servers:\n./client.sh start\n# Stop all of the clients:\n./client.sh stop\n# List active clients:\n./client.sh list\n\n# Spring:\n\ncurl http://127.0.0.1:8280/\ncurl http://127.0.0.1:8280/actuator/metrics\ncurl http://127.0.0.1:8280/actuator/prometheus\ncurl http://127.0.0.1:8280/combat/faceoff  # 2 monsters\ncurl http://127.0.0.1:8280/combat/melee    # 3-6 monsters\ncurl http://127.0.0.1:8280/combat/any      # 2-6 monsters\n\n# start stream of requests to the /any endpoint of the spring server\n./client.sh spring\n\n# Quarkus\n\ncurl http://127.0.0.1:8281/\ncurl http://127.0.0.1:8281/metrics         # micrometer \u0026 prometheus\ncurl http://127.0.0.1:8281/combat/faceoff  # 2 monsters\ncurl http://127.0.0.1:8281/combat/melee    # 3-6 monsters\ncurl http://127.0.0.1:8281/combat/any      # 2-6 monsters\n\n# start stream of requests to the /any endpoint of the quarkus (micrometer) server\n./client.sh quarkus\n\n# Quarkus with MP Metrics\n\ncurl http://127.0.0.1:8282/\ncurl http://127.0.0.1:8282/metrics         # MP metrics endpoint\ncurl http://127.0.0.1:8282/combat/faceoff  # 2 monsters\ncurl http://127.0.0.1:8282/combat/melee    # 3-6 monsters\ncurl http://127.0.0.1:8282/combat/any      # 2-6 monsters\n\n# start stream of requests to the /any endpoint of the quarkus (mpmetrics) server\n./client.sh mpmetrics\n```\n\nCheck out the prometheus dashboard (http://127.0.0.1:9090) to see emitted metrics.\nYou can import pre-created dashboards (see below) to visualize collected metrics\nin grafana (http://127.0.0.1:3000, admin|admin is default username/password). When\nconfiguring the Prometheus datasource in Graphana, use the docker-compose service\nname as the hostname: `http://prometheus:9090`.\n\n### Including native images\n\nIf you are using linux, building and testing native images is straightforward,\nbut if you are using windows or mac, we need to separate the steps a bit, as the\nnative image needs to be built with a container, and that will overwrite the\nOS-native image used for tests.\n\nUse an additional docker compose file to start native images.\nAppend docker-compose.override.yml to the list of files if necessary.\n\n```bash\ndocker-compose -f docker-compose.yml -f docker-compose-native.yml up -d\n```\n\nAlternately, use `mc.sh` to manage some of these operations for you:\n\n```bash\n# start all services (including non-native) using docker compose\n./mc.sh --native dc up -d\n```\n\n```bash\n# Quarkus Native\n\ncurl http://127.0.0.1:8283/\ncurl http://127.0.0.1:8283/metrics         # micrometer \u0026 prometheus\ncurl http://127.0.0.1:8283/combat/faceoff  # 2 monsters\ncurl http://127.0.0.1:8283/combat/melee    # 3-6 monsters\ncurl http://127.0.0.1:8283/combat/any      # 2-6 monsters\n\n# start stream of requests to the /any endpoint of the quarkus (micrometer) server\n./client.sh quarkus-native\n\n# Quarkus with MP Metrics Native\n\ncurl http://127.0.0.1:8284/\ncurl http://127.0.0.1:8284/metrics         # MP metrics endpoint\ncurl http://127.0.0.1:8284/combat/faceoff  # 2 monsters\ncurl http://127.0.0.1:8284/combat/melee    # 3-6 monsters\ncurl http://127.0.0.1:8284/combat/any      # 2-6 monsters\n\n# start stream of requests to the /any endpoint of the quarkus (mpmetrics) server\n./client.sh mpmetrics-native\n```\n\n### Prometheus and Grafana with docker-compose\n\nThe `${MONSTER_DIR}/deploy/dc/config` directory contains configuration for Prometheus and Grafana when run with docker-compose.\nThe config directory is bind-mounted into both containers. The docker-compose configuration also creates a bind mount to\nservice-specific subdirectories under `${MONSTER_DIR}/deploy/dc/target/data` for output.\n\nThe config directory conains the following files:\n\n* `grafana.ini` configures grafana\n* `grafana-*.json` are importable grafana dashboards\n* `prometheus.yml` defines jobs for spring and quarkus metrics, and declares `prometheus.rules.yaml`\n* `prometheus.rules.yaml` defines reporting rules for prometheus that create additional time series to pre-aggregate chattier metrics.\n\nTo reset prometheus and grafana (tossing all data):\n\n```bash\n# From ${MONSTER_DIR}/deploy/dc directory:\ndocker-compose stop prom grafana\ndocker-compose rm prom grafana\n# Remove data for prometheus and grafana\nrm -rf ./target/data/prometheus/*  ./target/data/grafana/*\n# restart\ndocker-compose up -d prom grafana\n```\n\nNote: the prometheus and grafana data directories must be owned\nby the host user. If you delete the directories by accident, recreate them manually before using docker-compose to start\nthe services again (as it will create the missing directories for you, and those will be owned by root, which will cause\npermission issues for services running as the host user).\n\n### Overlaying runtime container configuration\n\n1. Copy a configuration file, e.g. copy `quarkus-micrometer/src/main/resources/application.properties` to\n`${MONSTER_DIR}/deploy/dc/target/mc-quarkus-micrometer.properties`\n\n2. Create an override file, `${MONSTER_DIR}/deploy/dc/docker-compose.override.yml`, that mounts this file as a volume, replacing\n   the configuration file in the image:\n\n    ```yaml\n    version: '3.7'\n    services:\n\n      quarkus:\n        volumes:\n        - './target/mc-quarkus-micrometer.properties:/app/resources/application.properties'\n    ```\n\n## General bring-up instructions for Kubernetes\n\n[Initialize your cluster](#set-up-a-kubernetes-cluster)\n\n1. [Create or retrieve credentials for your cluster](#set-up-a-kubernetes-cluster)\n\n2. Set up custom namespaces (`gameontext` and `ebullientworks`)\n\n    ```bash\n    kubectl apply -f deploy/k8s/namespaces.yaml\n    ```\n\n3. Set up [kube-prometheus](https://github.com/coreos/kube-prometheus)\n\n    This script wraps all kinds of jsonnet goodness in a container so there is less setup over-all:\n\n    ```bash\n    ./deploy/k8s/kube-prometheus/build.sh prep     # Once. setup kube-prometheus jsonnet\n    # At least one time. Repeat if you change the monsters.jsonnet file\n    ./deploy/k8s/kube-prometheus/build.sh generate # Create manifests\n    ./deploy/k8s/kube-prometheus/build.sh apply    # Apply configuration to cluster\n    ```\n\n    Note there are customizations happening (in `./deploy/k8s/kube-prometheus/monsters.jsonnet`):\n\n    1. We reduce prometheus and alertmanager to single replicas. This is definitely a \"fit on a tinier system\" move that\n       goes away from resilience.\n    2. We instruct prometheus to monitor three additional namespaces: `gameon-system`, `ebullientworks` and `default`.\n       The first is for services from https://gameontext.org, the second is used by this project, and the third is for\n       your own experiments.\n\n4. Create an ingress for prometheus and grafana\n\n    ```bash\n    kubectl apply -f deploy/k8s/ingress/monitoring-ingress.yaml\n    echo \"Use the following urls for\n    Prometheus: http://prometheus.$(minikube ip).nip.io\n    Grafana dashboard: http://grafana.$(minikube ip).nip.io\"\n    ```\n\n4. Once the kube-prometheus manifests have applied cleanly, set up a Prometheus `ServiceMonitor` for our applications:\n\n    ```bash\n    kubectl apply -f deploy/k8s/service-monitor/\n    ```\n\n    If you delete/re-apply kube-prometheus metadata, you'll need to reapply this, too, as it is deployed into\n    the `monitoring` namespace.\n\n    For best results, ensure this is applied, and both `mc-quarkus-prometheus` and `mc-spring-prometheus` are\n    included in the list of Prometheus targets before moving on to the next step.\n\n    ```bash\n    echo Visit http://prometheus.$(minikube ip).nip.io/targets\n    ```\n\n4. Finally (!!), build and install the application:\n\n    ```bash\n    # Choices choices. For minikube, you may want to share the VM registry\n    eval $(minikube docker-env)\n\n    # Run through all of the sub-projects and build them\n    # in the local docker registry. Feel free to change that up.\n\n    ./mvnw install\n\n    # Depending on your choices, you may have to do a docker push\n    # to put fresh images wherever they need to go.\n\n    # Now deploy application metadata (service, deployment, ingress)\n    # Verify that the ingress definition will work for your kubernetes cluster\n\n    kubectl apply -f deploy/k8s/monsters/\n    kubectl apply -f deploy/k8s/ingress/monster-ingress.yaml\n    echo \"\n    Spring with Micrometer: http://spring.$(minikube ip).nip.io\n    Quarkus with Micrometer: http://quarkus.$(minikube ip).nip.io\n    Quarkus with MP Metrics: http://mpmetrics.$(minikube ip).nip.io\"\n    ```\n\nSo, after all of that, you should be able to do the following and get something interesting in return:\n\n```bash\n# This assumes minikube and/or minishift, with the configured ingress URL\ncurl http://monsters.192.168.99.100.nip.io/\ncurl http://monsters.192.168.99.100.nip.io/actuator/metrics\ncurl http://monsters.192.168.99.100.nip.io/actuator/prometheus\n\n# Encounters:\n# faceoff is 2 monsters\ncurl http://monsters.192.168.99.100.nip.io/combat/faceoff\n# melee is 3-6 monsters\ncurl http://monsters.192.168.99.100.nip.io/combat/melee\n# any is random from 2-6\ncurl http://monsters.192.168.99.100.nip.io/combat/any\n```\n\nCheck out the prometheus endpoint to see what metrics are being emitted.\n\n### Messing around with application configuration using ConfigMaps\n\nWe'll use Quarkus Micrometer for this example.\n\n1. Let's start by creating a new ConfigMap for application.properties that specifies\n   runtime configuration attributes, e.g. `deploy/k8s/config/mc-quarkus-micrometer-config.yaml`\n\n    ```yaml\n    apiVersion: v1\n    kind: ConfigMap\n    metadata:\n      name: mc-quarkus-micrometer-config\n      namespace: ebullientworks\n    data:\n      application.properties: |+\n        quarkus.http.port=8080\n    ```\n\n2. Update the appropriate deployment definition to reference the volume, e.g. `deploy/k8s/monsters/quarkus-micrometer.yaml`:\n\n    ```yaml\n       spec:\n         volumes:\n           - name: properties-volume\n             configMap:\n               name: mc-quarkus-micrometer-config\n         containers:\n         - image: ebullient/mc-quarkus-micrometer:latest-jvm\n           imagePullPolicy: IfNotPresent\n           name: mc-quarkus-micrometer\n           volumeMounts:\n           - name: properties-volume\n             mountPath: /app/resources/mc-quarkus-micrometer.properties\n      ...\n    ```\n\n3. Create the ConfigMap and update your deployment\n\n    ```bash\n    kubectl apply -f deploy/k8s/config/mc-quarkus-micrometer-config.yaml\n    kubectl apply -f deploy/k8s/monsters/quarkus-micrometer.yml\n    ```\n\n\n---\n\n### Set up a Kubernetes cluster\n\n`kubectl` needs to be able to talk to a Kuberenetes cluster! You may have one already, in which case, all you need to do\nis make sure `kubectl` can work with it.\n\n* [Minikube](#working-with-minikube) -- local development cluster\n* [CodeReady Containers](#working-with-codeready-containers) -- local development cluster (OpenShift 3.x)\n\n### Working with minikube\n\nIf you already have a configured minikube instance, skip to step 3.\n\n1. [Install minikube](https://kubernetes.io/docs/tasks/tools/install-minikube/)\n\n2. Start Minikube:\n\n    ```bash\n    minikube delete\n    minikube start --kubernetes-version=v1.19.4 \\\n    --cpus 4 --disk-size 40g \\\n    --memory 16384 --bootstrapper=kubeadm \\\n    --extra-config=kubelet.authentication-token-webhook=true \\\n    --extra-config=kubelet.authorization-mode=Webhook \\\n    --extra-config=scheduler.address=0.0.0.0 \\\n    --extra-config=controller-manager.address=0.0.0.0\n    minikube addons disable metrics-server\n    minikube addons enable ingress\n    ```\n\n3. Ensure the `minikube` context is current context for `kubectl`\n\n    ```bash\n    kubectl config set-context minikube\n\n    # ensure ingress is working\n    curl -v --raw http://$(minikube ip)/healthz\n    ```\n\n4. Update the ingress for your cluster to match the IP\n\n    ```bash\n    ./mvnw -Dcluster.ip=$(minikube ip) -Dminikube install -pl deploy/k8s\n    ```\n\n### Working with CodeReady Containers\n\nComing soon.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Febullient%2Fmonster-combat","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Febullient%2Fmonster-combat","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Febullient%2Fmonster-combat/lists"}