image-blog-vcs-docker-containers
May 10, 2018

How Docker Works with Helix Core

DevOps
Version Control

It is important to understand how Docker works. Here, we break down what Docker is and share how Docker works with Helix Core.

➡️ use Docker Containers with Helix Core

Back to top

What Is Docker?

Docker allows you to use containers to create, deploy, and run applications. 

The basic goal of a container is to package an application with its underlying dependencies, including:

  • Code.
  • Runtime.
  • System libraries.
  • Anything else it requires.

The resulting package or container can then easily be shipped unmodified between different environments such as development, test, QA, pre-production, and production.

The building blocks of Docker, such as Linux container and related technologies such as cgroups and kernel namespaces, have been around for rather longer. But Docker found a sweet spot in combining said technologies in a way that was much easier to use and greater than the sum of its parts.

A Closer Look at Docker

Here are a few highlights from the Docker overview:

  • Containers have similar resource isolation and allocation benefits to virtual machines. But  they have a different architectural approach allows them to be much more portable and efficient.
  • Docker users on average ship software 7x more after deploying Docker in their environment. 
  • Docker containers spin up and down in seconds, making it easy to scale an application service at any time to satisfy peak customer demand. Then you can just as easily spin down those containers to only use the resources you need when you need it.

Docker delivers many advantages. But there are of course some complexities to understand when implementing it—particularly for production systems.

Back to top

Why Use Docker with Helix Core?

We have been successfully using Docker containers in a variety of our internal projects at Perforce. And a couple customers mentioned a longer term aim of “Dockerizing” all their applications, potentially including Helix Core Server (and/or replication instances). So, I decided to investigate how Docker might affect things.

Here's a quick summary of what I found. Keep reading for the full details.

  • The basic performance of p4d within a Docker container is very similar to outside a container when it comes to read/write of underlying db.* metadata files (from a directory shared with the host). 
  • When using basic Docker network forwarding (from outside the container to the p4d inside the container), there can be a significant performance degradation, around 2x, which is due to the docker-proxy process (and not unexpected). An unexpected result, however, is that running the Docker container with “--net=host” (which uses host system network stack) does not significantly improve the performance. 

Not Using Helix Core Yet?

If you're not using Helix Core yet, you can start using it for free. Helix Core — complete with code review, Git support, and endless integrations and client options — for teams of up to 5 users.

➡️ try Helix Core

Back to top

How Docker Works with Helix Core

Here's how Docker works with Helix Core.

1. Look at Docker Architecture

A Docker image is a static snapshot of a file system, based on a series of layers. Each one has a unique hash. Images are versioned and can be tagged (E.g. Ubuntu:14.04 or Ubuntu:latest). A Docker container is a running instance of an image. Docker uses AUFS (Another Unified File System) and each image layer is read-only. When the container is running, a writable top-most file system layer is created.

Let’s look at the history of our container which shows us the layers and their sizes:

~/benchmark$ docker history p4benchmark
IMAGE CREATED CREATED BY SIZE

bc29eb7387e8 44 hours ago /bin/sh -c #(nop) CMD ["/run_in_docker.sh"] 0 B

fd307858e6ed 44 hours ago /bin/sh -c #(nop) EXPOSE 1777/tcp 0 B

f0e6d83e59e3 46 hours ago /bin/sh -c #(nop) COPY file:1b62b51286d922508 151 B

7b93c7db720b 4 days ago /bin/sh -c #(nop) COPY file:dbaafa84747899a13 114 B

3dfae18d29da 4 days ago /bin/sh -c apt-get update;apt-get instal 65.29 MB

3a1326cf000a 4 days ago /bin/sh -c #(nop) ENV DEBIAN_FRONTEND=noninte 0 B

db005dd7ab5d 12 days ago /bin/sh -c #(nop) MAINTAINER Robert Cowham "r 0 B

b72889fa879c 13 days ago /bin/sh -c #(nop) CMD ["/bin/bash"] 187 MB

:

 

Most of the layers are very small, although one is 65 MB (when apt-get is used to install several packages) and the base layer is 187 MB. Note that the hash of the last (bottom) layer refers to the base Ubuntu image, as we can see with the following command.

~/benchmark$ docker history ubuntu:14.04
IMAGE CREATED CREATED BY SIZE

b72889fa879c 13 days ago /bin/sh -c #(nop) CMD ["/bin/bash"] 187 MB

:

 

This layering makes it easy to share common layers between images (and thus containers), which reduces data copying and makes it faster to startup multiple containers based on the same image.

2. Run a Docker Container and Persist Data

A container is typically run with the “docker run” command (examples discussed in detailed section below). It can then be seen with “docker ps”.

~/benchmark$ docker run -v /home/rcowham/benchmark/p4:/p4 p4benchmark /run_in_docker.sh

~/benchmark$ docker ps

CONTAINER ID        IMAGE         COMMAND               STATUS

51a70c423936        p4benchmark   "/run_in_docker.sh"   Up 2 minutes

 

The container actually runs as a subprocess of the Docker daemon (server) on the host system, which typically makes it very fast to start. Normally, when you run your container, the top-most file system layer is writable. But when the container finishes any changes are discarded. This means that running any process such as a database — one for which you want written data to persist — needs to be handled differently.

The simplest way to do this is to mount a directory on the host system within the container. In the above “docker run” example we use the –v flag to mount a host directory within the container as /p4. See Docker's documentation for further options.

3. Set Docker Networking Options

By default, the Docker server daemon connects the host network to the network within the container via a bridge. This allows easy forwarding of host ports to ports within the container. For example, by passing “-p 2345:1666” to the “docker run” command, the host port 2345 is connected to port 1666 inside the container. As noted in the benchmark below, this is simple but has a performance cost.

For further information, check out:

4. Get Helix Server Benchmarks

First, find out how your server configuration (storage/RAM/operating system) might stack up against best-performing configurations for Perforce Helix Core. Our Performance Lab has designed a set of benchmarks to measure the performance of critical Perforce operations. 

That article also links to our “Benchmarks Results” page, where you can post the results of your runs and compare and contrast against other people’s results. For the purposes of this article, I used both benchmarks:

  • Branchsubmit: Measures, among other things the rate at which files can be committed to the Helix Core server.
  • Browse: Provides a method to evaluate the CPU performance and network utilization of your Helix Core server for lots of small client operations (fstat and filelog).

I customized them slightly to make the benchmarks easy to run on a single machine (browse in particular defaults to being run on several machines with multiple client machines working against a single server). You can download my setup, including scripts, Dockerfiles and environment.

The README.html (.md is source) describes the specifics. The KB article also lists datasets you need to download from the FTP site (note size of checkpoint is 1.4GB, and the resulting database needs 40GB of free disk to run!)

5. Branch Submit Benchmark Results

This benchmark required very little customization as it is configured to all run on the server machine. I was using 16.1 p4d, on Linux X86_64 with 64 GB of RAM. As noted in the benchmark docs, it is worth running the “setup” command once, and then the “runme” two or three times to ensure file system cache is used.

 

 

Native 

Docker

Difference

submitCommitTime

2,140 

2,176 

102%

submitCommitRate

32,712 

32,188 

98%

 

The commit rate for native p4d after file system cache was warmed up was very respectable, in the range of nearly 33,000 files per second. This result would put the server configuration on the first page of published benchmark results! And the results, when run inside Docker, were within a few percent. So no significant overhead for accessing the host filesystem from within the container.

6. Browse Benchmark Results

This was more interesting and took a little more configuration effort. The base script requires multiple hosts and a compiled test client to generate lots of small commands against the p4d. I modified the script to run both client and server on the same machine as it was simpler in my environment. I did have to tweak a Linux setting as the tests produce so many TCP connections so quickly that it exhausted the standard settings on the machine  - so changed sysctl net.ipv4.ip_local_port_range from default range “32768    61000” to “15000    61000”.

 

 

 Native 

Docker

Different to Native 

Docker net=host 

 Difference to native 

totalSeconds

54

135

249%

122

225%

maxFstatSecond

6,660

3,220

48%

3,305

50%

maxFilelogSecond

608

292

48%

302

50%

 

Thus, we can see a significant performance penalty (middle column). Using “top” it was easy to see that the docker-proxy process was using around 50% of a CPU during the tests (with the p4d in 10–20% range), and it is clear that the port forwarding from host port to the p4d port inside the container is the cause. The final two columns show the same test where we configured Docker to use the host networking stack (using parameter “--net=host” for “docker run” command). 

Back to top

Should You Use Docker with Helix Core?

There are many benefits to using Docker containers.

For Development and Deployment

The benefits Docker brings to development and deployment processes are tremendous. Of course, it can be overhyped. Sensible evaluation, testing, and evolution is important. If you look at the resources behind Docker (and related technology) such as Google with Kubernetes, Amazon Web Services support, and Microsoft’s recent announcements, it is clearly a trend to be embraced. 

With Helix Core

The benefits of Docker for creating Helix Core test environments are obvious.

We are migrating various test and demo scenarios to use Docker. What previously took multiple virtual machines can now be done with multiple containers. And there are major benefits:

  • Startup times of minutes become seconds.
  • The resource overhead of running multiple VMs on a single host is also significantly reduced. 

Get Started With Helix Core

Get started with Helix Core today — and test out Docker containers for yourself. You can try Helix Core for free for up to 5 users and 20 workspaces.

➡️ try Helix Core

 

Related Content:

Back to top