diff --git a/.github/configure b/.github/configure new file mode 100755 index 0000000..1d1ea23 --- /dev/null +++ b/.github/configure @@ -0,0 +1,20 @@ +#!/bin/bash + +git config --global advice.detachedHead false + +( + cd .github + git clone --depth 1 --branch "${ENTANDO_GITHUB_TOOLS_VERSION}" "https://github.com/entando-ps/github-tools" &>/dev/null +) + +. .github/github-tools/lib.sh + +configure.start "$1" + +if [[ "$GITHUB_REF" == refs/tags/* ]]; then + . .github/github-tools/base.configure --tag "$GITHUB_REF" +else + . .github/github-tools/base.configure "$GH_PR_TITLE" "$GH_PR_NUMBER" +fi + +configure.complete diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..3745f7c --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,53 @@ +name: Docker Image CI + +env: + ENTANDO_GITHUB_TOOLS_VERSION: "v0.1.2" + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GH_PR_TITLE: ${{ github.event.pull_request.title }} + GH_PR_NUMBER: ${{ github.event.pull_request.number }} + GH_PR_RUN_NUMBER: ${{ github.run_number }} + IMAGES_TO_BUILD: "Dockerfile:entando-solr" + GITHUB_REF: ${{ github.ref }} + +on: + push: + branches: [ "develop", "release/*" ] + tags: [ 'v*' ] + pull_request: + branches: [ "develop", "release/*" ] + +jobs: + #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + publish: + permissions: + contents: read + pull-requests: write + + runs-on: ubuntu-24.04 + + steps: + - uses: actions/checkout@v4 + + - name: Configure + run: if [ -f ".github/configure" ]; then . .github/configure "publish"; fi + + - name: Build Docker image + run: | + .github/github-tools/docker.multiBuild \ + "${IMAGES_TO_BUILD}" \ + "${ARTIFACT_VERSION}" \ + "${{ vars.DOCKER_ORG }}" \ + ; + + - name: Publish Docker image + run: | + GH_DO_COMMENT=true \ + .github/github-tools/docker.multiPublish \ + "${IMAGES_TO_BUILD}" \ + "${ARTIFACT_VERSION}" \ + "${{ vars.DOCKER_ORG }}" \ + "${{ vars.DOCKER_REGISTRY }}" \ + "${{ secrets.DOCKER_USERNAME }}" \ + "${{ secrets.DOCKER_PASSWORD }}" \ + "${ARTIFACT_PUB_TYPE}" \ + ; diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..b3361fb --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,12 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Ignored default folder with query files +/queries/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml +# Editor-based HTTP Client requests +/httpRequests/ + +.idea diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..003e912 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,3 @@ +FROM solr:8.11.4 + +COPY --chown=solr:0 entando-init.sh /opt/docker-solr/entando-init.sh \ No newline at end of file diff --git a/README.md b/README.md index b5cef22..455570d 100644 --- a/README.md +++ b/README.md @@ -1 +1,187 @@ -# entando-solr \ No newline at end of file +# entando-solr + +Docker image for Apache Solr used by Entando, based on the official [solr](https://hub.docker.com/_/solr) image. + +## What this image adds + +An init script (`entando-init.sh`) that creates an `entando` Solr core on first startup (standalone mode). + +## Base image + +| Component | Version | +|-----------|---------| +| Solr | 8.11.4 | +| JDK | Eclipse Temurin 11.0.27 | +| OS | Ubuntu 20.04 | + +## Build + +```bash +docker build -t entando/entando-solr:8 . +``` + +## Run (standalone) + +```bash +docker run -d --name solr -p 8983:8983 entando/entando-solr:8 +``` + +The `entando` core can be created via the init script: + +```bash +docker exec solr /opt/docker-solr/entando-init.sh +``` + +## Standalone deployment (Kubernetes / OpenShift) + +A single-node Solr deployment with persistent storage. Suitable for development, testing, or small production environments. + +A sample manifest is provided in [`samples/entando-solr-standalone.yaml`](samples/entando-solr-standalone.yaml). + +### Deploy + +```bash +kubectl apply -f samples/entando-solr-standalone.yaml -n YOUR-NAMESPACE +kubectl get pods -l app=solr -w +``` + +### Create the Entando core + +```bash +kubectl port-forward service/solr 8983:8983 +``` + +In another terminal: + +```bash +curl "http://localhost:8983/solr/admin/cores?action=CREATE&name=entando&instanceDir=entando&dataDir=data" +``` + +### Configure the EntandoApp + +```bash +kubectl scale deploy/YOUR-APP-NAME-deployment --replicas=0 -n YOUR-NAMESPACE +``` + +Add the following environment variables to the deployment: + +```yaml +spec: + containers: + - env: + - name: SOLR_ACTIVE + value: "true" + - name: SOLR_ADDRESS + value: http://solr:8983/solr +``` + +Scale back up: + +```bash +kubectl scale deploy/YOUR-APP-NAME-deployment --replicas=1 -n YOUR-NAMESPACE +``` + +## SolrCloud deployment (Kubernetes / OpenShift) + +A clustered Solr deployment with Zookeeper, suitable for production environments requiring high availability and replication. + +A sample manifest is provided in [`samples/entando-solrCloud.yaml`](samples/entando-solrCloud.yaml). + +### Prerequisites + +- A working Entando instance +- Helm +- Cluster-level permissions for CRDs + +### Install Solr Operator + +```bash +helm repo add apache-solr https://solr.apache.org/charts +helm repo update + +kubectl create -f https://solr.apache.org/operator/downloads/crds/v0.5.0/all-with-dependencies.yaml +helm install solr-operator apache-solr/solr-operator --version 0.5.0 +``` + +### Deploy SolrCloud + +Adjust resource settings (memory, CPU, storage, replicas) in the manifest as needed, then: + +```bash +kubectl apply -f samples/entando-solrCloud.yaml -n YOUR-NAMESPACE +kubectl get solrclouds -w +``` + +### Create collections + +Set up port forwarding (leave it running): + +```bash +kubectl port-forward service/solr-solrcloud-common 8983:80 +``` + +In another terminal, create the Solr collection. The first collection (primary tenant, or the only one in single-tenant setups) **must** use `entando` as the collection name: + +```bash +curl "http://localhost:8983/solr/admin/collections?action=CREATE&name=entando&numShards=1&replicationFactor=3&maxShardsPerNode=2" +``` + +#### Multitenancy + +For multitenant environments, create an additional collection for each secondary tenant using the tenant name as the collection name: + +```bash +curl "http://localhost:8983/solr/admin/collections?action=CREATE&name=YOUR-TENANT-NAME&numShards=1&replicationFactor=3&maxShardsPerNode=2" +``` + +| Placeholder | Description | +|-------------|-------------| +| `YOUR-TENANT-NAME` | The identifying name of the tenant. In most cases, it will also be used to determine the base URL of the tenant (e.g., `yoursite` results in `yoursite.your-domain.com`). | + +The number of shards and shards per node should be adjusted for very large quantities of content (50k+). In such cases, adjustments to replicas and other resources may also be needed. + +### Configure the EntandoApp + +```bash +kubectl scale deploy/YOUR-APP-NAME-deployment --replicas=0 -n YOUR-NAMESPACE +``` + +Add the following environment variables to the deployment: + +```yaml +spec: + containers: + - env: + - name: SOLR_ACTIVE + value: "true" + - name: SOLR_ADDRESS + value: http://solr-solrcloud-common/solr +``` + +Scale back up: + +```bash +kubectl scale deploy/YOUR-APP-NAME-deployment --replicas=1 -n YOUR-NAMESPACE +``` + +### Generate the Solr schema + +The schema is generated automatically for the primary (`entando`) collection. For secondary tenant collections, trigger it manually: go to **App Builder > Content > Solr Configuration** and click **Refresh** next to each content type. + +Then reindex: **App Builder > Content > Settings > Reload the indexes**. + +## Why not the previous image? + +The previous `entando/entando-solr:8` was based on `solr:8.10.1` with OpenJDK 11.0.13, which lacks +**cgroup v2** support (added in JDK 11.0.16). On modern Linux kernels and OpenShift clusters using +cgroup v2, the JVM fails to detect container CPU and memory limits, leading to resource over-allocation. + +Rebasing on `solr:8.11.4` (JDK 11.0.27) fixes this and also includes security patches +(including the Log4Shell fix shipped in Solr 8.11.1). + +## License + +This project is licensed under the Apache License 2.0 — see the [LICENSE](LICENSE) file for details. + +Apache Solr is licensed under the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). +Eclipse Temurin is licensed under the [GPL v2 with Classpath Exception](https://openjdk.org/legal/gplv2+ce.html). \ No newline at end of file diff --git a/entando-init.sh b/entando-init.sh new file mode 100755 index 0000000..d7164b7 --- /dev/null +++ b/entando-init.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash + +ENTANDO_DATA="/var/solr/data/entando" + +if [ -d "$ENTANDO_DATA" ]; then + echo "Entando data already present. Skip" +else + echo "Need to create entando core" + sleep 15 + solr create_core -c entando +fi \ No newline at end of file diff --git a/entando-project b/entando-project new file mode 100644 index 0000000..c7a1655 --- /dev/null +++ b/entando-project @@ -0,0 +1 @@ +ENTANDO_PRJ_VERSION=8.11.4 \ No newline at end of file diff --git a/samples/entando-solr-standalone.yaml b/samples/entando-solr-standalone.yaml new file mode 100644 index 0000000..8487463 --- /dev/null +++ b/samples/entando-solr-standalone.yaml @@ -0,0 +1,83 @@ +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: solr-data + labels: + app: solr +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 10Gi +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: solr + labels: + app: solr +spec: + replicas: 1 + selector: + matchLabels: + app: solr + strategy: + type: Recreate + template: + metadata: + labels: + app: solr + spec: + containers: + - name: solr + image: entando/entando-solr:8.11.4 + ports: + - containerPort: 8983 + name: solr + protocol: TCP + env: + - name: SOLR_JAVA_MEM + value: "-Xms1024m -Xmx1024m" + resources: + requests: + cpu: 250m + memory: 1Gi + limits: + cpu: 1000m + memory: 1Gi + volumeMounts: + - name: solr-data + mountPath: /var/solr + readinessProbe: + httpGet: + path: /solr/admin/info/system + port: 8983 + initialDelaySeconds: 15 + periodSeconds: 10 + livenessProbe: + httpGet: + path: /solr/admin/info/system + port: 8983 + initialDelaySeconds: 30 + periodSeconds: 15 + volumes: + - name: solr-data + persistentVolumeClaim: + claimName: solr-data +--- +apiVersion: v1 +kind: Service +metadata: + name: solr + labels: + app: solr +spec: + selector: + app: solr + ports: + - port: 8983 + targetPort: 8983 + protocol: TCP + name: solr \ No newline at end of file diff --git a/samples/entando-solrCloud.yaml b/samples/entando-solrCloud.yaml new file mode 100644 index 0000000..d48bf63 --- /dev/null +++ b/samples/entando-solrCloud.yaml @@ -0,0 +1,52 @@ +apiVersion: solr.apache.org/v1beta1 +kind: SolrCloud +metadata: + name: solr +spec: + customSolrKubeOptions: + podOptions: + resources: + limits: + memory: 2Gi + cpu: 1000m + requests: + cpu: 350m + memory: 2Gi + dataStorage: + persistent: + pvcTemplate: + spec: + resources: + requests: + storage: 10Gi + reclaimPolicy: Delete + replicas: 3 + solrImage: + repository: entando/entando-solr + tag: "8.11.4" + solrJavaMem: -Xms2048M -Xmx2048M + updateStrategy: + method: StatefulSet + zookeeperRef: + provided: + chroot: /explore + image: + pullPolicy: IfNotPresent + repository: pravega/zookeeper + tag: 0.2.13 + persistence: + reclaimPolicy: Delete + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi + replicas: 3 + zookeeperPodPolicy: + resources: + limits: + memory: 500Mi + requests: + cpu: 250m + memory: 500Mi \ No newline at end of file