<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>lokyoung (刘晨阳)</title>
    <link>https://ruby-china.org/lokyoung</link>
    <description></description>
    <language>en-us</language>
    <item>
      <title>Ruby China 7 岁生日快乐</title>
      <description>&lt;p&gt;Ruby China7 岁啦，生日快乐~&lt;/p&gt;</description>
      <author>lokyoung</author>
      <pubDate>Sun, 28 Oct 2018 00:13:52 +0800</pubDate>
      <link>https://ruby-china.org/topics/37689</link>
      <guid>https://ruby-china.org/topics/37689</guid>
    </item>
    <item>
      <title>后端渲染还是前后端分离？Listen to yourself.</title>
      <description>&lt;h2 id="TL;DR"&gt;TL;DR&lt;/h2&gt;
&lt;p&gt;本文提及的后端渲染主要指 Rails 后端渲染。这里说的前后端分离不意味着使用了 React/Vue 这样的前端库就是前后分离。在后端渲染的应用中也可以集成 React/Vue。&lt;/p&gt;
&lt;h2 id="前言"&gt;前言&lt;/h2&gt;
&lt;p&gt;最近这两年由于前端技术圈一直都很热门，有不少产品都做成了前后端分离的单页应用（SPA）。&lt;/p&gt;

&lt;p&gt;关于前后端分离究竟是好还是不好，社区里之前曾有过一次比较激烈的探讨 &lt;a href="https://ruby-china.org/topics/34846" rel="nofollow" target="_blank"&gt;https://ruby-china.org/topics/34846&lt;/a&gt; 。大家都各有各的看法，不过从这个话题的回答中我个人感觉社区中很多人其实是不太支持前后端分离的，毕竟 Rails 这样的全栈框架已经可以很好地适用于大多数应用，Rails 自带的 ujs 和 form 已经足够处理很多前端开发中的常见问题。&lt;/p&gt;

&lt;p&gt;昨天看到有同学也在纠结是 Rails 项目是做成单页应用还是前后端分离 &lt;a href="https://ruby-china.org/topics/36894" rel="nofollow" target="_blank"&gt;https://ruby-china.org/topics/36894&lt;/a&gt; 。我在最近的一个 Rails 项目里也有过这样的纠结和尝试，所以做了一段回答。我把之前问题的回答做了份整理，想说给大家听听。&lt;/p&gt;
&lt;h2 id="我的尝试"&gt;我的尝试&lt;/h2&gt;
&lt;p&gt;我们在项目技术选型时想到有些界面的交互比较复杂，再加上我们想用 ant-design 的 UI，而实现了 ant-design 的 UI 库只有用 React/Vue/Angular 实现的。而 Vue 是一个相对轻量级的库，集成进 Rails 很容易。所以经过考虑，我们决定引入 Vue。但是不做成单页应用，就用后端渲染，想最大程度地利用 Rails 带给我们的便捷。（之前我也看到过很多批判前后分离的，所以在这里我主观上也是不希望做成单页应用的）&lt;/p&gt;

&lt;p&gt;但是到了真正开发的时候，由于我们引入了基于 Vue 的第三方 UI 库，对于 Vue 的依赖其实比较重。而我们又是传统的后端渲染方式，所以碰到了这样几个问题：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;我们开启了 turbolinks，需要在 turbolinks 相应的 callback 中销毁和重新注册相关 Vue 组件。但是我们引入的第三方 UI 库的某些组件在 turbolinks 开启的情况下会出现一些意想不到的的问题。&lt;/li&gt;
&lt;li&gt;表单操作方面，Vue 不能直接在 Rails 原生的表单中使用。如果还是使用 ujs 的方式去处理表单，遇到需要 Vue 去处理某些数据绑定的操作，也还是不方便。如果使用 Vue 去构建 Form，提交表单只能发起异步请求，不会有 Rails 原生表单的行为，一些本来交给 Rails 处理的行为（例如在 controller 中 redirect）需要交给前端处理。而且这样的行为在一个非前后端分离的项目中可能会显得比较怪异。例：如果使用了 Vue 去提交一个表单，想在提交成功之后做 redirect。由于是一个异步请求，Rails 并不能帮助我们进行 redirect，只能在前端使用&lt;code&gt;window.location&lt;/code&gt;这样类似的方式进行 redirect。这个行为既不符合 Rails 也不符合单页应用的规范。（单页应用中通常使用前端 Router 去跳转）&lt;/li&gt;
&lt;li&gt;前后端数据命名规范不一致。在 js 中，命名的规范是 camelCase，在 Rails 中是下划线的形式。使用了 Vue 之后在写前端逻辑时应该会倾向于 camelCase，所以我们还是需要对 Rails 返回给前端的数据做一道转换。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;我们在最初的开发中就一直想着的就是避免做成单页应用，但是随着开发的进展和我们遇到的问题，我们发现我们的代码既不像一个后端渲染应用，也不像单页应用。究其根本，在我们决定使用基于 Vue 的 ant-design UI 库的时候，我们就应当想到重度依赖这些组件的界面，就应当做成单页应用。这样就可以减少很多不必要的麻烦。&lt;/p&gt;
&lt;h2 id="单页应用的缺点"&gt;单页应用的缺点&lt;/h2&gt;
&lt;p&gt;为什么我们在最初会坚持使用后端渲染而不是前后端分离呢？在这时我又重新思考了下项目开始时考虑到的单页应用的缺点：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SEO 问题&lt;/strong&gt;。由于单页应用依赖 js 渲染，所以 SEO 一直是老生常谈的问题。只能通过引入 SSR（服务端渲染）解决。但是如果我们现在正在开发的是一个管理系统（SaaS/OA/CRM），大多数界面都是需要登录之后才可以访问的，所以爬虫压根就没有机会进入这些界面，也就不存在 SEO 的问题。而需要 SEO 的界面通常不会有很麻烦的交互，完全可以摆脱对前端框架的依赖，直接使用后端渲染。&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;首屏加载&lt;/strong&gt;。有很多调查表明首屏加载速度慢是网站用户流失的最大原因之一。单页应用需要在首页中加载大量的资源文件，所以加载耗时会比后端渲染更费时。但是现在主流的前端框架在 build production 版本的时候都会对资源文件进行优化压缩，配合 Lazy Loading、gzip，最后得到的资源文件大小并不会很大。&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;让 Rails 变成了一个 API&lt;/strong&gt;。Rails 在这里只是一个提供数据，处理后端业务逻辑的 API。Rails 中很多便利的东西我们都不能使用（View helper、form 以及很多前端相关的 gem）。在后端渲染情况下，同一个界面我们只需要维护一份 view。但是前后分离的话，在 Rails 层面我们需要维护返回的 json，在前端去维护真正的界面 template。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;这三个主要痛点中，最后一点是我们无法去改变去优化的。Rails 这个全栈框架带给前端开发的各种优点，我们都将无法从中获益。&lt;strong&gt;但是换一个角度思考，在我自己的例子中，我因为不忍心放弃 Rails 在前端开发中的优势，在一些并不太适合用后端渲染的界面中使用 Rails 去渲染，反而束缚了自己，让 Rails 的这些优点成为了“阻碍”&lt;/strong&gt;。&lt;/p&gt;
&lt;h2 id="后端渲染还是前后端分离？"&gt;后端渲染还是前后端分离？&lt;/h2&gt;
&lt;p&gt;这个问题没有标准答案，一切都需要根据我们的场景和环境所决定。针对于我们的场景，既然我们选择了基于 Vue 的 UI 库，也就意味着我们在前端方面会强依赖于 Vue，这时候如果为了使用后端渲染而选择后端渲染，则显得很不合时宜。事实也证明，强行后端渲染让我们花费了更多的精力去调试很多意外的问题，最后得到的还是一份不规范的代码。
究竟该如何选择，我想给出点简单的建议：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;如果你有很多重前端的场景，一些业务场景重度依赖于 React/Vue，或者说你使用了一些基于 React/Vue 的 UI 库。为了减少你处理一些不必要的麻烦的时间，建议直接上 SPA。一些轻交互或者无交互简单界面可以依旧使用后端渲染，更加方便。&lt;/li&gt;
&lt;li&gt;如果你仅仅是用 React/Vue 处理某些交互麻烦的地方，如果 React/Vue 对当前项目来说只是 jQuery 般的存在，后端渲染会是更好的选择。Rails 在很多产品中的成功经验让我们有这个信心能用 Rails 就完成大多数前端的开发工作。&lt;/li&gt;
&lt;li&gt;最最重要的是，选择适合当前团队的方案。如果你现在的团队成员有过 SPA 的经验，并且更适应 SPA 的开发方式，那么前后端分离无论是对于开发效率还是质量来说可能都是更好的方式。反之，如果你的团队更熟悉传统的后端渲染的方式，为什么就一定要为了前后端分离而分离呢？前后端分离只是一种不同的开发方式，前后端分离可以实现的业务使用后端渲染一样可以实现。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;无论是后端渲染还是前后端分离，我们的目的都是为了解决问题。二者并没有优劣之分，都是针对 Web 开发的解决方案。无论我们采用其中哪种方式，使用怎样的框架和库，都是为了提升开发效率和质量，都是了给我们自己带来便利。而不是让我们自己去硬生生地去为了使用后端渲染或者前后端分离强行去适应，反而制造出很多本来没有的问题。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;你不必因为这几年前端的“热”就去盲目追随这个潮流，所有场景不加思索就直接前后端分离，放弃后端渲染。同时，你也不必像我一样，在过于依赖前端框架、使用前后端分离会更合适的场景硬要上后端渲染&lt;/strong&gt;。看清楚当前的业务场景，找到适合自己和团队的方式，高效高质量地开发才是我们最终的目标。&lt;/p&gt;</description>
      <author>lokyoung</author>
      <pubDate>Thu, 07 Jun 2018 00:05:53 +0800</pubDate>
      <link>https://ruby-china.org/topics/36915</link>
      <guid>https://ruby-china.org/topics/36915</guid>
    </item>
    <item>
      <title>使用 Jenkins 在 Ubuntu 下构建 Rails 持续集成环境</title>
      <description>&lt;h2 id="前言"&gt;前言&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;持续集成 (continuous integration)&lt;/strong&gt;，就是在敏捷开发中经常提到的 CI。&lt;br&gt;
每一次代码提交更新都要通过 CI 中的自动化测试，这样可以 &lt;strong&gt;尽早发现现有的 bug&lt;/strong&gt;。其目的在于让 &lt;strong&gt;产品快速迭代的同时，尽可能保持高质量&lt;/strong&gt;。&lt;br&gt;
以我们做 Rails 的开发为例，为例保证项目的质量，我们都会写一定的自动化测试 (例如 RSpec、minitest)。在多人协作的项目中，我们会基于当前的开发 (develop) 分支，开一个新的分支进行开发，在代码合并到 develop 分支前，跑一遍测试，通过了才能合并。如果没有 CI，这样的一个操作都是开发人员手动在本地操作的，这样也会带来一些潜在的问题。首先由于测试都是由手动触发并且在本地运行，所以每次开发人员都必须要记住去跑测试，并且这个操作有时也会是很耗时的。其次每一个人本地的环境不一定是一致的，同样的测试在某一个开发人员本地通过了，在另一个人的 PC 或者线上并不一定可以通过。在引入了 CI 之后，每一次提交都会在 CI 服务器上运行测试，这样不仅将之前需要手动触发的操作自动化，同时也保证了测试是在统一的环境 (CI 服务器) 下运行的。&lt;/p&gt;

&lt;p&gt;CI 保证了交付的质量和效率，给开发团队提供了极大的帮助。不过现有的 CI 服务价格通常都十分昂贵 (以 RubyChina 使用的 Travis CI 为例，对于开源项目是免费的，但是私有项目的最低价格高达$69/month)。所以很多团队会选择开源的持续集成工具搭建自己的 CI 服务，其中最出名的就是&lt;a href="https://jenkins.io/" rel="nofollow" target="_blank" title=""&gt;Jenkins&lt;/a&gt;了。社区里 Jenkins 相关的中文资料不多，我最近正好在做相关的工作，所以就整理成了这篇博客。&lt;/p&gt;
&lt;h2 id="环境搭建"&gt;环境搭建&lt;/h2&gt;
&lt;p&gt;在这里首先介绍下我使用服务器的一些基本信息，我使用的是 digitalocean 的$10/month 的 VPS（单核 CPU、1GB 内存、30GB SSD，最开始时候用的是$5，但是每次使用 jenkins 进行 build 时都会因为内存不够而进程崩溃），使用的操作系统是 Ubuntu 14.04.5 x64，Jenkins 的版本是 2.19.4。你也可以选择在本地操作系统直接搭建或者使用 Vagrant 搭建。&lt;/p&gt;
&lt;h3 id="Jenkins Setup"&gt;Jenkins Setup&lt;/h3&gt;
&lt;p&gt;在 Ubuntu 上安装 jenkins&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;wget &lt;span class="nt"&gt;-q&lt;/span&gt; &lt;span class="nt"&gt;-O&lt;/span&gt; - https://pkg.jenkins.io/debian/jenkins.io.key | &lt;span class="nb"&gt;sudo &lt;/span&gt;apt-key add -
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s1"&gt;'echo deb http://pkg.jenkins.io/debian-stable binary/ &amp;gt; /etc/apt/sources.list.d/jenkins.list'&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get update
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install &lt;/span&gt;jenkins
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这几段命令执行完成之后 jenkins 成功安装在你的机器上并且运行在 8080 端口上了，同时你系统中也新建了一个名为&lt;code&gt;jenkins&lt;/code&gt;的用户。
这时你可以在浏览器中访问你服务器的 8080 端口，页面会提示你系统的初始密码存储在&lt;code&gt;/var/lib/jenkins/secrets/initialAdminPassword&lt;/code&gt;这个文件里。从里面获取密码粘贴到界面的输入框后就完成了认证。认证之后会让你给你两个安装 plugin 的选项，我有些选择恐惧症，所以就选择了安装推荐的 plugin。
安装完成后会让你填写用户名、密码之类的基本信息，以后从浏览器登录 jenkins 后台时需要用到。填写完成后就进入了 jenkins 的 dashboard。&lt;/p&gt;

&lt;p&gt;由于之后会使用 jenkins 用户安装 Ruby，需要 root 权限。所以在这里我们给予该用户 root 权限。&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 把jenkins用户加入sudo用户组&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;adduser jenkins &lt;span class="nb"&gt;sudo&lt;/span&gt;
&lt;span class="c"&gt;# 设置密码（也可以选择在visudo设置NOPASSWD让用户请求sudo权限时不需要输入密码）&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;passwd jenkins
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="Ruby环境搭建"&gt;Ruby 环境搭建&lt;/h3&gt;
&lt;p&gt;首先安装 Ruby 相关的一些依赖&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;su - jenkins
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install &lt;/span&gt;autoconf bison build-essential libssl-dev libyaml-dev libreadline6 libreadline6-dev zlib1g zlib1g-dev
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在这里我使用了&lt;code&gt;rvm&lt;/code&gt;去管理 CI 服务器上的 Ruby 版本。
安装 rvm&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;gpg &lt;span class="nt"&gt;--keyserver&lt;/span&gt; hkp://keys.gnupg.net &lt;span class="nt"&gt;--recv-keys&lt;/span&gt; 409B6B1796C275462A1703113804BB82D39DC0E3
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="se"&gt;\c&lt;/span&gt;url &lt;span class="nt"&gt;-sSL&lt;/span&gt; https://get.rvm.io | bash
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;将 rvm 加入 shell profile 中，在.bashrc 文件下加入下面这行&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/.rvm/scripts/rvm"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;source&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/.rvm/scripts/rvm"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;安装项目中的 Ruby 版本 (我的是 2.3.1)&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;rvm &lt;span class="nb"&gt;install &lt;/span&gt;2.3.1
&lt;span class="nv"&gt;$ &lt;/span&gt;rvm use 2.3.1
&lt;span class="c"&gt;# 安装bunlder&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;gem &lt;span class="nb"&gt;install &lt;/span&gt;bundler
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;安装一些 gem 相关的依赖，因为很多时候我们的 rails 应用需要 JavaScript runtime，所以在这里我也安装了 nodejs&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install &lt;/span&gt;libcurl3-dev libpq-dev nodejs
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="安装PostgreSQL"&gt;安装 PostgreSQL&lt;/h3&gt;
&lt;p&gt;在我的服务器上我使用 PostgreSQL 作为数据库&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 安装postgres&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install &lt;/span&gt;postgresql postgresql-contrib
&lt;span class="c"&gt;# 设置postgres password，这里为了演示我直接设置成'password'&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo&lt;/span&gt; &lt;span class="nt"&gt;-u&lt;/span&gt; postgres psql &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"ALTER USER postgres PASSWORD 'password';"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;接着配置好 database.yml 文件，在这里我直接在 jenkins 用户 home 目录下创建。&lt;/p&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# ~/ci_database.yml&lt;/span&gt;

&lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nl"&gt;&amp;amp;default&lt;/span&gt;
  &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;    &lt;span class="s"&gt;localhost&lt;/span&gt;
  &lt;span class="na"&gt;adapter&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgresql&lt;/span&gt;
  &lt;span class="na"&gt;encoding&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unicode&lt;/span&gt;
  &lt;span class="na"&gt;pool&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;

&lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;*default&lt;/span&gt;
  &lt;span class="na"&gt;database&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;jenkins_test&lt;/span&gt;
  &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres&lt;/span&gt;
  &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;password&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="ssh配置"&gt;ssh 配置&lt;/h3&gt;
&lt;p&gt;由于我们的 repo 大多数都是用 Git 进行管理的，所以我们也需要在 server 上安装 git&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install &lt;/span&gt;git
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;生成 jenkins 用户的 ssh key&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;ssh-keygen
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里由于我的项目的 repo 在 GitHub 上，所以之后我就以集成 GitHub 为例。&lt;br&gt;
在 shell 中打印出 ssh 公钥，拷贝到你的 Github 用户下&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; ~/.ssh/id_ras.pub
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;建立 ssh 和 Github 的连接&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;ssh &lt;span class="nt"&gt;-T&lt;/span&gt; git@github.com
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="创建jenkins job"&gt;创建 jenkins job&lt;/h2&gt;
&lt;p&gt;首先进入你的 jenkins dashboard，点击页面左上方的&lt;code&gt;New Item&lt;/code&gt;，在新的页面中输入你的 CI job 的名称，然后选择&lt;code&gt;Freestyle project&lt;/code&gt;之后点击 ok 进入下一步。&lt;br&gt;
下一个页面中是对你项目的一些配置。选择 GitHub project 后填写你项目在 GitHub 中的 url。&lt;br&gt;
接着在&lt;code&gt;Source Code Management&lt;/code&gt;中选择&lt;code&gt;Git&lt;/code&gt;，在&lt;code&gt;Repository URL&lt;/code&gt;填写 repo 的 url，由于我们之前配置好了 ssh，所以直接填写 ssh url(git@github:username/repo.git)。&lt;br&gt;
之后选择需要构建的分支，在&lt;code&gt;Branch Specifier&lt;/code&gt;我填写了空，代表所有分支都要进行构建。&lt;br&gt;
接着在&lt;code&gt;Build&lt;/code&gt;中选择&lt;code&gt;Add build step&lt;/code&gt; -&amp;gt; &lt;code&gt;Execute shell&lt;/code&gt;，接着在其中添加你的 build 脚本。&lt;/p&gt;

&lt;p&gt;下面贴出我的 build 脚本，大家可以针对自己需求自己定制。&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash -x                                 # 指定执行本段脚本的shell为bash，默认情况会使用sh&lt;/span&gt;
&lt;span class="nb"&gt;source&lt;/span&gt; ~/.bashrc                               &lt;span class="c"&gt;# 读取rvm&lt;/span&gt;
bundle &lt;span class="nb"&gt;install
cp&lt;/span&gt; ~/my_database.yml ./config/database.yml     &lt;span class="c"&gt;# 将之前写好的数据库配置yml文件拷贝到当前项目中&lt;/span&gt;
&lt;span class="nv"&gt;RAILS_ENV&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;test &lt;/span&gt;bundle &lt;span class="nb"&gt;exec &lt;/span&gt;rake db:setup       &lt;span class="c"&gt;# 初始化数据库&lt;/span&gt;
&lt;span class="nv"&gt;RAILS_ENV&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;test &lt;/span&gt;bundle &lt;span class="nb"&gt;exec &lt;/span&gt;rake &lt;span class="nb"&gt;test&lt;/span&gt;           &lt;span class="c"&gt;# 运行测试，我使用的是minitest&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这时候基本的 Jenkins job 就配置好了，在 dashboard 中你可以自己点击 build 手动触发。每一次 build 都会从 Git repo 中拉取代码，运行你的 build 脚本。只有当脚本中所有的流程都通过并且成功之后，这个 job 的状态才会是成功的。&lt;br&gt;
不过这对我们来说还是不够的，现在只能通过手动触发 build，还并不能在我们每次 commit 并且 push 到 Git repo 后自动完成构建。所以我们需要将我们当前配置好的 Jenkins job 和 Git repo 进行集成。&lt;/p&gt;
&lt;h2 id="GitHub集成"&gt;GitHub 集成&lt;/h2&gt;&lt;h3 id="Commit后自动构建项目"&gt;Commit 后自动构建项目&lt;/h3&gt;
&lt;p&gt;我们在 dashboard 中选中我们的 Project，点击&lt;code&gt;Configuration&lt;/code&gt;再次进入配置界面。&lt;br&gt;
在&lt;code&gt;Build Triggers&lt;/code&gt;配置触发构建的条件。这里我勾选了&lt;code&gt;Build when a change is pushed to GitHub&lt;/code&gt;，这样会在每次 commit push 到 GitHub 上之后进行构建。这也是我们在项目中的通常做法。不过光在 Jenkins 中配置了是不够的，我们需要 GitHub 在每次收到 push 后通过 webhook 告知 Jenkins 可以开始进行构建。&lt;br&gt;
在 GitHub 中进入你 project 的 repository，选择&lt;code&gt;Settings&lt;/code&gt; -&amp;gt; &lt;code&gt;Webhooks&lt;/code&gt; -&amp;gt; &lt;code&gt;Add webhook&lt;/code&gt;接着填写你的 Jenkins hooks url，这段 url 就是 jenkins server 的 url 加上&lt;code&gt;/github-webhook&lt;/code&gt;。例：&lt;a href="http://my-jenkins-server/github-webhook/" rel="nofollow" target="_blank"&gt;http://my-jenkins-server/github-webhook/&lt;/a&gt; 。
在&lt;code&gt;Which events would you like to trigger this webhook?&lt;/code&gt; 中选择 &lt;code&gt;Just the push event&lt;/code&gt;。
配置好后点击&lt;code&gt;Add webhook&lt;/code&gt;。&lt;br&gt;
&lt;em&gt;Note: 这里需要你的 jenkins 安装了 GitHub plugin，如果你在安装 jenkins 时选择了安装推荐的 plugin，是会给你默认装上的。&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;完成后再进行 commit 和 push，你会发现在 push 之后会自动触发 jenkins 的 build 环节。&lt;/p&gt;
&lt;h3 id="更改GitHub commit状态"&gt;更改 GitHub commit 状态&lt;/h3&gt;
&lt;p&gt;使用 CI 服务集成到 Github 时，通常有三种状态：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;pending: 代表构建正在执行中，尚未完成。
&lt;img src="https://l.ruby-china.com/photo/2016/0f9b8a8117d193bae481517efa564115.png!large" title="" alt=""&gt;
&lt;/li&gt;
&lt;li&gt;passed: 代表构建成功。&lt;br&gt;
&lt;img src="https://l.ruby-china.com/photo/2016/4717528719c89d2c9b7b997953d06d3b.png!large" title="" alt=""&gt;
&lt;/li&gt;
&lt;li&gt;failed: 构建失败，通常可能由某些测试没有通过导致。
&lt;img src="https://l.ruby-china.com/photo/2016/5060777e534ab1be287f00c58d6340c1.png!large" title="" alt=""&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;如果想显示这些状态，就需要 Jenkins 将构建的状态进行同步。&lt;/p&gt;
&lt;h4 id="生成GitHub access token"&gt;生成 GitHub access token&lt;/h4&gt;
&lt;p&gt;这里将 Jenkins 的 build 时的一些状态同步到 GitHub 上，Jenkins 向 GitHub 发送请求去同步这些状态，所以需要 GitHub 的 access_token。
进入你 GitHub 账号的 Settings 页面中，选中&lt;code&gt;Developer settings&lt;/code&gt; -&amp;gt; &lt;code&gt;Personal access tokens&lt;/code&gt; -&amp;gt; &lt;code&gt;Generate access token&lt;/code&gt;。在&lt;code&gt;Select scopes&lt;/code&gt;中选择 token 可以操作的 scope，选中&lt;code&gt;repo&lt;/code&gt;和&lt;code&gt;admin:repo_hook&lt;/code&gt;，之后点击&lt;code&gt;Generate token&lt;/code&gt;。token 生成后复制到你的剪贴板上，我们在 Jenkins 的配置中会用到它。&lt;/p&gt;
&lt;h4 id="配置jenkins GitHub Configuration"&gt;配置 jenkins GitHub Configuration&lt;/h4&gt;
&lt;p&gt;进入 Jenkins 的 dashboard，点击左侧的&lt;code&gt;Manage Jenkins&lt;/code&gt; -&amp;gt; &lt;code&gt;Configure System&lt;/code&gt;，找到&lt;code&gt;GitHub&lt;/code&gt;这栏，点击 Add GitHub Server，之后在 Credentials 那栏中点击&lt;code&gt;Add&lt;/code&gt;。在 Kind 中选择&lt;code&gt;Secret text&lt;/code&gt;，将之前复制的 access token 粘贴到 Secret 那栏，在 ID 中可以选择给这条 credential 命名。最后点击&lt;code&gt;Add&lt;/code&gt;就完成了，然后在 Credentials 那栏选中你刚刚添加的 credential。点击屏幕下方的&lt;code&gt;Save&lt;/code&gt;保存配置修改。&lt;/p&gt;
&lt;h4 id="设置commit status"&gt;设置 commit status&lt;/h4&gt;
&lt;p&gt;回到 dashboard，进入 job 的 Configuration 界面，在&lt;code&gt;Build&lt;/code&gt;中选择&lt;code&gt;Add build step&lt;/code&gt; -&amp;gt; &lt;code&gt;Set build status to "pending" on GitHub commit&lt;/code&gt;。添加后拖动这个 build step 到之前添加的&lt;code&gt;Execute shell&lt;/code&gt;之前。这样才能保证在 build 开始前就把 commit status 设置成 pending。&lt;br&gt;
&lt;img src="https://l.ruby-china.com/photo/2016/910e7f31276f47ad09367fbd51f1013d.png!large" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;之后在&lt;code&gt;Post-build Actions&lt;/code&gt;中选择&lt;code&gt;Add post-build action&lt;/code&gt; -&amp;gt; &lt;code&gt;Set GitHub commit status&lt;/code&gt;。在&lt;code&gt;Status result&lt;/code&gt;那栏中选择&lt;code&gt;One of default messages and statuses&lt;/code&gt;。配置好后点击&lt;code&gt;Save&lt;/code&gt;保存。这样配置完成之后，你在 GitHub 中每一次 commit 的状态都会随着 CI 的状态而改变。
&lt;img src="https://l.ruby-china.com/photo/2016/884e5a648d8654a3edb77729f676abf9.png!large" title="" alt=""&gt;&lt;/p&gt;
&lt;h2 id="结语"&gt;结语&lt;/h2&gt;
&lt;p&gt;持续集成给现在的开发工作带来了很大的便利，将构建操作自动化，可以显著帮助开发者尽早发现现有系统中的问题。完成稳定而又高效的迭代。Jenkins 作为一个开源的持续集成软件，可以让我们可以自定义搭建一个免费的持续服务。&lt;br&gt;
Jenkins 中也提供了各种各样强大的插件（例如 RVM 插件，可以让 RVM 安装并且使用当前 project 中指定的 Ruby 版本），现在的 Jenkins 自身也支持持续部署、持续交付的功能。个人认为 Jenkins 对于开发者还是有相当大的学习使用价值的。我在这里也仅仅是一个 Getting Started 的介绍，有不正确的地方希望大家指正，也希望有感兴趣的朋友以后能在社区里一起交流相关的问题，大家共同进步。&lt;/p&gt;
&lt;h2 id="参考资料"&gt;参考资料&lt;/h2&gt;
&lt;p&gt;&lt;a href="http://www.eq8.eu/blogs/6-jenkins-ci-for-rails-4-rspec-cucumber-selenium" rel="nofollow" target="_blank" title=""&gt;Jenkins CI for Rails 4, RSpec, Cucumber, Selenium&lt;/a&gt;&lt;br&gt;
&lt;a href="https://gist.github.com/ostinelli/b77c20d91e4e33507813" rel="nofollow" target="_blank" title=""&gt;Jenkins CI on Ubuntu&lt;/a&gt;&lt;/p&gt;</description>
      <author>lokyoung</author>
      <pubDate>Fri, 09 Dec 2016 16:17:54 +0800</pubDate>
      <link>https://ruby-china.org/topics/31857</link>
      <guid>https://ruby-china.org/topics/31857</guid>
    </item>
    <item>
      <title>使用 Upstart + Inspeqtor 管理你的 Sidekiq (监控、崩溃自动重启、邮件通知)</title>
      <description>&lt;h2 id="前言"&gt;前言&lt;/h2&gt;
&lt;p&gt;最近在工作中碰到一个问题，服务器上的 Sidekiq 崩溃之后，由于我们在服务器端并没有对 Sidekiq 进行监控和管理，当察觉到 Sidekiq 进程崩溃时已经有大量的 background job 停留在队列中无法执行。
这无疑是一件相当痛苦的事，所以我开始找寻办法去解决这一问题。
而实际上，Sidekiq 的作者就已经给出了最好的解决方案 (可以参考他博客的文章&lt;a href="http://www.mikeperham.com/2015/07/16/sidekiq-and-upstart/" rel="nofollow" target="_blank" title=""&gt;Sidekiq and Upstart&lt;/a&gt;)——用 Ubuntu 自带的&lt;em&gt;Upstart&lt;/em&gt;去保证 Sidekiq 不会因为 Ruby 虚拟机崩溃等原因停止工作，用&lt;em&gt;Inspeqtor&lt;/em&gt;结合 Upstart 去监控你的 Sidekiq（Sidekiq 进程失败时发送邮件通知）。&lt;/p&gt;
&lt;h2 id="Upstart"&gt;Upstart&lt;/h2&gt;&lt;h3 id="简介"&gt;简介&lt;/h3&gt;
&lt;p&gt;Upstart 是 Ubuntu 系统自带的基于事件的初始化常驻程序，可以在系统开机和关机时启动和关闭服务，在系统运行时对服务进行监督。
Upstart 可以让被监督的进程在非正常关闭时，自动重启该进程，保证其在系统中正常稳定地运行。
可以使用系统自带的工具去解决问题，相比较使用第三方工具而言，无疑是更好的方式。所以我选择了 Upstart 来管理服务器上的 Sidekiq 进程。&lt;br&gt;
&lt;strong&gt;PS&lt;/strong&gt;: Upstart 除了可以在 Ubuntu 系统上使用外，在 Debian、Fedora、openSUSE、Chrome OS 等发行版上也有相关支持。而在最近两年一些 Linux 发行版的新版本中（Ubuntu 15.04, CentOS 7 等），可以使用更先进的 Systemd 实现 Upstart 的功能。Upstart 的详细信息，可以参考 Ubuntu 官方的&lt;a href="http://upstart.ubuntu.com/cookbook/" rel="nofollow" target="_blank" title=""&gt;Upstart Cookbook&lt;/a&gt;。&lt;/p&gt;
&lt;h3 id="Upstart监督Sidekiq配置"&gt;Upstart 监督 Sidekiq 配置&lt;/h3&gt;
&lt;p&gt;在服务器的/etc/init 目录下新建一个&lt;code&gt;*.conf&lt;/code&gt;文件，在这里我新建了一个名为&lt;code&gt;sidekiq.conf&lt;/code&gt;的配置文件。&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# /etc/init/sidekiq.conf - Sidekiq config&lt;/span&gt;

description &lt;span class="s2"&gt;"Sidekiq Background Worker"&lt;/span&gt;

&lt;span class="c"&gt;# 在系统开机时启动服务，关机时关闭服务&lt;/span&gt;
start on runlevel &lt;span class="o"&gt;[&lt;/span&gt;2345]
stop on runlevel &lt;span class="o"&gt;[&lt;/span&gt;06]

&lt;span class="c"&gt;# 在进程崩溃时自动重启进程&lt;/span&gt;
respawn
&lt;span class="c"&gt;# 30秒之内尝试3次重启，如果失败，则放弃重启&lt;/span&gt;
respawn limit 3 30

&lt;span class="c"&gt;# 正常退出所接收到的信号，0(Linux程序正常退出码)&lt;/span&gt;
&lt;span class="c"&gt;# TERM是通过sidekiqctl停止sidekiq时发送的信号&lt;/span&gt;
&lt;span class="c"&gt;# 除了这两种信号之外，其余任何终止sidekiq的方式都会触发respawn&lt;/span&gt;
normal &lt;span class="nb"&gt;exit &lt;/span&gt;0 TERM

&lt;span class="c"&gt;# 通过reload指令向正在运行的进程发送USR1信号(对于Sidekiq来说，USR1意味着停止接收新的background job)&lt;/span&gt;
reload signal USR1

&lt;span class="c"&gt;# 通过upstart启动的sidekiq实例的序号&lt;/span&gt;
instance &lt;span class="nv"&gt;$index&lt;/span&gt;

script
&lt;span class="c"&gt;# this script runs in /bin/sh by default&lt;/span&gt;
&lt;span class="c"&gt;# respawn as bash so we can source in rbenv&lt;/span&gt;
&lt;span class="nb"&gt;exec&lt;/span&gt; /bin/bash &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="no"&gt;EOT&lt;/span&gt;&lt;span class="sh"&gt;'
  # Pick your poison :) Or none if you're using a system wide installed Ruby.
  # rbenv
  # source /home/apps/.bash_profile
  # OR
  # source /home/apps/.profile
  # OR system:
  # source /etc/profile.d/rbenv.sh
  #
  # rvm
  # source /home/apps/.rvm/scripts/rvm

  # Logs out to /var/log/upstart/sidekiq.log by default

  cd /var/www/app
  # 注：这里必须在bundle exec前加上exec，否则会在另外一个进程(不受Upstart监控)中开启sidekiq
  # sidekiq -i 的参数和之前传入是实例序号index一致
  exec bundle exec sidekiq -i &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;index&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="sh"&gt; -e production
&lt;/span&gt;&lt;span class="no"&gt;EOT
&lt;/span&gt;end script
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;只需要上面这个简单的配置文件，就完成了 Upstart 中 sidekiq 的配置。接下来，我们需要通过 Upstart 来启动 sidekiq，这样才可以让 sidekiq 进程在 Upstart 的监督下运行。&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 由于在系统中可以开启多个sidekiq进程，所以你可以通过指定sidekiq进程的编号方便你对某一个sidekiq进程进行管理&lt;/span&gt;
&lt;span class="c"&gt;# 下列启动序号为0的sidekiq实例（在我们我应用中，只需要一个sidekiq进程）&lt;/span&gt;
&lt;span class="c"&gt;# 启动sidekiq&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;service sidekiq start &lt;span class="nv"&gt;index&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0

&lt;span class="c"&gt;# 终止sidekiq&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;service sidekiq stop &lt;span class="nv"&gt;index&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0

&lt;span class="c"&gt;# 重启sidekiq&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;service sidekiq restart &lt;span class="nv"&gt;index&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在通过 Upstart 的方式启动 sidekiq 之后，sidekiq 进程如果遇到异常情况造成崩溃，之后立刻重生（重新启动一个 sidekiq 进程）。你可以尝试使用 kill 的方式强制关闭 sidekiq，会发现 sidekiq 不会在你的进程列表中消失（pid 会改变)。现在你只能通过以上命令中的 stop 来关闭 sidekiq。&lt;/p&gt;
&lt;h3 id="部署"&gt;部署&lt;/h3&gt;
&lt;p&gt;sidekiq 部署的最佳实践，是尽可能早的让 sidekiq 处于 quiet 状态（停止接受新的 job，只处理当前在队列中的 job），并且尽可能晚的重启 sidekiq。
在/etc/init/sidekiq.conf 中我们曾指定过 reload signal USR1，这表示向当前 Upstart 进程发送 reload 命令时，传送一个名为 USR1 的信号过去。USR1 是 sidekiq 系统内置的一个信号量，当 sidekiq 接收到这个信号时，便会进入 quiet 状态。&lt;br&gt;
在你的部署脚本的早期阶段执行以下命令：&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;service sidekiq reload &lt;span class="nv"&gt;index&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;重启 sidekiq 也十分地方便，使用 Upstart 自带的 restart 即可，restart 命令会停止当前任务，之后再次启动。不过 restart 命令和单纯地先执行 stop 然后执行 start 不一样，restart 命令会保留当前任务停止时的各项配置，在重新启动时从硬盘中读取这些信息。这样就不会造成如果在重启时，如果正好有任务还在队列中执行，却因为重启而停止导致没有执行完的情况了。
在你的部署脚本中尽量靠后的位置运行重启命令：&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;service sidekiq restart &lt;span class="nv"&gt;index&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;PS&lt;/strong&gt;: 由于 sudo 需要输入密码，而在自动化部署时无法输入密码。而我们启动 Upstart 是通过 service 的方式，所以可以让部署用户在执行 service 命令时不需要输入密码。
打开 sudo 配置文件：&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;visudo
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在打开的配置文件中加上一行（用你的系统用户名替换 current_user）&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;current_user &lt;span class="nv"&gt;ALL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;NOPASSWD:/usr/sbin/service
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="Inspeqtor"&gt;Inspeqtor&lt;/h2&gt;&lt;h3 id="简介"&gt;简介&lt;/h3&gt;
&lt;p&gt;Inspeqtor 是 Sidekiq 作者自己写的一个监控工具，可以对系统中的开启的服务（通过 init.d, systemd 或者 upstart 启动的进程）进行监控。
同时也可以监控进程的内存占用量和 CPU 使用量。你可以针对不同的进程配置相应的监控规则，在违反这些规则时重启进程或者向你发送邮件告知。
在之前我们通过配置 Upstart 启动 Sidekiq，所以可以使用 Inspeqtor 对 Sidekiq 进程进行监控（这里主要想实现的目标，是在 Sidekiq 崩溃重启时可以收到邮件通知）。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PS&lt;/strong&gt;：Inspeqtor 和 God, bluepill 等基于 Ruby 的监控工具不同，Inspeqtor 不需要依赖于 Ruby，所以安装也更加方便。&lt;/p&gt;
&lt;h3 id="环境搭建和通知邮箱配置"&gt;环境搭建和通知邮箱配置&lt;/h3&gt;&lt;h4 id="安装"&gt;安装&lt;/h4&gt;
&lt;p&gt;Inspeqtor 的安装教程可以在&lt;a href="https://github.com/mperham/inspeqtor/wiki/Installation" rel="nofollow" target="_blank" title=""&gt;官方 wiki&lt;/a&gt;中找到，在这里我只列出 Ubuntu 系统中的安装方式。&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;curl &lt;span class="nt"&gt;-L&lt;/span&gt; https://bit.ly/InspeqtorDEB | &lt;span class="nb"&gt;sudo &lt;/span&gt;bash
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install &lt;/span&gt;inspeqtor
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="命令行基本操作"&gt;命令行基本操作&lt;/h4&gt;
&lt;p&gt;这里同样参考自 wiki，有兴趣的朋友可以好好研读。
CentOS 6.5 / Ubuntu with Upstart&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;initctl start inspeqtor
&lt;span class="nv"&gt;$ &lt;/span&gt;initctl stop inspeqtor
&lt;span class="nv"&gt;$ &lt;/span&gt;initctl restart inspeqtor
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;inspeqtor 的 log 会在/var/log/upstart/inspeqtor.log 中输出。&lt;/p&gt;
&lt;h4 id="邮箱配置"&gt;邮箱配置&lt;/h4&gt;
&lt;p&gt;对发送 email 的配置在 inspeqtor 的全局配置文件/etc/inspeqtor/inspeqtor.conf 中。
可以通过配置 gmail，普通的 smtp 邮箱和服务器本机的 smtp 邮件服务三种方式发送邮件。
这里我列出普通 smtp 邮箱的配置&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# /etc/inspeqtor/inspeqtor.conf&lt;/span&gt;

send alerts via email with
  username bubba,
  password &lt;span class="s2"&gt;"correct horse battery staple"&lt;/span&gt;,
  smtp_server smtp.example.com,
  to_email accounting@example.com,
  tls_port 587
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;更多的配置可以查看官方 wiki 中的&lt;a href="https://github.com/mperham/inspeqtor/wiki/Global-Configuration" rel="nofollow" target="_blank" title=""&gt;Global Configuration&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PS&lt;/strong&gt;: inspeqtor 标准版只能指定一个收件邮箱，如果你想让多个邮箱接收 inspeqtor 邮件，可以使用邮件组。&lt;/p&gt;
&lt;h3 id="监控sidekiq"&gt;监控 sidekiq&lt;/h3&gt;
&lt;p&gt;我们之前通过使用 Upstart 实现了让 sidekiq 意外崩溃时的自动重生，在这里我们需要的只是在 sidekiq 崩溃重启时发生邮件通知我们。
由于 inspeqtor 默认会在其监控下进程的 pid 改变时发送邮件通知，所以监控 sidekiq 的配置文件非常简单。
新建配置文件/etc/inspeqtor/services.d/sidekiq.inq。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PS&lt;/strong&gt;: 按道理说，在这里我们只需要添加一个配置文件即可，不需要添加监控规则（因为 pid 改变时会自动发送邮件），但是我尝试过，如果不添加一条监控规则，inspeqtor 是不会对 sidekiq 进行监控的。所以我随意添加了一条 CPU 占用率 2 次大于 95% 时发送邮件通知的规则。&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# /etc/inspeqtor/services.d/sidekiq.inq&lt;/span&gt;

check service sidekiq
  &lt;span class="k"&gt;if &lt;/span&gt;cpu:user &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; 95% &lt;span class="k"&gt;for &lt;/span&gt;2 cycles &lt;span class="k"&gt;then &lt;/span&gt;alert
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;配置完成后，执行 restart 指令重新启动 inspeqtor 便可以在 sidekiq 进程崩溃时收到邮件。&lt;/p&gt;
&lt;h3 id="inspeqtor部署集成"&gt;inspeqtor 部署集成&lt;/h3&gt;
&lt;p&gt;之前曾经提到过，inspeqtor 在进程的 pid 变化时会触发 alert（发送邮件）。而我们在部署时是会对 sidekiq 进行重启的（pid 会改变），那么在默认情况下，部署时会收到 inspeqtor 发来的通知邮件。很显然，这样的邮件是没有必要的。所以 inspeqtor 提供了针对部署时的指令，可以在应用部署期间暂停对进程的监控，这样就不会收到不必要的通知了。&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 在部署开始时运行这条指令（建议在部署脚本的第一步运行）&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;inspeqtorctl start deploy

&lt;span class="c"&gt;# 在部署结束时运行(建议在部署脚本的最后执行)&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;inspeqtorctl finish deploy
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;PS&lt;/strong&gt;: inspeqtorctl 默认情况下需要 sudo 才可以执行，可以通过修改 inspeqtor 的 Upstart 配置文件（/etc/init/inspeqtor.conf）指定当前用户所在 group，group 中的用户执行 inspeqtorctl 就不需要输入 sudo 了。&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# /etc/init/inspeqtor.conf&lt;/span&gt;

setgid current_user_group
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="参考资料"&gt;参考资料&lt;/h2&gt;
&lt;p&gt;&lt;a href="http://www.mikeperham.com/2015/07/16/sidekiq-and-upstart/" rel="nofollow" target="_blank" title=""&gt;Sidekiq and Upstart&lt;/a&gt;
&lt;a href="http://upstart.ubuntu.com/cookbook/" rel="nofollow" target="_blank" title=""&gt;Upstart Cookbook&lt;/a&gt;&lt;/p&gt;</description>
      <author>lokyoung</author>
      <pubDate>Sun, 17 Apr 2016 22:24:44 +0800</pubDate>
      <link>https://ruby-china.org/topics/29752</link>
      <guid>https://ruby-china.org/topics/29752</guid>
    </item>
    <item>
      <title>carrierwave 上传中文名称的文件后，文件名无法显示</title>
      <description>&lt;p&gt;如题，使用 carrierwave 上传文件，英文名的文件正常。但是含有汉字的文件上传后，文件名就变成了 ____  这样的，无法正常显示。这个该怎么去调整。&lt;/p&gt;</description>
      <author>lokyoung</author>
      <pubDate>Sat, 31 Oct 2015 15:37:04 +0800</pubDate>
      <link>https://ruby-china.org/topics/27903</link>
      <guid>https://ruby-china.org/topics/27903</guid>
    </item>
    <item>
      <title>Ruby China 生日快乐~</title>
      <description>&lt;p&gt;刚刚刷下社区发现今天是 Ruby China 的创立 4 周年纪念日。作为一个 Ruby 的新人和 Ruby 的爱好者，祝 Ruby China 生日快乐，送上最诚挚的祝福~&lt;/p&gt;</description>
      <author>lokyoung</author>
      <pubDate>Wed, 28 Oct 2015 00:14:19 +0800</pubDate>
      <link>https://ruby-china.org/topics/27857</link>
      <guid>https://ruby-china.org/topics/27857</guid>
    </item>
    <item>
      <title>想问一下 GitHub Pages 的页面怎么让百度能抓取到</title>
      <description>&lt;p&gt;如题，我的博客是用 github pages 进行建立的。
github pages 貌似会拒绝百度爬虫的抓取（说是由于百度爬虫抓取频率过于频繁导致）。
我也尝试使用了国内的 cdn，但用百度站长进行测试还是无法抓取。
虽说技术博客给不给百度收录也没什么影响，但还是想请教下论坛的各位前辈有没有办法解决这个问题。
Thanks!&lt;/p&gt;</description>
      <author>lokyoung</author>
      <pubDate>Sun, 20 Sep 2015 15:34:58 +0800</pubDate>
      <link>https://ruby-china.org/topics/27406</link>
      <guid>https://ruby-china.org/topics/27406</guid>
    </item>
  </channel>
</rss>
