Why this Migration matters
Moving your ColdFusion applications to a Kubernetes cluster brings repeatable deployments, horizontal Scaling, stronger isolation, and faster Disaster recovery. Containers remove machine drift, while Kubernetes orchestrates rolling updates, health checks, self-healing, and autoscaling. With proper Configuration, your CFML stack becomes more resilient, observable, and cloud‑native without sacrificing Features like CF Admin, datasources, or Scheduled tasks.
Prerequisites / Before You Start
-
Identify what you will migrate:
- Application codebases, CF mappings, Custom tags, JVM arguments.
- CF Admin settings (datasources, mail server, caching, file system paths).
- Third-party libraries, OSGi bundles, native binaries.
- Scheduled tasks, PDF generation (PDFg/Headless Chrome), Solr/Lucene, Redis/Memcached.
- Web server connectors (IIS/Apache) and URL rewrites (move to Ingress rules).
- File uploads and shared assets (plan for object storage or Persistent Volumes).
-
Backups and Disaster recovery:
- Full database backups and point-in-time recovery tested.
- Export CF Admin Configuration:
- Adobe ColdFusion 2021+ with cfsetup (JSON) and cfpm packages.
- Adobe ColdFusion 2018 with CAR files.
- Lucee/CommandBox with CFConfig (JSON).
- Backup application files, S3/object storage buckets, and job queues.
-
- Confirm CF version supports Java version in your base image.
- Verify JDBC drivers and ORM/Hibernate versions.
- Confirm Solr, Redis, Elasticsearch, mail server, and PDF rendering compatibility.
-
Kubernetes and cluster requirements:
- Kubernetes v1.24+ recommended.
- Container registry access (private registry, ECR, GCR, ACR, or self-hosted).
- Ingress controller (NGINX, Traefik, HAProxy), external DNS, TLS certificates (Let’s Encrypt or corporate CA).
- Storage class for Persistent Volumes if needed.
-
Security and Compliance:
- Plan to store secrets in Kubernetes Secrets, sealed-secrets, or a vault (HashiCorp Vault, AWS Secrets Manager).
- Define network policies, RBAC roles, and Pod Security admission.
- Prepare vulnerability scanning for images (Trivy, Grype).
-
Observability:
- Logging backend (ELK/Elastic, OpenSearch, Loki).
- Metrics (Prometheus/Grafana) and traceability (OpenTelemetry, Zipkin/Jaeger) if needed.
-
Organizational readiness:
- CI/CD pipeline (GitHub Actions, GitLab CI, Jenkins, Azure DevOps).
- Blue/Green or Canary rollout process.
- Rollback plan and Service Level Objectives.
Reference Architecture on Kubernetes
A typical ColdFusion-on-Kubernetes Architecture uses:
- Deployment with multiple replicas of ColdFusion (Adobe or Lucee).
- Service (ClusterIP) to expose pods internally.
- Ingress to route external HTTP(S) traffic and perform TLS termination.
- ConfigMap for non-secret configuration, Secrets for sensitive values (DB passwords, license keys).
- Readiness and liveness probes to ensure zero-downtime rollouts and self-healing.
- HPA (Horizontal Pod Autoscaler) Scaling on CPU/memory or custom metrics.
- Externalized dependencies:
- Databases (managed service where possible).
- Redis/Memcached for sessions and caching.
- Solr/Elasticsearch as a separate service.
- Object storage for assets (S3/GCS/Azure Blob) instead of local filesystem.
Example traffic flow:
Client -> Ingress Controller -> Service -> CF Pods (Tomcat) -> External DB/Redis/S3
Step-by-Step Migration guide
1) Choose runtime and base image
-
Adobe ColdFusion:
- Official images exist (e.g., Adobe ColdFusion 2021/2023). Use environment variables to accept EULA and supply serial numbers or run in Developer/Trial mode.
- Use cfpm to install modules (PDFg, SAML, ORM) and cfsetup to import configuration.
-
Lucee:
- Commonly deployed via CommandBox images (Ortus Solutions). Leverage CFConfig, environment variables, and BOX_INSTALL for Automation.
-
Decide on image slimness versus convenience:
- A minimal JRE + Tomcat + CF runtime image will be smaller and more secure.
- Include Linux packages your app needs (e.g., ImageMagick, fonts for PDF).
-
Pin versions:
- Use immutable tags (not latest) for reproducibility.
2) Externalize configuration and secrets
-
Never bake secrets into the image.
-
Adobe ColdFusion 2021+:
- Use cfsetup to export/import CF Admin settings to/from a JSON file.
- Use cfpm to install/remove Features at build or start time.
-
Adobe ColdFusion 2018:
- Use CAR files scripted import on container start.
- Consider upgrading to simplify Automation.
-
Lucee:
- Use CFConfig JSON to configure datasources, mappings, mail, and other settings.
-
Use Kubernetes Secrets:
- DB passwords, SMTP credentials, license keys, S3 keys.
- Mount as files or expose as environment variables.
-
ConfigMap for non-sensitive values:
- Feature flags, log levels, cache toggles, datasource names (not passwords).
3) Containerize the application
-
Project structure:
- Place CFML code under a consistent webroot (/app).
- Keep environment-specific configuration external (12-factor configuration).
- Avoid writing to local disk; use object storage or a mounted volume if truly necessary.
-
Build-time tasks:
- Install fonts for PDF rendering.
- Install system libraries (libX11, headless Chrome or wkhtmltopdf if you rely on those).
- Add JDBC drivers.
-
Web server:
- Most Kubernetes deployments front Tomcat HTTP via Ingress; skip native IIS/Apache connectors.
- Handle URL rewrites in Ingress rules or in Tomcat’s web.xml if needed.
4) Build and push images
-
Build:
- Use Docker BuildKit or buildpacks.
- Perform multi-stage builds if compiling native tooling.
-
Push to registry:
- Tag images with app, version, git sha.
- Configure imagePullSecrets in Kubernetes for private registries.
5) Define Kubernetes manifests
-
Namespace and RBAC:
- Create a dedicated namespace.
- Use a ServiceAccount with least privileges.
-
Secrets and ConfigMaps:
- Store DB credentials, SMTP, OAuth keys, CF license, and any private keys.
-
- Set resource requests/limits.
- Add liveness and readiness probes.
- Use rollingUpdate strategy with maxSurge and maxUnavailable tuned for your SLO.
-
Service:
- ClusterIP service on port 8500 (Tomcat/HTTP) or 8080 depending on your image.
-
Ingress:
- TLS termination, host rules, path-based routing.
- Optionally enable sticky sessions while migrating sessions to Redis.
-
HPA:
- CPU/memory thresholds and min/max replicas.
-
NetworkPolicy:
- Allow only traffic from Ingress and to approved egress (DB, Redis, SMTP).
6) Sessions and cache strategy
-
Avoid sticky sessions if possible by externalizing sessions:
- Configure ColdFusion to store sessions in Redis or database.
- For Adobe CF Enterprise, consider the built-in caching and Session replication options, but Redis is more Cloud-native.
-
For short-term:
- Enable sticky sessions in Ingress to ease cutover, then migrate to shared sessions.
7) Database connectivity and schema changes
- Use Secrets for JDBC passwords and drivers.
- Validate connection strings and pool sizes in non-prod.
- Use an initContainer or CI step with Liquibase/Flyway to manage schema migrations.
- Ensure connection draining during rollouts to avoid transaction loss.
8) Observability and diagnostics
-
Logging:
- Log to stdout/stderr; aggregate via Fluent Bit/Fluentd/Vector to ELK/OpenSearch/Loki.
- Replace rolling file appenders with console loggers where possible.
-
Metrics:
- Expose JVM metrics via JMX Exporter sidecar or Java agent.
- Track GC, heap, thread pools, and request latency.
-
Tracing:
- Optional OpenTelemetry instrumentation to trace DB calls and external services.
9) Non-production rollout
- Deploy to dev/staging first.
- Run smoke tests and Integration tests.
- Perform load tests to validate autoscaling and resource limits.
10) Production cutover
-
Use Blue/Green or Canary:
- Blue/Green: two environments behind a traffic switch (DNS/Ingress).
- Canary: route a small percentage of traffic to the new version and increase gradually.
-
Rollback plan:
- Keep the previous image and manifests ready.
- Use kubectl rollout undo or Helm rollback if needed.
11) Resource tuning and autoscaling
- Start with conservative requests/limits (e.g., 512Mi–2Gi memory, 250–1000m CPU). Tune via load testing.
- Configure HPA with a target utilization (e.g., 60% CPU).
- Consider VPA or KEDA for more advanced scaling.
12) Security hardening
- Run as non-root; drop Linux capabilities.
- Read-only root filesystem if possible.
- Regularly patch images; use a minimal base.
- Restrict egress with NetworkPolicies.
- Use TLS everywhere; rotate secrets and certificates.
- Audit logs and enforce signature verification for images (Cosign).
Examples (Dockerfiles and Kubernetes manifests)
Adobe ColdFusion (2021/2023) Dockerfile example
Dockerfile
FROM adobe/coldfusion:2023.5.0
Accept EULA via env or build-arg in CI; do not hardcode secrets
ENV acceptEULA=YES \
enableSecureProfile=true \
password=use-a-strong-admin-password
Install optional features via cfpm
RUN cfpm install orm,document,rest
Import CF Admin configuration (exported via cfsetup on-prem)
Place cfsetup.json next to Dockerfile or fetch from a secure store in CI
COPY cfsetup.json /opt/coldfusion/cfsetup.json
RUN cfsetup import /opt/coldfusion/cfsetup.json
Add JDBC drivers, fonts, and system packages as needed
RUN microdnf install -y freetype fontconfig dejavu-sans-fonts && microdnf clean all
Add application code
WORKDIR /app
COPY ./app/ /app/
Expose Tomcat HTTP
EXPOSE 8500
Healthchecks will be configured via Kubernetes probes
Lucee (CommandBox) Dockerfile example
Dockerfile
FROM ortussolutions/commandbox:adobe11
For Lucee use a lucee-based tag, e.g., ortussolutions/commandbox:lucee5
Example uses CommandBox for CFML engine bootstrapping
ENV CFCONFIG_ADMINPASSWORD=use-a-strong-admin-password \
HEAP_SIZE=1024m \
ENVIRONMENT=prod
Install dependencies (fonts, tools)
USER root
RUN microdnf install -y freetype fontconfig && microdnf clean all
USER box
Add CFConfig to configure datasources, mail, mappings, etc.
COPY cfconfig.json /app/cfconfig.json
RUN cfconfig import /app/cfconfig.json
Add application code
COPY ./app/ /app/
WORKDIR /app
EXPOSE 8080
Kubernetes manifests (simplified)
Namespace and secrets:
yaml
apiVersion: v1
kind: Namespace
metadata:
name: cf-prod
apiVersion: v1
kind: Secret
metadata:
name: cf-secrets
namespace: cf-prod
type: Opaque
stringData:
DB_URL: “jdbc:postgresql://db.prod.svc:5432/mydb”
DB_USER: “cf_user”
DB_PASS: “supersecret”
CF_ADMIN_PASSWORD: “use-a-strong-admin-password”
ConfigMap:
yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: cf-config
namespace: cf-prod
data:
CF_ENV: “production”
LOG_LEVEL: “INFO”
Deployment, Service, Ingress, HPA:
yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: cf-app
namespace: cf-prod
spec:
replicas: 3
selector:
matchLabels:
app: cf-app
template:
metadata:
labels:
app: cf-app
spec:
serviceAccountName: cf-runtime
containers:
- name: cf
image: registry.example.com/cf-app:1.0.0
imagePullPolicy: IfNotPresent
ports:- containerPort: 8500
envFrom: - configMapRef:
name: cf-config - secretRef:
name: cf-secrets
resources:
requests:
cpu: “500m”
memory: “1024Mi”
limits:
cpu: “1500m”
memory: “2048Mi”
readinessProbe:
httpGet:
path: /health
port: 8500
initialDelaySeconds: 20
periodSeconds: 10
livenessProbe:
httpGet:
path: /health
port: 8500
initialDelaySeconds: 60
periodSeconds: 20
volumeMounts: - name: temp
mountPath: /tmp
volumes:
- containerPort: 8500
-
name: temp
emptyDir: {}apiVersion: v1
kind: Service
metadata:
name: cf-svc
namespace: cf-prod
spec:
type: ClusterIP
selector:
app: cf-app
ports: -
port: 80
targetPort: 8500
protocol: TCP
name: httpapiVersion: Networking.k8s.io/v1
kind: Ingress
metadata:
name: cf-ingress
namespace: cf-prod
annotations:
kubernetes.io/ingress.class: “nginx”
nginx.ingress.kubernetes.io/ssl-redirect: “true”
nginx.ingress.kubernetes.io/proxy-body-size: “50m”
nginx.ingress.kubernetes.io/affinity: “cookie” # temporary if you need sticky sessions
spec:
tls: - hosts:
- cf.example.com
secretName: cf-tls
rules:
- cf.example.com
- host: cf.example.com
http:
paths:-
path: /
pathType: Prefix
backend:
service:
name: cf-svc
port:
number: 80apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: cf-hpa
namespace: cf-prod
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: cf-app
minReplicas: 3
maxReplicas: 15
metrics:
-
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 60
Notes:
- Replace /health with a Lightweight CFML template that verifies DB/Redis connectivity only for readiness, not for liveness.
- Use network policies to restrict egress to DB/Redis/SMTP.
Risks, Common Issues, and How to Avoid Them
-
Sticky sessions masking statelessness:
- Risk: Relying on session affinity can hide scaling issues.
- Mitigation: Move sessions to Redis or another shared store; test with affinity disabled.
-
Writing to local disk:
- Risk: Pods are ephemeral; data may be lost on restart.
- Mitigation: Use object storage (S3) or a Persistent Volume; ensure correct file permissions and lifecycle.
-
Long JVM warm-up and cold starts:
- Risk: Slow start causes failed probes and rollout delays.
- Mitigation: Tune JVM heap and class loading; increase initialDelaySeconds; pre-warm caches in readiness probe or init logic.
-
PDF generation dependencies:
- Risk: Headless Chrome/wkhtmltopdf and fonts missing in containers.
- Mitigation: Bundle necessary fonts and tools; verify in CI; consider a dedicated microservice for PDF.
-
Solr running inside CF container:
- Risk: Coupling reduces resiliency and makes scaling harder.
- Mitigation: Externalize Solr/Elasticsearch; run as separate Deployment or use managed service.
-
Security gaps:
- Risk: Root containers, exposed admin endpoints, plaintext secrets.
- Mitigation: Run as non-root, restrict admin endpoints with network policy and auth, use Secrets and sealed-secrets, enforce TLS.
-
Configuration drift:
- Risk: Manual changes in CF Admin diverge from code.
- Mitigation: Treat config as code (cfsetup/CFConfig in source control); block manual edits in production.
-
Memory pressure and OOMKills:
- Risk: Improper heap relative to container limit.
- Mitigation: Set -Xms/-Xmx within pod memory limits; monitor GC and heap usage.
-
Connector/web server mismatch:
- Risk: Legacy IIS/Apache settings not mapped to Ingress.
- Mitigation: Convert rewrite rules to Ingress annotations or rewrite-target rules; test path normalization and headers.
-
Licensing for Adobe CF:
- Risk: License misconfiguration blocks startup.
- Mitigation: Pass license via Secret/env; verify license terms for container usage; test in lower environments.
Post-Migration Checklist
-
Deployment health:
- All pods Ready with passing liveness/readiness probes.
- HPA scales up/down under synthetic load.
-
Application functionality:
- Login/session flow works with Redis/shared sessions.
- File uploads/downloads function via object storage or volumes.
- Scheduled tasks migrated:
- Prefer Kubernetes CronJobs for Infrastructure jobs.
- If CF scheduler is used, ensure single-runner pattern (leader election or dedicated Deployment).
-
Integrations:
- Datasources connect with correct credentials and IP whitelists.
- Mail server, Payment gateways, SSO/SAML/OAuth endpoints working.
- Solr/Elasticsearch indices available.
-
Observability:
- Logs visible in central system with correlation IDs.
- Metrics and alerts firing correctly (heap, CPU, error rate).
- Traces sampled and viewable if enabled.
-
Security:
- Admin endpoints disabled or IP-restricted.
- TLS certificates installed and valid.
- NetworkPolicies enforced; only required egress allowed.
- Containers run as non-root; image scan clean or acceptable.
-
- Latency and throughput meet SLOs.
- GC behavior acceptable; no frequent full GCs.
- Connection pools tuned and not saturated.
-
Operations:
- Rollout and rollback tested.
- Disaster recovery documented and tested (restore backups, redeploy from scratch).
- Runbooks updated; on-call team understands the topology.
Additional Implementation Tips
Health endpoints
- Readiness should verify the app is ready to serve (e.g., minimal DB ping).
- Liveness should be lightweight (e.g., a static page) to avoid killing pods due to transient DB issues.
Migrations and deployments
- Use Helm or Kustomize for templated manifests.
- Embed versioned config via ConfigMaps and mount paths, or reference Git SHAs.
CI/CD
- Build, scan, sign, and push images in CI.
- Promote images through environments (dev -> staging -> prod).
- Use GitOps (Argo CD, Flux) for drift detection and declarative ops.
Data and cache warming
- Optional initContainers or Jobs to warm caches and precompile templates.
- Avoid expensive work in the pod startup path if it delays readiness.
Frequently Asked Questions
How do I handle ColdFusion scheduled tasks in a Kubernetes environment?
Use Kubernetes CronJobs for Infrastructure-level scheduling. If you must keep CF’s internal scheduler, run it in a dedicated Deployment with one replica and disable it in web-facing replicas. Alternatively, implement leader election or a distributed lock using Redis so only one replica executes tasks.
Can I migrate without sticky sessions?
Yes. Configure session storage in a shared backend like Redis or your database, then disable sticky sessions at the Ingress. Validate login/logout, cart, and multi-step flows under load to ensure correctness. Externalizing sessions improves horizontal Scalability and resilience.
Should I run Solr inside the same container as ColdFusion?
No. Run Solr as its own Deployment or use a managed search service. Decoupling improves Scalability and availability and prevents CF pod restarts from affecting indexing/search.
How do I import my existing CF Admin configuration?
- Adobe ColdFusion 2021/2023: Use cfsetup to export to JSON from your current server, then cfsetup import during container build or startup. Use cfpm to install optional modules.
- Adobe ColdFusion 2018: Use CAR files and scripted import at startup.
- Lucee: Use CFConfig JSON with CommandBox-based images.
What’s the best way to deal with file uploads and generated assets?
Avoid writing to pod storage. Use object storage (S3/GCS/Azure Blob) and serve via a CDN. If you must use POSIX files, mount a Persistent Volume and ensure access modes and Performance meet your needs.
