dockerdocker-composeenvironment-variables.env

Docker Not Updating Environment Variables from .env File on Restart


I have a docker-compose.yml file with WordPress, MySQL, and Adminer services, where environment variables are read from a local .env file. Here’s my docker-compose.yml:

version: '3.8'

services:
  wordpress:
    image: wordpress:6
    container_name: wp_dev
    environment:
      - WORDPRESS_DB_HOST=db:3306
      - WORDPRESS_DB_NAME=$MYSQL_DATABASE
      - WORDPRESS_DB_USER=$MYSQL_USER
      - WORDPRESS_DB_PASSWORD=$MYSQL_PASSWORD
    ports:
      - "8008:80"
    volumes:
      - ./wp-data:/var/www/html

  db:
    image: mysql:5
    container_name: mysql_dev
    environment:
      - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
      - MYSQL_DATABASE=${MYSQL_DATABASE}
      - MYSQL_USER=${MYSQL_USER}
      - MYSQL_PASSWORD=${MYSQL_PASSWORD}
    ports:
      - "3305:3306"
    volumes:
      - db_data:/var/lib/mysql

  adminer:
    image: adminer:latest
    container_name: adminer_dev
    ports:
      - "8080:8080"

volumes:
  db_data:

Here’s my .env file:

MYSQL_HOST=db:3306
MYSQL_DATABASE=wordpress
MYSQL_ROOT_PASSWORD=root
MYSQL_USER=user
MYSQL_PASSWORD=user_pwd

Everything works fine on the initial startup, but when I change a variable in the .env file (e.g., MYSQL_PASSWORD=user_pass) and run docker-compose restart, I get the following error: enter image description here

What I’ve Tried

Question

Can someone explain if Docker is caching the old environment variable values, and if so, where? How can I ensure that changes in the .env file are reflected when rebuilding the containers?

Thanks for any help or suggestions!


Solution

  • Don't use docker compose restart. When you change the Compose file, re-run docker compose up -d instead.

    Internally, Compose reads the docker-compose.yml file and creates and runs the containers as described. Things like the environment variables are recorded in the container metadata, and debug commands like docker inspect wp_dev will show them.

    If you run docker compose restart (or just plain docker restart), it stops the process in the container and starts a new process with the same container metadata and the same container filesystem. For purposes of your question, it does not update the container metadata, which means the new process starts with the old environment variables. The "same container filesystem" also means it's not necessarily starting from a clean copy of the image, which can result in occasional inconsistent behavior; it's almost always better to delete a container and run a new one. (You almost never need docker {,compose} start or restart, nor should you need docker stop without planning to docker rm.)

    On the other hand, docker compose up knows to look at the existing containers and compare it to the Compose file, and to apply any differences that are needed. If you change an environment variable, you need to stop and delete the old container and recreate it with a different environment; docker compose up handles that for you. On the other hand, you haven't changed the database proper and that container will get left alone.

    In the specific case of changing the database password, you also need to take notice that the environment-variable setup only happens on uninitialized databases. Unless you've used the mysql CLI tool or otherwise ran the SQL commands to change the password inside the database, the database will still have the old password, even if the environment-variable setting is different. You can docker compose down -v to delete everything, even the database storage, to start over, and at that point the changed password will apply, but this sequence has taken all of the database data with it.