CNE GCP Ready: Adding OSGi Modules or Client Extensions With Overlays
The Cloud Native Experience (CNE) toolkit uses overlays to customize standard Liferay deployments.
Upload custom files (such as OSGi modules, client extensions, configuration files, or site initializers) to a project-level Google Cloud Storage bucket shared by every environment in the project, then configure each environment to apply them during pod startup.
This approach avoids custom Liferay image builds, applies changes on top of the standard container, and is fully managed through GitOps.
CNE overlay buckets are scoped to the project rather than to each environment. You are on the older per-environment model if your GitOps repository has no project.yaml file enabling the overlay bucket. The old per-environment buckets are not migrated automatically, and an overlay configuration built for that model stops working until you migrate. See Enable and Configure the Overlay Bucket.
CNE supports two overlay workflows:
- Manual overlays
- Automated overlays with GitOps and CI
How Overlays Work
When overlays are enabled, an init container downloads files from the overlay bucket during pod startup and copies them into the Liferay runtime filesystem.
Overlay files are layered into the container at startup time and are not persisted in a separate volume.
The overlay bucket is provisioned once per project and shared by every environment in that project. Enabling overlays end to end requires three separate settings: the project-level bucket, project-level access to that bucket, and the per-environment overlay processing toggle in liferay.yaml, which is disabled by default.
Enable and Configure the Overlay Bucket
Before configuring either overlay workflow, provision the project’s overlay bucket and grant environments access to it. Complete these steps once per project.
Create the Overlay Bucket
In liferay/projects/<projectId>/project.yaml, enable the overlay bucket:
overlayBucket:
enabled: true
This setting defaults to false. Setting overlayBucket.enabled to true in project.yaml provisions the project’s overlay Google Cloud Storage bucket, with versioning enabled, uniform bucket-level access, and STANDARD storage class.
overlayBucket.forceDestroy defaults to false. Set it to true to delete the bucket’s contents when the bucket resource is deleted.
With overlayBucket.forceDestroy set to true, deleting the bucket resource deletes every overlay artifact in it. There is no recovery.
Commit and push project.yaml to your GitOps repository. Argo CD provisions the bucket through a project-scoped resources Application (namespace liferay-<projectId>-resources, for example liferay-acme-resources), separate from the per-environment application namespaces used for the rest of your deployment.
Grant Overlay Access
In the project’s base file, liferay/projects/<projectId>/base/infrastructure.yaml, grant environments read access to the bucket:
overlayAccess:
enabled: true
This setting also defaults to false. Setting it in the project’s base file applies to every environment in the project at once, granting each environment’s Google service account the read-only roles/storage.objectViewer role on the project bucket. Pods in one project cannot access another project’s overlay bucket.
Set overlayBucket in project.yaml to provision the bucket, and set overlayAccess in base/infrastructure.yaml to grant environments access to it.
If an individual environment must use different overlay access than its siblings, override overlayAccess in that environment’s own infrastructure.yaml instead of the project’s base file.
Commit and push the change to your GitOps repository. Argo CD synchronizes every environment with the new access grant.
If your project previously used a per-environment overlay bucket, its contents are not copied to the new bucket. Re-upload your existing customizations to the new location.
Manual Overlay Workflow
Locate the Overlay Bucket
Open the Google Cloud Console and navigate to Cloud Storage → Buckets.
Locate the bucket associated with your project. Overlay bucket names contain -overlay- followed by the project ID and a generated suffix, for example my-deployment-overlay-acme-2225eb.
Upload Customizations
Create a top-level folder in the bucket and upload your customizations.
Example:
overlay_test_1/
└── osgi/
└── client-extensions/
Configure the Overlay
In your environment-specific liferay.yaml (liferay/projects/<projectId>/environments/<environmentId>/liferay.yaml), configure the overlay:
liferay-default:
overlay:
copy:
- from: overlay_test_1/osgi/client-extensions/*
into: osgi/client-extensions
enabled: true
Overlay Configuration Reference
| Property | Description |
|---|---|
enabled: true | Enables overlay processing during pod startup |
copy.from | Source path in the overlay bucket |
copy.into | Destination path inside the Liferay container |
The bucket name is detected through the LIFERAY_OVERLAY_BUCKET_NAME environment variable, and the platform chart sets the storage provider. Configure only the properties above.
Commit and push the configuration change to your GitOps repository.
Argo CD synchronizes the environment and applies the overlay configuration.
Automated Overlay Workflow (GitOps and CI)
Locate the Overlay Bucket
-
Switch to the project’s resources namespace:
kubens liferay-<projectId>-resources -
List the overlay bucket resource:
kubectl get buckets.storage.gcp.m.upbound.io --selector app=liferay,project-id=<projectId>Example output:
NAME SYNCED READY EXTERNAL-NAME AGE my-deployment-overlay-acme-2225eb True True my-deployment-overlay-acme-2225eb 22h
Use the EXTERNAL-NAME value as the bucket name.
Configure CI Authentication
Unlike AWS environments, GCP environments do not provision CI upload credentials for overlays automatically.
Configure authentication separately using Workload Identity Federation (WIF).
-
Create a Google Service Account for CI uploads:
liferay-ci-uploader@PROJECT_ID.iam.gserviceaccount.com -
Grant the service account permission to upload overlay objects:
gcloud storage buckets add-iam-policy-binding gs://${GCS_BUCKET_NAME} \ --member="serviceAccount:liferay-ci-uploader@${PROJECT_ID}.iam.gserviceaccount.com" \ --role="roles/storage.objectCreator" -
Configure Workload Identity Federation for your CI provider.
For more information, see Workload Identity Federation with GitHub Actions.
Build and Upload Customizations
Configure the following GitHub Actions secrets:
| Secret | Description |
|---|---|
GCP_WIF_PROVIDER | Full resource name of the Workload Identity Provider |
GCP_CI_UPLOADER_SA | Email address of the CI uploader Google Service Account |
GCS_BUCKET_NAME | Project overlay bucket name without the gs:// prefix |
Example workflow:
name: CNE Workspace Build
on: [push]
permissions:
contents: read
id-token: write
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up JDK 11
uses: actions/setup-java@v4
with:
java-version: "11"
distribution: "adopt"
- name: Build with Gradle
run: cd workspace/ && ./gradlew build deploy
- name: Authenticate to GCP
uses: google-github-actions/auth@v2
with:
workload_identity_provider: ${{ secrets.GCP_WIF_PROVIDER }}
service_account: ${{ secrets.GCP_CI_UPLOADER_SA }}
- name: Upload customizations to GCS bucket
run: |
gcloud storage cp \
--recursive \
workspace/bundles/osgi/ \
gs://${{ secrets.GCS_BUCKET_NAME }}/workspace_build_${{ github.run_number }}/
Configure the Overlay
In liferay/projects/<projectId>/environments/<environmentId>/liferay.yaml, configure the overlay to use the uploaded artifacts:
liferay-default:
overlay:
copy:
- from: "workspace_build_1/osgi/client-extensions/*"
into: osgi/client-extensions
enabled: true
Quote the from value when it contains wildcard patterns. For example, "workspace_build_1/osgi/client-extensions/*".
Commit and push the change to your GitOps repository.
Argo CD synchronizes the environment and applies the overlay configuration.
Verify the Overlay Deployment
Check the overlay init container logs:
kubectl logs liferay-default-0 -c liferay-overlay
The init container logs each step as a JSON line, and invokes rclone with --use-json-log, so the copy operation itself also logs in JSON between these two lines. Example output:
{"message": "Copying from \":gcs,env_auth=true:my-deployment-overlay-acme-2225eb/workspace_build_1/osgi/client-extensions\" to \"/temp/osgi/client-extensions\".", "script": "overlay-sync.sh", "severity": "INFO", "timestamp": "2026-01-01T00:00:00Z"}
...
{"message": "Copy completed successfully.", "script": "overlay-sync.sh", "severity": "INFO", "timestamp": "2026-01-01T00:00:01Z"}
Overlay files are applied during pod startup. Restart the pod to apply updated overlay content.