by Ginny Henningsen
This article describes typical use cases for Linux containers (LXC) and Docker containers, and provides quick-reference guides for common LXC and Docker commands.
Table of Contents
Choosing a Container Technology
Container Technologies: The Basics
LXC Containers
Docker Containers
Important LXC and Docker Concepts
"Best Fit" Use Cases
Final Thoughts
Learn More
Appendix A
LXC Commands Quick Reference
Docker Commands Quick Reference
About the Author
Choosing a Container Technology
Why should you deploy applications in a container? There are well-known benefits associated with container technologies: the ability to sandbox running applications, control system resources, and easily replicate application environments to speed deployments. But deciding which technology to select for application delivery on Oracle Linux—LXC or Docker—requires some thought. While there are advantages with respect to each container technology, there really is no single "best" choice—the optimal solution depends on the specific application and requirements. In other words, your best choice is truly the technology that's the best fit for the task at hand.
This article explores LXC and Docker container technologies to help IT administrators understand their similarities and differences, as well as typical use cases. When the time comes to use either LXC or Docker, this article also includes a handy quick reference "cheat sheet" containing sample commands for commonly performed tasks.
Container Technologies: The Basics
Let's take a quick look at the similarities and differences between LXC and Docker containers and how they differ from well-established hypervisor technologies (such as Xen, Microsoft Hyper-V, or VMware's ESXi). As shown in Figure 1, traditional virtualization solutions implement the hypervisor as an additional software layer on top of the native host operating system. The hypervisor supports multiple virtual machine (VM) guests, performing hardware emulation to access underlying physical server resources. The additional work of emulation imposes some degree of performance overhead, which is why LXC and Docker containers are considered a lighter-weight approach to isolating applications in comparison to conventional virtualization solutions.

Figure 1. LXC and Docker containers versus hypervisor-based virtualization.
With traditional virtualization solutions, each VM guest contains an isolated, full-blown operating system instance with its own OS kernel and user space. This allows a single physical machine to support applications running simultaneously on completely different operating systems while fully sandboxing them from one another. As an example, Oracle VM (which uses the Xen hypervisor) can support applications that run within separate Linux, Oracle Solaris, and Microsoft Windows guest VMs.
LXC Containers
In contrast, LXC containers share the same kernel space (with the same drivers and kernel modules) as the host operating system, but each container has its own isolated user space (Figure 1). LXC containers take advantage of the cgroups resource management and namespace capabilities in Linux, which is how LXC containers implement resource control and isolation.
LXC containers can be deployed in two different ways, either as application or as system containers (although they are primarily deployed as system containers):
- LXC application containers can isolate a single application, similar to a
chroot
jail. Application containers make it easy to scale an application or a service, because additional container instances can be deployed quickly in a cookie-cutter fashion to meet demand. LXC application containers share the host's root file system and are created with lxc-execute
, which runs a cut-down version of init
. Because Docker containers provide similar application container functionality and offer other advantages, Docker containers are typically implemented rather than LXC for use cases where application containers are the best fit.
- LXC system containers are the typical use case for LXC containers. Each LXC system container runs an
init
process that provides an isolated execution environment, enabling support for a complete multiprocess application stack. Like a hypervisor-based virtualization solution, LXC system containers provide sandboxing of the entire stack—processes running in one container can't see or impact processes running in another. But unlike a hypervisor-based virtualization solution using VMware ESXi, Microsoft Hyper-V, or Oracle VM, LXC containers can support only Linux guest VMs that use the host's kernel and device drivers.
Docker Containers
A Docker container is an application container best suited for a single application or service. Unlike an LXC system container, a Docker container does not run a separate init
process, so a single container can't easily host a multitiered stack. Instead, multiple Docker containers (each running a separate service or application) must be connected to one another to construct a full multitiered stack. Docker containers are ideally suited for isolating a service, such as a web service, and container instances can be easily cloned to scale the service and support greater capacity.
Docker containers are built using file system layers that capture the complete application environment into a virtual container. The base Docker container image consists of OS binaries and libraries. When the base image is modified—typically by installing application packages and configuring software—the new container shares the same binaries and libraries as the base, as depicted in Figure 1.
Docker containers are managed and run by the Docker Engine, which makes system calls to the underlying OS kernel. You can define a small text file (a Dockerfile) that captures the application container and all of its dependencies. This file can then be moved to any system that has a Docker Engine and be rebuilt, greatly simplifying application portability. At this time, Docker Engines are available for all major Linux distributions and Microsoft operating systems. The ability to capture an application, its environment, and all dependencies and move that across platforms is a significant difference in comparison to Linux-only LXC containers.
Important LXC and Docker Concepts
Because they are both lightweight virtualization tools, LXC and Docker containers have some notable similarities. Unlike a traditional hypervisor-based approach, LXC containers don't require the duplication of a full operating system installed as a guest, and Docker containers rely on efficiently layered images. Both LXC and Docker containers are open source–based, taking advantage of private Linux namespaces to sandbox applications and Linux cgroups to enable resource allocations and limits. And with both technologies, each container gets its own networking stack—a private network interface with a virtual bridge that allows the container to communicate while providing a separate VLAN. On Linux systems, both LXC and Docker containers can leverage an underlying Btrfs file system for fast snapshots, which helps to create new Docker image layers quickly or copy a root file system rapidly when you are cloning an LXC container.
LXC and Docker containers also feature some significant differences—even beyond the prominent difference of an LXC system container supporting an init
process while a Docker container does not. Docker containers are built from previously captured Docker images (Figure 2). Images can be downloaded from (as well as published to) a Docker registry, either the public Docker Hub Registry maintained by Docker, Inc. or a privately maintained local registry. Oracle publishes images for various distribution versions of Oracle Linux 6, Oracle Linux 7, and MySQL to the Docker Hub Registry, and these can be freely downloaded and run as a base layer of a Docker container.
Docker captures all changes made to a base image (such as installing application packages, resolving dependencies, and configuring settings), and you can commit these changes to build a new container image. To save space, Docker stores only changes to a base image in layers to reconstruct the full container image. You can build and run a container image interactively in the Docker Engine, but more commonly, a Dockerfile is defined to build the container image and run the application.

Figure 2. Docker captures changes to a container image and uses layers to efficiently reconstruct a container.
As an example, Figure 2 depicts a container image created on the local host by pulling an Oracle Linux 6.5 image from the Docker Hub Registry. The following docker run
command runs the base Oracle Linux 6.5 image as a container named ContainerA, executing /bin/bash
. Running the shell allows the user to then interactively install packages in the container.
# docker run -i -t --name ContainerA oraclelinux:6.5 /bin/bash
Suppose the administrator configures this Oracle Linux 6.5 image by installing Apache web server packages and web server content. Once the container is installed and configured, the configuration can be committed as follows, generating a new Docker image named ContainerAprime:
# docker commit -m "httpd installed" `docker ps -l -q` ContainerAprime
Figure 2 illustrates how Docker uses layering in container images—the A' image consists of the base Oracle Linux 6.5 image and changes made to that image to construct ContainerAprime
. To deploy three web servers, the Docker Engine can be given these commands to generate three containerized web servers from the same image:
# docker run -d --name websvr0 -p 8080:80 ContainerAprime /usr/sbin/httpd -D FOREGROUND# docker run -d --name websvr1 -p 8081:80 ContainerAprime /usr/sbin/httpd -D FOREGROUND# docker run -d --name websvr2 -p 8082:80 ContainerAprime /usr/sbin/httpd -D FOREGROUND
It's important to understand that Docker container storage is ephemeral. Docker containers are transient in nature and data does not persist beyond the lifespan of a container's execution. Associating a data volume with a container using the -v
flag allows the container to access, modify, and persist data on the host. For example, in the following command, the -v
flag causes the directory /home/datadir
on the host to be mounted as /var/lib/mysql
(the default database location for MySQL) on the container db
:
# docker run --name db -d -e MYSQL_ROOT_PASSWORD=s5cr5t -v /home/datadir:/var/lib/mysql \ mysql/mysql-server:db1
In contrast to the layering used to construct Docker images, LXC containers are built from template scripts that live on the underlying host Linux system in /usr/share/lxc/template
s. The Oracle Linux 7 distribution includes templates that can create user space containers for many common Linux distributions (including Oracle Linux, Fedora, Gentoo, Ubuntu, and so on). These template scripts configure an LXC container, defining a number of system settings (such as the host name, root file system location, white-listed cgroup devices, and network interface configurations) and container resources. The lxc-oracle
template also defines and sets default passwords for the oracle
and root
users. The -t argument specifies the template to be used in creating the container:
# lxc-create -n ol7ctr1 -B btrfs -t oracle -- --release=7.latest
Rather than editing a given template, configuration files in /usr/share/lxc/config
can be used to tweak settings for a particular container type. It's also possible to modify configuration parameters (such as network settings) in a container-specific configuration file (such as /container/ContainerAprime/config
).
"Best Fit" Use Cases
There are a number of use cases that are well-suited for LXC containers, including the following:
- Running multiple Linux distributions and versions on the same machine. For example, on an Oracle Linux 7 host, applications can execute in LXC containers that run Oracle Linux 5, Oracle Linux 6, or Oracle Linux 7. Oracle tests and fully supports specific Oracle distribution versions as LXC containers (see "Supported Oracle Linux Container Versions" in the Oracle Linux documentation). This capability allows an existing application qualified on Oracle Linux 5, for example, to execute on an Oracle Linux 7 system. Templates are also provided for other Linux distributions (although these containers are not tested or supported by Oracle). Because LXC containers share the same kernel with the host, containerized applications cannot have any dependencies on release-specific drivers or kernel modules to function properly.
- Creating isolated environments for application development and Quality Assurance (QA) testing. LXC containers can be deployed as development and test sandboxes, effectively quarantining applications. Oracle Database 12_c_ is fully supported on LXC containers (see the Supported Virtualization and Partitioning Technologies for Oracle Database and RAC Product Releases web page and the Oracle Database Release Notes for Linux). This support makes it easy to deploy isolated development and testing environments for Oracle Database. An LXC container created for development purposes can be easily and quickly cloned to replicate the environment for QA testing.
- Running a multitier software stack. Because LXC containers run an
init
process, they can easily support a multitier stack such as LAMP (Linux, Apache, MySQL, Perl/PHP/Python) for deploying web services. Depending on the load and server resources, multiple copies of the stack can be replicated to provision additional servers, with each copy of the stack isolated from the others. Each container has its own IP address, which allows each web server to operate independently. In the event of compromise (such as a Denial of Service attack), each container instance is isolated.
- Creating environments that are subject to resource controls. Because LXC containers can use Linux control group mechanisms, it's possible to allocate and limit resources for applications within a container. For example, by limiting CPU shares or memory for containers that host noncritical workloads, an administrator can prevent resource starvation for critical workloads.
Docker application containers are well-suited to deploying a single application service, such web service deployments of NGINX, Apache, lighttpd, or other httpd
servers. By creating additional container instances, it's easy to scale service capacity and support additional demand—while at the same time isolating workloads for better service reliability.
Docker offers additional flexibility because it captures deployment requirements and dependencies, making it easy to move an application service to a different platform. Docker registries also provide mechanisms for application publishing and sharing. Developers can publish an application (including the full environment in which the application runs properly) internally to a corporate registry or publicly on the Docker Hub Registry.
Final Thoughts
Container technologies have substantial benefits, especially given the need to isolate applications to increase service levels. Both LXC and Docker containers provide application sandboxes so that if a security flaw is exploited or a containerized application is compromised, it's unable to affect other applications and services running in other containers. Clearly there are use cases in which lightweight LXC or Docker container technologies are a good fit.
Learn More
The Oracle Linux documentation (the Oracle Linux Administrator's Solutions Guide for Release 6 or the Oracle Linux Administrator's Guide for Oracle Linux 7) has detailed sections on getting started with both LXC and Docker container technologies. There are also excellent resources for learning more about Docker at http://docs.docker.com/, including information on installing Docker on different operating systems, the Docker Engine User Guide, and the Docker reference manual.
Appendix A
To help you get started with LXC and Docker technologies, this appendix contains quick reference "cheat sheets." For both technologies, Table 1 and Table 2 list tasks that administrators frequently perform and an example of the appropriate command-line syntax.
LXC Commands Quick Reference
Table 1. Common LXC Tasks and Commands
| Install and configure LXC using the installation instructions for your OS. For optimal performance when cloning, create a Btrfs file system and mount it for LXC containers to use.
See the chapter "Configuring Operating System Containers" in the Oracle Linux Administrator's Solutions Guide for Release 6 or the Oracle Linux Administrator's Guide for Oracle Linux 7. |
| Run a bash
shell in an application container.
lxc-execute -n mycon1 -o /tmp/mycon1.log /bin/bash
|
| Create an Oracle Linux 6 system container named ol6ctr1
using the lxc-oracle
template script.
lxc-create -n ol6ctr1 -B btrfs -t oracle -- --release=6.latest
|
| Create the ol6ctr1
container using the lxc-oracle
template and a configuration file.
lxc-create -n ol6ctr1 -B btrfs -f config -t oracle -- --release=6
|
| Start the system container ol6ctr1
.
lxc-start -n ol6ctr1 -d -o /container/ol6ctr1_debug.log -l DEBUG
|
| Start the container ol6ctr1
as a daemon that writes its diagnostic output to the specified log.
lxc-start -n ol6ctr1 -d -o /container/ol6ctr1_debug.log -l DEBUG
|
| Log in to the container named ol6ctr1
.
lxc-console -n ol6ctr1
|
| Snapshot the root file system of a container for later cloning.
btrfs subvolume snapshot /container/ol6ctr1/rootfs /container/ol6ctr1/rootfs_snap
|
| Clone a container (method 1).
lxc-clone -o ol6ctr1 -n ol6ctr2
|
| Clone a container (method 2) using a previously captured snapshot of its root file system.
lxc-create -n ol6ctr3 -B btrfs -t oracle -- --templatefs=/container/ol6ctr1/rootfs_snap
|
| List all LXC containers or list containers running on the host.
lxc-ls lxc-ls --active
|
| List usage statistics and the IP address for a container.
lxc-info --stats --ips --name ol6ctr1
|
| Attach to a running container from the host and run a command there.
lxc-attach -n ol6ctr1 -- /bin/ps aux
|
| Suspend or resume container execution.
lxc-freeze -n ol6ctr1
lxc-unfreeze -n ol6ctr1
|
| Shut down a container after halting processes.
lxc-stop --nokill -n ol6ctr1
|
| Shut down a container, terminating its processes immediately.
lxc-stop -k -n ol6ctr1
|
| Monitor a container's state (for example, starting, running, stopping, stopped, and so on).
lxc-monitor -n ol6ctr1
|
| Display the CPU cores on which container processes can run.
lxc-cgroup -n ol6ctr1 cpuset.cpus
|
| Restrict container processes to run on the specified CPU cores.
lxc-cgroup -n ol6ctr1 cpuset.cpus 0,1
|
| Set a container's relative share of CPU time.
lxc-cgroup -n ol6ctr2 cpu.shares 256
|
| Limit a container to 256 MB when memory is low or contended; otherwise, set a hard limit of 512 MB.
lxc-cgroup -n ol6ctr2 memory.soft_limit_in_bytes 268435456
lxc-cgroup -n ol6ctr2 memory.limit_in_bytes 53687091
|
| Modify the file /container/name/config
to apply cgroup settings permanently.
lxc.cgroup.cpu.shares=256
lxc.cgroup.blkio.weight=500
|
Docker Commands Quick Reference
Table 2. Common Docker Tasks and Commands
| Install and configure Docker using the installation instructions for your OS. For optimal performance in cloning, create a Btrfs file system and mount it for Docker containers to use.
See the chapter “Installing and Configuring the Docker Engine on Oracle Linux 6” or “Installing and Configuring the Docker Engine on Oracle Linux 7” in the Oracle Linux Docker User's Guide. |
| Display information about the host and the version of the Docker Engine.
docker info
|
| Pull the Oracle Linux 6.6 image from the Docker Hub Registry.
docker pull oraclelinux:6.6
|
| Pull the latest Oracle Linux 7 image from the Docker Hub Registry.
docker pull oraclelinux:7
|
| Pull the latest MySQL image from the Docker Hub Registry.
docker pull mysql/mysql-server
|
| Log in to the Docker Hub Registry as the user myaccount
.
docker login --username=myaccount [--email=myemail@mycompany.com](mailto:--email=myemail@mycompany.com)
|
| Push an image to the Docker Hub Registry for the user myaccount
.
docker push myaccount/myimage
|
| List the available images to run using the host's Docker Engine.
docker images
|
| Create a container named guest
from the Oracle Linux 7 image and run a bash
shell interactively in the container.
docker run -i -t --name guest oraclelinux:7 /bin/bash
|
| Show information about running containers or about all containers.
docker ps
docker ps -a
|
| Show information about the most recently created container, displaying only its numeric ID.
docker ps -l -q
|
| Stop a running container named mynginx
.
docker stop mynginx
|
| Send the "hang up" (HUP) signal to a container.
docker kill -s HUP mynginx
|
| Restart the container myginx
.
docker restart mynginx
|
| Create a new image mycon/httpd:r1
from the latest running container, capturing the most recent changes.
docker commit -m "configured web server" `docker ps -l -q` mycon/httpd:r2
|
| Show the history of changes made to a Docker image.
docker history mycon:/httpd:r2
|
| Remove a container that is not currently running.
docker rm guest
|
| Remove a container image.
docker rmi oraclelinux:6.6
|
| Run httpd
as a foreground process in the container, mapping port 80 in the container to port 8080 on the host.
docker run -d --name ol6ctr1 -p 8080:80 mycon/httpd:r1 /usr/sbin/httpd -D FOREGROUND
|
| Run the NginX server as a background process.
docker run -d -p 80:80 my_image nginx -g 'daemon off;'
|
| Run the HTTP server with a relative weight of CPU shares (the value is relative to the default of 1024).
docker run -d --cpushares=512 --name guest2 -p 8080:80 mycon/httpd:r2
|
| Run the HTTP server with memory limited to 12 MB (the minimum hard limit is 4 MB).
docker run -d --memory=12m --name guest2 -p 8080:80 mycon/httpd:r2
|
| Run a MySQL server in a container named db
, mounting /home/datadir
on the host as /var/lib/mysql
.
docker run --name db -d -e MYSQL_ROOT_PASSWORD=s5cr5t -v /home/datadir:/var/lib/mysql \
mysql/mysql-server:db1
|
| List running processes in a container; display a live stream of container resource usage statistics.
docker top guest; docker stats mycon1 mycon2
|
| Execute a command on a container, in this case, the container mycon1
.
docker exec -i -t mycon1 bash
|
| Display information about a container, in this case, the IP address of the container mycon1
.
docker inspect -f '{{ .NetworkSettings.IPAddress }}' mycon1
|
| Save the container (and all of its layers) as a tar
file.
docker save -o webserver.tar mycon/httpd:r1
|
| Load a tar
file from a saved container tar
file image.
docker load -i webserver.tar
|
| Build a new Docker container image from a Dockerfile.
docker build -t mycon/httpd:r2 ./Dockerfile
|
| A simple Dockerfile example that configures and runs an Apache web server on an Oracle Linux 7 base image:
FROM oraclelinux:7
MAINTAINER E. Jones <[ejones@email-address.com](mailto:ejones@email-address.com)>
RUN yum install -y httpd perl && yum clean all
COPY webpagecontent /var/www/html/index.html
EXPOSE 80
CMD /usr/sbin/httpd -D FOREGROUND
Note: A more complex Dockerfile example is one that installs the Oracle WebLogic 12.2.1 Quick Install Distro, available here. |
| Import a file system image from a local tar
file.
cat myimage.tgz | docker import - example/imagelocal
|
| Copy from a container to the local file system (perhaps to save output from a container application to the local host).
docker cp mycon1:/tmp/mydir /tmp
|
| Copy files or directories from a local file system on the host into a container.
docker cp /tmp/app.conf mycon1:/etc/myapp
|
About the Author
Ginny Henningsen has worked for the last 18 years as a freelance writer developing technical collateral and documentation for high-tech companies. Prior to that, Henningsen worked for Sun Microsystems, Inc. as a systems engineer in King of Prussia, Pennsylvania, and in Milwaukee, Wisconsin, with a focus on solution architectures, operating systems, and security. Henningsen has a BA from Carnegie-Mellon University and an MSCS from Villanova University.