From d979d4a8c7758c4a717701fb36aa5f1d0040cb37 Mon Sep 17 00:00:00 2001 From: Marcello de Sales Date: Thu, 17 Jan 2019 17:08:59 -0300 Subject: [PATCH] Initial commit --- .env | 4 + .github/CODE_OF_CONDUCT.md | 47 ++ .github/CONTRIBUTING.md | 166 +++++ .github/ISSUE_TEMPLATE.md | 34 + .github/PULL_REQUEST_TEMPLATE.md | 33 + .github/logo.png | Bin 0 -> 57845 bytes .gitignore | 7 + .gitlab-ci.yml | 203 ++++++ CHANGELOG | 1 + LICENSE | 21 + README.md | 312 +++++++++ builder/gradle.Dockerfile | 52 ++ builder/maven.Dockerfile | 52 ++ docker-compose-samples.yml | 125 ++++ docker-compose.yml | 227 ++++++ linker/Dockerfile | 53 ++ runner/collate.bash | 64 ++ runner/custom-jlink-jdk/Dockerfile | 113 +++ runner/regular-jdk/Dockerfile | 116 +++ runner/start.bash | 151 ++++ samples/README.md | 447 ++++++++++++ samples/gradle-java-jdk8-jre8/.dockerignore | 6 + samples/gradle-java-jdk8-jre8/Dockerfile | 24 + samples/gradle-java-jdk8-jre8/README.md | 368 ++++++++++ samples/gradle-java-jdk8-jre8/build.gradle | 32 + samples/gradle-java-jdk8-jre8/settings.gradle | 1 + .../src/gradle/jar.gradle | 4 + .../src/gradle/processResources.gradle | 23 + .../src/main/java/hello/Application.java | 30 + .../src/main/java/hello/util/BuildInfo.java | 45 ++ .../hello/util/DefaultResponseFilter.java | 37 + .../src/main/resources/application-dev.yml | 2 + .../src/main/resources/application-prd.yml | 2 + .../src/main/resources/application.yml | 7 + .../.dockerignore | 6 + .../Dockerfile | 29 + .../README.md | 368 ++++++++++ .../build.gradle | 32 + .../settings.gradle | 1 + .../src/gradle/jar.gradle | 4 + .../src/gradle/processResources.gradle | 23 + .../src/main/java/hello/Application.java | 30 + .../src/main/java/hello/util/BuildInfo.java | 45 ++ .../hello/util/DefaultResponseFilter.java | 37 + .../src/main/resources/application-dev.yml | 2 + .../src/main/resources/application-prd.yml | 2 + .../src/main/resources/application.yml | 7 + .../.dockerignore | 6 + .../Dockerfile | 29 + .../README.md | 368 ++++++++++ .../build.gradle | 32 + .../settings.gradle | 1 + .../src/gradle/jar.gradle | 4 + .../src/gradle/processResources.gradle | 23 + .../src/main/java/hello/Application.java | 30 + .../src/main/java/hello/util/BuildInfo.java | 45 ++ .../hello/util/DefaultResponseFilter.java | 37 + .../src/main/resources/application-dev.yml | 2 + .../src/main/resources/application-prd.yml | 2 + .../src/main/resources/application.yml | 7 + .../.dockerignore | 6 + .../Dockerfile | 29 + .../gradle-java-jdk8-x-jre11-custom/README.md | 368 ++++++++++ .../build.gradle | 32 + .../settings.gradle | 1 + .../src/gradle/jar.gradle | 4 + .../src/gradle/processResources.gradle | 23 + .../src/main/java/hello/Application.java | 30 + .../src/main/java/hello/util/BuildInfo.java | 45 ++ .../hello/util/DefaultResponseFilter.java | 37 + .../src/main/resources/application-dev.yml | 2 + .../src/main/resources/application-prd.yml | 2 + .../src/main/resources/application.yml | 7 + samples/gradle-kotlin-jdk8-jre8/.gitignore | 26 + samples/gradle-kotlin-jdk8-jre8/Dockerfile | 24 + samples/gradle-kotlin-jdk8-jre8/README.md | 174 +++++ samples/gradle-kotlin-jdk8-jre8/build.gradle | 54 ++ .../gradle-kotlin-jdk8-jre8/settings.gradle | 1 + .../src/main/kotlin/blog/BlogApplication.kt | 12 + .../src/main/resources/application.properties | 0 .../test/kotlin/blog/BlogApplicationTests.kt | 17 + .../gradle5-java-jdk11-x-jre12/.dockerignore | 6 + samples/gradle5-java-jdk11-x-jre12/Dockerfile | 31 + samples/gradle5-java-jdk11-x-jre12/README.md | 368 ++++++++++ .../gradle5-java-jdk11-x-jre12/build.gradle | 32 + .../settings.gradle | 1 + .../src/gradle/jar.gradle | 4 + .../src/gradle/processResources.gradle | 23 + .../src/main/java/hello/Application.java | 30 + .../src/main/java/hello/util/BuildInfo.java | 45 ++ .../hello/util/DefaultResponseFilter.java | 37 + .../src/main/resources/application-dev.yml | 2 + .../src/main/resources/application-prd.yml | 2 + .../src/main/resources/application.yml | 7 + samples/maven-java-jdk11-custom/.dockerignore | 6 + samples/maven-java-jdk11-custom/.gitignore | 18 + samples/maven-java-jdk11-custom/Dockerfile | 45 ++ samples/maven-java-jdk11-custom/LICENSE | 201 ++++++ samples/maven-java-jdk11-custom/README.md | 368 ++++++++++ .../jfr-config/application.yml | 26 + .../jfr-config/profile.jfc | 624 +++++++++++++++++ .../jfr-config/sample.jfr | 0 .../kubernetes/010_configmap.yaml | 662 ++++++++++++++++++ .../kubernetes/020_statefulset.yml | 76 ++ .../kubernetes/030_service.yaml | 17 + samples/maven-java-jdk11-custom/pom.xml | 90 +++ samples/maven-java-jdk11-custom/settings.xml | 280 ++++++++ .../hrkm/springbootsample/Application.java | 12 + .../controller/OOMController.java | 34 + .../controller/ProfileController.java | 22 + .../repository/FooRepository.java | 68 ++ .../springbootsample/service/FooService.java | 26 + .../src/main/resources/application.yaml | 7 + tools/build-push.sh | 12 + tools/list-images-to-process.sh | 27 + 115 files changed, 8084 insertions(+) create mode 100644 .env create mode 100644 .github/CODE_OF_CONDUCT.md create mode 100644 .github/CONTRIBUTING.md create mode 100644 .github/ISSUE_TEMPLATE.md create mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100755 .github/logo.png create mode 100644 .gitignore create mode 100644 .gitlab-ci.yml create mode 100644 CHANGELOG create mode 100644 LICENSE create mode 100644 README.md create mode 100644 builder/gradle.Dockerfile create mode 100644 builder/maven.Dockerfile create mode 100644 docker-compose-samples.yml create mode 100644 docker-compose.yml create mode 100644 linker/Dockerfile create mode 100644 runner/collate.bash create mode 100644 runner/custom-jlink-jdk/Dockerfile create mode 100644 runner/regular-jdk/Dockerfile create mode 100644 runner/start.bash create mode 100644 samples/README.md create mode 100644 samples/gradle-java-jdk8-jre8/.dockerignore create mode 100644 samples/gradle-java-jdk8-jre8/Dockerfile create mode 100644 samples/gradle-java-jdk8-jre8/README.md create mode 100644 samples/gradle-java-jdk8-jre8/build.gradle create mode 100644 samples/gradle-java-jdk8-jre8/settings.gradle create mode 100644 samples/gradle-java-jdk8-jre8/src/gradle/jar.gradle create mode 100644 samples/gradle-java-jdk8-jre8/src/gradle/processResources.gradle create mode 100644 samples/gradle-java-jdk8-jre8/src/main/java/hello/Application.java create mode 100644 samples/gradle-java-jdk8-jre8/src/main/java/hello/util/BuildInfo.java create mode 100644 samples/gradle-java-jdk8-jre8/src/main/java/hello/util/DefaultResponseFilter.java create mode 100644 samples/gradle-java-jdk8-jre8/src/main/resources/application-dev.yml create mode 100644 samples/gradle-java-jdk8-jre8/src/main/resources/application-prd.yml create mode 100644 samples/gradle-java-jdk8-jre8/src/main/resources/application.yml create mode 100644 samples/gradle-java-jdk8-x-jre11-custom-centos/.dockerignore create mode 100644 samples/gradle-java-jdk8-x-jre11-custom-centos/Dockerfile create mode 100644 samples/gradle-java-jdk8-x-jre11-custom-centos/README.md create mode 100644 samples/gradle-java-jdk8-x-jre11-custom-centos/build.gradle create mode 100644 samples/gradle-java-jdk8-x-jre11-custom-centos/settings.gradle create mode 100644 samples/gradle-java-jdk8-x-jre11-custom-centos/src/gradle/jar.gradle create mode 100644 samples/gradle-java-jdk8-x-jre11-custom-centos/src/gradle/processResources.gradle create mode 100644 samples/gradle-java-jdk8-x-jre11-custom-centos/src/main/java/hello/Application.java create mode 100644 samples/gradle-java-jdk8-x-jre11-custom-centos/src/main/java/hello/util/BuildInfo.java create mode 100644 samples/gradle-java-jdk8-x-jre11-custom-centos/src/main/java/hello/util/DefaultResponseFilter.java create mode 100644 samples/gradle-java-jdk8-x-jre11-custom-centos/src/main/resources/application-dev.yml create mode 100644 samples/gradle-java-jdk8-x-jre11-custom-centos/src/main/resources/application-prd.yml create mode 100644 samples/gradle-java-jdk8-x-jre11-custom-centos/src/main/resources/application.yml create mode 100644 samples/gradle-java-jdk8-x-jre11-custom-debian/.dockerignore create mode 100644 samples/gradle-java-jdk8-x-jre11-custom-debian/Dockerfile create mode 100644 samples/gradle-java-jdk8-x-jre11-custom-debian/README.md create mode 100644 samples/gradle-java-jdk8-x-jre11-custom-debian/build.gradle create mode 100644 samples/gradle-java-jdk8-x-jre11-custom-debian/settings.gradle create mode 100644 samples/gradle-java-jdk8-x-jre11-custom-debian/src/gradle/jar.gradle create mode 100644 samples/gradle-java-jdk8-x-jre11-custom-debian/src/gradle/processResources.gradle create mode 100644 samples/gradle-java-jdk8-x-jre11-custom-debian/src/main/java/hello/Application.java create mode 100644 samples/gradle-java-jdk8-x-jre11-custom-debian/src/main/java/hello/util/BuildInfo.java create mode 100644 samples/gradle-java-jdk8-x-jre11-custom-debian/src/main/java/hello/util/DefaultResponseFilter.java create mode 100644 samples/gradle-java-jdk8-x-jre11-custom-debian/src/main/resources/application-dev.yml create mode 100644 samples/gradle-java-jdk8-x-jre11-custom-debian/src/main/resources/application-prd.yml create mode 100644 samples/gradle-java-jdk8-x-jre11-custom-debian/src/main/resources/application.yml create mode 100644 samples/gradle-java-jdk8-x-jre11-custom/.dockerignore create mode 100644 samples/gradle-java-jdk8-x-jre11-custom/Dockerfile create mode 100644 samples/gradle-java-jdk8-x-jre11-custom/README.md create mode 100644 samples/gradle-java-jdk8-x-jre11-custom/build.gradle create mode 100644 samples/gradle-java-jdk8-x-jre11-custom/settings.gradle create mode 100644 samples/gradle-java-jdk8-x-jre11-custom/src/gradle/jar.gradle create mode 100644 samples/gradle-java-jdk8-x-jre11-custom/src/gradle/processResources.gradle create mode 100644 samples/gradle-java-jdk8-x-jre11-custom/src/main/java/hello/Application.java create mode 100644 samples/gradle-java-jdk8-x-jre11-custom/src/main/java/hello/util/BuildInfo.java create mode 100644 samples/gradle-java-jdk8-x-jre11-custom/src/main/java/hello/util/DefaultResponseFilter.java create mode 100644 samples/gradle-java-jdk8-x-jre11-custom/src/main/resources/application-dev.yml create mode 100644 samples/gradle-java-jdk8-x-jre11-custom/src/main/resources/application-prd.yml create mode 100644 samples/gradle-java-jdk8-x-jre11-custom/src/main/resources/application.yml create mode 100644 samples/gradle-kotlin-jdk8-jre8/.gitignore create mode 100644 samples/gradle-kotlin-jdk8-jre8/Dockerfile create mode 100644 samples/gradle-kotlin-jdk8-jre8/README.md create mode 100644 samples/gradle-kotlin-jdk8-jre8/build.gradle create mode 100644 samples/gradle-kotlin-jdk8-jre8/settings.gradle create mode 100644 samples/gradle-kotlin-jdk8-jre8/src/main/kotlin/blog/BlogApplication.kt create mode 100644 samples/gradle-kotlin-jdk8-jre8/src/main/resources/application.properties create mode 100644 samples/gradle-kotlin-jdk8-jre8/src/test/kotlin/blog/BlogApplicationTests.kt create mode 100644 samples/gradle5-java-jdk11-x-jre12/.dockerignore create mode 100644 samples/gradle5-java-jdk11-x-jre12/Dockerfile create mode 100644 samples/gradle5-java-jdk11-x-jre12/README.md create mode 100644 samples/gradle5-java-jdk11-x-jre12/build.gradle create mode 100644 samples/gradle5-java-jdk11-x-jre12/settings.gradle create mode 100644 samples/gradle5-java-jdk11-x-jre12/src/gradle/jar.gradle create mode 100644 samples/gradle5-java-jdk11-x-jre12/src/gradle/processResources.gradle create mode 100644 samples/gradle5-java-jdk11-x-jre12/src/main/java/hello/Application.java create mode 100644 samples/gradle5-java-jdk11-x-jre12/src/main/java/hello/util/BuildInfo.java create mode 100644 samples/gradle5-java-jdk11-x-jre12/src/main/java/hello/util/DefaultResponseFilter.java create mode 100644 samples/gradle5-java-jdk11-x-jre12/src/main/resources/application-dev.yml create mode 100644 samples/gradle5-java-jdk11-x-jre12/src/main/resources/application-prd.yml create mode 100644 samples/gradle5-java-jdk11-x-jre12/src/main/resources/application.yml create mode 100644 samples/maven-java-jdk11-custom/.dockerignore create mode 100644 samples/maven-java-jdk11-custom/.gitignore create mode 100644 samples/maven-java-jdk11-custom/Dockerfile create mode 100644 samples/maven-java-jdk11-custom/LICENSE create mode 100644 samples/maven-java-jdk11-custom/README.md create mode 100644 samples/maven-java-jdk11-custom/jfr-config/application.yml create mode 100644 samples/maven-java-jdk11-custom/jfr-config/profile.jfc create mode 100644 samples/maven-java-jdk11-custom/jfr-config/sample.jfr create mode 100644 samples/maven-java-jdk11-custom/kubernetes/010_configmap.yaml create mode 100644 samples/maven-java-jdk11-custom/kubernetes/020_statefulset.yml create mode 100644 samples/maven-java-jdk11-custom/kubernetes/030_service.yaml create mode 100644 samples/maven-java-jdk11-custom/pom.xml create mode 100644 samples/maven-java-jdk11-custom/settings.xml create mode 100644 samples/maven-java-jdk11-custom/src/main/java/com/example/hrkm/springbootsample/Application.java create mode 100644 samples/maven-java-jdk11-custom/src/main/java/com/example/hrkm/springbootsample/controller/OOMController.java create mode 100644 samples/maven-java-jdk11-custom/src/main/java/com/example/hrkm/springbootsample/controller/ProfileController.java create mode 100644 samples/maven-java-jdk11-custom/src/main/java/com/example/hrkm/springbootsample/repository/FooRepository.java create mode 100644 samples/maven-java-jdk11-custom/src/main/java/com/example/hrkm/springbootsample/service/FooService.java create mode 100644 samples/maven-java-jdk11-custom/src/main/resources/application.yaml create mode 100644 tools/build-push.sh create mode 100644 tools/list-images-to-process.sh diff --git a/.env b/.env new file mode 100644 index 0000000..c1a0ebb --- /dev/null +++ b/.env @@ -0,0 +1,4 @@ +UNMAZEDBOOT_BUILDER_GRADLE_VERSION=-0.5.0 +UNMAZEDBOOT_BUILDER_MAVEN_VERSION=-0.5.0 +UNMAZEDBOOT_LINKER_VERSION=-0.5.0 +UNMAZEDBOOT_RUNNER_VERSION=-0.5.0 diff --git a/.github/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..080c9b7 --- /dev/null +++ b/.github/CODE_OF_CONDUCT.md @@ -0,0 +1,47 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/4/ + diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md new file mode 100644 index 0000000..60c2e9b --- /dev/null +++ b/.github/CONTRIBUTING.md @@ -0,0 +1,166 @@ +# Contributing to unmazedboot + +:+1::tada: First off, thanks for taking the time to contribute! :tada::+1: + +The following is a set of guidelines for contributing to [unmazedboot](https://github.com/intuit/unmazedboot). These are mostly guidelines, not rules. Use your best judgment, and feel free to propose changes to this document in a pull request. + +*This contributing doc is based on the [CONTRIBUTING.md of Atom](https://github.com/atom/atom/blob/master/CONTRIBUTING.md)* + +#### Table Of Contents + +[Code of Conduct](#code-of-conduct) + +[Channels](#channels) + +[How Can I Contribute?](#how-can-i-contribute) + * [Reporting Bugs](#reporting-bugs) + * [Suggesting Enhancements](#suggesting-enhancements) + * [Code Contribution](#code-contribution) + * [Pull Requests](#pull-requests) + +[Styleguides](#styleguides) + * [Git Commit Messages](#git-commit-messages) + * [JavaScript Styleguide](#javascript-styleguide) + +[Issue and Pull Request Labels](#issue-and-pull-request-labels) + +## Code of Conduct + +This project and everyone participating in it is governed by the [Code of Conduct](CODE_OF_CONDUCT.md). + +## Channels + +* [Join the unmazedboot Gitter Channels](https://gitter.im/unmazedboot) + * Use the `#general` channel for general questions or discussion about unmazedboot + * Use the `#development` channel for questions, discussion and suggestions about code and development + +## How Can I Contribute? + +### Reporting Bugs + +This section guides you through submitting a bug report for unmazedboot. Following these guidelines helps maintainers and the community understand your report :pencil:, reproduce the behavior :computer: :computer:, and find related reports :mag_right:. + +When you are creating a bug report, please [include as many details as possible](#how-do-i-submit-a-good-bug-report). Fill out [the required template](ISSUE_TEMPLATE.md), the information it asks for helps us resolve issues faster. + +> **Note:** If you find a **Closed** issue that seems like it is the same thing that you're experiencing, open a new issue and include a link to the original issue in the body of your new one. + + +#### How Do I Submit A (Good) Bug Report? + +Bugs are tracked as [GitHub issues](https://guides.github.com/features/issues/). Create an issue on that repository and provide the following information by filling in [the template](ISSUE_TEMPLATE.md). + +Explain the problem and include additional details to help maintainers reproduce the problem: + +* **Use a clear and descriptive title** for the issue to identify the problem. +* **Describe the exact steps which reproduce the problem** +* **Provide specific examples to demonstrate the steps**. Include links to files or GitHub projects, or copy/pasteable snippets, which you use in those examples. If you're providing snippets in the issue, use [Markdown code blocks](https://help.github.com/articles/markdown-basics/#multiple-lines). +* **Describe the behavior you observed after following the steps** and point out what exactly is the problem with that behavior. +* **Explain which behavior you expected to see instead and why.** +* **Include screenshots and animated GIFs** which show you following the described steps and clearly demonstrate the problem. You can use [this tool](http://www.cockos.com/licecap/) to record GIFs on macOS and Windows, and [this tool](https://github.com/colinkeenan/silentcast) or [this tool](https://github.com/GNOME/byzanz) on Linux. +* **If the problem wasn't triggered by a specific action**, describe what you were doing before the problem happened and share more information using the guidelines below. + +Include details about your configuration and environment: + +* **Which version of unmazedboot are you using?** +* **What's the name and version of the OS you're using?** +* **What are the version of the docker and docker-compose you're using?** + +### Suggesting Enhancements + +This section guides you through submitting an enhancement suggestion for unmazedboot, including completely new features and minor improvements to existing functionality. Following these guidelines helps maintainers and the community understand your suggestion :pencil: and find related suggestions :mag_right:. + +When you are creating an enhancement suggestion, please [include as many details as possible](#how-do-i-submit-a-good-enhancement-suggestion). Fill in [the template](ISSUE_TEMPLATE.md), including the steps that you imagine you would take if the feature you're requesting existed. + +#### How Do I Submit A (Good) Enhancement Suggestion? + +Enhancement suggestions are tracked as [GitHub issues](https://guides.github.com/features/issues/). Create an issue on that repository and provide the following information: + +* **Use a clear and descriptive title** for the issue to identify the suggestion. +* **Provide a step-by-step description of the suggested enhancement** in as many details as possible. +* **Provide specific examples to demonstrate the steps**. Include copy/pasteable snippets which you use in those examples, as [Markdown code blocks](https://help.github.com/articles/markdown-basics/#multiple-lines). +* **Describe the current behavior** and **explain which behavior you expected to see instead** and why. +* **Include screenshots and animated GIFs** which help you demonstrate the steps or point out the part of unmazedboot which the suggestion is related to. You can use [this tool](http://www.cockos.com/licecap/) to record GIFs on macOS and Windows, and [this tool](https://github.com/colinkeenan/silentcast) or [this tool](https://github.com/GNOME/byzanz) on Linux. +* **Explain why this enhancement would be useful** to unmazedboot users. +* **List some other tools or applications where this enhancement exists.** +* **Specify which version of unmazedboot you're using.** +* **Specify the name and version of the OS you're using.** + +### Code Contribution + +#### Local development + +Make sure you have latest docker for desktop installed. + +- Clone the repo to your machine (or fork it to your github account then clone from there) +``` +git clone git@github.com:intuit/unmazedboot.git +cd unmazedboot +``` + +- Make your branch from `develop` with `git checkout develop` + +- Install all dependencies then `docker-compose build --pull` + +### Pull Requests + +* Fill in [the required template](PULL_REQUEST_TEMPLATE.md) +* Do not include issue numbers in the PR title +* Include screenshots and animated GIFs in your pull request whenever possible. +* Follow the [hadolint](#dockerfile-styleguide) styleguides from https://github.com/hadolint/hadolint. +* End all files with a newline + +## Styleguides + +### Git Commit Messages + +* Use the present tense ("Add feature" not "Added feature") +* Use the imperative mood ("Move cursor to..." not "Moves cursor to...") +* Try to limit the length of commit message +* Reference issues and pull requests liberally after the first line, if applicable +* Consider starting the commit message with an applicable emoji: + * :art: `:art:` when improving the format/structure of the code + * :racehorse: `:racehorse:` when improving performance + * :non-potable_water: `:non-potable_water:` when plugging memory leaks + * :memo: `:memo:` when writing docs + * :penguin: `:penguin:` when fixing something on Linux + * :apple: `:apple:` when fixing something on macOS + * :checkered_flag: `:checkered_flag:` when fixing something on Windows + * :bug: `:bug:` when fixing a bug + * :fire: `:fire:` when removing code or files + * :green_heart: `:green_heart:` when fixing the CI build + * :white_check_mark: `:white_check_mark:` when adding tests + * :lock: `:lock:` when dealing with security + * :arrow_up: `:arrow_up:` when upgrading dependencies + * :arrow_down: `:arrow_down:` when downgrading dependencies + * :shirt: `:shirt:` when removing linter warnings + +### Dockerfile Linter + +All Dockerfile is validated with [Hadolint](https://github.com/hadolint/hadolint). Make sure to disable the things you need to get a clean build. + + +## Issue and Pull Request Labels + +This section lists the labels we use to help us track and manage issues and pull requests. + +The labels are loosely grouped by their purpose, but it's not required that every issue have a label from every group or that an issue can't have more than one label from the same group. + +Please open an issue if you have suggestions for new labels. + +#### Type of Issue and Issue State + +| Label name | Description | +| --- | --- | +| `enhancement` | Feature requests. | +| `bug` | Confirmed bugs or reports that are very likely to be bugs. | +| `question` | Questions more than bug reports or feature requests (e.g. how do I do X). | +| `feedback` | General feedback more than bug reports or feature requests. | +| `help-wanted` | The team would appreciate help from the community in resolving these issues. | +| `more-information-needed` | More information needs to be collected about these problems or feature requests (e.g. steps to reproduce). | +| `needs-reproduction` | Likely bugs, but haven't been reliably reproduced. | +| `blocked` | Issues blocked on other issues. | +| `duplicate` | Issues which are duplicates of other issues, i.e. they have been reported before. | +| `wontfix` | The team has decided not to fix these issues for now, either because they're working as intended or for some other reason. | +| `invalid` | Issues which aren't valid (e.g. user errors). | +| `documentation` | Documentation needed or certain part needs to be further explained. | + diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 0000000..868c0b8 --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,34 @@ + + +### Description + +[Description of the issue] + +### Steps to Reproduce + +1. [First Step] +2. [Second Step] +3. [and so on...] + +**Expected behavior:** [What you expect to happen] + +**Actual behavior:** [What actually happens] + +**Reproduces how often:** [What percentage of the time does it reproduce?] + +### Versions + +[docker, docker-compose] + +### Additional Information + +Any additional information, configuration or data that might be necessary to reproduce the issue. + diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..7bf8eab --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,33 @@ +### Requirements + + + +### Description of the Change + + + +### Alternate Designs + + + + +### Benefits + + + +### Possible Drawbacks + + + +### Applicable Issues + + + diff --git a/.github/logo.png b/.github/logo.png new file mode 100755 index 0000000000000000000000000000000000000000..b1963162ca320e1aa23a4440938e9c50f71ded7c GIT binary patch literal 57845 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 b^5g#n_zYZ25*%#V00000NkvXXu0mjfdEd$+ literal 0 HcmV?d00001 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f708f19 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +sample/build/ +sample/.gradle/ +sample/bin +sample/.classpath +sample/.project +sample/.settings +.DS_Store diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..bb8d43f --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,203 @@ +# Based on https://gitlab.com/andy.wilson/get-docker-compose-latest-version/blob/0f888504cd40feca0cfaecfa9007cdd1c3e5d1d3/.gitlab-ci.yml +# https://stackoverflow.com/questions/39868369/run-docker-compose-build-in-gitlab-ci-yml/52734017#52734017 +# Use Docker-in-Docker service +image: + name: docker/compose:1.23.1 # update tag to whatever version you want to use. + entrypoint: ["/bin/sh", "-c"] + +variables: + # When using dind service we need to instruct docker, to talk with the + # daemon started inside of the service. The daemon is available with + # a network connection instead of the default /var/run/docker.sock socket. + # + # The 'docker' hostname is the alias of the service container as described at + # https://docs.gitlab.com/ee/ci/docker/using_docker_images.html#accessing-the-services + # + # Note that if you're using Kubernetes executor, the variable should be set to + # tcp://localhost:2375 because of how Kubernetes executor connects services + # to the job container + DOCKER_HOST: tcp://docker:2375/ + # When using dind, it's wise to use the overlayfs driver for + # improved performance. # workaround GitLab running `sh` + # https://gitlab.com/gitlab-org/gitlab-ce/issues/30426 + DOCKER_DRIVER: overlay2 + +services: + - name: docker:dind + +before_script: + - docker version + - docker-compose version + - env + +stages: + - setup + - lint + - docker-build + - docker-push + +# Run our pre-lint checks +tools-version: + stage: setup + script: + - docker pull hadolint/hadolint + - docker run hadolint/hadolint hadolint --version + - docker pull mivok/markdownlint + - docker run mivok/markdownlint --version + +dockerfiles: + stage: lint + script: + # excluding a few https://github.com/hadolint/hadolint/issues/281, https://github.com/hadolint/hadolint/issues/279 + # $ find . -name Dockerfile \( ! -path ./runner/openjdk-8/Dockerfile ! -path ./runner/openjdk-8-x-openjdk-10/Dockerfile ! -path ./runner/openjdk-8-x-openjdk-11/Dockerfile ! -path ./runner/openjdk-10/Dockerfile \) -exec echo "echo 'hadolint {}' && docker run -i hadolint/hadolint hadolint - < {}" \; + - echo 'hadolint ./samples/gradle-java-jdk8-x-jre11-custom/Dockerfile' && docker run -i hadolint/hadolint hadolint - < ./samples/gradle-java-jdk8-x-jre11-custom/Dockerfile + - echo 'hadolint ./samples/gradle-java-jdk10-jre10/Dockerfile' && docker run -i hadolint/hadolint hadolint - < ./samples/gradle-java-jdk10-jre10/Dockerfile + - echo 'hadolint ./samples/gradle-java-jdk8-x-jre10-custom/Dockerfile' && docker run -i hadolint/hadolint hadolint - < ./samples/gradle-java-jdk8-x-jre10-custom/Dockerfile + - echo 'hadolint ./samples/gradle-java-jdk8-jre8/Dockerfile' && docker run -i hadolint/hadolint hadolint - < ./samples/gradle-java-jdk8-jre8/Dockerfile + - echo 'hadolint ./builder/maven-3/jdk-10/Dockerfile' && docker run -i hadolint/hadolint hadolint - < ./builder/maven-3/jdk-10/Dockerfile + - echo 'hadolint ./builder/maven-3/jdk-8/Dockerfile' && docker run -i hadolint/hadolint hadolint - < ./builder/maven-3/jdk-8/Dockerfile + - echo 'hadolint ./builder/maven-3/jdk-8-x-jdk-11/Dockerfile' && docker run -i hadolint/hadolint hadolint - < ./builder/maven-3/jdk-8-x-jdk-11/Dockerfile + - echo 'hadolint ./builder/maven-3/jdk-8-x-jdk-10/Dockerfile' && docker run -i hadolint/hadolint hadolint - < ./builder/maven-3/jdk-8-x-jdk-10/Dockerfile + - echo 'hadolint ./builder/gradle-4/jdk-10/Dockerfile' && docker run -i hadolint/hadolint hadolint - < ./builder/gradle-4/jdk-10/Dockerfile + - echo 'hadolint ./builder/gradle-4/jdk-8/Dockerfile' && docker run -i hadolint/hadolint hadolint - < ./builder/gradle-4/jdk-8/Dockerfile + - echo 'hadolint ./builder/gradle-4/jdk-8-x-jdk-11/Dockerfile' && docker run -i hadolint/hadolint hadolint - < ./builder/gradle-4/jdk-8-x-jdk-11/Dockerfile + - echo 'hadolint ./builder/gradle-4/jdk-8-x-jdk-10/Dockerfile' && docker run -i hadolint/hadolint hadolint - < ./builder/gradle-4/jdk-8-x-jdk-10/Dockerfile + +docker-compose: + stage: lint + script: + - > + docker-compose + --file - < docker-compose.yml + config + +# lint the README using Markdownlint +readme: + stage: lint + allow_failure: True + script: + - > + docker run -i + mivok/markdownlint + --rules ~MD013 + - < README.md + +# Lint the Dockerfile using Hadolint +build-gitlab: + stage: docker-build + before_script: + # Private registry here in GitLabs require login + # https://docs.gitlab.com/ee/ci/docker/using_docker_build.html#authenticating-to-the-container-registry + # https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html#creating-a-personal-access-token + # Variables are in the environment https://gitlab.com/groups/supercash/-/settings/ci_cd + # Look at the env vars above for details + - docker login -u ${GITLAB_DOCKER_LOGIN} -p ${GITLAB_DOCKER_PASSWORD} ${CI_REGISTRY} + + # Process images with docker-compose config + - apk add --no-cache curl jq python py-pip + - pip install yq + + script: + # Get the name of the original image by compose to store in a temporary script at dockerhub-images.sh + # So that we can run it in deploy https://gitlab.com/gitlab-org/gitlab-runner/issues/1099#note_4002529 + - BUILDER_GIT_SHA=${CI_COMMIT_SHA} + - BUILDER_GIT_BRANCH=${CI_COMMIT_REF_NAME} + - if [ "${BUILDER_GIT_BRANCH}" = "master" ]; then DOCKER_IMAGE_TAG="latest"; else DOCKER_IMAGE_TAG="${BUILDER_GIT_BRANCH}"; fi + - echo "Setting the docker image tag as ${DOCKER_IMAGE_TAG}" + - docker-compose build --pull --parallel + + - echo "Current docker images" + - docker images + + # Create the list of images + - mkdir images-list/ + + - IMAGES=$(docker-compose config | yq '.' | jq -r '..|.image? | select(.!=null)') + - echo "Current images are the folloing ${IMAGES}" + - > + for IMAGE_NAME in ${IMAGES}; do + DOCKER_HUB_IMAGE_TAG=${IMAGE_NAME}; + echo ""; + echo "=> processing image ${DOCKER_HUB_IMAGE_TAG}"; + echo ""; + + IMAGE=${DOCKER_HUB_IMAGE_TAG%:*}; + TAG=${DOCKER_HUB_IMAGE_TAG#*:}; + GROUP=${IMAGE/unmazedboot\//} + + GITLAB_IMAGE="${CI_REGISTRY_IMAGE}/${GROUP}/${TAG}:${DOCKER_IMAGE_TAG}"; + echo "=> Tag image ${DOCKER_HUB_IMAGE_TAG} for gitlab as ${GITLAB_IMAGE}"; + echo "docker tag ${DOCKER_HUB_IMAGE_TAG} ${GITLAB_IMAGE}"; + docker tag ${DOCKER_HUB_IMAGE_TAG} ${GITLAB_IMAGE}; + echo ""; + + echo "=> Pushing to Gitlab ${GITLAB_IMAGE}"; + docker push ${GITLAB_IMAGE}; + echo ""; + + METADATA_FILE="images-list/${CI_COMMIT_SHA}-${TAG}-image.txt"; + echo "<= Saving metadata '${GITLAB_IMAGE}|${DOCKER_HUB_IMAGE_TAG}' at ${METADATA_FILE}"; + echo "${GITLAB_IMAGE}|${DOCKER_HUB_IMAGE_TAG}" > ${METADATA_FILE}; + done + + # ^^^ Tag and push the image with the name of this repo to be reused in the deploy stage + # https://docs.gitlab.com/ee/ci/docker/using_docker_build.html#container-registry-examples + # https://forum.gitlab.com/t/passing-docker-image-between-build-and-test-stage-in-gitlab-runner/2444/9" + + artifacts: + paths: + - images-list/ + when: on_success + +push-github: + stage: docker-push + dependencies: + - build-gitlab + before_script: + # Private registry here in GitLabs require login + # https://docs.gitlab.com/ee/ci/docker/using_docker_build.html#authenticating-to-the-container-registry + # https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html#creating-a-personal-access-token + # Look at the env vars above for details + - echo "Login to the GitLab Docker Registry" + - docker login -u ${GITLAB_DOCKER_LOGIN} -p ${GITLAB_DOCKER_PASSWORD} ${CI_REGISTRY} + + # Login to the AWS Docker Registry + - echo "Login to Dockerhub Registry" + - docker login -u ${DOCKERHUB_LOGIN} -p ${DOCKERHUB_PASSWORD} + + - echo "Here's the Docker registry details docker info" + - docker info | grep Registry + + script: + # Pull and tag the gitlab image with the original docker image name again + # https://gitlab.com/gitlab-org/gitlab-runner/issues/1099#note_4002529 + + # Artifacts are created under CI_PROJECT_DIR https://forum.gitlab.com/t/gitlab-ci-artifacts-not-found/7588 + - echo "Looking at the files at ${CI_PROJECT_DIR}" + + - IMAGE_FILES=$(find ${CI_PROJECT_DIR} -name "*-image.txt") + - echo "Current images metadata the folloing \n ${IMAGE_FILES}" + # the image name below IMAGE_FILE is on the format "gitlab|github created above" + + - > + for IMAGE_FILE in ${IMAGE_FILES}; do + NAMES=$(cat ${IMAGE_FILE}); + GITLAB_IMAGE=${NAMES%|*}; + DOCKER_HUB_IMAGE=${NAMES#*|}; + echo ""; + echo "<========= pulling ${GITLAB_IMAGE}"; + docker pull ${GITLAB_IMAGE}; + echo ""; + + echo "========= tagging ${GITLAB_IMAGE} as ${DOCKER_HUB_IMAGE}"; + docker tag ${GITLAB_IMAGE} ${DOCKER_HUB_IMAGE}; + echo "" + + echo "=========> pushing ${DOCKER_HUB_IMAGE}"; + docker push ${DOCKER_HUB_IMAGE}; + done + + - echo "Pushed all images to DockerHub!!!" + + only: + - master diff --git a/CHANGELOG b/CHANGELOG new file mode 100644 index 0000000..a2e94ba --- /dev/null +++ b/CHANGELOG @@ -0,0 +1 @@ +1. Initial version 0.1.0 diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..75b54f9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014-2015 Intuit Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..908b633 --- /dev/null +++ b/README.md @@ -0,0 +1,312 @@ +# Generic SpringBoot Docker files and image management + + + +Get started with your SpringBoot App in seconds. Use your favorite builder (Gradle or Maven) and choose your version of JRE - without needing to manage a complex maze of non-business logic steps in your Dockerfiles! + +## Benefits + +* No more copy-and-paste Dockerfile boilerplate code for your App's Runnable Jars! + * We use the Builder Pattern for Gradle and Maven +* Decoupled way to run your application in different JVMs + * Our parameterized builds allows you to just select which JVM implementation to run! +* Enterprise-friendly: Pick and choose the base images for your applications and push to your internal Docker Registry! + +# Current Support + +* `Builder`: Any Java build system. + * [x] `Maven` different base Operating Systems. + * [x] `Gradle` different base Operating Systems. + * [ ] `Bazel` Waiting for contributions. +* `Linker`: Any JDK 9+ with support to `jlink` to generate custom JVMs tailored for your application `.jar` + * [x] `OpenJDK on Alpine `musl` + * [x] `OpenJDK on Debian `glibc` +* `Runner`: Any JVM available to the Custom JVMs generated by the `Linker` for your application. + +All images are located at the [DockerHub Intuit Repository](https://cloud.docker.com/u/intuit/repository/list?name=unmazedboot&namespace=intuit). + +## Builder + +Implementation of a set of `ONBUILD` instructions that are reusable for any SpringBoot Application: + +* Injection of env vars such as `GIT_SHA`, `GIT_BRANCH` and `BUILD_NUMBER` for versioning. +* Supports the following builders: + * [x] Gradle 4.x.x + openjdk 1.8 + * [x] Maven 3.x.x + openjdk 1.8 + * [x] Gradle 4.x.x + openjdk 1.11 + * [x] Gradle 5.x.x + openjdk 1.12 + * [x] Maven 3.x.x + openjdk 1.11 + * [x] Maven 3.x.x + openjdk 1.12 + +## Linker + +Implementation of the call using `jlink` to create a custom VM for your application based on the generated Jar. + +* Custom Runners will consume the linker JVM. + +## Runner + +Implementation of all tasks to execute a runnable `WAR` from a SpringBoot application. + +* Uses the built executable file to the appropriate directory. +* Prepares the image with underlying capabilities to make TLS calls. +* Uses small JRE images. +* Supports the following Runners: + * [x] JRE Slim 1.8 + * [x] JRE Slim 1.11 + * [x] JRE Slim 1.12 + * [x] JRE Alpine 1.11 + * [x] JRE Alpine 1.12 + +## Samples + +Implementation of samples using the Docker Images for both `builder` and `runner`. +Look at the directory `samples` for details. + +* Samples with the following: + * [x] Java/Gradle SpringBoot 2.x with JRE Slim 1.8 + * [x] Java/Gradle SpringBoot 2.x with JRE Slim 1.11 + * [x] Java/Gradle SpringBoot 2.x with JRE Slim 1.12 + * [x] Kotlin/Gradle SpringBoot 2.x with JRE Slim 1.8 + * [ ] Kotlin/Gradle SpringBoot 2.x with JRE Slim 1.11 + +# Gradle Builder + +* Gradle version is latest 5.0.0, currently at 4.10.1 with OpenJDK 1.8 + +* Uses Gradle as the builder tool and requires: + * `build.gradle`: Main build file + * `settings.gradle`: Project settings + * `src/build/gradle`: Individual tasks implementation linked at `build.gradle` +* Regular Java project using maven structure + * `src/main/java`: java project + +## Gradle Builder Args + +Requires the use of the following build args + +* `BUILDER_GIT_SHA`: the current sha of the project +* `BUILDER_GIT_BRANCH`: the current branch of the project +* `BUILDER_GRADLE_BUILD_CMD`: the command used to build the executable `jar` or `war` + * `gradle bootRepackage` or `gradle build` + * https://docs.spring.io/spring-boot/docs/1.5.16.RELEASE/reference/html/build-tool-plugins-gradle-plugin.html#build-tool-plugins-gradle-packaging + +## Gradle Builder Dockerfile + +If you use gradle, declare your images with the dependency to gradle. Note that builder image +must be annotated `as unmazedboot-builder-artifacts`, so that the runner knows where to get the built artifacts from. + +* The builder should be the first image of the Dockerfile + * It can also include additional steps required by the builder such as installing new dependencies, etc. + +```dockerfile +FROM unmazedboot/builder:gradle4.10.2-jdk8-alpine as unmazedboot-builder-artifacts + +RUN echo "You can add extra packages or anything needed to the final image for building" +``` + +# Maven Builder + +* Latest Maven version with versions +* Uses Maven as the builder tool and requires: + * `pom.xml`: Main build file + * `settings.xml`: Project settings + * `src/build/gradle`: Individual tasks implementation linked at `build.gradle` +* Regular Java project using maven structure + * `src/main/java`: java project + +## Maven Builder Args + +Requires the use of the following build args + +* `BUILDER_GIT_SHA`: the current sha of the project +* `BUILDER_GIT_BRANCH`: the current branch of the project +* `BUILDER_MAVEN_BUILD_CMD`: the command used to build the executable `jar` or `war` + * `mvn -s settings.xml install -P embedded` +* `BUILDER_DIR`: The directory containing the executable file. + * Default Gradle directory is `build/libs` + * Default Maven directory is `target` + +# Generic Runner + +* The runner image is the same for any builder supported + * Gradle + * Maven +* The single image simplifies the whole process and requires a couple of args +* Entrypoint defined as `start.sh` with the following capabilities + * Sources a group of files under the `/runtime/sources/*.sh` dir + * Creates JAVA_OPTS based on values under `/runtime/java-opts/*.opt` + * Executes a default command provided, showing debug information + +Those are the runtime information important when deploying springboot in Docker/Kubernetes environments. In addition: + +* `/runtime/sources` gives you a mount path to execute additional app-based hooks + * You can use side-cars during Kubernetes deployments +* `runtime/java-opts` are values that comes from sidecars or secret values + +## Runner Args + +Requires the use of the following build args to build, providing optional values. + +* `RUNNER_EXTENSION`: the extension of the executable binary + * Gradle has plenty of examples with `jar` and `war` files. +* `RUNNER_PORT`: the port to use in the `EXPOSE` instruction in the final Docker Image +* `RUNNER_HOOKS_DIR_SOURCES`: the sources directory to be executed before executing +* `RUNNER_ENV_HOOK_VAR`: the name of the env to be populated with contents from `RUNNER_HOOKS_ENV_VAR_DIR` + * Defaults to `JAVA_OPTS` +* `RUNNER_HOOKS_ENV_VAR_DIR`: the directory with contents to be concatenated as value for `RUNNER_ENV_HOOK_VAR` + * Those values for `mem`, `agents`, etc. +* `RUNNER_CMD_EXEC`: The command to execute after the sources and var has been processed. + 1. source `RUNNER_HOOKS_DIR_SOURCES/*.sh` + 2. `RUNNER_ENV_HOOK_VAR`=concat of all `RUNNER_HOOKS_ENV_VAR_DIR/*.opt` + 3. `RUNNER_CMD_EXEC` is executed, already set for runnable springboot apps + +This runnable image will require any stage of the Dockerfile to be named `as unmazedboot-builder-artifacts` as shown above. + +## Runner Dockerfile + +* The runner is the last image in the `Dockerfile` without any stage name. + * It also should be specified the tag referring to the supported runtime. +* The version supported is the tag with the kind of JRE to use. + +```dockerfile +FROM intuit/unmazedboot:runner-openjdk-8-jre-slim + +RUN echo "You can include more libraries or anything in the Runnable image" +``` + +# Gradle Sample + +* Provide the build args as needed. +* You can use the default images. + * See the samples for details + * See the runner Dockerfile for details + +Go to the directory `sample` directory for more details. + +## Build all Samples + +Building all samples in parallel (`docker-compose version 1.23.1, build b02f1306`) + +``` +$ docker-compose -f docker-compose-samples.yaml build --parallel +Building sample-gradle-java-jre8 ... +Building sample-gradle-java-jre10 ... +Building samples-gradle-java-custom-jre10 ... +Building sample-gradle-java-jre8 +Building samples-gradle-java-custom-jre10 +Building sample-gradle-java-jre10 +``` + +## JVM Hooks + +* It's common to add the creation of `JAVA_OPTS` either in a shell script +or a concatenation of all things needed. + * In addition, JAVA_OPTS may depend on agents available in given environments +* For a given environment, you can inject sources that will compute what's needed + * In this case, something that is run before JAVA_OPTS gets created. + +The support for hooks is added as a feature that uses an environment injector +pattern. This is useful when dealing with containers in Kubernetes that are +initialized via `InitContainer` and requires sources. There are 2 types as explained +above and the sample is in JDK 11 cross-compiled + +``` +$ docker-compose -f docker-compose-samples.yaml up --build samples-gradle-java-jdk8-x-jre-custom-11 +Building samples-gradle-java-jdk8-x-jre-custom-11 +Step 1/10 : ARG BUILDER_GIT_SHA=${GIT_SHA:-0101010} +Step 2/10 : ARG BUILDER_GIT_BRANCH=${GIT_BRANCH:-develop} +Step 3/10 : ARG BUILDER_BUILD_NUMBER=${BUILD_NUMBER:-0223} +Step 4/10 : ARG BUILDER_GRADLE_DOWNLOAD_DEPENDENCIES_CMD="gradle downloadDependencies" +Step 5/10 : ARG BUILDER_GRADLE_BUILD_CMD="gradle build -x test" +Step 6/10 : ARG BUILDER_DIR="build/libs" +Step 7/10 : ARG RUNNER_EXTENSION="jar" +Step 8/10 : ARG RUNNER_PORT="8080" +Step 9/10 : FROM unmazedboot/builder:gradle-4-jdk8-x-jdk11 as unmazedboot-builder-artifacts +# Executing 18 build triggers + ---> Using cache +... +... +---> Using cache + ---> dd9c8589da4c + +Step 10/10 : FROM unmazedboot/runner:jre8-x-jre11-custom +# Executing 34 build triggers + ---> Using cache +... +... + ---> Using cache + ---> 73f12942ee77 + +Successfully built 73f12942ee77 +Successfully tagged sample-jdk8-x-jre11-custom:latest +Starting springboot-docker-reusable-images_samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 ... done +Attaching to springboot-docker-reusable-images_samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 +samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | +samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | => Initializing SpringBoot Runner 'start.sh' +samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | +samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | => Processing env hooks at /runtime/sources +samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | +samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | [1] source /runtime/sources/myself.sh +samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | +samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | => Processing hooks at /runtime/java-opts +samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | +samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | [1] << /runtime/java-opts/mem.opt +samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | +samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | Exporting JAVA_OPTS= -XX:+UnlockExperimentalVMOptions -XX:+UseG1GC -XX:+UseStringDeduplication -XX:MaxRAMFraction=2 -XshowSettings:vm +samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | +samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | ####### Debugging env before app start ########## +samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | +samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | DEBUG_ENV=true +samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | HOSTNAME=dc6ede09cd5b +samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | JAVA_OPTS= -XX:+UnlockExperimentalVMOptions -XX:+UseG1GC -XX:+UseStringDeduplication -XX:MaxRAMFraction=2 -XshowSettings:vm +samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | JAVA_HOME=/opt/jdk-custom/jre +samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | RUNNER_EXTENSION=jar +samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | BUILDER_DIR=build/libs +samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | RUNNER_PORT=8080 +samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | RUNNER_HOOKS_ENV_VAR_DIR=/runtime/java-opts +samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | PWD=/runtime +samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | HOME=/root +samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | NAME=Marcello +samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | RUNNER_CMD_EXEC=java $JAVA_OPTS -jar /runtime/server.jar $JAR_OPTS +samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | APP_TIMEZONE=PST +samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | CITY=San Diego +samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | SHLVL=1 +samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | RUNNER_HOOKS_DIR_SOURCES=/runtime/sources +samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/jdk-custom/jre/bin +samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | _=/usr/bin/env +samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | +samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | Starting the app +samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | java $JAVA_OPTS -jar /runtime/server.jar $JAR_OPTS +samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | +samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | OpenJDK 64-Bit Server VM warning: Option MaxRAMFraction was deprecated in version 10.0 and will likely be removed in a future release. +samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | VM settings: +samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | Max. Heap Size (Estimated): 3.89G +samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | Using VM: OpenJDK 64-Bit Server VM +samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | +samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | +samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | . ____ _ __ _ _ +samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ +samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ +samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | \\/ ___)| |_)| | | | | || (_| | ) ) ) ) +samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | ' |____| .__|_| |_|_| |_\__, | / / / / +samples-gradle-java-jdk8-x-jre-custom-11_1_76ab77ce7bd7 | =========|_|==============|___/=/_/_/_/ +``` + +* Execute the sample for more details + +## Start all samples + +``` +$ docker-compose -f docker-compose-samples.yaml up +``` + +# Contributing + +* See [Contributing](https://github.com/intuit/unmazedboot/blob/master/.github/CONTRIBUTING.md) + +# Builds + +* We use GitLab Build Pipelines +* Deployments are from the Master Branch +* Docker Images will be pushed to Docker Registry available at hub.docker.com diff --git a/builder/gradle.Dockerfile b/builder/gradle.Dockerfile new file mode 100644 index 0000000..211ffbf --- /dev/null +++ b/builder/gradle.Dockerfile @@ -0,0 +1,52 @@ +# ##################################################################### +# Build and pull dependencies +# ##################################################################### +# Build Arguments to be received from a build pipeline +# Use --build-arg = during docker build +# https://github.com/moby/moby/issues/15025#issuecomment-371466934 +# ##################################################################### +ARG UNMAZEDBOOT_INTERNAL_BASE_IMAGE + +# hadolint ignore=DL3006 +FROM ${UNMAZEDBOOT_INTERNAL_BASE_IMAGE} + +# hadolint ignore=DL3002 +USER root + +ARG UNMAZEDBOOT_INTERNAL_DEPENDENCIES +RUN sh -c "${UNMAZEDBOOT_INTERNAL_DEPENDENCIES}" + +# Adding dependencies to the image that the user requires +ONBUILD ARG BUILDER_BINARY_DEPENDENCIES +ONBUILD RUN sh -c "${BUILDER_BINARY_DEPENDENCIES:-echo installing-no-builder-dependencies}" + +# The command used to build the gradle app +ONBUILD ARG UNMAZEDBOOT_BUILDER_GRADLE_BUILD_CMD +# The extension of the produced artifacts, usually "jar" or "war" +ONBUILD ARG UNMAZEDBOOT_BUILDER_PACKAGE_EXTENSION +ONBUILD ENV UNMAZEDBOOT_BUILDER_PACKAGE_EXTENSION=${UNMAZEDBOOT_BUILDER_PACKAGE_EXTENSION} +# The dir where the artifacts are built, usually "build/" +ONBUILD ARG UNMAZEDBOOT_BUILDER_DIR +ONBUILD ENV UNMAZEDBOOT_BUILDER_DIR=${UNMAZEDBOOT_BUILDER_DIR} + +WORKDIR /app/ + +# Copy the needed files to build a gradle project +ONBUILD COPY ./build.gradle build.gradle +ONBUILD COPY ./settings.gradle settings.gradle +ONBUILD COPY ./src src/ + +ONBUILD RUN echo "Executing UNMAZEDBOOT_BUILDER_GRADLE_BUILD_CMD='${UNMAZEDBOOT_BUILDER_GRADLE_BUILD_CMD}'" +ONBUILD RUN ${UNMAZEDBOOT_BUILDER_GRADLE_BUILD_CMD} + +ONBUILD RUN echo "Built artifacts at /app/${UNMAZEDBOOT_BUILDER_DIR} and looking for package .${UNMAZEDBOOT_BUILDER_PACKAGE_EXTENSION}" +ONBUILD RUN find . -name "/app/${UNMAZEDBOOT_BUILDER_DIR}/*.${UNMAZEDBOOT_BUILDER_PACKAGE_EXTENSION}" + +# Just rename the built version +ONBUILD RUN echo "Renaming the executable ${UNMAZEDBOOT_BUILDER_PACKAGE_EXTENSION} to the runtime dir" +ONBUILD RUN mkdir /runtime/ && \ + find /app/${UNMAZEDBOOT_BUILDER_DIR} -name "*.${UNMAZEDBOOT_BUILDER_PACKAGE_EXTENSION}" ! -name "*sources*" ! -name "*javadoc*" -exec cp -t /runtime {} + && \ + mv /runtime/*.${UNMAZEDBOOT_BUILDER_PACKAGE_EXTENSION} /runtime/server.jar + +ONBUILD RUN echo "Contents for built /runtime/server.jar" +ONBUILD RUN echo "jar -tf /runtime/server.jar" diff --git a/builder/maven.Dockerfile b/builder/maven.Dockerfile new file mode 100644 index 0000000..37856d6 --- /dev/null +++ b/builder/maven.Dockerfile @@ -0,0 +1,52 @@ +# ##################################################################### +# Build and pull dependencies +# ##################################################################### +# Build Arguments to be received from a build pipeline +# Use --build-arg = during docker build +# https://github.com/moby/moby/issues/15025#issuecomment-371466934 +# ##################################################################### +ARG UNMAZEDBOOT_INTERNAL_BASE_IMAGE + +# hadolint ignore=DL3006 +FROM ${UNMAZEDBOOT_INTERNAL_BASE_IMAGE} + +# hadolint ignore=DL3002 +USER root + +ARG UNMAZEDBOOT_INTERNAL_DEPENDENCIES +RUN sh -c "${UNMAZEDBOOT_INTERNAL_DEPENDENCIES}" + +# Adding dependencies to the image that the user requires +ONBUILD ARG UNMAZEDBOOT_BUILDER_BINARY_DEPENDENCIES +ONBUILD RUN sh -c "${UNMAZEDBOOT_BUILDER_BINARY_DEPENDENCIES:-echo installing-no-builder-dependencies}" + +# The command used to build the maven app +ONBUILD ARG UNMAZEDBOOT_BUILDER_MAVEN_BUILD_CMD +# The extension of the produced artifacts, usually "jar" or "war" +ONBUILD ARG UNMAZEDBOOT_BUILDER_PACKAGE_EXTENSION +ONBUILD ENV UNMAZEDBOOT_BUILDER_PACKAGE_EXTENSION=${UNMAZEDBOOT_BUILDER_PACKAGE_EXTENSION} +# The dir where the artifacts are built, usually "build/" +ONBUILD ARG UNMAZEDBOOT_BUILDER_DIR +ONBUILD ENV UNMAZEDBOOT_BUILDER_DIR=${UNMAZEDBOOT_BUILDER_DIR} + +WORKDIR /app/ + +# Copy the needed files to build a maven project +ONBUILD COPY ./pom.xml pom.xml +ONBUILD COPY ./settings.xml settings.xml +ONBUILD COPY ./src src/ + +ONBUILD RUN echo "Executing UNMAZEDBOOT_BUILDER_MAVEN_BUILD_CMD=${UNMAZEDBOOT_BUILDER_MAVEN_BUILD_CMD}" +ONBUILD RUN ${UNMAZEDBOOT_BUILDER_MAVEN_BUILD_CMD} + +ONBUILD RUN echo "Built artifacts at /app/${UNMAZEDBOOT_BUILDER_DIR} and looking for package .${UNMAZEDBOOT_BUILDER_PACKAGE_EXTENSION}" +ONBUILD RUN find . -name "/app/${UNMAZEDBOOT_BUILDER_DIR}/*.${UNMAZEDBOOT_BUILDER_PACKAGE_EXTENSION}" + +# Just rename the built version +ONBUILD RUN echo "Renaming the executable ${UNMAZEDBOOT_BUILDER_PACKAGE_EXTENSION} to the runtime dir" +ONBUILD RUN mkdir /runtime/ && \ + find /app/${UNMAZEDBOOT_BUILDER_DIR} -name "*.${UNMAZEDBOOT_BUILDER_PACKAGE_EXTENSION}" ! -name "*sources*" ! -name "*javadoc*" -exec cp -t /runtime {} + && \ + mv /runtime/*.${UNMAZEDBOOT_BUILDER_PACKAGE_EXTENSION} /runtime/server.jar + +ONBUILD RUN echo "Contents for built /runtime/server.jar" +ONBUILD RUN echo "jar -tf /runtime/server.jar" diff --git a/docker-compose-samples.yml b/docker-compose-samples.yml new file mode 100644 index 0000000..d5e34d9 --- /dev/null +++ b/docker-compose-samples.yml @@ -0,0 +1,125 @@ +version: "3.7" + +services: + + sample-gradle-java-jre8: + image: intuit/unmazedboot-sample:jdk8-jre8-debian${UNMAZEDBOOT_RUNNER_VERSION} + build: + context: samples/gradle-java-jdk8-jre8 + args: + - UNMAZEDBOOT_BUILDER_GRADLE_VERSION=${UNMAZEDBOOT_BUILDER_GRADLE_VERSION} + - UNMAZEDBOOT_RUNNER_VERSION=${UNMAZEDBOOT_RUNNER_VERSION} + - UNMAZEDBOOT_BUILDER_GIT_SHA=11110000 + - UNMAZEDBOOT_BUILDER_GIT_BRANCH=master + environment: + - RUNNER_DEBUG_ENV=true + ports: + - 8080:8080 + + sample-jdk11-x-jre-custom-12: + image: intuit/unmazedboot-sample:jdk11-x-jre12-custom-debian${UNMAZEDBOOT_RUNNER_VERSION} + build: + context: samples/gradle5-java-jdk11-x-jre12 + args: + - UNMAZEDBOOT_BUILDER_GRADLE_VERSION=${UNMAZEDBOOT_BUILDER_GRADLE_VERSION} + - UNMAZEDBOOT_LINKER_VERSION=${UNMAZEDBOOT_LINKER_VERSION} + - UNMAZEDBOOT_RUNNER_VERSION=${UNMAZEDBOOT_RUNNER_VERSION} + - UNMAZEDBOOT_BUILDER_GIT_SHA=11110000 + - UNMAZEDBOOT_BUILDER_GIT_BRANCH=master + environment: + - RUNNER_DEBUG_ENV=true + ports: + - 8081:8080 + + samples-gradle-java-jdk8-x-jre-custom-11-alpine: + image: intuit/unmazedboot-sample:jdk8-x-jre11-custom-alpine${UNMAZEDBOOT_RUNNER_VERSION} + build: + context: samples/gradle-java-jdk8-x-jre11-custom + args: + - UNMAZEDBOOT_BUILDER_GRADLE_VERSION=${UNMAZEDBOOT_BUILDER_GRADLE_VERSION} + - UNMAZEDBOOT_LINKER_VERSION=${UNMAZEDBOOT_LINKER_VERSION} + - UNMAZEDBOOT_RUNNER_VERSION=${UNMAZEDBOOT_RUNNER_VERSION} + - UNMAZEDBOOT_BUILDER_GIT_SHA=11110000 + - UNMAZEDBOOT_BUILDER_GIT_BRANCH=master + environment: + - DEBUG_ENV=true + #- JAVA_OPTS=--marcello + ports: + - 8082:8080 + # volumes: + # - "./samples/gradle-java-jdk8-x-jre11-custom/hooks/sources:/runtime/sources/" + # - "./samples/gradle-java-jdk8-x-jre11-custom/hooks/java-opts:/runtime/java-opts" + + samples-gradle-java-jdk8-x-jre-custom-11-debian: + image: intuit/unmazedboot-sample:jdk8-x-jre11-custom-debian${UNMAZEDBOOT_RUNNER_VERSION} + build: + context: samples/gradle-java-jdk8-x-jre11-custom-debian + args: + - UNMAZEDBOOT_BUILDER_GRADLE_VERSION=${UNMAZEDBOOT_BUILDER_GRADLE_VERSION} + - UNMAZEDBOOT_LINKER_VERSION=${UNMAZEDBOOT_LINKER_VERSION} + - UNMAZEDBOOT_RUNNER_VERSION=${UNMAZEDBOOT_RUNNER_VERSION} + - UNMAZEDBOOT_BUILDER_GIT_SHA=00011001 + - UNMAZEDBOOT_BUILDER_GIT_BRANCH=develop + environment: + - RUNNER_DEBUG_ENV=true + #- JAVA_OPTS=--marcello + ports: + - 8083:8080 + # volumes: + # - "./samples/gradle-java-jdk8-x-jre11-custom/hooks/sources:/runtime/sources/" + # - "./samples/gradle-java-jdk8-x-jre11-custom/hooks/java-opts:/runtime/java-opts" + + samples-gradle-java-jdk8-x-jre-custom-11-centos: + image: intuit/unmazedboot-sample:jdk8-x-jre11-custom-centos${UNMAZEDBOOT_RUNNER_VERSION} + build: + context: samples/gradle-java-jdk8-x-jre11-custom-centos + args: + - UNMAZEDBOOT_BUILDER_GRADLE_VERSION=${UNMAZEDBOOT_BUILDER_GRADLE_VERSION} + - UNMAZEDBOOT_LINKER_VERSION=${UNMAZEDBOOT_LINKER_VERSION} + - UNMAZEDBOOT_RUNNER_VERSION=${UNMAZEDBOOT_RUNNER_VERSION} + - UNMAZEDBOOT_BUILDER_GIT_SHA=00011001 + - UNMAZEDBOOT_BUILDER_GIT_BRANCH=develop + environment: + - RUNNER_DEBUG_ENV=true + #- JAVA_OPTS=--marcello + ports: + - 8084:8080 + # volumes: + # - "./samples/gradle-java-jdk8-x-jre11-custom/hooks/sources:/runtime/sources/" + # - "./samples/gradle-java-jdk8-x-jre11-custom/hooks/java-opts:/runtime/java-opts" + + samples-maven-java-jdk11-x-jre-custom-11: + image: intuit/unmazedboot-sample:jre11-custom${UNMAZEDBOOT_RUNNER_VERSION} + build: + context: samples/maven-java-jdk11-custom + args: + - UNMAZEDBOOT_BUILDER_MAVEN_VERSION=${UNMAZEDBOOT_BUILDER_MAVEN_VERSION} + - UNMAZEDBOOT_LINKER_VERSION=${UNMAZEDBOOT_LINKER_VERSION} + - UNMAZEDBOOT_RUNNER_VERSION=${UNMAZEDBOOT_RUNNER_VERSION} + ports: + - 8085:8080 + - 7199:7199 + volumes: + - "~/.m2:/root/.m2" + - "./samples/maven-java-jdk11-custom/jfr-config:/runtime/jfr" + environment: + - DEBUG_ENV=true + - JAVA_OPTS=-showversion -XshowSettings:vm + - SPRING_CONFIG_LOCATION=/runtime/jfr/application.yml + +############ Kotlin Samples + + samples-gradle-kotlin-jdk8-jre8: + image: intuit/unmazedboot-sample-kotlin:jdk8-jre8-debian${UNMAZEDBOOT_RUNNER_VERSION} + build: + context: samples/gradle-kotlin-jdk1.8 + args: + - UNMAZEDBOOT_BUILDER_GRADLE_VERSION=${UNMAZEDBOOT_BUILDER_GRADLE_VERSION} + - UNMAZEDBOOT_RUNNER_VERSION=${UNMAZEDBOOT_RUNNER_VERSION} + ports: + - 8086:8080 + environment: + - DEBUG_ENV=true + - JAVA_OPTS=-showversion -XshowSettings:vm + + #samples/gradle-kotlin-jdk10-jre10: diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..dde0c24 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,227 @@ +version: "3.7" + +services: + +############# Builder JDK 8 + + builder-gradle4.10.2-jdk8-slim: + image: intuit/unmazedboot-builder-gradle:4.10.2-jdk8-slim${UNMAZEDBOOT_BUILDER_GRADLE_VERSION} + build: + context: builder + dockerfile: gradle.Dockerfile + args: + - UNMAZEDBOOT_INTERNAL_BASE_IMAGE=gradle:4.10.2-jdk8-slim + - UNMAZEDBOOT_INTERNAL_DEPENDENCIES=echo none + + builder-gradle4.10.2-jdk8-alpine: + image: intuit/unmazedboot-builder-gradle:4.10.2-jdk8-alpine${UNMAZEDBOOT_BUILDER_GRADLE_VERSION} + build: + context: builder + dockerfile: gradle.Dockerfile + args: + - UNMAZEDBOOT_INTERNAL_BASE_IMAGE=gradle:4.10.2-jdk8-alpine + # https://github.com/passbolt/passbolt_docker/issues/75#issuecomment-439629647 + # The command cp -t used below does not work without coreutils + - UNMAZEDBOOT_INTERNAL_DEPENDENCIES=apk add coreutils --no-cache + + builder-gradle5.0.0-jdk8-slim: + image: intuit/unmazedboot-builder-gradle:5.0.0-jdk8-slim${UNMAZEDBOOT_BUILDER_GRADLE_VERSION} + build: + context: builder + dockerfile: gradle.Dockerfile + args: + - UNMAZEDBOOT_INTERNAL_BASE_IMAGE=gradle:5.0.0-jdk8-slim + - UNMAZEDBOOT_INTERNAL_DEPENDENCIES=echo none + + builder-gradle5.0.0-jdk8-alpine: + image: intuit/unmazedboot-builder-gradle:5.0.0-jdk8-alpine${UNMAZEDBOOT_BUILDER_GRADLE_VERSION} + build: + context: builder + dockerfile: gradle.Dockerfile + args: + - UNMAZEDBOOT_INTERNAL_BASE_IMAGE=gradle:5.0.0-jdk8-alpine + # https://github.com/passbolt/passbolt_docker/issues/75#issuecomment-439629647 + # The command cp -t used below does not work without coreutils + - UNMAZEDBOOT_INTERNAL_DEPENDENCIES=apk add coreutils --no-cache + + builder-maven3.6.0-jdk8-slim: + image: intuit/unmazedboot-builder-maven:3.6.0-jdk8-slim${UNMAZEDBOOT_BUILDER_MAVEN_VERSION} + build: + context: builder + dockerfile: maven.Dockerfile + args: + - UNMAZEDBOOT_INTERNAL_BASE_IMAGE=maven:3.6.0-jdk-8-slim + - UNMAZEDBOOT_INTERNAL_DEPENDENCIES=echo none + + builder-maven3.6.0-jdk8-alpine: + image: intuit/unmazedboot-builder-maven:3.6.0-jdk8-alpine${UNMAZEDBOOT_BUILDER_MAVEN_VERSION} + build: + context: builder + dockerfile: maven.Dockerfile + args: + - UNMAZEDBOOT_INTERNAL_BASE_IMAGE=maven:3.6.0-jdk-8-alpine + # https://github.com/passbolt/passbolt_docker/issues/75#issuecomment-439629647 + # The command cp -t used below does not work without coreutils + - UNMAZEDBOOT_INTERNAL_DEPENDENCIES=apk add coreutils --no-cache + +############# Builder JDK 11 + + builder-gradle4.10.2-jdk11-slim: + image: intuit/unmazedboot-builder-gradle:4.10.2-jdk11-slim${UNMAZEDBOOT_BUILDER_GRADLE_VERSION} + build: + context: builder + dockerfile: gradle.Dockerfile + args: + - UNMAZEDBOOT_INTERNAL_BASE_IMAGE=gradle:4.10.2-jdk11-slim + - UNMAZEDBOOT_INTERNAL_DEPENDENCIES=echo none + + builder-gradle5.0.0-jdk11-slim: + image: intuit/unmazedboot-builder-gradle:5.0.0-jdk11-slim${UNMAZEDBOOT_BUILDER_GRADLE_VERSION} + build: + context: builder + dockerfile: gradle.Dockerfile + args: + - UNMAZEDBOOT_INTERNAL_BASE_IMAGE=gradle:5.0.0-jdk11-slim + - UNMAZEDBOOT_INTERNAL_DEPENDENCIES=echo none + + builder-maven3.6.0-jdk11-slim: + image: intuit/unmazedboot-builder-maven:3.6.0-jdk11-slim${UNMAZEDBOOT_BUILDER_MAVEN_VERSION} + build: + context: builder + dockerfile: maven.Dockerfile + args: + - UNMAZEDBOOT_INTERNAL_BASE_IMAGE=maven:3.6.0-jdk-11-slim + - UNMAZEDBOOT_INTERNAL_DEPENDENCIES=echo none + +############# Builder JDK 12 + + builder-maven3.6.0-jdk12-alpine: + image: intuit/unmazedboot-builder-maven:3.6.0-jdk12-alpine${UNMAZEDBOOT_BUILDER_MAVEN_VERSION} + build: + context: builder + dockerfile: maven.Dockerfile + args: + - UNMAZEDBOOT_INTERNAL_BASE_IMAGE=maven:3.6.0-jdk-12-alpine + # https://github.com/passbolt/passbolt_docker/issues/75#issuecomment-439629647 + # The command cp -t used below does not work without coreutils + - UNMAZEDBOOT_INTERNAL_DEPENDENCIES=apk add coreutils --no-cache + +############ Linker + + linker-jdk11-alpine: + image: intuit/unmazedboot-linker:jdk11-alpine${UNMAZEDBOOT_LINKER_VERSION} + build: + context: linker + args: + - UNMAZEDBOOT_INTERNAL_BASE_IMAGE=alpine:3.8 + - UNMAZEDBOOT_INTERNAL_DEPENDENCIES=wget https://download.java.net/java/early_access/alpine/25/binaries/openjdk-11-ea+25_linux-x64-musl_bin.tar.gz && tar zxf openjdk-11-ea+25_linux-x64-musl_bin.tar.gz && ln -s jdk-11 jdk && rm -f openjdk-11-ea+25_linux-x64-musl_bin.tar.gz + + # https://github.com/docker-library/openjdk/issues/217#issuecomment-436275472 + # Debian generates large libjvm and can be decreased + linker-jdk11-debian: + image: intuit/unmazedboot-linker:jdk11-debian${UNMAZEDBOOT_LINKER_VERSION} + build: + context: linker + args: + - UNMAZEDBOOT_INTERNAL_BASE_IMAGE=openjdk:11-jdk-slim + - UNMAZEDBOOT_INTERNAL_DEPENDENCIES=apt-get update && apt-get install -y binutils + - UNMAZEDBOOT_POST_JLINK_CMD=find /opt/jdk-custom/ -name libjvm.so | xargs ls -lah && find /opt/jdk-custom -name libjvm.so | xargs strip -p --strip-unneeded && find /opt/jdk-custom/ -name libjvm.so | xargs ls -lah + + linker-jdk12-alpine: + image: intuit/unmazedboot-linker:jdk12-alpine${UNMAZEDBOOT_LINKER_VERSION} + build: + context: linker + args: + - UNMAZEDBOOT_INTERNAL_BASE_IMAGE=openjdk:12-jdk-alpine + - UNMAZEDBOOT_INTERNAL_DEPENDENCIES=echo none + + linker-jdk12-debian: + image: intuit/unmazedboot-linker:jdk12-debian${UNMAZEDBOOT_LINKER_VERSION} + build: + context: linker + args: + - UNMAZEDBOOT_INTERNAL_BASE_IMAGE=openjdk:12-jdk + - UNMAZEDBOOT_INTERNAL_DEPENDENCIES=echo none + + linker-oracheljdk11-centos: + image: intuit/unmazedboot-linker:oracheljdk11-centos${UNMAZEDBOOT_LINKER_VERSION} + build: + context: linker + args: + - UNMAZEDBOOT_INTERNAL_BASE_IMAGE=sgrio/java-oracle:jdk_11_centos + - UNMAZEDBOOT_INTERNAL_DEPENDENCIES=echo none + - UNMAZEDBOOT_CUSTOM_JLINK_PATH=/usr/lib/jvm/java-11-oracle/bin/jlink + +############ Runner (Custom) + + runner-custom-jdk-alpine3.8: + image: intuit/unmazedboot-runner:custom-jdk-alpine3.8${UNMAZEDBOOT_RUNNER_VERSION} + build: + context: runner + dockerfile: custom-jlink-jdk/Dockerfile + args: + - UNMAZEDBOOT_INTERNAL_BASE_IMAGE=alpine:3.8 + - UNMAZEDBOOT_INTERNAL_DEPENDENCIES=apk update && apk add bash ca-certificates libressl libressl-dev --no-cache && update-ca-certificates + + runner-custom-jdk-centos7: + image: intuit/unmazedboot-runner:custom-jdk-centos7${UNMAZEDBOOT_RUNNER_VERSION} + build: + context: runner + dockerfile: custom-jlink-jdk/Dockerfile + args: + - UNMAZEDBOOT_INTERNAL_BASE_IMAGE=centos:7.5.1804 + - UNMAZEDBOOT_INTERNAL_DEPENDENCIES=yum -y install openssl + + runner-custom-jdk-debian9-slim: + image: intuit/unmazedboot-runner:custom-jdk-debian9-slim${UNMAZEDBOOT_RUNNER_VERSION} + build: + context: runner + dockerfile: custom-jlink-jdk/Dockerfile + args: + - UNMAZEDBOOT_INTERNAL_BASE_IMAGE=debian:sid-20181112-slim + - UNMAZEDBOOT_INTERNAL_DEPENDENCIES=apt-get update && apt-get install -y --no-install-recommends curl ca-certificates && apt-get clean && rm -rf /var/lib/apt/lists/* + + runner-openjdk-8u181-debian9-slim: + image: intuit/unmazedboot-runner:openjdk-8u181-debian9-slim${UNMAZEDBOOT_RUNNER_VERSION} + build: + context: runner + dockerfile: regular-jdk/Dockerfile + args: + - UNMAZEDBOOT_INTERNAL_BASE_IMAGE=openjdk:8u181-jre-slim + - UNMAZEDBOOT_INTERNAL_DEPENDENCIES=echo none + + runner-openjdk-8u181-alpine3.8: + image: intuit/unmazedboot-runner:openjdk-8u181-alpine3.8${UNMAZEDBOOT_RUNNER_VERSION} + build: + context: runner + dockerfile: regular-jdk/Dockerfile + args: + - UNMAZEDBOOT_INTERNAL_BASE_IMAGE=openjdk:8u181-jre-alpine3.8 + - UNMAZEDBOOT_INTERNAL_DEPENDENCIES=apk update && apk add bash ca-certificates libressl libressl-dev --no-cache && update-ca-certificates + + runner-openjdk-11-debian-slim: + image: intuit/unmazedboot-runner:openjdk-11-debian-slim${UNMAZEDBOOT_RUNNER_VERSION} + build: + context: runner + dockerfile: regular-jdk/Dockerfile + args: + - UNMAZEDBOOT_INTERNAL_BASE_IMAGE=openjdk:11-jre-slim + - UNMAZEDBOOT_INTERNAL_DEPENDENCIES=echo none + + runner-oraclejdk-jdk_11_centos: + image: intuit/unmazedboot-runner:oraclejdk-11-centos${UNMAZEDBOOT_RUNNER_VERSION} + build: + context: runner + dockerfile: regular-jdk/Dockerfile + args: + - UNMAZEDBOOT_INTERNAL_BASE_IMAGE=sgrio/java-oracle:jdk_11_centos + - UNMAZEDBOOT_INTERNAL_DEPENDENCIES=echo none + + runner-oraclejdk-11-alpine: + image: intuit/unmazedboot-runner:oraclejdk-11-alpine${UNMAZEDBOOT_RUNNER_VERSION} + build: + context: runner + dockerfile: regular-jdk/Dockerfile + args: + - UNMAZEDBOOT_INTERNAL_BASE_IMAGE=sgrio/java-oracle:jdk_11_alpine + - UNMAZEDBOOT_INTERNAL_DEPENDENCIES=apk update && apk add bash ca-certificates libressl libressl-dev --no-cache && update-ca-certificates diff --git a/linker/Dockerfile b/linker/Dockerfile new file mode 100644 index 0000000..6b60ced --- /dev/null +++ b/linker/Dockerfile @@ -0,0 +1,53 @@ +# ##################################################################### +# Build stage for running the Executable SpringBoot WAR files +# +# 1. Use a FROM gradle:4.10.2-jdk10 as unmazedboot-builder-artifacts +# 2. Build your steps needed +# 3. For runtime image use FROM marcellodesales/spring-boot-package-runner +# - It will copy the generate WAR and resources properly +# * Look at background info https://spring.io/guides/gs/spring-boot-docker/ +# * https://github.com/moby/moby/issues/15025#issuecomment-371466934 +# ##################################################################### +ARG UNMAZEDBOOT_INTERNAL_BASE_IMAGE + +# hadolint ignore=DL3006 +FROM ${UNMAZEDBOOT_INTERNAL_BASE_IMAGE} + +WORKDIR /opt + +ARG UNMAZEDBOOT_INTERNAL_DEPENDENCIES +RUN sh -c "${UNMAZEDBOOT_INTERNAL_DEPENDENCIES}" + +ENV JAVA_HOME=/opt/jdk +ENV PATH="$PATH:$JAVA_HOME/bin" + +# Using Jlink to create a custom JRE for the user +# The user-selected list of JDK modules to JRE +# http://openjdk.java.net/jeps/220, http://openjdk.java.net/projects/jigsaw/doc/jdk-modularization.html +ONBUILD ARG UNMAZEDBOOT_LINKER_JDK_MODULES +ONBUILD ENV UNMAZEDBOOT_LINKER_JDK_MODULES=${UNMAZEDBOOT_LINKER_JDK_MODULES:-java.base,java.logging,java.xml,jdk.unsupported,java.sql,java.naming,java.desktop,java.management,java.security.jgss,java.instrument} + +# Using the JLink http://openjdk.java.net/jeps/282 +ONBUILD RUN echo "Building custom JRE '/opt/jdk-custom' with UNMAZEDBOOT_LINKER_JDK_MODULES='${UNMAZEDBOOT_LINKER_JDK_MODULES}'" + +# The UNMAZEDBOOT_LINKER_JDK_MODULES are passed as a param, so onbuild it too +ONBUILD ENV UNMAZEDBOOT_INTERNAL_JLINK_COMMAND_ARGS="--module-path /opt/jdk/jmods \ + --verbose \ + --add-modules ${UNMAZEDBOOT_LINKER_JDK_MODULES} \ + --output /opt/jdk-custom \ + --compress 2 \ + --no-header-files \ + --no-man-pages" + +ARG UNMAZEDBOOT_CUSTOM_JLINK_PATH +ENV UNMAZEDBOOT_CUSTOM_JLINK_PATH=${UNMAZEDBOOT_CUSTOM_JLINK_PATH:-date} +# Some images have jlink in the path, others don't, so guaranteeing that we can provide during the build of this image +ONBUILD RUN echo "Linking jlink ${UNMAZEDBOOT_INTERNAL_JLINK_COMMAND_ARGS} || ${UNMAZEDBOOT_CUSTOM_JLINK_PATH} ${UNMAZEDBOOT_INTERNAL_JLINK_COMMAND_ARGS}" +ONBUILD RUN jlink ${UNMAZEDBOOT_INTERNAL_JLINK_COMMAND_ARGS} || ${UNMAZEDBOOT_CUSTOM_JLINK_PATH} ${UNMAZEDBOOT_INTERNAL_JLINK_COMMAND_ARGS} + +# https://github.com/docker-library/openjdk/issues/217#issuecomment-436275472 + +ARG UNMAZEDBOOT_POST_JLINK_CMD +ENV UNMAZEDBOOT_POST_JLINK_CMD=${UNMAZEDBOOT_POST_JLINK_CMD:-date} +RUN echo "Will execute command ${UNMAZEDBOOT_POST_JLINK_CMD} after jlink execution" +ONBUILD RUN sh -c "${UNMAZEDBOOT_POST_JLINK_CMD}" diff --git a/runner/collate.bash b/runner/collate.bash new file mode 100644 index 0000000..5a91308 --- /dev/null +++ b/runner/collate.bash @@ -0,0 +1,64 @@ +#!/bin/bash + +COLLATOR_KEY="COLLATE_" + +echo "" +echo "****** Initializing Collator ****** " +echo "" +echo "* Filtering environment variables start with '${COLLATOR_KEY}*'" +echo "" + +ENVS=$(env) +ENVS=(${ENVS// /}) + +# Collect all the env vars as system properties +for i in "${!ENVS[@]}"; do + ENV_PAIR=${ENVS[i]} + ENV_KEY=${ENV_PAIR%=*} + ENV_VALUE=${ENV_PAIR#*=} + ENV_VALUE=$(echo ${ENV_VALUE} | sed "s/\"//g") + + # CONTRAST_DIR=/my/dir ====>>>> -Dcontrast.key=/my/dir + if [[ "${ENV_KEY}" =~ ^${COLLATOR_KEY}* ]]; then + VALUE_FROM=${ENV_VALUE%>*} + VALUE_TO=${ENV_VALUE#*>} + + # It must be from an existing file or directory + echo "=> Processing ${ENV_KEY} collate from '${VALUE_FROM}' to '${VALUE_TO}'" + if [[ ! "${VALUE_FROM}" == *"*"* ]] && [ ! -f ${VALUE_FROM} ] && [ ! -d ${VALUE_FROM} ]; then + echo "ERROR: The origin path '${VALUE_FROM}' does NOT exist!" + continue + fi + + # Copy the files only as is, with same name or different as specified + # /from/a.txt > /from/b.txt | /from/a.txt > /from + if [[ "${VALUE_FROM}" == *"*"* ]]; then + # When providing wildcards, the to is expected to be a dir + mkdir -p ${VALUE_TO} | true + cp --verbose ${VALUE_FROM} ${VALUE_TO} + + else + + # The parent dir must exist for the file at least + PARENT_TO=$(dirname ${VALUE_TO}) + if [ ! -d ${PARENT_TO} ]; then + echo "WARN: Destination path '${VALUE_TO}' does not have a dir at ${PARENT_TO}!" + echo "* Creating dir ${PARENT_TO}" + mkdir -p ${PARENT_TO} + fi + + if [ -f ${VALUE_FROM} ]; then + cp --verbose ${VALUE_FROM} ${VALUE_TO} + + elif [ -d ${VALUE_FROM} ]; then + cp --verbose -R ${VALUE_FROM} ${VALUE_TO} + fi + fi + + echo "" + fi +done + +echo "" +echo "Collation process finished!" +echo "" diff --git a/runner/custom-jlink-jdk/Dockerfile b/runner/custom-jlink-jdk/Dockerfile new file mode 100644 index 0000000..6bb3619 --- /dev/null +++ b/runner/custom-jlink-jdk/Dockerfile @@ -0,0 +1,113 @@ +# ##################################################################### +# Build stage for running the Executable SpringBoot WAR files +# +# 1. Use a FROM gradle:4.10.2-jdk10 as unmazedboot-builder-artifacts +# 2. Build your steps needed +# 3. For runtime image use FROM marcellodesales/spring-boot-package-runner +# - It will copy the generate WAR and resources properly +# * Look at background info https://spring.io/guides/gs/spring-boot-docker/ +# * https://github.com/moby/moby/issues/15025#issuecomment-371466934 +# ##################################################################### +ARG UNMAZEDBOOT_INTERNAL_BASE_IMAGE +FROM ${UNMAZEDBOOT_INTERNAL_BASE_IMAGE} + +ARG UNMAZEDBOOT_INTERNAL_DEPENDENCIES +RUN sh -c "${UNMAZEDBOOT_INTERNAL_DEPENDENCIES}" + +USER root + +ENV JAVA_HOME=/opt/jdk-custom/jre +ENV PATH="$PATH:$JAVA_HOME/bin" + +# https://dev.to/gimlet2/dockerizing-java-10-spring-boot-app-3b4c +# Similar setup for 11 Copying the custom JRE created by the Builder +ONBUILD RUN echo "Copying custom JRE /opt/jdk-custom /opt/jdk-custom/jre" +# hadolint ignore=DL3022 +ONBUILD COPY --from=unmazedboot-jdk-linker /opt/jdk-custom /opt/jdk-custom/jre + +# libapr: to support Tomcat production http://tomcat.apache.org/native-doc/ +# https://stackoverflow.com/questions/4278047/apr-based-apache-tomcat-native-library-was-not-found-on-the-java-library-path +# RUN apt-get install -y add-apt-repository +# RUN add-apt-repository ppa:ondrej/apache2 && apt-get update && apt-get install -y libapr1.0-dev libssl-dev +# https://stackoverflow.com/questions/40319869/spring-boot-embedded-tomcat-performance/40446766#40446766 +# Change SpringBoot App to use APR: https://gist.github.com/andreldm/7f89a3279438467a0bd41e6c1249d014#file-aprconfiguration-java + +WORKDIR /runtime + +ONBUILD ARG UNMAZEDBOOT_RUNNER_PORT +ONBUILD ENV UNMAZEDBOOT_RUNNER_PORT=${UNMAZEDBOOT_RUNNER_PORT} + +# All files under UNMAZEDBOOT_RUNNER_HOOKS_DIR_SOURCES will be sourced +ONBUILD ARG UNMAZEDBOOT_RUNNER_HOOKS_DIR_SOURCES +ONBUILD ENV UNMAZEDBOOT_RUNNER_HOOKS_DIR_SOURCES=${UNMAZEDBOOT_RUNNER_HOOKS_DIR_SOURCES:-/runtime/sources} +ONBUILD RUN mkdir ${UNMAZEDBOOT_RUNNER_HOOKS_DIR_SOURCES} +# Creating the hook for environments to be sourced +ONBUILD RUN echo "export SPRINGBOOT_RUNNER_JRE_VERSION=\"openjdk:custom\"" >> ${UNMAZEDBOOT_RUNNER_HOOKS_DIR_SOURCES}/springboot.sh && \ + echo "export BUILDER_SPRINGBOOT_BUILD_TIME=\"$(date)\"" >> ${UNMAZEDBOOT_RUNNER_HOOKS_DIR_SOURCES}/springboot.sh + +ONBUILD RUN echo "Sources hooks dir during build" && ls -la ${UNMAZEDBOOT_RUNNER_HOOKS_DIR_SOURCES} + +# All files under UNMAZEDBOOT_RUNNER_HOOKS_ENV_VAR_DIR will be concatenated with JAVA_OPTS +ONBUILD ARG UNMAZEDBOOT_RUNNER_HOOKS_ENV_VAR_DIR +ONBUILD ENV UNMAZEDBOOT_RUNNER_HOOKS_ENV_VAR_DIR=${UNMAZEDBOOT_RUNNER_HOOKS_ENV_VAR_DIR:-/runtime/java-opts} +ONBUILD RUN echo "Creating java-opts hooks dir ${UNMAZEDBOOT_RUNNER_HOOKS_ENV_VAR_DIR} for JAVA_OPTS creation" + +ONBUILD RUN mkdir ${UNMAZEDBOOT_RUNNER_HOOKS_ENV_VAR_DIR} +# Creating the hook for springboot to to be appended by entry.sh +ONBUILD RUN echo "-Djava.security.egd=file:/dev/./urandom" > ${UNMAZEDBOOT_RUNNER_HOOKS_ENV_VAR_DIR}/springboot.opt +ONBUILD RUN echo "--show-module-resolution" > ${UNMAZEDBOOT_RUNNER_HOOKS_ENV_VAR_DIR}/jdk-custom-debug.opt + +# https://hub.docker.com/_/openjdk/, section "Make JVM respect CPU and RAM limits" +# On startup JVM tries to detect the number of available CPU cores and the amount of RAM +# to adjust its internal parameters (like the number of garbage collector threads to +# spawn) accordingly. When container is run with limited CPU/RAM, standard system API, +# used by JVM for probing, will return host-wide values. This can cause excessive CPU +# usage and memory allocation errors with older versions of JVM. +# Inside Linux containers, recent versions of OpenJDK 8 can correctly detect +# container-limited number of CPU cores by default. To enable the detection of +# container-limited amount of RAM the following options can be used: +# Removed deprecated -XX:+UseCGroupMemoryLimitForHeap +ONBUILD RUN echo "-XX:+UnlockExperimentalVMOptions" > ${UNMAZEDBOOT_RUNNER_HOOKS_ENV_VAR_DIR}/docker.opt +ONBUILD RUN echo "-showversion -XshowSettings:vm" > ${UNMAZEDBOOT_RUNNER_HOOKS_ENV_VAR_DIR}/vminfo.opt + +# start.sh will execute CMD_ENV after processing the hooks dir and creating JAVA_OPTS +ONBUILD RUN echo "JAVA_OPTS hooks during build" && ls -la ${UNMAZEDBOOT_RUNNER_HOOKS_ENV_VAR_DIR} + +ONBUILD ARG UNMAZEDBOOT_RUNNER_INIT_SCRIPTS_DIR +ONBUILD ENV UNMAZEDBOOT_RUNNER_INIT_SCRIPTS_DIR=${UNMAZEDBOOT_RUNNER_INIT_SCRIPTS_DIR:-/runtime/init} +ONBUILD RUN echo "Creating init scripts dir ${UNMAZEDBOOT_RUNNER_INIT_SCRIPTS_DIR} to execute before the app" +ONBUILD RUN mkdir ${UNMAZEDBOOT_RUNNER_INIT_SCRIPTS_DIR} + +# Copy from the previous stage +ONBUILD RUN echo "Will copy from unmazedboot-builder-artifacts /runtime /runtime" +# hadolint ignore=DL3022 +ONBUILD COPY --from=unmazedboot-builder-artifacts /runtime /runtime +ONBUILD RUN ls -la /runtime + +ONBUILD RUN echo "Will copy from /app/src/main/resources /runtime/resources" +# hadolint ignore=DL3022 +ONBUILD COPY --from=unmazedboot-builder-artifacts /app/src/main/resources /runtime/resources +ONBUILD RUN ls -la /runtime/resources + +ONBUILD EXPOSE ${UNMAZEDBOOT_RUNNER_PORT} + +# The CMD exec can be provided by users as well, so users can change what is executed +ONBUILD ARG UNMAZEDBOOT_RUNNER_CMD_EXEC +ONBUILD ENV UNMAZEDBOOT_RUNNER_CMD_EXEC=${UNMAZEDBOOT_RUNNER_CMD_EXEC:-"java \$JAVA_OPTS -jar /runtime/server.jar \$JAR_OPTS"} +ONBUILD RUN echo "Defining the UNMAZEDBOOT_RUNNER_CMD_EXEC=${UNMAZEDBOOT_RUNNER_CMD_EXEC}. Override if needed." +ONBUILD RUN echo "Entrypoint will execute UNMAZEDBOOT_RUNNER_CMD_EXEC from /runtime/start.bash" + +COPY start.bash /runtime/start.bash +COPY collate.bash /runtime/collate.bash + +# The builder Git SHA and Branch +ONBUILD ARG UNMAZEDBOOT_BUILDER_GIT_SHA +ONBUILD ARG UNMAZEDBOOT_BUILDER_GIT_BRANCH +ONBUILD ENV BUILD_TAG=sha=${UNMAZEDBOOT_BUILDER_GIT_SHA},build=${UNMAZEDBOOT_BUILDER_GIT_BRANCH} +ONBUILD ENV BUILD_COMMIT=${UNMAZEDBOOT_BUILDER_GIT_SHA} +ONBUILD ENV BUILD_BRANCH=${UNMAZEDBOOT_BUILDER_GIT_BRANCH} +ONBUILD RUN echo "Finished preparing image with env vars BUILD_COMMIT=${BUILD_COMMIT} from BUILD_BRANCH=${BUILD_BRANCH}" + +# Start will call the UNMAZEDBOOT_RUNNER_CMD_EXEC value from the image after processing +# All the env hooks and JAVA_OPTS +ENTRYPOINT ["/bin/bash", "/runtime/start.bash"] diff --git a/runner/regular-jdk/Dockerfile b/runner/regular-jdk/Dockerfile new file mode 100644 index 0000000..8f7b614 --- /dev/null +++ b/runner/regular-jdk/Dockerfile @@ -0,0 +1,116 @@ +# ##################################################################### +# Build stage for running the Executable SpringBoot WAR files +# +# 1. Use a FROM gradle:4.10.1-jdk8 as unmazedboot-builder-artifacts +# 2. Build your steps needed +# 3. For runtime image use FROM marcellodesales/spring-boot-package-runner +# - It will copy the generate WAR and resources properly +# * Look at background info https://spring.io/guides/gs/spring-boot-docker/ +# * https://github.com/moby/moby/issues/15025#issuecomment-371466934 +# +# https://stackoverflow.com/questions/46815897/jdk-8-is-not-installed-error-404-not-found +# ##################################################################### +# ##################################################################### +# Build stage for running the Executable SpringBoot WAR files +# +# 1. Use a FROM gradle:4.10.2-jdk10 as unmazedboot-builder-artifacts +# 2. Build your steps needed +# 3. For runtime image use FROM marcellodesales/spring-boot-package-runner +# - It will copy the generate WAR and resources properly +# * Look at background info https://spring.io/guides/gs/spring-boot-docker/ +# * https://github.com/moby/moby/issues/15025#issuecomment-371466934 +# ##################################################################### +ARG UNMAZEDBOOT_INTERNAL_BASE_IMAGE +FROM ${UNMAZEDBOOT_INTERNAL_BASE_IMAGE} + +ENV UNMAZEDBOOT_INTERNAL_BASE_IMAGE=UNMAZEDBOOT_INTERNAL_BASE_IMAGE + +ARG UNMAZEDBOOT_INTERNAL_DEPENDENCIES +RUN sh -c "${UNMAZEDBOOT_INTERNAL_DEPENDENCIES}" + +USER root + +# libapr: to support Tomcat production http://tomcat.apache.org/native-doc/ +# https://stackoverflow.com/questions/4278047/apr-based-apache-tomcat-native-library-was-not-found-on-the-java-library-path +# RUN apt-get install -y add-apt-repository +# RUN add-apt-repository ppa:ondrej/apache2 && apt-get update && apt-get install -y libapr1.0-dev libssl-dev +# https://stackoverflow.com/questions/40319869/spring-boot-embedded-tomcat-performance/40446766#40446766 +# Change SpringBoot App to use APR: https://gist.github.com/andreldm/7f89a3279438467a0bd41e6c1249d014#file-aprconfiguration-java + +WORKDIR /runtime + +ONBUILD ARG UNMAZEDBOOT_RUNNER_PORT +ONBUILD ENV UNMAZEDBOOT_RUNNER_PORT=${UNMAZEDBOOT_RUNNER_PORT} + +# All files under UNMAZEDBOOT_RUNNER_HOOKS_DIR_SOURCES will be sourced +ONBUILD ARG UNMAZEDBOOT_RUNNER_HOOKS_DIR_SOURCES +ONBUILD ENV UNMAZEDBOOT_RUNNER_HOOKS_DIR_SOURCES=${UNMAZEDBOOT_RUNNER_HOOKS_DIR_SOURCES:-/runtime/sources} +ONBUILD RUN mkdir ${UNMAZEDBOOT_RUNNER_HOOKS_DIR_SOURCES} +# Creating the hook for environments to be sourced +ONBUILD RUN echo "export SPRINGBOOT_RUNNER_JRE_VERSION=\"${UNMAZEDBOOT_INTERNAL_BASE_IMAGE}\"" >> ${UNMAZEDBOOT_RUNNER_HOOKS_DIR_SOURCES}/springboot.sh && \ + echo "export BUILD_TIME=\"$(date)\"" >> ${UNMAZEDBOOT_RUNNER_HOOKS_DIR_SOURCES}/springboot.sh + +ONBUILD RUN echo "Sources hooks dir during build" && ls -la ${UNMAZEDBOOT_RUNNER_HOOKS_DIR_SOURCES} + +# All files under UNMAZEDBOOT_RUNNER_HOOKS_ENV_VAR_DIR will be concatenated with JAVA_OPTS +ONBUILD ARG UNMAZEDBOOT_RUNNER_HOOKS_ENV_VAR_DIR +ONBUILD ENV UNMAZEDBOOT_RUNNER_HOOKS_ENV_VAR_DIR=${UNMAZEDBOOT_RUNNER_HOOKS_ENV_VAR_DIR:-/runtime/java-opts} +ONBUILD RUN echo "Creating java-opts hooks dir ${UNMAZEDBOOT_RUNNER_HOOKS_ENV_VAR_DIR} for JAVA_OPTS creation" +ONBUILD RUN mkdir ${UNMAZEDBOOT_RUNNER_HOOKS_ENV_VAR_DIR} +# Creating the hook for springboot to to be appended by entry.sh +# shellcheck disable=SC2039 +ONBUILD RUN echo "-Djava.security.egd=file:/dev/./urandom" > ${UNMAZEDBOOT_RUNNER_HOOKS_ENV_VAR_DIR}/springboot.opt + +# https://hub.docker.com/_/openjdk/, section "Make JVM respect CPU and RAM limits" +# On startup JVM tries to detect the number of available CPU cores and the amount of RAM +# to adjust its internal parameters (like the number of garbage collector threads to +# spawn) accordingly. When container is run with limited CPU/RAM, standard system API, +# used by JVM for probing, will return host-wide values. This can cause excessive CPU +# usage and memory allocation errors with older versions of JVM. +# Inside Linux containers, recent versions of OpenJDK 8 can correctly detect +# container-limited number of CPU cores by default. To enable the detection of +# container-limited amount of RAM the following options can be used: +# shellcheck disable=SC2039 +ONBUILD RUN echo "-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap" > ${UNMAZEDBOOT_RUNNER_HOOKS_ENV_VAR_DIR}/docker.opt + +# start.sh will execute CMD_ENV after processing the hooks dir and creating JAVA_OPTS +ONBUILD RUN echo "JAVA_OPTS hooks during build" && ls -la ${UNMAZEDBOOT_RUNNER_HOOKS_ENV_VAR_DIR} + +ONBUILD ARG UNMAZEDBOOT_RUNNER_INIT_SCRIPTS_DIR +ONBUILD ENV UNMAZEDBOOT_RUNNER_INIT_SCRIPTS_DIR=${UNMAZEDBOOT_RUNNER_INIT_SCRIPTS_DIR:-/runtime/init} +ONBUILD RUN echo "Creating init scripts dir ${UNMAZEDBOOT_RUNNER_INIT_SCRIPTS_DIR} to execute before the app" +ONBUILD RUN mkdir ${UNMAZEDBOOT_RUNNER_INIT_SCRIPTS_DIR} + +# Copy from the previous stage +ONBUILD RUN echo "Will copy from unmazedboot-builder-artifacts /runtime /runtime" +# hadolint ignore=DL3022 +ONBUILD COPY --from=unmazedboot-builder-artifacts /runtime /runtime +ONBUILD RUN ls -la /runtime + +ONBUILD RUN echo "Will copy from /app/src/main/resources /runtime/resources" +# hadolint ignore=DL3022 +ONBUILD COPY --from=unmazedboot-builder-artifacts /app/src/main/resources /runtime/resources +ONBUILD RUN ls -la /runtime/resources + +ONBUILD EXPOSE ${UNMAZEDBOOT_RUNNER_PORT} + +# The CMD exec can be provided by users as well, so users can change what is executed +ONBUILD ARG UNMAZEDBOOT_RUNNER_CMD_EXEC +ONBUILD ENV UNMAZEDBOOT_RUNNER_CMD_EXEC=${UNMAZEDBOOT_RUNNER_CMD_EXEC:-"java \$JAVA_OPTS -jar /runtime/server.jar \$JAR_OPTS"} +ONBUILD RUN echo "Defining the UNMAZEDBOOT_RUNNER_CMD_EXEC=${UNMAZEDBOOT_RUNNER_CMD_EXEC}. Override if needed." +ONBUILD RUN echo "Entrypoint will execute UNMAZEDBOOT_RUNNER_CMD_EXEC from /runtime/start.bash" + +COPY start.bash /runtime/start.bash +COPY collate.bash /runtime/collate.bash + +# The builder Git SHA and Branch +ONBUILD ARG UNMAZEDBOOT_BUILDER_GIT_SHA +ONBUILD ARG UNMAZEDBOOT_BUILDER_GIT_BRANCH +ONBUILD ENV BUILD_TAG=sha=${UNMAZEDBOOT_BUILDER_GIT_SHA},build=${UNMAZEDBOOT_BUILDER_GIT_BRANCH} +ONBUILD ENV BUILD_COMMIT=${UNMAZEDBOOT_BUILDER_GIT_SHA} +ONBUILD ENV BUILD_BRANCH=${UNMAZEDBOOT_BUILDER_GIT_BRANCH} +ONBUILD RUN echo "Finished preparing image with env vars BUILD_COMMIT=${BUILD_COMMIT} from BUILD_BRANCH=${BUILD_BRANCH}" + +# Start will call the UNMAZEDBOOT_RUNNER_CMD_EXEC value from the image after processing +# All the env hooks and JAVA_OPTS +ENTRYPOINT ["/bin/bash", "/runtime/start.bash"] diff --git a/runner/start.bash b/runner/start.bash new file mode 100644 index 0000000..e85a63a --- /dev/null +++ b/runner/start.bash @@ -0,0 +1,151 @@ +#!/bin/bash + +##### +## * Processes hook sources before +## * Creates ENV var +## * Calls CMD +## +## Author: Marcello.deSales@gmail.com +##### + +# Source all env files in the + +echo "" +echo "=> Initializing SpringBoot Runner 'start.sh'" + +if [ ! -z "${UNMAZEDBOOT_COLLATOR_ENABLED}" ]; then + echo "" + echo "* Executing Collator collate.sh" + /bin/bash collate.bash +fi + +# When init containers dir is defined +if [ ! -z "${UNMAZEDBOOT_RUNNER_INIT_SCRIPTS_DIR}" ]; then + if [ ! -d "${UNMAZEDBOOT_RUNNER_INIT_SCRIPTS_DIR}" ]; then + echo "[ERROR]: provided init dir RUNNER_INIT_SCRIPTS_DIR=${UNMAZEDBOOT_RUNNER_INIT_SCRIPTS_DIR} is NOT a directory!" + echo "" + + else + echo "" + echo "########## Running init scripts at '${UNMAZEDBOOT_RUNNER_INIT_SCRIPTS_DIR}'" + echo "" + + FILE_NAMES=$(find ${UNMAZEDBOOT_RUNNER_INIT_SCRIPTS_DIR} -name '*.sh') + FILES=(${FILE_NAMES// / }) + + for i in "${!FILES[@]}"; do + INIT_FILE=${FILES[i]} + echo "[$((i+1))] executing 'sh ${INIT_FILE}'" + echo "" + sh ${INIT_FILE} + + if [ $? -eq 0 ]; then + echo "[$((i+1))] OK successful execution of '${INIT_FILE}'" + else + echo "[$((i+1))] ERROR executing 'sh ${INIT_FILE}'. Check the logs!" + fi + echo "" + done + fi +fi + +if [ -z "${UNMAZEDBOOT_RUNNER_HOOKS_DIR_SOURCES}" ]; then + UNMAZEDBOOT_RUNNER_HOOKS_DIR_SOURCES=/runtime/sources +fi + +if [ -d "${UNMAZEDBOOT_RUNNER_HOOKS_DIR_SOURCES}" ]; then + echo "" + echo "########## Processing source hooks at '${UNMAZEDBOOT_RUNNER_HOOKS_DIR_SOURCES}'" + echo "" + + # Look for all env files + FILE_NAMES=$(find ${UNMAZEDBOOT_RUNNER_HOOKS_DIR_SOURCES} -name '*.sh') + FILES=(${FILE_NAMES// / }) + + for i in "${!FILES[@]}"; do + FILE=${FILES[i]} + echo "[$((i+1))] source ${FILE}" + source $FILE + done +fi + +# Create an environment hook to be created based on opt files +# This is here in case someone wants to reuse this for other languages +if [ -z "${UNMAZEDBOOT_RUNNER_ENV_HOOK_VAR}" ]; then + UNMAZEDBOOT_RUNNER_ENV_HOOK_VAR=JAVA_OPTS +fi + +if [ -z "${UNMAZEDBOOT_RUNNER_HOOKS_ENV_VAR_DIR}" ]; then + UNMAZEDBOOT_RUNNER_HOOKS_ENV_VAR_DIR=/runtime/java-opts +fi + +# Just print if it is in debug mode +if [ ! -z "${UNMAZEDBOOT_RUNNER_DEBUG_ENV}" ]; then + echo "" + echo "####### Debugging env before processing ##########" + echo "" + env + echo "" +fi + +if [ -d "${UNMAZEDBOOT_RUNNER_HOOKS_ENV_VAR_DIR}" ]; then + echo "" + echo "=> Processing ${UNMAZEDBOOT_RUNNER_ENV_HOOK_VAR} hooks at ${UNMAZEDBOOT_RUNNER_HOOKS_ENV_VAR_DIR}" + echo "" + + # Look for all opt files + FILE_NAMES=$(find ${RUNNER_HOOKS_ENV_VAR_DIR} -name '*.opt') + FILES=(${FILE_NAMES// / }) + + # Concat the options from all the files + OPTS="" + for i in "${!FILES[@]}"; do + FILE=${FILES[i]} + echo "[$((i+1))] ${UNMAZEDBOOT_RUNNER_ENV_HOOK_VAR} << ${FILE}" + OPTS="${OPTS} $(cat ${FILE})" + done + echo "" + + # https://askubuntu.com/questions/879144/how-to-generate-environment-variable-name-dynamically-and-export-it/879147#879147 + # https://stackoverflow.com/questions/11966983/bash-giving-a-printf-v-invalid-option-error/11967145#11967145 + + # if the env var was provided initial, concatenate with the values loaded + # The env provided has higher precedence JAVA_OPTS=$JAVA_OPTS ${OPTS} + IFS='%' + CURRENT_VALUE="$(printf "%s" ${!UNMAZEDBOOT_RUNNER_ENV_HOOK_VAR})" + unset IFS + + if [ ! -z "${CURRENT_VALUE}" ]; then + # https://unix.stackexchange.com/questions/251893/get-environment-variable-by-variable-name/251896#251896 + # https://logbuffer.wordpress.com/2010/09/23/bash-scripting-preserve-whitespaces-in-variables/ + echo "Exporting and merging ${UNMAZEDBOOT_RUNNER_ENV_HOOK_VAR}=${CURRENT_VALUE} ${OPTS}" + + # Having the variables together places a space between them + RESOLVED_VALUE="$(printf %s "${CURRENT_VALUE}") $(printf %s "${OPTS}")" + + else + echo "Exporting found opts ${UNMAZEDBOOT_RUNNER_ENV_HOOK_VAR}=${OPTS}" + RESOLVED_VALUE="$(printf %s "${OPTS}")" + fi + + # Resolve any environment variable + RESOLVED_VALUE=$(echo $RESOLVED_VALUE) + export "${UNMAZEDBOOT_RUNNER_ENV_HOOK_VAR}=${RESOLVED_VALUE}" +fi + +echo "" + +# Just print if it is in debug mode +if [ ! -z "${UNMAZEDBOOT_RUNNER_DEBUG_ENV}" ]; then + echo "" + echo "####### Debugging env after processing, before app start ##########" + echo "" + env + echo "" +fi + +echo "####### Starting the app ####### " +echo "" +echo "${UNMAZEDBOOT_RUNNER_CMD_EXEC}" +echo "" +sh -c "${UNMAZEDBOOT_RUNNER_CMD_EXEC}" diff --git a/samples/README.md b/samples/README.md new file mode 100644 index 0000000..8568093 --- /dev/null +++ b/samples/README.md @@ -0,0 +1,447 @@ +# SpringBoot Samples + +* This shows the differences between the JREs +* Their performance is definitely different +* Starting with JDK10, modules are huge improvement + * You can see the difference between regular JDK 10 and custom JRE 10 built + * So far we have cross-compiled version of jdk8 samples running in JRE 10 custom and full + +> **ATTENTION**: Run this from the root dir!!! + +## Building + +* Use the latest `docker-compose` support with `--parallel` + * That will speed up the entire build + +``` +$ docker-compose -f docker-compose-samples.yaml build --parallel +Building sample-gradle-java-jre8 ... +Building sample-gradle-java-jre10 ... +Building samples-gradle-java-custom-jre10 ... +Building sample-gradle-java-jre8 +Building samples-gradle-java-custom-jre10 +Building sample-gradle-java-jre10 +``` + +## Run the applications + +* Just use regular `up` + +``` +$ docker-compose -f docker-compose-samples.yaml up +Recreating springboot-docker-reusable-images_sample-gradle-java-jre10_1 ... done +Recreating springboot-docker-reusable-images_sample-gradle-java-jre8_1 ... done +Recreating springboot-docker-reusable-images_samples-gradle-java-custom-jre10_1 ... done +Attaching to springboot-docker-reusable-images_samples-gradle-java-custom-jre10_1, springboot-docker-reusable-images_sample-gradle-java-jre8_1, springboot-docker-reusable-images_sample-gradle-java-jre10_1 +samples-gradle-java-custom-jre10_1 | +samples-gradle-java-custom-jre10_1 | => Initializing SpringBoot Runner 'start.sh' +samples-gradle-java-custom-jre10_1 | +samples-gradle-java-custom-jre10_1 | => Processing env hooks at /runtime/sources +samples-gradle-java-custom-jre10_1 | +sample-gradle-java-jre10_1 | +sample-gradle-java-jre10_1 | => Initializing SpringBoot Runner 'start.sh' +sample-gradle-java-jre10_1 | +sample-gradle-java-jre8_1 | +sample-gradle-java-jre8_1 | => Initializing SpringBoot Runner 'start.sh' +sample-gradle-java-jre8_1 | +sample-gradle-java-jre8_1 | => Processing env hooks at /runtime/sources +sample-gradle-java-jre8_1 | +samples-gradle-java-custom-jre10_1 | [1] source /runtime/sources/springboot.sh +sample-gradle-java-jre8_1 | [1] source /runtime/sources/springboot.sh +sample-gradle-java-jre10_1 | => Processing env hooks at /runtime/sources +sample-gradle-java-jre10_1 | +samples-gradle-java-custom-jre10_1 | +samples-gradle-java-custom-jre10_1 | => Processing hooks at /runtime/java-opts +samples-gradle-java-custom-jre10_1 | +sample-gradle-java-jre8_1 | +samples-gradle-java-custom-jre10_1 | [1] << /runtime/java-opts/docker.opt +sample-gradle-java-jre10_1 | [1] source /runtime/sources/springboot.sh +sample-gradle-java-jre8_1 | => Processing hooks at /runtime/java-opts +sample-gradle-java-jre8_1 | +sample-gradle-java-jre10_1 | +sample-gradle-java-jre10_1 | => Processing hooks at /runtime/java-opts +sample-gradle-java-jre10_1 | +sample-gradle-java-jre8_1 | [1] << /runtime/java-opts/docker.opt +samples-gradle-java-custom-jre10_1 | [2] << /runtime/java-opts/jdk10-debug.opt +sample-gradle-java-jre10_1 | [1] << /runtime/java-opts/docker.opt +sample-gradle-java-jre8_1 | [2] << /runtime/java-opts/springboot.opt +sample-gradle-java-jre8_1 | +sample-gradle-java-jre8_1 | Exporting JAVA_OPTS= -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -Djava.security.egd=file:/dev/./urandom +samples-gradle-java-custom-jre10_1 | [3] << /runtime/java-opts/springboot.opt +samples-gradle-java-custom-jre10_1 | +samples-gradle-java-custom-jre10_1 | Exporting JAVA_OPTS= -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap --show-module-resolution -Djava.security.egd=file:/dev/./urandom +sample-gradle-java-jre10_1 | [2] << /runtime/java-opts/jdk10-debug.opt +sample-gradle-java-jre8_1 | +sample-gradle-java-jre10_1 | [3] << /runtime/java-opts/springboot.opt +sample-gradle-java-jre10_1 | +sample-gradle-java-jre10_1 | Exporting JAVA_OPTS= -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap --show-module-resolution -Djava.security.egd=file:/dev/./urandom +samples-gradle-java-custom-jre10_1 | +samples-gradle-java-custom-jre10_1 | ####### Debugging env before app start ########## +samples-gradle-java-custom-jre10_1 | +samples-gradle-java-custom-jre10_1 | BUILDER_SPRINGBOOT_BUILD_TIME=Mon Nov 12 04:12:21 UTC 2018 +samples-gradle-java-custom-jre10_1 | DEBUG_ENV=true +samples-gradle-java-custom-jre10_1 | HOSTNAME=784fb32378fd +samples-gradle-java-custom-jre10_1 | SPRINGBOOT_RUNNER_JRE_VERSION=openjdk:custom +samples-gradle-java-custom-jre10_1 | JAVA_OPTS= -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap --show-module-resolution -Djava.security.egd=file:/dev/./urandom +samples-gradle-java-custom-jre10_1 | JAVA_HOME=/opt/jdk-custom/jre +samples-gradle-java-custom-jre10_1 | UNMAZEDBOOT_BUILDER_PACKAGE_EXTENSION=jar +samples-gradle-java-custom-jre10_1 | BUILDER_DIR=build/libs +samples-gradle-java-custom-jre10_1 | RUNNER_PORT=8080 +samples-gradle-java-custom-jre10_1 | RUNNER_HOOKS_ENV_VAR_DIR=/runtime/java-opts +samples-gradle-java-custom-jre10_1 | PWD=/runtime +samples-gradle-java-custom-jre10_1 | HOME=/root +samples-gradle-java-custom-jre10_1 | RUNNER_CMD_EXEC=java $JAVA_OPTS -jar /runtime/server.jar $JAR_OPTS +samples-gradle-java-custom-jre10_1 | APP_TIMEZONE=PST +samples-gradle-java-custom-jre10_1 | SHLVL=1 +samples-gradle-java-custom-jre10_1 | RUNNER_HOOKS_DIR_SOURCES=/runtime/sources +samples-gradle-java-custom-jre10_1 | PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/jdk-custom/jre/bin +samples-gradle-java-custom-jre10_1 | _=/usr/bin/env +samples-gradle-java-custom-jre10_1 | +samples-gradle-java-custom-jre10_1 | Starting the app +samples-gradle-java-custom-jre10_1 | java $JAVA_OPTS -jar /runtime/server.jar $JAR_OPTS +samples-gradle-java-custom-jre10_1 | +sample-gradle-java-jre8_1 | ####### Debugging env before app start ########## +sample-gradle-java-jre8_1 | +sample-gradle-java-jre10_1 | +sample-gradle-java-jre10_1 | ####### Debugging env before app start ########## +sample-gradle-java-jre10_1 | +sample-gradle-java-jre10_1 | BUILDER_SPRINGBOOT_BUILD_TIME=Mon Nov 12 04:12:08 UTC 2018 +sample-gradle-java-jre10_1 | DEBUG_ENV=true +sample-gradle-java-jre10_1 | LANG=C.UTF-8 +sample-gradle-java-jre10_1 | HOSTNAME=f7b35c0a9b63 +sample-gradle-java-jre10_1 | SPRINGBOOT_RUNNER_JRE_VERSION=openjdk:10-jre-slim +sample-gradle-java-jre10_1 | JAVA_OPTS= -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap --show-module-resolution -Djava.security.egd=file:/dev/./urandom +sample-gradle-java-jre10_1 | JAVA_HOME=/docker-java-home +sample-gradle-java-jre10_1 | UNMAZEDBOOT_BUILDER_PACKAGE_EXTENSION=jar +sample-gradle-java-jre10_1 | BUILDER_DIR=build/libs +sample-gradle-java-jre10_1 | RUNNER_PORT=8080 +sample-gradle-java-jre10_1 | RUNNER_HOOKS_ENV_VAR_DIR=/runtime/java-opts +sample-gradle-java-jre10_1 | JAVA_VERSION=10.0.2 +sample-gradle-java-jre10_1 | PWD=/runtime +sample-gradle-java-jre10_1 | HOME=/root +sample-gradle-java-jre10_1 | JAVA_DEBIAN_VERSION=10.0.2+13-2 +sample-gradle-java-jre10_1 | RUNNER_CMD_EXEC=java $JAVA_OPTS -jar /runtime/server.jar $JAR_OPTS +sample-gradle-java-jre10_1 | SHLVL=1 +sample-gradle-java-jre10_1 | RUNNER_HOOKS_DIR_SOURCES=/runtime/sources +sample-gradle-java-jre10_1 | PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin +sample-gradle-java-jre10_1 | _=/usr/bin/env +sample-gradle-java-jre10_1 | +samples-gradle-java-custom-jre10_1 | OpenJDK 64-Bit Server VM warning: Option UseCGroupMemoryLimitForHeap was deprecated in version 10.0 and will likely be removed in a future release. +sample-gradle-java-jre8_1 | BUILDER_SPRINGBOOT_BUILD_TIME=Mon Nov 12 04:12:05 UTC 2018 +sample-gradle-java-jre8_1 | DEBUG_ENV=true +sample-gradle-java-jre8_1 | LANG=C.UTF-8 +sample-gradle-java-jre8_1 | HOSTNAME=d3eb00c6311b +sample-gradle-java-jre8_1 | SPRINGBOOT_RUNNER_JRE_VERSION=openjdk:8-jre-slim +sample-gradle-java-jre8_1 | JAVA_OPTS= -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -Djava.security.egd=file:/dev/./urandom +sample-gradle-java-jre8_1 | JAVA_HOME=/docker-java-home/jre +sample-gradle-java-jre8_1 | UNMAZEDBOOT_BUILDER_PACKAGE_EXTENSION=jar +sample-gradle-java-jre8_1 | BUILDER_DIR=build/libs +sample-gradle-java-jre8_1 | RUNNER_PORT=8080 +sample-gradle-java-jre8_1 | RUNNER_HOOKS_ENV_VAR_DIR=/runtime/java-opts +sample-gradle-java-jre8_1 | JAVA_VERSION=8u181 +sample-gradle-java-jre8_1 | PWD=/runtime +sample-gradle-java-jre8_1 | HOME=/root +sample-gradle-java-jre8_1 | CA_CERTIFICATES_JAVA_VERSION=20170531+nmu1 +sample-gradle-java-jre8_1 | JAVA_DEBIAN_VERSION=8u181-b13-2~deb9u1 +sample-gradle-java-jre8_1 | RUNNER_CMD_EXEC=java $JAVA_OPTS -jar /runtime/server.jar $JAR_OPTS +sample-gradle-java-jre8_1 | SHLVL=1 +sample-gradle-java-jre8_1 | RUNNER_HOOKS_DIR_SOURCES=/runtime/sources +sample-gradle-java-jre8_1 | PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin +sample-gradle-java-jre8_1 | _=/usr/bin/env +sample-gradle-java-jre10_1 | Starting the app +sample-gradle-java-jre10_1 | java $JAVA_OPTS -jar /runtime/server.jar $JAR_OPTS +samples-gradle-java-custom-jre10_1 | root java.sql jrt:/java.sql +sample-gradle-java-jre8_1 | +sample-gradle-java-jre8_1 | Starting the app +sample-gradle-java-jre8_1 | java $JAVA_OPTS -jar /runtime/server.jar $JAR_OPTS +sample-gradle-java-jre8_1 | +samples-gradle-java-custom-jre10_1 | root java.logging jrt:/java.logging +samples-gradle-java-custom-jre10_1 | root java.management jrt:/java.management +samples-gradle-java-custom-jre10_1 | root java.xml jrt:/java.xml +samples-gradle-java-custom-jre10_1 | root jdk.unsupported jrt:/jdk.unsupported +samples-gradle-java-custom-jre10_1 | root java.datatransfer jrt:/java.datatransfer +samples-gradle-java-custom-jre10_1 | root java.instrument jrt:/java.instrument +samples-gradle-java-custom-jre10_1 | root java.security.jgss jrt:/java.security.jgss +sample-gradle-java-jre10_1 | +samples-gradle-java-custom-jre10_1 | root java.desktop jrt:/java.desktop +samples-gradle-java-custom-jre10_1 | root java.naming jrt:/java.naming +samples-gradle-java-custom-jre10_1 | root java.prefs jrt:/java.prefs +samples-gradle-java-custom-jre10_1 | root java.security.sasl jrt:/java.security.sasl +samples-gradle-java-custom-jre10_1 | root java.base jrt:/java.base +samples-gradle-java-custom-jre10_1 | java.security.sasl requires java.logging jrt:/java.logging +samples-gradle-java-custom-jre10_1 | java.prefs requires java.xml jrt:/java.xml +samples-gradle-java-custom-jre10_1 | java.naming requires java.security.sasl jrt:/java.security.sasl +samples-gradle-java-custom-jre10_1 | java.desktop requires java.xml jrt:/java.xml +samples-gradle-java-custom-jre10_1 | java.desktop requires java.prefs jrt:/java.prefs +samples-gradle-java-custom-jre10_1 | java.desktop requires java.datatransfer jrt:/java.datatransfer +samples-gradle-java-custom-jre10_1 | java.security.jgss requires java.naming jrt:/java.naming +samples-gradle-java-custom-jre10_1 | java.sql requires java.xml jrt:/java.xml +samples-gradle-java-custom-jre10_1 | java.sql requires java.logging jrt:/java.logging +samples-gradle-java-custom-jre10_1 | java.base binds java.naming jrt:/java.naming +samples-gradle-java-custom-jre10_1 | java.base binds java.security.jgss jrt:/java.security.jgss +samples-gradle-java-custom-jre10_1 | java.base binds java.security.sasl jrt:/java.security.sasl +samples-gradle-java-custom-jre10_1 | java.base binds java.logging jrt:/java.logging +samples-gradle-java-custom-jre10_1 | java.base binds java.desktop jrt:/java.desktop +samples-gradle-java-custom-jre10_1 | java.base binds java.management jrt:/java.management +samples-gradle-java-custom-jre10_1 | java.datatransfer binds java.desktop jrt:/java.desktop +sample-gradle-java-jre10_1 | OpenJDK 64-Bit Server VM warning: Option UseCGroupMemoryLimitForHeap was deprecated in version 10.0 and will likely be removed in a future release. +sample-gradle-java-jre10_1 | root jdk.javadoc jrt:/jdk.javadoc +sample-gradle-java-jre10_1 | root jdk.jdi jrt:/jdk.jdi +sample-gradle-java-jre10_1 | root jdk.jshell jrt:/jdk.jshell +sample-gradle-java-jre10_1 | root jdk.sctp jrt:/jdk.sctp +sample-gradle-java-jre10_1 | root jdk.jsobject jrt:/jdk.jsobject +sample-gradle-java-jre10_1 | root jdk.xml.dom jrt:/jdk.xml.dom +sample-gradle-java-jre10_1 | root jdk.unsupported jrt:/jdk.unsupported +sample-gradle-java-jre10_1 | root jdk.scripting.nashorn jrt:/jdk.scripting.nashorn +sample-gradle-java-jre10_1 | root jdk.httpserver jrt:/jdk.httpserver +sample-gradle-java-jre10_1 | root jdk.management jrt:/jdk.management +sample-gradle-java-jre10_1 | root jdk.net jrt:/jdk.net +sample-gradle-java-jre10_1 | root jdk.security.auth jrt:/jdk.security.auth +sample-gradle-java-jre10_1 | root jdk.dynalink jrt:/jdk.dynalink +sample-gradle-java-jre10_1 | root java.se jrt:/java.se +sample-gradle-java-jre10_1 | root jdk.compiler jrt:/jdk.compiler +sample-gradle-java-jre10_1 | root jdk.accessibility jrt:/jdk.accessibility +sample-gradle-java-jre10_1 | root jdk.jartool jrt:/jdk.jartool +sample-gradle-java-jre10_1 | root jdk.jconsole jrt:/jdk.jconsole +sample-gradle-java-jre10_1 | root jdk.attach jrt:/jdk.attach +sample-gradle-java-jre10_1 | root jdk.security.jgss jrt:/jdk.security.jgss +sample-gradle-java-jre10_1 | jdk.security.jgss requires java.security.jgss jrt:/java.security.jgss +sample-gradle-java-jre10_1 | jdk.security.jgss requires java.logging jrt:/java.logging +sample-gradle-java-jre10_1 | jdk.security.jgss requires java.security.sasl jrt:/java.security.sasl +sample-gradle-java-jre10_1 | jdk.attach requires jdk.internal.jvmstat jrt:/jdk.internal.jvmstat +sample-gradle-java-jre10_1 | jdk.jconsole requires jdk.management jrt:/jdk.management +sample-gradle-java-jre10_1 | jdk.jconsole requires jdk.internal.jvmstat jrt:/jdk.internal.jvmstat +sample-gradle-java-jre10_1 | jdk.jconsole requires jdk.management.agent jrt:/jdk.management.agent +sample-gradle-java-jre10_1 | jdk.jconsole requires java.desktop jrt:/java.desktop +sample-gradle-java-jre10_1 | jdk.jconsole requires jdk.attach jrt:/jdk.attach +sample-gradle-java-jre10_1 | jdk.jconsole requires java.management.rmi jrt:/java.management.rmi +sample-gradle-java-jre10_1 | jdk.jconsole requires java.rmi jrt:/java.rmi +sample-gradle-java-jre10_1 | jdk.jconsole requires java.management jrt:/java.management +sample-gradle-java-jre10_1 | jdk.accessibility requires java.desktop jrt:/java.desktop +sample-gradle-java-jre10_1 | jdk.compiler requires java.compiler jrt:/java.compiler +sample-gradle-java-jre10_1 | java.se requires java.datatransfer jrt:/java.datatransfer +sample-gradle-java-jre10_1 | java.se requires java.naming jrt:/java.naming +sample-gradle-java-jre10_1 | java.se requires java.xml jrt:/java.xml +sample-gradle-java-jre10_1 | java.se requires java.desktop jrt:/java.desktop +sample-gradle-java-jre10_1 | java.se requires java.management.rmi jrt:/java.management.rmi +sample-gradle-java-jre10_1 | java.se requires java.sql jrt:/java.sql +sample-gradle-java-jre10_1 | java.se requires java.rmi jrt:/java.rmi +sample-gradle-java-jre10_1 | java.se requires java.instrument jrt:/java.instrument +sample-gradle-java-jre10_1 | java.se requires java.logging jrt:/java.logging +sample-gradle-java-jre10_1 | java.se requires java.sql.rowset jrt:/java.sql.rowset +sample-gradle-java-jre10_1 | java.se requires java.scripting jrt:/java.scripting +sample-gradle-java-jre10_1 | java.se requires java.security.sasl jrt:/java.security.sasl +sample-gradle-java-jre10_1 | java.se requires java.prefs jrt:/java.prefs +sample-gradle-java-jre10_1 | java.se requires java.compiler jrt:/java.compiler +sample-gradle-java-jre10_1 | java.se requires java.security.jgss jrt:/java.security.jgss +sample-gradle-java-jre10_1 | java.se requires java.xml.crypto jrt:/java.xml.crypto +sample-gradle-java-jre10_1 | java.se requires java.management jrt:/java.management +sample-gradle-java-jre10_1 | jdk.dynalink requires java.logging jrt:/java.logging +sample-gradle-java-jre10_1 | jdk.security.auth requires java.naming jrt:/java.naming +sample-gradle-java-jre10_1 | jdk.security.auth requires java.security.jgss jrt:/java.security.jgss +sample-gradle-java-jre10_1 | jdk.management requires java.management jrt:/java.management +sample-gradle-java-jre10_1 | jdk.scripting.nashorn requires jdk.dynalink jrt:/jdk.dynalink +sample-gradle-java-jre10_1 | jdk.scripting.nashorn requires java.scripting jrt:/java.scripting +sample-gradle-java-jre10_1 | jdk.scripting.nashorn requires java.logging jrt:/java.logging +sample-gradle-java-jre10_1 | jdk.xml.dom requires java.xml jrt:/java.xml +sample-gradle-java-jre10_1 | jdk.jsobject requires java.desktop jrt:/java.desktop +sample-gradle-java-jre10_1 | jdk.jshell requires jdk.internal.le jrt:/jdk.internal.le +sample-gradle-java-jre10_1 | jdk.jshell requires jdk.compiler jrt:/jdk.compiler +sample-gradle-java-jre10_1 | jdk.jshell requires java.logging jrt:/java.logging +sample-gradle-java-jre10_1 | jdk.jshell requires java.prefs jrt:/java.prefs +sample-gradle-java-jre10_1 | jdk.jshell requires java.compiler jrt:/java.compiler +sample-gradle-java-jre10_1 | jdk.jshell requires jdk.jdi jrt:/jdk.jdi +sample-gradle-java-jre10_1 | jdk.jshell requires jdk.internal.ed jrt:/jdk.internal.ed +sample-gradle-java-jre10_1 | jdk.jshell requires jdk.internal.opt jrt:/jdk.internal.opt +sample-gradle-java-jre10_1 | jdk.jdi requires jdk.jdwp.agent jrt:/jdk.jdwp.agent +sample-gradle-java-jre10_1 | jdk.jdi requires jdk.attach jrt:/jdk.attach +sample-gradle-java-jre10_1 | jdk.javadoc requires java.compiler jrt:/java.compiler +sample-gradle-java-jre10_1 | jdk.javadoc requires java.xml jrt:/java.xml +sample-gradle-java-jre10_1 | jdk.javadoc requires jdk.compiler jrt:/jdk.compiler +sample-gradle-java-jre10_1 | java.security.jgss requires java.naming jrt:/java.naming +sample-gradle-java-jre10_1 | java.security.sasl requires java.logging jrt:/java.logging +sample-gradle-java-jre10_1 | jdk.management.agent requires java.management.rmi jrt:/java.management.rmi +sample-gradle-java-jre10_1 | jdk.management.agent requires java.management jrt:/java.management +sample-gradle-java-jre10_1 | java.desktop requires java.prefs jrt:/java.prefs +sample-gradle-java-jre10_1 | java.desktop requires java.xml jrt:/java.xml +sample-gradle-java-jre10_1 | java.desktop requires java.datatransfer jrt:/java.datatransfer +sample-gradle-java-jre10_1 | java.management.rmi requires java.rmi jrt:/java.rmi +sample-gradle-java-jre10_1 | java.management.rmi requires java.naming jrt:/java.naming +sample-gradle-java-jre10_1 | java.management.rmi requires java.management jrt:/java.management +sample-gradle-java-jre10_1 | java.rmi requires java.logging jrt:/java.logging +sample-gradle-java-jre10_1 | java.naming requires java.security.sasl jrt:/java.security.sasl +sample-gradle-java-jre10_1 | java.sql requires java.xml jrt:/java.xml +sample-gradle-java-jre10_1 | java.sql requires java.logging jrt:/java.logging +sample-gradle-java-jre10_1 | java.sql.rowset requires java.sql jrt:/java.sql +sample-gradle-java-jre10_1 | java.sql.rowset requires java.logging jrt:/java.logging +sample-gradle-java-jre10_1 | java.sql.rowset requires java.naming jrt:/java.naming +sample-gradle-java-jre10_1 | java.prefs requires java.xml jrt:/java.xml +sample-gradle-java-jre10_1 | java.xml.crypto requires java.logging jrt:/java.logging +sample-gradle-java-jre10_1 | java.xml.crypto requires java.xml jrt:/java.xml +sample-gradle-java-jre10_1 | jdk.jshell binds jdk.editpad jrt:/jdk.editpad +sample-gradle-java-jre10_1 | java.compiler binds jdk.javadoc jrt:/jdk.javadoc +sample-gradle-java-jre10_1 | java.compiler binds jdk.compiler jrt:/jdk.compiler +sample-gradle-java-jre10_1 | jdk.internal.jvmstat binds jdk.jstatd jrt:/jdk.jstatd +sample-gradle-java-jre10_1 | java.scripting binds jdk.scripting.nashorn jrt:/jdk.scripting.nashorn +sample-gradle-java-jre10_1 | java.management binds java.management.rmi jrt:/java.management.rmi +sample-gradle-java-jre10_1 | java.management binds jdk.management jrt:/jdk.management +sample-gradle-java-jre10_1 | java.management binds jdk.internal.vm.compiler.management jrt:/jdk.internal.vm.compiler.management +sample-gradle-java-jre10_1 | java.base binds jdk.zipfs jrt:/jdk.zipfs +sample-gradle-java-jre10_1 | java.base binds java.desktop jrt:/java.desktop +sample-gradle-java-jre10_1 | java.base binds jdk.crypto.ec jrt:/jdk.crypto.ec +sample-gradle-java-jre10_1 | java.base binds java.security.sasl jrt:/java.security.sasl +sample-gradle-java-jre10_1 | java.base binds jdk.security.jgss jrt:/jdk.security.jgss +sample-gradle-java-jre10_1 | java.base binds java.smartcardio jrt:/java.smartcardio +sample-gradle-java-jre10_1 | java.base binds java.security.jgss jrt:/java.security.jgss +sample-gradle-java-jre10_1 | java.base binds java.naming jrt:/java.naming +sample-gradle-java-jre10_1 | java.base binds java.xml.crypto jrt:/java.xml.crypto +sample-gradle-java-jre10_1 | java.base binds jdk.crypto.cryptoki jrt:/jdk.crypto.cryptoki +sample-gradle-java-jre10_1 | java.base binds jdk.charsets jrt:/jdk.charsets +sample-gradle-java-jre10_1 | java.base binds jdk.localedata jrt:/jdk.localedata +sample-gradle-java-jre10_1 | java.base binds jdk.jlink jrt:/jdk.jlink +sample-gradle-java-jre10_1 | java.base binds jdk.compiler jrt:/jdk.compiler +sample-gradle-java-jre10_1 | java.base binds jdk.jdeps jrt:/jdk.jdeps +sample-gradle-java-jre10_1 | java.base binds jdk.javadoc jrt:/jdk.javadoc +sample-gradle-java-jre10_1 | java.base binds jdk.jartool jrt:/jdk.jartool +sample-gradle-java-jre10_1 | java.base binds java.management jrt:/java.management +sample-gradle-java-jre10_1 | java.base binds jdk.security.auth jrt:/jdk.security.auth +sample-gradle-java-jre10_1 | java.base binds java.logging jrt:/java.logging +sample-gradle-java-jre10_1 | java.datatransfer binds java.desktop jrt:/java.desktop +sample-gradle-java-jre10_1 | java.naming binds jdk.naming.dns jrt:/jdk.naming.dns +sample-gradle-java-jre10_1 | java.naming binds jdk.naming.rmi jrt:/jdk.naming.rmi +sample-gradle-java-jre10_1 | jdk.dynalink binds jdk.scripting.nashorn jrt:/jdk.scripting.nashorn +sample-gradle-java-jre10_1 | jdk.naming.rmi requires java.naming jrt:/java.naming +sample-gradle-java-jre10_1 | jdk.naming.rmi requires java.rmi jrt:/java.rmi +sample-gradle-java-jre10_1 | jdk.naming.dns requires java.naming jrt:/java.naming +sample-gradle-java-jre10_1 | jdk.jdeps requires jdk.compiler jrt:/jdk.compiler +sample-gradle-java-jre10_1 | jdk.jdeps requires java.compiler jrt:/java.compiler +sample-gradle-java-jre10_1 | jdk.jlink requires jdk.internal.opt jrt:/jdk.internal.opt +sample-gradle-java-jre10_1 | jdk.jlink requires jdk.jdeps jrt:/jdk.jdeps +sample-gradle-java-jre10_1 | jdk.crypto.cryptoki requires jdk.crypto.ec jrt:/jdk.crypto.ec +sample-gradle-java-jre10_1 | jdk.internal.vm.compiler.management requires jdk.internal.vm.compiler jrt:/jdk.internal.vm.compiler +sample-gradle-java-jre10_1 | jdk.internal.vm.compiler.management requires jdk.internal.vm.ci jrt:/jdk.internal.vm.ci +sample-gradle-java-jre10_1 | jdk.internal.vm.compiler.management requires jdk.management jrt:/jdk.management +sample-gradle-java-jre10_1 | jdk.internal.vm.compiler.management requires java.management jrt:/java.management +sample-gradle-java-jre10_1 | jdk.jstatd requires jdk.internal.jvmstat jrt:/jdk.internal.jvmstat +sample-gradle-java-jre10_1 | jdk.jstatd requires java.rmi jrt:/java.rmi +sample-gradle-java-jre10_1 | jdk.editpad requires jdk.internal.ed jrt:/jdk.internal.ed +sample-gradle-java-jre10_1 | jdk.editpad requires java.desktop jrt:/java.desktop +sample-gradle-java-jre10_1 | jdk.internal.vm.compiler requires jdk.management jrt:/jdk.management +sample-gradle-java-jre10_1 | jdk.internal.vm.compiler requires jdk.unsupported jrt:/jdk.unsupported +sample-gradle-java-jre10_1 | jdk.internal.vm.compiler requires java.instrument jrt:/java.instrument +sample-gradle-java-jre10_1 | jdk.internal.vm.compiler requires java.management jrt:/java.management +sample-gradle-java-jre10_1 | jdk.internal.vm.compiler requires jdk.internal.vm.ci jrt:/jdk.internal.vm.ci +sample-gradle-java-jre10_1 | jdk.internal.vm.ci binds jdk.internal.vm.compiler jrt:/jdk.internal.vm.compiler +samples-gradle-java-custom-jre10_1 | +samples-gradle-java-custom-jre10_1 | . ____ _ __ _ _ +samples-gradle-java-custom-jre10_1 | /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ +samples-gradle-java-custom-jre10_1 | ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ +samples-gradle-java-custom-jre10_1 | \\/ ___)| |_)| | | | | || (_| | ) ) ) ) +samples-gradle-java-custom-jre10_1 | ' |____| .__|_| |_|_| |_\__, | / / / / +samples-gradle-java-custom-jre10_1 | =========|_|==============|___/=/_/_/_/ +samples-gradle-java-custom-jre10_1 | :: Spring Boot :: (v2.0.3.RELEASE) +samples-gradle-java-custom-jre10_1 | +samples-gradle-java-custom-jre10_1 | 2018-11-12 04:16:07.577 INFO 17 --- [ main] hello.Application : Starting Application on 784fb32378fd with PID 17 (/runtime/server.jar started by root in /runtime) +samples-gradle-java-custom-jre10_1 | 2018-11-12 04:16:07.591 INFO 17 --- [ main] hello.Application : No active profile set, falling back to default profiles: default +sample-gradle-java-jre8_1 | +sample-gradle-java-jre8_1 | . ____ _ __ _ _ +sample-gradle-java-jre8_1 | /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ +sample-gradle-java-jre8_1 | ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ +sample-gradle-java-jre8_1 | \\/ ___)| |_)| | | | | || (_| | ) ) ) ) +sample-gradle-java-jre8_1 | ' |____| .__|_| |_|_| |_\__, | / / / / +sample-gradle-java-jre8_1 | =========|_|==============|___/=/_/_/_/ +sample-gradle-java-jre8_1 | :: Spring Boot :: (v2.0.3.RELEASE) +sample-gradle-java-jre8_1 | +samples-gradle-java-custom-jre10_1 | 2018-11-12 04:16:07.772 INFO 17 --- [ main] ConfigServletWebServerApplicationContext : Refreshing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@10e31a9a: startup date [Mon Nov 12 04:16:07 UTC 2018]; root of context hierarchy +sample-gradle-java-jre8_1 | 2018-11-12 04:16:08.187 INFO 16 --- [ main] hello.Application : Starting Application on d3eb00c6311b with PID 16 (/runtime/server.jar started by root in /runtime) +sample-gradle-java-jre8_1 | 2018-11-12 04:16:08.202 INFO 16 --- [ main] hello.Application : No active profile set, falling back to default profiles: default +sample-gradle-java-jre10_1 | +sample-gradle-java-jre10_1 | . ____ _ __ _ _ +sample-gradle-java-jre10_1 | /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ +sample-gradle-java-jre10_1 | ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ +sample-gradle-java-jre10_1 | \\/ ___)| |_)| | | | | || (_| | ) ) ) ) +sample-gradle-java-jre10_1 | ' |____| .__|_| |_|_| |_\__, | / / / / +sample-gradle-java-jre10_1 | =========|_|==============|___/=/_/_/_/ +sample-gradle-java-jre10_1 | :: Spring Boot :: (v2.0.3.RELEASE) +sample-gradle-java-jre10_1 | +sample-gradle-java-jre8_1 | 2018-11-12 04:16:08.409 INFO 16 --- [ main] ConfigServletWebServerApplicationContext : Refreshing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@24273305: startup date [Mon Nov 12 04:16:08 UTC 2018]; root of context hierarchy +sample-gradle-java-jre10_1 | 2018-11-12 04:16:08.789 INFO 17 --- [ main] hello.Application : Starting Application on f7b35c0a9b63 with PID 17 (/runtime/server.jar started by root in /runtime) +sample-gradle-java-jre10_1 | 2018-11-12 04:16:08.847 INFO 17 --- [ main] hello.Application : No active profile set, falling back to default profiles: default +sample-gradle-java-jre10_1 | 2018-11-12 04:16:09.034 INFO 17 --- [ main] ConfigServletWebServerApplicationContext : Refreshing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@31304f14: startup date [Mon Nov 12 04:16:09 UTC 2018]; root of context hierarchy +samples-gradle-java-custom-jre10_1 | WARNING: An illegal reflective access operation has occurred +samples-gradle-java-custom-jre10_1 | WARNING: Illegal reflective access by org.springframework.cglib.core.ReflectUtils$1 (jar:file:/runtime/server.jar!/BOOT-INF/lib/spring-core-5.0.7.RELEASE.jar!/) to method java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain) +samples-gradle-java-custom-jre10_1 | WARNING: Please consider reporting this to the maintainers of org.springframework.cglib.core.ReflectUtils$1 +samples-gradle-java-custom-jre10_1 | WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations +samples-gradle-java-custom-jre10_1 | WARNING: All illegal access operations will be denied in a future release +samples-gradle-java-custom-jre10_1 | 2018-11-12 04:16:10.827 INFO 17 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http) +samples-gradle-java-custom-jre10_1 | 2018-11-12 04:16:11.223 INFO 17 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] +samples-gradle-java-custom-jre10_1 | 2018-11-12 04:16:11.226 INFO 17 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/8.5.31 +samples-gradle-java-custom-jre10_1 | 2018-11-12 04:16:11.349 INFO 17 --- [ost-startStop-1] o.a.catalina.core.AprLifecycleListener : The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: [/usr/java/packages/lib:/usr/lib64:/lib64:/lib:/usr/lib] +sample-gradle-java-jre10_1 | WARNING: An illegal reflective access operation has occurred +sample-gradle-java-jre10_1 | WARNING: Illegal reflective access by org.springframework.cglib.core.ReflectUtils$1 (jar:file:/runtime/server.jar!/BOOT-INF/lib/spring-core-5.0.7.RELEASE.jar!/) to method java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain) +sample-gradle-java-jre10_1 | WARNING: Please consider reporting this to the maintainers of org.springframework.cglib.core.ReflectUtils$1 +sample-gradle-java-jre10_1 | WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations +sample-gradle-java-jre10_1 | WARNING: All illegal access operations will be denied in a future release +samples-gradle-java-custom-jre10_1 | 2018-11-12 04:16:11.601 INFO 17 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext +samples-gradle-java-custom-jre10_1 | 2018-11-12 04:16:11.602 INFO 17 --- [ost-startStop-1] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 3840 ms +samples-gradle-java-custom-jre10_1 | 2018-11-12 04:16:12.089 INFO 17 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean : Servlet dispatcherServlet mapped to [/] +samples-gradle-java-custom-jre10_1 | 2018-11-12 04:16:12.097 INFO 17 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'characterEncodingFilter' to: [/*] +samples-gradle-java-custom-jre10_1 | 2018-11-12 04:16:12.098 INFO 17 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'hiddenHttpMethodFilter' to: [/*] +samples-gradle-java-custom-jre10_1 | 2018-11-12 04:16:12.098 INFO 17 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'httpPutFormContentFilter' to: [/*] +samples-gradle-java-custom-jre10_1 | 2018-11-12 04:16:12.098 INFO 17 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'requestContextFilter' to: [/*] +samples-gradle-java-custom-jre10_1 | 2018-11-12 04:16:12.098 INFO 17 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'defaultResponseFilter' to: [/*] +samples-gradle-java-custom-jre10_1 | 2018-11-12 04:16:12.429 INFO 17 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] +sample-gradle-java-jre8_1 | 2018-11-12 04:16:12.597 INFO 16 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http) +sample-gradle-java-jre8_1 | 2018-11-12 04:16:12.688 INFO 16 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] +sample-gradle-java-jre8_1 | 2018-11-12 04:16:12.690 INFO 16 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/8.5.31 +sample-gradle-java-jre8_1 | 2018-11-12 04:16:12.724 INFO 16 --- [ost-startStop-1] o.a.catalina.core.AprLifecycleListener : The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: [/usr/java/packages/lib/amd64:/usr/lib/x86_64-linux-gnu/jni:/lib/x86_64-linux-gnu:/usr/lib/x86_64-linux-gnu:/usr/lib/jni:/lib:/usr/lib] +samples-gradle-java-custom-jre10_1 | 2018-11-12 04:16:12.956 INFO 17 --- [ main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@10e31a9a: startup date [Mon Nov 12 04:16:07 UTC 2018]; root of context hierarchy +sample-gradle-java-jre8_1 | 2018-11-12 04:16:13.035 INFO 16 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext +sample-gradle-java-jre8_1 | 2018-11-12 04:16:13.035 INFO 16 --- [ost-startStop-1] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 4643 ms +sample-gradle-java-jre8_1 | 2018-11-12 04:16:13.266 INFO 16 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean : Servlet dispatcherServlet mapped to [/] +samples-gradle-java-custom-jre10_1 | 2018-11-12 04:16:13.280 INFO 17 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/]}" onto public java.lang.String hello.Application.home() +sample-gradle-java-jre8_1 | 2018-11-12 04:16:13.282 INFO 16 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'characterEncodingFilter' to: [/*] +sample-gradle-java-jre8_1 | 2018-11-12 04:16:13.284 INFO 16 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'hiddenHttpMethodFilter' to: [/*] +sample-gradle-java-jre8_1 | 2018-11-12 04:16:13.285 INFO 16 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'httpPutFormContentFilter' to: [/*] +sample-gradle-java-jre8_1 | 2018-11-12 04:16:13.285 INFO 16 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'requestContextFilter' to: [/*] +sample-gradle-java-jre8_1 | 2018-11-12 04:16:13.286 INFO 16 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'defaultResponseFilter' to: [/*] +samples-gradle-java-custom-jre10_1 | 2018-11-12 04:16:13.301 INFO 17 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity> org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.error(javax.servlet.http.HttpServletRequest) +samples-gradle-java-custom-jre10_1 | 2018-11-12 04:16:13.303 INFO 17 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse) +sample-gradle-java-jre10_1 | 2018-11-12 04:16:13.334 INFO 17 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http) +samples-gradle-java-custom-jre10_1 | 2018-11-12 04:16:13.434 INFO 17 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] +samples-gradle-java-custom-jre10_1 | 2018-11-12 04:16:13.434 INFO 17 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] +sample-gradle-java-jre10_1 | 2018-11-12 04:16:13.470 INFO 17 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] +sample-gradle-java-jre10_1 | 2018-11-12 04:16:13.470 INFO 17 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/8.5.31 +sample-gradle-java-jre10_1 | 2018-11-12 04:16:13.541 INFO 17 --- [ost-startStop-1] o.a.catalina.core.AprLifecycleListener : The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: [/usr/java/packages/lib:/usr/lib/x86_64-linux-gnu/jni:/lib/x86_64-linux-gnu:/usr/lib/x86_64-linux-gnu:/usr/lib/jni:/lib:/usr/lib] +sample-gradle-java-jre10_1 | 2018-11-12 04:16:13.871 INFO 17 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext +sample-gradle-java-jre10_1 | 2018-11-12 04:16:13.871 INFO 17 --- [ost-startStop-1] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 4865 ms +samples-gradle-java-custom-jre10_1 | 2018-11-12 04:16:13.881 INFO 17 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup +sample-gradle-java-jre8_1 | 2018-11-12 04:16:13.927 INFO 16 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] +samples-gradle-java-custom-jre10_1 | 2018-11-12 04:16:14.056 INFO 17 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path '' +samples-gradle-java-custom-jre10_1 | 2018-11-12 04:16:14.073 INFO 17 --- [ main] hello.Application : Started Application in 7.995 seconds (JVM running for 8.875) +sample-gradle-java-jre10_1 | 2018-11-12 04:16:14.358 INFO 17 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean : Servlet dispatcherServlet mapped to [/] +sample-gradle-java-jre10_1 | 2018-11-12 04:16:14.363 INFO 17 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'characterEncodingFilter' to: [/*] +sample-gradle-java-jre10_1 | 2018-11-12 04:16:14.364 INFO 17 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'hiddenHttpMethodFilter' to: [/*] +sample-gradle-java-jre10_1 | 2018-11-12 04:16:14.364 INFO 17 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'httpPutFormContentFilter' to: [/*] +sample-gradle-java-jre10_1 | 2018-11-12 04:16:14.364 INFO 17 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'requestContextFilter' to: [/*] +sample-gradle-java-jre10_1 | 2018-11-12 04:16:14.364 INFO 17 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'defaultResponseFilter' to: [/*] +sample-gradle-java-jre8_1 | 2018-11-12 04:16:14.495 INFO 16 --- [ main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@24273305: startup date [Mon Nov 12 04:16:08 UTC 2018]; root of context hierarchy +sample-gradle-java-jre8_1 | 2018-11-12 04:16:14.724 INFO 16 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/]}" onto public java.lang.String hello.Application.home() +sample-gradle-java-jre8_1 | 2018-11-12 04:16:14.732 INFO 16 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse) +sample-gradle-java-jre8_1 | 2018-11-12 04:16:14.732 INFO 16 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity> org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.error(javax.servlet.http.HttpServletRequest) +sample-gradle-java-jre8_1 | 2018-11-12 04:16:14.771 INFO 16 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] +sample-gradle-java-jre8_1 | 2018-11-12 04:16:14.772 INFO 16 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] +sample-gradle-java-jre10_1 | 2018-11-12 04:16:14.810 INFO 17 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] +sample-gradle-java-jre8_1 | 2018-11-12 04:16:15.104 INFO 16 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup +sample-gradle-java-jre8_1 | 2018-11-12 04:16:15.378 INFO 16 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path '' +sample-gradle-java-jre8_1 | 2018-11-12 04:16:15.393 INFO 16 --- [ main] hello.Application : Started Application in 8.606 seconds (JVM running for 10.108) +sample-gradle-java-jre10_1 | 2018-11-12 04:16:15.399 INFO 17 --- [ main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@31304f14: startup date [Mon Nov 12 04:16:09 UTC 2018]; root of context hierarchy +sample-gradle-java-jre10_1 | 2018-11-12 04:16:15.550 INFO 17 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/]}" onto public java.lang.String hello.Application.home() +sample-gradle-java-jre10_1 | 2018-11-12 04:16:15.558 INFO 17 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse) +sample-gradle-java-jre10_1 | 2018-11-12 04:16:15.558 INFO 17 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity> org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.error(javax.servlet.http.HttpServletRequest) +sample-gradle-java-jre10_1 | 2018-11-12 04:16:15.595 INFO 17 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] +sample-gradle-java-jre10_1 | 2018-11-12 04:16:15.595 INFO 17 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] +sample-gradle-java-jre10_1 | 2018-11-12 04:16:15.882 INFO 17 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup +sample-gradle-java-jre10_1 | 2018-11-12 04:16:15.963 INFO 17 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path '' +sample-gradle-java-jre10_1 | 2018-11-12 04:16:15.969 INFO 17 --- [ main] hello.Application : Started Application in 9.065 seconds (JVM running for 10.528) +``` diff --git a/samples/gradle-java-jdk8-jre8/.dockerignore b/samples/gradle-java-jdk8-jre8/.dockerignore new file mode 100644 index 0000000..38aeebd --- /dev/null +++ b/samples/gradle-java-jdk8-jre8/.dockerignore @@ -0,0 +1,6 @@ +.gitignore +docker-compose.yaml +Dockerfile +mvnw +mvnw.cmd +README.md diff --git a/samples/gradle-java-jdk8-jre8/Dockerfile b/samples/gradle-java-jdk8-jre8/Dockerfile new file mode 100644 index 0000000..0c44853 --- /dev/null +++ b/samples/gradle-java-jdk8-jre8/Dockerfile @@ -0,0 +1,24 @@ +### Builder Arguments +ARG UNMAZEDBOOT_BUILDER_GIT_SHA=${UNMAZEDBOOT_BUILDER_GIT_SHA:-000000} +ARG UNMAZEDBOOT_BUILDER_GIT_BRANCH=${UNMAZEDBOOT_BUILDER_GIT_BRANCH:-master} +ARG UNMAZEDBOOT_BUILDER_GRADLE_BUILD_CMD="gradle build -x test" +ARG UNMAZEDBOOT_BUILDER_DIR="build/libs" +ARG UNMAZEDBOOT_BUILDER_PACKAGE_EXTENSION="jar" +ARG UNMAZEDBOOT_BUILDER_GRADLE_VERSION=${UNMAZEDBOOT_BUILDER_GRADLE_VERSION:--latest} + +### Runner Arguments +ARG UNMAZEDBOOT_RUNNER_PORT="8080" +ARG UNMAZEDBOOT_RUNNER_VERSION=${UNMAZEDBOOT_RUNNER_VERSION:--latest} + +# ##################################################################### +# Build stage for building the target directory before running tests +# ##################################################################### +FROM intuit/unmazedboot-builder-gradle:4.10.2-jdk8-alpine${UNMAZEDBOOT_BUILDER_GRADLE_VERSION} as unmazedboot-builder-artifacts + +# ##################################################################### +# Build stage for running the runtime image +# ##################################################################### +FROM intuit/unmazedboot-runner:openjdk-8u181-debian9-slim${UNMAZEDBOOT_RUNNER_VERSION} + +# The image depends on the built artifacts by the stage +# Add init scripts that are executed before the app starts diff --git a/samples/gradle-java-jdk8-jre8/README.md b/samples/gradle-java-jdk8-jre8/README.md new file mode 100644 index 0000000..9a149dc --- /dev/null +++ b/samples/gradle-java-jdk8-jre8/README.md @@ -0,0 +1,368 @@ +# Running + +* Using SpringBoot 2.0.3 +* Using Starter Web + +## BootRun + +* Uses `build.gradle` +* Run with `bootRun` default profile + +``` +gradle bootRun +``` + +* Run with `bootRun` with `dev` profile + +``` +SPRING_PROFILES_ACTIVE=dev gradle bootRun +``` + +## Docker Container + +* Uses the `Dockerfile` +* Build a Docker Image default arguments + +``` +$ docker build -t myapp . +Sending build context to Docker daemon 20.23MB +Step 1/7 : ARG GIT_SHA=${GIT_SHA:-0101010} +Step 2/7 : ARG GIT_BRANCH=${GIT_BRANCH:-develop} +Step 3/7 : ARG BUILD_NUMBER=${BUILD_NUMBER:-0223} +Step 4/7 : ARG GRADLE_BUILD_TASKS="build -x test" +Step 5/7 : ARG EXECUTABLE_TASK_TYPE="jar" +Step 6/7 : FROM marcellodesales/springboot-builder as unmazedboot-builder-artifacts + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Running in 6b7c60c82fa1 +Will execute gradle downloadDependencies +Removing intermediate container 6b7c60c82fa1 + ---> Running in 44f6a573e60e + +Welcome to Gradle 4.10.1! + +Here are the highlights of this release: + - Incremental Java compilation by default + - Periodic Gradle caches cleanup + - Gradle Kotlin DSL 1.0-RC6 + - Nested included builds + - SNAPSHOT plugin versions in the `plugins {}` block + +For more details see https://docs.gradle.org/4.10.1/release-notes.html + +Starting a Gradle Daemon (subsequent builds will be faster) + +> Task :downloadDependencies + +Retrieving dependencies for annotationProcessor + +.. +.. + +Retrieving dependencies for testRuntimeOnly + +BUILD SUCCESSFUL in 14s +1 actionable task: 1 executed +Removing intermediate container 44f6a573e60e + ---> Running in 40a596327554 +Will execute gradle build -x test +Removing intermediate container 40a596327554 + ---> Running in 8642c9c067f4 + +Welcome to Gradle 4.10.1! + +Here are the highlights of this release: + - Incremental Java compilation by default + - Periodic Gradle caches cleanup + - Gradle Kotlin DSL 1.0-RC6 + - Nested included builds + - SNAPSHOT plugin versions in the `plugins {}` block + +For more details see https://docs.gradle.org/4.10.1/release-notes.html + +Starting a Gradle Daemon (subsequent builds will be faster) +> Task :compileJava +> Task :processResources +> Task :classes +> Task :bootJar +> Task :jar SKIPPED +> Task :assemble +> Task :check +> Task :build + +BUILD SUCCESSFUL in 20s +3 actionable tasks: 3 executed +Removing intermediate container 8642c9c067f4 + ---> 405621119bcf +Step 7/7 : FROM marcellodesales/springboot-executable-runner + ---> Using cache + ---> Using cache + ---> Using cache + ---> Running in 46cb7cebdf3b +-rw-r--r-- 1 root root 16141378 Sep 16 23:16 /tmp/myapp-0.1.0.jar +Removing intermediate container 46cb7cebdf3b + ---> Running in b47bfaf3a78d +Will copy from /app/src/main/resources /runtime/resources +Removing intermediate container b47bfaf3a78d + ---> Running in cc5b00fe7dad +total 20 +drwxr-xr-x 2 root root 4096 Sep 16 23:17 . +drwxr-xr-x 1 root root 4096 Sep 16 23:17 .. +-rw-r--r-- 1 root root 48 Sep 16 23:12 application-dev.yml +-rw-r--r-- 1 root root 47 Sep 16 23:12 application-prd.yml +-rw-r--r-- 1 root root 51 Sep 16 23:12 application.yml +Removing intermediate container cc5b00fe7dad + ---> Running in 40a70b1e8304 +Renaming the executable jar to the runtime dir +Removing intermediate container 40a70b1e8304 + ---> Running in 3d3eea4bdd5c +Removing intermediate container 3d3eea4bdd5c + ---> 89923a61a08c +Successfully built 89923a61a08c +Successfully tagged myapp:latest +``` + +* Running in the `dev` profile + * Loads the file `application-dev.yml` + * The logs will be showing `The following profiles are active: dev` + +``` +$ docker run -ti -e SPRING_PROFILES_ACTIVE=dev -p 8080:8080 myapp + + . ____ _ __ _ _ + /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ +( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ + \\/ ___)| |_)| | | | | || (_| | ) ) ) ) + ' |____| .__|_| |_|_| |_\__, | / / / / + =========|_|==============|___/=/_/_/_/ + :: Spring Boot :: (v2.0.3.RELEASE) + +2018-09-16 23:17:50.719 INFO 9 --- [ main] hello.Application : Starting Application on 44fb9b4347d6 with PID 9 (/runtime/server.jar started by root in /runtime) +2018-09-16 23:17:50.725 INFO 9 --- [ main] hello.Application : The following profiles are active: dev +2018-09-16 23:17:50.820 INFO 9 --- [ main] ConfigServletWebServerApplicationContext : Refreshing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@6833ce2c: startup date [Sun Sep 16 23:17:50 UTC 2018]; root of context hierarchy +2018-09-16 23:17:52.445 INFO 9 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http) +``` + +## Validating + +``` +curl localhost:8080 +Hello Docker World from My App: Environment for development% +``` + +## Docker Build Args + +``` +docker build -t myapp --build-arg GIT_SHA=$(git rev-parse HEAD) \ + --build-arg GIT_BRANCH=$(git rev-parse --abbrev-ref --symbolic HEAD) \ + --build-arg BUILD_NUMBER=1234 . +``` + +# Sample Features + +## Response Filter with Build Info + +* Build with build information while running + +``` +GIT_SHA=$(git rev-parse HEAD) \ +GIT_BRANCH=$(git rev-parse --abbrev-ref --symbolic HEAD) \ +BUILD_TAG=$USER \ +gradle clean bootRun +``` + +* HTTP Response Headers filters + +``` +$ curl -i localhost:8080 +HTTP/1.1 200 +X-App-Build-Info: commit=486223a73d435c778ac2ef93b68ee637652ee370;branch=feature/sample/show-build-info-all-response-headers;tag=mdesales;time=2018-09-17-05:32:07-UTC;version=0.1.0 +Content-Type: text/plain;charset=UTF-8 +Content-Length: 47 +Date: Mon, 17 Sep 2018 05:32:12 GMT + +Hello Docker World from My App: Default profile% +``` + +## Verification with Docker Containers + + +* Build the docker image with the arguments + +``` +$ docker build -t sample --build-arg BUILDER_GIT_SHA=$(git rev-parse HEAD) --build-arg BUILDER_GIT_BRANCH=$(git rev-parse --abbrev-ref --symbolic HEAD) --build-arg BUILDER_BUILD_NUMBER=$USER . +Sending build context to Docker daemon 4.205MB +Step 1/10 : ARG BUILDER_GIT_SHA=${GIT_SHA:-0101010} +Step 2/10 : ARG BUILDER_GIT_BRANCH=${GIT_BRANCH:-develop} +Step 3/10 : ARG BUILDER_BUILD_NUMBER=${BUILD_NUMBER:-0223} +Step 4/10 : ARG BUILDER_GRADLE_DOWNLOAD_DEPENDENCIES_CMD="gradle downloadDependencies" +Step 5/10 : ARG BUILDER_GRADLE_BUILD_CMD="gradle build -x test" +Step 6/10 : ARG BUILDER_DIR="build/libs" +Step 7/10 : ARG UNMAZEDBOOT_BUILDER_PACKAGE_EXTENSION="jar" +Step 8/10 : ARG RUNNER_PORT="8080" +Step 9/10 : FROM marcellodesales/springboot-builder:gradle-4.10.1-jdk-8 as unmazedboot-builder-artifacts +# Executing 15 build triggers + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Running in fa0d5676f667 +Removing intermediate container fa0d5676f667 + ---> Running in c8633ef774b5 +Removing intermediate container c8633ef774b5 + ---> Running in 34de329e478d +Executing BUILDER_GRADLE_DOWNLOAD_DEPENDENCIES_CMD='gradle downloadDependencies' +Removing intermediate container 34de329e478d + ---> Running in 9d9642a2dacf + +Welcome to Gradle 4.10.1! + +Here are the highlights of this release: + - Incremental Java compilation by default + - Periodic Gradle caches cleanup + - Gradle Kotlin DSL 1.0-RC6 + - Nested included builds + - SNAPSHOT plugin versions in the `plugins {}` block + +For more details see https://docs.gradle.org/4.10.1/release-notes.html + +Starting a Gradle Daemon (subsequent builds will be faster) + +> Task :downloadDependencies + +Retrieving dependencies for annotationProcessor + +... +... + +Retrieving dependencies for testRuntimeOnly + + +BUILD SUCCESSFUL in 25s +1 actionable task: 1 executed +Removing intermediate container 9d9642a2dacf + ---> Running in 9d8c260964ec +Executing BUILDER_GRADLE_BUILD_CMD='gradle build -x test' +Removing intermediate container 9d8c260964ec + ---> Running in a628ad0694c1 + +Welcome to Gradle 4.10.1! + +Here are the highlights of this release: + - Incremental Java compilation by default + - Periodic Gradle caches cleanup + - Gradle Kotlin DSL 1.0-RC6 + - Nested included builds + - SNAPSHOT plugin versions in the `plugins {}` block + +For more details see https://docs.gradle.org/4.10.1/release-notes.html + +Starting a Gradle Daemon (subsequent builds will be faster) +> Task :processResources +> Task :compileJava +> Task :classes +> Task :bootJar +> Task :jar SKIPPED +> Task :assemble +> Task :check +> Task :build + +BUILD SUCCESSFUL in 27s +3 actionable tasks: 3 executed +Removing intermediate container a628ad0694c1 + ---> ff3d11b8f007 +Step 10/10 : FROM marcellodesales/springboot-runner:openjdk-8-jre-slim +# Executing 15 build triggers + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Running in f028ec130c35 +-rwxr--r-- 1 root root 16151787 Sep 17 05:43 /tmp/myapp-0.1.0.jar +Removing intermediate container f028ec130c35 + ---> Running in fdd68c834c82 +Will copy from /app/src/main/resources /runtime/resources +Removing intermediate container fdd68c834c82 + ---> Running in 712af509ad8c +total 20 +drwxr-xr-x 2 root root 4096 Sep 17 05:43 . +drwxr-xr-x 1 root root 4096 Sep 17 05:43 .. +-rw-r--r-- 1 root root 48 Sep 16 23:32 application-dev.yml +-rw-r--r-- 1 root root 47 Sep 16 23:32 application-prd.yml +-rw-r--r-- 1 root root 185 Sep 17 05:14 application.yml +Removing intermediate container 712af509ad8c + ---> Running in a0d64b1c78e0 +Renaming the executable jar to the runtime dir +Removing intermediate container a0d64b1c78e0 + ---> Running in 65b7521b34eb +Removing intermediate container 65b7521b34eb + ---> Running in 3689b3c4ad9d +Removing intermediate container 3689b3c4ad9d + ---> f8c20d9b537e +Successfully built f8c20d9b537e +Successfully tagged sample:latest +``` + +* Run the container + * Note that you need to bind the host's port to the one from the container. + * The end of the output confirms the server is running with the port displayed. + +``` +$ docker run -ti -p 8080:8080 sample + + . ____ _ __ _ _ + /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ +( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ + \\/ ___)| |_)| | | | | || (_| | ) ) ) ) + ' |____| .__|_| |_|_| |_\__, | / / / / + =========|_|==============|___/=/_/_/_/ + :: Spring Boot :: (v2.0.3.RELEASE) + +2018-09-17 05:46:23.906 INFO 9 --- [ main] hello.Application : Starting Application on adab7dc7946f with PID 9 (/runtime/server.jar started by root in /runtime) +2018-09-17 05:46:23.918 INFO 9 --- [ main] hello.Application : No active profile set, falling back to default profiles: default +2018-09-17 05:46:24.089 INFO 9 --- [ main] ConfigServletWebServerApplicationContext : Refreshing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@5b1d2887: startup date [Mon Sep 17 05:46:24 UTC 2018]; root of context hierarchy +2018-09-17 05:46:25.929 INFO 9 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http) +2018-09-17 05:46:25.974 INFO 9 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] +2018-09-17 05:46:25.975 INFO 9 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/8.5.31 +2018-09-17 05:46:25.994 INFO 9 --- [ost-startStop-1] o.a.catalina.core.AprLifecycleListener : The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: [/usr/java/packages/lib/amd64:/usr/lib/x86_64-linux-gnu/jni:/lib/x86_64-linux-gnu:/usr/lib/x86_64-linux-gnu:/usr/lib/jni:/lib:/usr/lib] +2018-09-17 05:46:26.130 INFO 9 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext +2018-09-17 05:46:26.131 INFO 9 --- [ost-startStop-1] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 2047 ms +2018-09-17 05:46:26.325 INFO 9 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean : Servlet dispatcherServlet mapped to [/] +2018-09-17 05:46:26.331 INFO 9 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'characterEncodingFilter' to: [/*] +2018-09-17 05:46:26.332 INFO 9 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'hiddenHttpMethodFilter' to: [/*] +2018-09-17 05:46:26.332 INFO 9 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'httpPutFormContentFilter' to: [/*] +2018-09-17 05:46:26.333 INFO 9 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'requestContextFilter' to: [/*] +2018-09-17 05:46:26.333 INFO 9 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'defaultResponseFilter' to: [/*] +2018-09-17 05:46:26.556 INFO 9 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] +2018-09-17 05:46:26.932 INFO 9 --- [ main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@5b1d2887: startup date [Mon Sep 17 05:46:24 UTC 2018]; root of context hierarchy +2018-09-17 05:46:27.060 INFO 9 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/]}" onto public java.lang.String hello.Application.home() +2018-09-17 05:46:27.069 INFO 9 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse) +2018-09-17 05:46:27.071 INFO 9 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity> org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.error(javax.servlet.http.HttpServletRequest) +2018-09-17 05:46:27.123 INFO 9 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] +2018-09-17 05:46:27.124 INFO 9 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] +2018-09-17 05:46:27.388 INFO 9 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup +2018-09-17 05:46:27.459 INFO 9 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path '' +2018-09-17 05:46:27.471 INFO 9 --- [ main] hello.Application : Started Application in 4.275 seconds (JVM running for 4.926) +``` + +* Make the call to the server + * Note tha the TAG here is different because the Dockerfile overrides the `BUILD_TAG` value! + +``` +$ curl -i localhost:8080 +HTTP/1.1 200 +X-App-Build-Info: commit=d02650d801f8fc5db7ed0cc92422f897df3a0f4b;branch=feature/sample/show-build-info-all-response-headers;tag=sha:d02650d801f8fc5db7ed0cc92422f897df3a0f4b,build:feature/sample/show-build-info-all-response-headers/mdesales;time=2018-09-17-05:43:19-UTC;version=0.1.0 +Content-Type: text/plain;charset=UTF-8 +Content-Length: 47 +Date: Mon, 17 Sep 2018 05:44:10 GMT + +Hello Docker World from My App: Default profile% +``` diff --git a/samples/gradle-java-jdk8-jre8/build.gradle b/samples/gradle-java-jdk8-jre8/build.gradle new file mode 100644 index 0000000..2369a3b --- /dev/null +++ b/samples/gradle-java-jdk8-jre8/build.gradle @@ -0,0 +1,32 @@ +// Group and version (used by jar) +group = 'hello' +version = '0.1.0' + +buildscript { + repositories { + mavenCentral() + } + dependencies { + classpath("org.springframework.boot:spring-boot-gradle-plugin:2.0.3.RELEASE") + } +} + +apply plugin: 'java' +apply plugin: 'eclipse' +apply plugin: 'org.springframework.boot' +apply plugin: 'io.spring.dependency-management' + +apply from: 'src/gradle/jar.gradle' +apply from: 'src/gradle/processResources.gradle' + +repositories { + mavenCentral() +} + +sourceCompatibility = 1.8 +targetCompatibility = 1.8 + +dependencies { + compile("org.springframework.boot:spring-boot-starter-web") + testCompile("org.springframework.boot:spring-boot-starter-test") +} diff --git a/samples/gradle-java-jdk8-jre8/settings.gradle b/samples/gradle-java-jdk8-jre8/settings.gradle new file mode 100644 index 0000000..bebf3f4 --- /dev/null +++ b/samples/gradle-java-jdk8-jre8/settings.gradle @@ -0,0 +1 @@ +rootProject.name = "myapp" diff --git a/samples/gradle-java-jdk8-jre8/src/gradle/jar.gradle b/samples/gradle-java-jdk8-jre8/src/gradle/jar.gradle new file mode 100644 index 0000000..0b06acd --- /dev/null +++ b/samples/gradle-java-jdk8-jre8/src/gradle/jar.gradle @@ -0,0 +1,4 @@ +bootJar { + baseName = rootProject.name + version = project.version +} diff --git a/samples/gradle-java-jdk8-jre8/src/gradle/processResources.gradle b/samples/gradle-java-jdk8-jre8/src/gradle/processResources.gradle new file mode 100644 index 0000000..b9cc58b --- /dev/null +++ b/samples/gradle-java-jdk8-jre8/src/gradle/processResources.gradle @@ -0,0 +1,23 @@ +// https://dzone.com/articles/resource-filtering-gradle +import org.apache.tools.ant.filters.* + +// Expose the commit and branch values for the resources below +ext { + time = new Date().format("yyyy-MM-dd-HH:mm:ss-z", TimeZone.getTimeZone('UTC')) + version = project.version +} + +processResources { + filter ReplaceTokens, tokens: [ + "build.time": time, + "build.version": version + ] +} + +// Process resources when compiling +compileJava.dependsOn(processResources) // added for spring-boot-configuration-processor + +// Include the processResources when running "gradle bootRun" +bootJar { + launchScript() +} diff --git a/samples/gradle-java-jdk8-jre8/src/main/java/hello/Application.java b/samples/gradle-java-jdk8-jre8/src/main/java/hello/Application.java new file mode 100644 index 0000000..8055ad0 --- /dev/null +++ b/samples/gradle-java-jdk8-jre8/src/main/java/hello/Application.java @@ -0,0 +1,30 @@ +package hello; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.context.properties.EnableConfigurationProperties; + +@SpringBootApplication +@RestController +@EnableConfigurationProperties +public class Application { + + @Value("${app.name}") + private String name; + + @Value("${app.description}") + private String description; + + @RequestMapping("/") + public String home() { + return "Hello Docker World from " + this.name + ": " + this.description; + } + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + +} diff --git a/samples/gradle-java-jdk8-jre8/src/main/java/hello/util/BuildInfo.java b/samples/gradle-java-jdk8-jre8/src/main/java/hello/util/BuildInfo.java new file mode 100644 index 0000000..7530aa4 --- /dev/null +++ b/samples/gradle-java-jdk8-jre8/src/main/java/hello/util/BuildInfo.java @@ -0,0 +1,45 @@ +package hello.util; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.context.properties.ConfigurationProperties; +import javax.annotation.PostConstruct; +import org.springframework.stereotype.Component; + +@Component +@ConfigurationProperties(prefix="build") +public class BuildInfo { + + private String commit; + + private String branch; + + private String time; + + private String version; + + public void setCommit(String commit) { + this.commit = commit; + } + + public void setBranch(String branch) { + this.branch = branch; + } + + public void setTime(String time) { + this.time = time; + } + + public void setVersion(String version) { + this.version = version; + } + + @PostConstruct + public void initIt() throws Exception { + System.out.println("INITIALIZED : " + this); + } + + @Override + public String toString() { + return "commit=" + commit + ";branch=" + branch + ";time=" + time + ";version=" + version; + } +} diff --git a/samples/gradle-java-jdk8-jre8/src/main/java/hello/util/DefaultResponseFilter.java b/samples/gradle-java-jdk8-jre8/src/main/java/hello/util/DefaultResponseFilter.java new file mode 100644 index 0000000..6e4a54e --- /dev/null +++ b/samples/gradle-java-jdk8-jre8/src/main/java/hello/util/DefaultResponseFilter.java @@ -0,0 +1,37 @@ +package hello.util; + +import java.io.IOException; +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletResponse; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class DefaultResponseFilter implements Filter { + + @Autowired + private BuildInfo buildInfo; + + @Override + public void destroy() {} + + @Override + public void init(FilterConfig arg0) throws ServletException {} + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException { + + HttpServletResponse res = (HttpServletResponse)response; + res.setHeader("X-App-Build-Info", buildInfo.toString()); + + chain.doFilter(request, res); + + } + +} diff --git a/samples/gradle-java-jdk8-jre8/src/main/resources/application-dev.yml b/samples/gradle-java-jdk8-jre8/src/main/resources/application-dev.yml new file mode 100644 index 0000000..9c73229 --- /dev/null +++ b/samples/gradle-java-jdk8-jre8/src/main/resources/application-dev.yml @@ -0,0 +1,2 @@ +app: + description: Environment for development diff --git a/samples/gradle-java-jdk8-jre8/src/main/resources/application-prd.yml b/samples/gradle-java-jdk8-jre8/src/main/resources/application-prd.yml new file mode 100644 index 0000000..12f7f7e --- /dev/null +++ b/samples/gradle-java-jdk8-jre8/src/main/resources/application-prd.yml @@ -0,0 +1,2 @@ +app: + description: Environment for production diff --git a/samples/gradle-java-jdk8-jre8/src/main/resources/application.yml b/samples/gradle-java-jdk8-jre8/src/main/resources/application.yml new file mode 100644 index 0000000..c796125 --- /dev/null +++ b/samples/gradle-java-jdk8-jre8/src/main/resources/application.yml @@ -0,0 +1,7 @@ +app: + name: My App + description: Default profile + +build: + version: "@build.version@" + time: "@build.time@" diff --git a/samples/gradle-java-jdk8-x-jre11-custom-centos/.dockerignore b/samples/gradle-java-jdk8-x-jre11-custom-centos/.dockerignore new file mode 100644 index 0000000..38aeebd --- /dev/null +++ b/samples/gradle-java-jdk8-x-jre11-custom-centos/.dockerignore @@ -0,0 +1,6 @@ +.gitignore +docker-compose.yaml +Dockerfile +mvnw +mvnw.cmd +README.md diff --git a/samples/gradle-java-jdk8-x-jre11-custom-centos/Dockerfile b/samples/gradle-java-jdk8-x-jre11-custom-centos/Dockerfile new file mode 100644 index 0000000..8a6b8d7 --- /dev/null +++ b/samples/gradle-java-jdk8-x-jre11-custom-centos/Dockerfile @@ -0,0 +1,29 @@ +### Builder Arguments +ARG UNMAZEDBOOT_BUILDER_GIT_SHA=${UNMAZEDBOOT_BUILDER_GIT_SHA:-000000} +ARG UNMAZEDBOOT_BUILDER_GIT_BRANCH=${UNMAZEDBOOT_BUILDER_GIT_BRANCH:-master} +ARG UNMAZEDBOOT_BUILDER_GRADLE_BUILD_CMD="gradle build -x test" +ARG UNMAZEDBOOT_BUILDER_DIR="build/libs" +ARG UNMAZEDBOOT_BUILDER_PACKAGE_EXTENSION="jar" +ARG UNMAZEDBOOT_BUILDER_GRADLE_VERSION=${UNMAZEDBOOT_BUILDER_GRADLE_VERSION:--latest} + +### Linker Argumentss +ARG UNMAZEDBOOT_LINKER_VERSION=${UNMAZEDBOOT_LINKER_VERSION:--latest} + +### Runner Arguments +ARG UNMAZEDBOOT_RUNNER_PORT="8080" +ARG UNMAZEDBOOT_RUNNER_VERSION=${UNMAZEDBOOT_RUNNER_VERSION:--latest} + +# ##################################################################### +# Build stage for building the target directory before running tests +# ##################################################################### +FROM intuit/unmazedboot-builder-gradle:4.10.2-jdk8-alpine${UNMAZEDBOOT_BUILDER_GRADLE_VERSION} as unmazedboot-builder-artifacts + +# ##################################################################### +# Build stage for making a jlink specific for the app +# ##################################################################### +FROM intuit/unmazedboot-linker:oracheljdk11-centos${UNMAZEDBOOT_LINKER_VERSION} as unmazedboot-jdk-linker + +# ##################################################################### +# Build stage for running the runtime image (MUST MATCH LINKER TYPE) +# ##################################################################### +FROM intuit/unmazedboot-runner:custom-jdk-centos7${UNMAZEDBOOT_RUNNER_VERSION} diff --git a/samples/gradle-java-jdk8-x-jre11-custom-centos/README.md b/samples/gradle-java-jdk8-x-jre11-custom-centos/README.md new file mode 100644 index 0000000..9a149dc --- /dev/null +++ b/samples/gradle-java-jdk8-x-jre11-custom-centos/README.md @@ -0,0 +1,368 @@ +# Running + +* Using SpringBoot 2.0.3 +* Using Starter Web + +## BootRun + +* Uses `build.gradle` +* Run with `bootRun` default profile + +``` +gradle bootRun +``` + +* Run with `bootRun` with `dev` profile + +``` +SPRING_PROFILES_ACTIVE=dev gradle bootRun +``` + +## Docker Container + +* Uses the `Dockerfile` +* Build a Docker Image default arguments + +``` +$ docker build -t myapp . +Sending build context to Docker daemon 20.23MB +Step 1/7 : ARG GIT_SHA=${GIT_SHA:-0101010} +Step 2/7 : ARG GIT_BRANCH=${GIT_BRANCH:-develop} +Step 3/7 : ARG BUILD_NUMBER=${BUILD_NUMBER:-0223} +Step 4/7 : ARG GRADLE_BUILD_TASKS="build -x test" +Step 5/7 : ARG EXECUTABLE_TASK_TYPE="jar" +Step 6/7 : FROM marcellodesales/springboot-builder as unmazedboot-builder-artifacts + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Running in 6b7c60c82fa1 +Will execute gradle downloadDependencies +Removing intermediate container 6b7c60c82fa1 + ---> Running in 44f6a573e60e + +Welcome to Gradle 4.10.1! + +Here are the highlights of this release: + - Incremental Java compilation by default + - Periodic Gradle caches cleanup + - Gradle Kotlin DSL 1.0-RC6 + - Nested included builds + - SNAPSHOT plugin versions in the `plugins {}` block + +For more details see https://docs.gradle.org/4.10.1/release-notes.html + +Starting a Gradle Daemon (subsequent builds will be faster) + +> Task :downloadDependencies + +Retrieving dependencies for annotationProcessor + +.. +.. + +Retrieving dependencies for testRuntimeOnly + +BUILD SUCCESSFUL in 14s +1 actionable task: 1 executed +Removing intermediate container 44f6a573e60e + ---> Running in 40a596327554 +Will execute gradle build -x test +Removing intermediate container 40a596327554 + ---> Running in 8642c9c067f4 + +Welcome to Gradle 4.10.1! + +Here are the highlights of this release: + - Incremental Java compilation by default + - Periodic Gradle caches cleanup + - Gradle Kotlin DSL 1.0-RC6 + - Nested included builds + - SNAPSHOT plugin versions in the `plugins {}` block + +For more details see https://docs.gradle.org/4.10.1/release-notes.html + +Starting a Gradle Daemon (subsequent builds will be faster) +> Task :compileJava +> Task :processResources +> Task :classes +> Task :bootJar +> Task :jar SKIPPED +> Task :assemble +> Task :check +> Task :build + +BUILD SUCCESSFUL in 20s +3 actionable tasks: 3 executed +Removing intermediate container 8642c9c067f4 + ---> 405621119bcf +Step 7/7 : FROM marcellodesales/springboot-executable-runner + ---> Using cache + ---> Using cache + ---> Using cache + ---> Running in 46cb7cebdf3b +-rw-r--r-- 1 root root 16141378 Sep 16 23:16 /tmp/myapp-0.1.0.jar +Removing intermediate container 46cb7cebdf3b + ---> Running in b47bfaf3a78d +Will copy from /app/src/main/resources /runtime/resources +Removing intermediate container b47bfaf3a78d + ---> Running in cc5b00fe7dad +total 20 +drwxr-xr-x 2 root root 4096 Sep 16 23:17 . +drwxr-xr-x 1 root root 4096 Sep 16 23:17 .. +-rw-r--r-- 1 root root 48 Sep 16 23:12 application-dev.yml +-rw-r--r-- 1 root root 47 Sep 16 23:12 application-prd.yml +-rw-r--r-- 1 root root 51 Sep 16 23:12 application.yml +Removing intermediate container cc5b00fe7dad + ---> Running in 40a70b1e8304 +Renaming the executable jar to the runtime dir +Removing intermediate container 40a70b1e8304 + ---> Running in 3d3eea4bdd5c +Removing intermediate container 3d3eea4bdd5c + ---> 89923a61a08c +Successfully built 89923a61a08c +Successfully tagged myapp:latest +``` + +* Running in the `dev` profile + * Loads the file `application-dev.yml` + * The logs will be showing `The following profiles are active: dev` + +``` +$ docker run -ti -e SPRING_PROFILES_ACTIVE=dev -p 8080:8080 myapp + + . ____ _ __ _ _ + /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ +( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ + \\/ ___)| |_)| | | | | || (_| | ) ) ) ) + ' |____| .__|_| |_|_| |_\__, | / / / / + =========|_|==============|___/=/_/_/_/ + :: Spring Boot :: (v2.0.3.RELEASE) + +2018-09-16 23:17:50.719 INFO 9 --- [ main] hello.Application : Starting Application on 44fb9b4347d6 with PID 9 (/runtime/server.jar started by root in /runtime) +2018-09-16 23:17:50.725 INFO 9 --- [ main] hello.Application : The following profiles are active: dev +2018-09-16 23:17:50.820 INFO 9 --- [ main] ConfigServletWebServerApplicationContext : Refreshing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@6833ce2c: startup date [Sun Sep 16 23:17:50 UTC 2018]; root of context hierarchy +2018-09-16 23:17:52.445 INFO 9 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http) +``` + +## Validating + +``` +curl localhost:8080 +Hello Docker World from My App: Environment for development% +``` + +## Docker Build Args + +``` +docker build -t myapp --build-arg GIT_SHA=$(git rev-parse HEAD) \ + --build-arg GIT_BRANCH=$(git rev-parse --abbrev-ref --symbolic HEAD) \ + --build-arg BUILD_NUMBER=1234 . +``` + +# Sample Features + +## Response Filter with Build Info + +* Build with build information while running + +``` +GIT_SHA=$(git rev-parse HEAD) \ +GIT_BRANCH=$(git rev-parse --abbrev-ref --symbolic HEAD) \ +BUILD_TAG=$USER \ +gradle clean bootRun +``` + +* HTTP Response Headers filters + +``` +$ curl -i localhost:8080 +HTTP/1.1 200 +X-App-Build-Info: commit=486223a73d435c778ac2ef93b68ee637652ee370;branch=feature/sample/show-build-info-all-response-headers;tag=mdesales;time=2018-09-17-05:32:07-UTC;version=0.1.0 +Content-Type: text/plain;charset=UTF-8 +Content-Length: 47 +Date: Mon, 17 Sep 2018 05:32:12 GMT + +Hello Docker World from My App: Default profile% +``` + +## Verification with Docker Containers + + +* Build the docker image with the arguments + +``` +$ docker build -t sample --build-arg BUILDER_GIT_SHA=$(git rev-parse HEAD) --build-arg BUILDER_GIT_BRANCH=$(git rev-parse --abbrev-ref --symbolic HEAD) --build-arg BUILDER_BUILD_NUMBER=$USER . +Sending build context to Docker daemon 4.205MB +Step 1/10 : ARG BUILDER_GIT_SHA=${GIT_SHA:-0101010} +Step 2/10 : ARG BUILDER_GIT_BRANCH=${GIT_BRANCH:-develop} +Step 3/10 : ARG BUILDER_BUILD_NUMBER=${BUILD_NUMBER:-0223} +Step 4/10 : ARG BUILDER_GRADLE_DOWNLOAD_DEPENDENCIES_CMD="gradle downloadDependencies" +Step 5/10 : ARG BUILDER_GRADLE_BUILD_CMD="gradle build -x test" +Step 6/10 : ARG BUILDER_DIR="build/libs" +Step 7/10 : ARG UNMAZEDBOOT_BUILDER_PACKAGE_EXTENSION="jar" +Step 8/10 : ARG RUNNER_PORT="8080" +Step 9/10 : FROM marcellodesales/springboot-builder:gradle-4.10.1-jdk-8 as unmazedboot-builder-artifacts +# Executing 15 build triggers + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Running in fa0d5676f667 +Removing intermediate container fa0d5676f667 + ---> Running in c8633ef774b5 +Removing intermediate container c8633ef774b5 + ---> Running in 34de329e478d +Executing BUILDER_GRADLE_DOWNLOAD_DEPENDENCIES_CMD='gradle downloadDependencies' +Removing intermediate container 34de329e478d + ---> Running in 9d9642a2dacf + +Welcome to Gradle 4.10.1! + +Here are the highlights of this release: + - Incremental Java compilation by default + - Periodic Gradle caches cleanup + - Gradle Kotlin DSL 1.0-RC6 + - Nested included builds + - SNAPSHOT plugin versions in the `plugins {}` block + +For more details see https://docs.gradle.org/4.10.1/release-notes.html + +Starting a Gradle Daemon (subsequent builds will be faster) + +> Task :downloadDependencies + +Retrieving dependencies for annotationProcessor + +... +... + +Retrieving dependencies for testRuntimeOnly + + +BUILD SUCCESSFUL in 25s +1 actionable task: 1 executed +Removing intermediate container 9d9642a2dacf + ---> Running in 9d8c260964ec +Executing BUILDER_GRADLE_BUILD_CMD='gradle build -x test' +Removing intermediate container 9d8c260964ec + ---> Running in a628ad0694c1 + +Welcome to Gradle 4.10.1! + +Here are the highlights of this release: + - Incremental Java compilation by default + - Periodic Gradle caches cleanup + - Gradle Kotlin DSL 1.0-RC6 + - Nested included builds + - SNAPSHOT plugin versions in the `plugins {}` block + +For more details see https://docs.gradle.org/4.10.1/release-notes.html + +Starting a Gradle Daemon (subsequent builds will be faster) +> Task :processResources +> Task :compileJava +> Task :classes +> Task :bootJar +> Task :jar SKIPPED +> Task :assemble +> Task :check +> Task :build + +BUILD SUCCESSFUL in 27s +3 actionable tasks: 3 executed +Removing intermediate container a628ad0694c1 + ---> ff3d11b8f007 +Step 10/10 : FROM marcellodesales/springboot-runner:openjdk-8-jre-slim +# Executing 15 build triggers + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Running in f028ec130c35 +-rwxr--r-- 1 root root 16151787 Sep 17 05:43 /tmp/myapp-0.1.0.jar +Removing intermediate container f028ec130c35 + ---> Running in fdd68c834c82 +Will copy from /app/src/main/resources /runtime/resources +Removing intermediate container fdd68c834c82 + ---> Running in 712af509ad8c +total 20 +drwxr-xr-x 2 root root 4096 Sep 17 05:43 . +drwxr-xr-x 1 root root 4096 Sep 17 05:43 .. +-rw-r--r-- 1 root root 48 Sep 16 23:32 application-dev.yml +-rw-r--r-- 1 root root 47 Sep 16 23:32 application-prd.yml +-rw-r--r-- 1 root root 185 Sep 17 05:14 application.yml +Removing intermediate container 712af509ad8c + ---> Running in a0d64b1c78e0 +Renaming the executable jar to the runtime dir +Removing intermediate container a0d64b1c78e0 + ---> Running in 65b7521b34eb +Removing intermediate container 65b7521b34eb + ---> Running in 3689b3c4ad9d +Removing intermediate container 3689b3c4ad9d + ---> f8c20d9b537e +Successfully built f8c20d9b537e +Successfully tagged sample:latest +``` + +* Run the container + * Note that you need to bind the host's port to the one from the container. + * The end of the output confirms the server is running with the port displayed. + +``` +$ docker run -ti -p 8080:8080 sample + + . ____ _ __ _ _ + /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ +( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ + \\/ ___)| |_)| | | | | || (_| | ) ) ) ) + ' |____| .__|_| |_|_| |_\__, | / / / / + =========|_|==============|___/=/_/_/_/ + :: Spring Boot :: (v2.0.3.RELEASE) + +2018-09-17 05:46:23.906 INFO 9 --- [ main] hello.Application : Starting Application on adab7dc7946f with PID 9 (/runtime/server.jar started by root in /runtime) +2018-09-17 05:46:23.918 INFO 9 --- [ main] hello.Application : No active profile set, falling back to default profiles: default +2018-09-17 05:46:24.089 INFO 9 --- [ main] ConfigServletWebServerApplicationContext : Refreshing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@5b1d2887: startup date [Mon Sep 17 05:46:24 UTC 2018]; root of context hierarchy +2018-09-17 05:46:25.929 INFO 9 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http) +2018-09-17 05:46:25.974 INFO 9 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] +2018-09-17 05:46:25.975 INFO 9 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/8.5.31 +2018-09-17 05:46:25.994 INFO 9 --- [ost-startStop-1] o.a.catalina.core.AprLifecycleListener : The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: [/usr/java/packages/lib/amd64:/usr/lib/x86_64-linux-gnu/jni:/lib/x86_64-linux-gnu:/usr/lib/x86_64-linux-gnu:/usr/lib/jni:/lib:/usr/lib] +2018-09-17 05:46:26.130 INFO 9 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext +2018-09-17 05:46:26.131 INFO 9 --- [ost-startStop-1] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 2047 ms +2018-09-17 05:46:26.325 INFO 9 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean : Servlet dispatcherServlet mapped to [/] +2018-09-17 05:46:26.331 INFO 9 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'characterEncodingFilter' to: [/*] +2018-09-17 05:46:26.332 INFO 9 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'hiddenHttpMethodFilter' to: [/*] +2018-09-17 05:46:26.332 INFO 9 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'httpPutFormContentFilter' to: [/*] +2018-09-17 05:46:26.333 INFO 9 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'requestContextFilter' to: [/*] +2018-09-17 05:46:26.333 INFO 9 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'defaultResponseFilter' to: [/*] +2018-09-17 05:46:26.556 INFO 9 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] +2018-09-17 05:46:26.932 INFO 9 --- [ main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@5b1d2887: startup date [Mon Sep 17 05:46:24 UTC 2018]; root of context hierarchy +2018-09-17 05:46:27.060 INFO 9 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/]}" onto public java.lang.String hello.Application.home() +2018-09-17 05:46:27.069 INFO 9 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse) +2018-09-17 05:46:27.071 INFO 9 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity> org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.error(javax.servlet.http.HttpServletRequest) +2018-09-17 05:46:27.123 INFO 9 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] +2018-09-17 05:46:27.124 INFO 9 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] +2018-09-17 05:46:27.388 INFO 9 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup +2018-09-17 05:46:27.459 INFO 9 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path '' +2018-09-17 05:46:27.471 INFO 9 --- [ main] hello.Application : Started Application in 4.275 seconds (JVM running for 4.926) +``` + +* Make the call to the server + * Note tha the TAG here is different because the Dockerfile overrides the `BUILD_TAG` value! + +``` +$ curl -i localhost:8080 +HTTP/1.1 200 +X-App-Build-Info: commit=d02650d801f8fc5db7ed0cc92422f897df3a0f4b;branch=feature/sample/show-build-info-all-response-headers;tag=sha:d02650d801f8fc5db7ed0cc92422f897df3a0f4b,build:feature/sample/show-build-info-all-response-headers/mdesales;time=2018-09-17-05:43:19-UTC;version=0.1.0 +Content-Type: text/plain;charset=UTF-8 +Content-Length: 47 +Date: Mon, 17 Sep 2018 05:44:10 GMT + +Hello Docker World from My App: Default profile% +``` diff --git a/samples/gradle-java-jdk8-x-jre11-custom-centos/build.gradle b/samples/gradle-java-jdk8-x-jre11-custom-centos/build.gradle new file mode 100644 index 0000000..2369a3b --- /dev/null +++ b/samples/gradle-java-jdk8-x-jre11-custom-centos/build.gradle @@ -0,0 +1,32 @@ +// Group and version (used by jar) +group = 'hello' +version = '0.1.0' + +buildscript { + repositories { + mavenCentral() + } + dependencies { + classpath("org.springframework.boot:spring-boot-gradle-plugin:2.0.3.RELEASE") + } +} + +apply plugin: 'java' +apply plugin: 'eclipse' +apply plugin: 'org.springframework.boot' +apply plugin: 'io.spring.dependency-management' + +apply from: 'src/gradle/jar.gradle' +apply from: 'src/gradle/processResources.gradle' + +repositories { + mavenCentral() +} + +sourceCompatibility = 1.8 +targetCompatibility = 1.8 + +dependencies { + compile("org.springframework.boot:spring-boot-starter-web") + testCompile("org.springframework.boot:spring-boot-starter-test") +} diff --git a/samples/gradle-java-jdk8-x-jre11-custom-centos/settings.gradle b/samples/gradle-java-jdk8-x-jre11-custom-centos/settings.gradle new file mode 100644 index 0000000..bebf3f4 --- /dev/null +++ b/samples/gradle-java-jdk8-x-jre11-custom-centos/settings.gradle @@ -0,0 +1 @@ +rootProject.name = "myapp" diff --git a/samples/gradle-java-jdk8-x-jre11-custom-centos/src/gradle/jar.gradle b/samples/gradle-java-jdk8-x-jre11-custom-centos/src/gradle/jar.gradle new file mode 100644 index 0000000..0b06acd --- /dev/null +++ b/samples/gradle-java-jdk8-x-jre11-custom-centos/src/gradle/jar.gradle @@ -0,0 +1,4 @@ +bootJar { + baseName = rootProject.name + version = project.version +} diff --git a/samples/gradle-java-jdk8-x-jre11-custom-centos/src/gradle/processResources.gradle b/samples/gradle-java-jdk8-x-jre11-custom-centos/src/gradle/processResources.gradle new file mode 100644 index 0000000..b9cc58b --- /dev/null +++ b/samples/gradle-java-jdk8-x-jre11-custom-centos/src/gradle/processResources.gradle @@ -0,0 +1,23 @@ +// https://dzone.com/articles/resource-filtering-gradle +import org.apache.tools.ant.filters.* + +// Expose the commit and branch values for the resources below +ext { + time = new Date().format("yyyy-MM-dd-HH:mm:ss-z", TimeZone.getTimeZone('UTC')) + version = project.version +} + +processResources { + filter ReplaceTokens, tokens: [ + "build.time": time, + "build.version": version + ] +} + +// Process resources when compiling +compileJava.dependsOn(processResources) // added for spring-boot-configuration-processor + +// Include the processResources when running "gradle bootRun" +bootJar { + launchScript() +} diff --git a/samples/gradle-java-jdk8-x-jre11-custom-centos/src/main/java/hello/Application.java b/samples/gradle-java-jdk8-x-jre11-custom-centos/src/main/java/hello/Application.java new file mode 100644 index 0000000..8055ad0 --- /dev/null +++ b/samples/gradle-java-jdk8-x-jre11-custom-centos/src/main/java/hello/Application.java @@ -0,0 +1,30 @@ +package hello; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.context.properties.EnableConfigurationProperties; + +@SpringBootApplication +@RestController +@EnableConfigurationProperties +public class Application { + + @Value("${app.name}") + private String name; + + @Value("${app.description}") + private String description; + + @RequestMapping("/") + public String home() { + return "Hello Docker World from " + this.name + ": " + this.description; + } + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + +} diff --git a/samples/gradle-java-jdk8-x-jre11-custom-centos/src/main/java/hello/util/BuildInfo.java b/samples/gradle-java-jdk8-x-jre11-custom-centos/src/main/java/hello/util/BuildInfo.java new file mode 100644 index 0000000..7530aa4 --- /dev/null +++ b/samples/gradle-java-jdk8-x-jre11-custom-centos/src/main/java/hello/util/BuildInfo.java @@ -0,0 +1,45 @@ +package hello.util; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.context.properties.ConfigurationProperties; +import javax.annotation.PostConstruct; +import org.springframework.stereotype.Component; + +@Component +@ConfigurationProperties(prefix="build") +public class BuildInfo { + + private String commit; + + private String branch; + + private String time; + + private String version; + + public void setCommit(String commit) { + this.commit = commit; + } + + public void setBranch(String branch) { + this.branch = branch; + } + + public void setTime(String time) { + this.time = time; + } + + public void setVersion(String version) { + this.version = version; + } + + @PostConstruct + public void initIt() throws Exception { + System.out.println("INITIALIZED : " + this); + } + + @Override + public String toString() { + return "commit=" + commit + ";branch=" + branch + ";time=" + time + ";version=" + version; + } +} diff --git a/samples/gradle-java-jdk8-x-jre11-custom-centos/src/main/java/hello/util/DefaultResponseFilter.java b/samples/gradle-java-jdk8-x-jre11-custom-centos/src/main/java/hello/util/DefaultResponseFilter.java new file mode 100644 index 0000000..ff48f36 --- /dev/null +++ b/samples/gradle-java-jdk8-x-jre11-custom-centos/src/main/java/hello/util/DefaultResponseFilter.java @@ -0,0 +1,37 @@ +package hello.util; + +import java.io.IOException; +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletResponse; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class DefaultResponseFilter implements Filter { + + @Autowired + private BuildInfo buildInfo; + + @Override + public void destroy() {} + + @Override + public void init(FilterConfig arg0) throws ServletException {} + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException { + + HttpServletResponse res = (HttpServletResponse)response; + res.setHeader("X-App-Build-Info", buildInfo.toString()); + + chain.doFilter(request, res); + + } + +} diff --git a/samples/gradle-java-jdk8-x-jre11-custom-centos/src/main/resources/application-dev.yml b/samples/gradle-java-jdk8-x-jre11-custom-centos/src/main/resources/application-dev.yml new file mode 100644 index 0000000..9c73229 --- /dev/null +++ b/samples/gradle-java-jdk8-x-jre11-custom-centos/src/main/resources/application-dev.yml @@ -0,0 +1,2 @@ +app: + description: Environment for development diff --git a/samples/gradle-java-jdk8-x-jre11-custom-centos/src/main/resources/application-prd.yml b/samples/gradle-java-jdk8-x-jre11-custom-centos/src/main/resources/application-prd.yml new file mode 100644 index 0000000..12f7f7e --- /dev/null +++ b/samples/gradle-java-jdk8-x-jre11-custom-centos/src/main/resources/application-prd.yml @@ -0,0 +1,2 @@ +app: + description: Environment for production diff --git a/samples/gradle-java-jdk8-x-jre11-custom-centos/src/main/resources/application.yml b/samples/gradle-java-jdk8-x-jre11-custom-centos/src/main/resources/application.yml new file mode 100644 index 0000000..c796125 --- /dev/null +++ b/samples/gradle-java-jdk8-x-jre11-custom-centos/src/main/resources/application.yml @@ -0,0 +1,7 @@ +app: + name: My App + description: Default profile + +build: + version: "@build.version@" + time: "@build.time@" diff --git a/samples/gradle-java-jdk8-x-jre11-custom-debian/.dockerignore b/samples/gradle-java-jdk8-x-jre11-custom-debian/.dockerignore new file mode 100644 index 0000000..38aeebd --- /dev/null +++ b/samples/gradle-java-jdk8-x-jre11-custom-debian/.dockerignore @@ -0,0 +1,6 @@ +.gitignore +docker-compose.yaml +Dockerfile +mvnw +mvnw.cmd +README.md diff --git a/samples/gradle-java-jdk8-x-jre11-custom-debian/Dockerfile b/samples/gradle-java-jdk8-x-jre11-custom-debian/Dockerfile new file mode 100644 index 0000000..0e7fb93 --- /dev/null +++ b/samples/gradle-java-jdk8-x-jre11-custom-debian/Dockerfile @@ -0,0 +1,29 @@ +### Builder Arguments +ARG UNMAZEDBOOT_BUILDER_GIT_SHA=${UNMAZEDBOOT_BUILDER_GIT_SHA:-000000} +ARG UNMAZEDBOOT_BUILDER_GIT_BRANCH=${UNMAZEDBOOT_BUILDER_GIT_BRANCH:-master} +ARG UNMAZEDBOOT_BUILDER_GRADLE_BUILD_CMD="gradle build -x test" +ARG UNMAZEDBOOT_BUILDER_DIR="build/libs" +ARG UNMAZEDBOOT_BUILDER_PACKAGE_EXTENSION="jar" +ARG UNMAZEDBOOT_BUILDER_GRADLE_VERSION=${UNMAZEDBOOT_BUILDER_GRADLE_VERSION:--latest} + +### Linker Argumentss +ARG UNMAZEDBOOT_LINKER_VERSION=${UNMAZEDBOOT_LINKER_VERSION:--latest} + +### Runner Arguments +ARG UNMAZEDBOOT_RUNNER_PORT="8080" +ARG UNMAZEDBOOT_RUNNER_VERSION=${UNMAZEDBOOT_RUNNER_VERSION:--latest} + +# ##################################################################### +# Build stage for building the target directory before running tests +# ##################################################################### +FROM intuit/unmazedboot-builder-gradle:4.10.2-jdk8-alpine${UNMAZEDBOOT_BUILDER_GRADLE_VERSION} as unmazedboot-builder-artifacts + +# ##################################################################### +# Build stage for making a jlink specific for the app +# ##################################################################### +FROM intuit/unmazedboot-linker:jdk11-debian${UNMAZEDBOOT_LINKER_VERSION} as unmazedboot-jdk-linker + +# ##################################################################### +# Build stage for running the runtime image (MUST MATCH LINKER TYPE) +# ##################################################################### +FROM intuit/unmazedboot-runner:custom-jdk-debian9-slim${UNMAZEDBOOT_RUNNER_VERSION} diff --git a/samples/gradle-java-jdk8-x-jre11-custom-debian/README.md b/samples/gradle-java-jdk8-x-jre11-custom-debian/README.md new file mode 100644 index 0000000..9a149dc --- /dev/null +++ b/samples/gradle-java-jdk8-x-jre11-custom-debian/README.md @@ -0,0 +1,368 @@ +# Running + +* Using SpringBoot 2.0.3 +* Using Starter Web + +## BootRun + +* Uses `build.gradle` +* Run with `bootRun` default profile + +``` +gradle bootRun +``` + +* Run with `bootRun` with `dev` profile + +``` +SPRING_PROFILES_ACTIVE=dev gradle bootRun +``` + +## Docker Container + +* Uses the `Dockerfile` +* Build a Docker Image default arguments + +``` +$ docker build -t myapp . +Sending build context to Docker daemon 20.23MB +Step 1/7 : ARG GIT_SHA=${GIT_SHA:-0101010} +Step 2/7 : ARG GIT_BRANCH=${GIT_BRANCH:-develop} +Step 3/7 : ARG BUILD_NUMBER=${BUILD_NUMBER:-0223} +Step 4/7 : ARG GRADLE_BUILD_TASKS="build -x test" +Step 5/7 : ARG EXECUTABLE_TASK_TYPE="jar" +Step 6/7 : FROM marcellodesales/springboot-builder as unmazedboot-builder-artifacts + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Running in 6b7c60c82fa1 +Will execute gradle downloadDependencies +Removing intermediate container 6b7c60c82fa1 + ---> Running in 44f6a573e60e + +Welcome to Gradle 4.10.1! + +Here are the highlights of this release: + - Incremental Java compilation by default + - Periodic Gradle caches cleanup + - Gradle Kotlin DSL 1.0-RC6 + - Nested included builds + - SNAPSHOT plugin versions in the `plugins {}` block + +For more details see https://docs.gradle.org/4.10.1/release-notes.html + +Starting a Gradle Daemon (subsequent builds will be faster) + +> Task :downloadDependencies + +Retrieving dependencies for annotationProcessor + +.. +.. + +Retrieving dependencies for testRuntimeOnly + +BUILD SUCCESSFUL in 14s +1 actionable task: 1 executed +Removing intermediate container 44f6a573e60e + ---> Running in 40a596327554 +Will execute gradle build -x test +Removing intermediate container 40a596327554 + ---> Running in 8642c9c067f4 + +Welcome to Gradle 4.10.1! + +Here are the highlights of this release: + - Incremental Java compilation by default + - Periodic Gradle caches cleanup + - Gradle Kotlin DSL 1.0-RC6 + - Nested included builds + - SNAPSHOT plugin versions in the `plugins {}` block + +For more details see https://docs.gradle.org/4.10.1/release-notes.html + +Starting a Gradle Daemon (subsequent builds will be faster) +> Task :compileJava +> Task :processResources +> Task :classes +> Task :bootJar +> Task :jar SKIPPED +> Task :assemble +> Task :check +> Task :build + +BUILD SUCCESSFUL in 20s +3 actionable tasks: 3 executed +Removing intermediate container 8642c9c067f4 + ---> 405621119bcf +Step 7/7 : FROM marcellodesales/springboot-executable-runner + ---> Using cache + ---> Using cache + ---> Using cache + ---> Running in 46cb7cebdf3b +-rw-r--r-- 1 root root 16141378 Sep 16 23:16 /tmp/myapp-0.1.0.jar +Removing intermediate container 46cb7cebdf3b + ---> Running in b47bfaf3a78d +Will copy from /app/src/main/resources /runtime/resources +Removing intermediate container b47bfaf3a78d + ---> Running in cc5b00fe7dad +total 20 +drwxr-xr-x 2 root root 4096 Sep 16 23:17 . +drwxr-xr-x 1 root root 4096 Sep 16 23:17 .. +-rw-r--r-- 1 root root 48 Sep 16 23:12 application-dev.yml +-rw-r--r-- 1 root root 47 Sep 16 23:12 application-prd.yml +-rw-r--r-- 1 root root 51 Sep 16 23:12 application.yml +Removing intermediate container cc5b00fe7dad + ---> Running in 40a70b1e8304 +Renaming the executable jar to the runtime dir +Removing intermediate container 40a70b1e8304 + ---> Running in 3d3eea4bdd5c +Removing intermediate container 3d3eea4bdd5c + ---> 89923a61a08c +Successfully built 89923a61a08c +Successfully tagged myapp:latest +``` + +* Running in the `dev` profile + * Loads the file `application-dev.yml` + * The logs will be showing `The following profiles are active: dev` + +``` +$ docker run -ti -e SPRING_PROFILES_ACTIVE=dev -p 8080:8080 myapp + + . ____ _ __ _ _ + /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ +( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ + \\/ ___)| |_)| | | | | || (_| | ) ) ) ) + ' |____| .__|_| |_|_| |_\__, | / / / / + =========|_|==============|___/=/_/_/_/ + :: Spring Boot :: (v2.0.3.RELEASE) + +2018-09-16 23:17:50.719 INFO 9 --- [ main] hello.Application : Starting Application on 44fb9b4347d6 with PID 9 (/runtime/server.jar started by root in /runtime) +2018-09-16 23:17:50.725 INFO 9 --- [ main] hello.Application : The following profiles are active: dev +2018-09-16 23:17:50.820 INFO 9 --- [ main] ConfigServletWebServerApplicationContext : Refreshing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@6833ce2c: startup date [Sun Sep 16 23:17:50 UTC 2018]; root of context hierarchy +2018-09-16 23:17:52.445 INFO 9 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http) +``` + +## Validating + +``` +curl localhost:8080 +Hello Docker World from My App: Environment for development% +``` + +## Docker Build Args + +``` +docker build -t myapp --build-arg GIT_SHA=$(git rev-parse HEAD) \ + --build-arg GIT_BRANCH=$(git rev-parse --abbrev-ref --symbolic HEAD) \ + --build-arg BUILD_NUMBER=1234 . +``` + +# Sample Features + +## Response Filter with Build Info + +* Build with build information while running + +``` +GIT_SHA=$(git rev-parse HEAD) \ +GIT_BRANCH=$(git rev-parse --abbrev-ref --symbolic HEAD) \ +BUILD_TAG=$USER \ +gradle clean bootRun +``` + +* HTTP Response Headers filters + +``` +$ curl -i localhost:8080 +HTTP/1.1 200 +X-App-Build-Info: commit=486223a73d435c778ac2ef93b68ee637652ee370;branch=feature/sample/show-build-info-all-response-headers;tag=mdesales;time=2018-09-17-05:32:07-UTC;version=0.1.0 +Content-Type: text/plain;charset=UTF-8 +Content-Length: 47 +Date: Mon, 17 Sep 2018 05:32:12 GMT + +Hello Docker World from My App: Default profile% +``` + +## Verification with Docker Containers + + +* Build the docker image with the arguments + +``` +$ docker build -t sample --build-arg BUILDER_GIT_SHA=$(git rev-parse HEAD) --build-arg BUILDER_GIT_BRANCH=$(git rev-parse --abbrev-ref --symbolic HEAD) --build-arg BUILDER_BUILD_NUMBER=$USER . +Sending build context to Docker daemon 4.205MB +Step 1/10 : ARG BUILDER_GIT_SHA=${GIT_SHA:-0101010} +Step 2/10 : ARG BUILDER_GIT_BRANCH=${GIT_BRANCH:-develop} +Step 3/10 : ARG BUILDER_BUILD_NUMBER=${BUILD_NUMBER:-0223} +Step 4/10 : ARG BUILDER_GRADLE_DOWNLOAD_DEPENDENCIES_CMD="gradle downloadDependencies" +Step 5/10 : ARG BUILDER_GRADLE_BUILD_CMD="gradle build -x test" +Step 6/10 : ARG BUILDER_DIR="build/libs" +Step 7/10 : ARG UNMAZEDBOOT_BUILDER_PACKAGE_EXTENSION="jar" +Step 8/10 : ARG RUNNER_PORT="8080" +Step 9/10 : FROM marcellodesales/springboot-builder:gradle-4.10.1-jdk-8 as unmazedboot-builder-artifacts +# Executing 15 build triggers + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Running in fa0d5676f667 +Removing intermediate container fa0d5676f667 + ---> Running in c8633ef774b5 +Removing intermediate container c8633ef774b5 + ---> Running in 34de329e478d +Executing BUILDER_GRADLE_DOWNLOAD_DEPENDENCIES_CMD='gradle downloadDependencies' +Removing intermediate container 34de329e478d + ---> Running in 9d9642a2dacf + +Welcome to Gradle 4.10.1! + +Here are the highlights of this release: + - Incremental Java compilation by default + - Periodic Gradle caches cleanup + - Gradle Kotlin DSL 1.0-RC6 + - Nested included builds + - SNAPSHOT plugin versions in the `plugins {}` block + +For more details see https://docs.gradle.org/4.10.1/release-notes.html + +Starting a Gradle Daemon (subsequent builds will be faster) + +> Task :downloadDependencies + +Retrieving dependencies for annotationProcessor + +... +... + +Retrieving dependencies for testRuntimeOnly + + +BUILD SUCCESSFUL in 25s +1 actionable task: 1 executed +Removing intermediate container 9d9642a2dacf + ---> Running in 9d8c260964ec +Executing BUILDER_GRADLE_BUILD_CMD='gradle build -x test' +Removing intermediate container 9d8c260964ec + ---> Running in a628ad0694c1 + +Welcome to Gradle 4.10.1! + +Here are the highlights of this release: + - Incremental Java compilation by default + - Periodic Gradle caches cleanup + - Gradle Kotlin DSL 1.0-RC6 + - Nested included builds + - SNAPSHOT plugin versions in the `plugins {}` block + +For more details see https://docs.gradle.org/4.10.1/release-notes.html + +Starting a Gradle Daemon (subsequent builds will be faster) +> Task :processResources +> Task :compileJava +> Task :classes +> Task :bootJar +> Task :jar SKIPPED +> Task :assemble +> Task :check +> Task :build + +BUILD SUCCESSFUL in 27s +3 actionable tasks: 3 executed +Removing intermediate container a628ad0694c1 + ---> ff3d11b8f007 +Step 10/10 : FROM marcellodesales/springboot-runner:openjdk-8-jre-slim +# Executing 15 build triggers + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Running in f028ec130c35 +-rwxr--r-- 1 root root 16151787 Sep 17 05:43 /tmp/myapp-0.1.0.jar +Removing intermediate container f028ec130c35 + ---> Running in fdd68c834c82 +Will copy from /app/src/main/resources /runtime/resources +Removing intermediate container fdd68c834c82 + ---> Running in 712af509ad8c +total 20 +drwxr-xr-x 2 root root 4096 Sep 17 05:43 . +drwxr-xr-x 1 root root 4096 Sep 17 05:43 .. +-rw-r--r-- 1 root root 48 Sep 16 23:32 application-dev.yml +-rw-r--r-- 1 root root 47 Sep 16 23:32 application-prd.yml +-rw-r--r-- 1 root root 185 Sep 17 05:14 application.yml +Removing intermediate container 712af509ad8c + ---> Running in a0d64b1c78e0 +Renaming the executable jar to the runtime dir +Removing intermediate container a0d64b1c78e0 + ---> Running in 65b7521b34eb +Removing intermediate container 65b7521b34eb + ---> Running in 3689b3c4ad9d +Removing intermediate container 3689b3c4ad9d + ---> f8c20d9b537e +Successfully built f8c20d9b537e +Successfully tagged sample:latest +``` + +* Run the container + * Note that you need to bind the host's port to the one from the container. + * The end of the output confirms the server is running with the port displayed. + +``` +$ docker run -ti -p 8080:8080 sample + + . ____ _ __ _ _ + /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ +( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ + \\/ ___)| |_)| | | | | || (_| | ) ) ) ) + ' |____| .__|_| |_|_| |_\__, | / / / / + =========|_|==============|___/=/_/_/_/ + :: Spring Boot :: (v2.0.3.RELEASE) + +2018-09-17 05:46:23.906 INFO 9 --- [ main] hello.Application : Starting Application on adab7dc7946f with PID 9 (/runtime/server.jar started by root in /runtime) +2018-09-17 05:46:23.918 INFO 9 --- [ main] hello.Application : No active profile set, falling back to default profiles: default +2018-09-17 05:46:24.089 INFO 9 --- [ main] ConfigServletWebServerApplicationContext : Refreshing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@5b1d2887: startup date [Mon Sep 17 05:46:24 UTC 2018]; root of context hierarchy +2018-09-17 05:46:25.929 INFO 9 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http) +2018-09-17 05:46:25.974 INFO 9 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] +2018-09-17 05:46:25.975 INFO 9 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/8.5.31 +2018-09-17 05:46:25.994 INFO 9 --- [ost-startStop-1] o.a.catalina.core.AprLifecycleListener : The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: [/usr/java/packages/lib/amd64:/usr/lib/x86_64-linux-gnu/jni:/lib/x86_64-linux-gnu:/usr/lib/x86_64-linux-gnu:/usr/lib/jni:/lib:/usr/lib] +2018-09-17 05:46:26.130 INFO 9 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext +2018-09-17 05:46:26.131 INFO 9 --- [ost-startStop-1] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 2047 ms +2018-09-17 05:46:26.325 INFO 9 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean : Servlet dispatcherServlet mapped to [/] +2018-09-17 05:46:26.331 INFO 9 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'characterEncodingFilter' to: [/*] +2018-09-17 05:46:26.332 INFO 9 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'hiddenHttpMethodFilter' to: [/*] +2018-09-17 05:46:26.332 INFO 9 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'httpPutFormContentFilter' to: [/*] +2018-09-17 05:46:26.333 INFO 9 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'requestContextFilter' to: [/*] +2018-09-17 05:46:26.333 INFO 9 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'defaultResponseFilter' to: [/*] +2018-09-17 05:46:26.556 INFO 9 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] +2018-09-17 05:46:26.932 INFO 9 --- [ main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@5b1d2887: startup date [Mon Sep 17 05:46:24 UTC 2018]; root of context hierarchy +2018-09-17 05:46:27.060 INFO 9 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/]}" onto public java.lang.String hello.Application.home() +2018-09-17 05:46:27.069 INFO 9 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse) +2018-09-17 05:46:27.071 INFO 9 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity> org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.error(javax.servlet.http.HttpServletRequest) +2018-09-17 05:46:27.123 INFO 9 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] +2018-09-17 05:46:27.124 INFO 9 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] +2018-09-17 05:46:27.388 INFO 9 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup +2018-09-17 05:46:27.459 INFO 9 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path '' +2018-09-17 05:46:27.471 INFO 9 --- [ main] hello.Application : Started Application in 4.275 seconds (JVM running for 4.926) +``` + +* Make the call to the server + * Note tha the TAG here is different because the Dockerfile overrides the `BUILD_TAG` value! + +``` +$ curl -i localhost:8080 +HTTP/1.1 200 +X-App-Build-Info: commit=d02650d801f8fc5db7ed0cc92422f897df3a0f4b;branch=feature/sample/show-build-info-all-response-headers;tag=sha:d02650d801f8fc5db7ed0cc92422f897df3a0f4b,build:feature/sample/show-build-info-all-response-headers/mdesales;time=2018-09-17-05:43:19-UTC;version=0.1.0 +Content-Type: text/plain;charset=UTF-8 +Content-Length: 47 +Date: Mon, 17 Sep 2018 05:44:10 GMT + +Hello Docker World from My App: Default profile% +``` diff --git a/samples/gradle-java-jdk8-x-jre11-custom-debian/build.gradle b/samples/gradle-java-jdk8-x-jre11-custom-debian/build.gradle new file mode 100644 index 0000000..2369a3b --- /dev/null +++ b/samples/gradle-java-jdk8-x-jre11-custom-debian/build.gradle @@ -0,0 +1,32 @@ +// Group and version (used by jar) +group = 'hello' +version = '0.1.0' + +buildscript { + repositories { + mavenCentral() + } + dependencies { + classpath("org.springframework.boot:spring-boot-gradle-plugin:2.0.3.RELEASE") + } +} + +apply plugin: 'java' +apply plugin: 'eclipse' +apply plugin: 'org.springframework.boot' +apply plugin: 'io.spring.dependency-management' + +apply from: 'src/gradle/jar.gradle' +apply from: 'src/gradle/processResources.gradle' + +repositories { + mavenCentral() +} + +sourceCompatibility = 1.8 +targetCompatibility = 1.8 + +dependencies { + compile("org.springframework.boot:spring-boot-starter-web") + testCompile("org.springframework.boot:spring-boot-starter-test") +} diff --git a/samples/gradle-java-jdk8-x-jre11-custom-debian/settings.gradle b/samples/gradle-java-jdk8-x-jre11-custom-debian/settings.gradle new file mode 100644 index 0000000..bebf3f4 --- /dev/null +++ b/samples/gradle-java-jdk8-x-jre11-custom-debian/settings.gradle @@ -0,0 +1 @@ +rootProject.name = "myapp" diff --git a/samples/gradle-java-jdk8-x-jre11-custom-debian/src/gradle/jar.gradle b/samples/gradle-java-jdk8-x-jre11-custom-debian/src/gradle/jar.gradle new file mode 100644 index 0000000..0b06acd --- /dev/null +++ b/samples/gradle-java-jdk8-x-jre11-custom-debian/src/gradle/jar.gradle @@ -0,0 +1,4 @@ +bootJar { + baseName = rootProject.name + version = project.version +} diff --git a/samples/gradle-java-jdk8-x-jre11-custom-debian/src/gradle/processResources.gradle b/samples/gradle-java-jdk8-x-jre11-custom-debian/src/gradle/processResources.gradle new file mode 100644 index 0000000..b9cc58b --- /dev/null +++ b/samples/gradle-java-jdk8-x-jre11-custom-debian/src/gradle/processResources.gradle @@ -0,0 +1,23 @@ +// https://dzone.com/articles/resource-filtering-gradle +import org.apache.tools.ant.filters.* + +// Expose the commit and branch values for the resources below +ext { + time = new Date().format("yyyy-MM-dd-HH:mm:ss-z", TimeZone.getTimeZone('UTC')) + version = project.version +} + +processResources { + filter ReplaceTokens, tokens: [ + "build.time": time, + "build.version": version + ] +} + +// Process resources when compiling +compileJava.dependsOn(processResources) // added for spring-boot-configuration-processor + +// Include the processResources when running "gradle bootRun" +bootJar { + launchScript() +} diff --git a/samples/gradle-java-jdk8-x-jre11-custom-debian/src/main/java/hello/Application.java b/samples/gradle-java-jdk8-x-jre11-custom-debian/src/main/java/hello/Application.java new file mode 100644 index 0000000..8055ad0 --- /dev/null +++ b/samples/gradle-java-jdk8-x-jre11-custom-debian/src/main/java/hello/Application.java @@ -0,0 +1,30 @@ +package hello; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.context.properties.EnableConfigurationProperties; + +@SpringBootApplication +@RestController +@EnableConfigurationProperties +public class Application { + + @Value("${app.name}") + private String name; + + @Value("${app.description}") + private String description; + + @RequestMapping("/") + public String home() { + return "Hello Docker World from " + this.name + ": " + this.description; + } + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + +} diff --git a/samples/gradle-java-jdk8-x-jre11-custom-debian/src/main/java/hello/util/BuildInfo.java b/samples/gradle-java-jdk8-x-jre11-custom-debian/src/main/java/hello/util/BuildInfo.java new file mode 100644 index 0000000..7530aa4 --- /dev/null +++ b/samples/gradle-java-jdk8-x-jre11-custom-debian/src/main/java/hello/util/BuildInfo.java @@ -0,0 +1,45 @@ +package hello.util; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.context.properties.ConfigurationProperties; +import javax.annotation.PostConstruct; +import org.springframework.stereotype.Component; + +@Component +@ConfigurationProperties(prefix="build") +public class BuildInfo { + + private String commit; + + private String branch; + + private String time; + + private String version; + + public void setCommit(String commit) { + this.commit = commit; + } + + public void setBranch(String branch) { + this.branch = branch; + } + + public void setTime(String time) { + this.time = time; + } + + public void setVersion(String version) { + this.version = version; + } + + @PostConstruct + public void initIt() throws Exception { + System.out.println("INITIALIZED : " + this); + } + + @Override + public String toString() { + return "commit=" + commit + ";branch=" + branch + ";time=" + time + ";version=" + version; + } +} diff --git a/samples/gradle-java-jdk8-x-jre11-custom-debian/src/main/java/hello/util/DefaultResponseFilter.java b/samples/gradle-java-jdk8-x-jre11-custom-debian/src/main/java/hello/util/DefaultResponseFilter.java new file mode 100644 index 0000000..ff48f36 --- /dev/null +++ b/samples/gradle-java-jdk8-x-jre11-custom-debian/src/main/java/hello/util/DefaultResponseFilter.java @@ -0,0 +1,37 @@ +package hello.util; + +import java.io.IOException; +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletResponse; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class DefaultResponseFilter implements Filter { + + @Autowired + private BuildInfo buildInfo; + + @Override + public void destroy() {} + + @Override + public void init(FilterConfig arg0) throws ServletException {} + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException { + + HttpServletResponse res = (HttpServletResponse)response; + res.setHeader("X-App-Build-Info", buildInfo.toString()); + + chain.doFilter(request, res); + + } + +} diff --git a/samples/gradle-java-jdk8-x-jre11-custom-debian/src/main/resources/application-dev.yml b/samples/gradle-java-jdk8-x-jre11-custom-debian/src/main/resources/application-dev.yml new file mode 100644 index 0000000..9c73229 --- /dev/null +++ b/samples/gradle-java-jdk8-x-jre11-custom-debian/src/main/resources/application-dev.yml @@ -0,0 +1,2 @@ +app: + description: Environment for development diff --git a/samples/gradle-java-jdk8-x-jre11-custom-debian/src/main/resources/application-prd.yml b/samples/gradle-java-jdk8-x-jre11-custom-debian/src/main/resources/application-prd.yml new file mode 100644 index 0000000..12f7f7e --- /dev/null +++ b/samples/gradle-java-jdk8-x-jre11-custom-debian/src/main/resources/application-prd.yml @@ -0,0 +1,2 @@ +app: + description: Environment for production diff --git a/samples/gradle-java-jdk8-x-jre11-custom-debian/src/main/resources/application.yml b/samples/gradle-java-jdk8-x-jre11-custom-debian/src/main/resources/application.yml new file mode 100644 index 0000000..c796125 --- /dev/null +++ b/samples/gradle-java-jdk8-x-jre11-custom-debian/src/main/resources/application.yml @@ -0,0 +1,7 @@ +app: + name: My App + description: Default profile + +build: + version: "@build.version@" + time: "@build.time@" diff --git a/samples/gradle-java-jdk8-x-jre11-custom/.dockerignore b/samples/gradle-java-jdk8-x-jre11-custom/.dockerignore new file mode 100644 index 0000000..38aeebd --- /dev/null +++ b/samples/gradle-java-jdk8-x-jre11-custom/.dockerignore @@ -0,0 +1,6 @@ +.gitignore +docker-compose.yaml +Dockerfile +mvnw +mvnw.cmd +README.md diff --git a/samples/gradle-java-jdk8-x-jre11-custom/Dockerfile b/samples/gradle-java-jdk8-x-jre11-custom/Dockerfile new file mode 100644 index 0000000..70d0811 --- /dev/null +++ b/samples/gradle-java-jdk8-x-jre11-custom/Dockerfile @@ -0,0 +1,29 @@ +### Builder Arguments +ARG UNMAZEDBOOT_BUILDER_GIT_SHA=${UNMAZEDBOOT_BUILDER_GIT_SHA:-000000} +ARG UNMAZEDBOOT_BUILDER_GIT_BRANCH=${UNMAZEDBOOT_BUILDER_GIT_BRANCH:-master} +ARG UNMAZEDBOOT_BUILDER_GRADLE_BUILD_CMD="gradle build -x test" +ARG UNMAZEDBOOT_BUILDER_DIR="build/libs" +ARG UNMAZEDBOOT_BUILDER_PACKAGE_EXTENSION="jar" +ARG UNMAZEDBOOT_BUILDER_GRADLE_VERSION=${UNMAZEDBOOT_BUILDER_GRADLE_VERSION:--latest} + +### Linker Argumentss +ARG UNMAZEDBOOT_LINKER_VERSION=${UNMAZEDBOOT_LINKER_VERSION:--latest} + +### Runner Arguments +ARG UNMAZEDBOOT_RUNNER_PORT="8080" +ARG UNMAZEDBOOT_RUNNER_VERSION=${UNMAZEDBOOT_RUNNER_VERSION:--latest} + +# ##################################################################### +# Build stage for building the target directory before running tests +# ##################################################################### +FROM intuit/unmazedboot-builder-gradle:4.10.2-jdk8-alpine${UNMAZEDBOOT_BUILDER_GRADLE_VERSION} as unmazedboot-builder-artifacts + +# ##################################################################### +# Build stage for making a jlink specific for the app +# ##################################################################### +FROM intuit/unmazedboot-linker:jdk11-alpine${UNMAZEDBOOT_LINKER_VERSION} as unmazedboot-jdk-linker + +# ##################################################################### +# Build stage for running the runtime image (MUST MATCH LINKER TYPE) +# ##################################################################### +FROM intuit/unmazedboot-runner:custom-jdk-alpine3.8${UNMAZEDBOOT_RUNNER_VERSION} diff --git a/samples/gradle-java-jdk8-x-jre11-custom/README.md b/samples/gradle-java-jdk8-x-jre11-custom/README.md new file mode 100644 index 0000000..9a149dc --- /dev/null +++ b/samples/gradle-java-jdk8-x-jre11-custom/README.md @@ -0,0 +1,368 @@ +# Running + +* Using SpringBoot 2.0.3 +* Using Starter Web + +## BootRun + +* Uses `build.gradle` +* Run with `bootRun` default profile + +``` +gradle bootRun +``` + +* Run with `bootRun` with `dev` profile + +``` +SPRING_PROFILES_ACTIVE=dev gradle bootRun +``` + +## Docker Container + +* Uses the `Dockerfile` +* Build a Docker Image default arguments + +``` +$ docker build -t myapp . +Sending build context to Docker daemon 20.23MB +Step 1/7 : ARG GIT_SHA=${GIT_SHA:-0101010} +Step 2/7 : ARG GIT_BRANCH=${GIT_BRANCH:-develop} +Step 3/7 : ARG BUILD_NUMBER=${BUILD_NUMBER:-0223} +Step 4/7 : ARG GRADLE_BUILD_TASKS="build -x test" +Step 5/7 : ARG EXECUTABLE_TASK_TYPE="jar" +Step 6/7 : FROM marcellodesales/springboot-builder as unmazedboot-builder-artifacts + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Running in 6b7c60c82fa1 +Will execute gradle downloadDependencies +Removing intermediate container 6b7c60c82fa1 + ---> Running in 44f6a573e60e + +Welcome to Gradle 4.10.1! + +Here are the highlights of this release: + - Incremental Java compilation by default + - Periodic Gradle caches cleanup + - Gradle Kotlin DSL 1.0-RC6 + - Nested included builds + - SNAPSHOT plugin versions in the `plugins {}` block + +For more details see https://docs.gradle.org/4.10.1/release-notes.html + +Starting a Gradle Daemon (subsequent builds will be faster) + +> Task :downloadDependencies + +Retrieving dependencies for annotationProcessor + +.. +.. + +Retrieving dependencies for testRuntimeOnly + +BUILD SUCCESSFUL in 14s +1 actionable task: 1 executed +Removing intermediate container 44f6a573e60e + ---> Running in 40a596327554 +Will execute gradle build -x test +Removing intermediate container 40a596327554 + ---> Running in 8642c9c067f4 + +Welcome to Gradle 4.10.1! + +Here are the highlights of this release: + - Incremental Java compilation by default + - Periodic Gradle caches cleanup + - Gradle Kotlin DSL 1.0-RC6 + - Nested included builds + - SNAPSHOT plugin versions in the `plugins {}` block + +For more details see https://docs.gradle.org/4.10.1/release-notes.html + +Starting a Gradle Daemon (subsequent builds will be faster) +> Task :compileJava +> Task :processResources +> Task :classes +> Task :bootJar +> Task :jar SKIPPED +> Task :assemble +> Task :check +> Task :build + +BUILD SUCCESSFUL in 20s +3 actionable tasks: 3 executed +Removing intermediate container 8642c9c067f4 + ---> 405621119bcf +Step 7/7 : FROM marcellodesales/springboot-executable-runner + ---> Using cache + ---> Using cache + ---> Using cache + ---> Running in 46cb7cebdf3b +-rw-r--r-- 1 root root 16141378 Sep 16 23:16 /tmp/myapp-0.1.0.jar +Removing intermediate container 46cb7cebdf3b + ---> Running in b47bfaf3a78d +Will copy from /app/src/main/resources /runtime/resources +Removing intermediate container b47bfaf3a78d + ---> Running in cc5b00fe7dad +total 20 +drwxr-xr-x 2 root root 4096 Sep 16 23:17 . +drwxr-xr-x 1 root root 4096 Sep 16 23:17 .. +-rw-r--r-- 1 root root 48 Sep 16 23:12 application-dev.yml +-rw-r--r-- 1 root root 47 Sep 16 23:12 application-prd.yml +-rw-r--r-- 1 root root 51 Sep 16 23:12 application.yml +Removing intermediate container cc5b00fe7dad + ---> Running in 40a70b1e8304 +Renaming the executable jar to the runtime dir +Removing intermediate container 40a70b1e8304 + ---> Running in 3d3eea4bdd5c +Removing intermediate container 3d3eea4bdd5c + ---> 89923a61a08c +Successfully built 89923a61a08c +Successfully tagged myapp:latest +``` + +* Running in the `dev` profile + * Loads the file `application-dev.yml` + * The logs will be showing `The following profiles are active: dev` + +``` +$ docker run -ti -e SPRING_PROFILES_ACTIVE=dev -p 8080:8080 myapp + + . ____ _ __ _ _ + /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ +( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ + \\/ ___)| |_)| | | | | || (_| | ) ) ) ) + ' |____| .__|_| |_|_| |_\__, | / / / / + =========|_|==============|___/=/_/_/_/ + :: Spring Boot :: (v2.0.3.RELEASE) + +2018-09-16 23:17:50.719 INFO 9 --- [ main] hello.Application : Starting Application on 44fb9b4347d6 with PID 9 (/runtime/server.jar started by root in /runtime) +2018-09-16 23:17:50.725 INFO 9 --- [ main] hello.Application : The following profiles are active: dev +2018-09-16 23:17:50.820 INFO 9 --- [ main] ConfigServletWebServerApplicationContext : Refreshing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@6833ce2c: startup date [Sun Sep 16 23:17:50 UTC 2018]; root of context hierarchy +2018-09-16 23:17:52.445 INFO 9 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http) +``` + +## Validating + +``` +curl localhost:8080 +Hello Docker World from My App: Environment for development% +``` + +## Docker Build Args + +``` +docker build -t myapp --build-arg GIT_SHA=$(git rev-parse HEAD) \ + --build-arg GIT_BRANCH=$(git rev-parse --abbrev-ref --symbolic HEAD) \ + --build-arg BUILD_NUMBER=1234 . +``` + +# Sample Features + +## Response Filter with Build Info + +* Build with build information while running + +``` +GIT_SHA=$(git rev-parse HEAD) \ +GIT_BRANCH=$(git rev-parse --abbrev-ref --symbolic HEAD) \ +BUILD_TAG=$USER \ +gradle clean bootRun +``` + +* HTTP Response Headers filters + +``` +$ curl -i localhost:8080 +HTTP/1.1 200 +X-App-Build-Info: commit=486223a73d435c778ac2ef93b68ee637652ee370;branch=feature/sample/show-build-info-all-response-headers;tag=mdesales;time=2018-09-17-05:32:07-UTC;version=0.1.0 +Content-Type: text/plain;charset=UTF-8 +Content-Length: 47 +Date: Mon, 17 Sep 2018 05:32:12 GMT + +Hello Docker World from My App: Default profile% +``` + +## Verification with Docker Containers + + +* Build the docker image with the arguments + +``` +$ docker build -t sample --build-arg BUILDER_GIT_SHA=$(git rev-parse HEAD) --build-arg BUILDER_GIT_BRANCH=$(git rev-parse --abbrev-ref --symbolic HEAD) --build-arg BUILDER_BUILD_NUMBER=$USER . +Sending build context to Docker daemon 4.205MB +Step 1/10 : ARG BUILDER_GIT_SHA=${GIT_SHA:-0101010} +Step 2/10 : ARG BUILDER_GIT_BRANCH=${GIT_BRANCH:-develop} +Step 3/10 : ARG BUILDER_BUILD_NUMBER=${BUILD_NUMBER:-0223} +Step 4/10 : ARG BUILDER_GRADLE_DOWNLOAD_DEPENDENCIES_CMD="gradle downloadDependencies" +Step 5/10 : ARG BUILDER_GRADLE_BUILD_CMD="gradle build -x test" +Step 6/10 : ARG BUILDER_DIR="build/libs" +Step 7/10 : ARG UNMAZEDBOOT_BUILDER_PACKAGE_EXTENSION="jar" +Step 8/10 : ARG RUNNER_PORT="8080" +Step 9/10 : FROM marcellodesales/springboot-builder:gradle-4.10.1-jdk-8 as unmazedboot-builder-artifacts +# Executing 15 build triggers + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Running in fa0d5676f667 +Removing intermediate container fa0d5676f667 + ---> Running in c8633ef774b5 +Removing intermediate container c8633ef774b5 + ---> Running in 34de329e478d +Executing BUILDER_GRADLE_DOWNLOAD_DEPENDENCIES_CMD='gradle downloadDependencies' +Removing intermediate container 34de329e478d + ---> Running in 9d9642a2dacf + +Welcome to Gradle 4.10.1! + +Here are the highlights of this release: + - Incremental Java compilation by default + - Periodic Gradle caches cleanup + - Gradle Kotlin DSL 1.0-RC6 + - Nested included builds + - SNAPSHOT plugin versions in the `plugins {}` block + +For more details see https://docs.gradle.org/4.10.1/release-notes.html + +Starting a Gradle Daemon (subsequent builds will be faster) + +> Task :downloadDependencies + +Retrieving dependencies for annotationProcessor + +... +... + +Retrieving dependencies for testRuntimeOnly + + +BUILD SUCCESSFUL in 25s +1 actionable task: 1 executed +Removing intermediate container 9d9642a2dacf + ---> Running in 9d8c260964ec +Executing BUILDER_GRADLE_BUILD_CMD='gradle build -x test' +Removing intermediate container 9d8c260964ec + ---> Running in a628ad0694c1 + +Welcome to Gradle 4.10.1! + +Here are the highlights of this release: + - Incremental Java compilation by default + - Periodic Gradle caches cleanup + - Gradle Kotlin DSL 1.0-RC6 + - Nested included builds + - SNAPSHOT plugin versions in the `plugins {}` block + +For more details see https://docs.gradle.org/4.10.1/release-notes.html + +Starting a Gradle Daemon (subsequent builds will be faster) +> Task :processResources +> Task :compileJava +> Task :classes +> Task :bootJar +> Task :jar SKIPPED +> Task :assemble +> Task :check +> Task :build + +BUILD SUCCESSFUL in 27s +3 actionable tasks: 3 executed +Removing intermediate container a628ad0694c1 + ---> ff3d11b8f007 +Step 10/10 : FROM marcellodesales/springboot-runner:openjdk-8-jre-slim +# Executing 15 build triggers + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Running in f028ec130c35 +-rwxr--r-- 1 root root 16151787 Sep 17 05:43 /tmp/myapp-0.1.0.jar +Removing intermediate container f028ec130c35 + ---> Running in fdd68c834c82 +Will copy from /app/src/main/resources /runtime/resources +Removing intermediate container fdd68c834c82 + ---> Running in 712af509ad8c +total 20 +drwxr-xr-x 2 root root 4096 Sep 17 05:43 . +drwxr-xr-x 1 root root 4096 Sep 17 05:43 .. +-rw-r--r-- 1 root root 48 Sep 16 23:32 application-dev.yml +-rw-r--r-- 1 root root 47 Sep 16 23:32 application-prd.yml +-rw-r--r-- 1 root root 185 Sep 17 05:14 application.yml +Removing intermediate container 712af509ad8c + ---> Running in a0d64b1c78e0 +Renaming the executable jar to the runtime dir +Removing intermediate container a0d64b1c78e0 + ---> Running in 65b7521b34eb +Removing intermediate container 65b7521b34eb + ---> Running in 3689b3c4ad9d +Removing intermediate container 3689b3c4ad9d + ---> f8c20d9b537e +Successfully built f8c20d9b537e +Successfully tagged sample:latest +``` + +* Run the container + * Note that you need to bind the host's port to the one from the container. + * The end of the output confirms the server is running with the port displayed. + +``` +$ docker run -ti -p 8080:8080 sample + + . ____ _ __ _ _ + /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ +( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ + \\/ ___)| |_)| | | | | || (_| | ) ) ) ) + ' |____| .__|_| |_|_| |_\__, | / / / / + =========|_|==============|___/=/_/_/_/ + :: Spring Boot :: (v2.0.3.RELEASE) + +2018-09-17 05:46:23.906 INFO 9 --- [ main] hello.Application : Starting Application on adab7dc7946f with PID 9 (/runtime/server.jar started by root in /runtime) +2018-09-17 05:46:23.918 INFO 9 --- [ main] hello.Application : No active profile set, falling back to default profiles: default +2018-09-17 05:46:24.089 INFO 9 --- [ main] ConfigServletWebServerApplicationContext : Refreshing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@5b1d2887: startup date [Mon Sep 17 05:46:24 UTC 2018]; root of context hierarchy +2018-09-17 05:46:25.929 INFO 9 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http) +2018-09-17 05:46:25.974 INFO 9 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] +2018-09-17 05:46:25.975 INFO 9 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/8.5.31 +2018-09-17 05:46:25.994 INFO 9 --- [ost-startStop-1] o.a.catalina.core.AprLifecycleListener : The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: [/usr/java/packages/lib/amd64:/usr/lib/x86_64-linux-gnu/jni:/lib/x86_64-linux-gnu:/usr/lib/x86_64-linux-gnu:/usr/lib/jni:/lib:/usr/lib] +2018-09-17 05:46:26.130 INFO 9 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext +2018-09-17 05:46:26.131 INFO 9 --- [ost-startStop-1] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 2047 ms +2018-09-17 05:46:26.325 INFO 9 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean : Servlet dispatcherServlet mapped to [/] +2018-09-17 05:46:26.331 INFO 9 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'characterEncodingFilter' to: [/*] +2018-09-17 05:46:26.332 INFO 9 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'hiddenHttpMethodFilter' to: [/*] +2018-09-17 05:46:26.332 INFO 9 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'httpPutFormContentFilter' to: [/*] +2018-09-17 05:46:26.333 INFO 9 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'requestContextFilter' to: [/*] +2018-09-17 05:46:26.333 INFO 9 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'defaultResponseFilter' to: [/*] +2018-09-17 05:46:26.556 INFO 9 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] +2018-09-17 05:46:26.932 INFO 9 --- [ main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@5b1d2887: startup date [Mon Sep 17 05:46:24 UTC 2018]; root of context hierarchy +2018-09-17 05:46:27.060 INFO 9 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/]}" onto public java.lang.String hello.Application.home() +2018-09-17 05:46:27.069 INFO 9 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse) +2018-09-17 05:46:27.071 INFO 9 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity> org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.error(javax.servlet.http.HttpServletRequest) +2018-09-17 05:46:27.123 INFO 9 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] +2018-09-17 05:46:27.124 INFO 9 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] +2018-09-17 05:46:27.388 INFO 9 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup +2018-09-17 05:46:27.459 INFO 9 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path '' +2018-09-17 05:46:27.471 INFO 9 --- [ main] hello.Application : Started Application in 4.275 seconds (JVM running for 4.926) +``` + +* Make the call to the server + * Note tha the TAG here is different because the Dockerfile overrides the `BUILD_TAG` value! + +``` +$ curl -i localhost:8080 +HTTP/1.1 200 +X-App-Build-Info: commit=d02650d801f8fc5db7ed0cc92422f897df3a0f4b;branch=feature/sample/show-build-info-all-response-headers;tag=sha:d02650d801f8fc5db7ed0cc92422f897df3a0f4b,build:feature/sample/show-build-info-all-response-headers/mdesales;time=2018-09-17-05:43:19-UTC;version=0.1.0 +Content-Type: text/plain;charset=UTF-8 +Content-Length: 47 +Date: Mon, 17 Sep 2018 05:44:10 GMT + +Hello Docker World from My App: Default profile% +``` diff --git a/samples/gradle-java-jdk8-x-jre11-custom/build.gradle b/samples/gradle-java-jdk8-x-jre11-custom/build.gradle new file mode 100644 index 0000000..2369a3b --- /dev/null +++ b/samples/gradle-java-jdk8-x-jre11-custom/build.gradle @@ -0,0 +1,32 @@ +// Group and version (used by jar) +group = 'hello' +version = '0.1.0' + +buildscript { + repositories { + mavenCentral() + } + dependencies { + classpath("org.springframework.boot:spring-boot-gradle-plugin:2.0.3.RELEASE") + } +} + +apply plugin: 'java' +apply plugin: 'eclipse' +apply plugin: 'org.springframework.boot' +apply plugin: 'io.spring.dependency-management' + +apply from: 'src/gradle/jar.gradle' +apply from: 'src/gradle/processResources.gradle' + +repositories { + mavenCentral() +} + +sourceCompatibility = 1.8 +targetCompatibility = 1.8 + +dependencies { + compile("org.springframework.boot:spring-boot-starter-web") + testCompile("org.springframework.boot:spring-boot-starter-test") +} diff --git a/samples/gradle-java-jdk8-x-jre11-custom/settings.gradle b/samples/gradle-java-jdk8-x-jre11-custom/settings.gradle new file mode 100644 index 0000000..bebf3f4 --- /dev/null +++ b/samples/gradle-java-jdk8-x-jre11-custom/settings.gradle @@ -0,0 +1 @@ +rootProject.name = "myapp" diff --git a/samples/gradle-java-jdk8-x-jre11-custom/src/gradle/jar.gradle b/samples/gradle-java-jdk8-x-jre11-custom/src/gradle/jar.gradle new file mode 100644 index 0000000..0b06acd --- /dev/null +++ b/samples/gradle-java-jdk8-x-jre11-custom/src/gradle/jar.gradle @@ -0,0 +1,4 @@ +bootJar { + baseName = rootProject.name + version = project.version +} diff --git a/samples/gradle-java-jdk8-x-jre11-custom/src/gradle/processResources.gradle b/samples/gradle-java-jdk8-x-jre11-custom/src/gradle/processResources.gradle new file mode 100644 index 0000000..b9cc58b --- /dev/null +++ b/samples/gradle-java-jdk8-x-jre11-custom/src/gradle/processResources.gradle @@ -0,0 +1,23 @@ +// https://dzone.com/articles/resource-filtering-gradle +import org.apache.tools.ant.filters.* + +// Expose the commit and branch values for the resources below +ext { + time = new Date().format("yyyy-MM-dd-HH:mm:ss-z", TimeZone.getTimeZone('UTC')) + version = project.version +} + +processResources { + filter ReplaceTokens, tokens: [ + "build.time": time, + "build.version": version + ] +} + +// Process resources when compiling +compileJava.dependsOn(processResources) // added for spring-boot-configuration-processor + +// Include the processResources when running "gradle bootRun" +bootJar { + launchScript() +} diff --git a/samples/gradle-java-jdk8-x-jre11-custom/src/main/java/hello/Application.java b/samples/gradle-java-jdk8-x-jre11-custom/src/main/java/hello/Application.java new file mode 100644 index 0000000..8055ad0 --- /dev/null +++ b/samples/gradle-java-jdk8-x-jre11-custom/src/main/java/hello/Application.java @@ -0,0 +1,30 @@ +package hello; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.context.properties.EnableConfigurationProperties; + +@SpringBootApplication +@RestController +@EnableConfigurationProperties +public class Application { + + @Value("${app.name}") + private String name; + + @Value("${app.description}") + private String description; + + @RequestMapping("/") + public String home() { + return "Hello Docker World from " + this.name + ": " + this.description; + } + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + +} diff --git a/samples/gradle-java-jdk8-x-jre11-custom/src/main/java/hello/util/BuildInfo.java b/samples/gradle-java-jdk8-x-jre11-custom/src/main/java/hello/util/BuildInfo.java new file mode 100644 index 0000000..7530aa4 --- /dev/null +++ b/samples/gradle-java-jdk8-x-jre11-custom/src/main/java/hello/util/BuildInfo.java @@ -0,0 +1,45 @@ +package hello.util; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.context.properties.ConfigurationProperties; +import javax.annotation.PostConstruct; +import org.springframework.stereotype.Component; + +@Component +@ConfigurationProperties(prefix="build") +public class BuildInfo { + + private String commit; + + private String branch; + + private String time; + + private String version; + + public void setCommit(String commit) { + this.commit = commit; + } + + public void setBranch(String branch) { + this.branch = branch; + } + + public void setTime(String time) { + this.time = time; + } + + public void setVersion(String version) { + this.version = version; + } + + @PostConstruct + public void initIt() throws Exception { + System.out.println("INITIALIZED : " + this); + } + + @Override + public String toString() { + return "commit=" + commit + ";branch=" + branch + ";time=" + time + ";version=" + version; + } +} diff --git a/samples/gradle-java-jdk8-x-jre11-custom/src/main/java/hello/util/DefaultResponseFilter.java b/samples/gradle-java-jdk8-x-jre11-custom/src/main/java/hello/util/DefaultResponseFilter.java new file mode 100644 index 0000000..ff48f36 --- /dev/null +++ b/samples/gradle-java-jdk8-x-jre11-custom/src/main/java/hello/util/DefaultResponseFilter.java @@ -0,0 +1,37 @@ +package hello.util; + +import java.io.IOException; +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletResponse; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class DefaultResponseFilter implements Filter { + + @Autowired + private BuildInfo buildInfo; + + @Override + public void destroy() {} + + @Override + public void init(FilterConfig arg0) throws ServletException {} + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException { + + HttpServletResponse res = (HttpServletResponse)response; + res.setHeader("X-App-Build-Info", buildInfo.toString()); + + chain.doFilter(request, res); + + } + +} diff --git a/samples/gradle-java-jdk8-x-jre11-custom/src/main/resources/application-dev.yml b/samples/gradle-java-jdk8-x-jre11-custom/src/main/resources/application-dev.yml new file mode 100644 index 0000000..9c73229 --- /dev/null +++ b/samples/gradle-java-jdk8-x-jre11-custom/src/main/resources/application-dev.yml @@ -0,0 +1,2 @@ +app: + description: Environment for development diff --git a/samples/gradle-java-jdk8-x-jre11-custom/src/main/resources/application-prd.yml b/samples/gradle-java-jdk8-x-jre11-custom/src/main/resources/application-prd.yml new file mode 100644 index 0000000..12f7f7e --- /dev/null +++ b/samples/gradle-java-jdk8-x-jre11-custom/src/main/resources/application-prd.yml @@ -0,0 +1,2 @@ +app: + description: Environment for production diff --git a/samples/gradle-java-jdk8-x-jre11-custom/src/main/resources/application.yml b/samples/gradle-java-jdk8-x-jre11-custom/src/main/resources/application.yml new file mode 100644 index 0000000..c796125 --- /dev/null +++ b/samples/gradle-java-jdk8-x-jre11-custom/src/main/resources/application.yml @@ -0,0 +1,7 @@ +app: + name: My App + description: Default profile + +build: + version: "@build.version@" + time: "@build.time@" diff --git a/samples/gradle-kotlin-jdk8-jre8/.gitignore b/samples/gradle-kotlin-jdk8-jre8/.gitignore new file mode 100644 index 0000000..9243c63 --- /dev/null +++ b/samples/gradle-kotlin-jdk8-jre8/.gitignore @@ -0,0 +1,26 @@ +.gradle +/build/ +!gradle/wrapper/gradle-wrapper.jar + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr +/out/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ \ No newline at end of file diff --git a/samples/gradle-kotlin-jdk8-jre8/Dockerfile b/samples/gradle-kotlin-jdk8-jre8/Dockerfile new file mode 100644 index 0000000..0c44853 --- /dev/null +++ b/samples/gradle-kotlin-jdk8-jre8/Dockerfile @@ -0,0 +1,24 @@ +### Builder Arguments +ARG UNMAZEDBOOT_BUILDER_GIT_SHA=${UNMAZEDBOOT_BUILDER_GIT_SHA:-000000} +ARG UNMAZEDBOOT_BUILDER_GIT_BRANCH=${UNMAZEDBOOT_BUILDER_GIT_BRANCH:-master} +ARG UNMAZEDBOOT_BUILDER_GRADLE_BUILD_CMD="gradle build -x test" +ARG UNMAZEDBOOT_BUILDER_DIR="build/libs" +ARG UNMAZEDBOOT_BUILDER_PACKAGE_EXTENSION="jar" +ARG UNMAZEDBOOT_BUILDER_GRADLE_VERSION=${UNMAZEDBOOT_BUILDER_GRADLE_VERSION:--latest} + +### Runner Arguments +ARG UNMAZEDBOOT_RUNNER_PORT="8080" +ARG UNMAZEDBOOT_RUNNER_VERSION=${UNMAZEDBOOT_RUNNER_VERSION:--latest} + +# ##################################################################### +# Build stage for building the target directory before running tests +# ##################################################################### +FROM intuit/unmazedboot-builder-gradle:4.10.2-jdk8-alpine${UNMAZEDBOOT_BUILDER_GRADLE_VERSION} as unmazedboot-builder-artifacts + +# ##################################################################### +# Build stage for running the runtime image +# ##################################################################### +FROM intuit/unmazedboot-runner:openjdk-8u181-debian9-slim${UNMAZEDBOOT_RUNNER_VERSION} + +# The image depends on the built artifacts by the stage +# Add init scripts that are executed before the app starts diff --git a/samples/gradle-kotlin-jdk8-jre8/README.md b/samples/gradle-kotlin-jdk8-jre8/README.md new file mode 100644 index 0000000..0076dd3 --- /dev/null +++ b/samples/gradle-kotlin-jdk8-jre8/README.md @@ -0,0 +1,174 @@ +# Kotlin JDK 1.8 - JRE 1.8 sample + +* This sample code was created by following the initial steps of +the tutorial https://spring.io/guides/tutorials/spring-boot-kotlin/ + +# UnmazedBoot Process + +* Dockerfile was added following the UnmazedBoot instructions + +1. Create a Dockerfile selecting the first stage the Builder image + +This step requires the inspection of the build system used and the target JVM instructions used. +For instance, the Kotlin tutorial uses Gradle and JDK8. For this reason, the builder image +selected is using Gradle with JDK8. + +2. If the project is to run in a JRE 8, then select the Runner image with the base OS desired + +Since this tutorial simply runs the application, then we just selected the base image +with JRE8. That simplified the initial process of using the current tutorial. + +# Building + +``` +$ docker-compose -f docker-compose-samples.yml build samples-gradle-kotlin-jdk8-jre8 +Building samples-gradle-kotlin-jdk8-jre8 +Step 1/10 : ARG UNMAZEDBOOT_BUILDER_GIT_SHA=${UNMAZEDBOOT_BUILDER_GIT_SHA:-000000} +Step 2/10 : ARG UNMAZEDBOOT_BUILDER_GIT_BRANCH=${UNMAZEDBOOT_BUILDER_GIT_BRANCH:-master} +Step 3/10 : ARG UNMAZEDBOOT_BUILDER_GRADLE_BUILD_CMD="gradle build -x test" +Step 4/10 : ARG UNMAZEDBOOT_BUILDER_DIR="build/libs" +Step 5/10 : ARG UNMAZEDBOOT_BUILDER_PACKAGE_EXTENSION="jar" +Step 6/10 : ARG UNMAZEDBOOT_BUILDER_GRADLE_VERSION=${UNMAZEDBOOT_BUILDER_GRADLE_VERSION:--latest} +Step 7/10 : ARG UNMAZEDBOOT_RUNNER_PORT="8080" +Step 8/10 : ARG UNMAZEDBOOT_RUNNER_VERSION=${UNMAZEDBOOT_RUNNER_VERSION:--latest} +Step 9/10 : FROM intuit/unmazedboot-builder-gradle:4.10.2-jdk8-alpine${UNMAZEDBOOT_BUILDER_GRADLE_VERSION} as unmazedboot-builder-artifacts +# Executing 18 build triggers + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> e57b60923ea1 + +Step 10/10 : FROM intuit/unmazedboot-runner:openjdk-8u181-debian9-slim${UNMAZEDBOOT_RUNNER_VERSION} +# Executing 35 build triggers + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> 9a527d7584e5 + +Successfully built 9a527d7584e5 +Successfully tagged intuit/unmazedboot-sample-kotlin:jdk8-jre8-debian-0.5.0 +``` + +# Running + +``` +$ docker-compose -f docker-compose-samples.yml up samples-gradle-kotlin-jdk8-jre8 +springboot-docker-reusable-images_samples-gradle-kotlin-jdk8-jre8_1_2541dba0d467 is up-to-date +Attaching to springboot-docker-reusable-images_samples-gradle-kotlin-jdk8-jre8_1_2541dba0d467 +samples-gradle-kotlin-jdk8-jre8_1_2541dba0d467 | +samples-gradle-kotlin-jdk8-jre8_1_2541dba0d467 | => Initializing SpringBoot Runner 'start.sh' +samples-gradle-kotlin-jdk8-jre8_1_2541dba0d467 | +samples-gradle-kotlin-jdk8-jre8_1_2541dba0d467 | ########## Running init scripts at '/runtime/init' +samples-gradle-kotlin-jdk8-jre8_1_2541dba0d467 | +samples-gradle-kotlin-jdk8-jre8_1_2541dba0d467 | +samples-gradle-kotlin-jdk8-jre8_1_2541dba0d467 | ########## Processing source hooks at '/runtime/sources' +samples-gradle-kotlin-jdk8-jre8_1_2541dba0d467 | +samples-gradle-kotlin-jdk8-jre8_1_2541dba0d467 | [1] source /runtime/sources/springboot.sh +samples-gradle-kotlin-jdk8-jre8_1_2541dba0d467 | +samples-gradle-kotlin-jdk8-jre8_1_2541dba0d467 | => Processing JAVA_OPTS hooks at /runtime/java-opts +samples-gradle-kotlin-jdk8-jre8_1_2541dba0d467 | +samples-gradle-kotlin-jdk8-jre8_1_2541dba0d467 | [1] JAVA_OPTS << ./java-opts/docker.opt +samples-gradle-kotlin-jdk8-jre8_1_2541dba0d467 | [2] JAVA_OPTS << ./java-opts/springboot.opt +samples-gradle-kotlin-jdk8-jre8_1_2541dba0d467 | +samples-gradle-kotlin-jdk8-jre8_1_2541dba0d467 | Exporting and merging JAVA_OPTS=-showversion -XshowSettings:vm -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -Djava.security.egd=file:/dev/./urandom +samples-gradle-kotlin-jdk8-jre8_1_2541dba0d467 | +samples-gradle-kotlin-jdk8-jre8_1_2541dba0d467 | ####### Starting the app ####### +samples-gradle-kotlin-jdk8-jre8_1_2541dba0d467 | +samples-gradle-kotlin-jdk8-jre8_1_2541dba0d467 | java $JAVA_OPTS -jar /runtime/server.jar $JAR_OPTS +samples-gradle-kotlin-jdk8-jre8_1_2541dba0d467 | +samples-gradle-kotlin-jdk8-jre8_1_2541dba0d467 | VM settings: +samples-gradle-kotlin-jdk8-jre8_1_2541dba0d467 | Max. Heap Size (Estimated): 2.22G +samples-gradle-kotlin-jdk8-jre8_1_2541dba0d467 | Ergonomics Machine Class: server +samples-gradle-kotlin-jdk8-jre8_1_2541dba0d467 | Using VM: OpenJDK 64-Bit Server VM +samples-gradle-kotlin-jdk8-jre8_1_2541dba0d467 | +samples-gradle-kotlin-jdk8-jre8_1_2541dba0d467 | openjdk version "1.8.0_181" +samples-gradle-kotlin-jdk8-jre8_1_2541dba0d467 | OpenJDK Runtime Environment (build 1.8.0_181-8u181-b13-2~deb9u1-b13) +samples-gradle-kotlin-jdk8-jre8_1_2541dba0d467 | OpenJDK 64-Bit Server VM (build 25.181-b13, mixed mode) +samples-gradle-kotlin-jdk8-jre8_1_2541dba0d467 | +samples-gradle-kotlin-jdk8-jre8_1_2541dba0d467 | +samples-gradle-kotlin-jdk8-jre8_1_2541dba0d467 | . ____ _ __ _ _ +samples-gradle-kotlin-jdk8-jre8_1_2541dba0d467 | /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ +samples-gradle-kotlin-jdk8-jre8_1_2541dba0d467 | ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ +samples-gradle-kotlin-jdk8-jre8_1_2541dba0d467 | \\/ ___)| |_)| | | | | || (_| | ) ) ) ) +samples-gradle-kotlin-jdk8-jre8_1_2541dba0d467 | ' |____| .__|_| |_|_| |_\__, | / / / / +samples-gradle-kotlin-jdk8-jre8_1_2541dba0d467 | =========|_|==============|___/=/_/_/_/ +samples-gradle-kotlin-jdk8-jre8_1_2541dba0d467 | :: Spring Boot :: (v2.1.1.RELEASE) +samples-gradle-kotlin-jdk8-jre8_1_2541dba0d467 | +samples-gradle-kotlin-jdk8-jre8_1_2541dba0d467 | 2019-01-11 20:18:03.997 INFO 19 --- [ main] blog.BlogApplicationKt : Starting BlogApplicationKt on e542c95a93cf with PID 19 (/runtime/server.jar started by root in /runtime) +samples-gradle-kotlin-jdk8-jre8_1_2541dba0d467 | 2019-01-11 20:18:04.007 INFO 19 --- [ main] blog.BlogApplicationKt : No active profile set, falling back to default profiles: default +samples-gradle-kotlin-jdk8-jre8_1_2541dba0d467 | 2019-01-11 20:18:05.090 INFO 19 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data repositories in DEFAULT mode. +samples-gradle-kotlin-jdk8-jre8_1_2541dba0d467 | 2019-01-11 20:18:05.139 INFO 19 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 29ms. Found 0 repository interfaces. +samples-gradle-kotlin-jdk8-jre8_1_2541dba0d467 | 2019-01-11 20:18:05.888 INFO 19 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration' of type [org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration$$EnhancerBySpringCGLIB$$2d61bec0] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying) +samples-gradle-kotlin-jdk8-jre8_1_2541dba0d467 | 2019-01-11 20:18:06.612 INFO 19 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http) +samples-gradle-kotlin-jdk8-jre8_1_2541dba0d467 | 2019-01-11 20:18:06.655 INFO 19 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] +samples-gradle-kotlin-jdk8-jre8_1_2541dba0d467 | 2019-01-11 20:18:06.655 INFO 19 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/9.0.13 +samples-gradle-kotlin-jdk8-jre8_1_2541dba0d467 | 2019-01-11 20:18:06.676 INFO 19 --- [ main] o.a.catalina.core.AprLifecycleListener : The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: [/usr/java/packages/lib/amd64:/usr/lib/x86_64-linux-gnu/jni:/lib/x86_64-linux-gnu:/usr/lib/x86_64-linux-gnu:/usr/lib/jni:/lib:/usr/lib] +samples-gradle-kotlin-jdk8-jre8_1_2541dba0d467 | 2019-01-11 20:18:06.841 INFO 19 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext +samples-gradle-kotlin-jdk8-jre8_1_2541dba0d467 | 2019-01-11 20:18:06.842 INFO 19 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 2741 ms +samples-gradle-kotlin-jdk8-jre8_1_2541dba0d467 | 2019-01-11 20:18:07.089 INFO 19 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting... +samples-gradle-kotlin-jdk8-jre8_1_2541dba0d467 | 2019-01-11 20:18:07.292 INFO 19 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed. +samples-gradle-kotlin-jdk8-jre8_1_2541dba0d467 | 2019-01-11 20:18:07.402 INFO 19 --- [ main] o.hibernate.jpa.internal.util.LogHelper : HHH000204: Processing PersistenceUnitInfo [ +samples-gradle-kotlin-jdk8-jre8_1_2541dba0d467 | name: default +samples-gradle-kotlin-jdk8-jre8_1_2541dba0d467 | ...] +samples-gradle-kotlin-jdk8-jre8_1_2541dba0d467 | 2019-01-11 20:18:07.527 INFO 19 --- [ main] org.hibernate.Version : HHH000412: Hibernate Core {5.3.7.Final} +samples-gradle-kotlin-jdk8-jre8_1_2541dba0d467 | 2019-01-11 20:18:07.529 INFO 19 --- [ main] org.hibernate.cfg.Environment : HHH000206: hibernate.properties not found +samples-gradle-kotlin-jdk8-jre8_1_2541dba0d467 | 2019-01-11 20:18:07.833 INFO 19 --- [ main] o.hibernate.annotations.common.Version : HCANN000001: Hibernate Commons Annotations {5.0.4.Final} +samples-gradle-kotlin-jdk8-jre8_1_2541dba0d467 | 2019-01-11 20:18:08.222 INFO 19 --- [ main] org.hibernate.dialect.Dialect : HHH000400: Using dialect: org.hibernate.dialect.H2Dialect +samples-gradle-kotlin-jdk8-jre8_1_2541dba0d467 | 2019-01-11 20:18:08.609 INFO 19 --- [ main] o.h.t.schema.internal.SchemaCreatorImpl : HHH000476: Executing import script 'org.hibernate.tool.schema.internal.exec.ScriptSourceInputNonExistentImpl@4de4b452' +samples-gradle-kotlin-jdk8-jre8_1_2541dba0d467 | 2019-01-11 20:18:08.617 INFO 19 --- [ main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA# Kotlin JDK 1.8 - JRE 1.8 sample + EntityManagerFactory for persistence unit 'default' +samples-gradle-kotlin-jdk8-jre8_1_2541dba0d467 | 2019-01-11 20:18:09.036 INFO 19 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor' +samples-gradle-kotlin-jdk8-jre8_1_2541dba0d467 | 2019-01-11 20:18:09.113 WARN 19 --- [ main] aWebConfiguration$JpaWebMvcConfiguration : spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning +samples-gradle-kotlin-jdk8-jre8_1_2541dba0d467 | 2019-01-11 20:18:09.562 INFO 19 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path '' +samples-gradle-kotlin-jdk8-jre8_1_2541dba0d467 | 2019-01-11 20:18:09.570 INFO 19 --- [ main] blog.BlogApplicationKt : Started BlogApplicationKt in 6.15 seconds (JVM running for 7.264) +samples-gradle-kotlin-jdk8-jre8_1_2541dba0d467 | 2019-01-11 20:59:47.126 INFO 19 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet' +samples-gradle-kotlin-jdk8-jre8_1_2541dba0d467 | 2019-01-11 20:59:47.136 INFO 19 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet' +samples-gradle-kotlin-jdk8-jre8_1_2541dba0d467 | 2019-01-11 20:59:47.241 INFO 19 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 104 ms +``` diff --git a/samples/gradle-kotlin-jdk8-jre8/build.gradle b/samples/gradle-kotlin-jdk8-jre8/build.gradle new file mode 100644 index 0000000..83a0a69 --- /dev/null +++ b/samples/gradle-kotlin-jdk8-jre8/build.gradle @@ -0,0 +1,54 @@ +buildscript { + ext { + kotlinVersion = '1.2.71' + springBootVersion = '2.1.1.RELEASE' + } + repositories { + mavenCentral() + } + dependencies { + classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") + classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}") + classpath("org.jetbrains.kotlin:kotlin-allopen:${kotlinVersion}") + classpath("org.jetbrains.kotlin:kotlin-noarg:${kotlinVersion}") + } +} + +apply plugin: 'kotlin' +apply plugin: 'kotlin-spring' +apply plugin: 'kotlin-jpa' +apply plugin: 'org.springframework.boot' +apply plugin: 'io.spring.dependency-management' + +group = 'com.example' +version = '0.0.1-SNAPSHOT' +sourceCompatibility = '1.8' + +repositories { + mavenCentral() +} + +dependencies { + implementation 'org.springframework.boot:spring-boot-starter-data-jpa' + implementation 'org.springframework.boot:spring-boot-starter-mustache' + implementation 'org.springframework.boot:spring-boot-starter-web' + implementation 'com.fasterxml.jackson.module:jackson-module-kotlin' + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8" + implementation "org.jetbrains.kotlin:kotlin-reflect" + runtimeOnly 'com.h2database:h2' + testImplementation 'org.springframework.boot:spring-boot-starter-test' +} + +compileKotlin { + kotlinOptions { + freeCompilerArgs = ['-Xjsr305=strict'] + jvmTarget = '1.8' + } +} + +compileTestKotlin { + kotlinOptions { + freeCompilerArgs = ['-Xjsr305=strict'] + jvmTarget = '1.8' + } +} diff --git a/samples/gradle-kotlin-jdk8-jre8/settings.gradle b/samples/gradle-kotlin-jdk8-jre8/settings.gradle new file mode 100644 index 0000000..0a383dd --- /dev/null +++ b/samples/gradle-kotlin-jdk8-jre8/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'demo' diff --git a/samples/gradle-kotlin-jdk8-jre8/src/main/kotlin/blog/BlogApplication.kt b/samples/gradle-kotlin-jdk8-jre8/src/main/kotlin/blog/BlogApplication.kt new file mode 100644 index 0000000..9f0915d --- /dev/null +++ b/samples/gradle-kotlin-jdk8-jre8/src/main/kotlin/blog/BlogApplication.kt @@ -0,0 +1,12 @@ +package blog + +import org.springframework.boot.autoconfigure.SpringBootApplication +import org.springframework.boot.runApplication + +@SpringBootApplication +class BlogApplication + +fun main(args: Array) { + runApplication(*args) +} + diff --git a/samples/gradle-kotlin-jdk8-jre8/src/main/resources/application.properties b/samples/gradle-kotlin-jdk8-jre8/src/main/resources/application.properties new file mode 100644 index 0000000..e69de29 diff --git a/samples/gradle-kotlin-jdk8-jre8/src/test/kotlin/blog/BlogApplicationTests.kt b/samples/gradle-kotlin-jdk8-jre8/src/test/kotlin/blog/BlogApplicationTests.kt new file mode 100644 index 0000000..6943967 --- /dev/null +++ b/samples/gradle-kotlin-jdk8-jre8/src/test/kotlin/blog/BlogApplicationTests.kt @@ -0,0 +1,17 @@ +package blog + +import org.junit.Test +import org.junit.runner.RunWith +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.test.context.junit4.SpringRunner + +@RunWith(SpringRunner::class) +@SpringBootTest +class BlogApplicationTests { + + @Test + fun contextLoads() { + } + +} + diff --git a/samples/gradle5-java-jdk11-x-jre12/.dockerignore b/samples/gradle5-java-jdk11-x-jre12/.dockerignore new file mode 100644 index 0000000..38aeebd --- /dev/null +++ b/samples/gradle5-java-jdk11-x-jre12/.dockerignore @@ -0,0 +1,6 @@ +.gitignore +docker-compose.yaml +Dockerfile +mvnw +mvnw.cmd +README.md diff --git a/samples/gradle5-java-jdk11-x-jre12/Dockerfile b/samples/gradle5-java-jdk11-x-jre12/Dockerfile new file mode 100644 index 0000000..b314e92 --- /dev/null +++ b/samples/gradle5-java-jdk11-x-jre12/Dockerfile @@ -0,0 +1,31 @@ +### Builder Arguments +ARG UNMAZEDBOOT_BUILDER_GIT_SHA=${UNMAZEDBOOT_BUILDER_GIT_SHA:-000000} +ARG UNMAZEDBOOT_BUILDER_GIT_BRANCH=${UNMAZEDBOOT_BUILDER_GIT_BRANCH:-master} +ARG UNMAZEDBOOT_BUILDER_GRADLE_BUILD_CMD="gradle build -x test" +ARG UNMAZEDBOOT_BUILDER_DIR="build/libs" +ARG UNMAZEDBOOT_BUILDER_PACKAGE_EXTENSION="jar" +ARG UNMAZEDBOOT_BUILDER_GRADLE_VERSION=${UNMAZEDBOOT_BUILDER_GRADLE_VERSION:--latest} + +### Linker Argumentss +ARG UNMAZEDBOOT_LINKER_VERSION=${UNMAZEDBOOT_LINKER_VERSION:--latest} + +### Runner Arguments +ARG UNMAZEDBOOT_RUNNER_PORT="8080" +ARG UNMAZEDBOOT_RUNNER_VERSION=${UNMAZEDBOOT_RUNNER_VERSION:--latest} + +# ##################################################################### +# Build stage for building the target directory before running tests +# ##################################################################### +FROM intuit/unmazedboot-builder-gradle:5.0.0-jdk11-slim${UNMAZEDBOOT_BUILDER_GRADLE_VERSION} as unmazedboot-builder-artifacts + +# ##################################################################### +# Build stage for making a jlink specific for the app +# ##################################################################### +FROM intuit/unmazedboot-linker:jdk12-alpine${UNMAZEDBOOT_LINKER_VERSION} as unmazedboot-jdk-linker + +# ##################################################################### +# Build stage for running the runtime image (MUST MATCH LINKER TYPE) +# ##################################################################### +FROM intuit/unmazedboot-runner:custom-jdk-alpine3.8${UNMAZEDBOOT_RUNNER_VERSION} + +# The image depends on the built artifacts by the stage diff --git a/samples/gradle5-java-jdk11-x-jre12/README.md b/samples/gradle5-java-jdk11-x-jre12/README.md new file mode 100644 index 0000000..9a149dc --- /dev/null +++ b/samples/gradle5-java-jdk11-x-jre12/README.md @@ -0,0 +1,368 @@ +# Running + +* Using SpringBoot 2.0.3 +* Using Starter Web + +## BootRun + +* Uses `build.gradle` +* Run with `bootRun` default profile + +``` +gradle bootRun +``` + +* Run with `bootRun` with `dev` profile + +``` +SPRING_PROFILES_ACTIVE=dev gradle bootRun +``` + +## Docker Container + +* Uses the `Dockerfile` +* Build a Docker Image default arguments + +``` +$ docker build -t myapp . +Sending build context to Docker daemon 20.23MB +Step 1/7 : ARG GIT_SHA=${GIT_SHA:-0101010} +Step 2/7 : ARG GIT_BRANCH=${GIT_BRANCH:-develop} +Step 3/7 : ARG BUILD_NUMBER=${BUILD_NUMBER:-0223} +Step 4/7 : ARG GRADLE_BUILD_TASKS="build -x test" +Step 5/7 : ARG EXECUTABLE_TASK_TYPE="jar" +Step 6/7 : FROM marcellodesales/springboot-builder as unmazedboot-builder-artifacts + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Running in 6b7c60c82fa1 +Will execute gradle downloadDependencies +Removing intermediate container 6b7c60c82fa1 + ---> Running in 44f6a573e60e + +Welcome to Gradle 4.10.1! + +Here are the highlights of this release: + - Incremental Java compilation by default + - Periodic Gradle caches cleanup + - Gradle Kotlin DSL 1.0-RC6 + - Nested included builds + - SNAPSHOT plugin versions in the `plugins {}` block + +For more details see https://docs.gradle.org/4.10.1/release-notes.html + +Starting a Gradle Daemon (subsequent builds will be faster) + +> Task :downloadDependencies + +Retrieving dependencies for annotationProcessor + +.. +.. + +Retrieving dependencies for testRuntimeOnly + +BUILD SUCCESSFUL in 14s +1 actionable task: 1 executed +Removing intermediate container 44f6a573e60e + ---> Running in 40a596327554 +Will execute gradle build -x test +Removing intermediate container 40a596327554 + ---> Running in 8642c9c067f4 + +Welcome to Gradle 4.10.1! + +Here are the highlights of this release: + - Incremental Java compilation by default + - Periodic Gradle caches cleanup + - Gradle Kotlin DSL 1.0-RC6 + - Nested included builds + - SNAPSHOT plugin versions in the `plugins {}` block + +For more details see https://docs.gradle.org/4.10.1/release-notes.html + +Starting a Gradle Daemon (subsequent builds will be faster) +> Task :compileJava +> Task :processResources +> Task :classes +> Task :bootJar +> Task :jar SKIPPED +> Task :assemble +> Task :check +> Task :build + +BUILD SUCCESSFUL in 20s +3 actionable tasks: 3 executed +Removing intermediate container 8642c9c067f4 + ---> 405621119bcf +Step 7/7 : FROM marcellodesales/springboot-executable-runner + ---> Using cache + ---> Using cache + ---> Using cache + ---> Running in 46cb7cebdf3b +-rw-r--r-- 1 root root 16141378 Sep 16 23:16 /tmp/myapp-0.1.0.jar +Removing intermediate container 46cb7cebdf3b + ---> Running in b47bfaf3a78d +Will copy from /app/src/main/resources /runtime/resources +Removing intermediate container b47bfaf3a78d + ---> Running in cc5b00fe7dad +total 20 +drwxr-xr-x 2 root root 4096 Sep 16 23:17 . +drwxr-xr-x 1 root root 4096 Sep 16 23:17 .. +-rw-r--r-- 1 root root 48 Sep 16 23:12 application-dev.yml +-rw-r--r-- 1 root root 47 Sep 16 23:12 application-prd.yml +-rw-r--r-- 1 root root 51 Sep 16 23:12 application.yml +Removing intermediate container cc5b00fe7dad + ---> Running in 40a70b1e8304 +Renaming the executable jar to the runtime dir +Removing intermediate container 40a70b1e8304 + ---> Running in 3d3eea4bdd5c +Removing intermediate container 3d3eea4bdd5c + ---> 89923a61a08c +Successfully built 89923a61a08c +Successfully tagged myapp:latest +``` + +* Running in the `dev` profile + * Loads the file `application-dev.yml` + * The logs will be showing `The following profiles are active: dev` + +``` +$ docker run -ti -e SPRING_PROFILES_ACTIVE=dev -p 8080:8080 myapp + + . ____ _ __ _ _ + /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ +( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ + \\/ ___)| |_)| | | | | || (_| | ) ) ) ) + ' |____| .__|_| |_|_| |_\__, | / / / / + =========|_|==============|___/=/_/_/_/ + :: Spring Boot :: (v2.0.3.RELEASE) + +2018-09-16 23:17:50.719 INFO 9 --- [ main] hello.Application : Starting Application on 44fb9b4347d6 with PID 9 (/runtime/server.jar started by root in /runtime) +2018-09-16 23:17:50.725 INFO 9 --- [ main] hello.Application : The following profiles are active: dev +2018-09-16 23:17:50.820 INFO 9 --- [ main] ConfigServletWebServerApplicationContext : Refreshing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@6833ce2c: startup date [Sun Sep 16 23:17:50 UTC 2018]; root of context hierarchy +2018-09-16 23:17:52.445 INFO 9 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http) +``` + +## Validating + +``` +curl localhost:8080 +Hello Docker World from My App: Environment for development% +``` + +## Docker Build Args + +``` +docker build -t myapp --build-arg GIT_SHA=$(git rev-parse HEAD) \ + --build-arg GIT_BRANCH=$(git rev-parse --abbrev-ref --symbolic HEAD) \ + --build-arg BUILD_NUMBER=1234 . +``` + +# Sample Features + +## Response Filter with Build Info + +* Build with build information while running + +``` +GIT_SHA=$(git rev-parse HEAD) \ +GIT_BRANCH=$(git rev-parse --abbrev-ref --symbolic HEAD) \ +BUILD_TAG=$USER \ +gradle clean bootRun +``` + +* HTTP Response Headers filters + +``` +$ curl -i localhost:8080 +HTTP/1.1 200 +X-App-Build-Info: commit=486223a73d435c778ac2ef93b68ee637652ee370;branch=feature/sample/show-build-info-all-response-headers;tag=mdesales;time=2018-09-17-05:32:07-UTC;version=0.1.0 +Content-Type: text/plain;charset=UTF-8 +Content-Length: 47 +Date: Mon, 17 Sep 2018 05:32:12 GMT + +Hello Docker World from My App: Default profile% +``` + +## Verification with Docker Containers + + +* Build the docker image with the arguments + +``` +$ docker build -t sample --build-arg BUILDER_GIT_SHA=$(git rev-parse HEAD) --build-arg BUILDER_GIT_BRANCH=$(git rev-parse --abbrev-ref --symbolic HEAD) --build-arg BUILDER_BUILD_NUMBER=$USER . +Sending build context to Docker daemon 4.205MB +Step 1/10 : ARG BUILDER_GIT_SHA=${GIT_SHA:-0101010} +Step 2/10 : ARG BUILDER_GIT_BRANCH=${GIT_BRANCH:-develop} +Step 3/10 : ARG BUILDER_BUILD_NUMBER=${BUILD_NUMBER:-0223} +Step 4/10 : ARG BUILDER_GRADLE_DOWNLOAD_DEPENDENCIES_CMD="gradle downloadDependencies" +Step 5/10 : ARG BUILDER_GRADLE_BUILD_CMD="gradle build -x test" +Step 6/10 : ARG BUILDER_DIR="build/libs" +Step 7/10 : ARG UNMAZEDBOOT_BUILDER_PACKAGE_EXTENSION="jar" +Step 8/10 : ARG RUNNER_PORT="8080" +Step 9/10 : FROM marcellodesales/springboot-builder:gradle-4.10.1-jdk-8 as unmazedboot-builder-artifacts +# Executing 15 build triggers + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Running in fa0d5676f667 +Removing intermediate container fa0d5676f667 + ---> Running in c8633ef774b5 +Removing intermediate container c8633ef774b5 + ---> Running in 34de329e478d +Executing BUILDER_GRADLE_DOWNLOAD_DEPENDENCIES_CMD='gradle downloadDependencies' +Removing intermediate container 34de329e478d + ---> Running in 9d9642a2dacf + +Welcome to Gradle 4.10.1! + +Here are the highlights of this release: + - Incremental Java compilation by default + - Periodic Gradle caches cleanup + - Gradle Kotlin DSL 1.0-RC6 + - Nested included builds + - SNAPSHOT plugin versions in the `plugins {}` block + +For more details see https://docs.gradle.org/4.10.1/release-notes.html + +Starting a Gradle Daemon (subsequent builds will be faster) + +> Task :downloadDependencies + +Retrieving dependencies for annotationProcessor + +... +... + +Retrieving dependencies for testRuntimeOnly + + +BUILD SUCCESSFUL in 25s +1 actionable task: 1 executed +Removing intermediate container 9d9642a2dacf + ---> Running in 9d8c260964ec +Executing BUILDER_GRADLE_BUILD_CMD='gradle build -x test' +Removing intermediate container 9d8c260964ec + ---> Running in a628ad0694c1 + +Welcome to Gradle 4.10.1! + +Here are the highlights of this release: + - Incremental Java compilation by default + - Periodic Gradle caches cleanup + - Gradle Kotlin DSL 1.0-RC6 + - Nested included builds + - SNAPSHOT plugin versions in the `plugins {}` block + +For more details see https://docs.gradle.org/4.10.1/release-notes.html + +Starting a Gradle Daemon (subsequent builds will be faster) +> Task :processResources +> Task :compileJava +> Task :classes +> Task :bootJar +> Task :jar SKIPPED +> Task :assemble +> Task :check +> Task :build + +BUILD SUCCESSFUL in 27s +3 actionable tasks: 3 executed +Removing intermediate container a628ad0694c1 + ---> ff3d11b8f007 +Step 10/10 : FROM marcellodesales/springboot-runner:openjdk-8-jre-slim +# Executing 15 build triggers + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Running in f028ec130c35 +-rwxr--r-- 1 root root 16151787 Sep 17 05:43 /tmp/myapp-0.1.0.jar +Removing intermediate container f028ec130c35 + ---> Running in fdd68c834c82 +Will copy from /app/src/main/resources /runtime/resources +Removing intermediate container fdd68c834c82 + ---> Running in 712af509ad8c +total 20 +drwxr-xr-x 2 root root 4096 Sep 17 05:43 . +drwxr-xr-x 1 root root 4096 Sep 17 05:43 .. +-rw-r--r-- 1 root root 48 Sep 16 23:32 application-dev.yml +-rw-r--r-- 1 root root 47 Sep 16 23:32 application-prd.yml +-rw-r--r-- 1 root root 185 Sep 17 05:14 application.yml +Removing intermediate container 712af509ad8c + ---> Running in a0d64b1c78e0 +Renaming the executable jar to the runtime dir +Removing intermediate container a0d64b1c78e0 + ---> Running in 65b7521b34eb +Removing intermediate container 65b7521b34eb + ---> Running in 3689b3c4ad9d +Removing intermediate container 3689b3c4ad9d + ---> f8c20d9b537e +Successfully built f8c20d9b537e +Successfully tagged sample:latest +``` + +* Run the container + * Note that you need to bind the host's port to the one from the container. + * The end of the output confirms the server is running with the port displayed. + +``` +$ docker run -ti -p 8080:8080 sample + + . ____ _ __ _ _ + /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ +( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ + \\/ ___)| |_)| | | | | || (_| | ) ) ) ) + ' |____| .__|_| |_|_| |_\__, | / / / / + =========|_|==============|___/=/_/_/_/ + :: Spring Boot :: (v2.0.3.RELEASE) + +2018-09-17 05:46:23.906 INFO 9 --- [ main] hello.Application : Starting Application on adab7dc7946f with PID 9 (/runtime/server.jar started by root in /runtime) +2018-09-17 05:46:23.918 INFO 9 --- [ main] hello.Application : No active profile set, falling back to default profiles: default +2018-09-17 05:46:24.089 INFO 9 --- [ main] ConfigServletWebServerApplicationContext : Refreshing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@5b1d2887: startup date [Mon Sep 17 05:46:24 UTC 2018]; root of context hierarchy +2018-09-17 05:46:25.929 INFO 9 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http) +2018-09-17 05:46:25.974 INFO 9 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] +2018-09-17 05:46:25.975 INFO 9 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/8.5.31 +2018-09-17 05:46:25.994 INFO 9 --- [ost-startStop-1] o.a.catalina.core.AprLifecycleListener : The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: [/usr/java/packages/lib/amd64:/usr/lib/x86_64-linux-gnu/jni:/lib/x86_64-linux-gnu:/usr/lib/x86_64-linux-gnu:/usr/lib/jni:/lib:/usr/lib] +2018-09-17 05:46:26.130 INFO 9 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext +2018-09-17 05:46:26.131 INFO 9 --- [ost-startStop-1] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 2047 ms +2018-09-17 05:46:26.325 INFO 9 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean : Servlet dispatcherServlet mapped to [/] +2018-09-17 05:46:26.331 INFO 9 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'characterEncodingFilter' to: [/*] +2018-09-17 05:46:26.332 INFO 9 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'hiddenHttpMethodFilter' to: [/*] +2018-09-17 05:46:26.332 INFO 9 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'httpPutFormContentFilter' to: [/*] +2018-09-17 05:46:26.333 INFO 9 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'requestContextFilter' to: [/*] +2018-09-17 05:46:26.333 INFO 9 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'defaultResponseFilter' to: [/*] +2018-09-17 05:46:26.556 INFO 9 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] +2018-09-17 05:46:26.932 INFO 9 --- [ main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@5b1d2887: startup date [Mon Sep 17 05:46:24 UTC 2018]; root of context hierarchy +2018-09-17 05:46:27.060 INFO 9 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/]}" onto public java.lang.String hello.Application.home() +2018-09-17 05:46:27.069 INFO 9 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse) +2018-09-17 05:46:27.071 INFO 9 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity> org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.error(javax.servlet.http.HttpServletRequest) +2018-09-17 05:46:27.123 INFO 9 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] +2018-09-17 05:46:27.124 INFO 9 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] +2018-09-17 05:46:27.388 INFO 9 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup +2018-09-17 05:46:27.459 INFO 9 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path '' +2018-09-17 05:46:27.471 INFO 9 --- [ main] hello.Application : Started Application in 4.275 seconds (JVM running for 4.926) +``` + +* Make the call to the server + * Note tha the TAG here is different because the Dockerfile overrides the `BUILD_TAG` value! + +``` +$ curl -i localhost:8080 +HTTP/1.1 200 +X-App-Build-Info: commit=d02650d801f8fc5db7ed0cc92422f897df3a0f4b;branch=feature/sample/show-build-info-all-response-headers;tag=sha:d02650d801f8fc5db7ed0cc92422f897df3a0f4b,build:feature/sample/show-build-info-all-response-headers/mdesales;time=2018-09-17-05:43:19-UTC;version=0.1.0 +Content-Type: text/plain;charset=UTF-8 +Content-Length: 47 +Date: Mon, 17 Sep 2018 05:44:10 GMT + +Hello Docker World from My App: Default profile% +``` diff --git a/samples/gradle5-java-jdk11-x-jre12/build.gradle b/samples/gradle5-java-jdk11-x-jre12/build.gradle new file mode 100644 index 0000000..c6a2582 --- /dev/null +++ b/samples/gradle5-java-jdk11-x-jre12/build.gradle @@ -0,0 +1,32 @@ +// Group and version (used by jar) +group = 'hello' +version = '0.1.0' + +buildscript { + repositories { + mavenCentral() + } + dependencies { + classpath("org.springframework.boot:spring-boot-gradle-plugin:2.0.4.RELEASE") + } +} + +apply plugin: 'java' +apply plugin: 'eclipse' +apply plugin: 'org.springframework.boot' +apply plugin: 'io.spring.dependency-management' + +apply from: 'src/gradle/jar.gradle' +apply from: 'src/gradle/processResources.gradle' + +repositories { + mavenCentral() +} + +sourceCompatibility = 1.11 +targetCompatibility = 1.11 + +dependencies { + compile("org.springframework.boot:spring-boot-starter-web") + testCompile("org.springframework.boot:spring-boot-starter-test") +} diff --git a/samples/gradle5-java-jdk11-x-jre12/settings.gradle b/samples/gradle5-java-jdk11-x-jre12/settings.gradle new file mode 100644 index 0000000..bebf3f4 --- /dev/null +++ b/samples/gradle5-java-jdk11-x-jre12/settings.gradle @@ -0,0 +1 @@ +rootProject.name = "myapp" diff --git a/samples/gradle5-java-jdk11-x-jre12/src/gradle/jar.gradle b/samples/gradle5-java-jdk11-x-jre12/src/gradle/jar.gradle new file mode 100644 index 0000000..0b06acd --- /dev/null +++ b/samples/gradle5-java-jdk11-x-jre12/src/gradle/jar.gradle @@ -0,0 +1,4 @@ +bootJar { + baseName = rootProject.name + version = project.version +} diff --git a/samples/gradle5-java-jdk11-x-jre12/src/gradle/processResources.gradle b/samples/gradle5-java-jdk11-x-jre12/src/gradle/processResources.gradle new file mode 100644 index 0000000..b9cc58b --- /dev/null +++ b/samples/gradle5-java-jdk11-x-jre12/src/gradle/processResources.gradle @@ -0,0 +1,23 @@ +// https://dzone.com/articles/resource-filtering-gradle +import org.apache.tools.ant.filters.* + +// Expose the commit and branch values for the resources below +ext { + time = new Date().format("yyyy-MM-dd-HH:mm:ss-z", TimeZone.getTimeZone('UTC')) + version = project.version +} + +processResources { + filter ReplaceTokens, tokens: [ + "build.time": time, + "build.version": version + ] +} + +// Process resources when compiling +compileJava.dependsOn(processResources) // added for spring-boot-configuration-processor + +// Include the processResources when running "gradle bootRun" +bootJar { + launchScript() +} diff --git a/samples/gradle5-java-jdk11-x-jre12/src/main/java/hello/Application.java b/samples/gradle5-java-jdk11-x-jre12/src/main/java/hello/Application.java new file mode 100644 index 0000000..8055ad0 --- /dev/null +++ b/samples/gradle5-java-jdk11-x-jre12/src/main/java/hello/Application.java @@ -0,0 +1,30 @@ +package hello; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.context.properties.EnableConfigurationProperties; + +@SpringBootApplication +@RestController +@EnableConfigurationProperties +public class Application { + + @Value("${app.name}") + private String name; + + @Value("${app.description}") + private String description; + + @RequestMapping("/") + public String home() { + return "Hello Docker World from " + this.name + ": " + this.description; + } + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + +} diff --git a/samples/gradle5-java-jdk11-x-jre12/src/main/java/hello/util/BuildInfo.java b/samples/gradle5-java-jdk11-x-jre12/src/main/java/hello/util/BuildInfo.java new file mode 100644 index 0000000..7530aa4 --- /dev/null +++ b/samples/gradle5-java-jdk11-x-jre12/src/main/java/hello/util/BuildInfo.java @@ -0,0 +1,45 @@ +package hello.util; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.context.properties.ConfigurationProperties; +import javax.annotation.PostConstruct; +import org.springframework.stereotype.Component; + +@Component +@ConfigurationProperties(prefix="build") +public class BuildInfo { + + private String commit; + + private String branch; + + private String time; + + private String version; + + public void setCommit(String commit) { + this.commit = commit; + } + + public void setBranch(String branch) { + this.branch = branch; + } + + public void setTime(String time) { + this.time = time; + } + + public void setVersion(String version) { + this.version = version; + } + + @PostConstruct + public void initIt() throws Exception { + System.out.println("INITIALIZED : " + this); + } + + @Override + public String toString() { + return "commit=" + commit + ";branch=" + branch + ";time=" + time + ";version=" + version; + } +} diff --git a/samples/gradle5-java-jdk11-x-jre12/src/main/java/hello/util/DefaultResponseFilter.java b/samples/gradle5-java-jdk11-x-jre12/src/main/java/hello/util/DefaultResponseFilter.java new file mode 100644 index 0000000..ff48f36 --- /dev/null +++ b/samples/gradle5-java-jdk11-x-jre12/src/main/java/hello/util/DefaultResponseFilter.java @@ -0,0 +1,37 @@ +package hello.util; + +import java.io.IOException; +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletResponse; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class DefaultResponseFilter implements Filter { + + @Autowired + private BuildInfo buildInfo; + + @Override + public void destroy() {} + + @Override + public void init(FilterConfig arg0) throws ServletException {} + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException { + + HttpServletResponse res = (HttpServletResponse)response; + res.setHeader("X-App-Build-Info", buildInfo.toString()); + + chain.doFilter(request, res); + + } + +} diff --git a/samples/gradle5-java-jdk11-x-jre12/src/main/resources/application-dev.yml b/samples/gradle5-java-jdk11-x-jre12/src/main/resources/application-dev.yml new file mode 100644 index 0000000..9c73229 --- /dev/null +++ b/samples/gradle5-java-jdk11-x-jre12/src/main/resources/application-dev.yml @@ -0,0 +1,2 @@ +app: + description: Environment for development diff --git a/samples/gradle5-java-jdk11-x-jre12/src/main/resources/application-prd.yml b/samples/gradle5-java-jdk11-x-jre12/src/main/resources/application-prd.yml new file mode 100644 index 0000000..12f7f7e --- /dev/null +++ b/samples/gradle5-java-jdk11-x-jre12/src/main/resources/application-prd.yml @@ -0,0 +1,2 @@ +app: + description: Environment for production diff --git a/samples/gradle5-java-jdk11-x-jre12/src/main/resources/application.yml b/samples/gradle5-java-jdk11-x-jre12/src/main/resources/application.yml new file mode 100644 index 0000000..c796125 --- /dev/null +++ b/samples/gradle5-java-jdk11-x-jre12/src/main/resources/application.yml @@ -0,0 +1,7 @@ +app: + name: My App + description: Default profile + +build: + version: "@build.version@" + time: "@build.time@" diff --git a/samples/maven-java-jdk11-custom/.dockerignore b/samples/maven-java-jdk11-custom/.dockerignore new file mode 100644 index 0000000..38aeebd --- /dev/null +++ b/samples/maven-java-jdk11-custom/.dockerignore @@ -0,0 +1,6 @@ +.gitignore +docker-compose.yaml +Dockerfile +mvnw +mvnw.cmd +README.md diff --git a/samples/maven-java-jdk11-custom/.gitignore b/samples/maven-java-jdk11-custom/.gitignore new file mode 100644 index 0000000..f3b7dd5 --- /dev/null +++ b/samples/maven-java-jdk11-custom/.gitignore @@ -0,0 +1,18 @@ +target/ +pom.xml.tag +pom.xml.releaseBackup +pom.xml.versionsBackup +pom.xml.next +release.properties +dependency-reduced-pom.xml +buildNumber.properties +.mvn/timing.properties + +# Avoid ignoring Maven wrapper jar file (.jar files are usually ignored) +!/.mvn/wrapper/maven-wrapper.jar + + +#eclipse +.settings +.classpath +.project \ No newline at end of file diff --git a/samples/maven-java-jdk11-custom/Dockerfile b/samples/maven-java-jdk11-custom/Dockerfile new file mode 100644 index 0000000..4ecefd8 --- /dev/null +++ b/samples/maven-java-jdk11-custom/Dockerfile @@ -0,0 +1,45 @@ +### Builder Arguments +ARG UNMAZEDBOOT_BUILDER_GIT_SHA=${UNMAZEDBOOT_BUILDER_GIT_SHA:-000000} +ARG UNMAZEDBOOT_BUILDER_GIT_BRANCH=${UNMAZEDBOOT_BUILDER_GIT_BRANCH:-master} +ARG UNMAZEDBOOT_BUILDER_MAVEN_BUILD_CMD="mvn clean package" +ARG UNMAZEDBOOT_BUILDER_DIR="target" +ARG UNMAZEDBOOT_BUILDER_PACKAGE_EXTENSION="jar" +ARG UNMAZEDBOOT_BUILDER_MAVEN_VERSION=${UNMAZEDBOOT_BUILDER_MAVEN_VERSION:--latest} + +### Linker Arguments +ARG UNMAZEDBOOT_LINKER_JDK_MODULES=jdk.jfr,jdk.management.agent,java.base,java.logging,java.xml,jdk.unsupported,java.sql,java.naming,java.desktop,java.management,java.security.jgss,java.instrument +ARG UNMAZEDBOOT_LINKER_VERSION=${UNMAZEDBOOT_LINKER_VERSION:--latest} + +### Runner Arguments +ARG UNMAZEDBOOT_RUNNER_PORT="8080" +ARG UNMAZEDBOOT_RUNNER_VERSION=${UNMAZEDBOOT_RUNNER_VERSION:--latest} + +# ##################################################################### +# Build stage for building the target directory before running tests +# ##################################################################### +FROM intuit/unmazedboot-builder-maven:3.6.0-jdk11-slim${UNMAZEDBOOT_BUILDER_MAVEN_VERSION} as unmazedboot-builder-artifacts + +# ##################################################################### +# Build stage for making a jlink specific for the app +# ##################################################################### +FROM intuit/unmazedboot-linker:jdk11-alpine${UNMAZEDBOOT_LINKER_VERSION} as unmazedboot-jdk-linker + +# ##################################################################### +# Build stage for running the runtime image +# ##################################################################### +FROM intuit/unmazedboot-runner:custom-jdk-alpine3.8${UNMAZEDBOOT_RUNNER_VERSION} + +# The image depends on the built artifacts by the stage + +ENV JAVA_FLIGHT_RECORDER_DIR=/runtime/jfr +# hadolint ignore=SC2039 +RUN echo "-XX:StartFlightRecording=name=sample,filename=${JAVA_FLIGHT_RECORDER_DIR}/sample.jfr,delay=30s,maxage=2h,maxsize=10m,dumponexit=true,settings=${JAVA_FLIGHT_RECORDER_DIR}/profile.jfc" > /runtime/java-opts/flight-recorder.opt + +# hadolint ignore=SC2039 +RUN echo $'-Dcom.sun.management.jmxremote.port=7199 \n\ + -Dcom.sun.management.jmxremote.rmi.port=7199 \n\ + -Dcom.sun.management.jmxremote.authenticate=false \n\ + -Dcom.sun.management.jmxremote.ssl=false' > /runtime/java-opts/jmx.opts + +# JVM debugging port +EXPOSE 7199 diff --git a/samples/maven-java-jdk11-custom/LICENSE b/samples/maven-java-jdk11-custom/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/samples/maven-java-jdk11-custom/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/samples/maven-java-jdk11-custom/README.md b/samples/maven-java-jdk11-custom/README.md new file mode 100644 index 0000000..9a149dc --- /dev/null +++ b/samples/maven-java-jdk11-custom/README.md @@ -0,0 +1,368 @@ +# Running + +* Using SpringBoot 2.0.3 +* Using Starter Web + +## BootRun + +* Uses `build.gradle` +* Run with `bootRun` default profile + +``` +gradle bootRun +``` + +* Run with `bootRun` with `dev` profile + +``` +SPRING_PROFILES_ACTIVE=dev gradle bootRun +``` + +## Docker Container + +* Uses the `Dockerfile` +* Build a Docker Image default arguments + +``` +$ docker build -t myapp . +Sending build context to Docker daemon 20.23MB +Step 1/7 : ARG GIT_SHA=${GIT_SHA:-0101010} +Step 2/7 : ARG GIT_BRANCH=${GIT_BRANCH:-develop} +Step 3/7 : ARG BUILD_NUMBER=${BUILD_NUMBER:-0223} +Step 4/7 : ARG GRADLE_BUILD_TASKS="build -x test" +Step 5/7 : ARG EXECUTABLE_TASK_TYPE="jar" +Step 6/7 : FROM marcellodesales/springboot-builder as unmazedboot-builder-artifacts + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Running in 6b7c60c82fa1 +Will execute gradle downloadDependencies +Removing intermediate container 6b7c60c82fa1 + ---> Running in 44f6a573e60e + +Welcome to Gradle 4.10.1! + +Here are the highlights of this release: + - Incremental Java compilation by default + - Periodic Gradle caches cleanup + - Gradle Kotlin DSL 1.0-RC6 + - Nested included builds + - SNAPSHOT plugin versions in the `plugins {}` block + +For more details see https://docs.gradle.org/4.10.1/release-notes.html + +Starting a Gradle Daemon (subsequent builds will be faster) + +> Task :downloadDependencies + +Retrieving dependencies for annotationProcessor + +.. +.. + +Retrieving dependencies for testRuntimeOnly + +BUILD SUCCESSFUL in 14s +1 actionable task: 1 executed +Removing intermediate container 44f6a573e60e + ---> Running in 40a596327554 +Will execute gradle build -x test +Removing intermediate container 40a596327554 + ---> Running in 8642c9c067f4 + +Welcome to Gradle 4.10.1! + +Here are the highlights of this release: + - Incremental Java compilation by default + - Periodic Gradle caches cleanup + - Gradle Kotlin DSL 1.0-RC6 + - Nested included builds + - SNAPSHOT plugin versions in the `plugins {}` block + +For more details see https://docs.gradle.org/4.10.1/release-notes.html + +Starting a Gradle Daemon (subsequent builds will be faster) +> Task :compileJava +> Task :processResources +> Task :classes +> Task :bootJar +> Task :jar SKIPPED +> Task :assemble +> Task :check +> Task :build + +BUILD SUCCESSFUL in 20s +3 actionable tasks: 3 executed +Removing intermediate container 8642c9c067f4 + ---> 405621119bcf +Step 7/7 : FROM marcellodesales/springboot-executable-runner + ---> Using cache + ---> Using cache + ---> Using cache + ---> Running in 46cb7cebdf3b +-rw-r--r-- 1 root root 16141378 Sep 16 23:16 /tmp/myapp-0.1.0.jar +Removing intermediate container 46cb7cebdf3b + ---> Running in b47bfaf3a78d +Will copy from /app/src/main/resources /runtime/resources +Removing intermediate container b47bfaf3a78d + ---> Running in cc5b00fe7dad +total 20 +drwxr-xr-x 2 root root 4096 Sep 16 23:17 . +drwxr-xr-x 1 root root 4096 Sep 16 23:17 .. +-rw-r--r-- 1 root root 48 Sep 16 23:12 application-dev.yml +-rw-r--r-- 1 root root 47 Sep 16 23:12 application-prd.yml +-rw-r--r-- 1 root root 51 Sep 16 23:12 application.yml +Removing intermediate container cc5b00fe7dad + ---> Running in 40a70b1e8304 +Renaming the executable jar to the runtime dir +Removing intermediate container 40a70b1e8304 + ---> Running in 3d3eea4bdd5c +Removing intermediate container 3d3eea4bdd5c + ---> 89923a61a08c +Successfully built 89923a61a08c +Successfully tagged myapp:latest +``` + +* Running in the `dev` profile + * Loads the file `application-dev.yml` + * The logs will be showing `The following profiles are active: dev` + +``` +$ docker run -ti -e SPRING_PROFILES_ACTIVE=dev -p 8080:8080 myapp + + . ____ _ __ _ _ + /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ +( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ + \\/ ___)| |_)| | | | | || (_| | ) ) ) ) + ' |____| .__|_| |_|_| |_\__, | / / / / + =========|_|==============|___/=/_/_/_/ + :: Spring Boot :: (v2.0.3.RELEASE) + +2018-09-16 23:17:50.719 INFO 9 --- [ main] hello.Application : Starting Application on 44fb9b4347d6 with PID 9 (/runtime/server.jar started by root in /runtime) +2018-09-16 23:17:50.725 INFO 9 --- [ main] hello.Application : The following profiles are active: dev +2018-09-16 23:17:50.820 INFO 9 --- [ main] ConfigServletWebServerApplicationContext : Refreshing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@6833ce2c: startup date [Sun Sep 16 23:17:50 UTC 2018]; root of context hierarchy +2018-09-16 23:17:52.445 INFO 9 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http) +``` + +## Validating + +``` +curl localhost:8080 +Hello Docker World from My App: Environment for development% +``` + +## Docker Build Args + +``` +docker build -t myapp --build-arg GIT_SHA=$(git rev-parse HEAD) \ + --build-arg GIT_BRANCH=$(git rev-parse --abbrev-ref --symbolic HEAD) \ + --build-arg BUILD_NUMBER=1234 . +``` + +# Sample Features + +## Response Filter with Build Info + +* Build with build information while running + +``` +GIT_SHA=$(git rev-parse HEAD) \ +GIT_BRANCH=$(git rev-parse --abbrev-ref --symbolic HEAD) \ +BUILD_TAG=$USER \ +gradle clean bootRun +``` + +* HTTP Response Headers filters + +``` +$ curl -i localhost:8080 +HTTP/1.1 200 +X-App-Build-Info: commit=486223a73d435c778ac2ef93b68ee637652ee370;branch=feature/sample/show-build-info-all-response-headers;tag=mdesales;time=2018-09-17-05:32:07-UTC;version=0.1.0 +Content-Type: text/plain;charset=UTF-8 +Content-Length: 47 +Date: Mon, 17 Sep 2018 05:32:12 GMT + +Hello Docker World from My App: Default profile% +``` + +## Verification with Docker Containers + + +* Build the docker image with the arguments + +``` +$ docker build -t sample --build-arg BUILDER_GIT_SHA=$(git rev-parse HEAD) --build-arg BUILDER_GIT_BRANCH=$(git rev-parse --abbrev-ref --symbolic HEAD) --build-arg BUILDER_BUILD_NUMBER=$USER . +Sending build context to Docker daemon 4.205MB +Step 1/10 : ARG BUILDER_GIT_SHA=${GIT_SHA:-0101010} +Step 2/10 : ARG BUILDER_GIT_BRANCH=${GIT_BRANCH:-develop} +Step 3/10 : ARG BUILDER_BUILD_NUMBER=${BUILD_NUMBER:-0223} +Step 4/10 : ARG BUILDER_GRADLE_DOWNLOAD_DEPENDENCIES_CMD="gradle downloadDependencies" +Step 5/10 : ARG BUILDER_GRADLE_BUILD_CMD="gradle build -x test" +Step 6/10 : ARG BUILDER_DIR="build/libs" +Step 7/10 : ARG UNMAZEDBOOT_BUILDER_PACKAGE_EXTENSION="jar" +Step 8/10 : ARG RUNNER_PORT="8080" +Step 9/10 : FROM marcellodesales/springboot-builder:gradle-4.10.1-jdk-8 as unmazedboot-builder-artifacts +# Executing 15 build triggers + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Running in fa0d5676f667 +Removing intermediate container fa0d5676f667 + ---> Running in c8633ef774b5 +Removing intermediate container c8633ef774b5 + ---> Running in 34de329e478d +Executing BUILDER_GRADLE_DOWNLOAD_DEPENDENCIES_CMD='gradle downloadDependencies' +Removing intermediate container 34de329e478d + ---> Running in 9d9642a2dacf + +Welcome to Gradle 4.10.1! + +Here are the highlights of this release: + - Incremental Java compilation by default + - Periodic Gradle caches cleanup + - Gradle Kotlin DSL 1.0-RC6 + - Nested included builds + - SNAPSHOT plugin versions in the `plugins {}` block + +For more details see https://docs.gradle.org/4.10.1/release-notes.html + +Starting a Gradle Daemon (subsequent builds will be faster) + +> Task :downloadDependencies + +Retrieving dependencies for annotationProcessor + +... +... + +Retrieving dependencies for testRuntimeOnly + + +BUILD SUCCESSFUL in 25s +1 actionable task: 1 executed +Removing intermediate container 9d9642a2dacf + ---> Running in 9d8c260964ec +Executing BUILDER_GRADLE_BUILD_CMD='gradle build -x test' +Removing intermediate container 9d8c260964ec + ---> Running in a628ad0694c1 + +Welcome to Gradle 4.10.1! + +Here are the highlights of this release: + - Incremental Java compilation by default + - Periodic Gradle caches cleanup + - Gradle Kotlin DSL 1.0-RC6 + - Nested included builds + - SNAPSHOT plugin versions in the `plugins {}` block + +For more details see https://docs.gradle.org/4.10.1/release-notes.html + +Starting a Gradle Daemon (subsequent builds will be faster) +> Task :processResources +> Task :compileJava +> Task :classes +> Task :bootJar +> Task :jar SKIPPED +> Task :assemble +> Task :check +> Task :build + +BUILD SUCCESSFUL in 27s +3 actionable tasks: 3 executed +Removing intermediate container a628ad0694c1 + ---> ff3d11b8f007 +Step 10/10 : FROM marcellodesales/springboot-runner:openjdk-8-jre-slim +# Executing 15 build triggers + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Using cache + ---> Running in f028ec130c35 +-rwxr--r-- 1 root root 16151787 Sep 17 05:43 /tmp/myapp-0.1.0.jar +Removing intermediate container f028ec130c35 + ---> Running in fdd68c834c82 +Will copy from /app/src/main/resources /runtime/resources +Removing intermediate container fdd68c834c82 + ---> Running in 712af509ad8c +total 20 +drwxr-xr-x 2 root root 4096 Sep 17 05:43 . +drwxr-xr-x 1 root root 4096 Sep 17 05:43 .. +-rw-r--r-- 1 root root 48 Sep 16 23:32 application-dev.yml +-rw-r--r-- 1 root root 47 Sep 16 23:32 application-prd.yml +-rw-r--r-- 1 root root 185 Sep 17 05:14 application.yml +Removing intermediate container 712af509ad8c + ---> Running in a0d64b1c78e0 +Renaming the executable jar to the runtime dir +Removing intermediate container a0d64b1c78e0 + ---> Running in 65b7521b34eb +Removing intermediate container 65b7521b34eb + ---> Running in 3689b3c4ad9d +Removing intermediate container 3689b3c4ad9d + ---> f8c20d9b537e +Successfully built f8c20d9b537e +Successfully tagged sample:latest +``` + +* Run the container + * Note that you need to bind the host's port to the one from the container. + * The end of the output confirms the server is running with the port displayed. + +``` +$ docker run -ti -p 8080:8080 sample + + . ____ _ __ _ _ + /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ +( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ + \\/ ___)| |_)| | | | | || (_| | ) ) ) ) + ' |____| .__|_| |_|_| |_\__, | / / / / + =========|_|==============|___/=/_/_/_/ + :: Spring Boot :: (v2.0.3.RELEASE) + +2018-09-17 05:46:23.906 INFO 9 --- [ main] hello.Application : Starting Application on adab7dc7946f with PID 9 (/runtime/server.jar started by root in /runtime) +2018-09-17 05:46:23.918 INFO 9 --- [ main] hello.Application : No active profile set, falling back to default profiles: default +2018-09-17 05:46:24.089 INFO 9 --- [ main] ConfigServletWebServerApplicationContext : Refreshing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@5b1d2887: startup date [Mon Sep 17 05:46:24 UTC 2018]; root of context hierarchy +2018-09-17 05:46:25.929 INFO 9 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http) +2018-09-17 05:46:25.974 INFO 9 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] +2018-09-17 05:46:25.975 INFO 9 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/8.5.31 +2018-09-17 05:46:25.994 INFO 9 --- [ost-startStop-1] o.a.catalina.core.AprLifecycleListener : The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: [/usr/java/packages/lib/amd64:/usr/lib/x86_64-linux-gnu/jni:/lib/x86_64-linux-gnu:/usr/lib/x86_64-linux-gnu:/usr/lib/jni:/lib:/usr/lib] +2018-09-17 05:46:26.130 INFO 9 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext +2018-09-17 05:46:26.131 INFO 9 --- [ost-startStop-1] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 2047 ms +2018-09-17 05:46:26.325 INFO 9 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean : Servlet dispatcherServlet mapped to [/] +2018-09-17 05:46:26.331 INFO 9 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'characterEncodingFilter' to: [/*] +2018-09-17 05:46:26.332 INFO 9 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'hiddenHttpMethodFilter' to: [/*] +2018-09-17 05:46:26.332 INFO 9 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'httpPutFormContentFilter' to: [/*] +2018-09-17 05:46:26.333 INFO 9 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'requestContextFilter' to: [/*] +2018-09-17 05:46:26.333 INFO 9 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'defaultResponseFilter' to: [/*] +2018-09-17 05:46:26.556 INFO 9 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] +2018-09-17 05:46:26.932 INFO 9 --- [ main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@5b1d2887: startup date [Mon Sep 17 05:46:24 UTC 2018]; root of context hierarchy +2018-09-17 05:46:27.060 INFO 9 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/]}" onto public java.lang.String hello.Application.home() +2018-09-17 05:46:27.069 INFO 9 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse) +2018-09-17 05:46:27.071 INFO 9 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity> org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.error(javax.servlet.http.HttpServletRequest) +2018-09-17 05:46:27.123 INFO 9 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] +2018-09-17 05:46:27.124 INFO 9 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] +2018-09-17 05:46:27.388 INFO 9 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup +2018-09-17 05:46:27.459 INFO 9 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path '' +2018-09-17 05:46:27.471 INFO 9 --- [ main] hello.Application : Started Application in 4.275 seconds (JVM running for 4.926) +``` + +* Make the call to the server + * Note tha the TAG here is different because the Dockerfile overrides the `BUILD_TAG` value! + +``` +$ curl -i localhost:8080 +HTTP/1.1 200 +X-App-Build-Info: commit=d02650d801f8fc5db7ed0cc92422f897df3a0f4b;branch=feature/sample/show-build-info-all-response-headers;tag=sha:d02650d801f8fc5db7ed0cc92422f897df3a0f4b,build:feature/sample/show-build-info-all-response-headers/mdesales;time=2018-09-17-05:43:19-UTC;version=0.1.0 +Content-Type: text/plain;charset=UTF-8 +Content-Length: 47 +Date: Mon, 17 Sep 2018 05:44:10 GMT + +Hello Docker World from My App: Default profile% +``` diff --git a/samples/maven-java-jdk11-custom/jfr-config/application.yml b/samples/maven-java-jdk11-custom/jfr-config/application.yml new file mode 100644 index 0000000..6472da5 --- /dev/null +++ b/samples/maven-java-jdk11-custom/jfr-config/application.yml @@ -0,0 +1,26 @@ +# Spring関連 +spring: + resources: + add-mappings: false + mvc: + throw-exception-if-no-handler-found: true + +server: + error: + path: /error + context-path: / + restTemplate: + defaultMaxPerRoute: 5 + maxTotal: 30 + connectionRequestTimeout: 2000 + connectTimeout: 2000 + readTimeout: 3000 + socketTimeout: 3000 + +management: + export.simple.enabled: true + endpoints.web.exposure.include: + - metrics + - info + - health + - env diff --git a/samples/maven-java-jdk11-custom/jfr-config/profile.jfc b/samples/maven-java-jdk11-custom/jfr-config/profile.jfc new file mode 100644 index 0000000..1683acf --- /dev/null +++ b/samples/maven-java-jdk11-custom/jfr-config/profile.jfc @@ -0,0 +1,624 @@ + + + + true + everyChunk + + + true + 1000 ms + + + true + everyChunk + + + true + 1000 ms + + + true + + + true + + + true + true + 10 ms + + + true + true + 10 ms + + + true + true + 10 ms + + + true + true + 10 ms + + + true + true + 10 ms + + + true + true + 0 ms + + + true + true + 0 ms + + + true + true + 0 ms + + + true + true + + + false + true + 0 ms + + + false + true + + + false + + + true + beginChunk + + + true + beginChunk + + + true + 10 ms + + + true + 10 ms + + + true + 0 ms + + + false + 0 ms + + + false + 0 ms + + + false + 0 ms + + + false + 0 ms + + + false + 0 ms + + + true + 0 ms + + + true + true + + + true + 60 s + + + true + beginChunk + + + true + beginChunk + + + true + beginChunk + + + true + beginChunk + + + true + beginChunk + + + true + beginChunk + + + true + beginChunk + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + false + everyChunk + + + true + everyChunk + + + true + beginChunk + + + true + beginChunk + + + true + beginChunk + + + true + beginChunk + + + false + + + true + + + true + + + true + + + true + + + true + + + true + true + + + true + true + + + true + + + true + 0 ms + + + true + 0 ms + + + true + 0 ms + + + true + 0 ms + + + true + 0 ms + + + true + 0 ms + + + true + 0 ms + + + true + 0 ms + + + false + 0 ms + + + false + 0 ms + + + true + 0 ms + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + false + true + + + true + + + false + everyChunk + + + false + + + true + true + 0 ns + + + true + beginChunk + + + true + 1000 ms + + + true + 100 ms + + + true + 10 s + + + true + + + false + + + true + beginChunk + + + true + everyChunk + + + true + 100 ms + + + true + beginChunk + + + true + everyChunk + + + true + + + true + beginChunk + + + true + beginChunk + + + true + 10 s + + + true + 1000 ms + + + true + 10 s + + + true + beginChunk + + + true + endChunk + + + true + 5 s + + + true + beginChunk + + + true + everyChunk + + + true + true + + + true + true + + + true + everyChunk + + + true + endChunk + + + true + endChunk + + + true + true + 10 ms + + + true + true + 10 ms + + + true + true + 10 ms + + + true + true + 10 ms + + + true + true + 10 ms + + + false + true + + + true + true + + + true + 1000 ms + + + true + + + true + + + true + + + true + + + true + 10 ms + + + true + 0 ms + + + 10 ms + true + + + true + 10 ms + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10 ms + 10 ms + 10 ms + false + + diff --git a/samples/maven-java-jdk11-custom/jfr-config/sample.jfr b/samples/maven-java-jdk11-custom/jfr-config/sample.jfr new file mode 100644 index 0000000..e69de29 diff --git a/samples/maven-java-jdk11-custom/kubernetes/010_configmap.yaml b/samples/maven-java-jdk11-custom/kubernetes/010_configmap.yaml new file mode 100644 index 0000000..aa37c26 --- /dev/null +++ b/samples/maven-java-jdk11-custom/kubernetes/010_configmap.yaml @@ -0,0 +1,662 @@ +kind: ConfigMap +metadata: + name: spring-boot-config +apiVersion: v1 +data: + application.yaml: |- + # Spring関連 + spring: + resources: + # 静的リソースへのマッピングを解除 + add-mappings: false + mvc: + throw-exception-if-no-handler-found: true + + # アプリケーションで利用する設定 + server: + error: + path: /error + restTemplate: + defaultMaxPerRoute: 5 + maxTotal: 30 + connectionRequestTimeout: 2000 + connectTimeout: 2000 + readTimeout: 3000 + socketTimeout: 3000 + context-path: / + + management: + export.simple.enabled: true + endpoints.web.exposure.include: + - metrics + - info + - health + - env + profile.jfc: |- + + + + true + everyChunk + + + true + 1000 ms + + + true + everyChunk + + + true + 1000 ms + + + true + + + true + + + true + true + 10 ms + + + true + true + 10 ms + + + true + true + 10 ms + + + true + true + 10 ms + + + true + true + 10 ms + + + true + true + 0 ms + + + true + true + 0 ms + + + true + true + 0 ms + + + true + true + + + false + true + 0 ms + + + false + true + + + false + + + true + beginChunk + + + true + beginChunk + + + true + 10 ms + + + true + 10 ms + + + true + 0 ms + + + false + 0 ms + + + false + 0 ms + + + false + 0 ms + + + false + 0 ms + + + false + 0 ms + + + true + 0 ms + + + true + true + + + true + 60 s + + + true + beginChunk + + + true + beginChunk + + + true + beginChunk + + + true + beginChunk + + + true + beginChunk + + + true + beginChunk + + + true + beginChunk + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + false + everyChunk + + + true + everyChunk + + + true + beginChunk + + + true + beginChunk + + + true + beginChunk + + + true + beginChunk + + + false + + + true + + + true + + + true + + + true + + + true + + + true + true + + + true + true + + + true + + + true + 0 ms + + + true + 0 ms + + + true + 0 ms + + + true + 0 ms + + + true + 0 ms + + + true + 0 ms + + + true + 0 ms + + + true + 0 ms + + + false + 0 ms + + + false + 0 ms + + + true + 0 ms + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + false + true + + + true + + + false + everyChunk + + + false + + + true + true + 0 ns + + + true + beginChunk + + + true + 1000 ms + + + true + 100 ms + + + true + 10 s + + + true + + + false + + + true + beginChunk + + + true + everyChunk + + + true + 100 ms + + + true + beginChunk + + + true + everyChunk + + + true + + + true + beginChunk + + + true + beginChunk + + + true + 10 s + + + true + 1000 ms + + + true + 10 s + + + true + beginChunk + + + true + endChunk + + + true + 5 s + + + true + beginChunk + + + true + everyChunk + + + true + true + + + true + true + + + true + everyChunk + + + true + endChunk + + + true + endChunk + + + true + true + 10 ms + + + true + true + 10 ms + + + true + true + 10 ms + + + true + true + 10 ms + + + true + true + 10 ms + + + false + true + + + true + true + + + true + 1000 ms + + + true + + + true + + + true + + + true + + + true + 10 ms + + + true + 0 ms + + + 10 ms + true + + + true + 10 ms + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10 ms + 10 ms + 10 ms + false + + + + + diff --git a/samples/maven-java-jdk11-custom/kubernetes/020_statefulset.yml b/samples/maven-java-jdk11-custom/kubernetes/020_statefulset.yml new file mode 100644 index 0000000..3fc3f95 --- /dev/null +++ b/samples/maven-java-jdk11-custom/kubernetes/020_statefulset.yml @@ -0,0 +1,76 @@ +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: k8s-jmc-sample +spec: + replicas: 1 + serviceName: k8s-jmc-sample + selector: + matchLabels: + app: k8s-jmc-sample + tire: backend + template: + metadata: + labels: + app: k8s-jmc-sample + tire: backend + spec: + containers: + - name: k8s-jmc-sample + image: gcr.io/{change-it-me}/k8s-jmc-sample:0.1.0-SNAPSHOT + imagePullPolicy: Always + resources: + requests: + cpu: 300m + memory: 512Mi + limits: + cpu: 900m + memory: 512Mi + ports: + - containerPort: 30001 + livenessProbe: + httpGet: + path: /actuator/health + port: 30001 + periodSeconds: 10 + timeoutSeconds: 5 + successThreshold: 1 + failureThreshold: 30 + initialDelaySeconds: 30 + readinessProbe: + failureThreshold: 30 + httpGet: + path: /actuator/health + port: 30001 + scheme: HTTP + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 5 + env: + - name: GET_HOSTS_FROM + value: dns + - name: SPRING_PROFILES_ACTIVE + value: "development" + - name: SPRING_SERVER_PORT + value: "30001" + volumeMounts: + - mountPath: /spring-boot/config + name: spring-boot-config + - mountPath: /spring-boot/jfr + name: flight-record-dir + volumes: + - name: spring-boot-config + configMap: + name: spring-boot-config + volumeClaimTemplates: + - metadata: + name: flight-record-dir + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 10Gi + + + \ No newline at end of file diff --git a/samples/maven-java-jdk11-custom/kubernetes/030_service.yaml b/samples/maven-java-jdk11-custom/kubernetes/030_service.yaml new file mode 100644 index 0000000..b90b7f0 --- /dev/null +++ b/samples/maven-java-jdk11-custom/kubernetes/030_service.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: Service +metadata: + name: k8s-jmc-sample + labels: + app: k8s-jmc-sample + tire: backend +spec: + type: NodePort + ports: + - port: 30001 + targetPort: 30001 + nodePort: 30001 + name: k8s-jmc-sample + selector: + app: k8s-jmc-sample + tire: backend diff --git a/samples/maven-java-jdk11-custom/pom.xml b/samples/maven-java-jdk11-custom/pom.xml new file mode 100644 index 0000000..f1af125 --- /dev/null +++ b/samples/maven-java-jdk11-custom/pom.xml @@ -0,0 +1,90 @@ + + + 4.0.0 + + com.example.hrkm + k8s-jmc-sample + 0.1.0-SNAPSHOT + jar + + k8s-jmc-sample + + + org.springframework.boot + spring-boot-starter-parent + 2.0.4.RELEASE + + + + + UTF-8 + UTF-8 + 1.8 + + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-actuator + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + org.eclipse.jgit + org.eclipse.jgit + 5.0.1.201806211838-r + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + com.google.cloud.tools + jib-maven-plugin + 0.9.8 + + + openjdk:11-jdk + + + gcr.io/${gcp.project.name}/${project.name}:${project.version} + + + true + + -XX:StartFlightRecording=name=sample,filename=/spring-boot/jfr/sample.jfr,delay=30s,maxage=2h,maxsize=10m,dumponexit=true,settings=/spring-boot/config/profile.jfc + -Dcom.sun.management.jmxremote.port=7199 + -Dcom.sun.management.jmxremote.rmi.port=7199 + -Dcom.sun.management.jmxremote.authenticate=false + -Dcom.sun.management.jmxremote.ssl=false + + + --server.port=${SPRING_SERVER_PORT} + --spring.config.location=/spring-boot/config/application.yaml + + + + + + + + + diff --git a/samples/maven-java-jdk11-custom/settings.xml b/samples/maven-java-jdk11-custom/settings.xml new file mode 100644 index 0000000..de53b57 --- /dev/null +++ b/samples/maven-java-jdk11-custom/settings.xml @@ -0,0 +1,280 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/maven-java-jdk11-custom/src/main/java/com/example/hrkm/springbootsample/Application.java b/samples/maven-java-jdk11-custom/src/main/java/com/example/hrkm/springbootsample/Application.java new file mode 100644 index 0000000..899afe4 --- /dev/null +++ b/samples/maven-java-jdk11-custom/src/main/java/com/example/hrkm/springbootsample/Application.java @@ -0,0 +1,12 @@ +package com.example.hrkm.springbootsample; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } +} diff --git a/samples/maven-java-jdk11-custom/src/main/java/com/example/hrkm/springbootsample/controller/OOMController.java b/samples/maven-java-jdk11-custom/src/main/java/com/example/hrkm/springbootsample/controller/OOMController.java new file mode 100644 index 0000000..09c3449 --- /dev/null +++ b/samples/maven-java-jdk11-custom/src/main/java/com/example/hrkm/springbootsample/controller/OOMController.java @@ -0,0 +1,34 @@ +package com.example.hrkm.springbootsample.controller; + +import java.io.ByteArrayOutputStream; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/oom") +public class OOMController { + private Logger log = LoggerFactory.getLogger(getClass()); + + + @RequestMapping(value = "/trigger", method = RequestMethod.GET) + public String trigger() throws Exception { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + + byte[] src = new byte[1024 * 1024]; + for (int i = 0, len = src.length; i < len; i++) { + src[i] = (byte) (0x000000ff & i); + } + + // 1MiB x 8092 bytes + for (int i = 0, len = 1024 * 1024; i < len; i++) { + out.write(src, 0, src.length); + log.info("dummy memory size = {}", out.toByteArray().length); + + Thread.sleep(10); + } + return "hello."; + } +} diff --git a/samples/maven-java-jdk11-custom/src/main/java/com/example/hrkm/springbootsample/controller/ProfileController.java b/samples/maven-java-jdk11-custom/src/main/java/com/example/hrkm/springbootsample/controller/ProfileController.java new file mode 100644 index 0000000..21f7689 --- /dev/null +++ b/samples/maven-java-jdk11-custom/src/main/java/com/example/hrkm/springbootsample/controller/ProfileController.java @@ -0,0 +1,22 @@ +package com.example.hrkm.springbootsample.controller; + +import java.util.List; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import com.example.hrkm.springbootsample.service.FooService; + +@RestController +@RequestMapping("/profile") +public class ProfileController { + @Autowired + private FooService fooService; + + @RequestMapping(value = "/trigger", method = RequestMethod.GET) + public List trigger( + @RequestParam(value = "q", required = false, defaultValue = "java") String query) { + return this.fooService.search(query); + } +} diff --git a/samples/maven-java-jdk11-custom/src/main/java/com/example/hrkm/springbootsample/repository/FooRepository.java b/samples/maven-java-jdk11-custom/src/main/java/com/example/hrkm/springbootsample/repository/FooRepository.java new file mode 100644 index 0000000..ef4f847 --- /dev/null +++ b/samples/maven-java-jdk11-custom/src/main/java/com/example/hrkm/springbootsample/repository/FooRepository.java @@ -0,0 +1,68 @@ +package com.example.hrkm.springbootsample.repository; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.internal.storage.file.FileRepository; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Repository; + +@Repository +public class FooRepository { + + private final String githubReposiory = "https://github.com/h-r-k-matsumoto/k8s-jmc-sample.git"; + + private Logger log = LoggerFactory.getLogger(getClass()); + + public List search(String query) { + Path homePath = this.initRepository(); + List result = new ArrayList<>(); + this.grep(homePath, homePath, query.toUpperCase(), result); + return result; + } + + private void grep(Path home, Path path, String query, List result) { + log.info("grep {}", path); + + try { + Files.list(path).forEach((f) -> { + if (!Files.exists(f)) { + return; + } else if (Files.isDirectory(f)) { + grep(home, f, query, result); + } else { + String filename = f.getFileName().toString(); + if (filename.toUpperCase().indexOf(query) != -1) { + result.add(home.relativize(f).toString()); + } + } + }); + } catch (Exception ex) { + throw new RuntimeException(ex); + } + } + + private Path initRepository() { + log.info("init repository start"); + try { + Path gitHomePath = Files.createTempDirectory("git"); + Path repository = gitHomePath.resolve("k8s-jmc-sample"); + Path gitFile = repository.resolve(".git"); + + try (Git git = new Git(new FileRepository(gitFile.toFile()));) { + Git.cloneRepository()// + .setDirectory(repository.toFile())// + .setURI(githubReposiory)// + .setBranch("master").call(); + } + log.info("init repository end"); + + return repository; + } catch (Exception ex) { + throw new RuntimeException(ex); + } + } +} diff --git a/samples/maven-java-jdk11-custom/src/main/java/com/example/hrkm/springbootsample/service/FooService.java b/samples/maven-java-jdk11-custom/src/main/java/com/example/hrkm/springbootsample/service/FooService.java new file mode 100644 index 0000000..cc137bb --- /dev/null +++ b/samples/maven-java-jdk11-custom/src/main/java/com/example/hrkm/springbootsample/service/FooService.java @@ -0,0 +1,26 @@ +package com.example.hrkm.springbootsample.service; + +import java.util.List; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.util.StringUtils; +import com.example.hrkm.springbootsample.repository.FooRepository; + +@Service +public class FooService { + + private Logger log = LoggerFactory.getLogger(getClass()); + + @Autowired + private FooRepository fooRepository; + + public List search(String query) { + if (StringUtils.isEmpty(query)) { + throw new IllegalArgumentException(" query is required."); + } + log.info(" query = {}", query); + return this.fooRepository.search(query); + } +} diff --git a/samples/maven-java-jdk11-custom/src/main/resources/application.yaml b/samples/maven-java-jdk11-custom/src/main/resources/application.yaml new file mode 100644 index 0000000..768533e --- /dev/null +++ b/samples/maven-java-jdk11-custom/src/main/resources/application.yaml @@ -0,0 +1,7 @@ +management: + export.simple.enabled: true + endpoints.web.exposure.include: + - metrics + - info + - health + - env diff --git a/tools/build-push.sh b/tools/build-push.sh new file mode 100644 index 0000000..c3d7ebd --- /dev/null +++ b/tools/build-push.sh @@ -0,0 +1,12 @@ +IMAGES=$(docker-compose config | yq '.' | jq -r '..|.image? | select(.!=null)') +IMAGES=(${IMAGES// / }) + +for i in "${!IMAGES[@]}"; do + IMAGE_AND_TAG=${IMAGES[i]} + echo "" + echo "[$((i+1))] processing image ${IMAGE_AND_TAG}" + IMAGE=${IMAGE_AND_TAG%:*} + TAG=${IMAGE_AND_TAG#*:} + echo "" + echo "* IMAGE=$IMAGE and TAG=$TAG" +done diff --git a/tools/list-images-to-process.sh b/tools/list-images-to-process.sh new file mode 100644 index 0000000..f72992b --- /dev/null +++ b/tools/list-images-to-process.sh @@ -0,0 +1,27 @@ +#!/bin/sh + +IMAGES=$(docker-compose config | yq '.' | jq -r '..|.image? | select(.!=null)') + +for IMAGE in ${IMAGES}; do + DOCKER_HUB_IMAGE_TAG=${IMAGE}; + echo "processing image ${DOCKER_HUB_IMAGE_TAG} "; + IMAGE=${DOCKER_HUB_IMAGE_TAG%:*}; + TAG=${DOCKER_HUB_IMAGE_TAG#*:}; + GROUP=${IMAGE/unmazedboot\//} + + IMG_NO_GRP=${IMAGE/GROUP/} + + CI_COMMIT_SHA=23920390293 + CI_REGISTRY_IMAGE="gitlab.com/regi/unmazed" + + echo "image name ${IMAGE} tag ${TAG} and group ${GROUP} image no group ${IMG_NO_GRP}"; + + GITLAB_IMAGE="${CI_REGISTRY_IMAGE}/${GROUP}/${TAG}:${CI_COMMIT_SHA}"; + + echo "=> Tag image ${DOCKER_HUB_IMAGE_TAG} for gitlab as ${GITLAB_IMAGE}"; + + echo "<= Revert is 'docker pull ${GITLAB_IMAGE} && \n docker tag ${GITLAB_IMAGE} ${DOCKER_HUB_IMAGE_TAG}' && \n docker push ${DOCKER_HUB_IMAGE_TAG}" + + echo "" +done +