Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

自定义Node镜像 #111

Open
willson-wang opened this issue Dec 16, 2022 · 0 comments
Open

自定义Node镜像 #111

willson-wang opened this issue Dec 16, 2022 · 0 comments
Labels
包管理工具 npm package manager

Comments

@willson-wang
Copy link
Owner

背景

最近一段时间公司陆续有业务组,反馈云服务器上构建的时候,npm依赖拉取不下来,导致项目部署不成功,于是发现主要是两个问题导致(公司目前主流还是使用yarn 1.x 版本)

  • 项目yarn.lock内还使用了npm官方源or yarn官方源安装的包
  • 部分npm包,在install相关钩子执行的时候,会去下载一些二进制文件,而这些二进制文件往往是国外的地址

所以为了彻底解决yarn install的时候,能够不受这些因素的影响,决定提供node基础镜像,在镜像里面替换yarn.lock内的链接,且添加对应的.npmrc,保证项目不受外国网络限制,能够正常install

制作镜像

基于公司的应用场景,决定提供两类基础镜像

  • alpine镜像
  • alpine镜像

两类镜像,各提供三个版本

  • 12.x.x
  • 14.x.x
  • 16.x.x

.npmrc

yarnpnpmnpm等包管理工具,读取配置的优先级是,命令行参数 > 配置文件参数
yarnpnpm这些后于npm的包管理工具,默认都会读取.npmrc文件,所以为了考虑将来可能切换包管理工具,使用.npmrc来保存配置,而不是使用.yarnrc

yarn读取配置文件的顺序如下所示

  • 项目目录下的.npmrc
  • 用户目录下的.npmrc
  • 项目目录下的.yarnrc
  • 用于目录下的.yarnrc

如果存在多个配置文件,则会进行合并

Checking for configuration file "/Users/xxx/node-performance/.npmrc".
Checking for configuration file "/Users/xiaoming/.npmrc".
Found configuration file "/Users/xiaoming/.npmrc".
Checking for configuration file "/usr/local/etc/npmrc".
Checking for configuration file "/Users/xxx/node-performance/.npmrc".
Checking for configuration file "/Users/xxx/.npmrc".
Checking for configuration file "/Users/xiaoming/Documents/.npmrc".
Checking for configuration file "/Users/xiaoming/.npmrc".
Found configuration file "/Users/xiaoming/.npmrc".Checking for configuration file "/Users/.npmrc".
Checking for configuration file "/Users/xxx/node-performance/.yarnrc".
Checking for configuration file "/Users/xiaoming/.yarnrc".
Found configuration file "/Users/xiaoming/.yarnrc".
Checking for configuration file "/usr/local/etc/yarnrc".Checking for configuration file "/Users/xxx/node-performance/.yarnrc".
Checking for configuration file "/Users/xxx/.yarnrc".
Checking for configuration file "/Users/xiaoming/Documents/.yarnrc".
Checking for configuration file "/Users/xiaoming/.yarnrc".
Found configuration file "/Users/xiaoming/.yarnrc".
Checking for configuration file "/Users/.yarnrc"

.npmrc内两类内置两类参数

  • 源地址
  • 一些npm包下载第三方文件时,允许使用指定下载地址的参数

最终的.npmrc如下所示

// 常用变量
sass_binary_site=https://npmmirror.com/mirrors/node-sass
sentrycli_cdnurl=https://npmmirror.com/mirrors/sentry-cli
electron_mirror=https://npmmirror.com/mirrors/electron
chromedriver_cdnurl=https://npmmirror.com/mirrors/chromedriver
operadriver_cdnurl=https://npmmirror.com/mirrors/operadriver
selenium_cdnurl=https://npmmirror.com/mirrors/selenium
puppeteer_download_host=https://npmmirror.com/mirrors
grpc-node-binary-host-mirror=https://npmmirror.com/mirrors

// 指定源
registry=https://registry.npmmirror.com

替换yarn.lock

const fs = require('fs');

function createReg(regsitry: string) {
  return new RegExp(`http(s)?://${regsitry}`, 'g');
}

export default function changeYarnLockRegistry(registry: string, yarnLockFile: string) {
  if (registry.slice(-1) === '/') {
    registry = registry.slice(0, -1);
  }
  console.log('当前替换的源为: ', registry);
  const replaceMap = new Map([
    [/\/download\/@.*\//g, '/-/'],
    [/\/download\//g, '/-/'],
    [/\/-\/-\/download/g, '/download/-/download'],
    [/\/-\/download\/download/g, '/download/-/download'],
    [createReg('registry.npmjs.org'), registry],
    [createReg('registry.yarnpkg.com'), registry],
    [createReg('r.cnpmjs.org'), registry],
    [createReg('registry.npm.taobao.org'), registry],
    [createReg('registry.nlark.com'), registry],
    [createReg('registry.npmmirror.com'), registry],
    [createReg('registry.enpmjs.org'), registry],
  ]);

  let content = fs.readFileSync(yarnLockFile, 'utf8');

  for (const [key, value] of replaceMap) {
    content = content.replace(key, value);
  }

  fs.writeFileSync(yarnLockFile, content, 'utf8');
}

使用上面的方法,对yarn.lock内的源地址进行替换,替换成执行的源地址,这样就能100%保证yarn.lock内的源地址

简版镜像(alpine)

.npmrcyarn.lock替换方法准备好之后,后面就是镜像的制作了
制作镜像

FROM node:12.22.11-alpine

# 修正时区
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories && apk update \
	  && apk add -U tzdata && cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime

# 将当前目录下的.npmrc拷贝到镜像的根目录,确保构建工具能够正确读取配置
COPY ./.npmrc /root/.npmrc

# 添加一个参数,确保能够知道镜像是否使用的是最新镜像
ARG NODE_VERSION

# 这里在设置一次的目的是保证,在postInstall这些钩子里面,执行js脚本的时候,在脚本里面通过npm install包的时候,能够使用指定的源,而不是yarn官方源去下载
RUN npm config set registry https://registry.npmmirror.com/ \
    && yarn config set registry https://registry.npmmirror.com/ \
    && npm install -g [email protected] @yunke/[email protected] \
    && pnpm config set store-dir /root/.pnpm-store \
    && yinstall cover \
    && npm config set yk_node_version $YK_NODE_VERSION

yinstall内包含yarn.lock替换逻辑

完整版镜像

完整版镜像与简版镜像制作的区别,就只有时区的设置不同,其它都是一样的

FROM node:12.22.11

RUN sed -i 's#http://security.debian.org/debian-security#http://mirrors.aliyun.com/debian-security#g' /etc/apt/sources.list && \
    sed -i 's#http://deb.debian.org#http://mirrors.aliyun.com#g' /etc/apt/sources.list && \
    apt-get clean && \
    apt-get update && \
    apt-get install -y tzdata && \
    ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime

ARG YK_NODE_VERSION

COPY ./.npmrc /root/.npmrc

RUN npm config set registry registry https://registry.npmmirror.com/ \
    && yarn config set registry registry https://registry.npmmirror.com/ \
    && npm install -g [email protected] @yunke/[email protected] \
    && pnpm config set store-dir /root/.pnpm-store \
    && yinstall cover \
    && npm config set yk_node_version $YK_NODE_VERSION

总结

yarn 1.x的版本,源地址是保存在yarn.lock内的,所以当有yarn.lock存在时,只能去修改yarn.lock内的源地址才有效,直接设置registry参数是无效的,这个问题,在后续的pnpmnpmyarn 2.x中都得到了解决,只需要设置registry就可以控制npm包的下载地址,但是对于一些npm包内下载第三方包,目前还是只能通过指定对应的变量来控制下载地址

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
包管理工具 npm package manager
Projects
None yet
Development

No branches or pull requests

1 participant