diff --git a/cloud_build/flutter_agy_docker/Dockerfile b/cloud_build/flutter_agy_docker/Dockerfile index 140f14453..09d62e1a4 100644 --- a/cloud_build/flutter_agy_docker/Dockerfile +++ b/cloud_build/flutter_agy_docker/Dockerfile @@ -31,7 +31,8 @@ RUN set -eux; \ echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | tee /etc/apt/sources.list.d/github-cli.list > /dev/null; \ apt-get update && apt-get install -y gh; \ # install yq, a YAML/XML/TOML processor like jq - wget -qO /usr/local/bin/yq https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64; \ + ARCH=$(dpkg --print-architecture); \ + wget -qO /usr/local/bin/yq "https://github.com/mikefarah/yq/releases/latest/download/yq_linux_${ARCH}"; \ chmod a+x /usr/local/bin/yq; \ locale-gen en_US.UTF-8; \ ln -s $(which fdfind) /usr/local/bin/fd; \ diff --git a/cloud_build/flutter_agy_docker/Dockerfile.base b/cloud_build/flutter_agy_docker/Dockerfile.base index 74a895a8f..a67085cd1 100644 --- a/cloud_build/flutter_agy_docker/Dockerfile.base +++ b/cloud_build/flutter_agy_docker/Dockerfile.base @@ -9,6 +9,7 @@ FROM ubuntu:24.04 AS flutter-fetcher # 1. Define the ARG with a fallback default version ARG FLUTTER_VERSION="3.44.3" +ARG TARGETARCH ENV TZ="America/Los_Angeles" \ DEBIAN_FRONTEND=noninteractive \ @@ -39,7 +40,12 @@ USER coder RUN set -ex; \ export PATH="/opt/flutter/bin:${PATH}"; \ # 1. Download and uncompress the flutter tool - curl -fsSL https://storage.googleapis.com/flutter_infra_release/releases/stable/linux/flutter_linux_${FLUTTER_VERSION}-stable.tar.xz | tar -xJ --no-same-owner -C /opt; \ + ARCH="${TARGETARCH:-$(dpkg --print-architecture)}"; \ + EXCLUDE_CACHE=""; \ + if [ "$ARCH" = "arm64" ] || [ "$ARCH" = "aarch64" ]; then \ + EXCLUDE_CACHE="--exclude=flutter/bin/cache"; \ + fi; \ + curl -fsSL "https://storage.googleapis.com/flutter_infra_release/releases/stable/linux/flutter_linux_${FLUTTER_VERSION}-stable.tar.xz" | tar -xJ --exclude=.pub-preload-cache $EXCLUDE_CACHE --no-same-owner -C /opt; \ # 2. Run config to ONLY ENABLE web (and disable everything else) flutter config \ --enable-web \ diff --git a/cloud_build/flutter_agy_docker/README.md b/cloud_build/flutter_agy_docker/README.md index 35ceaa1e5..47b9940e9 100644 --- a/cloud_build/flutter_agy_docker/README.md +++ b/cloud_build/flutter_agy_docker/README.md @@ -6,41 +6,25 @@ Below are step-by-step instructions for getting started. ## 1. (Optional) Building the Docker Image Locally -> **Important Platform Note:** Flutter does not fully support `linux/arm64` yet. If you are on an Apple Silicon (M1/M2/M3) machine, you *must* set the platform to `linux/amd64` when building and running. +> **Platform Note:** This environment natively supports both `linux/amd64` (x86_64) and `linux/arm64` (Apple Silicon/ARM) architectures (for Dart/Flutter Web development only). -### For x86 / Intel: +### Building the Docker image: ```shell podman build -t flutter_docker . ``` -### For Apple Silicon (using podman): -```shell -podman build --platform linux/amd64 -t flutter_docker . -``` - ### Building a specific Flutter version: You can override the default Flutter version using the `FLUTTER_VERSION` build argument. ```shell -podman build --platform linux/amd64 --build-arg FLUTTER_VERSION=3.45.0 -t flutter_docker:3.45.0 . +podman build --build-arg FLUTTER_VERSION=3.45.0 -t flutter_docker:3.45.0 . ``` ## 2. Running the Docker Image Locally You can run the container in any project folder. The current working directory (`$PWD`) will be mapped to `/app` inside the container. -### For x86 / Intel: ```shell podman run --userns=keep-id:uid=1000,gid=1000 -it \ - -v ".:/app:z" \ - -v "dart_tool_cache:/app/.dart_tool" \ - -v "dart_build_cache:/app/build" \ - -v "$USER/.gemini:/home/coder/.gemini:z" \ - flutter_docker:latest -``` - -### For Apple Silicon (using podman): -```shell -podman run --platform linux/amd64 --userns=keep-id:uid=1000,gid=1000 -it \ -v "${PWD}:/app:z" \ -v "dart_tool_cache:/app/.dart_tool" \ -v "dart_build_cache:/app/build" \ diff --git a/cloud_build/flutter_agy_docker/cloudbuild.yaml b/cloud_build/flutter_agy_docker/cloudbuild.yaml index ba79450d7..6785012ce 100644 --- a/cloud_build/flutter_agy_docker/cloudbuild.yaml +++ b/cloud_build/flutter_agy_docker/cloudbuild.yaml @@ -4,52 +4,7 @@ steps: # ========================================== - # STEP 1: Build the Static Base Image - # ========================================== - - name: 'gcr.io/cloud-builders/docker' - entrypoint: 'bash' - args: ['-c', 'docker pull us-docker.pkg.dev/flutter-infra/flutter-infra/flutter_base:latest || exit 0'] - - - name: 'gcr.io/cloud-builders/docker' - dir: 'cloud_build/flutter_agy_docker/' - args: - - 'build' - - '--cache-from' - - 'us-docker.pkg.dev/flutter-infra/flutter-infra/flutter_base:latest' - - '--build-arg' - - 'FLUTTER_VERSION=$_FLUTTER_VERSION' - - '-t' - - 'us-docker.pkg.dev/flutter-infra/flutter-infra/flutter_base:$_FLUTTER_VERSION' - - '-f' - - 'Dockerfile.base' - - '.' - - # ========================================== - # STEP 2: Build the Auto-Updating Dev Image - # ========================================== - - name: 'gcr.io/cloud-builders/docker' - entrypoint: 'bash' - args: ['-c', 'docker pull us-docker.pkg.dev/flutter-infra/flutter-infra/flutter_docker:latest || exit 0'] - - - name: 'gcr.io/cloud-builders/docker' - dir: 'cloud_build/flutter_agy_docker/' - args: - - 'build' - - '--cache-from' - - 'us-docker.pkg.dev/flutter-infra/flutter-infra/flutter_docker:latest' - - '--build-arg' - - 'FLUTTER_VERSION=$_FLUTTER_VERSION' - # Force apt-get to run by injecting the unique build ID - - '--build-arg' - - 'CACHE_BUSTER=$BUILD_ID' - - '-t' - - 'us-docker.pkg.dev/flutter-infra/flutter-infra/flutter_docker:$_FLUTTER_VERSION' - - '-f' - - 'Dockerfile' - - '.' - - # ========================================== - # STEP 3: Conditionally Tag and Push 'latest', 'stable', or 'beta' + # STEP 1: Determine tags based on version # ========================================== - name: 'gcr.io/cloud-builders/docker' entrypoint: 'bash' @@ -58,8 +13,7 @@ steps: - | set -euo pipefail - # Install curl and jq (handles both Debian and Alpine builder variants) - # We temporarily disable exit-on-error to allow the fallback to work cleanly + # Install curl and jq set +e apt-get update && apt-get install -y curl jq 2>/dev/null || apk add curl jq 2>/dev/null set -e @@ -79,16 +33,13 @@ steps: BETA_VERSION=$$(echo "$$JSON_DATA" | \ jq -r '.current_release.beta as $$beta_hash | .releases[] | select(.hash == $$beta_hash) | .version' | head -n 1) - # Validate that the versions were successfully parsed. - # -z "$$STABLE_VERSION" checks if the variable is an empty string (e.g., if jq failed entirely). - # "$$STABLE_VERSION" == "null" checks if jq succeeded but couldn't find the requested data in the JSON. if [ -z "$$STABLE_VERSION" ] || [ "$$STABLE_VERSION" == "null" ]; then - echo "Error: STABLE_VERSION could not be parsed from JSON. The JSON structure may have changed." + echo "Error: STABLE_VERSION could not be parsed." exit 1 fi if [ -z "$$BETA_VERSION" ] || [ "$$BETA_VERSION" == "null" ]; then - echo "Error: BETA_VERSION could not be parsed from JSON. The JSON structure may have changed." + echo "Error: BETA_VERSION could not be parsed." exit 1 fi @@ -96,45 +47,103 @@ steps: echo "Current beta version is: $$BETA_VERSION" echo "Building for version: $_FLUTTER_VERSION" - if [ "$_FLUTTER_VERSION" == "$$STABLE_VERSION" ]; then - echo "Version $_FLUTTER_VERSION is stable. Tagging and pushing as latest and stable." + BASE_TAGS="us-docker.pkg.dev/flutter-infra/flutter-infra/flutter_base:$_FLUTTER_VERSION" + DEV_TAGS="us-docker.pkg.dev/flutter-infra/flutter-infra/flutter_docker:$_FLUTTER_VERSION" - # Tag the previously built versioned images - docker tag us-docker.pkg.dev/flutter-infra/flutter-infra/flutter_base:$_FLUTTER_VERSION us-docker.pkg.dev/flutter-infra/flutter-infra/flutter_base:stable - docker tag us-docker.pkg.dev/flutter-infra/flutter-infra/flutter_base:$_FLUTTER_VERSION us-docker.pkg.dev/flutter-infra/flutter-infra/flutter_base:latest - docker tag us-docker.pkg.dev/flutter-infra/flutter-infra/flutter_docker:$_FLUTTER_VERSION us-docker.pkg.dev/flutter-infra/flutter-infra/flutter_docker:stable - docker tag us-docker.pkg.dev/flutter-infra/flutter-infra/flutter_docker:$_FLUTTER_VERSION us-docker.pkg.dev/flutter-infra/flutter-infra/flutter_docker:latest + if [ "$_FLUTTER_VERSION" == "$$STABLE_VERSION" ]; then + echo "Version $_FLUTTER_VERSION is stable. Tagging as stable and latest." + BASE_TAGS="$$BASE_TAGS,us-docker.pkg.dev/flutter-infra/flutter-infra/flutter_base:stable,us-docker.pkg.dev/flutter-infra/flutter-infra/flutter_base:latest" + DEV_TAGS="$$DEV_TAGS,us-docker.pkg.dev/flutter-infra/flutter-infra/flutter_docker:stable,us-docker.pkg.dev/flutter-infra/flutter-infra/flutter_docker:latest" + elif [ "$_FLUTTER_VERSION" == "$$BETA_VERSION" ]; then + echo "Version $_FLUTTER_VERSION is beta. Tagging as beta." + BASE_TAGS="$$BASE_TAGS,us-docker.pkg.dev/flutter-infra/flutter-infra/flutter_base:beta" + DEV_TAGS="$$DEV_TAGS,us-docker.pkg.dev/flutter-infra/flutter-infra/flutter_docker:beta" + else + echo "Version $_FLUTTER_VERSION is neither stable nor beta. Using version tag only." + fi - # Push the new tags - docker push us-docker.pkg.dev/flutter-infra/flutter-infra/flutter_base:stable - docker push us-docker.pkg.dev/flutter-infra/flutter-infra/flutter_base:latest - docker push us-docker.pkg.dev/flutter-infra/flutter-infra/flutter_docker:stable - docker push us-docker.pkg.dev/flutter-infra/flutter-infra/flutter_docker:latest + echo "BASE_TAGS=$$BASE_TAGS" > /workspace/tags.env + echo "DEV_TAGS=$$DEV_TAGS" >> /workspace/tags.env - elif [ "$_FLUTTER_VERSION" == "$$BETA_VERSION" ]; then - echo "Version $_FLUTTER_VERSION is beta. Tagging and pushing as beta." + # ========================================== + # STEP 2: Build the Multi-Arch Base Image + # ========================================== + - name: 'gcr.io/cloud-builders/docker' + dir: 'cloud_build/flutter_agy_docker/' + entrypoint: 'bash' + args: + - '-c' + - | + set -euo pipefail - # Tag the previously built versioned images - docker tag us-docker.pkg.dev/flutter-infra/flutter-infra/flutter_base:$_FLUTTER_VERSION us-docker.pkg.dev/flutter-infra/flutter-infra/flutter_base:beta - docker tag us-docker.pkg.dev/flutter-infra/flutter-infra/flutter_docker:$_FLUTTER_VERSION us-docker.pkg.dev/flutter-infra/flutter-infra/flutter_docker:beta + # Register QEMU emulators for multi-arch build + docker run --privileged --rm tonistiigi/binfmt --install all + + # Create a new buildx builder + docker buildx create --use + + # Read tags + source /workspace/tags.env + + # Convert comma-separated tags to -t arguments + IFS=',' read -ra ADDR <<< "$$BASE_TAGS" + TAG_ARGS=() + for tag in "$${ADDR[@]}"; do + TAG_ARGS+=("-t" "$$tag") + done + + # Build and push the base image + docker buildx build \ + --platform linux/amd64,linux/arm64 \ + --cache-from us-docker.pkg.dev/flutter-infra/flutter-infra/flutter_base:latest \ + --cache-to type=inline \ + --build-arg FLUTTER_VERSION=$_FLUTTER_VERSION \ + "$${TAG_ARGS[@]}" \ + -f Dockerfile.base \ + --push \ + . - # Push the new tags - docker push us-docker.pkg.dev/flutter-infra/flutter-infra/flutter_base:beta - docker push us-docker.pkg.dev/flutter-infra/flutter-infra/flutter_docker:beta + # ========================================== + # STEP 3: Build the Multi-Arch Dev Image + # ========================================== + - name: 'gcr.io/cloud-builders/docker' + dir: 'cloud_build/flutter_agy_docker/' + entrypoint: 'bash' + args: + - '-c' + - | + set -euo pipefail - else - echo "Version $_FLUTTER_VERSION is neither the stable nor beta release. Skipping extra tags." - fi + # Register QEMU emulators + docker run --privileged --rm tonistiigi/binfmt --install all + + # Create a new buildx builder + docker buildx create --use + + # Read tags + source /workspace/tags.env + + # Convert comma-separated tags to -t arguments + IFS=',' read -ra ADDR <<< "$$DEV_TAGS" + TAG_ARGS=() + for tag in "$${ADDR[@]}"; do + TAG_ARGS+=("-t" "$$tag") + done + + # Build and push the developer image + docker buildx build \ + --platform linux/amd64,linux/arm64 \ + --cache-from us-docker.pkg.dev/flutter-infra/flutter-infra/flutter_docker:latest \ + --cache-to type=inline \ + --build-arg FLUTTER_VERSION=$_FLUTTER_VERSION \ + --build-arg CACHE_BUSTER=$BUILD_ID \ + "$${TAG_ARGS[@]}" \ + -f Dockerfile \ + --push \ + . substitutions: _FLUTTER_VERSION: "3.44.3" -# Push both the base and the final developer image to the registry -images: - - 'us-docker.pkg.dev/flutter-infra/flutter-infra/flutter_base:$_FLUTTER_VERSION' - - 'us-docker.pkg.dev/flutter-infra/flutter-infra/flutter_docker:$_FLUTTER_VERSION' - -# Force Cloud Build to send logs directly to Cloud Logging -# instead of an autogenerated GCS bucket options: logging: CLOUD_LOGGING_ONLY diff --git a/cloud_build/flutter_agy_docker/docker-compose.yml b/cloud_build/flutter_agy_docker/docker-compose.yml index 7db5d4e89..a37e1f11e 100644 --- a/cloud_build/flutter_agy_docker/docker-compose.yml +++ b/cloud_build/flutter_agy_docker/docker-compose.yml @@ -9,7 +9,6 @@ services: dev: image: us-docker.pkg.dev/flutter-infra/flutter-infra/flutter_docker:stable - platform: linux/amd64 # Dynamically reads the environment variable container_name: ${ENV_NAME:-coder-env} stdin_open: true