Deploying a Vaadin Application with Control Center
Control Center manages the deployment of Vaadin applications through a custom Kubernetes resource called App
. When an App
manifest is applied, Control Center automatically provisions all necessary components: deployments, services, ingress routing, configuration, certificate requests, and more.
To learn more about how Control Center manages applications internally, refer to the Architecture section.
This guide covers the steps to prepare a Vaadin application, package it as a container image, and deploy it to a cluster using Control Center.
Add the Control Center Dependency
To enable Control Center integration (for example, metadata reporting and health endpoints), add the control-center-starter
dependency to your project.
Source code
build.gradle.kts
build.gradle.kts
dependencies {
implementation("com.vaadin:control-center-starter")
}
build.gradle.kts
build.gradle.kts
pom.xml
pom.xml
pom.xml
pom.xml
Tip
| When using the Vaadin Bill Of Materials (BOM), the version does not need to be specified explicitly. |
Build the Application Image
Spring Boot supports building container images using Cloud Native Buildpacks, which is the recommended approach for Vaadin applications.
Buildpacks offer several benefits:
-
Simplified image creation — no need to write or maintain a Dockerfile
-
Optimized image layering — dependencies, classes, and static resources are separated to improve caching and rebuild performance
-
Secure defaults — minimal base images, non-root execution, and JVM tuning are applied automatically
The resulting image is production-ready and follows best practices out-of-the-box.
Source code
Terminal
./gradlew bootBuildImage -Pvaadin.productionMode=true --imageName=company/my-app:1.0.0
Terminal
Terminal
Terminal
This produces a Docker image tagged as company/my-app:1.0.0
.
Create and Apply the App Resource
Create a Kubernetes manifest using the App
custom resource. This manifest instructs Control Center to deploy the application and manage its configuration.
Source code
my-app.yaml
my-app.yaml
apiVersion: vaadin.com/v1alpha1
kind: App
metadata:
name: my-app
namespace: vaadin
spec:
host: demo.example.com
image: company/my-app:1.0.0
version: "1.0.0"
replicas: 3
Field Overview
-
metadata.name
: Logical name of the application inside the cluster. -
metadata.namespace
: Namespace where the application should be deployed (optional). -
spec.host
: Public hostname where the application will be reachable. -
spec.image
: Fully qualified container image reference. -
spec.version
: Application version (used for tracking and visibility). -
spec.replicas
: Number of instances (default: 1).
Add Environment Variables
Environment variables can be added to the application using the spec.env
field. These variables are injected into the container and become available to the Vaadin application at runtime—either through the standard Java System.getenv()
API or automatically mapped by Spring Boot into configuration properties.
This mechanism is useful for setting configuration values such as logging levels, Spring profiles, external API keys, or feature toggles.
Source code
my-app.yaml
my-app.yaml
spec:
env:
- name: LOGGING_LEVEL_MY_PACKAGE
value: debug
- name: API_KEY
valueFrom:
secretKeyRef:
name: my-secret
key: api-key
Important
| Changes to environment variables trigger an application redeployment. |
Configure Resource Limits
To control the amount of CPU and memory allocated to the application pods, use the spec.resources
field. This helps ensure fair scheduling and cluster stability.
Source code
my-app.yaml
my-app.yaml
spec:
resources:
requests:
cpu: "500m"
memory: "256Mi"
limits:
cpu: "1000m"
memory: "512Mi"
-
requests
define the minimum resources the pod is guaranteed to receive. -
limits
define the maximum resources the pod can consume.
Setting both helps the Kubernetes scheduler place the pod efficiently and enforce upper bounds during runtime.
Provision a Database
Control Center can automatically provision a database for a deployed application on the managed PostgreSQL cluster that is installed with Control Center. The database is automatically created, and credentials are injected into the application environment.
To provision a database, set the spec.postgres.database
field in the App
manifest with the name of a database.
Example App
manifest with database provisioning enabled:
Source code
my-app.yaml
my-app.yaml
apiVersion: vaadin.com/v1alpha1
kind: App
metadata:
name: my-app
namespace: vaadin
spec:
host: demo.example.com
image: company/my-app:1.0.0
version: "1.0.0"
postgres:
database: my-database
When the application starts, Control Center injects the database configuration into the environment, and Spring Boot automatically configures a DataSource
bean.
This DataSource
can be used directly in the application, for example via JdbcTemplate
.
Source code
Inject and use the database connection
public class CustomerView extends VerticalLayout {
public CustomerView(DataSource dataSource) {
var customerList = new UnorderedList();
var jdbc = new JdbcTemplate(dataSource);
jdbc.queryForList("SELECT name FROM customers", String.class).forEach(name -> {
customerList.add(new ListItem(name));
});
add(new H1("Customer List"));
add(customerList);
}
}
Database configuration is handled entirely through environment variables, allowing standard Spring Boot features such as Flyway migrations or JPA/Hibernate integration to work without additional configuration.
Enable User Authentication
Control Center includes a preconfigured instance of Keycloak to provide secure user authentication for deployed applications. This integration supports advanced identity features including multi-factor authentication (MFA) and passwordless login.
Configure Spring Security
Add the following Spring Security configuration to the application using the ControlCenterSecurityConfigurer
provided by the control-center-starter
dependency:
Source code
Java
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
return http
.with(ControlCenterSecurityConfigurer.controlCenter(), Customizer.withDefaults())
.build();
}
}
This configuration enables authentication through the Keycloak instance managed by Control Center.
To define who can access to the application views, refer to Annotating View Classes.
Note
| The configurer can be added to an existing security configuration. |
Reference a Keycloak Realm in the App Manifest
To activate authentication, the application must declare the Keycloak realm to use in the App
manifest. This is done by adding the keycloak.realm
property:
Source code
my-app.yaml
my-app.yaml
spec:
keycloak:
realm: my-realm
A realm in Keycloak represents an isolated identity space. Each realm contains its own users, credentials, roles, and authentication settings.
To list available realms in the cluster:
Source code
Terminal
kubectl get realms -n vaadin
Example output:
Source code
NAME AGE MESSAGE STATE
control-center 30s Realm is up-to-date APPLIED
my-realm 30s Realm is up-to-date APPLIED
A default realm named control-center
is created automatically during Control Center installation. New realms can also be created and managed; for details, refer to the Identity Management documentation.
Once configured, users must authenticate through the specified realm before accessing the application.
Apply the Manifest
Once the App
manifest is written and saved, it can be applied to the Kubernetes cluster using the kubectl apply
command.
Source code
Terminal
kubectl apply -f my-app.yaml
This instructs Kubernetes to create the custom resource in the specified namespace. Control Center continuously watches for changes to App
resources and automatically begin provisioning the application based on the declared specification.
When the manifest is applied, Control Center performs a series of automated operations:
-
A Kubernetes
Deployment
is created using the specified image, configured with sane defaults for Vaadin applications, including health probes, memory and CPU limits, and internal management ports. -
A
Service
andIngress
are provisioned to expose the application on the specifiedhost
, using HTTPS. -
A TLS certificate is requested from the configured issuer (such as Let’s Encrypt) for the
host
. -
If DNS management is enabled, a corresponding DNS record is created automatically and kept in sync.
-
Runtime configuration is injected via config maps and secrets, including identity provider integration and optional database connections.
This flow ensures that the application is fully integrated into the cluster with minimal configuration, using secure and production-ready defaults.
To verify the deployment status, run:
Source code
Terminal
kubectl get apps -A
Example output:
Source code
NAMESPACE NAME AGE PHASE READY URI VERSION
vaadin my-app 30s RUNNING 3/3 https://demo.example.com 1.0.0
Explanation of the columns:
-
PHASE
: Current lifecycle state (PENDING
,RUNNING
,FAILED
) -
READY
: Indicates how many replicas are running and ready -
URI
: Public HTTPS URL where the application is exposed -
VERSION
: Application version as declared inspec.version
If the PHASE
remains in PENDING
, inspect the related events, pod status, and logs to determine whether an image pull, DNS, or certificate issue is delaying the rollout.
Once the status is RUNNING
and the READY
column matches the desired replicas, the application is live.
To access it, point your browser to:
Source code
https://demo.example.com
This completes the deployment process. The application is now fully integrated into the cluster, secured with HTTPS, and managed by Control Center.