Skip to content

CI: Try to use macos-latest on arm64 to build arm images #144

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 12 additions & 73 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ concurrency:
cancel-in-progress: true
on:
workflow_dispatch:
schedule:
- cron: "0 5 * * 3" # At 05:00 on Wednesday # https://crontab.guru/#0_5_*_*_3
push:
branches:
- main
Expand All @@ -17,62 +15,28 @@ on:
- "*"

jobs:
build_source_gem:
name: build source
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: ruby/setup-ruby@v1
with:
ruby-version: "3.3"
working-directory: test/rcd_test
bundler-cache: true

- name: Build source gem
run: |
cd test/rcd_test/
bundle exec rake gem

- name: Upload source gem
uses: actions/upload-artifact@v4
with:
name: gem-ruby
path: test/rcd_test/pkg/rcd_test-?.?.?.gem # e.g. rcd_test-1.0.0.gem

build_native_gem:
name: build native
strategy:
fail-fast: false
matrix:
include:
- platform: aarch64-linux-gnu
alias: aarch64-linux
- platform: aarch64-linux-musl
- platform: arm-linux-gnu
alias: arm-linux
- platform: arm-linux-musl
- platform: arm64-darwin
- platform: jruby
- platform: x64-mingw-ucrt
static: true
- platform: x64-mingw32
static: true
- platform: x86-linux-gnu
alias: x86-linux
- platform: x86-linux-musl
- platform: x86-mingw32
- platform: x86_64-darwin
- platform: x86_64-linux-gnu
alias: x86_64-linux
- platform: x86_64-linux-musl
runs-on: ubuntu-latest
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- uses: ruby/setup-ruby@v1
- uses: ruby/setup-ruby-pkgs@v1
with:
ruby-version: "3.3"
bundler-cache: true

brew: "docker docker-buildx colima"
- name: enable buildx command
run: |
mkdir -p ~/.docker
echo '{"cliPluginsExtraDirs": ["/opt/homebrew/lib/docker/cli-plugins"]}' > ~/.docker/config.json
cat ~/.docker/config.json
- name: start colima
run: |
colima start
- name: Fetch docker buildx layer cache
uses: actions/cache@v4
with:
Expand All @@ -82,7 +46,7 @@ jobs:
- name: Build docker image
run: |
docker buildx create --driver docker-container --use
bundle exec rake build:${{ matrix.platform }} RCD_DOCKER_BUILD="docker buildx build --cache-from=type=local,src=tmp/build-cache --cache-to=type=local,dest=tmp/build-cache-new --load"
bundle exec rake build:arm:${{ matrix.platform }} RCD_DOCKER_BUILD="docker buildx build --cache-from=type=local,src=tmp/build-cache --cache-to=type=local,dest=tmp/build-cache-new"
docker images
- name: Update and prune docker buildx layer cache
run: |
Expand Down Expand Up @@ -137,31 +101,6 @@ jobs:
name: gem-${{ matrix.alias }}
path: test/rcd_test/pkg/*-*-*.gem

test_source_gem:
name: source gem
needs: build_source_gem
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest]
ruby: ["3.4.0-rc1", "3.3", "3.2", "3.1", "3.0", "2.7", "2.6", "2.5", "2.4"]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby }}
- name: Download source gem
uses: actions/download-artifact@v4
with:
name: gem-ruby
- name: Test source gem
run: |
gem install --local *.gem --verbose
cd test/rcd_test/
bundle install
ruby -rrcd_test -S rake test

test-x86_64-linux-setup-ruby:
name: "${{ matrix.platform }} setup-ruby(${{ matrix.ruby }})"
needs: build_native_gem
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/publish-images.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,10 @@ jobs:
' | tee -a $GITHUB_OUTPUT
- name: Build docker image
env:
RCD_DOCKER_BUILD: docker buildx build --cache-from=type=local,src=tmp/build-cache --cache-to=type=local,dest=tmp/build-cache-new --load
RCD_DOCKER_BUILD: docker buildx build --cache-from=type=local,src=tmp/build-cache --cache-to=type=local,dest=tmp/build-cache-new
run: |
docker buildx create --driver docker-container --use
bundle exec rake build:${{matrix.platform}}
bundle exec rake build:x86:${{matrix.platform}}
# move build cache and remove outdated layers
rm -rf tmp/build-cache
mv tmp/build-cache-new tmp/build-cache
Expand Down
43 changes: 43 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,46 @@ docker buildx create --use --driver=docker-container
bundle exec rake build
```


### Create builder instance for two architectures

Building with qemu emulation fails currently with a segfault, so that it must be built by a builder instance with at least one remote node for the other architecture.
Building on native hardware is also much faster (~45 minutes) than on qemu.
A two-nodes builder requires obviously a ARM and a Intel/AMD device.
It can be created like this:

```sh
# Make sure the remote instance can be connected
$ docker -H ssh://isa info

# Create a new builder with the local instance
# Disable the garbage collector by the config file
$ docker buildx create --name isayoga --config build/buildkitd.toml

# Add the remote instance
$ docker buildx create --name isayoga --config build/buildkitd.toml --append ssh://isa

# They are inactive from the start
$ docker buildx ls
NAME/NODE DRIVER/ENDPOINT STATUS BUILDKIT PLATFORMS
isayoga docker-container
\_ isayoga0 \_ unix:///var/run/docker.sock inactive
\_ isayoga1 \_ ssh://isa inactive
default* docker
\_ default \_ default running v0.13.2 linux/arm64

# Bootstrap the instances
$ docker buildx inspect --bootstrap --builder isayoga

# Set the new builder as default
$ docker buildx use isayoga

# Now it should be default and in state "running"
$ docker buildx ls
NAME/NODE DRIVER/ENDPOINT STATUS BUILDKIT PLATFORMS
isayoga* docker-container
\_ isayoga0 \_ unix:///var/run/docker.sock running v0.18.2 linux/arm64
\_ isayoga1 \_ ssh://isa running v0.18.2 linux/amd64, linux/amd64/v2, linux/amd64/v3, linux/386
default docker
\_ default \_ default running v0.13.2 linux/arm64
```
129 changes: 89 additions & 40 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,27 @@ CLEAN.include("tmp")

RakeCompilerDock::GemHelper.install_tasks

def build_mri_images(platforms, host_platforms, output: )
plats = host_platforms.map(&:first).join(",")
platforms.each do |platform, _|
sdf = "tmp/docker/Dockerfile.mri.#{platform}.#{host_platforms.first[1]}"
image_name = RakeCompilerDock::Starter.container_image_name(platform: platform)

RakeCompilerDock.docker_build(sdf, tag: image_name, platform: plats, output: output)

if image_name.include?("linux-gnu")
RakeCompilerDock.docker_build(sdf, tag: image_name.sub("linux-gnu", "linux"), platform: plats, output: output)
end
end
end

def build_jruby_images(host_platforms, output: )
image_name = RakeCompilerDock::Starter.container_image_name(rubyvm: "jruby")
plats = host_platforms.map(&:first).join(",")
sdf = "tmp/docker/Dockerfile.jruby.#{host_platforms.first[1]}"
RakeCompilerDock.docker_build(sdf, tag: image_name, platform: plats, output: output)
end

platforms = [
# tuple is [platform, target]
["aarch64-linux-gnu", "aarch64-linux-gnu"],
Expand All @@ -25,47 +46,84 @@ platforms = [
["x86_64-linux-musl", "x86_64-unknown-linux-musl"],
]

host_platforms = [
# tuple is [docker platform, rake task, RUBY_PLATFORM matcher]
["linux/amd64", "x86", /^x86_64|^x64|^amd64/],
["linux/arm64", "arm", /^aarch64|arm64/],
]
local_platform = host_platforms.find { |_,_,reg| reg =~ RUBY_PLATFORM } or
raise("RUBY_PLATFORM #{RUBY_PLATFORM} is not supported as host")

namespace :build do

platforms.each do |platform, target|
sdf = "Dockerfile.mri.#{platform}"
mkdir_p "tmp/docker"

host_platforms.each do |docker_platform, rake_platform|
namespace rake_platform do

desc "Build image for platform #{platform}"
task platform => sdf
task sdf do
image_name = RakeCompilerDock::Starter.container_image_name(platform: platform)
sh(*RakeCompilerDock.docker_build_cmd(platform), "-t", image_name, "-f", "Dockerfile.mri.#{platform}", ".")
if image_name.include?("linux-gnu")
sh("docker", "tag", image_name, image_name.sub("linux-gnu", "linux"))
platforms.each do |platform, target|
sdf = "tmp/docker/Dockerfile.mri.#{platform}.#{rake_platform}"
df = ERB.new(File.read("Dockerfile.mri.erb"), trim_mode: ">").result(binding)
File.write(sdf, df)
CLEAN.include(sdf)
end
sdf = "tmp/docker/Dockerfile.jruby.#{rake_platform}"
df = File.read("Dockerfile.jruby")
File.write(sdf, df)

builder = RakeCompilerDock::ParallelDockerBuild.new(platforms.map{|pl, _| "tmp/docker/Dockerfile.mri.#{pl}.#{rake_platform}" } + ["tmp/docker/Dockerfile.jruby.#{rake_platform}"], workdir: "tmp/docker", task_prefix: "common-#{rake_platform}-", platform: docker_platform)

platforms.each do |platform, target|
sdf = "tmp/docker/Dockerfile.mri.#{platform}.#{rake_platform}"

if docker_platform == local_platform[0]
# Load image after build on local platform only
desc "Build and load image for platform #{platform} on #{docker_platform}"
task platform => sdf do
build_mri_images([platform], [local_platform], output: 'load')
end
else
desc "Build image for platform #{platform} on #{docker_platform}"
task platform => sdf
end
multitask :all => platform
end
end

df = ERB.new(File.read("Dockerfile.mri.erb"), trim_mode: ">").result(binding)
File.write(sdf, df)
CLEAN.include(sdf)
sdf = "tmp/docker/Dockerfile.jruby.#{rake_platform}"
if docker_platform == local_platform[0]
# Load image after build on local platform only
desc "Build and load image for JRuby on #{docker_platform}"
task :jruby => sdf do
build_jruby_images([local_platform], output: 'load')
end
else
desc "Build image for JRuby on #{docker_platform}"
task :jruby => sdf
end
multitask :all => :jruby
end
desc "Build all images on #{docker_platform} in parallel"
task rake_platform => "#{rake_platform}:all"
end

desc "Build image for JRuby"
task :jruby => "Dockerfile.jruby"
task "Dockerfile.jruby" do
image_name = RakeCompilerDock::Starter.container_image_name(rubyvm: "jruby")
sh(*RakeCompilerDock.docker_build_cmd("jruby"), "-t", image_name, "-f", "Dockerfile.jruby", ".")
all_mri_images = host_platforms.flat_map do |_, rake_platform|
platforms.map do |platform, |
"#{rake_platform}:#{platform}"
end
end

RakeCompilerDock::ParallelDockerBuild.new(platforms.map{|pl, _| "Dockerfile.mri.#{pl}" } + ["Dockerfile.jruby"], workdir: "tmp/docker")

desc "Build images for all MRI platforms in parallel"
desc "Build images for all MRI platforms and hosts in parallel"
if ENV['RCD_USE_BUILDX_CACHE']
task :mri => platforms.map(&:first)
task :mri => all_mri_images
else
multitask :mri => platforms.map(&:first)
multitask :mri => all_mri_images
end

desc "Build images for all platforms in parallel"
all_images = all_mri_images + host_platforms.map { |_, pl| "#{pl}:jruby" }
desc "Build images for all platforms and hosts in parallel"
if ENV['RCD_USE_BUILDX_CACHE']
task :all => platforms.map(&:first) + ["jruby"]
task :all => all_images
else
multitask :all => platforms.map(&:first) + ["jruby"]
multitask :all => all_images
end
end

Expand Down Expand Up @@ -115,18 +173,9 @@ task :update_lists do
end

namespace :release do
desc "push all docker images"
task :images do
image_name = RakeCompilerDock::Starter.container_image_name(rubyvm: "jruby")
sh("docker", "push", image_name)

platforms.each do |platform, _|
image_name = RakeCompilerDock::Starter.container_image_name(platform: platform)
sh("docker", "push", image_name)

if image_name.include?("linux-gnu")
sh("docker", "push", image_name.sub("linux-gnu", "linux"))
end
end
desc "Push all docker images on #{host_platforms.map(&:first).join(",")}"
task :images => "build:all" do
build_jruby_images(host_platforms, output: 'push')
build_mri_images(platforms, host_platforms, output: 'push')
end
end
2 changes: 2 additions & 0 deletions build/buildkitd.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[worker.oci]
gc = false
Loading
Loading