Eleven Out of Twelve

The composer.json in each service had this in its post-install-cmd section: "post-install-cmd": [ "bin/console cache:clear --env=prod", "bin/console doctrine:migrations:migrate --no-interaction" ] post-install-cmd runs during composer install, which in the production Dockerfile runs during the image build. There is no database available during a Docker build. The migration command either failed silently, or connected to nothing, or was skipped by Doctrine when it couldn’t find a schema to compare against. In any case, it didn’t migrate anything. ...

May 17, 2026 · 5 min · Guillaume Delré

Ready Is Not the Same as Started

The rolling deploy looked clean. A new pod started. Kubernetes saw the healthcheck pass — php -v returned zero — and began routing traffic to the new container. For the next forty seconds — out of a possible sixty — that container was polling for the database. Requests that landed on it during that window got errors. Not many — the window was short — but enough to show up as noise in the monitoring. The kind of noise that gets dismissed as a transient network issue and filed nowhere. The deploy succeeded. The pod eventually became ready. The mechanism that caused it was still there, waiting for the next deploy. ...

May 17, 2026 · 8 min · Guillaume Delré

Fifteen Minutes Before the First Test

The pipeline had two stages that had nothing to do with code: provision and deprovision. Between them, in sequence, came phpunit, phpmetrics, and behat. stages: - build - provision - phpunit - phpmetrics - behat - deprovision - deploy Before the first assertion ran, fifteen minutes had passed. Terraform had cloned an infrastructure repository, authenticated to Azure, and applied a VM configuration. Ansible had connected to the new VM, installed PHP, configured the application, wired up a database and a Redis instance. Then the tests ran. Then Terraform destroyed what Ansible had built. ...

May 16, 2026 · 5 min · Guillaume Delré

What Survives the Build

At some point during a cloud migration audit, someone ran this: docker run --rm <image> php -r "var_dump(require '.env.local.php');" The output showed everything that composer dump-env prod had compiled into the image at build time. Which meant it showed everything that had been in the .env file when the image was built. Which meant it showed these, among others: INFLUXDB_INIT_ADMIN_TOKEN=<influxdb-admin-token> GF_SECURITY_ADMIN_USER=admin GF_SECURITY_ADMIN_PASSWORD=admin123 BLACKFIRE_CLIENT_ID=<blackfire-client-id> BLACKFIRE_CLIENT_TOKEN=<blackfire-client-token> BLACKFIRE_SERVER_ID=<blackfire-server-id> BLACKFIRE_SERVER_TOKEN=<blackfire-server-token> NGROK_AUTHTOKEN=replace-me-optionnal Twenty-five variables in total. Every credential that had accumulated in the root .env over three years, now permanent in an image layer. ...

May 14, 2026 · 5 min · Guillaume Delré

Building a self-hosted homelab with Docker Compose and Traefik

For years I wanted a homelab at home. A place of my own to host development tools, monitor my machines, run home automation, and experiment without risking breaking anything important. The idea is simple. Getting it running, a bit less so. Back then, Kubernetes didn’t exist yet. Options for running multiple services on a single machine came down to bash scripting, hand-written Nginx configs, and a lot of coffee. Tutorials on “homelab for humans” were nowhere to be found. ...

February 17, 2026 · 11 min · Guillaume Delré

Local HTTPS with Traefik: traefik.me is dead, long live sslip.io

The setup seemed perfect. Point *.traefik.me at 127.0.0.1, download a wildcard certificate from the same domain, drop it into Traefik, and every local service gets a clean HTTPS URL with no IP in the address bar. No Let’s Encrypt rate limits, no mkcert to explain to teammates, no self-signed warnings to click through. Just https://myapp.traefik.me and a green padlock. Then in March 2025, Let’s Encrypt revoked the certificate. The wildcard cert for traefik.me is gone and it’s not coming back. ...

April 17, 2025 · 5 min · Guillaume Delré

From Vagrant to Docker Compose: a retrospective

I ran Vagrant for years. A Vagrantfile per project, a shared base box, a provision script that worked on Tuesday but not on Thursday. The promise was simple: reproducible environments for everyone on the team. The reality was more complicated. The Vagrant years The setup made sense at the time. One VM per project, provisioned with shell scripts or Ansible, shared via a versioned Vagrantfile. Onboarding was theoretically vagrant up and you’re done. ...

April 18, 2022 · 4 min · Guillaume Delré

Controlling a USB missile launcher over HTTP with FastAPI and Docker

The rule was simple: whoever breaks the CI build owes the team a coffee. It worked fine for a while. Then someone suggested we needed something with more immediate feedback. Something physical. Something that fires. A Dream Cheeky Thunder appeared on a desk shortly after. Four foam missiles, a USB cable, and a very clear team consensus: hook it to the cluster, wire it to the build pipeline, and let the CI decide who deserves a volley. ...

February 21, 2017 · 4 min · Guillaume Delré