Restores state from previous runs

Sometimes it’s not sufficient to just cache directories (CACHE), it’d be best to cache complex state such as running processes or mounted files.

Webapp.io provides this powerful but dangerous caching mechanism via RUN REPEATABLE. It’s particularly useful for complicated declarative cluster state like docker, docker-compose and kubectl.

It’s recommended to combine RUN REPEATABLE with multi-stage builds for large performance improvements.

RUN REPEATABLE for Docker

Layerfile
# install docker

COPY . .
RUN REPEATABLE docker build -t myimage
RUN docker run -d -p 8080:8080 myimage

In this Layerfile, the docker cache from previous runs will be reused because RUN REPEATABLE uses the cache from after the last time this step ran.

If you had three pipelines at 9am, 10am, and 11am, the effective steps run would look like this:

  • 9am pipeline: cp (9am files) . && docker build -t myimage
  • 10am pipeline: cp -a (9am files) . && docker build -t myimage && cp -a (10am files) . && docker build -t myimage
  • 11am pipeline: cp -a (9am files) . && docker build -t myimage && cp -a (10am files) . && docker build -t myimage && cp -a (11am files) . && docker build -t myimage

In particular, docker would see that it had been used multiple times, and would be able to re-use the docker cache from previous invocations to greatly improve build speed.

RUN REPEATABLE for docker-compose

Layerfile
FROM vm/ubuntu:18.04

# install the latest version of Docker, as in the official Docker installation tutorial.
RUN apt-get update && \
    apt-get install ca-certificates curl gnupg lsb-release && \
    sudo mkdir -p /etc/apt/keyrings && \
    curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg && \
    echo \
    "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" |\
    sudo tee /etc/apt/sources.list.d/docker.list > /dev/null && \
    apt-get update && \
    apt-get install docker-ce docker-ce-cli containerd.io

RUN curl -L "https://github.com/docker/compose/releases/download/1.27.4/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose && \
    chmod +x /usr/local/bin/docker-compose

COPY . .

RUN REPEATABLE docker-compose up -d --build --force-recreate --remove-orphans && sleep 5

EXPOSE WEBSITE localhost:8000

In this Layerfile, all of these things are reused from the moment immediately after the previous invocation:

  • The docker layer cache (e.g., pulled images)
  • Any created networks or volumes

RUN REPEATABLE for kubernetes (kubectl, k8s, k3s)

Layerfile
FROM vm/ubuntu:18.04

# install the latest version of Docker, as in the official Docker installation tutorial.
RUN apt-get update && \
    apt-get install ca-certificates curl gnupg lsb-release && \
    sudo mkdir -p /etc/apt/keyrings && \
    curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg && \
    echo \
    "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" |\
    sudo tee /etc/apt/sources.list.d/docker.list > /dev/null && \
    apt-get update && \
    apt-get install docker-ce docker-ce-cli containerd.io

# install & start k3s
RUN curl -sfL https://get.k3s.io | sh -s - --docker

# this script might use helm, kompose, jsonnet, or any other manifest handling logic
RUN REPEATABLE ./build-images-and-manifests.sh && k3s kubectl apply -f dist/manifests --prune

EXPOSE WEBSITE localhost:8000

RUN REPEATABLE gives 50-95% speedups here.

In this Layerfile, we’d set up a kubernetes cluster for you and then snapshot it after you’d started all of your services.

The next time you push, kubernetes’ own declarative logic would figure out which pods to delete/restart given the manifests created. This means that if you had 20 microservices and only changed one, it’d be the only one that is re-deployed with this Layerfile.