npm私服搭建與包發佈

需求與背景

需求

  • 公司開發環境與外網隔絕,須要搭建內網私有npm庫,確保私密性
  • 確保npm服務快速、穩定,減小開發人員和CI服務器的重複下載量並提升下載速度
  • 控制npm模塊質量和安全,對於下載、發佈npm包有對應的權限管理

當下流行的解決方案

  • 使用 Nexus 搭建 npm 私服

    Nexus倉庫管理平臺支持範圍普遍,可用於maven、npm等倉庫。目前Nexus Repository Manager更新到了3,查看官方文檔html

  • 使用 Sinopia 搭建 npm 私服

    Sinopia是一個零配置的私有的帶緩存功能的npm包管理工具。前端

搭建過程

使用Nexus

  • 下載解壓

    官方下載連接](help.sonatype.com/repomanager…),執行:java

    $ wget https://download.sonatype.com/nexus/3/latest-unix.tar.gz #下載
    $ sudo mv latest-unix.tar.gz /opt/nexus3.tar.gz #移動到 /opt 目錄
    $ sudo tar -xzvf nexus3.tar.gz #解壓
    複製代碼

    注意運行Nexus須要Java 8 運行時環境(JRE),請自行安裝。node

  • 建立運行用戶

    單首創建一個 nexus 用戶用來運行linux

    # 建立用戶、指定用戶目錄、受權
    $ sudo useradd -d /home/nexus -m nexus
    $ sudo chown -R nexus:nexus /home/nexus
    $ sudo chown -R nexus:nexus /opt/nexus-3.15.2-01
    $ sudo chown -R nexus:nexus /opt/sonatype-work/
    複製代碼

    修改運行用戶配置項:修改 /opt/nexus-3.15.2-01/bin 目錄下的配置文件nexus.rc爲 run_as_user="nexus"android

  • 運行

    修改端口指8073並開放iptables防火牆,對/opt/sonatype-work/nexus3/etc/nexus.properties文件進行修改:git

    # Jetty section 
    application-port=8073
    application-host=0.0.0.0                                                                 # nexus-args=${jetty.etc}/jetty.xml,${jetty.etc}/jetty-http.xml,${jetty.etc}/jetty-requestlog.xml 
    # nexus-context-path=/ # Nexus section # nexus-edition=nexus-pro-edition # nexus-features=\ # nexus-pro-feature 
    複製代碼

    啓動服務,如下爲nexus服務命令:github

    # 啓動 nexus 服務
    $ sudo service nexus start
    # 重啓 nexus 服務
    $ sudo service nexus restart
    # 中止 nexus 服務
    $ sudo service nexus stop
    # 查看 nexus 服務狀態
    $ sudo service nexus status 
    複製代碼

    查看日誌檢查服務狀態:docker

    $ tail -f /opt/sonatype-work/nexus3/log/nexus.log
    複製代碼

    至此,nexus 服務已搭建完畢!可以使用默認帳號admin/admin123 登陸ip:8073後對npm倉庫進行管理npm

  • 倉庫管理

    建立倉庫,npm 倉庫有三種,這三種咱們都須要建立

  1. npm(proxy) - 代理npm倉庫

    將公共 npm 服務器的資源代理緩存,減小重複下載,加快開發人員和CI服務器的下載速度。

    建立時需填寫Name(npm-external)和Remote Storage(公有庫地址,填寫官方或淘寶鏡像,https://registry.npmjs.org/)。

    該倉庫地址爲:http://ip:8073/repository/npm-external/

  2. npm(hosted) - 私有npm倉庫

    用於 上傳本身的npm包 以及第三方npm包。

    建立時只需填寫Name(npm-internal)。

    該倉庫地址爲:http://ip:8073/repository/npm-internal/

    請注意:發佈包時請將registry設爲該地址。

  3. npm(group) - npm倉庫組

    用於將多個內部或外部 npm 倉庫統一爲一個 npm倉庫。能夠新建一個npm倉庫組將 上面兩個剛剛建立的兩個 npm 倉庫都添加進去。這樣能夠經過這個 npm倉庫組,既能夠訪問 公有npm倉庫 又能夠訪問本身的 私有npm倉庫。

    建立時需填寫Name(npm-all),而後選擇須要添加到組裏的 其餘 npm 倉庫(npm-externalnpm-internal)。

    該倉庫地址爲:http://ip:8073/repository/npm-all/

    請注意:安裝包以及卸載包時請將registry設爲該地址。

  • 用戶管理

    將包發佈到nexus npm倉庫須要設置一下 Nexus Repository Manager 的權限。不然沒法登錄到咱們的私服。在Security->Realms欄目裏,將npm Bearer Token Realm 選入Active。

以後咱們須要在Security->Users欄目裏添加用戶,只有這樣添加的用戶才能夠發佈包。經測試,在客戶端使用 npm adduser 建立的用戶沒有發佈權限。

使用Sinopia

  • 服務器上安裝node

    Node 官網已經把 linux 下載版本更改成已編譯好的版本了,咱們能夠直接下載解壓後使用,下載連接

    咱們選擇node-v11.9.0-linux-x64.tar.gz這個版本:

    $ wget https://nodejs.org/dist/v11.9.0/node-v11.9.0-linux-x64.tar.gz   #下載
    $ tar xf node-v11.9.0-linux-x64.tar.gz       #解壓
    $ cd node-v11.9.0-linux-x64/                 #進入解壓目錄
    $ ./bin/node -v                              #執行node命令 查看版本
    v11.9.0
    複製代碼

    使用ln命令設置軟連接到/usr/local/bin目錄,/usr/local/bin是給用戶放置本身的可執行程序的地方:

    ln -s /usr/local/node-v11.9.0-linux-x64/bin/npm   /usr/local/bin/ 
    ln -s /usr/local/node-v11.9.0-linux-x64/bin/node   /usr/local/bin/
    複製代碼
  • 服務器上安裝Sinopia

    使用默認npmjs.org registry,在服務器上安裝sinopia:

    $ npm install -g sinopia
    $ sinopia                    
    -bash: sinopia: command not found     #測試sinopia命令,此時會報找不到命令
    複製代碼

    找不到命令,緣由在於環境變量沒設置,修改/etc/profile文件,在末尾添加如下內容:

    export NODE_HOME=/usr/local/node-v11.9.0-linux-x64  #Node所在路徑
    export PATH=$NODE_HOME/bin:$PATH
    複製代碼

    執行命令 source /etc/profile使生效,再次運行sinopia:

    $ Sinopia doesn't need superuser privileges. Don't run it under root.
     warn  --- config file  - /root/.config/sinopia/config.yaml
     warn  --- http address - http://localhost:4873/
    複製代碼

    修改iptables設置,開放4873端口:

    $ iptables -I INPUT 4 -p tcp -m state --state NEW -m tcp --dport 4873  -j ACCEPT        #容許 4873 端口
    $ service iptables save                         #保存 iptables 規則
    複製代碼

    【坑1】訪問虛擬機的npm倉庫地址被拒絕

    除了開放iptables的4873端口外,還須要在sinopia的配置文件末尾加上:

    listen: 0.0.0.0:4873
    複製代碼

    從新啓動

    $ Sinopia doesn't need superuser privileges. Don't run it under root.
     warn  --- config file  - /root/.config/sinopia/config.yaml
     warn  --- http address - http://0.0.0.0:4873/
    複製代碼

    這樣咱們就能經過本身虛擬機的ip:4873訪問了

配置文件在/root/.config/sinopia/config.yaml,相關配置字段意義在文件中都有註釋

  • 使用守護進程啓動(pm2)

​ 安裝:npm install -g pm2 啓動:pm2 start sinopia

  • 用戶管理

    配置文件中關於鑑權的默認配置爲:

    auth:
      htpasswd:
        file: ./htpasswd   //保存用戶的帳號密碼等信息
        # Maximum amount of users allowed to register, defaults to "+inf".
        # You can set this to -1 to disable registration.
        max_users: 1000  //默認爲1000,改成-1後,禁止註冊
    複製代碼

    添加用戶的方法:在客戶端終端運行 npm adduser --registry http://xxxxx:4873/ ,設置相應的用戶名、密碼、郵箱後便可登陸、發佈包。

    若是將配置項max_users設爲-1,表示禁用 npm adduser 命令來建立用戶,需手動在htpasswd文件中添加用戶信息來初始化用戶。

客戶端使用

使用 nrm 管理registry

$npm install -g nrm
 
$ nrm ls
* npm ---- https://registry.npmjs.org/
  cnpm --- http://r.cnpmjs.org/
  taobao - https://registry.npm.taobao.org/
  nj ----- https://registry.nodejitsu.com/
  rednpm - http://registry.mirror.cqupt.edu.cn/
  npmMirror  https://skimdb.npmjs.com/registry/
  edunpm - http://registry.enpmjs.org/
  
$ nrm add ynpm http://XXXXXX:4873 # 添加私服的npm鏡像地址
$ nrm use ynpm # 使用私服的鏡像地址
複製代碼

安裝包

npm install lodash # sinopia發現本地沒有 lodash包,就會從 官方鏡像下載
npm --loglevel info install lodash  # 設置loglevel 可查看下載包時的詳細請求信息
複製代碼
[storage]$ ls      
#下載過以後,私服的storage目錄下回緩存安裝包
[storage]$ ls                                                                                   
lodash
複製代碼
rm -rf node-modules # 刪除目錄
npm insatll lodash # 第二次安裝就會從緩存下載了,速度很快
複製代碼

發佈包與撤銷發佈包

在項目根目錄下運行$ npm publish發佈新包。

運行$ npm unpublish 包名 --force撤銷發佈包。

$ npm publish
+ @shawn280/ly-cli@1.0.0
複製代碼

查看發佈的包,已成功發佈:

做用域scope管理髮布包

常常有看到@xxx/yyy類型的開源npm包,緣由是包名稱不免會有重名,若是已經有人在 npm 上註冊該包名,再次 npm publish 同名包時會告知發佈失敗,這時能夠經過 scope 做用域來解決

  • 定義做用域包

    修改package.json中包名稱:

    {
         "name": "@username/project-name"
    }
    複製代碼

    須要注意的是,若是是發佈到官方registry,scope必定要是本身註冊的用戶名,而若是是發佈到本身的npm私服,scope能夠不是用戶名

  • 發佈做用域包

    做用域模塊默認發佈是私有的

    發佈到官方registry時,直接npm publish會報錯,緣由是隻有付費用戶才能發佈私有 scope 包,免費用戶只能發佈公用包,所以須要添加 access=public 參數;

    發佈到本身的npm私服時,不加access=public參數也能夠發佈

    npm publish --access=public
    複製代碼
  • 使用做用域包

    npm install @username/project-name
    var projectName = require('@username/project-name')
    複製代碼

總結

  • 以上的狀況並無考慮在遇到一些黑客攻擊的狀況下,因此爲了儘可能保證代碼的安全,能夠在前端加一層 Nginx 而後配置 SSH 公鑰來做爲雙層驗證。

  • 兩種解決方案的對比:

    1. 都緩存了從proxy倉庫下載過的包,沒有同步整個proxy倉庫的包。
    2. 存儲方式:nexus使用blob store,sinopia直接保存包文件到storage目錄。
    3. nexus管理界面能夠清緩存;sinopia貌似沒有命令和工具,可是能夠刪除經過刪除storage目錄下包目錄的方式清除緩存。
    4. 使用nexus時,發佈包安裝、卸載包須要設置不一樣的registry,而Sinopia一直用同一個就能夠。
    5. nexus管理頁面上展現了更多的包信息,相比而言sinopia也就是nodejs風格的包主頁上信息較少。
    6. sinopia更適合前端工程,優勢是配置簡單,對環境依賴少(僅node就夠了),而且支持在windows系統下運行;nexus支持倉庫種類最多,是用戶羣體最大的一個倉庫平臺,maven、docker、npm、gradle均支持,java須要maven倉庫、android須要gradle倉庫、運維須要docker倉庫,前端須要npm倉庫,若是公司已有nexus平臺管理這些倉庫,接入新的倉庫會較方便。
    7. sinopia 的權限管理比較弱,對用戶權限,發佈權限,下載權限控制不是很駕輕就熟;緩存優化不足,常常會在安裝共有包的時候處於掛起狀態

One more thing...

sinopia 在15年的時候就中止更新了,繼而由 verdaccio 提供更新升級,二者用法基本上都是一致的。對於企業級的應用來講,技術選型時請慎重選擇sinopia,建議選擇verdaccio。

參考文檔

juejin.im/entry/5bceb…

zhuanlan.zhihu.com/p/35907412

segmentfault.com/a/119000000…

www.cnblogs.com/LittleSix/p…

huang-x-h.github.io/2016/06/09/…

segmentfault.com/a/119000001…

相關文章
相關標籤/搜索