14

I was able to build a multiarch image successfully from an M1 Macbook which is arm64. Here's my docker file and trying to run from a raspberrypi aarch64/arm64 and I am getting this error when running the image: standard_init_linux.go:228: exec user process caused: exec format error

Editing the post with the python file as well:

FROM frolvlad/alpine-python3

RUN pip3 install docker
RUN mkdir /hoster
WORKDIR /hoster
ADD hoster.py /hoster/

CMD ["python3", "-u", "hoster.py"]




#!/usr/bin/python3
import docker
import argparse
import shutil
import signal
import time
import sys
import os

label_name = "hoster.domains"
enclosing_pattern = "#-----------Docker-Hoster-Domains----------\n"
hosts_path = "/tmp/hosts"
hosts = {}

def signal_handler(signal, frame):
    global hosts
    hosts = {}
    update_hosts_file()
    sys.exit(0)

def main():
    # register the exit signals
    signal.signal(signal.SIGINT, signal_handler)
    signal.signal(signal.SIGTERM, signal_handler)

    args = parse_args()
    global hosts_path
    hosts_path = args.file

    dockerClient = docker.APIClient(base_url='unix://%s' % args.socket)
    events = dockerClient.events(decode=True)
    #get running containers
    for c in dockerClient.containers(quiet=True, all=False):
        container_id = c["Id"]
        container = get_container_data(dockerClient, container_id)
        hosts[container_id] = container

    update_hosts_file()

    #listen for events to keep the hosts file updated
    for e in events:
        if e["Type"]!="container": 
            continue
        
        status = e["status"]
        if status =="start":
            container_id = e["id"]
            container = get_container_data(dockerClient, container_id)
            hosts[container_id] = container
            update_hosts_file()

        if status=="stop" or status=="die" or status=="destroy":
            container_id = e["id"]
            if container_id in hosts:
                hosts.pop(container_id)
                update_hosts_file()


def get_container_data(dockerClient, container_id):
    #extract all the info with the docker api
    info = dockerClient.inspect_container(container_id)
    container_hostname = info["Config"]["Hostname"]
    container_name = info["Name"].strip("/")
    container_ip = info["NetworkSettings"]["IPAddress"]
    if info["Config"]["Domainname"]:
        container_hostname = container_hostname + "." + info["Config"]["Domainname"]
    
    result = []

    for values in info["NetworkSettings"]["Networks"].values():
        
        if not values["Aliases"]: 
            continue

        result.append({
                "ip": values["IPAddress"] , 
                "name": container_name,
                "domains": set(values["Aliases"] + [container_name, container_hostname])
            })

    if container_ip:
        result.append({"ip": container_ip, "name": container_name, "domains": [container_name, container_hostname ]})

    return result


def update_hosts_file():
    if len(hosts)==0:
        print("Removing all hosts before exit...")
    else:
        print("Updating hosts file with:")

    for id,addresses in hosts.items():
        for addr in addresses:
            print("ip: %s domains: %s" % (addr["ip"], addr["domains"]))

    #read all the lines of thge original file
    lines = []
    with open(hosts_path,"r+") as hosts_file:
        lines = hosts_file.readlines()

    #remove all the lines after the known pattern
    for i,line in enumerate(lines):
        if line==enclosing_pattern:
            lines = lines[:i]
            break;

    #remove all the trailing newlines on the line list
    if lines:
        while lines[-1].strip()=="": lines.pop()

    #append all the domain lines
    if len(hosts)>0:
        lines.append("\n\n"+enclosing_pattern)
        
        for id, addresses in hosts.items():
            for addr in addresses:
                lines.append("%s    %s\n"%(addr["ip"],"   ".join(addr["domains"])))
        
        lines.append("#-----Do-not-add-hosts-after-this-line-----\n\n")

    #write it on the auxiliar file
    aux_file_path = hosts_path+".aux"
    with open(aux_file_path,"w") as aux_hosts:
        aux_hosts.writelines(lines)

    #replace etc/hosts with aux file, making it atomic
    shutil.move(aux_file_path, hosts_path)


def parse_args():
    parser = argparse.ArgumentParser(description='Synchronize running docker container IPs with host /etc/hosts file.')
    parser.add_argument('socket', type=str, nargs="?", default="tmp/docker.sock", help='The docker socket to listen for docker events.')
    parser.add_argument('file', type=str, nargs="?", default="/tmp/hosts", help='The /etc/hosts file to sync the containers with.')
    return parser.parse_args()

if __name__ == '__main__':
    main()
Nitesh
  • 191
  • 1
  • 3
  • 7
  • Can you share the file `hoster.py`? Otherwise it's impossible to recreate the issue. – Davide Madrisan Oct 27 '21 at 15:13
  • Added the hoster.py file to the post – Nitesh Oct 27 '21 at 16:54
  • "exec format error" means what it looks like it says -- the thing you're trying to run isn't a legitimate executable for the current platform. – Charles Duffy Oct 27 '21 at 16:55
  • Note that a M1 macbook and a RPi are absolutely not binary-compatible. Yes, they use the same _family_ of instruction set, but that doesn't mean they're 100% compatible, and they absolutely are not in practice. Moreover, binaries compiled for MacOS aren't expected to run on Linux, even when the CPUs _are_ running the same instruction set – Charles Duffy Oct 27 '21 at 16:55
  • @DavideMadrisan, the Python script has no bearing on this problem. The issue happens before the Python interpreter is executed; it can't possibly get far enough to start to load the script. – Charles Duffy Oct 27 '21 at 16:57
  • Answer here: https://stackoverflow.com/a/70614305/8832840 – Ryan Jan 08 '22 at 02:52
  • Does this answer your question? [standard\_init\_linux.go:178: exec user process caused "exec format error"](https://stackoverflow.com/questions/42494853/standard-init-linux-go178-exec-user-process-caused-exec-format-error) – Ryan Jan 08 '22 at 02:53

3 Answers3

10

A "multiarch" Python interpreter built on MacOS is intended to target MacOS-on-Intel and MacOS-on-Apple's-arm64.

There is absolutely no binary compatibility with Linux-on-Apple's-arm64, or with Linux-on-aarch64. You can't run MacOS executables on Linux, no matter if the architecture matches or not.

Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
  • 1
    For building docker images targeted at a different platform, you can use docker's "buildkit" extension (packaged with docker-for-mac). IE: `docker buildx build --platform=linux/amd64 .... ` – John Sep 20 '22 at 20:22
4

This happens when you build the image in a machine(host) whose operating system/platform that is different from the platform that you want to spin up the containers.

The solution is to build the docker image using the same machine/operating system(that needs to run it/that needs to spin up the container(s)).

In my case I build NodeJS, Python, Nginx, redis and postgres images in an OSX host and was trying to spin up containers from the images in an Ubuntu debian host. I solved by building the images in Ubuntu debian and span up the containers in the same platform(Ubuntu debian)

Elijah Baraza
  • 291
  • 4
  • 4
1

you can now use docker buildx build with target platform as mentioned here:

docker buildx build --platform linux/amd64 -t my-cool-image .

reference: https://www.macstadium.com/blog/building-docker-images-on-apple-silicon-with-buildx

Scouser
  • 11
  • 3
  • While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. - [From Review](/review/late-answers/34437404) – DSDmark May 27 '23 at 14:51