volta-cli / volta

Volta: JS Toolchains as Code. ⚡
https://volta.sh
Other
11.17k stars 238 forks source link

Provide statically-linked musl binary for Alpine Linux #473

Open BryanHunt opened 5 years ago

BryanHunt commented 5 years ago

I tried adding volta to a container and when I try to execute it, I get:

bash: /root/.volta/volta: No such file or directory

Here is the Dockerfile I'm using:

FROM alpine:3.9

RUN apk update
RUN apk add bash
RUN apk add openssl
RUN apk add curl
RUN apk add git

RUN touch ~/.bash_profile
RUN curl -sSLf https://get.volta.sh | bash

CMD [ "/bin/bash" ]
charlespierce commented 5 years ago

Hi @BryanHunt, thanks for reporting this! I'll admit to not having experience with Docker (though I'm going to look into it a bit since this Dockerfile seems straightforward enough). This is a strange one, as the error seems to indicate that the installer worked and correctly modified the profile, but that that it failed to install the files (which it would do first, and so if that failed the rest shouldn't have happened).

Can you show the contents of /root/.bash_profile, as well as the contents of /root/.volta (if it exists) in the container? Also, is there a log from the startup that would show the output of the Volta installer? Thanks!

BryanHunt commented 5 years ago

I think the issue is that there are some shared system libraries missing and the error message is misleading.

charlespierce commented 5 years ago

Thanks for the follow-up @BryanHunt. That would definitely be misleading if the root cause was an inability to find shared libraries. While we can’t do much to fix bash having bad errors, with some investigation, we may be able to better document the required libraries.

charlespierce commented 5 years ago

@BryanHunt I dug in a bit with that Dockerfile, and you're right, there are a number of shared libraries that aren't available with that setup of Alpine. The biggest issue is that the current builds of Volta are all dynamically linked to glibc, while Alpine is built using musl libc.

We have talked in the past about doing some static linking in Volta (when we were looking at OpenSSL compatibility issues), but we ultimately decided against it for a number of reasons. We could discuss the idea of providing a fully statically-linked version as an advanced option, with the disclaimers that the end-user is responsible for keeping it up-to-date as that version won't be getting security updates from the shared libraries on the system.

charlespierce commented 5 years ago

Tracking in the Updates / Notifications project, as if we make a statically-linked binary, we should absolutely have a path for upgrading and notifying users that a new version is available.

izelnakri commented 4 years ago

This would be a great feature for docker based CI and development environments since alpine based containers are extremely slim. Would appreciate if someone look into this or/and if we get an official image on docker hub just like official github actions.

vanstinator commented 3 years ago

I'd really appreciate a way to run volta on an alpine docker image as well!

markhughes commented 3 years ago

I can install it fine, however it wont execute.. really strange:

My install script is like:

apk update
apk add --no-cache python3 git curl bash openssl
curl https://get.volta.sh | bash
# ls ~/.volta/bin/
volta          volta-migrate  volta-shim

then trying to run:

# ~/.volta/bin/volta
sh: /root/.volta/bin/volta: not found

Edit: digging deeper,

/ # ldd /root/.volta/bin/volta
        /lib64/ld-linux-x86-64.so.2 (0x7feba275a000)
        libssl.so.1.1 => /lib/libssl.so.1.1 (0x7feba1e73000)
        libcrypto.so.1.1 => /lib/libcrypto.so.1.1 (0x7feba1bf2000)
        libc.so.6 => /lib64/ld-linux-x86-64.so.2 (0x7feba275a000)
Error loading shared library ld-linux-x86-64.so.2: No such file or directory (needed by /root/.volta/bin/volta)
        libdl.so.2 => /lib64/ld-linux-x86-64.so.2 (0x7feba275a000)
        libgcc_s.so.1 => /usr/lib/libgcc_s.so.1 (0x7feba1bd8000)
        librt.so.1 => /lib64/ld-linux-x86-64.so.2 (0x7feba275a000)
        libpthread.so.0 => /lib64/ld-linux-x86-64.so.2 (0x7feba275a000)
        libm.so.6 => /lib64/ld-linux-x86-64.so.2 (0x7feba275a000)
Error relocating /root/.volta/bin/volta: __register_atfork: symbol not found
Error relocating /root/.volta/bin/volta: __res_init: symbol not found
/ # 

We can add some compat. like so:

apk add libc6-compat
ln -s /lib/libc.musl-x86_64.so.1 /lib/ld-linux-x86-64.so.2

Which fixes one of the shared library issues, however.. I get this still:

# ldd /root/.volta/bin/volta
        /lib64/ld-linux-x86-64.so.2 (0x7f41da931000)
        libssl.so.1.1 => /lib/libssl.so.1.1 (0x7f41da04a000)
        libcrypto.so.1.1 => /lib/libcrypto.so.1.1 (0x7f41d9dc9000)
        libc.so.6 => /lib64/ld-linux-x86-64.so.2 (0x7f41da931000)
        libdl.so.2 => /lib64/ld-linux-x86-64.so.2 (0x7f41da931000)
        libgcc_s.so.1 => /usr/lib/libgcc_s.so.1 (0x7f41d9daf000)
        librt.so.1 => /lib64/ld-linux-x86-64.so.2 (0x7f41da931000)
        libpthread.so.0 => /lib64/ld-linux-x86-64.so.2 (0x7f41da931000)
        libm.so.6 => /lib64/ld-linux-x86-64.so.2 (0x7f41da931000)
Error relocating /root/.volta/bin/volta: __register_atfork: symbol not found
Error relocating /root/.volta/bin/volta: __res_init: symbol not found
markhughes commented 3 years ago

OK for those looking for a solution you can duplicate what is done here:

https://github.com/Docker-Hub-frolvlad/docker-alpine-glibc/blob/master/Dockerfile

This adds glibc. So I didn't really trust using that docker image by the way.. so I copied that into my own, then after that I ran the following:

RUN  apk update
RUN  apk add --no-cache python3 git curl bash openssl
RUN apk add --no-cache libstdc++6
RUN  curl https://get.volta.sh | bash
RUN . ~/.profile 
RUN  volta --version

from here I get:

 # volta --version
1.0.2

Woohoo! tada

So from here I tried to run node:

/ # volta install node@14
success: installed and set node@14.16.1 (with npm@6.14.12) as default
/ # node --version
node: error while loading shared libraries: libstdc++.so.6: cannot open shared object file: No such file or directory

Yikes, ok, my attempt to fix it:

/ # apk add libstdc++
(1/1) Installing libstdc++ (10.2.1_pre1-r3)
Executing glibc-bin-2.33-r0.trigger
/usr/glibc-compat/sbin/ldconfig: /usr/glibc-compat/lib/ld-linux-x86-64.so.2 is not a symbolic link

OK: 83 MiB in 38 packages
/ # node --version
node: /usr/lib/libstdc++.so.6: no version information available (required by node)
node: /usr/lib/libstdc++.so.6: no version information available (required by node)
node: /usr/lib/libstdc++.so.6: no version information available (required by node)
node: /usr/lib/libstdc++.so.6: no version information available (required by node)
node: /usr/lib/libstdc++.so.6: no version information available (required by node)
node: /usr/lib/libstdc++.so.6: no version information available (required by node)
node: /usr/lib/libstdc++.so.6: no version information available (required by node)
node: /usr/lib/libstdc++.so.6: no version information available (required by node)
v14.16.1

Umm, it kind of works? With a bunch of warnings.. still investigating, but here if anyone has pointers

markhughes commented 3 years ago

I've managed to compile and run a next.js project with it.

The REPL seems to work fine, with some warnings of course

# node
node: /usr/lib/libstdc++.so.6: no version information available (required by node)
node: /usr/lib/libstdc++.so.6: no version information available (required by node)
node: /usr/lib/libstdc++.so.6: no version information available (required by node)
node: /usr/lib/libstdc++.so.6: no version information available (required by node)
node: /usr/lib/libstdc++.so.6: no version information available (required by node)
node: /usr/lib/libstdc++.so.6: no version information available (required by node)
node: /usr/lib/libstdc++.so.6: no version information available (required by node)
node: /usr/lib/libstdc++.so.6: no version information available (required by node)
Welcome to Node.js v14.16.1.
Type ".help" for more information.
> console.log('it seems ok?')
it seems ok?
gligoran commented 3 years ago

Hi!

We're switching from nvm to volta in our team to better handle versions or both node and npm for all developers. It's been a great experience so far, but I as the initiator and our devops engineer were talking about using it in our CI pipelines. That would make it much easier to upgrade node and keep the version of npm we want in those environments.

I tried the approach @markhughes took, but not all npm packages seem to install OK for me this way.

Is this being considered? If so, is there a possible timeline when this would be possible?

Cheers and keep up the great work 👍

charlespierce commented 3 years ago

@gligoran We haven't really investigated too much what it would take to create a statically-linked binary. Given the work that was done up-thread, it seems like it may be fairly straightforward to get Volta itself working in that environment. We'd be happy to accept a PR to add that to our CI / Release matrix so that there are binaries available.

One other concern I have is that you're having issues with npm packages and @markhughes was seeing warnings about libstdc++. I don't know if Node provides pre-built binaries that work on Alpine, so it may be the case that in those environments you need to have Node compiled from source. Volta, unfortunately, doesn't support that at the moment (and it would be a much larger change than the above).

gligoran commented 3 years ago

I don't know if Node provides pre-built binaries that work on Alpine, so it may be the case that in those environments you need to have Node compiled from source. Volta, unfortunately, doesn't support that at the moment (and it would be a much larger change than the above).

I think you might be right. I'm not too knowledgeable about libstdc++ and compilations from source and such, but I think you might be right. Comparing official node docker images for Ubuntu (buster) and Alpine 3.13, the first downloads prebuilt binaries and the other downloads the source and (I presume) compiles it. I'm also not familiar enough with all of this to know if the built binaries could be extracted from these images, stored somewhere and then used by volta to download.

markhughes commented 3 years ago

Honestly, after weeks of research it was just easier to not use Alpine. Sure, it's a lot smaller which is great. However lots of things just.. break.

I don't recall what, but I ran into further issues with node-gyp stuff. The hassle was just not worth it. I started again with a Debian image and was all set in 15 minutes.

lynsei commented 2 years ago

I'd recommend using the GLibC variant.