Understanding Platform.sh Architecture

Immutable Environments and GitOps Model

Platform.sh operates on the principle of immutable environments—each environment is created from a Git branch and inherits infrastructure configuration from the .platform and .platform.app.yaml files.

  • Every code change triggers a full build and deploy lifecycle
  • Service definitions (e.g., databases, caches) are version-locked per environment
  • Infrastructure-as-code governs service orchestration

Build and Deploy Separation

The platform separates the build (compile-time) from deploy (runtime) phases. Misunderstanding this separation often causes:

  • Runtime failures due to missing files (e.g., built assets not committed)
  • Confusion over environment variables available during build vs. deploy

Common Enterprise-Level Issues

1. Environment Drift Across Branches

  • Configurations diverge subtly between staging and production
  • Different versions of services (e.g., MariaDB 10.3 vs. 10.5) break migrations
  • YAML configs copied manually instead of merged through Git

2. Service Dependency Failures

  • Applications fail to connect to services due to late starts or misconfigured routes
  • Custom services missing readiness probes

3. Build Failures in Monorepo Structures

  • Incorrect mount or source directives in monorepos
  • Shared dependencies not vendored correctly

Diagnostics and Observability Tools

Activity Logs and Deploy Reports

Each environment has detailed activity logs accessible via CLI or web UI:

platform activity:logs -e staging

Inspect Build Logs Separately

Use the following to isolate build-phase issues:

platform build:log -e feature/login-refactor

Environment Variables and Relationships

Dump and inspect environment variables for service bindings:

printenv | grep PLATFORM_RELATIONSHIPS | base64 --decode | jq

Architectural Pitfalls

1. Configuration Duplication

Teams often duplicate YAML configs across branches. This leads to divergence and subtle bugs. Use shared includes or Git merges to enforce consistency.

2. Overloaded Services

Many teams underestimate required resources, leading to OOM errors or slow response times under load. Define memory and disk explicitly in .platform/services.yaml.

3. Build-Time vs Runtime Confusion

Placing runtime-only logic (e.g., API keys, secrets) in the build hook leads to inaccessible configuration during actual deployment.

Step-by-Step Troubleshooting Guide

1. Verify Service Version and Health

Inspect service containers:

platform ssh -e prod -- php -r 'print_r(getenv());'

Confirm correct versions of services (e.g., PostgreSQL):

platform relationships -e prod

2. Inspect File Persistence and Mounts

Ensure writable directories are defined correctly:

mounts:
  "/data": "shared:data"

3. Debug Routing and Endpoint Mismatches

Check .platform/routes.yaml for proper upstreams and routes:

https://{default}/:
  type: upstream
  upstream: "app:http"

4. Isolate Failing Services

Spin up a new environment with minimal dependencies to test isolated failures. Use platform environment:branch to replicate production.

5. Use the Debug Container

Launch a sandboxed container for deep inspection:

platform ssh -e staging --container debug

Best Practices for Scalable Use of Platform.sh

  • Keep configuration centralized and version-controlled via Git
  • Define clear build and deploy hooks in .platform.app.yaml
  • Use environment variables and relationships to decouple services
  • Implement CI jobs that validate configuration before merge to main
  • Automate promotion pipelines using platform environment:merge

Conclusion

While Platform.sh simplifies much of DevOps, its Git-based, immutable environment model requires precise configuration and disciplined development practices. Most production issues stem not from Platform.sh itself, but from subtle misuse of its configuration paradigms. By understanding build/deploy separation, centralizing YAML configs, and using the CLI for observability, teams can maintain resilient, scalable environments with minimal friction.

FAQs

1. Why does my code build locally but fail on Platform.sh?

Platform.sh uses a clean build environment. If your build relies on local files not committed to Git or runtime secrets, it will fail during the build phase.

2. How can I test service connectivity before full deployment?

Use a debug container or spin up a staging environment with minimal services to validate connectivity via CLI tools like curl or netcat.

3. What causes "Permission denied" errors in write directories?

By default, most directories are read-only. You must explicitly define writable mounts in .platform.app.yaml.

4. How do I prevent environment drift?

Always merge configuration changes through Git rather than manual editing. Use pull requests to propagate changes downstream.

5. Is it possible to cache dependencies between builds?

Yes. Use the cache directive in .platform.app.yaml to persist directories like node_modules or vendor across builds for faster performance.