A Kubernetes operator for managing micro-frontend applications and UI components in a declarative way.
The UI Operator enables organizations to deploy and manage complex web applications built with micro-frontend architecture. It provides a declarative approach to:
- Deploy UI applications: Manage main UI shell applications that host micro-frontends
- Orchestrate UI components: Deploy and configure individual micro-frontend components
- Configure runtime exposure: Set up routing, authentication, and runtime configuration for components
- Handle dependencies: Automatically manage relationships between UI applications and their components
The operator manages three Custom Resource Definitions (CRDs):
ScalityUI
(cluster-scoped): Defines the main UI application with global configurationScalityUIComponent
(namespaced): Represents individual micro-frontend componentsScalityUIComponentExposer
(namespaced): Configures how components are exposed and integrated
Note: The architecture diagram below uses Mermaid syntax which may not render in all Markdown viewers. A static image version is available here.
graph TD
subgraph ControlPlane["Config & Orchestration Layer"]
User(["User/Admin"])
Operator["UI Operator<br/>(Reconciliation Loop)"]
K8sAPI["Kubernetes API"]
CRDs["Custom Resource Definitions"]
subgraph CustomResources["Custom Resources"]
ScalityUI["ScalityUI<br/>(Main Shell Config)"]
ScalityUIComp["ScalityUIComponent<br/>(Remote Module)"]
ScalityUIExp["ScalityUIComponentExposer<br/>(Integration Config)"]
end
K8sResources["K8s Resources<br/>(Deployments, Services, etc.)"]
Status["Status & Events"]
end
subgraph DataPlane["Application Layer"]
Pods["Running Pods<br/>(UI Components)"]
Ingress["Ingress/Service<br/>(Exposure)"]
ShellUI["Shell Frontend<br/>(React Application)"]
EndUser(["End User Browser"])
end
User ==>|"Installs"| CRDs
User ==>|"Installs"| Operator
User ==>|"Creates"| ScalityUI
User ==>|"Creates"| ScalityUIComp
User ==>|"Creates"| ScalityUIExp
ScalityUI -.->|"Stored in"| K8sAPI
ScalityUIComp -.->|"Stored in"| K8sAPI
ScalityUIExp -.->|"Stored in"| K8sAPI
K8sAPI ==>|"Watch events"| Operator
Operator ==>|"Creates/Updates"| K8sResources
K8sResources ==>|"Creates"| Pods
Pods ==>|"Exposed via"| Ingress
Operator -.->|"Updates"| Status
Status -.->|"Available via"| K8sAPI
ShellUI ==>|"Loads dynamically"| Ingress
EndUser ==>|"Accesses"| ShellUI
classDef operator fill:#1E88E5,color:white,stroke:none
classDef crd fill:#43A047,color:white,stroke:none
classDef resource fill:#FF8F00,color:white,stroke:none
classDef k8sComponents fill:#FF8F00,color:white,stroke:none
classDef plane fill:#121212,stroke:#424242,stroke-width:1px,color:white
classDef user fill:#9C27B0,color:white,stroke:none
classDef status fill:#F44336,color:white,stroke:none
class Operator operator
class CRDs crd
class ScalityUI,ScalityUIComp,ScalityUIExp,K8sResources resource
class K8sAPI,Ingress,Pods,ShellUI k8sComponents
class Status status
class User,EndUser user
class ControlPlane,DataPlane plane
- Quick Start
- Installation
- Basic Usage
- Configuration
- API Reference
- Features
- Examples
- Operations
- Development
- Kubernetes cluster v1.11.3+
- kubectl v1.11.3+
- Cluster admin permissions
-
Install the operator:
# Using latest stable release (recommended for production) kubectl apply -f https://raw.githubusercontent.com/ui-operator/ui-operator/0.1.0/dist/install.yaml # Using specific version kubectl apply -f https://raw.githubusercontent.com/ui-operator/ui-operator/{version}/dist/install.yaml # Using main branch (not recommended for production) kubectl apply -f https://raw.githubusercontent.com/ui-operator/ui-operator/main/dist/install.yaml
-
Verify installation:
kubectl get pods -n ui-operator-system
-
Check CRDs are installed:
kubectl get crd | grep ui.scality.com
-
Create a UI application:
apiVersion: ui.scality.com/v1alpha1 kind: ScalityUI metadata: name: my-ui-app spec: image: "my-registry/ui-shell:v1.0.0" productName: "My Application"
-
Deploy a UI component:
apiVersion: ui.scality.com/v1alpha1 kind: ScalityUIComponent metadata: name: dashboard-component namespace: my-app spec: image: "my-registry/dashboard:v1.0.0" mountPath: "/app/config"
-
Expose the component:
apiVersion: ui.scality.com/v1alpha1 kind: ScalityUIComponentExposer metadata: name: dashboard-exposer namespace: my-app spec: scalityUI: "my-ui-app" scalityUIComponent: "dashboard-component" appHistoryBasePath: "/dashboard"
# Using latest stable release (recommended for production)
kubectl apply -f https://raw.githubusercontent.com/ui-operator/ui-operator/0.1.0/dist/install.yaml
# Using specific version
kubectl apply -f https://raw.githubusercontent.com/ui-operator/ui-operator/{version}/dist/install.yaml
# Using main branch (not recommended for production)
kubectl apply -f https://raw.githubusercontent.com/ui-operator/ui-operator/main/dist/install.yaml
-
Clone the repository:
git clone https://github.com/ui-operator/ui-operator.git cd ui-operator
-
Install CRDs:
make install
-
Deploy the operator:
make deploy IMG=ui-operator/ui-operator:latest
-
Build and push the operator image:
make docker-build docker-push IMG=<your-registry>/ui-operator:tag
-
Deploy with your custom image:
make deploy IMG=<your-registry>/ui-operator:tag
Check that the operator is running:
# Check operator pod
kubectl get pods -n ui-operator-system
# Check CRDs
kubectl get crd | grep ui.scality.com
# Check operator logs
kubectl logs -n ui-operator-system deployment/ui-operator-controller-manager
The ScalityUI
resource defines the main UI application:
apiVersion: ui.scality.com/v1alpha1
kind: ScalityUI
metadata:
name: my-shell-ui-app
spec:
image: "my-registry/ui-shell:v1.0.0"
productName: "My Application"
themes:
light:
type: "core-ui"
name: "light-theme"
logo:
type: "path"
value: "/assets/logo.png"
navbar:
main:
- internal:
kind: "navigation"
view: "dashboard"
icon: "dashboard"
label:
en: "Dashboard"
networks:
ingressClassName: "nginx"
host: "my-app.example.com"
tls:
- secretName: "ui-tls"
hosts:
- "my-app.example.com"
auth:
kind: "OIDC"
providerUrl: "https://auth.example.com"
clientId: "my-ui-app"
scopes: "openid email profile"
The ScalityUIComponent
resource defines individual micro-frontend components:
apiVersion: ui.scality.com/v1alpha1
kind: ScalityUIComponent
metadata:
name: monitoring-component
namespace: ui
spec:
image: "my-registry/monitoring-ui:v1.2.0"
mountPath: "/app/configs"
imagePullSecrets:
- name: registry-secret
The ScalityUIComponentExposer
resource configures how components are exposed:
apiVersion: ui.scality.com/v1alpha1
kind: ScalityUIComponentExposer
metadata:
name: monitoring-exposer
namespace: ui
spec:
scalityUI: "my-shell-ui-app"
scalityUIComponent: "monitoring-component"
appHistoryBasePath: "/monitoring"
selfConfiguration:
apiEndpoint: "https://api.example.com/monitoring"
features:
- "metrics"
- "alerts"
Field | Type | Required | Description |
---|---|---|---|
image |
string | Yes | Container image for the main UI shell |
productName |
string | Yes | Product name displayed in the UI |
themes |
object | No | Light and dark theme configurations |
navbar |
object | No | Navigation bar configuration |
networks |
object | No | Networking and ingress configuration |
auth |
object | No | Default authentication configuration |
imagePullSecrets |
array | No | Image pull secrets for private registries |
Field | Type | Required | Description |
---|---|---|---|
image |
string | Yes | Container image for the UI component |
mountPath |
string | Yes | Path where configuration files are mounted |
imagePullSecrets |
array | No | Image pull secrets for private registries |
Field | Type | Required | Description |
---|---|---|---|
scalityUI |
string | Yes | Reference to ScalityUI resource |
scalityUIComponent |
string | Yes | Reference to ScalityUIComponent resource |
appHistoryBasePath |
string | Yes | Base path for the component in the URL |
selfConfiguration |
object | No | Runtime configuration for the component |
- Micro-frontend Management: Deploy and manage multiple UI components
- Runtime Configuration: Dynamic configuration injection for components
- Authentication Integration: OIDC and other auth providers
- Ingress Management: Automatic routing and exposure
- Dependency Management: Automatic relationship handling
- Rolling Updates: Zero-downtime updates for components
# UI Application
apiVersion: ui.scality.com/v1alpha1
kind: ScalityUI
metadata:
name: basic-ui
spec:
image: "nginx:latest"
productName: "Basic App"
---
# UI Component
apiVersion: ui.scality.com/v1alpha1
kind: ScalityUIComponent
metadata:
name: hello-component
namespace: default
spec:
image: "nginx:latest"
mountPath: "/app/config"
---
# Component Exposer
apiVersion: ui.scality.com/v1alpha1
kind: ScalityUIComponentExposer
metadata:
name: hello-exposer
namespace: default
spec:
scalityUI: "basic-ui"
scalityUIComponent: "hello-component"
appHistoryBasePath: "/hello"
apiVersion: ui.scality.com/v1alpha1
kind: ScalityUI
metadata:
name: secure-ui
spec:
image: "my-registry/ui-shell:v1.0.0"
productName: "Secure Application"
auth:
kind: "OIDC"
providerUrl: "https://auth.example.com"
clientId: "secure-ui"
responseType: "code"
scopes: "openid email profile"
providerLogout: true
# Multiple components with different configurations
apiVersion: ui.scality.com/v1alpha1
kind: ScalityUIComponentExposer
metadata:
name: dashboard-exposer
namespace: default
spec:
scalityUI: "main-ui"
scalityUIComponent: "dashboard-component"
appHistoryBasePath: "/dashboard"
selfConfiguration:
theme: "dark"
refreshInterval: 30
---
apiVersion: ui.scality.com/v1alpha1
kind: ScalityUIComponentExposer
metadata:
name: settings-exposer
namespace: default
spec:
scalityUI: "main-ui"
scalityUIComponent: "settings-component"
appHistoryBasePath: "/settings"
The operator exposes Prometheus metrics at /metrics
:
# ServiceMonitor for Prometheus
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: ui-operator-metrics
spec:
selector:
matchLabels:
app.kubernetes.io/name: ui-operator
endpoints:
- port: metrics
interval: 30s
path: /metrics
# Check UI status
kubectl get scalityui my-ui-app -o yaml
# Check component status
kubectl describe scalityuicomponent my-component
# Check exposer status
kubectl get scalityuicomponentexposer my-exposer -o yaml
# Operator logs
kubectl logs -n ui-operator-system deployment/ui-operator-controller-manager
# Component logs
kubectl logs deployment/my-component
- Component not starting: Check image pull secrets and registry access
- Configuration not applied: Verify exposer references correct UI and component
- Ingress not working: Check ingress controller and network configuration
# Backup all UI resources
kubectl get scalityui,scalityuicomponent,scalityuicomponentexposer -o yaml > ui-backup.yaml
# Restore resources
kubectl apply -f ui-backup.yaml
# Update to latest stable release (recommended)
kubectl apply -f https://raw.githubusercontent.com/ui-operator/ui-operator/0.1.0/dist/install.yaml
# Update to specific version
kubectl apply -f https://raw.githubusercontent.com/ui-operator/ui-operator/{version}/dist/install.yaml
# Update using main branch (not recommended for production)
kubectl apply -f https://raw.githubusercontent.com/ui-operator/ui-operator/main/dist/install.yaml
# Check operator version
kubectl get deployment -n ui-operator-system ui-operator-controller-manager -o jsonpath='{.spec.template.spec.containers[0].image}'
# Delete all custom resources
kubectl delete scalityui --all
kubectl delete scalityuicomponent --all
kubectl delete scalityuicomponentexposer --all
# Remove operator (use the same version you installed)
kubectl delete -f https://raw.githubusercontent.com/ui-operator/ui-operator/0.1.0/dist/install.yaml
# Remove CRDs (optional)
kubectl delete crd scalityuis.ui.scality.com
kubectl delete crd scalityuicomponents.ui.scality.com
kubectl delete crd scalityuicomponentexposers.ui.scality.com
The UI Operator leverages Kubernetes Role-Based Access Control (RBAC) to secure access to resources. When installed, the operator creates several roles and bindings to manage permissions.
The following roles are created during installation:
-
Manager Role (ClusterRole):
- Used by the operator to manage resources
- Permissions to manage deployments, services, configmaps, ingresses, etc.
- Full access to the CRDs it manages
-
Editor Roles (ClusterRole):
scalityui-editor-role
: For users who need to create/update/delete ScalityUI resourcesscalityuicomponent-editor-role
: For users who need to create/update/delete ScalityUIComponent resourcesscalityuicomponentexposer-editor-role
: For users who need to create/update/delete ScalityUIComponentExposer resources
-
Viewer Roles (ClusterRole):
scalityui-viewer-role
: For users who only need read access to ScalityUI resourcesscalityuicomponent-viewer-role
: For users who only need read access to ScalityUIComponent resourcesscalityuicomponentexposer-viewer-role
: For users who only need read access to ScalityUIComponentExposer resources
-
Support Roles:
metrics-reader-role
: For accessing Prometheus metricsleader-election-role
: For the operator's leader election mechanism
Different users require different levels of permissions:
- Need permissions to install the operator and CRDs
- Required permissions:
cluster-admin
or equivalent
- Need permissions to create and manage ScalityUI resources (cluster-scoped)
- Required ClusterRoleBinding:
scalityui-editor-role
- Need permissions to create and manage components in their namespaces
- Required RoleBindings in relevant namespaces:
scalityuicomponent-editor-role
scalityuicomponentexposer-editor-role
- Need permissions to view but not modify resources
- Required RoleBindings: Viewer roles for respective resource types
To assign permissions to a user or group:
# Example: Granting a user edit permissions for UI Components
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: developer-ui-component-editor
namespace: my-app-namespace
subjects:
- kind: User
name: developer@example.com
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: scalityuicomponent-editor-role
apiGroup: rbac.authorization.k8s.io
-
Follow Least Privilege Principle:
- Assign the minimum necessary permissions
- Use viewer roles for users who only need read access
-
Namespace Isolation:
- Create components and exposers in dedicated namespaces
- Limit access to those namespaces with RoleBindings
-
Audit Role Assignments:
- Regularly review who has access to create/modify resources
- Use
kubectl auth can-i
to verify permissions
-
Secure Access to the Main UI Resource:
- Since ScalityUI is cluster-scoped, carefully control who can create/modify them
# Clone the repository
git clone https://github.com/ui-operator/ui-operator.git
cd ui-operator
# Build the operator
make build
# Run tests
make test
# Build Docker image
make docker-build IMG=<your-registry>/ui-operator:tag
# Install CRDs
make install
# Run operator locally (outside cluster)
make run
# Run unit tests
make test
# Run tests with coverage
make test-cover
# Run e2e tests
make test-e2e
# Run specific controller tests
go test ./internal/controller/scalityuicomponentexposer -v
├── api/v1alpha1/ # CRD type definitions
├── internal/controller/ # Controller implementations
├── config/ # Kubernetes manifests
├── examples/ # Example configurations
├── test/ # Test files
└── Makefile # Build targets