Skip to content

Deployment

View Markdown

A Vertique application deploys easily as a container or pod, with a clear line between what it owns and what the platform owns:

  • Containers, not fat jars. Applications package as OCI images via Jib, already configured by the archetype. The same framework launcher entrypoint runs locally and in the container, as a non-root user by default.
  • Configuration from the environment. No config file is required to start with framework defaults. Runtime configuration is mounted next to the process and is never baked into the image.
  • Secrets stay on the platform. Four secret providers (Vault, AWS Secrets Manager, AWS SSM, Azure Key Vault) resolve ${key} placeholders at runtime. No resolved value is written to disk, and no credential belongs in an image layer.
  • Probes built in. /health/live and /health/ready serve on a separate management port for the orchestrator’s own probes. Metrics and tracing are opt-in modules.
  • An explicit platform boundary. Process supervision, scaling, TLS termination, log shipping, and network policy belong to the platform, and this page states them explicitly.

This page explains what mvn -ntp package produces, how a generated application’s own container image is built, and which responsibilities belong to the application versus the platform that runs it: configuration, secrets, health reporting, and everything below the application process.

Working directory: rest-app/, the REST application generated in Quickstart.

Terminal window
mvn -ntp package

Expected result: BUILD SUCCESS, producing target/rest-app-0.1.0-SNAPSHOT.jar. That jar contains only the application’s own compiled classes and resources, plus its META-INF/services/dev.vertique.core.VertiqueComponentFactory service-registration entry. It has no bundled dependency classes and no Main-Class manifest attribute:

Manifest-Version: 1.0
Created-By: Maven JAR Plugin 3.4.1
Build-Jdk-Spec: 25

Running it directly confirms this:

Terminal window
java -jar target/rest-app-0.1.0-SNAPSHOT.jar

Expected result: no main manifest attribute, in target/rest-app-0.1.0-SNAPSHOT.jar. The missing attribute is a deliberate framework choice. Vertique applications package as an OCI container image via Jib and do not use a maven-shade fat jar, so mvn -ntp package on its own never needs to assemble a runnable, dependency-bundling artifact. See vertique-launcher’s module reference for the full rationale and for dev.vertique.launcher.VertiqueApplication, the framework-owned entrypoint class every generated application runs through.

Two supported paths turn this packaged jar into a running application. Both name that same entrypoint class, and neither names the jar itself. Locally, mvn -ntp exec:java (used throughout Quickstart and Persistence) runs exec-maven-plugin configured with a mainClass of dev.vertique.launcher.VertiqueApplication, assembling the full Maven runtime classpath itself. For deployment, Jib assembles that same classpath as container image layers. Your own application code does not have to wire either path. Both are set up once, by the archetype’s generated pom.xml, parented on vertique-app-parent.

The generated project’s own README.md documents the container-build command directly:

Builds a local container image with Jib.
mvn -ntp jib:dockerBuild

Working directory: rest-app/, with a reachable Docker daemon. jib:dockerBuild loads the built image into your local Docker daemon. The jib:build goal, not covered here, pushes to a registry and needs no local daemon.

Terminal window
mvn -ntp jib:dockerBuild

Running it announces the target image name up front: rest-app, taken from the generated pom.xml’s own ${project.artifactId}. It then builds the application’s dependency, resource, and class layers before fetching the declared base image:

[INFO] Containerizing application to Docker daemon as rest-app...
[INFO] Getting manifest for base image eclipse-temurin:25-jre...
[INFO] Building dependencies layer...
[INFO] Building snapshot dependencies layer...
[INFO] Building resources layer...
[INFO] Building classes layer...
[INFO] Building jvm arg files layer...

A completed run reports BUILD SUCCESS and leaves an image named rest-app in your local Docker daemon, ready for docker run. The plugin configuration below names no explicit tag, so Docker applies its own default tag to the reference. The generated pom.xml’s own jib-maven-plugin configuration is:

<plugin>
<groupId>com.google.cloud.tools</groupId>
<artifactId>jib-maven-plugin</artifactId>
<configuration>
<from>
<image>eclipse-temurin:25-jre</image>
</from>
<to>
<image>${project.artifactId}</image>
</to>
<container>
<mainClass>dev.vertique.launcher.VertiqueApplication</mainClass>
<!-- Run as a numeric non-root user rather than as root. -->
<user>65532:65532</user>
</container>
</configuration>
</plugin>

The mainClass named here is the same dev.vertique.launcher.VertiqueApplication entrypoint exec-maven-plugin names for the local run above. The container runs the same generated code through the same framework-owned launcher. It is not a separate build. Once the image is running, publish its two ports and call the same endpoints Quickstart already proves locally: its /hello call and this page’s own Health and observability endpoints below. Substitute whatever host ports you chose in docker run’s own -p mapping.

Configuration establishes the rule, and this container image does not change it. Each relative configured directory (config/ by default) resolves against the running process’s own current working directory and never against the compiled classpath. No configuration file is required for the application to start with framework defaults. The Jib configuration above sets no container.workingDirectory, so it does not change that resolution rule for the containerized process. It also does not copy the project’s config/ directory into the image, so the config/application.json that a local mvn -ntp exec:java run reads is absent in the container. Provide runtime configuration to a container the same way you would to any other Vertique process: mount or otherwise place a config/ directory next to wherever the container’s entrypoint runs from, or set VERTX_CONFIG_LOCATIONS.

Secret material belongs to the platform running the container. It never belongs to the image or the application’s own repository. The application declares where a secret comes from, with a ${key} placeholder reference or a config.stores entry. The platform is responsible for making the backing secret store reachable and populated at runtime. See Configuration for the placeholder idiom itself. Vertique’s four secret providers are:

None of these providers writes a resolved secret value back into a file on disk, and none of them belongs in a container image layer. The credentials each provider itself needs to reach its backing store (a Vault token, an AWS role, an Azure managed identity) are the platform’s responsibility to supply, typically through environment variables, a mounted credential file, or an ambient identity the runtime environment already grants the container. Never bake a credential into the image.

The application’s management port serves the same two endpoints in a container as anywhere else, mounted by vertique-management’s ManagementVerticle on a port separate from the main HTTP server:

Endpoint Backing check set UP response DOWN response
GET /health/live @Liveness-qualified HealthCheck set 200 503
GET /health/ready @Readiness-qualified HealthCheck set 200 503

Quickstart’s own generated integration test already calls /health/live and asserts an UP status. A container orchestrator (or any other platform-owned process supervisor) points its own liveness and readiness probes at these same two paths on the management port and does not re-implement health logic. See vertique-management’s module reference for the full response shape, aggregation rules, and how to contribute an application-owned HealthCheck.

Metrics and distributed tracing are both opt-in, added by naming a module in your own component. No starter wires either one automatically. Observability covers both: the meter registry and its backends, tracing and trace-log correlation, and the correlation thread the platform’s log pipeline can rely on.

Everything below the application process is the deploying platform’s responsibility. Neither the framework nor the application owns it:

  • Process supervision and restart: starting the container, restarting it on crash or failed health probe, and rolling out a new image version.
  • Scaling: how many instances run and how traffic is distributed across them.
  • TLS termination: Vertique’s own HTTP and management servers serve plain HTTP. Terminating TLS in front of them (a load balancer, ingress controller, or sidecar) is a platform decision.
  • Log shipping: the application logs to its configured output. Collecting, shipping, and retaining those logs is the platform’s concern.
  • Network policy: which callers can reach the HTTP port, and whether the management port is reachable at all from outside the platform’s own probes.