Initial port of documentation to mkdocs

This commit is contained in:
Gabriel Roldan 2025-12-06 09:48:40 -03:00 committed by Gabriel Roldan
parent 0307a076d6
commit 6d6c082b64
53 changed files with 1262 additions and 542 deletions

252
.github/workflows/docs-preview.yaml vendored Normal file
View File

@ -0,0 +1,252 @@
name: Documentation Preview
on:
pull_request:
branches: [ main ]
paths:
- 'docs/**'
- '.github/workflows/docs-preview.yaml'
workflow_dispatch:
inputs:
branch_name:
description: 'Branch name for preview'
required: false
default: ''
permissions:
contents: write
pull-requests: write
issues: write
jobs:
build-preview:
runs-on: ubuntu-latest
if: github.event_name == 'pull_request' || github.event.inputs.branch_name != ''
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
ref: ${{ github.event.inputs.branch_name || github.event.pull_request.head.sha || github.head_ref }}
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
cache: 'pip'
cache-dependency-path: 'docs/requirements.txt'
- name: Set up Docker for diagrams
uses: docker/setup-buildx-action@v3
- name: Build Documentation Preview
working-directory: docs
run: |
# Calculate Preview URL and Banner
if [ "${{ github.event_name }}" = "pull_request" ]; then
SITE_URL="https://geoserver.org/geoserver-cloud/preview/pr-${{ github.event.number }}/"
BANNER="📝 This is a preview build for PR #${{ github.event.number }}"
else
BRANCH_NAME="${{ github.event.inputs.branch_name || github.ref_name }}"
SAFE_BRANCH_NAME=$(echo "$BRANCH_NAME" | sed 's/[^a-zA-Z0-9-]/-/g')
SITE_URL="https://geoserver.org/geoserver-cloud/preview/branch-${SAFE_BRANCH_NAME}/"
BANNER="🌿 This is a preview build for branch: ${BRANCH_NAME}"
fi
# Build with preview settings using Makefile
make build-preview SITE_URL="$SITE_URL" BANNER_MESSAGE="$BANNER"
- name: Set preview path
id: preview-path
run: |
if [ "${{ github.event_name }}" = "pull_request" ]; then
echo "path=preview/pr-${{ github.event.number }}" >> $GITHUB_OUTPUT
echo "name=pr-${{ github.event.number }}" >> $GITHUB_OUTPUT
else
BRANCH_NAME="${{ github.event.inputs.branch_name || github.ref_name }}"
SAFE_BRANCH_NAME=$(echo "$BRANCH_NAME" | sed 's/[^a-zA-Z0-9-]/-/g')
echo "path=preview/branch-${SAFE_BRANCH_NAME}" >> $GITHUB_OUTPUT
echo "name=branch-${SAFE_BRANCH_NAME}" >> $GITHUB_OUTPUT
fi
- name: Deploy to GitHub Pages Preview
uses: peaceiris/actions-gh-pages@v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: docs/site
destination_dir: ${{ steps.preview-path.outputs.path }}
keep_files: true
commit_message: 'docs: deploy preview for ${{ steps.preview-path.outputs.name }} [skip ci]'
- name: Upload preview artifacts
uses: actions/upload-artifact@v4
with:
name: documentation-preview-${{ steps.preview-path.outputs.name }}
path: docs/site/
retention-days: 14
- name: Comment on PR with preview link
if: github.event_name == 'pull_request'
uses: actions/github-script@v7
with:
script: |
const prNumber = context.payload.pull_request.number;
const commitSha = context.payload.pull_request.head.sha.substring(0, 7);
const previewUrl = `https://geoserver.org/geoserver-cloud/preview/pr-${prNumber}/`;
const artifactUrl = `${context.payload.repository.html_url}/actions/runs/${context.runId}`;
const comment = `
## 📖 Documentation Preview Ready!
The documentation has been built for this PR.
### 🔗 [Click here to view the Live Preview](${previewUrl})
*(Note: It may take a minute for GitHub Pages to update)*
### 📊 Build Information:
- **Commit**: \`${commitSha}\`
- **Status**: ✅ Build Successful
- **Artifacts**: [Download Build](${artifactUrl})
---
*Generated by GitHub Actions*
`;
const existingComments = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber
});
const botComment = existingComments.data.find(comment =>
comment.user.type === 'Bot' &&
comment.body.includes('📖 Documentation Preview Ready!')
);
try {
if (botComment) {
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: botComment.id,
body: comment
});
} else {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
body: comment
});
}
} catch (error) {
console.log('Could not post/update comment on PR:', error.message);
}
compare-changes:
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
steps:
- name: Checkout base branch
uses: actions/checkout@v4
with:
ref: ${{ github.base_ref }}
path: base
- name: Checkout PR branch
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
path: pr
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Set up Docker for diagrams
uses: docker/setup-buildx-action@v3
- name: Build base documentation
run: |
if [ -d "base/docs" ] && [ -f "base/docs/build.sh" ]; then
cd base/docs
./build.sh
mv site ../../base-site
else
mkdir -p base-site
echo "<html><body><h1>No documentation in base branch</h1></body></html>" > base-site/index.html
fi
- name: Build PR documentation
working-directory: pr/docs
run: |
./build.sh
mv site ../../pr-site
- name: Compare documentation changes
run: |
echo "## 📊 Documentation Changes Analysis" > /tmp/changes.md
echo "" >> /tmp/changes.md
base_files=$(find base-site -name "*.html" | wc -l)
pr_files=$(find pr-site -name "*.html" | wc -l)
echo "- **Pages in Base**: $base_files" >> /tmp/changes.md
echo "- **Pages in PR**: $pr_files" >> /tmp/changes.md
echo "- **Net Change**: $((pr_files - base_files))" >> /tmp/changes.md
echo "" >> /tmp/changes.md
echo "### 🆕 New Pages" >> /tmp/changes.md
new_pages=$(mktemp)
find pr-site -name "*.html" -type f | while read pr_file; do
relative_path=${pr_file#pr-site/}
base_file="base-site/$relative_path"
if [ ! -f "$base_file" ]; then
echo "- \`$relative_path\`" >> "$new_pages"
fi
done
if [ -s "$new_pages" ]; then
cat "$new_pages" >> /tmp/changes.md
else
echo "*None*" >> /tmp/changes.md
fi
rm -f "$new_pages"
echo "" >> /tmp/changes.md
echo "### 🗑️ Removed Pages" >> /tmp/changes.md
removed_pages=$(mktemp)
find base-site -name "*.html" -type f | while read base_file; do
relative_path=${base_file#base-site/}
pr_file="pr-site/$relative_path"
if [ ! -f "$pr_file" ]; then
echo "- \`$relative_path\`" >> "$removed_pages"
fi
done
if [ -s "$removed_pages" ]; then
cat "$removed_pages" >> /tmp/changes.md
else
echo "*None*" >> /tmp/changes.md
fi
rm -f "$removed_pages"
- name: Add comparison to PR comment
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
try {
const changes = fs.readFileSync('/tmp/changes.md', 'utf8');
const comment = changes;
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.payload.pull_request.number,
body: comment
});
} catch (error) {
console.log('Error posting comparison:', error);
}

52
.github/workflows/docs.yaml vendored Normal file
View File

@ -0,0 +1,52 @@
name: Build and Deploy Documentation
on:
push:
branches: [ main ]
paths:
- 'docs/**'
- '.github/workflows/docs.yaml'
workflow_dispatch:
jobs:
build-deploy:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
cache: 'pip'
cache-dependency-path: 'docs/requirements.txt'
- name: Install dependencies
run: |
cd docs
pip install -r requirements.txt
- name: Set up Docker for diagrams
uses: docker/setup-buildx-action@v3
- name: Generate C4 diagrams
run: |
cd docs/structurizr
./structurizr-generate-diagrams.sh
- name: Build documentation
run: |
cd docs
mkdocs build --strict --verbose
- name: Deploy to GitHub Pages
uses: peaceiris/actions-gh-pages@v4
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./docs/site
commit_message: 'docs: deploy documentation [skip ci]'

5
docs/.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
# Documentation build artifacts
.venv/
site/
src/assets/images/structurizr
structurizr/exports/

35
docs/Makefile Normal file
View File

@ -0,0 +1,35 @@
.PHONY: help build serve serve-preview clean build-preview
# Show this help message
help:
@echo "Usage: make [target]"
@echo ""
@echo "Targets:"
@echo " build Build the documentation using mkdocs.yml"
@echo " serve Start the development server"
@echo " serve-preview Start the development server with a preview banner (BANNER_MESSAGE=...)"
@echo " clean Remove build artifacts"
@echo " build-preview Build with custom settings (SITE_URL=... BANNER_MESSAGE=...)"
@echo " help Show this help message"
# Default build
build:
./build.sh
# Start development server
serve:
./serve.sh
# Start development server with preview banner
# Usage: make serve-preview BANNER_MESSAGE="Preview..."
serve-preview:
./serve.sh "$(BANNER_MESSAGE)"
# Clean build artifacts
clean:
./clean.sh
# Build preview with custom URL and banner
# Usage: make build-preview SITE_URL="https://..." BANNER_MESSAGE="Preview..."
build-preview:
./build.sh "$(SITE_URL)" "$(BANNER_MESSAGE)"

81
docs/README.md Normal file
View File

@ -0,0 +1,81 @@
# GeoServer Cloud Documentation
This directory contains the complete documentation for the GeoServer Cloud project, built with MkDocs Material theme and featuring C4 model architectural diagrams.
## Quick Start
### Build Documentation
```bash
# One-time setup and build
./build.sh
```
### Development Server
```bash
# Start development server with auto-reload
./serve.sh
```
### Clean Build
```bash
# Remove all generated files and rebuild
./clean.sh && ./build.sh
```
## Documentation Structure
The documentation is organized into three main sections within the `src` directory:
```
docs/
├── build.sh # Main build script (sets up venv, generates diagrams, builds docs)
├── serve.sh # Development server script
├── clean.sh # Clean build artifacts script
├── requirements.txt # Python dependencies for MkDocs
├── mkdocs.yml # MkDocs configuration
├── src/ # Documentation source files (Markdown)
│ ├── index.md # Homepage
│ ├── deploy/ # Deployment guides (Docker Compose, Helm)
│ ├── configuration/ # Configuration reference and guides
│ ├── developer-guide/ # Developer documentation and architecture
│ └── assets/ # Static assets (images, CSS)
├── structurizr/ # C4 model architectural diagrams definitions
│ ├── workspace.dsl # Main C4 model definition
│ ├── dynamic-views.dsl # Dynamic view definitions
│ └── ... # Diagram generation scripts
└── site/ # Generated static documentation (after build)
```
## Build Process
The `build.sh` script handles the complete build process:
1. **Environment Setup**: Creates Python virtual environment and installs dependencies.
2. **Diagram Generation**:
- Runs Structurizr CLI to generate PlantUML from DSL files.
- Converts PlantUML to SVG using Docker.
- Copies SVGs to `src/assets/images/structurizr/` directory.
3. **Documentation Build**: Uses MkDocs to build the complete static site.
4. **Validation**: Ensures all links and references are valid.
## Requirements
- **Python 3.8+**: For MkDocs and dependencies.
- **Docker**: For C4 diagram generation (Structurizr CLI and PlantUML).
- **Internet connection**: For pulling Docker images during diagram generation.
## Contributing
When contributing to documentation:
1. Follow the existing structure and style.
2. Update both content and navigation in `mkdocs.yml` if adding new pages.
3. Test with `./serve.sh` locally before submitting.
4. Ensure all links work by running `./build.sh`.
5. If modifying architecture, update `structurizr/workspace.dsl` and/or `dynamic-views.dsl`.

View File

@ -1,4 +0,0 @@
theme: jekyll-theme-modernist
title: GeoServer Cloud
description: Dockerized GeoServer micro-services
show_downloads: false

View File

@ -1,15 +0,0 @@
---
---
// overrides for https://github.com/pages-themes/modernist/blob/master/_sass/jekyll-theme-modernist.scss
@import "{{ site.theme }}";
.inner {
max-width: 100%;
}
//change width, default value of 740px is too narrow
.wrapper {
width:75%;
}

121
docs/build.sh Executable file
View File

@ -0,0 +1,121 @@
#!/bin/bash
set -e
# Documentation build script for GeoServer Cloud
# Usage: ./build.sh [site_url] [banner_message]
SITE_URL="$1"
BANNER_MESSAGE="$2"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
VENV_DIR="${SCRIPT_DIR}/.venv"
echo "🏗️ Building GeoServer Cloud Documentation"
echo "=========================================="
# Function to check if command exists
command_exists() {
command -v "$1" >/dev/null 2>&1
}
# Check required dependencies
echo "🔍 Checking dependencies..."
if ! command_exists python3; then
echo "❌ Python 3 is required but not installed"
exit 1
fi
if ! command_exists docker; then
echo "❌ Docker is required for diagram generation but not installed"
exit 1
fi
echo "✅ All required dependencies found"
# Create and activate virtual environment
echo ""
echo "🐍 Setting up Python virtual environment..."
if [ ! -d "$VENV_DIR" ]; then
echo "Creating new virtual environment..."
python3 -m venv "$VENV_DIR"
else
echo "Using existing virtual environment..."
fi
# Activate virtual environment
echo "Activating virtual environment: $VENV_DIR"
source "$VENV_DIR/bin/activate"
# Verify we're in the virtual environment
if [[ "$VIRTUAL_ENV" != "$VENV_DIR" ]]; then
echo "❌ Failed to activate virtual environment"
exit 1
fi
echo "✅ Virtual environment activated: $VIRTUAL_ENV"
# Upgrade pip and install dependencies
echo "📦 Installing Python dependencies..."
python -m pip install --upgrade pip
pip install -r requirements.txt
echo "✅ Python environment ready"
# Generate C4 model diagrams
echo ""
echo "📊 Generating C4 model diagrams..."
cd structurizr
# Generate diagrams
echo "🔄 Running Structurizr diagram generation..."
./structurizr-generate-diagrams.sh
echo "✅ Diagram generation completed"
# Return to docs directory
cd "$SCRIPT_DIR"
# Determine config file
CONFIG_FILE="mkdocs.yml"
if [ -n "$SITE_URL" ]; then
echo ""
echo "🔧 Configuring for preview..."
echo " URL: $SITE_URL"
if [ -n "$BANNER_MESSAGE" ]; then
echo " Banner: $BANNER_MESSAGE"
fi
# Export variables for mkdocs-env-config-plugin
export SITE_URL
export BANNER_MESSAGE
fi
# Validate MkDocs configuration
echo ""
echo "🔧 Validating MkDocs configuration..."
mkdocs --version
# Build documentation
echo ""
echo "📚 Building documentation..."
mkdocs build --verbose --strict
# Add preview metadata if preview build
if [ -n "$BANNER_MESSAGE" ]; then
echo "<!-- Preview build -->" >> site/index.html
echo "<!-- Generated: $(date) -->" >> site/index.html
fi
echo ""
echo "✅ Documentation build completed successfully!"
echo ""
echo "📁 Built site location: ${SCRIPT_DIR}/site/"
echo "🌐 To serve locally: mkdocs serve"
echo "🔄 To clean build: rm -rf site/ && ./build.sh"
echo ""
echo "💡 Remember to activate the virtual environment for future runs:"
echo " source .venv/bin/activate"

43
docs/clean.sh Executable file
View File

@ -0,0 +1,43 @@
#!/bin/bash
set -e
# Clean build script for GeoServer Cloud Documentation
# This script removes all generated files and build artifacts
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
echo "🧹 Cleaning GeoServer Cloud Documentation"
echo "========================================="
# Remove built site
if [ -d "site" ]; then
echo "🗑️ Removing built site directory..."
rm -rf site/
echo "✅ Site directory removed"
else
echo " No site directory to remove"
fi
# Remove generated diagrams (preserving .gitkeep)
if [ -d "structurizr/exports" ]; then
echo "🗑️ Removing generated diagram exports..."
find structurizr/exports/ -name "*.puml" -delete 2>/dev/null || true
echo "✅ Diagram exports removed"
else
echo " No diagram exports to remove"
fi
# Remove SVG files from src/assets
if [ -d "src/assets/images/structurizr" ]; then
echo "🗑️ Removing SVG diagrams from src/assets..."
rm -f src/assets/images/structurizr/*.svg
echo "✅ Src assets SVG files removed"
else
echo " No src assets SVG files to remove"
fi
echo ""
echo "✅ Cleanup completed!"
echo ""
echo "💡 To rebuild everything: ./build.sh"
echo "🚀 To start development server: ./serve.sh"

View File

@ -1,182 +0,0 @@
x-variables:
environment: &common_env
SPRING_PROFILES_ACTIVE: "jdbcconfig"
GEOWEBCACHE_CACHE_DIR: /data/geowebcache
x-gs-dependencies: &gs-dependencies
rabbitmq:
condition: service_healthy
required: true
discovery:
condition: service_healthy
required: true
config:
condition: service_healthy
required: true
database:
condition: service_started
volumes:
postgresql_config_data: # volume for postgresql data, used to store the geoserver config through jdbcconfig
geowebcache_data: # used by gwc and web-ui to locate the default gwc tile cache directory
services:
rabbitmq:
image: rabbitmq:4-management-alpine
user: "1000:1000"
restart: unless-stopped
tmpfs:
- /var/lib/rabbitmq:size=512m,mode=1777 # Store RabbitMQ data in memory
healthcheck:
test: rabbitmq-diagnostics is_running
start_period: 10s
interval: 15s
timeout: 30s
retries: 3
deploy:
resources:
limits:
cpus: '4.0'
memory: 2G
database:
# be sure geoserver.backend.jdbcconfig.initdb is set to true in application.yml at lease for the first app run
image: postgres:15-alpine
environment:
POSTGRES_DB: geoserver_config
POSTGRES_USER: geoserver
POSTGRES_PASSWORD: geo5erver
volumes:
- postgresql_config_data:/var/lib/postgresql/data
deploy:
resources:
limits:
cpus: '2.0'
memory: 1G
# Spring Cloud Config service, provides centralized configuration to all
# microservices. Being a Discovery First Bootstrap configuration, it'll
# register itself with the Eureka discovery service and can be scaled
config:
image: geoservercloud/geoserver-cloud-config:2.28.1.1
user: 1000:1000 # set the userid:groupid the container runs as
environment:
# default to `native` loading the config embedded in /etc/geoserver
# use `git` to fetch the config from a git repository, and CONFIG_GIT_URI to change
# the default repository https://github.com/geoserver/geoserver-cloud-config.git
SPRING_PROFILES_ACTIVE: native
# If using the `git` profile, get the config from this tag
SPRING_CLOUD_CONFIG_SERVER_GIT_DEFAULT_LABEL: v2.28.1.1
# Uncomment to bind to a local filesystem directory if using the 'native' profile
#volumes:
# - ./config:/etc/geoserver
deploy:
resources:
limits:
cpus: '2.0'
memory: 256M
discovery:
image: geoservercloud/geoserver-cloud-discovery:2.28.1.1
user: "1000:1000"
depends_on:
- config
ports:
- 8761:8761
deploy:
resources:
limits:
cpus: '2.0'
memory: 256M
# Application facade, provides a single entry point routing to all
# microservices (e.g. http://localhost:9090/geoserver/cloud/wms, http://localhost:9090/geoserver/cloud/wfs, etc)
gateway:
image: geoservercloud/geoserver-cloud-gateway:2.28.1.1
user: 1000:1000 # set the userid:groupid the container runs as
depends_on:
discovery:
condition: service_healthy
environment:
# eat our own dogfood and set a base path
GEOSERVER_BASE_PATH: /geoserver/cloud
ports:
- 9090:8080
deploy:
resources:
limits:
cpus: '4.0'
memory: 1G
# GeoServer template service configuration
geoserver_template:
image: geoservercloud/geoserver-cloud-webui:2.28.1.1
user: "1000:1000"
environment:
<<: *common_env
volumes:
- geowebcache_data:/data/geowebcache
deploy:
mode: replicated
replicas: 0
resources:
limits:
cpus: '2.0'
memory: 1G
# GeoServer microservices
wfs:
image: geoservercloud/geoserver-cloud-wfs:2.28.1.1
extends:
service: geoserver_template
depends_on: *gs-dependencies
deploy:
replicas: 1
wms:
image: geoservercloud/geoserver-cloud-wms:2.28.1.1
extends:
service: geoserver_template
depends_on: *gs-dependencies
deploy:
replicas: 1
wcs:
image: geoservercloud/geoserver-cloud-wcs:2.28.1.1
extends:
service: geoserver_template
depends_on: *gs-dependencies
deploy:
replicas: 1
wps:
image: geoservercloud/geoserver-cloud-wps:2.28.1.1
extends:
service: geoserver_template
depends_on: *gs-dependencies
deploy:
replicas: 1
restconfig:
image: geoservercloud/geoserver-cloud-rest:2.28.1.1
extends:
service: geoserver_template
depends_on: *gs-dependencies
deploy:
replicas: 1
webui:
image: geoservercloud/geoserver-cloud-webui:2.28.1.1
extends:
service: geoserver_template
depends_on: *gs-dependencies
deploy:
replicas: 1
gwc:
image: geoservercloud/geoserver-cloud-gwc:2.28.1.1
extends:
service: geoserver_template
depends_on: *gs-dependencies
deploy:
replicas: 1

View File

@ -1,67 +0,0 @@
# GeoServer Cloud with podman
## Why podman?
[Podman](https://podman.io/)'s aim is to be a secure open source replacement for Docker
and not depending on one daemon with root rights in order to prevent being a single point failure.
A further design goal is being able to run containers with only user privileges.
https://cloudnweb.dev/2019/10/heres-why-podman-is-more-secured-than-docker-devsecops/
Additionally Podman can create and play Kubernetes files for easing migration to k8s:
https://www.redhat.com/sysadmin/compose-kubernetes-podman
Integration with systemd including dependencies is also a feature of podman.
https://fedoramagazine.org/auto-updating-podman-containers-with-systemd/
For further information please have a look at the project page:
https://podman.io/whatis.html
## Required packages for different distributions
### RHEL 8.5 / CentOS 8.5 (Stream) and newer
```bash
sudo dnf -y install podman podman-plugins
```
### Ubuntu
Follow Podman's [Ubuntu installation instructions](https://podman.io/getting-started/installation)
to install from the Kubic repo. The default version installed through `apt install podman`
(currently `3.0.1`) may be too old.
```bash
. /etc/os-release
echo "deb https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/xUbuntu_${VERSION_ID}/ /" | sudo tee /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list
curl -L "https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/xUbuntu_${VERSION_ID}/Release.key" | sudo apt-key add -
sudo apt-get update
sudo apt-get -y upgrade
sudo apt-get -y install podman
```
```
podman version
Version: 3.4.2
API Version: 3.4.2
Go Version: go1.16.6
Built: Wed Dec 31 21:00:00 1969
OS/Arch: linux/amd64
```
## Running Geoserver Cloud
### Traditional way
* [Manual](traditional/manual/podman.md)
* Script (needs to be done)
### Pods (k8s style)
* Manual (needs to be done)
* Script (needs to be done)

View File

@ -1,2 +0,0 @@
GSCLOUD_VERSION=1.8.7

View File

@ -1 +0,0 @@
datadir

View File

@ -1,183 +0,0 @@
## Running GeoServer Cloud
This documentation describes how to run GeoServer Cloud with podman without pods (traditional way) based on
### Creating network
```bash
podman network create gs-cloud-network
```
### Creating volumes
Persistent storage for Rabbitmq
```bash
podman volume create rabbitmq_data
```
Creating a shared directory for the different GeoServer containers, e.g. `webui`, `wms`, etc.
```bash
podman volume create shared_data_directory
```
### Downloading images
In order to speed up the "starting" part of the documentation we are going to download the images as the first stop
```bash
podman pull docker.io/library/rabbitmq:4-management-alpine
export GSCLOUD_VERSION=2.28.1.1
for service in discovery config gateway rest webui wms wfs wcs
do
podman pull docker.io/geoservercloud/geoserver-cloud-$service:${GSCLOUD_VERSION}
done
```
### Creating primary containers
Following containers are required as the "base system".
Please start the containers in the described order:
#### Rabbitmq
```bash
podman run -d --name=rabbitmq --network gs-cloud-network -v rabbitmq_data:/var/lib/rabbitmq --restart always rabbitmq:4-management-alpine
```
#### Discovery
```bash
podman run -d --name=discovery --hostname=discovery \
--network gs-cloud-network \
-p 8761:8761 \
--restart always \
geoservercloud/geoserver-cloud-discovery:$GSCLOUD_VERSION
```
Accepted environment variables default values:
-e SERVER_PORT=8761
-e EUREKA_INSTANCE_HOSTNAME=discovery
#### Config
```bash
podman run -d --name=config --hostname=config \
--network gs-cloud-network \
-e SPRING_PROFILES_ACTIVE=git \
-e CONFIG_GIT_URI=https://github.com/geoserver/geoserver-cloud-config.git \
-e SPRING_CLOUD_CONFIG_SERVER_GIT_DEFAULT_LABEL=v2.28.1.1 \
-e CONFIG_GIT_BASEDIR=/opt/app/git_config \
geoservercloud/geoserver-cloud-config:$GSCLOUD_VERSION
```
Accepted environment variables default values:
-e EUREKA_SERVER_URL=http://discovery:8761/eureka
-e SPRING_PROFILES_ACTIVE=git
-e CONFIG_GIT_URI=https://github.com/geoserver/geoserver-cloud-config.git
-e SPRING_CLOUD_CONFIG_SERVER_GIT_DEFAULT_LABEL=master
-e CONFIG_GIT_BASEDIR=/opt/app/git_config
-e CONFIG_NATIVE_PATH=/opt/app/config
#### Gateway
```bash
podman run -d --name=gateway \
--network gs-cloud-network \
-p 9090:8080 \
geoservercloud/geoserver-cloud-gateway:$GSCLOUD_VERSION
```
Accepted environment variables default values:
-e EUREKA_SERVER_URL=http://discovery:8761/eureka
### Creating service containers
Depending on your use case you can start any of the following containers.
Accepted environment variables default values:
-e EUREKA_SERVER_URL=http://discovery:8761/eureka
-e SPRING_PROFILES_ACTIVE=datadir|jdbcconfig
-e GEOSERVER_DATA_DIR=/opt/app/data_directory
Accepted environment variables default values for webui:
-e EUREKA_SERVER_URL=http://discovery:8761/eureka
-e SPRING_PROFILES_ACTIVE=datadir|jdbcconfig
-e GEOSERVER_DATA_DIR=/opt/app/data_directory
-e WEBUI_IMPORTER_ENABLED=false|true
```bash
for service in webui rest wms wfs wcs gwc
do
podman run -d --name=$service \
--network gs-cloud-network \
-e SPRING_PROFILES_ACTIVE=datadir \
-v shared_data_directory:/opt/app/data_directory \
geoservercloud/geoserver-cloud-$service:$GSCLOUD_VERSION
done
```
### Integration with systemd
For better integration with your linux distribution which has to be based on systemd.
Of course, the containers will be running for security reasons with a normal user account.
#### Preparing systemd
```bash
mkdir -p ~/.config/systemd/user/
```
#### Creating "base system" systemd files
```bash
for service in rabbitmq discovery config gateway
do
podman generate systemd --new -n $service > ~/.config/systemd/user/container-$service.service
done
```
##### Removing running containers
```bash
podman rm -f rabbitmq discovery config gateway
```
#### Adjusting dependencies base system
```bash
for service in config gateway
do
sed -i "/Wants=network-online.target/c\Wants=network-online.target container-discovery.service" ~/.config/systemd/user/container-$service.service
sed -i "/After=network-online.target/c\After=network-online.target container-discovery.service" ~/.config/systemd/user/container-$service.service
done
```
##### Enabling and starting containers with systemd
```bash
systemctl --user enable --now container-rabbitmq container-discovery container-config container-gateway
```
#### Creating "service containers" systemd files
```bash
for service in rest webui wms wfs wcs gwc
do
podman generate systemd --new -n $service > ~/.config/systemd/user/container-$service.service
podman rm -f $service
sed -i "/Wants=network-online.target/c\Wants=network-online.target container-config.service" ~/.config/systemd/user/container-$service.service
sed -i "/After=network-online.target/c\After=network-online.target container-config.service" ~/.config/systemd/user/container-$service.service
systemctl --user enable --now container-$service
done
```

View File

@ -1,11 +0,0 @@
#!/bin/bash
# read GSCLOUD_VERSION from ./.env
export $(cat ./.env)
podman pull docker.io/library/rabbitmq:4-management-alpine
for i in discovery config gateway rest webui wms wfs wcs gwc
do
podman pull docker-daemon:geoservercloud/geoserver-cloud-$i:$GSCLOUD_VERSION
done

View File

@ -1,7 +0,0 @@
#!/bin/bash
for service in gateway rest webui wms wfs wcs gwc discovery config rabbitmq
do
podman container stop -i $service
podman container rm -i $service
done

View File

@ -1,50 +0,0 @@
#!/bin/bash
podman network create gscloud 2>/dev/null
podman volume create rabbitmq_data 2>/dev/null
# read GSCLOUD_VERSION from ./.env
export $(cat ./.env)
STD_OPTS="-d --network gscloud"
# Note rabbitmq and discovery are the only containers addressed
# by hostname inside the cluster, so we're adding the --hostname
# parameter to `podman run` on them. All other container urls are
# resolved by discovery.
echo Starting rabbitmq...
podman run $STD_OPTS --name=rabbitmq --hostname=rabbitmq \
-v rabbitmq_data:/var/lib/rabbitmq \
--restart always \
rabbitmq:4-management-alpine
echo Starting discovery:$GSCLOUD_VERSION...
podman run $STD_OPTS --name=discovery --hostname=discovery \
-p 8761:8761 \
--restart always \
geoservercloud/geoserver-cloud-discovery:$GSCLOUD_VERSION
echo Starting config:$GSCLOUD_VERSION...
podman run $STD_OPTS --name=config \
--restart always \
-e SPRING_PROFILES_ACTIVE=native \
-e CONFIG_NATIVE_PATH=/etc/geoserver \
geoservercloud/geoserver-cloud-config:$GSCLOUD_VERSION
echo Starting gateway:$GSCLOUD_VERSION...
podman run $STD_OPTS --name=gateway \
-p 9090:8080 \
geoservercloud/geoserver-cloud-gateway:$GSCLOUD_VERSION
mkdir -p datadir
#for i in webui wms wfs wcs rest
for i in webui wms wfs wcs rest gwc
do
echo Starting $i:$GSCLOUD_VERSION...
podman run $STD_OPTS --name=$i \
-e SPRING_PROFILES_ACTIVE=datadir \
-v ./datadir:/opt/app/data_directory:z \
geoservercloud/geoserver-cloud-$i:$GSCLOUD_VERSION
done

125
docs/mkdocs.yml Normal file
View File

@ -0,0 +1,125 @@
site_name: GeoServer Cloud Documentation
site_description: Cloud Native distribution of GeoServer
site_author: GeoServer Project
copyright: "&copy; 2023 Open Source Geospatial Foundation. All rights reserved."
repo_url: https://github.com/geoserver/geoserver-cloud
edit_uri: edit/main/docs/src/
site_url: !ENV [SITE_URL, 'https://geoserver.org/geoserver-cloud']
docs_dir: src
theme:
name: material
custom_dir: overrides
logo: assets/images/geoserver-logo.png
favicon: assets/images/favicon.ico
features:
- navigation.tabs
- navigation.sections
- navigation.expand
- navigation.indexes
- navigation.top
- toc.integrate
- search.suggest
- search.highlight
- content.code.copy
- content.code.annotate
palette:
- media: "(prefers-color-scheme: light)"
scheme: default
primary: blue
accent: blue
toggle:
icon: material/brightness-7
name: Switch to dark mode
- media: "(prefers-color-scheme: dark)"
scheme: slate
primary: blue
accent: blue
toggle:
icon: material/brightness-4
name: Switch to light mode
font:
text: Inter
code: JetBrains Mono
icon:
repo: fontawesome/brands/github
extra_css:
- assets/stylesheets/extra.css
markdown_extensions:
- admonition
- attr_list
- def_list
- footnotes
- md_in_html
- toc:
permalink: true
title: On this page
- pymdownx.arithmatex:
generic: true
- pymdownx.betterem:
smart_enable: all
- pymdownx.caret
- pymdownx.details
- pymdownx.emoji:
emoji_index: !!python/name:material.extensions.emoji.twemoji
emoji_generator: !!python/name:material.extensions.emoji.to_svg
- pymdownx.highlight:
anchor_linenums: true
line_spans: __span
pygments_lang_class: true
- pymdownx.inlinehilite
- pymdownx.keys
- pymdownx.mark
- pymdownx.smartsymbols
- pymdownx.superfences:
custom_fences:
- name: mermaid
class: mermaid
format: !!python/name:pymdownx.superfences.fence_code_format
- pymdownx.tabbed:
alternate_style: true
- pymdownx.tasklist:
custom_checkbox: true
- pymdownx.tilde
plugins:
- search:
separator: '[\s\-,:!=\[\]()"`/]+|\.(?!\d)|&[lg]t;|(?!\b)(?=[A-Z][a-z])'
- minify:
minify_html: true
nav:
- Home: index.md
- Deployment:
- Overview: deploy/index.md
- Docker Compose: deploy/docker-compose/index.md
- Helm Charts: deploy/helm/index.md
- Configuration:
- Externalized configuration guide: configuration/index.md
- Migration 2.26 to 2.27: configuration/migration-2.26-to-2.27.md
- Developer Guide:
- Overview: developer-guide/index.md
- Building: developer-guide/build_instructions.md
- Contributing: developer-guide/coding_standards.md
- Services:
- Discovery Service: developer-guide/services/discovery-service.md
- Gateway Service: developer-guide/services/gateway-service.md
- REST Config Service: developer-guide/services/restconfig-v1-service.md
- Event Bus: developer-guide/event-bus/index.md
- Extensions: developer-guide/extensions/adding_extensions.md
extra:
banner_message: !ENV [BANNER_MESSAGE, '']
analytics:
provider: google
property: G-YRM5CB206D
version:
provider: mike
social:
- icon: fontawesome/brands/github
link: https://github.com/geoserver/geoserver-cloud
- icon: fontawesome/solid/globe
link: https://geoserver/geoserver-cloud

7
docs/overrides/main.html Normal file
View File

@ -0,0 +1,7 @@
{% extends "base.html" %}
{% block announce %}
{% if config.extra.banner_message %}
{{ config.extra.banner_message }}
{% endif %}
{% endblock %}

15
docs/requirements.txt Normal file
View File

@ -0,0 +1,15 @@
# MkDocs and core dependencies
mkdocs>=1.5.0,<2.0.0
mkdocs-material>=9.4.0,<10.0.0
# Markdown extensions
pymdown-extensions>=10.4.0,<11.0.0
# Plugins
mkdocs-minify-plugin>=0.7.0,<1.0.0
# Environment variable support is built into MkDocs via !ENV tag (requires PyYAML with env tag support)
# Optional: Additional useful plugins
# mkdocs-git-revision-date-localized-plugin>=1.2.0,<2.0.0
# mkdocs-awesome-pages-plugin>=2.9.0,<3.0.0
# mkdocs-redirects>=1.2.0,<2.0.0

49
docs/serve.sh Executable file
View File

@ -0,0 +1,49 @@
#!/bin/bash
set -e
# Development server script for GeoServer Cloud Documentation
# Usage: ./serve.sh [banner_message]
# Example: ./serve.sh "🔍 Development Preview"
BANNER_MESSAGE="$1"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
VENV_DIR="${SCRIPT_DIR}/.venv"
echo "🌐 Starting GeoServer Cloud Documentation Server"
echo "================================================"
# Check if virtual environment exists
if [ ! -d "$VENV_DIR" ]; then
echo "❌ Virtual environment not found. Please run ./build.sh first."
exit 1
fi
# Activate virtual environment
echo "🐍 Activating virtual environment..."
source "$VENV_DIR/bin/activate"
# Check if MkDocs is available
if ! command -v mkdocs >/dev/null 2>&1; then
echo "❌ MkDocs not found. Please run ./build.sh first."
exit 1
fi
echo "✅ Environment ready"
echo ""
# Export banner message if provided
if [ -n "$BANNER_MESSAGE" ]; then
echo "🏷️ Banner message: $BANNER_MESSAGE"
export BANNER_MESSAGE
fi
echo "🚀 Starting development server..."
echo "📍 Local URL: http://127.0.0.1:8000"
echo "🌐 Network URL: http://$(hostname):8000"
echo "🔄 Auto-reload enabled for content changes"
echo ""
echo "Press Ctrl+C to stop the server"
echo ""
# Start the development server (bind to all interfaces for network access)
mkdocs serve --dev-addr 0.0.0.0:8000

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

Before

Width:  |  Height:  |  Size: 57 KiB

After

Width:  |  Height:  |  Size: 57 KiB

View File

Before

Width:  |  Height:  |  Size: 431 KiB

After

Width:  |  Height:  |  Size: 431 KiB

View File

@ -0,0 +1,2 @@
# This file ensures the structurizr images directory is preserved in git
# Generated SVG diagram files are placed here during the build process

View File

@ -0,0 +1,241 @@
/* Custom styles for GeoServer Cloud documentation */
/* Color scheme customization matching docs.geoserver.org */
:root {
/* GeoServer Blue */
--gs-blue: #0082b6;
/* Material Theme Overrides */
--md-primary-fg-color: var(--gs-blue);
--md-primary-fg-color--light: #349bc4;
--md-primary-fg-color--dark: #006a94;
--md-accent-fg-color: var(--gs-blue);
/* Header overrides - White background, Blue text */
--md-header-bg: #ffffff;
--md-header-fg: var(--gs-blue);
/* Tabs overrides */
--md-tabs-bg: #ffffff;
--md-tabs-fg: var(--gs-blue);
/* Fonts */
--md-text-font: "Lucida Sans Unicode", "Lucida Grande", Verdana, Arial, Helvetica, sans-serif;
--md-code-font: "Consolas", "Monaco", "Bitstream Vera Sans Mono", monospace;
}
/* Body Font Override */
body {
font-family: var(--md-text-font);
}
/* Content Headers Styling */
.md-typeset h1,
.md-typeset h2,
.md-typeset h3,
.md-typeset h4,
.md-typeset h5,
.md-typeset h6 {
color: var(--gs-blue);
font-family: "Lucida Sans", "Lucida Sans Unicode", "Lucida Grande", Verdana, Arial, Helvetica, sans-serif;
}
/* Search input visibility on white header */
.md-search__input {
background-color: #f0f0f0;
}
.md-search__input:hover {
background-color: #e5e5e5;
}
/* Announcement bar styling */
.md-announce {
background-color: var(--gs-blue);
color: white;
text-align: center;
padding: 0.75rem 1rem;
font-weight: 600;
font-size: 0.9rem;
}
.md-announce a {
color: white;
text-decoration: underline;
}
.md-announce a:hover {
color: #e0e0e0;
}
/* Card grid layout for index pages */
.grid.cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 1rem;
margin: 1.5rem 0;
}
.grid.cards > .card {
border: 1px solid var(--md-default-fg-color--lightest);
border-radius: 0.25rem;
padding: 1.5rem;
transition: border-color 0.125s, box-shadow 0.125s;
}
.grid.cards > .card:hover {
border-color: var(--md-accent-fg-color);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}
/* Performance table styling */
.performance-table {
width: 100%;
border-collapse: collapse;
margin: 1rem 0;
}
.performance-table th,
.performance-table td {
padding: 0.75rem;
text-align: left;
border-bottom: 1px solid var(--md-default-fg-color--lightest);
}
.performance-table th {
font-weight: 600;
background-color: var(--md-default-bg-color);
}
/* Code block enhancements */
.highlight .filename {
background-color: var(--md-code-bg-color);
color: var(--md-code-fg-color);
padding: 0.5rem 1rem;
border-top-left-radius: 0.25rem;
border-top-right-radius: 0.25rem;
font-family: var(--md-code-font);
font-size: 0.875rem;
font-weight: 500;
}
/* Architecture diagram styling */
.architecture-diagram {
text-align: center;
margin: 2rem 0;
}
.architecture-diagram img {
max-width: 100%;
height: auto;
border: 1px solid var(--md-default-fg-color--lightest);
border-radius: 0.25rem;
}
/* Module badge styling */
.module-badge {
display: inline-block;
padding: 0.25rem 0.5rem;
font-size: 0.75rem;
font-weight: 500;
color: white;
border-radius: 0.25rem;
margin-right: 0.5rem;
}
.module-badge.core {
background-color: #2563eb;
}
.module-badge.cloud {
background-color: #f59e0b;
}
.module-badge.benchmarks {
background-color: #64748b;
}
/* API reference styling */
.api-method {
border-left: 4px solid var(--md-accent-fg-color);
padding-left: 1rem;
margin: 1rem 0;
}
.api-method-signature {
font-family: var(--md-code-font);
background-color: var(--md-code-bg-color);
padding: 0.5rem;
border-radius: 0.25rem;
margin-bottom: 0.5rem;
}
/* Quality attributes styling */
.quality-tree {
margin: 1.5rem 0;
}
.quality-tree ul {
list-style-type: none;
padding-left: 1.5rem;
}
.quality-tree > ul {
padding-left: 0;
}
.quality-tree li {
margin: 0.5rem 0;
position: relative;
}
.quality-tree li:before {
content: "▸";
position: absolute;
left: -1rem;
color: var(--md-accent-fg-color);
}
/* Responsive design */
@media screen and (max-width: 768px) {
.grid.cards {
grid-template-columns: 1fr;
}
.architecture-diagram {
margin: 1rem 0;
}
}
/* Dark mode adjustments */
[data-md-color-scheme="slate"] {
/* Revert header to dark for slate mode if desired, or keep custom.
Usually slate mode expects dark header. */
--md-header-bg: #1e1e20; /* Default slate header */
--md-header-fg: var(--md-primary-fg-color);
.grid.cards > .card {
border-color: var(--md-default-fg-color--lightest);
background-color: var(--md-default-bg-color);
}
.performance-table th {
background-color: var(--md-code-bg-color);
}
}
/* Print styles */
@media print {
.grid.cards {
display: block;
}
.grid.cards > .card {
break-inside: avoid;
margin-bottom: 1rem;
}
.architecture-diagram img {
max-width: 100%;
page-break-inside: avoid;
}
}

View File

@ -10,7 +10,6 @@ Here are three `docker compose` based deployment examples to try out:
* Our preferred option, the [pgconfig](stable/pgconfig/compose.yml) Catalog back-end, specifically developed for GeoServer Cloud with scalability in mind, storing all Catalog and GeoServer configuration in a PostgreSQL database.
* A shared [data-directory](stable/datadir/compose.yml) option, using a mounted volume to share a traditional GeoServer data directory across all services.
* And a **deprecated** [jdbcconfig](jdbcconfig/compose.yml) option, using the GeoServer [jdbcconfig](https://docs.geoserver.org/main/en/user/community/jdbcconfig/index.html) and [jdbcstore](https://docs.geoserver.org/main/en/user/community/jdbcstore/index.html) community modules.
Open a terminal and enter the directory where you just downloaded that file, and run `docker compose pull` to fetch the docker images from [Dockerhub](https://hub.docker.com/u/geoservercloud/):

View File

@ -66,7 +66,3 @@ Please check out the [docker-compose](./docker-compose/index.md) deployment docu
## Kubernetes
Please check out the example [Helm](https://helm.sh/) chart on this [helm-geoserver-cloud](https://github.com/camptocamp/helm-geoserver-cloud) repository as a starting point to deploy to K8s.
## Podman
Follow the [Podman](https://podman.io/)'s [deployment guide](./podman/index.md) to use Podman's daemonless container engine for Cloud Native GeoServer containers.

View File

@ -3,7 +3,7 @@
Requirements:
* Java >= 21 JDK
* [Maven](https://maven.apache.org/) >= `3.6.3`
* [Maven](https://maven.apache.org/) >= `3.9`
* A recent [Docker](https://docs.docker.com/engine/install/) version with the [Compose](https://docs.docker.com/compose/) plugin.
### Clone the repository
@ -106,7 +106,7 @@ docker buildx rm gscloud-builder
*GeoServer Cloud* depends on a custom GeoServer branch, `gscloud/gs_version/integration`, which contains patches to upstream GeoServer that have not yet been integrated into the mainstream `main` branch.
Additionally, this branch changes the artifact versions (e.g. from `2.26.0` to `2.26.0.0`), to avoid confusing maven if you also work with vanilla GeoServer, and to avoid your IDE downloading the latest `2.23-SNAPSHOT` artifacts from the OsGeo maven repository, overriding your local maven repository ones, and having confusing compilation errors that would require re-building the branch we need.
Additionally, this branch changes the artifact versions (e.g. from `2.28.0` to `2.28.0.0`), to avoid confusing maven if you also work with vanilla GeoServer, and to avoid your IDE downloading the latest `2.28-SNAPSHOT` artifacts from the OsGeo maven repository, overriding your local maven repository ones, and having confusing compilation errors that would require re-building the branch we need.
The `gscloud/gs_version/integration` branch is checked out as a submodule on the [camptocamp/geoserver-cloud-geoserver](https://github.com/camptocamp/geoserver-cloud-geoserver) repository, which publishes the custom geoserver maven artifacts to the Github maven package registry.

View File

@ -47,6 +47,13 @@ In addition to Checkstyle, the project uses:
Style checks are run as part of the build process. You can trigger them manually with:
```bash
# Run all checks
make lint
```
or using maven directly:
```bash
# Run all checks
mvn validate -Dqa -fae -ntp -T1C

View File

@ -1,15 +1,15 @@
# Understanding the event bus data flow
For general information about the event bus, hava a look [here](../../../src/catalog/event-bus/README.md).
For general information about the event bus, have a look [here](https://github.com/geoserver/geoserver-cloud/blob/main/src/catalog/event-bus/README.md).
The following diagram demonstrates the data flow on the event bus:
![Event Bus Data flow](../../img/gs_cloud_eventbus_diagram.svg)
![Event Bus Data flow](../../assets/images//gs_cloud_eventbus_diagram.svg)
1. Changes on the catalog/config level are usually done via the REST interface or the WebUI (via the Gateway)
2. Changes are persisted in the catalog/config
3. The `CatalogApplicationEventPublisher` listens to the events of the (native) GeoServer/Catalog (triggered by step 2)
4. Whenever such an event fires, the `CatalogApplicationEventPublisher` will publish a "local" `GeoServerEvent`. Have a look [here](../../../src/catalog/events/README.md) for the full type hierarchy.
4. Whenever such an event fires, the `CatalogApplicationEventPublisher` will publish a "local" `GeoServerEvent`. Have a look [here](https://github.com/geoserver/geoserver-cloud/blob/main/src/catalog/events/README.md) for the full type hierarchy.
5. The `RemoteGeoServerEventBridge` (listens to these `GeoServerEvent`s and) broadcasts `RemoteGeoServerEvent`s to the event bus.
6. All registered microservices listen for incoming `RemoteGeoServerEvent`s
7. The payload of these remote events will be published as local events to reload/refresh the catalog/config locally.

View File

@ -19,7 +19,7 @@ Only a curated list of the [vast amount](http://geoserver.org/release/stable/) o
The following diagram depicts the System's general architecture:
![Cloud Native GeoServer Architecture Diagram](../img/gs_cloud_architecture_diagram.svg "Cloud Native GeoServer Architecture Diagram")
![Cloud Native GeoServer Architecture Diagram](../assets/images/gs_cloud_architecture_diagram.svg "Cloud Native GeoServer Architecture Diagram")
> - Hexagons represent microservices;
> - coloured rectangles, logical groupings of components;
@ -87,7 +87,6 @@ Each microservice is its own self-contained application, including only the GeoS
| |_ backends/ ............................ Spring Boot AutoConfigurations for specific catalog back-ends
| | |_ common/ ........................ Basic catalog and config bean wiring common to all back-ends
| | |_ datadir/ ....................... Shared "data directory" catalog back-end
| | |_ jdbcconfig/ .................... "jdbcconfig" catalog back-end
| | |_ pgconfig/ ...................... PostgreSQL catalog back-end
| |
| |_ cache/ ............................... Spring Boot JCache support and auto-configurations for the Catalog

View File

@ -8,7 +8,7 @@ at graceful shut down time.
Inter-service communication will then be automatically load balanced to all available service instances of a given type.
The most common scenario is when for High Availability or performance reasons, there are several instances of a specific service,
hence incoming requests passing through the [Gateway Service](gateway-service.yml) get served by a different instance in a round-robin
hence incoming requests passing through the [Gateway Service] get served by a different instance in a round-robin
fashion.
**Docker image**: `geoservercloud/gs-cloud-discovery-service`.
@ -37,9 +37,10 @@ In the default docker composition, there's only one instance of the discovery se
more instances can be launched, al
Since the discovery service are fixed entry points, we're setting up two peer aware eureka instances for HA.
# Browse to http://localhost:8761 and http://localhost:8762 to verify they see each
# other and all services are registered at both eureka instances.
# See http://cloud.spring.io/spring-cloud-static/spring-cloud.html#_peer_awareness
Browse to http://localhost:8761 and http://localhost:8762 to verify they see each other and all services are registered at both eureka instances.
See http://cloud.spring.io/spring-cloud-static/spring-cloud.html#_peer_awareness
https://docs.spring.io/spring-cloud-netflix/docs/2.2.7.RELEASE/reference/html/

View File

@ -5,7 +5,7 @@
**Service name**: `gateway-service`.
This is the logical service name by which web clients will get the actual instances addresses from the [discovery-service](discovery-service.yml) and perform client-side load balancing against when interacting with the service.
This is the logical service name by which web clients will get the actual instances addresses from the [discovery-service] and perform client-side load balancing against when interacting with the service.
## Service Configuration

View File

@ -6,7 +6,7 @@ Spring Boot/Cloud microservice that exposes GeoServer [REST API](https://docs.ge
**Service name**: `restconfig-v1`.
Logical service name by which the [gateway-service](gateway-service.yml) will get the actual instances addresses from the [discovery-service](discovery-service.yml) and perform client-side load balancing against when interacting with the service.
Logical service name by which the [gateway-service] will get the actual instances addresses from the [discovery-service] and perform client-side load balancing against when interacting with the service.
## Configuration

View File

@ -136,7 +136,7 @@ Only a curated list of the [vast amount](http://geoserver.org/release/stable/) n
The following diagram depicts the system's general architecture:
![GeoServer Cloud Architecture Diagram](img/gs_cloud_architecture_diagram.svg "GeoServer Cloud Architecture Diagram")
![GeoServer Cloud Architecture Diagram](assets/images/gs_cloud_architecture_diagram.svg "GeoServer Cloud Architecture Diagram")
> - Hexagons represent microservices.
> - Colored rectangles represent logical groupings of components.
@ -159,7 +159,7 @@ release.
# Developer's Guide
Follow the [Developer's Guide](develop/index.md) to learn more about the System's design and how to get started contributing to it.
Follow the [Developer's Guide](developer-guide/index.md) to learn more about the System's design and how to get started contributing to it.
# Deployment Guide

View File

@ -0,0 +1,6 @@
workspace "GeoServer Cloud - Dynamic Views" "Runtime scenarios for GeoServer Cloud" {
model {
}
views {
}
}

View File

@ -0,0 +1,2 @@
# This file ensures the exports directory is preserved in git
# Generated PlantUML files (.puml) are created here during diagram generation

View File

@ -0,0 +1,42 @@
#!/bin/bash
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
EXPORT_DIR="${SCRIPT_DIR}/exports"
OUTPUT_DIR="${SCRIPT_DIR}/../src/assets/images/structurizr"
# Create the output directory if it doesn't exist
mkdir -p "$OUTPUT_DIR"
# Pull PlantUML Docker image
echo "Pulling PlantUML Docker image..."
docker pull plantuml/plantuml:latest
# Loop through all PlantUML files and convert them to SVG
for puml_file in "$EXPORT_DIR"/*.puml; do
if [ -f "$puml_file" ]; then
base_name=$(basename "$puml_file" .puml)
echo "Converting $(basename "$puml_file") to SVG..."
# Use PlantUML Docker image to convert PUML to SVG with current user permissions
docker run --rm --user "$(id -u):$(id -g)" -v "${EXPORT_DIR}:/work" plantuml/plantuml -tsvg "/work/$(basename "$puml_file")"
# Move the generated SVG to the output directory
if [ -f "${EXPORT_DIR}/${base_name}.svg" ]; then
# Remove existing file first to avoid permission issues
rm -f "${OUTPUT_DIR}/${base_name}.svg"
# Move the file (now has correct permissions)
mv "${EXPORT_DIR}/${base_name}.svg" "${OUTPUT_DIR}/${base_name}.svg"
echo "✓ Generated ${base_name}.svg"
else
echo "⚠ Failed to generate ${base_name}.svg"
fi
fi
done
echo "Conversion complete. SVG files are in: $OUTPUT_DIR"
# List the generated files
echo "Generated files:"
ls -la "$OUTPUT_DIR"/*.svg 2>/dev/null || echo "No SVG files found"

View File

@ -0,0 +1,80 @@
#!/bin/bash
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
EXPORTS_DIR="${SCRIPT_DIR}/exports"
# Create the export directory if it doesn't exist
mkdir -p "$EXPORTS_DIR"
echo "Step 1: Pulling the latest Structurizr CLI Docker image"
docker pull structurizr/cli:latest
echo "Step 2: Generating PlantUML files from Structurizr DSL"
# Track if any exports succeeded
EXPORTS_SUCCEEDED=false
# Export workspace.dsl to PlantUML (required)
if [ -f "${SCRIPT_DIR}/workspace.dsl" ]; then
echo "Exporting workspace.dsl to PlantUML..."
if docker run --rm -v "${SCRIPT_DIR}:/usr/local/structurizr" structurizr/cli:latest export \
-workspace /usr/local/structurizr/workspace.dsl \
-format plantuml/c4plantuml \
-output /usr/local/structurizr/exports; then
echo "✅ Workspace views exported successfully"
EXPORTS_SUCCEEDED=true
else
echo "❌ Workspace export failed"
exit 1
fi
else
echo "❌ ERROR: workspace.dsl not found - this is required!"
exit 1
fi
# Export dynamic-views.dsl to PlantUML (must be valid if present)
if [ -f "${SCRIPT_DIR}/dynamic-views.dsl" ]; then
echo "Exporting dynamic-views.dsl to PlantUML..."
if docker run --rm -v "${SCRIPT_DIR}:/usr/local/structurizr" structurizr/cli:latest export \
-workspace /usr/local/structurizr/dynamic-views.dsl \
-format plantuml/c4plantuml \
-output /usr/local/structurizr/exports; then
echo "✅ Dynamic views exported successfully"
else
echo "❌ Dynamic views export failed"
exit 1
fi
else
echo " dynamic-views.dsl not found (skipping dynamic views)"
fi
# Verify we have at least some PlantUML files
if ! ls "${EXPORTS_DIR}"/*.puml 1> /dev/null 2>&1; then
echo "❌ ERROR: No PlantUML files were generated!"
exit 1
fi
echo "Step 3: Converting PlantUML to SVG"
./plantuml-generate-svg.sh
# Verify SVG files were created
SVG_OUTPUT_DIR="${SCRIPT_DIR}/../src/assets/images/structurizr"
if ! ls "${SVG_OUTPUT_DIR}"/*.svg 1> /dev/null 2>&1; then
echo "❌ ERROR: No SVG files were generated!"
exit 1
fi
echo "✅ Diagram generation completed successfully"
# List the generated files
echo "Generated files:"
echo "PlantUML files:"
find "$EXPORTS_DIR" -name "*.puml" | sort | while read -r file; do
echo " - $(basename "$file")"
done
echo "SVG files:"
find "$SVG_OUTPUT_DIR" -name "*.svg" | sort | while read -r file; do
file_size=$(stat -f%z "$file" 2>/dev/null || stat -c%s "$file" 2>/dev/null)
echo " - $(basename "$file") (Size: $file_size bytes)"
done

View File

@ -0,0 +1,82 @@
workspace "GeoServer Cloud" "Architecture documentation for GeoServer Cloud" {
model {
properties {
"structurizr.groupSeparator" "/"
}
user = person "User" "A user of GeoServer Cloud"
developer = person "Developer" "A developer extending or deploying GeoServer Cloud"
geoserverCloud = softwareSystem "GeoServer Cloud" "Cloud Native GeoServer" {
group "Infrastructure" {
gateway = container "Gateway Service" "API Gateway and Load Balancer" "Spring Cloud Gateway"
discovery = container "Discovery Service" "Service Registry" "Eureka"
config = container "Config Service" "Centralized Configuration" "Spring Cloud Config"
}
group "Microservices" {
wfs = container "WFS Service" "Web Feature Service" "GeoServer WFS"
wms = container "WMS Service" "Web Map Service" "GeoServer WMS"
wcs = container "WCS Service" "Web Coverage Service" "GeoServer WCS"
rest = container "REST Service" "REST Configuration API" "GeoServer REST"
}
group "Frontends" {
webui = container "Web UI" "Administration Interface" "GeoServer Web UI"
}
}
user -> gateway "Uses"
developer -> gateway "Configures"
gateway -> wfs "Routes to"
gateway -> wms "Routes to"
gateway -> wcs "Routes to"
gateway -> rest "Routes to"
gateway -> webui "Routes to"
wfs -> discovery "Registers with"
wms -> discovery "Registers with"
wcs -> discovery "Registers with"
rest -> discovery "Registers with"
webui -> discovery "Registers with"
gateway -> discovery "Discovers services from"
wfs -> config "Gets config from"
wms -> config "Gets config from"
wcs -> config "Gets config from"
rest -> config "Gets config from"
webui -> config "Gets config from"
gateway -> config "Gets config from"
}
views {
systemContext geoserverCloud "SystemContext" {
include *
autoLayout
}
container geoserverCloud "Containers" {
include *
autoLayout
}
styles {
element "Person" {
shape Person
background #08427B
color #ffffff
}
element "Software System" {
background #1168BD
color #ffffff
}
element "Container" {
background #438DD5
color #ffffff
}
}
}
}