Setting Up a Simple Docker Development Environment
So I wanted to create a development environment where I won’t need to worry about a plethora of dependecy errors that Windows might throw at me. Yes, I know. Developing on Windows is weird, but I don’t want to buy a Mac because I like playing games (though I’ve heard Apple is starting to change that). What about Linux? Having done that before, I find switching back and forth between my Ubuntu and Windows a bit troublesome.
With that in mind, I thought the next best thing is to just setup a Docker containers and build it from there. Easy, right? Well, yes and no.
The ‘yes’ part is that it took me less than 10 minutes to get an app up and running (I’m using Django as an example). On the flip side, I needed a few more hours just to learn about the various customizations and hidden pitfalls for me to get to where I wanted.
So my idea was:
- Create a Django app container.
- Connect it to PostgreSQL database container.
- Set up the build process such that everytime the app is rebuilt, the migrations will be automatically pushed to the database.
The first two steps were simple with a quick look on the Docker documentation. The app connected to the database, and I mounted the project folder to the container so that any change in the python code will be detected by the Django server.
The third step was a little bit complicated. At first when I build the two containers with Docker Compose, things came out okay. You got the green tick mark, and everything seemed find and dandy. However, in the Docker logs, Django had trouble connecting to the database before it reloads itself a few seconds later. Strange. But I didn’t notice that would be an issue until later on.
I began to test the migrations by adding some models in. To automate the migration at build, I created a start.sh script that I would call from command: in the Compose configuration file. With that, the app will be built and the models are migrated before the server starts up! It didn’t work…
So what happened?
It turns out that docker containers are not built sequentially (I should have realized that…). From this I learned two new things depends_on
and health_check
depends_on
helps declare the relationship between the services. If my Django app depends on the database, I can declare something like this for my Django service:
depends_on:
- postgres
health_check
can be used during the database service build to confirm if the database has been setup correctly.
depends_on:
- postgres
condition: service_healthy
The catch is that in the health_check
, the condition should be to check that the database is indeed setup properly and running, rather than just the postgres service running (returning exit code 0). Having realized that, I used this command:
psql -h localhost -p 5432 -U postgres_usr -d postgres_db.
This is used to connect to the database that I was setting up, and if the database is not ready, it will return an exit code other than 0, indicating an error.
And with that little tidbit, I have created a development environment that can be setup at the push of a button (or more like a command line because I setup a build script for it).
I’m going to try setting up various development environments with different frameworks just to practice, and I have a feeling that whatever I learned to use above will be replaced by something a lot better.
Until then ~
— UTQ —