The key value proposition of Docker is that once you build a container image, you can run it anywhere. I like the way Adrian Mouat puts it:
> What is Software: program Q, when given input P, will produce output R.
>HOWEVER: One of the major problems in modern computing is our Ps and Qs don’t match when we move between environments, causing our Rs to differ unexpectedly.
>Docker containers are essentially just a complete statement of P and Q. That is to say they specify the entire state of the runtime environment (P) and the program to run (Q).
But be warned, this doesn’t hold up in several cases. One of those cases bit me last week. If you use the VOLUME keyword in the Dockerfile and your app is sensitive to the “file modified time” then watch out for a Gotcha:
If you create a container image with some data exposed in a volume, when you run the container, the mtime of folders within the volume is set to when the container was run rather than when the container image was created.
If you are not using VOLUMEs, there’s no problem, the mtime of folders will be always be the same every time you run the container. Also, the problem only shows itself for folders, instead of files.
I logged the issue here: https://github.com/docker/docker/issues/17018
The reason it affects us so much is that Yii v1 publishes assets (js/css/images) to a public url which is determined by the hash of the name and the filemtime of the parent folder. Since our website runs on a cluster and the deployment of a new version will cause new containers to be started at slightly different times, we end up with a situation where each container generates assets at a different url.
There are many solutions:
- We could turn on stickiness on the load balancer so all requests go to the same machine. This isn’t great because stickiness doesn’t load balance so well.
- We could patch zii so it uses
publish(blah,true)which would not take into account the modified time. This isn’t great because hacking Yii core isn’t good, it’s nice to use a clean copy of yii.
- We could generate the assets before building the data-container. No, this wouldn’t work because yii would notice the new timestamp of the folder and assets would be generated again, differently for each server.
- We could override the annoying Yii classes (e.g. CDetailView and use DetailView instead). This would require changing 50+ files and would mean we could never use the standard yii widgets which would be a source of mistakes from the devs.
- We could use “
touch -d” to reset the modification time of the affected folders so that every machine is in sync and generates the assets with the same name.
We went with the “
touch -d” hack for the moment. However ugly it might be, it is a one-line fix in the deployment pipeline
docker run --rm --volumes-from app-data ubuntu bash -c 'touch --date=$(date +%Y%m%d) /var/www/app/vendor/yiisoft/yii/framework/zii/widgets/assets';
For reference: I was using Docker v1.8.3.