You can put a limit in place by using the -m or --memory flag on the docker run or docker create commands.
where unit = b, k, m or g
docker run -d --name ch6_mariadb \ --memory 256m \ # Set a memory constraint --cpu-shares 1024 --user nobody \ --cap-drop all \ dockerfile/mariadb
docker run -d -P --name ch6_wordpress \ --memory 512m \ --cpu-shares 512 \ # Set a relative process weight --user nobody \ --cap-drop net_raw \ --link ch6_mariadb \ wordpress:4.1
You can see the CPU set restrictions in action by stressing one of your machine cores and examining your CPU workload:
# Start a container limited to a single CPU and run a load generator docker run -d \ --cpuset-cpus 0 \ # Restrict to CPU number 0 --name ch6_stresser dockerinaction/ch6_stresser # Start a container to watch the load on the CPU under load docker run -it --rm dockerinaction/ch6_htop
The value can be either list or range forms:
0,1,2—A list including the first three cores of the CPU 0-2—A range including the first three cores of the CPUyou can use the --device flag to specify a set of devices to mount into the new container.
Running this example will work only if you have a webcam at /dev/video0:
docker -it --rm \ --device /dev/video0:/dev/video0 \ # Mount video0 ubuntu:latest ls -al /dev
Docker creates a unique IPC namespace for each container by default. The Linux IPC namespace partitions share memory primitives such as named shared memory blocks and semaphores, as well as message queues.
docker -d --name ch6_ipc_consumer \ --ipc container:ch6_ipc_producer \ # Join IPC namespace dockerinaction/ch6_ipc -consumer
Memory isolation is a desirable trait. If you encounter a situation where you need to operate in the same namespace as the rest of the host, you can do so using an open memory container:
docker -d --name ch6_ipc_producer \ # Start a producer --ipc host \ # Use open memory container dockerinaction/ch6_ipc –producer docker -d --name ch6_ipc_consumer \ # Start a consumer --ipc host \ # Use open memory container dockerinaction/ch6_ipc -consumer
Linux recently released a new user (USR) namespace that allows users in one namespace to be mapped to users in another.
When Docker adopts the USR namespace, you’ll be able to map user IDs on the host to user IDs in a container namespace. So, I could map user 1000 on my host to user 2 in the container. This is particularly useful for resolving file permissions issues in cases like reading and writing to volumes.
You can get a list of available users in an image with the following command:
docker run --rm busybox:latest awk -F: '$0=$1' /etc/passwd
Docker provides the --user or -u flag on docker run and docker create for setting the user. This will set the user to “nobody”:
docker run --rm \ --user nobody \ # Set run-as user to nobody busybox:latest id # Outputs: uid=99(nobody) gid=99(nobody)
It can also accept user and group names or IDs. When you use IDs instead of names, the options start to open up:
docker run --rm \ -u nobody:default \ # Set run-as user to nobody and group to default busybox:latest id # Outputs: uid=99(nobody) gid=1000(default) docker run --rm \ -u 10000:20000 \ # Set UID and GID busybox:latest id # Outputs: uid=10000 gid=20000
For example, how do you handle a log file written to a volume?The preferred way is with volume containers. If logs are written to a volume by a process running as user 1001 and another container tries to access that file as user 1002, then file permissions might prevent the operation.
One way to overcome this obstacle would be to specifically manage the user ID of the running user. You can either edit the image ahead of time by setting the user ID of the user you’re going to run the container with, or you can use the desired user and group ID:
mkdir logFiles sudo chown 2000:2000 logFiles # Set ownership of directory to desired user and group docker run --rm -v "$(pwd)"/logFiles:/logFiles \ # Write important log file -u 2000:2000 ubuntu:latest \ # Set UID:GID to 2000:2000 /bin/bash -c "echo This is important info > /logFiles/important.log" docker run --rm -v "$(pwd)"/logFiles:/logFiles \ # Append to log from another container -u 2000:2000 ubuntu:latest \ # Also set UID:GID to 2000:2000 /bin/bash -c "echo More info >> /logFiles/important.log" sudo rm –r logFiles
When you create a new container, Docker drops a specific set of capabilities by default. This is done to further isolate the running process from the administrative functions of the operating system. At the time of this writing, this set includes the following:
SETPCAP—Modify process capabilities SYS_MODULE—Insert/remove kernel modules SYS_RAWIO—Modify kernel memory SYS_PACCT—Configure process accounting SYS_NICE—Modify priority of processes SYS_RESOURCE—Override resource limits SYS_TIME—Modify the system clock SYS_TTY_CONFIG—Configure TTY devices AUDIT_WRITE—Write the audit log AUDIT_CONTROL—Configure audit subsystem MAC_OVERRIDE—Ignore kernel MAC policy MAC_ADMIN—Configure MAC configuration SYSLOG—Modify kernel print behavior NET_ADMIN—Configure the network SYS_ADMIN—Catchall for administrative functionsYou can drop capabilities from a container using the --cap-drop flag on
docker create or docker run.
docker run --rm -u nobody \ ubuntu:latest \ /bin/bash -c "capsh --print | grep net_raw" docker run --rm -u nobody \ --cap-drop net_raw \ # Drop NET_RAW capability ubuntu:latest \ /bin/bash -c "capsh --print | grep net_raw"
Similar to the --cap-drop flag, the --cap-add flag will add capabilities.
docker run --rm -u nobody \ ubuntu:latest \ /bin/bash –c "capsh --print | grep sys_admin" # SYS_ADMIN is not included docker run --rm -u nobody \ --cap-add sys_admin \ # Add SYS_ADMIN ubuntu:latest \ /bin/bash –c "capsh --print | grep sys_admin"
In those cases when you need to run a system administration task inside a container, you can grant that container privileged access to your computer. Use the –privileged flag on docker create or docker run to enable this mode:
docker run --rm \ --privileged \ ubuntu:latest id # Check out our IDs docker run --rm \ --privileged \ ubuntu:latest capsh –print # Check out our Linux capabilities docker run --rm \ --privileged \ ubuntu:latest ls /dev # Check out list of mounted devices docker run --rm \ --privileged \ ubuntu:latest ifconfig # Examine network configuration
LSM(Linux Security Modules) is a framework that Linux adopted to act as an interface layer between the operating system and security providers.
AppArmor and SELinux are both LSM providers. They both provide mandatory access control (MAC—the system defines access rules) and replace the standard Linux discretionary access control (file owners define access rules).
The flag available on docker run and docker create is --security-opt.
LXC(Linux Containers) is a container runtime provider—a tool that actually works with Linux to create namespaces and all the components that go into building a container.
As Docker matured and portability became a concern, a new container runtime called libcontainer was built, replacing LXC.
If you’re running a system where you can and want to use LXC, you can change the container provider and take advantage of those additional features.
Once Docker is configured for LXC, you can use the --lxc-conf flag on docker run or docker create to set the LXC configuration for a container:
docker run -d \ --lxc-conf="lxc.cgroup.cpuset.cpus=0,1" \ # Limited to two CPU cores by LXC --name ch6_stresser dockerinaction/ch6_stresser docker run -it --rm dockerinaction/ch6_htop docker rm -vf ch6_stresser