Skip to content
This repository has been archived by the owner on Jun 18, 2019. It is now read-only.

Uses Dockerfile for building Debian packages #87

Merged
merged 11 commits into from
Feb 23, 2018
Merged

Uses Dockerfile for building Debian packages #87

merged 11 commits into from
Feb 23, 2018

Conversation

conorsch
Copy link
Contributor

@conorsch conorsch commented Feb 8, 2018

Status

Work in progress.

Description of Changes

Partial progress toward #75.

Ran into a problem with PaX flags on some of the binaries. Node itself is handled, but inside the homedir, other binaries are created at app-build time that don't exist at container build time.

Should work as-is for non-grsecurity-patched kernels, and presumably on Mac hosts, as well.

Did not excise the Ansible and Vagrant logic yet, but that should happen once we finalize the container config.

Testing

Run make build and confirm the Debian packages are created cleanly.

Conor Schaefer added 4 commits February 8, 2018 13:07
Intended to build the "sunder-build" image, which will be used for
creating the Sunder Linux Debian packages. Will be set as a dependency
of the "build" target in the Makefile.
The "sunder-build" image contains the necessary tooling for kicking off
a build of the Sunder Electron app, creating artifacts in the form of
Debian packages.

The apt package installation logic, pulling in the dependencies, was
ported from the existing Ansible config. The `npm` build commands will
be placed in an adjacent script, since running those requires the
application code from the git repo to be mounted inside the container,
which will happen as a container "run" action, not "build" action.
Not folding this logic into the Dockerfile build info, since it requires
the application code to be mounted inside the container. The volume
requirement mandates that the `npm` commands in the build script be run
as a container "run" action, not as part of the container "build"
action.
Building using containers now, which should make it far easier for new
contributors to get started using the repo.
@conorsch
Copy link
Contributor Author

conorsch commented Feb 8, 2018

@msheiny More eyes here would be appreciated. Typical grsecurity-related pain points for mmap executables. See what you can do to drag this over the finish line.

@garrettr
Copy link
Contributor

garrettr commented Feb 9, 2018

@conorsch I have a WIP local branch (sorry, should've said something I guess) for this issue. I'll see if I can merge them.

@msheiny
Copy link
Contributor

msheiny commented Feb 9, 2018

k - keep me posted @garrettr if i can help. ive done a lot of fire-fighting with this issue in other Docker repos. Something having to do with the extended file ACL attributes not sticking around after the image is created. To get around it sometimes I'll chown the binary in question to the USER pegged to start the docker container and lay down the pax flags in the entrypoint script.

@@ -0,0 +1,31 @@
ARG NODE_VERSION=8.9.4
FROM node:$NODE_VERSION
Copy link
Contributor

Choose a reason for hiding this comment

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

Most of what this Dockerfile is doing is implementing the Linux instructions from the electron-builder documentation. What do you think about basing this docker image on one of the electronuserland/builder base images, e.g. FROM electronuserland/builder:8 for Node 8, instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ha, should have checked for an electron-specific base image! Yes, I don't mind switching to that if it keeps us lean. @msheiny?

Copy link
Contributor

Choose a reason for hiding this comment

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

❤️

Copy link
Contributor

Choose a reason for hiding this comment

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

hey @garrettr what are your thoughts on yarn? is it a "drop-in" replacement for npm? i am reading into that electronuserland builder tooling around their docker images.. they are 💩 'ing on npm every chance they get and have yarn in all the examples.


icns2png --extract --output "${SUNDER_CODE}/build/icons/" "${SUNDER_CODE}/build/icon.icns"
npm install
npm rebuild
Copy link
Contributor

Choose a reason for hiding this comment

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

Pretty sure you don't want to call npm rebuild anymore, it will actually break things because it will rebuild native module for the system's version of Node rather than Electron's version of Node. The order of events is:

  1. npm install builds native modules for system Node by default
  2. There is a postinstall hook in package.json that runs electron-builder install-app-deps, which takes care of rebuilding native modules against Electron's version of Node.

I'm pretty sure calling npm rebuild at this point will do the wrong thing, e.g. similar to how it was causing breakage on CircleCI that I fixed in 960dc2b.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The npm rebuild step was lifted verbatim from the vagrant config logic, so glad we're refreshing all of this. Seems like using an electron-specific builder image would simplify this logic, as well.

Copy link
Contributor

Choose a reason for hiding this comment

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

Honestly the hardest thing about returning to work on this was grokking all of the interactions between native modules and the rest of our code/dependencies/NPM/etc. 😓

fi

icns2png --extract --output "${SUNDER_CODE}/build/icons/" "${SUNDER_CODE}/build/icon.icns"
npm install
Copy link
Contributor

Choose a reason for hiding this comment

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

I suggest we npm install in the Dockerfile. It is a time-consuming step and in general I would expect the Sunder code to change more frequently than its underlying dependencies, so it will probably be worthwhile for Docker to cache the results of npm install in a layer.

References:

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes! npm install downloads a mammoth amount of dependencies, so very happy to cache that.

Makefile Outdated
docker build . -t sunder-build

build: docker-build ## Builds Sunder Debian packages for Linux.
docker run -v "$(PWD):/sunder" \
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't recommend bind mounting the entire code directory in the container. There is at least one serious problem with it, which I encountered while working on my own branch to implement Docker builds: node_modules cannot be shared between the host and container if the host and container are not running the same OS/arch (e.g. my macOS development host vs. a Linux build container), due to our project's use of native modules.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Blacklisting dirs via .dockerignore may be a sane approach here, to ensure that e.g. node_modules aren't included.

Copy link
Contributor

Choose a reason for hiding this comment

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

the ignore file only works with context during build time.. not with volume mounting unfortunately. Realistically we should have a docker container for node instead of asking devs to run raw commands but thats another scope. So I say we do COPY in docker build with the ignore logic to get around this... i tried a couple other solutions but havent found a work-around yet.

someone suggested just running -v /sunder/node_modules which mounts a blank directory there but its root owned :|

Copy link
Contributor

Choose a reason for hiding this comment

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

@msheiny I'd recommend COPYing the source into the container, in which case .dockerignore will work for you. I think the only directory you should need to bind mount is the directory where the build output ends up.

@garrettr
Copy link
Contributor

@conorsch @msheiny Check out the comments I just wrote, describing my concerns with this approach so far. Some of them may be controversial, so I'm interested in your feedback. I will attempt to branch from this PR and fix the described issues myself, unless one of you beats me to it (I need to finish the remaining open documentation issues first).

@conorsch
Copy link
Contributor Author

@garrettr Great comments throughout! Largely I totally agree. @msheiny will take a crack at this and try to shore up what I got started.

Previous logic did not take into account a condition where a user wants
to run the container with a volume mapped to a uid which doesnt already
exist in the container. Now we are explicitly setting the `node` user to
match the builder's user id.

Also introduce some logic to correct volume mounting permissions from a
named volume mounted over-top of node_modules
A few changes here:

* Trimmed down docker apt dependencies, purge apt archive packages
* Utilize named volume in makefile to ensure a user's node_modules
folder gets ignored. This could be problematic for instance if a user
built locally with npm on Mac and then tries to use that same folder to
build under the docker env.
* Fix a weird scenario with a ruby binary getting grsec mprotect denials
during the build process. The only way I could figure out how to fix was
to run once, re-flag file, run again. I'm sure theres a better way but I
timeboxed myself.
Cleaning up by labels is much easier maintanence-wise. So in this
commit, we add the label metadata to the images and provide a makefile
target to ease in clean-up. Note - this doesnt clean containers. Thats
what `docker container prune` is for.
@msheiny
Copy link
Contributor

msheiny commented Feb 22, 2018

Hey @garrettr / @conorsch -- i made a number of changes here that I hope keeps all happy, a few notes:

  • the electron container you referenced replaces yarn with npm so it didnt seem like a good replacement at this time. I didn't want to get in the weeds of having to debug a whole new tool in this PR. Though all the kewl kids are talking about yarn vs. npm - I have no dog in the fight. just reporting the news..
  • the node_modules issue of mounting an OSX based folder into a linux container -- good call on that. I got around that issue by creating a named volume and then mounting that over-top the mapped local volume.
  • moving npm install works if we do COPY of source but not when we do volume mounting at run-time. with my new named volume logic though.. the node_modules folder will stick around in docker space so on subsequent re-runs the npm install will be relatively short.

Since I made a slew of changes I can no longer stamp this as good to go.. so I'll back off to address any comments either of you have.

PS - I miss you @garrettr ❤️

@msheiny
Copy link
Contributor

msheiny commented Feb 22, 2018

@conorsch corrected me --> replaces npm with yarn

@msheiny
Copy link
Contributor

msheiny commented Feb 22, 2018

whoopsss clarification.. @conorsch pointed out i could have edited my original comment instead of making a new comment. Now I've just made 2 un-necessary comments :|

@conorsch
Copy link
Contributor Author

@msheiny These changes look great! Taking them for a spin now.

Noticed a few dangling references to Ansible (e.g. requirements.txt, Makefile)—will clean those up after testing locally.

Didn't originally realize I can purge containers by filters as well!
Cool. So I expanded the clean-up logic a bit to also clean containers
and delete the named volume.
@msheiny
Copy link
Contributor

msheiny commented Feb 22, 2018

Oh by the way... I also notice changes with package-lock.json now... should i be committing that change in this PR? This might be one loose end with this new volume mounting logic

@conorsch
Copy link
Contributor Author

I also notice changes with package-lock.json now.

Good call, @msheiny. I see changes as well, and worse, I'm seeing two package-lock.json files changing after a container-based deb package build:

$ git diff --name-status
M       app/package-lock.json
M       package-lock.json

Culls "ansible" from the list of Python requirements, and excises
associated Makefile target that ran Ansible commands.
@conorsch
Copy link
Contributor Author

Drat, we still have work to do. Building and then installing on Debian Stretch shows a blank window when running the app:

sunder-blank-window

@msheiny
Copy link
Contributor

msheiny commented Feb 22, 2018

uggghh thats weird -- i got it built and working on my box :(

@conorsch
Copy link
Contributor Author

Will keep trying throughout the day... I made sure to run make clean prior to make build.

@conorsch
Copy link
Contributor Author

At @msheiny's encouragement, I reran make clean && make build several times. Each time produced a working deb package for me. LGTM!

@conorsch
Copy link
Contributor Author

Hmm, because I technically opened this PR, I cannot formally approve it for merge. I hereby approve @msheiny's changes, without which the container story wouldn't work at all. @msheiny, can you rubberstamp here if you agree?

Copy link
Contributor

@msheiny msheiny left a comment

Choose a reason for hiding this comment

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

Approving my own changes.. based off Conor's given approval 👍

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants