{"id":19331371,"url":"https://github.com/andriykalashnykov/spring-on-k8s","last_synced_at":"2025-04-22T23:31:53.865Z","repository":{"id":37984137,"uuid":"444558531","full_name":"AndriyKalashnykov/spring-on-k8s","owner":"AndriyKalashnykov","description":"Run a Spring Boot app on Kubernetes","archived":false,"fork":false,"pushed_at":"2024-04-09T03:47:37.000Z","size":2041,"stargazers_count":7,"open_issues_count":10,"forks_count":5,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-04-18T23:46:00.392Z","etag":null,"topics":["buildpacks","custom-buildpack","cve-scanning","docker","docker-image","java","kapp","kubernetes","maven","observability","opentracing","pack","spring-boot","spring-cloud-sleuth","swagger","swagger-ui","tanzu","ytt"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/AndriyKalashnykov.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"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}},"created_at":"2022-01-04T20:46:37.000Z","updated_at":"2023-09-08T07:29:03.000Z","dependencies_parsed_at":"2023-11-28T04:49:37.369Z","dependency_job_id":null,"html_url":"https://github.com/AndriyKalashnykov/spring-on-k8s","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AndriyKalashnykov%2Fspring-on-k8s","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AndriyKalashnykov%2Fspring-on-k8s/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AndriyKalashnykov%2Fspring-on-k8s/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AndriyKalashnykov%2Fspring-on-k8s/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/AndriyKalashnykov","download_url":"https://codeload.github.com/AndriyKalashnykov/spring-on-k8s/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250340315,"owners_count":21414522,"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":["buildpacks","custom-buildpack","cve-scanning","docker","docker-image","java","kapp","kubernetes","maven","observability","opentracing","pack","spring-boot","spring-cloud-sleuth","swagger","swagger-ui","tanzu","ytt"],"created_at":"2024-11-10T02:39:49.857Z","updated_at":"2025-04-22T23:31:53.440Z","avatar_url":"https://github.com/AndriyKalashnykov.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Test](https://github.com/AndriyKalashnykov/spring-on-k8s/actions/workflows/test.yml/badge.svg?branch=main)](https://github.com/AndriyKalashnykov/spring-on-k8s/actions/workflows/test.yml)\n[![Hits](https://hits.seeyoufarm.com/api/count/incr/badge.svg?url=https%3A%2F%2Fgithub.com%2FAndriyKalashnykov%2Fspring-on-k8s\u0026count_bg=%2379C83D\u0026title_bg=%23555555\u0026icon=\u0026icon_color=%23E7E7E7\u0026title=hits\u0026edge_flat=false)](https://hits.seeyoufarm.com)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n# Running Spring Boot app on Kubernetes\n\nThis project describes how to run Spring Boot app on Kubernetes.\nYou don't actually need to rewrite your app in order to target a K8s\ncluster: Spring Boot can run on many platforms, thanks to\nthe abstraction level it provides.\n\nThis app is made of a single REST controller:\n\n```java\n@RestController\n\nclass HelloController {\n    @Value(\"${app.message:Hello world!}\")\n    private String message;\n  \n    @GetMapping(value = \"/\", produces = MediaType.TEXT_PLAIN_VALUE)\n    String greeting() {\n        // Just return a simple String.\n        return message;\n    }\n}\n```\n\n## Pre-requisites\n\n* [sdkman](https://sdkman.io/install)\n\n    Install and use JDK 19\n\n    ```bash\n    sdk install java 19-tem\n    sdk use java 19-tem\n    ```\n* [Apache Maven](https://maven.apache.org/install.html)\n\n  Install Apache Maven 3.8.6\n\n    ```bash\n    sdk install maven 3.8.6\n    sdk use maven 3.8.6\n    ```\n* [Docker](https://docs.docker.com/engine/install/)\n* [Cloud Native Buildpacks](https://buildpacks.io/docs/tools/pack/)\n* [curl](https://help.ubidots.com/en/articles/2165289-learn-how-to-install-run-curl-on-windows-macosx-linux)\n* [jq](https://github.com/stedolan/jq/wiki/Installation)\n* [git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git)\n* [kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/)\n* [carvel](https://carvel.dev/)\n* [Taznu CLI and plugins](https://docs-staging.vmware.com/en/Tanzu-Application-Platform/1.0/tap/GUID-install-general.html#cli-and-plugin) - Optional\n\n### Compiling application\n\n```bash\nmvn clean package -Djava.version=19\n```\n\n### Running application locally\n\n```bash\nmvn clean spring-boot:run -Djava.version=19\n```\n\nThe app is available at [http://localhost:8080](http://localhost:8080)\n\n```bash\ncurl localhost:8080/v1/hello\nHello world!\n\ncurl localhost:8080/v1/bye\nBye world!\n```\n\n#### Application health, configurations etc.\n\n```bash\ncurl http://localhost:8080/actuator | jq .\n\n{\n  \"_links\": {\n    \"self\": {\n      \"href\": \"http://localhost:8080/actuator\",\n      \"templated\": false\n    },\n    \"health\": {\n      \"href\": \"http://localhost:8080/actuator/health\",\n      \"templated\": false\n    },\n    \"health-path\": {\n      \"href\": \"http://localhost:8080/actuator/health/{*path}\",\n      \"templated\": true\n    },\n    \"prometheus\": {\n      \"href\": \"http://localhost:8080/actuator/prometheus\",\n      \"templated\": false\n    }\n  }\n}\n```\n\n#### Application REST API documentation with Swagger UI\n\nOpen Swagger UI page [http://localhost:8080/swagger-ui/](http://localhost:8080/swagger-ui/)\n\n![Swagger UI](./docs/swagger-ui.png \"Swagger UI\")\n\n## Creating a Docker image\n\nOur goal is to run this app in a K8s cluster: you first need to package\nthis app in a Docker image.\n\n### Buildpacks\n\nUse [Cloud Native Buildpacks](https://buildpacks.io) to build \u0026 push your Docker image:\n\n```bash \nexport DOCKER_LOGIN=andriykalashnykov\nexport DOCKER_PWD=YOUR-REGISTRY-PASSWORD\nmvn clean spring-boot:build-image -Djava.version=18 -Dimage.publish=true -Dimage.name=andriykalashnykov/spring-on-k8s:latest -Ddocker.publishRegistry.username=${DOCKER_LOGIN} -Ddocker.publishRegistry.password=${DOCKER_PWD}\n```\n\n### Docker\nIf you \u003ci\u003estill\u003c/i\u003e want to do it with Docker - here's a proper (multistage, non-root, JAR layers, distroless runtime image base, etc.) [`Dockerfile`](https://github.com/AndriyKalashnykov/spring-on-k8s/blob/facebc172dbb9f068167da774b50b41ae3385a82/Dockerfile) you can use.\n\nRun this command to build this image:\n```bash\ndocker build -t andriykalashnykov/spring-on-k8s:latest --build-arg JDK_VENDOR=eclipse-temurin --build-arg JDK_VERSION=17 .\n```\n\nYou can now push this image to your favorite Docker registry:\n```bash\ndocker push andriykalashnykov/spring-on-k8s:latest\n```\n\n## Scanning for [Log4j 2 CVE-2021-44228](https://www.docker.com/blog/apache-log4j-2-cve-2021-44228/) and other vulnerabilities \n\n```bash\n# scan for all CVEs\ndocker scan andriykalashnykov/spring-on-k8s:latest \n# scan for CVE-2021-44228\ndocker scan andriykalashnykov/spring-on-k8s:latest  | grep 'Arbitrary Code Execution'\n```\n\n### Using workaround to mitigate `Log4j 2 CVE-2021-44228` by creating Docker image with [custom buildpack](https://github.com/alexandreroman/cve-2021-44228-workaround-buildpack)\n\n```bash\npack build andriykalashnykov/spring-on-k8s:latest  -b ghcr.io/alexandreroman/cve-2021-44228-workaround-buildpack -b paketo-buildpacks/java --builder paketobuildpacks/builder:buildpackless-base\n```\n\n## Running Docker image\n\n```bash\ndocker run --rm -p 8080:8080 andriykalashnykov/spring-on-k8s:latest \n```\n\n## Deploying application to Kubernetes\n\nThis project includes Kubernetes descriptors, so you can easily deploy\nthis app to your favorite K8s cluster:\n\n```bash\nytt -f ./k8s | kapp deploy -y --into-ns spring-on-k8s -a spring-on-k8s -f-\n```\n\nUsing this command, monitor the allocated IP address for this app:\n```bash\nkubectl -n spring-on-k8s get svc\n\nNAME     TYPE           CLUSTER-IP       EXTERNAL-IP     PORT(S)        AGE\napp-lb   LoadBalancer   xx.100.200.204   xx.205.141.26   80:31633/TCP   90s\n```\n\nAt some point, you should see an IP address under the column `EXTERNAL-IP`.\n\nIf you hit this address, you will get a greeting message from the app:\n\n```bash\ncurl $(kubectl -n spring-on-k8s get svc app | sed -n '2 p' | awk '{print $4}')\n\nHello Kubernetes!\n```\n\n## Undeploy application from Kubernetes\n\n```bash\nkapp delete -a spring-on-k8s --yes\n```\n\n## Configure VMware Tanzu Observability (Wavefront)\n\nWavefront for Spring Boot allows you to quickly configure your\nenvironment, so Spring Boot components send metrics, histograms,\nand traces/spans to the Wavefront service, for more details see\nhow to [examine Spring Boot data in Wavefront dashboards and charts](https://docs.wavefront.com/wavefront_springboot.html#prerequisites-for-wavefront-spring-boot-starter)\n\n### Sending Data From Spring Boot Into Wavefront\n\nYou can send data from your Spring Boot applications into Wavefront using the Wavefront for Spring Boot Starter \n(all users) or the Wavefront Spring Boot integration (Wavefront customers and trial users).\n\n* **Freemium** :  All users can run the Spring Boot Starter with the default settings to view their data in the Wavefront Freemium instance. Certain limitations apply, for example, alerts are not available, but you don’t have to sign up.\n* **Wavefront Customer or Trial User** : Wavefront customers or trial users can modify the default Wavefront Spring Boot Starter to send data to their cluster. [You can sign up for a free 30-day trial here](https://tanzu.vmware.com/observability)\n\n#### Sending Data From Spring Boot Into Wavefront - Freemium\n\nTo configure `Freeminum` modify [application.yml](https://github.com/AndriyKalashnykov/spring-on-k8s/blob/2d109fbb2ea2a5c3c4a99a55c6daa9c8700e78f0/src/main/resources/application.yml)\nby specifying `freemium-account : true`, setting `name` of the overarching application and current `service` name in particular.\n\n```yaml\nwavefront:\n  freemium-account: true\n  application:\n    name: spring-on-k8s\n    service: backend\n```\n\n#### Sending Data From Spring Boot Into Wavefront - Wavefront Customer or Trial User\n\nTo configure `Wavefront Customer or Trial User` modify [application.yml](https://github.com/AndriyKalashnykov/spring-on-k8s/blob/2d109fbb2ea2a5c3c4a99a55c6daa9c8700e78f0/src/main/resources/application.yml)\nby specifying `freemium-account : false` and providing `uri` and `api-token` of the Wavefront instance.\n\n```yaml\nwavefront:\n  freemium-account: false\n  application:\n    name: spring-on-k8s\n    service: backend\n\nmanagement:\n  metrics:\n    export:\n      wavefront:\n        api-token: \"$API_Token\"\n        uri: \"$wavefront_instance\"\n```\n\nWe also need to configure Wavefront dependencies based on how you want to send data to Wavefront. Two options are available \n`Spring Cloud Sleuth` and `OpenTracing`.\n\n#### Sending data to `Wavefront` with `Spring Cloud Sleuth`\n\nModfy Maven project file [`pom.xml`](https://github.com/AndriyKalashnykov/spring-on-k8s/blob/831fc8364ab39b8eacb854aa18b51ca8ba2ff704/pom.xml)\n\n```xml\n\u003cdependencyManagement\u003e\n  \u003cdependencies\u003e\n    \u003cdependency\u003e\n      \u003cgroupId\u003ecom.wavefront\u003c/groupId\u003e\n      \u003cartifactId\u003ewavefront-spring-boot-bom\u003c/artifactId\u003e\n      \u003cversion\u003e2.2.0\u003c/version\u003e\n      \u003ctype\u003epom\u003c/type\u003e\n      \u003cscope\u003eimport\u003c/scope\u003e\n    \u003c/dependency\u003e\n    \n    \u003cdependency\u003e\n      \u003cgroupId\u003eorg.springframework.cloud\u003c/groupId\u003e\n      \u003cartifactId\u003espring-cloud-dependencies\u003c/artifactId\u003e\n      \u003cversion\u003e2020.0.4\u003c/version\u003e\n      \u003ctype\u003epom\u003c/type\u003e\n      \u003cscope\u003eimport\u003c/scope\u003e\n    \u003c/dependency\u003e\n  \u003c/dependencies\u003e\n\u003c/dependencyManagement\u003e\n\n\u003cdependencies\u003e\n  \u003cdependency\u003e\n    \u003cgroupId\u003ecom.wavefront\u003c/groupId\u003e\n    \u003cartifactId\u003ewavefront-spring-boot-starter\u003c/artifactId\u003e\n  \u003c/dependency\u003e                   \n  \u003cdependency\u003e\n    \u003cgroupId\u003eorg.springframework.cloud\u003c/groupId\u003e\n    \u003cartifactId\u003espring-cloud-starter-sleuth\u003c/artifactId\u003e\n  \u003c/dependency\u003e\n\u003c/dependencies\u003e\n```\n\n#### Sending data to `Wavefront` with `OpenTracing`\n\nModfy Maven project file [`pom.xml`](https://github.com/AndriyKalashnykov/spring-on-k8s/blob/831fc8364ab39b8eacb854aa18b51ca8ba2ff704/pom.xml)\n\n```xml\n\u003cdependencyManagement\u003e\n  \u003cdependencies\u003e\n    \u003cdependency\u003e\n      \u003cgroupId\u003ecom.wavefront\u003c/groupId\u003e\n      \u003cartifactId\u003ewavefront-spring-boot-bom\u003c/artifactId\u003e\n      \u003cversion\u003e2.2.0\u003c/version\u003e\n      \u003ctype\u003epom\u003c/type\u003e\n      \u003cscope\u003eimport\u003c/scope\u003e\n    \u003c/dependency\u003e\n  \u003c/dependencies\u003e\n\u003c/dependencyManagement\u003e\n\n\u003cdependencies\u003e\n  \u003cdependency\u003e\n    \u003cgroupId\u003ecom.wavefront\u003c/groupId\u003e\n    \u003cartifactId\u003ewavefront-spring-boot-starter\u003c/artifactId\u003e\n  \u003c/dependency\u003e\n  \n  \u003cdependency\u003e\n    \u003cgroupId\u003eio.opentracing.contrib\u003c/groupId\u003e\n    \u003cartifactId\u003eopentracing-spring-cloud-starter\u003c/artifactId\u003e\n    \u003cversion\u003e0.5.9\u003c/version\u003e\n  \u003c/dependency\u003e\n\u003c/dependencies\u003e\n```\n\nNow you can run the project and observe link to the Wavefront dashboard:\n\n```bash\nmvn clean package\n\n[INFO] Scanning for projects...\n  .   ____          _            __ _ _\n /\\\\ / ___'_ __ _ _(_)_ __  __ _ \\ \\ \\ \\\n( ( )\\___ | '_ | '_| | '_ \\/ _` | \\ \\ \\ \\\n \\\\/  ___)| |_)| | | | | || (_| |  ) ) ) )\n  '  |____| .__|_| |_|_| |_\\__, | / / / /\n =========|_|==============|___/=/_/_/_/\n :: Spring Boot ::                (v2.5.5)\n\n2022-01-12 Wed 16:28:04.185 INFO  59841 [    main] com.vmware.demos.springonk8s.ApplicationTests:55 : Starting ApplicationTests using Java 17.0.1 on akalashnyko-a02.vmware.com with PID 59841 (started by akalashnykov in /Users/akalashnykov/projects/spring-on-k8s)\n2022-01-12 Wed 16:28:04.186 INFO  59841 [    main] com.vmware.demos.springonk8s.ApplicationTests:659 : No active profile set, falling back to default profiles: default\n2022-01-12 Wed 16:28:04.820 INFO  59841 [    main] org.springframework.cloud.context.scope.GenericScope:283 : BeanFactory id=964ae347-b9e4-313e-8d67-3ac7de89d489\n2022-01-12 Wed 16:28:05.287 INFO  59841 [    main] org.springframework.boot.web.embedded.tomcat.TomcatWebServer:108 : Tomcat initialized with port(s): 0 (http)\n2022-01-12 Wed 16:28:05.295 INFO  59841 [    main] org.apache.catalina.core.StandardService:173 : Starting service [Tomcat]\n2022-01-12 Wed 16:28:05.296 INFO  59841 [    main] org.apache.catalina.core.StandardEngine:173 : Starting Servlet engine: [Apache Tomcat/9.0.53]\n2022-01-12 Wed 16:28:05.391 INFO  59841 [    main] org.apache.catalina.core.ContainerBase.[Tomcat].[localhost].[/]:173 : Initializing Spring embedded WebApplicationContext\n2022-01-12 Wed 16:28:05.391 INFO  59841 [    main] org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext:290 : Root WebApplicationContext: initialization completed in 1189 ms\n2022-01-12 Wed 16:28:05.492 INFO  59841 [    main] io.micrometer.core.instrument.push.PushMeterRegistry:71 : publishing metrics for WavefrontMeterRegistry every 1m\n2022-01-12 Wed 16:28:07.116 INFO  59841 [    main] org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver:58 : Exposing 4 endpoint(s) beneath base path '/actuator'\n2022-01-12 Wed 16:28:07.201 INFO  59841 [    main] org.springframework.boot.web.embedded.tomcat.TomcatWebServer:220 : Tomcat started on port(s): 65081 (http) with context path ''\n2022-01-12 Wed 16:28:07.224 INFO  59841 [    main] com.vmware.demos.springonk8s.ApplicationTests:61 : Started ApplicationTests in 4.046 seconds (JVM running for 4.742)\n\nYour existing Wavefront account information has been restored from disk.\n\nTo share this account, make sure the following is added to your configuration:\n\n        management.metrics.export.wavefront.api-token=dc9addea-8bae-467e-8f04-6b5dcfad1527\n        management.metrics.export.wavefront.uri=https://wavefront.surf\n\nConnect to your Wavefront dashboard using this one-time use link:\nhttps://wavefront.surf/us/8HggSpT5BD\n\n2022-01-12 Wed 16:28:07.773 INFO  59841 [o-auto-1-exec-1] org.apache.catalina.core.ContainerBase.[Tomcat].[localhost].[/]:173 : Initializing Spring DispatcherServlet 'dispatcherServlet'\n2022-01-12 Wed 16:28:07.773 INFO  59841 [o-auto-1-exec-1] org.springframework.web.servlet.DispatcherServlet:525 : Initializing Servlet 'dispatcherServlet'\n2022-01-12 Wed 16:28:07.775 INFO  59841 [o-auto-1-exec-1] org.springframework.web.servlet.DispatcherServlet:547 : Completed initialization in 2 ms\n[INFO] Tests run: 4, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 5.13 s - in com.vmware.demos.springonk8s.ApplicationTests\n[INFO] \n[INFO] Results:\n[INFO] \n[INFO] Tests run: 4, Failures: 0, Errors: 0, Skipped: 0\n\n```\n\nClick on Wavefront dashboard link [https://wavefront.surf/us/8HggSpT5BD](https://wavefront.surf/us/8HggSpT5BD) and navigate to `Dashboards -\u003e Spring Boot`\n\n\n![Spring Boot Dashboard](./docs/spring-dash.png \"Spring Boot Dashboard\")\n\nyou may also want to check `Applications -\u003e Traces`\n\n![Application Traces Dashboard](./docs/traces-dash.png \"Application Traces Dashboard\")\n\n## Application Accelerator for VMware Tanzu\n\n[Creating Application Accelerators](https://docs.vmware.com/en/Application-Accelerator-for-VMware-Tanzu/1.0/acc-docs/GUID-creating-accelerators-index.html)\nand [Creating an accelerator.yaml](https://docs.vmware.com/en/Application-Accelerator-for-VMware-Tanzu/1.0/acc-docs/GUID-creating-accelerators-accelerator-yaml.html)\n\n## Publishing the accelerator\n\n### With kubectl\n\n```bash\nmkdir -p ~/projects/; cd ~/projects/\ngit clone git@github.com:AndriyKalashnykov/spring-on-k8s.git\n\nkubectl apply -f  ~/projects/spring-on-k8s/k8s-resource.yaml --namespace accelerator-system\n```\n\n### With Tanzu CLI\n\n```bash\ntanzu acc create spring-on-k8s --kubeconfig $HOME/.kube/config  --git-repository https://github.com/AndriyKalashnykov/spring-on-k8s.git --git-branch main\n```\n\n## Deleting the accelerator\n\n### With kubectl\n```bash\nkubectl delete -f  ~/projects/spring-on-k8s/k8s-resource.yaml --namespace accelerator-system\n``` \n\n### With Tanzu CLI\n\n```bash\ntanzu acc delete spring-on-k8s --kubeconfig $HOME/.kube/config\n```\n\n## Contribute\n\nContributions are always welcome!\n\nFeel free to open issues \u0026 send PR.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandriykalashnykov%2Fspring-on-k8s","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fandriykalashnykov%2Fspring-on-k8s","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandriykalashnykov%2Fspring-on-k8s/lists"}