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:
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!
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.