invoiceninja / dockerfiles

Docker files for Invoice Ninja
https://hub.docker.com/r/invoiceninja/invoiceninja
GNU General Public License v2.0
392 stars 255 forks source link

Improve caching of layers in Dockerfile to reduce container size #293

Closed lonix1 closed 3 years ago

lonix1 commented 3 years ago

The Dockerfile uses a multi-stage build, which is good. But it pulls two 170MiB+ file layers (zip files I think), every time, which is not good.

Since there are multiple releases every day (which is cool, it means this project is moving fast!), every redeploy is very heavy. It will make people reluctant to try new versions, and complain about old bugs that are already fixed.

I want to help but I'm not a PHP guy, so I'm unsure if there's any way to minimize those zip files. Are there any PHP users here who can advise? The main thing is to place those stages toward the end, to benefit from docker's caching of layers. But the files themselves are huge, how can we split them into smaller bits?

turbo124 commented 3 years ago

I think the issue is the build isn't a delta build but a full clean build of the repository. I'm not sure if it is even possible to make it smaller.

One possibile angle is using the internal self updater which uses git behind the scenes to update the repository. To test, if you drop to the shell in the server container and execute git pull it should have the git history there and should internally update - i think.

lonix1 commented 3 years ago

I hope someone will be able to lend a hand on this one.

In the meantime I had a thought...

That 170MiB - is all that the app? I may not be a PHP person, but I was wondering whether that is the app PLUS the php platform?

If it's both, then maybe they should be separated:

That's how I'd do it in other platforms... I'd separate my code (the app itself) from the platform/framework/libraries.

I don't if that would work with a PHP app though? Something to think about.

turbo124 commented 3 years ago

@lonix1 the app is a beast, particularly the third party dependencies add considerable weight to the application. I think at least half of the build size is the vendor folder.

lonix1 commented 3 years ago

That is good news... it means it can be optimized - the vendor stuff could be separated from the app itself.

But how is the million dollar question :smile: I'm sure someone who has done this before can advise at some point! Perf is always a "work in progress"!

lwj5 commented 3 years ago

@lonix1 I found your issue there are 2 executables

/usr/lib/chromium -rwxr-xr-x 1 root root 172.5M Oct 25 07:17 chrome

/var/www/app/vendor/beganovich/snappdf/versions/865615-Linux_x64/chrome-linux -rwxr-xr-x 1 invoicen invoicen 277.6M Mar 23 14:03 chrome

Is there a way to unbundle the latter chrome with snappdf?

turbo124 commented 3 years ago

@lwj5 does the container come with chromium already? it could be possible to build without the bundled snappdf version which should reduce the size of the image. @beganovich will the chromium binary work just as well as the chrome one?

lonix1 commented 3 years ago

Actually there are two issues here:

beganovich commented 3 years ago

@turbo124 yep, container binary should work just the same as the one that snappdf downloads.

Here's example: https://github.com/beganovich/invoiceninja5-dockerfiles/blob/master/docker-compose.yml#L28

lwj5 commented 3 years ago

@lonix1 I've reshuffled the Dockerfile #306. Let me know if there are any comments.

Chrome is getting pull in from composer through beganovich/snappdf.

I'm not sure if there's a way to exclude the folder from composer.json in invoiceninja/invoiceninja or otherwise, I could just delete the folder /var/www/app/vendor/beganovich/snappdf/versions/

lwj5 commented 3 years ago

@turbo124 yes, chromium is installed with the container Could you replace post-install-cmd in composer.json with this if [ "${IS_DOCKER:-false}" != "true" ]; then vendor/bin/snappdf download; fi for the next IN release

turbo124 commented 3 years ago

@lwj5 done!

lonix1 commented 3 years ago

@lwj5 Thanks for looking into this!

I'm not familiar with IN's build system, so can't comment in detail. But if I understand you correctly, you are saying that chromium is installed in a separate layer, only once? That's much better than now. And if that path is not needed then it should be deleted, that's the benefit of the multi-stage dockerfile, to remove leftover junk from previous layers (but maybe @beganovich can confirm first?)

I think to reduce the container size is a "work in progress" - we can discuss again after the next version.

lwj5 commented 3 years ago

Np. I’ll merge the PR which will close this for now.

We’ll see the size of the next release and the delta after 2 releases.