Self-contained docker build with ARM64 publishing - #3962

Merged
Gedochao merged 8 commits into
VirtusLab:mainfrom
keynmol:self-contained-docker-build
Dec 22, 2025
Merged

Self-contained docker build with ARM64 publishing#3962
Gedochao merged 8 commits into
VirtusLab:mainfrom
keynmol:self-contained-docker-build

Conversation

@keynmol

@keynmolkeynmol commented Nov 18, 2025

Copy link
Copy Markdown
Contributor

Fixes#2132

At the moment, the scala-cli docker image is built using a combination of mill tasks, scripts, and dockerfiles that require externally built binary. What's more, it's only built for x86.

With ARM64 runners on GHA being GA, I propose a simplification - a self-contained multi-stage dockerfile, with a custom Github Workflow that merges the images into a single manifest, meaning that docker will pull the correct image no matter the target platform.

Manifest merging and pushing is a complicated step, and Docker have been amending their docs with the example, which is what this workflow is based on.

I've been using this setup in multiple apps, e.g. Mimalyzer.


There are some aspects of the build I don't really understand – static, mostly static images, customisation for Linux x86, etc.

This proposal attempts to do the simplest possible thing, so that building a docker image is just docker build . -t VirtusLab/scala-cli.

Currently, it only publishes to ghcr.io to test out the workflows without disturbing the main image on docker hub. But additional publishing steps are easily added, of course

Comment threadDockerfile

@GedochaoGedochao left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tgodzik@zielinsky can you take a look as well? I think it'd be good to have another pair of eyes on this (or two)

Comment thread.github/workflows/publish-docker.yml Outdated
Comment thread.github/workflows/publish-docker.yml Outdated
Comment thread.github/workflows/publish-docker.yml Outdated
Comment threadDockerfile
@Gedochao

Copy link
Copy Markdown
Contributor

There are some aspects of the build I don't really understand – static, mostly static images, customisation for Linux x86, etc.

Static and mostly static images are in the understanding of GraalVM, as per this doc: https://www.graalvm.org/21.3/reference-manual/native-image/StaticImages/index.html
The way they're built is based on the mill-native-image plugin: https://github.com/alexarchambault/mill-native-image

(...) customisation for Linux x86 (...)

What particular customisation for Linux x86 did you mean?

(...) etc.

Shoot away, I'll try to answer, or at least direct you in the direction of an answer.

What's there in this area was initially coded by @alexarchambault (who's also the author of mill-native-image). While I've tinkered with this here and there, most of it has been lying untouched for a long, long time, and I'm not all that familiar with it either.

@tgodziktgodzik left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know much about this, I only built basic docker images. Overall look ok as long as it work 😅

@zielinskyzielinsky left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few comments from me 😅

Comment thread.github/workflows/publish-docker.yml Outdated
Comment thread.github/workflows/publish-docker.yml Outdated
Comment thread.github/workflows/publish-docker.yml Outdated
Comment thread.github/workflows/publish-docker.yml Outdated
Comment thread.github/workflows/publish-docker.yml Outdated
Comment thread.github/workflows/publish-docker.yml Outdated
Comment thread.github/workflows/publish-docker.yml Outdated
@keynmol

Copy link
Copy Markdown
ContributorAuthor

@Gedochao

What particular customisation for Linux x86 did you mean?

This line threw me off

https://github.com/keynmol/scala-cli/blob/93079619648e0b475f874ee2676387b488d7a637/project/settings/package.mill.scala#L406

@Gedochao

Copy link
Copy Markdown
Contributor

Just to make sure.

We currently have the following images, which are updated with each Scala CLI release:

@keynmol your intention is to create a third one, yes?
smth like virtuslab/scala-cli-platform-native?

@Gedochao

Copy link
Copy Markdown
Contributor

Also, how can we safely test this?

@keynmol

keynmol commented Nov 21, 2025

Copy link
Copy Markdown
ContributorAuthor

Here's my plan:

  1. Merge this workflow as is, make sure it publishes a working ghcr.io/virtuslab/scala-cli image (similar to existing DockerHub virtuslab/scala-cli)
  2. Modify the workflow in a separate PR to build the slim image in the same way (similar to existing DockerHub virtuslab/scala-cli-slim)
  3. Add DockerHub publishing steps to both images
  4. Remove old docker publishing logic

Up to step 3, the existing docker images on DockerHub are safe and won't be touched, as we only publish to ghcr.io, using it as our testing area.

Steps 1-3 can be done in separate PRs as they won't affect existing dockerhub publishing steps.

In the end, we should have virtuslab/scala-cli and virtuslab/scala-cli-slim that have a manifest merging two platforms, so users automatically get the right image (see screenshot)
CleanShot 2025-11-21 at 10 05 06@2x

@Gedochao

Copy link
Copy Markdown
Contributor

Okay... sounds reasonable.
Let's get the CI green and do it one step at a time.

@Gedochao

Gedochao commented Nov 24, 2025

Copy link
Copy Markdown
Contributor

The CI is green.
@keynmol the workflow is still on Ubuntu 22.04, while the other workflows already rely on 24.04 (I left comments earlier).
Otherwise, we seem to be good to merge here (might want to rebase on main while you're at it)

@keynmol

keynmol commented Nov 24, 2025

Copy link
Copy Markdown
ContributorAuthor

I have responded to the Ubuntu version comment: #3962 (comment)

Actually scratch that, in this instance it won't have any effect, I will update

@GedochaoGedochao left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM
@keynmol ready to merge?

@Gedochao

Copy link
Copy Markdown
Contributor

@zielinsky I will wait for your okay before clicking merge.

@keynmol

Copy link
Copy Markdown
ContributorAuthor

I think so, no doubt it will require more iterations when the work flow actually runs :)

@zielinskyzielinsky left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One question from me before approval.

Comment thread.github/workflows/publish-docker.yml Outdated

@zielinskyzielinsky left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM for now, let's test it!

@Gedochao
Gedochao merged commit 5c37f88 into VirtusLab:mainDec 22, 2025
104 of 106 checks passed
@keynmol

Copy link
Copy Markdown
ContributorAuthor

Workflow succeeded, and the image is published correctly, containing two platform-specific images: https://github.com/VirtusLab/scala-cli/actions/runs/20428482272/job/58694886877#step:7:1

But I think the visibility of packages needs to be changed in repository and package settings

@keynmol
keynmol deleted the self-contained-docker-build branch March 19, 2026 09:09
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Publish Arm64 Docker image

4 participants

@keynmol@Gedochao@tgodzik@zielinsky
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Self-contained docker build with ARM64 publishing - #3962

Merged
Gedochao merged 8 commits into
VirtusLab:mainfrom
keynmol:self-contained-docker-build
Dec 22, 2025
Merged

Self-contained docker build with ARM64 publishing#3962
Gedochao merged 8 commits into
VirtusLab:mainfrom
keynmol:self-contained-docker-build

Conversation

@keynmol

@keynmolkeynmol commented Nov 18, 2025

Copy link
Copy Markdown
Contributor

Fixes#2132

At the moment, the scala-cli docker image is built using a combination of mill tasks, scripts, and dockerfiles that require externally built binary. What's more, it's only built for x86.

With ARM64 runners on GHA being GA, I propose a simplification - a self-contained multi-stage dockerfile, with a custom Github Workflow that merges the images into a single manifest, meaning that docker will pull the correct image no matter the target platform.

Manifest merging and pushing is a complicated step, and Docker have been amending their docs with the example, which is what this workflow is based on.

I've been using this setup in multiple apps, e.g. Mimalyzer.


There are some aspects of the build I don't really understand – static, mostly static images, customisation for Linux x86, etc.

This proposal attempts to do the simplest possible thing, so that building a docker image is just docker build . -t VirtusLab/scala-cli.

Currently, it only publishes to ghcr.io to test out the workflows without disturbing the main image on docker hub. But additional publishing steps are easily added, of course

Comment threadDockerfile

@GedochaoGedochao left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tgodzik@zielinsky can you take a look as well? I think it'd be good to have another pair of eyes on this (or two)

Comment thread.github/workflows/publish-docker.yml Outdated
Comment thread.github/workflows/publish-docker.yml Outdated
Comment thread.github/workflows/publish-docker.yml Outdated
Comment threadDockerfile
@Gedochao

Copy link
Copy Markdown
Contributor

There are some aspects of the build I don't really understand – static, mostly static images, customisation for Linux x86, etc.

Static and mostly static images are in the understanding of GraalVM, as per this doc: https://www.graalvm.org/21.3/reference-manual/native-image/StaticImages/index.html
The way they're built is based on the mill-native-image plugin: https://github.com/alexarchambault/mill-native-image

(...) customisation for Linux x86 (...)

What particular customisation for Linux x86 did you mean?

(...) etc.

Shoot away, I'll try to answer, or at least direct you in the direction of an answer.

What's there in this area was initially coded by @alexarchambault (who's also the author of mill-native-image). While I've tinkered with this here and there, most of it has been lying untouched for a long, long time, and I'm not all that familiar with it either.

@tgodziktgodzik left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know much about this, I only built basic docker images. Overall look ok as long as it work 😅

@zielinskyzielinsky left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few comments from me 😅

Comment thread.github/workflows/publish-docker.yml Outdated
Comment thread.github/workflows/publish-docker.yml Outdated
Comment thread.github/workflows/publish-docker.yml Outdated
Comment thread.github/workflows/publish-docker.yml Outdated
Comment thread.github/workflows/publish-docker.yml Outdated
Comment thread.github/workflows/publish-docker.yml Outdated
Comment thread.github/workflows/publish-docker.yml Outdated
@keynmol

Copy link
Copy Markdown
ContributorAuthor

@Gedochao

What particular customisation for Linux x86 did you mean?

This line threw me off

https://github.com/keynmol/scala-cli/blob/93079619648e0b475f874ee2676387b488d7a637/project/settings/package.mill.scala#L406

@Gedochao

Copy link
Copy Markdown
Contributor

Just to make sure.

We currently have the following images, which are updated with each Scala CLI release:

@keynmol your intention is to create a third one, yes?
smth like virtuslab/scala-cli-platform-native?

@Gedochao

Copy link
Copy Markdown
Contributor

Also, how can we safely test this?

@keynmol

keynmol commented Nov 21, 2025

Copy link
Copy Markdown
ContributorAuthor

Here's my plan:

  1. Merge this workflow as is, make sure it publishes a working ghcr.io/virtuslab/scala-cli image (similar to existing DockerHub virtuslab/scala-cli)
  2. Modify the workflow in a separate PR to build the slim image in the same way (similar to existing DockerHub virtuslab/scala-cli-slim)
  3. Add DockerHub publishing steps to both images
  4. Remove old docker publishing logic

Up to step 3, the existing docker images on DockerHub are safe and won't be touched, as we only publish to ghcr.io, using it as our testing area.

Steps 1-3 can be done in separate PRs as they won't affect existing dockerhub publishing steps.

In the end, we should have virtuslab/scala-cli and virtuslab/scala-cli-slim that have a manifest merging two platforms, so users automatically get the right image (see screenshot)
CleanShot 2025-11-21 at 10 05 06@2x

@Gedochao

Copy link
Copy Markdown
Contributor

Okay... sounds reasonable.
Let's get the CI green and do it one step at a time.

@Gedochao

Gedochao commented Nov 24, 2025

Copy link
Copy Markdown
Contributor

The CI is green.
@keynmol the workflow is still on Ubuntu 22.04, while the other workflows already rely on 24.04 (I left comments earlier).
Otherwise, we seem to be good to merge here (might want to rebase on main while you're at it)

@keynmol

keynmol commented Nov 24, 2025

Copy link
Copy Markdown
ContributorAuthor

I have responded to the Ubuntu version comment: #3962 (comment)

Actually scratch that, in this instance it won't have any effect, I will update

@GedochaoGedochao left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM
@keynmol ready to merge?

@Gedochao

Copy link
Copy Markdown
Contributor

@zielinsky I will wait for your okay before clicking merge.

@keynmol

Copy link
Copy Markdown
ContributorAuthor

I think so, no doubt it will require more iterations when the work flow actually runs :)

@zielinskyzielinsky left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One question from me before approval.

Comment thread.github/workflows/publish-docker.yml Outdated

@zielinskyzielinsky left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM for now, let's test it!

@Gedochao
Gedochao merged commit 5c37f88 into VirtusLab:mainDec 22, 2025
104 of 106 checks passed
@keynmol

Copy link
Copy Markdown
ContributorAuthor

Workflow succeeded, and the image is published correctly, containing two platform-specific images: https://github.com/VirtusLab/scala-cli/actions/runs/20428482272/job/58694886877#step:7:1

But I think the visibility of packages needs to be changed in repository and package settings

@keynmol
keynmol deleted the self-contained-docker-build branch March 19, 2026 09:09
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Publish Arm64 Docker image

4 participants

@keynmol@Gedochao@tgodzik@zielinsky
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Self-contained docker build with ARM64 publishing - #3962

Merged
Gedochao merged 8 commits into
VirtusLab:mainfrom
keynmol:self-contained-docker-build
Dec 22, 2025
Merged

Self-contained docker build with ARM64 publishing#3962
Gedochao merged 8 commits into
VirtusLab:mainfrom
keynmol:self-contained-docker-build

Conversation

@keynmol

@keynmolkeynmol commented Nov 18, 2025

Copy link
Copy Markdown
Contributor

Fixes#2132

At the moment, the scala-cli docker image is built using a combination of mill tasks, scripts, and dockerfiles that require externally built binary. What's more, it's only built for x86.

With ARM64 runners on GHA being GA, I propose a simplification - a self-contained multi-stage dockerfile, with a custom Github Workflow that merges the images into a single manifest, meaning that docker will pull the correct image no matter the target platform.

Manifest merging and pushing is a complicated step, and Docker have been amending their docs with the example, which is what this workflow is based on.

I've been using this setup in multiple apps, e.g. Mimalyzer.


There are some aspects of the build I don't really understand – static, mostly static images, customisation for Linux x86, etc.

This proposal attempts to do the simplest possible thing, so that building a docker image is just docker build . -t VirtusLab/scala-cli.

Currently, it only publishes to ghcr.io to test out the workflows without disturbing the main image on docker hub. But additional publishing steps are easily added, of course

Comment threadDockerfile

@GedochaoGedochao left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tgodzik@zielinsky can you take a look as well? I think it'd be good to have another pair of eyes on this (or two)

Comment thread.github/workflows/publish-docker.yml Outdated
Comment thread.github/workflows/publish-docker.yml Outdated
Comment thread.github/workflows/publish-docker.yml Outdated
Comment threadDockerfile
@Gedochao

Copy link
Copy Markdown
Contributor

There are some aspects of the build I don't really understand – static, mostly static images, customisation for Linux x86, etc.

Static and mostly static images are in the understanding of GraalVM, as per this doc: https://www.graalvm.org/21.3/reference-manual/native-image/StaticImages/index.html
The way they're built is based on the mill-native-image plugin: https://github.com/alexarchambault/mill-native-image

(...) customisation for Linux x86 (...)

What particular customisation for Linux x86 did you mean?

(...) etc.

Shoot away, I'll try to answer, or at least direct you in the direction of an answer.

What's there in this area was initially coded by @alexarchambault (who's also the author of mill-native-image). While I've tinkered with this here and there, most of it has been lying untouched for a long, long time, and I'm not all that familiar with it either.

@tgodziktgodzik left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know much about this, I only built basic docker images. Overall look ok as long as it work 😅

@zielinskyzielinsky left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few comments from me 😅

Comment thread.github/workflows/publish-docker.yml Outdated
Comment thread.github/workflows/publish-docker.yml Outdated
Comment thread.github/workflows/publish-docker.yml Outdated
Comment thread.github/workflows/publish-docker.yml Outdated
Comment thread.github/workflows/publish-docker.yml Outdated
Comment thread.github/workflows/publish-docker.yml Outdated
Comment thread.github/workflows/publish-docker.yml Outdated
@keynmol

Copy link
Copy Markdown
ContributorAuthor

@Gedochao

What particular customisation for Linux x86 did you mean?

This line threw me off

https://github.com/keynmol/scala-cli/blob/93079619648e0b475f874ee2676387b488d7a637/project/settings/package.mill.scala#L406

@Gedochao

Copy link
Copy Markdown
Contributor

Just to make sure.

We currently have the following images, which are updated with each Scala CLI release:

@keynmol your intention is to create a third one, yes?
smth like virtuslab/scala-cli-platform-native?

@Gedochao

Copy link
Copy Markdown
Contributor

Also, how can we safely test this?

@keynmol

keynmol commented Nov 21, 2025

Copy link
Copy Markdown
ContributorAuthor

Here's my plan:

  1. Merge this workflow as is, make sure it publishes a working ghcr.io/virtuslab/scala-cli image (similar to existing DockerHub virtuslab/scala-cli)
  2. Modify the workflow in a separate PR to build the slim image in the same way (similar to existing DockerHub virtuslab/scala-cli-slim)
  3. Add DockerHub publishing steps to both images
  4. Remove old docker publishing logic

Up to step 3, the existing docker images on DockerHub are safe and won't be touched, as we only publish to ghcr.io, using it as our testing area.

Steps 1-3 can be done in separate PRs as they won't affect existing dockerhub publishing steps.

In the end, we should have virtuslab/scala-cli and virtuslab/scala-cli-slim that have a manifest merging two platforms, so users automatically get the right image (see screenshot)
CleanShot 2025-11-21 at 10 05 06@2x

@Gedochao

Copy link
Copy Markdown
Contributor

Okay... sounds reasonable.
Let's get the CI green and do it one step at a time.

@Gedochao

Gedochao commented Nov 24, 2025

Copy link
Copy Markdown
Contributor

The CI is green.
@keynmol the workflow is still on Ubuntu 22.04, while the other workflows already rely on 24.04 (I left comments earlier).
Otherwise, we seem to be good to merge here (might want to rebase on main while you're at it)

@keynmol

keynmol commented Nov 24, 2025

Copy link
Copy Markdown
ContributorAuthor

I have responded to the Ubuntu version comment: #3962 (comment)

Actually scratch that, in this instance it won't have any effect, I will update

@GedochaoGedochao left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM
@keynmol ready to merge?

@Gedochao

Copy link
Copy Markdown
Contributor

@zielinsky I will wait for your okay before clicking merge.

@keynmol

Copy link
Copy Markdown
ContributorAuthor

I think so, no doubt it will require more iterations when the work flow actually runs :)

@zielinskyzielinsky left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One question from me before approval.

Comment thread.github/workflows/publish-docker.yml Outdated

@zielinskyzielinsky left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM for now, let's test it!

@Gedochao
Gedochao merged commit 5c37f88 into VirtusLab:mainDec 22, 2025
104 of 106 checks passed
@keynmol

Copy link
Copy Markdown
ContributorAuthor

Workflow succeeded, and the image is published correctly, containing two platform-specific images: https://github.com/VirtusLab/scala-cli/actions/runs/20428482272/job/58694886877#step:7:1

But I think the visibility of packages needs to be changed in repository and package settings

@keynmol
keynmol deleted the self-contained-docker-build branch March 19, 2026 09:09
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Publish Arm64 Docker image

4 participants

@keynmol@Gedochao@tgodzik@zielinsky
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Self-contained docker build with ARM64 publishing - #3962

Merged
Gedochao merged 8 commits into
VirtusLab:mainfrom
keynmol:self-contained-docker-build
Dec 22, 2025
Merged

Self-contained docker build with ARM64 publishing#3962
Gedochao merged 8 commits into
VirtusLab:mainfrom
keynmol:self-contained-docker-build

Conversation

@keynmol

@keynmolkeynmol commented Nov 18, 2025

Copy link
Copy Markdown
Contributor

Fixes#2132

At the moment, the scala-cli docker image is built using a combination of mill tasks, scripts, and dockerfiles that require externally built binary. What's more, it's only built for x86.

With ARM64 runners on GHA being GA, I propose a simplification - a self-contained multi-stage dockerfile, with a custom Github Workflow that merges the images into a single manifest, meaning that docker will pull the correct image no matter the target platform.

Manifest merging and pushing is a complicated step, and Docker have been amending their docs with the example, which is what this workflow is based on.

I've been using this setup in multiple apps, e.g. Mimalyzer.


There are some aspects of the build I don't really understand – static, mostly static images, customisation for Linux x86, etc.

This proposal attempts to do the simplest possible thing, so that building a docker image is just docker build . -t VirtusLab/scala-cli.

Currently, it only publishes to ghcr.io to test out the workflows without disturbing the main image on docker hub. But additional publishing steps are easily added, of course

Comment threadDockerfile

@GedochaoGedochao left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tgodzik@zielinsky can you take a look as well? I think it'd be good to have another pair of eyes on this (or two)

Comment thread.github/workflows/publish-docker.yml Outdated
Comment thread.github/workflows/publish-docker.yml Outdated
Comment thread.github/workflows/publish-docker.yml Outdated
Comment threadDockerfile
@Gedochao

Copy link
Copy Markdown
Contributor

There are some aspects of the build I don't really understand – static, mostly static images, customisation for Linux x86, etc.

Static and mostly static images are in the understanding of GraalVM, as per this doc: https://www.graalvm.org/21.3/reference-manual/native-image/StaticImages/index.html
The way they're built is based on the mill-native-image plugin: https://github.com/alexarchambault/mill-native-image

(...) customisation for Linux x86 (...)

What particular customisation for Linux x86 did you mean?

(...) etc.

Shoot away, I'll try to answer, or at least direct you in the direction of an answer.

What's there in this area was initially coded by @alexarchambault (who's also the author of mill-native-image). While I've tinkered with this here and there, most of it has been lying untouched for a long, long time, and I'm not all that familiar with it either.

@tgodziktgodzik left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know much about this, I only built basic docker images. Overall look ok as long as it work 😅

@zielinskyzielinsky left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few comments from me 😅

Comment thread.github/workflows/publish-docker.yml Outdated
Comment thread.github/workflows/publish-docker.yml Outdated
Comment thread.github/workflows/publish-docker.yml Outdated
Comment thread.github/workflows/publish-docker.yml Outdated
Comment thread.github/workflows/publish-docker.yml Outdated
Comment thread.github/workflows/publish-docker.yml Outdated
Comment thread.github/workflows/publish-docker.yml Outdated
@keynmol

Copy link
Copy Markdown
ContributorAuthor

@Gedochao

What particular customisation for Linux x86 did you mean?

This line threw me off

https://github.com/keynmol/scala-cli/blob/93079619648e0b475f874ee2676387b488d7a637/project/settings/package.mill.scala#L406

@Gedochao

Copy link
Copy Markdown
Contributor

Just to make sure.

We currently have the following images, which are updated with each Scala CLI release:

@keynmol your intention is to create a third one, yes?
smth like virtuslab/scala-cli-platform-native?

@Gedochao

Copy link
Copy Markdown
Contributor

Also, how can we safely test this?

@keynmol

keynmol commented Nov 21, 2025

Copy link
Copy Markdown
ContributorAuthor

Here's my plan:

  1. Merge this workflow as is, make sure it publishes a working ghcr.io/virtuslab/scala-cli image (similar to existing DockerHub virtuslab/scala-cli)
  2. Modify the workflow in a separate PR to build the slim image in the same way (similar to existing DockerHub virtuslab/scala-cli-slim)
  3. Add DockerHub publishing steps to both images
  4. Remove old docker publishing logic

Up to step 3, the existing docker images on DockerHub are safe and won't be touched, as we only publish to ghcr.io, using it as our testing area.

Steps 1-3 can be done in separate PRs as they won't affect existing dockerhub publishing steps.

In the end, we should have virtuslab/scala-cli and virtuslab/scala-cli-slim that have a manifest merging two platforms, so users automatically get the right image (see screenshot)
CleanShot 2025-11-21 at 10 05 06@2x

@Gedochao

Copy link
Copy Markdown
Contributor

Okay... sounds reasonable.
Let's get the CI green and do it one step at a time.

@Gedochao

Gedochao commented Nov 24, 2025

Copy link
Copy Markdown
Contributor

The CI is green.
@keynmol the workflow is still on Ubuntu 22.04, while the other workflows already rely on 24.04 (I left comments earlier).
Otherwise, we seem to be good to merge here (might want to rebase on main while you're at it)

@keynmol

keynmol commented Nov 24, 2025

Copy link
Copy Markdown
ContributorAuthor

I have responded to the Ubuntu version comment: #3962 (comment)

Actually scratch that, in this instance it won't have any effect, I will update

@GedochaoGedochao left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM
@keynmol ready to merge?

@Gedochao

Copy link
Copy Markdown
Contributor

@zielinsky I will wait for your okay before clicking merge.

@keynmol

Copy link
Copy Markdown
ContributorAuthor

I think so, no doubt it will require more iterations when the work flow actually runs :)

@zielinskyzielinsky left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One question from me before approval.

Comment thread.github/workflows/publish-docker.yml Outdated

@zielinskyzielinsky left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM for now, let's test it!

@Gedochao
Gedochao merged commit 5c37f88 into VirtusLab:mainDec 22, 2025
104 of 106 checks passed
@keynmol

Copy link
Copy Markdown
ContributorAuthor

Workflow succeeded, and the image is published correctly, containing two platform-specific images: https://github.com/VirtusLab/scala-cli/actions/runs/20428482272/job/58694886877#step:7:1

But I think the visibility of packages needs to be changed in repository and package settings

@keynmol
keynmol deleted the self-contained-docker-build branch March 19, 2026 09:09
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Publish Arm64 Docker image

4 participants

@keynmol@Gedochao@tgodzik@zielinsky
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Self-contained docker build with ARM64 publishing - #3962

Merged
Gedochao merged 8 commits into
VirtusLab:mainfrom
keynmol:self-contained-docker-build
Dec 22, 2025
Merged

Self-contained docker build with ARM64 publishing#3962
Gedochao merged 8 commits into
VirtusLab:mainfrom
keynmol:self-contained-docker-build

Conversation

@keynmol

@keynmolkeynmol commented Nov 18, 2025

Copy link
Copy Markdown
Contributor

Fixes#2132

At the moment, the scala-cli docker image is built using a combination of mill tasks, scripts, and dockerfiles that require externally built binary. What's more, it's only built for x86.

With ARM64 runners on GHA being GA, I propose a simplification - a self-contained multi-stage dockerfile, with a custom Github Workflow that merges the images into a single manifest, meaning that docker will pull the correct image no matter the target platform.

Manifest merging and pushing is a complicated step, and Docker have been amending their docs with the example, which is what this workflow is based on.

I've been using this setup in multiple apps, e.g. Mimalyzer.


There are some aspects of the build I don't really understand – static, mostly static images, customisation for Linux x86, etc.

This proposal attempts to do the simplest possible thing, so that building a docker image is just docker build . -t VirtusLab/scala-cli.

Currently, it only publishes to ghcr.io to test out the workflows without disturbing the main image on docker hub. But additional publishing steps are easily added, of course

Comment threadDockerfile

@GedochaoGedochao left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tgodzik@zielinsky can you take a look as well? I think it'd be good to have another pair of eyes on this (or two)

Comment thread.github/workflows/publish-docker.yml Outdated
Comment thread.github/workflows/publish-docker.yml Outdated
Comment thread.github/workflows/publish-docker.yml Outdated
Comment threadDockerfile
@Gedochao

Copy link
Copy Markdown
Contributor

There are some aspects of the build I don't really understand – static, mostly static images, customisation for Linux x86, etc.

Static and mostly static images are in the understanding of GraalVM, as per this doc: https://www.graalvm.org/21.3/reference-manual/native-image/StaticImages/index.html
The way they're built is based on the mill-native-image plugin: https://github.com/alexarchambault/mill-native-image

(...) customisation for Linux x86 (...)

What particular customisation for Linux x86 did you mean?

(...) etc.

Shoot away, I'll try to answer, or at least direct you in the direction of an answer.

What's there in this area was initially coded by @alexarchambault (who's also the author of mill-native-image). While I've tinkered with this here and there, most of it has been lying untouched for a long, long time, and I'm not all that familiar with it either.

@tgodziktgodzik left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know much about this, I only built basic docker images. Overall look ok as long as it work 😅

@zielinskyzielinsky left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few comments from me 😅

Comment thread.github/workflows/publish-docker.yml Outdated
Comment thread.github/workflows/publish-docker.yml Outdated
Comment thread.github/workflows/publish-docker.yml Outdated
Comment thread.github/workflows/publish-docker.yml Outdated
Comment thread.github/workflows/publish-docker.yml Outdated
Comment thread.github/workflows/publish-docker.yml Outdated
Comment thread.github/workflows/publish-docker.yml Outdated
@keynmol

Copy link
Copy Markdown
ContributorAuthor

@Gedochao

What particular customisation for Linux x86 did you mean?

This line threw me off

https://github.com/keynmol/scala-cli/blob/93079619648e0b475f874ee2676387b488d7a637/project/settings/package.mill.scala#L406

@Gedochao

Copy link
Copy Markdown
Contributor

Just to make sure.

We currently have the following images, which are updated with each Scala CLI release:

@keynmol your intention is to create a third one, yes?
smth like virtuslab/scala-cli-platform-native?

@Gedochao

Copy link
Copy Markdown
Contributor

Also, how can we safely test this?

@keynmol

keynmol commented Nov 21, 2025

Copy link
Copy Markdown
ContributorAuthor

Here's my plan:

  1. Merge this workflow as is, make sure it publishes a working ghcr.io/virtuslab/scala-cli image (similar to existing DockerHub virtuslab/scala-cli)
  2. Modify the workflow in a separate PR to build the slim image in the same way (similar to existing DockerHub virtuslab/scala-cli-slim)
  3. Add DockerHub publishing steps to both images
  4. Remove old docker publishing logic

Up to step 3, the existing docker images on DockerHub are safe and won't be touched, as we only publish to ghcr.io, using it as our testing area.

Steps 1-3 can be done in separate PRs as they won't affect existing dockerhub publishing steps.

In the end, we should have virtuslab/scala-cli and virtuslab/scala-cli-slim that have a manifest merging two platforms, so users automatically get the right image (see screenshot)
CleanShot 2025-11-21 at 10 05 06@2x

@Gedochao

Copy link
Copy Markdown
Contributor

Okay... sounds reasonable.
Let's get the CI green and do it one step at a time.

@Gedochao

Gedochao commented Nov 24, 2025

Copy link
Copy Markdown
Contributor

The CI is green.
@keynmol the workflow is still on Ubuntu 22.04, while the other workflows already rely on 24.04 (I left comments earlier).
Otherwise, we seem to be good to merge here (might want to rebase on main while you're at it)

@keynmol

keynmol commented Nov 24, 2025

Copy link
Copy Markdown
ContributorAuthor

I have responded to the Ubuntu version comment: #3962 (comment)

Actually scratch that, in this instance it won't have any effect, I will update

@GedochaoGedochao left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM
@keynmol ready to merge?

@Gedochao

Copy link
Copy Markdown
Contributor

@zielinsky I will wait for your okay before clicking merge.

@keynmol

Copy link
Copy Markdown
ContributorAuthor

I think so, no doubt it will require more iterations when the work flow actually runs :)

@zielinskyzielinsky left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One question from me before approval.

Comment thread.github/workflows/publish-docker.yml Outdated

@zielinskyzielinsky left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM for now, let's test it!

@Gedochao
Gedochao merged commit 5c37f88 into VirtusLab:mainDec 22, 2025
104 of 106 checks passed
@keynmol

Copy link
Copy Markdown
ContributorAuthor

Workflow succeeded, and the image is published correctly, containing two platform-specific images: https://github.com/VirtusLab/scala-cli/actions/runs/20428482272/job/58694886877#step:7:1

But I think the visibility of packages needs to be changed in repository and package settings

@keynmol
keynmol deleted the self-contained-docker-build branch March 19, 2026 09:09
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Publish Arm64 Docker image

4 participants

@keynmol@Gedochao@tgodzik@zielinsky
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Self-contained docker build with ARM64 publishing - #3962

Merged
Gedochao merged 8 commits into
VirtusLab:mainfrom
keynmol:self-contained-docker-build
Dec 22, 2025
Merged

Self-contained docker build with ARM64 publishing#3962
Gedochao merged 8 commits into
VirtusLab:mainfrom
keynmol:self-contained-docker-build

Conversation

@keynmol

@keynmolkeynmol commented Nov 18, 2025

Copy link
Copy Markdown
Contributor

Fixes#2132

At the moment, the scala-cli docker image is built using a combination of mill tasks, scripts, and dockerfiles that require externally built binary. What's more, it's only built for x86.

With ARM64 runners on GHA being GA, I propose a simplification - a self-contained multi-stage dockerfile, with a custom Github Workflow that merges the images into a single manifest, meaning that docker will pull the correct image no matter the target platform.

Manifest merging and pushing is a complicated step, and Docker have been amending their docs with the example, which is what this workflow is based on.

I've been using this setup in multiple apps, e.g. Mimalyzer.


There are some aspects of the build I don't really understand – static, mostly static images, customisation for Linux x86, etc.

This proposal attempts to do the simplest possible thing, so that building a docker image is just docker build . -t VirtusLab/scala-cli.

Currently, it only publishes to ghcr.io to test out the workflows without disturbing the main image on docker hub. But additional publishing steps are easily added, of course

Comment threadDockerfile

@GedochaoGedochao left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tgodzik@zielinsky can you take a look as well? I think it'd be good to have another pair of eyes on this (or two)

Comment thread.github/workflows/publish-docker.yml Outdated
Comment thread.github/workflows/publish-docker.yml Outdated
Comment thread.github/workflows/publish-docker.yml Outdated
Comment threadDockerfile
@Gedochao

Copy link
Copy Markdown
Contributor

There are some aspects of the build I don't really understand – static, mostly static images, customisation for Linux x86, etc.

Static and mostly static images are in the understanding of GraalVM, as per this doc: https://www.graalvm.org/21.3/reference-manual/native-image/StaticImages/index.html
The way they're built is based on the mill-native-image plugin: https://github.com/alexarchambault/mill-native-image

(...) customisation for Linux x86 (...)

What particular customisation for Linux x86 did you mean?

(...) etc.

Shoot away, I'll try to answer, or at least direct you in the direction of an answer.

What's there in this area was initially coded by @alexarchambault (who's also the author of mill-native-image). While I've tinkered with this here and there, most of it has been lying untouched for a long, long time, and I'm not all that familiar with it either.

@tgodziktgodzik left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know much about this, I only built basic docker images. Overall look ok as long as it work 😅

@zielinskyzielinsky left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few comments from me 😅

Comment thread.github/workflows/publish-docker.yml Outdated
Comment thread.github/workflows/publish-docker.yml Outdated
Comment thread.github/workflows/publish-docker.yml Outdated
Comment thread.github/workflows/publish-docker.yml Outdated
Comment thread.github/workflows/publish-docker.yml Outdated
Comment thread.github/workflows/publish-docker.yml Outdated
Comment thread.github/workflows/publish-docker.yml Outdated
@keynmol

Copy link
Copy Markdown
ContributorAuthor

@Gedochao

What particular customisation for Linux x86 did you mean?

This line threw me off

https://github.com/keynmol/scala-cli/blob/93079619648e0b475f874ee2676387b488d7a637/project/settings/package.mill.scala#L406

@Gedochao

Copy link
Copy Markdown
Contributor

Just to make sure.

We currently have the following images, which are updated with each Scala CLI release:

@keynmol your intention is to create a third one, yes?
smth like virtuslab/scala-cli-platform-native?

@Gedochao

Copy link
Copy Markdown
Contributor

Also, how can we safely test this?

@keynmol

keynmol commented Nov 21, 2025

Copy link
Copy Markdown
ContributorAuthor

Here's my plan:

  1. Merge this workflow as is, make sure it publishes a working ghcr.io/virtuslab/scala-cli image (similar to existing DockerHub virtuslab/scala-cli)
  2. Modify the workflow in a separate PR to build the slim image in the same way (similar to existing DockerHub virtuslab/scala-cli-slim)
  3. Add DockerHub publishing steps to both images
  4. Remove old docker publishing logic

Up to step 3, the existing docker images on DockerHub are safe and won't be touched, as we only publish to ghcr.io, using it as our testing area.

Steps 1-3 can be done in separate PRs as they won't affect existing dockerhub publishing steps.

In the end, we should have virtuslab/scala-cli and virtuslab/scala-cli-slim that have a manifest merging two platforms, so users automatically get the right image (see screenshot)
CleanShot 2025-11-21 at 10 05 06@2x

@Gedochao

Copy link
Copy Markdown
Contributor

Okay... sounds reasonable.
Let's get the CI green and do it one step at a time.

@Gedochao

Gedochao commented Nov 24, 2025

Copy link
Copy Markdown
Contributor

The CI is green.
@keynmol the workflow is still on Ubuntu 22.04, while the other workflows already rely on 24.04 (I left comments earlier).
Otherwise, we seem to be good to merge here (might want to rebase on main while you're at it)

@keynmol

keynmol commented Nov 24, 2025

Copy link
Copy Markdown
ContributorAuthor

I have responded to the Ubuntu version comment: #3962 (comment)

Actually scratch that, in this instance it won't have any effect, I will update

@GedochaoGedochao left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM
@keynmol ready to merge?

@Gedochao

Copy link
Copy Markdown
Contributor

@zielinsky I will wait for your okay before clicking merge.

@keynmol

Copy link
Copy Markdown
ContributorAuthor

I think so, no doubt it will require more iterations when the work flow actually runs :)

@zielinskyzielinsky left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One question from me before approval.

Comment thread.github/workflows/publish-docker.yml Outdated

@zielinskyzielinsky left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM for now, let's test it!

@Gedochao
Gedochao merged commit 5c37f88 into VirtusLab:mainDec 22, 2025
104 of 106 checks passed
@keynmol

Copy link
Copy Markdown
ContributorAuthor

Workflow succeeded, and the image is published correctly, containing two platform-specific images: https://github.com/VirtusLab/scala-cli/actions/runs/20428482272/job/58694886877#step:7:1

But I think the visibility of packages needs to be changed in repository and package settings

@keynmol
keynmol deleted the self-contained-docker-build branch March 19, 2026 09:09
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Publish Arm64 Docker image

4 participants

@keynmol@Gedochao@tgodzik@zielinsky
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Self-contained docker build with ARM64 publishing - #3962

Merged
Gedochao merged 8 commits into
VirtusLab:mainfrom
keynmol:self-contained-docker-build
Dec 22, 2025
Merged

Self-contained docker build with ARM64 publishing#3962
Gedochao merged 8 commits into
VirtusLab:mainfrom
keynmol:self-contained-docker-build

Conversation

@keynmol

@keynmolkeynmol commented Nov 18, 2025

Copy link
Copy Markdown
Contributor

Fixes#2132

At the moment, the scala-cli docker image is built using a combination of mill tasks, scripts, and dockerfiles that require externally built binary. What's more, it's only built for x86.

With ARM64 runners on GHA being GA, I propose a simplification - a self-contained multi-stage dockerfile, with a custom Github Workflow that merges the images into a single manifest, meaning that docker will pull the correct image no matter the target platform.

Manifest merging and pushing is a complicated step, and Docker have been amending their docs with the example, which is what this workflow is based on.

I've been using this setup in multiple apps, e.g. Mimalyzer.


There are some aspects of the build I don't really understand – static, mostly static images, customisation for Linux x86, etc.

This proposal attempts to do the simplest possible thing, so that building a docker image is just docker build . -t VirtusLab/scala-cli.

Currently, it only publishes to ghcr.io to test out the workflows without disturbing the main image on docker hub. But additional publishing steps are easily added, of course

Comment threadDockerfile

@GedochaoGedochao left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tgodzik@zielinsky can you take a look as well? I think it'd be good to have another pair of eyes on this (or two)

Comment thread.github/workflows/publish-docker.yml Outdated
Comment thread.github/workflows/publish-docker.yml Outdated
Comment thread.github/workflows/publish-docker.yml Outdated
Comment threadDockerfile
@Gedochao

Copy link
Copy Markdown
Contributor

There are some aspects of the build I don't really understand – static, mostly static images, customisation for Linux x86, etc.

Static and mostly static images are in the understanding of GraalVM, as per this doc: https://www.graalvm.org/21.3/reference-manual/native-image/StaticImages/index.html
The way they're built is based on the mill-native-image plugin: https://github.com/alexarchambault/mill-native-image

(...) customisation for Linux x86 (...)

What particular customisation for Linux x86 did you mean?

(...) etc.

Shoot away, I'll try to answer, or at least direct you in the direction of an answer.

What's there in this area was initially coded by @alexarchambault (who's also the author of mill-native-image). While I've tinkered with this here and there, most of it has been lying untouched for a long, long time, and I'm not all that familiar with it either.

@tgodziktgodzik left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know much about this, I only built basic docker images. Overall look ok as long as it work 😅

@zielinskyzielinsky left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few comments from me 😅

Comment thread.github/workflows/publish-docker.yml Outdated
Comment thread.github/workflows/publish-docker.yml Outdated
Comment thread.github/workflows/publish-docker.yml Outdated
Comment thread.github/workflows/publish-docker.yml Outdated
Comment thread.github/workflows/publish-docker.yml Outdated
Comment thread.github/workflows/publish-docker.yml Outdated
Comment thread.github/workflows/publish-docker.yml Outdated
@keynmol

Copy link
Copy Markdown
ContributorAuthor

@Gedochao

What particular customisation for Linux x86 did you mean?

This line threw me off

https://github.com/keynmol/scala-cli/blob/93079619648e0b475f874ee2676387b488d7a637/project/settings/package.mill.scala#L406

@Gedochao

Copy link
Copy Markdown
Contributor

Just to make sure.

We currently have the following images, which are updated with each Scala CLI release:

@keynmol your intention is to create a third one, yes?
smth like virtuslab/scala-cli-platform-native?

@Gedochao

Copy link
Copy Markdown
Contributor

Also, how can we safely test this?

@keynmol

keynmol commented Nov 21, 2025

Copy link
Copy Markdown
ContributorAuthor

Here's my plan:

  1. Merge this workflow as is, make sure it publishes a working ghcr.io/virtuslab/scala-cli image (similar to existing DockerHub virtuslab/scala-cli)
  2. Modify the workflow in a separate PR to build the slim image in the same way (similar to existing DockerHub virtuslab/scala-cli-slim)
  3. Add DockerHub publishing steps to both images
  4. Remove old docker publishing logic

Up to step 3, the existing docker images on DockerHub are safe and won't be touched, as we only publish to ghcr.io, using it as our testing area.

Steps 1-3 can be done in separate PRs as they won't affect existing dockerhub publishing steps.

In the end, we should have virtuslab/scala-cli and virtuslab/scala-cli-slim that have a manifest merging two platforms, so users automatically get the right image (see screenshot)
CleanShot 2025-11-21 at 10 05 06@2x

@Gedochao

Copy link
Copy Markdown
Contributor

Okay... sounds reasonable.
Let's get the CI green and do it one step at a time.

@Gedochao

Gedochao commented Nov 24, 2025

Copy link
Copy Markdown
Contributor

The CI is green.
@keynmol the workflow is still on Ubuntu 22.04, while the other workflows already rely on 24.04 (I left comments earlier).
Otherwise, we seem to be good to merge here (might want to rebase on main while you're at it)

@keynmol

keynmol commented Nov 24, 2025

Copy link
Copy Markdown
ContributorAuthor

I have responded to the Ubuntu version comment: #3962 (comment)

Actually scratch that, in this instance it won't have any effect, I will update

@GedochaoGedochao left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM
@keynmol ready to merge?

@Gedochao

Copy link
Copy Markdown
Contributor

@zielinsky I will wait for your okay before clicking merge.

@keynmol

Copy link
Copy Markdown
ContributorAuthor

I think so, no doubt it will require more iterations when the work flow actually runs :)

@zielinskyzielinsky left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One question from me before approval.

Comment thread.github/workflows/publish-docker.yml Outdated

@zielinskyzielinsky left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM for now, let's test it!

@Gedochao
Gedochao merged commit 5c37f88 into VirtusLab:mainDec 22, 2025
104 of 106 checks passed
@keynmol

Copy link
Copy Markdown
ContributorAuthor

Workflow succeeded, and the image is published correctly, containing two platform-specific images: https://github.com/VirtusLab/scala-cli/actions/runs/20428482272/job/58694886877#step:7:1

But I think the visibility of packages needs to be changed in repository and package settings

@keynmol
keynmol deleted the self-contained-docker-build branch March 19, 2026 09:09
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Publish Arm64 Docker image

4 participants

@keynmol@Gedochao@tgodzik@zielinsky
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Self-contained docker build with ARM64 publishing - #3962

Merged
Gedochao merged 8 commits into
VirtusLab:mainfrom
keynmol:self-contained-docker-build
Dec 22, 2025
Merged

Self-contained docker build with ARM64 publishing#3962
Gedochao merged 8 commits into
VirtusLab:mainfrom
keynmol:self-contained-docker-build

Conversation

@keynmol

@keynmolkeynmol commented Nov 18, 2025

Copy link
Copy Markdown
Contributor

Fixes#2132

At the moment, the scala-cli docker image is built using a combination of mill tasks, scripts, and dockerfiles that require externally built binary. What's more, it's only built for x86.

With ARM64 runners on GHA being GA, I propose a simplification - a self-contained multi-stage dockerfile, with a custom Github Workflow that merges the images into a single manifest, meaning that docker will pull the correct image no matter the target platform.

Manifest merging and pushing is a complicated step, and Docker have been amending their docs with the example, which is what this workflow is based on.

I've been using this setup in multiple apps, e.g. Mimalyzer.


There are some aspects of the build I don't really understand – static, mostly static images, customisation for Linux x86, etc.

This proposal attempts to do the simplest possible thing, so that building a docker image is just docker build . -t VirtusLab/scala-cli.

Currently, it only publishes to ghcr.io to test out the workflows without disturbing the main image on docker hub. But additional publishing steps are easily added, of course

Comment threadDockerfile

@GedochaoGedochao left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tgodzik@zielinsky can you take a look as well? I think it'd be good to have another pair of eyes on this (or two)

Comment thread.github/workflows/publish-docker.yml Outdated
Comment thread.github/workflows/publish-docker.yml Outdated
Comment thread.github/workflows/publish-docker.yml Outdated
Comment threadDockerfile
@Gedochao

Copy link
Copy Markdown
Contributor

There are some aspects of the build I don't really understand – static, mostly static images, customisation for Linux x86, etc.

Static and mostly static images are in the understanding of GraalVM, as per this doc: https://www.graalvm.org/21.3/reference-manual/native-image/StaticImages/index.html
The way they're built is based on the mill-native-image plugin: https://github.com/alexarchambault/mill-native-image

(...) customisation for Linux x86 (...)

What particular customisation for Linux x86 did you mean?

(...) etc.

Shoot away, I'll try to answer, or at least direct you in the direction of an answer.

What's there in this area was initially coded by @alexarchambault (who's also the author of mill-native-image). While I've tinkered with this here and there, most of it has been lying untouched for a long, long time, and I'm not all that familiar with it either.

@tgodziktgodzik left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know much about this, I only built basic docker images. Overall look ok as long as it work 😅

@zielinskyzielinsky left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few comments from me 😅

Comment thread.github/workflows/publish-docker.yml Outdated
Comment thread.github/workflows/publish-docker.yml Outdated
Comment thread.github/workflows/publish-docker.yml Outdated
Comment thread.github/workflows/publish-docker.yml Outdated
Comment thread.github/workflows/publish-docker.yml Outdated
Comment thread.github/workflows/publish-docker.yml Outdated
Comment thread.github/workflows/publish-docker.yml Outdated
@keynmol

Copy link
Copy Markdown
ContributorAuthor

@Gedochao

What particular customisation for Linux x86 did you mean?

This line threw me off

https://github.com/keynmol/scala-cli/blob/93079619648e0b475f874ee2676387b488d7a637/project/settings/package.mill.scala#L406

@Gedochao

Copy link
Copy Markdown
Contributor

Just to make sure.

We currently have the following images, which are updated with each Scala CLI release:

@keynmol your intention is to create a third one, yes?
smth like virtuslab/scala-cli-platform-native?

@Gedochao

Copy link
Copy Markdown
Contributor

Also, how can we safely test this?

@keynmol

keynmol commented Nov 21, 2025

Copy link
Copy Markdown
ContributorAuthor

Here's my plan:

  1. Merge this workflow as is, make sure it publishes a working ghcr.io/virtuslab/scala-cli image (similar to existing DockerHub virtuslab/scala-cli)
  2. Modify the workflow in a separate PR to build the slim image in the same way (similar to existing DockerHub virtuslab/scala-cli-slim)
  3. Add DockerHub publishing steps to both images
  4. Remove old docker publishing logic

Up to step 3, the existing docker images on DockerHub are safe and won't be touched, as we only publish to ghcr.io, using it as our testing area.

Steps 1-3 can be done in separate PRs as they won't affect existing dockerhub publishing steps.

In the end, we should have virtuslab/scala-cli and virtuslab/scala-cli-slim that have a manifest merging two platforms, so users automatically get the right image (see screenshot)
CleanShot 2025-11-21 at 10 05 06@2x

@Gedochao

Copy link
Copy Markdown
Contributor

Okay... sounds reasonable.
Let's get the CI green and do it one step at a time.

@Gedochao

Gedochao commented Nov 24, 2025

Copy link
Copy Markdown
Contributor

The CI is green.
@keynmol the workflow is still on Ubuntu 22.04, while the other workflows already rely on 24.04 (I left comments earlier).
Otherwise, we seem to be good to merge here (might want to rebase on main while you're at it)

@keynmol

keynmol commented Nov 24, 2025

Copy link
Copy Markdown
ContributorAuthor

I have responded to the Ubuntu version comment: #3962 (comment)

Actually scratch that, in this instance it won't have any effect, I will update

@GedochaoGedochao left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM
@keynmol ready to merge?

@Gedochao

Copy link
Copy Markdown
Contributor

@zielinsky I will wait for your okay before clicking merge.

@keynmol

Copy link
Copy Markdown
ContributorAuthor

I think so, no doubt it will require more iterations when the work flow actually runs :)

@zielinskyzielinsky left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One question from me before approval.

Comment thread.github/workflows/publish-docker.yml Outdated

@zielinskyzielinsky left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM for now, let's test it!

@Gedochao
Gedochao merged commit 5c37f88 into VirtusLab:mainDec 22, 2025
104 of 106 checks passed
@keynmol

Copy link
Copy Markdown
ContributorAuthor

Workflow succeeded, and the image is published correctly, containing two platform-specific images: https://github.com/VirtusLab/scala-cli/actions/runs/20428482272/job/58694886877#step:7:1

But I think the visibility of packages needs to be changed in repository and package settings

@keynmol
keynmol deleted the self-contained-docker-build branch March 19, 2026 09:09
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Publish Arm64 Docker image

4 participants

@keynmol@Gedochao@tgodzik@zielinsky