Fixing slow down speeds w/ curl in alpine docker images

isaacadams

Isaac Adams

Posted on November 21, 2019

Fixing slow down speeds w/ curl in alpine docker images

The problem

After playing around with using the jenkins:alpine base image and attempting to download a .war (60 MB) file using curl, I discovered that it was EXTREMELY slow. I am talking about the difference between it taking a minute and a half on my host machine and 15 mins during the docker image build.

FROM jenkins:alpine

ARG JENKINS_VERSION
ENV JENKINS_WAR="/usr/share/jenkins/jenkins.war"

USER root
RUN curl -o ${JENKINS_WAR} -L \
    https://updates.jenkins-ci.org/download/war/${JENKINS_VERSION}/jenkins.war
RUN chown jenkins:jenkins ${JENKINS_WAR}
USER jenkins
Enter fullscreen mode Exit fullscreen mode

Obviously, this is ridiculous and there had to be something wrong. After searching online, I found there was very little documentation on how to resolve this issue, so I started doing my own experimenting.

Overview

downloading .war of 60 MB took

  • minute and a half on host machine host machine
  • 15 min during docker alpine image build alpine slow

NOTICE

  • made some updates were made on 12.4.2019

What did NOT work 👎

Adding docker build ... options

I was unable to get any increase from adding in options to docker build ... such as ...

  • --network host : performs the commands using the host network
  • -m 1GB : allocates more memory to the image build

Fixing alpine DNS issues

I also read online about some DNS issues that alpine has and followed some of their instructions for fixing them. None of that helped increase download speeds.

Using the docker "ADD" command (12.4.2019)

Using ADD is easily the cleanest and most straightforward option. However, I found it was just as slow as using curl. See the secondary solution at the end of this article to see how I was able to still use the simplicity of ADD and while also getting an increase in speed.

FROM jenkins:alpine
...
ADD https://updates.jenkins-ci.org/download/war/${JENKINS_VERSION} ${JENKINS_WAR}
...

Enter fullscreen mode Exit fullscreen mode

Changing image base (some success)

I noticed that when switched out from an alpine based image, I was able to significantly increase my download speeds. However, it still wasn't as fast as my host machine.

Notice the change in "TAG" in first line the FROM jenkins:TAG from "alpine" to "latest". The "latest" tag does not use alpine.

FROM jenkins:latest

ARG JENKINS_VERSION
ENV JENKINS_WAR="/usr/share/jenkins/jenkins.war"

USER root
RUN curl -o ${JENKINS_WAR} -L \
    https://updates.jenkins-ci.org/download/war/${JENKINS_VERSION}/jenkins.war
RUN chown jenkins:jenkins ${JENKINS_WAR}
USER jenkins
Enter fullscreen mode Exit fullscreen mode

non alpine faster

Increasing curl limit rate (some success)

Using the alpine base image, I found that setting --limit-rate 1G as a curl ... option increased the download speed. I could have stopped at this point, but the download was still taking about 1-5 mins. It seemed rather unstable to me, so I kept experimenting.

FROM jenkins:alpine

ARG JENKINS_VERSION
ENV JENKINS_WAR="/usr/share/jenkins/jenkins.war"

USER root
RUN curl --limit-rate 1G -o ${JENKINS_WAR} -L \
    https://updates.jenkins-ci.org/download/war/${JENKINS_VERSION}/jenkins.war
RUN chown jenkins:jenkins ${JENKINS_WAR}
USER jenkins
Enter fullscreen mode Exit fullscreen mode

Alt Text

The solution 😄

I found that by combining switching the image base (from alpine to debian) and setting --limit-rate 1G curl option I was able to make the download happen in 2 seconds.

I still wanted to use alpine as my base image, so I changed the dockerfile to use multi-stage.

FROM debian:buster-slim as downloader

RUN apt update && apt install curl -y

USER root
ARG JENKINS_VERSION
WORKDIR /home/root

# running curl inside the debian image instead of alpine
RUN curl --limit-rate 1G -o jenkins.war -L \
    https://updates.jenkins-ci.org/download/war/${JENKINS_VERSION}/jenkins.war


FROM jenkins:alpine

ENV JENKINS_WAR="/usr/share/jenkins/jenkins.war"
# getting the downloaded .war file from the debian image
COPY --from=downloader /home/root/jenkins.war ${JENKINS_WAR}

USER root
RUN chown jenkins:jenkins ${JENKINS_WAR}
USER jenkins

Enter fullscreen mode Exit fullscreen mode

debian image fastest

Another better solution 🚀 (12.4.2019)

It suddenly hit me that the ADD or COPY docker commands must have the capability to use URLs. Once I confirmed that ADD can do this, I felt so dumb. When I first tried using ADD to download the jenkins.war file it was still very slow 😢

BUT, then I thought, "what about switching the base image and then using ADD?". And what do you know, it was FAST 😄 It took about 3 seconds to download. This is more simple because the code is easier to follow and it removes the need to run apt update and apt install curl. This results in a smaller image overall.

FROM debian:buster-slim as downloader

ARG JENKINS_VERSION
WORKDIR /home/root
ADD https://updates.jenkins-ci.org/download/war/${JENKINS_VERSION}/jenkins.war \
jenkins.war

FROM jenkins:alpine

ENV JENKINS_WAR="/usr/share/jenkins/jenkins.war"
COPY --from=downloader /home/root/jenkins.war ${JENKINS_WAR}

USER root
RUN chown jenkins:jenkins ${JENKINS_WAR}
Enter fullscreen mode Exit fullscreen mode
💖 💪 🙅 🚩
isaacadams
Isaac Adams

Posted on November 21, 2019

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related