「docker-sinopia」使用Docker部署npm私服Sinopia

docker

21 Dec 2016

Author:wuguanxi


0.需求

代码写多了需要一个好的包管理工具,在javascript世界里就是npm了。但是npm也有缺点,国内访问的速度,还有npm是公开的,公司的项目不能往上面传。

1.sinopia

于是npm私有化的sinopia 项目进入了我们的视野,其作者是 rlidwka 猫大神

网上有很多文章安利Sinopia

比如这篇 《从零开始搭建npm仓库》

和这篇 使用sinopia搭建私有的npm仓库

首先,我先大概讲讲 Sinopia 的思路,我大概扫过一眼代码,大致有以下三点:

通过兼容官方的 Registry 的接口来对终端中 NPM 命令的兼容,从而不需要使用像 cnpm 这样的命令

正是由于 npm 支持诸如 --registry 以及 .npmrc 这样的配置文件,所以才使得上一条可以正常使用,而不需要任何 hacky 的代价

官方的 npm 使用 CouchDB 作为仓库数据库(大致听说),不过 Sinopia 将直接使用文件系统来作为存储结构,这样可以非常方便我们对缓存以及发布的仓库进行查看

安装启动非常简单

    $ npm install -g sinopia
    $ sinopia

1.1 sinopia的权限管理

这里先说一下sinopia的权限管理,后面会用到

sinopia 使用config.yml文件进行配置,而其中权限管理也是在里面

1.1.1 注册问题可以通过设置max_users: -1来禁止注册

    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: -1

虽然禁止注册,但还是可以通过同目录下的 htpasswd 文件写入用户信息,下面我在htpasswd写入一个test用户

    test:$6$kMLVq2SadeapeA==$rhJI1L92Xt99n23Voa4yq3TqwWD0pS08mNfBQNwX7XkUOHectx2x31nVIpUDTTFcpOgKw6PBbixDTOnNqdwDd1:autocreated 2016-12-20T02:15:13.371Z

密码是 123456 通过SHA1哈稀后转base64

1.1.2 packages 权限配置

    packages:
      '*':
        # allow all users to read packages (including non-authenticated users)
        #
        # you can specify usernames/groupnames (depending on your auth plugin)
        # and three keywords: "$all", "$anonymous", "$authenticated"
        access: $all

        # allow 'test' to publish packages
        publish: test

        # if package is not available locally, proxy requests to 'npmjs' registry
        proxy: npmjs

access是安装权限的用户列表

publish是发布权限的用户列表

proxy是代理对应uplinks

access,和publish 可以使用

$all 表示所有人都可以执行对应的操作

$authenticated 表示只有通过验证的人可以执行对应操作

$anonymous 表示只有匿名者可以进行对应操作(通常无用)

或者填写用户配置表里的用户名字

上面配置表示所有的包,所有人都可以下载,但只有test用户能发布

2.问题来了

看一下github sinopia项目已经一年多没有更新了,而且大部分新的issues都没有closed

果然,npm安装sinopia时报错,error还挺多。

原来,这一年node在某个版本v8更新了crypt3和sinopia冲突了

3.docker

既然是环境的问题,那么在作者修复前docker是最合适的解决方案了。(其实就算作者修复后docker也很好用)

3.1 docker介绍

如果你还不知道docker,那么可以将docker看成是轻量级的虚拟机,隔离环境。

docker官网

用docker快速配置前端开发环境

3.2docker的一些概念

Docker 中最重要的三个概念是 Container(容器)、Image(镜像)和 Volume(卷)

Image 是静态内容,如果你要把某个 Image 跑起来,那就需要一个 Container。这里面有一点很重要:Container 中所做的改动不会保存到 Image。举个例子,你跑起来一个 Ubuntu Image,然后 touch wisdomtmt 创建一个新文件,这时候如果直接重启 Container,文件就没了。那怎么保存改动?很简单,执行 docker commit ContainerID TAG 即可。

有同学就要问了,如果每次做改动都要 commit,我写起代码来岂不是很不方便?万一写到一半不小心重启 Docker 怎么办?这确实是个问题,Docker 也有对应的解决方法:使用 Volume。

简单来说,Volume 就是专门存放数据的文件夹,启动 Image 时可以挂载一个或多个 Volume,Volume 中的数据独立于 Image,重启不会丢失。我们创建一个 Volume,挂载到系统的一个目录下,然后把代码都放进去就可以了

3.3下载安装docker

Mac和windows用户推荐使用Docker Toolbox 官网

Linux 环境配置可以参考这篇:Installation on Ubuntu

安装不详细展开,下面都以Linux为列。

3.4使用docker

创建sinopia镜像

这里使用https://github.com/kfatehi/docker-sinopia/ 里的配置文件为基础稍作修改

    $ mkdir docker 
    $ cd docker
    $ git clone https://github.com/kfatehi/docker-sinopia.git
    $ cd docker-sinopia
    $ ls
    config.yaml  Dockerfile  Makefile  README.md  start.sh
    $ vim htpasswd

创建htpasswd并修改:

    test:$6$kMLVq2SadeapeA==$rhJI1L92Xt99n23Voa4yq3TqwWD0pS08mNfBQNwX7XkUOHectx2x31nVIpUDTTFcpOgKw6PBbixDTOnNqdwDd1:autocreated 2016-12-20T02:15:13.371Z
    vim config.yaml

修改配置文件里的用户权限:

    packages:
      '@*/*':
        # scoped packages
        access: $all
        publish: test

      '*':
        # allow all users (including non-authenticated users) to read and
        # publish all packages
        #
        # you can specify usernames/groupnames (depending on your auth plugin)
        # and three keywords: "$all", "$anonymous", "$authenticated"
        access: $all

        # allow all known users to publish packages
        # (anyone can register by default, remember?)
        publish: test
    vim Dockerfile

修改Dockerfile

    FROM node:0.12
    MAINTAINER Keyvan Fatehi <keyvanfatehi@gmail.com>
    RUN adduser --disabled-password --gecos "" sinopia
    RUN mkdir -p /opt/sinopia/storage
    WORKDIR /opt/sinopia
    ADD /htpasswd /opt/sinopia/htpasswd
    RUN chmod +rw htpasswd
    RUN npm install js-yaml sinopia
    RUN chown -R sinopia:sinopia /opt/sinopia
    USER sinopia
    ADD /config.yaml /tmp/config.yaml
    ADD /start.sh /opt/sinopia/start.sh
    CMD ["/opt/sinopia/start.sh"]
    EXPOSE 4873
    VOLUME /opt/sinopia

修改了第一行,指定node版本0.12

插入6~7行,将htpasswd文件复制到镜像内并赋予权限

注意最后一行是说指定 /opt/sinopia 文件夹为VOLUME,数据卷,即使重启这个容器 卷里面的内容都不会消失

Dockerfile是docker制作镜像的指令文件在它所在的目录下,我们使用以下命令

    $ sudo docker build -t sinopia .

注意后面.不是句号

稍等片刻(视网络环境,国内比较慢,服务器上好很多),docker会下载基础镜像文件(我们这里是node:0.12)然后自动按照Dockerfile的步骤配置好并生成

  $ sudo docker images

    REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
    sinopia             latest              72b028393246        5 minutes ago       703.4 MB

查看生成的镜像

    $ sudo docker run -itd --name my-sinopia -p 4873:4873 sinopia
    390975e8bf66503babde356ab074b33cefd688cbe259046ff9a4556f3a4c0c88

容器开启镜像跑起来

-itd d是后台运行 -p 是端口映射 --name 是命名容器

    $ sudo docker ps -a
    CONTAINER ID        IMAGE               COMMAND                  CREATED              STATUS                       PORTS                    NAMES
    390975e8bf66        sinopia             "/opt/sinopia/start.s"   About a minute ago   Up About a minute            0.0.0.0:4873->4873/tcp   my-sinopia

ps -a 是查看当前的容器

    $ sudo docker logs my-sinopia

    #
    # This is the default config file. It allows all users to do anything,
    # so don't use it on production systems.
    #
    # Look here for more config file examples:
    # https://github.com/rlidwka/sinopia/tree/master/conf
    #

    # path to a directory with all packages
    storage: ./storage

    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

    # a list of other known repositories we can talk to
    uplinks:
      npmjs:
        url: https://registry.npmjs.org/

    packages:
      '@*/*':
        # scoped packages
        access: $all
        publish: test

      '*':
        # allow all users (including non-authenticated users) to read and
        # publish all packages
        #
        # you can specify usernames/groupnames (depending on your auth plugin)
        # and three keywords: "$all", "$anonymous", "$authenticated"
        access: $all

        # allow all known users to publish packages
        # (anyone can register by default, remember?)
        publish: test

        # if package is not available locally, proxy requests to 'npmjs' registry
        proxy: npmjs

    # log settings
    logs:
      - {type: stdout, format: pretty, level: http}
      #- {type: file, path: sinopia.log, level: info}

    listen:
      - 0.0.0.0:4873
     warn  --- config file  - /opt/sinopia/config.yaml
     warn  --- http address - http://0.0.0.0:4873/

看logs可以知道我们的sinopia服务已经跑起来了,由于端口映射的关系,我们用浏览器访问服务器的4873端口即可

这里我在服务器用nginx做了映射,可以访问

3.5备份和恢复

备份

    sudo docker run --volumes-from my-sinopia -v $(pwd):/backup ubuntu tar cvf /backup/backup.tar /opt/sinopia

    ……

    backup.tar  config.yaml  Dockerfile  htpasswd  Makefile  README.md  start.sh

会生成一个backup.tar

恢复:

    sudo docker stop my-sinopia
    sudo docker rm my-sinopia
    sudo docker run --name my-sinopia -d -p 4873:4873 sinopia
    sudo docker stop my-sinopia
    sudo docker run --volumes-from my-sinopia -v $(pwd):/backup ubuntu tar xvf /backup/backup.tar
    sudo docker start sinopia

可以看出,其实就是备份数据卷里面的内容

4.使用nrm管理npm源

本地安装nrm

    $ npm install -g nrm
    $ nrm add private  http://sinopia.rococolate.com/  # 添加新的npm源,这里是我的sinopia
    $ nrm use private # 使用我的sinopia

5.登录和发布

    nrm use private

       Registry has been set to: http://sinopia.rococolate.com/

    npm adduser
    Username: test
    Password:123456
    Email: (this IS public) 123456@qq.com

    npm whoami
    test

我们以test身份登录成功,刚好有个Alert对话框的UI包,我尝试发布

    npm publish
    + nm_show_tips@1.0.0

发布成功