Like, I have a generic Flask container repository that I clone as a starting base...change the domain name(s) on the config file, app name, etc. Then just copy things into the src/ directory and spin it up.
For me, this is really easy to spin up a new flask project. I do the same with golang [sort of, it really just downloads a binary+config file into a container that has all of my logging, etc setup].
The problem with doing LXC is where you have inheritance chains like this:
[Base Container of Ubuntu + Logging + Monitoring] -> [Base Flask Container] -> [Flask Container for Website X]
[Base Container of Ubuntu + Logging + Monitoring] -> [Base Flask Container] -> [Flask Container for API for Website X]
[Base Container of Ubuntu + Logging + Monitoring] -> [Container for Mail Service]
[Base Container of Ubuntu + Logging + Monitoring] -> [Container for Kibana]
[Base Container of Ubuntu + Logging + Monitoring] -> [Container for Redis-Cache]
etc.
Tbh, I think that is what docker really fixes. The ability to easily inherit containers so you only have to make changes in one spot to change all of them.
Builds, as an example. This was my first introduction to Docker - scaling Jenkins worker nodes was allocating yet another VM. As you scale to tens or hundreds of build slaves, you realize utilization across the cluster is down. Scaling builds with Docker was simple and efficient to implement and it allowed me to drive utilization up dramatically.
Now there's 15 different companies, integrations, and tooling surrounding this space to make that process repeatable to the masses. Amazing.
We're seeing the same thing in the orchestration, paas, sdn, iaas, YOUR ACRONYM OF CHOICE, and one common theme is that ecosystem is standardizing around Docker. That's pretty powerful.
Since you asked, the drawback of just logging into an image, editing files, and installing software is that you can only reproduce that image by grabbing an entire file system.
When I use Docker, I create a git repository containing a 'Dockerfile', which is basically a series of shell commands to configure a machine. I also add copies of any configuration files I'll need, and use the Dockerfile to copy them onto the machine during setup.
This can be extremely fast in practice: Docker has a caching system which "runs" unchanged lines in Dockerfile by looking up a cached VM image, so I can often edit the Dockerfile and rebuild the image in a second or so.
This approach is really nice when I have to look at an image a year later and figure out how I created it, perhaps with the goal of upgrading to a new OS release or whatever. I just glance at the Dockerfile, change the base OS version, and re-run it.
sudo docker run -i -t ubuntu /bin/bash sudo docker commit [container id] [tag]
Is that what you are looking for?
But for my part I tend to just layer changes piece by piece. So e.g. I have a docker image that's a "base development" image, and create separate docker containers to run each web app I'm experimenting with, with a shared volume with a separate docker container that I ssh into and run a screen session in with the code/git repositories. In effect that means that bringing up a new docker image for a new project is at most a couple of lines of change unless the project has particular/different dependencies.
If you ever heard some of Heroku's propaganda surrounding "eternal applications", it also applies here: the stack you're deploying on will never update out from under you, because it's pinned by your Dockerfile. You can confidently move your app to any old server and it'll run exactly the same. One good analogy I've heard is that a Docker image is the reductio ad absurdum of a static binary: it doesn't depend on your system, just on itself.
Although it still supports lxc, docker now defaults to libcontainer (https://github.com/dotcloud/docker/tree/master/pkg/libcontai...), it's own container implementation.