Running snapcraft on container fails on specific guest hosts - multipass is required

Hi, I managed to create a container that is running and snapping successfully snaps. However, when I create a container from the same Dockerfile and snapcraft wrapper on a K8s cluster on which I don’t have access to the nodes or the pods it fails with message " You need ‘multipass’ set-up to build snaps: https://multipass.run."

What am I missing here? Are there requirements for the guest host? Or maybe some hardening that I’m not aware of?

That’s the Dockerfile that was inspired by - https://github.com/cibuilds/snapcraft/blob/trunk/core20/Dockerfile

FROM <ubuntu-base-image>:latest

USER root

ENV TZ=Europe/Minsk
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone

RUN apt-get update && apt-get install -y \
                snapd \
                squashfs-tools \
                curl jq vim wget\
        && \
    rm -rf /var/lib/apt/lists/*

# Manually install the core18 snap, a dependency of the snapcraft snap
RUN curl -L $(curl -H "X-Ubuntu-Series: 16" "https://api.snapcraft.io/api/v1/snaps/details/core18" | jq ".download_url" -r) --output core18.snap && \
        mkdir -p /snap/core18 && \
        unsquashfs -d /snap/core18/current core18.snap && \
        rm -f core18.snap

# Manually install the snapcraft snap, so we can use it to build new snaps
RUN curl -L https://api.snapcraft.io/api/v1/snaps/download/vMTKRaLjnOJQetI78HjntT37VuoyssFE_6751.snap --output snapcraft.snap && \

        mkdir -p /snap/snapcraft && \
        unsquashfs -d /snap/snapcraft/current snapcraft.snap && \
        rm -f snapcraft.snap

# Install the Snapcraft runner
COPY snapcraft-wrapper /snap/bin/snapcraft


#Install locals
RUN apt update && apt install -y locales
RUN locale-gen en_US.UTF-8
RUN update-locale LANG=en_US.UTF-8
ENV LANG="en_US.utf8"
ENV LANGUAGE="en_US.utf8"
ENV LC_ALL="en_US.utf8"

ENV JAVA_HOME /usr/lib/jvm/jdk-17-oracle-x64
# Set the proper environment
ENV PATH=/snap/bin:$PATH

The snapcraft-wrapper

#!/bin/sh

SNAP="/snap/snapcraft/current"
SNAP_NAME="$(awk '/^name:/{print $2}' $SNAP/meta/snap.yaml)"
SNAP_VERSION="$(awk '/^version:/{print $2}' $SNAP/meta/snap.yaml)"
SNAP_ARCH="amd64"

export SNAP
export SNAP_NAME
export SNAP_VERSION
export SNAP_ARCH

exec "$SNAP/usr/bin/python3" "$SNAP/bin/snapcraft" "$@"

snap list output from the VM that runs the container:

snap list

Name      Version   Rev    Tracking       Publisher      Notes
core18    20230901  2796   latest/stable  canonical✓     base
core20    20230801  2015   latest/stable  canonical✓     base
helm      2.16.12   290    2.16/stable    snapcrafters✪  classic
microk8s  v1.21.13  3410   1.21/stable    canonical✓     classic
snapd     2.60.4    20290  latest/stable  canonical✓     snapd

snap list --version

snap    2.60.4
snapd   2.60.4
series  16
ubuntu  20.04
kernel  5.4.0-152-generic

snapcraft.yaml

name: test1
version: '0.1'
base: core18
summary: running snapcraft from an ubuntu container
description: |
  bla bla

grade: devel
confinement: devmode

parts:
  my-part:
    plugin: nil

snapcraft defaults to do its builds in containers or VMs … so it will try to spawn either a multipass or an lxd instance when starting … you can force it to not do this by giving it the --destructive-mode option on the cmdline (though this is obviously at your own risk and you need to care for yourself that the build env is correctly matching the base of the snap you are building)…

1 Like

Thank you very much for the reply @ogra , indeed it helped me to bypass this issue, now I need to figure why it fails on

Sorry, an error occurred in Snapcraft: ('Connection aborted.', FileNotFoundError(2, 'No such file or directory'))

I guess it means that snapd does not run inside the container properly. I’m still trying to figure why it works perfect on container that is launched from my local VM while in my CI/CD it fails.

If you can provide a full traceback for that error, we may be able to help you more.

1 Like

sure.

Sorry, an error occurred in Snapcraft:
('Connection aborted.', FileNotFoundError(2, 'No such file or directory'))
Traceback (most recent call last):
  File "/snap/snapcraft/current/lib/python3.6/site-packages/urllib3/connectionpool.py", line 706, in urlopen
    chunked=chunked,
  File "/snap/snapcraft/current/lib/python3.6/site-packages/urllib3/connectionpool.py", line 394, in _make_request
    conn.request(method, url, **httplib_request_kw)
  File "/snap/snapcraft/current/usr/lib/python3.6/http/client.py", line 1281, in request
    self._send_request(method, url, body, headers, encode_chunked)
  File "/snap/snapcraft/current/usr/lib/python3.6/http/client.py", line 1327, in _send_request
    self.endheaders(body, encode_chunked=encode_chunked)
  File "/snap/snapcraft/current/usr/lib/python3.6/http/client.py", line 1276, in endheaders
    self._send_output(message_body, encode_chunked=encode_chunked)
  File "/snap/snapcraft/current/usr/lib/python3.6/http/client.py", line 1042, in _send_output
    self.send(msg)
  File "/snap/snapcraft/current/usr/lib/python3.6/http/client.py", line 980, in send
    self.connect()
  File "/snap/snapcraft/current/lib/python3.6/site-packages/requests_unixsocket/adapters.py", line 41, in connect
    sock.connect(socket_path)
FileNotFoundError: [Errno 2] No such file or directory

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/snap/snapcraft/current/lib/python3.6/site-packages/requests/adapters.py", line 449, in send
    timeout=timeout
  File "/snap/snapcraft/current/lib/python3.6/site-packages/urllib3/connectionpool.py", line 756, in urlopen
    method, url, error=e, _pool=self, _stacktrace=sys.exc_info()[2]
  File "/snap/snapcraft/current/lib/python3.6/site-packages/urllib3/util/retry.py", line 532, in increment
    raise six.reraise(type(error), error, _stacktrace)
  File "/snap/snapcraft/current/lib/python3.6/site-packages/urllib3/packages/six.py", line 769, in reraise
    raise value.with_traceback(tb)
  File "/snap/snapcraft/current/lib/python3.6/site-packages/urllib3/connectionpool.py", line 706, in urlopen
    chunked=chunked,
  File "/snap/snapcraft/current/lib/python3.6/site-packages/urllib3/connectionpool.py", line 394, in _make_request
    conn.request(method, url, **httplib_request_kw)
  File "/snap/snapcraft/current/usr/lib/python3.6/http/client.py", line 1281, in request
    self._send_request(method, url, body, headers, encode_chunked)
  File "/snap/snapcraft/current/usr/lib/python3.6/http/client.py", line 1327, in _send_request
    self.endheaders(body, encode_chunked=encode_chunked)
  File "/snap/snapcraft/current/usr/lib/python3.6/http/client.py", line 1276, in endheaders
    self._send_output(message_body, encode_chunked=encode_chunked)
  File "/snap/snapcraft/current/usr/lib/python3.6/http/client.py", line 1042, in _send_output
    self.send(msg)
  File "/snap/snapcraft/current/usr/lib/python3.6/http/client.py", line 980, in send
    self.connect()
  File "/snap/snapcraft/current/lib/python3.6/site-packages/requests_unixsocket/adapters.py", line 41, in connect
    sock.connect(socket_path)
urllib3.exceptions.ProtocolError: ('Connection aborted.', FileNotFoundError(2, 'No such file or directory'))

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/snap/snapcraft/current/bin/snapcraft", line 33, in <module>
    sys.exit(load_entry_point('snapcraft==5.0', 'console_scripts', 'snapcraft')())
  File "/snap/snapcraft/current/lib/python3.6/site-packages/click/core.py", line 1137, in __call__
    return self.main(*args, **kwargs)
  File "/snap/snapcraft/current/lib/python3.6/site-packages/click/core.py", line 1062, in main
    rv = self.invoke(ctx)
  File "/snap/snapcraft/current/lib/python3.6/site-packages/click/core.py", line 1646, in invoke
    super().invoke(ctx)
  File "/snap/snapcraft/current/lib/python3.6/site-packages/click/core.py", line 1404, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/snap/snapcraft/current/lib/python3.6/site-packages/click/core.py", line 763, in invoke
    return __callback(*args, **kwargs)
  File "/snap/snapcraft/current/lib/python3.6/site-packages/click/decorators.py", line 26, in new_func
    return f(get_current_context(), *args, **kwargs)
  File "/snap/snapcraft/current/lib/python3.6/site-packages/snapcraft/cli/_runner.py", line 130, in run
    snap_command.invoke(ctx)
  File "/snap/snapcraft/current/lib/python3.6/site-packages/click/core.py", line 1404, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/snap/snapcraft/current/lib/python3.6/site-packages/click/core.py", line 763, in invoke
    return __callback(*args, **kwargs)
  File "/snap/snapcraft/current/lib/python3.6/site-packages/snapcraft/cli/lifecycle.py", line 387, in snap
    _execute(steps.PRIME, parts=tuple(), pack_project=True, output=output, **kwargs)
  File "/snap/snapcraft/current/lib/python3.6/site-packages/snapcraft/cli/lifecycle.py", line 102, in _execute
    lifecycle.execute(step, project_config, parts)
  File "/snap/snapcraft/current/lib/python3.6/site-packages/snapcraft/internal/lifecycle/_runner.py", line 115, in execute
    project_config.get_build_snaps(), project_config.project._get_content_snaps()
  File "/snap/snapcraft/current/lib/python3.6/site-packages/snapcraft/internal/lifecycle/_runner.py", line 75, in _install_build_snaps
    installed_snaps = repo.snaps.install_snaps(build_snaps)
  File "/snap/snapcraft/current/lib/python3.6/site-packages/snapcraft/internal/repo/snaps.py", line 294, in install_snaps
    snap_pkg_channel = snap_pkg.get_store_snap_info()["channel"]
  File "/snap/snapcraft/current/lib/python3.6/site-packages/snapcraft/internal/repo/snaps.py", line 116, in get_store_snap_info
    self._store_snap_info = _get_store_snap_info(self.name)
  File "/snap/snapcraft/current/lib/python3.6/site-packages/snapcraft/internal/repo/snaps.py", line 386, in _get_store_snap_info
    snap_info = requests_unixsocket.get(url)
  File "/snap/snapcraft/current/lib/python3.6/site-packages/requests_unixsocket/__init__.py", line 51, in get
    return request('get', url, **kwargs)
  File "/snap/snapcraft/current/lib/python3.6/site-packages/requests_unixsocket/__init__.py", line 46, in request
    return session.request(method=method, url=url, **kwargs)
  File "/snap/snapcraft/current/lib/python3.6/site-packages/requests/sessions.py", line 542, in request
    resp = self.send(prep, **send_kwargs)
  File "/snap/snapcraft/current/lib/python3.6/site-packages/requests/sessions.py", line 655, in send
    r = adapter.send(request, **kwargs)
  File "/snap/snapcraft/current/lib/python3.6/site-packages/requests/adapters.py", line 498, in send
    raise ConnectionError(err, request=request)
requests.exceptions.ConnectionError: ('Connection aborted.', FileNotFoundError(2, 'No such file or directory'))
You can find the traceback in file '/tmp/tmpsydhwcp0/trace.txt'.

Hi ! @NZL .

The requests_unixsocket library, it seems to be related to connecting to a Unix socket file that is missing.

@NZL, verify that the socket file specified in the error exists. If it doesn’t, there might be an issue with the installation or configuration.

1 Like

Thanks for the reply, I found a very similar thread - Error while building snap in docker container - #2 by jamesh. Unfortunately, I don’t think I’ll get permissions to run in a privileged mode as well.

Looks like this part -

File "/snap/snapcraft/current/lib/python3.6/site-packages/requests_unixsocket/adapters.py", line 41, in connect sock.connect(socket_path) FileNotFoundError: [Errno 2] No such file or directory

When I check the file in the container I see


 19 class UnixHTTPConnection(httplib.HTTPConnection, object):
 20
 21     def __init__(self, unix_socket_url, timeout=60):
 22         """Create an HTTP connection to a unix domain socket
 23
 24         :param unix_socket_url: A URL with a scheme of 'http+unix' and the
 25         netloc is a percent-encoded path to a unix domain socket. E.g.:
 26         'http+unix://%2Ftmp%2Fprofilesvc.sock/status/pid'
 27         """
 28         super(UnixHTTPConnection, self).__init__('localhost', timeout=timeout)
 29         self.unix_socket_url = unix_socket_url
 30         self.timeout = timeout
 31         self.sock = None
 32
 33     def __del__(self):  # base class does not have d'tor
 34         if self.sock:
 35             self.sock.close()
 36
 37     def connect(self):
 38         sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
 39         sock.settimeout(self.timeout)
 40         socket_path = unquote(urlparse(self.unix_socket_url).netloc)
 41         sock.connect(socket_path)
 42         self.sock = sock

Yep, I see you can not modify the file, it’s only readable.

Perhaps, you should reinstall snapcraft ~ @NZL .

But first, you should perhaps execute these commands :

multipass delete --all

multipass purge