{"id":24617620,"url":"https://github.com/pacphi/spring-boot-with-kotlin-and-jpa-example","last_synced_at":"2025-10-26T11:33:49.213Z","repository":{"id":43256972,"uuid":"127375286","full_name":"pacphi/spring-boot-with-kotlin-and-jpa-example","owner":"pacphi","description":"Sample Spring Boot microservice implemented with Kotlin","archived":false,"fork":false,"pushed_at":"2023-07-29T18:21:27.000Z","size":177,"stargazers_count":3,"open_issues_count":23,"forks_count":4,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-03-31T06:51:08.128Z","etag":null,"topics":["docker","java","kubernetes","pivotal-application-service","spring-boot"],"latest_commit_sha":null,"homepage":null,"language":"Kotlin","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/pacphi.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}},"created_at":"2018-03-30T03:11:53.000Z","updated_at":"2023-07-29T18:21:05.000Z","dependencies_parsed_at":"2023-01-23T00:30:16.811Z","dependency_job_id":null,"html_url":"https://github.com/pacphi/spring-boot-with-kotlin-and-jpa-example","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/pacphi%2Fspring-boot-with-kotlin-and-jpa-example","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pacphi%2Fspring-boot-with-kotlin-and-jpa-example/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pacphi%2Fspring-boot-with-kotlin-and-jpa-example/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pacphi%2Fspring-boot-with-kotlin-and-jpa-example/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pacphi","download_url":"https://codeload.github.com/pacphi/spring-boot-with-kotlin-and-jpa-example/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252819650,"owners_count":21809059,"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":["docker","java","kubernetes","pivotal-application-service","spring-boot"],"created_at":"2025-01-24T23:39:45.205Z","updated_at":"2025-10-26T11:33:43.940Z","avatar_url":"https://github.com/pacphi.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Example: Spring Boot with Kotlin and JPA\n\nThis repository contains a sample Spring Boot microservice implemented with Kotlin.\n\nBuilds further upon the ideas and implementation in this [article](https://blog.codecentric.de/en/2017/06/kotlin-spring-working-jpa-data-classes/) on the codecentric blog.\n\nAlso serves as a proving ground to explore and compare the relative levels of effort to get a service and database configured and deployed to multiple container orchestration platforms:\n\n* Docker\n* Pivotal Application Service\n* Kubernetes ( minikube | GKE | Azure | Pivotal Container Service (PKS) )\n\n## Prerequisites\n\n* [jq](https://stedolan.github.io/jq/) 1.5 or better\n* Java [JDK](http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html) 1.8u162 or better\n\t* Note: as of 2018-07-28 this project does not yet work with Java 10 or 11.\n* [CF CLI](https://github.com/cloudfoundry/cli#downloads) 6.35.2 or better if you want to push the application to a Cloud Foundry (CF) instance\n* [Postman](https://www.getpostman.com) 6.0.10 or better to simplify interaction with API endpoints\n* An instance of [Postgres](https://www.postgresql.org) 10.3 or better\n* Docker ([Community](https://store.docker.com/search?type=edition\u0026offering=community) or [Enterprise](https://store.docker.com/search?type=edition\u0026offering=enterprise) Editions for Windows | Mac | Linux) 18.03.0 or better\n* Google Cloud [SDK](https://cloud.google.com/sdk/) 195.0.0 or better\n* Azure [CLI](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli?view=azure-cli-latest) 2.0 or better\n* Kubernetes if you want to deploy the application to minikube, GKE, Azure or PKS\n\t* [kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/) 1.10.0 or better\n\t* [minikube](https://github.com/kubernetes/minikube/releases) 0.25.2 or better \n\t* [kops](https://github.com/kubernetes/kops) 1.8.1 or better\n\t* [juju](https://kubernetes.io/docs/getting-started-guides/ubuntu/installation/) 2.3 or better\n\t* [GKE](https://cloud.google.com/kubernetes-engine/docs/quickstart)\n\t* [Azure](https://docs.microsoft.com/en-us/azure/virtual-machines/linux/overview#getting-started-with-linux-on-azure)\n\t* [PKS](https://docs.pivotal.io/runtimes/pks/1-0/using-prerequisites.html) 1.0.0\n\n\n## Clone\n\n```\ngit clone https://github.com/pacphi/spring-boot-with-kotlin-and-jpa-example.git\n```\n\n\n## How to Build\n\n### with Maven\n\n```\ncd spring-boot-with-kotlin-and-jpa-example\n./mvnw package\n```\n\n### with Gradle\n\n```\ncd spring-boot-with-kotlin-and-jpa-example\nrm -Rf cities-web/build\nmkdir -p cities-web/build\ntouch cities-web/build/oauth2accesstoken\n./gradlew build\n```\n\nAn artifact is produced with a `version` which is managed in both the `pom.xml` and `gradle.properties` files in the root of this project.  Where you see `x.x.x` below, replace with the a real version (e.g., `1.0.0-SNAPSHOT`).\n\n\n## How to set up a Kubernetes cluster\n\n### on Minikube\n\nSetup\n\n```\nminikube start\nminikube dashboard\n```\n\nTeardown\n\n```\nminikube stop\nminikube delete\n```\n\n### on GKE using kops\n\n\u003e Distilled from [Getting Started with kops on GCE](https://github.com/kubernetes/kops/blob/master/docs/tutorial/gce.md)\n\nCreate environment variables\n\n```\nexport BUCKET_SUFFIX=\u003creplace_with_bucket_suffix\u003e\nexport PROJECT=`gcloud config get-value project`\nexport KOPS_FEATURE_FLAGS=AlphaAllowGCE\nexport ZONE=\u003creplace_with_zone\u003e\nexport KOPS_STATE_STORE=gs://kubernetes-clusters-${BUCKET_SUFFIX}/\n```\n\nCreate storage bucket\n\n```\ngsutil mb gs://kubernetes-clusters-${BUCKET_SUFFIX}\n```\n\nCreate cluster configuration\n\n```\nkops create cluster simple.k8s.local --zones ${ZONE} --project=${PROJECT} --ssh-public-key=\u003creplace_with_ssh_public_key\u003e\n```\n\nCheck configuration\n\n```\nkops get cluster\nkops get cluster simple.k8s.local -oyaml\nkops get instancegroup --name simple.k8s.local\n```\n\nCreate cluster\n\n```\nkops update cluster simple.k8s.local --yes\nkops validate cluster\n```\n\nUse \n\n```\nkubectl get nodes --show-labels\n```\n\nTeardown\n\n```\nkops delete cluster simple.k8s.local --yes\n```\n\n### on Azure using juju\n\n\u003e Distilled from [Using the Microsoft Azure public cloud](https://jujucharms.com/docs/devel/help-azure) and [Setting up Kubernetes with Juju](https://kubernetes.io/docs/getting-started-guides/ubuntu/installation/)\n\nInitialize juju\n\n```\njuju update-clouds\n```\n\nAuthenticate and list subscription(s)\n\n```\naz login\naz account list\n```\n\nCreate service principal (if one does not already exist)\n\n```\nexport SUB_ID=`az account list | jq '.[0].id' -r`\nexport APP_PASSWORD=b00tMe\naz ad sp create-for-rbac --name \"my.k8s.io\" --password $APP_PASSWORD --role Owner\n```\n\n\u003e Notes: (1) We're setting a subscription id variable to the first id returned from the acccount list. If you have more than one account; be sure choose one with elevated privileges. (2) The `APP_PASSWORD` value should be replaced. (3) The `--name` option from the create service principal command above is arbitrary. (4) Capture `appId` and `tenantId` from the output. Export two additional environment variables based on these values.\n\n```\nexport APP_ID=...\nexport TENANT_ID=...\n```\n\nLogin with service principal\n\n```\naz login --service-principal -u $APP_ID -p $APP_PASSWORD --tenant $TENANT_ID\n```\n\nList environment variables with ID\n\n```\nenv | grep ID\n```\n\nAdd service principal credentials to juju\n\n```\njuju add-credential azure\n```\n\n\u003e When prompted enter an arbitrary credential name, select `service-principal-secret` as the `Auth type`, and employ `$APP_ID`, `$SUB_ID` and `$APP_PASSWORD` environment variables values respectively for `application-id`, `subscription-id` and `application-password`.\n\nCreate controller and deploy cluster\n\n```\njuju bootstrap azure/{REGION} {CLUSTER_NAME}\njuju deploy canonical-kubernetes\n```\n\n\u003e Replace {REGION} and {CLUSTER_NAME} above with a valid [region](https://azure.microsoft.com/en-us/global-infrastructure/regions/) within Azure and an arbitrary name for your cluster. Creating the controller will take 5-10 minutes. Deploying the cluster will take another 10-15 minutes.\n\nMonitor deployment\n\n```\njuju status\n```\n\n\u003e When all states are green and Idle, the cluster is ready to be used\n\nCreate the kubectl config directory\n\n```\nmkdir -p ~/.kube\n```\n\nCopy the kubeconfig file to the default location\n\n```\njuju scp kubernetes-master/0:/home/ubuntu/config ~/.kube/config\n```\n\nQuery the cluster\n\n```\nkubectl cluster-info\n```\n\nTeardown\n\n```\nexport CLUSTER_CONTROLLER=`juju switch`\njuju destroy-controller $CLUSTER_CONTROLLER --destroy-all-models\n```\n\n* [Delete the service principal](https://docs.microsoft.com/en-us/cli/azure/ad/sp?view=azure-cli-latest#az-ad-sp-delete) you created.\n\n\n### on PKS\n\n\u003e Assuming you've installed PKS on [vSphere](https://docs.pivotal.io/runtimes/pks/1-0/vsphere.html) or [GCP](https://docs.pivotal.io/runtimes/pks/1-0/gcp.html), consult [Using PKS](https://docs.pivotal.io/runtimes/pks/1-0/using.html).  Also see [PKS CLI](https://docs.pivotal.io/runtimes/pks/1-0/cli/index.html).\n\n\n## How to configure a private registry\n\n### with Google Container Registry\n\nHave a look at the following guides to get acquainted with Google Cloud Registry\n \n* [Quickstart for Container Registry](https://cloud.google.com/container-registry/docs/quickstart)\n* [Pushing and Pulling Images](https://cloud.google.com/container-registry/docs/pushing-and-pulling)\n\nBe sure to initialize your application default credentials\n\n```\ngcloud auth application-default login\n```\n\n### with Azure Container Registry\n\n\u003e Distilled from the [Quickstart](https://docs.microsoft.com/en-us/azure/container-registry/container-registry-get-started-azure-cli)\n\n```\nexport AZ_GROUP=containers-dc64336a2\nexport AZ_REGISTRY=cr0dc64336a2\naz group create --name $AZ_GROUP --location westus2\naz acr create --resource-group $AZ_GROUP --name $AZ_REGISTRY --sku Basic\n```\n\n\u003e Feel free to modify the `AZ_GROUP` and `AZ_REGISTRY` environment variable values above.\n\n## Preparing Minikube to work with a private registry\n\nYou must [authorize](https://github.com/kubernetes/minikube/issues/321#issuecomment-265222572) minikube to work with your private registry.  \n\n### with Google Container Registry\n\nSee [Google Container Registry Advanced Authentication](https://cloud.google.com/container-registry/docs/advanced-authentication).\n\nThe easiest way to do this is to:\n\n```\t\ngcloud auth application-default print-access-token\nminikube ssh\nsudo docker login -u oauth2accesstoken -p \"\u003creplace_me_with_token\u003e\" https://us.gcr.io\nexit\n```\n\n\n## How to create a Docker image\n\nThis project supports building, tagging, and deploying a Docker container image to a private registry via Maven plugin configuration or standard Docker commandline.\n\nConsult the following table and replace occurences of bracketed variables appearing below\n\n| Hostname | Project Id | Version | Cloud |\n|:------------|:--------------|:-----------|:-------|\n| {HOSTNAME} | {PROJECT_ID} | {VERSION} | |\n| us.gcr.io | fe-cphillipson | latest | Google  |\n| cr0dc64336a2.azurecr.io | fe-cphillipson | latest | Azure |\n\nStart here\n\n```\ncd cities-web\n```\n\n### push to Google Container Registry\n\n#### with Maven\n\n```\ndocker login -u oauth2accesstoken -p \"$(gcloud auth application-default print-access-token)\" https://us.gcr.io\n./mvnw install -Ddocker.image.prefix={HOSTNAME}/{PROJECT_ID}\n```\n\n\u003e Note: if you do not specify `docker.image.prefix` as above it will default to `pivotalio`.\n\n#### with Gradle\n\n```\ngcloud auth application-default print-access-token \u003e build/oauth2accesstoken\ncat build/oauth2accesstoken\ndocker login -u oauth2accesstoken -p \"\u003creplace_me_with_token\u003e\" https://us.gcr.io\n./gradlew build pushDockerToGcr -PdockerImagePrefix={HOSTNAME}/{PROJECT_ID}\n```\n\n\u003e Note: if you do not specify `dockerImagePrefix` as above it will default to `pivotalio`.\n   \n\n#### with Docker\n\n```\ndocker build -t cities-web .\ndocker tag cities-web {HOSTNAME}/{PROJECT_ID}/cities-web:{VERSION}\ngcloud docker -- push {HOSTNAME}/{PROJECT_ID}/cities-web:{VERSION}\n```\n\n### push to Azure Container Registry\n\n#### with Docker\n\n```\naz acr login --name $AZ_REGISTRY\nexport AZ_REGISTRY_HOSTNAME=`az acr list --resource-group $AZ_GROUP --query \"[].{acrLoginServer:loginServer}\" --output json | jq '.[0].acrLoginServer'`\ndocker tag pivotalio/cities-web $AZ_REGISTRY_HOSTNAME/fe-cphillipson/cities-web:latest\ndocker push $AZ_REGISTRY_HOSTNAME/fe-cphillipson/cities-web:latest\n```\n\n\n## How to start Postgres\n\n### with Docker\n\nStart\n\n```\ndocker run -it --rm -p 5432:5432 -e POSTGRES_PASSWORD=postgres -e POSTGRES_DB=geo_data -d postgres:10.3\n```\nStop and cleanup\n\n```\ndocker ps -a\ndocker stop {container_id}\ndocker rm {container_id}\n```\n\n\u003e `{container_id} is the identifer for the running/stopped postgres instance\n\n\n### with Kubernetes\n\n```\ncd cities-web\n```\n\nDeploy postgres with a persistent volume claim\n\n```\nkubectl create -f specs/k8s/postgres.yml\n```\n\nCreate a config map with the hostname of Postgres\n\n```\nkubectl create configmap hostname-config --from-literal=postgres_host=$(kubectl get svc postgres -o jsonpath=\"{.spec.clusterIP}\")\n```\n\nDelete the hostname config map\n\n```\nkubectl delete cm hostname-config\n```\n\nDelete Postgres\n\n```\nkubectl delete -f specs/k8s/postgres.yml\n```\n\n\n### with Pivotal Cloud Foundry\n\nAssuming a Postgres option is available from the Marketplace, like [ElephantSQL](https://www.elephantsql.com) on [Pivotal Web Services](https://run.pivotal.io)\n\n```\ncf create-service elephantsql panda my-pgdb\n```\n\n\u003e Note: this plan will cost you $19/month, so if you're merely evaluating, please remember to shutdown the service with `cf delete-service my-pgdb`.\n\n\n## How to Run \n\n### with Maven\n\n```\ncd cities-web\njava -Dspring.profiles.active=postgres,seeded -jar target/cities-web-x.x.x.jar\n```\n\nor \n\n```\n./mvnw -p cities-web spring-boot:run -Dspring.profiles.active=postgres,seeded\n```\n\n### with Gradle\n\n```\ncd cities-web\njava -Dspring.profiles.active=postgres,seeded -jar build/libs/cities-web-x.x.x-exec.jar\n```\n\nor\n\n```\n./gradlew cities-web:bootRun -Dspring.profiles.active=postgres,seeded\n```\n\n\u003e Press `Ctrl+C` to exit.\n\n\n### with Docker Compose\n\nThis setup uses ephemeral storage.  When the `db` container is stopped all data will be lost!\n\n\u003e Optional: edit the `docker-compose.yml` file to swap the `webapp` image.\n\nto startup (from root directory)\n\n```\ncd specs/docker\ndocker-compose up -d\n```\n\nto shutdown\n\n```\ndocker-compose down\n```\n\n\n### with Kubernetes\n\nEdit `specs/k8s/cities-web.yml` and replace `image` with appropriate private registry image, then deploy the app with\n\n```\nkubectl create -f specs/k8s/cities-web.yml\n```\n\n\u003e Note: pulling an image from Azure Container service requires an [image pull secret](https://docs.microsoft.com/en-us/azure/container-registry/container-registry-auth-aks#access-with-kubernetes-secret).  So the yml file mentioned above will need to modified to accommodate this constraint.\n\n#### on Minikube\n\nGet the external IP address of service\n\n```\nminikube service cities-web --url\n```\n\n#### on Azure, GKE or PKS\n\nCreate an external load balancer for your app\n\n```\nkubectl expose deployment cities-web --type=LoadBalancer --port=8080\n```\n\n\u003e Note: It may take a few minutes for the load balancer to be created\n\n```\nkubectl get svc cities-web\n```\n\n\u003e Get the external IP address of service, then the app will be accessible at `http://\u003cExternal IP Address\u003e:8080`\n\n\n#### Logs\n\nView logs for troubleshooting purposes\n\n```\nkubectl logs deployment/cities-web\n```\n\n#### Scaling\n\nScale your application\n\n```\nkubectl scale deployment cities-web --replicas=3\n```\n\n#### Updating\n\nTo update the image that the containers in your deployment are using\n\n```\nkubectl set image deployment/cities-web cities-web={HOSTNAME}/{PROJECT_ID}/cities-web:{VERSON}\n```\n\n#### Cleaning up\n\nDelete the Spring Boot app deployment\n\n```\nkubectl delete -f specs/k8s/cities-web.yml\n```\n\nDelete the service for the app\n\n```\nkubectl delete svc cities-web\n```\n\n### with Pivotal Cloud Foundry\n\n#### How to target a foundation\n\n```\ncf login -a {CF_INSTANCE_URL}\n```\n\nE.g., to deploy to Pivotal Web Services\n\n```\ncf login -a https://api.run.pivotal.io\n```\n\n\u003e when prompted, supply your account credentials.\n\nthen to target a new organization and space, execute\n\n```\ncf target -o {ORG} -s {SPACE}\n```\n\n\u003e where `{ORG}` is an organization name and `{SPACE}` is an environment; e.g., `cf target -o catepillar -s test`\n\n\n#### How to deploy application instance(s)\n\n##### (cf push)\n\nwith manifest.yml\n\n```\ncf push -p {PATH/TO/ARTIFACT}\n```\n\n\u003e Note: `{PATH/TO/ARTIFACT}` is the path to an executable JAR. If Maven was used to build project, specify `target/cities-web-x.x.x.jar`. If Gradle was used, specify `build/libs/cities-web-x.x.x-exec.jar`.\n\n##### (Gradle CF plugin)\n\n```\n./gradlew cf-push -Pcf.ccHost={CF_INSTANCE_URL} -Pcf.ccUser={CF_USER} -Pcf.ccPassword={CF_PASSWORD} -Pcf.org={ORG} -Pcf.space={SPACE}\n```\n\nor if you want to orchestrate a blue-green deployment, try\n\n```\n./gradlew cf-push-blue-green -Pcf.ccHost={CF_INSTANCE_URL} -Pcf.domain={CF_DOMAIN} -Pcf.ccUser={CF_USER} -Pcf.ccPassword={CF_PASSWORD} -Pcf.org={ORG} -Pcf.space={SPACE}\n```\n\n\u003e Consult [pivotalservices/ya-cf-app-gradle-plugin](https://github.com/pivotalservices/ya-cf-app-gradle-plugin#using-the-plugin) for detailed configuration options.\n\n#### How to delete application instance(s)\n\n##### (cf delete)\n\n```\ncf delete cities-web\n```\n\n\n## Working with sample data\n\nEdit the .sql file in `cities-web/src/main/resources/db/sql/test` and add `INSERT` statements, like:\n\n```\nINSERT INTO city (id, name, description, latitude, longitude, updated_at, created_at) VALUES ('SFO', 'San Francisco', '', 37.781555, -122.393990, '2018-03-25 15:00:00', '2018-03-25 15:00:00');\n```\n\n\n## Working with API\n\nApplication endpoints\n\n```\nGET /cities\nGET /cities/{id}\nPUT /cities/{id}\nPOST /cities/{id}\nDELETE /cities/{id}\n```\n\nand of course there are the [actuator endpoints](https://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-endpoints.html) provided by Spring Boot\n\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpacphi%2Fspring-boot-with-kotlin-and-jpa-example","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpacphi%2Fspring-boot-with-kotlin-and-jpa-example","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpacphi%2Fspring-boot-with-kotlin-and-jpa-example/lists"}