Aldebaran

人生最棒的感觉,就是你做到别人说你做不到的事。

0%

生产环境下使用cnpm搭建私有npm服务

指原莉乃

为什么需要私有npm

官方的 npm 可以说是最大的 JavaScript 模块仓库,大约有 60 多万个开源的 JavaScript 模块。那为什么我们还需要一个私有 npm 仓库呢?

总结起来,有以下几点原因:

保证 npm 服务的快速、稳定。由于国内网络环境的原因,从官方 npm 上安装模块依赖时,可能需要花费很长的时间。在部署私有 npm 后,可以把经过审核的 npm 模块加入到私有仓库,这样在开发环境和生产环境中就可以对模块进行快速安装了。另外还能避免类似 left-pad 事件的发生1。
发布私有 npm 模块。官方 npm 上的模块全部是开源的,然而在实际开发过程中,我们需

方案

最终选择的是cnpmjs,因为sinopia虽然有web权限控制,但是其项目本身截至(2018-7-16 18:2:29)有三年未有更新;verdaccio是sinopia的fork.

cnpm简介

CNPM 是一个Nodejs的库,致力于打造私有的 NPM 注册服务。当然,除了私有库功能以外,CNPM官网 (http://cnpmjs.org/) 还提供了NPM同步的服务。

CNPM官方发布的架构图:

00

从CNPM的架构图中,我们可以看出CNPM是对NPM做的镜像服务,CNPM会定期同步NPM的资源库,同时CNPM支持发布私有的库,这样就非常方便地集成了公有库和私有库,对于公司内部的开发者来说,基本感觉不到两种库的区别。

另外,我们使用NPM下载依赖包时,经常性地会遇到一些包下载失败的情况,主要原因了NPM的注册服务器在国外,国内的网络环境访问国外的IP并不是太好。所以,直接配置到国内的NPM镜像,可以减少NPM下载出错机会。

安装

  • 最低要求

    • NodeJS >= 4.3.1
    • Databases: only required one type
      • sqlite3 >= 3.0.2, we use sqlite3 by default
      • MySQL >= 0.5.0, include mysqld and mysql cli. I test on [email protected] and 5.7
      • MariaDB
      • PostgreSQL
    • Python 2.7
    • 磁盘尽量大
  • MySQL

    ## 这里没有优化参数,大并发的需求,因此不选择用编译安装
    ## 以ubuntu为例
    $ cd /usr/local/src
    $ wget https://repo.mysql.com//mysql-apt-config_0.8.10-1_all.deb
    $ apt-get update
    $ apt-get install mysql-server
  • NodeJS

    $ cd /usr/local/src
    $ wget https://nodejs.org/dist/v8.11.3/node-v8.11.3-linux-x64.tar.xz
    $ tar xf node-v8.11.3-linux-x64.tar.xz
    $ mv node-v8.11.3-linux-x64 /usr/local
    $ ln -s /usr/local/node-v8.11.3-linux-x64 /usr/local/node
    $ ln -s /usr/local/node/bin/npm /usr/local/bin/npm
    $ ln -s /usr/local/node/bin/node /usr/local/bin/node
    $ ln -s /usr/local/node/bin/npx /usr/local/bin/npx
  • 代码拉取

    $ apt-get install python sqlite3
    
    $ mkdir -p /data/wwwroot && cd /data/wwwroot
    $ git clone https://github.com/cnpm/cnpmjs.org.git
    $ cd cnpmjs.org
    ## 最新的(2018-7-16 17:54:37)3.x不稳定,建议暂时用2.x
    $ git checkout remotes/origin/2.x
    $ git branch
    
    $ sudo npm install
    ## 可选: 国内下载如果过慢,开源指定源下载
    $ sudo npm install --registry=https://registry.npm.taobao.org
    ## 可选: 如果用root用户直接运行npm install,那么需要加入--unsafe-perm参数)
    $ npm install --registry=https://registry.npm.taobao.org --unsafe-perm

    01

  • MySQL创建数据库和数据库权限

    ## 新建数据库名
    mysql> CREATE DATABASE IF NOT EXISTS cnpmjs_dev DEFAULT CHARSET utf8 COLLATE utf8_general_ci;
    
    ## 新建用户
    mysql> GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER, CREATE TEMPORARY TABLES, CREATE VIEW, SHOW VIEW ON cnpmjs_dev.* TO 'cnpmjs_root'@'192.168.%.%' IDENTIFIED BY 'conDH55ds9n1p11DH55d';
    mysql> GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER, CREATE TEMPORARY TABLES, CREATE VIEW, SHOW VIEW ON cnpmjs_dev.* TO 'cnpmjs_root'@'localhost' IDENTIFIED BY 'conDH55ds9n1p11DH55d';
    mysql> flush privileges;
    
    ## 导入建表文件
    mysql> source /data/wwwroot/cnpmjs.org/docs/db.sql;
  • 当前使用的配置文件(有删改)

    ...
    var dataDir = path.join('/data/download/.cnpmjs.org');
    ...
      registryPort: 7001,
      webPort: 7002,
      bindingHost:'192.168.99.131', // only binding on 127.0.0.1 for local access
    ...
      // enable gzip response or not
      // enableCompress:是否开启gzip压缩支持,推荐为true
      enableCompress: true,
    
      // default system admins
      admins: {
        // name: email
        ccqq: '[email protected]',
        fengmk2: '[email protected]',
        admin: '[email protected]',
        dead_horse: '[email protected]',
      },
    ...
      database: {
        db: 'cnpmjs_dev',
        username: 'cnpmjs_root',
        password: 'conDH55ds9n1p11DH55d',
    
        // the sql dialect of the database
        // - currently supported: 'mysql', 'sqlite', 'postgres', 'mariadb'
        dialect: 'mysql',
    
        // custom host; default: 127.0.0.1
        host: '127.0.0.1',
    
        // custom port; default: 3306
        port: 3306,
    
        sessionSecret: '37376.com cnpmjs.org session secret',
    ...
      // enable private mode or not
      // private mode: only admins can publish, other users just can sync package from source npm
      // public mode: all users can publish
      // “none”:永不同步,只管理私有用户上传的包,其他源包会直接从源站获取;
      // “exist”:定时同步已经存在于数据库的包;
      // “all”:定时同步所有源站的包;
      enablePrivate: true,
    
      // registry scopes, if don't set, means do not support scopes
      //也就是在 install 的时候遇到含有 scope 的包就会去私有npm下载包 如:@cnpm/demo ,公共的 npm 会去 sourceNpmRegistry: 'https://registry.npm.taobao.org', 下载包 。
      // scopes: [ '@cnpm', '@cnpmtest', '@cnpm-test' ],
      scopes: [ '@cnpm', '@cnpmtest', '@cnpm-test', '@37376test', '@37376demo', '@37376' ],
    ...
      // upstream registry is base on cnpm/cnpmjs.org or not
      // if your upstream is official npm registry, please turn it off
      sourceNpmRegistryIsCNpm: true,
    
      // if install return 404, try to sync from source registry
      syncByInstall: true,
    
      // sync mode select
      // none: do not sync any module, proxy all public modules from sourceNpmRegistry
      // exist: only sync exist modules
      // all: sync all modules
      syncModel: 'exist', // 'none', 'all', 'exist'
    ...
      // sync devDependencies or not, default is false
      syncDevDependencies: true,
      // try to remove all deleted versions from original registry
      syncDeletedVersions: true,
    ...
    };
  • 启动

    $ node start
    
    or
    
    $ nohup node /data/wwwroot/cnpmjs.org/dispatch.js > /data/download/.cnpmjs.org/logs/nodejs_stdout.log 2>&1 &

使用cnpm

下载

如果私有库没有对应的库,cnpm会自动同步到NPM 找到我们要下载的库和版本,先在CNPM中存一份,然后再传给客户端一份,运行原理和Maven的原理一样。

$ npm install request --registry=http://192.168.99.131:7001

上传

默认cnpm只有admin组才有权限上传。

# make sure you have login cnpm
$ cnpm publish