{"id":15805057,"url":"https://github.com/ddobrin/quotes-workshop","last_synced_at":"2026-01-23T07:05:16.440Z","repository":{"id":243244586,"uuid":"797294659","full_name":"ddobrin/quotes-workshop","owner":"ddobrin","description":null,"archived":false,"fork":false,"pushed_at":"2024-11-06T17:47:29.000Z","size":55680,"stargazers_count":0,"open_issues_count":2,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-05-07T18:08:10.198Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","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/ddobrin.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,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2024-05-07T15:05:28.000Z","updated_at":"2024-10-29T15:36:54.000Z","dependencies_parsed_at":"2024-09-10T18:22:00.779Z","dependency_job_id":"9d97ae6c-7dca-4a59-9fbc-268c9c3f78de","html_url":"https://github.com/ddobrin/quotes-workshop","commit_stats":null,"previous_names":["ddobrin/quotes-workshop"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/ddobrin/quotes-workshop","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ddobrin%2Fquotes-workshop","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ddobrin%2Fquotes-workshop/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ddobrin%2Fquotes-workshop/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ddobrin%2Fquotes-workshop/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ddobrin","download_url":"https://codeload.github.com/ddobrin/quotes-workshop/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ddobrin%2Fquotes-workshop/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28682285,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-23T05:48:07.525Z","status":"ssl_error","status_checked_at":"2026-01-23T05:48:07.129Z","response_time":59,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":[],"created_at":"2024-10-05T02:03:23.658Z","updated_at":"2026-01-23T07:05:16.426Z","avatar_url":"https://github.com/ddobrin.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Quotes Service - JIT and Native Java Build \u0026 Deployment to Cloud Run\n\n## Originally published\nhttps://github.com/GoogleCloudPlatform/serverless-production-readiness-java-gcp/tree/main/services/quotes\n\n## VertexAI and Gemini settings\nSet the following environment variables to build and run the app\n```shell\nexport VERTEX_AI_GEMINI_PROJECT_ID=\u003cyour project id\u003e\nexport VERTEX_AI_GEMINI_LOCATION=\u003cregion\u003e\nexport VERTEX_AI_GEMINI_MODEL=\u003c\u003cmodel id\u003e\u003e\n```\n# Build\n\n### Create a Spring Boot Application\n```\n# clone the repo\ngit clone https://github.com/ddobrin/quotes-workshop\n```\n\n### Validate that you have Java 21 and Maven installed\n```shell\njava -version\n```\n\n## Setup GraalVM\nIn order to build JIT or Native Java app images, please set up Java and GraalVM and the associated Java 21 distributions.\nA simple installer is available from [SDKMan](https://sdkman.io/install)\n```shell\ncurl -s \"https://get.sdkman.io\" | bash\nsource \"$HOME/.sdkman/bin/sdkman-init.sh\"\nsdk version\n\nsdk install java 21.0.2-graal\n```\n\n### Validate that GraalVM for Java is installed if building native images\n```shell\njava -version\n\n# should indicate this or later version\njava version \"21\" 2023-09-19\nJava(TM) SE Runtime Environment Oracle GraalVM 21+35.1 (build 21+35-jvmci-23.1-b15)\nJava HotSpot(TM) 64-Bit Server VM Oracle GraalVM 21+35.1 (build 21+35-jvmci-23.1-b15, mixed mode, sharing)\n```\n\n### Validate that the starter app is good to go\n```\n./mvnw package -Pproduction spring-boot:run\n```\n\nFrom a terminal window, test the app\n```\ncurl localhost:8083/start\n\n# Output\nHello from your local environment!\n\n# get quotes from the app\ncurl localhost:8083/quotes\ncurl localhost:8083/random-quote\n```\n\n### Build a JIT and Native Java application image\n```\n./mvnw package -DskipTests -Pproduction\n\n./mvnw native:compile -Pnative -DskipTests -Pproduction\n```\n\n### Start your app with AOT enabled\n```shell\njava -Dspring.aot.enabled=true -jar target/quotes-1.0.0.jar\n```\n### Build a JIT Docker image with Dockerfiles\n```shell\n# build an image with jlink\ndocker build . -f ./containerize/Dockerfile-jlink -t quotes-jlink\n\n# build an image with a fat JAR\ndocker build -f ./containerize/Dockerfile-fatjar -t quotes-fatjar .\n\n# build an image with custom layers\ndocker build -f ./containerize/Dockerfile-custom -t quotes-custom .\n```\n### Build a JIT and Native Java Docker Image with Buildpacks\n```\n./mvnw spring-boot:build-image -Dspring-boot.build-image.imageName=quotes -Pproduction\n\n\n./mvnw spring-boot:build-image  -DskipTests -Pnative -Dspring-boot.build-image.imageName=quotes-native -Pproduction\n```\n\n### Test the locally built images on the local machine\n```shell\ndocker run --rm -p 8080:8083 quotes\n\ndocker run --rm -p 8080:8083 quotes-native\n```\n### Build, test with CloudBuild in Cloud Build\n```shell\ngcloud builds submit  --machine-type E2-HIGHCPU-32\n\ngcloud builds submit --config cloudbuild-docker.yaml --machine-type E2-HIGHCPU-32\n\ngcloud builds submit  --config cloudbuild-native.yaml --machine-type E2-HIGHCPU-32 \n```\n# Deploy\n### Tag and push images to a registry\nIf you have built the image locally, tag it first and push to a container registry\n```shell\n# tag the image\nexport PROJECT_ID=$(gcloud config list --format 'value(core.project)')\necho   $PROJECT_ID\n\n# tag and push JIT image\ndocker tag quotes gcr.io/${PROJECT_ID}/quotes\ndocker push gcr.io/${PROJECT_ID}/quotes\n\n# tag and push Native image\ndocker tag quotes-native gcr.io/${PROJECT_ID}/quotes-native\ndocker push gcr.io/${PROJECT_ID}/quotes-native\n```\n\n### Deploy Docker images to Cloud Run\n\nCheck existing deployed Cloud Run Services\n```shell\nexport PROJECT_ID=$(gcloud config list --format 'value(core.project)')\necho   $PROJECT_ID\n\ngcloud run services list\n```\n\nDeploy the Quotes JIT image\n```shell\n# note the URL of the deployed service\ngcloud run deploy quotes \\\n     --image gcr.io/${PROJECT_ID}/quotes \\\n     --region us-central1 \\\n     --memory 2Gi --allow-unauthenticated\n```\n\nDeploy the Quotes Native Java image\n```shell\n# note the URL of the deployed service\ngcloud run deploy quotes-native \\\n     --image gcr.io/${PROJECT_ID}/quotes-native \\\n     --region us-central1 \\\n     --memory 2Gi --allow-unauthenticated\n```\n\n### Test the application\nStart the containerized app locally:\n```shell\n# validate that app has started\ncurl localhost:8080:/start\n\n# get quotes from the app\ncurl localhost:8083/quotes\ncurl localhost:8083/random-quote\n\n# add a new quote to the repository\ncurl --location 'http://localhost:8083/quotes' \\\n--header 'Content-Type: application/json' \\\n--data '{\n    \"author\" : \"Isabel Allende\",\n    \"quote\" : \"The longer I live, the more uninformed I feel. Only the young have an explanation for everything.\",\n    \"book\" : \"City of the Beasts\"\n}'\n\n# Validate that the quote has been added\ncurl localhost:8083/quotes\n```\n\nTest the application in Cloud Run\n```shell\n# find the Quotes URL is you have not noted it\ngcloud run services list | grep quotes\n✔  quotes                    us-central1   https://quotes-...-uc.a.run.app       \n✔  quotes-native             us-central1   https://quotes-native-...-uc.a.run.app\n# validate that app passes start-up check\ncurl \u003cURL\u003e:/start\n\n# get quotes from the app\ncurl \u003cURL\u003e:/quotes\ncurl \u003cURL\u003e:/random-quote\n\n# add a new quote to the repository\ncurl --location '\u003cURL\u003e:/quotes' \\\n--header 'Content-Type: application/json' \\\n--data '{\n    \"author\" : \"Isabel Allende\",\n    \"quote\" : \"The longer I live, the more uninformed I feel. Only the young have an explanation for everything.\",\n    \"book\" : \"City of the Beasts\"\n}'\n```\n\nIf you have deployed the app with security enabled, (no --allow-unauthenticated flag) you can test it with a Bearer token. You can use also an alternative [HTTP test client](https://httpie.io/) \n```shell\nTOKEN=$(gcloud auth print-identity-token)\n\n# Get the URL of the deployed app\n# Test JIT image\nhttp -A bearer -a $TOKEN  https://\u003cBASE_URL\u003e/random-quote\nhttp -A bearer -a $TOKEN  https://\u003cBASE_URL\u003e/quotes\n\n# Test Native Java image\nhttp -A bearer -a $TOKEN \u003cBASE_URL\u003e/random-quote\nhttp -A bearer -a $TOKEN \u003cBASE_URL\u003e/quotes\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fddobrin%2Fquotes-workshop","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fddobrin%2Fquotes-workshop","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fddobrin%2Fquotes-workshop/lists"}