Skip to content

Instantly share code, notes, and snippets.

@x-yuri

x-yuri/a.md Secret

Last active December 10, 2023 09:55
Show Gist options
  • Save x-yuri/c99237fa0980f540b24ab17c5a7e8e79 to your computer and use it in GitHub Desktop.
Save x-yuri/c99237fa0980f540b24ab17c5a7e8e79 to your computer and use it in GitHub Desktop.

If we copy the image to Artifact Registry:

resource "google_artifact_registry_repository" "cloud-run-test" {
  location = "europe-central2"
  repository_id = "cloud-run-test"
  format = "DOCKER"
}
$ terraform apply
$ docker pull cloudnativelabs/whats-my-ip
$ docker tag cloudnativelabs/whats-my-ip europe-central2-docker.pkg.dev/PROJECT_ID/cloud-run-test/whats-my-ip
$ docker push europe-central2-docker.pkg.dev/PROJECT_ID/cloud-run-test/whats-my-ip
resource "google_cloud_run_v2_service" "cloud-run-test" {
    name = "cloud-run-test"
    location = "europe-central2" 
    template {
        containers {
            image = "europe-central2-docker.pkg.dev/PROJECT_ID/cloud-run-test/whats-my-ip"
        }
    }
}

resource "google_artifact_registry_repository" "cloud-run-test" {
  location = "europe-central2"
  repository_id = "cloud-run-test"
  format = "DOCKER"
}
$ terraform apply
$ gcloud logging read 'logName:projects/PROJECT_ID/logs/run.googleapis.com%2F' --format 'text(logName, textPayload, timestamp)' --project PROJECT_ID --freshness=5m
---
log_name:     projects/PROJECT_ID/logs/run.googleapis.com%2Fvarlog%2Fsystem
text_payload: Container called exit(2).
timestamp:    2023-12-09T04:57:12.567151674Z
---
log_name:     projects/PROJECT_ID/logs/run.googleapis.com%2Fstderr
text_payload: /home/server: line 1: syntax error: unexpected "("
timestamp:    2023-12-09T04:57:11.574154Z

os/arch or:

a.sh:

set -eu
image=cloudnativelabs/whats-my-ip
registry=https://registry-1.docker.io
curl_args=(-sS -H 'Accept: application/vnd.docker.distribution.manifest.v2+json')

scope=repository:$image:pull
token=`curl -sS "https://auth.docker.io/token?service=registry.docker.io&scope=$scope" | jq -r .token`
curl_args+=(-H "Authorization: Bearer $token")

manifest=`curl "${curl_args[@]}" "$registry/v2/$image/manifests/latest"`
config_digest=`echo "$manifest" | jq -r .config.digest`

config=`curl "${curl_args[@]}" -L "$registry/v2/$image/blobs/$config_digest"`
os=`echo "$config" | jq -r .os`
architecture=`echo "$config" | jq -r .architecture`

echo "$os/$architecture"
$ bash a.sh
linux/amd64

file:

$ docker container create cloudnativelabs/whats-my-ip
$ docker cp 97bd786fbc2dd1df6925121ae8c0febebaf1a6f8785c10a7a7237e5799791289:/home/server /tmp/server
$ docker rm 97bd786fbc2dd1df6925121ae8c0febebaf1a6f8785c10a7a7237e5799791289

$ file /tmp/server
/tmp/server: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), statically linked, Go BuildID=edc3254ee8543cb3d51767295b041bc44368d286, with debug_info, not stripped

$ od -t x1z /tmp/server | head -3
0000000 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00  >.ELF............<
0000020 02 00 03 00 01 00 00 00 40 a7 09 08 34 00 00 00  >........@...4...<
0000040 14 01 00 00 00 00 00 00 34 00 20 00 07 00 28 00  >........4. ...(.<

From the description:

Go web server running on port 8080


sh /home/server:

$ docker run --rm -it cloudnativelabs/whats-my-ip sh /home/server
/home/server: line 1: syntax error: unexpected "("

$ docker history --no-trunc cloudnativelabs/whats-my-ip | less
IMAGE                                                                     CREATED       CREATED BY                                                                                                SIZE      COMMENT
sha256:7be89ad1e6ef4ef4eac70f5be5fca9501eea2159a01f29b2b407690cfdcc0c1e   6 years ago   /bin/sh -c #(nop)  CMD ["/bin/sh" "-c" "/home/server"]                                                    0B        
<missing>                                                                 6 years ago   /bin/sh -c #(nop) COPY file:eadac022277eddb995689c668b68561cef126d9b5ca9a3992a2b2b31a1ae1b18 in /home/    4.84MB    
<missing>                                                                 6 years ago   /bin/sh -c #(nop)  CMD ["sh"]                                                                             0B        
<missing>                                                                 6 years ago   /bin/sh -c #(nop) ADD file:c9ecd8ff00c653fb652ad5a0a9215e1f467f0cd9933653b8a2e5e475b68597ab in /          1.11MB    

A simple go server (not the original implementation):

server.go:

package main

import (
    "fmt"
    "net/http"
)

func root(w http.ResponseWriter, req *http.Request) {
    w.Header().Set("Content-Type", "text/html; charset=utf-8")
    fmt.Fprintf(w, "hello world (go)\n")
}

func main() {
    http.HandleFunc("/", root)
    fmt.Printf("Server running...\n");
    http.ListenAndServe(":8080", nil)
}

Dockerfile:

FROM alpine:3.18 AS build
COPY server.go .
RUN apk add go && go build server.go

FROM alpine:3.18
COPY --from=build /server /home/server
CMD ["/bin/sh", "-c", "/home/server"]
$ docker build -t i .
$ docker history --no-trunc i | less
IMAGE                                                                     CREATED          CREATED BY                                                                                          SIZE      COMMENT
sha256:a9eb6fb2e9ed7adb06b830feda760219c43fd6b6f05c517bb5dd1941e0a7f80e   21 minutes ago   CMD ["/bin/sh" "-c" "/home/server"]                                                                 0B        buildkit.dockerfile.v0
<missing>                                                                 21 minutes ago   COPY /server /home/server # buildkit                                                                6.68MB    buildkit.dockerfile.v0
<missing>                                                                 5 months ago     /bin/sh -c #(nop)  CMD ["/bin/sh"]                                                                  0B        
<missing>                                                                 5 months ago     /bin/sh -c #(nop) ADD file:1da756d12551a0e3e793e02ef87432d69d4968937bd11bed0af215db19dd94cd in /    7.33MB    

The CMD line differs a bit:

-/bin/sh -c #(nop)  CMD ["/bin/sh" "-c" "/home/server"]
+CMD ["/bin/sh" "-c" "/home/server"]
$ docker tag i europe-central2-docker.pkg.dev/PROJECT_ID/cloud-run-test/i
$ docker push europe-central2-docker.pkg.dev/PROJECT_ID/cloud-run-test/i
resource "google_cloud_run_v2_service" "cloud-run-test" {
    name = "cloud-run-test"
    location = "europe-central2" 
    template {
        containers {
            image = "europe-central2-docker.pkg.dev/PROJECT_ID/cloud-run-test/i"
        }
    }
}
$ terraform apply
$ gcloud logging read 'logName:projects/PROJECT_ID/logs/run.googleapis.com\%2F' --format 'text(logName, textPayload, timestamp)' --project PROJECT_ID --freshness=5m
---
log_name:     projects/PROJECT_ID/logs/run.googleapis.com%2Fvarlog%2Fsystem
text_payload: Default STARTUP TCP probe succeeded after 1 attempt for container "i-1" on port 8080.
timestamp:    2023-12-09T07:02:32.756159Z
---
log_name:     projects/PROJECT_ID/logs/run.googleapis.com%2Fstdout
text_payload: Server running...
timestamp:    2023-12-09T07:02:32.743640Z

Running a 32-bit go server on Cloud Run:

Dockerfile:

FROM alpine:3.18 AS build
COPY server.go .
RUN apk add go && GOARCH=386 go build server.go

FROM alpine:3.18
COPY --from=build /server /home/server
CMD ["/bin/sh", "-c", "/home/server"]
$ docker build -t i32 .
$ docker tag i32 europe-central2-docker.pkg.dev/PROJECT_ID/cloud-run-test/i32
$ docker push europe-central2-docker.pkg.dev/PROJECT_ID/cloud-run-test/i32
resource "google_cloud_run_v2_service" "cloud-run-test" {
    name = "cloud-run-test"
    location = "europe-central2" 
    template {
        containers {
            image = "europe-central2-docker.pkg.dev/PROJECT_ID/cloud-run-test/i32"
        }
    }
}
$ terraform apply
$ gcloud logging read 'logName:projects/PROJECT_ID/logs/run.googleapis.com\%2F' --format 'text(logName, textPayload, timestamp)' --project PROJECT_ID --freshness=5m
---
log_name:     projects/PROJECT_ID/logs/run.googleapis.com%2Fvarlog%2Fsystem
text_payload: Container called exit(2).
timestamp:    2023-12-09T07:53:43.173579304Z
---
log_name:     projects/PROJECT_ID/logs/run.googleapis.com%2Fstderr
text_payload: /home/server: line 2: syntax error: unexpected "("
timestamp:    2023-12-09T07:53:42.174998Z
---
log_name:     projects/PROJECT_ID/logs/run.googleapis.com%2Fstderr
text_payload: /home/server: line 1: ?ELFAAABCA??: not found
timestamp:    2023-12-09T07:53:42.174974Z

$ docker run --rm -it i32 sh -c 'apk add file; file /home/server'
...
/home/server: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), statically linked, Go BuildID=-UmeOax9gDsURrJp1IOc/CXhXTcfUnoQh7DBkw3r2/kOV85W8Lgl0qM7iB94ov/ExdX4uzfHMS2PUt1AdAO, with debug_info, not stripped

$ docker run --rm -it i32 sh -c 'apk add coreutils; od -t x1z /home/server | head -3'
...
0000000 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00  >.ELF............<
0000020 02 00 03 00 01 00 00 00 d0 c9 0a 08 34 00 00 00  >............4...<
0000040 14 01 00 00 00 00 00 00 34 00 20 00 07 00 28 00  >........4. ...(.<

It seems like Cloud Run doesn't expect 32-bit binaries, and when faced with one it falls back to sh (sh /path/to/executable).

link

I tried to run cloudnativelabs/whats-my-ip on GCP (Cloud Run), and there are 2 things I don't understand.

First, it fails:

/home/server: line 1: syntax error: unexpected "(" Container called exit(2).

The image contains a Go program, but this looks like it tries to run it as a script. Because there's no syntax when you run a binary.

That's one thing I don't understand. What's happening here? Why does it fail? Does it really think the entrypoint is a script? A shell script? Why?

Another is, I tried to build a separate image with the binary (more on it here):

FROM alpine:3.18  # or debian:bookworm-slim
COPY server .
CMD ["/server"]

Locally that worked out, but on Cloud Run it said:

terminated: Application failed to start: failed to load /server: exec format error Application exec likely failed

Supposedly this happens when trying to run a linux/arm... image on linux/amd64. But even if it means general architecture mismatch... I tried to run a simple http server (Perl and Go versions) on Cloud Run and it succeeded. I'm running Linux and uname -m says x86_64. So supposedly I'm linux/amd64. Cloud Run most likely too. And Docker Hub says linux/amd64 for cloudnativelabs/whats-my-ip. So what's its problem? From what I can see everything considered here is linux/amd64. And locally it runs, but not on Cloud Run.

To sum it up, the image runs locally but not on Cloud Run. The binary from the image runs locally but not on Cloud Run. Images I build locally do run on Cloud Run. Every part of this is linux/amd64. What am I doing wrong?

Of course the specific image (cloudnativelabs/whats-my-ip) doesn't matter much. But there are apparently other images like it.

As for the linked question (exec format error), I think it's about running linux/arm... images on linux/adm64. Which doesn't looks like the case here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment