Composing a Django application in Docker
• Mark Eschbach
Next up on the road to moving off Heroku is getting our application Dockerized. Hopefully this is fairly straightforward. Unforunately my Docker images from a few months ago are now bit-rot. Let’s re-run themm. Maybe the universe has settled consistently.
I’m not a huge fan of Docker’s Kitematic because it feels to centered around launching images. Great if that is what you are doing however much of my time is spent around conatiner management while developing. I tend to use Portainer. Fairly easy launch:
docker run -d -p 9000:9000 portainer/portainer. Interesting: the time in the Docker VM was never updated on machine resume. Unforunately with Docker for OSX this is really annoying, I have to use their restart button to get the time in sync.
Looks like the bitrot came from an old cached layers. Deleted the related images and reran the creation process and done. The original scripts were running the Vagrant provisioning script which is inappropriate since we shouldn’t be booting 10 services within a single container. Let’s just drop the provisioning script and stumble through the dependencies. It’s a Python Django application so hopefully this isn’t too difficult. There are a great deal of data analytics packages in there, so let’s see.
With the provisioning script stripped out, I realized I should probably place
.dockerignore file so the local
node_modules don’t get sucked in. Right, if I rerun the base image script I find myself rebuilding all the images. Eventually I’m going to need to figure out how to have the developers share common Docker images. Probably through an ECR instance not shared directly with the application.
After re-giggering the provisioning system to only install the needed deps, pip, and application dependencies it’s working out pretty good. While looking at how to pass a file other than Dockerfile to build I discovered you can compress images from a build; would have been helpful last night for maintance. Porbably bad for cache. It’s a little gnarly however the approach to use is piping in the Dockerfile, like
docker build -t some:image -<Dockerfile-run. You can read through the opinion on the Docker Issue Tracker…it’s long. Wait! It’s all the way down at the bottom! The
-f flag with the file as an argument. You still have to pass a build context for them though; so you have to needlessly send a directory for reasons. Erroring out when attempting to access the build context would have been a better approach in my opinion but meh.
SHELL command fails to execute when attempting to spin up the container. I’ll just have to fall back to the
CMD command. I’ll have to read into the documentation at some point for the difference between these two approaches.
Docker Compose makes life really easy for development. Coming from Heroku everything is pass through the environment. Links and environment variables for everyone! Oh hey! Look! They have a Django quickstart. Their
Dockerfile looks a lot like mine.
I’ve got a simple configuration setup. For the most part it’s working. With the exception of the Postgres container is not yet done initializing and thus doesn’t accept connections. This is really a larger problem I’ll probably have to face in regards to initialization for the developer’s machines. Almost there! Just a few more things to figure out. For some reason our toolchain launches the Django application everytime it’s trying to compile the React bundles. Well, this is a very frustrating. Nothing I’ve tried has had the slightest effect on NPM trying to run the Django service.
After all that it looks like the main problem is actually with the
CMD entry point. For every
RUN command it finds it seems to be running the
CMD first. Time to fucking RTFM for me. Riddle me this: when does the CMD values come into play? In there it contradicts itself by saying it should be set to a service and an interactive shell :-/. Dockerfile CMD doesn’t spec anything more either. Dockerfile RUN says nothing about this interesting case either. It looks like it’s using the CMD form
CMD ["some/command"] to replace the shell and provides
RUN arguments to the
CMD parameter every time.
Well, I got WebPack running with Django…but they are on different ports and not using assets from the same host. I’ll have to hit up the guy who built it out to see what advice he has on the subject. Victory for now but definitely not deployable in proudction. Now time to go howl at the moon so I feel less crazy!