diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 052a682498b..177dbf16e18 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -496,6 +496,68 @@ jobs: run: npm run eslint working-directory: ./email + docker-slim-smoke: + name: Slim Docker smoke 🐳 + needs: [backend-build] + runs-on: ubuntu-24.04 + permissions: + contents: read + services: + postgres: + image: postgres:17 + env: + POSTGRES_PASSWORD: postgres + POSTGRES_DB: postgres + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 5s + --health-timeout 3s + --health-retries 10 + steps: + - uses: actions/checkout@v4 + + - name: Setup environment + uses: ./.github/actions/setup-env + with: + node: "false" + + - name: Download backend build result + uses: ./.github/actions/download-backend-build + + - name: Build slim Docker image + run: ./gradlew dockerSlim + env: + SKIP_SERVER_BUILD: true + + - name: Start slim image + run: | + docker run -d --name tolgee-slim --network host \ + -e SPRING_DATASOURCE_URL=jdbc:postgresql://localhost:5432/postgres \ + -e SPRING_DATASOURCE_USERNAME=postgres \ + -e SPRING_DATASOURCE_PASSWORD=postgres \ + tolgee/tolgee:slim + + - name: Wait for app to report healthy + run: | + for i in $(seq 1 90); do + status=$(curl -fsS http://localhost:8080/actuator/health 2>/dev/null \ + | jq -r '.status // empty') + if [ "$status" = "UP" ]; then + echo "Slim image healthy after $((i * 2))s" + exit 0 + fi + echo "[$i] status=${status:-}; retrying in 2s" + sleep 2 + done + echo "❌ Slim image did not report UP within 180s" + exit 1 + + - name: Dump container logs on failure + if: failure() + run: docker logs tolgee-slim || true + everything-passed: name: Everything passed 🎉 needs: @@ -508,6 +570,7 @@ jobs: - schema-check - migration-check - data-cy-check + - docker-slim-smoke - e2e - e2e-code-checks - e2e-install-deps @@ -550,6 +613,10 @@ jobs: failed_jobs+=("data-cy-check") fi + if [[ "${{ needs.docker-slim-smoke.result }}" != "success" ]]; then + failed_jobs+=("docker-slim-smoke") + fi + if [[ "${{ needs.e2e.result }}" != "success" ]]; then failed_jobs+=("e2e") fi diff --git a/backend/app/src/main/kotlin/io/tolgee/commandLineRunners/EmbeddedPostgresDeprecationCommandLineRunner.kt b/backend/app/src/main/kotlin/io/tolgee/commandLineRunners/EmbeddedPostgresDeprecationCommandLineRunner.kt new file mode 100644 index 00000000000..913e5e87e29 --- /dev/null +++ b/backend/app/src/main/kotlin/io/tolgee/commandLineRunners/EmbeddedPostgresDeprecationCommandLineRunner.kt @@ -0,0 +1,27 @@ +package io.tolgee.commandLineRunners + +import io.tolgee.configuration.tolgee.PostgresAutostartProperties +import io.tolgee.configuration.tolgee.PostgresAutostartProperties.PostgresAutostartMode +import org.slf4j.LoggerFactory +import org.springframework.boot.CommandLineRunner +import org.springframework.stereotype.Component + +@Component +class EmbeddedPostgresDeprecationCommandLineRunner( + private val postgresAutostartProperties: PostgresAutostartProperties, +) : CommandLineRunner { + private val logger = LoggerFactory.getLogger(this::class.java) + + override fun run(vararg args: String) { + if (!postgresAutostartProperties.enabled || postgresAutostartProperties.mode != PostgresAutostartMode.EMBEDDED) { + return + } + + logger.warn( + "The embedded PostgreSQL bundled in the tolgee/tolgee image is deprecated and will be removed in Tolgee v4. " + + "Migrate to an external database before upgrading. " + + "See https://docs.tolgee.io/platform/self_hosting/running_with_docker" + + "#migrate-from-the-bundled-database", + ) + } +} diff --git a/backend/data/src/main/kotlin/io/tolgee/configuration/tolgee/PostgresAutostartProperties.kt b/backend/data/src/main/kotlin/io/tolgee/configuration/tolgee/PostgresAutostartProperties.kt index a2a3f3efb4f..6e5cb5d4aa2 100644 --- a/backend/data/src/main/kotlin/io/tolgee/configuration/tolgee/PostgresAutostartProperties.kt +++ b/backend/data/src/main/kotlin/io/tolgee/configuration/tolgee/PostgresAutostartProperties.kt @@ -21,7 +21,13 @@ class PostgresAutostartProperties { "This is default option when running Tolgee using Java. " + "See [Running with Java](/self_hosting/running_with_java.mdx).\n" + "- `EMBEDDED` - Tolgee tries to run it's embedded PostgreSQL " + - "which is bundled in the `tolgee/tolgee` Docker image.", + "which is bundled in the `tolgee/tolgee` Docker image.\n" + + "\n" + + "`EMBEDDED` is deprecated. Tolgee v4 removes the bundled PostgreSQL from the " + + "`tolgee/tolgee` image, so setups using it have to move to an external database " + + "before upgrading. See " + + "[Migrate from the bundled database](/self_hosting/running_with_docker" + + "#migrate-from-the-bundled-database).", ) var mode: PostgresAutostartMode = PostgresAutostartMode.DOCKER diff --git a/docker/app/Dockerfile.slim b/docker/app/Dockerfile.slim new file mode 100644 index 00000000000..1639fdbafaf --- /dev/null +++ b/docker/app/Dockerfile.slim @@ -0,0 +1,47 @@ +FROM eclipse-temurin:21-jre-alpine + +RUN apk --no-cache add bash + +############# +### Tolgee # +############# + +# Expose application port +EXPOSE 8080 + +# Define persistent volume for data storage +VOLUME /data + +# Environment variables for configuration +# Postgres autostart is disabled — the slim image doesn't bundle the postgres +# server, so it must be run against an external database. +ENV HEALTHCHECK_PORT=8080 \ + spring_profiles_active=docker \ + TOLGEE_POSTGRES_AUTOSTART_ENABLED=false + +# Copy necessary application files +COPY BOOT-INF/lib /app/lib +COPY META-INF /app/META-INF +COPY BOOT-INF/classes /app +COPY --chmod=755 cmd.sh /app + +# Download OpenTelemetry Java agent for distributed tracing +# When OTEL_JAVAAGENT_ENABLED=true, cmd.sh will use this agent +# See: docs/observability/ +# Version is passed from gradle.properties via --build-arg (see gradle/docker.gradle) +ARG OTEL_AGENT_VERSION +RUN test -n "$OTEL_AGENT_VERSION" || (echo "OTEL_AGENT_VERSION build arg is required" && exit 1) +RUN wget -O /app/opentelemetry-javaagent.jar \ + "https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/download/v${OTEL_AGENT_VERSION}/opentelemetry-javaagent.jar" + +################# +### Let's go ## +################# + +# Define the startup command +ENTRYPOINT ["/app/cmd.sh"] + + +# Health check to ensure the app is up and running +HEALTHCHECK --interval=10s --timeout=3s --retries=20 \ + CMD wget --spider -q "http://127.0.0.1:$HEALTHCHECK_PORT/actuator/health" || exit 1 diff --git a/gradle/docker.gradle b/gradle/docker.gradle index 95e0d6bff2b..3ae4be3389a 100644 --- a/gradle/docker.gradle +++ b/gradle/docker.gradle @@ -33,6 +33,23 @@ tasks.register('docker') { dependsOn("dockerPrepare") } +// Builds the slim Docker image, tagged as tolgee/tolgee:slim. +// Uses Dockerfile.slim - JRE-only base, no embedded postgres. +// The slim image is not published; it is built on demand by the EE image +// build in the billing repo and by the slim smoke test. +tasks.register('dockerSlim') { + doLast { + exec { + workingDir dockerPath + commandLine "docker", "build", ".", + "-f", "Dockerfile.slim", + "-t", "tolgee/tolgee:slim", + "--build-arg", "OTEL_AGENT_VERSION=${opentelemetryJavaagentVersion}" + } + } + dependsOn("dockerPrepare") +} + // Builds and pushes multi-platform Docker image for CI. // Reads configuration from environment variables: // - VERSION: image tag version (default: 'latest')