Here's the problems we're solving with Docker:
* Sanity in our environments. We know exactly what goes into each and every environment, which are specialized based on the one-app-per-container principle. No more asking "why does software X build/execute on machine A and not machines B-C?"
* Declarative deployments. Using Docker, Core OS, and fleet[1], this is the closest solution I've found to the dream of specifying what I want running across a cluster of machines, rather than procedurally specifying the steps to deploy something (e.g. Chef, Ansible, and the lot). There's been other attempts for declarative deployments (Pallet comes to mind), but I think Docker and Fleet provide even better composability. This is my favorite gain.
* Managing Cabal dependency hell. Most of our application development is in Haskell, and we've found we prefer specifying a Docker image than working with Cabal sandboxes. This is equally a gain on other programming platforms. You can replace virtualenv for Python and rvm for Ruby with Docker containers.
* Bridging a gap with less-technical coworkers. We work with some statisticians. Smart folks, but getting them to install and configure ODBC & FreeTDS properly was a nightmare. Training them in an hour on Docker and boot2docker has saved so much frustration. Not only are they able to run software that the devs provide, but they can contribute and be (mostly) guaranteed that it'll work on our side, too.
I was skeptical about Docker for a long time, but after working with it for the greater part of the year, I've been greatly satisfied. It's not a solution to everything—I'm careful to avoid hammer syndrome—but I think it's a huge step forwards for development and operations.
[1]: https://coreos.com/using-coreos/clustering/
Addendum: Yes, some of these gains can be equally solved with VMs, but I can run through /dozens/ of iterations of building Docker images by the time you've spun up one VM.