GoogleCloudPlatform / GoogleCloudPlatform/cloud-sql-proxy

Alpine image: linux/arm64 variant ships an x86-64 userland because Dockerfile.alpine pins an amd64-specific base digest

Open
#2,651 0 comments 0 reactions 0 assignees View on GitHub
type: bug
Dominant language
Go
Stars
1.4k
Forks
352
Avg merge
14h 54m
Merged PRs (30d)
5

Description

### Bug Description

The linux/arm64 variant of the Alpine container image ships an x86-64 userland. The proxy binary itself is correctly cross-compiled for arm64, but busybox, apk, and everything else is x86-64. On arm64 nodes, `/bin/sh` and all other tools fail with `exec format error`, and the proxy's `--fuse` mode is broken because `fusermount` is an x86-64 binary.

Root cause: the final stage of `Dockerfile.alpine` pins `alpine:3` to an amd64-specific image manifest digest instead of the multi-arch index digest. Digest pinning bypasses buildx platform selection, so the `--platform linux/arm64` build silently uses the amd64 rootfs. The pin is unchanged at v2.24.1, so current releases are affected.

The removed bookworm variant (#2630) had the identical defect (see step 3 below), which suggests the digest-update automation systematically resolves platform manifest digests instead of index digests. Suggested fix: pin the index digest for `alpine:3` (the tag already publishes linux/arm64 in its manifest list), and fix the automation so the pin does not regress on the next update.

### Example code (or command)

```dockerfile
# Dockerfile.alpine (unchanged as of v2.24.1) — final stage pins an
# amd64-only manifest digest:
FROM alpine:3@sha256:79ff19e9084a00eece421b2523fb93e22d730e2c0e525905de047e848e56d95f
```

```sh
# Runtime symptom on an arm64 node:
$ kubectl exec -it -c cloud-sql-proxy -- /bin/sh
exec /bin/sh: exec format error
```

### Stacktrace

```bash

```

### Steps to reproduce?

No arm64 hardware is required; everything below inspects the published images with `crane`.

1. Compare the base rootfs layer of the amd64 and arm64 manifests. They are identical, which is impossible for a correct multi-arch build:

```sh
IMG=gcr.io/cloud-sql-connectors/cloud-sql-proxy:2.23-alpine
crane manifest $IMG | jq -r '.manifests[] | select(.platform.os == "linux") | "\(.platform.architecture) \(.digest)"'
# then, for each digest:
crane manifest gcr.io/cloud-sql-connectors/cloud-sql-proxy@ | jq -r '.layers[0].digest'

# Observed:
# amd64 layers[0] = sha256:55afa1ecc21d2bb5e5045f32dafee56272ffd89860bac26f6c32123439af26a4
# arm64 layers[0] = sha256:55afa1ecc21d2bb5e5045f32dafee56272ffd89860bac26f6c32123439af26a4
# (the alpine 3.24.1 x86_64 minirootfs layer)
```

2. Confirm that busybox in the arm64 image is an x86-64 ELF:

```sh
$ crane export --platform linux/arm64 $IMG - | tar -xO bin/busybox | head -c 20 | xxd
00000000: 7f45 4c46 0201 0100 0000 0000 0000 0000 .ELF............
00000010: 0300 3e00 ..>.
# e_machine = 0x3e (EM_X86_64); aarch64 would be 0xb7
```

3. (Optional) Confirm the same pattern in the removed bookworm variant:

```sh
# 2.23-bookworm shares its base layer across platforms:
# amd64 (sha256:06b15bd1b81bb27956d45da63d574010258ca14f605dbc79e446d6b742873461)
# layers[0] = sha256:20face757db20cd2eddf8149ec7d6b4f1630481ae00d25ad6396bcc5bef5b082
# arm64 (sha256:d80cd7c7689e6e56d76b8f4248513910cc09747eb66d8a91b3e5aef343bbe16a)
# layers[0] = sha256:20face757db20cd2eddf8149ec7d6b4f1630481ae00d25ad6396bcc5bef5b082
```

4. (Optional) On any arm64 host, run a shell in the image to observe
the runtime failure:

```sh
docker run --rm -it --entrypoint /bin/sh gcr.io/cloud-sql-connectors/cloud-sql-proxy:2.23-alpine
# exec /bin/sh: exec format error
```

### Environment

- Image: `gcr.io/cloud-sql-connectors/cloud-sql-proxy:2.23-alpine` (`linux/arm64` variant); `Dockerfile.alpine` carries the same pin at `v2.24.1`, so current releases are affected as well
- Host: any linux/arm64 node (e.g. GKE arm64 node pools); the defect is also verifiable host-independently with `crane` as above
- Tools used for verification: `crane`, `jq`, `xxd`

### Additional Details

_No response_

Contributor guide

Open the contributing guide

Research direction

Start with Dockerfile.alpine and inspect the final alpine:3 digest, then use crane manifest to distinguish the platform manifest from the multi-arch index. Trace the digest-update automation mentioned in the issue and verify it preserves index digests. Done means the linux/arm64 image contains an arm64 Alpine rootfs and the pin does not regress on the next update.

Written by the indexing model from the issue text.

Assessment

Tech stack
docker, dockerfile
Domain
build-system, devops, infrastructure
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
65/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.