Migration - Upgrades

How to Move ColdFusion to a Kubernetes Cluster

Contents show

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.
  • Version compatibility:

    • 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.
See also  How to Reduce Risk During Large ColdFusion Migrations

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.
  • Deployment:

    • 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.
See also  How to Move ColdFusion Logs and Metrics to a New Server

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:
  • 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: http

    apiVersion: 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:
  • host: cf.example.com
    http:
    paths:
    • path: /
      pathType: Prefix
      backend:
      service:
      name: cf-svc
      port:
      number: 80

      apiVersion: 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.
See also  How to Migrate ColdFusion Datasources to a New Database Server

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.
  • Performance:

    • 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.

About the author

Aaron Longnion

Aaron Longnion

Hey there! I'm Aaron Longnion — an Internet technologist, web software engineer, and ColdFusion expert with more than 24 years of experience. Over the years, I've had the privilege of working with some of the most exciting and fast-growing companies out there, including lynda.com, HomeAway, landsofamerica.com (CoStar Group), and Adobe.com.

I'm a full-stack developer at heart, but what really drives me is designing and building internet architectures that are highly scalable, cost-effective, and fault-tolerant — solutions built to handle rapid growth and stay ahead of the curve.