patterndockerMinor
Using Docker images as vehicles for binary deployment artifacts
Viewed 0 times
dockerartifactsvehiclesbinaryforusingimagesdeployment
Problem
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 (
Now, let's say we're using the following
Note that because of the two separate
When our CI/CD build system (e.g. GitHub Actions) needs to create a new build, it'll basically run
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 contai
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/ChangesOftenNote 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 contai
Solution
I've seen it done before but wouldn't call it common. There are other artifact servers, and many git repositories have the concept of a release with artifacts that makes more sense.
I suspect Docker Hub is one of many artifact servers to introduce rate limits and other usage caps, so if you do this, make sure you control (or pay for) the registry server. Otherwise the risk is you'll exceed limits and lose access to your artifacts.
If you only want to copy binaries, then I'd skip the base image and use
It's also possible to bypass the docker engine entirely and pull the artifacts from the registry server directly to the filesystem. I have a regclient project that ships a
Note that the sha's are unique and persistent, so if that hash is unchanged there's no need to pull the binary again. And the above example has a few extra layers since the command is expected to run in the image as a non-root user (/etc/passwd, ca-certificates, and a home directory). For a non-running image, that could be a single layer. E.g.:
I suspect Docker Hub is one of many artifact servers to introduce rate limits and other usage caps, so if you do this, make sure you control (or pay for) the registry server. Otherwise the risk is you'll exceed limits and lose access to your artifacts.
If you only want to copy binaries, then I'd skip the base image and use
FROM scratch.It's also possible to bypass the docker engine entirely and pull the artifacts from the registry server directly to the filesystem. I have a regclient project that ships a
regctl command with regctl image manifest and regctl layer pull commands. E.g.:$ regctl image manifest regclient/regctl
{
"schemaVersion": 2,
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"config": {
"mediaType": "application/vnd.docker.container.image.v1+json",
"size": 3019,
"digest": "sha256:e3abac7c7ce78aaa5efddb5abedd54f8ed3077d9d5b03b5a66ecf9f4c3502454"
},
"layers": [
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 930,
"digest": "sha256:41437cd6a6e3d3098329474c62ccc5bd01fcf6b41bf35f0e8c89db96110b23ac"
},
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 122413,
"digest": "sha256:69d6afda22ccf4f223c016bfd3a108fe0a1ddd15c72978bd238b19201e0e1973"
},
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 161,
"digest": "sha256:57dd9736a25ab0b55d9d364dc20ee0946a844a8ac72d7f986ef902826f933e89"
},
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 3963283,
"digest": "sha256:282c5a3b4b6c8bf0b7038204919bbfc26c8b120cd87f4a1f573c12c808774c1c"
}
]
}
$ regctl layer pull regclient/regctl sha256:282c5a3b4b6c8bf0b7038204919bbfc26c8b120cd87f4a1f573c12c808774c1c | tar -tzvf -
-rwxr-xr-x root/root 10235904 2020-11-05 20:52 regctlNote that the sha's are unique and persistent, so if that hash is unchanged there's no need to pull the binary again. And the above example has a few extra layers since the command is expected to run in the image as a non-root user (/etc/passwd, ca-certificates, and a home directory). For a non-running image, that could be a single layer. E.g.:
# change image to your scratch-based source
image=regclient/regctl
store=/tmp
sha=$(regctl image manifest $image --format '{{ (index .Layers 0).Digest}}')
if [ ! -d "$store/$sha" ]; then
mkdir -p "$store/$sha"
regctl layer pull $image $sha | tar -xzvf - -C "$store/$sha"
fi
echo "result in $store/$sha"Code Snippets
$ regctl image manifest regclient/regctl
{
"schemaVersion": 2,
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"config": {
"mediaType": "application/vnd.docker.container.image.v1+json",
"size": 3019,
"digest": "sha256:e3abac7c7ce78aaa5efddb5abedd54f8ed3077d9d5b03b5a66ecf9f4c3502454"
},
"layers": [
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 930,
"digest": "sha256:41437cd6a6e3d3098329474c62ccc5bd01fcf6b41bf35f0e8c89db96110b23ac"
},
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 122413,
"digest": "sha256:69d6afda22ccf4f223c016bfd3a108fe0a1ddd15c72978bd238b19201e0e1973"
},
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 161,
"digest": "sha256:57dd9736a25ab0b55d9d364dc20ee0946a844a8ac72d7f986ef902826f933e89"
},
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 3963283,
"digest": "sha256:282c5a3b4b6c8bf0b7038204919bbfc26c8b120cd87f4a1f573c12c808774c1c"
}
]
}
$ regctl layer pull regclient/regctl sha256:282c5a3b4b6c8bf0b7038204919bbfc26c8b120cd87f4a1f573c12c808774c1c | tar -tzvf -
-rwxr-xr-x root/root 10235904 2020-11-05 20:52 regctl# change image to your scratch-based source
image=regclient/regctl
store=/tmp
sha=$(regctl image manifest $image --format '{{ (index .Layers 0).Digest}}')
if [ ! -d "$store/$sha" ]; then
mkdir -p "$store/$sha"
regctl layer pull $image $sha | tar -xzvf - -C "$store/$sha"
fi
echo "result in $store/$sha"Context
StackExchange DevOps Q#12768, answer score: 2
Revisions (0)
No revisions yet.