Skip to content

Instantly share code, notes, and snippets.

@miminar
Created May 6, 2016 19:50
Show Gist options
  • Save miminar/0952e2d8df4d29ea1e8af5b7ce1e6e20 to your computer and use it in GitHub Desktop.
Save miminar/0952e2d8df4d29ea1e8af5b7ce1e6e20 to your computer and use it in GitHub Desktop.

Reproducer of a slow push due to image complexity

Prerequisities

  • Deploy 2 VMs with RHEL7.
  • Install docker v1.8.2-10.el7 on both.
  • Choose a machine hosting upstream docker registry. Let's call it RegistryNode.
  • Let's call the other Client.
  • Remember the IP or hostname of the RegistryNode

Setup

  • Enable tcp port 5000 on RegistryNode.
  • Copy setup-registry-host.sh to RegistryNode and run it.
  • Copy setup-client-host.sh to Client and run it.
  • Copy generate-load.sh to Client and run it.

Test

Now the interesting part. We've got two images of similar size:

  1. $REGISTRY_NODE:5000/test/packed
  2. $REGISTRY_NODE:5000/test/unpacked

The former has 3 layers, each containing just one file - a tarball. The latter has also 3 layers, each containing unpacked tarball of the first image.

Push without load

Compare the times of running following command without any load:

time docker push "$REGISTRY_NODE:5000/test/packed"
time docker push "$REGISTRY_NODE:5000/test/unpacked"

Time of the latter will be slightly bigger due to higher complexity of the layers.

# Important - re-deploy the registry on *RegistryNode* before re-runing or continuing with other test
docker stop test-registry
./setup-regisitry-host.sh

Push with load

Generate some load on the Client:

./generate-load.sh

Compare the times again:

time docker push "$REGISTRY_NODE:5000/test/packed"
time docker push "$REGISTRY_NODE:5000/test/unpacked"

This time the second push will be a lot slower.

#!/bin/bash
set -euo pipefail
CORES=`grep '^processor\s*:' /proc/cpuinfo | wc -l`
for i in `seq $CORES`; do
dd if=/dev/zero of=/dev/null &
done
trap 'kill $(jobs -p)' EXIT
wait %%
#!/bin/bash
#
# Run as root.
# Requires docker to be installed and configured.
# This script installs upstream docker registry and runs it.
set -euo pipefail
IFS=$'\n\t'
USAGE="Usage: $0 <registry-host-name> <registry-port>"
if [[ $# -lt 2 ]]; then
printf "%s\n" "$USAGE"
exit 1
fi
IMAGES=(fedora centos ubuntu)
HOSTNAME="$1"
PORT="$2"
set -x
for img in "${IMAGES[@]}"; do
docker pull docker.io/$img
done
tmp=`mktemp -d`
function finish {
rm -rf "$tmp"
}
trap finish EXIT
pushd $tmp
mkdir packed unpacked
echo "FROM scratch" >unpacked/Dockerfile
echo "FROM scratch" >packed/Dockerfile
for img in "${IMAGES[@]}"; do
mkdir "packed/$img" "unpacked/$img"
cid=`docker run -d $img /bin/true`
docker export -o "packed/${img}.tar" $cid
tar -xf "packed/${img}.tar" -C "unpacked/$img"
echo "ADD $img /$img" >>unpacked/Dockerfile
echo "COPY $img.tar /$img.tar" >>packed/Dockerfile
done
for dir in packed unpacked; do
docker inspect "$HOSTNAME:$PORT/test/$dir" >/dev/null && continue
docker build -t $HOSTNAME:$PORT/test/$dir $dir
done
popd
set +x
echo "Built images:"
docker images | egrep "$HOSTNAME:$PORT/test/(un)?packed"
echo
set -x
docker history "$HOSTNAME:$PORT/test/unpacked"
docker history "$HOSTNAME:$PORT/test/packed"
#!/bin/bash
# Run as root.
# Requires docker to be installed and configured.
# This script installs upstream docker registry and runs it.
set -euo pipefail
docker pull docker.io/registry:2.2.1
docker run -it --name test-registry --rm docker.io/registry:2.2.1 &
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment