Scratch image not running with a cross compiled go binary -- help

Hi everyone,

I hope someone around here has dealt with a similar issue:
I am trying to run a pre-compiled Go binary on a scratch image on a RPi3, without success.
The container is stuck as “installed”

I have a simple hello world application in Go:

package main

import (
  "fmt"
)

func main(){
  fmt.Println("Hello world!")
}

This is pre-compiled with the following command for cross-compilation.
I have tried to use all available tricks to make the binary static, in case that was the problem, which shouldnt because of few dependancies.

env CGO_ENABLED=0 GOOS=linux GOARCH=arm go build -a --installsuffix cgo -v -tags netgo -ldflags '-extldflags "-static"' .

This yields the following verbosity for the installed packages:

runtime/internal/sys
errors
math/bits
internal/cpu
unicode/utf8
runtime/internal/math
internal/bytealg
math
runtime/internal/atomic
internal/race
sync/atomic
unicode
runtime
internal/testlog
strconv
sync
io
reflect
syscall
internal/syscall/unix
time
sort
internal/poll
internal/fmtsort
os
fmt
Test

I copied the binary to the required location and then I apply the following Dockerfile

FROM resin/scratch
COPY ./app/Test /Test
CMD ["/Test"]

Of course, the structure of the directory is:
mytest/dockerfile
mytest/app/Test

Upon running, we see the holy Unicorn of success:

Unfortunaly, the container doesnt pass the installed states.
As well, I tried to read the logs of the host but I am not able to make sense out of that.

On the other hand, if I introduce an Alpine run image, it does work!

FROM balenalib/raspberrypi3-alpine:latest-run
COPY ./app/Test /Test
CMD ["bash","/usr/src/app/start.sh"]

And start.sh as

#!/bin/bash

chmod +x Test
./Test

Also, alternatively, I am able to run a nats server in the following way:

FROM balenalib/%%BALENA_MACHINE_NAME%%-golang:latest-build AS build
# get package without install -d
RUN go get -d github.com/nats-io/nats-server
WORKDIR /go/src/github.com/nats-io/nats-server
# build nats-server
RUN CGO_ENABLED=0 go build -a -tags netgo -ldflags="-w -s"

# second pass. only build the container with the go bin file
FROM resin/scratch
COPY --from=build /go/src/github.com/nats-io/nats-server/nats-server /nats-server
CMD ["/nats-server", "-p","4222", "-m","8222"]

On the internet most people would run go get from some github repository. That actually works. However, what I wanted to have is the entire project locally compiled, but I cannot understand why it doesnt work.

Anyone?

Hey @mvargasevans, I will investigate and get back to you as soon as I have anything.

Hey @mvargasevans,

I got your example working.
To reproduce, create a test.go:

package main

import (
	"fmt"
	"time"
)

func main() {
	for {
		fmt.Println("Hello world!")
		time.Sleep(time.Second)
	}
}

Compile it with env GOOS=linux GOARCH=arm GOARM=5 go build test.go

And this is the Dockerfile.template:

FROM balenalib/%%BALENA_MACHINE_NAME%%-alpine:latest-run
WORKDIR /usr/src/app
COPY test test
CMD ["./test"]

The final image has 35MB.

Could you give it a go and let me know if it works?

Cheers

Hi Danksu

First, thanks for putting time into this.
I tried your code, final size is 35 Mb.

However, I get a command not found: ./test
I placed Dockerfile.template and test into the same directory.

Am I missing something?

Hey @mvargasevans ,

Just to be on the same page, can you go to https://github.com/dansku/go-docker-arm-crosscompile-balena and clone the repo to your computer.

Then go to the folder and run balena push <applicationName>.

Let me know if you still have the same issue

Hey

  1. Cloned the repo.
  2. uploaded the files with balena push
  3. File is 35.10 MB
  4. Same result, command not found.

Folder:
Dockerfile.template
test
(as cloned)

FROM balenalib/%%BALENA_MACHINE_NAME%%-alpine:latest-run

WORKDIR /usr/src/app

COPY test test

CMD ["./test"]

@mvargasevans could you please Grant support access to the device so I can take a look?
Thanks

There I gave access!
Thanks

Could you try adding RUN chmod +x test on the line above CMD ["./test"] and see if it changes anything?

Hey!
That works.
I was doing that in the start.sh file but skipped it here. Thanks.

Now that we are on the same page, the question is:
How can we deploy a scratch image?

in the past I tried this:

FROM resin/scratch
COPY ./test /test
#RUN chmod +x test
CMD ["/test"]

Is that something to try?

Hi there,

Yes, you should be able to use a scratch image, however I’d recommend you don’t use resin/scratch as this image is 3 years old.

The following should work for you:

FROM scratch

WORKDIR /usr/src/app
COPY test test

CMD ["./test"]

Hi,

So I changed to this code:

FROM scratch
WORKDIR /usr/src/app

COPY test test
#RUN chmod +x test
CMD ["./test"]

As well tried “/test” as you can see in the first post.

However it stays in installed and the service tries to continuosly restart.
Ideas?

Hey @mvargasevans,

Try this dockerfile

FROM scratch
WORKDIR /usr/src/app
COPY test test
CMD ["./test"]

But make sure to run, on your computer chmod a+x test before pushing it to balena. Tested here and it worked!

Glad to here there is working! but no luck here.
Maybe I missed something.
Did you do anything else in between?

Update:
I am using git bash and there seems to be an issue with the chmod command on it. Hold on, please dont waste your time in this until I check this.

Hi to all!

First, the solution works and I highly appreciate the effort.
The final issue was that Git bash doesnt really accept chmod.
Here the answer is provided: link

Basically, in git bash:
git update-index --chmod=+x test

Aleluya!
The image is now a beautiful 1.8 mb

1 Like

Hey @mvargasevans thanks for posting this back. Glad to hear this is finally working :slight_smile: