Open neilstuartcraig opened 8 years ago
I do think the above is correct.
To provide Alpine-compatible binaries, node itself would have to provide them - nvm
simply installs whatever is available on nodejs.org. I think it would be great to add alpine binaries to the list of build targets that node core produces - filing an issue on https://github.com/nodejs/node would be the right place for that.
Ah, I see...I thought NVM maintained a separate repo. I'll file a bug with the Node project.
Would NVM need any changes to download the correct binary for Alpine and other busybox-based OS's?
Just for note - nvm install -s 0.12
worked on Alpine after doing the above.
Thanks for the quick response!
Any changes nvm would need would be minimal - solely grabbing the right OS and architecture strings, based on what node chose.
It seems like when nvm
supports installing node from source >= v1.0, it will also work on alpine, and I'm continuing to work on that.
OK cool, thanks for that - seems like a reasonably easy win then. I have filed https://github.com/nodejs/node/issues/6965.
For speed, binaries would be best of course but building from source would be helpful as a fallback.
Thanks again!
Sorry, also just thought...are you interested in adding some info to either a separate doc or the main readme for Alpine/busybox users? How to get NVM working on these is fresh in my memory and I think it'd be useful to note how to get it installed and what the current limitations are (and why) on Alpine/busybox would be useful - it took me an hour or two of reading and trying things so maybe it might save other folks some time which is always nice :-)
If it's more than a few sentences, I'd love to see a draft first, otherwise a PR to the main readme is great.
OK cool - i'll draft something over the next day or two and post it here - i'll keep it as short as possible.
Hi again @ljharb
Here's my draft on the above - please let me know what you think and/or whether you want me to PR it in some fashion (add to readme.md or a new doc - i'm thinking new doc might be best as it's probably only interesting to a minority). I won't be offended if you think this is complete rubbish so please let me know your honest thoughts 😼.
In order to provide the best performance (and other optimisations), NVM will download and install pre-compiled binaries for Node (and NPM) when you run nvm install X
. The Node project compiles, tests and hosts/provides pre-these compiled binaries which are built for mainstream/traditional Linux distributions (such as Debian, Ubuntu, CentOS, RedHat et al).
Alpine Linux, unlike mainstream/traditional Linux distributions, is based on busybox, a very compact (~5MB) Linux distribution. Busybox (and thus Alpine Linux) uses a different C/C++ stack to most mainstream/traditional Linux distributions - musl. This makes binary programs built for such mainstream/traditional incompatible with Alpine Linux, thus we cannot simply nvm install X
on Alpine Linux and expect the downloaded binary to run correctly - you'll likely see "...does not exist" errors if you try that.
There is a -s
flag for nvm install
which requests NVM download Node source and compile it locally but currently (May 2016), this is not available for Node versions newer than v0.10 so unless you need an older Node version, this won't help you. Work is in progress on source-builds for newer Node versions but is not yet complete.
If installing NVM on Alpine Linux is still what you want or need to do, you should be able to achieve this by running the following from you Alpine Linux shell:
apk add bash
wget -qO- https://raw.githubusercontent.com/creationix/nvm/v0.31.1/install.sh | /bin/bash
The Node project has some desire but no concrete plans (due to the overheads of building, testing and support) to offer Alpine-compatible binaries.
As a potential alternative, Michael Hart (a Node contributor) has some Docker images for Alpine Linux with Node and optionally, NPM, pre-installed.
Cheers Neil
Thanks, this looks great! I guess this can go as a section in the readme between "Compatibility issues" and "Problems"?
Great. I'll send a PR as soon as I get a moment. Cheers
Could you help me understand the status of this? I came with this intent of opening a separate issue, but while looking through existing issues first, this one surprised me. I seem to have no trouble installing nvm
and running nvm install
in a directory that contains an .nvmrc
. Is this not expected to work?
It did take me a bit to get it working, but because I was not installing the nodejs
package for a system level node
to be available. This was causing me to run into the following error: nvm is not compatible with the npm config "prefix" option: currently set to ""
. Once I install the nodejs
package, things work fine.
Since this is is for an alpine docker image for a Jenkins agent, I was hoping to skip the need for a system node
since I was hoping nvm
by itself could handle making node
and npm
available for the build.
Should a system node
really be necessary? If not, I'm happy to open a separate issue to track that separately.
@travi you shouldn't need the "nodejs" package for anything, nor a system node. The prefix error is likely that you have a "prefix" line in ~/.npmrc
, or an env variable setting the prefix - that should be removed. A separate issue would be great!
Ok, thanks. That at least confirms my thought that a system node should be unnecessary.
This is a clean docker image with no .npmrc
outside of the project being built (with only save-exact=true
as content) and no env vars related to this.
I'll get this broken into a separate issue.
I have 3 potential options that enable using nvm on alpine with precompiled binaries in the node unofficial-builds project. https://unofficial-builds.nodejs.org/ <-- these are used in the official node:alpine docker images currently.
I have a branch I can submit for a pull request for just readme updates https://github.com/bpmccurdy/nvm/tree/alpine-readme here are the updates:
Alpine Linux, unlike mainstream/traditional Linux distributions, is based on BusyBox, a very compact (~5MB) Linux distribution. BusyBox (and thus Alpine Linux) uses a different C/C++ stack to most mainstream/traditional Linux distributions - musl. There currently is no musl based binary published in the nodejs official builds but they do publish a musl based binary in the nodejs unofficial builds which they use in the node:alpine docker image. The node:alpine docker image is a potential alternative to nvm for using node on alpine linux.
For now you can override the nvm_get_arch
function to return x64-musl
on x64 Alpine Distributions. Currently the Node project only has unofficial builds for x64-musl
. Sorry no ARM-musl
/x86-musl
,etc
builds for now. The Node project has some desire but no concrete plans (due to the overheads of building, testing and support) to offer Official Alpine-compatible binaries.
For more info about unofficial builds visit: https://unofficial-builds.nodejs.org/
If installing nvm on Alpine Linux is still what you want or need to do, you should be able to achieve this by running one of the following from your Alpine Linux shell:
Pre-compiled binaries for musl based architectures are unofficially available for most node versions after node v8.16.0
cd && touch .profile
apk add --no-cache libstdc++ coreutils curl bash
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.1/install.sh | bash
echo "export NVM_NODEJS_ORG_MIRROR=https://unofficial-builds.nodejs.org/download/release" >> .profile
echo "nvm_get_arch() { nvm_echo \"x64-musl\"; }" >> .profile
source .profile
libstdc++
- is the only package that is necessary to run node/npm once it is installed.bash
- is required to install nvm... BusyBox's sh
has some issues with chmod
ing the nvm-exec file, but bash can be removed again after install if you want to slim your image.coreutils
/curl
- is required to for nvm because BusyBox is not 100% POSIX compliant. Mainly ls
not accepting a -q
argument and wget
not having the progress bar option.Since there are no io.js builds available for musl you can also disable all io.js versions from showing up in nvm ls-remote by also running:
echo "export NVM_IOJS_ORG_MIRROR=https://example.com" >> .profile
There is a -s
flag for nvm install
which requests nvm download Node source and compile it locally. This does not use anything unofficial but it is much slower and more cpu intensive to install and build each version of node.
apk add -U curl bash ca-certificates openssl ncurses coreutils python2 make gcc g++ libgcc linux-headers grep util-linux binutils findutils
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.1/install.sh | bash
Similar to the pre-compiled binaries
libstdc++
- is the only package that is necessary to run node/npm once it is installed.I also have another option that detects musl automatically for people in nvm.sh
so they don't have to override the nvm_get_arch
function in their .profile. nvm
would need to be versioned for this though.
Branch: https://github.com/bpmccurdy/nvm/tree/unofficial-musl-support
Assuming nodejs keeps the same naming structure (node-v13.0.1-linux-x64-musl.tar.xz) when the finally make the musl build an official distribution nvm would likely not need further updating to support it. Basically in the nvm_get_arch
function I added to the end
if (ldd $(which echo) | nvm_grep -q musl); then
NVM_ARCH="${NVM_ARCH}-musl"
fi
The readme is also updated in this branch similarly to Option 1 but without the override script and info. It would also require some more work to update the version references everywhere before it could be pulled.
I'm also open to making a couple more adjustments to Option 2 that would have nvm automatically backup to the unofficial-build mirror if no normal distribution was found without manually having to set NVM_NODEJS_ORG_MIRROR. Which basically would fully resolve this issue.
Let me know if you like any of these options :) Sorry for such a long message, I wanted to include everything I had 👍
@bpmccurdy thanks; sorry for the delay.
Noting in the docs that Alpine only requires libstdc++
to be able to install from source seems like a great option.
Can you elaborate a bit more on the nvm_get_arch
change?
@bpmccurdy thanks. This works perfectly for me, it installs node in the image and allows to change the version from the inside container. for testing purposes. I use zsh, but I think the same should work with bash.
RUN apk add --no-cache libstdc++; \
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.1/install.sh | bash; \
echo 'source $HOME/.profile;' >> $HOME/.zshrc
RUN { \
echo 'export NVM_NODEJS_ORG_MIRROR=https://unofficial-builds.nodejs.org/download/release;'; \
echo 'nvm_get_arch() { nvm_echo "x64-musl"; }'; \
} > $HOME/.profile; \
NVM_DIR="$HOME/.nvm"; source $HOME/.nvm/nvm.sh; source $HOME/.profile; \
nvm install 13.8.0
or like so
RUN apk add --no-cache libstdc++; \
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.1/install.sh | bash; \
echo 'source $HOME/.profile;' >> $HOME/.zshrc; \
echo 'export NVM_NODEJS_ORG_MIRROR=https://unofficial-builds.nodejs.org/download/release;' >> $HOME/.profile; \
echo 'nvm_get_arch() { nvm_echo "x64-musl"; }' >> $HOME/.profile; \
NVM_DIR="$HOME/.nvm"; source $HOME/.nvm/nvm.sh; source $HOME/.profile; \
nvm install 13.8.0
Taking the instructions from above, I have created a little wrapper that you can use without making changes to .profile
export NVM_NODEJS_ORG_MIRROR=https://unofficial-builds.nodejs.org/download/release
NVM_DIR="$HOME/.nvm"
source "$HOME/.nvm/nvm.sh"
nvm_get_arch() { nvm_echo "x64-musl"; }
nvm $@
If you want I guess you can alias this over the original nvm. Not sure if it works though.
@takase1121 if there's a way to detect x64-musl
reliably, then I'd be happy to accept a PR to modify nvm_get_arch
.
@ljharb
Well, I found a way to do that quite reliably. I was looking around and found this. It checks output of ldd --version
against musl
and -musl
.
In order to confirm the reliability of this method, I cloned musl
and made a script to search each commit for musl
in dynlink.c
(The file that contains entry point for ldd). The result is as such:
Checking commit message:
This is where support for ldd
is added to musl. Great. The commit belongs to v0.9.1
which should be around 2012. Unless your OS runs on a very old version of musl (I don't think that's very possible), it will work.
This is the script I used:
found=0
total=0
firstfound=""
for commit in $(git rev-list --reverse master)
do
git checkout $commit > /dev/null 2>&1
grep --include="dynlink.c" -rnw '.' -e "musl" > /dev/null
if [ $? -eq 0 ]
then
if [ -z "$firstfound" ]; then firstfound="$commit"; fi
found=$(( found + 1 ))
fi
total=$(( total + 1 ))
done
percentage=$(echo "scale=2; $found / $total * 100" | bc)
echo "$found out of $total commits has it, $percentage% coverage"
echo "First found in $firstfound"
However this is only a proof from musl's source code. The distro could change it themselves and that is a problem. I don't have time and resources to conduct tests on multiple machines/VMs. Hopefully somebody else can give a better proof than mine.
EDIT: I just realize this is almost duplicate of Option 2 above.
I was using @bpmccurdy 's option 1 but with latest docker image update nvm stopped working. There is some strange curl error (416 ). I'm using nvm version 0.39.1 and docker amazeeio/php - 8.0-cli-drupal-22.2.0, amazeeio/php - 7.4-cli-drupal-latest
$ nvm install
Found '/app/frontend/.nvmrc' with version <lts/fermium>
Downloading and installing node v14.19.1...
Downloading https://unofficial-builds.nodejs.org/download/release/v14.19.1/node-v14.19.1-linux-x64-musl.tar.xz...
########################################################################################################## 100.0%curl: (22) The requested URL returned error: 416
Binary download from https://unofficial-builds.nodejs.org/download/release/v14.19.1/node-v14.19.1-linux-x64-musl.tar.xz failed, trying source.
grep: /home/.nvm/.cache/bin/node-v14.19.1-linux-x64-musl/node-v14.19.1-linux-x64-musl.tar.xz: No such file or directory
Provided file to checksum does not exist.
Binary download failed, trying source.
Detected that you have 12 CPU core(s)
Running with 11 threads to speed up the build
Clang v3.5+ detected! CC or CXX not specified, will use Clang as C/C++ compiler!
Downloading https://unofficial-builds.nodejs.org/download/release/v14.19.1/node-v14.19.1.tar.xz...
curl: (22) The requested URL returned error: 404
Binary download from https://unofficial-builds.nodejs.org/download/release/v14.19.1/node-v14.19.1.tar.xz failed, trying source.
grep: /home/.nvm/.cache/src/node-v14.19.1/node-v14.19.1.tar.xz: No such file or directory
Provided file to checksum does not exist.
This is pretty much what is needed on the .zshrc
| .profile
export NVM_NODEJS_ORG_MIRROR=https://unofficial-builds.nodejs.org/download/release # Set up unofficial builds
export NVM_IOJS_ORG_MIRROR=https://example.com # (Optional) Disable IOJS from appearing on ls-remote
nvm_get_arch() { nvm_echo x64-musl; } # Needed to build the download URL
why someone can't just fix this issue once and for all? Alpine is everywhere since docker is out, its just a tiny if statement
and so many developers will get happier.
@asolopovas nvm isn't going to point to "unofficial builds", they're unofficial.
I would be happy to accept a PR that returns the proper nvm_get_arch
value, though.
https://github.com/nvm-sh/nvm/pull/3212, some tests are failing, but for it to work NVM_NODEJS_ORG_MIRROR environment varialbe must be equale to "https://unofficial-builds.nodejs.org/download/release", or how would you like me to add the propper value than?
It’d be fine to use that in tests, but to be clear - what happens when pointing to the default node version list with that arch?
If understood you correctly, nothing should happen without unless environment variabl NVM_NODEJS_ORG_MIRROR is set to url with musl build it will fail trying to get musl build from official source
On Sun, 1 Oct 2023, 00:43 Jordan Harband, @.***> wrote:
It’d be fine to use that in tests, but to be clear - what happens when pointing to the default node version list with that arch?
— Reply to this email directly, view it on GitHub https://github.com/nvm-sh/nvm/issues/1102#issuecomment-1741883424, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABUS5IDTWTSXCX6O55PU7S3X5CVBTANCNFSM4CEZFXYA . You are receiving this because you were mentioned.Message ID: @.***>
Then we should have a test for that failure.
Hi
First off, thanks for NVM - I use it frequently and see it being used everywhere and it's been great. To that end, I'd really like to use NVM on my current project which is basically a CI running via Docker - i'd like to be able to use Alpine Linux as the base image.
I can get NVM to install on Alpine by doing:
Which is great. But then the resulting Node binary won't run and I believe from doing a little reading that this is likely to be because Alpine needs musl rather than GCC built binaries.
I tried using the
-s
flag innvm install
but that tells me it is not usable for Node > 1.I see Alpine and other busybox-based distros gaining a lot of traction as they're so fast, perfect for containerised use - hence my interest.
So my question is...Do you think the above is correct and if so (or if similar), can I offer help in perhaps providing Alpine-compatible binaries? I can perhaps script a compilation of all the existing versions of Node source - though it'd take some time to run - then upload them somewhere e.g. S3.
If the above is of any interest, please let me know as I am keen to help wherever necessary.
Cheers Neil