
Docker Compose Debug: The `.env` Typo That Broke Everything
Ugh, the smell of burnt toast. Not literally, but that’s the vibe I got when my perfectly orchestrated docker-compose setup went south. I was so proud of myself. I’d finally gotten my dev environment...
r5yn1r4143
3w ago
Ugh, the smell of burnt toast. Not literally, but that’s the vibe I got when my perfectly orchestrated docker-compose setup went south. I was so proud of myself. I’d finally gotten my dev environment to spin up all the necessary services – a web app, a database, Redis for caching, and even a little worker service. It was beautiful, a symphony of containers humming along. Or so I thought.
TL;DR: My docker-compose setup failed spectacularly due to a simple typo in my .env file, leading to incorrect database connection strings and unexpected service behavior. The fix involved carefully reviewing the .env file and ensuring all variable names and values were accurate.
The Grand Plan and the Tiny Mistake
I was building a new feature that required a robust data pipeline. My plan was to use docker-compose to isolate the dependencies and make it super easy for anyone on the team to get the project running. I had a docker-compose.yml file defining my services, and a .env file to hold all the sensitive bits and configuration variables like database credentials, API keys, and port mappings. This is standard practice, right? Keeps your docker-compose.yml clean and your secrets out of version control.
I meticulously wrote my docker-compose.yml, referencing environment variables like this:
services:
webapp:
build: .
ports:
- "${WEB_PORT}:8000"
environment:
DATABASE_URL: "${DB_URL}"
REDIS_HOST: "${REDIS_HOST}"
depends_on:
- db
- redis db:
image: postgres:14-alpine
volumes:
- postgres_data:/var/lib/postgresql/data/
environment:
POSTGRES_USER: "${DB_USER}"
POSTGRES_PASSWORD: "${DB_PASSWORD}"
POSTGRES_DB: "${DB_NAME}"
redis:
image: redis:7-alpine
ports:
- "${REDIS_PORT}:6379"
volumes:
postgres_data:
And in my .env file, I had:
WEB_PORT=8080
DB_HOST=db # This is actually not used by the container directly but good for local dev references
DB_USER=myuser
DB_PASSWORD=mypassword
DB_NAME=mydatabase
DB_URL=postgresql://${DB_USER}:${DB_PASSWORD}@${DB_HOST}:5432/${DB_NAME}
REDIS_HOST=redis
REDIS_PORT=6379
Everything looked fine. I ran docker-compose up -d. The containers started… sort of. The Redis and Postgres containers came up without a hitch. But the web app and the worker service? Total chaos.
The "What in the World?!" Moment
My web app logs were a cascade of errors. The most prominent one looked like this:
ERROR: connection to server at "db" failed: Connection timed out
Is the server running on that host and accepting TCP/IP connections?
Wait, "db"? I thought I explicitly set the DB_HOST and DB_URL to use the correct hostname. My brain went into overdrive. Was Docker networking broken? Did Postgres not start correctly? Did I mess up the depends_on clause? I started digging through the Postgres logs, which, thankfully, were clean. No complaints about authentication or anything.
Then, I looked at the webapp logs again. Another error popped up:
Traceback (most recent call last):
File "app.py", line 25, in <module>
redis_client = redis.Redis(host=os.getenv('REDIS_HOST'), port=int(os.getenv('REDIS_PORT')))
ValueError: invalid literal for int() with base 10: 'redis:6379'
Okay, now this was weird. The Redis error was complaining about a port that looked like redis:6379. That’s not a port number! That’s a hostname and a port number mashed together. My REDIS_PORT variable in the .env file was supposed to be just 6379.
My mind flashed back to the .env file. I scrolled through it, my eyes scanning for inconsistencies. And there it was. A single, unassuming typo.
I had typed:
REDIS_PORT=redis:6379
Instead of:
REDIS_PORT=6379
And because the DATABASE_URL was constructed using that REDIS_HOST and REDIS_PORT (well, not directly, but my brain was now convinced I had typed similar mistakes everywhere), I had a sinking feeling. I re-checked the DB_URL construction. Ah, the DB_URL was actually constructed using ${DB_HOST} which was correct. The webapp was trying to connect to Redis using host=redis and port=redis:6379. My web app’s code was expecting a simple integer for the port, and it got a string that looked like a hostname and port. Hence the ValueError.
But why was the Postgres connection failing with "Connection timed out" to "db"? The DB_URL in my .env file was also referencing ${DB_HOST}. I looked at that line again:
DB_URL=postgresql://${DB_USER}:${DB_PASSWORD}@${DB_HOST}:5432/${DB_NAME}
And the definition of DB_HOST:
DB_HOST=db
This should have worked because Docker's internal DNS resolves service names (like db) to their container IPs within the same network. So the webapp would correctly find the db service. The "Connection timed out" error was a red herring. The real issue was that the webapp never even got to properly configure its database connection because it crashed earlier when trying to set up the Redis connection due to the REDIS_PORT typo. Once the Redis connection failed to initialize, the application threw up its hands and stopped processing, leading to that generic database connection error for Postgres. It was a domino effect of errors, all stemming from one tiny mistake.
The Debugging Journey (and How to Avoid It)
My debugging process involved a few key steps:
Comments
Sign in to join the discussion.