Repository navigation
Description
EDIT: Still the case in April 2025.
Related:
Expected behavior
GHCR and DockerHub registries should be publishing the same image builds.
Actual behavior
# Different images:
docker run -it --rm -v /var/run/docker.sock:/var/run/docker.sock wagoodman/dive docker.io/drwetter/testssl.sh:3.2
docker run -it --rm -v /var/run/docker.sock:/var/run/docker.sock wagoodman/dive ghcr.io/testssl/testssl.sh:3.2Your DockerHub and GHCR publishing seems to be handled differently? You have a Github Actions workflow for the GHCR registry, but it's targeting the Dockerfile.git (Old Alpine) image in the 3.2 branch:
| file: Dockerfile.git |
testssl.sh/.github/workflows/docker-3.2.yml
Lines 61 to 63 in b21c5ee
| tags: | | |
| ghcr.io/${{ github.repository }}:${{ env.BUILD_VERSION }} | |
| ghcr.io/${{ github.repository }}:latest |
Line 3 in b21c5ee
| FROM alpine:3.17 |
DockerHub is apparently watching the repo and builds automatically (thus the Dockerfile used from each branch associated to a tag?): #2085 (comment)
This file was only added AFAIK for CI usage, where it builds differently by performing a git clone of the repo instead of using COPY:
Line 14 in b21c5ee
| && git clone --depth 1 --branch ${BUILD_VERSION} $URL /home/testssl \ |
Allowing via build ARG to control the repo and branch (ARCHIVE_URL doesn't appear to be used):
Lines 7 to 9 in b21c5ee
| ARG BUILD_VERSION | |
| ARG ARCHIVE_URL=https://github.com/drwetter/testssl.sh/archive/ | |
| ARG URL=https://github.com/drwetter/testssl.sh.git |
The CI itself is only using the build version:
| build-args: BUILD_VERSION |
There is rarely a need for this style of image building?
- Usually any fork of
testssl.shis going to also have theDockerfileassociated to it. - This would just be building with the source a remote of a repo + branch where you don't want to use the
Dockerfilein sync with that commit? - What advantage / need does it serve over a local
git cloneand building from theDockerfilein that repo?
IIRC, it was possibly used in the past to have the CI support building the different branches of this project. However the CI should be triggered and building with the correct branch source here?:
testssl.sh/.github/workflows/docker-3.2.yml
Lines 21 to 22 in b21c5ee
| - name: Source checkout | |
| uses: actions/checkout@v4 |
EDIT: You've been reluctant to remove it because of the possibility of someone else building from it. There is no other known consumer beyond the CI, I'd encourage dropping it until you have a valid reason to keep it (revert the removal and address the image changes required at that point).
I am aware of one user @jauderho that would need to update their workflow, should the file be dropped. Perhaps they can weigh in on if that'd be an issue for them.
Likewise you have for both 3.0 and 3.2 these branch triggers, both with scheduled cron jobs:
testssl.sh/.github/workflows/docker-3.2.yml
Lines 3 to 9 in b21c5ee
| on: | |
| push: | |
| branches: | |
| - 3.2 | |
| workflow_dispatch: | |
| schedule: | |
| - cron: "0 8 * * 1" |
testssl.sh/.github/workflows/docker-3.0.yml
Lines 3 to 9 in ece9447
| on: | |
| push: | |
| branches: | |
| - 3.0 | |
| workflow_dispatch: | |
| schedule: | |
| - cron: "0 8 * * 1" |
However scheduled workflows are only from the default branch (now 3.2): https://github.com/testssl/testssl.sh/actions/workflows/docker-3.2.yml
As you'll see no scheduled builds are in the 3.0 history for the past year: https://github.com/testssl/testssl.sh/actions/workflows/docker-3.0.yml
You could adapt the scheduled workflow of docker-mailserver, which references a workflow to run and the associated branch (@).
That lives on the default branch, and without providing a branch reference, will run the referenced workflow from that scheduled run workflows last commit (not what you want when referencing workflows to run that get updated), thus referencing the branch is important.
Activity
[-][BUG] GHCR registry is publishing `3.2` images with Alpine base[/-][+][FEATURE] GHCR registry should use `3.2` images with LEAP, not Alpine base[/+]drwetter commentedon Oct 13, 2023
IIRC I asked you when you refactored the Dockerfile whether you could do the same for the GCHR Dockerfile and your responded that you lacked time.
Don't know who's actually using the GCHR file and I can't recall atm the circumstances why it is like it is. Maybe @jauderho was involved.
If you believe it should be changed, you're welcome to make a proposal. It would be great to keep it short and concise.
polarathene commentedon Oct 15, 2023
I am open to contributing a PR to revise your Github Actions with the docker image workflows. It may not be "short and concise", but well intentioned and beneficial for maintenance. The technical reasoning is below.
I propose:
3.0(or any other branch that isn't the default). This workflow would have separate jobs defined to build the different versions (release branches) you want to support (similar to this example, although it's jobs are for a different purpose).@to work the way you'd expect.3.0/3.2tag without support for specific releases (which could be supported).:latesttag that points to your current default branch (3.2 presently, but you tend to adjust this as the version changes rather than anedgeor similar unreleased branch (typicallymain/masterordevelop)). It will adapt to your default branch changes implicitly, meeting the expectations of your users when no tag is specified?The above would drop the
Dockerfile.gitas I don't think it serves any real value for you to have and maintain. Users should just clone the repo + branch of interest and build theDockerfile.drwetter commentedon Apr 25, 2025
see https://github.com/testssl/testssl.sh/actions/runs/14668993333
opensuse/leap:15.6: no match for platform in manifest: not found
drwetter commentedon Apr 25, 2025
Looks like GHCR pulls from docker hub and the images opensuse is providing for 15.6 are here: https://hub.docker.com/layers/opensuse/leap/15.6/images/sha256-a5b038ad32138fe8600b978422290bae846b24f4fdbf6026eb0a4c89efa6f161 . So there is linux/amd64, linux/arm64, linux/ppc64le, linux/s390x but no linux/386, linux/arm/v7, linux/arm/v6
I have no clue about the usage of the usage of 386, arm/v7, arm/v6.
polarathene commentedon Apr 25, 2025
Yes the base image without a registry prefix will fallback to
docker.io(DockerHub) when using Docker Buildx. I don't think openSUSE has images on GHCR, but they do have their own registry that could probably be used if you preferred that over DockerHub.Shouldn't be an issue to leave as-is AFAIK.
The ARM v7 and v6 archs are legacy. I'd say the same about 386 (roughly x86 32-bit). I doubt that the
ppc64le+s390xtargets get used that much too?May be better to just publish the standard
amd64+arm64archs, and then wait upon users to open issues if there are any expecting images for the other platforms?drwetter commentedon Apr 26, 2025
🤷♂️ can't tell. I kind of like ancient hardware and people using it.
Alpine had issues (left is probably DNS, see other thread(s).
So either 1) somebody retests the edge cases in Alpine and we'll get a "go", then we could switch back to Alpine. My guts say we will run into problems 😃 and maybe it's not worth spending time for that.
would be picking Fedora instead -- you offered that a while back before . The only thing which concerns me that it needs care every 6-1 months. For opensuse leap I needed to make some changes as some binaries were removed(?) and others were in other packages.
Debian is an option because it's always an option :-) and they support almost every architecture. Image is larger though. Have you tried a multitstage image before, I can't remember?
This is just the Debian image, there's no socat or openssl in there:
Chisel is an option but if you say it's not that stable yet, I'd rather stay with a classical or multistage image. And: see also your comment EDIT: Actual image size reduction wasn't as big as I initially thought
jauderho commentedon Apr 26, 2025
[1] https://www.theregister.com/2023/05/16/alpine_linux_318/
[2] https://docs.docker.com/engine/install/
drwetter commentedon Apr 27, 2025
Off the top of my head I can't recall what the problems were (here) with docker and DNS. We had without docker DNS issues especially with NSS and I am glad that they are solved. Thus I am not tempted to roll that up again, unless one does extensive testing to convince me that all problems are gone.
Debian vs. Ubuntu: The number of architectures are pretty similar (https://github.com/docker-library/official-images#architectures-other-than-amd64). Also I doubt that this project needs always the latest and greatest binaries with one exception though: OpenSSL 3.5.0 would be great to have probably -- that's included in Debian Trixie, to be released sometime in June.
Both base images are bigger though, if @polarathene can squeeze the image with a multistage build, that probably would help.
Ok, personally I don't care much where people get the docker image from. I'd like to offer both though. Just for my information: Do you have numbers or did others also report that? As of now the account is the official image for this project is a payed one and if it's being throttled , that would be not fine.
jauderho commentedon Apr 28, 2025
I threw together a quick Dockerfile for Ubuntu yesterday. https://github.com/jauderho/dockerfiles/blob/main/testssl.sh/Dockerfile.ubuntu
Build command:
DOCKER_BUILDKIT=0 docker build -t testssl --build-arg "BUILD_VERSION=v3.2.0" -f Dockerfile.ubuntu .Image size
I'm open to suggestions on how to pare down the image from @polarathene or anyone else.
polarathene commentedon Apr 28, 2025
Verbose response incoming 😆
Platforms
My policy is not to release to archs that nobody has specifically requested to be supported. As you said you have no stats, for all you know it's a waste of resources (which we can shrug at since it's at no cost to us, but it's still a waste).
It's rather simple to drop platforms and then have a user chime in with "hey what happened to X? I need that" and you restore it 🤷♂ (it's editing one line for you AFAIK)
The appeal of someone using such maybe is neat, but if there were support issues that you can't reproduce and are likely due to their niche platform usage, is the platform actually going to receive support or is the time not justified to resolve it?
For projects I maintain, users must express interest by requesting the platform and there needs to be enough demand to warrant it vs them making a local build. ARMv7 was dropped with any remaining users directed to build the image themselves or establish a community image for that arch (didn't happen AFAIK), or spend <$50 to get a newer system (Last popular ARMv7 device I recall was I think was 2016 or older).
Fedora
You know you can upgrade the base image at whatever pace is comfortable for you right?
If you're already comfortable with other distros for the base image due to a slower release cadence and have no concerns about the older versions packaged... what difference would it be to use a release of Fedora for the same time frame?
Fedora EOL tends to be approx a year after release, so no more security / bugfix updates after that. As a maintainer for a Debian based image, the major upgrades are roughly 2 years apart, with a lot more changes to accommodate at once, this is less of a concern when the distro releases in a shorter cycle as it's spread out.
FWIW, you didn't have much concerns with Alpine did you and that released as often as Fedora, but has a 2 year EOL window instead.
Debian / Ubuntu
If you're referring to Debian with a similar size optimization to Leap and Fedora, the package manager doesn't offer that. I believe there's something called deboostrap, but I've not investigated it to compare.
docker-mailserver.I can't really assist with Ubuntu/Debian, other than via
chiselwhich is bound to Ubuntu release cycles (April/October) and has reduced package selection.chiselis great for static binary builds that only need core files / packages to run, but something like this project which is a shell script relying on various packages for commands to call may take longer to land slices ("package" support).Chisel
For reference (for anyone else curious about the prior chisel discussion).
Chisel is stable AFAIK, it's used by some official images like dotNET language and various Canonical images. I said it was fairly new (only hit
1.0.0a few months ago IIRC), that the UX could be improved given some more time to mature (I've opened various issues at their repo that you can filter for regarding that).For you to switch to
chisel, you are presently blocked until thissocatslice is added, or you maintain that yourself in the meantime. I'm not too familiar with their slice config (it's effectively config of what to retain from a package, stripping out any weight not deemed important), but the example I reference at that issue can probably be opened as a PR as-is and adjusted with reviewer feedback, since I did find that slice from a past PR that later didn't need it.Chisel examples
Here's what you can do with
chiselatm (but lackingsocatfunctionality):Dockerfile example
mkdir -p /usr/local/binwas necessary to add aschiseldoesn't provide that by default like openSUSE, Ubuntu and other actual distros do.dash_binsprovidesdashshell, it was only added for the/usr/bin/shsymlink, you could manually add that but for aRUNto work like above, you'd need to switch to the bash shell as default (forRUN) viaSHELL ["/bin/bash", "-c"]. Only 100KB difference in this case, so might as well keep it.passwd_binsprovidespasswdpackage foruseradd. You could use the currentDockerfileapproach I added for a lighter weight user creation (4MB lighter):Looking at what
chiselwithpasswd-base_dataslice would install, and Google's distroless (Debian), neither actually has an/etc/shadowso you could skip that. Personally I'd probably skip the non-root user too (could installtestsslfiles to/opt/testssl), but up to you.Once there is a
socatslice and officialchiselimage published, you could slim it down to just this (also assumeschiselembeds a CA bundle, otherwiseCOPYone prior toRUN):Dockerfile example
The usage of an earlier
RUNpresently is not space efficient withchisel(but is planned to be).This will produce the same image size as the prior example with
COPYfrom/root-fsof an earlier stage.Dropped
mkdir -p /usr/local/binas it is no longer needed due to that path being created viaRUN --mountfor chisel.The first
RUNhas no shell onFROM scratch, so uses the JSONRUNsyntax (a tad awkward vsCOPYfrom an earlier stage at/root-fs). It provides/usr/bin/sh -> /usr/bin/dashfor convenience with the nextRUN.You could alternatively temporarily mount Nushell (a shell self-contained into a single static linked binary) and use that to run the command.
Without setting
SHELLit'd look like this (treats thechiselcommand as a single string):Or with
SHELL(NOTE: The syntax is not like bash/sh once you go multi-line with HEREDOC):Didn't seem worth it.
Seems more competitive/simpler than Fedora or Leap variants I think?
DockerHub throttling
I've only heard about the recent change with DockerHub to throttle unpaid users.
You would not be throttled via a paid account, but anyone pulling your images from the registry that isn't paid will be throttled.
I have heard that since the change was made that they've relaxed it a bit. I've done a fair amount of image pulling today (free user), and not hit any rate limit issues AFAIK. It may only affect users that are deploying/updating a system with many images at once.
Alpine / musl quirks
That's good, but I'd still feel uncomfortable adopting Alpine personally 😓 If it works for you and what you do with it, awesome. I've lost too much time to Alpine / musl troubleshooting with the only motivator being slightly smaller usage on disk/network I/O.
curl/wget/nslookup/dig/etc, but I was unsuccessful)NXDOMAIN(eg public vs private DNS, where order queried may be important).A+AAAAqueries being sent out with musl when not necessary, with glibc this could be controlled via/etc/gai.conf. The other issue related to k8s discussed has been resolved IIRC, when there is a large number of hosts to resolve.I haven't gone over this or this, some of that may be outdated but the 2nd link shows a fair amount of differences (not DNS specific).
It's great that Alpine / musl has been resolving common pain points with using it, but I've been bitten enough by it that I'm wary to use it for anything serious (besides DNS, I've experienced performance degradation and also some software detecting "linux" and pulling pre-built binaries that dynamically link to glibc). I just prefer less headaches sticking with glibc personally over potentially saving a few MB 🤷♂
polarathene commentedon Apr 28, 2025
You can look into debootstrap like I briefly mentioned above, but I don't know how worthwhile it is.
There's some tooling like Slim or BLAFS if the project has full test coverage for functionality (I think these tools mostly pay attention to file-level access), and they'll strip out everything else which if done well would still be functional. I've not used either personally.
The chisel examples in my previous comment are competitive (but without
socat, incomplete):Current official images published:
docker.io=> openSUSE Leapghcr.io=> Alpine (Docker.git)So
chisel(with eventualsocat) should be roughly the size of openSUSE Leap, maybe a smidge smaller.drwetter commentedon Apr 29, 2025
@jauderho : 170MB is too large .
If @polarathene shares my concerns wrt alpine we should not use it. For the platforms: lets agree ro disagree. Problem solved 😃
Wrt the type of the remaining distros... let's stick to the facts:
The thing with socat/chisel, @polarathene : I am not sure I understand. Whatever a slice is: can't we just add (binary or package) it somehow? If the answer is no via apt it in another stage of the Dockerfile and later copy the binary? A short answer is also fine . 😃
polarathene commentedon Apr 30, 2025
What you request is possible in a few ways yes.
Skip to my next comment, it provides a single
Dockerfilethat meets your wishlist, bothsocat+ OpenSSL 3.5.0 presently need workarounds, but as those are resolved upstream you can drop them, or delay switching to chisel until then.Verbose response with full insights follows.
chiselis a tool that has a YAML "slice" config per package supported. It basically says what content to keep in a package and discard the rest. These slice configs are per Ubuntu release, presently 25.04 is not supported so there is a bit of a delay there too (reference:chiselrelease process FAQ).Custom slices workaround solution
Without an official
socatslice, you can add your own (like the one shown here), butchisellacks an overlay-like feature so you would need to git clone achisel-releasesbranch (eg Ubuntu 24.04), then add your custom slice and pointchiselto use that git repo instead (usually you would just use--release ubuntu-24.04and chisel would clone that branch itself behind scenes).Since the above example installs to
/root-fsfor a laterCOPY --link, instead of the bind mount, you could alternatively have an earlierCOPYbeforeRUNif you prefer. The bind mount is more useful if installing withchiselin aFROM scratchstage.So the it's 4 extra lines to the
Dockerfileto support, plus your repo needs to commit thesocat.yamlfile (main drawback), until someone PRs the socat slice and it gets added to the officialchisel-releasesrepo.Actually... since
socat.yamlisn't too big, you could optionally embed it into theDockerfile:Potentially, depends how you go about it.
There is no
aptavailable, consider it similar todnf/zypperability to make a minimal install via--installrootbut optimized at the expense of package selection.There is a slice for
dpkgwhich can be used to install a.debpackage AFAIK, but again that seems like a hassle?All those linked deps are supported by chisel, looks like with the slices already installed, we'd only need to add
libwrap0_libsslice.EDIT: I have shared the approach of copying a binary from another stage/distro later with OpenSSL 3.5, you can refer to that for how that'd work. Or if you have a DEB package, you could likewise install that via
dpkgI think (but you would need to install thedpkg_binsslice first).TL;DR:
OpenSSL 3.5.0 is a bit too new, may take a while to land to distros with release cycles.
Copy OpenSSL 3.5 from Debian Trixie into Chisel image
The
openssl_binsslice installs the OpenSSL binary + related config files, it'll also bring in the required libs it links via separate slices notablylibssl3t64.I suppose it's possible to
keep size down by removing the main openssl binary itself in the same(with the current approach using a separate prep stage that createsRUNand/root-fssize won't matter here we can justCOPY) copy over OpenSSL from another stage (Debian Trixie) that provides v3.5.0 🤔Earlier attempt with some troubleshooting towards solution
Nope, that did not go well 😓
Actually my mistake, this was due to Ubuntu 24.04 which shipped a much older OpenSSL (3.0), but we can see from the earlier error that there is still a dependency on 3.5.0 compatible
libcrypto.so.3, so this won't be possible to support unless we copy over that as well.Even Ubuntu 24.10 lacks OpenSSL 3.4 and we can't use Ubuntu 25.04 with Chisel just yet, so
libssl.so.3would need to be copied over as well.So let's give that a spin:
Success 🎉
drwetter commentedon Apr 30, 2025
Sounds excellent! 👍👍 What's the size of that thing?
(I have some comments to your comment but ... later. Need to get other stuff done first).
Thanks!
polarathene commentedon Apr 30, 2025
TL;DR:
Quick overview:
chiseldo not supportarm/v6(armel) arch for packages.chiselreleases only publishesarm(arm/v7/armhfI think), notarmelwhich might prevent native builds on that legacy platform, but that's rather moot given that the OpenSSL 3.5 workaroundarmelpackage from Debian is incompatible witharmhfinstalled packages fromchisel/ Ubuntu.chiselreleases also lacks a binary fori386, you'd need to either build that yourself or use the performance optimization to build each image variant without emulation.Reference - Future Goal
No workarounds:
openssl_bins(25.10?)socat_binsslice officially addedchiselimage published for supported archsi386+arm/v6archsReference - Full
Dockerfiles (workarounds)Before/After reference with all the details covered in prior comment vs this comment.
Earlier `Dockerfile` iteration (where the previous comment reached)
This was what I had in my prior comment, but the OpenSSL 3.5 workaround was specific to AMD64 / x86_64 arch. Building for non-native archs also was notably slower (presumably the case with existing setup in CI), but less verbose.
So this was quite the test of my skillset in pulling all this off 😓
Obviously it's far less appealing to adopt with the workarounds. May be best to wait until later this year.
The earlier iteration above could be used (without the OpenSSL 3.5 workaround), which leaves the only benefit below as faster image builds (for platforms that don't match the build host) but I doubt that matters much for this project vs simplicity? 😝 (seeing that you've been fine without such an optimization so far)
If helpful here is the above improved
Dockerfilebut with only one of the workarounds applied:Cross-platform OpenSSL 3.5 workaround (without native build speed optimization)
NOTE: This
Dockerfilecannot buildi386arch due tochisellacking a release for it.This one is needed for
i386support:Native build speed optimization (without OpenSSL 3.5 workaround)
Supporting other Architectures
Ubuntu package archives with supported architectures between these two repos:
amd64+i386)arm64+armhf+ppc64el+riscv64+s390x)Debian doesn't have this split.
If needing to add packages for foreign architectures with Ubuntu you will need to update
/etc/apt/sources.list.d/ubuntu.sourcesby appending this (add a similarArchitecturesconstraint to existing repos fori386):NOTE: ⚠ There is no
linux/arm/v6(armel) arch for the ubuntu images, onlylinux/arm/v7(armhf). Debian has support forarm/v6/armel.The definition for
armhfandarmelvaries:arm/v7=>armhf+arm/v6=>armelarm/v7=>armhf(Debian) vsarm/v6=>armhf(Raspbian) (refers toarm/v5asarmelarmv7+armhf(arm/v6?)Some state there is a bit of compatibility between v6 and v7 via
armhf, provided no v7 specific features are used? 🤷♂There's also this Alpine discussion from May 2020 about dropping armv6, but noting Pi Zero W (armv6 based) is supported until Jan 2026.
Regardless, you can see it's more of a maintenance hassle when it's not implicit. Since this is a CI specific concern and for your project presumably only relevant with publishing releases, then optimizing speed of the building for platforms not native to the build host arch is unlikely a concern for you to worry about 😅
The OpenSSL workaround however would require this until October-ish for Ubuntu 25.10, when you should be able to remove it.
OpenSSL 3.5 workaround support
The OpenSSL workaround is a bit problematic when spanning multiple platforms due to arch specific filesystem differences for where dependencies are stored.
The arch used will install OpenSSL libs into
/usr/lib/with an arch specific directory:amd64=>x86_64-linux-gnuarm64=>aarch64-linux-gnuarmhf(Docker target:arm/v7) =>arm-linux-gnueabihfarmel(Docker target:arm/v6) =>arm-linux-gnueabi(EDIT: Not supported on Ubuntu/Chisel, only Debian)i386=> (Docker target:386) =>i386-linux-gnuppc64el(Docker target:ppc64le) =>powerpc64le-linux-gnuTIP: When building each platfrom, if it's running native/emulated:
aptorchiselviadpkg --print-architecture. Similar to how you might useuname -morTARGETARCH+TARGETVARIANT.FROM --platform, or inferred) viadpkg --print-foreign-architectures. Those will be any other archs you've added viadpkg --add-architecture.There's two common conventions for architecture names, but sometimes it varies between projects a little bit too 😕 (here's a helpful resource on the topic) We would need to map these arch to the toolchain value like shown above, or provide them via an ARG per platform (tad awkward).
Easiest way to workaround that within a
Dockerfileis probably going to be settingENVwith a bunch of platform specific stages. Naming each stage variant with a suffix that we can refer to via the appropriateTARGETARCHvalue (list of the mappings here).Then update the two OpenSSL library
COPYto reference theTARGET_TRIPLEENV and adjust the stage to use the arch specific variants:chisel-${TARGETARCH}${TARGETVARIANT}is where Docker will work backwards in stages of what to build, so it can get a bit confusing at a glance with how it infers the the right arch (especially when paired with the performance changes in the next section).NOTE:
TARGETVARIANTwill be blank for most platform targets, but forarm/v6andarm/v7it's thev6/v7parts. Similarly there isamd64/v4variant and lower to match the differentx86-64-v4optimized builds some projects build (Debian doesn't have optimized package repos for such, but some other distros do like CachyOS).UPDATE: I've verified that
arm/v6(armel) is not compatible with thearmhfpackage arch with Ubuntu /chisel, it'd fail to run thearmelOpenSSL 3.5 from Debian that links to a different interpreter:So that rules out that platform with
chisel..Reference - Image platforms + variants published
BTW regarding image arch support on DockerHub for official images, there is this official document. Probably why you may find inconsistencies with the images published to GHCR (which aren't managed indirectly like with DockerHub review process + policies for official/endorsed images).
That or I misunderstood it 😅 (I think the only reason the arch's listed there may not be supported by such images is if they lack package manager support, such as Ubuntu lacking
linux/arm/v6).EDIT: Slight mixup also on my end. I was thinking of DockerHub vs GHCR, but the issue from #2748 was actually the switch between the two Dockerfile moving from Alpine to openSUSE Leap 😅
openSUSE Leap 15.6 was published to DockerHub without
linux/arm(armhf/arm/v7) variant.-Currently the
latesttag points all archs to 15.6 platform images, but still retains thelinux/armplatform pointed to Leap 15.5 😬armhfor similar at the equivalent 15.5 repo, so not quite sure where that arch was sourced from in their published 15.5 image.Meanwhile
debian:12-slimand other image tags don't have alinux/armorlinux/arm/v6, there's onlylinux/arm/v5andlinux/arm/v7(also alinux/arm64/v8but AFAIK that's equivalent tolinux/arm64, except v8 will exist as aTARGETVARIANT with the long form, I guess the short-form selects the lowest variant🤷♂). When I pull--platform linux/arm/v6or--platform linux/armand inspect that image it's thelinux/arm/v5image. Perhaps armv5 is compatible with armv6 🤔Tip - Performance with chisel
EDIT: I somehow forgot about image layer caching with CI 😂 Ah well, I'll keep this here since the discussion thread is full of insights for any interested readers.
When building an image for non-native targets (compared to the Docker build host), these will use virtualization/emulation and depending on operations in
RUNcan be much slower to perform.On a budget VPS instance these two examples stood out where ARM64 is emulated via QEMU:
RUN chisel cut --release ...=> 65s (AMD64) vs 277s (ARM64)RUN apt-get -qq update && apt-get -qq install openssl=> 12s (AMD64) vs 170s (ARM64)Concurrent image builds can be faster than sequential, it's what you have the CI performing:
https://github.com/testssl/testssl.sh/blob/3a9746ccc5714d9b151d942a61652ad9fa8b6cd3/.github/workflows/docker-3.2.yml#L56C22-L56C95
UPDATE:
full set of platforms you currently support(except forarm/v6) all within 260s (--no-cachewas used, 206s withouti386) on that same build host (Vultr Fedora 42 with 1vCPU and 1GB RAM + zram swap). While the concurrent image builds for platforms (linux/amd64,linux/arm64,linux/arm/v7,linux/ppc64le) via emulation (QEMU) instead took 1,260s (21 minutes). The low spec resources probably ramp those times up a bit 😓 (you also have CI cache leveraged, making most of this benefit irrelevant)chiselbinary available is missing legacy archs, at least withi386and possibly one ofarm/v6/arm/v7(or they might both be supported byarm?). So this is another benefit of only pulling a single arch ofchiselto build images for all other platforms.You'd probably find the two arm images the🤷♂Dockerfilebuilds might even be effectively the same in content? So whileTARGETARCHwill providearmfor selecting thechiselbinary, and with assistancearmhffor packages, we're effectively building the same image twice and tagging it for both of these legacy platformsWe can run the native build host arch instead when the operations we need to run do not require emulating an architecture to prepare the image, such as cross-platform builds or in this case a package manager like
chiselthat supports installing for non-native archs via--archoption.We need to provide
chisel cut --archwith the appropriate Ubuntu arch, which luckily many of these align with theTARGETARCHENV that BuildKit sets implicitly as anARG, except for legacyarm/v6+arm/v7, where we'd need to instead providearmhf.We would need to map the appropriate
--archvalue fromTARGETARCHENV, at least for legacy platforms you still want to supporti386+armv6+armv7:EDIT: Turns out
armhfisarm/v7only. I haven't tried running that asarm/v6(armel) properly without OpenSSL 3.5armelcopied from from Debian. Assuming incompatible.Then in the
RUNthat callschisel cutwe just add--arch $(cat /target-arch.txt)and add an extraCOPYprior to thatRUN.Since
chiselisn't an official image yet, we'd actually want that--platformoption set on our temporarychiselstage instead. And since we want to run the build host arch, we should swap theTARGETARCHarg forBUILDARCH.EDIT: This makes
i386supported 👍 (that legacy arch is not published on GH releases)I believe a similar approach can be used for
aptto get openssl in Debian (same arch names, bit broader in support, but noriscv64- maybe with Debian Trixie). Since they have the same arch convention as Ubuntu, we can use the sametarget-arch.txtwithaptas we dochisel:polarathene commentedon Apr 30, 2025
55MB (with OpenSSL 3.5 added)
Same as before mostly, for some reason
docker image lsis showing 77MB, butdivereports 45MB + 8MB which is similar todocker image history:So 55MB?
A little larger than the openSUSE Leap 15.6 image. No advantage to switching beyond broader arch support. Without OpenSSL 3.5 + libs copied over, it is 1.7MB smaller.
Regarding performance of musl base image (Alpine) vs glibc base image (openSUSE Leap), several runs invoked:
Alpine remains slower. These were compared back in early 2023 when discussing what to replace Alpine with.
Additional packages (DNS)
I just noticed I missed some packages related to DNS.
bind9-dnsutils_bins(also provides thelibidn2-0_libsslice), which brings inlibidn+dig(instead ofdrillwhich lacks a slice, openSUSE Leap provideddrillvia theldnspackage).diguntil switching over to onlydrill, and with the Alpine base it added inlibidnfordrillto support IDN lookups. So that is one drawback if another DNS client can't be used for that? FWIWdrill/ldnsis in maintenance mode.Dockerfilewhen it was Alpine based, I provide a good overview of each package requirement. Presumablybusybox_binscould be dropped iftar(viatar_tarslice) andxxd(no slice yet) were available. Not sure if busybox is otherwise providing anything elsetestssl.shwould need that coreutils doesn't 🤷♂busyboxadds symlinks not only forhexdump, but alsoxxd(optional, but apparently performant). For DNS it also addsnslookup+hostname.The
curl_binsslice also brings in thelibidn2-0_libsslice, so thebind9-dnsutils_bins(adds 47MB weight) slice is only necessary if needingdig, not space efficient. Bringingdigin like I showed with OpenSSL would not be reasonable (far too large of a list), butdrillis one extra librarylibldns+ symlink, so should be doable (only +480KB weight), can probably just use a custom slice for that actually (EDIT: I've created one here, it could be inlined withCOPYlike thesocatslice example I provided).Likewise here is an
xxdslice. I haven't opened an issue upstream to request it as there's barely any size bonus from replacingbusybox_binsslice withxxd_bins(23KB) +tar_tar(432KB), asbusyboxbinary itself is only about 847KB:xxd slice
COPY <<HEREDOC /chisel-releases/slices/xxd.yaml package: xxd essential: - xxd_copyright slices: bins: essential: - libc6_libs contents: /usr/bin/xxd: copyright: contents: /usr/share/doc/xxd/copyright: HEREDOCxxdmight be optional, buthexdump(48KB frombsdmainutils, no slice available) apparently isn't 😓 so busybox remains.testssl.sh/Dockerfile
Line 19 in 3a9746c
testssl.sh/Dockerfile.git
Line 13 in 3a9746c
For reference:
hexdump+xxd)Dockerfile#2305 (comment) (Alpine / Debian package history and individual package purposes, related)Dockerfile.git)Tip -
DockerfilevsDockerfile.gitYou could effectively have a
Dockerfile.gitreplacement by swapping:COPY --chown=testssl:testssl . /home/testssl/With:
ADDis a usefulDockerfileinstruction mostly similar toCOPY, but in this case it allows us to replace the manualgit cloneinvoked in aRUN:testssl.sh/Dockerfile.git
Line 14 in 3a9746c
That's effectively the same as doing a
git clone, although it'd be a bit lighter withADD:ADDwith git repos is to exclude the.git/directory (has a weight of 6.7MB when I built it, 9.3MB in current GHCR image).gitpackage installed to support this either 👍 (8MB less)A caveat with cloning a repo in a
Dockerfile(regardless ofgit cloneorADD ...approach) is that it won't be part of the Docker build context (which filters the local host filesystem via.dockerignore), that's only relevant when usingADD/COPYwith the local host filesystem.Apart from differences between distros, this is really the only difference between your
DockerfilevsDockerfile.gitsupport. So instead of a distinction by using git or not, you could have both distros supporting both approaches if you like within their respectiveDockerfile.To do so there would be a final two stages like this:
The last stage would be the default (since I'm talking about
Dockerfile.gitI've made itdist-git, butdist-localwould usually make more sense to prefer as default). The other can be opt-in via CLI option like--target dist-local.Alpine 60MB => 28MB
The current Alpine image (
Dockerfile.git) is 60MB:COPYfor parity to openSUSE Leap (Dockerfile).ADD/COPYyou can also remove thegitpackage to remove another 8MB from each build.The current 60MB image actually has two binaries from git (6.5MB) that have since been removed (note: you should really consider squash merges of PRs btw, commit history is messy to navigate):
openssl.Linux.i686(32-bit support)openssl.Linux.x86_64.krbAnd as noted the
.git/dir was slightly larger in the current GHCR Alpine image published than when I build it locally now. Hence approx 9MB delta to disregard (effectively down to 51MB-ish). Removing.git/(6.7MB) and thegitpackage (8MB) is 14MB-ish (the layer size measurements fromdiveinspection aren't that precise below MB there is some rounding going on). That'd bring us down to around the 38MB measurementdiveshows (presumably closer to 37.5MB).The
apk updateadds 2MB, only because it's run without--no-cache(kinda redundant to not store the repo updates though),apk add --no-cacheimplies--update(akaapk update). So that can be dropped too.Lack of
.dockerignoredifference (7-8MB)That leaves the remaining weight difference from the git clone itself vs the benefit of build context excludes via
.dockerignore:COPYbuild.Removing the excess from a git clone
Eventually
ADDwill stabilize--excludewhich could presumably filter that extra weight out.For now you could use
git cloneinRUNas the image currently does, butrmthe two OpenSSL bins, followed by removing thegitpackage, all within the sameRUNif the verbosity is worth it:Notes:
USER testsslwas set in an earlier stage, it needs to switch back to root to add the git package (to keep it out ofdist-localweight).cd /home/testsslis only needed if it's not already the PWD from an earlierWORKDIR.${GIT_BRANCH?branch-required}is a little worse in UX forRUNvs withADD.Error message with `RUN`
Actual error is in the middle of all that output.
Error message with `ADD`
Error message with `RUN` + `test -n`
The current check is done in
RUNon the ENV existing, not too friendly UX:On the topic of better error support, this can be helpful:
The
-uwould trigger a failure when an ENV/variable is referenced that is unset like: