工欲善其事,必先利其器
背景是公司内部服务器是网络隔离的, 但是要做自动化构建、测试等,通常都需要从外部拉取依赖。所以,我又要搭建内部的镜像源了。(为什么说又呢。。。)
毫无疑问,是要用到一个服务器专门做镜像源的服务器,它有特殊的网络策略,内网的服务器可以和它连通,用作内外网的转发,以下假设使用 Nginx
做反向代理。
那么,当前公司内部之前已经搭建了 Private NPM Registry(使用 cnpm
搭建),私有包自然是从内部服务器下载,而 Public 包,则是通过 301
重定向到 taobao registry 。
npm install xxxx -dd # verbose mode 分析npm下载过程
一开始的思路是希望在 Nginx
内部做重定向(serverfault),防止在客户端做重定向,而客户端网络隔离。以下为参考配置,主要方法是将 301/302/307
的 HTTP 请求定义为错误并内部重定向到特定 uri
,然后再通过 proxy_pass
反向代理至公共源。
server {
...
location / {
proxy_pass http://reg.cnpm.internal; # 内部搭建的CNPM
proxy_intercept_errors on;
error_page 301 302 307 = @handle_redirect;
}
location @handle_redirect {
set $saved_redirect_location '$upstream_http_location';
proxy_pass http://registry.taobao.org; # 镜像服务器能够访问的NPM
}
}
配置好之后使用 npm install
测试,发现依然失败,分析 verbose
得知,registry info
已经成功获取到数据,但是 info 里面的 tarball
地址却还是原来注册服务器的地址。通过 npm info xxx
或者直接 curl
可以验证:
{
_id:"compare",
_rev:"6-d647d4531309933813e678fc321bb664",
name:"compare",
description:"Compare primitives the right way (using `<`, `>` and `==`)",
dist-tags:{
latest:"2.0.0"
},
versions:{
#...
2.0 .0:{
#...
dist:{
integrity:"sha512-FXeLLVm09Uh7Updmmx2NCCRG2nMq+mdY3DR9PqhVeOrie3IFU+occFQoqziFkHlTUDw8mDgmdblIZ+J9tsSAUA==",
shasum:"8090b34dcb288f629e905972da69ea7a6d5922a0",
tarball:"https://registry.npmjs.org/compare/-/compare-2.0.0.tgz",
fileCount:4,
unpackedSize:2682,
npm-signature:"... "
},
#...
}
},
#...
}
在开发人员的工作电脑上,自然是可以正常使用的,但在内部服务器通向互联网的流量都被阻止了。
所以,“代理”不能够单纯地转发响应,而且要“修改”响应。我选择了 Verdaccio 。
- It’s a web app based on Node.js
- It’s a private npm registry
- It’s a local network proxy
- It’s a Pluggable application
- It’s a fairly easy install and use
- We offer Docker and Kubernetes support
从官方仓库下载默认配置文件:https://github.com/verdaccio/verdaccio/blob/master/conf/docker.yaml,按照官方配置文档配置多个 uplink
(类似 Nginx
的 upstream
),然后在 packages
下配置包匹配规则。
uplinks:
npmjs:
url: https://registry.npmjs.org/
cache: true
internal_npm:
url: http://reg.cnpm.internal
cache: false
packages:
'@private_scope/*': # 根据情况配置私有scope,可以配置多条
access: $all
proxy: internal_npm # 转发到上游
'**':
# 匹配所有包
access: $all
#publish: $authenticated
proxy: npmjs
然后启动:
docker run --name verdaccio \
-v /path-to/verdaccio/config.yaml:/verdaccio/conf/config.yaml:ro \
-v /data/verdaccio/storage:/verdaccio/storage \
-v /data/verdaccio/plugins:/verdaccio/plugins \
-d \
-p 4873:4873 \
--restart always \
verdaccio/verdaccio
至此,这个 NPM 代理即可正常地在内部使用, info 响应里面的 tarball
也会被替换成代理的链接,并且同时支持内部包、外部包。