Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Server: Switch to node:16-bullseye and add python to the image to support building on non amd64 platforms #5202

Merged
merged 1 commit into from
Aug 23, 2021

Conversation

piotrb
Copy link
Contributor

@piotrb piotrb commented Jul 17, 2021

The issue is that node:12 (which uses buildpack-deps:buster) uses quite old libs, among them glibc ..
Now a bunch of the node deps can pull down prebuild libs (especially this was an issue with sqlite) ..
But on armv7 (ie raspberry pi devices) these prebuilt libraries do not exist, and building them from source
requires newer libraries.

Also to instal sqlite from source python seems to be needed.

Also took the opportunity to apply some best practices and merged the layers for the apt installs and cleaned the caches afterwards.


This may be a bit of a controversial switch to use node-build, but unfortunately there doesn't seem to be official ubuntu based node base images to use instead of node:12 .. so this may need to be it .. alternate thoughts are welcome :)

@laurent22
Copy link
Owner

laurent22 commented Jul 17, 2021

I don't know what problem is being solved. Also if multiple fixes are included they should be split into multiple pull requests, with link to the bug that's being fixed.

@piotrb
Copy link
Contributor Author

piotrb commented Jul 17, 2021

This was needed to be able to get it working on armv7 architecture .. I could try to strip it down a little bit .. I just dislike having multiple related PRs like that :)

The tl;dr of the change is that its switching to an ubuntu focal based base image rather than a debian buster one .. focal has a lot of updated packages compared to buster (and buster is the current "stable" debian so there is no straightforward upgrade path there).

Let me see if I can re-explain ...

The reason your current Dockerfile works is because a few of the node packages download pre-compiled binary libraries for "most" platforms .. I think the biggest offender there was sharp .. (see https://sharp.pixelplumbing.com/install for platform notes). If you needed to actually build them you'd run into versioning issues :)

So .. the core reason that I needed to switch to ubuntu:focal is because of the glibc version that comes with buster ..

Issue 1: need the equivalent of node:12 but with ubuntu:focal ..

Solution:

  1. Switch to buildpack-deps:focal (node:12 uses buildpack-deps as its base too)
  2. Install node 12 inside that manually (I've become fond of using node-build to do this, its quite universal and light weight)

Issue 2: need python to install sqlite libs from source .. because again there is no armv7 pre-compiled version available

Solution:

Install python ..

Technically at this point this could be ok .. and I could revert the PR to this state ..

Bonus Issue: the way apt was being run is against Dockerfile best practices. Its recommended that apt installs are all one RUN line with apt-get update, install, and a cache clean all in one docker layer.

https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#run

Solution: clean up the RUN line that install vim and python to that best practice.

@piotrb
Copy link
Contributor Author

piotrb commented Jul 17, 2021

If you would like me to run a build again on armv7 .. just to document the original build issue .. I could .. I mean I opened this PR so I can help have the mainline support armv7 properly .. so I don't have to maintain my own branch .. I would think that supporting armv7 may be very nice for this project since hobbyists may want to run the server on their RPi devices :)

@piotrb
Copy link
Contributor Author

piotrb commented Jul 18, 2021

Original Build Log Step 21/36 : RUN npm run bootstrap ---> Running in 2b06b2ab3001

root@ bootstrap /home/joplin
lerna bootstrap --force-local --no-ci

lerna notice cli v3.22.1
lerna info versioning independent
lerna info Bootstrapping 7 packages
lerna info Installing external dependencies
lerna ERR! npm install exited 1 in '@joplin/tools'
lerna ERR! npm install stdout:

sharp@0.25.2 install /home/joplin/packages/tools/node_modules/sharp
(node install/libvips && node install/dll-copy && prebuild-install --runtime=napi) || (node-gyp rebuild && node install/dll-copy)

make: Entering directory '/home/joplin/packages/tools/node_modules/sharp/build'
CC(target) Release/obj.target/nothing/../node-addon-api/src/nothing.o
AR(target) Release/obj.target/../node-addon-api/src/nothing.a
COPY Release/nothing.a
TOUCH Release/obj.target/libvips-cpp.stamp
CXX(target) Release/obj.target/sharp/src/common.o
sharp.target.mk:138: recipe for target 'Release/obj.target/sharp/src/common.o' failed
make: Leaving directory '/home/joplin/packages/tools/node_modules/sharp/build'

lerna ERR! npm install stderr:
ERR! sharp Use with glibc 2.24 requires manual installation of libvips >= 8.9.1
info sharp Attempting to build from source via node-gyp but this may fail due to the above error
info sharp Please see https://sharp.pixelplumbing.com/install for required dependencies
../src/common.cc:23:22: fatal error: vips/vips8: No such file or directory
#include <vips/vips8>
^
compilation terminated.
make: *** [Release/obj.target/sharp/src/common.o] Error 1
gyp ERR! build error
gyp ERR! stack Error: make failed with exit code: 2
gyp ERR! stack at ChildProcess.onExit (/usr/local/lib/node_modules/npm/node_modules/node-gyp/lib/build.js:194:23)
gyp ERR! stack at ChildProcess.emit (events.js:314:20)
gyp ERR! stack at Process.ChildProcess._handle.onexit (internal/child_process.js:276:12)
gyp ERR! System Linux 5.10.17-v7l+
gyp ERR! command "/usr/local/bin/node" "/usr/local/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js" "rebuild"
gyp ERR! cwd /home/joplin/packages/tools/node_modules/sharp
gyp ERR! node -v v12.22.3
gyp ERR! node-gyp -v v5.1.0
gyp ERR! not ok
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@1.2.13 (node_modules/fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.2.13: wanted {"os":"darwin","arch":"any"} (current: {"os":"linux","arch":"arm"})

npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! sharp@0.25.2 install: (node install/libvips && node install/dll-copy && prebuild-install --runtime=napi) || (node-gyp rebuild && node install/dll-copy)
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the sharp@0.25.2 install script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR! /home/joplin/.npm/_logs/2021-07-18T00_03_40_754Z-debug.log

lerna ERR! npm install exited 1 in '@joplin/tools'
lerna WARN complete Waiting for 3 child processes to exit. CTRL-C to exit immediately.
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! root@ bootstrap: lerna bootstrap --force-local --no-ci
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the root@ bootstrap script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR! /home/joplin/.npm/_logs/2021-07-18T00_03_41_028Z-debug.log

The main issue there is:

lerna ERR! npm install stderr:
ERR! sharp Use with glibc 2.24 requires manual installation of libvips >= 8.9.1

in the node:12 image glibc 2.24 is used:

# apt-cache policy libc6
libc6:
  Installed: 2.24-11+deb9u4
  Candidate: 2.24-11+deb9u4
  Version table:
 *** 2.24-11+deb9u4 100
        100 /var/lib/dpkg/status

And .. the required libvips is not available:

# apt search libvips-dev
Sorting... Done
Full Text Search... Done
libvips-dev/oldstable 8.4.5-1+deb9u2 armhf
  image processing system good for very large ones (dev)

@piotrb
Copy link
Contributor Author

piotrb commented Jul 18, 2021

Basically once I switched out the base image and added node back in .. it complained about missing python to install the sqlite lib .. so I added that ..

@laurent22
Copy link
Owner

Ok thanks for explaining. What I don't understand is that, for me, the point of a Docker image is a reproducible environment that should work wherever it's installed, but in your case it seems libvips is missing for some reasons.

And if it's missing can't it just be added with "apt-get"?

@piotrb
Copy link
Contributor Author

piotrb commented Jul 18, 2021

Correct, you could if the correct version was available on debian buster .. but as you see here:

# apt search libvips-dev
Sorting... Done
Full Text Search... Done
libvips-dev/oldstable 8.4.5-1+deb9u2 armhf
  image processing system good for very large ones (dev)

The last available version if 8.4.5 .. and the node libs need 8.9.1

@piotrb
Copy link
Contributor Author

piotrb commented Jul 18, 2021

debian buster has very very conservative versions of libraries .. it often is quite troublesome to get recent things for it .. thus the switch to ubuntu focal which is the current long term supported ubuntu (also debian based at its core, but much more updated)

@laurent22
Copy link
Owner

And if we use this image, does it mean the server will now be compatible with ARM? (as mentioned in this issue - #4937)

Also any reason why it's called "buildpack-deps:focal" instead of something clearer like "ubuntu:focal"?

@piotrb
Copy link
Contributor Author

piotrb commented Jul 18, 2021

using this image will "allow" it to support ARM .. but you still have to update your dockerhub publishing pipeline to build an armv7 (and possibly some more like armv8, etc) architecture versions of the image ..

buildpack-deps:focal is a base image which is ultimately based on ubuntu:focal .. but it also adds a lot of the common development tools needed to actually build/run things ..

see: https://hub.docker.com/_/buildpack-deps

focal is built using this dockerfile: https://github.com/docker-library/buildpack-deps/blob/master/ubuntu/focal/Dockerfile
which is based on focal-scm: https://github.com/docker-library/buildpack-deps/blob/master/ubuntu/focal/scm/Dockerfile
which is based on focal-curl: https://github.com/docker-library/buildpack-deps/blob/master/ubuntu/focal/curl/Dockerfile
which is based on ubuntu:focal

The buildpack-deps group of images are very commonly used in the community and are at the base of a lot of common images .. like node .. ruby .. etc

In fact the previous node:12 image was based on it too.

@tessus
Copy link
Collaborator

tessus commented Jul 25, 2021

debian buster has very very conservative versions of libraries

Right, but what about buster-backports?

@piotrb
Copy link
Contributor Author

piotrb commented Aug 18, 2021

I split out the one small tweak to its own PR so at least that can go through uncontested .. I'm having a look at your build scripts and seeing how I can easily add proper multi platform support in .. so you actually publish armv7 (and maybe arm64 while we're at it) packages to dockerhub .. I'll try the buster-backports path if possible ..

@piotrb
Copy link
Contributor Author

piotrb commented Aug 18, 2021

debian buster has very very conservative versions of libraries

Right, but what about buster-backports?

Eh no it doesn't look like buster-backports has libvips or libc .. so I think my original approach is kind of the only way here ..

@piotrb
Copy link
Contributor Author

piotrb commented Aug 18, 2021

I bumped node to 16 in this PR to match the version upstream

@piotrb
Copy link
Contributor Author

piotrb commented Aug 18, 2021

This overlaps with #5337 so let's mere that one first and then I'll clean this up

@@ -1,9 +1,21 @@
# https://versatile.nl/blog/deploying-lerna-web-apps-with-docker

FROM node:16
FROM buildpack-deps:focal
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now that we use node:16, doesn't it have the dependencies that you need? If it doesn't can't we just manually install them on top of node:16? I'd rather use an image that specifically for Node if possible.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm .. 16 is still based on buster .. but there is 16-bullseye .. so let check if that would do it ..

@piotrb piotrb force-pushed the armv7-fixes branch 2 times, most recently from f83a402 to 8d9183c Compare August 19, 2021 00:07
@piotrb
Copy link
Contributor Author

piotrb commented Aug 19, 2021

Yup, switching to 16-bullseye did it .. I cleaned this up a bit .. since there is a bit of an overlap with that other vim related PR .. this will probably need a rebase once that is merged .. but this is probably the smallest diff now to make this build properly on non amd64

@piotrb piotrb changed the title Server: Switch to buildpack-deps:focal as the base image and then install node via node-build, also add python. Server: Switch to node:16-bullseye and add python to the image to support building on non amd64 platforms Aug 19, 2021
@piotrb
Copy link
Contributor Author

piotrb commented Aug 19, 2021

Other than possible merge conflicts once the other PR is merged .. is there any concerns left @laurent22 ?

@laurent22
Copy link
Owner

Thanks @piotrb, that looks good I think. Did you have the opportunity to build that image, and how does it compare to the previous one in terms of size?

@piotrb
Copy link
Contributor Author

piotrb commented Aug 20, 2021

I have some screenshots in the other pr .. but the short of it is:
Your last "latest" image is ~784 megs

The updated build generates 3 images now (one for each arch).

amd64 turned out to be ~719megs
arm64 ~714megs
and arm/v7 ~684megs

So on average all the images are a bit smaller


I'd say if you're seriously concerned about image size we should be swapping over to alpine if possible .. debian/ubuntu based images are naturally going to be larger.

For comparison ..
node:16-alpine is ~38megs
node:16-buster (same as node:16 you were originally using) is ~330megs
node:16-bullseye is ~340megs


Your node deps are pretty deep .. I'm not sure if you need all that you include in the server package .. it just feels like a lot of deps for seemingly something relatively simple .. a backend server to sync notes ;) .. why does it need to know about renderers and gfm and all that stuff? (that's just an aside, but I'm sure the node_modules folder is pretty massive inside the image .. since the difference between the ~340megs and the final ~720 megs .. is going to be any packages you install .. so that's almost 500 megs of node packages and source code ;)

This uses newer libs which are needed to build some of the dependencies which are not available pre-built on non-amd64 architectures.

Also to instal sqlite from source python seems to be needed.
@piotrb
Copy link
Contributor Author

piotrb commented Aug 20, 2021

Alright I rebased this PR so it doesn't conflict with the main branch .. its ready to be merged (if you'd like to to potentially take a stab at slimming things down, let's do that outside this PR please)

@laurent22
Copy link
Owner

Reducing the Node dependencies would probably require splitting the lib package into sub-packages (not an option) or using some tree shacking algorithm. That might remove the sync target related code in particular which is not needed.

As for Markdown rendering, it's for the published notes which need to be rendered to HTML

@laurent22
Copy link
Owner

ok let's merge and I will try the next release with this. Thanks for the update!

@laurent22 laurent22 merged commit 9b2094f into laurent22:dev Aug 23, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
server Issues related to Joplin Server
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants