Let's say we're in an environment where we have a modern CI/CD pipeline for a number of containerized apps. We also have a number legacy apps which haven't been containerized yet.
I'm wondering how sound/unusual/crazy the following idea is: even for apps which don't run in containers in production, use container images and a container registry as a vehicle to deploy binary build artifacts.
Here's a very simple example to illustrate the idea: let's say we have a .NET app which consists of two projects. One that rarely changes and contains a large number of static assets (ChangesRarely
), and another small, lightweight one which changes often (ChangesOften
).
Now, let's say we're using the following Dockerfile
to build the app in a multi-stage build:
FROM mcr.microsoft.com/dotnet/sdk:3.1 AS builder
ADD src src
RUN dotnet publish -o buildOutput/ChangesRarely src/ChangesRarely
RUN dotnet publish -o buildOutput/ChangesOften src/ChangesOften
FROM alpine
COPY --from=builder buildOutput/ChangesRarely /buildOutput/ChangesRarely
COPY --from=builder buildOutput/ChangesOften /buildOutput/ChangesOften
Note that because of the two separate COPY
instructions, the resulting image will contain two separate layers. This will be important in just a second.
When our CI/CD build system (e.g. GitHub Actions) needs to create a new build, it'll basically run docker build -t myapp .
and push the resulting image to a container registry. So far, pretty standard.
Now let's say we want to deploy a new version to production. Again, "production" isn't some sort of container orchestrator (yet) - assume it's a set of plain old servers in a data center. So here's where the approach might become a tad unusual:
Each production server runs a Docker engine- but only to pull the container image and subsequently copy the build artifacts out of it, deploying them to their final destination (some local folder):
id=$(docker create myapp) # pulls image from container registry, if necessary
docker cp $id:/buildOutput - | tar zxf - # copy build artifacts
docker rm -v $id # destroy temp container
I've confirmed that this really works. But, why would you do that? Three main reasons:
The container registry acts as a unified store for all build artifacts (for containerized and non-containerized apps). No need to manage two different artifact stores.
Image layers which are identical across builds (such as the large
ChangesRarely
layer in the example above) only need to be stored once in the container registry, preserving storage spaceThey also will be cached by the production server's Docker engine, preserving network bandwidth and reducing deployment times.
How usual or unusual is this approach?
Any problems with the approach that I might be missing?