From 0c4690017b7e9bb8f176adf9da6089838d7345d3 Mon Sep 17 00:00:00 2001 From: Jonathan Knight Date: Thu, 23 Sep 2021 19:43:43 +0300 Subject: [PATCH 1/2] Add simple example. Reorganise and clean-up examples docs Bump Coherence version to 21.06.2 --- .github/workflows/build.yaml | 6 + .github/workflows/coherence-matrix.yaml | 6 +- Makefile | 18 +- api/v1/zz_generated.deepcopy.go | 1 - docs/about/01_overview.adoc | 4 +- docs/examples/010_overview.adoc | 69 ---- docs/examples/020_deployment.adoc | 14 - docs/examples/030_federation.adoc | 14 - docs/examples/500_autoscaler.adoc | 12 - docs/images/GitHub-Mark-32px.png | Bin 0 -> 2940 bytes docs/metrics/020_metrics.adoc | 15 +- docs/no-operator/010_overview.adoc | 68 ---- docs/no-operator/015_server.adoc | 14 - docs/no-operator/016_client.adoc | 14 - docs/no-operator/020_simple.adoc | 14 - docs/no-operator/030_metrics.adoc | 14 - docs/no-operator/040_tls.adoc | 14 - docs/sitegen.yaml | 19 +- .../000_overview.adoc | 5 +- .../.mvn/wrapper/MavenWrapperDownloader.java | 0 .../.mvn/wrapper/maven-wrapper.jar | Bin .../.mvn/wrapper/maven-wrapper.properties | 0 examples/015_simple_image/README.adoc | 258 +++++++++++++++ examples/015_simple_image/build.gradle | 40 +++ .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 59203 bytes .../gradle/wrapper/gradle-wrapper.properties | 5 + examples/015_simple_image/gradlew | 185 +++++++++++ examples/015_simple_image/gradlew.bat | 89 +++++ .../{autoscaler => 015_simple_image}/mvnw | 0 .../{autoscaler => 015_simple_image}/mvnw.cmd | 0 .../server-image => 015_simple_image}/pom.xml | 46 ++- examples/015_simple_image/settings.gradle | 7 + .../tls/FileBasedPasswordProvider.java | 2 +- .../resources/tangosol-coherence-override.xml | 0 .../src/main/resources/test-cache-config.xml | 0 examples/020_hello_world/README.adoc | 151 +++++++++ .../020_hello_world/default-coherence.yaml | 4 + examples/020_hello_world/simple.yaml | 10 + .../.mvn/wrapper/MavenWrapperDownloader.java | 0 .../.mvn/wrapper/maven-wrapper.jar | Bin .../.mvn/wrapper/maven-wrapper.properties | 0 .../README.adoc | 16 +- examples/{deployment => 021_deployment}/mvnw | 0 .../{deployment => 021_deployment}/mvnw.cmd | 0 .../{deployment => 021_deployment}/pom.xml | 10 +- .../scripts/README.md | 0 .../scripts/port-forward-es.sh | 0 .../scripts/port-forward-grafana.sh | 0 .../scripts/port-forward-kibana.sh | 0 .../scripts/port-forward-prometheus.sh | 0 .../com/oracle/coherence/examples/Main.java | 2 +- .../com/oracle/coherence/examples/Person.java | 2 +- .../coherence/examples/package-info.java | 2 +- .../main/resources/client-cache-config.xml | 2 +- .../main/resources/helidon-logging.properties | 2 +- .../src/main/resources/proxy-cache-config.xml | 2 +- .../main/resources/storage-cache-config.xml | 2 +- .../src/main/resources/storage-pof-config.xml | 2 +- .../src/main/yaml/example-cluster-app.yaml | 0 .../yaml/example-cluster-persistence.yaml | 0 .../src/main/yaml/example-cluster-proxy.yaml | 0 .../src/main/yaml/example-cluster.yaml | 0 .../.mvn/wrapper/MavenWrapperDownloader.java | 0 .../.mvn/wrapper/maven-wrapper.jar | Bin .../.mvn/wrapper/maven-wrapper.properties | 0 examples/{tls => 090_tls}/README.adoc | 8 +- examples/{tls => 090_tls}/client/pom.xml | 0 .../k8s/client/FileBasedPasswordProvider.java | 0 .../coherence/examples/k8s/client/Main.java | 0 .../main/resources/client-cache-config.xml | 0 .../main/resources/tls-coherence-override.xml | 0 .../{tls => 090_tls}/manifests/ca-cert.yaml | 0 .../{tls => 090_tls}/manifests/ca-issuer.yaml | 0 .../manifests/client-keystore-password.yaml | 0 .../manifests/client-keystore.yaml | 0 .../manifests/client-no-tls.yaml | 0 .../{tls => 090_tls}/manifests/client.yaml | 0 .../manifests/coherence-cluster-2.yaml | 0 .../manifests/coherence-cluster-extend.yaml | 0 .../manifests/coherence-cluster-mgmt.yaml | 0 .../manifests/coherence-cluster-no-tls.yaml | 0 .../manifests/coherence-cluster.yaml | 0 .../manifests/install-certs.sh | 0 .../manifests/selfsigned-issuer.yaml | 0 .../manifests/server-keystore-password.yaml | 0 .../manifests/server-keystore.yaml | 0 .../manifests/uninstall-certs.sh | 0 examples/{tls => 090_tls}/mvnw | 0 examples/{tls => 090_tls}/mvnw.cmd | 0 examples/{tls => 090_tls}/pom.xml | 9 +- examples/{tls => 090_tls}/server/pom.xml | 4 - .../main/resources/server-cache-config.xml | 0 .../main/resources/tls-coherence-override.xml | 0 .../README.adoc | 9 +- .../main/resources/storage-cache-config.xml | 0 .../resources/tangosol-coherence-override.xml | 0 .../src/main/yaml/primary-cluster.yaml | 0 .../src/main/yaml/secondary-cluster.yaml | 0 .../.mvn/wrapper/MavenWrapperDownloader.java | 117 +++++++ .../.mvn/wrapper/maven-wrapper.jar | Bin 0 -> 50710 bytes .../.mvn/wrapper/maven-wrapper.properties | 2 + .../README.adoc | 8 +- .../images/autoscaler.png | Bin .../images/prometheus-ui-empty.png | Bin .../images/prometheus-ui-metrics.png | Bin .../k8s-metrics-server.yaml | 0 .../manifests/cluster.yaml | 0 .../manifests/hpa.yaml | 0 .../manifests/prometheus-adapter-values.yaml | 0 examples/200_autoscaler/mvnw | 310 ++++++++++++++++++ examples/200_autoscaler/mvnw.cmd | 182 ++++++++++ .../{autoscaler => 200_autoscaler}/pom.xml | 9 +- .../oracle/coherence/examples/HeapUsage.java | 2 +- .../coherence/examples/HeapUsageMBean.java | 2 +- .../coherence/examples/package-info.java | 2 +- .../main/resources/client-cache-config.xml | 2 +- .../main/resources/coherence-cache-config.xml | 2 +- .../src/main/resources/custom-mbeans.xml | 2 +- examples/{helm => 300_helm}/README.adoc | 7 + examples/{helm => 300_helm}/chart/Chart.yaml | 0 examples/{helm => 300_helm}/chart/README.md | 0 .../chart/templates/NOTES.txt | 0 .../chart/templates/_helpers.tpl | 0 .../chart/templates/coherence.yaml | 0 .../chart/templates/hook.yaml | 0 examples/{helm => 300_helm}/chart/values.yaml | 0 .../400_Istio/README.adoc | 24 +- .../400_Istio}/images/istioKiali.png | Bin .../900_demo/README.adoc | 5 +- examples/900_demo/images/GitHub-Mark-64px.png | Bin 0 -> 2625 bytes .../900_demo}/images/coherence-demo.png | Bin examples/README.adoc | 92 +++++- .../no-operator/000_overview.adoc | 5 +- .../no-operator/01_simple_server/README.adoc | 11 +- examples/no-operator/02_metrics/README.adoc | 13 +- .../no-operator/03_extend_tls/README.adoc | 11 +- examples/no-operator/README.adoc | 86 ++--- examples/no-operator/server-image/README.adoc | 24 -- examples/no-operator/test-client/README.adoc | 1 + examples/no-operator/test-client/pom.xml | 2 +- examples/pom.xml | 20 +- java/pom.xml | 4 +- 142 files changed, 1670 insertions(+), 465 deletions(-) delete mode 100644 docs/examples/010_overview.adoc delete mode 100644 docs/examples/020_deployment.adoc delete mode 100644 docs/examples/030_federation.adoc delete mode 100644 docs/examples/500_autoscaler.adoc create mode 100644 docs/images/GitHub-Mark-32px.png delete mode 100644 docs/no-operator/010_overview.adoc delete mode 100644 docs/no-operator/015_server.adoc delete mode 100644 docs/no-operator/016_client.adoc delete mode 100644 docs/no-operator/020_simple.adoc delete mode 100644 docs/no-operator/030_metrics.adoc delete mode 100644 docs/no-operator/040_tls.adoc rename docs/examples/100_tls.adoc => examples/000_overview.adoc (85%) rename examples/{autoscaler => 015_simple_image}/.mvn/wrapper/MavenWrapperDownloader.java (100%) rename examples/{autoscaler => 015_simple_image}/.mvn/wrapper/maven-wrapper.jar (100%) rename examples/{autoscaler => 015_simple_image}/.mvn/wrapper/maven-wrapper.properties (100%) create mode 100644 examples/015_simple_image/README.adoc create mode 100644 examples/015_simple_image/build.gradle create mode 100644 examples/015_simple_image/gradle/wrapper/gradle-wrapper.jar create mode 100644 examples/015_simple_image/gradle/wrapper/gradle-wrapper.properties create mode 100755 examples/015_simple_image/gradlew create mode 100644 examples/015_simple_image/gradlew.bat rename examples/{autoscaler => 015_simple_image}/mvnw (100%) rename examples/{autoscaler => 015_simple_image}/mvnw.cmd (100%) rename examples/{no-operator/server-image => 015_simple_image}/pom.xml (56%) create mode 100644 examples/015_simple_image/settings.gradle rename examples/{no-operator/server-image => 015_simple_image}/src/main/java/com/oracle/coherence/examples/tls/FileBasedPasswordProvider.java (97%) rename examples/{no-operator/server-image => 015_simple_image}/src/main/resources/tangosol-coherence-override.xml (100%) rename examples/{no-operator/server-image => 015_simple_image}/src/main/resources/test-cache-config.xml (100%) create mode 100644 examples/020_hello_world/README.adoc create mode 100644 examples/020_hello_world/default-coherence.yaml create mode 100644 examples/020_hello_world/simple.yaml rename examples/{deployment => 021_deployment}/.mvn/wrapper/MavenWrapperDownloader.java (100%) rename examples/{deployment => 021_deployment}/.mvn/wrapper/maven-wrapper.jar (100%) rename examples/{deployment => 021_deployment}/.mvn/wrapper/maven-wrapper.properties (100%) rename examples/{deployment => 021_deployment}/README.adoc (97%) rename examples/{deployment => 021_deployment}/mvnw (100%) rename examples/{deployment => 021_deployment}/mvnw.cmd (100%) rename examples/{deployment => 021_deployment}/pom.xml (93%) rename examples/{deployment => 021_deployment}/scripts/README.md (100%) rename examples/{deployment => 021_deployment}/scripts/port-forward-es.sh (100%) rename examples/{deployment => 021_deployment}/scripts/port-forward-grafana.sh (100%) rename examples/{deployment => 021_deployment}/scripts/port-forward-kibana.sh (100%) rename examples/{deployment => 021_deployment}/scripts/port-forward-prometheus.sh (100%) rename examples/{deployment => 021_deployment}/src/main/java/com/oracle/coherence/examples/Main.java (98%) rename examples/{deployment => 021_deployment}/src/main/java/com/oracle/coherence/examples/Person.java (98%) rename examples/{deployment => 021_deployment}/src/main/java/com/oracle/coherence/examples/package-info.java (76%) rename examples/{deployment => 021_deployment}/src/main/resources/client-cache-config.xml (95%) rename examples/{deployment => 021_deployment}/src/main/resources/helidon-logging.properties (94%) rename examples/{deployment => 021_deployment}/src/main/resources/proxy-cache-config.xml (97%) rename examples/{deployment => 021_deployment}/src/main/resources/storage-cache-config.xml (96%) rename examples/{deployment => 021_deployment}/src/main/resources/storage-pof-config.xml (91%) rename examples/{deployment => 021_deployment}/src/main/yaml/example-cluster-app.yaml (100%) rename examples/{deployment => 021_deployment}/src/main/yaml/example-cluster-persistence.yaml (100%) rename examples/{deployment => 021_deployment}/src/main/yaml/example-cluster-proxy.yaml (100%) rename examples/{deployment => 021_deployment}/src/main/yaml/example-cluster.yaml (100%) rename examples/{tls => 090_tls}/.mvn/wrapper/MavenWrapperDownloader.java (100%) rename examples/{tls => 090_tls}/.mvn/wrapper/maven-wrapper.jar (100%) rename examples/{tls => 090_tls}/.mvn/wrapper/maven-wrapper.properties (100%) rename examples/{tls => 090_tls}/README.adoc (99%) rename examples/{tls => 090_tls}/client/pom.xml (100%) rename examples/{tls => 090_tls}/client/src/main/java/com/oracle/coherence/examples/k8s/client/FileBasedPasswordProvider.java (100%) rename examples/{tls => 090_tls}/client/src/main/java/com/oracle/coherence/examples/k8s/client/Main.java (100%) rename examples/{tls => 090_tls}/client/src/main/resources/client-cache-config.xml (100%) rename examples/{tls => 090_tls}/client/src/main/resources/tls-coherence-override.xml (100%) rename examples/{tls => 090_tls}/manifests/ca-cert.yaml (100%) rename examples/{tls => 090_tls}/manifests/ca-issuer.yaml (100%) rename examples/{tls => 090_tls}/manifests/client-keystore-password.yaml (100%) rename examples/{tls => 090_tls}/manifests/client-keystore.yaml (100%) rename examples/{tls => 090_tls}/manifests/client-no-tls.yaml (100%) rename examples/{tls => 090_tls}/manifests/client.yaml (100%) rename examples/{tls => 090_tls}/manifests/coherence-cluster-2.yaml (100%) rename examples/{tls => 090_tls}/manifests/coherence-cluster-extend.yaml (100%) rename examples/{tls => 090_tls}/manifests/coherence-cluster-mgmt.yaml (100%) rename examples/{tls => 090_tls}/manifests/coherence-cluster-no-tls.yaml (100%) rename examples/{tls => 090_tls}/manifests/coherence-cluster.yaml (100%) rename examples/{tls => 090_tls}/manifests/install-certs.sh (100%) rename examples/{tls => 090_tls}/manifests/selfsigned-issuer.yaml (100%) rename examples/{tls => 090_tls}/manifests/server-keystore-password.yaml (100%) rename examples/{tls => 090_tls}/manifests/server-keystore.yaml (100%) rename examples/{tls => 090_tls}/manifests/uninstall-certs.sh (100%) rename examples/{tls => 090_tls}/mvnw (100%) rename examples/{tls => 090_tls}/mvnw.cmd (100%) rename examples/{tls => 090_tls}/pom.xml (90%) rename examples/{tls => 090_tls}/server/pom.xml (93%) rename examples/{tls => 090_tls}/server/src/main/resources/server-cache-config.xml (100%) rename examples/{tls => 090_tls}/server/src/main/resources/tls-coherence-override.xml (100%) rename examples/{federation => 100_federation}/README.adoc (96%) rename examples/{federation => 100_federation}/src/main/resources/storage-cache-config.xml (100%) rename examples/{federation => 100_federation}/src/main/resources/tangosol-coherence-override.xml (100%) rename examples/{federation => 100_federation}/src/main/yaml/primary-cluster.yaml (100%) rename examples/{federation => 100_federation}/src/main/yaml/secondary-cluster.yaml (100%) create mode 100644 examples/200_autoscaler/.mvn/wrapper/MavenWrapperDownloader.java create mode 100644 examples/200_autoscaler/.mvn/wrapper/maven-wrapper.jar create mode 100644 examples/200_autoscaler/.mvn/wrapper/maven-wrapper.properties rename examples/{autoscaler => 200_autoscaler}/README.adoc (99%) rename examples/{autoscaler => 200_autoscaler}/images/autoscaler.png (100%) rename examples/{autoscaler => 200_autoscaler}/images/prometheus-ui-empty.png (100%) rename examples/{autoscaler => 200_autoscaler}/images/prometheus-ui-metrics.png (100%) rename examples/{autoscaler => 200_autoscaler}/k8s-metrics-server.yaml (100%) rename examples/{autoscaler => 200_autoscaler}/manifests/cluster.yaml (100%) rename examples/{autoscaler => 200_autoscaler}/manifests/hpa.yaml (100%) rename examples/{autoscaler => 200_autoscaler}/manifests/prometheus-adapter-values.yaml (100%) create mode 100755 examples/200_autoscaler/mvnw create mode 100644 examples/200_autoscaler/mvnw.cmd rename examples/{autoscaler => 200_autoscaler}/pom.xml (93%) rename examples/{autoscaler => 200_autoscaler}/src/main/java/com/oracle/coherence/examples/HeapUsage.java (99%) rename examples/{autoscaler => 200_autoscaler}/src/main/java/com/oracle/coherence/examples/HeapUsageMBean.java (94%) rename examples/{autoscaler => 200_autoscaler}/src/main/java/com/oracle/coherence/examples/package-info.java (77%) rename examples/{autoscaler => 200_autoscaler}/src/main/resources/client-cache-config.xml (95%) rename examples/{autoscaler => 200_autoscaler}/src/main/resources/coherence-cache-config.xml (97%) rename examples/{autoscaler => 200_autoscaler}/src/main/resources/custom-mbeans.xml (91%) rename examples/{helm => 300_helm}/README.adoc (98%) rename examples/{helm => 300_helm}/chart/Chart.yaml (100%) rename examples/{helm => 300_helm}/chart/README.md (100%) rename examples/{helm => 300_helm}/chart/templates/NOTES.txt (100%) rename examples/{helm => 300_helm}/chart/templates/_helpers.tpl (100%) rename examples/{helm => 300_helm}/chart/templates/coherence.yaml (100%) rename examples/{helm => 300_helm}/chart/templates/hook.yaml (100%) rename examples/{helm => 300_helm}/chart/values.yaml (100%) rename docs/examples/800_istio.adoc => examples/400_Istio/README.adoc (79%) rename {docs => examples/400_Istio}/images/istioKiali.png (100%) rename docs/examples/900_demo.adoc => examples/900_demo/README.adoc (75%) create mode 100644 examples/900_demo/images/GitHub-Mark-64px.png rename {docs => examples/900_demo}/images/coherence-demo.png (100%) rename docs/examples/810_helm.adoc => examples/no-operator/000_overview.adoc (84%) delete mode 100644 examples/no-operator/server-image/README.adoc diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index d1beb328c..b5c59787a 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -137,6 +137,12 @@ jobs: run: | make e2e-helm-test + - name: Examples Tests + shell: bash + run: | + make build-examples + make test-examples + - name: Deploy Snapshots if: ${{ github.ref == 'refs/heads/master' && success() }} env: diff --git a/.github/workflows/coherence-matrix.yaml b/.github/workflows/coherence-matrix.yaml index 9742a23d1..821fe09a0 100644 --- a/.github/workflows/coherence-matrix.yaml +++ b/.github/workflows/coherence-matrix.yaml @@ -29,7 +29,7 @@ jobs: fail-fast: false matrix: coherenceVersion: - - "21.06.1" + - "21.06.2" - "20.12.2" - "14.1.2-0-0-SNAPSHOT" - "14.1.1-0-7-SNAPSHOT" @@ -39,8 +39,8 @@ jobs: - "12.2.1-4-11-SNAPSHOT" - "12.2.1-3-15-SNAPSHOT" include: - - coherenceVersion: "21.06.1" - coherence-image: "ghcr.io/oracle/coherence-ce:21.06.1" + - coherenceVersion: "21.06.2" + coherence-image: "ghcr.io/oracle/coherence-ce:21.06.2" - coherenceVersion: "20.12.2" coherence-image: "ghcr.io/oracle/coherence-ce:20.12.2" - coherenceVersion: "14.1.2-0-0-SNAPSHOT" diff --git a/Makefile b/Makefile index 082962ae2..8e31d9081 100644 --- a/Makefile +++ b/Makefile @@ -32,8 +32,8 @@ COMPATIBLE_SELECTOR = control-plane=coherence # ---------------------------------------------------------------------------------------------------------------------- # The Coherence image to use for deployments that do not specify an image # ---------------------------------------------------------------------------------------------------------------------- -COHERENCE_VERSION ?= 21.06.1 -COHERENCE_IMAGE ?= oraclecoherence/coherence-ce:21.06.1 +COHERENCE_VERSION ?= 21.06.2 +COHERENCE_IMAGE ?= oraclecoherence/coherence-ce:21.06.2 # This is the Coherence image that will be used in tests. # Changing this variable will allow test builds to be run against different Coherence versions # without altering the default image name. @@ -606,8 +606,7 @@ copyright: ## Check copyright headers org.glassfish.copyright.Copyright -C hack/copyright.txt \ -X .adoc \ -X bin/ \ - -X build/_output/ \ - -X build/tools/ \ + -X build/ \ -X clientset/ \ -X dashboards/ \ -X /Dockerfile \ @@ -622,6 +621,10 @@ copyright: ## Check copyright headers -X hack/sdk/ \ -X go.mod \ -X go.sum \ + -X .gradle/ \ + -X gradle/ \ + -X gradlew \ + -X gradlew.bat \ -X HEADER.txt \ -X helm-charts/coherence-operator/templates/NOTES.txt \ -X .iml \ @@ -629,6 +632,7 @@ copyright: ## Check copyright headers -X java/src/copyright/EXCLUDE.txt \ -X Jenkinsfile \ -X .jar \ + -X jib-cache/ \ -X .jks \ -X .json \ -X LICENSE.txt \ @@ -1482,7 +1486,7 @@ mvn-deploy: java-client # ---------------------------------------------------------------------------------------------------------------------- .PHONY: build-examples build-examples: - ./mvnw -B -f ./examples package -DskipTests -P docker $(MAVEN_BUILD_OPTS) + ./mvnw -B -f ./examples package jib:dockerBuild -DskipTests $(MAVEN_BUILD_OPTS) # ---------------------------------------------------------------------------------------------------------------------- # Build and test the examples @@ -1800,7 +1804,9 @@ docs: -Doperator.image=$(OPERATOR_IMAGE) \ -Doperator.utils.image=$(UTILS_IMAGE) \ $(MAVEN_OPTIONS) - + mkdir -p $(BUILD_OUTPUT)/docs/images/images + cp -r docs/images/ build/_output/docs/images/ + find examples/ -name \*.png -exec cp {} build/_output/docs/images/images/ \; # ---------------------------------------------------------------------------------------------------------------------- # Start a local web server to serve the documentation. diff --git a/api/v1/zz_generated.deepcopy.go b/api/v1/zz_generated.deepcopy.go index b9d7a6ac8..06c8ce62b 100644 --- a/api/v1/zz_generated.deepcopy.go +++ b/api/v1/zz_generated.deepcopy.go @@ -1,4 +1,3 @@ -//go:build !ignore_autogenerated // +build !ignore_autogenerated /* diff --git a/docs/about/01_overview.adoc b/docs/about/01_overview.adoc index 9830c2db8..0c0c65bac 100644 --- a/docs/about/01_overview.adoc +++ b/docs/about/01_overview.adoc @@ -51,14 +51,14 @@ Hints and tips to troubleshoot common issues. ==== [CARD] .Guides & Examples -[icon=explore,link=docs/examples/010_overview.adoc] +[icon=explore,link=examples/000_overview.adoc] -- There are a number of examples of using the Coherence Operator and different Coherence features in Kubernetes. -- [CARD] .Non-Operator Guides & Examples -[icon=fa-ban,link=docs/no-operator/010_overview.adoc] +[icon=fa-ban,link=examples/no-operator/000_overview.adoc] -- Examples for those in the unlucky situation of not being able to install Operators, CRDs, RBAC cluster roles etc, and therfore need to manage Coherence clusters manually. -- diff --git a/docs/examples/010_overview.adoc b/docs/examples/010_overview.adoc deleted file mode 100644 index 63fbd8f50..000000000 --- a/docs/examples/010_overview.adoc +++ /dev/null @@ -1,69 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2021, Oracle and/or its affiliates. - Licensed under the Universal Permissive License v 1.0 as shown at - http://oss.oracle.com/licenses/upl. - -/////////////////////////////////////////////////////////////////////////////// - -= Overview - -== Examples Overview - -There are a number of examples which show you how to build and deploy applications for the Coherence Operator. - -[PILLARS] -==== -[CARD] -.Deployment -[link=docs/examples/020_deployment.adoc] --- -This example showcases how to deploy Coherence applications using the Coherence Operator. --- - -[CARD] -.Federation -[link=docs/examples/030_federation.adoc] --- -This is a simple Coherence federation example. The federation feature requires Coherence Grid Edition. --- - - -[CARD] -.TLS -[link=docs/examples/100_tls.adoc] --- -Securing Coherence clusters using TLS. --- - -[CARD] -.Autoscaling -[link=docs/examples/500_autoscaler.adoc] --- -Scaling Coherence clusters using the horizontal Pod Autoscaler. --- - -[CARD] -.Istio -[link=docs/examples/800_istio.adoc] --- -Istio Support --- - -[CARD] -.Helm -[link=docs/examples/810_helm.adoc] --- -Manage Coherence resources using Helm. --- -==== - -[PILLARS] -==== -[CARD] -.Coherence Demo App -[link=docs/examples/900_demo.adoc] --- -Deploying the Coherence demo application. --- -==== diff --git a/docs/examples/020_deployment.adoc b/docs/examples/020_deployment.adoc deleted file mode 100644 index 70128b4cb..000000000 --- a/docs/examples/020_deployment.adoc +++ /dev/null @@ -1,14 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2021, Oracle and/or its affiliates. - Licensed under the Universal Permissive License v 1.0 as shown at - http://oss.oracle.com/licenses/upl. - -/////////////////////////////////////////////////////////////////////////////// - -= Coherence Deployment Example - - -// DO NOT EDIT THIS FILE -// This file imports the example README.adoc file. -include::../../examples/deployment/README.adoc[] diff --git a/docs/examples/030_federation.adoc b/docs/examples/030_federation.adoc deleted file mode 100644 index d4c99dd31..000000000 --- a/docs/examples/030_federation.adoc +++ /dev/null @@ -1,14 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2021, Oracle and/or its affiliates. - Licensed under the Universal Permissive License v 1.0 as shown at - http://oss.oracle.com/licenses/upl. - -/////////////////////////////////////////////////////////////////////////////// - -= Coherence Federation Example - - -// DO NOT EDIT THIS FILE -// This file imports the example README.adoc file. -include::../../examples/federation/README.adoc[] diff --git a/docs/examples/500_autoscaler.adoc b/docs/examples/500_autoscaler.adoc deleted file mode 100644 index 3c24867ab..000000000 --- a/docs/examples/500_autoscaler.adoc +++ /dev/null @@ -1,12 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2021, Oracle and/or its affiliates. - Licensed under the Universal Permissive License v 1.0 as shown at - http://oss.oracle.com/licenses/upl. - -/////////////////////////////////////////////////////////////////////////////// -= Autoscaling Coherence Cluster - -// DO NOT EDIT THIS FILE -// This file imports the example README.adoc file. -include::../../examples/autoscaler/README.adoc[] diff --git a/docs/images/GitHub-Mark-32px.png b/docs/images/GitHub-Mark-32px.png new file mode 100644 index 0000000000000000000000000000000000000000..663841a2447cbe2e9a44abe94827ae1a98d5ec83 GIT binary patch literal 2940 zcmai02|QG58$W|=DM>`4$+V!%lEO>|W1lQ(sD@OAInzwcKCX#Nh-yNMCDbUAq)Ud| zgk-N|Nof;lp}Mq9y44pYzB3Yizv}BfzjvPJJm>lUpXEKz{Eo=m%XNnOJaqs7W)R(+ zNRWifx2iJq%a4e74+$8bR*+C%Oo6Z)n`E)i1?&xC)H}Rwd zGgxwiDF7(uz@{SRC`_`!a}=j^Iqdh~GE)Z~VC{%cOI5OM<$>wcCVX#;%3cUigVud;6 zVb0&d5>SNZEI#5Z$u}M+kRQxra0CoC3ohrS1hK;ecw=LEpvg6nCzIppIT?z@pQsC} z5GAB=P#7c{#bly>hU5!K;8c=7Me==ja6l9Z$g!64+0_!$w@xc{HP&p-kO?H9r2 zPsa0}>$$o!Uc;ZpfMQd6<7jhm4hP& zz0#6kjYY3?vO)a-ooeF*Es@0+P*}m>1TABV*7aspI4D^(~dR z7w5#CeiGZg&j1be^6fWH^+gW@v zFgE)0wIQ1~?V+`YEpxBdy=uE?cl}-aYKuo6QvVC|(;C|yQfq2z>XR@>vu`52ZIn8y zPcK{NcWNC9mmht%C7b0R8N}oL%kD7I$(5e=eiYzVM$S#0)&FjIk44KXu0Os+Iy1hd za#(mn%FQ`?*UK=(EHbBqE`Gbul6HSqHns%IP<}uwC10G*t=&_%Rk7kf@f!Qu+BBke z*?~o3Q&3AWPLuj6m|VNLc*9sifTZKRJD{q78F=$%>tETUJ@o2sT+o>%X4@n;j$OE{ zzKbH!&r2?A&kpOZ_WkQlbiPKqkaRQVgr3P9m!g|_nFOmP9K{V{^X4vO0h*^wiM^v% zq@UMw*!{yN#?@{@JV1>?zY8N*Er<`O^eYzV>Qr8~>s&KUtbaA==sq%`AcoRiW0Xh; zMB#UPj3{jCeX40_Zn=ql^1Z3`Vez!eyM8BS8oFcdPc05`XRcSECC2F-*?0>l%bLFT zlZDf~dX5`9S=OL*eBi|vu7F1S2Un?IdQx|Fl-;0gPjJ$~OkgSflNpv2dwUNoH(p z?E1Pcb>6&q{Gl5r7+Uhjl%$;NhY6)%zIKS7is4d+EQKrEgGyh5>k{4Bi_1$(A8714 zmIgcE87~+S3HCd*J8aWUNzjICB?^!SbMnZ4#&F}vab5p{f#N{TO07}@V(budxwJdc zw{xND^U#;9(ni4IlEmxv=EqNVg(H+j{{8753v`rSX=ai5$ez~5S6?`O$wRcNvL+ER z)VFum9FC8qrKGmVl$1AET48OAkM>KF)mNIcj zrbkgx`4S}qo|rd>^F*3c`<5hA(Ty$~%DqQkKIaiz^fa%bOQO8GX+n3RqP9o z5m(rD6bJ9+ny0=N+Q(mZ=mn5@R{r;7ieTHqZLeL0-Zn)2p0RpqWD;si!3RGZ6Jb^U z0iA2O!6V&t!`d$_ZN1}-i)1jX49jfklDL+~g&!%>EsqfDhR!O1!i3nqv6p5ZRcD} zRg~>(p<4uNM{RQvYup%Bnhy#jv55gM#lsEPTDuxMs@=T? zER-l9^$dByPOYq>f7OOK`}I4-T8T z;^EnIL={ozL76?L;LL|^i+YqEXZK+$w?Fv}x_1>?DL(q|?$c||Tx=vID|wrxt0PPM zDd*6@TGrS=MMtIDM~{k3|E7+-mX2Oo@;Uv>_))meev_Ij*NNx=XE*%8`GuV?H!jpB zy{YmA+Txf@+{aCQuXM$y)UI|nrR{${J8s~z7EYsy*)um~2ALQl(AxRzHu|C|P@|t( z(X25Tm+F`Ij29idxmNq>Ms#SZPsYRC`K?WHyUAm7-(GkiS{{(okP)JXdas7lY2qp` z%}FJ+MlAa{7ZW38Vt6=Yn>~O~yVcLD>}d&|!))4mxeA>mQF@u-uMpZ`WZh?wi_r>4 zd!^+0`1p*pX4w=4+yZq@ElZ + + + com.oracle.coherence.ce + coherence-bom + ${coherence.version} + pom + import + + + +---- + +In the `build.gradle` file we add the bom as a platform dependency. +[source,groovy] +.build.gradle +---- +dependencies { + implementation platform("com.oracle.coherence.ce:coherence-bom:21.06.2") +---- + +We can then add the `coherence` and `coherence-management` modules as dependencies + +[source,xml] +.pom.xml +---- + + + com.oracle.coherence.ce + coherence + + + com.oracle.coherence.ce + coherence-management + + +---- + +In the `build.gradle` file we add the bom as a platform dependency. +[source,groovy] +.build.gradle +---- +dependencies { + implementation platform("com.oracle.coherence.ce:coherence-bom:21.06.2") + + implementation "com.oracle.coherence.ce:coherence" + implementation "com.oracle.coherence.ce:coherence-management" +} +---- + +=== Add the JIB Plugin + +To build the image using JIB we need to add the JIB plugin to the project. + +In the `pom.xml` file we add JIB to the `plugins` section. + +[source,xml] +.pom.xml +---- + + + + com.google.cloud.tools + jib-maven-plugin + 3.1.4 + + + +---- + +In the `build.gradle` file we add JIB to the `plugins` section. +[source,groovy] +.build.gradle +---- +plugins { + id 'java' + id 'com.google.cloud.tools.jib' version '3.1.4' +} +---- + +=== Configure the JIB Plugin + +Now we can configure the JIB plugin with the properties specific to our image. +In this example the configuration is very simple, the JIB plugin documentation shows many more options. + +We are going to set the following options: +* The name and tags for the image we will build. +* The main class that we will run as the entry point to the image - in this case `com.tangosol.net.Coherence`. +* The base image. In this example we will us a distroless Java 11 image. A distroless image is more secure as it contains nothing more than core linux and a JRE. There is no shell or other tools to introduce CVEs. The downside of this is that there is no shell, so you cannot exec into the running container, or use a shell script as an entry point. If you don;t need those things a distroless image is a great choice. + +==== Maven Configuration + +In the `pom.xml` file we configure the plugin where it is declared in the `plugins` section: +[source,xml] +.pom.xml +---- + + com.google.cloud.tools + jib-maven-plugin + ${version.plugin.jib} + + + gcr.io/distroless/java:11 <1> + + + ${project.artifactId} <2> + + ${project.version} <3> + latest + + + + com.tangosol.net.Coherence <4> + OCI <5> + + + +---- +<1> The base image will be `gcr.io/distroless/java:11` +<2> The image name is set to the Maven module name using the property `${project.artifactId}` +<3> There will be two tags for the image, `latest` and the project version taken from the `${project.version}` property. +<4> The main class to use when the image is run is set to `com.tangosol.net.Coherence` +<5> The image type is set to `OCI` + +==== Gradle Configuration + +In the `build.gradle` file we configure JIB in the `jib` section: +[source,groovy] +.build.gradle +---- +jib { + from { + image = 'gcr.io/distroless/java:11' // <1> + } + to { + image = "${project.name}" // <2> + tags = ["${version}", 'latest'] // <3> + } + container { + mainClass = 'com.tangosol.net.Coherence' // <4> + format = 'OCI' // <5> + } +} +---- +<1> The base image will be `gcr.io/distroless/java:11` +<2> The image name is set to the Maven module name using the property `${project.artifactId}` +<3> There will be two tags for the image, `latest` and the project version taken from the `${project.version}` property. +<4> The main class to use when the image is run is set to `com.tangosol.net.Coherence` +<5> The image type is set to `OCI` + + +=== Build the Image + +To create the server image run the relevant commands as documented in the JIB plugin documentation. +In this case we're going to build the image using Docker, although JIB offers other alternatives. + +Using Maven we run: +[source,bash] +---- +./mvnw compile jib:dockerBuild +---- + +Using Gradle we run: +[source,bash] +---- +./gradlew compileJava jibDockerBuild +---- + +The command above will create an image named `simple-coherence` with two tags, `latest` and `1.0.0`. +Listing the local images should show the new images. +[source,bash] +---- +$ docker images | grep simple +simple-coherence 1.0.0 1613cd3b894e 51 years ago 227MB +simple-coherence latest 1613cd3b894e 51 years ago 227MB +---- + +=== Run the Image + +The image just built can be run using Docker (or your chosen container tool). +In this example we'll run it interactively, just to prove it runs and starts Coherence. +[source,bash] +---- +docker run -it --rm simple-coherence:latest +---- + +The console output should display Coherence starting and finally show the Coherence service list, which will look something like this: +[source,bash] +---- +Services + ( + ClusterService{Name=Cluster, State=(SERVICE_STARTED, STATE_JOINED), Id=0, OldestMemberId=1} + TransportService{Name=TransportService, State=(SERVICE_STARTED), Id=1, OldestMemberId=1} + InvocationService{Name=Management, State=(SERVICE_STARTED), Id=2, OldestMemberId=1} + PartitionedCache{Name=$SYS:Config, State=(SERVICE_STARTED), Id=3, OldestMemberId=1, LocalStorage=enabled, PartitionCount=257, BackupCount=1, AssignedPartitions=257, BackupPartitions=0, CoordinatorId=1} + PartitionedCache{Name=PartitionedCache, State=(SERVICE_STARTED), Id=4, OldestMemberId=1, LocalStorage=enabled, PartitionCount=257, BackupCount=1, AssignedPartitions=257, BackupPartitions=0, CoordinatorId=1} + PartitionedCache{Name=PartitionedTopic, State=(SERVICE_STARTED), Id=5, OldestMemberId=1, LocalStorage=enabled, PartitionCount=257, BackupCount=1, AssignedPartitions=257, BackupPartitions=0, CoordinatorId=1} + ProxyService{Name=Proxy, State=(SERVICE_STARTED), Id=6, OldestMemberId=1} + ) +---- + +Press `ctrl-C` to exit the container, the `--rm` option we used above wil automatically delete the stopped container. + +We now have a simple Coherence image we can use in other examples and when trying out the Coherence Operator. + +=== Configuring the Image at Runtime + +With recent Coherence versions, Coherence configuration items that can be set using system properties prefixed with `coherence.` can also be set using environment variables. This makes it simple to set those properties when running containers because environment variables can be set from the commandline. + +To set a property the system property name needs to be converted to an environment variable name. +This is done by converting the name to uppercase and replacing dots ('.') with underscores ('_'). + +For example, to set the cluster name we would set the `coherence.cluster` system property. +To run the image and set cluster name with an environment variable we convert `coherence.cluster` to `COHERENCE_CLUSTER` and run: + +[source,bash] +---- +docker run -it --rm -e COHERENCE_CLUSTER=my-cluster simple-coherence:latest +---- + +This is much simpler than trying to change the Java commandline the image entrypoint uses. + diff --git a/examples/015_simple_image/build.gradle b/examples/015_simple_image/build.gradle new file mode 100644 index 000000000..d7b84a790 --- /dev/null +++ b/examples/015_simple_image/build.gradle @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. + * Licensed under the Universal Permissive License v 1.0 as shown at + * http://oss.oracle.com/licenses/upl. + */ + +plugins { + id 'java' + id 'com.google.cloud.tools.jib' version '3.1.4' +} + +group = 'com.oracle.coherence.examples' +version = '1.0.0' +sourceCompatibility = '1.8' + +repositories { + mavenCentral() + mavenLocal() +} + +dependencies { + implementation platform("com.oracle.coherence.ce:coherence-bom:21.06.2") + + implementation "com.oracle.coherence.ce:coherence" + implementation "com.oracle.coherence.ce:coherence-management" +} + +jib { + from { + image = 'gcr.io/distroless/java:11' + } + to { + image = "${project.name}" + tags = ["${version}", 'latest'] + } + container { + mainClass = 'com.tangosol.net.Coherence' + format = 'OCI' + } +} diff --git a/examples/015_simple_image/gradle/wrapper/gradle-wrapper.jar b/examples/015_simple_image/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..e708b1c023ec8b20f512888fe07c5bd3ff77bb8f GIT binary patch literal 59203 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

K7UpUK$>l@ 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 E2O(~oYXATM literal 0 HcmV?d00001 diff --git a/examples/015_simple_image/gradle/wrapper/gradle-wrapper.properties b/examples/015_simple_image/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..be52383ef --- /dev/null +++ b/examples/015_simple_image/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/examples/015_simple_image/gradlew b/examples/015_simple_image/gradlew new file mode 100755 index 000000000..4f906e0c8 --- /dev/null +++ b/examples/015_simple_image/gradlew @@ -0,0 +1,185 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# 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 +# +# https://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. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/examples/015_simple_image/gradlew.bat b/examples/015_simple_image/gradlew.bat new file mode 100644 index 000000000..107acd32c --- /dev/null +++ b/examples/015_simple_image/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/examples/autoscaler/mvnw b/examples/015_simple_image/mvnw similarity index 100% rename from examples/autoscaler/mvnw rename to examples/015_simple_image/mvnw diff --git a/examples/autoscaler/mvnw.cmd b/examples/015_simple_image/mvnw.cmd similarity index 100% rename from examples/autoscaler/mvnw.cmd rename to examples/015_simple_image/mvnw.cmd diff --git a/examples/no-operator/server-image/pom.xml b/examples/015_simple_image/pom.xml similarity index 56% rename from examples/no-operator/server-image/pom.xml rename to examples/015_simple_image/pom.xml index 1578f87e4..89c9b2ee9 100644 --- a/examples/no-operator/server-image/pom.xml +++ b/examples/015_simple_image/pom.xml @@ -16,45 +16,39 @@ jar 1.0.0 - Oracle Coherence Simple Kubernetes Example - Simple Coherence + Simple Coherence Image + Simple Coherence Image UTF-8 8 8 - - 21.06.1 + 21.06.2 - 1.0-b01-ea 3.1.4 + + + + com.oracle.coherence.ce + coherence-bom + ${coherence.version} + pom + import + + + + - com.oracle.coherence.ce coherence - ${coherence.version} - com.oracle.coherence.ce coherence-management - ${coherence.version} - - - - com.oracle.coherence.ce - coherence-metrics - ${coherence.version} - - - - org.glassfish.external - opendmk_jmxremote_optional_jar - ${version.lib.glassfish.jmxmp} @@ -66,16 +60,16 @@ ${version.plugin.jib} - gcr.io/distroless/java:11 - - ${project.artifactId}:${project.version} + ${project.artifactId} + + ${project.version} + latest + - com.tangosol.net.Coherence OCI diff --git a/examples/015_simple_image/settings.gradle b/examples/015_simple_image/settings.gradle new file mode 100644 index 000000000..0446acdd9 --- /dev/null +++ b/examples/015_simple_image/settings.gradle @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. + * Licensed under the Universal Permissive License v 1.0 as shown at + * http://oss.oracle.com/licenses/upl. + */ + +rootProject.name = 'simple-coherence' \ No newline at end of file diff --git a/examples/no-operator/server-image/src/main/java/com/oracle/coherence/examples/tls/FileBasedPasswordProvider.java b/examples/015_simple_image/src/main/java/com/oracle/coherence/examples/tls/FileBasedPasswordProvider.java similarity index 97% rename from examples/no-operator/server-image/src/main/java/com/oracle/coherence/examples/tls/FileBasedPasswordProvider.java rename to examples/015_simple_image/src/main/java/com/oracle/coherence/examples/tls/FileBasedPasswordProvider.java index 5ad71ced8..132e45ea7 100644 --- a/examples/no-operator/server-image/src/main/java/com/oracle/coherence/examples/tls/FileBasedPasswordProvider.java +++ b/examples/015_simple_image/src/main/java/com/oracle/coherence/examples/tls/FileBasedPasswordProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021 Oracle and/or its affiliates. + * Copyright (c) 2021, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ diff --git a/examples/no-operator/server-image/src/main/resources/tangosol-coherence-override.xml b/examples/015_simple_image/src/main/resources/tangosol-coherence-override.xml similarity index 100% rename from examples/no-operator/server-image/src/main/resources/tangosol-coherence-override.xml rename to examples/015_simple_image/src/main/resources/tangosol-coherence-override.xml diff --git a/examples/no-operator/server-image/src/main/resources/test-cache-config.xml b/examples/015_simple_image/src/main/resources/test-cache-config.xml similarity index 100% rename from examples/no-operator/server-image/src/main/resources/test-cache-config.xml rename to examples/015_simple_image/src/main/resources/test-cache-config.xml diff --git a/examples/020_hello_world/README.adoc b/examples/020_hello_world/README.adoc new file mode 100644 index 000000000..2574d4a76 --- /dev/null +++ b/examples/020_hello_world/README.adoc @@ -0,0 +1,151 @@ +/////////////////////////////////////////////////////////////////////////////// + + Copyright (c) 2021, Oracle and/or its affiliates. + Licensed under the Universal Permissive License v 1.0 as shown at + http://oss.oracle.com/licenses/upl. + +/////////////////////////////////////////////////////////////////////////////// += A "Hello World" Operator Example + +== A "Hello World" Operator Example + +This is the most basic example of how to deploy a simple Coherence cluster to Kubernetes using the Coherence Operator. + +[TIP] +==== +image:GitHub-Mark-32px.png[] The complete source code for this example is in the https://github.com/oracle/coherence-operator/tree/master/examples/020_hello_world[Coherence Operator GitHub] repository. +==== + +=== Install the Operator + +If you have not already done so, you need to install the Coherence Operator. +There are a few simple ways to do this as described in the <> + +=== A Default Coherence Cluster + +All the fields in the Coherence CRD spec are optional, the Operator will apply default values, if required, for fields not specified. + +For example, this is the minimum required yaml to run a Coherence cluster: +[source,yaml] +.default-coherence.yaml +---- +apiVersion: coherence.oracle.com/v1 +kind: Coherence +metadata: + name: test +---- + +The yaml above could be installed into Kubernetes using kubectl: +[source,bash] +---- +kubectl create -f default-coherence.yaml +---- + +The command above will create a Coherence cluster named `test` in the `default` Kubernetes namespace. + +Because no `spec` was specified in the yaml, the Operator will use its defaults for certain fields. + +* The `replicas` field, which controls the number of Pods in the cluster, will default to `3`. +* The image used to run Coherence will be the default for this version of the Operator, +typically this is the latest Coherence CE image released at the time the Operator version was released. +* No ports will be exposed on the container, and no additional services will be created. + +We can list the resources that have been created by the Operator. +[source,bash] +---- +kubectl get all +---- + +Which should display something like this: +[source,bash] +---- +NAME READY STATUS RESTARTS AGE +pod/test-0 1/1 Running 0 81s +pod/test-1 1/1 Running 0 81s +pod/test-2 1/1 Running 0 81s + +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +service/test-sts ClusterIP None 7/TCP 81s +service/test-wka ClusterIP None 7/TCP 81s + +NAME READY AGE +statefulset.apps/test 3/3 81s +---- +* We can see that the Operator has created a `StatefulSet`, with three `Pods` and there are two `Services`. +* The `test-sts` service is the headless service required for the `StatefulSet`. +* The `test-wka` service is the headless service that Coherence will use for well known address cluster discovery. + +We can now undeploy the cluster: +[source,bash] +---- +kubectl delete -f default-coherence.yaml +---- + + +=== Deploy the Simple Server Image + +We can deploy a specific image by setting the `spec.image` field in the yaml. +In this example we'll deploy the `simple-coherence:1.0.0` image built in the +<> example. + +To deploy a specific image we just need to set the `spec.image` field. +[source,yaml] +.simple.yaml +---- +apiVersion: coherence.oracle.com/v1 +kind: Coherence +metadata: + name: simple +spec: + image: simple-coherence:1.0.0 <1> + replicas: 6 <2> + ports: + - name: extend <3> + port: 20000 +---- +<1> We have set the image to use to the <> example `simple-coherence:1.0.0`. +<2> We have set the `replicas` field to `6`, so this time there should only be six Pods. +<3> The simple image starts a Coherence Extend proxy on port `20000`, so we expose this port in the `Coherence` spec. The Operator will then expose the port on the Coherence container and create a Service for the port. + +We can deploy the simple cluster into Kubernetes using kubectl: +[source,bash] +---- +kubectl create -f simple.yaml +---- + +Now list the resources the Operator has created. +[source,bash] +---- +kubectl get all +---- + +Which this time should look something like this: +[source,bash] +---- +NAME READY STATUS RESTARTS AGE +pod/test-0 1/1 Running 0 4m49s +pod/test-1 1/1 Running 0 4m49s +pod/test-2 1/1 Running 0 4m49s +pod/test-3 1/1 Running 0 4m49s +pod/test-4 1/1 Running 0 4m49s +pod/test-5 1/1 Running 0 4m49s + +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +service/kubernetes ClusterIP 10.96.0.1 443/TCP 164d +service/test-extend ClusterIP 10.108.166.193 20000/TCP 4m49s +service/test-sts ClusterIP None 7/TCP 4m49s +service/test-wka ClusterIP None 7/TCP 4m49s + +NAME READY AGE +statefulset.apps/test 6/6 4m49s +---- +* We can see that the Operator has created a `StatefulSet`, with six `Pods` and there are three `Services`. +* The `simple-sts` service is the headless service required for the `StatefulSet`. +* The `simple-wka` service is the headless service that Coherence will use for well known address cluster discovery. +* The `simple-extend` service is the service that exposes the Extend port `20000`, and could be used by Extend clients to connect to the cluster. + +We can now delete the simple cluster: +[source,bash] +---- +kubectl delete -f simple.yaml +---- diff --git a/examples/020_hello_world/default-coherence.yaml b/examples/020_hello_world/default-coherence.yaml new file mode 100644 index 000000000..de2efc941 --- /dev/null +++ b/examples/020_hello_world/default-coherence.yaml @@ -0,0 +1,4 @@ +apiVersion: coherence.oracle.com/v1 +kind: Coherence +metadata: + name: test diff --git a/examples/020_hello_world/simple.yaml b/examples/020_hello_world/simple.yaml new file mode 100644 index 000000000..febc9fb53 --- /dev/null +++ b/examples/020_hello_world/simple.yaml @@ -0,0 +1,10 @@ +apiVersion: coherence.oracle.com/v1 +kind: Coherence +metadata: + name: test +spec: + image: simple-coherence:1.0.0 + replicas: 6 + ports: + - name: extend + port: 20000 diff --git a/examples/deployment/.mvn/wrapper/MavenWrapperDownloader.java b/examples/021_deployment/.mvn/wrapper/MavenWrapperDownloader.java similarity index 100% rename from examples/deployment/.mvn/wrapper/MavenWrapperDownloader.java rename to examples/021_deployment/.mvn/wrapper/MavenWrapperDownloader.java diff --git a/examples/deployment/.mvn/wrapper/maven-wrapper.jar b/examples/021_deployment/.mvn/wrapper/maven-wrapper.jar similarity index 100% rename from examples/deployment/.mvn/wrapper/maven-wrapper.jar rename to examples/021_deployment/.mvn/wrapper/maven-wrapper.jar diff --git a/examples/deployment/.mvn/wrapper/maven-wrapper.properties b/examples/021_deployment/.mvn/wrapper/maven-wrapper.properties similarity index 100% rename from examples/deployment/.mvn/wrapper/maven-wrapper.properties rename to examples/021_deployment/.mvn/wrapper/maven-wrapper.properties diff --git a/examples/deployment/README.adoc b/examples/021_deployment/README.adoc similarity index 97% rename from examples/deployment/README.adoc rename to examples/021_deployment/README.adoc index 0a3c15f1e..24acf6c4d 100644 --- a/examples/deployment/README.adoc +++ b/examples/021_deployment/README.adoc @@ -1,9 +1,15 @@ += Coherence Deployment Example + == Coherence Operator Deployment Example This example showcases how to deploy Coherence applications using the Coherence Operator. This example shows how to use the Kubernetes Horizontal Pod Autoscaler to scale Coherence clusters. -You can find the source code in the https://github.com/oracle/coherence-operator/tree/master/examples/deployment[Operator GitHub Repo] + +[TIP] +==== +image:GitHub-Mark-32px.png[] The complete source code for this example is in the https://github.com/oracle/coherence-operator/tree/master/examples/021_deployment[Coherence Operator GitHub] repository. +==== The following scenarios are covered: @@ -59,7 +65,7 @@ to match your selected namespace when running the examples. [#clone-the-github-repository] == Clone the GitHub repository -These examples exist in the `examples/deployment` directory in the +These examples exist in the `examples/021_deployment` directory in the https://github.com/oracle/coherence-operator[Coherence Operator GitHub repository]. Clone the repository: @@ -68,7 +74,7 @@ Clone the repository: ---- git clone https://github.com/oracle/coherence-operator -cd coherence-operator/examples/deployment +cd coherence-operator/examples/021_deployment ---- Ensure you have Docker running and JDK 11+ build environment set and use the @@ -125,7 +131,7 @@ coherence-operator-controller-manager-74d49cd9f9-sgzjr 1/1 Running 1 [#examples] == Run the Examples -Ensure you are in the `examples/deployment` directory to run the following commands. +Ensure you are in the `examples/021_deployment` directory to run the following commands. [#ex1] === Example 1 - Coherence cluster only @@ -340,7 +346,7 @@ Ensure the `example-cluster-proxy-0` pod is Running and READY before continuing. ==== Connect via CohQL and add data -In a separate terminal, change to the `examples/deployments` directory and run the following to +In a separate terminal, change to the `examples/021_deployments` directory and run the following to start Coherence Query Language (CohQL): [source,bash] diff --git a/examples/deployment/mvnw b/examples/021_deployment/mvnw similarity index 100% rename from examples/deployment/mvnw rename to examples/021_deployment/mvnw diff --git a/examples/deployment/mvnw.cmd b/examples/021_deployment/mvnw.cmd similarity index 100% rename from examples/deployment/mvnw.cmd rename to examples/021_deployment/mvnw.cmd diff --git a/examples/deployment/pom.xml b/examples/021_deployment/pom.xml similarity index 93% rename from examples/deployment/pom.xml rename to examples/021_deployment/pom.xml index cf0ac7cbd..851af6fac 100644 --- a/examples/deployment/pom.xml +++ b/examples/021_deployment/pom.xml @@ -16,11 +16,11 @@ com.oracle.coherence.ce - 21.06 + 21.06.2 1.3.1 - 2.8.0 + 3.1.4 ${project.version} @@ -44,12 +44,6 @@ ${coherence.version} - - ${coherence.group.id} - coherence-metrics - ${coherence.version} - - io.helidon.bundles helidon-bundles-webserver diff --git a/examples/deployment/scripts/README.md b/examples/021_deployment/scripts/README.md similarity index 100% rename from examples/deployment/scripts/README.md rename to examples/021_deployment/scripts/README.md diff --git a/examples/deployment/scripts/port-forward-es.sh b/examples/021_deployment/scripts/port-forward-es.sh similarity index 100% rename from examples/deployment/scripts/port-forward-es.sh rename to examples/021_deployment/scripts/port-forward-es.sh diff --git a/examples/deployment/scripts/port-forward-grafana.sh b/examples/021_deployment/scripts/port-forward-grafana.sh similarity index 100% rename from examples/deployment/scripts/port-forward-grafana.sh rename to examples/021_deployment/scripts/port-forward-grafana.sh diff --git a/examples/deployment/scripts/port-forward-kibana.sh b/examples/021_deployment/scripts/port-forward-kibana.sh similarity index 100% rename from examples/deployment/scripts/port-forward-kibana.sh rename to examples/021_deployment/scripts/port-forward-kibana.sh diff --git a/examples/deployment/scripts/port-forward-prometheus.sh b/examples/021_deployment/scripts/port-forward-prometheus.sh similarity index 100% rename from examples/deployment/scripts/port-forward-prometheus.sh rename to examples/021_deployment/scripts/port-forward-prometheus.sh diff --git a/examples/deployment/src/main/java/com/oracle/coherence/examples/Main.java b/examples/021_deployment/src/main/java/com/oracle/coherence/examples/Main.java similarity index 98% rename from examples/deployment/src/main/java/com/oracle/coherence/examples/Main.java rename to examples/021_deployment/src/main/java/com/oracle/coherence/examples/Main.java index d8e77f5d6..f414c716b 100644 --- a/examples/deployment/src/main/java/com/oracle/coherence/examples/Main.java +++ b/examples/021_deployment/src/main/java/com/oracle/coherence/examples/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. + * Copyright (c) 2020, 2021, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ diff --git a/examples/deployment/src/main/java/com/oracle/coherence/examples/Person.java b/examples/021_deployment/src/main/java/com/oracle/coherence/examples/Person.java similarity index 98% rename from examples/deployment/src/main/java/com/oracle/coherence/examples/Person.java rename to examples/021_deployment/src/main/java/com/oracle/coherence/examples/Person.java index 702f4a4f6..1ca436a1d 100644 --- a/examples/deployment/src/main/java/com/oracle/coherence/examples/Person.java +++ b/examples/021_deployment/src/main/java/com/oracle/coherence/examples/Person.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. + * Copyright (c) 2020, 2021, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ diff --git a/examples/deployment/src/main/java/com/oracle/coherence/examples/package-info.java b/examples/021_deployment/src/main/java/com/oracle/coherence/examples/package-info.java similarity index 76% rename from examples/deployment/src/main/java/com/oracle/coherence/examples/package-info.java rename to examples/021_deployment/src/main/java/com/oracle/coherence/examples/package-info.java index a629aff9c..f955fd078 100644 --- a/examples/deployment/src/main/java/com/oracle/coherence/examples/package-info.java +++ b/examples/021_deployment/src/main/java/com/oracle/coherence/examples/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. + * Copyright (c) 2020, 2021, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ diff --git a/examples/deployment/src/main/resources/client-cache-config.xml b/examples/021_deployment/src/main/resources/client-cache-config.xml similarity index 95% rename from examples/deployment/src/main/resources/client-cache-config.xml rename to examples/021_deployment/src/main/resources/client-cache-config.xml index 5e96b845b..61183abe8 100644 --- a/examples/deployment/src/main/resources/client-cache-config.xml +++ b/examples/021_deployment/src/main/resources/client-cache-config.xml @@ -1,6 +1,6 @@ diff --git a/examples/deployment/src/main/resources/helidon-logging.properties b/examples/021_deployment/src/main/resources/helidon-logging.properties similarity index 94% rename from examples/deployment/src/main/resources/helidon-logging.properties rename to examples/021_deployment/src/main/resources/helidon-logging.properties index b74936ab6..3fa279ae2 100644 --- a/examples/deployment/src/main/resources/helidon-logging.properties +++ b/examples/021_deployment/src/main/resources/helidon-logging.properties @@ -1,4 +1,4 @@ -# Copyright (c) 2019, 2020, Oracle and/or its affiliates. +# Copyright (c) 2020, 2021, Oracle and/or its affiliates. # Licensed under the Universal Permissive License v 1.0 as shown at # http://oss.oracle.com/licenses/upl. diff --git a/examples/deployment/src/main/resources/proxy-cache-config.xml b/examples/021_deployment/src/main/resources/proxy-cache-config.xml similarity index 97% rename from examples/deployment/src/main/resources/proxy-cache-config.xml rename to examples/021_deployment/src/main/resources/proxy-cache-config.xml index 3814953bf..5fe11401d 100644 --- a/examples/deployment/src/main/resources/proxy-cache-config.xml +++ b/examples/021_deployment/src/main/resources/proxy-cache-config.xml @@ -1,7 +1,7 @@ diff --git a/examples/autoscaler/src/main/resources/coherence-cache-config.xml b/examples/200_autoscaler/src/main/resources/coherence-cache-config.xml similarity index 97% rename from examples/autoscaler/src/main/resources/coherence-cache-config.xml rename to examples/200_autoscaler/src/main/resources/coherence-cache-config.xml index bce2e2cc7..f66c80154 100644 --- a/examples/autoscaler/src/main/resources/coherence-cache-config.xml +++ b/examples/200_autoscaler/src/main/resources/coherence-cache-config.xml @@ -1,6 +1,6 @@ diff --git a/examples/autoscaler/src/main/resources/custom-mbeans.xml b/examples/200_autoscaler/src/main/resources/custom-mbeans.xml similarity index 91% rename from examples/autoscaler/src/main/resources/custom-mbeans.xml rename to examples/200_autoscaler/src/main/resources/custom-mbeans.xml index a4b47b519..4756e6ccd 100644 --- a/examples/autoscaler/src/main/resources/custom-mbeans.xml +++ b/examples/200_autoscaler/src/main/resources/custom-mbeans.xml @@ -1,6 +1,6 @@ diff --git a/examples/helm/README.adoc b/examples/300_helm/README.adoc similarity index 98% rename from examples/helm/README.adoc rename to examples/300_helm/README.adoc index 987749215..e68a78c52 100644 --- a/examples/helm/README.adoc +++ b/examples/300_helm/README.adoc @@ -5,12 +5,19 @@ http://oss.oracle.com/licenses/upl. /////////////////////////////////////////////////////////////////////////////// += Manage Coherence using Helm + == Manage Coherence Resources using Helm Occasionally there is a requirement to manage Coherence resources using Helm instead of Kubernetes tools such as `kubectl`. There is no Helm chart for a Coherence resource as it is a single resource and any Helm chart and values file would need to replicate the entire Coherence CRD if it was to be of generic enough use for everyone. For this reason, anyone wanting to manage Coherence resource using Helm will need to create their own chart, which can then be specific to their needs. This example shows some ways that Helm can be used to manage Coherence resources. +[TIP] +==== +image:GitHub-Mark-32px.png[] The complete source code for this example is in the https://github.com/oracle/coherence-operator/tree/master/examples/300_helm[Coherence Operator GitHub] repository. +==== + === A Simple Generic Helm Chart This example contains the most basic Helm chart possible to support managing a Coherence resource locate in the `chart/` directory. The chart is actually completely generic and would support any configuration of Coherence resource. diff --git a/examples/helm/chart/Chart.yaml b/examples/300_helm/chart/Chart.yaml similarity index 100% rename from examples/helm/chart/Chart.yaml rename to examples/300_helm/chart/Chart.yaml diff --git a/examples/helm/chart/README.md b/examples/300_helm/chart/README.md similarity index 100% rename from examples/helm/chart/README.md rename to examples/300_helm/chart/README.md diff --git a/examples/helm/chart/templates/NOTES.txt b/examples/300_helm/chart/templates/NOTES.txt similarity index 100% rename from examples/helm/chart/templates/NOTES.txt rename to examples/300_helm/chart/templates/NOTES.txt diff --git a/examples/helm/chart/templates/_helpers.tpl b/examples/300_helm/chart/templates/_helpers.tpl similarity index 100% rename from examples/helm/chart/templates/_helpers.tpl rename to examples/300_helm/chart/templates/_helpers.tpl diff --git a/examples/helm/chart/templates/coherence.yaml b/examples/300_helm/chart/templates/coherence.yaml similarity index 100% rename from examples/helm/chart/templates/coherence.yaml rename to examples/300_helm/chart/templates/coherence.yaml diff --git a/examples/helm/chart/templates/hook.yaml b/examples/300_helm/chart/templates/hook.yaml similarity index 100% rename from examples/helm/chart/templates/hook.yaml rename to examples/300_helm/chart/templates/hook.yaml diff --git a/examples/helm/chart/values.yaml b/examples/300_helm/chart/values.yaml similarity index 100% rename from examples/helm/chart/values.yaml rename to examples/300_helm/chart/values.yaml diff --git a/docs/examples/800_istio.adoc b/examples/400_Istio/README.adoc similarity index 79% rename from docs/examples/800_istio.adoc rename to examples/400_Istio/README.adoc index ce5d8a738..4cc833083 100644 --- a/docs/examples/800_istio.adoc +++ b/examples/400_Istio/README.adoc @@ -5,11 +5,15 @@ http://oss.oracle.com/licenses/upl. /////////////////////////////////////////////////////////////////////////////// -= Istio Support += Using Coherence with Istio -== Istio Support +== Using Coherence with Istio -You can run the Coherence cluster and manage then using the Coherence Operator alongside Istio. Coherence clusters managed with the Coherence Operator 3.2.0 and later work with Istio 1.9.1 and later. Coherence caches can be accessed from outside the Coherence cluster via Coherence*Extend, REST, and other supported Coherence clients. Using Coherence clusters with Istio does not require the Coherence Operator to also be using Istio (and vice-versa) . The Coherence Operator can manage Coherence clusters independent of whether those clusters are using Istio or not. +You can run the Coherence cluster and manage then using the Coherence Operator alongside https://istio.io[Istio]. +Coherence clusters managed with the Coherence Operator 3.2.0 and later work with Istio 1.9.1 and later. +Coherence caches can be accessed from outside the Coherence cluster via Coherence*Extend, REST, and other supported Coherence clients. +Using Coherence clusters with Istio does not require the Coherence Operator to also be using Istio (and vice-versa) . +The Coherence Operator can manage Coherence clusters independent of whether those clusters are using Istio or not. [IMPORTANT] ==== @@ -35,7 +39,7 @@ kubectl label namespace coherence istio-injection=enabled Istio Sidecar AutoInjection is done automatically when you label the coherence namespace with istio-injection. -After the namespace is labeled, you can install the operator using your preferred method in the Operator https://oracle.github.io/coherence-operator/docs/latest/#/installation/01_installation[Installation Guide]. +After the namespace is labeled, you can install the operator using your preferred method in the Operator <>. After installed operator, use the following command to confirm the operator is running: @@ -94,7 +98,7 @@ You can see that 3 members in the cluster are running with 3 pods. 2/2 in READY === TLS -Coherence cluster works with mTLS. Coherence client can also support TLS through Istio Gateway with TLS termination to connect to Coherence cluster running inside kubernetes. For example, you can apply the following Istio Gateway and Virtual Service in the namespace of the Coherence cluster. Before applying the gateway, create a secret for the credential from the certiticate and key (e.g. server.crt and server.key) to be used by the Gateway: +Coherence cluster works with mTLS. Coherence client can also support TLS through Istio Gateway with TLS termination to connect to Coherence cluster running inside kubernetes. For example, you can apply the following Istio Gateway and Virtual Service in the namespace of the Coherence cluster. Before applying the gateway, create a secret for the credential from the certificate and key (e.g. server.crt and server.key) to be used by the Gateway: [source,bash] ---- @@ -160,7 +164,7 @@ kubectl apply -f tlsGateway.yaml -n coherence-example kubectl apply -f tlsVS.yaml -n coherence-example ---- -Then configure a Coherence*Extend client to connect to the proxy server via TLS protocol. Below is an example of a configuration of an Extend client using TLS port 8043 configured in the Gateway and server.jks created earlier in the example. +Then configure a Coherence*Extend client to connect to the proxy server via TLS protocol. Below is an example of a configuration of an Extend client using TLS port 8043 configured in the Gateway and server.jks created earlier in the example. client-cache-config.xml ---- @@ -194,7 +198,7 @@ client-cache-config.xml ... ---- -If you are using Docker for Desktop, $INGRESS_HOST is 127.0.0.1 and you can use the Kubectl port-forward to allow the Extend client to access the Coherence cluster from your localhost: +If you are using Docker for Desktop, `$INGRESS_HOST` is `127.0.0.1`, and you can use the Kubectl port-forward to allow the Extend client to access the Coherence cluster from your localhost: [source,bash] ---- @@ -203,12 +207,12 @@ kubectl port-forward -n istio-system 8043:8043 === Prometheus -The coherence metrics that record and track the health of Coherence cluster using Prometheus are also available in Istio environment and can be viewed through Granfana. However, Coherence cluster traffic is not visible by Istio. +The coherence metrics that record and track the health of Coherence cluster using Prometheus are also available in Istio environment and can be viewed through Grafana. However, Coherence cluster traffic is not visible by Istio. === Traffic Visualization -Istio provides traffic management capabilities, including the ability to visualize traffic in Kiali. You do not need to change your applications to use this feature. The Istio proxy (envoy) sidecar that is injected into your pods provides it. The image below shows an example with traffic flow. In this example, you can see how the traffic flows in from the Istio gateway on the left, to the cluster services, and then to the individual cluster members. This example has storage members (example-cluster-storage), a proxy member running proxy service (example-cluster-proxy), and a REST member running http server (example-cluster-rest). However, Coherence cluster traffic between members is not visible. +Istio provides traffic management capabilities, including the ability to visualize traffic in https://kiali.io[Kiali]. You do not need to change your applications to use this feature. The Istio proxy (envoy) sidecar that is injected into your pods provides it. The image below shows an example with traffic flow. In this example, you can see how the traffic flows in from the Istio gateway on the left, to the cluster services, and then to the individual cluster members. This example has storage members (example-cluster-storage), a proxy member running proxy service (example-cluster-proxy), and a REST member running http server (example-cluster-rest). However, Coherence cluster traffic between members is not visible. -image::../images/istioKiali.png[width=1024,height=512] +image::images/istioKiali.png[width=1024,height=512] To learn more, see https://istio.io/latest/docs/concepts/traffic-management/[Istio traffic management]. diff --git a/docs/images/istioKiali.png b/examples/400_Istio/images/istioKiali.png similarity index 100% rename from docs/images/istioKiali.png rename to examples/400_Istio/images/istioKiali.png diff --git a/docs/examples/900_demo.adoc b/examples/900_demo/README.adoc similarity index 75% rename from docs/examples/900_demo.adoc rename to examples/900_demo/README.adoc index a17d5e657..265a7eba4 100644 --- a/docs/examples/900_demo.adoc +++ b/examples/900_demo/README.adoc @@ -14,10 +14,9 @@ can run stand alone but can also be installed on the Coherence Operator. When installed using the Coherence Operator, the setup includes two Coherence Clusters, in the same Kubernetes cluster, which are configured with Active/Active Federation. -image::../images/coherence-demo.png[Service Details,width="950",align="center"] +image::images/coherence-demo.png[Service Details,width="950",align="center"] -image::../images/GitHub-Mark-64px.png[GitHub,width="32"] -Please see https://github.com/coherence-community/coherence-demo[The Coherence Demo GitHub project] for full instructions. +image:GitHub-Mark-32px.png[] Please see https://github.com/coherence-community/coherence-demo[The Coherence Demo GitHub project] for full instructions. diff --git a/examples/900_demo/images/GitHub-Mark-64px.png b/examples/900_demo/images/GitHub-Mark-64px.png new file mode 100644 index 0000000000000000000000000000000000000000..182a1a3f734fc1b7d712c68b04c29bad9460d6cd GIT binary patch literal 2625 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 W4I>>0bz>}E>ge79v> +== Examples Overview -* <> +There are a number of examples which show you how to build and deploy applications for the Coherence Operator. -* <> +[TIP] +==== +image:GitHub-Mark-32px.png[] The complete source code for the examples is in the https://github.com/oracle/coherence-operator/tree/master/examples/[Coherence Operator GitHub] repository. +==== + +[PILLARS] +==== +[CARD] +.Hello World +[link=examples/020_hello_world/README.adoc] +-- +Deploying the most basic Coherence cluster using the Operator. +-- + +[CARD] +.Simple Coherence Image +[link=examples/015_simple_image/README.adoc] +-- +Building a simple Coherence image with JIB using Maven or Gradle. +-- +==== + +[PILLARS] +==== +[CARD] +.Deployment +[link=examples/020_deployment.adoc] +-- +This example showcases how to deploy Coherence applications using the Coherence Operator. +-- + +[CARD] +.TLS +[link=examples/090_tls/README.adoc] +-- +Securing Coherence clusters using TLS. +-- + +[CARD] +.Federation +[link=examples/100_federation/README.adoc] +-- +This is a simple Coherence federation example. The federation feature requires Coherence Grid Edition. +-- + +[CARD] +.Autoscaling +[link=examples/200_autoscaler/README.adoc] +-- +Scaling Coherence clusters using the horizontal Pod Autoscaler. +-- + +[CARD] +.Helm +[link=examples/300_helm/README.adoc] +-- +Manage Coherence resources using Helm. +-- + +[CARD] +.Istio +[link=examples/400_Istio/README.adoc] +-- +Istio Support +-- +==== + +[PILLARS] +==== +[CARD] +.Coherence Demo App +[link=examples/900_demo.adoc] +-- +Deploying the Coherence demo application. +-- +==== diff --git a/docs/examples/810_helm.adoc b/examples/no-operator/000_overview.adoc similarity index 84% rename from docs/examples/810_helm.adoc rename to examples/no-operator/000_overview.adoc index 7a3ba4494..75c13bd1a 100644 --- a/docs/examples/810_helm.adoc +++ b/examples/no-operator/000_overview.adoc @@ -5,8 +5,9 @@ http://oss.oracle.com/licenses/upl. /////////////////////////////////////////////////////////////////////////////// -= Manage Coherence using Helm + += Overview // DO NOT EDIT THIS FILE // This file imports the example README.adoc file. -include::../../examples/helm/README.adoc[] +include::README.adoc[lines=9..-1] diff --git a/examples/no-operator/01_simple_server/README.adoc b/examples/no-operator/01_simple_server/README.adoc index 90e7db64e..6cd7049fa 100644 --- a/examples/no-operator/01_simple_server/README.adoc +++ b/examples/no-operator/01_simple_server/README.adoc @@ -5,10 +5,17 @@ http://oss.oracle.com/licenses/upl. /////////////////////////////////////////////////////////////////////////////// += A Simple Coherence Cluster + == A Simple Coherence Cluster in Kubernetes This example shows how to deploy a simple Coherence cluster in Kubernetes manually, without using the Coherence Operator. +[TIP] +==== +image:GitHub-Mark-32px.png[] The complete source code for this example is in the https://github.com/oracle/coherence-operator/tree/master/examples/no-operator/01_simple_server[Coherence Operator GitHub] repository. +==== + *Prerequisites* This example assumes that you have already built the example server image. @@ -260,8 +267,8 @@ Map (?): cache test We should see output something like this: [source] ---- -2021-09-17 12:25:12.143/14.600 Oracle Coherence CE 21.06.1 (thread=com.tangosol.net.CacheFactory.main(), member=1): Loaded cache configuration from "file:/Users/jonathanknight/dev/Projects/GitOracle/coherence-operator-3.0/examples/no-operator/test-client/target/classes/client-cache-config.xml" -2021-09-17 12:25:12.207/14.664 Oracle Coherence CE 21.06.1 (thread=com.tangosol.net.CacheFactory.main(), member=1): Created cache factory com.tangosol.net.ExtensibleConfigurableCacheFactory +2021-09-17 12:25:12.143/14.600 Oracle Coherence CE 21.06.2 (thread=com.tangosol.net.CacheFactory.main(), member=1): Loaded cache configuration from "file:/Users/jonathanknight/dev/Projects/GitOracle/coherence-operator-3.0/examples/no-operator/test-client/target/classes/client-cache-config.xml" +2021-09-17 12:25:12.207/14.664 Oracle Coherence CE 21.06.2 (thread=com.tangosol.net.CacheFactory.main(), member=1): Created cache factory com.tangosol.net.ExtensibleConfigurableCacheFactory Cache Configuration: test SchemeName: remote diff --git a/examples/no-operator/02_metrics/README.adoc b/examples/no-operator/02_metrics/README.adoc index 3580fb034..c26e16c92 100644 --- a/examples/no-operator/02_metrics/README.adoc +++ b/examples/no-operator/02_metrics/README.adoc @@ -5,11 +5,18 @@ http://oss.oracle.com/licenses/upl. /////////////////////////////////////////////////////////////////////////////// += Enabling Coherence Metrics + == Enabling Coherence Metrics This example shows how to deploy a simple Coherence cluster in Kubernetes manually, and enabling the Pods in that cluster to expose a http endpoint to allow access to Coherence metrics. This example expands on the `StatefulSet` used in the first simple deployment example. +[TIP] +==== +image:GitHub-Mark-32px.png[] The complete source code for this example is in the https://github.com/oracle/coherence-operator/tree/master/examples/no-operator/02_metrics[Coherence Operator GitHub] repository. +==== + *Prerequisites* This example assumes that you have already built the example server image. @@ -138,9 +145,9 @@ curl -X GET http://127.0.0.1:9612/metrics/Coherence.Cluster.Size which will display something like this: [source,bash] ---- -vendor:coherence_cluster_size{cluster="storage", version="21.06.1"} 3 +vendor:coherence_cluster_size{cluster="storage", version="21.06.2"} 3 ---- -This displays the metric name in Prometheus format `vendor:coherence_cluster_size`, the metric labels `cluster="storage", version="21.06.1"` and the metric value, in this case `3` as there are three cluster members because we specified a replicas value of 3 in the `StatefulSet`. +This displays the metric name in Prometheus format `vendor:coherence_cluster_size`, the metric labels `cluster="storage", version="21.06.2"` and the metric value, in this case `3` as there are three cluster members because we specified a replicas value of 3 in the `StatefulSet`. We can also receive the same response as `json` by using either the accepted media type header `"Accept: application/json"`: [source,bash] @@ -156,7 +163,7 @@ curl -X GET http://127.0.0.1:9612/metrics/Coherence.Cluster.Size.json Both requests will display something like this: [source,bash] ---- -[{"name":"Coherence.Cluster.Size","tags":{"cluster":"storage","version":"21.06.1"},"scope":"VENDOR","value":3}] +[{"name":"Coherence.Cluster.Size","tags":{"cluster":"storage","version":"21.06.2"},"scope":"VENDOR","value":3}] ---- We have now verified that the `Pods` in the cluster are producing metrics. diff --git a/examples/no-operator/03_extend_tls/README.adoc b/examples/no-operator/03_extend_tls/README.adoc index a9f70b4c2..2e04d260a 100644 --- a/examples/no-operator/03_extend_tls/README.adoc +++ b/examples/no-operator/03_extend_tls/README.adoc @@ -5,17 +5,24 @@ http://oss.oracle.com/licenses/upl. /////////////////////////////////////////////////////////////////////////////// += Secure Coherence Extend with TLS + == Secure Coherence Extend with TLS This example shows how to deploy a simple Coherence cluster in Kubernetes manually, and secure the Extend endpoint using TLS. This example expands on the `StatefulSet` used in the first simple deployment example. +[TIP] +==== +image:GitHub-Mark-32px.png[] The complete source code for this example is in the https://github.com/oracle/coherence-operator/tree/master/examples/no-operator/03_extend_tls[Coherence Operator GitHub] repository. +==== + *Prerequisites* This example assumes that you have already built the example server image. There are a number of ways to use TLS to secure ingress in Kubernetes. We could use a load balancer `Service` and terminate TLS at the load balance, or we could use an add-on such as Istio to manage TLS ingress. Both of those approaches would require no changes to the Coherence server, as the server would not know TLS was being used. -The https://oracle.github.io/coherence-operator/docs/latest/#/docs/examples/010_overview[Coherence Operator Examples] +The https://oracle.github.io/coherence-operator/docs/latest/#/examples/010_overview[Coherence Operator Examples] contains examples of using TLS with Coherence and using Istio. The TLS example also shows how to use Kubernetes built in certificate management to create keys and certificates. In this example we are going to actually change the server to use TLS for its Extend endpoints. @@ -340,7 +347,7 @@ Map (?): cache test This will not throw an exception because the client is not using TLS so the server rejected the connection. [source] ---- -2021-09-17 18:19:39.182/12.090 Oracle Coherence CE 21.06.1 (thread=com.tangosol.net.CacheFactory.main(), member=1): Error while starting service "RemoteCache": com.tangosol.net.messaging.ConnectionException: could not establish a connection to one of the following addresses: [127.0.0.1:20000] +2021-09-17 18:19:39.182/12.090 Oracle Coherence CE 21.06.2 (thread=com.tangosol.net.CacheFactory.main(), member=1): Error while starting service "RemoteCache": com.tangosol.net.messaging.ConnectionException: could not establish a connection to one of the following addresses: [127.0.0.1:20000] at com.tangosol.coherence.component.util.daemon.queueProcessor.service.peer.initiator.TcpInitiator.openConnection(TcpInitiator.CDB:139) at com.tangosol.coherence.component.util.daemon.queueProcessor.service.peer.Initiator.ensureConnection(Initiator.CDB:11) at com.tangosol.coherence.component.net.extend.remoteService.RemoteCacheService.openChannel(RemoteCacheService.CDB:7) diff --git a/examples/no-operator/README.adoc b/examples/no-operator/README.adoc index 747db74f9..89d23c16e 100644 --- a/examples/no-operator/README.adoc +++ b/examples/no-operator/README.adoc @@ -5,68 +5,54 @@ http://oss.oracle.com/licenses/upl. /////////////////////////////////////////////////////////////////////////////// += Coherence in Kubernetes Without the Operator + == Coherence in Kubernetes Without the Operator Although this project is all about the Coherence Kubernetes Operator, there are occasions where using an Operator is not possible. For example, some corporate or cloud security policies ban the use of CRDs, or have very restrictive RBAC policies that ultimately make it impossible to run Operators that uses their own CRDs or require cluster roles (or even just namespace roles). - -This example shows how to run a simple Coherence cluster in Kubernetes manually. +These example shows how to run a Coherence clusters in Kubernetes manually. Obviously the features of the Operator such as safe scaling, safe rolling upgrades, etc. will not be available. -There are various parts to the example, each described below: +[TIP] +==== +image:GitHub-Mark-32px.png[] The complete source code for the examples is in the https://github.com/oracle/coherence-operator/tree/master/examples/no-operator/[Coherence Operator GitHub] repository. +==== === Prerequisites - There are some common prerequisites used by all the examples. -==== The Server Image - -The `server-image/` directory contains a simple Maven project that builds an image containing a very simple Coherence application. -This application is nothing more than a cache configuration file that has an Extend proxy along with Coherence metrics and management over REST. We will use this image in the various examples we cover here. When we run the image it will start a simple storage enabled Coherence server. +* *The Server Image* -The server image Maven project, in the `server-image/` directory, uses the -https://github.com/GoogleContainerTools/jib/tree/master/jib-maven-plugin[JIB Maven plugin] -to build an image we can use in these examples. JIB is simple to use and configure and creates reasonably secure images based on distroless Java base images. These images contain the core Linux runtime and a JVM, there are no command line shells or other utilities to introduce security concerns. The down-side is that you cannot exec into a running container, but with the introduction of ephemeral containers in Kubernetes, this is not such an issue. +These examples use the image built in the <> example. +The image is nothing more than a cache configuration file that has an Extend proxy along with Coherence metrics and management over REST. +We will use this image in the various examples we cover here. When we run the image it will start a simple storage enabled Coherence server. -To create the server image run the following command from the `server-image/` directory: -[source,bash] ----- -mvn clean compile jib:dockerBuild ----- -The command above will create an image named `simple-coherence:1.0.0` which we use in the examples. - -==== The Test Client - -In the `test-client/` directory is a simple Maven project that we will use to run a simple Extend client. -This will allow us to show connectivity to our test cluster from outside of Kubernetes. - -To run the test client we can run this command from the `test-client/` directory: -[source,bash] ----- -mvn exec:java ----- -This will start a Coherence interactive console as an Extend client. -We can then run various commands to test Extend connectivity. +* *The Test Client* +In the <> directory is a simple Maven project that we will use to run a simple Extend client. == The Examples -There are a number of examples where we cover different configuration options and functionality. -Each example is in its own source directory with its own README instructions. - -|=== -|Directory |Description - -|`01_simple_server/` -|Run a simple Coherence storage enabled cluster as a `StatefulSet` and connect an Extend client to it. - -|`02_metrics/` -|Expands the simple storage enabled server to expose metrics that can be scraped by Prometheus. - -|`03_extend_tls/` -|Expands the simple storage enabled server to secure Extend using TLS. -|=== - - - - - +[PILLARS] +==== +[CARD] +.Simple Server +[link=examples/no-operator/01_simple_server/README.adoc] +-- +Run a simple Coherence storage enabled cluster as a StatefulSet and connect an Extend client to it. +-- + +[CARD] +.Simple Server with Metrics +[link=examples/no-operator/02_metrics/README.adoc] +-- +Expands the simple storage enabled server to expose metrics that can be scraped by Prometheus. +-- + +[CARD] +.Securing Extend with TLS +[link=examples/no-operator/03_extend_tls/README.adoc] +-- +Expands the simple storage enabled server to secure Extend using TLS. +-- +==== diff --git a/examples/no-operator/server-image/README.adoc b/examples/no-operator/server-image/README.adoc deleted file mode 100644 index 5359770f2..000000000 --- a/examples/no-operator/server-image/README.adoc +++ /dev/null @@ -1,24 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2021, Oracle and/or its affiliates. - Licensed under the Universal Permissive License v 1.0 as shown at - http://oss.oracle.com/licenses/upl. - -/////////////////////////////////////////////////////////////////////////////// -== Example Coherence Server Image - -The `examples/no-operator/server-image/` directory contains a simple Maven project that builds an image containing a very simple Coherence application. -This application is nothing more than a cache configuration file that has an Extend proxy along with Coherence metrics and management over REST. We will use this image in the various examples we cover here. When we run the image it will start a simple storage enabled Coherence server. - -The server image Maven project, in the `server-image/` directory, uses the -https://github.com/GoogleContainerTools/jib/tree/master/jib-maven-plugin[JIB Maven plugin] -to build an image we can use in these examples. JIB is simple to use and configure and creates reasonably secure images based on distroless Java base images. These images contain the core Linux runtime and a JVM, there are no command line shells or other utilities to introduce security concerns. The down-side is that you cannot exec into a running container, but with the introduction of ephemeral containers in Kubernetes, this is not such an issue. - -To create the server image run the following command from the `server-image/` directory: -[source,bash] ----- -mvn clean compile jib:dockerBuild ----- -The command above will create an image named `simple-coherence:1.0.0` which we use in some of the Non-Operator examples. - - diff --git a/examples/no-operator/test-client/README.adoc b/examples/no-operator/test-client/README.adoc index ac6e83ad2..8bb02d02c 100644 --- a/examples/no-operator/test-client/README.adoc +++ b/examples/no-operator/test-client/README.adoc @@ -5,6 +5,7 @@ http://oss.oracle.com/licenses/upl. /////////////////////////////////////////////////////////////////////////////// += Example Extend Client == Example Extend Client In the `examples/no-operator/test-client/` directory is a simple Maven project that we will use to run a simple Extend client. diff --git a/examples/no-operator/test-client/pom.xml b/examples/no-operator/test-client/pom.xml index 7805a4336..0a051b0a7 100644 --- a/examples/no-operator/test-client/pom.xml +++ b/examples/no-operator/test-client/pom.xml @@ -25,7 +25,7 @@ 8 - 21.06.1 + 21.06.2 ${project.basedir} diff --git a/examples/pom.xml b/examples/pom.xml index cf82cd921..8d4bda345 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -18,10 +18,24 @@ Oracle Coherence Operator Examples Parent - deployment - autoscaler - tls + 015_simple_image + 021_deployment + 200_autoscaler + 090_tls + + + + + com.google.cloud.tools + jib-maven-plugin + 3.1.4 + + true + + + + diff --git a/java/pom.xml b/java/pom.xml index d2b395dd0..879d9baac 100644 --- a/java/pom.xml +++ b/java/pom.xml @@ -40,7 +40,7 @@ 8 - 21.06.1 + 21.06.2 com.oracle.coherence.ce ${coherence.version} @@ -84,7 +84,7 @@ 3.0.0 2.0.0-M3 3.1.1 - 3.1.1 + 3.1.4 3.1.1 3.7.0 3.2.0 From 369f27158c8e616328b31c857354d9c99d72c03e Mon Sep 17 00:00:00 2001 From: Jonathan Knight Date: Thu, 23 Sep 2021 22:07:12 +0300 Subject: [PATCH 2/2] Remove examples build from CI --- .github/workflows/build.yaml | 6 ------ examples/no-operator/README.adoc | 7 +++++++ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index b5c59787a..d1beb328c 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -137,12 +137,6 @@ jobs: run: | make e2e-helm-test - - name: Examples Tests - shell: bash - run: | - make build-examples - make test-examples - - name: Deploy Snapshots if: ${{ github.ref == 'refs/heads/master' && success() }} env: diff --git a/examples/no-operator/README.adoc b/examples/no-operator/README.adoc index 89d23c16e..798434a64 100644 --- a/examples/no-operator/README.adoc +++ b/examples/no-operator/README.adoc @@ -14,6 +14,13 @@ For example, some corporate or cloud security policies ban the use of CRDs, or h These example shows how to run a Coherence clusters in Kubernetes manually. Obviously the features of the Operator such as safe scaling, safe rolling upgrades, etc. will not be available. +[NOTE] +==== +We really recommend that you try and use the Coherence Operator for managing Coherence clusters in Kubernetes. +It is possible to run the Operator with fewer RBAC permissions, for example without `ClusterRoles` and only using `Roles` restricted to a single namespace. The Operator can also run without installing its web-hooks. Ultimately though it requires the CRD to be installed, which could be done manually instead of allowing the Operator to install it. +If you really cannot change the minds of those dictating policies that mean you cannot use the Operator then these examples may be useful. +==== + [TIP] ==== image:GitHub-Mark-32px.png[] The complete source code for the examples is in the https://github.com/oracle/coherence-operator/tree/master/examples/no-operator/[Coherence Operator GitHub] repository.