@ruebe @dreadpirateshawn, to jump in and clarify a few things here:
A container image, in aggregate, is simply a root filesystem (snapshot) for a given process. This snapshot only encapsulates the userspace pieces (specifically, the filesystem).
It is correct that containers will use the kernel of the host where they are running. Just like normal processes running “bare” on the system would. They do not share libraries with the host or use a different kernel if the image is different. Each Docker container has its own set of libraries since each container has its own, unique root filesystem, but the kernel is always shared with the host.
Those libraries, including glibc, are in userspace. And the first rule of kernel maintenance, is “DO NOT BREAK USERSPACE”.
The kernel is generally quite good about providing backwards compatibility of interfaces (e.g. syscalls) across subsequent versions. If they don’t, it’s a (high priority) bug.
So, running a
ubuntu:12.04 container on a more modern kernel, is generally very safe if original and target kernels are both vanilla. You ask, however, about the opposite case of running a
ubuntu:16.04 application on a Ubuntu 12.04 (you don’t say precisely which version, I guess something like
3.13.11?). That’s unsafe, but it doesn’t mean applications you run will necessarily fail out of the gate. Many applications (
$YOUR_WEBAPP, etc.) don’t rely on recent kernel features. If you look at the list of Linux system calls and when they were added, very few are added post-3.13. So that might explain why things seem to be working, but it doesn’t mean there aren’t nasty runtime bugs and errors lurking around the corner somewhere.
At any rate, you probably shouldn’t try to run applications targeted for future versions of the kernel on older ones, but I hope that helps explain more why they may seem to work.