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

yarn install fails inside a Docker Container with --userns-remap enabled #1750

Closed
lawliet89 opened this issue Nov 9, 2016 · 3 comments · Fixed by #2898
Closed

yarn install fails inside a Docker Container with --userns-remap enabled #1750

lawliet89 opened this issue Nov 9, 2016 · 3 comments · Fixed by #2898

Comments

@lawliet89
Copy link
Contributor

lawliet89 commented Nov 9, 2016

Do you want to request a feature or report a bug?

Bug

What is the current behavior?
Running yarn install in a Docker container with the daemon having --userns-remap enabled fails with the following:

  Error: https://registry.yarnpkg.com/immutable/-/immutable-3.8.1.tgz: EINVAL: invalid argument, chown '/root/.yarn-cache/npm-immutable-3.8.1/package.json'
      at Error (native)

If the current behavior is a bug, please provide the steps to reproduce.

Start the Docker daemon with --userns-remap enabled.

Then try to run or build a Docker image with yarn install:

# Inside the Docker container
$ id
uid=0(root) gid=0(root) groups=0(root)
$ strace -o strace.log -ff yarn install
$ tail yarn-error.log 
Trace: 
  Error: https://registry.yarnpkg.com/immutable/-/immutable-3.8.1.tgz: EINVAL: invalid argument, chown '/root/.yarn-cache/npm-immutable-3.8.1/package.json'
      at Error (native)
$ grep chown strace.log.*
strace.log.202:chown("/root/.yarn-cache/npm-bowser-1.4.6/package.json", 502, 20) = 0
strace.log.202:chown("/root/.yarn-cache/npm-bowser-1.4.6/.npmignore", 502, 20) = 0
strace.log.202:chown("/root/.yarn-cache/npm-alt-utils-1.0.0/package.json", 501, 20) = 0
strace.log.202:chown("/root/.yarn-cache/npm-immutable-3.8.1/package.json", 116435139, 1876110778) = -1 EINVAL (Invalid argument)
strace.log.202:chown("/root/.yarn-cache/npm-bowser-1.4.6/LICENSE", 502, 20) = 0
strace.log.202:chown("/root/.yarn-cache/npm-react-15.3.2/package.json", 616931727, 1876110778) = -1 EINVAL (Invalid argument)
strace.log.202:chown("/root/.yarn-cache/npm-alt-0.18.6/package.json", 502, 20) = 0
strace.log.202:chown("/root/.yarn-cache/npm-react-addons-css-transition-group-15.3.2/package.json", 616931727, 1876110778) = -1 EINVAL (Invalid argument)
strace.log.202:chown("/root/.yarn-cache/npm-numeral-1.5.3/package.json", 501, 20) = 0
strace.log.203:chown("/root/.yarn-cache/npm-alt-utils-1.0.0/lib/ActionListeners.js", 501, 20) = 0
strace.log.203:chown("/root/.yarn-cache/npm-alt-utils-1.0.0/lib", 501, 20) = 0
strace.log.204:chown("/root/.yarn-cache/npm-moment-2.15.1/package.json", 1000, 1000) = 0
strace.log.204:chown("/root/.yarn-cache/npm-react-addons-update-15.3.2/package.json", 616931727, 1876110778) = -1 EINVAL (Invalid argument)
strace.log.205:chown("/root/.yarn-cache/npm-bowser-1.4.6/README.md", 502, 20) = 0
strace.log.205:chown("/root/.yarn-cache/npm-alt-utils-1.0.0/.npmignore", 501, 20) = 0
strace.log.205:chown("/root/.yarn-cache/npm-classnames-2.2.5/package.json", 501, 20) = 0
strace.log.205:chown("/root/.yarn-cache/npm-lodash-4.16.4/package.json", 501, 20) = 0

I am running --userns-remap=teamcity:teamcity with the following information:

$ id teamcity
uid=1001(teamcity) gid=1001(teamcity) groups=1001(teamcity),999(docker)
$ cat /etc/subuid
ubuntu:100000:65536
teamcity:165536:65536
$ cat /etc/subgid
ubuntu:100000:65536
teamcity:165536:65536

What is the expected behavior?
Successful installation

I believe this is the same issue encountered in #1485, #918 and #869. If I do npm install, it installs successfully.

If I run the container with --userns=host, it runs successfully. So I can only conclude this issue is due to the Linux user namespace.

Please mention your node.js, yarn and operating system version.

$ node --version
v6.7.0
$ uname -a
Linux 2970f7786932 3.13.0-100-generic #147-Ubuntu SMP Tue Oct 18 16:48:51 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux

strace:

@ianmurrays
Copy link

Same issue here, happens with builds in CircleCI.

@lawliet89
Copy link
Contributor Author

lawliet89 commented Nov 11, 2016

Based on the giant UIDs/GIDs in the chown syscalls above, I thought it might be related to nodejs/node#8515 but upgrading to Node 7.x did not fix it.

I dug around for a bit and I found that Writer is being constructed with the large UID in props with the stacktrace below:

Trace: hmm
    at new Writer (/usr/share/yarn/node_modules/fstream/lib/writer.js:28:13)
    at DirWriter._process (/usr/share/yarn/node_modules/fstream/lib/dir-writer.js:142:36)
    at DirWriter.add (/usr/share/yarn/node_modules/fstream/lib/dir-writer.js:72:8)
    at Extract.<anonymous> (/usr/share/yarn/node_modules/fstream/lib/reader.js:227:22)
    at emitOne (events.js:101:20)
    at Extract.emit (events.js:188:7)
    at Extract.Parse._startEntry (/usr/share/yarn/node_modules/tar/lib/parse.js:268:8)
    at Extract.Parse._process (/usr/share/yarn/node_modules/tar/lib/parse.js:131:12)
    at BlockStream.<anonymous> (/usr/share/yarn/node_modules/tar/lib/parse.js:47:8)
    at emitOne (events.js:96:13)
{ parent: 
   DirWriter {
     domain: null,
     _events: 
      { ready: [Function],
        error: [Object],
        drain: [Object],
        close: [Object] },
     _eventsCount: 4,
     _maxListeners: undefined,
     type: 'Directory',
     props: 
      { path: '/root/.yarn-cache/npm-css-modules-require-hook-2.1.1',
        strip: 1,
        type: 'Directory',
        Directory: true,
        root: null,
        parent: null },
     depth: 0,
     clobber: true,
     parent: null,
     root: [Circular],
     path: '/root/.yarn-cache/npm-css-modules-require-hook-2.1.1',
     _path: '/root/.yarn-cache/npm-css-modules-require-hook-2.1.1',
     basename: 'npm-css-modules-require-hook-2.1.1',
     dirname: '/root/.yarn-cache',
     linkpath: null,
     size: undefined,
     readable: false,
     writable: true,
     _buffer: [],
     ready: true,
     filter: null,
     _old: 
      { dev: 33,
        mode: 16877,
        nlink: 2,
        uid: 0,
        gid: 0,
        rdev: 0,
        blksize: 4096,
        ino: 751,
        size: 4096,
        blocks: 8,
        atime: 2016-11-11T07:33:26.965Z,
        mtime: 2016-11-11T07:33:26.965Z,
        ctime: 2016-11-11T07:33:26.965Z,
        birthtime: 2016-11-11T07:33:26.965Z,
        Directory: true,
        type: 'Directory' },
     _madeDir: null,
     _processing: true },
  root: 
   DirWriter {
     domain: null,
     _events: 
      { ready: [Function],
        error: [Object],
        drain: [Object],
        close: [Object] },
     _eventsCount: 4,
     _maxListeners: undefined,
     type: 'Directory',
     props: 
      { path: '/root/.yarn-cache/npm-css-modules-require-hook-2.1.1',
        strip: 1,
        type: 'Directory',
        Directory: true,
        root: null,
        parent: null },
     depth: 0,
     clobber: true,
     parent: null,
     root: [Circular],
     path: '/root/.yarn-cache/npm-css-modules-require-hook-2.1.1',
     _path: '/root/.yarn-cache/npm-css-modules-require-hook-2.1.1',
     basename: 'npm-css-modules-require-hook-2.1.1',
     dirname: '/root/.yarn-cache',
     linkpath: null,
     size: undefined,
     readable: false,
     writable: true,
     _buffer: [],
     ready: true,
     filter: null,
     _old: 
      { dev: 33,
        mode: 16877,
        nlink: 2,
        uid: 0,
        gid: 0,
        rdev: 0,
        blksize: 4096,
        ino: 751,
        size: 4096,
        blocks: 8,
        atime: 2016-11-11T07:33:26.965Z,
        mtime: 2016-11-11T07:33:26.965Z,
        ctime: 2016-11-11T07:33:26.965Z,
        birthtime: 2016-11-11T07:33:26.965Z,
        Directory: true,
        type: 'Directory' },
     _madeDir: null,
     _processing: true },
  type: 'File',
  depth: 1,
  path: '/root/.yarn-cache/npm-css-modules-require-hook-2.1.1/package.json',
  filter: null,
  mode: 420,
  uid: 1673151026,
  gid: 593637566,
  size: 2453,
  mtime: 2016-02-22T13:28:27.000Z,
  cksum: 5973,
  linkpath: '',
  ustar: 'ustar\u0000',
  ustarver: '00',
  uname: '',
  gname: '',
  devmaj: 0,
  devmin: 0,
  fill: '',
  'NODETAR.depth': '1',
  'NODETAR.follow': 'false',
  'NODETAR.ignoreFiles.0': '.npmignore',
  'NODETAR.ignoreFiles.1': '.gitignore',
  'NODETAR.ignoreFiles.2': 'package.json',
  'NODETAR.type': 'File',
  dev: 16777220,
  nlink: 1,
  'NODETAR.blksize': '4096',
  ino: 58949408,
  'NODETAR.blocks': '8' }

This is my progress so far and I will update if I find out more

@lawliet89
Copy link
Contributor Author

lawliet89 commented Nov 14, 2016

Let us consider the tarball from https://registry.yarnpkg.com/react-select-plus/-/react-select-plus-1.0.0-rc.1.patch1.tgz

If we list the tar contents:

$ tar --numeric-owner -tvf react-select-plus-1.0.0-rc.1.patch1.tgz  
-rw-r--r-- 57095740/20    2386 2016-10-14 01:58 package/package.json
-rw-r--r-- 1348941372/20    39 2016-02-04 02:52 package/.npmignore
-rw-r--r-- 6764092/20    18621 2016-10-13 01:30 package/README.md
-rw-r--r-- 677852732/20   1074 2016-03-26 02:25 package/LICENSE
-rw-r--r-- 610743868/20    458 2016-06-23 01:05 package/wallaby.js
-rw-r--r-- 2691118652/20   549 2016-02-04 02:52 package/gulpfile.js
-rw-r--r-- 946288188/20 309165 2016-05-24 04:15 package/.publish/app.js
-rw-r--r-- 2556900924/20 60953 2016-05-24 04:15 package/.publish/bundle.js
-rw-r--r-- 476526140/20 685862 2016-05-24 04:15 package/.publish/common.js
-rw-r--r-- 6764092/20    63069 2016-05-24 04:15 package/.publish/standalone.js
-rw-r--r-- 2422683196/20 11223 2016-05-24 04:15 package/.publish/example.css
-rw-r--r-- 6764092/20     2948 2016-05-24 04:15 package/.publish/index.html
-rw-r--r-- 275199548/20   1406 2016-05-24 04:15 package/.publish/standalone.html
-rw-r--r-- 6764092/20       82 2016-02-04 02:52 package/.travis.yml
-rw-r--r-- 1348941372/20  1671 2016-04-05 00:38 package/CHANGES.md
-rw-r--r-- 4284954172/20  3233 2016-02-18 05:57 package/CONTRIBUTING.md
-rw-r--r-- 3630642748/20 28949 2016-10-13 01:30 package/HISTORY.md
-rw-r--r-- 6764092/20      528 2016-06-23 01:05 package/ISSUE_TEMPLATE.md
-rw-r--r-- 3496425020/20    63 2016-02-04 02:52 package/.eslintignore
-rw-r--r-- 6764092/20      789 2016-02-04 02:52 package/.eslintrc
-rw-r--r-- 4284954172/20 85632 2016-02-05 02:37 package/coverage/coverage.json
-rw-r--r-- 2556900924/20 15264 2016-02-05 02:37 package/coverage/lcov.info
-rw-r--r-- 6764092/20    84066 2016-10-14 01:55 package/dist/react-select-plus.js
-rw-r--r-- 1214723644/20 47306 2016-10-14 01:55 package/dist/react-select-plus.min.js
-rw-r--r-- 4284954172/20  9006 2016-10-14 01:55 package/dist/react-select-plus.css
-rw-r--r-- 2154247740/20  7096 2016-10-14 01:55 package/dist/react-select-plus.min.css
...
# snip

You can see that the UID for package/package.json stored in the tarball is 57095740. If we strace yarn, we can see that it is trying to chown the extracted file to this UID, which fails when the UID is outside of the subuid range of the user that Docker has mapped the container's root to.

The cause of this whole problem is this line of code. We are running as root in the container, but not really root because of the user namespace.

There have been many issues related to this (e.g. isaacs/node-tar#39 and npm/fstream#52 to list a few).

The workaround should do.

NPM seems to get around this by re-setting the UID/GID to the current user unless unsafe-params is set.

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

Successfully merging a pull request may close this issue.

3 participants