How to make deb or rpm packages work inside snaps


#1

Hi there i am a new to snapcraft and any kind of packaging tools,

By reading the documentation on creating my first snap here i was so exited especially the part about stage packages which states

stage-packages lists the dependencies needed to actually run the contents of the snap. They’ll be packed into the final snap. Here, the requirement is for the hello-world part to download and unpack libqt5gui5 with all its dependencies. This method can reuse any of the 48000 .deb packages that traditional Ubuntu provides. It’s really that easy: just specify the packages you need embedded into your snap.

so i started out and wanted to create a snap for my website using apache2 and git deb packages. The idea was to have a script which pulls my website from a repo on daily basis and using apache2 server i could host my website on a device at home (lets say rpi).

Now when i specified apache2 and git as my stage-packaes and built my snap, the snapcraft pulled all the files required by apache2 and git and created directory structure of those in my prime area (say bin env var etc…). Now i want to start apache2 on my system start so i created an daemon app in my snap which runs a script which in turn starts the apache2 and does the git routine.

Now the problem is that when i start the apache2 which in turn runs a script which has hard links to other resources required by it like /usr/bin/… which apache2 cannot find as they are in /snap/my-snap/current/usr/bin/…

How do i address this problem ?
I was thinking if snaps can somehow use virtualization (like docker containers) then there wont be any problem. can we do that can we virtualize a snap?


#2

Welcome!

Let me start by saying you were mostly right about the use of stage-packages, they are a booster to get started quickly if the package in question is built in such a way that is reusable; for the case of apache2 that is not so as you have come to discover. There are some ways of solving this using some form of preload (snapcraft update && snapcraft define snapcraft-preload) which can get cumbersome or take the easier path of creating apache2 from a part yourself.

For that latter task, @kyrofa has done some work like this to setup the full LAMP stack required for nextcloud. Here is his blog post series describing this: https://kyrofa.com/posts/snapping-nextcloud-the-web-server


#3

Yeah, building apache as a part is easy and you end up with only the bits you need. It’s changed a bit since that post was written though (no more search/replace, I just ship a custom config). Feel free to refer to the nextcloud snap itself for more info.


#4

Thanks a lot @sergiusens your answer solve my problem, yet i am curious to know about the first method you specified. can you please elobrate :slight_smile:


#5

I would avoid it still if you are not familiar with how library loading and aliasing works.

To be complete, snapcraft-preload can be used as described on http://blog.sergiusens.org/posts/The-Snapcraft-Parts-Ecosystem/ or more specificall on https://github.com/sergiusens/snapcraft-preload

When such is done, many of the syscalls are wrapped into detecting $SNAP paths and mangle the parameters to the real calls.


#6

Thank sergiusens,

I had a thought about making deb packages usable in snaps, again i am just a newbee trying to get hold of things and please correct me if i am wrong

The linux kernal has process virtualization right, can we use that on each deb inside the snap (here apache2 and git) so that the particular deb uses the resources from $SNAP area rather than resources at system area.

This could help a developer to put together a snap with debs with a breeze ( as most of the deb packages are not built for reuse i assume and converting those debs to reusable format not practical atleast not happen any time sooner) and the developer migration from something like docker to snapps would happen and there would be more traction in snaps development area.


#7

There are several different approaches you can use here, @chani, and the best one really depends on details of the application you are using.

When you ask snapcraft to ship a deb or an rpm package in the snap, or even unpack a tarball containing pre-built binaries, the content will be bundled in your snap and will be installed (mounted read-only) in the final system under the /snap/yoursnap/current/ directory. That means you’ll end up with directories which are typically found at the root, such as /usr/bin and /usr/lib under a place they don’t expect, such as /snap/yoursnap/current/usr/bin, etc.

Then, when the application runs, one of these things will happen:

Option 1: application is relocatable

This is the nirvana option, which makes me want to go after developers to buy them tea or beer.

The application might simply not care about where it’s installed, because they have no external resources or looks for them as a path relative to the binary app.

Option 2: application may be configured

In many cases, the application relies on configuration files, environment variables, or even command line flags to tell it where to run. This is very easy to get sorted.

If the application expects a flag defining its root, or perhaps its data directory, simply modify the command: line in the snapcraft.yaml to provide the given flag.

If the application expects a configuration file with its root, that file may be shipped in the snap itself so that it can be pointed to with a flag or similar, or alternatively a copy of that shipped configuration file living in $SNAP_DATA so that other bits may be tuned at runtime.

If the application expects an environment variable, that may also be sorted directly in snapcraft.yaml by including a section either at the top level or under the application entry, along the lines of:

environment:
    SOME_VAR_NAME: /snap/yoursnap/current/

and/or

apps:
    myapp:
        command: ...
        environment:
            SOME_VAR_NAME: /snap/yoursnap/current/

If the configuration is more complex than that, there’s always the option of replacing the application command in snapcraft.yaml with a shell script shipped in the snap which is tasked with performing the configuration and tuning before the real application runs.

In many well known cases, snapcraft itself will do exactly that and inject the wrapper before the actual application is run so that the real command knows where to find its data, its libraries, etc. Looking into the meta/snap.yaml file of the built snap, check the commands to understand better how that takes place.

Option 3: rebuild from source

I realize the topic here is pre-built binaries, but it’s worth pointing out that this is always an option assuming the source code is available. That is, rebuilding the software from source it can always be tuned to look into any desired location.

Option 4: chroot

If the software is hardcoded to look into a fixed location, the option is to tune the world around it instead.

If the software doesn’t care about writing anywhere, it’s trivial to call it from a script with:

chroot $SNAP /usr/bin/app

More likely, though, it’ll want to use some storage, or logs, or temporary files, so that won’t work. If the content of the snap is small enough, it may be copied into a temporary writable directory and have the chroot done there instead.

If that’s not an option, read on.

Option 5: bind mounts

This is the most flexible option of all, but right now it requires the snap to remain in devmode. In the near future, we’ll fix that and make that much easier to do, and it will also work under strict mode.

The idea here is bind-mounting the content you want into specific locations. For example, inside a script used as your app’s command, you can fully replace directories by bind mounting them:

mount --bind /snap/yoursnap/current/opt /optc

This option is extremely flexible and allows pretty much anything to be made to work with enough tuning, but it’s also extremely easy to get wrong, in the sense that you may be making content that you’d like to use later inaccessible. For example, snapctl lives in /usr/bin, so if you want to replace that one it might be good to move the directory elsewhere first.

Once we implement the planned feature, this will be made easier to use.


So those are a few ways in which you can get out of the trouble when using pre-built binaries. There are likely others.

Please let us know how things go for you.


Having trouble snapping a mono app
#8

I didn’t know about this, it will certainly be helpful in eliminating many of my wrapper scripts (which I have been using to set env vars previously). Is this documented on snapcraft.io? If it isn’t it probably should be. I would’ve avoided a lot of wrapper scripts had I known about this earlier!


#9

Thanks to your quote I found out that the example was slightly wrong, for missing the app name level. Please have a look above to see the difference.

I wouldn’t be surprised if it’s not yet documented, and indeed it needs to be.


Declaratively defining environment variables
#10

I was about to start a new thread but it seems like you’re dealing with the issue here? How do I install a Deb package inside a Snap? E.g. I need hunspell-en-gb inside the LibreOffice Snap for spellcheck to work (btw that’s a bug right? Really the LibreOffice Snap should depend on the relevant language package but I don’t know how we get Snappy to do that and I don’t know how we’d get it to install any new packages it needs for other languages the user wants (maybe we need a script for that?))

I’m assuming I need hunspell? That’s what got spellcheck working for me in the Deb before…


#11

This question is really tied to the snap in question. I know some minimal thing about LibreOffice and think I recall that it has a built in implementation to bring in language packs, this is the way to go I believe instead of using the deb.


#12

Maybe, I don’t know how one would sort that out with the Snap.