Understanding how containers work at a low level

Hello to all. I am new to this group and I hope I can find the answers I have been looking for.

I have read multiple articles where a Container is compared to Java software in that both are OS independent as long as the appropriate run-time is installed. JRE for Java and Docker run-time for containers.

My first question, is a container compiled or interpreted?

Do containers use Just In Time (JIT) compilation or any form of dynamic compilation?
Do containers utilize a similar Bytecode? What is the process to get from Source Code to Machine Code?

When a container is run on a system, what is the path for the code to take to get to RAM and then CPU registers etc?

I need to understand the loading process for containers.

Thank You,

Jared

Those articles seem to send you down the wrong track. A container simply runs a process (which can have child processes). The only difference compared to running that process directly on the host is that it’s isolated when it commes to namespaces of ressources, permissions, privlieges - a container sees itself as an independend system (e.g. localhost in a container, is local to the container, not to the host).

Docker is just a convinience runtime for containers. Independend what container runtime you use: the images are “just” a way to encapsulate applications, their dependencies and configuration bundled with a (hopefully clever) entrypoint script that does the setup magic.

After reading the first part of my response, can you elaborate what you are looking for exactly.

A container is not a vm - a container does not have its own kernel, it will not boot, it will not start services, it will ONLY execute the process declared in the ENTRYPOINT and/or CMD directive of the Dockerfile. As a matter of fact a container does not realy have an OS - the base images are just a point in time snapshots of a loose set of binaries, dependencies and config files that make up the familar part of the OS, without beeing a full OS.

May I suggest this excellent, free, self-paced docker training? Introduction to Containers

Thank you for the information on the self-paced docker training. I have started looking through some of the items but they do not seem to go into details on the low level in the weeds type of information.

To elaborate on the path the code takes to get to RAM etc and to expand on my question on the loading process for containers. In a non-container system when I want to run a piece of code I have basically two different types of languages, a compiled and interpreted. (I am speaking broad strokes and do not want to get into corner cases etc) So, for example, I take C++ as a compiled language and Java as interpreted.

With C++ I write the code and then compile it (this includes the linkers etc) so taking source code then translating it to machine code. The compiling process makes it so the program is specific to they type of system (windows runs on windows, linux on linux etc).

With Java I write the code and then use an interpreter in order to run. The source code gets converted to bytecode by javac and then JRE, in this case, will then interpret the bytecode into machine code at run-time…

Ok, so now on my host, for compiled code (C++ in this case) I run the executable and the host OS loads the machine code into memory (creates the stack, heap, data, text etc…) and then the process of running instruction starts, moving from RAM into registers, adding, jumping etc.

For interpreted code (Java) when I run the code the JRE/JVM converts the bytecode to machine code using JIT (Just-In-Time) compiler. This occurs at run-time. The OS loader takes the JIT machine code and then the process of running instruction starts. This process allows Java to be OS independent as long as the system has JRE installed to run.

Now to containers.

From your comments above and from further reading it looks like a container could be both compiled and/or interpreted depending on the language of the code. I just found an article in regards to Java and Docker and it said that the container will house the JRE so the host does not have to have it pre-installed. Is this correct?

Does the host machine only need the container run-time installed to so the containers and their encapsulated processes can run?

I apologize if this is a bit disjointed. I am just trying to figure out how, at the low level of the OS actually executes a program? How do containers interact with the host loader? How the Machine code in the container gets loaded into the Hosts RAM, CPU registers etc.

Thanks,
Jared

A container is a set of isolated processes. This isolation is ensured by the operating system kernel.

The OS creates processes, and provides services such as memory management, i/o etc. to these processes. The kernel can, at its discretion, limit access to the services and resources it controls. For example, it may allow a process access to only a subset of available memory, only a subset of the available file systems and so on. A process, or a set of processes which are limited in this way by the kernel is a container.

To recap, a container can run compiled code, interpreted code or a mix - it does not matter. Code in a container is loaded into RAM and executed on the CPU in exactly the same way as any other process - by the OS. It’s just that the OS kernel imposes certain limits on each container (group of processes), and isolates them from each other in terms of resources like network interfaces and file systems.

1 Like

Are you familiar with chroot jails on linux? Think about a container as beeing a chroot jail on steroids.

The JRE is a depdendecy for your Java application. Of course it needs to be present inside the container. You either use a base image that allready comes with the JRE preinstalled or install it in your Dockerfile yourself.

Since “Docker Images” implement the OCI Container Image specs, every container runtime supporting OCI Container Image specs will do. The most convenient container runtimes are docker and podman, which in reality are convenience wrapper arround “the real container engines”.

In regards to chroot jails I am not familiar.

Thank you for the information on the host OS and the creating of processes to run the code. I believe I understand that when the container is run a process is created on the host to run the code. This process sets security, and resource management.

I can understand interpreted code and containers as the bytecode is read and machine code is created for the specific architecture.

With compiled code and containers, how does the container runtime engine get the machine code to work on the specific host architecture? Does the container runtime engine re-compile the source code or machine code to work specifically on the host architecture? Does the container runtime engine “interpret” the machine code at runtime?

My understanding is that one of the main benefits of containers is that compiled software only needs to be done once and then, through containerization, it is OS independent and can be run on any OS as long as it has the container runtime installed. From my prior question, how does the machine code “interpretation” work?

Thanks,

At one point this may have been the truth when Docker was only available for x86_64 linux architectures. Things changed :wink: Images need to be build specificy for a target architecture, the binaries inside the image must be compatible with the target architecture - an image build for an archtecture (ex: x86_64) will not work on another (ex: arm, mips or any other non x86_64 ). Windows Container can not be run anywhere except on Windows. Windows and MacOS run Linux Containers in a vm.

The binaries inside a container must match the architecture they are operated on. There is no interpretation, no transpilation, no emulation, none of those things. A container is realy just a native host process beeing isolated and restricited.

Thank you for this information. As the articles I found said that containers were independent of the host system. I had to specifically look for multi-architecture builds to find anything.

I assume this will allow a single container to run on different architectures but it does look like the source code needs to be compiled for each architecture separately (along with some other items) and then added to a single container. At that point the container could be used on any of the architectures supplied.

Still incorrect… Anyway, I give up.

What is there to “give up” on.

The articles I found “Docker: Building Images for Multiple Architectures” and “Modern multi-architecture builds with Docker” basically say that a single container can be created to run on different architectures.

“Multiarch builds is a Docker feature that allows you to build one image that runs on any number of target architectures”

Is this “Still incorrect”?