目录

  1. 一、节点管理
    1. 1.1 添加节点
    2. 1.2 节点服务器配置
  2. 二、 测试项目
  3. 三、测试报告插件
    1. 3.1 Publish HTML reports插件使用
    2. 3.2 测试报告无法加载CSS的问题
      1. 3.2.1 临时方案
      2. 3.2.2 永久方案

前面几篇文章主要讲了jenkins搭建和项目构建相关内容,已经能满足自动编译,自动部署等功能,但还差一项很重要的工作:自动化测试!

作为敏捷开发必不可少的工作,我们需要每次构建后都要跑一遍自动化测试,做全量回归,如果有需要还有冒烟测试。那么下面就来介绍如何实现每次构建项目后自动执行一个自动化测试任务。

一、节点管理

一般来说,测试都基于windows操作系统,比如用selenium编写web项目的自动化测试,用teststack.white编写client项目自动化测试。而我们的jenkins是通过docker容器安装部署的,实际是linux环境,这里就会遇到操作系统不兼容的问题。

事实上,不仅仅是需要测试才会遇到这种情况,如果我们要通过jenkins for docker部署一个.net framework 项目,也是同样的问题。

但jenkins提供了节点管理的功能,能搭建起一个跨系统跨平台的集群,既能解决系统兼容问题,也能解决单点jenkins性能不足的问题。

1.1 添加节点

  • jenkins“系统管理”–“管理节点” 进入节点管理页面,点左边栏“新建节点”

    1

  • 填写节点名称,选择“Permanent Agent”

    2

  • 填写配置如下

    3

    • of executors:并发量,可同时执行job的数量,默认是1,根据需要填写
    • 远程工作目录:节点服务器的工作目录,目录不要有中文
    • 用法:默认为“尽可能使用该节点”,修改为“只允许运行绑定到这台机器的Job”
    • Environment variables:环境变量,如图所示,需要增加一个键值对,表示把节点服务器的PATH环境变量赋值到jenkins节点中,如果不配置环境变量,新建的这个节点将不能读取到节点服务器上的PATH环境,比如不能启动python命令
  • save后显示如下界面,点“Launch”按钮,下载“slave-agent.jnlp”文件

    4

1.2 节点服务器配置

登陆需要用于执行测试的windows服务器

  • 安装JDK
  • 创建工作目录,和1.1配置的远程工作目录一致,如“d:\jenkins”
  • 拷贝1.1章节最后一步下载的“slave-agent.jnlp”文件到该服务器,可以放到工作目录下,目录不要有中文
  • 运行“slave-agent.jnlp”即可

可将“slave-agent.jnlp”文件放在启动项里,使其开机启动,或者做成服务

成功运行后可在jenkins节点管理看到该节点,并且状态由红字提示“不在线”变成正常

二、 测试项目

添加测试项目和添加普通项目类似:

  • 添加自由软件风格项目

  • 指定第一章创建的节点执行该项目

    5

  • 添加测试项目的git源

    6

  • 配置构建触发器

    7

    • 勾选“Build after other projects are built”,选择“Trigger only if build is stable”,填写前置项目名称,表示当这些前置项目成功构建后,执行这个项目
    • 根据需要,勾选“Build when a change is pushed to GitLab.”,用于配置Gitlab webhook触发项目,可参考该系列第二篇文章 http://wurang.net/jenkins02_use/
  • 构建环境同样根据实际需要配置

    8

  • 添加构建脚本

    9

  • 最后构建后发送邮件通知

这里容易踩坑,找不到python命令,请参考1.2章节查看环境变量键值对设置。

另外生成的测试报告不方便查看,需要在节点服务器上搭建iis或者nginx,这对于jenkins集群来说并不是很好的做法。所以我们还需一个测试报告的插件。

三、测试报告插件

3.1 Publish HTML reports插件使用

  • 安装Publish HTML reports插件

  • 编辑jenkins测试项目

  • 构建后操作增加Publish HTML reports

    10

    • HTML directory to archive:测试报告目录,相对于项目工作目录
    • Index page[s]:测试报告页面
    • Report title:报告名称
    • Keep past HTML reports:保留旧的测试报告,默认不保留
    • Always link to last build:始终连接到最新的构建
    • Include files:包含文件,如果测试报告文件夹内还有css或js文件,需要根据需要填写
  • 配置完成后,重新构建测试项目,就可以在项目左边栏点击“HTML Report”查看测试报告了,如果保留了旧的测试报告,也可以在这里选择查看

    11

  • 除了上面的方式查看测试报告外,还可以使用URL:项目地址/HTML_Report/ 来访问,比如在邮件通知模板里用下面的代码在邮件显示测试报告地址

    1
    ${PROJECT_URL}HTML_Report

    修改该测试项目的邮件通知模板,拷贝“系统设置”里默认的邮件模板内容,加入自定义的代码

    12

3.2 测试报告无法加载CSS的问题

如果测试报告用到了CSS和JS,即使我们在3.1章节中配置了“Include files”,还是不能正常加载测试报告,会丢失CSS和JS文件,控制台报错跨域问题。这是因为Jenkins由java开发,默认对跨域做了安全限制,这是jenkins的CSP(Content Security Policy)默认配置的,配置项为:

1
sandbox; default-src 'none'; img-src 'self'; style-src 'self';

在这种配置下,HTML内联样式,js,ajax都不可以使用。

解决这个问题的方式有两种,归根到底都是修改CSP:

3.2.1 临时方案

  • 进入Jenkins脚本命令行

    13

  • 输入以下命令并运行

    1
    System.setProperty("hudson.model.DirectoryBrowserSupport.CSP", "")

PS:需要注意

  • 执行完命令后再次构建测试项目,对新生成的测试报告才有效
  • 重启jenkins后配置将失效

结合之前的项目配置经验,我们也可以创建一个专门用来自动执行这个脚本的项目,添加触发器,每次jenkins启动后,就执行项目。让它变成一个“永久”方案。

3.2.2 永久方案

由于上面那个“永久”方案操作起来有点麻烦,还不能治本,所以我们还是考虑其他方式。

还记得第一篇文章http://wurang.net/jenkins01_docker/ 关于Dockerfile里有一段代码吗?

1
2
3
4
5
...
RUN rm -f /etc/localtime && ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
# 设置环境变量,设置时区和降低安全配置以允许查看测试报告时访问到css
ENV JAVA_OPTS="-Duser.timezone=Asia/Shanghai -Dhudson.model.DirectoryBrowserSupport.CSP=\"default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline';\""
USER jenkins

设置了java的环境变量JAVA_OPTS,其中就包含了CSP的修改

1
-Dhudson.model.DirectoryBrowserSupport.CSP=\"default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline';\"

所以我们在制作jenkins镜像的时候,从根本上就解决了问题。

至此,jenkins已经覆盖了编译、部署、测试整个软件开发流程。下一篇,将会介绍一下jenkins 的用户和项目权限管理。

评论和共享

目录

  1. 一、 插件
    1. 1.1 进入插件中心
    2. 1.2 更新插件
    3. 1.3 安装插件
    4. 1.4 卸载与降级插件
    5. 1.5 需要的插件
  2. 二、 使用示例
    1. 2.1 创建项目
    2. 2.2 源码管理
    3. 2.3 构建触发器
    4. 2.4 构建脚本
    5. 2.5 构建环境
      1. 2.5.1 Delete workspace before build starts 排除文件夹
      2. 2.5.2 Console Output日志加时间戳
    6. 2.6 构建后发布项目
      1. 2.6.1 设置SSH Server
      2. 2.6.2 发布到SSH Server
    7. 2.7 构建后邮件通知
      1. 2.7.1 配置Extended E-mail Notification
      2. 2.7.2 在项目中使用Extended E-mail Notification
  3. 三、 其他
    1. 3.1 SSH Server root权限执行命令或脚本
    2. 3.2 jenkins工作目录相关介绍
    3. 3.3 pm2相关知识介绍

一、 插件

正式介绍使用之前,还需要准备安装一些插件,插件中心使用操作如下:

1.1 进入插件中心

1

1.2 更新插件

2

1.3 安装插件

3

1.4 卸载与降级插件

4

1.5 需要的插件

  • GitLab Plugin
  • Gitlab Hook Plugin
  • Email Extension Plugin (默认安装)
  • Publish Over SSH
  • Timestamper (默认安装)
  • Workspace Cleanup Plugin (默认安装)

二、 使用示例

注:示例为dotnet core项目和nodejs项目,项目来源为Gitlab

2.1 创建项目

创建项目如下图所示,选择自由风格项目

5

2.2 源码管理

6

选择git源,Repo URL建议使用SSH地址,这时会提示没有权限,因为我们还没有将jenkins的public key添加到gitlab上。所以我们需要先拿到jenkins的public key:

  • 在宿主机上执行命令,其中myjenkins是容器名称

    1
    docker exec -it myjenkins /bin/bash
  • 进入jenkins容器后执行命令创建一对ssh的key

    1
    ssh-keygen -t rsa
  • 一路回车键,即可完成key的创建工作,这时我们进入默认目录查看

    1
    cd ~/.ssh
  • 会出现两个文件,一个是’id_rsa’还有一个是’id_rsa.pub’,我们需要查看’id_rsa.pub’文件,并记录下来

    1
    cat id_rsa.pub

    拷贝上面的文件内容,粘贴到记事本或其他文件管理软件并保存(后续操作仍会用到) 如:

    1
    ssh-rsa xxxxxxxxxxxjenkins@xxxxxx
  • 登陆gitlab账号(不要使用个人账号,建议使用部门公共账号、管理员账号),进入设置页面的’SSH KEYS’选项卡,填入拷贝好的public key,然后点’Add key’保存

    7

  • 再回到jenkins,点击’Add’添加认证方式

    8

  • 类型选为’SSH Username with private key’,Private Key选为’From the jenkins master ~/.ssh’,Username和Description可选填,用于备注,然后点’Add’完成添加

    9

  • 使用上面新建的认证方式后,原来红色的报错提醒就消失了,表示认证通过。最后修改一下需要拉取的分支,默认是’master’分支,我这里根据需要改成了’test’分支

    10

上面的配置完成后,jenkins就能从gitlab拉取项目了,可以在项目主菜单左边栏选择’立即构建’,看看是否成功:

11

2.3 构建触发器

通过2.2章节的配置,我们能够点击’立即构建’来主动开始一次构建,实际项目中,我们可能希望提交代码后,自动开始构建,这时需要配置构建触发器。下面演示gitlab触发器配置(需要安装Gitlab Hook Plugin插件):

12

  • 勾选’Build when a change is pushed to GitLab’,记录后面的URL,如本例中的’http://192.168.2.200:8081/project/Dent_WebSite_Test

  • 点击’高级’展开更多配置项

  • 在’Allowed branches’配置项选择’Filter branches by name’,在’Include’栏填入监听的分支名称,如’test’。表示触发器只监听来自test分支的事件。

  • 点击’Generate’按钮,生成’Secret token’并记录下来

  • 登陆gitlab(权限至少是master、owner或admin),进入jenkins需要配置的对应的项目,’Settings’选项卡,’Intergrations’配置页面。

    13

  • URL填写刚才记录的URL,如’http://192.168.2.200:8081/project/Dent_WebSite_Test

  • Secret Token填写刚才记录的Secret token

  • 勾选’push events’和’Merge Request event’,表示监听push和merge事件,然后点’Add webhook’,即可看到新建的webhooks

    14

  • 点击’Test’,选择’Push events’,测试看是否返回’HTTP 200’

    15

上面的配置完成后,就可以用git提交代码或者合并代码到test,看看jenkins是否自动开始构建。

PS: 触发器根据实际情况配置,一般来说实际项目中测试环境需要用触发器自动触发构建,而生产环境建议人工构建,避免误操作提交到master分支后冲掉生产环境!

2.4 构建脚本

前面我们已经完成了拉取代码的配置,接下来就要考虑如何’处理’这些源码:

  • 在’构建’栏增加构建步骤,选择’Execute shell’,创建shell脚本

    16

  • 如下图所示,是一个nodejs项目,它依次执行几个命令

    17

    • 需要注意的是每个命令用&&符号隔开,表示当前一个命令执行成功返回exit code = 0 后,下面的指令才执行,否则退出,用于避免前面的指令执行不成功,后面的指令继续执行
    • 点击’高级’展开更多配置,可以看到’Exit code to set build unstable’,默认exit code非0都会触发整个构建为unstable,也可以手动设置,如只监听exit code 为1,才会让构建变成unstable
  • 如下图所示,是一个dotnet core项目的编译shell脚本

    18

    • 这里将编译后的文件放到了workspace的jenkins_publish目录下面,这个workspace就是jenkins拉取git项目所在的目录
    • 最后一句将测试环境的配置文件改名,用于使其生效

2.5 构建环境

2.5.1 Delete workspace before build starts 排除文件夹

一般情况下,我们可能需要每次构建前,都要清空整个工作目录,也就是jenkins拉取git项目的目录,为了防止不必要的、多余的文件产生干扰,这时就需要勾选’构建环境’里面的’Delete workspace before build starts’,前提是安装了’Workspace Cleanup Plugin’插件:

19

也有另外几种情况,比如在nodejs项目中,每次清空工作目录后,执行’npm install’或’cnpm install’都需要很长时间,所以我们想保留’node_modules’文件夹,假如我们这个项目有两个二级目录(分别叫’app’和’frontend’)下面有’node_modules’文件夹,则配置如下所示:

20

  • 点开’高级’配置,添加4个Exclude输入栏
  • ‘ **/node_modules/** ‘表示node_modules文件夹和文件不删除
  • 还需添加两个二级目录’app’和’frontend’,否则只有子文件夹,没有父文件夹,实际上就是不存在任何文件夹
  • 还需添加’ **/.git/** ‘,因为下一次构建时,保留了’app’和’frontend’的’node_modules’文件夹以及文件内容,git不允许pull项目到非空目录,所以’ **/.git/** ‘目录也不能被清除
  • 不要勾选‘Apply pattern also on directories’,可能存在bug,勾选后反而不起作用

2.5.2 Console Output日志加时间戳

如下图所示,勾选’Add timestamps to the Console Output’,前提是安装’Timestamper’插件。这样构建时,在Console Output就能看到时间戳:

21

22

2.6 构建后发布项目

最后,我们要把’编译’或’处理’后的文件发布到指定的服务器上,常用方式为SSH,也可以通过FTP,下面都以SSH作为说明和示例(检查’Publish Over SSH’插件是否安装)。

2.6.1 设置SSH Server

进入’系统管理’里面的’系统设置’,找到’Publish over SSH’:

23

  • Passphrase:不用填写(如果你在2.2节,给jenkins创建ssh key时,一路回车没有添加这一属性,就无需配置)
  • Path to Key:填写’.ssh/id_rsa’,就是2.2节生成的私钥的文件路径
  • 点’增加’按钮,新增一个SSH Server,并点击’高级’展开更多配置
  • Name:SSH Server名称,用于展示和备注
  • Hostname:SSH Server的ip地址
  • Username:SSH Server用于发布服务的用户名,这里使用了www用户
  • Remote Directory: SSH Server用于发布服务的根目录,这里使用了www用户的目录/home/www/
  • Port:SSH Server的SSH服务端口,默认22

jenkins配置完成后,还需要对SSH Server做一些配置:

  • 远程连接到SSH Server上

  • 切换到SSH Server用于发布服务的用户,如www

  • 复制2.2节jenkins公钥的内容(id_rsa.pub),粘贴到该用户的’~/.ssh/authorized_keys’文件中,如果不存在则需要创建

  • 确保’~/.ssh’文件夹权限是700

    1
    chmod 700 ~/.ssh
  • 确保’authorized_keys’文件夹权限是600

    1
    chmod 600 ~/.ssh/authorized_keys
  • 确保’~/.ssh’文件夹及其内容的所有者是用于发布服务的用户

回到jenkins,如下图所示,点击’Test Configuration’,看是否返回Success!

24

2.6.2 发布到SSH Server

进入jenkins的项目,继续完成项目的发布配置,添加’ Send files or execute commands over SSH ‘构建步骤。

25

参考下图配置(示例为nodejs项目):

26

  • Add Transfer Set:添加一个传输
  • Name:选择需要发布的SSH Server
  • 在第一个Transfer处,写一些脚本,清理和重新创建部署目录,由于发布使用www用户,删除某些文件夹可能没有权限,所以需要用’sudo’来执行,’sudo’需要root用户的密码,我们这里需要免密码操作,操作详情可以看3.1章节
  • 在第二个Transfer处,Source files填写需要发布哪些文件
    • 该目录相对于工作目录,也就是jenkins拉取项目的目录,详情可以看3.2章节
    • 所有文件和文件夹填写’ **\** ‘
    • 如果有空文件夹,点开’高级’配置,如图中第5步所示,勾选’Make empty dirs’,否则空文件夹不会被发布
    • 如果要发布指定文件夹下的所有文件以及文件夹,填写’ foldername\ ‘,注意斜杠一定要有
    • 如果要发布多个目录,用英文逗号隔开
  • Remove prefix:如图所示,如果要发布app文件夹下的所有子内容,而不要把app这个文件夹也发布过去,需要在这里配置’app’
  • Remote directory:SSH Server的发布目录,相对于2.6.1章节,SSH Server配置的Remote Directory
  • Exec command:根据实际需求,执行一些命令,图中执行脚本安装nodejs包、重启pm2服务、重启nginx服务

dotnet core的参考配置如下,相对比较简单,发布后重启supervisor和nginx即可:

27

2.7 构建后邮件通知

上面的配置完成后已经能够正常使用,为了每次构建的信息能及时通知到团队,还需要配置邮件通知。

jenkins自带一个简单版的邮件通知功能,但不能满足一些复杂需求和定制需求,所以这里使用’Extended E-mail Notification’插件

2.7.1 配置Extended E-mail Notification

  • 进入’系统管理’里面的’系统设置’,找到’Jenkins Location’,填写’系统管理员邮件地址’:

    28

  • 找到’Extended E-mail Notification’,按下图所示配置:

    29

    • SMTP server:SMTP服务器地址
    • Default user E-mail suffix:默认邮件后缀
    • 点击’高级’展开更多配置
    • 勾选’Use SMTP Authentication’
    • 填写’User Name’,’Password’和’SMTP Port’
    • Default Recipients:默认收件人
  • Default Content就是邮件模板,这里给一个参考:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8">
    <title>${ENV, var="JOB_NAME"}-第${BUILD_NUMBER}次构建日志</title>
    </head>
    <body leftmargin="8" marginwidth="0" topmargin="8" marginheight="4"
    offset="0">
    <table width="95%" cellpadding="0" cellspacing="0"
    style="font-size: 11pt; font-family: Tahoma, Arial, Helvetica, sans-serif">
    <tr>
    <td><br />
    <b><font color="#0B610B">构建信息</font></b>
    <hr size="2" width="100%" align="center" /></td>
    </tr>
    <tr>
    <td>
    <ul>
    <li>项目名称 : ${PROJECT_NAME}</li>
    <li>构建编号 : 第${BUILD_NUMBER}次构建</li>
    <li>GIT URL: ${GIT_URL}</li>
    <li>GIT BRANCH: ${GIT_BRANCH}</li>
    <li>GIT COMMIT: ${GIT_COMMIT}</li>
    <li>触发原因: ${CAUSE}</li>
    <li>构建日志: <a href="${BUILD_URL}console">${BUILD_URL}console</a></li>
    <li>构建 Url : <a href="${BUILD_URL}">${BUILD_URL}</a></li>
    <li>工作目录 : <a href="${PROJECT_URL}ws">${PROJECT_URL}ws</a></li>
    <li>项目 Url : <a href="${PROJECT_URL}">${PROJECT_URL}</a></li>
    </ul>
    </td>
    </tr>
    <tr>
    <td><b><font color="#0B610B">变更集</font></b>
    <hr size="2" width="100%" align="center" /></td>
    </tr>
    <tr>
    <td>${JELLY_SCRIPT,template="html"}<br/>
    <hr size="2" width="100%" align="center" /></td>
    </tr>
    </table>
    </body>
    </html>

2.7.2 在项目中使用Extended E-mail Notification

回到jenkins项目配置,添加名为’Editable Email Notification’的构建后操作,配置如下:

30

  • Project Recipient List:项目收件人邮箱列表
  • Default Content:邮件内容模板,默认调用2.7.1章节配置的模板内容,也可以在这里自定义
  • Attach Build Log:是否附件构建日志,一般选择’Attach Build Log’
  • Trigger:点开’高级’,配置触发器,条件有很多,根据需要配置,这里’Recipient List’就是项目收件人邮箱列表

至此,一个’完整’的jenins项目就部署完成了(由于还没有集成测试,所以完整打引号,jenkins集成测试请参见该系列第三篇文章)。

三、 其他

3.1 SSH Server root权限执行命令或脚本

通过SSH Server发布和部署项目往往会遇到权限不够,需要用’sudo’升权限的情况,在自动化流程里,不想使用密码或者暴露密码,那么可以参考下面的方式:

  • 进入SSH Server

  • 切换到root用户

  • 编辑sudoers文件

    1
    vi /etc/sudoers
  • 在文档最后,给www用户添加无需密码的指令或脚本

    1
    www ALL=(root) NOPASSWD:/usr/bin/systemctl,/bin/supervisorctl,/usr/bin/rm

    上面的命令表示www用户以sudo执行systemctl、supervisor和rm命令时不需要密码。

    因为给www用户rm权限比较危险,所以这里也可以填某个位置的脚本文件,封装起来相对更安全,根据项目需要自行选择。

  • 在sudoers文件还需注释掉下面的配置,用于允许其他来源的控制台传输sudo命令

    1
    #Defaults requiretty

3.2 jenkins工作目录相关介绍

jenkins工作目录就是jenkins拉取git项目的目录,可以在jenkins项目左边栏点击’工作空间’查看:

32

在宿主机上,可以进入docker jenkins容器映射的卷查看,如

1
cd /var/lib/docker/volumes/jenkins/_data/workspace/项目名

或者在宿主机上直接进入docker jenkins容器内,在jenkins_home文件夹中查看

1
2
3
docker exec -it myjenkins /bin/bash #宿主机上执行
#进入容器
cd /var/jenkins_home/workspace/项目名

3.3 pm2相关知识介绍

  • 不建议给每个nodejs项目配置局部pm2,建议给SSH Server配置全局的pm2

    1
    sudo npm install pm2 -g
  • pm2作用于每一个用户,如果是用www用户部署的node项目,在root用户下不能用’pm2 status’查看到pm2托管的项目,不要用不同的用户启动pm2,以免项目冲突

  • pm2开机启动方法如下:

    配置完pm2托管的项目后执行命令

    1
    2
    pm2 save
    pm2 startup

    再用root用户执行提示反馈的命令即可

评论和共享

目录

  1. 一、 关于持续集成
    1. 1.1 什么是持续集成
    2. 1.2 为什么要持续集成
  2. 二、 搭建Jenkins
    1. 2.1 什么是jenkins
    2. 2.2 Jenkins for Docker
      1. 2.2.1 准备工作
      2. 2.2.2 拉取Jenkins for Docker
      3. 2.2.3 通过Dockerfile定制jenkins
      4. 2.2.4 使用Jenkins for Docker
      5. 2.2.4 如何复用与迁移
    3. 2.3 如何升级Jenkins

一、 关于持续集成

1.1 什么是持续集成

持续集成, 简称CI(continuous integration).是一种软件开发实践,即团队开发成员经常集成他们的工作,每次集成都通过自动化的构建(包括编译,发布,自动化测试)来验证,从而尽早地发现集成错误。

传统瀑布模型(水平划分项目阶段):

1

敏捷开发与CI模型(垂直划分项目阶段):

2

1.2 为什么要持续集成

  • 保证质量:CI是敏捷开发重要的一步,其目的在于让产品快速迭代的同时,尽可能保持高质量
  • 减少风险:CI讲求开发、部署、测试100%通过,通过多次集成,便于检查错误
  • 较少重复过程:自动化的构建、部署与测试节省重复工作,让团队能集中精力去做更重要的事
  • 增强项目可见性:每一次集成不论成功或失败,都能获得数据和信息供团队分析与决策
  • 增强团队协作:团队成员能清楚知道每一次提交代码后产生的影响,成员之间需要更密切的沟通来保证集成成功

二、 搭建Jenkins

2.1 什么是jenkins

Jenkins是一款用Java编写的开源的持续集成工具,是目前使用范围最广的CI工具。他长这样:

3

2.2 Jenkins for Docker

上文也说到Jenkins使用Java编写,所以支持跨平台。详细的介绍和安装说明可以查看官网

我们这里用到另一种方式,Jenkins for Docker. 这种方式在使用上更为轻量,不用在服务器上安装JDK,甚至不需要去研究如何安装Jenkins. 另外通过编写Dockerfile,能定制出符合我们需求的Jenkins配置,同时能够方便的复用和迁移。

2.2.1 准备工作

  • 需要一台装有Docker的宿主机(必要)

  • 需要一些Docker的基础知识与常用命令(必要)

  • docker宿主机设置代理(非必要)

    • 创建代理配置文件

      1
      2
      mkdir -p /etc/systemd/system/docker.service.d
      vi /etc/systemd/system/docker.service.d/http-proxy.conf
    • 内容填写参考如下

      1
      2
      [Service]
      Environment="HTTP_PROXY=http://192.168.2.100:1080/" "HTTPS_PROXY=https://192.168.2.100:1080/" "NO_PROXY=localhost,127.0.0.1"

      表示使用192.168.2.100:1080作为代理,且localhost不走代理

    • 更新配置

      1
      systemctl daemon-reload
    • 重启Docker

      1
      systemctl restart docker

2.2.2 拉取Jenkins for Docker

  • 宿主机执行命令拉取Jenkins的Docker Image

    1
    docker pull jenkins

    这个镜像体积不小,约800M,由于受国内网络环境影响,下载可能很慢,如果需要给docker设置代理请参考2.2.1 “docker宿主机设置代理”

  • 查看Jenkins镜像

    1
    docker images

    4

    到这里已经可以使用jenkins了,但我们还需做一些定制,比如给Jenkins镜像安装Nodejs、dotnet Core SDK等

2.2.3 通过Dockerfile定制jenkins

  • 根据需要编写Dockerfile

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    FROM jenkins
    MAINTAINER wurang
    USER root
    # 将 shell 替换为 bash
    RUN rm /bin/sh && ln -s /bin/bash /bin/sh
    # 设置中科大软件镜像源
    RUN sed -i 's/deb.debian.org/mirrors.ustc.edu.cn/g' /etc/apt/sources.list
    RUN sed -i 's|security.debian.org|mirrors.ustc.edu.cn/debian-security|g' /etc/apt/sources.list
    # upgrade
    RUN apt-get update && apt-get upgrade -y && apt-get install -y apt-utils sudo
    # 安装必要软件包
    RUN apt-get install -y build-essential curl libunwind8 gettext apt-transport-https nasm autoconf automake libtool libpng-dev pkg-config
    # 安装dotnet core 2.0
    RUN curl https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > microsoft.gpg \
    && mv microsoft.gpg /etc/apt/trusted.gpg.d/microsoft.gpg \
    && sh -c 'echo "deb [arch=amd64] https://packages.microsoft.com/repos/microsoft-debian-stretch-prod stretch main" > /etc/apt/sources.list.d/dotnetdev.list' \
    && apt-get update && apt-get install -y dotnet-sdk-2.0.0
    # 安装nodejs
    RUN curl -sL https://deb.nodesource.com/setup_6.x | bash - && apt-get install -y nodejs
    # 安装cnpm
    RUN npm install -g cnpm --registry=https://registry.npm.taobao.org
    # 清理缓存
    RUN apt-get clean && apt-get autoclean
    # 解决时区问题
    RUN rm -f /etc/localtime && ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
    # 设置环境变量,设置时区和降低安全配置以允许查看测试报告时访问到css
    ENV JAVA_OPTS="-Duser.timezone=Asia/Shanghai -Dhudson.model.DirectoryBrowserSupport.CSP=\"default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline';\""
    USER jenkins
  • 生成定制镜像

    1
    docker build -t auto-jenkins .
  • 查看镜像

    1
    docker images

    5

    auto-jenkins即为通过Dockerfile生成的定制镜像

2.2.4 使用Jenkins for Docker

  • 运行Jenkins容器

    1
    docker run --name myjenkins -d -p 8081:8080 -p 50000:50000 -v jenkins:/var/jenkins_home auto-jenkins
    • –name myjenkins 表示为运行的docker容器命名myjenkins
    • -d 表示用后台执行命令
    • -p 8081:8080 将Jenkins容器的8080端口映射至宿主机的8081端口,必须映射容器的8080端口到宿主机,考虑到宿主机8080端口可能被占用,所以这里映射到了8081端口,记住这个端口将用于对Jenkins的访问
    • -p 50000:50000 将Jenkins容器的50000端口映射至宿主机的50000端口,必须映射容器的50000端口到宿主机
    • -v jenkins:/var/jenkins_home 将Jenkins容器的home目录作为卷挂载到宿主机 /var/lib/docker/volumes/jenkins 目录,jenkins容器的所有配置、工作信息都会存放在这里。也可以挂载到宿主机的其他目录,不过需要注意权限问题
    • auto-jenkins 表示从我们创建的名为auto-jenkins的镜像启动容器
  • 访问Jenkins

    启动容器后,可以看到如下所示的信息,记住红框内的密钥信息

    6

    启动完成后就可以通过访问宿主机IP+容器8080的映射端口来访问Jenkins了,如通过上面的配置,我们可以访问 http://XXXX:8081

    7

    这里需要填入刚才记住的密钥,如果忘记了,可以在宿主机的挂载卷内找到

    1
    cat /var/lib/docker/volumes/jenkins/_data/secrets/initialAdminPassword

    然后安装推荐插件

    8

    9

    设置管理员账号

    10

  • 开机自动运行容器

    最后不要忘了给宿主机设置开机启动Jenkins容器,可添加下面的开机脚本命令

    1
    docker start myjenkins

2.2.4 如何复用与迁移

如果需要迁移整套jenkins或者在其他服务器复用,可以按照下面的步骤:

  • 新服务器安装Docker
  • 新服务器拉取Jenkins Image
  • 拷贝之前编写好的Dockerfile到新服务器,运行build脚本创建auto-jenkins镜像
  • 运行容器
  • 访问Jenkins
  • 拷贝旧服务器的挂载卷 /var/lib/docker/volumes/jenkins 到新服务器对应位置(迁移则需要这一步,复用不需要)

2.3 如何升级Jenkins

初次访问Jenkins for Docker,一般会遇到升级提示

11

升级步骤如下:

  • 右键”download”获取更新包地址

  • 进入jenkins容器

    1
    docker exec -it -u root myjenkins /bin/bash
  • 执行命令

    1
    2
    3
    4
    cd /usr/share/jenkins/ # 进入jenkins目录
    mkdir bak # 创建备份文件夹
    mv jenkins.war bak/jenkins.war.bak # 备份war包
    wget http://updates.jenkins-ci.org/download/war/2.73.2/jenkins.war # 下载更新包,地址为第一步获取的更新地址
  • 重启jenkins

    访问jenkins_url/restart 如 “http://XXXX:8081/restart” 重启jenkins

评论和共享

最近项目组上持续集成,于是利用jenkins的docker镜像做二次开发,原本写好的Dockerfile在生成docker image后不小心被误删,一番折腾后终于找了回来。

如下图所示:

  • jenkins为原始镜像
  • auto-jenkins为使用Dockerfile生成的镜像

1

使用history命令查询auto-jenkins镜像所执行的所有命令:

1
docker history auto-jenkins --no-trunc

2

可以从查询结果中识别出Dockerfile以外的命令,然后自下而上,找回Dockerfile的执行命令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
FROM jenkins
USER root
RUN rm /bin/sh && ln -s /bin/bash /bin/sh
RUN sed -i 's/deb.debian.org/mirrors.ustc.edu.cn/g' /etc/apt/sources.list
RUN sed -i 's|security.debian.org|mirrors.ustc.edu.cn/debian-security|g' /etc/apt/sources.list
RUN apt-get update && apt-get upgrade -y && apt-get install -y apt-utils sudo
RUN apt-get install -y build-essential curl libunwind8 gettext apt-transport-https
RUN curl https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > microsoft.gpg \
&& mv microsoft.gpg /etc/apt/trusted.gpg.d/microsoft.gpg \
&& sh -c 'echo "deb [arch=amd64] https://packages.microsoft.com/repos/microsoft-debian-stretch-prod stretch main" > /etc/apt/sources.list.d/dotnetdev.list' \
&& apt-get update && apt-get install -y dotnet-sdk-2.0.0
RUN curl -sL https://deb.nodesource.com/setup_6.x | bash - && apt-get install -y nodejs
RUN npm install -g cnpm --registry=https://registry.npm.taobao.org
RUN apt-get clean && apt-get autoclean
RUN rm -f /etc/localtime && ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
ENV JAVA_OPTS=-Duser.timezone=Asia/Shanghai
USER jenkins

综上,从Docker Image找回Dockerfile,需满足如下条件:

  • 需存在Dockerfile生成的Docker Image
  • 利用Docker Image只能找到任何已提交到Image的指令,如Dockerfile生成的Image,或Container提交的Image。如果在Container中执行的指令没有Commit到Image,则不能用Image的history命令查询。

评论和共享

项目使用Webpack打包,打包完成后生成一些asset,不管是本地开发还是jenkins持续集成,都希望自动上传这些asset到阿里云OSS,于是用nodejs写一个脚本:

1. upload_oss.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
var co = require('co');
var OSS = require('ali-oss') //阿里云oss模块
var fs = require("fs"); //文件模块
var path = require("path");
//---------------------------使用说明----------------------------
//获取命令行传入参数(第0个参数是node 第1个参数是js文件 第2个文件是本地文件夹路径 第3个是oss相对目录)
//命令格式举例: node oss/upload_oss.js ../../static/ /static/
var localPath = process.argv[2]
var remotePath = process.argv[3]
if(localPath == null || remotePath == null){
throw new Error("缺少目录参数!");
return
}
localPath = path.resolve(localPath); //本地目录
remotePath = path.resolve(remotePath); //OSS相对目录
if(!fs.existsSync(localPath)){
throw new Error("本地目录"+ localPath + "不存在!")
return
}
//上传列表
var fileDic = new Array();
//阿里云OSS配置
var client = new OSS({
region: 'oss-cn-shenzhen',
accessKeyId: 'xxxx',
accessKeySecret: 'xxxx',
bucket: 'xxxx'
});
console.log('---------上传OSS---------');
console.log('【Step1】 分析目录');
readDir(localPath)
function readDir(filePath){
filePath = path.resolve(filePath);
//遍历文件目录
var pa = fs.readdirSync(filePath);
pa.forEach(function(filename,index){
var file = path.join(filePath,filename)
var info = fs.statSync(file)
//目录
if(info.isDirectory()){
readDir(file);
}
//文件
else {
//添加到上传列表
var localDir = path.join(filePath,filename);
var remoteDir = path.join(remotePath, localDir.replace(localPath,""));
fileDic[localDir] = remoteDir;
console.log("add file:" + localDir)
}
})
}
console.log('【Step2】 上传文件');
co(function* () {
for(var localDir in fileDic)
{
var result = yield client.put(fileDic[localDir], localDir);
console.log("upload from '" + localDir + "' to '" + fileDic[localDir] + "'");
}
console.log('【Step3】 完成');
}
).catch(function (err) {
throw new Error(err);
}
);

2. package.json调用

1
2
3
4
5
"scripts": {
"dev": "webpack-dev-server --devtool inline-source-map --progress --color --watch-poll",
"test": "export NODE_ENV=test && webpack --progress --color && node oss/upload_oss.js ../test_static/ /demo/test_static/",
"prod": "export NODE_ENV=production && webpack --progress --color && node oss/upload_oss.js ../static/ /demo/static/",
}

如上所示:

  • test环境下,上传本地test_static文件夹到OSS的demo/test_static
  • prod环境下,上传本地static文件夹到OSS的demo/static

评论和共享

目录

  1. 1. 背景
  2. 2. 关于查找资料
    1. 2.1 百度搜索
    2. 2.2 Google搜索
    3. 2.3 官方文档
  3. 3. 解决实时刷新
    1. 3.1 前期准备
    2. 3.2 webpack、webpack-dev-server属性操作方式
    3. 3.3 watch与watch-poll
      1. 3.3.1 查询文档
      2. 3.3.2 webpack如何使用watch和watch-poll
      3. 3.3.3 webpack-dev-server如何使用watch和watch-poll
      4. 3.3.4 watch-poll并没有完全解决问题
    4. 3.4 webpack-dev-server的服务地址相关属性
      1. 3.4.1 host
      2. 3.4.2 disableHostCheck
      3. 3.4.3 port
      4. 3.4.4 public
    5. 3.5 webpack、webpack-dev-server在虚拟机或docker下开启自动刷新方法复盘总结
  4. 4. webpack-dev-server的两种刷新模式
    1. 4.1 如何启用inline和iframe模式
    2. 4.2 iframe
    3. 4.3 inline
  5. 5. 模块热替换HMR
    1. 5.1 什么是HMR
    2. 5.2 使用HMR
    3. 5.3 其他相关介绍
      1. 5.3.1 vue使用HMR
      2. 5.3.2 webstorm可能引起hot失效的问题
  6. 6. 其他替代技术
    1. 6.1 BrowserSyncPlugin
    2. 6.2 LiveReloadPlugin

1. 背景

公司前端项目从webpack1.X 升级到webpack2.X,加之技术需求和业务需求增长过快,开发人员没有充足时间深入学习webpack相关技术栈,导致很多配置失效、冗余或者无法辨别究竟有什么用途。

此外,我们基于docker-machine封装了vue、webpack、nodejs等前端开发环境到docker image,docker-machine本身基于Virtual Box,这种虚拟机+Docker的方式又挖了一把大坑。详情见:Docker搭建前端开发环境

综上,几种情况导致我们在docker中使用webpack-dev-server,没办法实时刷新,但在本机开发时却可以。

启动命令为:

1
webpack-dev-server --devtool inline-source-map --progress --color --watch

部分webpack配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
var webpack = require('webpack');
// ...
// var BrowserSyncPlugin = require('browser-sync-webpack-plugin');
var LiveReloadPlugin = require('webpack-livereload-plugin');
var config = {
entry: //...
output: {
path: path.resolve(__dirname, '../'),
filename: //...
chunkFilename: //...
},
module: {
rules: [{
test: /\.vue$/,
use: 'vue-loader'
}]
//...
},
plugins: [
// new webpack.HotModuleReplacementPlugin(), //热更新插件
(prod || test) ? function() {} : new LiveReloadPlugin({
appendScriptTag: true,
}),
//...
],
//...
}

一副很有历史痕迹的配置文件,留下了几个问题:

  • 问题一:在虚拟机或Docker下为什么不能实时刷新
  • 问题二:看上去功能重复的插件如BrowserSyncPlugin、LiveReloadPlugin、HotModuleReplacementPlugin究竟有什么区别,为什么会被注释

2. 关于查找资料

2.1 百度搜索

很多情况下,国内开发同学习惯在百度搜索相关问题,不可否认,百度搜索的中文问题有时候确实能比较快的找到答案,但在我们这个问题上,通过“webpack”,“自动刷新”,“HMR”等关键词中,找到几篇文章,但都存在一些问题,节选如下:

上面搜索的结果大部分是Webpack相关,除了版本对不上之外,还没法解决我们的问题。当然可以换新的关键词如“webpack 虚拟机 自动刷新”,效果基本和上面一样存在问题。

2.2 Google搜索

百度不行上google,在google通过“webpack hot reload vue virtual machine”等关键词搜到的结果一般来自于stackoverflow、github。一般github的问题会带项目的版本号,至少不会看岔了版本。stackoverflow比较专业的问题也会留下项目版本,操作系统等信息。最后在下面两篇文章中找到了“自动刷新”问题的答案:

Google搜索相对成本比较大,一方面是“技术”成本,另一方面是语言成本。虽然问题能解决,但对于知识体系的梳理并没有特别的帮助。偿还技术债归根到底还是要去看官方文档。

2.3 官方文档

这里列举的官方文档总共有三份,后面章节所有的介绍都基于这三份文档:

注意文档分为六部分,可以在导航栏切换。

5

3. 解决实时刷新

3.1 前期准备

开始解决问题之前,我们先做一下配置最小化,也就是把不清楚的,没有用的配置项去掉,减少干扰。最初的配置文件修改如下:

主要彻底删除了三个插件:browser-sync-webpack-plugin、webpack-livereload-plugin和HotModuleReplacementPlugin相关的所有配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
var webpack = require('webpack');
// 省略...
var config = {
entry: //...
output: {
path: path.resolve(__dirname, '../'),
filename: //...
chunkFilename: //...
},
module: {
rules: [{
test: /\.vue$/,
use: 'vue-loader'
}]
//...
},
plugins: [
//...
],
//...
}

3.2 webpack、webpack-dev-server属性操作方式

在官方文档中,webpack和webpack-dev-server的属性一般有两种操作方式,一种是CLI也就是命令行方式,另一种是修改配置的方式

  • CLI方式只需在命令行中用双横杠加属性即可操作属性值

    1
    webpack --progress=true --color=false --watch
  • CLI里面的每一个属性默认值为true,也就是说上面的例子“–watch”等同于“–watch=true”

  • 配置方式需要修改webpack.config文件,下面通过配置方式启用webpack的watch模式

    1
    2
    3
    4
    5
    var config = {
    entry: xx,
    watch:true, //添加watch
    //...
    }
  • CLI和配置方式二选一,不要同时使用,以免造成配置混乱,可读性差

  • CLI和配置方式同时使用时,CLI的优先级高,会盖掉配置文件的配置

3.3 watch与watch-poll

3.3.1 查询文档

https://webpack.js.org/configuration/watch/ 找到webpack的watch属性介绍:

6

  • watch属性用来监听文件变化
  • webpack-dev-server默认开启watch
  • 如果watch模式不起作用(watch对于NFS文件系统和虚拟机没有作用),可以尝试watchOptions.poll模式

同时在https://webpack.js.org/configuration/dev-server/#devserver-watchoptions-中找到了关于webpack-dev-server的watch属性介绍:

7

  • webpack用文件系统通知文件变化。如果使用NFS系统也就是网络文件系统,即网络磁盘、共享盘等,包括虚拟机,这些情况下用watch没有效果,需要打开watchOptions.poll模式

通过上面的信息,我们知道了由于虚拟机不能使用watch通知文件变化,需要用poll这种主动轮询的方式通知。这也许能解决我们的问题。

3.3.2 webpack如何使用watch和watch-poll

  • webpack命令默认没有启动watch,如果需要打开watch,两种方式

    • CLI命令行下添加watch属性

      1
      webpack --watch
    • 或者在配置文件中添加配置

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      var webpack = require('webpack');
      //...
      var config = {
      entry: xx,
      watch:true, //添加watch
      output: {
      path: path.resolve(__dirname, '../'),
      //...
      },
      //...
      }
  • 如果在虚拟机下用webpack,需要使用watch poll模式,两种方式

    • CLI命令行下添加watch–poll属性

      1
      webpack --watch-poll
    • 或者在配置文件中添加配置

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      var webpack = require('webpack');
      //...
      var config = {
      entry: xx,
      watchOptions: {
      poll: true
      }, //添加watchOptions节点,设置poll为true
      output: {
      path: path.resolve(__dirname, '../'),
      //...
      },
      //...
      }

3.3.3 webpack-dev-server如何使用watch和watch-poll

  • 因为我们使用的是webpack-dev-server,又因为webpack-dev-server默认开启watch,所以我们没有必要再做任何配置

  • 如果我们在虚拟机下用是webpack-dev-server,那就需要watch poll模式,两种方式

    • CLI命令行下添加watch–poll属性

      1
      webpack-dev-server --watch-poll
    • 或者在配置文件中添加配置

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      var webpack = require('webpack');
      //...
      var config = {
      entry: xx,
      devServer:{
      watchOptions: {
      poll: true
      }
      }, //添加devServer节点,添加watchOptions子节点,设置poll为true
      output: {
      path: path.resolve(__dirname, '../'),
      //...
      },
      //...
      }

3.3.4 watch-poll并没有完全解决问题

经过这一番折腾,本以为我们把启动命令从

1
webpack-dev-server --devtool inline-source-map --progress --color --watch

改成

1
webpack-dev-server --devtool inline-source-map --progress --color --watch-poll

就能解决【问题一】,然而结果事与愿违。还有其他哪里不对吗?

在Chrome的控制台中,看到下面的信息:

8

8080端口是webpack-dev-server的默认端口,从图中可以得知“[WDS] Disconnected!”,也就是说WebpackDevServer链接中断,紧接着是socket连接被拒。了解webpack-dev-server自动刷新原理的同学应该知道,自动刷新和热更新都是基于websocket来通知触发,这里展开又是长篇大论,所以不再多说,有兴趣自行了解。仅贴一下官方文档的解释,至于为什么贴devServer的inline属性文档说明,还是请看第4章。

9

websocket报错至少告诉我们自动刷新不成功是网络问题,那回顾一下使用虚拟机或者docker machine时的网络架构模式。如下图所示:

10

  • 如果在虚拟机下使用webpack-dev-server,实际上其服务地址应该是192.168.99.100:8080
  • 如果在docker machine中创建容器,并在其中使用webpack-dev-server,实际上其服务地址应该是172.17.0.2:8080,又因为docker容器和docker machine有做端口映射,也可以使用地址192.168.99.100:8080来访问webpack-dev-server服务

不管是哪种情况,都与我们目前遇到的不符。目前,我们webpack-dev-server服务地址是localhost:8080,也就是192.168.1.2:8080,事实上webpack-dev-server服务根本不在PC上。仔细想一下,webpack-dev-server默认ip为localhost,默认端口为8080,如果我们没有做配置,按默认来,那么确实是现在这个结果。【问题一】没解决,又生一问题,看看目前的问题库:

  • 问题一:在虚拟机或Docker下为什么不能实时刷新
    • 子问题a:在虚拟机或Docker下webpack-dev-server服务地址设置问题【新增】
  • 问题二:看上去功能重复的插件如BrowserSyncPlugin、LiveReloadPlugin、HotModuleReplacementPlugin究竟有什么区别,为什么会被注释

那么接下来,想办法把webpack-dev-server服务地址问题搞定。

3.4 webpack-dev-server的服务地址相关属性

3.4.1 host

官方文档中,host属性说明如下:

11

通过指定host,可以设置webpack-dev-server服务地址,文档中特别说明“如果需要外部访问服务地址,要将host指定为0.0.0.0”。暂且先不管这个“0.0.0.0”,既然在3.3.4小节中,我们期望的服务地址是“192.168.99.100”,那我们尝试用host指定一下这个IP。

1
webpack-dev-server --devtool inline-source-map --progress --color --host 192.168.99.100 --watch-poll

执行一下,但却得到报错:

12

报错提示为没法监听到“192.168.99.100”的8080端口。

这里也好理解,我们的webpack-dev-server运行在docker容器中,也就是“172.17.0.2”这个IP,docker和docker machine之间是端口映射关系,只有当docker容器的8080端口有服务,docker machine的8080端口才有用。那我们直接在docker容器中把服务放到docker machine上是不行的。

那尝试改成docker容器自己的IP“172.17.0.2”看看结果:

1
webpack-dev-server --devtool inline-source-map --progress --color --host 172.17.0.2 --watch-poll

编译正常,但还存在两个问题:

  • 我们一般不关注docker容器的IP,只关注docker或者docker machine的IP,他们之间有端口映射关系,所以把host改到docker容器上不是什么好方法

  • 虽然编译没报错,但Chrome的控制台报另一个错误了,这回换成“172.17.0.2”这个IP访问不到。事实如此,我们的本机PC和docker 容器之间并不互通,一直以来都是以docker machine作为桥梁。

    13

得,直接把host定位到docker machine不行,把host定位到docker容器本身也不行。那怎么破?这时候再回到官方文档的介绍,试试指定host到“0.0.0.0”,在网络中0.0.0.0意思为整个网络:

1
webpack-dev-server --devtool inline-source-map --progress --color --host 0.0.0.0 --watch-poll

编译也正常,回到Chrome看下控制台,WTF!还有错:

14

这回不是找不到服务地址了,却提示无效的host头部。问题库再来一员。

  • 问题一:在虚拟机或Docker下为什么不能实时刷新
    • 子问题a:在虚拟机或Docker下webpack-dev-server服务地址设置问题【新增】
    • 子问题b: host指定到0.0.0.0提示Invalid Host header【新增】
  • 问题二:看上去功能重复的插件如BrowserSyncPlugin、LiveReloadPlugin、HotModuleReplacementPlugin究竟有什么区别,为什么会被注释

3.4.2 disableHostCheck

【子问题b】相对来说比较好解决,google一下,信息都指向到disableHostCheck这个属性上:

15

说出于安全考虑,检查host看是否存在攻击行为,那我们现在是开发使用,给他禁了吧:

1
webpack-dev-server --devtool inline-source-map --progress --color --host 0.0.0.0 --disable-host-check --watch-poll

这下终于没问题也不报错了,尝试一下改动代码,实时刷新终于OK了!

16

至此,【问题一】彻底解决!但跟host服务地址相关的几个属性有必要再介绍一下。

  • 问题一:在虚拟机或Docker下为什么不能实时刷新【已解决】
    • 子问题a:在虚拟机或Docker下webpack-dev-server服务地址设置问题【已解决】
    • 子问题b: host指定到0.0.0.0提示Invalid Host header【已解决】
  • 问题二:看上去功能重复的插件如BrowserSyncPlugin、LiveReloadPlugin、HotModuleReplacementPlugin究竟有什么区别,为什么会被注释

3.4.3 port

17

host属性用来指定webpack-dev-server服务的IP地址,那么port属性就是指定服务的端口了。由于默认端口是8080,比较容易被占用,所以可以人为去指定。

需要提醒一下,如果是使用docker,默认的8080端口或者指定的其他端口都需要做好映射!

3.4.4 public

18

解释说如果使用inline模式,并代理使用webpack-dev-server,可能会需要public属性。

在我这个例子中,webpack-dev-server的服务地址是0.0.0.0:8080,我们并没有用nginx之类的软件代理这个地址,所以在本例中,我们不需要使用public属性。

但如果0.0.0.0:8080被nginx代理为wds.XX.com这个域名,有可能会需要设置这个属性。

我在解决这一系列问题途中,搜索到stackoverflow和github上某些文章,说只要设置public属性就行了,这不是一个完全正确的答案:

  • host是说webpack-dev-server服务的源在哪里,必须存在目标的位置
  • public是说webpack-dev-server服务发布在哪里,这是指路

3.5 webpack、webpack-dev-server在虚拟机或docker下开启自动刷新方法复盘总结

上面介绍的比较杂,我们重新梳理一下解决【问题一】的路线:

  • 在虚拟机或Docker下为什么不能实时刷新

    这是因为watch属性不能在网络文件系统也就是虚拟机下监听文件变化,必须使用watch-poll主动轮询查询文件是否变更

  • 使用watch-poll后,找不到webpack-dev-server服务地址localhost:8080

    这是因为wds默认地址为localhost:8080,但实际上服务地址应该在虚拟机或docker machine上,指定host为0.0.0.0即可。意思为监听整个网络

  • wds服务地址指定为0.0.0.0:8080后,提示Invalid Host header

    这是因为wds出于安全考虑,检查host是否存在危险,毕竟0.0.0.0监听整个网络,而我们在开发机以及开发环境中并不会有什么风险,可以用过disableHostCheck禁用host检查

问题的答案有两种形式:

  • CLI

    1
    webpack-dev-server --host 0.0.0.0 --disable-host-check --watch-poll
  • 配置文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    var webpack = require('webpack');
    //...
    var config = {
    entry: xx,
    devServer:{
    host: "0.0.0.0", //指定wds服务ip为0.0.0.0用于监听整个网络
    // port: 9081, //自定义wds服务端口
    // public: "http://wds.myapp.com", //指定wds服务的发布位置
    disableHostCheck:true, //禁用host检查以解决Invalid Host header错误
    watchOptions: {
    poll: true //开启watch主动轮询模式
    }
    },
    output: {
    path: path.resolve(__dirname, '../'),
    //...
    },
    //...
    }

    同样的属性,配置文件和CLI不要混合使用,上面的配置文件搭配的CLI非常简单:

    1
    webpack-dev-server

最后,用docker的话记得映射wds的端口!

比如配合上面的例子,docker的run命令如下:

1
docker run -p 80:80 -p 8080:8080 centos

到这里还没完!一开始我们说了一些文章关于webpack的介绍混淆了1.x和2.x版本,还多次提到了inline模式。虽然已经解决了自动刷新的问题,但关于自动刷新还知之甚少。那下面来详细了解一下webpack-dev-server的自动刷新模式。

4. webpack-dev-server的两种刷新模式

webpack-dev-server实现自动刷新有两种方式,一种是inline模式,另一种是iframe模式。关于这两种模式的介绍和区别 详情介绍webpack-dev-server,iframe与inline的区别 这篇文章介绍的比较详细。

简单来说:

  • inline是将inline.js打包到bundle.js,inline.js包含了socket通讯代码,可以与wds进行通讯,用来响应wds反馈的文件变化通知,然后刷新整个url
  • iframe是在网页中嵌入一个iframe,文件发生变化时,wds通知到live.bundle.js,live.bundle.js本身也包含socket通讯,收到反馈后reload这个ifame以完成页面刷新

4.1 如何启用inline和iframe模式

文章一开始,我们列举了几篇文章,说都存在问题,包括本章开头介绍inline和iframe的文章也存在这个问题,他们分别是这样介绍的:

每一篇都说iframe无需配置,是默认的,而inline需要用CLI或配置打开。还有其他一些文章,还专门强调使用inline模式需要手动添加entry。这是因为这些文章用的文档都是webpack1.X版本,那我们看看官方是怎么说的:

  • webpack 1.X

    22

  • webpack 2.X

    23

    • inline默认开启
    • iframe模式需要配置
    • 建议使用inline模式配合模块热更新(inline和iframe都支持模块热更新)

综上所述:

  • webpack1.X中默认开启的是iframe模式,而webpack2.X中默认开启inline模式,同时webpack2.X也无需配置entry
  • 所以有必要提醒一下,如果你正在使用webpack2.X,需要启用inline模式,那么在CLI中添加inline是多此一举
  • 另外iframe模式下,访问地址加了目录webpack-dev-server,变成 http://ip:port/webpack-dev-server/index.html
  • inline模式会刷新整个url
  • iframe模式只会刷新iframe里面的页面,url并不会刷新

不管怎么说,理论上这两种模式都能完成自动刷新,下面看看实际运行结果。

4.2 iframe

注意下面的介绍都是基于虚拟机的架构,所以保留了watch-poll、host、disable-host-check等属性设置。

执行命令:

设置属性inline=false以启动iframe模式

1
webpack-dev-server --watch-poll --host 0.0.0.0 --port=9081 --inline=false --disable-host-check

24

iframe模式下,url地址确实增加了webpack-dev-server目录,同时整个页面最顶层有一个状态栏,整个页面被包裹在一个iframe里,注意观察下面的动图,看看url和顶层状态栏,以及页面如何刷新:

25

4.3 inline

inline就是webpack2.X默认模式,所以我们在第3章介绍的案例都是以inline模式运行,不再过多介绍,执行命令,看一下动图:

26

到这还是没结束。因为问题库里面,【问题一】解决了,但【问题二】还没解决:

  • 问题一:在虚拟机或Docker下为什么不能实时刷新【已解决】
    • 子问题a:在虚拟机或Docker下webpack-dev-server服务地址设置问题【已解决】
    • 子问题b: host指定到0.0.0.0提示Invalid Host header【已解决】
  • 问题二:看上去功能重复的插件如BrowserSyncPlugin、LiveReloadPlugin、HotModuleReplacementPlugin究竟有什么区别,为什么会被注释

那么继续往下看!

5. 模块热替换HMR

5.1 什么是HMR

27

上面是官方对于HMR的解释。HMR相对于自动更新来说:

  • 不需要刷新整个页面,因为这可能会影响到现有的表单、缓存等,同时响应速度比较慢
  • 整个应用在运行时,可以替换其中的模块,而不用重启应用

第4章也提到,inline和iframe模式都可以配合HMR使用,那我们如何开启HMR呢?

5.2 使用HMR

28

官方文档对于webpack2.X版本启用hot说明如下:

  • 如果通过CLI也就是命令行方式开启hot,会自动添加HotModuleReplacementPlugin

    1
    webpack-dev-server --host 0.0.0.0 --disable-host-check --watch-poll --hot
  • 如果使用配置方式开启hot,需要手动添加HotModuleReplacementPlugin

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    var webpack = require('webpack');
    //...
    var config = {
    entry: xx,
    devServer:{
    host: "0.0.0.0",
    disableHostCheck:true,
    hot:true, //开启hot
    watchOptions: {
    poll: true
    }
    },
    output: {
    path: path.resolve(__dirname, '../'),
    //...
    },
    plugins: [
    new webpack.HotModuleReplacementPlugin(), //热更新插件
    //...
    ],
    //...
    }

上面的例子中,默认使用inline模式配合hot开启HMR,如果要使用iframe模式,记得指定inline=false

现在我们知道【问题二】中HotModuleReplacementPlugin的用途了,只有在通过配置文件方式开启hot模式时,需要手动添加HotModuleReplacementPlugin

  • 问题一:在虚拟机或Docker下为什么不能实时刷新【已解决】
    • 子问题a:在虚拟机或Docker下webpack-dev-server服务地址设置问题【已解决】
    • 子问题b: host指定到0.0.0.0提示Invalid Host header【已解决】
  • 问题二:看上去功能重复的插件如BrowserSyncPlugin、LiveReloadPlugin、HotModuleReplacementPlugin究竟有什么区别,为什么会被注释
    • 子问题c: HotModuleReplacementPlugin是做什么用的【已解决】
    • 子问题d: BrowserSyncPlugin是做什么用的【新增】
    • 子问题e: LiveReloadPlugin是做什么用的【新增】

正确开启HMR后,浏览器控制台可以看到这个信息:

29

看一下HMR响应改变的动图,注意观察和inline自动刷新的区别,主要是url没有刷新,以及控制台里面的信息:

30

5.3 其他相关介绍

5.3.1 vue使用HMR

在vue中,使用vue-loader就可以完美兼容HMR模式,看看vue官方怎么介绍的:

https://vue-loader.vuejs.org/zh-cn/features/hot-reload.html

31

5.3.2 webstorm可能引起hot失效的问题

有同学反应,使用webstorm开发时,HMR失效了。这锅不是webstorm一个人背,官方是这样解释的:

32

有些编辑器默认使用“safe write”模式保存文件,比如webstorm,这种模式将文件变化先放到缓存里,并不直接改写文件,所以导致监听文件变更失败。遇到这种情况,可以取消“safe write”模式。

6. 其他替代技术

整篇文章还剩下两个问题:

  • 问题一:在虚拟机或Docker下为什么不能实时刷新【已解决】
    • 子问题a:在虚拟机或Docker下webpack-dev-server服务地址设置问题【已解决】
    • 子问题b: host指定到0.0.0.0提示Invalid Host header【已解决】
  • 问题二:看上去功能重复的插件如BrowserSyncPlugin、LiveReloadPlugin、HotModuleReplacementPlugin究竟有什么区别,为什么会被注释
    • 子问题c: HotModuleReplacementPlugin是做什么用的【已解决】
    • 子问题d: BrowserSyncPlugin是做什么用的【新增】
    • 子问题e: LiveReloadPlugin是做什么用的【新增】

一一攻破。

6.1 BrowserSyncPlugin

https://www.npmjs.com/package/browser-sync-webpack-plugin

主要解决浏览器同步问题,比如做兼容性调试时,一般同时打开IE、Chrome或开启手机浏览器模拟器等,该插件可以同步所有浏览器内容。与webpack共同使用时,一般用来代理webpack-dev-server服务已完成更多功能。详细不再过多介绍,按需使用。

6.2 LiveReloadPlugin

https://www.npmjs.com/package/webpack-livereload-plugin

基本功能与webpack-dev-server一致,但如果网站的assets由其他服务器提供,比如某些图片存在阿里云OSS,而你又想使用webpack的自动更新功能。那么就可以使用这个插件。

  • 问题一:在虚拟机或Docker下为什么不能实时刷新【已解决】
    • 子问题a:在虚拟机或Docker下webpack-dev-server服务地址设置问题【已解决】
    • 子问题b: host指定到0.0.0.0提示Invalid Host header【已解决】
  • 问题二:看上去功能重复的插件如BrowserSyncPlugin、LiveReloadPlugin、HotModuleReplacementPlugin究竟有什么区别,为什么会被注释
    • 子问题c: HotModuleReplacementPlugin是做什么用的【已解决】
    • 子问题d: BrowserSyncPlugin是做什么用的【已解决】
    • 子问题e: LiveReloadPlugin是做什么用的【已解决】

至此,所有的坑全部填完……

评论和共享

系统:CentOS 7

1. 安装SS

参考 官网

1
2
yum install python-setuptools && easy_install pip
pip install shadowsocks

2. 开启多用户

1
vi /etc/shadowsocks.json # 内容如下
1
2
3
4
5
6
7
8
9
10
11
12
13
{
"server":"0.0.0.0",
"local_address":"127.0.0.1",
"local_port":1080,
"port_password":{
"23331":"xxxx", //开放端口和密码
"23333":"yyyy", //开放端口和密码
},
"timeout":300,
"method":"aes-256-cfb",
"fast_open": false
}

3. 开机自启动

1
vi /etc/systemd/system/shadowsocks.service # 内容如下
1
2
3
4
5
6
7
8
9
[Unit]
Description=Shadowsocks
[Service]
TimeoutStartSec=0
ExecStart=/usr/bin/ssserver -c /etc/shadowsocks.json
[Install]
WantedBy=multi-user.target
1
2
systemctl enable shadowsocks
systemctl start shadowsocks

4. 安装BBR

1
2
3
wget --no-check-certificate https://github.com/teddysun/across/raw/master/bbr.sh
chmod +x bbr.sh
./bbr.sh

安装完提示重启,然后用以下命令查询是否返回bbr

1
lsmod | grep bbr

5. 设置防火墙

Vultr控制台防火墙有时不好使,还是原生配置吧

1
2
3
4
5
6
7
firewall-cmd --zone=public --add-port=80/tcp --permanent # 开80端口
firewall-cmd --zone=public --add-port=23331/tcp --permanent # 开23331 TCP端口
firewall-cmd --zone=public --add-port=23331/udp --permanent # 开23331 UDP端口
firewall-cmd --zone=public --add-port=23333/tcp --permanent # 开23333 TCP端口
firewall-cmd --zone=public --add-port=23333/udp --permanent # 开23333 UDP端口
firewall-cmd --reload # 重载配置
iptables -L -n # 查询防火墙规则

完事……

评论和共享

Hexo远程部署Vultr

发布在 internet

1. 本地操作

  • Hexo安装完成

  • Git安装完成

  • Git配置(Git Bash)

    1
    2
    git config --global user.name "你的用户名"
    git config --global user.email "你的电子邮箱"
  • Git SSH Keys(Git Bash)

    1
    2
    3
    4
    cd ~
    mkdir .ssh
    cd .ssh
    ssh-keygen -t rsa
  • Hexo安装hexo-deployer-git插件

2. Vultr配置

  • 新建用户

    1
    useradd git
  • 创建authorized_keys

    1
    2
    3
    4
    5
    6
    su git
    cd ~
    mkdir .ssh
    cd .ssh
    vi authorized_keys
    # 复制本机 ~/.ssh/id_rsa.pub 内容到此
  • 安装Git和Nginx

    1
    2
    3
    su #切换root
    yum -y update
    yum install -y nginx git-core
  • 创建Git仓库目录

    1
    2
    3
    4
    5
    su git
    cd ~
    mkdir hexo.git
    cd hexo.git
    git init --bare
  • 创建网站目录

    1
    2
    3
    su # 切换root
    mkdir -p /home/wwwroot/hexo
    chown git:git -R /home/wwwroot/hexo # 变更所有人
  • 配置Git Hook

    1
    2
    3
    su git
    cd ~/hexo.git/hooks
    vi post-receive # 内容如下
    1
    2
    3
    4
    5
    6
    7
    8
    #!/bin/bash
    GIT_REPO=/home/git/hexo.git # git 仓库
    TMP_GIT_CLONE=/tmp/hexo
    PUBLIC_WWW=/home/wwwroot/hexo #网站目录
    rm -rf ${TMP_GIT_CLONE}
    git clone $GIT_REPO $TMP_GIT_CLONE
    rm -rf ${PUBLIC_WWW}/*
    cp -rf ${TMP_GIT_CLONE}/* ${PUBLIC_WWW}
  • 赋予执行权限

    1
    chmod +x post-receive
  • 禁止Git用户登陆控制台

    1
    2
    3
    su //切换root
    vi /etc/passwd
    #找到 git:x:1000:1000::/home/git:/bin/bash 改成 git:x:1000:1000::/home/git:/usr/bin/git-shell
  • 配置Nginx

    1
    vi /etc/nginx/conf.d/hexo.conf #内容如下
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    server {
    listen 80 ;
    root /home/wwwroot/hexo;
    server_name XX.XX.com; # 域名
    access_log /var/log/nginx/hexo_access.log;
    error_log /var/log/nginx/hexo_error.log;
    location ~* ^.+\.(ico|gif|jpg|jpeg|png)$ {
    root /home/wwwroot/hexo;
    access_log off;
    expires 1d;
    }
    location ~* ^.+\.(css|js|txt|xml|swf|wav)$ {
    root /home/wwwroot/hexo;
    access_log off;
    expires 10m;
    }
    location / {
    root /home/wwwroot/hexo;
    if (-f $request_filename) {
    rewrite ^/(.*)$ /$1 break;
    }
    }
    }
  • 重启Nginx

    1
    systemctl restart nginx

3. Hexo配置

  • _config.yml文件配置如下:

    1
    2
    3
    deploy:
    - type: git
    repo: git@域名:/home/git/hexo.git

完事……

评论和共享

Scrum简介与实施指南v1.0

发布在 agile

一、什么是Scrum

Scrum就是3、3、5、5

二、第一个3——3个角色

1. Product Owner 简称PO

PO是获得授权一个人

PO职责:WHAT
• 清晰地表达你想要什么
• 对需求功能进行排序,告诉团队你最想先要什么
• 需求都要有价值:优化Team所执行工作的价值,不要提垃圾需求
• 会写PB(Product Backlog):确保产品待办列表对所有人可见、透明、清晰,并且显示 Scrum团队的下一步工作
• 及时与Team沟通反馈:确保Team对产品待办列表项有足够的理解

PO是墙头草:
• 一方面PO要了解客户需求的紧急性,要代表客户给Team施压
• 另一方面PO要了解Team的进度和产能,顶住来自客户的压力(攘外)

PO最大:
• Team只听PO

2. Team

Team的特点:
• 自管理:没有人分配任务,没有人告诉Team如何将PO的需求实现
• 跨职能:Team中的每个人必须具备实现PO需求的所有技能,包括设计、分析、编码、测试。但可以有特长或专注领域。
• 小团队:团队人数一般3-9人
• 在一起:所有成员是一个整体,没有子团队,没有领袖

Team的职责:HOW
• 会把PO写在Product Backlog中的User Story写AC(Accepance Case)
• 提供每个AC的估算
• 集中投入,按时交付

3. ScrumMaster

ScrumMaster的职责:Guide
• 确保PO和Team能正确理解并实施Scrum(安内)

三、第二个3——3个工件

1. Product Backlog

1

a. PB的拥有人:

PO

b. PB的内容:

  • Story:用户故事,也就是PO提出的原始需求,PO写
  • AC:Accepance Case,验收用例,是Team对Story的细化,Team写
  • 当前Sprint:当前Sprint的AC,PO自己拖拽过去
  • Done:做完的AC,PO自己拖拽过去

c. Story的写法:

作为XX(角色)

需要有XXX(功能)

用于XXX(实现价值)

d. Story的要求:

  • 每个Story一个泳道

  • 要排优先级

  • 适当的详细:近期要做的需求要详细,如下图,用户中心的Story打算近期做,细化成“手机注册”和“登陆”

    2

  • 可以随时变:每次改变需要重排优先级

e. AC的写法:(ATDD 验收测试驱动 TDD测试驱动,属于XP)

依赖:XX(依赖条件)

输入:XX

输出:XXX

3

f. PB什么时候写,什么时候拖拽

见第四节

2. Sprint Backlog

4

a. SB的拥有人:

Team

b. SB的内容:

  • 当前Sprint:从PB的的“当前Sprint”复制过来
  • TODO:当前Sprint的功能点一旦复制过来就进入TODO
  • Doing:Team从TODO中领取功能,拖拽到Doing。注意是Team,不是个人。一次领一个功能,直到Done后才能领下一个功能
  • Done:Team完成功能后,从Doing拖拽到Done。注意是完成所有步骤,包括测试

c. Increment

  • 增量就是每一个Done的功能,必须是正常可工作的
  • 增量可在PO的计划时间发布,也可临时发布

四、第一个5——5个活动

1. Product Backlog Refinement

简称PBR又叫PB进化

PBR是一个持续的阶段,并不是会议,需要Team和PO每天有固定的时间或随时沟通

a. PBR中需要搞定5件事

  • PO要把优先级排好

  • PO要把PB要写好,近期的要细化

  • Team要把近期的PB写成AC

  • Team要评估每个AC的工作量:选好一个AC为基准,以倍数的方式评估

    5

  • PO要制定发布计划:这个迭代周期完成后不发布增量就不制定

b. 为什么要写AC

  • 帮助整个Team理解功能( 你以为的你以为真的是你以为么 )
  • 分解PO的功能
  • 就是在做设计
  • 要识别出依赖
  • 能减少误判
  • 更容易估算复杂度
  • Team和PO的合作
  • 把PO解放出来去做更重要的事

c. Team与PO的沟通方式

  • Team要多给PO选择题和判断题,不要给论述题

    例子:

    • PO在PB上的Story是”要账号登陆功能”
    • Team在写AC的过程中,可以问PO“我们有手机号、邮箱、QQ、微信等登陆功能,你要哪些”,或者问“我们现在先实现手机号登陆比较靠谱,你看行不行”。不要问或少问“你想用哪些方式登陆”
  • PO要积极响应和反馈Team,PO决定产品功能的方向和准确性而非Team
  • Team写完AC后,PO负责批阅,确定功能的准确性

d. PBR实践

  • Team中的所有人都要写AC
  • 第一个迭代开始后,每天17:00固定时间Team和PO沟通下一个迭代的功能,写下一个迭代的AC
  • 一旦Team中有人暂时没有工作,就去写AC或与PO沟通下一个迭代的功能

2. Sprint Planning

迭代计划会议

a. 会议时间:

每个迭代开始的第一天,早9:30

一般1小时左右,如果PBR做的好,会议应该在30分钟左右

b. 参加人员:

  • PO
  • Team
  • ScrumMaster(非必需)

c. 会议内容:

  • Team提供迭代周期的产能,ScrumMaster协助评估产能
  • PO根据Team的产能,在PB中选择复杂度之和在产能内的AC,拖拽到“当前Sprint”
  • Team把PB“当前Sprint”的AC复制到SB中
  • Team和PO简单讨论哪些功能要做,怎么样做

3. Daily Scrum

每日立会

a. 会议时间

迭代周期内每天16:45

会议最多15分钟

b. 参加人员:

  • Team(只有Team能发言)
  • 所有人(非必需)

c. 会议内容:

所有Team成员回答3个问题

  • 昨天做完了什么
  • 今天要做完什么
  • 有什么问题

4. Sprint Review

迭代评审会议

a. 会议时间

迭代周期最后一天16:00

会议1小时

b. 参加人员

  • Team
  • PO
  • 所有人(非必需)

c. 会议内容

  • Team演示所有Done的增量
  • PO根据演示或总结用户的看法提出新的需求或修改需求到PB

5. Sprint Retrospective

a. 会议时间

迭代周期最后一天17:00

会议1小时

b. 参加人员

  • Team
  • PO
  • ScrumMaster

c. 会议内容

ScrumMaster和全组讨论改进

  • 我们需要开始做点什么
  • 我们需要停止做些什么
  • 我们需要保持什么

五、第二个5——5个价值观

  1. 承诺
  2. 勇气
  3. 专注
  4. 开放
  5. 尊重

评论和共享

目录

  1. 1. 什么是串流
  2. 2. 为什么要对PS4进行串流
  3. 3. 串流前的准备
    1. 3.1 PS4设置
    2. 3.2 路由设置
    3. 3.3 PSN ID与验证码
  4. 4. 串流工具与方法
    1. 4.1 PC
      1. 4.1.1 PS4 Remote play for PC
      2. 4.1.2 REM4P
      3. 4.1.3 PS4 Play
    2. 4.2 Android
      1. 4.2.1 Sony手机
      2. 4.2.2 非Sony手机
    3. 4.3 iOS
      1. 4.3.1 R-Play
      2. 4.3.2 使用PS4手柄游玩
    4. 4.4 Mac
    5. 4.5 PSV

不知不觉搭进去大半个月,终于要迎来这个系列最后一篇文章。这段时间仿佛又回到几年前折腾android刷机的时候。不得不说,年纪大了真折腾不动。那么闲话少说直接开搞:

1. 什么是串流

Streaming (串流处理) 是指透过网际网路传输数位音讯或视讯。

说简单点,就是把设备A的音视频通过网络在设备B上展示,同时设备B无需安装、存储、下载和等待。

往前说,得说到互联网刚普及时出现的流媒体Streaming Media,让用户脱离下载等待,实现边下边看。给你们两个“古董”感受一下:rmvb和Real Player

近一点说,直播的发展离不开流媒体。一个是直播通过流媒体在网络上展示,另一个是主播可以把主机游戏直接串到电脑上,再通过电脑进行直播。这个也是本文重点讨论的内容。

再近一点,上一篇文章讲到的搭建NAS,最后需要通过DLAN共享出来,那么DLAN也是基于流媒体技术。可以理解成“NAS”中存储的视频“串流”到电视进行播放。

在主机平台上,XBOX和PS先后推出了将主机游戏串流到其他显示设备的相关技术和软件。目的主要为了让游戏方式更灵活。

2. 为什么要对PS4进行串流

  • 长期出差在外地,不能玩放在家中的游戏设备?那么串流可以让你在外地,在电脑上畅玩PS4
  • 电视机被家人占用看电视,没法玩游戏?那么串流可以让闲置的电脑、平板用来做PS4的“显示器”
  • 想在没有电视的客厅、卧室、洗手间,想在上下班途中的公交地铁利用闲散时间玩游戏?串流可以让你在手机上爽一下,外接手柄和虚拟手柄都能带来很好的“手游”体验
  • 虽然XBOX和PS4提供直播,但都是国外平台,如果要在国内直播平台进行直播,那么就可以把主机串流到PC上

3. 串流前的准备

3.1 PS4设置

串流前需对PS4进行设置,主要是打开远程遥控和远程唤醒:

  • 启用遥控操作。选择 [设定] > [遥控操作连接设定],在[启用遥控操作]的方框打勾。
  • 将主机认证为常用PS4™主机。选择[设定] > [PlayStation Network/账号管理] > [认证为常用PS4] > [认证]。
  • 若要在PS4™为待命模式时开始遥控操作,选择[设定] > [省电设定] > [设定待命模式里的功能],在[与互联网保持连接]及[设为可通过网络启动PS4的电源]的方框打勾。

3.2 路由设置

串流分为内网和外网,很容易理解,在家里串流只考虑内网就可以。如果想在外面玩家中的设备,那就要考虑外网。

内网可以跳过,外网需具备下面几个条件(参考系列第一篇 http://wurang.net/merlin01_setting

  • 光猫桥接与路由拨号

  • 公网IP

  • DDNS(可选)

  • 开启UPnP

    1

  • 开启端口转发(不建议用DMZ)

    转发987的UDP

    转发9295至9304的BOTH(UDP和TCP)

    2

串流对路由没有要求,其他路由也只需要按实际操作开启UPnP并做端口转发即可。

3.3 PSN ID与验证码

几乎所有的串流软件都会要求输入PSN ID和验证码,获取的方法如下:

PSN ID: 不是登陆账号,而是ID,登陆后右上角显示的用户名一般就是ID,也可以在SONY官网登陆后查询(注意ID区分大小写)。https://account.sonyentertainmentnetwork.com/liquid/cam/account/profile/profile-details.action

验证码:在PS4中,前往 [设定] > [遥控操作连接设定]中选择[添加设备],看到的8位数字就是验证码,验证码需注意时效。

4. 串流工具与方法

我按设备和平台区分,如下所示:

4.1 PC

在2017年以前,串流软件主要有三种,可参考:http://bbs.duowan.com/thread-44938163-1-1.html

那个时期官方软件做的很烂,民间涌现出不少作品,如tmacdev的Remote Play和国人开发的PS4 play。在这个贴子中,Remoteplay PC(黑客)版即是tmacdev的版本,在“官网及技术支持”一栏中,Remoteplay PC官方版和黑客版网址刚好写反了。

3

如上图所示,帖子中也总结了三款软件的特点。当然,这是2016年的帖子,现在已经有不少变化了,我们重新整理一番:

4.1.1 PS4 Remote play for PC

Sony官方串流工具跟随3.5系统一雪前耻,目前主力串流工具。下载地址为:https://remoteplay.dl.playstation.net/remoteplay/lang/cs/index.html

项目 内容
系统支持 win8.1/win10
分辨率/帧数 PS4最高支持720P+60帧,PS4 Pro最高支持1080P+60帧
支持外设 仅键盘
支持按键映射
登录方式 PSN ID+验证码
手柄连接方式 有线/无线
网络连接方式 有线/无线
资费 免费

使用方法官网介绍的很清楚了。不得不说官方的东西用起来最简单。

登陆分自动和手动模式,默认自动模式,仅需登陆PSN。如果自动模式失败,再通过手动模式输入PSN ID和验证码即可登陆。

登陆默认先找内网登陆的PS4,再找公网的PS4.

PS4手柄通过USB线插到电脑上就能体验串流游戏了,当然也可以用无线转换器。

用有线的方式连接PS4和电脑串流效果非常好,1080P几乎不掉帧。无线连接推荐5G频段。当然5G的穿透衰减可能造成信号不稳定,这种情况下效果反而不如2.4G频段。2.4G能较流畅跑720P。

软件设置里,帧率选高即为60帧,标准为30帧。

4

官方的Remote Play几乎能满足所有的串流要求,唯一遗憾的是没有按键映射。也就是说只能用PS4手柄玩,不能用键盘或者鼠标玩。

如官方所说,如果在公网下串流使用,建议上传及下载皆为15 Mbps以上的连接速度。实际上国内运营商很少会给这么高的上行带宽,实测8M上传就能稳定跑720P。

顺便提醒一点,Remote Play支持待机唤醒,所以不玩的时候完全可以进入待机模式省电。

当然我们不能每次背着个手柄出差吧。如果想像模拟器那样用键盘玩,那么往下看。

4.1.2 REM4P

REM4P其实就是上面帖子中的黑客版,也就是tmacdev开发的产品。由于2017年,Sony官方的Remote Play逐渐完善,再加上版权打击,民间流传的串流工具几乎全部停止开发。于是tmacdev也关闭了所谓的Remote Play黑客版,并开发了一款插件,配合官方的Remote Play,实现键盘鼠标操作的功能。这款插件就叫REM4P.

REM4P是独立软件,单独购买,单独安装,配合官方Remote Play使用。官方购买连接为 https://tmacdev.com/product/rem4p/ 售价10英镑,约等于人名币88元。

软件的安装和使用请参考tmacdev官网,目前暂不支持Mac.

虽然tmacdev的黑客版已经停止开发,但仍能在其他渠道下载,目前仍能使用,而且其收费版还有破解版本。这里不做过多介绍了。

4.1.3 PS4 Play

国人开发的PS4 Play在2016年彻底火了一把。免费,支持键盘映射,性能还不错。唯一的缺憾是只支持有线连接。具体可见 http://bbs.duowan.com/thread-44901953-1-1.html

和tmacdev一样,在官方的压力下,软件目前也停止开发了,官网和论坛也全部关闭。

当然,PS4 Play也能在其他渠道下载,目前也能使用。

随着官方对PS4系统的不断升级,tmacdev的Remote Play黑客版和PS4 Play终会不能使用。

4.2 Android

4.2.1 Sony手机

大法家自己的手机肯定有福利。Google Play Store直接下载官方的Remote Play,用法和PC上没什么区别。同时还支持第三方手柄。如果想用PS4的手柄也可以,后面会介绍,请见4.3.2章节。

4.2.2 非Sony手机

不是Sony的手机也能用Remote Play,毕竟Android环境下,破解个app还不是分分钟的事。

如果手机已root,上xpose,详情见 https://forum.xda-developers.com/android/apps-games/5-0-playstation-remote-play-android-t3466339

不root据说也行,我没折腾,有需要自己google吧。

4.3 iOS

4.3.1 R-Play

Sony官方一直没有在iOS平台下发布过串流工具,所有的软件都是民间开发。早期在iOS下的串流工具叫Play Cast,后来由于商标问题,改名为Play Mira,售价都是68RMB,随后和所有第三方软件一样,被Sony官方怼了一波,在Apple Store下架了。已经下载了Play Mira的用户仍可以使用,但软件不支持4.55及以上系统。

然而事情没有结束,没过多久,Apple Store上架一款名为R-Play的应用,界面几乎和Play Mira一毛一样!售价同样68RMB。据说是沿用Play Mira的代码,做了4.55的适配,R-Play和Play Mira之间的关系网上有贴说明,这里不扒了。总之,目前用R-Play就可以在iOS上串流PS4。

由于第三方软件的不可靠性,个人不建议直接购买68的R-Play,如果不差钱当我没说。因为不知道什么时候又会下架,而且下架后是不退款的。建议某宝搜”rplay”,1-2块大洋买一个账号下载就好了。

项目 内容
分辨率/帧数 PS4最高支持720P+60帧,PS4 Pro最高支持1080P+60帧
支持外设 仅支持MIFI认证手柄
支持按键映射 自带虚拟按键
登录方式 PSN ID+验证码
网络连接方式 无线
资费 68RMB

R-Play登陆必须使用PSN ID 加验证码,为了更好的游戏体验,可以让PS4接网线,如果是PS4 Pro也可以使用5G Wifi

配置界面如下:
5

PS4 IP建议使用固定IP

WAN网络主机是串流到公网,这里可以填公网IP,方便起见最好填DDNS的域名。

首次登陆后会提醒“配置互联网游玩”,只有“配置互联网游玩”后才能在公网串流,配置过一次后,除非网络环境发生改变,否则不需再次“配置互联网游玩”。如果WAN网络主机填写的是公网IP,那么IP变更后也需要修改。

R-Play用起来的流畅度和官方的Remote Play没什么区别,自带的虚拟键盘可以调整按键大小和位置,体验很不错。

6

7

4.3.2 使用PS4手柄游玩

由于移动设备不能连接PS4手柄,所以如果想使用PS4手柄在移动设备上串流游戏,需要按以下的方法操作:

  • PS4手柄离PS4主机的距离必须在使用范围内。实际上就是要满足PS4手柄的无线操作距离,与内网或公网无关。也就是说手机只充当显示器,控制还是由PS4手柄直接与PS4交互。
  • 在PS4上登陆两个账号A和B
  • 使用PS4手柄进入账号A
  • 使用R-Play,登陆账号B
  • 按PS4手柄的”PS”键,即可用手柄在账号A下玩游戏了,成就所得为账号A

4.4 Mac

Mac上的串流工具也是官方的Remote Play,具体可以参考4.1章节。个人感觉Mac更适合无线串流,配合Mac自带的Wifi检测功能,也能更方便的观察线路质量。

4.5 PSV

PS4最早的串流工具就是PSV了,毕竟是自家产品。PS4和PSV的串流依赖于自建专用无线通信线路,点对点传输,可以不依赖于路由。早期串流质量和效果最好,所以PSV才有了手柄V的称号。

目前手机等移动设备有了串流工具后,PS4串流更方便,而且PSV串流不支持1080P(只支持540P+60帧),所以没必要为了串流去再买一台掌机了。

至此,关于路由引发的血案全部结束,实在是折腾不动了……

评论和共享

作者的图片

Wu Rang

Everything begin with HelloWorld!


System Architect


Guangzhou