From 67fedf1a4a93aed9c1ee1e14a21f4b098dde995e Mon Sep 17 00:00:00 2001 From: Charlie Lye Date: Thu, 9 May 2024 15:41:43 +0100 Subject: [PATCH] feat: build-images as earthly. (#6194) * Converts our build images from Dockerfile to Earthfile. This means we now need to reference the registry image from the devcontainer. Also now means you need earthly to build the build images. * Enables docker-in-docker within our devcontainer. * ARM ci now uses earthly wrapper to pick up the env vars. * Running devcontainer more than once outside vscode will reuse existing container. * If on master we enable the pushing of inline cache. --- .devcontainer/dev/devcontainer.json | 20 +- .devcontainer/dev/docker-in-docker/NOTES.md | 16 + .devcontainer/dev/docker-in-docker/README.md | 53 ++ .../devcontainer-feature.json | 70 ++ .devcontainer/dev/docker-in-docker/install.sh | 624 ++++++++++++++++++ .github/workflows/ci-arm.yml | 4 +- CODEOWNERS | 3 +- build-images/Dockerfile | 351 ---------- build-images/Earthfile | 410 +++++++++++- build-images/Makefile | 58 -- build-images/README.md | 31 +- build-images/entrypoint.sh | 14 +- build-images/install-docker.sh | 624 ++++++++++++++++++ build-images/run.sh | 44 +- scripts/earthly-ci | 6 + 15 files changed, 1870 insertions(+), 458 deletions(-) create mode 100644 .devcontainer/dev/docker-in-docker/NOTES.md create mode 100644 .devcontainer/dev/docker-in-docker/README.md create mode 100644 .devcontainer/dev/docker-in-docker/devcontainer-feature.json create mode 100755 .devcontainer/dev/docker-in-docker/install.sh delete mode 100644 build-images/Dockerfile delete mode 100755 build-images/Makefile create mode 100755 build-images/install-docker.sh diff --git a/.devcontainer/dev/devcontainer.json b/.devcontainer/dev/devcontainer.json index 792ffdbc010..e5fb68ec02e 100644 --- a/.devcontainer/dev/devcontainer.json +++ b/.devcontainer/dev/devcontainer.json @@ -1,22 +1,10 @@ { "name": "Development", - "build": { - "dockerfile": "../../build-images/Dockerfile", - "context": "../../build-images", - "target": "devbox" + "image": "aztecprotocol/devbox:1.0", + "features": { + // Use custom fork with noble added to list of supported distros. + "./docker-in-docker": {} }, "containerUser": "aztec-dev", - // ubuntu:noble is currently not supported. - // Can possibly workaround cherry-picking from here: - // https://github.com/devcontainers/features/blob/main/src/docker-in-docker/install.sh - // - // "image": "aztecprotocol/codespace", - // "features": { - // "docker-in-docker": { - // "version": "latest", - // "moby": true, - // "dockerDashComposeVersion": "v1" - // } - // }, "mounts": ["source=devbox-home,target=/home/aztec-dev,type=volume"] } diff --git a/.devcontainer/dev/docker-in-docker/NOTES.md b/.devcontainer/dev/docker-in-docker/NOTES.md new file mode 100644 index 00000000000..b8156f8b69f --- /dev/null +++ b/.devcontainer/dev/docker-in-docker/NOTES.md @@ -0,0 +1,16 @@ +## Limitations + +This docker-in-docker Dev Container Feature is roughly based on the [official docker-in-docker wrapper script](https://github.com/moby/moby/blob/master/hack/dind) that is part of the [Moby project](https://mobyproject.org/). With this in mind: +* As the name implies, the Feature is expected to work when the host is running Docker (or the OSS Moby container engine it is built on). It may be possible to get running in other container engines, but it has not been tested with them. +* The host and the container must be running on the same chip architecture. You will not be able to use it with an emulated x86 image with Docker Desktop on an Apple Silicon Mac, like in this example: + ``` + FROM --platform=linux/amd64 mcr.microsoft.com/devcontainers/typescript-node:16 + ``` + See [Issue #219](https://github.com/devcontainers/features/issues/219) for more details. + + +## OS Support + +This Feature should work on recent versions of Debian/Ubuntu-based distributions with the `apt` package manager installed. + +`bash` is required to execute the `install.sh` script. diff --git a/.devcontainer/dev/docker-in-docker/README.md b/.devcontainer/dev/docker-in-docker/README.md new file mode 100644 index 00000000000..29e3105c60b --- /dev/null +++ b/.devcontainer/dev/docker-in-docker/README.md @@ -0,0 +1,53 @@ +# Docker (Docker-in-Docker) (docker-in-docker) + +**FORKED HERE TO SUPPORT NOBLE** + +Create child containers _inside_ a container, independent from the host's docker instance. Installs Docker extension in the container along with needed CLIs. + +## Example Usage + +```json +"features": { + "ghcr.io/devcontainers/features/docker-in-docker:2": {} +} +``` + +## Options + +| Options Id | Description | Type | Default Value | +| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------- | ------------- | +| version | Select or enter a Docker/Moby Engine version. (Availability can vary by OS version.) | string | latest | +| moby | Install OSS Moby build instead of Docker CE | boolean | true | +| mobyBuildxVersion | Install a specific version of moby-buildx when using Moby | string | latest | +| dockerDashComposeVersion | Default version of Docker Compose (latest, v2 or none) | string | latest | +| azureDnsAutoDetection | Allow automatically setting the dockerd DNS server when the installation script detects it is running in Azure | boolean | true | +| dockerDefaultAddressPool | Define default address pools for Docker networks. e.g. base=192.168.0.0/16,size=24 | string | - | +| installDockerBuildx | Install Docker Buildx | boolean | true | +| installDockerComposeSwitch | Install Compose Switch (provided docker compose is available) which is a replacement to the Compose V1 docker-compose (python) executable. It translates the command line into Compose V2 docker compose then runs the latter. | boolean | true | + +## Customizations + +### VS Code Extensions + +- `ms-azuretools.vscode-docker` + +## Limitations + +This docker-in-docker Dev Container Feature is roughly based on the [official docker-in-docker wrapper script](https://github.com/moby/moby/blob/master/hack/dind) that is part of the [Moby project](https://mobyproject.org/). With this in mind: + +- As the name implies, the Feature is expected to work when the host is running Docker (or the OSS Moby container engine it is built on). It may be possible to get running in other container engines, but it has not been tested with them. +- The host and the container must be running on the same chip architecture. You will not be able to use it with an emulated x86 image with Docker Desktop on an Apple Silicon Mac, like in this example: + ``` + FROM --platform=linux/amd64 mcr.microsoft.com/devcontainers/typescript-node:16 + ``` + See [Issue #219](https://github.com/devcontainers/features/issues/219) for more details. + +## OS Support + +This Feature should work on recent versions of Debian/Ubuntu-based distributions with the `apt` package manager installed. + +`bash` is required to execute the `install.sh` script. + +--- + +_Note: This file was auto-generated from the [devcontainer-feature.json](https://github.com/devcontainers/features/blob/main/src/docker-in-docker/devcontainer-feature.json). Add additional notes to a `NOTES.md`._ diff --git a/.devcontainer/dev/docker-in-docker/devcontainer-feature.json b/.devcontainer/dev/docker-in-docker/devcontainer-feature.json new file mode 100644 index 00000000000..7b8b472245b --- /dev/null +++ b/.devcontainer/dev/docker-in-docker/devcontainer-feature.json @@ -0,0 +1,70 @@ +{ + "id": "docker-in-docker", + "version": "2.10.2", + "name": "Docker (Docker-in-Docker)", + "documentationURL": "https://github.com/devcontainers/features/tree/main/src/docker-in-docker", + "description": "Create child containers *inside* a container, independent from the host's docker instance. Installs Docker extension in the container along with needed CLIs.", + "options": { + "version": { + "type": "string", + "proposals": ["latest", "none", "20.10"], + "default": "latest", + "description": "Select or enter a Docker/Moby Engine version. (Availability can vary by OS version.)" + }, + "moby": { + "type": "boolean", + "default": true, + "description": "Install OSS Moby build instead of Docker CE" + }, + "mobyBuildxVersion": { + "type": "string", + "default": "latest", + "description": "Install a specific version of moby-buildx when using Moby" + }, + "dockerDashComposeVersion": { + "type": "string", + "enum": ["none", "latest", "v2"], + "default": "latest", + "description": "Default version of Docker Compose (latest, v2 or none)" + }, + "azureDnsAutoDetection": { + "type": "boolean", + "default": true, + "description": "Allow automatically setting the dockerd DNS server when the installation script detects it is running in Azure" + }, + "dockerDefaultAddressPool": { + "type": "string", + "default": "", + "proposals": [], + "description": "Define default address pools for Docker networks. e.g. base=192.168.0.0/16,size=24" + }, + "installDockerBuildx": { + "type": "boolean", + "default": true, + "description": "Install Docker Buildx" + }, + "installDockerComposeSwitch": { + "type": "boolean", + "default": true, + "description": "Install Compose Switch (provided docker compose is available) which is a replacement to the Compose V1 docker-compose (python) executable. It translates the command line into Compose V2 docker compose then runs the latter." + } + }, + "entrypoint": "/usr/local/share/docker-init.sh", + "privileged": true, + "containerEnv": { + "DOCKER_BUILDKIT": "1" + }, + "customizations": { + "vscode": { + "extensions": ["ms-azuretools.vscode-docker"] + } + }, + "mounts": [ + { + "source": "dind-var-lib-docker-${devcontainerId}", + "target": "/var/lib/docker", + "type": "volume" + } + ], + "installsAfter": ["ghcr.io/devcontainers/features/common-utils"] +} diff --git a/.devcontainer/dev/docker-in-docker/install.sh b/.devcontainer/dev/docker-in-docker/install.sh new file mode 100755 index 00000000000..4a433a02220 --- /dev/null +++ b/.devcontainer/dev/docker-in-docker/install.sh @@ -0,0 +1,624 @@ +#!/usr/bin/env bash +#------------------------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information. +#------------------------------------------------------------------------------------------------------------- +# +# Docs: https://github.com/microsoft/vscode-dev-containers/blob/main/script-library/docs/docker-in-docker.md +# Maintainer: The Dev Container spec maintainers + + +DOCKER_VERSION="${VERSION:-"latest"}" # The Docker/Moby Engine + CLI should match in version +USE_MOBY="${MOBY:-"true"}" +MOBY_BUILDX_VERSION="${MOBYBUILDXVERSION:-"latest"}" +DOCKER_DASH_COMPOSE_VERSION="${DOCKERDASHCOMPOSEVERSION:-"latest"}" #latest, v2 or none +AZURE_DNS_AUTO_DETECTION="${AZUREDNSAUTODETECTION:-"true"}" +DOCKER_DEFAULT_ADDRESS_POOL="${DOCKERDEFAULTADDRESSPOOL:-""}" +USERNAME="${USERNAME:-"${_REMOTE_USER:-"automatic"}"}" +INSTALL_DOCKER_BUILDX="${INSTALLDOCKERBUILDX:-"true"}" +INSTALL_DOCKER_COMPOSE_SWITCH="${INSTALLDOCKERCOMPOSESWITCH:-"true"}" +MICROSOFT_GPG_KEYS_URI="https://packages.microsoft.com/keys/microsoft.asc" +DOCKER_MOBY_ARCHIVE_VERSION_CODENAMES="bookworm buster bullseye bionic focal jammy noble" +DOCKER_LICENSED_ARCHIVE_VERSION_CODENAMES="bookworm buster bullseye bionic focal hirsute impish jammy noble" + +# Default: Exit on any failure. +set -e + +# Clean up +rm -rf /var/lib/apt/lists/* + +# Setup STDERR. +err() { + echo "(!) $*" >&2 +} + +if [ "$(id -u)" -ne 0 ]; then + err 'Script must be run as root. Use sudo, su, or add "USER root" to your Dockerfile before running this script.' + exit 1 +fi + +################### +# Helper Functions +# See: https://github.com/microsoft/vscode-dev-containers/blob/main/script-library/shared/utils.sh +################### + +# Determine the appropriate non-root user +if [ "${USERNAME}" = "auto" ] || [ "${USERNAME}" = "automatic" ]; then + USERNAME="" + POSSIBLE_USERS=("vscode" "node" "codespace" "$(awk -v val=1000 -F ":" '$3==val{print $1}' /etc/passwd)") + for CURRENT_USER in "${POSSIBLE_USERS[@]}"; do + if id -u ${CURRENT_USER} > /dev/null 2>&1; then + USERNAME=${CURRENT_USER} + break + fi + done + if [ "${USERNAME}" = "" ]; then + USERNAME=root + fi +elif [ "${USERNAME}" = "none" ] || ! id -u ${USERNAME} > /dev/null 2>&1; then + USERNAME=root +fi + +apt_get_update() +{ + if [ "$(find /var/lib/apt/lists/* | wc -l)" = "0" ]; then + echo "Running apt-get update..." + apt-get update -y + fi +} + +# Checks if packages are installed and installs them if not +check_packages() { + if ! dpkg -s "$@" > /dev/null 2>&1; then + apt_get_update + apt-get -y install --no-install-recommends "$@" + fi +} + +# Figure out correct version of a three part version number is not passed +find_version_from_git_tags() { + local variable_name=$1 + local requested_version=${!variable_name} + if [ "${requested_version}" = "none" ]; then return; fi + local repository=$2 + local prefix=${3:-"tags/v"} + local separator=${4:-"."} + local last_part_optional=${5:-"false"} + if [ "$(echo "${requested_version}" | grep -o "." | wc -l)" != "2" ]; then + local escaped_separator=${separator//./\\.} + local last_part + if [ "${last_part_optional}" = "true" ]; then + last_part="(${escaped_separator}[0-9]+)?" + else + last_part="${escaped_separator}[0-9]+" + fi + local regex="${prefix}\\K[0-9]+${escaped_separator}[0-9]+${last_part}$" + local version_list="$(git ls-remote --tags ${repository} | grep -oP "${regex}" | tr -d ' ' | tr "${separator}" "." | sort -rV)" + if [ "${requested_version}" = "latest" ] || [ "${requested_version}" = "current" ] || [ "${requested_version}" = "lts" ]; then + declare -g ${variable_name}="$(echo "${version_list}" | head -n 1)" + else + set +e + declare -g ${variable_name}="$(echo "${version_list}" | grep -E -m 1 "^${requested_version//./\\.}([\\.\\s]|$)")" + set -e + fi + fi + if [ -z "${!variable_name}" ] || ! echo "${version_list}" | grep "^${!variable_name//./\\.}$" > /dev/null 2>&1; then + err "Invalid ${variable_name} value: ${requested_version}\nValid values:\n${version_list}" >&2 + exit 1 + fi + echo "${variable_name}=${!variable_name}" +} + +# Use semver logic to decrement a version number then look for the closest match +find_prev_version_from_git_tags() { + local variable_name=$1 + local current_version=${!variable_name} + local repository=$2 + # Normally a "v" is used before the version number, but support alternate cases + local prefix=${3:-"tags/v"} + # Some repositories use "_" instead of "." for version number part separation, support that + local separator=${4:-"."} + # Some tools release versions that omit the last digit (e.g. go) + local last_part_optional=${5:-"false"} + # Some repositories may have tags that include a suffix (e.g. actions/node-versions) + local version_suffix_regex=$6 + # Try one break fix version number less if we get a failure. Use "set +e" since "set -e" can cause failures in valid scenarios. + set +e + major="$(echo "${current_version}" | grep -oE '^[0-9]+' || echo '')" + minor="$(echo "${current_version}" | grep -oP '^[0-9]+\.\K[0-9]+' || echo '')" + breakfix="$(echo "${current_version}" | grep -oP '^[0-9]+\.[0-9]+\.\K[0-9]+' 2>/dev/null || echo '')" + + if [ "${minor}" = "0" ] && [ "${breakfix}" = "0" ]; then + ((major=major-1)) + declare -g ${variable_name}="${major}" + # Look for latest version from previous major release + find_version_from_git_tags "${variable_name}" "${repository}" "${prefix}" "${separator}" "${last_part_optional}" + # Handle situations like Go's odd version pattern where "0" releases omit the last part + elif [ "${breakfix}" = "" ] || [ "${breakfix}" = "0" ]; then + ((minor=minor-1)) + declare -g ${variable_name}="${major}.${minor}" + # Look for latest version from previous minor release + find_version_from_git_tags "${variable_name}" "${repository}" "${prefix}" "${separator}" "${last_part_optional}" + else + ((breakfix=breakfix-1)) + if [ "${breakfix}" = "0" ] && [ "${last_part_optional}" = "true" ]; then + declare -g ${variable_name}="${major}.${minor}" + else + declare -g ${variable_name}="${major}.${minor}.${breakfix}" + fi + fi + set -e +} + +# Function to fetch the version released prior to the latest version +get_previous_version() { + local url=$1 + local repo_url=$2 + local variable_name=$3 + prev_version=${!variable_name} + + output=$(curl -s "$repo_url"); + message=$(echo "$output" | jq -r '.message') + + if [[ $message == "API rate limit exceeded"* ]]; then + echo -e "\nAn attempt to find latest version using GitHub Api Failed... \nReason: ${message}" + echo -e "\nAttempting to find latest version using GitHub tags." + find_prev_version_from_git_tags prev_version "$url" "tags/v" + declare -g ${variable_name}="${prev_version}" + else + echo -e "\nAttempting to find latest version using GitHub Api." + version=$(echo "$output" | jq -r '.tag_name') + declare -g ${variable_name}="${version#v}" + fi + echo "${variable_name}=${!variable_name}" +} + +get_github_api_repo_url() { + local url=$1 + echo "${url/https:\/\/github.com/https:\/\/api.github.com\/repos}/releases/latest" +} + +########################################### +# Start docker-in-docker installation +########################################### + +# Ensure apt is in non-interactive to avoid prompts +export DEBIAN_FRONTEND=noninteractive + + +# Source /etc/os-release to get OS info +. /etc/os-release +# Fetch host/container arch. +architecture="$(dpkg --print-architecture)" + +# Check if distro is supported +if [ "${USE_MOBY}" = "true" ]; then + if [[ "${DOCKER_MOBY_ARCHIVE_VERSION_CODENAMES}" != *"${VERSION_CODENAME}"* ]]; then + err "Unsupported distribution version '${VERSION_CODENAME}'. To resolve, either: (1) set feature option '\"moby\": false' , or (2) choose a compatible OS distribution" + err "Support distributions include: ${DOCKER_MOBY_ARCHIVE_VERSION_CODENAMES}" + exit 1 + fi + echo "Distro codename '${VERSION_CODENAME}' matched filter '${DOCKER_MOBY_ARCHIVE_VERSION_CODENAMES}'" +else + if [[ "${DOCKER_LICENSED_ARCHIVE_VERSION_CODENAMES}" != *"${VERSION_CODENAME}"* ]]; then + err "Unsupported distribution version '${VERSION_CODENAME}'. To resolve, please choose a compatible OS distribution" + err "Support distributions include: ${DOCKER_LICENSED_ARCHIVE_VERSION_CODENAMES}" + exit 1 + fi + echo "Distro codename '${VERSION_CODENAME}' matched filter '${DOCKER_LICENSED_ARCHIVE_VERSION_CODENAMES}'" +fi + +# Install dependencies +check_packages apt-transport-https curl ca-certificates pigz iptables gnupg2 dirmngr wget jq +if ! type git > /dev/null 2>&1; then + check_packages git +fi + +# Swap to legacy iptables for compatibility +if type iptables-legacy > /dev/null 2>&1; then + update-alternatives --set iptables /usr/sbin/iptables-legacy + update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy +fi + + + +# Set up the necessary apt repos (either Microsoft's or Docker's) +if [ "${USE_MOBY}" = "true" ]; then + + # Name of open source engine/cli + engine_package_name="moby-engine" + cli_package_name="moby-cli" + + # Import key safely and import Microsoft apt repo + curl -sSL ${MICROSOFT_GPG_KEYS_URI} | gpg --dearmor > /usr/share/keyrings/microsoft-archive-keyring.gpg + echo "deb [arch=${architecture} signed-by=/usr/share/keyrings/microsoft-archive-keyring.gpg] https://packages.microsoft.com/repos/microsoft-${ID}-${VERSION_CODENAME}-prod ${VERSION_CODENAME} main" > /etc/apt/sources.list.d/microsoft.list +else + # Name of licensed engine/cli + engine_package_name="docker-ce" + cli_package_name="docker-ce-cli" + + # Import key safely and import Docker apt repo + curl -fsSL https://download.docker.com/linux/${ID}/gpg | gpg --dearmor > /usr/share/keyrings/docker-archive-keyring.gpg + echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/${ID} ${VERSION_CODENAME} stable" > /etc/apt/sources.list.d/docker.list +fi + +# Refresh apt lists +apt-get update + +# Soft version matching +if [ "${DOCKER_VERSION}" = "latest" ] || [ "${DOCKER_VERSION}" = "lts" ] || [ "${DOCKER_VERSION}" = "stable" ]; then + # Empty, meaning grab whatever "latest" is in apt repo + engine_version_suffix="" + cli_version_suffix="" +else + # Fetch a valid version from the apt-cache (eg: the Microsoft repo appends +azure, breakfix, etc...) + docker_version_dot_escaped="${DOCKER_VERSION//./\\.}" + docker_version_dot_plus_escaped="${docker_version_dot_escaped//+/\\+}" + # Regex needs to handle debian package version number format: https://www.systutorials.com/docs/linux/man/5-deb-version/ + docker_version_regex="^(.+:)?${docker_version_dot_plus_escaped}([\\.\\+ ~:-]|$)" + set +e # Don't exit if finding version fails - will handle gracefully + cli_version_suffix="=$(apt-cache madison ${cli_package_name} | awk -F"|" '{print $2}' | sed -e 's/^[ \t]*//' | grep -E -m 1 "${docker_version_regex}")" + engine_version_suffix="=$(apt-cache madison ${engine_package_name} | awk -F"|" '{print $2}' | sed -e 's/^[ \t]*//' | grep -E -m 1 "${docker_version_regex}")" + set -e + if [ -z "${engine_version_suffix}" ] || [ "${engine_version_suffix}" = "=" ] || [ -z "${cli_version_suffix}" ] || [ "${cli_version_suffix}" = "=" ] ; then + err "No full or partial Docker / Moby version match found for \"${DOCKER_VERSION}\" on OS ${ID} ${VERSION_CODENAME} (${architecture}). Available versions:" + apt-cache madison ${cli_package_name} | awk -F"|" '{print $2}' | grep -oP '^(.+:)?\K.+' + exit 1 + fi + echo "engine_version_suffix ${engine_version_suffix}" + echo "cli_version_suffix ${cli_version_suffix}" +fi + +# Version matching for moby-buildx +if [ "${USE_MOBY}" = "true" ]; then + if [ "${MOBY_BUILDX_VERSION}" = "latest" ]; then + # Empty, meaning grab whatever "latest" is in apt repo + buildx_version_suffix="" + else + buildx_version_dot_escaped="${MOBY_BUILDX_VERSION//./\\.}" + buildx_version_dot_plus_escaped="${buildx_version_dot_escaped//+/\\+}" + buildx_version_regex="^(.+:)?${buildx_version_dot_plus_escaped}([\\.\\+ ~:-]|$)" + set +e + buildx_version_suffix="=$(apt-cache madison moby-buildx | awk -F"|" '{print $2}' | sed -e 's/^[ \t]*//' | grep -E -m 1 "${buildx_version_regex}")" + set -e + if [ -z "${buildx_version_suffix}" ] || [ "${buildx_version_suffix}" = "=" ]; then + err "No full or partial moby-buildx version match found for \"${MOBY_BUILDX_VERSION}\" on OS ${ID} ${VERSION_CODENAME} (${architecture}). Available versions:" + apt-cache madison moby-buildx | awk -F"|" '{print $2}' | grep -oP '^(.+:)?\K.+' + exit 1 + fi + echo "buildx_version_suffix ${buildx_version_suffix}" + fi +fi + +# Install Docker / Moby CLI if not already installed +if type docker > /dev/null 2>&1 && type dockerd > /dev/null 2>&1; then + echo "Docker / Moby CLI and Engine already installed." +else + if [ "${USE_MOBY}" = "true" ]; then + # Install engine + set +e # Handle error gracefully + apt-get -y install --no-install-recommends moby-cli${cli_version_suffix} moby-buildx${buildx_version_suffix} moby-engine${engine_version_suffix} + exit_code=$? + set -e + + if [ ${exit_code} -ne 0 ]; then + err "Packages for moby not available in OS ${ID} ${VERSION_CODENAME} (${architecture}). To resolve, either: (1) set feature option '\"moby\": false' , or (2) choose a compatible OS version (eg: 'ubuntu-20.04')." + exit 1 + fi + + # Install compose + apt-get -y install --no-install-recommends moby-compose || err "Package moby-compose (Docker Compose v2) not available for OS ${ID} ${VERSION_CODENAME} (${architecture}). Skipping." + else + apt-get -y install --no-install-recommends docker-ce-cli${cli_version_suffix} docker-ce${engine_version_suffix} + # Install compose + apt-get -y install --no-install-recommends docker-compose-plugin || echo "(*) Package docker-compose-plugin (Docker Compose v2) not available for OS ${ID} ${VERSION_CODENAME} (${architecture}). Skipping." + fi +fi + +echo "Finished installing docker / moby!" + +docker_home="/usr/libexec/docker" +cli_plugins_dir="${docker_home}/cli-plugins" + +# fallback for docker-compose +fallback_compose(){ + local url=$1 + local repo_url=$(get_github_api_repo_url "$url") + echo -e "\n(!) Failed to fetch the latest artifacts for docker-compose v${compose_version}..." + get_previous_version "${url}" "${repo_url}" compose_version + echo -e "\nAttempting to install v${compose_version}" + curl -fsSL "https://github.com/docker/compose/releases/download/v${compose_version}/docker-compose-linux-${target_compose_arch}" -o ${docker_compose_path} +} + +# If 'docker-compose' command is to be included +if [ "${DOCKER_DASH_COMPOSE_VERSION}" != "none" ]; then + case "${architecture}" in + amd64) target_compose_arch=x86_64 ;; + arm64) target_compose_arch=aarch64 ;; + *) + echo "(!) Docker in docker does not support machine architecture '$architecture'. Please use an x86-64 or ARM64 machine." + exit 1 + esac + + docker_compose_path="/usr/local/bin/docker-compose" + if [ "${DOCKER_DASH_COMPOSE_VERSION}" = "v1" ]; then + err "The final Compose V1 release, version 1.29.2, was May 10, 2021. These packages haven't received any security updates since then. Use at your own risk." + INSTALL_DOCKER_COMPOSE_SWITCH="false" + + if [ "${target_compose_arch}" = "x86_64" ]; then + echo "(*) Installing docker compose v1..." + curl -fsSL "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-Linux-x86_64" -o ${docker_compose_path} + chmod +x ${docker_compose_path} + + # Download the SHA256 checksum + DOCKER_COMPOSE_SHA256="$(curl -sSL "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-Linux-x86_64.sha256" | awk '{print $1}')" + echo "${DOCKER_COMPOSE_SHA256} ${docker_compose_path}" > docker-compose.sha256sum + sha256sum -c docker-compose.sha256sum --ignore-missing + elif [ "${VERSION_CODENAME}" = "bookworm" ]; then + err "Docker compose v1 is unavailable for 'bookworm' on Arm64. Kindly switch to use v2" + exit 1 + else + # Use pip to get a version that runs on this architecture + check_packages python3-minimal python3-pip libffi-dev python3-venv + echo "(*) Installing docker compose v1 via pip..." + export PYTHONUSERBASE=/usr/local + pip3 install --disable-pip-version-check --no-cache-dir --user "Cython<3.0" pyyaml wheel docker-compose --no-build-isolation + fi + else + compose_version=${DOCKER_DASH_COMPOSE_VERSION#v} + docker_compose_url="https://github.com/docker/compose" + find_version_from_git_tags compose_version "$docker_compose_url" "tags/v" + echo "(*) Installing docker-compose ${compose_version}..." + curl -fsSL "https://github.com/docker/compose/releases/download/v${compose_version}/docker-compose-linux-${target_compose_arch}" -o ${docker_compose_path} || { + if [[ $DOCKER_DASH_COMPOSE_VERSION == "latest" ]]; then + fallback_compose "$docker_compose_url" + else + echo -e "Error: Failed to install docker-compose v${compose_version}" + fi + } + + chmod +x ${docker_compose_path} + + # Download the SHA256 checksum + DOCKER_COMPOSE_SHA256="$(curl -sSL "https://github.com/docker/compose/releases/download/v${compose_version}/docker-compose-linux-${target_compose_arch}.sha256" | awk '{print $1}')" + echo "${DOCKER_COMPOSE_SHA256} ${docker_compose_path}" > docker-compose.sha256sum + sha256sum -c docker-compose.sha256sum --ignore-missing + + mkdir -p ${cli_plugins_dir} + cp ${docker_compose_path} ${cli_plugins_dir} + fi +fi + +# fallback method for compose-switch +fallback_compose-switch() { + local url=$1 + local repo_url=$(get_github_api_repo_url "$url") + echo -e "\n(!) Failed to fetch the latest artifacts for compose-switch v${compose_switch_version}..." + get_previous_version "$url" "$repo_url" compose_switch_version + echo -e "\nAttempting to install v${compose_switch_version}" + curl -fsSL "https://github.com/docker/compose-switch/releases/download/v${compose_switch_version}/docker-compose-linux-${architecture}" -o /usr/local/bin/compose-switch +} + +# Install docker-compose switch if not already installed - https://github.com/docker/compose-switch#manual-installation +if [ "${INSTALL_DOCKER_COMPOSE_SWITCH}" = "true" ] && ! type compose-switch > /dev/null 2>&1; then + if type docker-compose > /dev/null 2>&1; then + echo "(*) Installing compose-switch..." + current_compose_path="$(which docker-compose)" + target_compose_path="$(dirname "${current_compose_path}")/docker-compose-v1" + compose_switch_version="latest" + compose_switch_url="https://github.com/docker/compose-switch" + find_version_from_git_tags compose_switch_version "$compose_switch_url" + curl -fsSL "https://github.com/docker/compose-switch/releases/download/v${compose_switch_version}/docker-compose-linux-${architecture}" -o /usr/local/bin/compose-switch || fallback_compose-switch "$compose_switch_url" + chmod +x /usr/local/bin/compose-switch + # TODO: Verify checksum once available: https://github.com/docker/compose-switch/issues/11 + # Setup v1 CLI as alternative in addition to compose-switch (which maps to v2) + mv "${current_compose_path}" "${target_compose_path}" + update-alternatives --install ${docker_compose_path} docker-compose /usr/local/bin/compose-switch 99 + update-alternatives --install ${docker_compose_path} docker-compose "${target_compose_path}" 1 + else + err "Skipping installation of compose-switch as docker compose is unavailable..." + fi +fi + +# If init file already exists, exit +if [ -f "/usr/local/share/docker-init.sh" ]; then + echo "/usr/local/share/docker-init.sh already exists, so exiting." + # Clean up + rm -rf /var/lib/apt/lists/* + exit 0 +fi +echo "docker-init doesn't exist, adding..." + +if ! cat /etc/group | grep -e "^docker:" > /dev/null 2>&1; then + groupadd -r docker +fi + +usermod -aG docker ${USERNAME} + +# fallback for docker/buildx +fallback_buildx() { + local url=$1 + local repo_url=$(get_github_api_repo_url "$url") + echo -e "\n(!) Failed to fetch the latest artifacts for docker buildx v${buildx_version}..." + get_previous_version "$url" "$repo_url" buildx_version + buildx_file_name="buildx-v${buildx_version}.linux-${architecture}" + echo -e "\nAttempting to install v${buildx_version}" + wget https://github.com/docker/buildx/releases/download/v${buildx_version}/${buildx_file_name} +} + +if [ "${INSTALL_DOCKER_BUILDX}" = "true" ]; then + buildx_version="latest" + docker_buildx_url="https://github.com/docker/buildx" + find_version_from_git_tags buildx_version "$docker_buildx_url" "refs/tags/v" + echo "(*) Installing buildx ${buildx_version}..." + buildx_file_name="buildx-v${buildx_version}.linux-${architecture}" + + cd /tmp + wget https://github.com/docker/buildx/releases/download/v${buildx_version}/${buildx_file_name} || fallback_buildx "$docker_buildx_url" + + docker_home="/usr/libexec/docker" + cli_plugins_dir="${docker_home}/cli-plugins" + + mkdir -p ${cli_plugins_dir} + mv ${buildx_file_name} ${cli_plugins_dir}/docker-buildx + chmod +x ${cli_plugins_dir}/docker-buildx + + chown -R "${USERNAME}:docker" "${docker_home}" + chmod -R g+r+w "${docker_home}" + find "${docker_home}" -type d -print0 | xargs -n 1 -0 chmod g+s +fi + +tee /usr/local/share/docker-init.sh > /dev/null \ +<< EOF +#!/bin/sh +#------------------------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information. +#------------------------------------------------------------------------------------------------------------- + +set -e + +AZURE_DNS_AUTO_DETECTION=${AZURE_DNS_AUTO_DETECTION} +DOCKER_DEFAULT_ADDRESS_POOL=${DOCKER_DEFAULT_ADDRESS_POOL} +EOF + +tee -a /usr/local/share/docker-init.sh > /dev/null \ +<< 'EOF' +dockerd_start="AZURE_DNS_AUTO_DETECTION=${AZURE_DNS_AUTO_DETECTION} DOCKER_DEFAULT_ADDRESS_POOL=${DOCKER_DEFAULT_ADDRESS_POOL} $(cat << 'INNEREOF' + # explicitly remove dockerd and containerd PID file to ensure that it can start properly if it was stopped uncleanly + find /run /var/run -iname 'docker*.pid' -delete || : + find /run /var/run -iname 'container*.pid' -delete || : + + # -- Start: dind wrapper script -- + # Maintained: https://github.com/moby/moby/blob/master/hack/dind + + export container=docker + + if [ -d /sys/kernel/security ] && ! mountpoint -q /sys/kernel/security; then + mount -t securityfs none /sys/kernel/security || { + echo >&2 'Could not mount /sys/kernel/security.' + echo >&2 'AppArmor detection and --privileged mode might break.' + } + fi + + # Mount /tmp (conditionally) + if ! mountpoint -q /tmp; then + mount -t tmpfs none /tmp + fi + + set_cgroup_nesting() + { + # cgroup v2: enable nesting + if [ -f /sys/fs/cgroup/cgroup.controllers ]; then + # move the processes from the root group to the /init group, + # otherwise writing subtree_control fails with EBUSY. + # An error during moving non-existent process (i.e., "cat") is ignored. + mkdir -p /sys/fs/cgroup/init + xargs -rn1 < /sys/fs/cgroup/cgroup.procs > /sys/fs/cgroup/init/cgroup.procs || : + # enable controllers + sed -e 's/ / +/g' -e 's/^/+/' < /sys/fs/cgroup/cgroup.controllers \ + > /sys/fs/cgroup/cgroup.subtree_control + fi + } + + # Set cgroup nesting, retrying if necessary + retry_cgroup_nesting=0 + + until [ "${retry_cgroup_nesting}" -eq "5" ]; + do + set +e + set_cgroup_nesting + + if [ $? -ne 0 ]; then + echo "(*) cgroup v2: Failed to enable nesting, retrying..." + else + break + fi + + retry_cgroup_nesting=`expr $retry_cgroup_nesting + 1` + set -e + done + + # -- End: dind wrapper script -- + + # Handle DNS + set +e + cat /etc/resolv.conf | grep -i 'internal.cloudapp.net' > /dev/null 2>&1 + if [ $? -eq 0 ] && [ "${AZURE_DNS_AUTO_DETECTION}" = "true" ] + then + echo "Setting dockerd Azure DNS." + CUSTOMDNS="--dns 168.63.129.16" + else + echo "Not setting dockerd DNS manually." + CUSTOMDNS="" + fi + set -e + + if [ -z "$DOCKER_DEFAULT_ADDRESS_POOL" ] + then + DEFAULT_ADDRESS_POOL="" + else + DEFAULT_ADDRESS_POOL="--default-address-pool $DOCKER_DEFAULT_ADDRESS_POOL" + fi + + # Start docker/moby engine + ( dockerd $CUSTOMDNS $DEFAULT_ADDRESS_POOL > /tmp/dockerd.log 2>&1 ) & +INNEREOF +)" + +sudo_if() { + COMMAND="$*" + + if [ "$(id -u)" -ne 0 ]; then + sudo $COMMAND + else + $COMMAND + fi +} + +retry_docker_start_count=0 +docker_ok="false" + +until [ "${docker_ok}" = "true" ] || [ "${retry_docker_start_count}" -eq "5" ]; +do + # Start using sudo if not invoked as root + if [ "$(id -u)" -ne 0 ]; then + sudo /bin/sh -c "${dockerd_start}" + else + eval "${dockerd_start}" + fi + + retry_count=0 + until [ "${docker_ok}" = "true" ] || [ "${retry_count}" -eq "5" ]; + do + sleep 1s + set +e + docker info > /dev/null 2>&1 && docker_ok="true" + set -e + + retry_count=`expr $retry_count + 1` + done + + if [ "${docker_ok}" != "true" ] && [ "${retry_docker_start_count}" != "4" ]; then + echo "(*) Failed to start docker, retrying..." + set +e + sudo_if pkill dockerd + sudo_if pkill containerd + set -e + fi + + retry_docker_start_count=`expr $retry_docker_start_count + 1` +done + +# Execute whatever commands were passed in (if any). This allows us +# to set this script to ENTRYPOINT while still executing the default CMD. +exec "$@" +EOF + +chmod +x /usr/local/share/docker-init.sh +chown ${USERNAME}:root /usr/local/share/docker-init.sh + +# Clean up +rm -rf /var/lib/apt/lists/* + +echo 'docker-in-docker-debian script has completed!' diff --git a/.github/workflows/ci-arm.yml b/.github/workflows/ci-arm.yml index 3317870ec5f..c750b142724 100644 --- a/.github/workflows/ci-arm.yml +++ b/.github/workflows/ci-arm.yml @@ -44,7 +44,7 @@ jobs: # prepare images locally, tagged by commit hash - name: "Build E2E Image" timeout-minutes: 40 - run: earthly ./yarn-project+export-e2e-test-images + run: earthly-ci ./yarn-project+export-e2e-test-images # all the end-to-end integration tests for aztec e2e: @@ -62,7 +62,7 @@ jobs: - name: Test working-directory: ./yarn-project/end-to-end/ timeout-minutes: 15 - run: earthly -P --no-output +uniswap-trade-on-l1-from-l2 + run: earthly-ci -P --no-output +uniswap-trade-on-l1-from-l2 notify: needs: [e2e] diff --git a/CODEOWNERS b/CODEOWNERS index cdd57834a49..37be432af89 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1,5 +1,4 @@ -/build-system/ @charlielye -/build_manifest.yml @charlielye +/build-images/ @charlielye # Notify the AVM team of any changes to public oracle. /yarn-project/simulator/src/public/public_execution_context.ts @Maddiaa0 @fcarreiro @dbanks12 diff --git a/build-images/Dockerfile b/build-images/Dockerfile deleted file mode 100644 index 893c93fe4c0..00000000000 --- a/build-images/Dockerfile +++ /dev/null @@ -1,351 +0,0 @@ -######################################################################################################################## -# Build wasi-sdk. -FROM ubuntu:noble AS wasi-sdk-build -RUN apt update && apt install -y \ - clang \ - cmake \ - ninja-build \ - git \ - cargo -RUN git clone --depth 1 --recursive --branch wasi-sdk-22 \ - https://github.com/WebAssembly/wasi-sdk.git -RUN mkdir -p /wasi-sdk/build/install/opt/wasi-sdk -WORKDIR /wasi-sdk -ENV MAKEFLAGS="-j$(nproc)" -RUN make build/llvm.BUILT -RUN make build/wasi-libc.BUILT -RUN make build/compiler-rt.BUILT -RUN make build/libcxx.BUILT -RUN make build/config.BUILT -RUN make build/version.BUILT -RUN mv build/install/opt/wasi-sdk /opt/wasi-sdk -FROM ubuntu:noble AS wasi-sdk -COPY --from=wasi-sdk-build /opt/wasi-sdk /opt/wasi-sdk - -######################################################################################################################## -# Build osxcross. -FROM ubuntu:noble AS osxcross-build -RUN export DEBIAN_FRONTEND="noninteractive" \ - && apt-get update \ - && apt-get install --no-install-recommends -y \ - bash \ - binutils-multiarch-dev \ - build-essential \ - ca-certificates \ - clang \ - git \ - libbz2-dev \ - libmpc-dev \ - libmpfr-dev \ - libgmp-dev \ - liblzma-dev \ - libpsi3-dev \ - libssl-dev \ - libxml2-dev \ - libz-dev \ - lzma-dev \ - make \ - patch \ - python3 \ - uuid-dev \ - wget \ - xz-utils \ - zlib1g-dev \ - cmake \ - curl \ - && apt-get -y autoremove \ - && apt-get clean \ - && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* -WORKDIR /usr/src/osxcross -ARG OSX_CROSS_COMMIT="ff8d100f3f026b4ffbe4ce96d8aac4ce06f1278b" -RUN git clone https://github.com/tpoechtrager/osxcross.git . && git reset --hard $OSX_CROSS_COMMIT -ARG OSX_SDK="MacOSX14.0.sdk" -ARG OSX_SDK_URL="https://github.com/joseluisq/macosx-sdks/releases/download/14.0/${OSX_SDK}.tar.xz" -RUN curl -sSL "$OSX_SDK_URL" -o "./tarballs/$OSX_SDK.tar.xz" \ - && OSX_VERSION_MIN=14.0 UNATTENDED=1 ENABLE_COMPILER_RT_INSTALL=1 TARGET_DIR=/opt/osxcross ./build.sh \ - && rm -rf ./tarballs/$OSX_SDK.tar.xz /opt/osxcross/SDK/$OSX_SDK -FROM scratch AS osxcross -COPY --from=osxcross-build /opt/osxcross /opt/osxcross - -######################################################################################################################## -# Build foundry. -FROM ubuntu:noble AS foundry-build -RUN apt update && apt install -y git cargo -ARG TAG -RUN ulimit -n 65535 && \ - git clone --depth 1 --branch nightly-$TAG \ - https://github.com/foundry-rs/foundry.git && \ - cd foundry && cargo build --profile local && \ - mkdir -p /opt/foundry/bin && \ - for t in forge cast anvil chisel; do \ - mv ./target/local/$t /opt/foundry/bin/$t; \ - strip /opt/foundry/bin/$t; \ - done -FROM ubuntu:noble AS foundry -COPY --from=foundry-build /opt/foundry /opt/foundry -ENV PATH="/opt/foundry/bin:$PATH" - -######################################################################################################################## -# This image contains *just* what's needed to perform a full build of the aztec project. -# It acts as the base image for all CI builds, and we build on it to produce a developer box. -FROM ubuntu:noble as build -RUN apt update && \ - apt install -y \ - # Utils - curl \ - git \ - curl \ - wget \ - jq \ - gawk \ - unzip \ - netcat-openbsd \ - parallel \ - # C++ (clang=18, which we will move to. 16 is for current build.) - build-essential \ - cmake \ - ninja-build \ - clang \ - clang-16 \ - clang-format-16 \ - libc++-dev \ - libomp-dev \ - doxygen \ - # Node (18.19.1) - nodejs \ - npm \ - # Python (clang bindings for wasm bindgen.) - python3 \ - python3-clang \ - && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* - -# Install wasi-sdk. -COPY --from=aztecprotocol/wasi-sdk:22.0 /opt/wasi-sdk /opt/wasi-sdk - -# Install osxcross. Requires developer to mount SDK from their mac host. -COPY --from=aztecprotocol/osxcross:14.0 /opt/osxcross /opt/osxcross -ENV PATH="/opt/osxcross/bin:$PATH" -ENV LD_LIBRARY_PATH="/opt/osxcross/lib:$LD_LIBRARY_PATH" - -# Install foundry. -COPY --from=aztecprotocol/foundry:de33b6af53005037b463318d2628b5cfcaf39916 /opt/foundry /opt/foundry -ENV PATH="/opt/foundry/bin:$PATH" - -# Install rust and cross-compilers. Noir specifically uses 1.74.1. -# We add everyone write ownership so downstream boxes can write. -ENV RUSTUP_HOME=/opt/rust/rustup \ - CARGO_HOME=/opt/rust/cargo \ - PATH="/opt/rust/cargo/bin:$PATH" -RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain 1.74.1 && \ - rustup target add wasm32-unknown-unknown wasm32-wasi aarch64-apple-darwin && \ - chmod -R a+w /opt/rust - -# Install yq -RUN curl -sL https://github.com/mikefarah/yq/releases/download/v4.42.1/yq_linux_$(dpkg --print-architecture) \ - -o /usr/local/bin/yq && chmod +x /usr/local/bin/yq - -# Install yarn -RUN npm install --global yarn - -# Install solhint -RUN npm install --global solhint - -######################################################################################################################## -# We want to produce downstream images: codespace, devbox and sysbox. This image is the base image for each. -# It contains a suite of tools that developers might use to develop aztec. -FROM build as basebox -RUN yes | unminimize - -# Install stuff devs need. -RUN apt update && \ - apt install -y \ - zsh \ - fzf \ - libfuse2 \ - iproute2 \ - iputils-ping \ - telnet \ - lsb-release \ - tmux \ - vim \ - software-properties-common \ - gnupg \ - htop \ - cgroup-tools \ - neovim \ - sudo \ - clangd-16 \ - man \ - python3-blessed \ - && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* - -# Install earthly. -RUN wget https://github.com/earthly/earthly/releases/latest/download/earthly-linux-$(dpkg --print-architecture) -O /usr/local/bin/earthly && \ - chmod +x /usr/local/bin/earthly - -# Install gh (github cli). -RUN mkdir -p -m 755 /etc/apt/keyrings && wget -qO- https://cli.github.com/packages/githubcli-archive-keyring.gpg > /etc/apt/keyrings/githubcli-archive-keyring.gpg \ - && chmod go+r /etc/apt/keyrings/githubcli-archive-keyring.gpg \ - && echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | tee /etc/apt/sources.list.d/github-cli.list > /dev/null \ - && apt update \ - && apt install gh -y - -# Install gt (graphite). -RUN npm install -g @withgraphite/graphite-cli@stable - -# Install aws cli. -RUN curl "https://awscli.amazonaws.com/awscli-exe-linux-$(uname -m).zip" -o "awscliv2.zip" && \ - unzip awscliv2.zip && \ - ./aws/install --bin-dir /usr/local/bin --install-dir /usr/local/aws-cli --update && \ - rm -rf aws awscliv2.zip - -# Install terraform. -RUN curl -fsSL https://releases.hashicorp.com/terraform/1.7.5/terraform_1.7.5_linux_$(dpkg --print-architecture).zip -o terraform.zip \ - && unzip terraform.zip -d /usr/local/bin \ - && chmod +x /usr/local/bin/terraform \ - && rm terraform.zip - -# fzf seems to not install this file for some reason. -COPY ./key-bindings.zsh /usr/share/doc/fzf/examples/key-bindings.zsh - -# Sets LANG explicitly. Ensures tmux shows unicode symbols. -# Sets RUSTUP_HOME. -# Adds foundry and cargo bin dirs to PATH. -COPY environment /etc/environment - -# Cargo home and bin path should be set within users home dir at login. -RUN echo 'export CARGO_HOME="$HOME/.cargo"' >> /etc/zsh/zshenv -RUN echo 'export PATH="$HOME/.cargo/bin:$PATH"' >> /etc/zsh/zshenv - -# sudo group can sudo without password. -RUN echo '%sudo ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers - -######################################################################################################################## -# This devbox container can be used to provide a full development environment. -# -# It can be used as a dev container: -# - Configuration in .devcontainer/devcontainer.json. -# - To run locally install "Dev Containers" plugin in vscode. -# - To run in GitHub codespaces, visit the repo in github, press '.', and open the terminal. -# -# It can be used independently: -# - The user should use the ./run.sh script to launch. -# - A persistent volume will be mounted to /home/aztec-dev. -# - It provides docker via the hosts docker instance, mounted at /var/lib/docker.sock. -# - It uses an entrypoint script at runtime to perform uid/gid alignment with the host and drop into user account. -FROM basebox as devbox - -# Install docker client. Will use mounted host docker socket. -RUN curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --batch --yes --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg \ - && echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" \ - | tee /etc/apt/sources.list.d/docker.list > /dev/null \ - && apt-get update && apt-get install -y docker-ce-cli -ADD https://raw.githubusercontent.com/docker/docker-ce/master/components/cli/contrib/completion/bash/docker /etc/bash_completion.d/docker.sh - -RUN apt install -y gosu -ENV TERM=xterm-256color -# Detect if the host machine is Mac, if so set an env var, and disable prompts vcs info for performance. -RUN <> /etc/zsh/zshrc -EOF -# Create the user we'll run as and become the user. -RUN useradd --shell /bin/zsh -G sudo -m aztec-dev -USER aztec-dev -WORKDIR /home/aztec-dev -# Add dotfiles. -COPY --chown=aztec-dev:aztec-dev home . -# The .npmrc config is set to install global bins here, update PATH. -ENV PATH=/home/aztec-dev/.npm-global/bin:$PATH -# Need to ensure correct permissions, under some conditions these would otherwise be created by root. -RUN mkdir .vscode-server .npm-global .ssh -# Switch back to root. Gives option for root runtime adjustments before becoming aztec-dev. -USER root -# Use as entrypoint when running in an environment that requires uid/gid alignment (e.g. vanilla linux docker). -COPY ./entrypoint.sh /entrypoint.sh -ENTRYPOINT ["/entrypoint.sh"] -CMD ["/bin/zsh"] - -######################################################################################################################## -# This sysbox container can be used to provide a full development environment. -# It's more advanced than devbox in that it uses nestybox's sysbox container runtime to provide more of a vm experience. -# It's used primarily by internal aztec developers who have sysboxes running on a powerful underlying mainframe. -# It provides better isolation and security guarantees than a plain devbox. -FROM basebox AS sysbox - -###################### START OF STOCK NESTYBOX SYSTEMD CONTAINER ############################### -# -# Systemd installation -# -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - systemd \ - systemd-sysv \ - libsystemd0 \ - ca-certificates \ - dbus \ - iptables \ - iproute2 \ - kmod \ - locales \ - sudo \ - udev && \ - \ - # Prevents journald from reading kernel messages from /dev/kmsg - echo "ReadKMsg=no" >> /etc/systemd/journald.conf && \ - \ - # Housekeeping - apt-get clean -y && \ - rm -rf \ - /var/cache/debconf/* \ - /var/lib/apt/lists/* \ - /var/log/* \ - /tmp/* \ - /var/tmp/* \ - /usr/share/local/* && \ - \ - # Create default 'ubuntu/ubuntu' user - echo "ubuntu:ubuntu" | chpasswd && adduser ubuntu sudo - -# Disable systemd services/units that are unnecessary within a container. -RUN systemctl mask systemd-udevd.service \ - systemd-udevd-kernel.socket \ - systemd-udevd-control.socket \ - systemd-modules-load.service \ - sys-kernel-config.mount \ - sys-kernel-debug.mount \ - sys-kernel-tracing.mount \ - e2scrub_reap.service - -# Make use of stopsignal (instead of sigterm) to stop systemd containers. -STOPSIGNAL SIGRTMIN+3 - -# Set systemd as entrypoint. -ENTRYPOINT [ "/sbin/init", "--log-level=err" ] - -###################### END OF STOCK NESTYBOX SYSTEMD CONTAINER ############################### - -# Install docker. -RUN curl -fsSL https://get.docker.com -o get-docker.sh && sh get-docker.sh \ - # Add user "ubuntu" to the Docker group - && usermod -a -G docker ubuntu -ADD https://raw.githubusercontent.com/docker/docker-ce/master/components/cli/contrib/completion/bash/docker /etc/bash_completion.d/docker.sh - -# Install sshd. -RUN apt install --no-install-recommends -y openssh-server \ - && rm -rf /var/lib/apt/lists/* \ - && mkdir /home/ubuntu/.ssh \ - && chown ubuntu:ubuntu /home/ubuntu/.ssh \ - && echo 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDagCvr/+CA1jmFaJf+e9+Kw6iwfhvaKOpfbGEl5zLgB+rum5L4Kga6Jow1gLQeMnAHfqc2IgpsU4t04c8PYApAt8AWNDL+KxMiFytfjKfJ2DZJA73CYkFnkfnMtU+ki+JG9dAHd6m7ShtCSzE5n6EDO2yWCVWQfqE3dcnpwrymSWkJYrbxzeOixiNZ4f1nD9ddvFvTWGB4l+et5SWgeIaYgJYDqTI2teRt9ytJiDGrCWXs9olHsCZOL6TEJPUQmNekwBkjMAZ4TmbBMjwbUlIxOpW2UxzlONcNn7IlRcGQg0Gdbkpo/zOlCNXsvacvnphDk5vKKaQj+aQiG916LU5P charlie@aztecprotocol.com' >> /home/ubuntu/.ssh/authorized_keys \ - && echo 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDb5OVc+9S9nXx3/34F7eLVXjoPgQ3YHSdlfhTb8WflAGmpKJTLxtAYngtDBvhKofH5HrjPPkBWxOHP9KOTo0jxUQSr0suMpggLLOHuIrCszJKXIVi7whnQ4p2RHyzyS2ANwmpxWZmYxfgamzYst9JIvQYJgAPjTFweKBsG/Lc03knJ/qgz9BHqDSZHweMTnhv1dJNhZRKy1Lxyl/CjXKF374i8qbzVWJMeDgLEH6C84vCeaH89KMmM9J0+T31uEqxzIhZxNmRz9v+x6cQAVJtGi9OIveGT9qUQwKXZsk6/zorzxV+NiIvTWHxIn9epX/FUjgUmb/jFvpbEjDkbIngj adomurad@localhost.localdomain' >> /home/ubuntu/.ssh/authorized_keys \ - && echo 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFKlUeOh9DyAL85NJ10LE+nyfi8oYm+CwxQ9JMaB6H+t root@mainframe' >> /home/ubuntu/.ssh/authorized_keys \ - && chown ubuntu:ubuntu /home/ubuntu/.ssh/authorized_keys - -# Install google authenticator for setting up 2fa. -RUN apt update && apt install -y libpam-google-authenticator - -EXPOSE 22 diff --git a/build-images/Earthfile b/build-images/Earthfile index f546ee73556..7bdc6934d84 100644 --- a/build-images/Earthfile +++ b/build-images/Earthfile @@ -1,4 +1,412 @@ VERSION 0.8 +base-build: + FROM ubuntu:noble + RUN export DEBIAN_FRONTEND="noninteractive" \ + && apt update && apt install --no-install-recommends -y \ + build-essential \ + ca-certificates \ + bash \ + clang \ + cmake \ + make \ + ninja-build \ + git \ + cargo \ + curl \ + python3 \ + wget \ + && apt-get -y autoremove \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* + ARG TARGETARCH + SAVE IMAGE --push aztecprotocol/cache:base-build-1.0-$TARGETARCH + +######################################################################################################################## +# Build wasi-sdk. +wasi-sdk: + FROM +base-build + RUN git clone --depth 1 --recursive --branch wasi-sdk-22 https://github.com/WebAssembly/wasi-sdk.git \ + && mkdir -p /wasi-sdk/build/install/opt/wasi-sdk \ + && cd /wasi-sdk \ + && export MAKEFLAGS="-j$(nproc)" \ + && make build/llvm.BUILT \ + && make build/wasi-libc.BUILT \ + && make build/compiler-rt.BUILT \ + && make build/libcxx.BUILT \ + && make build/config.BUILT \ + && make build/version.BUILT \ + && mv build/install/opt/wasi-sdk /opt/wasi-sdk \ + && cd / && rm -rf /wasi-sdk + SAVE ARTIFACT /opt/wasi-sdk /opt/wasi-sdk + ARG TARGETARCH + SAVE IMAGE --push aztecprotocol/cache:wasi-sdk-22.0-$TARGETARCH + +######################################################################################################################## +# Build osxcross. +osxcross: + FROM +base-build + RUN apt update && apt-get install --no-install-recommends -y \ + binutils-multiarch-dev \ + libbz2-dev \ + libmpc-dev \ + libmpfr-dev \ + libgmp-dev \ + liblzma-dev \ + libpsi3-dev \ + libssl-dev \ + libxml2-dev \ + libz-dev \ + lzma-dev \ + patch \ + uuid-dev \ + xz-utils \ + zlib1g-dev \ + && apt-get -y autoremove \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* + RUN git clone --depth=1 https://github.com/tpoechtrager/osxcross.git \ + && cd /osxcross \ + && git reset --hard ff8d100f3f026b4ffbe4ce96d8aac4ce06f1278b \ + && export OSX_SDK="MacOSX14.0.sdk" \ + && export OSX_SDK_URL="https://github.com/joseluisq/macosx-sdks/releases/download/14.0/${OSX_SDK}.tar.xz" \ + && curl -sSL "$OSX_SDK_URL" -o "./tarballs/$OSX_SDK.tar.xz" \ + && OSX_VERSION_MIN=14.0 UNATTENDED=1 ENABLE_COMPILER_RT_INSTALL=1 TARGET_DIR=/opt/osxcross ./build.sh \ + && rm -rf /osxcross /opt/osxcross/SDK/$OSX_SDK + SAVE ARTIFACT /opt/osxcross /opt/osxcross + ARG TARGETARCH + SAVE IMAGE --push aztecprotocol/cache:osxcross-14.0-$TARGETARCH + +######################################################################################################################## +# Build foundry. +foundry-build: + LET FOUNDRY_TAG = de33b6af53005037b463318d2628b5cfcaf39916 + FROM +base-build + RUN ulimit -n 65535 \ + && git clone --depth 1 --branch nightly-$FOUNDRY_TAG https://github.com/foundry-rs/foundry.git \ + && cd foundry \ + && cargo build --profile local \ + && mkdir -p /opt/foundry/bin \ + && for t in forge cast anvil chisel; do \ + mv ./target/local/$t /opt/foundry/bin/$t; \ + strip /opt/foundry/bin/$t; \ + done \ + && rm -rf /foundry + SAVE ARTIFACT /opt/foundry /opt/foundry + ARG TARGETARCH + SAVE IMAGE --push aztecprotocol/cache:foundry-build-$FOUNDRY_TAG-$TARGETARCH + +foundry: + BUILD +foundry-build + LET FOUNDRY_TAG = de33b6af53005037b463318d2628b5cfcaf39916 + ARG TARGETARCH + FROM ubuntu:noble + COPY +foundry-build/opt/foundry /opt/foundry + ENV PATH="/opt/foundry/bin:$PATH" + SAVE IMAGE --push aztecprotocol/foundry:$FOUNDRY_TAG-$TARGETARCH + +######################################################################################################################## +# This image contains *just* what's needed to perform a full build of the aztec project. +# It acts as the base image for all CI builds, and we build on it to produce a developer box. build: - FROM aztecprotocol/build:1.0 \ No newline at end of file + BUILD +wasi-sdk + BUILD +osxcross + BUILD +foundry + FROM +base-build + RUN apt update && \ + apt install -y \ + # Utils + curl \ + git \ + curl \ + wget \ + jq \ + gawk \ + unzip \ + netcat-openbsd \ + parallel \ + # C++ (clang=18, which we will move to. 16 is for current build.) + build-essential \ + cmake \ + ninja-build \ + clang \ + clang-16 \ + clang-format-16 \ + libc++-dev \ + libomp-dev \ + doxygen \ + # Node (18.19.1) + nodejs \ + npm \ + # Python (clang bindings for wasm bindgen.) + python3 \ + python3-clang \ + && apt-get -y autoremove \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* + + # Install wasi-sdk. + COPY +wasi-sdk/opt/wasi-sdk /opt/wasi-sdk + + # Install osxcross. Requires developer to mount SDK from their mac host. + COPY +osxcross/opt/osxcross /opt/osxcross + ENV PATH="/opt/osxcross/bin:$PATH" + ENV LD_LIBRARY_PATH="/opt/osxcross/lib:$LD_LIBRARY_PATH" + + # Install foundry. + COPY +foundry-build/opt/foundry /opt/foundry + ENV PATH="/opt/foundry/bin:$PATH" + + # Install rust and cross-compilers. Noir specifically uses 1.74.1. + # We remove base-build's rust first. + # We give everyone write ownership so downstream boxes can write. + ENV RUSTUP_HOME=/opt/rust/rustup + ENV CARGO_HOME=/opt/rust/cargo + ENV PATH="/opt/rust/cargo/bin:$PATH" + RUN apt remove -y cargo rustc + RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain 1.74.1 && \ + rustup target add wasm32-unknown-unknown wasm32-wasi aarch64-apple-darwin && \ + chmod -R a+w /opt/rust + + # Install yarn + RUN npm install --global yarn + + # Install solhint + RUN npm install --global solhint + + # Install aws cli. + RUN curl "https://awscli.amazonaws.com/awscli-exe-linux-$(uname -m).zip" -o "awscliv2.zip" && \ + unzip awscliv2.zip && \ + ./aws/install --bin-dir /usr/local/bin --install-dir /usr/local/aws-cli --update && \ + rm -rf aws awscliv2.zip + + # Install terraform. + RUN curl -fsSL https://releases.hashicorp.com/terraform/1.7.5/terraform_1.7.5_linux_$(dpkg --print-architecture).zip -o terraform.zip \ + && unzip terraform.zip -d /usr/local/bin \ + && chmod +x /usr/local/bin/terraform \ + && rm terraform.zip + + ARG TARGETARCH + SAVE IMAGE --push aztecprotocol/build:1.0-$TARGETARCH + +######################################################################################################################## +# We want to produce downstream images: devbox and sysbox. This image is the base image for each. +# It contains a suite of tools that developers might use to develop aztec. +basebox: + BUILD +build + FROM +build + RUN yes | unminimize + + # Install stuff devs need. + RUN apt update && \ + apt install -y \ + zsh \ + fzf \ + libfuse2 \ + iproute2 \ + iputils-ping \ + telnet \ + lsb-release \ + tmux \ + vim \ + software-properties-common \ + gnupg \ + htop \ + cgroup-tools \ + neovim \ + sudo \ + clangd-16 \ + man \ + python3-blessed \ + && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* + + # Install earthly. + RUN wget https://github.com/earthly/earthly/releases/latest/download/earthly-linux-$(dpkg --print-architecture) -O /usr/local/bin/earthly && \ + chmod +x /usr/local/bin/earthly + + # Install gh (github cli). + RUN mkdir -p -m 755 /etc/apt/keyrings && wget -qO- https://cli.github.com/packages/githubcli-archive-keyring.gpg > /etc/apt/keyrings/githubcli-archive-keyring.gpg \ + && chmod go+r /etc/apt/keyrings/githubcli-archive-keyring.gpg \ + && echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | tee /etc/apt/sources.list.d/github-cli.list > /dev/null \ + && apt update \ + && apt install gh -y + + # Install gt (graphite). + RUN npm install -g @withgraphite/graphite-cli@stable + + # fzf seems to not install this file for some reason. + COPY ./key-bindings.zsh /usr/share/doc/fzf/examples/key-bindings.zsh + + # Sets LANG explicitly. Ensures tmux shows unicode symbols. + ENV LANG=C.UTF-8 + # Ensure we get color terminal. + ENV TERM=xterm-256color + + # Cargo home and bin path should be set within users home dir at login. + RUN echo 'export CARGO_HOME="$HOME/.cargo"' >> /etc/zsh/zshenv + RUN echo 'export PATH="$HOME/.cargo/bin:$PATH"' >> /etc/zsh/zshenv + + # sudo group can sudo without password. + RUN echo '%sudo ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers + + ARG TARGETARCH + SAVE IMAGE --push aztecprotocol/cache:basebox-1.0-$TARGETARCH + +######################################################################################################################## +# This devbox container can be used to provide a full development environment. +# +# It can be used as a dev container: +# - Configuration in .devcontainer/devcontainer.json. +# - To run locally install "Dev Containers" plugin in vscode. +# - To run in GitHub codespaces, visit the repo in github, press '.', and open the terminal. +# +# It can be used independently: +# - The user should use the ./run.sh script to launch. +# - A persistent volume will be mounted to /home/aztec-dev. +# - It provides docker via the hosts docker instance, mounted at /var/lib/docker.sock. +# - It uses an entrypoint script at runtime to perform uid/gid alignment with the host and drop into user account. +devbox: + BUILD +basebox + FROM +basebox + + # Install gosu so we can start as root, adjust uid/gid, and then use gosu to become aztec-dev. + RUN apt install -y gosu + + # Detect if the host machine is Mac, if so set an env var, and disable prompts vcs info for performance. + RUN echo ' \ + if mount | grep -q /host_mark/Users; then \ + export HOST_OSTYPE=darwin; \ + export PROMPT_LEAN_VCS=0; \ + fi \ + ' >> /etc/zsh/zshrc + + # Create the user we'll run as (remove ubuntu first). + RUN userdel -r ubuntu && useradd --shell /bin/zsh -G sudo -m aztec-dev + WORKDIR /home/aztec-dev + + # Add dotfiles. + COPY --chown=aztec-dev:aztec-dev home . + + # The .npmrc config is set to install global bins here, update PATH. + ENV PATH=/home/aztec-dev/.npm-global/bin:$PATH + + # Need to ensure correct permissions, under some conditions these would otherwise be created by root. + RUN mkdir .vscode-server .npm-global .ssh && chown aztec-dev:aztec-dev .* + + # Install docker using docker-in-docker dev-container feature install script, modified to permit noble. + COPY install-docker.sh /install-docker.sh + RUN /install-docker.sh && rm /install-docker.sh + + # Use as entrypoint when running in an environment that requires uid/gid alignment (e.g. vanilla linux docker). + COPY ./entrypoint.sh /entrypoint.sh + ENTRYPOINT ["/entrypoint.sh"] + CMD ["/bin/zsh"] + + ARG TARGETARCH + SAVE IMAGE --push aztecprotocol/devbox:1.0-$TARGETARCH + # Save it without the arch tag as this is what's referenced in devcontainer.json + SAVE IMAGE aztecprotocol/devbox:1.0 + +devbox-manifest: + LET VERSION = 1.0 + ARG TARGETARCH + WAIT + BUILD +devbox + END + LOCALLY + RUN docker push aztecprotocol/devbox:$VERSION-$TARGETARCH + RUN docker manifest rm aztecprotocol/devbox:$VERSION || true + RUN docker manifest create aztecprotocol/devbox:$VERSION \ + --amend aztecprotocol/devbox:$VERSION-amd64 \ + --amend aztecprotocol/devbox:$VERSION-arm64 + RUN docker manifest push aztecprotocol/devbox:$VERSION + +######################################################################################################################## +# This sysbox container can be used to provide a full development environment. +# It's more advanced than devbox in that it uses nestybox's sysbox container runtime to provide more of a vm experience. +# It's used primarily by internal aztec developers who have sysboxes running on a powerful underlying mainframe. +# It provides better isolation and security guarantees than a plain devbox. +sysbox: + FROM +basebox + + ###################### START OF STOCK NESTYBOX SYSTEMD CONTAINER ############################### + # + # Systemd installation + # + RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + systemd \ + systemd-sysv \ + libsystemd0 \ + ca-certificates \ + dbus \ + iptables \ + iproute2 \ + kmod \ + locales \ + sudo \ + udev && \ + \ + # Prevents journald from reading kernel messages from /dev/kmsg + echo "ReadKMsg=no" >> /etc/systemd/journald.conf && \ + \ + # Housekeeping + apt-get clean -y && \ + rm -rf \ + /var/cache/debconf/* \ + /var/lib/apt/lists/* \ + /var/log/* \ + /tmp/* \ + /var/tmp/* \ + /usr/share/local/* && \ + \ + # Create default 'ubuntu/ubuntu' user + echo "ubuntu:ubuntu" | chpasswd && adduser ubuntu sudo + + # Disable systemd services/units that are unnecessary within a container. + RUN systemctl mask systemd-udevd.service \ + systemd-udevd-kernel.socket \ + systemd-udevd-control.socket \ + systemd-modules-load.service \ + sys-kernel-config.mount \ + sys-kernel-debug.mount \ + sys-kernel-tracing.mount \ + e2scrub_reap.service + + # Make use of stopsignal (instead of sigterm) to stop systemd containers. + STOPSIGNAL SIGRTMIN+3 + + # Set systemd as entrypoint. + ENTRYPOINT [ "/sbin/init", "--log-level=err" ] + + ###################### END OF STOCK NESTYBOX SYSTEMD CONTAINER ############################### + + # Install docker. + RUN curl -fsSL https://get.docker.com -o get-docker.sh && sh get-docker.sh \ + # Add user "ubuntu" to the Docker group + && usermod -a -G docker ubuntu + ADD https://raw.githubusercontent.com/docker/docker-ce/master/components/cli/contrib/completion/bash/docker /etc/bash_completion.d/docker.sh + + # Install sshd. + RUN apt install --no-install-recommends -y openssh-server \ + && rm -rf /var/lib/apt/lists/* \ + && mkdir /home/ubuntu/.ssh \ + && chown ubuntu:ubuntu /home/ubuntu/.ssh \ + && echo 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDagCvr/+CA1jmFaJf+e9+Kw6iwfhvaKOpfbGEl5zLgB+rum5L4Kga6Jow1gLQeMnAHfqc2IgpsU4t04c8PYApAt8AWNDL+KxMiFytfjKfJ2DZJA73CYkFnkfnMtU+ki+JG9dAHd6m7ShtCSzE5n6EDO2yWCVWQfqE3dcnpwrymSWkJYrbxzeOixiNZ4f1nD9ddvFvTWGB4l+et5SWgeIaYgJYDqTI2teRt9ytJiDGrCWXs9olHsCZOL6TEJPUQmNekwBkjMAZ4TmbBMjwbUlIxOpW2UxzlONcNn7IlRcGQg0Gdbkpo/zOlCNXsvacvnphDk5vKKaQj+aQiG916LU5P charlie@aztecprotocol.com' >> /home/ubuntu/.ssh/authorized_keys \ + && echo 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDb5OVc+9S9nXx3/34F7eLVXjoPgQ3YHSdlfhTb8WflAGmpKJTLxtAYngtDBvhKofH5HrjPPkBWxOHP9KOTo0jxUQSr0suMpggLLOHuIrCszJKXIVi7whnQ4p2RHyzyS2ANwmpxWZmYxfgamzYst9JIvQYJgAPjTFweKBsG/Lc03knJ/qgz9BHqDSZHweMTnhv1dJNhZRKy1Lxyl/CjXKF374i8qbzVWJMeDgLEH6C84vCeaH89KMmM9J0+T31uEqxzIhZxNmRz9v+x6cQAVJtGi9OIveGT9qUQwKXZsk6/zorzxV+NiIvTWHxIn9epX/FUjgUmb/jFvpbEjDkbIngj adomurad@localhost.localdomain' >> /home/ubuntu/.ssh/authorized_keys \ + && echo 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFKlUeOh9DyAL85NJ10LE+nyfi8oYm+CwxQ9JMaB6H+t root@mainframe' >> /home/ubuntu/.ssh/authorized_keys \ + && chown ubuntu:ubuntu /home/ubuntu/.ssh/authorized_keys + + # Install google authenticator for setting up 2fa. + RUN apt update && apt install -y libpam-google-authenticator + + # We login to sysbox via ssh. This loses env vars set with ENV, so add them here. + # Sets RUSTUP_HOME. + # Adds foundry and cargo bin dirs to PATH. + COPY environment /etc/environment + + EXPOSE 22 + + ARG TARGETARCH + SAVE IMAGE aztecprotocol/sysbox:1.0-$TARGETARCH + SAVE IMAGE aztecprotocol/sysbox:1.0 \ No newline at end of file diff --git a/build-images/Makefile b/build-images/Makefile deleted file mode 100755 index 24934a9fa0a..00000000000 --- a/build-images/Makefile +++ /dev/null @@ -1,58 +0,0 @@ -ARCH := $(shell uname -m | sed 's/aarch64/arm64/') -FOUNDRY_TAG := de33b6af53005037b463318d2628b5cfcaf39916 -VERSION := 1.0 - -wasi-sdk: - docker build -t aztecprotocol/wasi-sdk:$(ARCH)-22.0 --target wasi-sdk --push . - docker manifest create aztecprotocol/wasi-sdk:22.0 \ - --amend aztecprotocol/wasi-sdk:x86_64-22.0 \ - --amend aztecprotocol/wasi-sdk:arm64-22.0 - docker manifest push aztecprotocol/wasi-sdk:22.0 - -foundry: - docker build -t aztecprotocol/foundry:$(ARCH)-$(FOUNDRY_TAG) --build-arg TAG=$(FOUNDRY_TAG) --target foundry --push . - docker tag aztecprotocol/foundry:$(ARCH)-$(FOUNDRY_TAG) aztecprotocol/foundry:$(FOUNDRY_TAG) - docker manifest rm aztecprotocol/foundry:$(FOUNDRY_TAG) - docker manifest create aztecprotocol/foundry:$(FOUNDRY_TAG) \ - --amend aztecprotocol/foundry:x86_64-$(FOUNDRY_TAG) \ - --amend aztecprotocol/foundry:arm64-$(FOUNDRY_TAG) - docker manifest push aztecprotocol/foundry:$(FOUNDRY_TAG) - -osxcross: - docker build -t aztecprotocol/osxcross:$(ARCH)-14.0 --target osxcross --push . - docker manifest rm aztecprotocol/osxcross:14.0 - docker manifest create aztecprotocol/osxcross:14.0 \ - --amend aztecprotocol/osxcross:x86_64-14.0 \ - --amend aztecprotocol/osxcross:arm64-14.0 - docker manifest push aztecprotocol/osxcross:14.0 - -build: - docker build -t aztecprotocol/build:$(ARCH)-$(VERSION) --target build . - docker tag aztecprotocol/build:$(ARCH)-$(VERSION) aztecprotocol/build - -build-push: build - docker push aztecprotocol/build:$(ARCH)-$(VERSION) - docker manifest rm aztecprotocol/build:$(VERSION) - docker manifest create aztecprotocol/build:$(VERSION) \ - --amend aztecprotocol/build:x86_64-$(VERSION) \ - --amend aztecprotocol/build:arm64-$(VERSION) - docker manifest push aztecprotocol/build:$(VERSION) - -devbox: - docker build -t aztecprotocol/devbox:$(ARCH)-$(VERSION) --target devbox . - docker tag aztecprotocol/devbox:$(ARCH)-$(VERSION) aztecprotocol/devbox - -devbox-push: devbox - docker push aztecprotocol/devbox:$(ARCH)-$(VERSION) - docker manifest rm aztecprotocol/devbox:$(VERSION) - docker manifest create aztecprotocol/devbox:$(VERSION) \ - --amend aztecprotocol/devbox:x86_64-$(VERSION) \ - --amend aztecprotocol/devbox:arm64-$(VERSION) - docker manifest push aztecprotocol/devbox:$(VERSION) - -sysbox: - docker build -t aztecprotocol/sysbox --target sysbox . - -all: build devbox sysbox - -.PHONY: all build devbox sysbox diff --git a/build-images/README.md b/build-images/README.md index 2ff02e1393f..d2824ba4564 100644 --- a/build-images/README.md +++ b/build-images/README.md @@ -2,10 +2,6 @@ To ensure a consistent environment for developers, and ease of getting started, we provide a development container. -## Install Docker - -If you don't already have docker installed, follow this guide: https://docs.docker.com/engine/install - ## Visual Studio Code If you use vscode, the simplest thing to do is install the "Dev Containers" plugin, and open the repo. @@ -25,3 +21,30 @@ Your repo will be mounted at `/workspaces/aztec-packages`, and your home directo This is also compatible with GitHub codespaces. Visit the repo at `http://github.com/aztecprotocol/aztec-packages`. Press `.`, and open a terminal window. You will be prompted to create a new machine. You can then continue to work within the browser, or reopen the codespace in your local vscode. + +## Building the build image + +If for some reason you want to build the images such as devbox yourself, follow these steps: + +### Install Docker + +If you don't already have docker installed, follow this guide: https://docs.docker.com/engine/install + +### Install earthly + +We use earthly to build things, follow this guide: https://earthly.dev/get-earthly + +### Build The Dev Container + +If you want to build entirely from scratch, you can do: + +``` +$ earthly +devbox +``` + +This will take significant time and compute however, as it builds several toolchains from the ground up. +If you have a reasonable internet connection, leveraging the cache to avoid building maybe prefereable. + +``` +$ earthly --use-inline-cache +devbox +``` \ No newline at end of file diff --git a/build-images/entrypoint.sh b/build-images/entrypoint.sh index d6f36b79dd0..52b676dad3a 100755 --- a/build-images/entrypoint.sh +++ b/build-images/entrypoint.sh @@ -5,18 +5,6 @@ set -e [ -n "$LOCAL_GROUP_ID" ] && groupmod -g $LOCAL_GROUP_ID aztec-dev [ -n "$LOCAL_USER_ID" ] && usermod -u $LOCAL_USER_ID aztec-dev &> /dev/null -# Find the group id of the docker socket, add aztec-dev to that group, or create the group and add aztec-dev. -if [ -S /var/run/docker.sock ]; then - SOCKET_GID=$(stat -c %g /var/run/docker.sock) - EXISTING_GROUP=$(getent group $SOCKET_GID | cut -d: -f1) - if [ -z "$EXISTING_GROUP" ]; then - # No existing group with that gid, so create one called 'docker' and add the user to it. - groupadd -g $SOCKET_GID docker - usermod -aG docker aztec-dev - else - # A group with the desired gid already exists, add the user to it. - usermod -aG $EXISTING_GROUP aztec-dev - fi -fi +/usr/local/share/docker-init.sh &> /dev/null exec /usr/sbin/gosu aztec-dev "$@" \ No newline at end of file diff --git a/build-images/install-docker.sh b/build-images/install-docker.sh new file mode 100755 index 00000000000..4a433a02220 --- /dev/null +++ b/build-images/install-docker.sh @@ -0,0 +1,624 @@ +#!/usr/bin/env bash +#------------------------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information. +#------------------------------------------------------------------------------------------------------------- +# +# Docs: https://github.com/microsoft/vscode-dev-containers/blob/main/script-library/docs/docker-in-docker.md +# Maintainer: The Dev Container spec maintainers + + +DOCKER_VERSION="${VERSION:-"latest"}" # The Docker/Moby Engine + CLI should match in version +USE_MOBY="${MOBY:-"true"}" +MOBY_BUILDX_VERSION="${MOBYBUILDXVERSION:-"latest"}" +DOCKER_DASH_COMPOSE_VERSION="${DOCKERDASHCOMPOSEVERSION:-"latest"}" #latest, v2 or none +AZURE_DNS_AUTO_DETECTION="${AZUREDNSAUTODETECTION:-"true"}" +DOCKER_DEFAULT_ADDRESS_POOL="${DOCKERDEFAULTADDRESSPOOL:-""}" +USERNAME="${USERNAME:-"${_REMOTE_USER:-"automatic"}"}" +INSTALL_DOCKER_BUILDX="${INSTALLDOCKERBUILDX:-"true"}" +INSTALL_DOCKER_COMPOSE_SWITCH="${INSTALLDOCKERCOMPOSESWITCH:-"true"}" +MICROSOFT_GPG_KEYS_URI="https://packages.microsoft.com/keys/microsoft.asc" +DOCKER_MOBY_ARCHIVE_VERSION_CODENAMES="bookworm buster bullseye bionic focal jammy noble" +DOCKER_LICENSED_ARCHIVE_VERSION_CODENAMES="bookworm buster bullseye bionic focal hirsute impish jammy noble" + +# Default: Exit on any failure. +set -e + +# Clean up +rm -rf /var/lib/apt/lists/* + +# Setup STDERR. +err() { + echo "(!) $*" >&2 +} + +if [ "$(id -u)" -ne 0 ]; then + err 'Script must be run as root. Use sudo, su, or add "USER root" to your Dockerfile before running this script.' + exit 1 +fi + +################### +# Helper Functions +# See: https://github.com/microsoft/vscode-dev-containers/blob/main/script-library/shared/utils.sh +################### + +# Determine the appropriate non-root user +if [ "${USERNAME}" = "auto" ] || [ "${USERNAME}" = "automatic" ]; then + USERNAME="" + POSSIBLE_USERS=("vscode" "node" "codespace" "$(awk -v val=1000 -F ":" '$3==val{print $1}' /etc/passwd)") + for CURRENT_USER in "${POSSIBLE_USERS[@]}"; do + if id -u ${CURRENT_USER} > /dev/null 2>&1; then + USERNAME=${CURRENT_USER} + break + fi + done + if [ "${USERNAME}" = "" ]; then + USERNAME=root + fi +elif [ "${USERNAME}" = "none" ] || ! id -u ${USERNAME} > /dev/null 2>&1; then + USERNAME=root +fi + +apt_get_update() +{ + if [ "$(find /var/lib/apt/lists/* | wc -l)" = "0" ]; then + echo "Running apt-get update..." + apt-get update -y + fi +} + +# Checks if packages are installed and installs them if not +check_packages() { + if ! dpkg -s "$@" > /dev/null 2>&1; then + apt_get_update + apt-get -y install --no-install-recommends "$@" + fi +} + +# Figure out correct version of a three part version number is not passed +find_version_from_git_tags() { + local variable_name=$1 + local requested_version=${!variable_name} + if [ "${requested_version}" = "none" ]; then return; fi + local repository=$2 + local prefix=${3:-"tags/v"} + local separator=${4:-"."} + local last_part_optional=${5:-"false"} + if [ "$(echo "${requested_version}" | grep -o "." | wc -l)" != "2" ]; then + local escaped_separator=${separator//./\\.} + local last_part + if [ "${last_part_optional}" = "true" ]; then + last_part="(${escaped_separator}[0-9]+)?" + else + last_part="${escaped_separator}[0-9]+" + fi + local regex="${prefix}\\K[0-9]+${escaped_separator}[0-9]+${last_part}$" + local version_list="$(git ls-remote --tags ${repository} | grep -oP "${regex}" | tr -d ' ' | tr "${separator}" "." | sort -rV)" + if [ "${requested_version}" = "latest" ] || [ "${requested_version}" = "current" ] || [ "${requested_version}" = "lts" ]; then + declare -g ${variable_name}="$(echo "${version_list}" | head -n 1)" + else + set +e + declare -g ${variable_name}="$(echo "${version_list}" | grep -E -m 1 "^${requested_version//./\\.}([\\.\\s]|$)")" + set -e + fi + fi + if [ -z "${!variable_name}" ] || ! echo "${version_list}" | grep "^${!variable_name//./\\.}$" > /dev/null 2>&1; then + err "Invalid ${variable_name} value: ${requested_version}\nValid values:\n${version_list}" >&2 + exit 1 + fi + echo "${variable_name}=${!variable_name}" +} + +# Use semver logic to decrement a version number then look for the closest match +find_prev_version_from_git_tags() { + local variable_name=$1 + local current_version=${!variable_name} + local repository=$2 + # Normally a "v" is used before the version number, but support alternate cases + local prefix=${3:-"tags/v"} + # Some repositories use "_" instead of "." for version number part separation, support that + local separator=${4:-"."} + # Some tools release versions that omit the last digit (e.g. go) + local last_part_optional=${5:-"false"} + # Some repositories may have tags that include a suffix (e.g. actions/node-versions) + local version_suffix_regex=$6 + # Try one break fix version number less if we get a failure. Use "set +e" since "set -e" can cause failures in valid scenarios. + set +e + major="$(echo "${current_version}" | grep -oE '^[0-9]+' || echo '')" + minor="$(echo "${current_version}" | grep -oP '^[0-9]+\.\K[0-9]+' || echo '')" + breakfix="$(echo "${current_version}" | grep -oP '^[0-9]+\.[0-9]+\.\K[0-9]+' 2>/dev/null || echo '')" + + if [ "${minor}" = "0" ] && [ "${breakfix}" = "0" ]; then + ((major=major-1)) + declare -g ${variable_name}="${major}" + # Look for latest version from previous major release + find_version_from_git_tags "${variable_name}" "${repository}" "${prefix}" "${separator}" "${last_part_optional}" + # Handle situations like Go's odd version pattern where "0" releases omit the last part + elif [ "${breakfix}" = "" ] || [ "${breakfix}" = "0" ]; then + ((minor=minor-1)) + declare -g ${variable_name}="${major}.${minor}" + # Look for latest version from previous minor release + find_version_from_git_tags "${variable_name}" "${repository}" "${prefix}" "${separator}" "${last_part_optional}" + else + ((breakfix=breakfix-1)) + if [ "${breakfix}" = "0" ] && [ "${last_part_optional}" = "true" ]; then + declare -g ${variable_name}="${major}.${minor}" + else + declare -g ${variable_name}="${major}.${minor}.${breakfix}" + fi + fi + set -e +} + +# Function to fetch the version released prior to the latest version +get_previous_version() { + local url=$1 + local repo_url=$2 + local variable_name=$3 + prev_version=${!variable_name} + + output=$(curl -s "$repo_url"); + message=$(echo "$output" | jq -r '.message') + + if [[ $message == "API rate limit exceeded"* ]]; then + echo -e "\nAn attempt to find latest version using GitHub Api Failed... \nReason: ${message}" + echo -e "\nAttempting to find latest version using GitHub tags." + find_prev_version_from_git_tags prev_version "$url" "tags/v" + declare -g ${variable_name}="${prev_version}" + else + echo -e "\nAttempting to find latest version using GitHub Api." + version=$(echo "$output" | jq -r '.tag_name') + declare -g ${variable_name}="${version#v}" + fi + echo "${variable_name}=${!variable_name}" +} + +get_github_api_repo_url() { + local url=$1 + echo "${url/https:\/\/github.com/https:\/\/api.github.com\/repos}/releases/latest" +} + +########################################### +# Start docker-in-docker installation +########################################### + +# Ensure apt is in non-interactive to avoid prompts +export DEBIAN_FRONTEND=noninteractive + + +# Source /etc/os-release to get OS info +. /etc/os-release +# Fetch host/container arch. +architecture="$(dpkg --print-architecture)" + +# Check if distro is supported +if [ "${USE_MOBY}" = "true" ]; then + if [[ "${DOCKER_MOBY_ARCHIVE_VERSION_CODENAMES}" != *"${VERSION_CODENAME}"* ]]; then + err "Unsupported distribution version '${VERSION_CODENAME}'. To resolve, either: (1) set feature option '\"moby\": false' , or (2) choose a compatible OS distribution" + err "Support distributions include: ${DOCKER_MOBY_ARCHIVE_VERSION_CODENAMES}" + exit 1 + fi + echo "Distro codename '${VERSION_CODENAME}' matched filter '${DOCKER_MOBY_ARCHIVE_VERSION_CODENAMES}'" +else + if [[ "${DOCKER_LICENSED_ARCHIVE_VERSION_CODENAMES}" != *"${VERSION_CODENAME}"* ]]; then + err "Unsupported distribution version '${VERSION_CODENAME}'. To resolve, please choose a compatible OS distribution" + err "Support distributions include: ${DOCKER_LICENSED_ARCHIVE_VERSION_CODENAMES}" + exit 1 + fi + echo "Distro codename '${VERSION_CODENAME}' matched filter '${DOCKER_LICENSED_ARCHIVE_VERSION_CODENAMES}'" +fi + +# Install dependencies +check_packages apt-transport-https curl ca-certificates pigz iptables gnupg2 dirmngr wget jq +if ! type git > /dev/null 2>&1; then + check_packages git +fi + +# Swap to legacy iptables for compatibility +if type iptables-legacy > /dev/null 2>&1; then + update-alternatives --set iptables /usr/sbin/iptables-legacy + update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy +fi + + + +# Set up the necessary apt repos (either Microsoft's or Docker's) +if [ "${USE_MOBY}" = "true" ]; then + + # Name of open source engine/cli + engine_package_name="moby-engine" + cli_package_name="moby-cli" + + # Import key safely and import Microsoft apt repo + curl -sSL ${MICROSOFT_GPG_KEYS_URI} | gpg --dearmor > /usr/share/keyrings/microsoft-archive-keyring.gpg + echo "deb [arch=${architecture} signed-by=/usr/share/keyrings/microsoft-archive-keyring.gpg] https://packages.microsoft.com/repos/microsoft-${ID}-${VERSION_CODENAME}-prod ${VERSION_CODENAME} main" > /etc/apt/sources.list.d/microsoft.list +else + # Name of licensed engine/cli + engine_package_name="docker-ce" + cli_package_name="docker-ce-cli" + + # Import key safely and import Docker apt repo + curl -fsSL https://download.docker.com/linux/${ID}/gpg | gpg --dearmor > /usr/share/keyrings/docker-archive-keyring.gpg + echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/${ID} ${VERSION_CODENAME} stable" > /etc/apt/sources.list.d/docker.list +fi + +# Refresh apt lists +apt-get update + +# Soft version matching +if [ "${DOCKER_VERSION}" = "latest" ] || [ "${DOCKER_VERSION}" = "lts" ] || [ "${DOCKER_VERSION}" = "stable" ]; then + # Empty, meaning grab whatever "latest" is in apt repo + engine_version_suffix="" + cli_version_suffix="" +else + # Fetch a valid version from the apt-cache (eg: the Microsoft repo appends +azure, breakfix, etc...) + docker_version_dot_escaped="${DOCKER_VERSION//./\\.}" + docker_version_dot_plus_escaped="${docker_version_dot_escaped//+/\\+}" + # Regex needs to handle debian package version number format: https://www.systutorials.com/docs/linux/man/5-deb-version/ + docker_version_regex="^(.+:)?${docker_version_dot_plus_escaped}([\\.\\+ ~:-]|$)" + set +e # Don't exit if finding version fails - will handle gracefully + cli_version_suffix="=$(apt-cache madison ${cli_package_name} | awk -F"|" '{print $2}' | sed -e 's/^[ \t]*//' | grep -E -m 1 "${docker_version_regex}")" + engine_version_suffix="=$(apt-cache madison ${engine_package_name} | awk -F"|" '{print $2}' | sed -e 's/^[ \t]*//' | grep -E -m 1 "${docker_version_regex}")" + set -e + if [ -z "${engine_version_suffix}" ] || [ "${engine_version_suffix}" = "=" ] || [ -z "${cli_version_suffix}" ] || [ "${cli_version_suffix}" = "=" ] ; then + err "No full or partial Docker / Moby version match found for \"${DOCKER_VERSION}\" on OS ${ID} ${VERSION_CODENAME} (${architecture}). Available versions:" + apt-cache madison ${cli_package_name} | awk -F"|" '{print $2}' | grep -oP '^(.+:)?\K.+' + exit 1 + fi + echo "engine_version_suffix ${engine_version_suffix}" + echo "cli_version_suffix ${cli_version_suffix}" +fi + +# Version matching for moby-buildx +if [ "${USE_MOBY}" = "true" ]; then + if [ "${MOBY_BUILDX_VERSION}" = "latest" ]; then + # Empty, meaning grab whatever "latest" is in apt repo + buildx_version_suffix="" + else + buildx_version_dot_escaped="${MOBY_BUILDX_VERSION//./\\.}" + buildx_version_dot_plus_escaped="${buildx_version_dot_escaped//+/\\+}" + buildx_version_regex="^(.+:)?${buildx_version_dot_plus_escaped}([\\.\\+ ~:-]|$)" + set +e + buildx_version_suffix="=$(apt-cache madison moby-buildx | awk -F"|" '{print $2}' | sed -e 's/^[ \t]*//' | grep -E -m 1 "${buildx_version_regex}")" + set -e + if [ -z "${buildx_version_suffix}" ] || [ "${buildx_version_suffix}" = "=" ]; then + err "No full or partial moby-buildx version match found for \"${MOBY_BUILDX_VERSION}\" on OS ${ID} ${VERSION_CODENAME} (${architecture}). Available versions:" + apt-cache madison moby-buildx | awk -F"|" '{print $2}' | grep -oP '^(.+:)?\K.+' + exit 1 + fi + echo "buildx_version_suffix ${buildx_version_suffix}" + fi +fi + +# Install Docker / Moby CLI if not already installed +if type docker > /dev/null 2>&1 && type dockerd > /dev/null 2>&1; then + echo "Docker / Moby CLI and Engine already installed." +else + if [ "${USE_MOBY}" = "true" ]; then + # Install engine + set +e # Handle error gracefully + apt-get -y install --no-install-recommends moby-cli${cli_version_suffix} moby-buildx${buildx_version_suffix} moby-engine${engine_version_suffix} + exit_code=$? + set -e + + if [ ${exit_code} -ne 0 ]; then + err "Packages for moby not available in OS ${ID} ${VERSION_CODENAME} (${architecture}). To resolve, either: (1) set feature option '\"moby\": false' , or (2) choose a compatible OS version (eg: 'ubuntu-20.04')." + exit 1 + fi + + # Install compose + apt-get -y install --no-install-recommends moby-compose || err "Package moby-compose (Docker Compose v2) not available for OS ${ID} ${VERSION_CODENAME} (${architecture}). Skipping." + else + apt-get -y install --no-install-recommends docker-ce-cli${cli_version_suffix} docker-ce${engine_version_suffix} + # Install compose + apt-get -y install --no-install-recommends docker-compose-plugin || echo "(*) Package docker-compose-plugin (Docker Compose v2) not available for OS ${ID} ${VERSION_CODENAME} (${architecture}). Skipping." + fi +fi + +echo "Finished installing docker / moby!" + +docker_home="/usr/libexec/docker" +cli_plugins_dir="${docker_home}/cli-plugins" + +# fallback for docker-compose +fallback_compose(){ + local url=$1 + local repo_url=$(get_github_api_repo_url "$url") + echo -e "\n(!) Failed to fetch the latest artifacts for docker-compose v${compose_version}..." + get_previous_version "${url}" "${repo_url}" compose_version + echo -e "\nAttempting to install v${compose_version}" + curl -fsSL "https://github.com/docker/compose/releases/download/v${compose_version}/docker-compose-linux-${target_compose_arch}" -o ${docker_compose_path} +} + +# If 'docker-compose' command is to be included +if [ "${DOCKER_DASH_COMPOSE_VERSION}" != "none" ]; then + case "${architecture}" in + amd64) target_compose_arch=x86_64 ;; + arm64) target_compose_arch=aarch64 ;; + *) + echo "(!) Docker in docker does not support machine architecture '$architecture'. Please use an x86-64 or ARM64 machine." + exit 1 + esac + + docker_compose_path="/usr/local/bin/docker-compose" + if [ "${DOCKER_DASH_COMPOSE_VERSION}" = "v1" ]; then + err "The final Compose V1 release, version 1.29.2, was May 10, 2021. These packages haven't received any security updates since then. Use at your own risk." + INSTALL_DOCKER_COMPOSE_SWITCH="false" + + if [ "${target_compose_arch}" = "x86_64" ]; then + echo "(*) Installing docker compose v1..." + curl -fsSL "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-Linux-x86_64" -o ${docker_compose_path} + chmod +x ${docker_compose_path} + + # Download the SHA256 checksum + DOCKER_COMPOSE_SHA256="$(curl -sSL "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-Linux-x86_64.sha256" | awk '{print $1}')" + echo "${DOCKER_COMPOSE_SHA256} ${docker_compose_path}" > docker-compose.sha256sum + sha256sum -c docker-compose.sha256sum --ignore-missing + elif [ "${VERSION_CODENAME}" = "bookworm" ]; then + err "Docker compose v1 is unavailable for 'bookworm' on Arm64. Kindly switch to use v2" + exit 1 + else + # Use pip to get a version that runs on this architecture + check_packages python3-minimal python3-pip libffi-dev python3-venv + echo "(*) Installing docker compose v1 via pip..." + export PYTHONUSERBASE=/usr/local + pip3 install --disable-pip-version-check --no-cache-dir --user "Cython<3.0" pyyaml wheel docker-compose --no-build-isolation + fi + else + compose_version=${DOCKER_DASH_COMPOSE_VERSION#v} + docker_compose_url="https://github.com/docker/compose" + find_version_from_git_tags compose_version "$docker_compose_url" "tags/v" + echo "(*) Installing docker-compose ${compose_version}..." + curl -fsSL "https://github.com/docker/compose/releases/download/v${compose_version}/docker-compose-linux-${target_compose_arch}" -o ${docker_compose_path} || { + if [[ $DOCKER_DASH_COMPOSE_VERSION == "latest" ]]; then + fallback_compose "$docker_compose_url" + else + echo -e "Error: Failed to install docker-compose v${compose_version}" + fi + } + + chmod +x ${docker_compose_path} + + # Download the SHA256 checksum + DOCKER_COMPOSE_SHA256="$(curl -sSL "https://github.com/docker/compose/releases/download/v${compose_version}/docker-compose-linux-${target_compose_arch}.sha256" | awk '{print $1}')" + echo "${DOCKER_COMPOSE_SHA256} ${docker_compose_path}" > docker-compose.sha256sum + sha256sum -c docker-compose.sha256sum --ignore-missing + + mkdir -p ${cli_plugins_dir} + cp ${docker_compose_path} ${cli_plugins_dir} + fi +fi + +# fallback method for compose-switch +fallback_compose-switch() { + local url=$1 + local repo_url=$(get_github_api_repo_url "$url") + echo -e "\n(!) Failed to fetch the latest artifacts for compose-switch v${compose_switch_version}..." + get_previous_version "$url" "$repo_url" compose_switch_version + echo -e "\nAttempting to install v${compose_switch_version}" + curl -fsSL "https://github.com/docker/compose-switch/releases/download/v${compose_switch_version}/docker-compose-linux-${architecture}" -o /usr/local/bin/compose-switch +} + +# Install docker-compose switch if not already installed - https://github.com/docker/compose-switch#manual-installation +if [ "${INSTALL_DOCKER_COMPOSE_SWITCH}" = "true" ] && ! type compose-switch > /dev/null 2>&1; then + if type docker-compose > /dev/null 2>&1; then + echo "(*) Installing compose-switch..." + current_compose_path="$(which docker-compose)" + target_compose_path="$(dirname "${current_compose_path}")/docker-compose-v1" + compose_switch_version="latest" + compose_switch_url="https://github.com/docker/compose-switch" + find_version_from_git_tags compose_switch_version "$compose_switch_url" + curl -fsSL "https://github.com/docker/compose-switch/releases/download/v${compose_switch_version}/docker-compose-linux-${architecture}" -o /usr/local/bin/compose-switch || fallback_compose-switch "$compose_switch_url" + chmod +x /usr/local/bin/compose-switch + # TODO: Verify checksum once available: https://github.com/docker/compose-switch/issues/11 + # Setup v1 CLI as alternative in addition to compose-switch (which maps to v2) + mv "${current_compose_path}" "${target_compose_path}" + update-alternatives --install ${docker_compose_path} docker-compose /usr/local/bin/compose-switch 99 + update-alternatives --install ${docker_compose_path} docker-compose "${target_compose_path}" 1 + else + err "Skipping installation of compose-switch as docker compose is unavailable..." + fi +fi + +# If init file already exists, exit +if [ -f "/usr/local/share/docker-init.sh" ]; then + echo "/usr/local/share/docker-init.sh already exists, so exiting." + # Clean up + rm -rf /var/lib/apt/lists/* + exit 0 +fi +echo "docker-init doesn't exist, adding..." + +if ! cat /etc/group | grep -e "^docker:" > /dev/null 2>&1; then + groupadd -r docker +fi + +usermod -aG docker ${USERNAME} + +# fallback for docker/buildx +fallback_buildx() { + local url=$1 + local repo_url=$(get_github_api_repo_url "$url") + echo -e "\n(!) Failed to fetch the latest artifacts for docker buildx v${buildx_version}..." + get_previous_version "$url" "$repo_url" buildx_version + buildx_file_name="buildx-v${buildx_version}.linux-${architecture}" + echo -e "\nAttempting to install v${buildx_version}" + wget https://github.com/docker/buildx/releases/download/v${buildx_version}/${buildx_file_name} +} + +if [ "${INSTALL_DOCKER_BUILDX}" = "true" ]; then + buildx_version="latest" + docker_buildx_url="https://github.com/docker/buildx" + find_version_from_git_tags buildx_version "$docker_buildx_url" "refs/tags/v" + echo "(*) Installing buildx ${buildx_version}..." + buildx_file_name="buildx-v${buildx_version}.linux-${architecture}" + + cd /tmp + wget https://github.com/docker/buildx/releases/download/v${buildx_version}/${buildx_file_name} || fallback_buildx "$docker_buildx_url" + + docker_home="/usr/libexec/docker" + cli_plugins_dir="${docker_home}/cli-plugins" + + mkdir -p ${cli_plugins_dir} + mv ${buildx_file_name} ${cli_plugins_dir}/docker-buildx + chmod +x ${cli_plugins_dir}/docker-buildx + + chown -R "${USERNAME}:docker" "${docker_home}" + chmod -R g+r+w "${docker_home}" + find "${docker_home}" -type d -print0 | xargs -n 1 -0 chmod g+s +fi + +tee /usr/local/share/docker-init.sh > /dev/null \ +<< EOF +#!/bin/sh +#------------------------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information. +#------------------------------------------------------------------------------------------------------------- + +set -e + +AZURE_DNS_AUTO_DETECTION=${AZURE_DNS_AUTO_DETECTION} +DOCKER_DEFAULT_ADDRESS_POOL=${DOCKER_DEFAULT_ADDRESS_POOL} +EOF + +tee -a /usr/local/share/docker-init.sh > /dev/null \ +<< 'EOF' +dockerd_start="AZURE_DNS_AUTO_DETECTION=${AZURE_DNS_AUTO_DETECTION} DOCKER_DEFAULT_ADDRESS_POOL=${DOCKER_DEFAULT_ADDRESS_POOL} $(cat << 'INNEREOF' + # explicitly remove dockerd and containerd PID file to ensure that it can start properly if it was stopped uncleanly + find /run /var/run -iname 'docker*.pid' -delete || : + find /run /var/run -iname 'container*.pid' -delete || : + + # -- Start: dind wrapper script -- + # Maintained: https://github.com/moby/moby/blob/master/hack/dind + + export container=docker + + if [ -d /sys/kernel/security ] && ! mountpoint -q /sys/kernel/security; then + mount -t securityfs none /sys/kernel/security || { + echo >&2 'Could not mount /sys/kernel/security.' + echo >&2 'AppArmor detection and --privileged mode might break.' + } + fi + + # Mount /tmp (conditionally) + if ! mountpoint -q /tmp; then + mount -t tmpfs none /tmp + fi + + set_cgroup_nesting() + { + # cgroup v2: enable nesting + if [ -f /sys/fs/cgroup/cgroup.controllers ]; then + # move the processes from the root group to the /init group, + # otherwise writing subtree_control fails with EBUSY. + # An error during moving non-existent process (i.e., "cat") is ignored. + mkdir -p /sys/fs/cgroup/init + xargs -rn1 < /sys/fs/cgroup/cgroup.procs > /sys/fs/cgroup/init/cgroup.procs || : + # enable controllers + sed -e 's/ / +/g' -e 's/^/+/' < /sys/fs/cgroup/cgroup.controllers \ + > /sys/fs/cgroup/cgroup.subtree_control + fi + } + + # Set cgroup nesting, retrying if necessary + retry_cgroup_nesting=0 + + until [ "${retry_cgroup_nesting}" -eq "5" ]; + do + set +e + set_cgroup_nesting + + if [ $? -ne 0 ]; then + echo "(*) cgroup v2: Failed to enable nesting, retrying..." + else + break + fi + + retry_cgroup_nesting=`expr $retry_cgroup_nesting + 1` + set -e + done + + # -- End: dind wrapper script -- + + # Handle DNS + set +e + cat /etc/resolv.conf | grep -i 'internal.cloudapp.net' > /dev/null 2>&1 + if [ $? -eq 0 ] && [ "${AZURE_DNS_AUTO_DETECTION}" = "true" ] + then + echo "Setting dockerd Azure DNS." + CUSTOMDNS="--dns 168.63.129.16" + else + echo "Not setting dockerd DNS manually." + CUSTOMDNS="" + fi + set -e + + if [ -z "$DOCKER_DEFAULT_ADDRESS_POOL" ] + then + DEFAULT_ADDRESS_POOL="" + else + DEFAULT_ADDRESS_POOL="--default-address-pool $DOCKER_DEFAULT_ADDRESS_POOL" + fi + + # Start docker/moby engine + ( dockerd $CUSTOMDNS $DEFAULT_ADDRESS_POOL > /tmp/dockerd.log 2>&1 ) & +INNEREOF +)" + +sudo_if() { + COMMAND="$*" + + if [ "$(id -u)" -ne 0 ]; then + sudo $COMMAND + else + $COMMAND + fi +} + +retry_docker_start_count=0 +docker_ok="false" + +until [ "${docker_ok}" = "true" ] || [ "${retry_docker_start_count}" -eq "5" ]; +do + # Start using sudo if not invoked as root + if [ "$(id -u)" -ne 0 ]; then + sudo /bin/sh -c "${dockerd_start}" + else + eval "${dockerd_start}" + fi + + retry_count=0 + until [ "${docker_ok}" = "true" ] || [ "${retry_count}" -eq "5" ]; + do + sleep 1s + set +e + docker info > /dev/null 2>&1 && docker_ok="true" + set -e + + retry_count=`expr $retry_count + 1` + done + + if [ "${docker_ok}" != "true" ] && [ "${retry_docker_start_count}" != "4" ]; then + echo "(*) Failed to start docker, retrying..." + set +e + sudo_if pkill dockerd + sudo_if pkill containerd + set -e + fi + + retry_docker_start_count=`expr $retry_docker_start_count + 1` +done + +# Execute whatever commands were passed in (if any). This allows us +# to set this script to ENTRYPOINT while still executing the default CMD. +exec "$@" +EOF + +chmod +x /usr/local/share/docker-init.sh +chown ${USERNAME}:root /usr/local/share/docker-init.sh + +# Clean up +rm -rf /var/lib/apt/lists/* + +echo 'docker-in-docker-debian script has completed!' diff --git a/build-images/run.sh b/build-images/run.sh index 97132414f76..2e54ba1ae90 100755 --- a/build-images/run.sh +++ b/build-images/run.sh @@ -2,6 +2,18 @@ set -eu cd $(dirname $0) +hostname=$(hostname) + +# Define next hostname based on this hostname for nesting. devbox, devbox1, etc. +if [[ $hostname == "devbox" ]]; then + hostname="devbox1" +elif [[ $hostname =~ ^devbox([0-9]+)$ ]]; then + num_suffix="${BASH_REMATCH[1]}" + new_num=$((num_suffix + 1)) + hostname="devbox$new_num" +else + hostname="devbox" +fi # On linux we need to perform uid/gid alignment to ensure files modified on the host have the correct owner. # The entrypoint.sh script picks up these environment variables and adjusts the aztec-dev user accordingly. @@ -10,14 +22,24 @@ if [[ "$OSTYPE" == "linux"* ]]; then ID_ARGS="-e LOCAL_USER_ID=$(id -u) -e LOCAL_GROUP_ID=$(id -g)" fi -docker run \ - -ti --rm \ - --hostname devbox \ - -e SSH_CONNECTION=' ' \ - ${ID_ARGS:-} \ - -w/workspaces/aztec-packages \ - -v$PWD/..:/workspaces/aztec-packages \ - -vdevbox-home:/home/aztec-dev \ - -v$HOME/.ssh/id_rsa:/home/aztec-dev/.ssh/id_rsa:ro \ - -v/var/run/docker.sock:/var/run/docker.sock \ - aztecprotocol/devbox +if docker ps -a --format '{{.Names}}' | grep -q '^aztec-devbox$'; then + # Container already exists. Exec into a new shell. + docker exec -ti --user aztec-dev aztec-devbox /bin/zsh +else + # We override the docker config dir to ensure we don't conflict with vscodes dev-container. + # They share the same home dir, but vscode will add some credentials config that it needs to its docker config. + docker run \ + -ti --rm \ + --name aztec-devbox \ + --hostname $hostname \ + -e SSH_CONNECTION=' ' \ + -e DOCKER_CONFIG=/home/aztec-dev/.docker-devbox \ + ${ID_ARGS:-} \ + -w/workspaces/aztec-packages \ + -v$PWD/..:/workspaces/aztec-packages \ + -vdevbox-home:/home/aztec-dev \ + -vdevbox-var-lib-docker:/var/lib/docker \ + -v$HOME/.ssh/id_rsa:/home/aztec-dev/.ssh/id_rsa:ro \ + --privileged \ + aztecprotocol/devbox:1.0 +fi \ No newline at end of file diff --git a/scripts/earthly-ci b/scripts/earthly-ci index e424c0a4201..fe625d87015 100755 --- a/scripts/earthly-ci +++ b/scripts/earthly-ci @@ -25,6 +25,12 @@ INCONSISTENT_GRAPH_STATE_COUNT=0 # Counter for 'inconsistent graph state' error MAX_ATTEMPTS=3 ATTEMPT_COUNT=0 +export EARTHLY_USE_INLINE_CACHE=true +if [ "$GITHUB_REF_NAME" == "master" ]; then + export EARTHLY_SAVE_INLINE_CACHE=true + export EARTHLY_PUSH=true +fi + # Handle earthly commands and retries while [ $ATTEMPT_COUNT -lt $MAX_ATTEMPTS ]; do if earthly $@ 2>&1 | tee $OUTPUT_FILE >&2 ; then