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
Use Node Alpine Version as Docker image base & use Yarn instead of NPM #8704
Use Node Alpine Version as Docker image base & use Yarn instead of NPM #8704
Conversation
Hi @stevefan1999-personal -- is there a specific reason you've updated the Dockerfile to use these configurations? |
@julianlam I want to image size to be as small as possible to better fit in a k8s cluster. Almost all of us use Alpine as base image. |
Right, and the choice between Debian Buster and Alpine...? You should not bundle imagemagick in the file, as it is not required by NodeBB unless you are using the imagemagick plugin, and if so you'll want to use a forked Dockerfile. |
@julianlam And I think that hacking the Dockerfile to use Alpine will be very dangerous and it will affect downstream images as well, so I rather take a step back and look for safer alternatives. And immediately I see that a slim version of node is available so I changed to that, plus I deleted all that apt cache so that it should have a comparable size to what you would get with Alpine. Also in the official guide to install NodeBB in Debian, ImageMagick is required. And I see that makes sense for others to derive a new image that install ImageMagick on their own. Now I removed it so the size should be the bare minimum now. I have pushed my modifications to Docker Hub. You can compare the size difference here: |
Thanks for the explanation. The change to use yarn is certainly ok, although I think some flag needs to be set in NodeBB setup, I will review again later today. |
@nilsramsperger this is an unsolicited plea for a second pair of eyes on this PR 😁 |
I think it LGTM. The image size now is trimmed down by 2,27x, a very considerable shrink in sizes. |
Switching to a smaller base image to shrink image size is a good idea. Buster-slim is a step in the right direction. |
@stevefan1999-personal Let's keep it simple and revert back to npm. I am okay if you want to switch to Alpine Linux since @nilsramsperger is using it. If you need imagemagick support, then ok to stick with Debian Buster as well. For reference here is his |
If somebody wants to open an issue on benchpress I can switch it to use musl-libc instead which should make it more portable across Linux distros. |
@nilsramsperger I will squash the commits for the one final round |
Thanks @stevefan1999-personal 😄 |
fbc8279
to
05441a3
Compare
05441a3
to
f27bd4a
Compare
@stevefan1999-personal good to know that yarn is somewhat more efficient on cache deletion than npm. |
Any news on this? Need help with any outstanding issues? After switching to yarn, I just can't use npm anymore unless I have to :p |
@NazimHAli yes, there is no way to keep node_modules for some reason, especially when it involved plugins, and I realized Docker might not be the right tech for this. |
I planned to use it in Kubernetes, but then I realized I cannot do layered volumes on demand, so I wanted to have a separate plugin volume that layered on top of the base image, so I don't have to worry about losing plugin after restarting. Someone made it with Synching and decided to recursively link everything into it, and I think this is not elegant. It is also possible if I use FUSE based OverlayFS implementation (because it requires root), but the performance won't be pretty. |
@stevefan1999-personal I made it working on kubernetes, but it is ugly so far. My PR #10036 would solve the module problem. But until then I hacked it with an initContainer in the deployment and a config.json template and a buildscript mounted from the configMap. |
By merging the user layer with the base layer using fuse-overlayfs, you can successfully save the user-initiated changes such as plugin and theme install. The only problem: it requires FUSE and SYS_ADMIN, which is considered unsafe to some people with a concern of breaching container security. But so far it works for me. |
43c3535
to
0a0f926
Compare
@nilsramsperger Can you kindly do a test run and let us know if there are any unexpected behaviours with this new image? |
Oh also expect longer build times for workflow since qemu emulation is prohibitively slow. At the very best we could just include arm64 and amd64 to lose 32-bit Raspberry Pi support (armv7). That might pity some people but any hobbyst should be able to figure out how to build an image matching their platform. I needed arm64 since I run it on Ampere. |
I'd say at the very least ppc64le (I wonder how many PowerPC devices run NodeBB...) and arm v6 should go. I'd even be in favor of dropping v7. Also, not sure if MongoDB docker image works on 32 bit ARM anyway. EDIT: Nope, it doesn't - amd64 and arm64 only. Redis and Postgres do, but I think it might be fine to just follow the default DB choice for NodeBB. The question is how much time it adds though, if it's not a lot I don't think keeping v7 would be bad. |
Signed-off-by: steve <29133953+stevefan1999-personal@users.noreply.github.com>
Okay. That should do it |
@julianlam I just did a small test run on the code, using the redis profile. The forum can be set up and be started. No problems this far. As mentioned in previous posts, the startup takes quite some time. This leads to some bad user experience, since the software feels like it hung up several times:
The performance definitely needs some improvement (IMHO). Greets |
Signed-off-by: steve <29133953+stevefan1999-personal@users.noreply.github.com>
docker-entrypoint.sh
Outdated
else | ||
echo "Config file not found at $CONFIG" | ||
echo "Starting installer" | ||
./nodebb install --config=$CONFIG |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just noticed that this is running install
instead of setup
like the current dockerfile. This would be a breaking change AFAIK, since unlike setup this requires user interaction to actually start NodeBB.
However, current Dockerfile requires a SETUP
env variable to run setup
, as such this could probably be left as-is and instead before the config file is checked the dockerfile could check for that variable and run ./nodebb setup
if it is set.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IIRC setup runs an interactive CLI that requires user input but on a containerized environment this is close to impossible (and there is a lot of gimmicks using docker attach
). Since I use Kubernetes to host NodeBB, that's even more impossible, and that's why I need to resort to using web installer instead. But I do agree this is a breaking change. Maybe we could add a switch for this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Setup can run with just env variables, which is why the current dockerfile has it (and probably why it requires a separate variable to run it).
As I said, I think a preferred solution might be leaving install as is and instead checking for the SETUP
env variable before the two existing paths for running NodeBB. It'd maintain compatibility with current Dockerfile while adding the installation functionality if config doesn't exist and the user didn't prepare for unattended setup.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh I have implemented the "init" verb now, but should I keep it as setup
or install
, though?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As I said: I think install
by default is a good choice, but for the sake of backwards compatibility the script should run setup
if an environmental variable called SETUP
is set (see this part of the current dockerfile: test -n "${SETUP}" && ./nodebb setup
).
So essentially, I think your solution is better for most cases (and being able to specify command is even better), but I think the previous one should still work not to break someone's workflow without a decent reason.
Can't suggest code changes in this thread since it's outdated, but something like
if [ -n $SETUP ]; then
./nodebb setup --config $CONFIG
elif [ -f $CONFIG ]; then
(rest of current code)
Would ensure current setups work.
This would allow you to change between "setup" (automated setup using environmental variables which is the current preferred way to run containerized NodeBB) or "install" (web install that guides user to fill in connection information, which is similar to WordPress) Signed-off-by: steve <29133953+stevefan1999-personal@users.noreply.github.com>
Signed-off-by: steve <29133953+stevefan1999-personal@users.noreply.github.com>
Signed-off-by: steve <29133953+stevefan1999-personal@users.noreply.github.com>
Signed-off-by: steve <29133953+stevefan1999-personal@users.noreply.github.com>
Hmm... The image from this PR doesn't seem to work at all for me - I'm mostly getting permission errors: nodebb-7-nodebb-1 | chmod: /opt/config: Operation not permitted
nodebb-7-nodebb-1 | chmod: /opt/config: Operation not permitted
nodebb-7-nodebb-1 | cp: can't create '/opt/config/package.json': Permission denied
nodebb-7-nodebb-1 | touch: /opt/config/package-lock.json: Permission denied
nodebb-7-nodebb-1 | ln: package.json: File exists
nodebb-7-nodebb-1 | ln: package-lock.json: File exists
[...]
nodebb-7-nodebb-1 | npm ERR! code EACCES
nodebb-7-nodebb-1 | npm ERR! syscall open
nodebb-7-nodebb-1 | npm ERR! path /usr/src/app/package-lock.json
nodebb-7-nodebb-1 | npm ERR! errno -13
nodebb-7-nodebb-1 | npm ERR! Error: EACCES: permission denied, open '/usr/src/app/package-lock.json'
[...]
nodebb-7-nodebb-1 | Error: EACCES: permission denied, copyfile '/usr/src/app/install/package.json' -> '/usr/src/app/package.json' The ln -fs $CONFIG_DIR/package.json package.json
ln -fs $CONFIG_DIR/package-lock.json package-lock.json For a dirty fix of the permission errors I even ran as root and found another issue, and I 100% blame NPM for it. What is it? So, logically, what protocol should this URL starting with The "workaround" is to use Oh, and the issue in NPM repo has been open since last february: npm/cli#2610 |
Signed-off-by: steve <29133953+stevefan1999-personal@users.noreply.github.com>
…ill no permission on config dir Signed-off-by: steve <29133953+stevefan1999-personal@users.noreply.github.com>
It still seems the permissions for the default config directory are broken, I'm still getting nodebb-nodebb-1 | chmod: /opt/config: Operation not permitted
nodebb-nodebb-1 | panic: no write permission for /opt/config I'm just running |
Interesting. It seems like you are running the container as another user that the UID-GID mapping isn't cleanly remapped. I need to think about that as well, since it could mean one of your upper directory does not give permission to that location (far as I remember it is chained, so if you can't the top/"leftmost" directory, the rest won't as well) |
I will defer to @oplik0's opinion on merging this wrt technical details. However, I noticed that you updated the readme to include information about the Docker config. That's great! I do want to move that out to a dedicated page on the documentation portal instead. So I will do that and then merely link out to it from the readme, just like the installation/upgrade sections. |
re: NodeBB/NodeBB#8704, this commit takes the changes to README.md and includes them in a new page in the documentation instead.
…ut add link to cloud install docs
This is now done, NodeBB/docs#78 will need to be merged at the same time for best effect 🪄 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This time I actually found how to fix the issues I ran into, so with just a few changes I'm all for this. It's far better than current solution, both by optimizing some parts of the image by using alpine, and by greatly improving usability with the volumes.
@@ -54,6 +54,7 @@ jobs: | |||
with: | |||
context: . | |||
file: ./Dockerfile | |||
platforms: linux/amd64,linux/arm64 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was already changed, see line 60 - I guess I didn't notice this was also a part of this PR
mkdir -p $CONFIG_DIR | ||
chmod -fR 760 $CONFIG_DIR | ||
|
||
if [[ ! -w $CONFIG_DIR/package.json ]]; then |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This actually returns true
if $CONFIG_DIR/package.json
doesn't exist. You need to check the directory itself here (just if [[ ! -w $CONFIG_DIR ]]
)
Fixing this resolves my issue from #8704 (comment) - though chmod
still throws an error
export SETUP="${SETUP:-}" | ||
|
||
mkdir -p $CONFIG_DIR | ||
chmod -fR 760 $CONFIG_DIR |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd redirect the errors from this to /dev/null
- volumes on at least some platforms mount owned by root, making this fail despite the folder still being writable.
Though I'd also add a comment explaining this to help debugging. E.g.
# If the folder is mounted as a volume this can fail, the check below is to ensure there is still write access
chmod -fR 760 $CONFIG_DIR 2> /dev/null
ln -fs $CONFIG_DIR/package.json package.json | ||
ln -fs $CONFIG_DIR/package-lock.json package-lock.json | ||
|
||
npm install --only=prod |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
npm moved to --omit
instead of --only
for some reason, so this throws a deprecation warning. So this should now be
npm install --omit=dev
(note that this is from npm >=8, which became the default in Node 16, so it's currently in all supported node versions)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Correction: also add --no-optional
because sass-embedded
currently doesn't support alpine Linux (it might soon-ish - it appears dart finally added support for musl builds a few months ago)
But npm doesn't catch this issue on the optional dependency because it only seems to look for generic os/architecture.
And sass removed musl-specific error handling in a refactor for some reason
@@ -14,28 +14,28 @@ USER node | |||
RUN npm install --omit=dev | |||
|
|||
|
|||
FROM node:lts | |||
FROM node:lts-alpine3.16 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This has been held up so long that 2 alpine versions came out, so it should be 3.18 now :)
@stevefan1999-personal I just wanted to ask if you're still interested in pursuing this PR (I think all that's left are the fixes from stevefan1999-personal#71 and possibly rebasing to develop, but I'm not sure how important that is), or if that's not the case if you'd be fine with me making a new PR based on your work here? |
@oplik0 You can take over some of it. You can choose what was essential first. I will split this PR into different parts. |
Well the prebuilt binaries for benchpress-rust is built against GLIBC, which is a big no no for Alpine.I tried to use Alpine and thus that prebuilt binary cannot import the symbols for GLIBC, neither libc6-compat do. I have succeeded to install rust from Alpine Edge and let Neon do its job, but it will increase the build time but roughly 1.5x.It is fixed a year later
The image size will drop more than 100MB when compared normally.