Runtime Resource Constraints for Host Binaries using Docker

If you are thinking about controlling resources assigned to Linux processes and do not want to fiddle with cgroups settings, then this article should be of some help to you.

In this article we’ll see how docker can be used to run the host binaries with specific resource control settings. By host binaries I mean the binaries available in the host running docker-engine.

We’ll run a host binary inside a docker container and use docker runtime options to assign resources to the containerized process. If you are looking for a detailed explanation of resource control mechanisms in docker, then Marek’s article is a definite read.

Let’s get started. First of all we need to create a docker image. We’ll create an empty docker image.

# cat >Dockerfile<<EOF
FROM scratch
WORKDIR /root
EOF
# docker build -t empty .
# docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
empty latest a3c4a18a2038 27 minutes ago 0 B

Now we can containerize any host binary by creating a container using the empty image and mounting the host directories as volumes. The command line looks like this :

docker run -itd -v /usr/bin:/usr/bin:ro -v /lib64:/lib64:ro -v /var:/var -v /tmp:/tmp empty <binary>

The above command line assumes <binary> resides in /usr/bin with dependencies in /lib64. The volume mounts needs to be suitably adjusted based on your specific environment.

You can specify the resource limits by providing relevant options during container creation. For example to specify a memory limit of 4MB the command line will look like this:

docker run -m 4M -itd -v /usr/bin:/usr/bin:ro -v /lib64:/lib64:ro -v /var:/var -v /tmp:/tmp empty <binary>

Similarly you can specify limits for CPU shares, disk bandwidth, physical CPUs to run the binary and many more. For a full list of runtime resource constraints option please refer to the docker run documentation here.

Let’s extend this to provide a login shell with runtime resource limits to users. For example the following puts a restriction on the total memory usage.

# cat /usr/local/bin/limitsh
#!/bin/bash
exec docker run -it --memory=8M --memory-swap=8M \
-v /usr:/usr:ro \
-v /bin:/bin:ro \
-v /lib64:/lib64:ro \
-v /etc:/etc:ro \
-v /home/$USER:/root \
-v /home/$USER/tmp:/tmp \
--rm=true empty bash -l

# echo "/usr/local/bin/limitsh" >> /etc/shells
# useradd testuser -g docker -s /usr/local/bin/limitsh

Let’s run a  simple test to verify the resource limits.

# su - testuser
[root@11098e0e86da ~]#cat mem_hog.c
#include <stdlib.h>
#include <string.h>
#define ALLOC_SIZE (8 * 1024 * 1024)

void main(int argc, char *argv[])
{
    char *p;
    p = (char *)malloc(ALLOC_SIZE);
    if (p)
       memset(p, 0, ALLOC_SIZE);
}
[root@11098e0e86da ~]#./mem_hog
Killed

The mem_hog process gets killed by the system.

There are numerous additional possibilities. For example you can add or remove specific capabilities. This is depicted below.

# cat /usr/local/bin/limitsh
#!/bin/bash
exec docker run -it --memory=8M --memory-swap=8M \
-v /usr:/usr:ro \
-v /bin:/bin:ro \
-v /lib64:/lib64:ro \
-v /etc:/etc:ro \
-v /home/$USER:/root \
-v /home/$USER/tmp:/tmp \
--rm=true --cap-add NET_ADMIN \
empty bash -l

Pradipta Kumar Banerjee

I'm a Cloud and Linux/ OpenSource enthusiast, with 16 years of industry experience at IBM. You can find more details about me here - Linkedin

You may also like...