• NPM 2016.05.21

NPM은 Node Packaged Modules의 줄임말입니다. 단어 그대로 Node.js에서 사용하는 모듈을 패키지로 모아 놓은 곳입니다. 사용자가 사용하고자 하는 패키지들을 다운받을 수 있습니다. 여기서는 공통으로 사용하는 npm이 아닌 private하게 npm을 구축하는 것을 설명하겠습니다.

NPM 설치


docker에 NPM 이미지를 아래의 명령어를 실행시켜 다운 받습니다.

$ docker pull rnbwd/sinopia

빠른 시작

아래의 명령어로 이미지를 실행시킵니다.

$ docker run --name sinopia -d -p 4873:4873 rnbwd/sinopia

sinopia는 기본적으로 4873 포트를 사용하고 docker를 실행 시, http://vm주소:4873으로 실행화면을 확인 할 수 있습니다.

스토리지 및 캐시 마운트

$ docker run --name sinopia -d -p 4873:4873 -v <local-path-to-storage>:/sinopia/storage rnbwd/sinopia

컨테이너가 정상적으로 실행되었을 시, cache 폴더와 storage 폴더가 생성된 것을 볼 수 있습니다.

cache폴더에는 public npm으로 받은 패키지의 모든 버전 정보 json 파일과 가장 최신 버전 패키지 압축 파일이 존재합니다. ( 만약 public npm에서 패키지를 install 한 후, 해당 패키지를 publish하려 하면 에러가 나면서 cache 폴더에 해당 패키지가 추가됩니다.)

storage폴더는 private 실행 시 npm debug 로그들이 쌓이게 됩니다.

config.yaml 파일 마운트

$ docker run -v <local-path-to-config>:/sinopia/config.yaml -d -p 4873:4873 rnbwd/sinopia

private npm을 사용하기 위해서는 config.yaml을 수정할 필요가 있습니다. docker container에서는 편집기가 실행되지 않으므로 config.yaml 파일을 마운트해 호스트 os에서 편집을 하던지, 스토리지를 마운트해 config 파일을 스토리지로 복사 -> 편집 -> 원 위치로 덮어쓰기 와 같은 형식으로 수정해야합니다.

현재 virtual box - coreos (835.13.0) - docker (1.8.3) 에서 위와 같이 config.yaml을 마운트 하려하면 [8] System error: not a directory 같이 에러가 나옵니다. (원인 파악중)

config.yaml

config.yaml은 sinopia를 처음 실행하는데 참조하는 파일입니다. 

 # path to a directory with all packages storage: ./storage/cache web: # enable: true title: Private NPM # logo: logo.png # template: custom.hbs auth: htpasswd: file: ./storage/htpasswd # Maximum amount of users allowed to register, defaults to "+inf". # You can set this to -1 to disable registration. #max_users: 1000 # a list of other known repositories we can talk to uplinks: npmjs: url: https://registry.npmjs.org/ # amount of time to wait for repository to respond # before giving up and use the local cached copy #timeout: 30s # maximum time in which data is considered up to date # # default is 2 minutes, so server won't request the same data from # uplink if a similar request was made less than 2 minutes ago #maxage: 2m # if two subsequent requests fail, no further requests will be sent to # this uplink for five minutes #max_fails: 2 #fail_timeout: 5m # timeouts are defined in the same way as nginx, see: # http://wiki.nginx.org/ConfigNotation packages: # uncomment this for packages with "local-" prefix to be available # for admin only, it's a recommended way of handling private packages 'local-*': allow_access: admin allow_publish: admin # # you can override storage directory for a group of packages this way: storage: 'local_storage' '@*/*': # scoped packages allow_access: $all allow_publish: $all '*': # allow all users (including non-authenticated users) to read and # publish all packages # # you can specify usernames/groupnames (depending on your auth plugin) # and three keywords: "$all", "$anonymous", "$authenticated" allow_access: $all # allow all known users to publish packages # (anyone can register by default, remember?) allow_publish: $all # if package is not available locally, proxy requests to 'npmjs' registry proxy: npmjs ##################################################################### # Advanced settings ##################################################################### # if you use nginx with custom path, use this to override links #url_prefix: https://foo.com # you can specify listen address (or simply a port) listen: 0.0.0.0:4873 # type: file | stdout | stderr # level: trace | debug | info | http (default) | warn | error | fatal # # parameters for file: name is filename # {type: 'file', path: 'sinopia.log', level: 'debug'}, # # parameters for stdout and stderr: format: json | pretty # {type: 'stdout', format: 'pretty', level: 'debug'}, logs: - {type: stdout, format: pretty, level: http} #- {type: file, path: sinopia.log, level: info} # you can specify proxy used with all requests in wget-like manner here # (or set up ENV variables with the same name) #http_proxy: http://something.local/ #no_proxy: localhost,127.0.0.1 # maximum size of uploaded json document # increase it if you have "request entity too large" errors # max_body_size: 500mb # Workaround for countless npm bugs. Must have for npm <1.14.x, but expect # it to be turned off in future versions. If `true`, latest tag is ignored, # and the highest semver is placed instead. #ignore_latest_tag: false

여기서 가장 중요한 것은 packages 부분입니다.

'local-*' 은 sinopia에 배포할 패키지의 이름 맨 처음에 local- 이 들어간 것을 뜻합니다.

storage : loca_storage는 local-* 패키지명이 들어오면 local_storage폴더에 패키지압축 파일 및 정보를 담고 있는 json 파일을 저장하게 됩니다.


패키지 내의 proxy: npmjs는 만일 private npm 서버에 원하는 패키지가 없을 시, npmjs에 지정한 주소로 다이렉팅 됩니다. 위에서 npmjs를 public npm 주소로 등록이 되어있습니다.


패키지 업로드(배포)


배포에 앞서 다음과 같이 설정을 해줍니다.

$ docker exec -it sinopia /bin/bash   $ npm set registry http://설정주소:4873 ### 예 http://IP주소:4873

다음 유저를 추가해 줍니다.

$ npm adduser --registry http://IP주소:4873 User: admin Password: admin Email: (this IS public): 이메일.com


등록한 계정으로 npm 로그인을 해줍니다.

$ npm login
User: admin
Password: admin
Email: (this IS public): 이메일.com

현재 확인해 본 결과, 가입을 하지 않고 바로 로그인으로 아이디를 생성할 수 있습니다.


여기서는 public npm에서 foo라는 패키지를 받고, 해당 패키지명을 변경한 후 private npm에 올리는 것으로 가정하겠습니다.

다음 업로드(배포)할 패키지의 package.json 파일을 수정합니다. (컨테이너 내의 sinopia/node_modules/foo)

 { "author": { "name": "AJ ONeal", "email": "coolaj86@gmail.com", "url": "http://coolaj86.info" }, "name": "local-foo", "description": "A test module with no `main`, `lib`, or `dependencies` specified", "version": "1.0.0", "repository": { "type": "git", "url": "git://github.com/coolaj86/node-pakman.git" }, "engines": { "node": ">= v0.2" }, "_npmUser": { "name": "coolaj86", "email": "coolaj86@gmail.com" }, "_id": "foo@1.0.0", "dependencies": {}, "devDependencies": {}, "_engineSupported": true, "_npmVersion": "1.0.101", "_nodeVersion": "v0.4.8", "_defaultsLoaded": true, "dist": { "shasum": "943e0ec03df00ebeb6273a5b94b916ba54b47581", "tarball": "http://registry.npmjs.org/foo/-/foo-1.0.0.tgz" }, ## 해당부분추가 "publishConfig": { "registry": "http://IP주소:4873/" },  ##해당 부분 추가 "maintainers": [ { "name": "coolaj86", "email": "coolaj86@gmail.com" } ], "directories": {}, "_shasum": "943e0ec03df00ebeb6273a5b94b916ba54b47581", "_resolved": "https://registry.npmjs.org/foo/-/foo-1.0.0.tgz", "_from": "foo@*" }

public npm에서 받았기 때문에 foo라는 패키지 이름 그대로 publish 할 시, 에러가 나면서 cache에 저장이 됩니다. (이미 public 으로 받았기 때문)

따라서 local-foo라고 이름을 변경을 합니다. 또한 publish에 필요한 설정을 

"publishConfig": {
"registry": "http://private npm 설정주소:4873/"
},

를 추가해 줍니다.


컨테이너에서 파일 경로를 아래와 같이 이동한 다음, publish를 실행합니다.

$ cd /sinopia/node_modules/foo
$npm publish

publish는 해당 패키지의 package.json을 읽고 실행하기 때문에 package.json 파일이 있는 폴더로 이동해서 진행합니다.

만약 똑같은 이름으로 이미 private npm 서버에 올라가 있거나, public npm으로 받은 패키지의 이름을 변경하지 않고 바로 올렸을 경우 다음과 같은 에러가 나옵니다.

npm ERR! Linux 4.2.2-coreos-r2
npm ERR! argv "node" "/usr/local/bin/npm" "publish"
npm ERR! node v0.10.40
npm ERR! npm  v2.14.5
npm ERR! code EPUBLISHCONFLICT
npm ERR! publish fail Cannot publish over existing version.
npm ERR! publish fail Update the 'version' field in package.json and try again.
npm ERR! publish fail
npm ERR! publish fail To automatically increment version numbers, see:
npm ERR! publish fail     npm help version
npm ERR! Please include the following file with any support request:
npm ERR!     /sinopia/node_modules/foo/npm-debug.log

해당 에러가 나지 않았을 시, http:// private npm 주소:4873 서버에서 확인할 수 있습니다.

외부에서 private NPM 패키지 다운로드


다음과 같은 방식으로 다운로드를 받을 수 있습니다.

$ npm install 패키지명 --registry private npm 주소 예시 $ npm install local-foo --registry http://ip주소:4873   또는 $ npm set registry private npm 주소 $ npm install 패키지명 예시 $ npm set registry http://ip주소:4873 $ npm get registry http://ip주소:4873/ # npm 패키지 다운로드 받고자 하는 주소 변경 $ npm install local-foo

다른 사용자가 받고자 하는 패키지가 private npm 서버에 있을 경우, private npm 서버에서 내려받습니다.

만약 없을 시에는 private npm 서버의 config.yaml에 정해 놓은 것 처럼 public npm서버에 연결이 되어 내려받게 됩니다.

  • 사용자가 원하는 패키지 -> private npm 서버에 없음 -> public npm 서버에서 내려받음 -> private npm 서버 캐시에 저장 -> 사용자 서버에서 다운로드

sinopia github 저장소


sinopia에 대한 더 많은 정보는 아래 주소에서 확인할 수 있습니다.

docker 이미지 설명: https://hub.docker.com/r/rnbwd/sinopia/

sinopia 패키지 설명: https://github.com/RnbWd/sinopia

'저장소 > NPM' 카테고리의 다른 글

NPM  (0) 2016.05.21

+ Recent posts