0% прочитано

Upgrading PHP for One Dockerized Project Without Breaking Another

When several Dockerized projects share one machine, a PHP upgrade should remain a local change to one environment. Isolated runtimes, separate workspace containers, clear service naming, and Composer compatibility checks help prevent one project upgrade from silently breaking another.

28 жовтня 2026 р. 10 хв читанняDevOps

When only one Dockerized project runs on a machine, a PHP upgrade looks local: change the version, rebuild the container, and verify the application.

The problem becomes more interesting when another project nearby still depends on a different PHP version.

The main question is no longer "how do I upgrade PHP?" but "where does the boundary of this upgrade actually end?"

If that boundary is unclear, one change in shared Docker infrastructure can silently alter the environment of another project.

A PHP upgrade should be a property of one containerized environment, not an implicit property of the whole machine.

Host PHP Should Not Define Project PHP

One of Docker’s main advantages is that each application can own its runtime.

Project A can run PHP 8.5 while project B remains on PHP 8.3, even when both run on the same machine.

Commands, tests, Composer, and background processes for each project should therefore run inside that project’s containers rather than accidentally using host PHP.

Three commands may represent three different runtimes
# Hostphp -v # Project Adocker exec project-a-workspace php -v # Project Bdocker exec project-b-workspace php -v

A Workspace Container Should Belong to One Project

The riskiest setup is when several projects implicitly depend on the same workspace container.

An upgrade of PHP, Composer, or system packages for one project then changes the tooling of another project automatically.

A safer model is one workspace per project or one explicitly versioned service per required PHP runtime.

Separate environments on one machine
Project A  workspace-85  php-fpm-85 Project B  workspace-83  php-fpm-83 Shared machine  != shared PHP runtime

Container and Service Naming Is Part of Isolation

Clear names are not just for convenience.

When several PHP-FPM, workspace, Redis, or Nginx containers exist at the same time, ambiguous naming increases the risk of running a command in the wrong place.

The name should make the project and runtime version obvious.

Quickly inspect the actual running containers
docker ps --format \  'table {{.Names}}\t{{.Image}}\t{{.Status}}'

Docker Compose Project Names Must Be Isolated Too

Even when Compose files are different, identical project names can create unexpected overlap in containers, networks, or volumes.

Each environment should therefore have its own Compose project name and explicit resource names where needed.

Different Compose projects on one machine
docker compose \  -p project_a \  up -d docker compose \  -p project_b \  up -d

Runtime Isolation Does Not Eliminate Port Collisions

Two projects may have separate PHP containers and still conflict at the host boundary.

For example, two Nginx containers cannot both bind the same host port at the same time.

The same applies to Redis, MySQL, Reverb, or other services when their ports are published.

When changing Docker configuration, inspect not only PHP versions but also the actual host-port bindings.

Inspect host port bindings
docker ps --format \  'table {{.Names}}\t{{.Ports}}'

Composer Must Run Against the Same PHP Runtime as the Application

Composer evaluates platform requirements against the PHP runtime that executes Composer itself.

If composer install runs on a host with PHP 8.5 while the application actually runs in a PHP 8.3 container, dependencies may install successfully but be incompatible with the project runtime.

Composer for a project should therefore run inside that project’s workspace container.

Check dependencies inside each runtime separately
docker exec project-a-workspace \  composer check-platform-reqs docker exec project-b-workspace \  composer check-platform-reqs

The PHP Constraint in composer.json Is Part of the Runtime Contract

Explicit PHP runtime requirement
{  "require": {    "php": "^8.5"  }}

If one project has moved to PHP 8.5, that requirement should be expressed not only in Docker configuration but also in Composer metadata.

This makes incompatibility visible earlier during dependency installation or platform checks instead of after application startup.

Do Not Share vendor Between Projects With Different Runtimes

Each project should own its own vendor directory and composer.lock.

A shared dependency directory between applications with different PHP requirements breaks the isolation model.

Updating one dependency set can then change the code loaded by another project.

Rebuild Only the Services You Intend to Change

Avoid rebuilding the entire stack unnecessarily
docker compose build workspace php-fpm docker compose up -d \  workspace \  php-fpm

If only the PHP version changes, there is no reason to rebuild every service automatically.

A targeted rebuild reduces the change surface and makes verification easier because the expected affected containers are explicit.

Verify Both the Upgraded Project and the Neighboring Project

If the goal of isolation is to avoid affecting the neighboring project, verification should prove that too.

After rebuilding, inspect PHP versions in both workspaces, verify their PHP-FPM services, and run a short availability check for both applications.

Otherwise, only half of the isolation promise is tested.

Verify both projects after changing one
docker exec project-a-workspace php -vdocker exec project-b-workspace php -v docker exec project-a-workspace \  composer check-platform-reqs docker exec project-b-workspace \  composer check-platform-reqs

A Shared Docker .env Can Create Hidden Coupling

Some Docker environments select the PHP version through a variable in a shared .env.

If two projects use the same Docker files and the same configuration, changing that variable for project A can silently change the next rebuild of project B.

Runtime configuration should therefore belong to a specific project or an explicit environment profile.

PHP Isolation Should Not Hide Shared Dependencies

Even with isolated PHP runtimes, projects may still accidentally share MySQL, Redis, networks, or volumes.

That is not always wrong, but shared dependencies should be explicit.

Avoid configurations where two projects use the same database names, Redis key space, or volumes unintentionally.

A Safe Single-Project Upgrade Has an Explicit Sequence

Minimal isolated-upgrade flow
1. Record the current runtimes of both projects.2. Verify Docker Compose project names.3. Inspect container names and ports.4. Change PHP only in the target project configuration.5. Rebuild only its workspace/php-fpm services.6. Verify php -v in the target container.7. Run composer check-platform-reqs.8. Verify the application.9. Re-check the neighboring project.10. Confirm its runtime did not change.

Version Upgrades and Runtime Isolation Are Different Problems

In the separate article about safely updating PHP after critical vulnerabilities I covered the mechanics of safely upgrading PHP itself.

In a Dockerized environment, there is an additional requirement: the change must remain inside the intended project boundary.

It is not enough to verify the new PHP version. You also need to prove that neighboring projects kept their own runtimes and dependency compatibility.

What to Verify After the Upgrade

Short verification checklist
[ ] Target workspace runs the new PHP version[ ] Neighbor workspace keeps its expected older PHP version[ ] PHP-FPM works for both projects[ ] Composer platform requirements pass in both projects[ ] No host port collisions exist[ ] Compose project names are distinct[ ] vendor directories are not shared[ ] Databases/Redis/volumes did not overlap accidentally[ ] Both applications respond after the change

Real Isolation Means the Neighboring Project Did Not Change

Docker makes it possible to run several PHP versions on one machine, but containers alone do not guarantee isolation.

The boundary must be explicit in runtime, workspace, Compose project name, ports, dependencies, and configuration.

After an upgrade, verify not only that the target project received the new version but also that the neighboring project kept its own.

The strongest proof of isolation is not only "the new container works," but also "the other container did not change."

An upgrade is truly isolated only when the neighboring project remains in the same environment afterward.