Swarm secrets are files, not environment variables

A secret in an environment variable is visible in docker inspect, in the process environment, and in any crash dump or error page that prints the environment.

services:
  php:
    secrets: [db_password]
    environment:
      DB_PASSWORD_FILE: /run/secrets/db_password

secrets:
  db_password:
    external: true

# and the application reads the file, which means a small change:
# $password = trim(file_get_contents(getenv('DB_PASSWORD_FILE')));

The _FILE convention is what several official images already use, so the pattern is familiar even if the application has to grow a helper for it. Secrets are mounted in a tmpfs and never touch the host disk, which is the property environment variables cannot offer. On a single host without swarm the same discipline is worth keeping with a bind-mounted file and restrictive permissions, because the migration later is then nothing.