<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Zero&#39;s Blog</title>
  <subtitle>点滴分享 多彩生活</subtitle>
  <link href="/atom.xml" rel="self"/>
  
  <link href="http://czero000.github.io/"/>
  <updated>2017-01-11T09:09:51.094Z</updated>
  <id>http://czero000.github.io/</id>
  
  <author>
    <name>C.c</name>
    
  </author>
  
  <generator uri="http://hexo.io/">Hexo</generator>
  
  <entry>
    <title>keepalived切换通知脚本</title>
    <link href="http://czero000.github.io/2017/01/11/keepalived-mail-notify.html"/>
    <id>http://czero000.github.io/2017/01/11/keepalived-mail-notify.html</id>
    <published>2017-01-11T08:59:19.000Z</published>
    <updated>2017-01-11T09:09:51.094Z</updated>
    
    <content type="html"><![CDATA[<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div></pre></td><td class="code"><pre><div class="line">more changeState_mail.py</div><div class="line">#!/usr/bin/python</div><div class="line"># -*- coding: UTF-8 -*-</div><div class="line">import smtplib</div><div class="line">import socket</div><div class="line">import time</div><div class="line">from email.MIMEText import MIMEText</div><div class="line">from email.Utils import formatdate</div><div class="line">from email.Header import Header</div><div class="line">import sys</div><div class="line"></div><div class="line">#发送邮件的相关信息，根据实际情况填写</div><div class="line">smtpHost = &apos;mail.xxx.com&apos;</div><div class="line">smtpPort = &apos;25&apos;</div><div class="line">sslPort  = &apos;465&apos;</div><div class="line">fromMail = &apos;user@xxx.com&apos;</div><div class="line">toMail  = &apos;user@xxx.com&apos;</div><div class="line">username = &apos;user@xxx.com&apos;</div><div class="line">password = &apos;passwd&apos;</div><div class="line">#解决中文问题</div><div class="line">reload(sys)</div><div class="line">sys.setdefaultencoding(&apos;utf8&apos;)</div><div class="line"> </div><div class="line">#邮件标题和内容</div><div class="line"> subject  = socket.gethostname() + &quot; HA status has changed&quot;</div><div class="line"> body= (time.strftime(&quot;%Y-%m-%d %H:%M:%S&quot;)) + &quot; vrrp transition, &quot; + socket.gethostname() + &quot; changed to be &quot; + sys.argv[1]</div><div class="line">  </div><div class="line">#初始化邮件</div><div class="line">  encoding = &apos;utf-8&apos;</div><div class="line">  mail = MIMEText(body.encode(encoding),&apos;plain&apos;,encoding)</div><div class="line">  mail[&apos;Subject&apos;] = Header(subject,encoding)</div><div class="line">  mail[&apos;From&apos;] = fromMail</div><div class="line">  mail[&apos;To&apos;] = toMail</div><div class="line">  mail[&apos;Date&apos;] = formatdate()</div><div class="line">   </div><div class="line">   try:</div><div class="line">#连接smtp服务器，明文/SSL/TLS三种方式，根据你使用的SMTP支持情况选择一种</div><div class="line">#普通方式，通信过程不加密</div><div class="line">#smtp = smtplib.SMTP(smtpHost,smtpPort)</div><div class="line">#smtp.ehlo()</div><div class="line">#smtp.login(username,password)</div><div class="line">    </div><div class="line">#tls加密方式，通信过程加密，邮件数据安全，使用正常的smtp端口</div><div class="line">#smtp = smtplib.SMTP(smtpHost,smtpPort)</div><div class="line">#smtp.ehlo()</div><div class="line">#smtp.starttls()</div><div class="line">#smtp.ehlo()</div><div class="line">#smtp.login(username,password)</div><div class="line">	 </div><div class="line">#纯粹的ssl加密方式，通信过程加密，邮件数据安全</div><div class="line">		smtp = smtplib.SMTP_SSL(smtpHost,sslPort)</div><div class="line">		smtp.ehlo()</div><div class="line">		smtp.login(username,password)</div><div class="line">				  </div><div class="line">#发送邮件</div><div class="line">		smtp.sendmail(fromMail,toMail,mail.as_string())</div><div class="line">		smtp.close()</div><div class="line">		print &apos;OK&apos;</div><div class="line">	except Exception:</div><div class="line">	    print &apos;Error: unable to send email&apos;</div></pre></td></tr></table></figure>
<p><a href="http://ofc9x1ccn.bkt.clouddn.com/keepalived/changeState_mail.py" target="_blank" rel="external">changeState_mail.py</a></p>
]]></content>
    
    <summary type="html">
    
      &lt;figure class=&quot;highlight plain&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;div class=&quot;line&quot;&gt;1&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;2&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;3&lt;/di
    
    </summary>
    
      <category term="Web" scheme="http://czero000.github.io/categories/Web/"/>
    
      <category term="Keepalived" scheme="http://czero000.github.io/categories/Web/Keepalived/"/>
    
    
      <category term="keepalived" scheme="http://czero000.github.io/tags/keepalived/"/>
    
  </entry>
  
  <entry>
    <title>跨平台桌面日历软件rainlendar</title>
    <link href="http://czero000.github.io/2017/01/11/rainlendar.html"/>
    <id>http://czero000.github.io/2017/01/11/rainlendar.html</id>
    <published>2017-01-11T06:58:57.000Z</published>
    <updated>2017-01-11T06:59:41.684Z</updated>
    
    <content type="html"><![CDATA[<p>Rainlendar 是一款跨平台桌面日历软件，它支持 Windows 、Mac 及 Linux，它的功能是能在桌面上显示一个漂亮的桌面日历及待办事项等等.</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">wget http://www.rainlendar.net/download/rainlendar2-lite_2.13.1.b147-1_amd64.deb</div><div class="line">sudo apt install -f</div><div class="line">/usr/bin/rainlendar2</div></pre></td></tr></table></figure>
<p>下载<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">http://ofc9x1ccn.bkt.clouddn.com/other/rainlendar2-lite_2.13.1.b147-1_amd64.deb</div><div class="line">http://ofc9x1ccn.bkt.clouddn.com/other/Simplified_Chinese.r2lang</div></pre></td></tr></table></figure></p>
]]></content>
    
    <summary type="html">
    
      &lt;p&gt;Rainlendar 是一款跨平台桌面日历软件，它支持 Windows 、Mac 及 Linux，它的功能是能在桌面上显示一个漂亮的桌面日历及待办事项等等.&lt;/p&gt;
&lt;figure class=&quot;highlight plain&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;
    
    </summary>
    
      <category term="Other" scheme="http://czero000.github.io/categories/Other/"/>
    
    
      <category term="rainlendar" scheme="http://czero000.github.io/tags/rainlendar/"/>
    
  </entry>
  
  <entry>
    <title>更改SSH Key密码</title>
    <link href="http://czero000.github.io/2017/01/11/change-sshkey.html"/>
    <id>http://czero000.github.io/2017/01/11/change-sshkey.html</id>
    <published>2017-01-11T06:19:55.000Z</published>
    <updated>2017-01-11T07:20:57.784Z</updated>
    
    <content type="html"><![CDATA[<p>通过 <code>ssh-keygen</code> 生成带有密码的私钥文件，当想要更改密码，可以通过下面方式更改密码或者将密码置为空。</p>
<ul>
<li>使用 <code>ssh-keygen</code></li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"></div><div class="line">ssh-keygen -f id_rsa -p</div></pre></td></tr></table></figure>
<ul>
<li>使用 <code>openssl</code><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">openssl rsa -in ~/.ssh/id_rsa -out ~/.ssh/id_rsa_new</div></pre></td></tr></table></figure>
</li>
</ul>
]]></content>
    
    <summary type="html">
    
      &lt;p&gt;通过 &lt;code&gt;ssh-keygen&lt;/code&gt; 生成带有密码的私钥文件，当想要更改密码，可以通过下面方式更改密码或者将密码置为空。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;使用 &lt;code&gt;ssh-keygen&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;figure class=&quot;hi
    
    </summary>
    
      <category term="System" scheme="http://czero000.github.io/categories/System/"/>
    
    
      <category term="ssh-key" scheme="http://czero000.github.io/tags/ssh-key/"/>
    
  </entry>
  
  <entry>
    <title>Centos7安装bind-从服务器</title>
    <link href="http://czero000.github.io/2017/01/09/install-bind-on-centos7.html"/>
    <id>http://czero000.github.io/2017/01/09/install-bind-on-centos7.html</id>
    <published>2017-01-09T09:43:54.000Z</published>
    <updated>2017-01-11T07:25:49.381Z</updated>
    
    <content type="html"><![CDATA[<h1 id="系统环境"><a href="#系统环境" class="headerlink" title="系统环境"></a>系统环境</h1><ul>
<li>系统版本: <code>CentOS Linux release 7.1.1503 (Core)</code> </li>
<li>软件安装: <code>bind bind-libs bind-devel bind-utils bind-chroot</code></li>
</ul>
<h1 id="安装"><a href="#安装" class="headerlink" title="安装"></a>安装</h1><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">yum install bind bind-libs bind-devel bind-utils bind-chroot -y</div></pre></td></tr></table></figure>
<h1 id="配置"><a href="#配置" class="headerlink" title="配置"></a>配置</h1><ul>
<li><p>拷贝 bind 相关文件， 准备 bind chroot 环境</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">cp -R /usr/share/doc/bind-*/sample/var/named/* /var/named/chroot/var/named/</div></pre></td></tr></table></figure>
</li>
<li><p>在 bind chroot 的目录中创建相关文件</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line">touch /var/named/chroot/var/named/data/cache_dump.db</div><div class="line">touch /var/named/chroot/var/named/data/named_stats.txt</div><div class="line">touch /var/named/chroot/var/named/data/named_mem_stats.txt</div><div class="line">touch /var/named/chroot/var/named/data/named.run</div><div class="line">mkdir /var/named/chroot/var/named/dynamic</div><div class="line">touch /var/named/chroot/var/named/dynamic/managed-keys.bind</div></pre></td></tr></table></figure>
</li>
<li><p>变更目录权限</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">chown -R named:named /var/named/chroot/var/named/data</div><div class="line">chown -R named:named /var/named/chroot/var/named/dynamic</div></pre></td></tr></table></figure>
</li>
<li><p>拷贝 named.conf 配置文件</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">cp -p /etc/named.conf /var/named/chroot/etc/named.conf</div></pre></td></tr></table></figure>
</li>
<li><p>修改 bind 配置文件</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div></pre></td><td class="code"><pre><div class="line">more named.conf </div><div class="line">// Default named.conf generated by install of bind-9.2.4-27.0.1.el4</div><div class="line">options &#123;</div><div class="line">        listen-on port 53 &#123; serverip; &#125;;</div><div class="line">        directory &quot;/var/named&quot;;</div><div class="line">        dump-file &quot;/var/named/data/cache_dump.db&quot;;</div><div class="line">        statistics-file &quot;/var/named/data/named_stats.txt&quot;;</div><div class="line">        memstatistics-file &quot;/var/named/data/named_mem_stats.txt&quot;;</div><div class="line">        version &quot;oOoOo...&quot;;</div><div class="line">        allow-query     &#123; any; &#125;;</div><div class="line">        recursion       no;</div><div class="line">        allow-transfer  &#123; serverip; &#125;;</div><div class="line">        pid-file&quot;/run/named/named.pid&quot;;</div><div class="line">        session-keyfile &quot;/run/named/session.key&quot;;</div><div class="line">        managed-keys-directory &quot;/var/named/dynamic&quot;;</div><div class="line">&#125;;</div><div class="line"></div><div class="line">controls &#123;</div><div class="line">        inet 127.0.0.1 allow &#123; localhost; &#125; keys &#123; rndckey; &#125;;</div><div class="line">&#125;;</div><div class="line"></div><div class="line">include &quot;/etc/rndc.key&quot;;</div><div class="line"></div><div class="line">logging &#123;</div><div class="line">        channel &quot;named_log&quot; &#123;</div><div class="line">        file &quot;/var/named/logs/named.log&quot; versions 10 size 5m;</div><div class="line">        severity dynamic;</div><div class="line">        print-category yes;</div><div class="line">        print-severity yes;</div><div class="line">        print-time yes;</div><div class="line">&#125;;</div><div class="line"></div><div class="line">channel &quot;query_log&quot; &#123;</div><div class="line">        file &quot;/var/named/logs/query.log&quot; versions 10 size 5m;</div><div class="line">        severity debug;</div><div class="line">        print-severity yes;</div><div class="line">        print-time yes;</div><div class="line">&#125;;</div><div class="line"></div><div class="line">category default &#123; named_log; &#125;;</div><div class="line">category queries &#123; query_log; &#125;;</div><div class="line">&#125;;</div><div class="line"></div><div class="line"></div><div class="line">zone &quot;.&quot; IN &#123;</div><div class="line">        type hint;</div><div class="line">        file &quot;named.cache&quot;;</div><div class="line">&#125;;</div><div class="line"></div><div class="line">zone &quot;czero.cn&quot; IN &#123;</div><div class="line">        type slave;</div><div class="line">        masters &#123; serverip; &#125;; </div><div class="line">        file &quot;czero.cn.db&quot;;</div><div class="line">&#125;;</div></pre></td></tr></table></figure>
</li>
<li><p>zone 配置</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div></pre></td><td class="code"><pre><div class="line">vim /var/named/chroot/var/named/example.local.zone</div><div class="line">;</div><div class="line">;       Addresses and other host information.</div><div class="line">;</div><div class="line">$TTL 86400</div><div class="line">@       IN      SOA     example.local. hostmaster.example.local. (</div><div class="line">                               2014101901      ; Serial</div><div class="line">                               43200      ; Refresh</div><div class="line">                               3600       ; Retry</div><div class="line">                               3600000    ; Expire</div><div class="line">                               2592000 )  ; Minimum</div><div class="line"> </div><div class="line">;       Define the nameservers and the mail servers</div><div class="line"> </div><div class="line">               IN      NS      ns1.example.local.</div><div class="line">               IN      NS      ns2.example.local.</div><div class="line">               IN      A       192.168.0.70</div><div class="line">               IN      MX      10 mx.example.local.</div><div class="line"> </div><div class="line">centos7          IN      A       192.168.0.70</div><div class="line">mx               IN      A       192.168.0.50</div><div class="line">ns1              IN      A       192.168.0.70</div><div class="line">ns2              IN      A       192.168.0.80</div></pre></td></tr></table></figure>
</li>
<li><p>启动服务</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">/usr/libexec/setup-named-chroot.sh /var/named/chroot on</div><div class="line">systemctl stop named</div><div class="line">systemctl disable named</div><div class="line">systemctl start named-chroot</div><div class="line">systemctl enable named-chroot</div></pre></td></tr></table></figure>
</li>
</ul>
]]></content>
    
    <summary type="html">
    
      &lt;h1 id=&quot;系统环境&quot;&gt;&lt;a href=&quot;#系统环境&quot; class=&quot;headerlink&quot; title=&quot;系统环境&quot;&gt;&lt;/a&gt;系统环境&lt;/h1&gt;&lt;ul&gt;
&lt;li&gt;系统版本: &lt;code&gt;CentOS Linux release 7.1.1503 (Core)&lt;/code&gt; 
    
    </summary>
    
      <category term="System" scheme="http://czero000.github.io/categories/System/"/>
    
      <category term="DNS" scheme="http://czero000.github.io/categories/System/DNS/"/>
    
    
      <category term="bind" scheme="http://czero000.github.io/tags/bind/"/>
    
  </entry>
  
  <entry>
    <title>测试使用docker</title>
    <link href="http://czero000.github.io/2017/01/06/use-docker.html"/>
    <id>http://czero000.github.io/2017/01/06/use-docker.html</id>
    <published>2017-01-06T02:44:48.000Z</published>
    <updated>2017-01-11T07:30:23.257Z</updated>
    
    <content type="html"><![CDATA[<h1 id="使用-docker-创建一个静态网站"><a href="#使用-docker-创建一个静态网站" class="headerlink" title="使用 docker 创建一个静态网站"></a>使用 docker 创建一个静态网站</h1><p>将 docker 作为本地 web 开发环境是使用 docker 的最简单情况，可以完全实现生产环境，保证开发环境和部署环境一致，下面讲创建一个简单的网站 sample。</p>
<h2 id="通过-Dockerfile-创建-sample-website"><a href="#通过-Dockerfile-创建-sample-website" class="headerlink" title="通过 Dockerfile 创建 sample website"></a>通过 Dockerfile 创建 sample website</h2><ul>
<li>创建工作目录</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">mkdir sample</div><div class="line">cd sample</div><div class="line">touch Dockerfile</div></pre></td></tr></table></figure>
<ul>
<li>创建 nginx 配置文件</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">mkdir nginx ; cd nginx</div><div class="line">wget https://raw.githubusercontent.com/jamtur01/dockerbook-code/master/code/5/sample/nginx/global.conf</div><div class="line">wget https://raw.githubusercontent.com/jamtur01/dockerbook-code/master/code/5/sample/nginx/nginx.conf</div></pre></td></tr></table></figure>
<ul>
<li>编写 Dockerfile</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line"># For a simple website</div><div class="line"># V0.1</div><div class="line">FROM ubuntu:16.04</div><div class="line">MAINTAINER Charlie.Cui &lt;charlie.cui127@gmail.com&gt;</div><div class="line">ENV REFRESHED_AT 2016-11-01</div><div class="line">RUN apt-get update</div><div class="line">RUN apt-get -qqy install nginx</div><div class="line">RUN mkdir -p /var/www/html</div><div class="line">ADD nginx/global.conf /etc/nginx/conf.d/</div><div class="line">ADD nginx/nginx.conf /etc/nginx/nginx.conf</div><div class="line">EXPOSE 80</div></pre></td></tr></table></figure>
<p>Dockerfile 内容主要包含下面几项</p>
<ol>
<li>安装 nginx</li>
<li>在容器中创建一个目录 <code>/var/www/html</code></li>
<li>将下载的本地 nginx 配置文件添加到镜像中</li>
<li>开放镜像的 80 端口</li>
</ol>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div></pre></td><td class="code"><pre><div class="line">//设置nginx 监听 80 端口，root目录为 /var/www/html/website</div><div class="line">::::::::::::::</div><div class="line">nginx/global.conf</div><div class="line">::::::::::::::</div><div class="line">server &#123;</div><div class="line">        listen          0.0.0.0:80;</div><div class="line">        server_name     _;</div><div class="line"></div><div class="line">        root            /var/www/html/website;</div><div class="line">        index           index.html index.htm;</div><div class="line"></div><div class="line">        access_log      /var/log/nginx/default_access.log;</div><div class="line">        error_log       /var/log/nginx/default_error.log;</div><div class="line">&#125;</div><div class="line"></div><div class="line"></div><div class="line">// 配置 nginx 为非守护进程模式， daemon off选项会阻止 nginx 进入后台，强制 nginx 在前台运行，这样是为了保持 docker 容器的活跃状态，默认情况下， nginx 会以守护进行方式启动，这会使容器短暂运行，在守护进程 fork 启动后，发起守护进程的源进程便会退出，容器也随之停止</div><div class="line">::::::::::::::</div><div class="line">nginx/nginx.conf</div><div class="line">::::::::::::::</div><div class="line">user www-data;</div><div class="line">worker_processes 4;</div><div class="line">pid /run/nginx.pid;</div><div class="line">daemon off;</div><div class="line"></div><div class="line">events &#123;  &#125;</div><div class="line"></div><div class="line">http &#123;</div><div class="line">  sendfile on;</div><div class="line">  tcp_nopush on;</div><div class="line">  tcp_nodelay on;</div><div class="line">  keepalive_timeout 65;</div><div class="line">  types_hash_max_size 2048;</div><div class="line">  include /etc/nginx/mime.types;</div><div class="line">  default_type application/octet-stream;</div><div class="line">  access_log /var/log/nginx/access.log;</div><div class="line">  error_log /var/log/nginx/error.log;</div><div class="line">  gzip on;</div><div class="line">  gzip_disable &quot;msie6&quot;;</div><div class="line">  include /etc/nginx/conf.d/*.conf;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<h2 id="构建-sample-网站和-nginx-镜像"><a href="#构建-sample-网站和-nginx-镜像" class="headerlink" title="构建 sample 网站和 nginx 镜像"></a>构建 sample 网站和 nginx 镜像</h2><p>利用之前的  Dockerfile，可以利用 <code>docker build</code> 命令构建出新的镜像，并将该镜像命名为 czero/nginx:v1<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">docker build -t Czero/nginx:v1 .</div></pre></td></tr></table></figure></p>
<p>通过 <code>docker history</code>可以看到构建过程</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div></pre></td><td class="code"><pre><div class="line">docker history czero/nginx:v1</div><div class="line">IMAGE               CREATED                  CREATED BY                                      SIZE                COMMENT</div><div class="line">32901d5b7262        19 hours ago             /bin/sh -c #(nop)  EXPOSE 80/tcp                0 B                 </div><div class="line">774362201d8f        19 hours ago             /bin/sh -c #(nop) ADD file:d6698a182fafaf3cb0   415 B               </div><div class="line">5e9f2a24c991        19 hours ago             /bin/sh -c #(nop) ADD file:9778ae1b43896011cc   286 B               </div><div class="line">5d9dd8c94af9        19 hours ago             /bin/sh -c mkdir -p /var/www/html               0 B                 </div><div class="line">4f866ff78749        19 hours ago             /bin/sh -c apt-get -qqy install nginx           56.81 MB            </div><div class="line">887048645d36        19 hours ago             /bin/sh -c apt-get update                       39.19 MB            </div><div class="line">6bc9139d50a3        20 hours ago             /bin/sh -c #(nop)  ENV REFRESHED_AT=2016-11-0   0 B                 </div><div class="line">0ce2ec18f130        20 hours ago             /bin/sh -c #(nop)  MAINTAINER Charlie.Cui &lt;ch   0 B                 </div><div class="line">c73a085dc378        Less than a second ago   /bin/sh -c #(nop)  CMD [&quot;/bin/bash&quot;]            0 B                 </div><div class="line">&lt;missing&gt;           Less than a second ago   /bin/sh -c mkdir -p /run/systemd &amp;&amp; echo &apos;doc   7 B                 </div><div class="line">&lt;missing&gt;           Less than a second ago   /bin/sh -c sed -i &apos;s/^#\s*\(deb.*universe\)$/   1.895 kB            </div><div class="line">&lt;missing&gt;           Less than a second ago   /bin/sh -c rm -rf /var/lib/apt/lists/*          0 B                 </div><div class="line">&lt;missing&gt;           Less than a second ago   /bin/sh -c set -xe   &amp;&amp; echo &apos;#!/bin/sh&apos; &gt; /u   745 B               </div><div class="line">&lt;missing&gt;           Less than a second ago   /bin/sh -c #(nop) ADD file:cd937b840fff16e04e   127.1 MB</div></pre></td></tr></table></figure>
<h2 id="从-sample-网站和-nginx-镜像构建容器"><a href="#从-sample-网站和-nginx-镜像构建容器" class="headerlink" title="从 sample 网站和 nginx 镜像构建容器"></a>从 sample 网站和 nginx 镜像构建容器</h2><p>使用 czero/nginx:v1 镜像，构建容器</p>
<ul>
<li>生成网站首页</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">// 创建 website 目录，创建首页文件 index.html</div><div class="line">cd sample</div><div class="line">mkdir website</div><div class="line">cd website</div><div class="line">wget https://raw.githubusercontent.com/jamtur01/dockerbook-code/master/code/5/sample/website/index.html</div></pre></td></tr></table></figure>
<ul>
<li>创建容器</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">docker run -d -p 80:80 --name blog -v $PWD/website:/var/www/html/website:ro czero/nginx:v1 nginx</div></pre></td></tr></table></figure>
<p>在执行<code>docker run</code>命令时，会创建一个 blog 容器，<code>-v</code>选项允许将宿主机的目录挂载到容器中，然后会传入 <code>nginx</code>启动命令，让 ningx 启动后已交互模式在前台运行。<br>卷在 docker 中非常有用，卷是一个或者多个容器内被选定的目录，可以绕过分层的联合文件系统，为 docker 提供持久数据或者共享数据，对卷的修改会直接生效，并会绕过镜像，当提交或者创建镜像时，卷不会被包含在镜像中。利用卷可以实现不想把代码或者应用等构建到镜像中，或者是希望同时对代码做开发和测试、代码频繁改动，不想在开发过程中重新构建镜像、希望在多个容器中共享代码。</p>
<p><code>-v</code>参数指定了卷的源目录和容器里的目的目录，这两个目录通过<code>:</code>分隔，如果目的目录不存在，docker 会自动创建。也可以在目的目录后面添加<code>rw、ro</code>来指定目录的读写状态<br><code>-p</code>参数指定了将容器内部的端口映射到本地的指定端口，<code>本地端口:容器端口</code>，可以不指定本地端口。</p>
<ul>
<li>查看容器</li>
</ul>
<p>通过<code>docker ps</code>命令可以查看正在运行的容器，可以看到 blog 容器正在活跃状态，并将 80 端口映射到本地的 80端口。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                NAMES</div><div class="line">e479aa5da8ae        czero/nginx:v1      &quot;nginx&quot;             16 minutes ago      Up 16 minutes       0.0.0.0:80-&gt;80/tcp   blog</div></pre></td></tr></table></figure></p>
<h2 id="使用-docker-构建一个-web-应用"><a href="#使用-docker-构建一个-web-应用" class="headerlink" title="使用 docker 构建一个 web 应用"></a>使用 docker 构建一个 web 应用</h2><p>现在构建一个更大的 web 应用，一个基于 sinatra 的 web 应用。</p>
<h3 id="构建-sinatra-应用程序"><a href="#构建-sinatra-应用程序" class="headerlink" title="构建 sinatra 应用程序"></a>构建 sinatra 应用程序</h3><ul>
<li>创建 Dockerfile 文件</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div></pre></td><td class="code"><pre><div class="line"># a sinatra website</div><div class="line">FROM ubuntu:16.04</div><div class="line">MAINTAINER Charlie.Cui &lt;charlie.cui127@gmail.com&gt;</div><div class="line">ENV REFRESHED_AT 2016-11-03</div><div class="line">RUN apt-get -qq update</div><div class="line">RUN apt-get -qqy install ruby ruby-dev build-essential redis-tools</div><div class="line">RUN gem sources --add https://gems.ruby-china.org/ --remove https://rubygems.org/</div><div class="line">RUN gem install --no-rdoc --no-ri sinatra json redis</div><div class="line"></div><div class="line">RUN mkdir -p /opt/webapp</div><div class="line">EXPOSE 4567</div><div class="line"></div><div class="line">CMD [&quot;/opt/webapp/bin/webapp&quot;]</div></pre></td></tr></table></figure>
<ul>
<li>构建 docker 镜像</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">docker build -t czero/sinatra:v1 .</div></pre></td></tr></table></figure>
<h3 id="创建-sinatra-容器"><a href="#创建-sinatra-容器" class="headerlink" title="创建 sinatra 容器"></a>创建 sinatra 容器</h3><ul>
<li>下载 sinatra web 应用代码</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">wget  --cut-dirs=3 -nH -r --no-parent --no-check-certificate http://dockerbook.com/code/5/sinatra/webapp/</div><div class="line">// 增加执行权限</div><div class="line">chmod +x $PWD/webapp/bin/webapp</div></pre></td></tr></table></figure>
<ul>
<li>创建 docker 容器</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">docker run -d -p 4567:4567 --name sinatra -v $PWD/webapp:/opt/webapp czero/sinatra:v1</div></pre></td></tr></table></figure>
<p>Dockerfile 中的 <code>CMD</code> 指令，会让镜像启动容器时，执行该命令</p>
<ul>
<li>查看容器执行命令的输出</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line">docker logs sinatra</div><div class="line">[2016-03-17 05:10:39] INFO  WEBrick 1.3.1</div><div class="line">[2016-03-17 05:10:39] INFO  ruby 2.3.1 (2016-04-26) [x86_64-linux-gnu]</div><div class="line">== Sinatra (v1.4.7) has taken the stage on 4567 for development with backup from WEBrick</div><div class="line">[2016-03-17 05:10:39] INFO  WEBrick::HTTPServer#start: pid=1 port=4567</div><div class="line">172.16.3.139 - - [17/Mar/2016:05:11:01 +0000] &quot;GET / HTTP/1.1&quot; 200 36 0.0064</div></pre></td></tr></table></figure>
<p>在运行 <code>docker logs</code> 命令时，加上<code>-f</code> 参数，会持续食醋胡容器的 <code>stderr</code> 和 <code>stdout</code></p>
<ul>
<li>查看 docker 容器中正在运行的程序</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">docker top sinatra</div><div class="line">UID                 PID                 PPID                C                   STIME               TTY                 TIME                CMD</div><div class="line">root                14395               14378               0                   13:10               ?                   00:00:00            /usr/bin/ruby /opt/webapp/bin/webapp</div></pre></td></tr></table></figure>
<ul>
<li>查看 docekr 容器端口映射</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">docker port sinatra</div><div class="line">4567/tcp -&gt; 0.0.0.0:4567</div></pre></td></tr></table></figure>
<ul>
<li>访问 sinatra</li>
</ul>
<p>sinatra 应用只接受输入参数，并将输入转成 JSON 输出<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div></pre></td><td class="code"><pre><div class="line">curl -i -H &apos;Accept: application/json&apos; -d &apos;name=Foo&amp;status=Bar&apos; http://localhost:4567/json</div><div class="line">HTTP/1.1 200 OK</div><div class="line">Content-Type: text/html;charset=utf-8</div><div class="line">Content-Length: 29</div><div class="line">X-Xss-Protection: 1; mode=block</div><div class="line">X-Content-Type-Options: nosniff</div><div class="line">X-Frame-Options: SAMEORIGIN</div><div class="line">Server: WEBrick/1.3.1 (Ruby/2.3.1/2016-04-26)</div><div class="line">Date: Thu, 17 Mar 2016 07:47:18 GMT</div><div class="line">Connection: Keep-Alive</div><div class="line"></div><div class="line">&#123;&quot;name&quot;:&quot;Foo&quot;,&quot;status&quot;:&quot;Bar&quot;&#125;#</div></pre></td></tr></table></figure></p>
<h2 id="构建-Redis-镜像和容器"><a href="#构建-Redis-镜像和容器" class="headerlink" title="构建 Redis 镜像和容器"></a>构建 Redis 镜像和容器</h2><p>扩展 sinatra 应用程序，在后端加入 redis 数据库，并在数据库中存入输入参数。构建全新的镜像和容器运行 redis 数据库，通过 docker 管理两个容器。</p>
<ul>
<li>创建Dockerfile</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line">cat Dockerfile</div><div class="line"># contarner for sinatra redis</div><div class="line">FROM ubuntu:16.04</div><div class="line">MAINTAINER Charlie.Cui &lt;charlie.cui127@gmail.com&gt;</div><div class="line">ENV REFRESHED_AT 2016-11-03</div><div class="line">RUN apt-get -qq update</div><div class="line">RUN apt-get -qqy install redis-server redis-tools</div><div class="line">EXPOSE 6379</div><div class="line">ENTRYPOINT [&quot;/usr/bin/redis-server&quot;]</div><div class="line">CMD []</div></pre></td></tr></table></figure>
<ul>
<li>生成镜像<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">docker build -t czero/redis:v1 .</div></pre></td></tr></table></figure>
</li>
</ul>
<p>dockerfile 指定安装 redis 服务，开放 6379 端口，并启动 redis 服务</p>
<ul>
<li>创建容器</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">docker run -d -p 6379:6379 --name sinatra_redis czero/redis:v1</div></pre></td></tr></table></figure>
<ul>
<li>测试连接 redis</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">// 本地安装 redis-tools</div><div class="line">apt install -f redis-tools</div><div class="line"></div><div class="line">// 连接 redis</div><div class="line">redis-cli -h 127.0.0.1</div></pre></td></tr></table></figure>
<h2 id="连接到-redis-容器"><a href="#连接到-redis-容器" class="headerlink" title="连接到 redis 容器"></a>连接到 redis 容器</h2><p>连接到 docker 容器有两种方式，</p>
<ul>
<li>ip地址方式</li>
<li>docker link功能</li>
</ul>
<h3 id="ip-方式连接"><a href="#ip-方式连接" class="headerlink" title="ip 方式连接"></a>ip 方式连接</h3><p>查看 容器 IP 信息<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">docker inspect sinatra_redis</div><div class="line"></div><div class="line">// 上面命令输出信息较多，可以利用-f 标志那个，过滤关键字</div><div class="line">docker inspect -f &apos;&#123;&#123; .NetworkSettings.IPAddress &#125;&#125;&apos; sinatra_redis</div><div class="line">172.17.0.3</div></pre></td></tr></table></figure></p>
<p>安装docker时，会创建一个名为 <code>docker0</code> 的网卡，主机上的容器都会在这个网卡上分配到一个地址，docker0 网卡，拥有一个私有IP段，<code>172.16～172.30</code>，网卡是一个虚拟的以太网桥，用于连接本地忘了和容器网络，在容器中，会以<code>veth</code>开头来命令网卡，并随机分配到一个 ip 地址，当知道了容器的ip，两个容器便可以通过 IP及端口相互访问，但是这种方式有个缺点。由于容器的 ip 地址是由 <code>docker0</code> 网卡分配的 ip 地址，当容器被重启，容器本身的 ip 地址会改变，这样当两个容量使用固定 ip 地址方式访问，这样便会连接不上。</p>
<h3 id="通过-link-连接-容器"><a href="#通过-link-连接-容器" class="headerlink" title="通过 link 连接 容器"></a>通过 link 连接 容器</h3><ul>
<li>删除掉之前的容器</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">docker stop $(docker ps -q)</div><div class="line">doker rm $(docker ps -aq)</div></pre></td></tr></table></figure>
<ul>
<li>创建新的 redis 容器</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">docker run -d --name sinatra_redis czero/redis:v1</div></pre></td></tr></table></figure>
<ul>
<li>创建 web 应用连接 redis</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line">docker run -p 4567 --name sinatra_web --link  sinatra_redis:db -t -i -v $PWD/sinatra_web/webapp:/opt/webapp czero/sinatra:v1 /bin/bash</div><div class="line">// 如果想要多个 web 应用同时连接 redis</div><div class="line">docker run -p 4567 --name sinatra_web1 --link  sinatra_redis:db -v $PWD/sinatra_web/webapp:/opt/webapp czero/sinatra:v1</div><div class="line">docker run -p 4567 --name sinatra_web2 --link  sinatra_redis:db -v $PWD/sinatra_web/webapp:/opt/webapp czero/sinatra:v1</div></pre></td></tr></table></figure>
<p><code>--link</code> 标志创建两连个容器间父子连接，这个标志需要两个参数: <strong>一个是要连接的容器名称，另外一个便是连接后容器的别名</strong> ,上面列子便是连接到 <code>sinatra_redis</code> 容器，并使用 <code>db</code> 作为别名。别名可以访问公开的信息，而无需关注底层容器的名字。连接让父容器可以访问子容器，并且把子容器的一些连接细节分给父容器。<br>这样会在安全性上得到提高，在启动 redis 时，并没有使用 <code>-p</code> 开放容器端口，当使用<code>--link</code> 时，可以让父容器直接访问子容器的开放端口。在启动容器守护进程时，如果加上 <code>--ice=false</code> 便会关闭所有没有连接的容器通信。<strong>被连接的容器要求必须是同一主机上的容器，不同主机上的容器不能连接</strong></p>
<p>在创建两个容器连接后，会在两个地方写入连接信息</p>
<ol>
<li>/etc/hosts 文件</li>
</ol>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">more /etc/hosts</div><div class="line">172.17.0.2      db 9e0071f714c4 sinatra_redis</div><div class="line">172.17.0.3      744d452651ca</div></pre></td></tr></table></figure>
<ol>
<li>包含连接信息的环境变量中</li>
</ol>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line">env   </div><div class="line">HOSTNAME=744d452651ca</div><div class="line">DB_NAME=/sinatra_web/db</div><div class="line">DB_PORT_6379_TCP_PORT=6379</div><div class="line">TERM=xterm</div><div class="line">DB_PORT=tcp://172.17.0.2:6379</div><div class="line">DB_PORT_6379_TCP=tcp://172.17.0.2:6379</div></pre></td></tr></table></figure>
<ul>
<li>容器应用通信</li>
</ul>
<p>使用 host 或者 ENV 给应用加入连接信息，例如<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">// web应用代码</div><div class="line">uri=URI.parse(env[&apos;DB_PORT&apos;])</div><div class="line">redis = redis.net(:host =&gt; uri.host, :port =&gt; uri.port )</div></pre></td></tr></table></figure></p>
<p><strong>在docker run 命令中加入 –dns 或者 –dns-search 标志可以为容器定义dns</strong></p>
<p>再次使用<code>curl</code>命令测试 sinatra 程序<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div></pre></td><td class="code"><pre><div class="line">curl -i -H &apos;Accept: application/json&apos; -d &apos;name=Foo&amp;status=Bar&apos; http://localhost:4567/json                                       </div><div class="line">HTTP/1.1 200 OK</div><div class="line">Content-Type: text/html;charset=utf-8</div><div class="line">Content-Length: 29</div><div class="line">X-Xss-Protection: 1; mode=block</div><div class="line">X-Content-Type-Options: nosniff</div><div class="line">X-Frame-Options: SAMEORIGIN</div><div class="line">Server: WEBrick/1.3.1 (Ruby/2.3.1/2016-04-26)</div><div class="line">Date: Fri, 18 Mar 2016 09:08:31 GMT</div><div class="line">Connection: Keep-Alive</div><div class="line"></div><div class="line">&#123;&quot;name&quot;:&quot;Foo&quot;,&quot;status&quot;:&quot;Bar&quot;&#125;</div></pre></td></tr></table></figure></p>
<p>再次确认 redis 是否收到更新</p>
]]></content>
    
    <summary type="html">
    
      &lt;h1 id=&quot;使用-docker-创建一个静态网站&quot;&gt;&lt;a href=&quot;#使用-docker-创建一个静态网站&quot; class=&quot;headerlink&quot; title=&quot;使用 docker 创建一个静态网站&quot;&gt;&lt;/a&gt;使用 docker 创建一个静态网站&lt;/h1&gt;&lt;p&gt;将 dock
    
    </summary>
    
      <category term="运维技术" scheme="http://czero000.github.io/categories/%E8%BF%90%E7%BB%B4%E6%8A%80%E6%9C%AF/"/>
    
      <category term="Docker" scheme="http://czero000.github.io/categories/%E8%BF%90%E7%BB%B4%E6%8A%80%E6%9C%AF/Docker/"/>
    
    
      <category term="docker" scheme="http://czero000.github.io/tags/docker/"/>
    
  </entry>
  
  <entry>
    <title>docker资源</title>
    <link href="http://czero000.github.io/2017/01/06/docker-resource.html"/>
    <id>http://czero000.github.io/2017/01/06/docker-resource.html</id>
    <published>2017-01-06T02:44:48.000Z</published>
    <updated>2017-01-11T07:07:21.738Z</updated>
    
    <content type="html"><![CDATA[<h1 id="Docker资源"><a href="#Docker资源" class="headerlink" title="Docker资源"></a>Docker资源</h1><h2 id="Docker官方英文资源："><a href="#Docker官方英文资源：" class="headerlink" title="Docker官方英文资源："></a>Docker官方英文资源：</h2><ul>
<li>docker官网：<a href="http://www.docker.com" target="_blank" rel="external">http://www.docker.com</a></li>
<li>Docker windows入门：<a href="https://docs.docker.com/windows/" target="_blank" rel="external">https://docs.docker.com/windows/</a></li>
<li>Docker Linux 入门：<a href="https://docs.docker.com/linux/" target="_blank" rel="external">https://docs.docker.com/linux/</a></li>
<li>Docker mac 入门：<a href="https://docs.docker.com/mac/" target="_blank" rel="external">https://docs.docker.com/mac/</a></li>
<li>Docker 用户指引：<a href="https://docs.docker.com/engine/userguide/" target="_blank" rel="external">https://docs.docker.com/engine/userguide/</a></li>
<li>Docker 官方博客：<a href="http://blog.docker.com/" target="_blank" rel="external">http://blog.docker.com/</a></li>
<li>Docker Hub: <a href="https://hub.docker.com/" target="_blank" rel="external">https://hub.docker.com/</a></li>
<li>Docker开源： <a href="https://www.docker.com/open-source" target="_blank" rel="external">https://www.docker.com/open-source</a></li>
</ul>
<h2 id="Docker中文资源："><a href="#Docker中文资源：" class="headerlink" title="Docker中文资源："></a>Docker中文资源：</h2><ul>
<li>Docker中文网站：<a href="http://www.docker.org.cn" target="_blank" rel="external">http://www.docker.org.cn</a></li>
<li>Docker入门教程: <a href="http://www.docker.org.cn/book/docker.html" target="_blank" rel="external">http://www.docker.org.cn/book/docker.html</a></li>
<li>Docker安装手册：<a href="http://www.docker.org.cn/book/install.html" target="_blank" rel="external">http://www.docker.org.cn/book/install.html</a></li>
<li>一小时Docker教程 ：<a href="https://blog.csphere.cn/archives/22" target="_blank" rel="external">https://blog.csphere.cn/archives/22</a></li>
<li>docker从入门到实践：<a href="http://dockerpool.com/static/books/docker_practice/index.html" target="_blank" rel="external">http://dockerpool.com/static/books/docker_practice/index.html</a></li>
<li>Docker纸质书：<a href="http://www.docker.org.cn/dockershuji.html" target="_blank" rel="external">http://www.docker.org.cn/dockershuji.html</a></li>
<li>DockerPPT：<a href="http://www.docker.org.cn/dockerppt.html" target="_blank" rel="external">http://www.docker.org.cn/dockerppt.html</a></li>
</ul>
]]></content>
    
    <summary type="html">
    
      &lt;h1 id=&quot;Docker资源&quot;&gt;&lt;a href=&quot;#Docker资源&quot; class=&quot;headerlink&quot; title=&quot;Docker资源&quot;&gt;&lt;/a&gt;Docker资源&lt;/h1&gt;&lt;h2 id=&quot;Docker官方英文资源：&quot;&gt;&lt;a href=&quot;#Docker官方英文资源：&quot; c
    
    </summary>
    
      <category term="运维技术" scheme="http://czero000.github.io/categories/%E8%BF%90%E7%BB%B4%E6%8A%80%E6%9C%AF/"/>
    
      <category term="Docker" scheme="http://czero000.github.io/categories/%E8%BF%90%E7%BB%B4%E6%8A%80%E6%9C%AF/Docker/"/>
    
    
      <category term="docker" scheme="http://czero000.github.io/tags/docker/"/>
    
  </entry>
  
  <entry>
    <title>nfs挂载错误</title>
    <link href="http://czero000.github.io/2017/01/05/nfs-error.html"/>
    <id>http://czero000.github.io/2017/01/05/nfs-error.html</id>
    <published>2017-01-05T13:56:33.000Z</published>
    <updated>2017-01-11T07:08:22.454Z</updated>
    
    <content type="html"><![CDATA[<p>在 <code>ubuntu-16.04</code>中挂载nfs 提示<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line">mount: wrong fs type, bad option, bad superblock on 172.16.8.88:/data/gjobs/upload,</div><div class="line">       missing codepage or helper program, or other error</div><div class="line">       (for several filesystems (e.g. nfs, cifs) you might</div><div class="line">       need a /sbin/mount.&lt;type&gt; helper program)</div><div class="line"></div><div class="line">       In some cases useful info is found in syslog - try</div><div class="line">       dmesg | tail or so.</div></pre></td></tr></table></figure></p>
<p>解决：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">apt install nfs-common</div><div class="line">yum install nfs-utils</div></pre></td></tr></table></figure></p>
]]></content>
    
    <summary type="html">
    
      &lt;p&gt;在 &lt;code&gt;ubuntu-16.04&lt;/code&gt;中挂载nfs 提示&lt;br&gt;&lt;figure class=&quot;highlight plain&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;div class=&quot;line&quot;&gt;1&lt;/div&gt;&lt;div 
    
    </summary>
    
      <category term="System" scheme="http://czero000.github.io/categories/System/"/>
    
      <category term="NFS" scheme="http://czero000.github.io/categories/System/NFS/"/>
    
    
      <category term="nfs" scheme="http://czero000.github.io/tags/nfs/"/>
    
  </entry>
  
  <entry>
    <title>GoForIt-待办事项及倒计时器</title>
    <link href="http://czero000.github.io/2017/01/04/go-for-it.html"/>
    <id>http://czero000.github.io/2017/01/04/go-for-it.html</id>
    <published>2017-01-04T06:58:57.000Z</published>
    <updated>2017-01-11T07:09:54.235Z</updated>
    
    <content type="html"><![CDATA[<p>如果您是拖延症患者的话，这款集成了待办事项及倒计时器的小软件或许可以帮助您提高工作效率。</p>
<p>Go For It! 界面透着 Elementary/GNOME HIG 的简洁风格，使用 Vala/GTK3 创建，其待办事项部分以 Todo.txt（更多说明参见文末）格式保存。</p>
<p>这个<a href="https://www.youtube.com/watch?v=mnw556C9FZQ#t=150" target="_blank" rel="external">视频说明了 Go For It! 的工作流程（朝内镜像）</a>，简单来说：</p>
<ol>
<li>在待办事项里添加打算完成的工作。</li>
<li>选择一个事项，在倒计时器里设定预期完成时间，点击开始。</li>
<li>开始工作。</li>
<li>倒计时结束或任务完成后，点击确定将事项标记为完成。</li>
<li>可以在事项完成后添加一个休息时间。</li>
</ol>
<p>Go For It! 提供 Linux 及 <a href="http://manuel-kehl.de/projects/go-for-it/download-windows-version" target="_blank" rel="external">Win</a> 平台版本，不久将提供 OS X 版本。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">Ubuntu PPA：</div><div class="line">sudo add-apt-repository ppa:mank319/go-for-it &amp;&amp; sudo apt-get update</div><div class="line">sudo apt-get install go-for-it</div></pre></td></tr></table></figure></p>
<p><a href="https://github.com/mank319/Go-For-It" target="_blank" rel="external">Github编译指南</a></p>
<p>与 Evernote 或 Google Keep 等具备待办事项功能的便笺本相比，<a href="http://todotxt.com/" target="_blank" rel="external">Todo.txt</a> 利用预定义纯文本方式记录事项，某种意义上保证了向前兼容性。同时因为是简单的纯文本，它可以方便和各个平台进行集成，包括命令行终端及 Vim 插件。iOS 及 Android 客户端更是不在话下。同步的工作由 Dropbox 实现。</p>
]]></content>
    
    <summary type="html">
    
      &lt;p&gt;如果您是拖延症患者的话，这款集成了待办事项及倒计时器的小软件或许可以帮助您提高工作效率。&lt;/p&gt;
&lt;p&gt;Go For It! 界面透着 Elementary/GNOME HIG 的简洁风格，使用 Vala/GTK3 创建，其待办事项部分以 Todo.txt（更多说明参见文末
    
    </summary>
    
      <category term="Other" scheme="http://czero000.github.io/categories/Other/"/>
    
    
      <category term="goforit" scheme="http://czero000.github.io/tags/goforit/"/>
    
  </entry>
  
  <entry>
    <title>Mac软件推荐</title>
    <link href="http://czero000.github.io/2017/01/04/mac-software.html"/>
    <id>http://czero000.github.io/2017/01/04/mac-software.html</id>
    <published>2017-01-04T06:58:57.000Z</published>
    <updated>2017-01-11T07:15:49.529Z</updated>
    
    <content type="html"><![CDATA[<table>
<thead>
<tr>
<th>分类</th>
<th>软件名</th>
<th>标签</th>
</tr>
</thead>
<tbody>
<tr>
<td>写作</td>
<td><strong>ulysses</strong></td>
<td>markdown</td>
</tr>
<tr>
<td></td>
<td><strong>mou</strong></td>
<td>markdown</td>
</tr>
<tr>
<td></td>
<td><strong>iA writer 和 MWeb</strong></td>
<td>markdown</td>
</tr>
<tr>
<td>工具</td>
<td><strong>Gemini 2</strong></td>
<td>删除重复软件</td>
</tr>
<tr>
<td></td>
<td><strong>Duplicate Finder</strong></td>
<td>删除重复软件(智能)</td>
</tr>
<tr>
<td></td>
<td><strong>Downie</strong></td>
<td>视频下载</td>
</tr>
<tr>
<td></td>
<td><strong>快贴</strong></td>
<td>跨平台复制粘贴软件</td>
</tr>
<tr>
<td></td>
<td><strong>Alfred</strong></td>
<td></td>
</tr>
<tr>
<td></td>
<td><strong>Yomail</strong></td>
<td>邮件软件</td>
</tr>
<tr>
<td></td>
<td><strong>在线视频播放器</strong></td>
<td></td>
</tr>
<tr>
<td></td>
<td><strong>Lastpass</strong></td>
<td>密码管理</td>
</tr>
<tr>
<td><strong>美化类</strong></td>
<td><strong>Pixelmator 和 affinity photo</strong></td>
<td>照片美化</td>
</tr>
<tr>
<td></td>
<td><strong>iFoto Converter</strong></td>
<td>打水印</td>
</tr>
</tbody>
</table>
]]></content>
    
    <summary type="html">
    
      &lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;分类&lt;/th&gt;
&lt;th&gt;软件名&lt;/th&gt;
&lt;th&gt;标签&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;写作&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;ulysses&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;mark
    
    </summary>
    
      <category term="Mac" scheme="http://czero000.github.io/categories/Mac/"/>
    
    
      <category term="mac" scheme="http://czero000.github.io/tags/mac/"/>
    
  </entry>
  
  <entry>
    <title>linux命令行密码管理</title>
    <link href="http://czero000.github.io/2016/12/29/ubuntu-pass.html"/>
    <id>http://czero000.github.io/2016/12/29/ubuntu-pass.html</id>
    <published>2016-12-29T04:13:23.000Z</published>
    <updated>2017-01-11T08:55:40.608Z</updated>
    
    <content type="html"><![CDATA[<a id="more"></a>
<h1 id="软件：pass"><a href="#软件：pass" class="headerlink" title="软件：pass"></a>软件：pass</h1><h2 id="安装软件包"><a href="#安装软件包" class="headerlink" title="安装软件包"></a>安装软件包</h2><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">apt install pass</div></pre></td></tr></table></figure>
<h2 id="初始化仓库"><a href="#初始化仓库" class="headerlink" title="初始化仓库"></a>初始化仓库</h2><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">gpg --gen-key</div><div class="line">pass init &lt;gpg-id&gt;</div></pre></td></tr></table></figure>
<p><em>该命令会在<code>~/.password-store</code>目录中创建一个密码仓库</em></p>
<h2 id="添加新的密码信息"><a href="#添加新的密码信息" class="headerlink" title="添加新的密码信息"></a>添加新的密码信息</h2><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">pass insert &lt;password-name&gt; -m</div></pre></td></tr></table></figure>
<h2 id="查看密码名称列表"><a href="#查看密码名称列表" class="headerlink" title="查看密码名称列表"></a>查看密码名称列表</h2><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">pass</div></pre></td></tr></table></figure>
<h2 id="复制密码到剪切板"><a href="#复制密码到剪切板" class="headerlink" title="复制密码到剪切板"></a>复制密码到剪切板</h2><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">pass -c &lt;password-name&gt;</div></pre></td></tr></table></figure>
<h2 id="粘帖剪切板中密码"><a href="#粘帖剪切板中密码" class="headerlink" title="粘帖剪切板中密码"></a>粘帖剪切板中密码</h2><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">Ctrl + Shift + v</div></pre></td></tr></table></figure>
<h2 id="移除密码记录"><a href="#移除密码记录" class="headerlink" title="移除密码记录"></a>移除密码记录</h2><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">pass rm &lt;password-name&gt;</div></pre></td></tr></table></figure>
]]></content>
    
    <summary type="html">
    
      &lt;a id=&quot;more&quot;&gt;&lt;/a&gt;
&lt;h1 id=&quot;软件：pass&quot;&gt;&lt;a href=&quot;#软件：pass&quot; class=&quot;headerlink&quot; title=&quot;软件：pass&quot;&gt;&lt;/a&gt;软件：pass&lt;/h1&gt;&lt;h2 id=&quot;安装软件包&quot;&gt;&lt;a href=&quot;#安装软件包&quot; cla
    
    </summary>
    
      <category term="System" scheme="http://czero000.github.io/categories/System/"/>
    
      <category term="Debian" scheme="http://czero000.github.io/categories/System/Debian/"/>
    
    
      <category term="ubuntu" scheme="http://czero000.github.io/tags/ubuntu/"/>
    
      <category term="pass" scheme="http://czero000.github.io/tags/pass/"/>
    
  </entry>
  
  <entry>
    <title>redmine项目管理搭建</title>
    <link href="http://czero000.github.io/2016/12/29/ubuntu-redmine.html"/>
    <id>http://czero000.github.io/2016/12/29/ubuntu-redmine.html</id>
    <published>2016-12-29T04:13:23.000Z</published>
    <updated>2017-01-11T07:47:55.674Z</updated>
    
    <content type="html"><![CDATA[<a id="more"></a>
<h2 id="系统环境"><a href="#系统环境" class="headerlink" title="系统环境"></a>系统环境</h2><p>ubuntu server 16.04 LTS</p>
<h2 id="开发工具"><a href="#开发工具" class="headerlink" title="开发工具"></a>开发工具</h2><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">sudo apt-get install build-essential</div><div class="line">sudo apt-get install subversion git</div></pre></td></tr></table></figure>
<p><strong>安装顺序：rvm ruby rails nginx mysql redmine</strong></p>
<hr>
<h2 id="安装过程"><a href="#安装过程" class="headerlink" title="安装过程"></a>安装过程</h2><h3 id="rvm-ruby-rails"><a href="#rvm-ruby-rails" class="headerlink" title="rvm + ruby + rails"></a>rvm + ruby + rails</h3><p>1. 安装 rvm （用于管理多个 ruby 版本的一个管理器）<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line">gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3</div><div class="line">curl -sSL https://get.rvm.io | bash -s stable</div><div class="line">//如果上面的连接失败，可以尝试:</div><div class="line">curl -L https://raw.githubusercontent.com/wayneeseguin/rvm/master/binscripts/rvm-installer | bash -s stable</div></pre></td></tr></table></figure></p>
<p>2. 载入 rvm 环境<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">source /etc/profile.d/rvm.sh</div></pre></td></tr></table></figure></p>
<p>3. 检查 rvm 是否安装成功<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">rvm -v</div><div class="line">rvm 1.27.0 (latest) by Wayne E. Seguin &lt;wayneeseguin@gmail.com&gt;, Michal Papis &lt;mpapis@gmail.com&gt; [https://rvm.io/]</div></pre></td></tr></table></figure></p>
<p>4. 安装 ruby 环境<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">rvm requirements    //更新依赖包</div><div class="line">rvm install 2.3.0   //安装较为稳定的 2.3.0 版本</div></pre></td></tr></table></figure></p>
<p>5. 设置 ruby 默认版本<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">rvm use 2.3.0 --default</div></pre></td></tr></table></figure></p>
<p>6. 变更镜像<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">gem sources --add https://gems.ruby-china.org/ --remove https://rubygems.org</div><div class="line">gem sources --add https://ruby.taobao.org/ --remove https://rubygems.org</div><div class="line">gem sources -l    //查看在用的 gem 源</div></pre></td></tr></table></figure></p>
<p>7. 安装 bundler<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">gem install bundler</div></pre></td></tr></table></figure></p>
<p>8. 安装 rails<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">gem install rails</div></pre></td></tr></table></figure></p>
<p>9. 检查安装包版本<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line">rvm -v</div><div class="line">1.27.0</div><div class="line"></div><div class="line">ruby -v</div><div class="line">2.3.0p0</div><div class="line"></div><div class="line">rails -v</div><div class="line">5.0.0</div><div class="line"></div><div class="line">bundler -v</div><div class="line">1.12.5</div></pre></td></tr></table></figure></p>
<p>10. 可选升级<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">gem update --system</div></pre></td></tr></table></figure></p>
<hr>
<h3 id="nginx"><a href="#nginx" class="headerlink" title="nginx"></a>nginx</h3><p>1. 安装 passenger<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">gem install passenger</div></pre></td></tr></table></figure></p>
<p>2. 安装 curl 模块<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">apt-get install libcurl4-openssl-dev</div></pre></td></tr></table></figure></p>
<p>3. 安装 pcre<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line">apt-get install libpcre3 libpcre3-dev</div><div class="line">// 或者采用源码安装</div><div class="line">wget https://sourceforge.net/projects/pcre/files/pcre/8.39/pcre-8.39.tar.gz</div><div class="line">tar -zxvf pcre-8.39.tar.gz</div><div class="line">cd pcre-8.39</div><div class="line">./configure</div><div class="line">make &amp; make install</div></pre></td></tr></table></figure></p>
<p>4. 安装nginx</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">passenger-install-nginx-module</div></pre></td></tr></table></figure>
<p>5. 配置nginx配置</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line">location / &#123;</div><div class="line">    #root   html;</div><div class="line">    #index  index.html index.htm;</div><div class="line">    root   /opt/redmine-3.3.0/public;</div><div class="line">    index  index.html index.htm;</div><div class="line">    passenger_enabled on;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<h3 id="mysql"><a href="#mysql" class="headerlink" title="mysql"></a>mysql</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">apt-get install mysql-server</div><div class="line">mysql_secure_installation</div></pre></td></tr></table></figure>
<h3 id="redmine"><a href="#redmine" class="headerlink" title="redmine"></a>redmine</h3><p>1. 将软件包安装到 <code>/opt</code> 目录下<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">// 下载软件包</div><div class="line">cd /opt/</div><div class="line">wget http://www.redmine.org/releases/redmine-3.3.0.tar.gz</div><div class="line">tar -zxvf redmine-3.3.0.tar.gz</div><div class="line">cd redmine-3.3.0</div></pre></td></tr></table></figure></p>
<p>2. 变更 gem 安装源<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">// 编辑 Gemfile，将 source 文件替换为淘宝源</div><div class="line">vim /opt/redmine-3.3.0/Gemfile</div><div class="line">source &apos;https://ruby.taobao.org&apos;</div></pre></td></tr></table></figure></p>
<p>3. 设置 redmine 数据库、用户名、口令<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">mysql -u root -p</div><div class="line">CREATE DATABASE redmine CHARACTER SET utf8;</div><div class="line">CREATE USER &apos;redmine&apos;@&apos;localhost&apos; IDENTIFIED BY &apos;redmine_pass&apos;;</div><div class="line">GRANT ALL PRIVILEGES ON redmine.* TO &apos;redmine&apos;@&apos;localhost&apos;;</div><div class="line">flush privileges;</div></pre></td></tr></table></figure></p>
<p>4. 设置连接数据库<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">// 编辑数据库配置文件</div><div class="line">cp config/database.yml.example config/database.yml</div><div class="line">vim config/database.yml</div></pre></td></tr></table></figure></p>
<p>5. 安装依赖包，根据 <code>bundle install --without development test</code> 的输出提示，安装缺少的依赖包<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div></pre></td><td class="code"><pre><div class="line">bundle install --without development test</div><div class="line"></div><div class="line">// 可能需要安装的依赖包</div><div class="line">apt-get install imagemagick //生成图片的依赖库。</div><div class="line">apt-get install libmagickwand-dev</div><div class="line">apt-get install libmysqlclient-dev</div><div class="line">gem install mysql2 -v &apos;0.3.21&apos;</div><div class="line">gem install rbpdf-font</div><div class="line">gem install rmagick -v &apos;2.15.4&apos;</div></pre></td></tr></table></figure></p>
<p>6. Session 存储密钥<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">rake generate_secret_token</div></pre></td></tr></table></figure></p>
<p>7. 生成 redmine 的数据库表结构和初始化数据<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">RAILS_ENV=production rake db:migrate    //生成表结构</div><div class="line">RAILS_ENV=production rake redmine:load_default_data //初始化数据</div></pre></td></tr></table></figure></p>
<p>8. 创建上传文件的目录和设置文件夹的权限<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line">useradd redmine -m</div><div class="line">passwd redmine  //设置 redmine 账户的密码</div><div class="line">chown -R redmine:redmine files log tmp public/plugin_assets</div><div class="line">chmod -R 755 files log tmp public/plugin_assets/</div></pre></td></tr></table></figure></p>
<p>9. 测试 redmine<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">ruby bin/rails server webrick -e production -b 0.0.0.0 -p 3000</div></pre></td></tr></table></figure></p>
<hr>
<h2 id="其他"><a href="#其他" class="headerlink" title="其他"></a>其他</h2><h3 id="变更目录权限"><a href="#变更目录权限" class="headerlink" title="变更目录权限"></a>变更目录权限</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">chown -R redmine:redmine /opt/redmine</div></pre></td></tr></table></figure>
<h3 id="设置开机启动"><a href="#设置开机启动" class="headerlink" title="设置开机启动"></a>设置开机启动</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">vim /etc/rc.local/</div><div class="line">source /etc/profile.d/rvm.sh    //调用ruby相关的环境变量</div><div class="line">/opt/nginx/sbin/nginx   //手动启动nginx</div></pre></td></tr></table></figure>
<h3 id="完整nginx配置"><a href="#完整nginx配置" class="headerlink" title="完整nginx配置"></a>完整nginx配置</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div></pre></td><td class="code"><pre><div class="line">server &#123;</div><div class="line">    listen       80;</div><div class="line">    server_name  redmine.example.com;</div><div class="line"></div><div class="line">    access_log  logs/redmine.example.com.access.log;</div><div class="line">    error_log   logs/redmine.example.com.error.log;</div><div class="line"></div><div class="line"></div><div class="line">    location / &#123;</div><div class="line">        root   /opt/redmine-3.3.0/public;</div><div class="line">        index  index.html index.htm;</div><div class="line">        passenger_enabled on;</div><div class="line">    &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<h3 id="邮件配置"><a href="#邮件配置" class="headerlink" title="邮件配置"></a>邮件配置</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div></pre></td><td class="code"><pre><div class="line">cd /opt/redmine-3.3.0/config</div><div class="line"></div><div class="line">cp configuration.yml.example configuration.yml</div><div class="line">vi configuration.yml</div><div class="line">---</div><div class="line">      delivery_method: :smtp</div><div class="line">       smtp_settings:</div><div class="line">       address: &quot;mail.example.com&quot;</div><div class="line">              port: 25</div><div class="line">              authentication: :login</div><div class="line">              domain: &apos;example.com&apos;</div><div class="line">              user_name: &apos;admin@example.com&apos;</div><div class="line">              password: &apos;xxxxxxx&apos;</div><div class="line">              enable_starttls_auto: false</div><div class="line">              openssl_verify_mode: &apos;none&apos;</div><div class="line"></div><div class="line">---</div></pre></td></tr></table></figure>
<h3 id="备份和恢复"><a href="#备份和恢复" class="headerlink" title="备份和恢复"></a>备份和恢复</h3><p>关于备份，官方提供的方法是<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line">Backups Redmine backups should include:</div><div class="line">data (stored in your redmine database)</div><div class="line">attachments (stored in the files directory of your Redmine install)</div><div class="line">Here is a simple shell script that can be used for daily backups (assuming you&apos;re using a mysql database):</div><div class="line"></div><div class="line"># Database</div><div class="line">/usr/bin/mysqldump -u &lt;username&gt; -p&lt;password&gt; &lt;redmine_database&gt; | gzip &gt; /path/to/backup/db/redmine_`date +%y_%m_%d`.gz</div><div class="line"></div><div class="line"># Attachments</div><div class="line">rsync -a /path/to/redmine/files /path/to/backup/files</div></pre></td></tr></table></figure></p>
<p>由于 Redmine 的用户和问题等信息存储于 Mysql 数据库，表名为 redmine 而附件等资源存储于 Redmine 安装目录的 files 目录下。<br>简单来说只需要备份 Mysql 数据库的对应的表和 redmine 软件的 files 目录即可。</p>
<h4 id="备份"><a href="#备份" class="headerlink" title="备份"></a>备份</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">// 备份数据库</div><div class="line">/usr/bin/mysqldump -uredmine -predmine_password  redmine | gzip &gt; /path/data/redmine.sql.gz</div><div class="line"></div><div class="line">// 备份软件(用 nginx 作为前端)</div><div class="line">tar -zcf /path/data/redmine_soft_time.tgz  nginx_dir redmine_dir git_dir</div></pre></td></tr></table></figure>
<h4 id="迁移或者恢复"><a href="#迁移或者恢复" class="headerlink" title="迁移或者恢复"></a>迁移或者恢复</h4><p>按照上面安装过程，安装 redmine 需要的环境,之后导入数据库（记得要创建 redmine 用户或给 mysql 授权），再将相应软件包解压即可<br>如果是升级，只拷贝 <code>file</code>目录。</p>
<h3 id="git-版本库配置"><a href="#git-版本库配置" class="headerlink" title="git 版本库配置"></a>git 版本库配置</h3><p>使用 redmine 运行用户，clone 项目至 redmine 目录，</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line">su - redmine</div><div class="line">ssh-keygen -t rsa</div><div class="line"></div><div class="line">copy .ssh/id_rsa.pub to git server</div><div class="line"></div><div class="line">git clone ssh://git@172.16.1.100/a.git</div><div class="line">git clone ssh://git@172.16.1.100/b.git</div><div class="line">git clone ssh://git@172.16.1.100/c.git</div><div class="line">git clone ssh://git@172.16.1.100/d.git</div><div class="line">git clone ssh://git@172.16.1.100/e.git</div></pre></td></tr></table></figure>
<p>项目-配置-版本库:新建<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line">SCM：Git</div><div class="line">库路径：/home/redmine/a/.git</div><div class="line">库路径：/home/redmine/b/.git</div><div class="line">库路径：/home/redmine/c/.git</div><div class="line">库路径：/home/redmine/d/.git</div><div class="line">库路径：/home/redmine/e/.git</div></pre></td></tr></table></figure></p>
<p>实时、定时更新<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">配置hook自动同步、配置cron定时pull</div></pre></td></tr></table></figure></p>
<h3 id="插件管理"><a href="#插件管理" class="headerlink" title="插件管理"></a>插件管理</h3><p>下载插件到 plugins 目录，并执行<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">bundle exec rake redmine:plugins:migrate RAILS_ENV=&apos;production&apos;</div></pre></td></tr></table></figure></p>
<p>scrum 插件<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">http://www.redmine.org/plugins/scrum-plugin</div></pre></td></tr></table></figure></p>
<h3 id="截图"><a href="#截图" class="headerlink" title="截图"></a>截图</h3><p>参考<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">http://www.myexception.cn/open-source/418471.html</div></pre></td></tr></table></figure></p>
]]></content>
    
    <summary type="html">
    
      &lt;a id=&quot;more&quot;&gt;&lt;/a&gt;
&lt;h2 id=&quot;系统环境&quot;&gt;&lt;a href=&quot;#系统环境&quot; class=&quot;headerlink&quot; title=&quot;系统环境&quot;&gt;&lt;/a&gt;系统环境&lt;/h2&gt;&lt;p&gt;ubuntu server 16.04 LTS&lt;/p&gt;
&lt;h2 id=&quot;开发工具&quot;&gt;&lt;a
    
    </summary>
    
      <category term="System" scheme="http://czero000.github.io/categories/System/"/>
    
      <category term="Debian" scheme="http://czero000.github.io/categories/System/Debian/"/>
    
    
      <category term="ubuntu" scheme="http://czero000.github.io/tags/ubuntu/"/>
    
      <category term="redmine" scheme="http://czero000.github.io/tags/redmine/"/>
    
  </entry>
  
  <entry>
    <title>匿名函数lambda</title>
    <link href="http://czero000.github.io/2016/12/09/python-lambda.html"/>
    <id>http://czero000.github.io/2016/12/09/python-lambda.html</id>
    <published>2016-12-09T14:04:46.000Z</published>
    <updated>2017-01-11T07:31:52.189Z</updated>
    
    <content type="html"><![CDATA[<h1 id="匿名函数-lambda"><a href="#匿名函数-lambda" class="headerlink" title="匿名函数 lambda"></a>匿名函数 lambda</h1><p>python 使用 lambda 创建匿名函数，匿名函数就是不适用 <code>def</code> 语句定义函数，语法<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">lambda [arg1[, arg2, ... argN]]: expression</div></pre></td></tr></table></figure></p>
<p>其中，参数是可选的，如果使用参数，参数通常也会在表达式中</p>
<ul>
<li>无参数</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line">// 使用函数定义</div><div class="line">def true():</div><div class="line">    return true</div><div class="line"></div><div class="line">// 等价表达式</div><div class="line">lambda :true</div><div class="line"></div><div class="line">// 保留 lambda 对象到变量中</div><div class="line">true = lambda: True</div><div class="line">true()</div><div class="line">True</div></pre></td></tr></table></figure>
<ul>
<li>含参数</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div></pre></td><td class="code"><pre><div class="line">// 使用def定义的函数</div><div class="line">def add( x, y ):</div><div class="line">    return x + y</div><div class="line"></div><div class="line">// 使用lambda的表达式</div><div class="line">lambda x, y: x + y</div><div class="line"></div><div class="line">// lambda也允许有默认值和使用变长参数</div><div class="line">lambda x, y = 2: x + y</div><div class="line">lambda *z: z</div><div class="line"></div><div class="line">// 调用lambda函数</div><div class="line">a = lambda x, y: x + y</div><div class="line">a( 1, 3 )</div><div class="line">4</div><div class="line"></div><div class="line">b = lambda x, y = 2: x + y</div><div class="line">b( 1 )</div><div class="line">3</div><div class="line">b( 1, 3 )</div><div class="line">4</div><div class="line"></div><div class="line">c = lambda *z: z</div><div class="line">c( 10, &apos;test&apos;)</div><div class="line">(10, &apos;test&apos;)</div></pre></td></tr></table></figure>
]]></content>
    
    <summary type="html">
    
      &lt;h1 id=&quot;匿名函数-lambda&quot;&gt;&lt;a href=&quot;#匿名函数-lambda&quot; class=&quot;headerlink&quot; title=&quot;匿名函数 lambda&quot;&gt;&lt;/a&gt;匿名函数 lambda&lt;/h1&gt;&lt;p&gt;python 使用 lambda 创建匿名函数，匿名函数就是不适用 
    
    </summary>
    
      <category term="Python" scheme="http://czero000.github.io/categories/Python/"/>
    
    
      <category term="python" scheme="http://czero000.github.io/tags/python/"/>
    
  </entry>
  
  <entry>
    <title>精简docker镜像</title>
    <link href="http://czero000.github.io/2016/12/01/simplify-docker-image.html"/>
    <id>http://czero000.github.io/2016/12/01/simplify-docker-image.html</id>
    <published>2016-12-01T09:27:14.000Z</published>
    <updated>2016-12-01T09:29:49.460Z</updated>
    
    <content type="html"><![CDATA[<p><img src="http://ofc9x1ccn.bkt.clouddn.com/docker/docker-images.png" alt=""><br>图注：一张图掌握 Docker 命令 - 简化版</p>
<p><img src="http://ofc9x1ccn.bkt.clouddn.com/docker/docker-commands.png" alt=""><br>图注：一张图掌握 Docker 命令 - 完整版</p>
<p>在 docker 镜像的制作过程中，有不少方式可以减少容器的空间占用，甚至镜像可以精简 98%，精简 docker 镜像，既节省了存储空间，又能节省带宽，加快传输。</p>
<h1 id="镜像层"><a href="#镜像层" class="headerlink" title="镜像层"></a>镜像层</h1><p>在开始制作镜像前，首先了解镜像的原理，而这其中最重要的概念就是镜像层(Layers)<br><img src="http://ofc9x1ccn.bkt.clouddn.com/docker/docker-image-layers.png" alt=""><br>在 <code>Dockerfile</code> 中的每条指令都会创建一个镜像层，继而会增加整体镜像的大小。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line">FROM busybox  </div><div class="line">RUN mkdir /tmp/foo  </div><div class="line">RUN dd if=/dev/zero of=/tmp/foo/bar bs=1048576 count=100  </div><div class="line">RUN rm /tmp/foo/bar</div></pre></td></tr></table></figure>
<p>在上面例子中，最终容器没有变回，但是新生成的镜像会比原生镜像大。</p>
<h1 id="精简方法"><a href="#精简方法" class="headerlink" title="精简方法"></a>精简方法</h1><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div></pre></td><td class="code"><pre><div class="line">// 原始 Dockerfile　文件</div><div class="line">FROM ubuntu:trusty  </div><div class="line">ENV VER     3.0.0  </div><div class="line">ENV TARBALL http://download.redis.io/releases/redis-$VER.tar.gz  </div><div class="line"># ==&gt; Install curl and helper tools...</div><div class="line">RUN apt-get update  </div><div class="line">RUN apt-get install -y  curl make gcc  </div><div class="line"># ==&gt; Download, compile, and install...</div><div class="line">RUN curl -L $TARBALL | tar zxv  </div><div class="line">WORKDIR  redis-$VER  </div><div class="line">RUN make  </div><div class="line">RUN make install  </div><div class="line">#...</div><div class="line"># ==&gt; Clean up...</div><div class="line">WORKDIR /  </div><div class="line">RUN apt-get remove -y --auto-remove curl make gcc  </div><div class="line">RUN apt-get clean  </div><div class="line">RUN rm -rf /var/lib/apt/lists/*  /redis-$VER  </div><div class="line">#...</div><div class="line">CMD [&quot;redis-server&quot;]</div></pre></td></tr></table></figure>
<p>通过这个例子，演示如何精简 docker 镜像大小。</p>
<h2 id="1-优化基础镜像"><a href="#1-优化基础镜像" class="headerlink" title="1. 优化基础镜像"></a>1. 优化基础镜像</h2><p>选用更小的基础镜像，在常用的 Linux 系统镜像中，Ubuntu、Centos、Debian中，debian 更为轻量。</p>
<h2 id="2-减少构建步骤"><a href="#2-减少构建步骤" class="headerlink" title="2. 减少构建步骤"></a>2. 减少构建步骤</h2><p>串联 Dockerfile 指令（一般为 RUN 命令）<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div></pre></td><td class="code"><pre><div class="line">// 优化后的 Dockerfile</div><div class="line">FROM debian:jessie</div><div class="line"></div><div class="line">ENV VER     3.0.0  </div><div class="line">ENV TARBALL http://download.redis.io/releases/redis-$VER.tar.gz</div><div class="line"></div><div class="line">RUN echo &quot;==&gt; Install curl and helper tools...&quot;  &amp;&amp; \  </div><div class="line">    apt-get update                      &amp;&amp; \</div><div class="line">    apt-get install -y  curl make gcc   &amp;&amp; \</div><div class="line">    \</div><div class="line">    echo &quot;==&gt; Download, compile, and install...&quot;  &amp;&amp; \</div><div class="line">    curl -L $TARBALL | tar zxv  &amp;&amp; \</div><div class="line">    cd redis-$VER               &amp;&amp; \</div><div class="line">    make                        &amp;&amp; \</div><div class="line">    make install                &amp;&amp; \</div><div class="line">    ...</div><div class="line">    echo &quot;==&gt; Clean up...&quot;  &amp;&amp; \</div><div class="line">    apt-get remove -y --auto-remove curl make gcc  &amp;&amp; \</div><div class="line">    apt-get clean                                  &amp;&amp; \</div><div class="line">    rm -rf /var/lib/apt/lists/*  /redis-$VER</div><div class="line">#...</div><div class="line">CMD [&quot;redis-server&quot;]</div></pre></td></tr></table></figure></p>
<h2 id="3-压缩镜像"><a href="#3-压缩镜像" class="headerlink" title="3. 压缩镜像"></a>3. 压缩镜像</h2><ul>
<li>使用命令或者工具压缩镜像</li>
</ul>
<p>docker 自带的一些命令还能协助压缩镜像，比如 export 和 import<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">docker run -d redis:lab-3</div><div class="line">$ docker export 71b1c0ad0a2b | docker import - redis:lab-4</div></pre></td></tr></table></figure></p>
<p>麻烦的是需要先将容器运行起来，而且这个过程中你会丢失镜像原有的一些信息，比如：导出端口，环境变量，默认指令。</p>
<ul>
<li>使用 <a href="https://github.com/jwilder/docker-squash" target="_blank" rel="external">docker-squash</a></li>
</ul>
<p><a href="https://github.com/jwilder/docker-squash#installation" target="_blank" rel="external">下载安装</a><br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">docker save redis:lab-3 \</div><div class="line"> | sudo docker-squash -verbose -t redis:lab-4  \</div><div class="line"> | docker load</div></pre></td></tr></table></figure></p>
<h2 id="4-使用最精简的基础镜像"><a href="#4-使用最精简的基础镜像" class="headerlink" title="4. 使用最精简的基础镜像"></a>4. 使用最精简的基础镜像</h2><p>使用 scratch 或者 busybox 作为基础镜像。</p>
<p>关于 scratch</p>
<ul>
<li>一个空镜像，只能用于构建镜像，通过 FROM scratch</li>
<li>在构建一些基础镜像，比如 debian 、 busybox，非常有用</li>
<li>用于构建超少镜像，比如构建一个包含所有库的二进制文件</li>
</ul>
<p>关于 busybox + 只有 1~5M 的大小 + 包含了常用的 UNIX 工具 + 非常方便构建小镜像这些超小的基础镜像，结合能生成静态原生 ELF 文件的编译语言，比如C/C++，比如 Go，特别方便构建超小的镜像。</p>
<h2 id="5-提取动态链接的-so-文件"><a href="#5-提取动态链接的-so-文件" class="headerlink" title="5. 提取动态链接的 .so 文件"></a>5. 提取动态链接的 .so 文件</h2><ul>
<li>查看系统信息</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div></pre></td><td class="code"><pre><div class="line">cat /etc/os-release</div><div class="line"></div><div class="line">NAME=&quot;Ubuntu&quot;  </div><div class="line">VERSION=&quot;14.04.2 LTS, Trusty Tahr&quot;  </div><div class="line"></div><div class="line">uname -a</div><div class="line">Linux localhost 3.13.0-46-generic #77-Ubuntu SMP  </div><div class="line">Mon Mar 2 18:23:39 UTC 2015  </div><div class="line">x86_64 x86_64 x86_64 GNU/Linux</div></pre></td></tr></table></figure>
<ul>
<li>打印共享的依赖库</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line">ldd  redis-3.0.0/src/redis-server</div><div class="line">    linux-vdso.so.1 =&gt;  (0x00007fffde365000)</div><div class="line">    libm.so.6 =&gt; /lib/x86_64-linux-gnu/libm.so.6 (0x00007f307d5aa000)</div><div class="line">    libpthread.so.0 =&gt; /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f307d38c000)</div><div class="line">    libc.so.6 =&gt; /lib/x86_64-linux-gnu/libc.so.6 (0x00007f307cfc6000)</div><div class="line">    /lib64/ld-linux-x86-64.so.2 (0x00007f307d8b9000)</div></pre></td></tr></table></figure>
<ul>
<li>打包需要的库文件</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line">tar ztvf rootfs.tar.gz</div><div class="line">4485167  2015-04-21 22:54  usr/local/bin/redis-server  </div><div class="line">1071552  2015-02-25 16:56  lib/x86_64-linux-gnu/libm.so.6  </div><div class="line"> 141574  2015-02-25 16:56  lib/x86_64-linux-gnu/libpthread.so.0</div><div class="line">1840928  2015-02-25 16:56  lib/x86_64-linux-gnu/libc.so.6  </div><div class="line"> 149120  2015-02-25 16:56  lib64/ld-linux-x86-64.so.2</div></pre></td></tr></table></figure>
<ul>
<li>制作 Dockerfile</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">FROM scratch  </div><div class="line">ADD  rootfs.tar.gz  /  </div><div class="line">COPY redis.conf     /etc/redis/redis.conf  </div><div class="line">EXPOSE 6379  </div><div class="line">CMD [&quot;redis-server&quot;]</div></pre></td></tr></table></figure>
]]></content>
    
    <summary type="html">
    
      &lt;p&gt;&lt;img src=&quot;http://ofc9x1ccn.bkt.clouddn.com/docker/docker-images.png&quot; alt=&quot;&quot;&gt;&lt;br&gt;图注：一张图掌握 Docker 命令 - 简化版&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://ofc9x1cc
    
    </summary>
    
      <category term="运维技术" scheme="http://czero000.github.io/categories/%E8%BF%90%E7%BB%B4%E6%8A%80%E6%9C%AF/"/>
    
      <category term="Docker" scheme="http://czero000.github.io/categories/%E8%BF%90%E7%BB%B4%E6%8A%80%E6%9C%AF/Docker/"/>
    
    
      <category term="docker" scheme="http://czero000.github.io/tags/docker/"/>
    
  </entry>
  
  <entry>
    <title>Keepalived Systemd启动脚本</title>
    <link href="http://czero000.github.io/2016/11/29/keepalived-systemctl.html"/>
    <id>http://czero000.github.io/2016/11/29/keepalived-systemctl.html</id>
    <published>2016-11-29T06:07:33.000Z</published>
    <updated>2017-01-11T09:49:51.947Z</updated>
    
    <content type="html"><![CDATA[<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div></pre></td><td class="code"><pre><div class="line">[Unit]</div><div class="line">Description=LVS and VRRP High Availability Monitor</div><div class="line">After=syslog.target network.target</div><div class="line"></div><div class="line">[Service]</div><div class="line">Type=forking</div><div class="line">PIDFile=/var/run/keepalived.pid</div><div class="line">KillMode=process</div><div class="line">EnvironmentFile=-/etc/sysconfig/keepalived</div><div class="line">ExecStart=/usr/sbin/keepalived $KEEPALIVED_OPTIONS</div><div class="line">ExecReload=/bin/kill -HUP $MAINPID</div><div class="line"></div><div class="line">[Install]</div><div class="line">WantedBy=multi-user.target</div></pre></td></tr></table></figure>
]]></content>
    
    <summary type="html">
    
      &lt;figure class=&quot;highlight plain&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;div class=&quot;line&quot;&gt;1&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;2&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;3&lt;/di
    
    </summary>
    
      <category term="Web" scheme="http://czero000.github.io/categories/Web/"/>
    
      <category term="keepalived" scheme="http://czero000.github.io/categories/Web/keepalived/"/>
    
    
      <category term="keepalived" scheme="http://czero000.github.io/tags/keepalived/"/>
    
  </entry>
  
  <entry>
    <title>keepalived高可用</title>
    <link href="http://czero000.github.io/2016/11/29/keepalived.html"/>
    <id>http://czero000.github.io/2016/11/29/keepalived.html</id>
    <published>2016-11-29T06:07:33.000Z</published>
    <updated>2017-01-11T08:07:32.287Z</updated>
    
    <content type="html"><![CDATA[<h3 id="介绍"><a href="#介绍" class="headerlink" title="介绍"></a>介绍</h3><p>Keepalived 是一种高性能的服务器高可用或热备解决方案，Keepalived可以用来防止服务器单点故障(单点故障是指一旦某一点出现故障就会导致整个系统架构的不可用)的发生，通过配合Nginx可以实现web前端服务的高可用。</p>
<h3 id="环境介绍"><a href="#环境介绍" class="headerlink" title="环境介绍"></a>环境介绍</h3><h4 id="系统版本"><a href="#系统版本" class="headerlink" title="系统版本"></a>系统版本</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">CentOS 6.5 x86_64</div></pre></td></tr></table></figure>
<h4 id="IP信息"><a href="#IP信息" class="headerlink" title="IP信息"></a>IP信息</h4><table>
<thead>
<tr>
<th>主ningx</th>
<th>备nginx</th>
</tr>
</thead>
<tbody>
<tr>
<td>172.16.6.245</td>
<td>172.16.6.246</td>
</tr>
</tbody>
</table>
<h3 id="keepalive"><a href="#keepalive" class="headerlink" title="keepalive"></a>keepalive</h3><h4 id="安装依赖软件包"><a href="#安装依赖软件包" class="headerlink" title="安装依赖软件包"></a>安装依赖软件包</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">yum install -y kernel-devel openssl-devel gcc gcc-c++ autoconf openssl openssl-devel</div></pre></td></tr></table></figure>
<h4 id="安装keepalive"><a href="#安装keepalive" class="headerlink" title="安装keepalive"></a>安装keepalive</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line">tar -zxf keepalived-1.2.17.tar.gz</div><div class="line">cd keepalived-1.2.17</div><div class="line">./configure --prefix=/usr/local/keepalived --with-kernel-dir=/usr/src/kernels/2.6.32-504.23.4.el6.x86_64</div><div class="line">make &amp;&amp; make install</div><div class="line">cd /usr/local/keepalived/</div><div class="line">cp etc/rc.d/init.d/keepalived /etc/rc.d/init.d/</div><div class="line">cp etc/sysconfig/keepalived /etc/sysconfig/</div><div class="line">mkdir /etc/keepalived</div><div class="line">cp $DIR/keepalived.conf /etc/keepalived/</div><div class="line">ln -s /usr/local/keepalived/sbin/keepalived /usr/sbin/</div><div class="line">chkconfig keepalived on</div></pre></td></tr></table></figure>
<h3 id="配置keepalive"><a href="#配置keepalive" class="headerlink" title="配置keepalive"></a>配置keepalive</h3><h4 id="主服务器配置文件"><a href="#主服务器配置文件" class="headerlink" title="主服务器配置文件"></a>主服务器配置文件</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div></pre></td><td class="code"><pre><div class="line">! Configuration File for keepalived</div><div class="line"></div><div class="line">global_defs &#123;</div><div class="line">   notification_email &#123;</div><div class="line">   charlie.cui@zerounix.com                       \\设置报警邮件地址，可以设置多个，每行一个,需要开启sendmail服务，根据实际情况配置 </div><div class="line">   notification_email_from mail.zerounix.com</div><div class="line">   smtp_server mail.zerounix.com</div><div class="line">   smtp_connect_timeout 30</div><div class="line">   router_id LVS_DEVEL                            \\ 节点名标识</div><div class="line">&#125;</div><div class="line"></div><div class="line">vrrp_script chk_https_port &#123;                       \\ 服务检查脚本</div><div class="line">    script &quot;/root/nginx_check&quot;</div><div class="line">    interval 2                                      \\检查间隔</div><div class="line">    weight 2                                       \\权重</div><div class="line">&#125;</div><div class="line">vrrp_instance VIP &#123;                                \\vrrp实例定义部分                               </div><div class="line">    state MASTER                                   \\ 标示状态为MASTER 指定Keepalived的角色（MASTER主，BACKUP备）</div><div class="line">    interface eth0                                 \\HA通信网卡</div><div class="line">    virtual_router_id 128                          \\ 虚拟路由标,同一个vrrp实例使用唯一的标识，即同一个vrrp_instance下的MASTER和BACKUP必须一致  </div><div class="line">    mcast_src_ip 172.16.6.245                      \\vrrp实体服务器的IP  发送多播包的地址，如果不设置默认使用绑定网卡的primary ip  </div><div class="line">    priority 100                                   \\MASTER权重要高于BACKUP 数字越大优选级越高  </div><div class="line">    advert_int 1                                   \\组播信息发送间隔，两个节点设置必须一样</div><div class="line">    authentication &#123;</div><div class="line">        auth_type PASS                             \\主从服务器验证方式  设置验证类型和密码，MASTER和BACKUP必须使用相同的密码才能正常通信  </div><div class="line">        auth_pass 1111</div><div class="line">    &#125;</div><div class="line">    virtual_ipaddress &#123;</div><div class="line">        172.16.6.250                                \\虚拟IP 可以设置多个虚拟IP地址，每行一个  </div><div class="line">    &#125;</div><div class="line">    track_script &#123;</div><div class="line">        chk_https_port                             \\调用检测脚本</div><div class="line">    &#125;</div><div class="line">    track_interface &#123;                              \\ 健康检测网卡</div><div class="line">　　eth0</div><div class="line">　　&#125;</div><div class="line">&#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<h4 id="备服务器配置文件"><a href="#备服务器配置文件" class="headerlink" title="备服务器配置文件"></a>备服务器配置文件</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div></pre></td><td class="code"><pre><div class="line">! Configuration File for keepalived</div><div class="line"></div><div class="line">global_defs &#123;</div><div class="line">   notification_email &#123;</div><div class="line">        charlie.cui@zerounix.com</div><div class="line">   &#125;</div><div class="line">   notification_email_from mail.zerounix.com</div><div class="line">   smtp_server mail.zerounix.com</div><div class="line">   smtp_connect_timeout 30</div><div class="line">   router_id LVS_DEVEL</div><div class="line">&#125;</div><div class="line"></div><div class="line">vrrp_script chk_https_port &#123;</div><div class="line">    script &quot;/root/nginx_check&quot;</div><div class="line">    interval 2</div><div class="line">    weight 2</div><div class="line">&#125;</div><div class="line">vrrp_instance VIP &#123;</div><div class="line">    state BACKUP</div><div class="line">    interface eth0</div><div class="line">    virtual_router_id 128</div><div class="line">    mcast_src_ip 172.16.6.246</div><div class="line">    priority 90</div><div class="line">    advert_int 1</div><div class="line">    authentication &#123;</div><div class="line">        auth_type PASS</div><div class="line">        auth_pass 1111</div><div class="line">    &#125;</div><div class="line">    virtual_ipaddress &#123;</div><div class="line">        172.16.6.250</div><div class="line">    &#125;</div><div class="line">    track_script &#123;</div><div class="line">        chk_https_port</div><div class="line">    &#125;</div><div class="line">    track_interface &#123;</div><div class="line">　　eth0</div><div class="line">　　&#125;</div><div class="line">&#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<h4 id="服务检查脚本"><a href="#服务检查脚本" class="headerlink" title="服务检查脚本"></a>服务检查脚本</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line">more nginx_check </div><div class="line">#!/bin/bash</div><div class="line">A=`ps -C nginx --no-header |wc -l`              </div><div class="line">if [ $A -eq 0 ];then                                      </div><div class="line">                /usr/local/nginx/sbin/nginx</div><div class="line">                sleep 3</div><div class="line">                if [ `ps -C nginx --no-header |wc -l` -eq 0 ];then</div><div class="line">                       killall keepalived</div><div class="line">                fi</div><div class="line">fi</div></pre></td></tr></table></figure>
<h3 id="运行keepalive"><a href="#运行keepalive" class="headerlink" title="运行keepalive"></a>运行keepalive</h3><p>配置完成后就可以运行看下效果了,分别在主从服务器上启动nginx和keepalived<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">service keepalived start</div></pre></td></tr></table></figure></p>
<p>启动之后通过<code>ip -a</code>命令查看主服务器的网络信息，可以看到在eth0网卡下生成了<code>172.16.6.250</code>这个虚拟ip，并可通过这个ip访问到nginx</p>
<p>然后我们关闭nginx的进程（如果配置了一次尝试重启那要注意下），然后我们可以通过ps -e查看keepalived进程是否关闭，正常情况下查看网络信息中，可以看到eth0网卡下的虚拟ip已经解除，然后在从服务器的网络信息中可以看到从服务器的eth0网卡绑定了虚拟ip，通过这个ip就访问到了从服务器的nginx去了，这是我们重新启动主服务器的nginx和keepalieved，我们可以发现虚拟ip就绑回到了主服务器。</p>
<h3 id="小结"><a href="#小结" class="headerlink" title="小结"></a>小结</h3><ul>
<li>keepalived通过虚拟路由实现双机热备，相比其他方案具有一定的优越性</li>
<li>因为是固定主从热备，该方案比较适合两个互备服务器性能有差异的情况</li>
<li>Keepalived同样可以实现双主互备，通过设置互为主备，然后通过DNS负载均衡到不同vip就可以实现</li>
</ul>
]]></content>
    
    <summary type="html">
    
      &lt;h3 id=&quot;介绍&quot;&gt;&lt;a href=&quot;#介绍&quot; class=&quot;headerlink&quot; title=&quot;介绍&quot;&gt;&lt;/a&gt;介绍&lt;/h3&gt;&lt;p&gt;Keepalived 是一种高性能的服务器高可用或热备解决方案，Keepalived可以用来防止服务器单点故障(单点故障是指一旦某一点出现故
    
    </summary>
    
      <category term="Web" scheme="http://czero000.github.io/categories/Web/"/>
    
      <category term="keepalived" scheme="http://czero000.github.io/categories/Web/keepalived/"/>
    
    
      <category term="keepalived" scheme="http://czero000.github.io/tags/keepalived/"/>
    
  </entry>
  
  <entry>
    <title>LVS+Keepalived高可用介绍</title>
    <link href="http://czero000.github.io/2016/11/29/keepalived-lvs.html"/>
    <id>http://czero000.github.io/2016/11/29/keepalived-lvs.html</id>
    <published>2016-11-29T06:07:33.000Z</published>
    <updated>2017-01-11T09:13:49.079Z</updated>
    
    <content type="html"><![CDATA[<h1 id="LVS-Keepalived介绍"><a href="#LVS-Keepalived介绍" class="headerlink" title="LVS+Keepalived介绍"></a>LVS+Keepalived介绍</h1><p>lVS是Linux Virtual Server的简写，即Linux虚拟服务器，是一个虚拟的服务器集群系统，LVS项目在1998年5月由章文嵩博士成立，是中国国内最早出现的自由软件项目之一。目前有三种IP负载均衡技术（VS/NAT、VS/TUN和VS/DR）；十种调度算法<code>（rrr|wrr|lc|wlc|lblc|lblcr|dh|sh|sed|nq）</code>。</p>
<p>Keepalived是一个类似于layer3，4&amp;5交换机制的软件，主要用作RealServer的健康状态检查以及LoadBalance主机和BackUP主机之间failover的实现。高可用架</p>
<p>##简单负载均衡架构</p>
<p>IP信息列表：</p>
<table>
<thead>
<tr>
<th>名称</th>
<th>IP</th>
</tr>
</thead>
<tbody>
<tr>
<td>LVS-VIP</td>
<td>172.16.7.55</td>
</tr>
<tr>
<td>LVS-Master</td>
<td>172.16.7.56</td>
</tr>
<tr>
<td>LVS-Slave</td>
<td>172.16.7.57</td>
</tr>
<tr>
<td>Web-RealServer</td>
<td>172.16.7.16</td>
</tr>
<tr>
<td>Web-RealServer</td>
<td>172.16.7.144</td>
</tr>
</tbody>
</table>
<h1 id="安装LVS和Keepalived"><a href="#安装LVS和Keepalived" class="headerlink" title="安装LVS和Keepalived"></a>安装LVS和Keepalived</h1><p>IPVS (IP Virtual Server)是整个负载均衡的基础，如果没有这个基础，故障隔离与切换就毫无意义。IPVS基本上是一种高效的Layer-4交换机，它提供负载平衡的功能。当一个TCP连接的初始SYN报文到达时，IPVS就选择一台服务器，将报文转发给它。此后通过查发报文的IP和TCP报文头地址，保证此连接的后继报文被转发到相同的服务器。这样，IPVS无法检查到请求的内容再选择服务器，这就要求后端的服务器组是提供相同的服务，不管请求被送到哪一台服务器，返回结果都应该是一样的。但是在有一些应用中后端的服务器可能功能不一，有的是提供HTML文档的Web服务器，有的是提供图片的Web服务器，有的是提供CGI的Web服务器。这时，就需要基于内容请求分发 (Content-Based Request Distribution)，同时基于内容请求分发可以提高后端服务器上访问的局部性。IPVS具体实现是由Ipvsadm这个程序来完成，因此判断一个系统是否具备ipvs功能，只要查看Ipvsadm程序是否安装，最简单的办法便是执行命令ipvsadm。</p>
<h2 id="下载相关软件包"><a href="#下载相关软件包" class="headerlink" title="下载相关软件包"></a>下载相关软件包</h2><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">cd /usr/local/src/</div><div class="line">wget http://www.linuxvirtualserver.org/software/kernel-2.6/ipvsadm-1.26.tar.gz</div><div class="line">wget http://www.keepalived.org/software/keepalived-1.2.17.tar.gz</div></pre></td></tr></table></figure>
<h2 id="安装LVS和Keepalived-1"><a href="#安装LVS和Keepalived-1" class="headerlink" title="安装LVS和Keepalived"></a>安装LVS和Keepalived</h2><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div></pre></td><td class="code"><pre><div class="line">lsmod | grep ip_vs                                                     #查看是否加载模块</div><div class="line">uname -r                                                              #查看内核版本   </div><div class="line">2.6.18-164.el5</div><div class="line">ln -s /usr/src/kernels/2.6.18-164.el5-i686/ /usr/src/linux            #防止ipvsadm找不到系统内核，需要安装kernel-devel</div><div class="line">tar -zxf ipvsadm-1.24.tar.gz                                          #解压源代码</div><div class="line">cd ipvsadm-1.24                                                       #切换目录</div><div class="line">make &amp;&amp; make install                                                  #编译安装</div><div class="line">find / -name ipvsadm                                                  #查找安装后文件位置</div><div class="line">/etc/rc.d/init.d/ipvsadm                       </div><div class="line">/usr/local/src/ipvsadm-1.24/ipvsadm</div><div class="line">/sbin/ipvsadm</div><div class="line"># ipvsadm                                                               #检验ipvsadm是否正确安装</div><div class="line">IP Virtual Server version 1.2.1 (size=4096)</div><div class="line">Prot LocalAddress:Port Scheduler Flags</div><div class="line"> -&gt; RemoteAddress:PortForward Weight ActiveConn InActConn </div><div class="line">lsmod | grep ip_vs                                                    #内核是否加载模块</div><div class="line">ip_vs77441  0</div></pre></td></tr></table></figure>
<p><strong>报错：</strong><br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">make[1]: *** [libipvs.o] Error 1</div><div class="line">make[1]: Leaving directory `/usr/local/src/ipvsadm-1.26/libipvs&apos;</div><div class="line">make: *** [libs] Error 2</div></pre></td></tr></table></figure></p>
<p><strong>解决：</strong><br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">yum install libnl* popt* -y</div></pre></td></tr></table></figure></p>
<h2 id="安装Keepalive"><a href="#安装Keepalive" class="headerlink" title="安装Keepalive"></a>安装Keepalive</h2><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div></pre></td><td class="code"><pre><div class="line">cd ..</div><div class="line">tar -zxf keepalived-1.1.15.tar.gz</div><div class="line">cd keepalived-1.1.15</div><div class="line">./configure --prefix=/usr/local/keepalived \</div><div class="line">-with-kernel-dir=/usr/src/kernels/2.6.18-164.el5-i686</div><div class="line">Keepalived configuration</div><div class="line">------------------------</div><div class="line">Keepalived version       : 1.1.15</div><div class="line">Compiler: gcc</div><div class="line">Compiler flags: -g -O2</div><div class="line">Extra Lib: -lpopt -lssl -lcrypto</div><div class="line">Use IPVS Framework       : Yes</div><div class="line">IPVS sync daemon support : Yes</div><div class="line">Use VRRP Framework       : Yes</div><div class="line">Use LinkWatch: No</div><div class="line">Use Debug flags: No</div><div class="line">make &amp;&amp; make install</div><div class="line">find / -name keepalived</div><div class="line">/usr/local/keepalived</div><div class="line">/usr/local/keepalived/etc/sysconfig/keepalived</div><div class="line">/usr/local/keepalived/etc/rc.d/init.d/keepalived</div><div class="line">/usr/local/keepalived/etc/keepalived</div><div class="line">/usr/local/keepalived/sbin/keepalived</div><div class="line">cd /usr/local/keepalived/</div><div class="line">cp etc/rc.d/init.d/keepalived /etc/rc.d/init.d/</div><div class="line">cp etc/sysconfig/keepalived /etc/sysconfig/</div><div class="line">mkdir /etc/keepalived</div><div class="line">cp etc/keepalived/keepalived.conf /etc/keepalived/</div><div class="line">ln -s /usr/local/keepalived/sbin/keepalived /usr/sbin/</div></pre></td></tr></table></figure>
<h1 id="配置LVS及Keepalived"><a href="#配置LVS及Keepalived" class="headerlink" title="配置LVS及Keepalived"></a>配置LVS及Keepalived</h1><h2 id="编写配置脚本"><a href="#编写配置脚本" class="headerlink" title="编写配置脚本"></a>编写配置脚本</h2><p>绑定VIP地址到LVS_Master上，并设定LVS工作模式为dr(此脚本不适用在Keepalived方案中，只可单独使用)，代码如下</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div></pre></td><td class="code"><pre><div class="line">cat lvs_dr</div><div class="line">#!/bin/bash</div><div class="line"># description: Start LVS of DirectorServer</div><div class="line"># Write by:Charlie.Cui</div><div class="line"> </div><div class="line">FRed=&quot;\E[31;40m&quot;; FGreen=&quot;\E[32;40m&quot;; FBlue=&quot;\E[34;40m&quot;; St0=&quot;\033[1m&quot;; St1=&quot;\033[5m&quot;; Ed=&quot;\033[0m&quot;  </div><div class="line"> </div><div class="line"># Set website director vip.</div><div class="line">LVS_VIP=172.16.7.55</div><div class="line">LVS_RIP1=172.16.7.16</div><div class="line">LVS_RIP2=172.16.7.144</div><div class="line"> </div><div class="line">. /etc/rc.d/init.d/functions</div><div class="line"> </div><div class="line">logger $0 called with $1</div><div class="line">case &quot;$1&quot; in</div><div class="line">start)</div><div class="line">        # set LVS vip</div><div class="line">        echo -e Starting LVS Of DirectorServer:&quot;\t&quot;&quot;$FGreen$Sto[OK]$Ed&quot;</div><div class="line">        echo -e Set LVS_VIP:&quot;\t&quot;&quot;$FGreen$Sto$LVS_VIP$Ed&quot;</div><div class="line">/sbin/ipvsadm --set 30 5 60</div><div class="line">/sbin/ifconfig eth1:0 $LVS_VIP broadcast $LVS_VIP netmask 255.255.255.255 broadcast $LVS_VIP up</div><div class="line">/sbin/route add -host $LVS_VIP dev eth1:0</div><div class="line">/sbin/ipvsadm -A -t $LVS_VIP:80 -s wrr -p 3</div><div class="line">/sbin/ipvsadm -a -t $LVS_VIP:80 -r $LVS_RIP1:80 -g -w 1</div><div class="line">/sbin/ipvsadm -a -t $LVS_VIP:80 -r $LVS_RIP2:80 -g -w 1</div><div class="line">touch /var/lock/subsys/ipvsadm &gt;/dev/null 2&gt;&amp;1</div><div class="line">;;</div><div class="line">stop)</div><div class="line">/sbin/ipvsadm -C</div><div class="line">/sbin/ipvsadm -Z</div><div class="line">/sbin/route del -host $LVS_VIP dev eth1:0</div><div class="line">/sbin/ifconfig eth1:0 down</div><div class="line">/bin/rm -rf /var/lock/subsys/ipvsadm &gt;/dev/null 2&gt;&amp;1</div><div class="line">        echo -e Stoping LVS Of DirectorServer:&quot;\t&quot;&quot;$FGreen$Sto[OK]$Ed&quot;</div><div class="line">;;</div><div class="line">status)</div><div class="line">        if [ ! -e /var/lock/subsys/ipvsadm ];then</div><div class="line">echo -e &quot;$FRed ipvsadm is stoped $Ed&quot;</div><div class="line">exit 1</div><div class="line">        else</div><div class="line">echo -e &quot;$FGreen$Sto ipvsadm is running $Ed&quot;</div><div class="line">        fi</div><div class="line">      ;;</div><div class="line">*)</div><div class="line">        echo &quot;Usage: $0 &#123;start|stop|status&#125;&quot;</div><div class="line">        exit 1</div><div class="line">esac</div><div class="line">exit 0</div></pre></td></tr></table></figure>
<ul>
<li>用ipvsadm -Ln查看虚拟服务器IP</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line">ipvsadm -Ln</div><div class="line">IP Virtual Server version 1.2.1 (size=4096)</div><div class="line">Prot LocalAddress:Port Scheduler Flags</div><div class="line">  -&gt; RemoteAddress:PortForward Weight ActiveConn InActConn</div><div class="line">TCP  172.16.7.55:80 wrr persistent 3</div><div class="line">  -&gt; 172.16.7.16:80Route   1      00</div><div class="line">  -&gt; 172.16.7.144:80Local   1      00</div></pre></td></tr></table></figure>
<ul>
<li>查看LVS_VIP 是否绑定到Master上</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div></pre></td><td class="code"><pre><div class="line">ip addr</div><div class="line">1: lo:  mtu 16436 qdisc noqueue</div><div class="line">    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00</div><div class="line">    inet 127.0.0.1/8 scope host lo</div><div class="line">    inet6 ::1/128 scope host</div><div class="line">valid_lft forever preferred_lft forever</div><div class="line">3: eth1:  mtu 1500 qdisc pfifo_fast qlen 1000</div><div class="line">    link/ether 00:50:56:9f:00:38 brd ff:ff:ff:ff:ff:ff</div><div class="line">    inet 172.16.7.56/24 brd 172.16.7.255 scope global eth1</div><div class="line">    inet 172.16.7.55/32 brd 172.16.7.55 scope global eth1:0</div><div class="line">    inet6 fe80::250:56ff:fe9f:38/64 scope link</div><div class="line">valid_lft forever preferred_lft forever</div><div class="line">4: sit0:  mtu 1480 qdisc noop</div><div class="line">    link/sit 0.0.0.0 brd 0.0.0.0</div></pre></td></tr></table></figure>
<hr>
<h2 id="配置Keepalived"><a href="#配置Keepalived" class="headerlink" title="配置Keepalived"></a>配置Keepalived</h2><p>修改/etc/keepalived/keepalived.conf,以下是Master的配置文件，Backup的只需要将红色的子修改即可。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div></pre></td><td class="code"><pre><div class="line">cat /etc/keepalived/keepalived.conf</div><div class="line">! Configuration File for keepalived</div><div class="line"> </div><div class="line">global_defs &#123;</div><div class="line">   notification_email &#123;</div><div class="line">charlie.cui@hotmail.com                             #配置管理员邮箱，用于报警一行设置一个，可以设置多个</div><div class="line">   &#125;</div><div class="line">notification_email_from mail.hotmail.com             #设置邮件发送地址</div><div class="line">   smtp_server 127.0.0.1                        #smtp Server地址</div><div class="line">   smtp_connect_timeout 30                              #与smtp服务超时时间</div><div class="line">   router_id LVS_Master                                 #路由ID和backup要不同，不然会报错</div><div class="line">&#125;</div><div class="line">#set VIP</div><div class="line">vrrp_instance VIP &#123;                                    </div><div class="line">    state MASTER                                 #指定Keepalived的角色，master代表主，backup代表辅</div><div class="line">    interface eth1                                       #指定HA检测网络的接口</div><div class="line">virtual_router_id 51                         #虚拟路由标示，同一个vrrp_instance下面master和backup要一样</div><div class="line">    priority 100                                 #优先级，数字大，优先级高，master要大于backup</div><div class="line">    advert_int 1                                 #设定master与backup之间存活检查的时间间隔</div><div class="line">    authentication &#123;                                     #设定验证类型和密码</div><div class="line">auth_type PASS                                   #设置验证类型，主要有PASS和AH两种</div><div class="line">auth_pass 1111                                   #设置验证密码，master和backup要一样，这样才能正常通信</div><div class="line">    &#125;           </div><div class="line">    virtual_ipaddress &#123;                                 </div><div class="line">172.16.7.55                                      #设置虚拟IP地址，可以设置多个，每行一个</div><div class="line">    &#125;</div><div class="line">&#125;</div><div class="line"> </div><div class="line">virtual_server 172.16.7.55 80 &#123;                         #设置虚拟服务器，需要指定ip地址和监听端口 </div><div class="line">    delay_loop 6                                 #健康检测时间，单位是秒</div><div class="line">    lb_algo rr                                           #设置负载调度算法，这里是rr，即轮询算法</div><div class="line">    lb_kind DR                                           #设置LVS实现负载均衡的机制，还可以为NAT和TUN</div><div class="line">persistence_timeout 50                               #会话保持时间，单位是秒，这个选项对于动态网页是非常有用的，为集群中的session共享提供了一个很好的解决方案。有个这个会话保持功能用户的请求会被一直分发到某个服务节点，直到超过这个会话保持时间，需要注意的是，这个会话保持时间，是最大无响应超时时间，也就是说用户在操作动态页面时，如果在50秒内没有执行任何操作，那么接下来的操作会被分发的其他节点，但是如果一直操作，则不受50秒限制。</div><div class="line">    protocol TCP                                 #指定转发协议类型，有tcp和udp两种</div><div class="line"> </div><div class="line">real_server 172.16.7.16 80 &#123;                     #配置RealServer信息，需要指定ip地址和监听端口    </div><div class="line">weight 3                                 #配置节点权重，数字大，权重大，服务器好可以设置较大的值，可以充分理由服务器资源</div><div class="line">TCP_CHECK &#123;                                      #RealServer的状态检测，单位秒</div><div class="line">connect_timeout 3                             #超时无响应时间</div><div class="line">nb_get_retry 3                                #重试次数</div><div class="line">delay_before_retry 3                  #重试间隔</div><div class="line">        &#125;</div><div class="line">    &#125;</div><div class="line"> </div><div class="line">real_server 172.16.7.144 80 &#123;</div><div class="line">weight 3</div><div class="line">TCP_CHECK &#123;</div><div class="line">connect_timeout 3</div><div class="line">nb_get_retry 3</div><div class="line">delay_before_retry 3</div><div class="line">        &#125;</div><div class="line">    &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<h2 id="配置RealServer"><a href="#配置RealServer" class="headerlink" title="配置RealServer"></a>配置RealServer</h2><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div></pre></td><td class="code"><pre><div class="line">cat lvs_real</div><div class="line">#!/bin/bash</div><div class="line">##Description: Start realserver</div><div class="line">FRed=&quot;\E[31;40m&quot;; FGreen=&quot;\E[32;40m&quot;; FBlue=&quot;\E[34;40m&quot;; St0=&quot;\033[1m&quot;; St1=&quot;\033[5m&quot;; Ed=&quot;\033[0m&quot;  </div><div class="line">VIP=172.16.7.55</div><div class="line">source= /etc/rc.d/init.d/functions</div><div class="line">case &quot;$1&quot; in</div><div class="line">start)</div><div class="line">        echo -e &quot;$FRed$St0 Start LVS of Realserver $Ed &quot;</div><div class="line">        echo -e &quot;$FGreen$St0 Set VIP: $VIP $Ed&quot;</div><div class="line">/sbin/ifconfig lo:0 $VIP broadcast $VIP netmask 255.255.255.255 up</div><div class="line">        echo &quot;1&quot; &gt;/proc/sys/net/ipv4/conf/lo/arp_ignore</div><div class="line">        echo &quot;2&quot; &gt;/proc/sys/net/ipv4/conf/lo/arp_announce</div><div class="line">        echo &quot;1&quot; &gt;/proc/sys/net/ipv4/conf/all/arp_ignore</div><div class="line">        echo &quot;2&quot; &gt;/proc/sys/net/ipv4/conf/all/arp_announce</div><div class="line">;;</div><div class="line">stop)</div><div class="line">        echo -e &quot;$FRed$St0 Close LVS Directorserver $Ed&quot;</div><div class="line"> </div><div class="line">/sbin/ifconfig lo:0 down</div><div class="line">        echo &quot;0&quot; &gt;/proc/sys/net/ipv4/conf/lo/arp_ignore</div><div class="line">        echo &quot;0&quot; &gt;/proc/sys/net/ipv4/conf/lo/arp_announce</div><div class="line">        echo &quot;0&quot; &gt;/proc/sys/net/ipv4/conf/all/arp_ignore</div><div class="line">        echo &quot;0&quot; &gt;/proc/sys/net/ipv4/conf/all/arp_announce</div><div class="line">;;</div><div class="line">*)</div><div class="line">        echo &quot;Usage:$0 &#123;start|stop&#125;&quot;</div><div class="line">exit 1</div><div class="line">esac</div></pre></td></tr></table></figure>
<h2 id="测试LVS-Keepalived"><a href="#测试LVS-Keepalived" class="headerlink" title="测试LVS+Keepalived"></a>测试LVS+Keepalived</h2><h3 id="在2台RealServer上面绑定LVS虚拟IP及抑制arp"><a href="#在2台RealServer上面绑定LVS虚拟IP及抑制arp" class="headerlink" title="在2台RealServer上面绑定LVS虚拟IP及抑制arp"></a>在2台RealServer上面绑定LVS虚拟IP及抑制arp</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div></pre></td><td class="code"><pre><div class="line">/opt/lvs_real start</div><div class="line"> Start LVS of Realserver </div><div class="line"> Set VIP: 172.16.7.55 </div><div class="line"></div><div class="line">ip addr</div><div class="line">1: lo:  mtu 16436 qdisc noqueue</div><div class="line">    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00</div><div class="line">    inet 127.0.0.1/8 scope host lo</div><div class="line">    inet 172.16.7.55/32 brd 172.16.7.55 scope global lo:0</div><div class="line">    inet6 ::1/128 scope host</div><div class="line">valid_lft forever preferred_lft forever</div><div class="line">3: eth1:  mtu 1500 qdisc pfifo_fast qlen 1000</div><div class="line">    link/ether 00:e0:81:b9:a4:88 brd ff:ff:ff:ff:ff:ff</div><div class="line">    inet 172.16.7.16/24 brd 172.16.7.255 scope global eth1</div><div class="line">    inet6 fe80::2e0:81ff:feb9:a488/64 scope link</div><div class="line">valid_lft forever preferred_lft forever</div><div class="line">4: sit0:  mtu 1480 qdisc noop</div><div class="line">    link/sit 0.0.0.0 brd 0.0.0.0</div></pre></td></tr></table></figure>
<h3 id="启动LVS-Master的keepalived服务，并查看日志"><a href="#启动LVS-Master的keepalived服务，并查看日志" class="headerlink" title="启动LVS_Master的keepalived服务，并查看日志"></a>启动LVS_Master的keepalived服务，并查看日志</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div></pre></td><td class="code"><pre><div class="line">[root@ssq-58-56 opt]# /etc/init.d/keepalived start</div><div class="line">Starting keepalived:[  OK  ]</div><div class="line">[root@ssq-58-56 ~]# tail -f /var/log/messages</div><div class="line">Apr  2 10:45:37 ssq-56 Keepalived: Terminating on signal</div><div class="line">Apr  2 10:45:37 ssq-56 Keepalived_vrrp: Terminating VRRP child process on signal</div><div class="line">Apr  2 10:45:37 ssq-56 Keepalived_vrrp: VRRP_Instance(VIP) removing protocol VIPs.</div><div class="line">Apr  2 10:45:37 ssq-56 Keepalived_healthcheckers: Netlink reflector reports IP 172.16.7.55 removed</div><div class="line">Apr  2 10:45:37 ssq-56 Keepalived_healthcheckers: Terminating Healthchecker child process on signal</div><div class="line">Apr  2 10:45:37 ssq-56 Keepalived: Stopping Keepalived v1.1.15 (03/19,2013)</div><div class="line">Apr  2 10:46:07 ssq-56 Keepalived: Starting Keepalived v1.1.15 (03/19,2013)</div><div class="line">Apr  2 10:46:07 ssq-56 Keepalived: Starting Healthcheck child process, pid=14324</div><div class="line">Apr  2 10:46:07 ssq-56 Keepalived_healthcheckers: Using MII-BMSR NIC polling thread...</div><div class="line">Apr  2 10:46:07 ssq-56 Keepalived_healthcheckers: Netlink reflector reports IP 115.182.58.56 added</div><div class="line">Apr  2 10:46:07 ssq-56 Keepalived_healthcheckers: Netlink reflector reports IP 172.16.7.56 added</div><div class="line">Apr  2 10:46:07 ssq-56 Keepalived_healthcheckers: Registering Kernel netlink reflector</div><div class="line">Apr  2 10:46:07 ssq-56 Keepalived_healthcheckers: Registering Kernel netlink command channel</div><div class="line">Apr  2 10:46:07 ssq-56 Keepalived_healthcheckers: Opening file &apos;/etc/keepalived/keepalived.conf&apos;.</div><div class="line">Apr  2 10:46:07 ssq-56 Keepalived_healthcheckers: Configuration is using : 12025 Bytes</div><div class="line">Apr  2 10:46:07 ssq-56 Keepalived_healthcheckers: Activating healtchecker for service [172.16.7.16:80]</div><div class="line">Apr  2 10:46:07 ssq-56 Keepalived_healthcheckers: Activating healtchecker for service [172.16.7.144:80]</div><div class="line">Apr  2 10:46:07 ssq-56 Keepalived: Starting VRRP child process, pid=14325</div><div class="line">Apr  2 10:46:07 ssq-56 Keepalived_vrrp: Using MII-BMSR NIC polling thread...</div><div class="line">Apr  2 10:46:07 ssq-56 Keepalived_vrrp: Netlink reflector reports IP 115.182.58.56 added</div><div class="line">Apr  2 10:46:07 ssq-56 Keepalived_vrrp: Netlink reflector reports IP 172.16.7.56 added</div><div class="line">Apr  2 10:46:07 ssq-56 Keepalived_vrrp: Registering Kernel netlink reflector</div><div class="line">Apr  2 10:46:07 ssq-56 Keepalived_vrrp: Registering Kernel netlink command channel</div><div class="line">Apr  2 10:46:07 ssq-56 Keepalived_vrrp: Registering gratutious ARP shared channel</div><div class="line">Apr  2 10:46:07 ssq-56 Keepalived_vrrp: Opening file &apos;/etc/keepalived/keepalived.conf&apos;.</div><div class="line">Apr  2 10:46:07 ssq-56 Keepalived_vrrp: Configuration is using : 36411 Bytes</div><div class="line">Apr  2 10:46:07 ssq-56 Keepalived_vrrp: VRRP sockpool: [ifindex(3), proto(112), fd(8,9)]</div><div class="line">Apr  2 10:46:08 ssq-56 Keepalived_vrrp: VRRP_Instance(VIP) Transition to MASTER STATE</div><div class="line">Apr  2 10:46:09 ssq-56 Keepalived_vrrp: VRRP_Instance(VIP) Entering MASTER STATE</div><div class="line">Apr  2 10:46:09 ssq-56 Keepalived_vrrp: VRRP_Instance(VIP) setting protocol VIPs.</div><div class="line">Apr  2 10:46:09 ssq-56 Keepalived_vrrp: VRRP_Instance(VIP) Sending gratuitous ARPs on eth1 for 172.16.7.55</div><div class="line">Apr  2 10:46:09 ssq-56 Keepalived_vrrp: Netlink reflector reports IP 172.16.7.55 added</div><div class="line">Apr  2 10:46:09 ssq-56 Keepalived_healthcheckers: Netlink reflector reports IP 172.16.7.55 added</div><div class="line">Apr  2 10:46:14 ssq-56 Keepalived_vrrp: VRRP_Instance(VIP) Sending gratuitous ARPs on eth1 for 172.16.7.55</div></pre></td></tr></table></figure>
<h3 id="启动backup的Keepalived服务，并查看日志"><a href="#启动backup的Keepalived服务，并查看日志" class="headerlink" title="启动backup的Keepalived服务，并查看日志"></a>启动backup的Keepalived服务，并查看日志</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div></pre></td><td class="code"><pre><div class="line">[root@ssq-58-57 opt]# /etc/init.d/keepalived start</div><div class="line">Starting keepalived:[  OK  ]</div><div class="line">[root@ssq-58-57 ~]# tail -f /var/log/messages</div><div class="line">Apr  2 10:51:44 ssq-57 Keepalived: Starting Keepalived v1.1.15 (03/19,2013)</div><div class="line">Apr  2 10:51:44 ssq-57 Keepalived_healthcheckers: Using MII-BMSR NIC polling thread...</div><div class="line">Apr  2 10:51:44 ssq-57 Keepalived: Starting Healthcheck child process, pid=28840</div><div class="line">Apr  2 10:51:44 ssq-57 Keepalived: Starting VRRP child process, pid=28841</div><div class="line">Apr  2 10:51:44 ssq-57 Keepalived_healthcheckers: Netlink reflector reports IP 115.182.58.57 added</div><div class="line">Apr  2 10:51:44 ssq-57 Keepalived_healthcheckers: Netlink reflector reports IP 172.16.7.57 added</div><div class="line">Apr  2 10:51:44 ssq-57 Keepalived_healthcheckers: Registering Kernel netlink reflector</div><div class="line">Apr  2 10:51:44 ssq-57 Keepalived_healthcheckers: Registering Kernel netlink command channel</div><div class="line">Apr  2 10:51:44 ssq-57 Keepalived_healthcheckers: Opening file &apos;/etc/keepalived/keepalived.conf&apos;.</div><div class="line">Apr  2 10:51:44 ssq-57 Keepalived_healthcheckers: Configuration is using : 12023 Bytes</div><div class="line">Apr  2 10:51:44 ssq-57 Keepalived_healthcheckers: Activating healtchecker for service [172.16.7.16:80]</div><div class="line">Apr  2 10:51:44 ssq-57 Keepalived_healthcheckers: Activating healtchecker for service [172.16.7.144:80]</div><div class="line">Apr  2 10:51:44 ssq-57 Keepalived_vrrp: Using MII-BMSR NIC polling thread...</div><div class="line">Apr  2 10:51:44 ssq-57 Keepalived_vrrp: Netlink reflector reports IP 115.182.58.57 added</div><div class="line">Apr  2 10:51:44 ssq-57 Keepalived_vrrp: Netlink reflector reports IP 172.16.7.57 added</div><div class="line">Apr  2 10:51:44 ssq-57 Keepalived_vrrp: Registering Kernel netlink reflector</div><div class="line">Apr  2 10:51:44 ssq-57 Keepalived_vrrp: Registering Kernel netlink command channel</div><div class="line">Apr  2 10:51:44 ssq-57 Keepalived_vrrp: Registering gratutious ARP shared channel</div><div class="line">Apr  2 10:51:44 ssq-57 Keepalived_vrrp: Opening file &apos;/etc/keepalived/keepalived.conf&apos;.</div><div class="line">Apr  2 10:51:44 ssq-57 Keepalived_vrrp: Configuration is using : 36409 Bytes</div><div class="line">Apr  2 10:51:44 ssq-57 Keepalived_vrrp: VRRP_Instance(VIP) Entering BACKUP STATE</div><div class="line">Apr  2 10:51:44 ssq-57 Keepalived_vrrp: VRRP sockpool: [ifindex(3), proto(112), fd(8,9)]</div></pre></td></tr></table></figure>
<h4 id="使用ipvsadm查看lvs状态"><a href="#使用ipvsadm查看lvs状态" class="headerlink" title="使用ipvsadm查看lvs状态"></a>使用ipvsadm查看lvs状态</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div></pre></td><td class="code"><pre><div class="line">[root@ssq-56 opt]# ipvsadm -Ln               </div><div class="line">IP Virtual Server version 1.2.1 (size=4096)</div><div class="line">Prot LocalAddress:Port Scheduler Flags</div><div class="line">  -&gt; RemoteAddress:PortForward Weight ActiveConn InActConn</div><div class="line">TCP  172.16.7.55:80 rr persistent 50</div><div class="line">  -&gt; 172.16.7.144:80Route   3      00</div><div class="line">  -&gt; 172.16.7.16:80Route   3      00    </div><div class="line"> </div><div class="line">[root@ssq-57 opt]# ipvsadm -Ln</div><div class="line">IP Virtual Server version 1.2.1 (size=4096)</div><div class="line">Prot LocalAddress:Port Scheduler Flags</div><div class="line">  -&gt; RemoteAddress:PortForward Weight ActiveConn InActConn</div><div class="line">TCP  172.16.7.55:80 rr persistent 50</div><div class="line">  -&gt; 172.16.7.144:80Route   3      00</div><div class="line">  -&gt; 172.16.7.16:80Route   3      00</div></pre></td></tr></table></figure>
<h3 id="测试负载均衡"><a href="#测试负载均衡" class="headerlink" title="测试负载均衡"></a>测试负载均衡</h3><ul>
<li><p>在172.16.7.16和172.16.7.144分别创建以本机IP命令的index.html文件，放到apache的DocumentRoot中（这里放置不同内容是为了方便测试，在生产环境中应该是相同文件）</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">[root@comp ~]# echo &quot;172.16.7.16&quot; &gt; /var/www/html/index.html</div><div class="line">[root@ssq-144 ~]# echo &quot;172.16.7.144&quot; &gt; /var/www/html/index.html</div></pre></td></tr></table></figure>
</li>
<li><p>用两台不同机器访问VIP</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line">[root@ssq-58-112 ~]# curl 172.16.7.55</div><div class="line">172.16.7.16</div><div class="line">[root@ssq-58-113 ~]# curl 172.16.7.55</div><div class="line">172.16.7.144</div></pre></td></tr></table></figure>
</li>
</ul>
<p>看到两台机器访问VIP，得到的内容不一样，说明负载均衡成功。</p>
<h3 id="测试高可用"><a href="#测试高可用" class="headerlink" title="测试高可用"></a>测试高可用</h3><ol>
<li>关闭master的Keepalived服务器，并查看backup日志</li>
</ol>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line">[root@ssq-58-56 opt]# /etc/init.d/keepalived stop</div><div class="line">Stopping keepalived:[  OK  ]</div><div class="line">[root@ssq-58-57 ~]# tail -f /var/log/messages</div><div class="line">Apr  2 11:10:19 ssq-57 Keepalived_vrrp: VRRP_Instance(VIP) Transition to MASTER STATE</div><div class="line">Apr  2 11:10:20 ssq-57 Keepalived_vrrp: VRRP_Instance(VIP) Entering MASTER STATE</div><div class="line">Apr  2 11:10:20 ssq-57 Keepalived_vrrp: VRRP_Instance(VIP) setting protocol VIPs.</div><div class="line">Apr  2 11:10:20 ssq-57 Keepalived_vrrp: VRRP_Instance(VIP) Sending gratuitous ARPs on eth1 for 172.16.7.55</div><div class="line">Apr  2 11:10:20 ssq-57 Keepalived_vrrp: Netlink reflector reports IP 172.16.7.55 added</div><div class="line">Apr  2 11:10:20 ssq-57 Keepalived_healthcheckers: Netlink reflector reports IP 172.16.7.55 added</div><div class="line">Apr  2 11:10:25 ssq-57 Keepalived_vrrp: VRRP_Instance(VIP) Sending gratuitous ARPs on eth1 for 172.16.7.55</div></pre></td></tr></table></figure>
<p>说明backup已经接管服务，测试访问<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line">curl 172.16.7.55</div><div class="line">172.16.7.144</div><div class="line">curl 172.16.7.55</div><div class="line">172.16.7.16</div></pre></td></tr></table></figure></p>
<p>web访问并没有受到影响</p>
<ol>
<li>启动master的Keepalived服务，并查看backup日志</li>
</ol>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line">/etc/init.d/keepalived start</div><div class="line">Starting keepalived:[  OK  ]</div><div class="line">[root@ssq-58-57 ~]# tail -f /var/log/messages</div><div class="line">Apr  2 11:13:48 ssq-57 Keepalived_vrrp: VRRP_Instance(VIP) Received higher prio advert</div><div class="line">Apr  2 11:13:48 ssq-57 Keepalived_vrrp: VRRP_Instance(VIP) Entering BACKUP STATE</div><div class="line">Apr  2 11:13:48 ssq-57 Keepalived_vrrp: VRRP_Instance(VIP) removing protocol VIPs.</div><div class="line">Apr  2 11:13:48 ssq-57 Keepalived_vrrp: Netlink reflector reports IP 172.16.7.55 removed</div><div class="line">Apr  2 11:13:48 ssq-57 Keepalived_healthcheckers: Netlink reflector reports IP 172.16.7.55 removed</div></pre></td></tr></table></figure>
<p>在master工作后，backup又将工作交还给master</p>
]]></content>
    
    <summary type="html">
    
      &lt;h1 id=&quot;LVS-Keepalived介绍&quot;&gt;&lt;a href=&quot;#LVS-Keepalived介绍&quot; class=&quot;headerlink&quot; title=&quot;LVS+Keepalived介绍&quot;&gt;&lt;/a&gt;LVS+Keepalived介绍&lt;/h1&gt;&lt;p&gt;lVS是Linux Virt
    
    </summary>
    
      <category term="Web" scheme="http://czero000.github.io/categories/Web/"/>
    
      <category term="keepalived" scheme="http://czero000.github.io/categories/Web/keepalived/"/>
    
    
      <category term="keepalived" scheme="http://czero000.github.io/tags/keepalived/"/>
    
      <category term="lvs" scheme="http://czero000.github.io/tags/lvs/"/>
    
  </entry>
  
  <entry>
    <title>keepalived配置文件说明</title>
    <link href="http://czero000.github.io/2016/11/29/keepalived-configfile.html"/>
    <id>http://czero000.github.io/2016/11/29/keepalived-configfile.html</id>
    <published>2016-11-29T06:07:33.000Z</published>
    <updated>2017-01-11T09:24:53.479Z</updated>
    
    <content type="html"><![CDATA[<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div><div class="line">67</div><div class="line">68</div><div class="line">69</div><div class="line">70</div><div class="line">71</div><div class="line">72</div><div class="line">73</div><div class="line">74</div><div class="line">75</div><div class="line">76</div><div class="line">77</div><div class="line">78</div><div class="line">79</div><div class="line">80</div><div class="line">81</div><div class="line">82</div><div class="line">83</div><div class="line">84</div><div class="line">85</div><div class="line">86</div><div class="line">87</div><div class="line">88</div><div class="line">89</div><div class="line">90</div><div class="line">91</div><div class="line">92</div><div class="line">93</div><div class="line">94</div><div class="line">95</div><div class="line">96</div><div class="line">97</div><div class="line">98</div><div class="line">99</div><div class="line">100</div></pre></td><td class="code"><pre><div class="line">keepalived既可以作为HA热备，也能作健康检查。下面对/etc/keepalived/keepalived.conf配置说明。</div><div class="line"></div><div class="line">global_defs &#123;</div><div class="line">   notification_email &#123;  #指定keepalived在发生切换时需要发送email到的对象，一行一个</div><div class="line">		monitor@3evip.cn</div><div class="line">   &#125;</div><div class="line">   notification_email_from monitor@3evip.cn #指定发件人</div><div class="line">   smtp_server stmp.3evip.cn #指定smtp服务器地址</div><div class="line">   smtp_connect_timeout 30 #指定smtp连接超时时间</div><div class="line">   router_id LVS_DEVEL #运行keepalived机器的一个标识</div><div class="line">&#125;</div><div class="line"></div><div class="line">vrrp_sync_group VG_1&#123; #监控多个网段的实例</div><div class="line">	group &#123;</div><div class="line">		inside_network #实例名</div><div class="line">		outside_network</div><div class="line">	&#125;</div><div class="line">	notify_master /path/xx.sh #指定当切换到master时，执行的脚本</div><div class="line">	netify_backup /path/xx.sh #指定当切换到backup时，执行的脚本</div><div class="line">	notify_fault &quot;path/xx.sh VG_1&quot; #故障时执行的脚本</div><div class="line">	notify /path/xx.sh </div><div class="line">	smtp_alert #使用global_defs中提供的邮件地址和smtp服务器发送邮件通知</div><div class="line">&#125;</div><div class="line"></div><div class="line">vrrp_instance inside_network &#123;</div><div class="line">    state BACKUP #指定那个为master，那个为backup，如果设置了nopreempt这个值不起作用，主备考priority决定</div><div class="line">    interface eth0 #设置实例绑定的网卡</div><div class="line">    dont_track_primary #忽略vrrp的interface错误（默认不设置）</div><div class="line">    track_interface&#123; #设置额外的监控，里面那个网卡出现问题都会切换</div><div class="line">		eth0</div><div class="line">		eth1</div><div class="line">    &#125;</div><div class="line">    mcast_src_ip #发送多播包的地址，如果不设置默认使用绑定网卡的primary ip</div><div class="line">    garp_master_delay #在切换到master状态后，延迟进行gratuitous ARP请求</div><div class="line">    virtual_router_id 50 #VPID标记</div><div class="line">    priority 99 #优先级，高优先级竞选为master</div><div class="line">    advert_int 1 #检查间隔，默认1秒</div><div class="line">    nopreempt #设置为不抢占 注：这个配置只能设置在backup主机上，而且这个主机优先级要比另外一台高</div><div class="line">    preempt_delay #抢占延时，默认5分钟</div><div class="line">    debug #debug级别</div><div class="line">    authentication &#123; #设置认证</div><div class="line">        auth_type PASS #认证方式</div><div class="line">        auth_pass 111111 #认证密码</div><div class="line">    &#125;</div><div class="line">    virtual_ipaddress &#123; #设置vip</div><div class="line">        192.168.36.200</div><div class="line">    &#125;</div><div class="line">&#125;</div><div class="line">virtual_server 192.168.36.99 80 &#123;</div><div class="line">    delay_loop 6 #健康检查时间间隔</div><div class="line">    lb_algo rr  #lvs调度算法rr|wrr|lc|wlc|lblc|sh|dh</div><div class="line">    lb_kind DR  #负载均衡转发规则NAT|DR|RUN</div><div class="line">    persistence_timeout 5 #会话保持时间</div><div class="line">    protocol TCP #使用的协议</div><div class="line">    persistence_granularity &lt;NETMASK&gt; #lvs会话保持粒度</div><div class="line">    virtualhost &lt;string&gt; #检查的web服务器的虚拟主机（host：头）    </div><div class="line">    sorry_server&lt;IPADDR&gt; &lt;port&gt; #备用机，所有realserver失效后启用</div><div class="line">    real_server 192.168.200.5 23 &#123;</div><div class="line">            weight 1 #默认为1,0为失效</div><div class="line">            inhibit_on_failure #在服务器健康检查失效时，将其设为0，而不是直接从ipvs中删除 </div><div class="line">            notify_up &lt;string&gt; | &lt;quoted-string&gt; #在检测到server up后执行脚本</div><div class="line">            notify_down &lt;string&gt; | &lt;quoted-string&gt; #在检测到server down后执行脚本</div><div class="line">	    TCP_CHECK &#123;</div><div class="line">	    	connect_timeout 3 #连接超时时间</div><div class="line">	    	nb_get_retry 3 #重连次数</div><div class="line">	    	delay_before_retry 3 #重连间隔时间</div><div class="line">	    	connect_port 23  健康检查的端口的端口</div><div class="line">	    	bindto &lt;ip&gt;   </div><div class="line">	    &#125;</div><div class="line">	    HTTP_GET | SSL_GET&#123;</div><div class="line">		url&#123; #检查url，可以指定多个</div><div class="line">		path /</div><div class="line">		digest &lt;string&gt; #检查后的摘要信息</div><div class="line">		status_code 200 #检查的返回状态码</div><div class="line">		&#125;</div><div class="line">		connect_port &lt;port&gt; </div><div class="line">		bindto &lt;IPADD&gt;</div><div class="line">		connect_timeout 5</div><div class="line">		nb_get_retry 3</div><div class="line">		delay_before_retry 2</div><div class="line">		&#125;</div><div class="line"></div><div class="line">		SMTP_CHECK&#123;</div><div class="line">			host&#123;</div><div class="line">		        	connect_ip &lt;IP ADDRESS&gt;</div><div class="line">				connect_port &lt;port&gt; #默认检查25端口</div><div class="line">				bindto &lt;IP ADDRESS&gt;</div><div class="line">			&#125;</div><div class="line">			connect_timeout 5</div><div class="line">			retry 3</div><div class="line">			delay_before_retry 2</div><div class="line">			helo_name &lt;string&gt; | &lt;quoted-string&gt; #smtp helo请求命令参数，可选</div><div class="line">		&#125;</div><div class="line">		MISC_CHECK&#123;</div><div class="line">			misc_path &lt;string&gt; | &lt;quoted-string&gt; #外部脚本路径</div><div class="line">			misc_timeout #脚本执行超时时间</div><div class="line">			misc_dynamic #如设置该项，则退出状态码会用来动态调整服务器的权重，返回0 正常，不修改；返回1，检查失败，权重改为0；返回2-255，正常，权重设置为：返回状态码-2</div><div class="line">		&#125;</div><div class="line">    &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
]]></content>
    
    <summary type="html">
    
      &lt;figure class=&quot;highlight plain&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;div class=&quot;line&quot;&gt;1&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;2&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;3&lt;/di
    
    </summary>
    
      <category term="Web" scheme="http://czero000.github.io/categories/Web/"/>
    
      <category term="keepalived" scheme="http://czero000.github.io/categories/Web/keepalived/"/>
    
    
      <category term="keepalived" scheme="http://czero000.github.io/tags/keepalived/"/>
    
  </entry>
  
  <entry>
    <title>Nginx+keepalived负载均衡</title>
    <link href="http://czero000.github.io/2016/11/29/keepalived-nginx.html"/>
    <id>http://czero000.github.io/2016/11/29/keepalived-nginx.html</id>
    <published>2016-11-29T06:07:33.000Z</published>
    <updated>2017-01-11T08:06:05.117Z</updated>
    
    <content type="html"><![CDATA[<p>CMDB新系统上线，设计整体架构要实现高可用，避免出现单点故障，设计使用keepalived+nginx部署前端Web Server。</p>
<h1 id="Keepalived介绍"><a href="#Keepalived介绍" class="headerlink" title="Keepalived介绍"></a>Keepalived介绍</h1><p>Keepalived 是一个基于VRRP协议来实现服务器高可用或热备解决方案，Keepalived可以用来防止服务器单点故障(单点故障是指一旦某一点出现故障就会导致整个系统架构的不可用)的发生，通过配合Nginx可以实现web前端服务的高可用。</p>
<h2 id="VRRP协议"><a href="#VRRP协议" class="headerlink" title="VRRP协议"></a>VRRP协议</h2><p>VRRP全称 Virtual Router Redundancy Protocol，即 虚拟路由冗余协议。可以认为它是实现路由器高可用的容错协议，即将N台提供相同功能的路由器组成一个路由器组(Router Group)，这个组里面有一个master和多个backup，但在外界看来就像一台一样，构成虚拟路由器，拥有一个虚拟IP（vip，也就是路由器所在局域网内其他机器的默认路由），占有这个IP的master实际负责ARP相应和转发IP数据包，组中的其它路由器作为备份的角色处于待命状态。master会发组播消息，当backup在超时时间内收不到vrrp包时就认为master宕掉了，这时就需要根据VRRP的优先级来选举一个backup当master，保证路由器的高可用。</p>
<p>在VRRP协议实现里，虚拟路由器使用 00-00-5E-00-01-XX 作为虚拟MAC地址，XX就是唯一的 VRID （Virtual Router IDentifier），这个地址同一时间只有一个物理路由器占用。在虚拟路由器里面的物理路由器组里面通过多播IP地址 224.0.0.18 来定时发送通告消息。每个Router都有一个 1-255 之间的优先级别，级别最高的（highest priority）将成为主控（master）路由器。通过降低master的优先权可以让处于backup状态的路由器抢占（pro-empt）主路由器的状态，两个backup优先级相同的IP地址较大者为master，接管虚拟IP。</p>
<h2 id="与heartbeat-corosync等比较"><a href="#与heartbeat-corosync等比较" class="headerlink" title="与heartbeat/corosync等比较"></a>与heartbeat/corosync等比较</h2><blockquote>
<p>Heartbeat、Corosync、Keepalived这三个集群组件我们到底选哪个好，首先我想说明的是，Heartbeat、Corosync是属于同一类型，Keepalived与Heartbeat、Corosync，根本不是同一类型的。Keepalived使用的vrrp协议方式，虚拟路由冗余协议 (Virtual Router Redundancy Protocol，简称VRRP)；Heartbeat或Corosync是基于主机或网络服务的高可用方式；简单的说就是，Keepalived的目的是模拟路由器的高可用，Heartbeat或Corosync的目的是实现Service的高可用。</p>
<p>所以一般Keepalived是实现前端高可用，常用的前端高可用的组合有，就是我们常见的LVS+Keepalived、Nginx+Keepalived、HAproxy+Keepalived。而Heartbeat或Corosync是实现服务的高可用，常见的组合有Heartbeat v3(Corosync)+Pacemaker+NFS+Httpd 实现Web服务器的高可用、Heartbeat v3(Corosync)+Pacemaker+NFS+MySQL 实现MySQL服务器的高可用。总结一下，Keepalived中实现轻量级的高可用，一般用于前端高可用，且不需要共享存储，一般常用于两个节点的高可用。而Heartbeat(或Corosync)一般用于服务的高可用，且需要共享存储，一般用于多节点的高可用。这个问题我们说明白了。</p>
<p>又有博友会问了，那heartbaet与corosync我们又应该选择哪个好啊，我想说我们一般用corosync，因为corosync的运行机制更优于heartbeat，就连从heartbeat分离出来的pacemaker都说在以后的开发当中更倾向于corosync，所以现在corosync+pacemaker是最佳组合。</p>
</blockquote>
<h2 id="Keepalived-nginx-配置方案"><a href="#Keepalived-nginx-配置方案" class="headerlink" title="Keepalived+nginx 配置方案"></a>Keepalived+nginx 配置方案</h2><ol>
<li><p>Nginx+Keepalived主从方式<br>多个主机使用一个VIP地址，一个做为主服务器，剩下的为备用服务器，正常下只有一个在工作，只有当主服务器出现故障时，被服务器才会被启用</p>
</li>
<li><p>Nginx+Keepalived双主(多主)方式<br>要求使用两个或两个以上的VIP地址，两个服务器互为主备或一主多备，同时在工作，当一台出现故障，请求转移到备用服务器，本文采用这种方式</p>
</li>
</ol>
<h2 id="整体架构图"><a href="#整体架构图" class="headerlink" title="整体架构图"></a>整体架构图</h2><p><img src="http://ofc9x1ccn.bkt.clouddn.com/nginx/keepalived-nginx.png" alt="global"></p>
<h1 id="安装"><a href="#安装" class="headerlink" title="安装"></a>安装</h1><h2 id="系统环境介绍"><a href="#系统环境介绍" class="headerlink" title="系统环境介绍"></a>系统环境介绍</h2><table>
<thead>
<tr>
<th>用途</th>
<th>ip</th>
<th>备注</th>
</tr>
</thead>
<tbody>
<tr>
<td>CMDB-DB-M</td>
<td>172.16.8.140</td>
<td>Ubuntu-16.04 LTS</td>
</tr>
<tr>
<td>CMDB-DB-S</td>
<td>172.16.8.144</td>
<td>Ubuntu-16.04 LTS</td>
</tr>
<tr>
<td>CMDB-Calc</td>
<td>172.16.8.244</td>
<td>Ubuntu-16.04 LTS</td>
</tr>
<tr>
<td>Gjobs-DB-M</td>
<td>172.16.8.158</td>
<td>Ubuntu-16.04 LTS</td>
</tr>
<tr>
<td>Gjobs-DB-S</td>
<td>172.16.8.169</td>
<td>Ubuntu-16.04 LTS</td>
</tr>
<tr>
<td>Gjob-Ansible</td>
<td>172.16.8.176</td>
<td>Ubuntu-16.04 LTS</td>
</tr>
<tr>
<td>Greports-DB-M</td>
<td>172.16.8.164</td>
<td>Ubuntu-16.04 LTS</td>
</tr>
<tr>
<td>Greports-DB-S</td>
<td>172.16.8.197</td>
<td>Ubuntu-16.04 LTS</td>
</tr>
<tr>
<td>Greports-Calc</td>
<td>172.16.8.204</td>
<td>Ubuntu-16.04 LTS</td>
</tr>
<tr>
<td>Nginx-PHP-M/B</td>
<td>172.16.8.156</td>
<td>Ubuntu-16.04 LTS</td>
</tr>
<tr>
<td>Nginx-PHP-B/M</td>
<td>172.16.8.178</td>
<td>Ubuntu-16.04 LTS</td>
</tr>
<tr>
<td>Nginx-Django-M/B</td>
<td>172.16.8.180</td>
<td>Ubuntu-16.04 LTS</td>
</tr>
<tr>
<td>Nginx-Django-B/M</td>
<td>172.16.8.243</td>
<td>Ubuntu-16.04 LTS</td>
</tr>
<tr>
<td>VIP</td>
<td>172.16.8.209</td>
<td>绑定到Nginx-PHP-M/B</td>
</tr>
<tr>
<td>VIP</td>
<td>172.16.8.208</td>
<td>绑定到Nginx-PHP-B/m</td>
</tr>
<tr>
<td>VIP</td>
<td>172.16.8.212</td>
<td>绑定到Nginx-Django-M/B</td>
</tr>
<tr>
<td>VIP</td>
<td>172.16.8.225</td>
<td>绑定到Nginx-Django-B/M</td>
</tr>
</tbody>
</table>
<h2 id="安装keepalived"><a href="#安装keepalived" class="headerlink" title="安装keepalived"></a>安装keepalived</h2><p>主备两个服务器都要安装keepalived</p>
<ul>
<li>安装依赖软件包</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">apt install gcc g++ make cmake openssl libssl-dev libpopt-dev -y</div></pre></td></tr></table></figure>
<ul>
<li>源码方式</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line">wget http://www.keepalived.org/software/keepalived-1.2.23.tar.gz</div><div class="line">tar -zxf keepalived-1.2.23.tar.gz</div><div class="line">cd keepalived-1.2.23/</div><div class="line">./configure --prefix=/usr/local/keepalived</div><div class="line">make &amp;&amp; make install</div><div class="line">cd /usr/local/keepalived/</div><div class="line">cp etc/rc.d/init.d/keepalived /etc/init.d/</div><div class="line">mkdir /etc/keepalived/</div><div class="line">cp etc/keepalived/keepalived.conf /etc/keepalived/</div><div class="line">cp etc/sysconfig/keepalived /etc/default/</div><div class="line">ln -s /usr/local/keepalived/sbin/keepalived /usr/sbin/</div></pre></td></tr></table></figure>
<ul>
<li>apt方式<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">apt install keepalived -y</div></pre></td></tr></table></figure>
</li>
</ul>
<h2 id="启动Keepalived"><a href="#启动Keepalived" class="headerlink" title="启动Keepalived"></a>启动Keepalived</h2><p>先在就可以先尝试启动keepalived服务，不过刚刚拷贝的init脚本并不适用在Ubuntu系统上(适用于CentOS/RHEL)，要稍作修改即可使用,下面的是keepalived apt方式安装的init脚本，直接拿来即可使用。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div></pre></td><td class="code"><pre><div class="line">vim /lib/systemd/system/keepalived.service</div><div class="line">[Unit]</div><div class="line">Description=Keepalive Daemon (LVS and VRRP)</div><div class="line">After=network-online.target</div><div class="line">Wants=network-online.target</div><div class="line"># Only start if there is a configuration file</div><div class="line">ConditionFileNotEmpty=/etc/keepalived/keepalived.conf</div><div class="line"></div><div class="line">[Service]</div><div class="line">Type=forking</div><div class="line">KillMode=process</div><div class="line"># Read configuration variable file if it is present</div><div class="line">EnvironmentFile=-/etc/default/keepalived</div><div class="line">ExecStart=/usr/sbin/keepalived $DAEMON_ARGS</div><div class="line">ExecReload=/bin/kill -HUP $MAINPID</div><div class="line"></div><div class="line">[Install]</div><div class="line">WantedBy=multi-user.target</div></pre></td></tr></table></figure></p>
<p><a href="http://ofc9x1ccn.bkt.clouddn.com/nginx/init-keepalived" target="_blank" rel="external">INIT-keepalived</a><br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">/etc/init.d/keepalived start</div></pre></td></tr></table></figure></p>
<h2 id="安装Nginx"><a href="#安装Nginx" class="headerlink" title="安装Nginx"></a>安装Nginx</h2><p>略</p>
<h1 id="配置"><a href="#配置" class="headerlink" title="配置"></a>配置</h1><h2 id="配置keepalived"><a href="#配置keepalived" class="headerlink" title="配置keepalived"></a>配置keepalived</h2><ul>
<li>主</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div></pre></td><td class="code"><pre><div class="line">! Configuration File for keepalived</div><div class="line"></div><div class="line">global_defs &#123;</div><div class="line">   notification_email &#123;</div><div class="line">        cc@zerounix.com</div><div class="line">   &#125;</div><div class="line">   notification_email_from mail.zerounix.com</div><div class="line">   smtp_server mail.zerounix.com</div><div class="line">   smtp_connect_timeout 30</div><div class="line">   router_id LVS_Master</div><div class="line">&#125;</div><div class="line"></div><div class="line">vrrp_script chk_nginx &#123;</div><div class="line">    script &quot;/usr/local/nginx/sbin/nginx_check&quot;</div><div class="line">    interval 2</div><div class="line">    weight 2</div><div class="line">&#125;</div><div class="line">vrrp_instance Nginx_PHP_1 &#123;</div><div class="line">    state MASTER</div><div class="line">    interface enp3s0</div><div class="line">    virtual_router_id 156</div><div class="line">    mcast_src_ip 172.16.8.178</div><div class="line">    priority 100</div><div class="line">    advert_int 1</div><div class="line">    authentication &#123;</div><div class="line">        auth_type PASS</div><div class="line">        auth_pass 1111</div><div class="line">    &#125;</div><div class="line">    virtual_ipaddress &#123;</div><div class="line">        172.16.8.208</div><div class="line">    &#125;</div><div class="line">    track_script &#123;</div><div class="line">        chk_nginx</div><div class="line">    &#125;</div><div class="line">    track_interface &#123;</div><div class="line">        enp3s0</div><div class="line">    &#125;</div><div class="line">&#125;</div><div class="line"></div><div class="line">vrrp_instance Nginx_PHP_2 &#123;</div><div class="line">    state BACKUP</div><div class="line">    interface enp3s0</div><div class="line">    virtual_router_id 178</div><div class="line">    mcast_src_ip 172.16.8.178</div><div class="line">    priority 190</div><div class="line">    advert_int 1</div><div class="line">    authentication &#123;</div><div class="line">        auth_type PASS</div><div class="line">        auth_pass 1111</div><div class="line">    &#125;</div><div class="line">    virtual_ipaddress &#123;</div><div class="line">        172.16.8.209</div><div class="line">    &#125;</div><div class="line">    track_script &#123;</div><div class="line">        chk_nginx</div><div class="line">    &#125;</div><div class="line">    track_interface &#123;</div><div class="line">        enp3s0</div><div class="line">    &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line">more nginx_check</div><div class="line">#!/bin/bash</div><div class="line">A=`ps -C nginx --no-header |wc -l`              </div><div class="line">if [ $A -eq 0 ];then                                      </div><div class="line">                /usr/local/nginx/sbin/nginx</div><div class="line">                sleep 3</div><div class="line">                if [ `ps -C nginx --no-header |wc -l` -eq 0 ];then</div><div class="line">                       killall keepalived</div><div class="line">                fi</div><div class="line">fi</div></pre></td></tr></table></figure>
<h2 id="测试keepalived"><a href="#测试keepalived" class="headerlink" title="测试keepalived"></a>测试keepalived</h2><ol>
<li>主Nginx停止Nginx或直接断网情况下（backup正常），访问虚拟IP：172.16.8.208/209的相关Web服务，正常，测试通过</li>
<li>backup Nginx停止Nginx或直接断网情况下（Master正常），访问虚拟IP：172.16.8.208/209的相关Web服务，正常，测试通过</li>
</ol>
]]></content>
    
    <summary type="html">
    
      &lt;p&gt;CMDB新系统上线，设计整体架构要实现高可用，避免出现单点故障，设计使用keepalived+nginx部署前端Web Server。&lt;/p&gt;
&lt;h1 id=&quot;Keepalived介绍&quot;&gt;&lt;a href=&quot;#Keepalived介绍&quot; class=&quot;headerlink&quot; 
    
    </summary>
    
      <category term="Web" scheme="http://czero000.github.io/categories/Web/"/>
    
      <category term="keepalived" scheme="http://czero000.github.io/categories/Web/keepalived/"/>
    
    
      <category term="nginx" scheme="http://czero000.github.io/tags/nginx/"/>
    
      <category term="keepalived" scheme="http://czero000.github.io/tags/keepalived/"/>
    
  </entry>
  
  <entry>
    <title>多容器应用栈</title>
    <link href="http://czero000.github.io/2016/11/18/many-container-on-docker.html"/>
    <id>http://czero000.github.io/2016/11/18/many-container-on-docker.html</id>
    <published>2016-11-18T09:19:51.000Z</published>
    <updated>2017-01-11T09:47:10.826Z</updated>
    
    <content type="html"><![CDATA[<h1 id="多容器应用栈"><a href="#多容器应用栈" class="headerlink" title="多容器应用栈"></a>多容器应用栈</h1><p>创建一个使用 Express 框架的、带有 Redis 后端的 Node.js 应用，并完全 Docker 化。应用会创建一系列的镜像来部署多容器应用。</p>
<ul>
<li>Nodejs 容器，服务于 Node 应用</li>
<li>Redis 容器，用于保存和集群化应用状态，Redis 会有两个备份容器</li>
<li>日志容器，用于捕捉应用日志</li>
</ul>
<h2 id="Redis-镜像"><a href="#Redis-镜像" class="headerlink" title="Redis 镜像"></a>Redis 镜像</h2><h3 id="Redis-基础镜像"><a href="#Redis-基础镜像" class="headerlink" title="Redis 基础镜像"></a>Redis 基础镜像</h3><p>构建 Redis 基础镜像，之后会使用基础镜像构建主从 Redis 镜像<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">docker build -t czero/redis .</div></pre></td></tr></table></figure></p>
<p><a href="http://ofc9x1ccn.bkt.clouddn.com/upload/docker/redis.tar.gz" target="_blank" rel="external">Redis Dockerfile</a></p>
<h3 id="构建-Redis-主镜像"><a href="#构建-Redis-主镜像" class="headerlink" title="构建 Redis 主镜像"></a>构建 Redis 主镜像</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">docker build -t czero/redis-primary .</div></pre></td></tr></table></figure>
<p>通过 <code>ENTRYPOINT</code> 指令制定了 <code>Redis</code> 服务的启动命令，<code>Redis</code> 服务的日志文件保存到<code>/var/log/redis/redis-server.log</code></p>
<p><a href="http://ofc9x1ccn.bkt.clouddn.com/upload/docker/redis_primary.tar.gz" target="_blank" rel="external">Redis_primary Dockerfile</a></p>
<h3 id="构建-Redis-从镜像"><a href="#构建-Redis-从镜像" class="headerlink" title="构建 Redis 从镜像"></a>构建 Redis 从镜像</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">docker build -t czero/redis_replica .</div></pre></td></tr></table></figure>
<p><a href="http://ofc9x1ccn.bkt.clouddn.com/upload/docker/redis_replica.tar.gz" target="_blank" rel="external">Redis_replica Dockerfile</a></p>
<h3 id="创建-Redis-后端集群"><a href="#创建-Redis-后端集群" class="headerlink" title="创建 Redis 后端集群"></a>创建 Redis 后端集群</h3><h4 id="构建-Redis-主容器"><a href="#构建-Redis-主容器" class="headerlink" title="构建 Redis 主容器"></a>构建 Redis 主容器</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">docker run -d -h Redisprimary --name redis_primary czero/redis_primary:latest</div></pre></td></tr></table></figure>
<ul>
<li>使用<code>-h</code>参数用来指定容器的主机名，用来后面从容器正确解析 <code>Redisprimary</code></li>
<li>使用<code>--name</code>指定容器名</li>
</ul>
<p>如果想要查看 <code>redis</code> 日志，直接使用<code>docker logs redis_primary</code> 会发现没有任何输出，因为<code>redis</code>把日志输出到日志文件中，可以运行另外一个容器来查看日志</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div></pre></td><td class="code"><pre><div class="line">docker run -ti --rm --volumes-from=redis_primary ubuntu:16.04 cat /var/log/redis/redis-server.log</div><div class="line"></div><div class="line">1:M 16 Nov 02:52:25.518 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.</div><div class="line">1:M 16 Nov 02:52:25.518 # Server started, Redis version 3.0.7</div><div class="line">1:M 16 Nov 02:52:25.518 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add &apos;vm.overcommit_memory = 1&apos; to /etc/sysctl.conf and then reboot or run the command &apos;sysctl vm.overcommit_memory=1&apos; for this to take effect.</div><div class="line">1:M 16 Nov 02:52:25.518 # WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command &apos;echo never &gt; /sys/kernel/mm/transparent_hugepage/enabled&apos; as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled.</div><div class="line">1:M 16 Nov 02:52:25.518 * The server is now ready to accept connections on port 6379</div><div class="line">1:M 16 Nov 04:10:50.447 * Slave 172.17.0.3:6379 asks for synchronization</div><div class="line">1:M 16 Nov 04:10:50.447 * Full resync requested by slave 172.17.0.3:6379</div><div class="line">1:M 16 Nov 04:10:50.447 * Starting BGSAVE for SYNC with target: disk</div><div class="line">1:M 16 Nov 04:10:50.448 * Background saving started by pid 9</div><div class="line">9:C 16 Nov 04:10:50.478 * DB saved on disk</div></pre></td></tr></table></figure>
<ul>
<li>使用<code>--rm</code> 参数指定的容器，只会运行一次，进程结束之后便会删除</li>
<li>使用<code>--volumes-from=</code>参数指定挂载那个容器的所有卷</li>
<li>后面便是指定使用某个镜像、执行某些命令</li>
</ul>
<h4 id="构建-Redis-从容器"><a href="#构建-Redis-从容器" class="headerlink" title="构建　Redis 从容器"></a>构建　Redis 从容器</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">docker run -d -h Redisreplica1 --name redis_replica1 --link redis_primary:Redisprimary czero/redis_replica:latest</div><div class="line">docker run -d -h Redisreplica2 --name redis_replica2 --link redis_primary:Redisprimary czero/redis_replica:latest</div></pre></td></tr></table></figure>
<ul>
<li>使用<code>-h</code>参数用来指定容器的主机名</li>
<li>使用<code>--name</code>指定容器名</li>
<li>使用<code>--link</code> 将<code>redis_primary</code>以别名<code>Redisprimary</code>连接到 <code>Redis</code> 从容器</li>
</ul>
<p>查看<code>redis_replica</code>的log，看看主从时候正常</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div></pre></td><td class="code"><pre><div class="line">docker run -ti --rm --volumes-from=redis_replica1 ubuntu:16.04 cat /var/log/redis/redis-replica.log</div><div class="line"></div><div class="line">1:S 16 Nov 04:10:50.445 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.</div><div class="line">1:S 16 Nov 04:10:50.445 # Server started, Redis version 3.0.7</div><div class="line">1:S 16 Nov 04:10:50.445 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add &apos;vm.overcommit_memory = 1&apos; to /etc/sysctl.conf and then reboot or run the command &apos;sysctl vm.overcommit_memory=1&apos; for this to take effect.</div><div class="line">1:S 16 Nov 04:10:50.445 # WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command &apos;echo never &gt; /sys/kernel/mm/transparent_hugepage/enabled&apos; as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled.</div><div class="line">1:S 16 Nov 04:10:50.445 * The server is now ready to accept connections on port 6379</div><div class="line">1:S 16 Nov 04:10:50.445 * Connecting to MASTER Redisprimary:6379</div><div class="line">1:S 16 Nov 04:10:50.446 * MASTER &lt;-&gt; SLAVE sync started</div><div class="line">1:S 16 Nov 04:10:50.446 * Non blocking connect for SYNC fired the event.</div><div class="line">1:S 16 Nov 04:10:50.446 * Master replied to PING, replication can continue...</div><div class="line">1:S 16 Nov 04:10:50.447 * Partial resynchronization not possible (no cached master)</div><div class="line">1:S 16 Nov 04:10:50.454 * Full resync from master: 48e2c5daef6f05d3e3d03c074001e301073da55b:1</div><div class="line">1:S 16 Nov 04:10:50.545 * MASTER &lt;-&gt; SLAVE sync: receiving 18 bytes from master</div><div class="line">1:S 16 Nov 04:10:50.545 * MASTER &lt;-&gt; SLAVE sync: Flushing old data</div><div class="line">1:S 16 Nov 04:10:50.545 * MASTER &lt;-&gt; SLAVE sync: Loading DB in memory</div><div class="line">1:S 16 Nov 04:10:50.545 * MASTER &lt;-&gt; SLAVE sync: Finished with success</div></pre></td></tr></table></figure>
<h2 id="Node-js-镜像"><a href="#Node-js-镜像" class="headerlink" title="Node.js 镜像"></a>Node.js 镜像</h2><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line">tree nodejs</div><div class="line">nodejs</div><div class="line">├── Dockerfile</div><div class="line">└── nodeapp</div><div class="line">    ├── package.json</div><div class="line">	    └── server.js</div><div class="line"></div><div class="line">		1 directory, 3 files</div><div class="line"></div><div class="line">		docker build -t czero/nodejs .</div></pre></td></tr></table></figure>
<pre><code>[Nodejs Dockerfile](http://ofc9x1ccn.bkt.clouddn.com/upload/docker/nodejs.tar.gz)
</code></pre><h3 id="创建-Node-容器"><a href="#创建-Node-容器" class="headerlink" title="创建 Node 容器"></a>创建 Node 容器</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">docker run -d  --name nodeapp -p 3000:3000 --link redis_primary:Redisprimary czero/nodejs:latest</div></pre></td></tr></table></figure>
<ul>
<li>使用<code>czero/nodejs:latest</code>镜像创建了一个名为 <code>nodeapp</code> 的新容器</li>
<li>使用使用<code>-p</code> 将容器的<code>3000</code>端口映射到宿主机的<code>3000</code>端口</li>
<li>使用<code>--link</code>将<code>redis_primary</code>以<code>Redisprimary</code>作为别名连接到新建的<code>nodeapp</code>容器</li>
</ul>
<h3 id="查看-Node-应用时候正常"><a href="#查看-Node-应用时候正常" class="headerlink" title="查看 Node 应用时候正常"></a>查看 Node 应用时候正常</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line">curl  localhost:3000  </div><div class="line">&#123;</div><div class="line">	  &quot;status&quot;: &quot;ok&quot;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>当<code>Node</code>应用返回<code>OK</code>便表示应用正常，浏览器的会话状态会被记录到<code>Redis</code>主容器<code>redis_primary</code>中，然后便会同步到两个从容器<code>redis_replica1、redis_replica2</code>中</p>
<h2 id="捕获应用日志"><a href="#捕获应用日志" class="headerlink" title="捕获应用日志"></a>捕获应用日志</h2><p>现在应用已经正常运行，使用<code>logstash</code>来捕获应用日志。</p>
<h3 id="创建-logstash-镜像"><a href="#创建-logstash-镜像" class="headerlink" title="创建 logstash 镜像"></a>创建 logstash 镜像</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">docker build -t czero/logstash .</div></pre></td></tr></table></figure>
<p><a href="http://ofc9x1ccn.bkt.clouddn.com/upload/docker/logstash.tar.gz" target="_blank" rel="external">Logstash Dockerfile</a></p>
<h3 id="构建-logstash-容器"><a href="#构建-logstash-容器" class="headerlink" title="构建 logstash 容器"></a>构建 logstash 容器</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">docker run -d --name logstash --volumes-from=nodeapp --volumes-from=redis_primary czero/logstash</div></pre></td></tr></table></figure>
<ul>
<li>使用两次<code>--volumes-from</code>挂载<code>nodeapp</code>、<code>redis_primary</code>的卷，用来访问<code>Redis</code>和<code>Node</code>的日志</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div></pre></td><td class="code"><pre><div class="line">docker logs -f logstash</div><div class="line">&#123;</div><div class="line">      &quot;message&quot; =&gt; &quot;::ffff:172.17.0.1 - - [Fri, 18 Nov 2016 08:30:31 GMT] \&quot;GET / HTTP/1.1\&quot; 200 20 \&quot;-\&quot; \&quot;curl/7.47.0\&quot;&quot;,</div><div class="line">      &quot;@version&quot; =&gt; &quot;1&quot;,</div><div class="line">      &quot;@timestamp&quot; =&gt; &quot;2016-11-18T08:30:31.254Z&quot;,</div><div class="line">      &quot;host&quot; =&gt; &quot;98b2284cb329&quot;,</div><div class="line">      &quot;path&quot; =&gt; &quot;/var/log/nodeapp/nodeapp.log&quot;,</div><div class="line">      &quot;type&quot; =&gt; &quot;syslog&quot;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>现在 Node 和 Redis 的日志便都输出到 logstash里面了。</p>
]]></content>
    
    <summary type="html">
    
      &lt;h1 id=&quot;多容器应用栈&quot;&gt;&lt;a href=&quot;#多容器应用栈&quot; class=&quot;headerlink&quot; title=&quot;多容器应用栈&quot;&gt;&lt;/a&gt;多容器应用栈&lt;/h1&gt;&lt;p&gt;创建一个使用 Express 框架的、带有 Redis 后端的 Node.js 应用，并完全 Docker 
    
    </summary>
    
      <category term="Docker" scheme="http://czero000.github.io/categories/Docker/"/>
    
    
      <category term="docker" scheme="http://czero000.github.io/tags/docker/"/>
    
  </entry>
  
  <entry>
    <title>Leanote备份脚本</title>
    <link href="http://czero000.github.io/2016/11/17/backup-leanote.html"/>
    <id>http://czero000.github.io/2016/11/17/backup-leanote.html</id>
    <published>2016-11-17T03:49:46.000Z</published>
    <updated>2017-01-11T07:28:52.493Z</updated>
    
    <content type="html"><![CDATA[<p>为知笔记收费了，把笔记迁移到 leanote 上，但是有担心笔记的安全，所以找到了一个备份脚本，每天备份日志到本地。</p>
<ul>
<li><p>备份脚本</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div><div class="line">67</div><div class="line">68</div><div class="line">69</div><div class="line">70</div><div class="line">71</div><div class="line">72</div><div class="line">73</div><div class="line">74</div><div class="line">75</div><div class="line">76</div><div class="line">77</div><div class="line">78</div><div class="line">79</div><div class="line">80</div><div class="line">81</div><div class="line">82</div><div class="line">83</div><div class="line">84</div><div class="line">85</div><div class="line">86</div><div class="line">87</div><div class="line">88</div><div class="line">89</div><div class="line">90</div><div class="line">91</div><div class="line">92</div><div class="line">93</div><div class="line">94</div><div class="line">95</div><div class="line">96</div><div class="line">97</div><div class="line">98</div><div class="line">99</div><div class="line">100</div><div class="line">101</div><div class="line">102</div><div class="line">103</div><div class="line">104</div><div class="line">105</div><div class="line">106</div><div class="line">107</div><div class="line">108</div><div class="line">109</div><div class="line">110</div><div class="line">111</div><div class="line">112</div><div class="line">113</div><div class="line">114</div><div class="line">115</div><div class="line">116</div><div class="line">117</div><div class="line">118</div><div class="line">119</div><div class="line">120</div><div class="line">121</div><div class="line">122</div><div class="line">123</div><div class="line">124</div><div class="line">125</div><div class="line">126</div><div class="line">127</div><div class="line">128</div><div class="line">129</div><div class="line">130</div><div class="line">131</div><div class="line">132</div><div class="line">133</div><div class="line">134</div><div class="line">135</div><div class="line">136</div><div class="line">137</div><div class="line">138</div><div class="line">139</div><div class="line">140</div><div class="line">141</div><div class="line">142</div><div class="line">143</div><div class="line">144</div><div class="line">145</div><div class="line">146</div><div class="line">147</div><div class="line">148</div><div class="line">149</div><div class="line">150</div><div class="line">151</div><div class="line">152</div><div class="line">153</div><div class="line">154</div><div class="line">155</div><div class="line">156</div><div class="line">157</div><div class="line">158</div><div class="line">159</div><div class="line">160</div><div class="line">161</div><div class="line">162</div><div class="line">163</div><div class="line">164</div><div class="line">165</div><div class="line">166</div><div class="line">167</div><div class="line">168</div><div class="line">169</div><div class="line">170</div><div class="line">171</div><div class="line">172</div><div class="line">173</div><div class="line">174</div><div class="line">175</div><div class="line">176</div><div class="line">177</div><div class="line">178</div><div class="line">179</div><div class="line">180</div><div class="line">181</div><div class="line">182</div><div class="line">183</div><div class="line">184</div><div class="line">185</div><div class="line">186</div><div class="line">187</div><div class="line">188</div><div class="line">189</div><div class="line">190</div><div class="line">191</div><div class="line">192</div><div class="line">193</div><div class="line">194</div><div class="line">195</div><div class="line">196</div><div class="line">197</div><div class="line">198</div><div class="line">199</div><div class="line">200</div><div class="line">201</div><div class="line">202</div><div class="line">203</div><div class="line">204</div><div class="line">205</div><div class="line">206</div><div class="line">207</div><div class="line">208</div><div class="line">209</div><div class="line">210</div><div class="line">211</div><div class="line">212</div><div class="line">213</div><div class="line">214</div><div class="line">215</div><div class="line">216</div><div class="line">217</div><div class="line">218</div><div class="line">219</div><div class="line">220</div><div class="line">221</div><div class="line">222</div><div class="line">223</div><div class="line">224</div><div class="line">225</div><div class="line">226</div><div class="line">227</div><div class="line">228</div><div class="line">229</div><div class="line">230</div><div class="line">231</div><div class="line">232</div><div class="line">233</div><div class="line">234</div><div class="line">235</div><div class="line">236</div><div class="line">237</div><div class="line">238</div><div class="line">239</div><div class="line">240</div><div class="line">241</div><div class="line">242</div><div class="line">243</div><div class="line">244</div><div class="line">245</div><div class="line">246</div><div class="line">247</div><div class="line">248</div><div class="line">249</div><div class="line">250</div><div class="line">251</div><div class="line">252</div><div class="line">253</div><div class="line">254</div><div class="line">255</div><div class="line">256</div><div class="line">257</div><div class="line">258</div><div class="line">259</div><div class="line">260</div><div class="line">261</div><div class="line">262</div><div class="line">263</div><div class="line">264</div><div class="line">265</div><div class="line">266</div><div class="line">267</div><div class="line">268</div><div class="line">269</div><div class="line">270</div><div class="line">271</div><div class="line">272</div><div class="line">273</div><div class="line">274</div><div class="line">275</div><div class="line">276</div><div class="line">277</div><div class="line">278</div><div class="line">279</div><div class="line">280</div><div class="line">281</div><div class="line">282</div><div class="line">283</div><div class="line">284</div><div class="line">285</div><div class="line">286</div><div class="line">287</div><div class="line">288</div><div class="line">289</div><div class="line">290</div><div class="line">291</div><div class="line">292</div><div class="line">293</div><div class="line">294</div><div class="line">295</div><div class="line">296</div><div class="line">297</div><div class="line">298</div><div class="line">299</div><div class="line">300</div><div class="line">301</div><div class="line">302</div><div class="line">303</div><div class="line">304</div><div class="line">305</div><div class="line">306</div><div class="line">307</div><div class="line">308</div><div class="line">309</div><div class="line">310</div><div class="line">311</div><div class="line">312</div><div class="line">313</div><div class="line">314</div><div class="line">315</div><div class="line">316</div><div class="line">317</div><div class="line">318</div><div class="line">319</div><div class="line">320</div><div class="line">321</div><div class="line">322</div><div class="line">323</div><div class="line">324</div><div class="line">325</div><div class="line">326</div><div class="line">327</div><div class="line">328</div><div class="line">329</div><div class="line">330</div><div class="line">331</div><div class="line">332</div><div class="line">333</div><div class="line">334</div><div class="line">335</div><div class="line">336</div><div class="line">337</div><div class="line">338</div><div class="line">339</div><div class="line">340</div><div class="line">341</div><div class="line">342</div><div class="line">343</div><div class="line">344</div><div class="line">345</div><div class="line">346</div><div class="line">347</div><div class="line">348</div><div class="line">349</div><div class="line">350</div><div class="line">351</div><div class="line">352</div><div class="line">353</div><div class="line">354</div><div class="line">355</div><div class="line">356</div><div class="line">357</div><div class="line">358</div><div class="line">359</div><div class="line">360</div><div class="line">361</div><div class="line">362</div><div class="line">363</div><div class="line">364</div><div class="line">365</div><div class="line">366</div><div class="line">367</div><div class="line">368</div><div class="line">369</div><div class="line">370</div><div class="line">371</div><div class="line">372</div><div class="line">373</div><div class="line">374</div><div class="line">375</div><div class="line">376</div><div class="line">377</div><div class="line">378</div><div class="line">379</div><div class="line">380</div><div class="line">381</div><div class="line">382</div><div class="line">383</div><div class="line">384</div><div class="line">385</div><div class="line">386</div><div class="line">387</div><div class="line">388</div><div class="line">389</div><div class="line">390</div><div class="line">391</div><div class="line">392</div><div class="line">393</div><div class="line">394</div><div class="line">395</div><div class="line">396</div><div class="line">397</div><div class="line">398</div><div class="line">399</div><div class="line">400</div><div class="line">401</div><div class="line">402</div><div class="line">403</div></pre></td><td class="code"><pre><div class="line">cat Leanote4MD.py</div><div class="line"></div><div class="line"><span class="comment">#!/usr/bin/env python</span></div><div class="line"><span class="comment">#encoding: utf8</span></div><div class="line"><span class="comment">#</span></div><div class="line"><span class="comment"># author: goodbest &lt;lovegoodbest@gmail.com&gt;</span></div><div class="line"><span class="comment"># github: github.com/goodbest</span></div><div class="line"></div><div class="line"><span class="keyword">import</span> requests</div><div class="line"><span class="keyword">import</span> json</div><div class="line"><span class="keyword">import</span> os</div><div class="line"><span class="keyword">import</span> sys</div><div class="line"><span class="keyword">from</span> datetime <span class="keyword">import</span> datetime</div><div class="line"><span class="keyword">import</span> dateutil.parser</div><div class="line"><span class="keyword">from</span> dateutil <span class="keyword">import</span> tz</div><div class="line"><span class="keyword">from</span> PIL <span class="keyword">import</span> Image</div><div class="line"><span class="keyword">from</span> StringIO <span class="keyword">import</span> StringIO</div><div class="line"><span class="keyword">from</span> requests_toolbelt <span class="keyword">import</span> SSLAdapter</div><div class="line"><span class="keyword">import</span> ssl</div><div class="line"><span class="keyword">import</span> argparse</div><div class="line"><span class="keyword">import</span> ConfigParser <span class="keyword">as</span> CP</div><div class="line"></div><div class="line">leanote_host = <span class="keyword">None</span></div><div class="line">leanote_token = <span class="keyword">None</span></div><div class="line">local_zone = <span class="keyword">None</span></div><div class="line">args = <span class="keyword">None</span></div><div class="line"></div><div class="line">configpath = <span class="string">"Leanote.cfg"</span></div><div class="line"></div><div class="line">DEBUG = <span class="number">0</span></div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">is_ok</span><span class="params">(myjson)</span>:</span></div><div class="line">    <span class="keyword">try</span>:</div><div class="line">      json_object = json.loads(myjson)</div><div class="line">    <span class="keyword">except</span> ValueError, e:</div><div class="line">        <span class="keyword">print</span> e</div><div class="line">        <span class="keyword">return</span> <span class="keyword">False</span></div><div class="line"></div><div class="line">    <span class="keyword">if</span> <span class="string">'Ok'</span> <span class="keyword">in</span> json_object:</div><div class="line">        <span class="keyword">if</span> json_object[<span class="string">'Ok'</span>]:</div><div class="line">            <span class="keyword">return</span> <span class="keyword">True</span></div><div class="line">        <span class="keyword">else</span>:</div><div class="line">            <span class="keyword">print</span> json_object[<span class="string">'Msg'</span>]</div><div class="line">            <span class="keyword">return</span> <span class="keyword">False</span></div><div class="line">    <span class="keyword">else</span>:</div><div class="line">        <span class="keyword">return</span> <span class="keyword">True</span></div><div class="line"></div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">req_get</span><span class="params">(url, param = <span class="string">''</span>, type = <span class="string">'json'</span>, token = True)</span>:</span></div><div class="line">    <span class="keyword">if</span> token:</div><div class="line">        <span class="keyword">if</span> param:</div><div class="line">            param.update(&#123;<span class="string">'token'</span>: leanote_token&#125;)</div><div class="line">        <span class="keyword">else</span>:</div><div class="line">            param=&#123;<span class="string">'token'</span>: leanote_token&#125;</div><div class="line"></div><div class="line">    s = requests.Session()</div><div class="line">    <span class="keyword">if</span> leanote_host.startswith(<span class="string">'https'</span>):</div><div class="line">        s.mount(<span class="string">'https://'</span>, SSLAdapter(ssl.PROTOCOL_TLSv1))</div><div class="line">    r = s.get(leanote_host + <span class="string">'/api/'</span> + url, params = param)</div><div class="line">    <span class="keyword">if</span> r.status_code == requests.codes.ok:</div><div class="line">        <span class="keyword">if</span> type==<span class="string">'json'</span>:</div><div class="line">            <span class="keyword">if</span> is_ok(r.text):</div><div class="line">                rj = json.loads(r.text)</div><div class="line">                <span class="comment"># if 'Msg' in rj:</span></div><div class="line">                <span class="comment">#     rj=rj['Msg']</span></div><div class="line">                <span class="keyword">return</span> rj</div><div class="line">            <span class="keyword">else</span>:</div><div class="line">                <span class="keyword">print</span> <span class="string">'[Err] requests to url %s fail'</span> %(r.url)</div><div class="line">                <span class="keyword">return</span> <span class="keyword">None</span></div><div class="line">        <span class="keyword">elif</span> type==<span class="string">'image'</span>:</div><div class="line">            i = Image.open(StringIO(r.content))</div><div class="line">            <span class="keyword">return</span> i</div><div class="line"></div><div class="line">    <span class="keyword">else</span>:</div><div class="line">        <span class="keyword">print</span> <span class="string">'[Err] connect to url %s fail, error code %d '</span> %(r.url, r.status_cde)</div><div class="line">        <span class="keyword">return</span> <span class="keyword">None</span></div><div class="line"></div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">req_post</span><span class="params">(url, param = <span class="string">''</span>, type = <span class="string">'json'</span>, token = True)</span>:</span></div><div class="line">    <span class="keyword">if</span> token:</div><div class="line">        <span class="keyword">if</span> param:</div><div class="line">            param.update(&#123;<span class="string">'token'</span>: leanote_token&#125;)</div><div class="line">        <span class="keyword">else</span>:</div><div class="line">            param=&#123;<span class="string">'token'</span>: leanote_token&#125;</div><div class="line"></div><div class="line">    s = requests.Session()</div><div class="line">    <span class="keyword">if</span> leanote_host.startswith(<span class="string">'https'</span>):</div><div class="line">        s.mount(<span class="string">'https://'</span>, SSLAdapter(ssl.PROTOCOL_TLSv1))</div><div class="line">    r = s.post(leanote_host + <span class="string">'/api/'</span> + url, data = param)</div><div class="line">    <span class="keyword">if</span> r.status_code == requests.codes.ok:</div><div class="line">        <span class="keyword">if</span> type==<span class="string">'json'</span>:</div><div class="line">            <span class="keyword">if</span> is_ok(r.text):</div><div class="line">                rj = json.loads(r.text)</div><div class="line">                <span class="comment"># if 'Msg' in rj:</span></div><div class="line">                <span class="comment">#     rj=rj['Msg']</span></div><div class="line">                <span class="keyword">return</span> rj</div><div class="line">            <span class="keyword">else</span>:</div><div class="line">                <span class="keyword">print</span> <span class="string">'[Err] requests to url %s fail'</span> %(r.url)</div><div class="line">                <span class="keyword">return</span> <span class="keyword">None</span></div><div class="line"></div><div class="line">    <span class="keyword">else</span>:</div><div class="line">        <span class="keyword">print</span> <span class="string">'[Err] connect to url %s fail, error code %d '</span> %(r.url, r.status_cde)</div><div class="line">        <span class="keyword">return</span> <span class="keyword">None</span></div><div class="line"></div><div class="line"></div><div class="line"><span class="comment">#ret leanote_token</span></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">login</span><span class="params">(email, pwd)</span>:</span></div><div class="line">    param = &#123;</div><div class="line">        <span class="string">'email'</span>: email,</div><div class="line">        <span class="string">'pwd'</span>:   pwd,</div><div class="line">    &#125;</div><div class="line">    r = req_get(<span class="string">'auth/login'</span>, param, token=<span class="keyword">False</span>)</div><div class="line">    <span class="keyword">if</span> r:</div><div class="line">        <span class="keyword">print</span> <span class="string">'Login success! Welcome %s (%s)'</span> %(r[<span class="string">'Username'</span>], r[<span class="string">'Email'</span>])</div><div class="line">        <span class="keyword">return</span> r[<span class="string">'Token'</span>]</div><div class="line">    <span class="keyword">else</span>:</div><div class="line">        <span class="keyword">print</span> <span class="string">'Login fail! Start again.'</span></div><div class="line">        exit()</div><div class="line"></div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">logout</span><span class="params">()</span>:</span></div><div class="line">    <span class="keyword">return</span> req_get(<span class="string">'auth/logout'</span>)</div><div class="line"></div><div class="line"></div><div class="line"><span class="comment">#ret dict(notebookId: type.Notebook&#125;</span></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">getNotebooks</span><span class="params">(includeTrash = False)</span>:</span></div><div class="line">    r = req_get(<span class="string">'notebook/getNotebooks'</span>)</div><div class="line">    <span class="keyword">if</span> r:</div><div class="line">        <span class="keyword">if</span> includeTrash:</div><div class="line">            <span class="keyword">return</span> &#123;notebook[<span class="string">'NotebookId'</span>] : notebook <span class="keyword">for</span> notebook <span class="keyword">in</span> r&#125;</div><div class="line">        <span class="keyword">else</span>:</div><div class="line">            <span class="keyword">return</span> &#123;notebook[<span class="string">'NotebookId'</span>] : notebook <span class="keyword">for</span> notebook <span class="keyword">in</span> r <span class="keyword">if</span> <span class="keyword">not</span> notebook[<span class="string">'IsDeleted'</span>]&#125;</div><div class="line">    <span class="keyword">else</span>:</div><div class="line">        <span class="keyword">return</span></div><div class="line"></div><div class="line"></div><div class="line"><span class="comment">#ret [type.Note], which contains noteId, and note meta data</span></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">getNotesMeta</span><span class="params">(notebookId)</span>:</span></div><div class="line">    param = &#123;</div><div class="line">        <span class="string">'notebookId'</span>: notebookId,</div><div class="line">    &#125;</div><div class="line">    <span class="keyword">return</span> req_get(<span class="string">'note/getNotes'</span>, param)</div><div class="line"></div><div class="line"></div><div class="line"><span class="comment">#ret type.NoteContent</span></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">getNoteDetail</span><span class="params">(noteId)</span>:</span></div><div class="line">    param = &#123;</div><div class="line">        <span class="string">'noteId'</span>: noteId,</div><div class="line">    &#125;</div><div class="line">    <span class="keyword">return</span> req_get(<span class="string">'note/getNoteAndContent'</span>, param)</div><div class="line"></div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">getImage</span><span class="params">(fileId)</span>:</span></div><div class="line">    param = &#123;</div><div class="line">        <span class="string">'fileId'</span>: fileId,</div><div class="line">    &#125;</div><div class="line">    <span class="keyword">return</span> req_get(<span class="string">'file/getImage'</span>, param, type = <span class="string">'image'</span>)</div><div class="line"></div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">addNotebook</span><span class="params">(title=<span class="string">'Import'</span>, parentId=<span class="string">''</span>, seq=<span class="number">-1</span>)</span>:</span></div><div class="line">    param = &#123;</div><div class="line">        <span class="string">'title'</span>: title,</div><div class="line">        <span class="string">'parentNotebookId'</span>: parentId,</div><div class="line">        <span class="string">'seq'</span> : seq</div><div class="line">    &#125;</div><div class="line">    <span class="keyword">return</span> req_post(<span class="string">'notebook/addNotebook'</span>, param)</div><div class="line"></div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">addNote</span><span class="params">(NotebookId, Title, Content, Tags=[], IsMarkdown = True, Abstract= <span class="string">''</span>, Files=[])</span>:</span></div><div class="line">    param = &#123;</div><div class="line">        <span class="string">'NotebookId'</span>: NotebookId,</div><div class="line">        <span class="string">'Title'</span>: Title,</div><div class="line">        <span class="string">'Content'</span>: Content,</div><div class="line">        <span class="string">'Tags[]'</span>: Tags,</div><div class="line">        <span class="string">'IsMarkdown'</span>: IsMarkdown,</div><div class="line">        <span class="string">'Abstract'</span>: Abstract,</div><div class="line">        <span class="comment">#'Files' : seq</span></div><div class="line">    &#125;</div><div class="line">    <span class="keyword">return</span> req_post(<span class="string">'note/addNote'</span>, param)</div><div class="line"></div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">readFromFile</span><span class="params">(filename)</span>:</span></div><div class="line">    <span class="keyword">import</span> yaml</div><div class="line">    file_meta = <span class="string">''</span></div><div class="line">    file_content = <span class="string">''</span></div><div class="line">    <span class="keyword">with</span> open (filename) <span class="keyword">as</span> f:</div><div class="line">        meta_flag=<span class="keyword">False</span></div><div class="line">        <span class="keyword">for</span> line <span class="keyword">in</span> f:</div><div class="line">            <span class="comment">#print line</span></div><div class="line">            <span class="keyword">if</span> meta_flag:</div><div class="line">                file_content += line</div><div class="line">            <span class="keyword">else</span>:</div><div class="line">                <span class="keyword">if</span> line.find(<span class="string">'---'</span>)&gt;<span class="number">-1</span>:</div><div class="line">                    meta_flag = <span class="keyword">True</span></div><div class="line">                <span class="keyword">else</span>:</div><div class="line">                    file_meta += line</div><div class="line"></div><div class="line">    <span class="keyword">if</span> <span class="keyword">not</span> meta_flag:</div><div class="line">        file_content = file_meta</div><div class="line">        file_meta = <span class="string">''</span></div><div class="line"></div><div class="line">    <span class="keyword">if</span> meta_flag:</div><div class="line">        meta = yaml.load(file_meta)</div><div class="line">    <span class="keyword">else</span>:</div><div class="line">        meta = &#123;&#125;</div><div class="line">    <span class="keyword">return</span> file_content, meta</div><div class="line"></div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">saveToFile</span><span class="params">(notes, noteBooks, path = <span class="string">'.'</span>)</span>:</span></div><div class="line">    unique_noteTitle = set()</div><div class="line">    <span class="keyword">for</span> note <span class="keyword">in</span> notes:</div><div class="line">        <span class="keyword">if</span> note[<span class="string">'Title'</span>] == <span class="string">''</span>:</div><div class="line">            filename = note[<span class="string">'NoteId'</span>]</div><div class="line">        <span class="keyword">else</span>:</div><div class="line">            filename = note[<span class="string">'Title'</span>]</div><div class="line"></div><div class="line">        <span class="keyword">if</span> filename <span class="keyword">in</span> unique_noteTitle:</div><div class="line">            filename=<span class="string">'%s_%s'</span> %(filename, note[<span class="string">'NoteId'</span>])</div><div class="line">        <span class="keyword">else</span>:</div><div class="line">            unique_noteTitle.add(filename)</div><div class="line"></div><div class="line">        <span class="keyword">if</span> note[<span class="string">'IsMarkdown'</span>]:</div><div class="line">            filename += <span class="string">'.md'</span></div><div class="line">        <span class="keyword">else</span>:</div><div class="line">            filename += <span class="string">'.txt'</span></div><div class="line">        <span class="keyword">try</span>:</div><div class="line">            <span class="keyword">with</span> open(path + <span class="string">'/'</span> + filename, <span class="string">'w'</span>) <span class="keyword">as</span> file:</div><div class="line">                <span class="keyword">print</span> <span class="string">'write file: %s'</span> %filename</div><div class="line">                file.write(<span class="string">'title: %s\n'</span> %note[<span class="string">'Title'</span>].encode(<span class="string">'utf-8'</span>))</div><div class="line"></div><div class="line"></div><div class="line">                date = dateutil.parser.parse(note[<span class="string">'CreatedTime'</span>])</div><div class="line">                file.write(<span class="string">'date: %s\n'</span> %datetime.strftime(date.astimezone(local_zone), <span class="string">'%Y/%m/%d %H:%M:%S'</span>))</div><div class="line"></div><div class="line">                date = dateutil.parser.parse(note[<span class="string">'UpdatedTime'</span>])</div><div class="line">                file.write(<span class="string">'updated: %s\n'</span> %datetime.strftime(date.astimezone(local_zone), <span class="string">'%Y/%m/%d %H:%M:%S'</span>))</div><div class="line"></div><div class="line">                <span class="keyword">if</span> note[<span class="string">'Tags'</span>]:</div><div class="line">                    <span class="keyword">if</span> len(note[<span class="string">'Tags'</span>]) == <span class="number">1</span>:</div><div class="line">                        <span class="keyword">if</span> note[<span class="string">'Tags'</span>][<span class="number">0</span>]:</div><div class="line">                            file.write(<span class="string">'tags:\n'</span>)</div><div class="line">                            <span class="keyword">for</span> tag <span class="keyword">in</span> note[<span class="string">'Tags'</span>]:</div><div class="line">                                file.write(<span class="string">'- %s\n'</span> %tag.encode(<span class="string">'utf-8'</span>))</div><div class="line"></div><div class="line">                category = []</div><div class="line">                current_notebook = note[<span class="string">'NotebookId'</span>]</div><div class="line">                category.append(noteBooks[current_notebook][<span class="string">'Title'</span>])</div><div class="line">                <span class="keyword">while</span> noteBooks[current_notebook][<span class="string">'ParentNotebookId'</span>] != <span class="string">''</span>:</div><div class="line">                    category.append(noteBooks[noteBooks[current_notebook][<span class="string">'ParentNotebookId'</span>]][<span class="string">'Title'</span>])</div><div class="line">                    current_notebook = noteBooks[current_notebook][<span class="string">'ParentNotebookId'</span>]</div><div class="line">                file.write(<span class="string">'categories:\n'</span>)</div><div class="line">                category.reverse()</div><div class="line">                <span class="keyword">for</span> cat <span class="keyword">in</span> category:</div><div class="line">                    file.write(<span class="string">'- %s\n'</span> %cat.encode(<span class="string">'utf-8'</span>))</div><div class="line"></div><div class="line">                file.write(<span class="string">'---\n'</span>)</div><div class="line">                file.write(<span class="string">'%s'</span> %note[<span class="string">'Content'</span>].encode(<span class="string">'utf-8'</span>))</div><div class="line"></div><div class="line">            file.close()</div><div class="line">            <span class="keyword">if</span> note[<span class="string">'Files'</span>]:</div><div class="line">                <span class="keyword">if</span> len(note[<span class="string">'Files'</span>]) &gt; <span class="number">0</span>:</div><div class="line">                    <span class="keyword">for</span> attach <span class="keyword">in</span> note[<span class="string">'Files'</span>]:</div><div class="line">                        <span class="keyword">if</span> <span class="keyword">not</span> attach[<span class="string">'IsAttach'</span>]:</div><div class="line">                            i = getImage(attach[<span class="string">'FileId'</span>])</div><div class="line">                            <span class="keyword">print</span> <span class="string">'saving its image: %s.%s'</span> %(attach[<span class="string">'FileId'</span>], i.format)</div><div class="line">                            i.save(attach[<span class="string">'FileId'</span>] + <span class="string">'.'</span> + i.format)</div><div class="line"></div><div class="line">        <span class="keyword">except</span>:</div><div class="line">            <span class="keyword">print</span> <span class="string">"error: "</span>, filename</div><div class="line"></div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">LeanoteExportToMD</span><span class="params">(path = <span class="string">'.'</span>)</span>:</span></div><div class="line">    <span class="keyword">print</span> <span class="string">'Reading your notebooks...'</span></div><div class="line">    noteBooks = getNotebooks()</div><div class="line"></div><div class="line">    <span class="comment">#get not deleted notes list</span></div><div class="line">    notes=[]</div><div class="line">    <span class="keyword">for</span> notebook <span class="keyword">in</span> noteBooks.values():</div><div class="line">        <span class="keyword">if</span> <span class="keyword">not</span> notebook[<span class="string">'IsDeleted'</span>]:</div><div class="line">            notesMeta = getNotesMeta(notebook[<span class="string">'NotebookId'</span>])</div><div class="line">            <span class="keyword">for</span> noteMeta <span class="keyword">in</span> notesMeta:</div><div class="line">                    <span class="keyword">if</span> <span class="keyword">not</span> noteMeta[<span class="string">'IsTrash'</span>]:</div><div class="line">                        note = getNoteDetail(noteMeta[<span class="string">'NoteId'</span>])</div><div class="line">                        notes.append(note)</div><div class="line">    <span class="keyword">print</span> <span class="string">'found %d notes'</span> %len(notes)</div><div class="line"></div><div class="line">    <span class="comment">#write file</span></div><div class="line">    saveToFile(notes, noteBooks, path = path)</div><div class="line">    <span class="keyword">print</span> <span class="string">'all done, bye~'</span></div><div class="line"></div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">LeanoteImportFromMD</span><span class="params">(path=<span class="string">'.'</span>)</span>:</span></div><div class="line">    <span class="comment"># filelist = os.listdir(path)</span></div><div class="line">    <span class="comment"># filelist = [file for file in filelist if file.find('.md')&gt;-1 or file.find('.txt')&gt;-1]</span></div><div class="line"></div><div class="line">    filelist = readfiles(path)</div><div class="line"></div><div class="line">    importedNotebookTitleMapID = &#123;&#125;</div><div class="line">    ret = addNotebook(title=<span class="string">'imported_note'</span>, parentId=<span class="string">''</span>, seq=<span class="number">-1</span>)</div><div class="line">    <span class="keyword">if</span> ret:</div><div class="line">        <span class="keyword">print</span> <span class="string">'imporing into a new notebook: %s'</span> %ret[<span class="string">'Title'</span>]</div><div class="line">        importedNotebookTitleMapID[<span class="string">'import'</span>] = ret[<span class="string">'NotebookId'</span>]</div><div class="line"></div><div class="line">    <span class="keyword">for</span> filename <span class="keyword">in</span> filelist:</div><div class="line">        content, meta = readFromFile(path + <span class="string">'/'</span> + filename)</div><div class="line">        <span class="keyword">if</span> DEBUG:</div><div class="line">            <span class="keyword">print</span> meta</div><div class="line"></div><div class="line">        parentTitle=<span class="string">'import'</span></div><div class="line">        currentTitle=<span class="string">''</span></div><div class="line">        <span class="keyword">if</span> meta.get(<span class="string">'categories'</span>):</div><div class="line">            categories= meta.get(<span class="string">'categories'</span>)</div><div class="line">        <span class="keyword">else</span>:</div><div class="line">            categories=[<span class="string">'import'</span>]</div><div class="line">        <span class="keyword">for</span> cat <span class="keyword">in</span> categories:</div><div class="line">            currentTitle=cat</div><div class="line">            <span class="keyword">if</span> currentTitle <span class="keyword">in</span> importedNotebookTitleMapID.keys():</div><div class="line">                parentTitle=currentTitle</div><div class="line">            <span class="keyword">else</span>:</div><div class="line">                ret = addNotebook(title = currentTitle, parentId = importedNotebookTitleMapID[parentTitle])</div><div class="line">                importedNotebookTitleMapID[currentTitle] = ret[<span class="string">'NotebookId'</span>]</div><div class="line">                parentTitle=currentTitle</div><div class="line"></div><div class="line">        <span class="keyword">if</span> <span class="keyword">not</span> meta.get(<span class="string">'title'</span>):</div><div class="line">            meta[<span class="string">'title'</span>] = filename.replace(<span class="string">'.md'</span>,<span class="string">''</span>).replace(<span class="string">'.txt'</span>,<span class="string">''</span>)</div><div class="line">        importedNote = addNote(NotebookId=importedNotebookTitleMapID[currentTitle], Title=meta.get(<span class="string">'title'</span>), Content=content, Tags=meta.get(<span class="string">'tags'</span>, []), Abstract=<span class="string">''</span>)</div><div class="line">        <span class="keyword">if</span> importedNote:</div><div class="line">            <span class="keyword">print</span> <span class="string">'imported %s'</span> %filename</div><div class="line">    <span class="keyword">print</span> <span class="string">'all done, bye~'</span></div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">readfiles</span><span class="params">(path)</span>:</span></div><div class="line">    <span class="keyword">assert</span> os.path.exists(path)</div><div class="line">    filelist = [os.path.join(root, f) <span class="keyword">for</span> root,_,files <span class="keyword">in</span> os.walk(path) <span class="keyword">for</span> f <span class="keyword">in</span> files <span class="keyword">if</span> f.find(<span class="string">'.md'</span>)&gt;<span class="number">-1</span> <span class="keyword">or</span> f.find(<span class="string">'.txt'</span>)&gt;<span class="number">-1</span>]</div><div class="line">    <span class="keyword">assert</span> filelist, <span class="string">"No files fond in %s"</span> % path</div><div class="line">    <span class="keyword">return</span> filelist</div><div class="line"></div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">main</span><span class="params">()</span>:</span></div><div class="line">    <span class="keyword">global</span> leanote_host</div><div class="line">    <span class="keyword">global</span> leanote_token</div><div class="line">    <span class="keyword">global</span> local_zone</div><div class="line">    <span class="keyword">global</span> args</div><div class="line"></div><div class="line">    args = init_options()</div><div class="line"></div><div class="line">    leanote_host=args.host</div><div class="line">    leanote_email=args.user</div><div class="line">    leanote_password=args.passwd</div><div class="line">    path = args.path</div><div class="line"></div><div class="line">    <span class="keyword">print</span> <span class="string">'Connecting to %s'</span> %leanote_host</div><div class="line">    leanote_token = login(leanote_email, leanote_password)</div><div class="line">    local_zone=tz.tzlocal()</div><div class="line"></div><div class="line">    <span class="keyword">if</span> args.choice == <span class="string">'import'</span>:</div><div class="line">        LeanoteImportFromMD(path)</div><div class="line">    <span class="keyword">elif</span> args.choice == <span class="string">'export'</span>:</div><div class="line">        LeanoteExportToMD(path)</div><div class="line">    <span class="keyword">else</span>:</div><div class="line">        <span class="keyword">print</span> <span class="string">'command format: \npython Leanote4MD.py import\npython Leanote4MD.py export'</span></div><div class="line"></div><div class="line">    logout()</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">init_options</span><span class="params">()</span>:</span></div><div class="line">    parser = argparse.ArgumentParser()</div><div class="line">    parser.add_argument(<span class="string">"choice"</span>, choices=[<span class="string">"import"</span>, <span class="string">"export"</span>], help=<span class="string">"import or export"</span>)</div><div class="line">    parser.add_argument(<span class="string">"--host"</span>, dest=<span class="string">"host"</span>, help=<span class="string">"host(defalt:http://leanote.com)"</span>)</div><div class="line">    parser.add_argument(<span class="string">"-u"</span>, <span class="string">"--user"</span>, dest=<span class="string">"user"</span>, help=<span class="string">"email for login"</span>)</div><div class="line">    parser.add_argument(<span class="string">"-p"</span>, <span class="string">"--passwd"</span>, dest=<span class="string">"passwd"</span>,help=<span class="string">"passwd for login"</span>)</div><div class="line">    parser.add_argument(<span class="string">"--path"</span>, dest=<span class="string">"path"</span>, help=<span class="string">"your save path (default is current dir)"</span>)</div><div class="line">    args = parser.parse_args()</div><div class="line"></div><div class="line">    config_args = readconfig()</div><div class="line">    <span class="keyword">if</span> <span class="keyword">not</span> args.host:</div><div class="line">        args.host = config_args.get(<span class="string">"host"</span>)</div><div class="line">    <span class="keyword">if</span> <span class="keyword">not</span> args.user:</div><div class="line">        args.user = config_args.get(<span class="string">"email"</span>)</div><div class="line">    <span class="keyword">if</span> <span class="keyword">not</span> args.passwd:</div><div class="line">        args.passwd = config_args.get(<span class="string">"passwd"</span>)</div><div class="line">    <span class="keyword">if</span> <span class="keyword">not</span> args.path:</div><div class="line">        args.path = config_args.get(<span class="string">"path"</span>)</div><div class="line"></div><div class="line">    <span class="keyword">if</span> DEBUG:</div><div class="line">        <span class="keyword">print</span> <span class="string">"choice:"</span>, args.choice</div><div class="line">        <span class="keyword">print</span> <span class="string">"host:"</span>, args.host</div><div class="line">        <span class="keyword">print</span> <span class="string">"user:"</span>,args.user</div><div class="line">        <span class="keyword">print</span> <span class="string">"passwd:"</span>,args.passwd</div><div class="line">        <span class="keyword">print</span> <span class="string">"path:"</span>, args.path</div><div class="line"></div><div class="line">    <span class="keyword">return</span> args</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">readconfig</span><span class="params">()</span>:</span></div><div class="line">    args = &#123;&#125;</div><div class="line">    config = CP.ConfigParser()</div><div class="line">    config.read(configpath)</div><div class="line">    args[<span class="string">"host"</span>] = config.get(<span class="string">"conn"</span>, <span class="string">"host"</span>)</div><div class="line">    args[<span class="string">"email"</span>] = config.get(<span class="string">"conn"</span>, <span class="string">"email"</span>)</div><div class="line">    args[<span class="string">"passwd"</span>] = config.get(<span class="string">"conn"</span>, <span class="string">"passwd"</span>)</div><div class="line">    args[<span class="string">"path"</span>] = config.get(<span class="string">"conn"</span>, <span class="string">"path"</span>)</div><div class="line">    <span class="keyword">return</span> args</div><div class="line"></div><div class="line"><span class="keyword">if</span> __name__ == <span class="string">'__main__'</span>:</div><div class="line">    sys.exit(main())</div></pre></td></tr></table></figure>
</li>
<li><p>备份脚本说明</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div></pre></td><td class="code"><pre><div class="line">#leanote导入导出MD工具</div><div class="line">- 可以把你储存在[Leanote](http://leanote.com)上的笔记、文章都导出成Markdown文件、文本文件</div><div class="line">- 也可以把你储存在硬盘的Markdown文件、文本文件都导入到[Leanote](http://leanote.com)上去</div><div class="line">- 目前支持导入导出含YAML格式的meta信息的文件，参照 [hexo](http://hexo.io/docs/front-matter.html)  的文件格式，也就是说文件头部可以有`title` `tags` </div><div class="line">`date` `categoris`等meta信息</div><div class="line">- 兼容官方网站，以及自建的服务器（基于beta4，以及API 0.1版本）</div><div class="line"></div><div class="line">#如何使用</div><div class="line">- 首先安装Python2版本</div><div class="line">- 确保机器已经安装 `requests` `Pillow` `PyYaml` `requests_toolbelt` 等模块，如果没装请 `pip install`</div><div class="line">- 然后在命令行执行`python leanote4MD.py`</div><div class="line">  - 如果报错，应该是你的 python 路径问题，或者缺少某些python module</div><div class="line">- 根据提示输入域名（默认是http://leanote.com）、用户邮箱、密码</div><div class="line">  - 域名不要忘记加`http://`</div><div class="line">  - 如果是自建服务器，请保证版本不低于 beta4</div><div class="line">  - 记得用邮箱，而不是用户名</div><div class="line">- 一般导入的错误都是文件没有严格按照YAML格式（多余空格等）造成的解析错误</div><div class="line"></div><div class="line"></div><div class="line">#功能</div><div class="line"></div><div class="line">- [x] 从Leanote导入、导出笔记本/子笔记本到MD或txt文本文件</div><div class="line">- [x] 保存为兼容 hexo front matter 的tag、category、date、title等</div><div class="line">  - 由于0.1版本API限制，导入时暂时无法设置 保存时间、修改时间</div><div class="line">- [x] 只导入、导出不在垃圾箱的笔记</div><div class="line">- [x] 数不尽的bug</div><div class="line">- [ ] 根据是否为已发布的blog，生成post或者draft属性</div><div class="line">- [x] 导出时保存图片到本地</div><div class="line">- [ ] 导入时提交图片到服务器</div></pre></td></tr></table></figure>
</li>
<li><p>备份脚本配置文件，原始备份脚本是交互式的，改为读取配置文件了</p>
</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line">cat Leanote.cfg</div><div class="line">[conn]</div><div class="line">host = http://leanote.com</div><div class="line">email = charlie.cui@qq.com</div><div class="line">passwd = </div><div class="line">path = /opt/Leanote4MD/LeaNote_BackUp/</div></pre></td></tr></table></figure>
<ul>
<li>备份脚本</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div></pre></td><td class="code"><pre><div class="line">more backupnote </div><div class="line">#!/bin/bash</div><div class="line">_work_dir=/opt/Leanote4MD</div><div class="line">_date=`date +%Y-%m-%d`</div><div class="line"></div><div class="line">backup() &#123;</div><div class="line">	mkdir -p $&#123;_work_dir&#125;/LeaNote_BackUp/$&#123;_date&#125;</div><div class="line">	cd _$&#123;_work_dir&#125;/LeaNote_BackUp</div><div class="line">	$&#123;_work_dir&#125;/Leanote4MD.py export |tee $LogFile</div><div class="line">	mv *.md $&#123;_date&#125;</div><div class="line">&#125;</div><div class="line"></div><div class="line">clean()&#123;</div><div class="line">	find  $&#123;_work_dir&#125;/LeaNote_BackUp/ -type d -mtime +30 |xargs rm -fr</div><div class="line">&#125;</div><div class="line">backup &amp;&amp; clean</div></pre></td></tr></table></figure>
<ul>
<li>增加cron，每天备份一次</li>
</ul>
<p><a href="http://ofc9x1ccn.bkt.clouddn.com/blog/Leanote4MD.py" target="_blank" rel="external">Leanote4MD.py</a></p>
]]></content>
    
    <summary type="html">
    
      &lt;p&gt;为知笔记收费了，把笔记迁移到 leanote 上，但是有担心笔记的安全，所以找到了一个备份脚本，每天备份日志到本地。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;备份脚本&lt;/p&gt;
&lt;figure class=&quot;highlight python&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class
    
    </summary>
    
      <category term="Blog" scheme="http://czero000.github.io/categories/Blog/"/>
    
    
      <category term="blog" scheme="http://czero000.github.io/tags/blog/"/>
    
      <category term="leanote" scheme="http://czero000.github.io/tags/leanote/"/>
    
  </entry>
  
</feed>
