Skip to content
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

Update docker images for use with docker buildx #211

Draft
wants to merge 35 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
099f30b
Update docker images for use with `docker buildx`
caspiano Dec 7, 2022
4dcd934
Update linux builds for aarch64
caspiano Dec 8, 2022
33e16b6
Compile libs with -O3
caspiano Dec 9, 2022
67de475
Use bdwgc 8.2.2
caspiano Dec 9, 2022
61c3f26
Remove duplication, extract target architecture to an argument `arch`
caspiano Dec 12, 2022
aadf825
Update linux README
caspiano Dec 12, 2022
4afb171
Simplify build
caspiano Dec 13, 2022
2015208
Ignore build directories
caspiano Dec 13, 2022
4cf85c1
Use 84codes to bootsrap
caspiano Dec 13, 2022
00e2f37
Simple readme for Docker builds
caspiano Dec 13, 2022
8837c9c
`shallow-clone` script
caspiano Dec 13, 2022
d2ae1e9
Add missing bundled.dockerfile arg
caspiano Dec 13, 2022
32d6b3b
Refactor docker Makefile to accept an arch argument
caspiano Dec 13, 2022
5430fe9
Seperate outputs from build context
caspiano Dec 13, 2022
1434d88
Parameterise llvm
caspiano Dec 13, 2022
d24f5c6
Missing backslash
caspiano Dec 14, 2022
4695c4f
Test build scripts work
caspiano Dec 14, 2022
44d4f7b
Set to tag that exists
caspiano Dec 14, 2022
84386fd
Minor `Makefile` edits for GH actions environment
caspiano Dec 14, 2022
efa14d5
Fix paths in test flow
caspiano Dec 14, 2022
d7654da
Remove deb reference in Docker Makefile
caspiano Dec 15, 2022
848f5da
Add test job to Docker Makefile
caspiano Dec 15, 2022
f09a7f9
Use `test` job for Docker test
caspiano Dec 15, 2022
354725b
Use `PREVIOUS_PACKAGE_ITERATION`
caspiano Dec 15, 2022
ec4ba9c
Use `docker load` instead of `docker import`
caspiano Dec 15, 2022
a5376a0
Add gha cache
caspiano Dec 18, 2022
bb3d325
Cache as much as possible, scoped by architecture
caspiano Dec 18, 2022
bdd4c0d
Enable aarch64
caspiano Dec 19, 2022
1ce0cd0
Remove missing env var from Docker README
caspiano Dec 19, 2022
8b12d8c
Add support for aarch64 in snap
caspiano Dec 20, 2022
39e55d6
Allow setting crystal repository via env
caspiano Dec 21, 2022
319add1
pipefail in `bundled.dockerfile`
caspiano Jan 5, 2023
7cc1c43
Set crystal repo via env var in docs build
caspiano Jan 9, 2023
05d276e
Use github org/repo
caspiano Jan 10, 2023
49c0d77
Revert 319add1
caspiano Jan 10, 2023
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
122 changes: 122 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
name: CI

on: [push, pull_request]

env:
PREVIOUS_CRYSTAL_VERSION: 1.6.0
CRYSTAL_VERSION: 1.6.2
PACKAGE_VERSION: 1

jobs:
linux-build:
# TODO: set architecture based off matrix value when ARM runner available
name: Build linux binaries
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
architecture:
- x86_64
- aarch64
steps:
-
name: Checkout the distribution scripts
uses: actions/checkout@v3

-
name: Cache Docker layers
uses: actions/cache@v3
with:
path: /tmp/.buildx-cache
key: ${{ runner.os }}-buildx-${{ github.sha }}
restore-keys: |
${{ runner.os }}-buildx-

-
name: Set up QEMU
uses: docker/setup-qemu-action@v2

-
name: Build the linux binaries
run: |
cd linux
make \
arch=${{ matrix.architecture }} \
CRYSTAL_VERSION=${{ env.CRYSTAL_VERSION }} \
PACKAGE_VERSION=${{ env.PACKAGE_VERSION }} \
PREVIOUS_CRYSTAL_VERSION=${{ env.PREVIOUS_CRYSTAL_VERSION }}

-
name: Upload the binaries for use in the next step
uses: actions/upload-artifact@v3
with:
name: linux-${{ env.CRYSTAL_VERSION }}-{{ matrix.architecture }}-${{ env.PACKAGE_VERSION }}
path: linux/build/*.gz


docker-build:
name: Build and test the docker images
runs-on: ubuntu-latest
needs: linux-build
strategy:
fail-fast: false
matrix:
architecture:
- x86_64
- aarch64
steps:
-
name: Checkout the distribution scripts
uses: actions/checkout@v3

-
name: Download the linux binaries
uses: actions/download-artifact@v3
with:
name: linux-${{ env.CRYSTAL_VERSION }}-{{ matrix.architecture }}-${{ env.PACKAGE_VERSION }}
path: docker/build-context

-
name: Cache Docker layers
uses: actions/cache@v3
with:
path: /tmp/.buildx-cache
key: ${{ runner.os }}-buildx-${{ github.sha }}
restore-keys: |
${{ runner.os }}-buildx-

-
name: Set up QEMU
uses: docker/setup-qemu-action@v2

-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2

-
name: Build the docker image
run: |
cd docker
make \
arch=${{ matrix.architecture }} \
CRYSTAL_VERSION=${{ env.CRYSTAL_VERSION }} \
PACKAGE_VERSION=${{ env.PACKAGE_VERSION }} \

-
name: Ensure images are well formed
run: |
# NOTE: Hack for GHA
sudo mkdir -p /var/lib/docker/tmp

cd docker
make test \
arch=${{ matrix.architecture }} \
CRYSTAL_VERSION=${{ env.CRYSTAL_VERSION }} \
PACKAGE_VERSION=${{ env.PACKAGE_VERSION }}

-
name: Upload the docker images
uses: actions/upload-artifact@v3
with:
name: docker-crystal-${{ env.CRYSTAL_VERSION }}-${{ env.PACKAGE_VERSION }}-{{ matrix.architecture }}
path: docker/build/*.gz
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ omnibus/bin
omnibus/crystal-darwin-*
omnibus/shards-darwin-*

build

docs/build/

darwin/build/
Expand Down
10 changes: 8 additions & 2 deletions darwin/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,12 @@ CRYSTAL_SHA1 ?= $(CRYSTAL_VERSION) ## Git tag/branch/sha1 to checkout and build
PACKAGE_ITERATION ?= 1
FORCE_GIT_TAGGED ?= 1 ## Require build to be based on git tag/branch

PREVIOUS_CRYSTAL_RELEASE_DARWIN_TARGZ ?= ## url to crystal-{version}-{package}-darwin-x86_64.tar.gz
PREVIOUS_CRYSTAL_VERSION ?= ## Version of the bootstrap compiler
PREVIOUS_PACKAGE_ITERATION ?= 1## Package iteration of the bootstrap compiler

CRYSTAL_REPOSITORY ?= crystal-lang/crystal

PREVIOUS_CRYSTAL_RELEASE_DARWIN_TARGZ ?= https://github.com/$(CRYSTAL_REPOSITORY)/releases/download/$(PREVIOUS_CRYSTAL_VERSION)/crystal-$(PREVIOUS_CRYSTAL_VERSION)-$(PREVIOUS_PACKAGE_ITERATION)-darwin-universal.tar.gz## Url to crystal-{version}-{package}-darwin-universal.tar.gz

OUTPUT_DIR = build

Expand Down Expand Up @@ -49,10 +54,11 @@ $(CURDIR)/../omnibus/crystal-darwin-x86_64/embedded/bin/crystal:
&& rm /tmp/crystal-darwin-x86_64.tar.gz \
&& chmod +x $(CURDIR)/../omnibus/crystal-darwin-x86_64/embedded/bin/crystal

# TODO: Shallow clone
$(OUTPUT_DIR)/$(DARWIN_NAME) $(OUTPUT_DIR)/$(DARWIN_PKG_NAME): ## Build omnibus crystal project
ifeq ($(FORCE_GIT_TAGGED), 0)
rm -Rf $(CURDIR)/tmp && mkdir -p $(CURDIR)/tmp && cd $(CURDIR)/tmp \
&& git clone https://github.com/crystal-lang/crystal \
&& git clone https://github.com/$(CRYSTAL_REPOSITORY) \
&& cd crystal \
&& git checkout $(CRYSTAL_SHA1) \
&& git checkout -b $(CRYSTAL_VERSION)
Expand Down
149 changes: 107 additions & 42 deletions docker/Makefile
Original file line number Diff line number Diff line change
@@ -1,78 +1,127 @@
# Recipies for this Makefile

## Build all docker images
## $ make DOCKER_TAG=nightly CRYSTAL_VERSION=0.xy.z CRYSTAL_DEB=... CRYSTAL_TARGZ=...
## Build ubuntu64 docker images
## $ make ubuntu64 DOCKER_TAG=nightly CRYSTAL_VERSION=0.xy.z CRYSTAL_TARGZ=...
## Build alpine docker images
## $ make alpine DOCKER_TAG=nightly CRYSTAL_VERSION=0.xy.z CRYSTAL_TARGZ=...
## Build all docker images for x86_64
## $ make arch=x86_64 DOCKER_TAG=nightly CRYSTAL_VERSION=0.xy.z CRYSTAL_TARGZ=...
## Build all docker images for aarch64
## $ make arch=aarch64 DOCKER_TAG=nightly CRYSTAL_VERSION=0.xy.z CRYSTAL_TARGZ=...
## Build ubuntu docker images for x86_64
## $ make ubuntu arch=x86_64 DOCKER_TAG=nightly CRYSTAL_VERSION=0.xy.z CRYSTAL_TARGZ=...
## Build alpine docker images for aarch64
## $ make alpine arch=aarch64 DOCKER_TAG=nightly CRYSTAL_VERSION=0.xy.z CRYSTAL_TARGZ=...

arch ?= ## Architecture to build for (x86_64, aarch64)
no_cache ?= ## Disable the docker build cache
pull_images ?= ## Always pull docker images to ensure they're up to date

CRYSTAL_VERSION ?= ## How the binaries should be branded
CRYSTAL_DEB ?= ## Which crystal.deb file to install in debian based docker images (ubuntu32)
CRYSTAL_TARGZ ?= ## Which crystal.tar.gz file to install in docker images (ubuntu64, alpine)
DOCKER_TAG ?= $(CRYSTAL_VERSION) ## How to tag the docker image (examples: `0.27.2`, `nightly20190307`). `-build` will be appended for build images.
DOCKER_REPOSITORY ?= crystallang/crystal ## Docker hub repository to commit image
PACKAGE_ITERATION ?= 1
PACKAGE_MAINTAINER = Crystal Team <[email protected]>

GC_VERSION = v8.2.0
DOCKER_TAG ?= $(CRYSTAL_VERSION)## How to tag the docker image (examples: `0.27.2`, `nightly20190307`). `-build` will be appended for build images.
DOCKER_REPOSITORY ?= crystallang/crystal## Docker hub repository to commit image

GC_VERSION = v8.2.2

ifeq ($(arch),x86_64)
DOCKER_BUILD_PLATFORM = linux/amd64
else ifeq ($(arch),aarch64)
DOCKER_BUILD_PLATFORM = linux/arm64
else
$(error Expected arch to be one of 'x86_64', or 'aarch64', got: $(arch))
endif

BASE_UBUNTU_DOCKER_IMAGE = ubuntu:focal

OUTPUT_DIR := build

BUILD_CONTEXT := $(CURDIR)/build-context
BUILD_ARGS_UBUNTU64 := --build-arg crystal_targz=crystal.tar.gz $(BUILD_CONTEXT)/ubuntu64 --build-arg base_docker_image=ubuntu:focal
BUILD_ARGS_ALPINE := --build-arg crystal_targz=crystal.tar.gz $(BUILD_CONTEXT)/alpine --build-arg gc_version=$(GC_VERSION)

CRYSTAL_TARGZ ?= $(BUILD_CONTEXT)/crystal-$(CRYSTAL_VERSION)-$(PACKAGE_ITERATION)-linux-$(arch).tar.gz## Which crystal.tar.gz file to install in docker images (ubuntu, alpine)

BUILD_ARGS_COMMON := \
$(if $(pull_images),--pull) \
$(if $(no_cache),--no-cache) \
$(if $(GITHUB_ACTIONS),--cache-from type=gha,mode=max,scope=$(arch) --cache-to type=gha,mode=max,scope=$(arch)) \
--platform $(DOCKER_BUILD_PLATFORM) \
--label "crystal_version=$(CRYSTAL_VERSION)" \
--label "package_iteration=$(PACKAGE_ITERATION)" \
--label "package_maintainer=$(PACKAGE_MAINTAINER)" \
--build-arg llvm_version=$(LLVM_VERSION)

BUILD_ARGS_UBUNTU := $(BUILD_ARGS_COMMON) \
--build-arg crystal_targz=crystal.tar.gz \
--build-arg base_docker_image=$(BASE_UBUNTU_DOCKER_IMAGE) \
$(BUILD_CONTEXT)/ubuntu

BUILD_ARGS_ALPINE := $(BUILD_ARGS_COMMON) \
--build-arg crystal_targz=crystal.tar.gz \
--build-arg gc_version=$(GC_VERSION) \
$(BUILD_CONTEXT)/alpine

DOCKER_TAG_UBUNTU := $(DOCKER_REPOSITORY):$(DOCKER_TAG)
DOCKER_TAG_ALPINE := $(DOCKER_REPOSITORY):$(DOCKER_TAG)-alpine

.PHONY: all64
all64: ubuntu64 alpine ## Build all x86_64 images
.PHONY: all
all: ubuntu alpine ## Build all images

.PHONY: all_ubuntu
all_ubuntu: ubuntu64 ## Build all ubuntu images
all_ubuntu: ubuntu ## Build all ubuntu images

.PHONY: ubuntu64
ubuntu64: ## Build ubuntu x86_64 images
ubuntu64: $(OUTPUT_DIR)/docker-$(CRYSTAL_VERSION)-ubuntu-x86_64.tar.gz
ubuntu64: $(OUTPUT_DIR)/docker-$(CRYSTAL_VERSION)-ubuntu-x86_64-build.tar.gz
.PHONY: ubuntu
ubuntu: ## Build ubuntu images
ubuntu: $(OUTPUT_DIR)/docker-$(CRYSTAL_VERSION)-ubuntu-$(arch).tar.gz
ubuntu: $(OUTPUT_DIR)/docker-$(CRYSTAL_VERSION)-ubuntu-$(arch)-build.tar.gz

.PHONY: alpine
alpine: ## Build alpine images
alpine: $(OUTPUT_DIR)/docker-$(CRYSTAL_VERSION)-alpine.tar.gz
alpine: $(OUTPUT_DIR)/docker-$(CRYSTAL_VERSION)-alpine-build.tar.gz
alpine: $(OUTPUT_DIR)/docker-$(CRYSTAL_VERSION)-alpine-$(arch).tar.gz
alpine: $(OUTPUT_DIR)/docker-$(CRYSTAL_VERSION)-alpine-$(arch)-build.tar.gz

$(BUILD_CONTEXT)/ubuntu64: ubuntu.Dockerfile $(BUILD_CONTEXT)/ubuntu64/crystal.tar.gz
$(BUILD_CONTEXT)/ubuntu: ubuntu.Dockerfile $(BUILD_CONTEXT)/ubuntu/crystal.tar.gz
cp ubuntu.Dockerfile $@/Dockerfile

$(BUILD_CONTEXT)/alpine: alpine.Dockerfile $(BUILD_CONTEXT)/alpine/crystal.tar.gz
cp alpine.Dockerfile $@/Dockerfile
mkdir $@/files/

%/crystal.deb:
mkdir -p $(shell dirname $@)
cp $(CRYSTAL_DEB) $@

%/crystal.tar.gz:
mkdir -p $(shell dirname $@)
cp $(CRYSTAL_TARGZ) $@

$(OUTPUT_DIR):
mkdir -p $(OUTPUT_DIR)
mkdir -p $(@)

$(BUILD_CONTEXT):
mkdir -p $(@)

.PHONY: scripts
scripts: $(BUILD_CONTEXT)
cp -r ../scripts $(BUILD_CONTEXT)/alpine

# Ubuntu x86_64
$(OUTPUT_DIR)/docker-$(CRYSTAL_VERSION)-ubuntu-x86_64.tar.gz: $(BUILD_CONTEXT)/ubuntu64 $(OUTPUT_DIR)
docker build -t $(DOCKER_TAG_UBUNTU) --target runtime $(BUILD_ARGS_UBUNTU64)
docker save $(DOCKER_TAG_UBUNTU) | gzip > $@
.PHONY: test
test: test_ubuntu test_alpine

$(OUTPUT_DIR)/docker-$(CRYSTAL_VERSION)-ubuntu-x86_64-build.tar.gz: $(BUILD_CONTEXT)/ubuntu64 $(OUTPUT_DIR)
docker build -t $(DOCKER_TAG_UBUNTU)-build --target build $(BUILD_ARGS_UBUNTU64)
docker save $(DOCKER_TAG_UBUNTU)-build | gzip > $@
.PHONY: test_ubuntu
test_ubuntu: ubuntu
$(call test_crystal_image, $(DOCKER_TAG_UBUNTU), $(OUTPUT_DIR)/docker-$(CRYSTAL_VERSION)-ubuntu-$(arch).tar.gz)

# Alpine x86_64
$(OUTPUT_DIR)/docker-$(CRYSTAL_VERSION)-alpine.tar.gz: $(BUILD_CONTEXT)/alpine $(OUTPUT_DIR)
docker build -t $(DOCKER_TAG_ALPINE) --target runtime $(BUILD_ARGS_ALPINE)
docker save $(DOCKER_TAG_ALPINE) | gzip > $@
.PHONY: test_alpine
test_alpine: alpine
$(call test_crystal_image, $(DOCKER_TAG_ALPINE), $(OUTPUT_DIR)/docker-$(CRYSTAL_VERSION)-alpine-$(arch).tar.gz)

$(OUTPUT_DIR)/docker-$(CRYSTAL_VERSION)-alpine-build.tar.gz: $(BUILD_CONTEXT)/alpine $(OUTPUT_DIR)
docker build -t $(DOCKER_TAG_ALPINE)-build --target build $(BUILD_ARGS_ALPINE)
docker save $(DOCKER_TAG_ALPINE)-build | gzip > $@
# Ubuntu
$(OUTPUT_DIR)/docker-$(CRYSTAL_VERSION)-ubuntu-$(arch).tar.gz: $(BUILD_CONTEXT)/ubuntu $(OUTPUT_DIR)
docker buildx build --tag $(DOCKER_TAG_UBUNTU) --target runtime -o type=docker,dest=- $(BUILD_ARGS_UBUNTU) | gzip > $@

$(OUTPUT_DIR)/docker-$(CRYSTAL_VERSION)-ubuntu-$(arch)-build.tar.gz: $(BUILD_CONTEXT)/ubuntu $(OUTPUT_DIR)
docker buildx build --tag $(DOCKER_TAG_UBUNTU)-build --target build -o type=docker,dest=- $(BUILD_ARGS_UBUNTU) | gzip > $@

# Alpine
$(OUTPUT_DIR)/docker-$(CRYSTAL_VERSION)-alpine-$(arch).tar.gz: $(BUILD_CONTEXT)/alpine $(OUTPUT_DIR) scripts
docker buildx build --tag $(DOCKER_TAG_ALPINE) --target runtime -o type=docker,dest=- $(BUILD_ARGS_ALPINE) | gzip > $@

$(OUTPUT_DIR)/docker-$(CRYSTAL_VERSION)-alpine-$(arch)-build.tar.gz: $(BUILD_CONTEXT)/alpine $(OUTPUT_DIR) scripts
docker buildx build --tag $(DOCKER_TAG_ALPINE)-build --target build -o type=docker,dest=- $(BUILD_ARGS_ALPINE) | gzip > $@

.PHONY: clean
clean: ## Clean up build and output directories
Expand All @@ -95,3 +144,19 @@ help: ## Show this help
@printf '\033[34mrecipes:\033[0m\n'
@grep -hE '^##.*$$' $(MAKEFILE_LIST) |\
awk 'BEGIN {FS = "## "}; /^## [a-zA-Z_-]/ {printf " \033[36m%s\033[0m\n", $$2}; /^## / {printf " %s\n", $$2}'

# Load the docker image and run `crystal` and `shards`
# Arguments:
# $1: The docker image tag to load
# $2: The docker tar ball to load
define test_crystal_image
docker load -i $(2) \
&& \
docker run --rm \
$(1) \
crystal --version \
&& \
docker run --rm \
$(1) \
shards --version
endef
15 changes: 15 additions & 0 deletions docker/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Docker builds

Crystal binaries are [built separately](../linux/README.md), then packaged into Docker images.

## Dependencies

- Crystal binaries for `x86_64` and `aarch64` (targz)
- `docker`

## Environment

- `CRYSTAL_VERSION`: How the binaries should be branded
- `CRYSTAL_TARGZ`: Which crystal.tar.gz file to install in docker images (ubuntu64, alpine)
- `DOCKER_TAG`: How to tag the docker image (examples: `0.27.2`, `nightly20190307`). `-build` will be appended for build images.
- `DOCKER_REPOSITORY`: Docker hub repository to commit image
Loading