NPM 사설 저장소 만들기

node 는 다양한 기능을 패키지 형태로 제공하는데 이를 통해 필요한 기능을 쉽게 추가하여 프로그램을 개발할 수 있다. 뿐만 아니라 npm 도구를 이용해서 최신 업데이트 된 기능을 쉽게 받아올 수 있다. 시스템 환경이 빠르게 변화하고 있고 프로그램이 정상적으로 동작하게 하기 위해서 기능을 최신으로 유지할 필요가 있다. 따라서 프로그램을 제공할 때 최신으로 업데이트 되도록 구성하는 것이 중요하다. 이런 상황은 운영 때만이 아니라 단기간의 프로젝트 중에도 발생할 수 있다. 어느 개발자가 작성한 코드는 여러 개발자들에 의해 사용되어질 수 있는데 이는 중복 개발도 막을 수 있고 따라서 생산성을 높여 개발 기간을 단축할 수 있기 때문이다. 이런 상황에서 공용되는 코드의 변경은 이를 사용하는 많은 개발자들에게 의사소통과 재작업을 일으켜서 오히려 손해가 될 수 있다. 이를 방지하기 위해 내부 공용 패키지에 대해서도 npm 도구를 적용해서 개발할 수 있어야 하고 패키지 변경에 대한 영향도 검토를 위해 테스트 코드가 필요하다.

이 내용은 마크다운 형식으로 작성되었고 마크다운 문법에서 배울 수 있다.

사설 저장소

github에 패키지를 올려서 받을 수 있는 방법도 있지만 여러가지 이유(npmjs.org 서버 다운 등)로 npm의 공공 저장소를 이용하지 못하는 경우 내부 사설 저장소가 대안이 될 수 있으므로 여기서는 다루지 않을 것이다. 구성하기 위해 도입할 수 있는 솔루션은 여럿1 있지만 유료이기도 하여 초기 셋업된 조직의 경우 선택하기 부담스럽다. 무료 중에 많이 사용되는 것으로 찾아본 결과 세가지 방법이 있다.

  1. couchDB를 npm과 연동 시키는 방법
    이 방법은 데이터베이스 자체를 설치해야 하는 부담이 있고 단순히 공공 저장소의 복사본으로 존재하므로 언급하지 않겠다. 자세한 내용은 링크를 따라가서 참조하면 좋겠다.
  2. sinopia 를 npm을 통해서 설치하는 방법
    npm을 사용하므로 쉽게 설치할 수 있다. 별다른 설정도 필요없다. 그러나 불행히도 최신 node 버전으로 제공되지 않아 설치에 어려움이 있어 nvm을 통해 node의 예전 버전을 설치하고 sinopia를 설치 구동시켜보자.
  3. Nexus 서버를 이용하는 방법
    넥서스 서버는 자바, 닷넷, node 등을 다방면에 제공하므로 요즘 같이 다양한 플랫폼을 사용하는 팀에서는 운영하기 유용하다 할 수 있다. 기존의 npmjs.org 의 저장소를 대신(proxy)해서 사용할 수 있고 사설 저장소도 구비할 수 있다. 저장소에 사용자를 등록하고 작업하는 부분이 버전 3부터 제공이 되고 있어 완성본이 나오면 정리하도록 하자. 자세한 방법은 링크를 참조하면 된다.

저장소 설치

여러 개발자 컴퓨터에서 접속할 수 있도록 한대의 서버를 마련하고 여기에 저장소를 설치하려고 한다. 저장소 서버에서 작업할 내용을 보도록 하자.

nvm 설치

일반적으로 nodejs 를 설치하려면 공식 사이트 에서 다운로드 받을 수 있지만 여기서는 sinopia 가 동작할 수 있는 과거 버전의 설치가 필요하므로 node 버전 관리 프로그램 nvm 을 이용하고자 한다. 아래 명령으로 nvm을 설치하는 스크립트를 받을 수 있다. 이 스크립트는 사용자 로그인 시 자동으로 수행되는 스크립트 파일(.bashrc)에 포함되므로 다시 로그인을 해야 사용할 수 있다.

$ curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.31.0/install.sh | bash

다운로드가 완료되면 터미널을 재 접속하라는 메시지가 나온다. 터미널 창을 닫고 다시 접속한다.

$ nvm install 0.12.12
$ nvm use v0.12.12

sinopia 가 동작할 수 있는 버전의 node 를 설치한다. 그리고 해당 버전으로 node 가 동작하도록 지정한다.

$ node -v
v0.12.12

실행되는 node 버전이 같음을 알 수 있다. 이제 node의 npm 을 이용해서 sinopia 를 설치해야 하는데 설치 과정 중, 소스코드를 실행 파일로 만드는 과정이 필요할 수 있다. 이에 필요한 도구를 먼저 설치한다.

$ sudo yum install -y gcc-c++ make

소스코드는 보통 c, c++ 언어로 작성되며 이를 실행 파일로 만드는 도구가 리눅스에서 gcc 라는 것이 있다. 이를 다운받아 실행할 수 있도록 한다.

sinopia 설치

sinopia가 동작 가능한 node 최종 버전이 0.12 이기 때문에 일반적인 node 설치 방법과 다르게 nvm 을 이용해서 해당 버전을 설치하였다. 이제 node 에서 제공하는 npm 이라는 도구를 이용해 sinopia 를 설치할 수 있다.

$ npm install -g sinopia

-g 선택으로 sinopia를 어디에서도 실행 가능하도록 설치한다.

$ sinopia
 warn  --- config file  - /home/admin/sinopia/config.yaml
 warn  --- http address - http://localhost:4873/
 ^C

sinopia를 실행한다. 접속할 수 있는 http 주소가 나타난다. 실행됨을 확인하고 control + c 를 눌러 종료한다. 출력에서 볼 수 있듯이 config.yaml 이 sinopia 의 설정 파일이다. 이 안의 설정을 바꾸어 자신의 환경에 적절하게 조정하자.

맨 처음으로 관리자 정보를 등록하도록 하자. 아래와 같이 node 함수를 사용하여 ‘password’ 라는 관리자 비밀번호를 암호화 한다.

$ cd sinopia
$ node
> crypto.createHash('sha1').update('password').digest('hex')
> 5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8'
> .exit
$ cd sinopia
$ vi config.yaml

비밀번호의 암호화를 마치고 .exit 명령으로 node 의 실행을 중단한다. 출력된 16진수 문자열을 복사한다. 사용이 익숙한 (vi 같은)편집기를 사용하여 설정 파일 config.yaml 을 열어서 아래와 같이 고친다. 아래 항목이 없다면 파일 맨 끝에 추가한다.

# a list of users
users:
  admin:
    # crypto.createHash('sha1').update(pass).digest('hex')
    password: 5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8

만일 node 로 코딩 지식이 있다면 아래 코드를 이용해서 여러명의 사용자를 한꺼번에 등록할 수 있다. 물론 userlist 에 정의된 사용자는 본인의 사용자들로 변경해서 붙여넣기를 해야 한다.

var fs = require('fs');
var crypto = require('crypto');
var sha512crypt = require('sha512crypt-node');
var salt = crypto.randomBytes(10).toString('base64');

var userlist = [ "user1:password1", "user2:password2" ];
var ht = fs.createWriteStream('./htpasswd', {flag:'a'});
userlist.forEach(function (val, index) {
  var idpwd = val.split(':');
  if (!idpwd || idpwd.length != 2) return;
  ht.write(idpwd[0]);
  var pwd = sha512crypt.sha512crypt(idpwd[1], salt);
  ht.write(':');
  ht.write(pwd);
  ht.write(':');
  ht.write('\n');
});
ht.end();

이 저장소에 개발자들이 접근할 수 있도록 주소가 필요하다. 기본 설정된 localhost 이름은 서버 안에서만 의미있는 이름이다. 서버 관리자에게 저장소 서버의 ip 주소에 도메인 이름을 지정하도록 요청하고 지정된 이름을 설정 파일 안에 기록해주어야 한다. config.yaml 파일 안에 아래 내용으로 수정 (없다면 추가) 한다.

# listen address and port
listen: npm-registry.company.com:4873

저장소 서버에서의 설정이 마무리 되었다. 이제 sinopia를 실행해 보자.

$ sinopia

저장소 사용하기

이제부터는 서버 작업을 마쳤으므로 자신의 컴퓨터에서 작업을 할 순서이다. 서버 설정 파일에 작성한 저장소 주소를 기억하는가? 자신의 컴퓨터에서 웹 브라우저를 실행하여 해당 주소를 입력해보자. 접속된 화면에서 우측 상단의 로그인 버튼을 클릭해서 서버에서 등록한 admin 계정으로 로그인 한다.

sinopia

저장소 주소 설정

sinopia 는 nmpjs.org 의 저장소와 연결하여 필요한 패키지를 전달해 준다. 만일 nmpjs.org 사이트가 닫혀있어도 이미 전에 다운 받은 적이 있던 패키지들은 sinopia에 담겨 있으므로 여전히 개발자들은 대신해서 패키지를 다운 받을 수 있다. 그렇다면 이제는 내 컴퓨터의 npm 은 지금 만들어논 사설 저장소를 사용하도록 설정해보자.

$ npm set registry "http://npm-registry.company.com:4873"
$ npm config get registry
http://npm-registry.company.com:4873

설정 전에는 .npmrc 파일은 없고 기본적으로 http://registry.npmjs.org 주소를 저장소로 사용하게 된다. npm set 명령으로 저장소 주소를 변경할 수 있고 npm config get 으로 저장소 주소를 확인할 수 있다. 이렇게 설정된 값은 홈 디렉토리 안에 .npmrc 파일 안에 아래와 같이 기록된다.

registry=http://npm-registry.company.com:4873

이제 서버에서 등록한 admin 계정으로 저장소에 로그인 해 보자.

$ npm login
Username: admin
Password:
Email: (this IS public) myid@company.com

비밀번호는 서버에서 암호화 이전에 지정한 단어를 기억해서 입력해야 한다. 메일 주소는 서버에서 체크하지 않으므로 그냥 자신의 주소를 입력한다. 아무 메시지가 나오지 않으면 정상적으로 로그인이 된 것이다. 기본 권한 설정에 따라서 패키지를 다운 받는 것은 로그인이 필요 없지만 (누구나 가능) 패키지를 배포하는 것은 인증된 사용자만이 가능하다.

sample 프로그램

간단한 node 프로그램을 개발하면서 사설 npm 저장소를 이용해보자. 먼저 프로그램 코드를 위치시킬 폴더 tester 폴더를 만들고 npm 을 이용해 폴더 구조를 만들자.

$ mkdir tester
$ cd tester
$ npm init
This utility will walk you through creating a package.json file.
...
save it as a dependency in the package.json file.

Press ^C at any time to quit.
name: (tester)
version: (1.0.0)
description: tester code for test of testee
entry point: (index.js)
test command:
git repository:
keywords: test
license: (ISC)
About to write to /Users/userid/tester/package.json:
{
  'name': 'tester',
  'version': '1.0.0',
  'description': 'tester code for test of testee',
  'main': 'index.js',
  'scripts': {
    'test': '...';
  },
  'keywords': [
    'test'
  ],
  'author': 'My Name <myid@company.com> (http://company.com)';,
  'license': 'ISC'
}

Is this ok? (yes)

초기화 과정 중에 질문이 많지만 그냥 enter 키만 치고 넘어가도 되는 내용들이다. 이제 폴더 내에 필요한 파일들이 생겨져 있다. 초기화 과정의 질문에도 나오지만 실행할 프로그램을 만들어 보자. vi index.js 명령으로 실행 파일을 편집기로 연다. 그리고 아래 코드를 붙여 넣어보자.

var chalk = require('chalk');
console.log(chalk.red('Hello,'), chalk.blue('world.'));
console.log(chalk.yellow('Hello, world.'));

이 내용을 저장하고 편집기를 종료하면 간단하게 Hello, world. 를 출력하는 프로그램이(index.js) 생긴다. 이를 실행하기 위해 코드에 나온 것 같이 chalk 라는 패키지가 필요하다. 아래 명령으로 이전에 설정한 sinopia 저장소를 통해서 패키지를 현재 폴더에 설치하게 된다.

$ npm install --save chalk
tester@1.0.0 /Users/userid/tester
└─┬ chalk@1.1.3
  ├── ansi-styles@2.2.1
  ├── escape-string-regexp@1.0.5
  ├─┬ has-ansi@2.0.0
  │ └── ansi-regex@2.0.0
  ├── strip-ansi@3.0.1
  └── supports-color@2.0.0

npm WARN EPACKAGEJSON tester@1.0.0 No repository field.

실행을 하면 패키지가 다운 받는 과정이 나타나는데 이것은 sinopia 가 npmjs.org를 대신해서 정상적으로 동작하고 있음을 보여준다. 설치할 때, –save 옵션을 사용하므로 package.json 파일에 어떤 패키지들을 설치했는지 기록되게 되는데 나중에 한꺼번에 필요한 패키지를 npm install 명령 하나로 업데이트 할 수 있다. 이제 필요한 패키지도 설치가 됐으니 실행을 해보도록 하자.

$ node index.js
Hello, world.
Hello, world.

출력 결과는 앞 단어는 적색, 뒤는 청색 그리고 다음 줄은 노란색으로 나타난다.

패키지 등록하기

사설 저장소를 만든 근본 목적이 내가 만든 패키지를 공개된 곳이 아닌 우리 안에 두고 우리끼리 공유해서 사용하고 싶어서이다. 이제 간단한 패키지를 만들어 보고 사설 저장소에 저장해 보겠다. 우선 현재 tester 폴더에서 나와서 새로 testee 폴더를 만들자.

$ cd ..
$ mkdir testee
$ cd testee
$ npm init

작업의 순서는 tester 프로그램을 만들 때와 동일하다. 똑같이 편집기를 통해서 아래와 같은 내용으로 index.js 파일을 만들자.

var exports = module.exports = {
  hello: function () {
    return 'hello, testee.';
  }
}

hello 함수를 제공하는 객체를 반환하는 패키지이다. 우선 인증된 사용자 만이 패키지를 배포할 수 있으므로 npm login 을 하고 publish 명령으로 배포를 한다.

$ npm login
Username: admin
Password:
$ npm publish
+ testee@1.0.0

testee 라는 패키지가 정상적으로 사설 저장소에 배포가 되었다. 사설 저장소의 웹 페이지로 들어가 보면

\> testee v1.0.0

By:

test for publishing

라는 메시지가 나타난다. readme 파일등 세밀하게 관리할 필요가 있는데 여기서는 생략하겠다.

패키지 사용하기

이미 tester 예제 프로그램을 통해서 npmjs.org 로부터 정상적으로 패키지를 가져오는 것을 확인하였다. 이제 사설 저장소에서도 방금 배포한 testee 패키지도 정상적으로 받아 올 수 있는지 확인하도록 하자. 이전 tester 프로그램을 작성하던 tester 폴더로 다시 이동해서 아래 명령으로 testee 패키지를 받아보자.

$ npm install --save testee
tester@1.0.0 /Users/userid/tester
└── testee@1.0.0

npm WARN EPACKAGEJSON tester@1.0.0 No repository field.

tester 폴더에서 testee 패키지를 받아 설치된 것을 확인할 수 있다. 마찬가지로 package.json 파일에도 저장되어 있다. 이제 설치된 패키지 함수가 정상적으로 동작하는 지 확인하자. tester 폴더의 index.js 파일을 아래와 같이 수정하자.

var chalk = require('chalk');
var testee = require('testee'); // 추가
console.log(chalk.red('Hello,'), chalk.blue('world.'));
console.log(chalk.yellow(testee.hello())); // 변경

파일을 저장하고 node index.js 명령으로 실행해 보자.

$ node index.js
Hello, world.
hello, testee.

패키지의 함수에서 제공된 문자열이 정상적으로 출력되었다.

맺음말

npm 을 통해서 전 세계 개발자들의 기술을 공유할 수 있어 시스템 구축의 생산성이 비약적으로 높아졌다. 검색만 잠깐 하면 필요한 기능을 제공하는 패키지를 쉽게 찾을 수 있고 소스를 받아서 일일이 환경에 맞춰 빌드 작업하는 것도 사라졌다. 실제 기업에서 작업을 하게되면 공개 패키지로는 해결이 안되는 세밀한 작업들이 많은데 이 또한 기업 내에서 반복적으로 일어나는 것이 많아서 기능을 제대로 구분한다면 패키지로 만들어 재사용할 수 있는 것들이 많다. 추가적으로 생산성이 더욱 향상 될 수 있다는 것이다. 일관성이 적고 늘 변화무쌍한 조직도 있지만 노력에 따라 가능한 패키지들을 뽑아낼 수 있다고 생각된다. 물론 이런 도구를 사용하기 위한 프로세스도 잘 정리되어야 서로간에 불편함을 덜 수 있으니 일하는 방식에 대해서도 더 많이 고려해서 적합한 도구가 제공되어야겠다.

참고 사이트


  1. npm Private Packages 는 월 7달러, 

답글 남기기

아래 항목을 채우거나 오른쪽 아이콘 중 하나를 클릭하여 로그 인 하세요:

WordPress.com 로고

WordPress.com의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Google photo

Google의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Twitter 사진

Twitter의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Facebook 사진

Facebook의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

%s에 연결하는 중