DockerInAction-Limiting risk with isolation

来源:互联网 发布:ios编程基础 编辑:程序博客网 时间:2024/06/06 10:17

6.1

Resource allowances

Memory limits

You can put a limit in place by using the -m or --memory flag on the docker run or docker create commands.

<number><optional unit>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

CPU

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

6.2

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 generatordocker 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 loaddocker 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 CPU

Access to devices

you 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

Shared memory

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

6.3

Using an open memory container

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 –producerdocker -d --name ch6_ipc_consumer \ # Start a consumer    --ipc host \                    # Use open memory container    dockerinaction/ch6_ipc -consumer

Understanding users

Introduction to the Linux user namespace

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.

Working with the run-as user

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

Users and volumes

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 logFilessudo chown 2000:2000 logFiles # Set ownership of directory to desired user and groupdocker 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

Adjusting OS feature access with capabilities

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 functions

You 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 includeddocker run --rm -u nobody \    --cap-add sys_admin \  # Add SYS_ADMIN    ubuntu:latest \    /bin/bash –c "capsh --print | grep sys_admin"

Running a container with full privileges

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 IDsdocker run --rm \    --privileged \    ubuntu:latest capsh –print # Check out our Linux capabilitiesdocker run --rm \    --privileged \    ubuntu:latest ls /dev # Check out list of mounted devicesdocker run --rm \    --privileged \    ubuntu:latest ifconfig # Examine network configuration

Stronger containers with enhanced tools

Specifying additional security options

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.

Fine-tuning with LXC

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_stresserdocker run -it --rm dockerinaction/ch6_htopdocker rm -vf ch6_stresser
0 0