canonical / docker-snap

https://snapcraft.io/docker
MIT License
52 stars 27 forks source link

build: compile docker-cli statically #159

Closed locnnil closed 5 months ago

locnnil commented 6 months ago

Compile docker-cli statically to avoid problems described on #132.

Currently, the docker-snap is shipped with the docker-cli dynamically linked:

lincoln@fenrir:~/docker/multiarch/dynamic/amd64$ ldd bin/docker
        linux-vdso.so.1 (0x00007ffc5850a000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x0000719048400000)
        /lib64/ld-linux-x86-64.so.2 (0x000071904a179000)

When shipping a companion snap based on core 20 or an older version, we encounter GLIBC problems due to incompatible versions:

lincoln@fenrir:~/docker/rocker$ sudo rocker hello-world
docker: /lib/aarch64-linux-gnu/libc.so.6: version `GLIBC_2.32' not found (required by docker)
docker: /lib/aarch64-linux-gnu/libc.so.6: version `GLIBC_2.34' not found (required by docker)

Note: "Companion snap" refers to the snap that is compiled to wrap docker and use it in systems like Ubuntu Core.

The static compilation of docker-cli aims to avoid GLIBC problems with compatibility between docker-snap and other snaps based on legacy core versions.

locnnil commented 6 months ago

@lucaskanashiro, could you please enable the workflow to run? Thank you!

lucaskanashiro commented 6 months ago

@locnnil thanks for this PR, the proposed change looks good. I am pretty sure you tested this version before submitting the PR but could you please give me some reproduction steps so I can try it myself locally?

locnnil commented 5 months ago

@lucaskanashiro Sure here is a quick guide to do so:

Preparation

First, we're going to test using an installation from the store, then we would build the docker-snap with the modifications of this PR.

Firstly, you need a companion snap, that is basically a snap that will wrapper docker functionality, let's call it rocker:

Creating the directory for the companion snap

mkdir -p rocker/src/usr/bin && cd rocker

Then create the script that will trigger the docker snap:

cat << 'EOF' > src/usr/bin/rocker_run.sh
#!/bin/sh -e

export PATH=$SNAP/docker-bin/bin:$PATH
docker run "$@"
EOF

chmod +x src/usr/bin/rocker_run.sh

Then we create the snapcraft.yaml file:

mkdir snap

cat << 'EOF' > snap/snapcraft.yaml
name: rocker
base: core20
version: '0.1'
summary: A test of interacting with the Docker snap through another snap.
description: |
  Here I am
  Rock you like a hurricane
  Here I am
  Rock you like a hurricane

grade: stable
confinement: strict

# Add an app section to the snapcraft.yaml for our script:
apps:
  rocker:
    command: usr/bin/rocker_run.sh
    plugs: [docker, docker-executables]
    environment:
      PATH: $SNAP/docker-bin/bin:$PATH

parts:
  copy-src:
    plugin: dump
    source: src/

plugs:
  docker-executables:
    interface: content
    content: executables
    target: $SNAP/docker-bin

EOF

OBS: It's important to use the core20 as base, because then, we're going to demonstrate the problem on #132 and how we get rid of it.

Now, it's time to build and install the snap:

snapcraft --use-lxd

sudo snap install --dangerous ./rocker_0.1_amd64.snap

Then, we connect the needed interfaces on rocker snap:

sudo snap connect rocker:docker             docker:docker-daemon
sudo snap connect rocker:docker-executables docker:docker-executables

The Results

Now, it's the final demonstration

Current behavior

By using the current docker snap, when trying to run the command we got:

$ sudo rocker hello-world
docker: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.32' not found (required by docker)
docker: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.34' not found (required by docker)

Ideal behavior

But using the docker snap with the docker-cli compiled statically, it executes the command perfectly.

First, it's necessary to build the docker snap with the modification of this PR.

Then prepare it:

# Remove the stable installation of docker snap
sudo snap remove docker --purge

# Install the compiled docker with the patch of this PR
sudo snap install --dangerous ./docker_24.0.5_amd64.snap

# Connect the interfaces
sudo snap connect docker:docker-cli            docker:docker-daemon
sudo snap connect docker:privileged           :docker-support
sudo snap connect docker:support               :docker-support
sudo snap connect docker:firewall-control  :firewall-control
sudo snap connect docker:network-control   :network-control

# Initialize the docker snap service
sudo snap start --enable docker.daemon

# Then test the rocker snap
sudo rocker hello-world

Then the rocker snap works as expected:

$ sudo rocker hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
c1ec31eb5944: Pull complete 
Digest: sha256:6352af1ab4ba4b138648f8ee88e63331aae519946d3b67dae50c313c6fc8200f
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/

Final Notes

The idea behind this companion snap is specially useful when dealing with UC systems.

lucaskanashiro commented 5 months ago

@locnnil thanks for the very detailed reproduction steps, appreciated!

I was able to reproduce the issue and also verify the fix. LGTM, +1.