Cloudron makes it easy to run web apps like WordPress, Nextcloud, GitLab on your server. Find out more or install now.


Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Bookmarks
  • Search
Skins
  • Light
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Brand Logo

Cloudron Forum

Apps | Demo | Docs | Install
  1. Cloudron Forum
  2. App Packaging & Development
  3. Stuck on packaging

Stuck on packaging

Scheduled Pinned Locked Moved App Packaging & Development
3 Posts 2 Posters 35 Views 2 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • jadudmJ Offline
    jadudmJ Offline
    jadudm
    wrote last edited by
    #1

    Hi all,

    I'm looking for some insight into packaging. Invariably, I get started packaging an app, and then I run into something about the Cloudron model that slows me down, and then weeks/months go by, because I can't dedicate lots of time to this kind of work.

    I'm going to pick Passbolt as my most recent example of a "started and then got stuck" problem. I thought "It would be nice to have a 100% open source password vault on Cloudron." That, and it looks easier to use than Bitwarden for my use case. I dug in a bit, and it seems straight-forward enough:

    • It is a PHP application.
    • It has installation instructions for many platforms.
      • It is already containerized/has a compose.
    • It only needs MariaDB/MySQL (Postgres is an option)

    Three approaches, none work?

    BLUF: All three approaches seem to be stuck on the non-writeable filesystem, and the inability for packages to map arbitrary paths inside the container to paths outside the container (e.g. --volumes).

    If there's another way to solve this packaging puzzle, I would appreciate suggestions. Otherwise, I'd love having the ability to add constrained volume mappings to the manifest. E.g.

    [
      { "path": "/var/log", "destination": "log" },
      ...
    ]
    

    where the "destinations" would be under /app/mappings/... or similar.

    First approach

    I started by wondering if I could use their Docker image as a base image, and just build some layers on top. What appears to be a blocker is that their container is writeable; so, Passbolt expects to be able to write logs to /var/log and so on. Because Cloudron expects containers to be read-only, this approach rapidly fails.

    I do not know of any way, in the Cloudron app model, to map arbitrary paths inside the container to paths outside the container. (Put another way: I cannot set up --volume mappings.) I cannot ln -s in a Dockerfile and have it persist. (If there is a way, I do not know what it is.) So, finding a way to grant write access to arbitrary paths within the container feels like a non-starter. (And I don't think I can prevent the app from engaging in this behavior, short of making upstream patches.)

    Unless someone can provide a nudge, I think this approach does not work.

    Second approach

    I decided I would look at the Ubuntu installation instructions, on the theory that I would use those to build a container. This looked promising; they have a Debian/Ubuntu package, so installation should be one apt-get call!

    Before I got very far, I realized this will still have the same problem as the Docker-based approach. Passbolt assumes it has a clean Debian installation to work with. And, the package installs a database and who-knows-what-else. (I already have a DB; I don't want apt-get to try and install MariaDB inside of the container...) So, this is much the same as installing Cloudron: it wants a whole machine, and expects to do all the work.

    Using their Ubuntu package does not seem like the right approach to building a new container.

    Third approach

    I could build it from scratch. They document it. To do this "right," I think I would:

    1. Build a "build container" that has everything needed to build the app. (This might be the Cloudron base image.)
    2. Use the container to build the app locally (but against the container's properties).
    3. Modify configs and things locally, after build.
    4. Build a Cloudron container.

    Unfortunately, I'm still going to run into the non-writeable filesystem. The code I built will still want to write to places that are impossible under the Cloudron security model. I... could try and patch their code, but ultimately, I'm going to need a way to make some things in /etc and /var editable. I think. Or, I have to find a way to modify the code/redirect those mappings. That feels complex and fragile as Passbolt updates their software; I don't want to maintain patchfiles against an upstream.

    Fourth approach

    I could make a PR against their codebase that attempts to move all file write operations into one fixed location in the filesystem, and make that location configurable via ENV var. (Or, multiple locations configurable via multiple ENV vars.)

    I don't know if they'd take that PR. (There's a lot of work in this approach. I'm not going to walk this path today.) It seems like, if the app was developed differently (meaning: if the app only wrote to the disk where I told it to), then this problem wouldn't exist. I'd set those environment variables and my uncle would be named "Bob."

    Unrelated?: certs

    I feel like I read how to solve this, somewhere... but now I can't remember/find it.

    The app expects the certs to be in /etc/ssl/certs... and I know Cloudron manages those. However, this feels like the least of my packaging problems at this point, and I know that the app should "just" listen to HTTP on the port declared in the manifest... but. I'll tackle that if/when I can tackle the other challenges.

    Thoughts?

    1. Are there any packages that exist that overcome these kinds problems? If so, I'd welcome a pointer to those packages, and I'll study those/pull inspiration from them for my packaging problem.
    2. Have others encountered this in their packaging? Did you find a way around?
    3. Is it sometimes the case that an app has been developed against a model that simply makes it "unpackageable?" Is this one of those cases?

    I'm out of questions, really. At some level, it feels like this should be easier/more straight-forward---like I'm missing something. But, maybe I'm not.

    I use Cloudron on a Dell 7040 I bought on eBay.

    jamesJ 1 Reply Last reply
    2
    • jadudmJ jadudm

      Hi all,

      I'm looking for some insight into packaging. Invariably, I get started packaging an app, and then I run into something about the Cloudron model that slows me down, and then weeks/months go by, because I can't dedicate lots of time to this kind of work.

      I'm going to pick Passbolt as my most recent example of a "started and then got stuck" problem. I thought "It would be nice to have a 100% open source password vault on Cloudron." That, and it looks easier to use than Bitwarden for my use case. I dug in a bit, and it seems straight-forward enough:

      • It is a PHP application.
      • It has installation instructions for many platforms.
        • It is already containerized/has a compose.
      • It only needs MariaDB/MySQL (Postgres is an option)

      Three approaches, none work?

      BLUF: All three approaches seem to be stuck on the non-writeable filesystem, and the inability for packages to map arbitrary paths inside the container to paths outside the container (e.g. --volumes).

      If there's another way to solve this packaging puzzle, I would appreciate suggestions. Otherwise, I'd love having the ability to add constrained volume mappings to the manifest. E.g.

      [
        { "path": "/var/log", "destination": "log" },
        ...
      ]
      

      where the "destinations" would be under /app/mappings/... or similar.

      First approach

      I started by wondering if I could use their Docker image as a base image, and just build some layers on top. What appears to be a blocker is that their container is writeable; so, Passbolt expects to be able to write logs to /var/log and so on. Because Cloudron expects containers to be read-only, this approach rapidly fails.

      I do not know of any way, in the Cloudron app model, to map arbitrary paths inside the container to paths outside the container. (Put another way: I cannot set up --volume mappings.) I cannot ln -s in a Dockerfile and have it persist. (If there is a way, I do not know what it is.) So, finding a way to grant write access to arbitrary paths within the container feels like a non-starter. (And I don't think I can prevent the app from engaging in this behavior, short of making upstream patches.)

      Unless someone can provide a nudge, I think this approach does not work.

      Second approach

      I decided I would look at the Ubuntu installation instructions, on the theory that I would use those to build a container. This looked promising; they have a Debian/Ubuntu package, so installation should be one apt-get call!

      Before I got very far, I realized this will still have the same problem as the Docker-based approach. Passbolt assumes it has a clean Debian installation to work with. And, the package installs a database and who-knows-what-else. (I already have a DB; I don't want apt-get to try and install MariaDB inside of the container...) So, this is much the same as installing Cloudron: it wants a whole machine, and expects to do all the work.

      Using their Ubuntu package does not seem like the right approach to building a new container.

      Third approach

      I could build it from scratch. They document it. To do this "right," I think I would:

      1. Build a "build container" that has everything needed to build the app. (This might be the Cloudron base image.)
      2. Use the container to build the app locally (but against the container's properties).
      3. Modify configs and things locally, after build.
      4. Build a Cloudron container.

      Unfortunately, I'm still going to run into the non-writeable filesystem. The code I built will still want to write to places that are impossible under the Cloudron security model. I... could try and patch their code, but ultimately, I'm going to need a way to make some things in /etc and /var editable. I think. Or, I have to find a way to modify the code/redirect those mappings. That feels complex and fragile as Passbolt updates their software; I don't want to maintain patchfiles against an upstream.

      Fourth approach

      I could make a PR against their codebase that attempts to move all file write operations into one fixed location in the filesystem, and make that location configurable via ENV var. (Or, multiple locations configurable via multiple ENV vars.)

      I don't know if they'd take that PR. (There's a lot of work in this approach. I'm not going to walk this path today.) It seems like, if the app was developed differently (meaning: if the app only wrote to the disk where I told it to), then this problem wouldn't exist. I'd set those environment variables and my uncle would be named "Bob."

      Unrelated?: certs

      I feel like I read how to solve this, somewhere... but now I can't remember/find it.

      The app expects the certs to be in /etc/ssl/certs... and I know Cloudron manages those. However, this feels like the least of my packaging problems at this point, and I know that the app should "just" listen to HTTP on the port declared in the manifest... but. I'll tackle that if/when I can tackle the other challenges.

      Thoughts?

      1. Are there any packages that exist that overcome these kinds problems? If so, I'd welcome a pointer to those packages, and I'll study those/pull inspiration from them for my packaging problem.
      2. Have others encountered this in their packaging? Did you find a way around?
      3. Is it sometimes the case that an app has been developed against a model that simply makes it "unpackageable?" Is this one of those cases?

      I'm out of questions, really. At some level, it feels like this should be easier/more straight-forward---like I'm missing something. But, maybe I'm not.

      jamesJ Online
      jamesJ Online
      james
      Staff
      wrote last edited by
      #2

      Hello @jadudm

      @jadudm said in Stuck on packaging:

      I started by wondering if I could use their Docker image as a base image , and just build some layers on top.

      If you wish have this app in the Cloudron app store, you need to use the Cloudron base image.


      @jadudm said in Stuck on packaging:

      I do not know of any way, in the Cloudron app model, to map arbitrary paths inside the container to paths outside the container.

      Many apps write to static locations that can not be configured.
      When packaging a software for Cloudron with such read-write paths always ask yourself the following question:

      • is the needed read-write path user-data or runtime-data?

      If it is user-data and backup worthy, it should go into /app/data/.
      Anything else which is just needed for the runtime should be in /run/ or /tmp/ which is temporary read-write on runtime.
      Also good to look at https://docs.cloudron.io/packaging/cheat-sheet/#filesystem.

      If you have static paths that need read-write you will have to symlink them accordingly to the destination.

      As an example I will use the Nextcloud Cloudron App.

      In the Dockerfile you can see the following lines:

      # create config folder link to make the config survive updates
      RUN rm -rf /app/code/config && ln -s /app/data/config /app/code/config && \
          mv /app/code/apps /app/pkg/apps_template && ln -s /app/data/apps /app/code/apps
      

      This way a dead symlinc is created that points to /app/data/apps so this dead symlink needs to be filled on runtime, but the symlink is persistent.
      From the start.sh:

      cp -rf /app/pkg/apps_template /app/data/apps
      

      So, on startup it needs to checked if the target already exists and if not, copy the original.
      This way the dead symlink get filled with life.

      This way you can make static read-only paths read-write.

      On the topic of runtime paths that need to be read-write but not are not backup worthy.
      There also is https://docs.cloudron.io/packaging/manifest/#runtimedirs which makes this a lot easier.
      But these paths can only be in /app/code/ so when the app wants to write /etc/ this is no option.

      Third approach

      This is the correct way. When using the Cloudron base image it is best to build from source.
      Some software also offers a apt package which installs other software alongside like mysql.
      Many times this can be avoided with apt parameters like --no-install-recommends, but in my opinion, building from source also gives a lot of insights about the software itself which aids further down the road when issues arise.

      Fourth approch

      @jadudm said in Stuck on packaging:

      I could make a PR against their codebase that attempts to move all file write operations into one fixed location in the filesystem, and make that location configurable via ENV var. (Or, multiple locations configurable via multiple ENV vars.)

      In my opinion, every software should have configuration options where it writes.
      This is always useful and if you have the capacity and knowledge to do these PRs, this should be very welcomed.
      But, I know some maintainers can be special. So, if you can deal with the FOSS dev frustration, please go for it.

      certs

      Here you go: https://docs.cloudron.io/packaging/addons/#tls


      @jadudm said in Stuck on packaging:

      Are there any packages that exist that overcome these kinds problems? If so, I'd welcome a pointer to those packages, and I'll study those/pull inspiration from them for my packaging problem.

      Yes, you can find many apps like in my example for Nextcloud that handle these static paths and move, symlink them to /run/ or /tmp.


      @jadudm said in Stuck on packaging:

      Have others encountered this in their packaging? Did you find a way around?

      Yes of course, every time an app is packaged the read-only nature can be difficult to work with.
      One big hint I can also give is the following.

      If you have an initial package of your custom app, and it fails to start since it wants to write some random path and does not even tell you where it wants to write.
      Put the app in recovery mode, making it all read-write, start your app startup script manually.
      Then, if you ssh into your Cloudron server you can run:

      docker diff $YOUR_APP_DOCKER_ID
      

      And docker diff will give you a detailed list of what paths were added, deleted or changed.


      @jadudm said in Stuck on packaging:

      Is it sometimes the case that an app has been developed against a model that simply makes it "unpackageable?" Is this one of those cases?

      Some apps can be very tricky to get working and need a lot of tinkering to get the paths and everything in order.
      Sometimes it could be just so much that the maintenance of this app would get out of hand.
      Then this needs consideration if this is really "worth it".


      @jadudm said in Stuck on packaging:

      I'm out of questions, really. At some level, it feels like this should be easier/more straight-forward---like I'm missing something. But, maybe I'm not.

      Don't throw the towel!
      Take breaks when you get stuck.
      @BrutalBirdie started this topic once https://forum.cloudron.io/topic/3486/zabbix-appdev-log which could also be done by everyone else.
      I would encourage everyone who starts packaging a Cloudron app for the first time to do the same.
      This way you are not alone with your struggles and can get fast feedback on roadblocks.


      I hope this wall of text is somewhat helpful.
      Please, don't hesitate to ask questions before you quit from frustration.

      1 Reply Last reply
      1
      • jadudmJ Offline
        jadudmJ Offline
        jadudm
        wrote last edited by
        #3

        Many thanks, @james. The text was absolutely helpful. Also, that diff hint is gold. I may end up with a PR against the docs when I'm done, because that kind of hint is a nice trick to figure out quickly all the places an app touches the disk.

        I use Cloudron on a Dell 7040 I bought on eBay.

        1 Reply Last reply
        0
        Reply
        • Reply as topic
        Log in to reply
        • Oldest to Newest
        • Newest to Oldest
        • Most Votes


        • Login

        • Don't have an account? Register

        • Login or register to search.
        • First post
          Last post
        0
        • Categories
        • Recent
        • Tags
        • Popular
        • Bookmarks
        • Search