<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>运维宝典</title>
  <icon>https://www.gravatar.com/avatar/b615352b03f524e824d3acb58744ae89</icon>
  <subtitle>精通原创，擅长盗版</subtitle>
  <link href="https://opsuri.com/atom.xml" rel="self"/>
  
  <link href="https://opsuri.com/"/>
  <updated>2025-02-22T16:08:34.930Z</updated>
  <id>https://opsuri.com/</id>
  
  <author>
    <name>Jeff.S</name>
    <email>&amp;#115;&amp;#104;&amp;#105;&amp;#121;&amp;#97;&amp;#111;&amp;#46;&amp;#122;&amp;#104;&amp;#64;&amp;#103;&amp;#109;&amp;#97;&amp;#105;&amp;#108;&amp;#46;&amp;#99;&amp;#111;&amp;#109;</email>
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>CentOS7迁移到RockyLinux9</title>
    <link href="https://opsuri.com/2025/03/01/Migrate-from-CentOS7-to-Rocky-Linux-9/"/>
    <id>https://opsuri.com/2025/03/01/Migrate-from-CentOS7-to-Rocky-Linux-9/</id>
    <published>2025-03-01T01:02:35.000Z</published>
    <updated>2025-02-22T16:08:34.930Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/lightgallery.js/1.0.1/css/lightgallery.min.css" /><div class=".article-gallery"><p><code>CentOS7</code>已停止支持超过半年了，因此需要将其迁移至其他Linux版本系统，如<code>Rocky Linux 9</code>、<code>Debian 12</code>等来避免可能导致的安全漏洞问题。现在来记录下迁移过程中遇到过的问题。</p><h2 id="CentOS-7-Update">CentOS 7 Update</h2><p>因为原版源已经从<code>mirror.centos.org</code>改为<code>vault.centos.org</code>，默认是找不到新更新的。你可以修改你的源为<code>vault.centos.org</code>或者使用<code>linuxmirror.cn</code>修改为国内镜像源。</p><span id="more"></span><p>为了提速，可将镜像源更改为国内源。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> yum update -y</span><br><span class="line"><span class="built_in">sudo</span> yum install epel-release -y</span><br><span class="line"><span class="built_in">sudo</span> yum install rpmconf -y</span><br><span class="line"><span class="built_in">sudo</span> rpmconf -a</span><br><span class="line"><span class="built_in">sudo</span> yum install yum-utils -y</span><br><span class="line"><span class="built_in">sudo</span> package-cleanup --leaves</span><br><span class="line"><span class="built_in">sudo</span> package-cleanup --orphans</span><br></pre></td></tr></table></figure><p>清除完后，重启。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> yum install dnf -y</span><br><span class="line"><span class="built_in">sudo</span> dnf remove yum yum-metadata-parser -y</span><br><span class="line"><span class="built_in">sudo</span> <span class="built_in">rm</span> -Rf /etc/yum</span><br><span class="line"><span class="built_in">sudo</span> dnf update -y</span><br></pre></td></tr></table></figure><p>更新完成后还原至原来的软件源<code>/etc/yum.repo.bak</code>并下载最新版本的repo</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> dnf install http://vault.centos.org/8.5.2111/BaseOS/x86_64/os/Packages/&#123;centos-linux-repos-8-3.el8.noarch.rpm,centos-linux-release-8.5-1.2111.el8.noarch.rpm,centos-gpg-keys-8-3.el8.noarch.rpm&#125; -y</span><br></pre></td></tr></table></figure><blockquote><p>不过我们先打开<code>BaseOS</code>, <code>AppSteam</code>, <code>Extra</code>源，看看他们是<code>mirror.centos.org</code>还是<code>vault.centos.org</code>。<br>如果不是<code>vault</code>则改过来。</p></blockquote><p>例如：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> sed -i <span class="string">&#x27;s|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g&#x27;</span> /etc/yum.repos.d/CentOS-*</span><br></pre></td></tr></table></figure><p>使用下面的命令时因为缓存还在使用<code>mirror.centos.org</code>的原因，会有报错，但是没关系，因为我们安装的是下载的网址内安装包。之后我们清除缓存即可。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> dnf upgrade https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm -y</span><br><span class="line"><span class="built_in">sudo</span> dnf clean all</span><br><span class="line"><span class="built_in">sudo</span> rpm -e `rpm -q kernel`</span><br></pre></td></tr></table></figure><p>这个时候，表面已经是<code>CentOS 8</code>了。可以通过</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cat</span> /etc/redhat-release</span><br></pre></td></tr></table></figure><p>查看。<br>更换源为国内镜像源 - 选择华为云源</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">bash &lt;(curl -sSL https://linuxmirrors.cn/main.sh)</span><br></pre></td></tr></table></figure><p>选择华为云源</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> dnf update -y</span><br></pre></td></tr></table></figure><p>安装完成后，表面上应该就会是<code>CentOS 8</code>, 但是应该也会有冲突的<code>python3</code>的报错，<code>sysvinit-tools</code>的报错等等。<br>我们先<code>dnf remove</code>移除<code>python3-pip</code>, <code>sysvinit-tools</code><br>也可以</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">rpm -e --nodeps sysvinit-tools</span><br><span class="line"><span class="comment"># dnf remove sysvinit-tools-2.88-14.dsf.el7.x86_64</span></span><br><span class="line">remove python3-setuptools-39.2.0-10.el7.noarch</span><br><span class="line"><span class="comment"># 我们无法移除gdbm 使用以下方式升级到CentOS 8</span></span><br><span class="line">dnf upgrade --best --allowerasing</span><br></pre></td></tr></table></figure><p>然后继续升级CentOS 7到CentOS 8</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">dnf clean all</span><br><span class="line">dnf --releasever=8 --allowerasing --<span class="built_in">setopt</span>=deltarpm=<span class="literal">false</span> distro-sync</span><br></pre></td></tr></table></figure><p>安装内核</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">dnf install kernel-core -y</span><br></pre></td></tr></table></figure><h2 id="安装CentOS-8-的最小版本">安装CentOS 8 的最小版本</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">dnf -y groupupdate <span class="string">&quot;Core&quot;</span> <span class="string">&quot;Minimal Install&quot;</span></span><br></pre></td></tr></table></figure><p>虽然，我们可以通过以下命令再次将<code>CentOS 8</code>转为<code>CentOS 8 Stream</code></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> dnf install centos-release-stream -y</span><br></pre></td></tr></table></figure><p>但是后续其实还有步骤，只要dnf版本足够高的话，其实可以直接迁移Rocky Linux。所以没有转换的必要。</p><p>与此同时<code>Rocky Linux 8</code>迁移到<code>Rocky Linux 9</code>需要使用<code>AlmaLinux</code>的<code>leapp</code>也就是<code>ELevate</code>工具来升级，且升级步骤必须使用<code>VPN</code>,直接下载依赖好像还是不行的。<code>leapp</code>默认只支持<code>CentOS</code>, 需要<code>leapp-data-xxx</code>来支持其他系统升级。<br>因为本身大版本升级操作系统是不支持的，所以官方也没有明确的方式，而<code>Rocky Linux 8.10 EOL</code>是<code>2029年</code>，其实直接迁移为<code>Rocky Linux 8</code>已经足够了。</p><h2 id="迁移到Rocky-Linux-8">迁移到Rocky Linux 8</h2><p>根据<code>Rocky Linux</code>的步骤继续迁移：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">curl https://raw.githubusercontent.com/rocky-linux/rocky-tools/main/migrate2rocky/migrate2rocky.sh -o migrate2rocky.sh</span><br><span class="line"><span class="built_in">chmod</span> u+x migrate2rocky.sh</span><br></pre></td></tr></table></figure><p>运行脚本:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">./migrate2rocky.sh -r</span><br></pre></td></tr></table></figure><p>等待运行完毕重启后：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cat</span> /etc/*release*</span><br><span class="line"></span><br><span class="line">Rocky Linux release 8.10 (Green Obsidian)</span><br><span class="line">NAME=<span class="string">&quot;Rocky Linux&quot;</span></span><br><span class="line">VERSION=<span class="string">&quot;8.10 (Green Obsidian)&quot;</span></span><br><span class="line">ID=<span class="string">&quot;rocky&quot;</span></span><br><span class="line">ID_LIKE=<span class="string">&quot;rhel centos fedora&quot;</span></span><br><span class="line">VERSION_ID=<span class="string">&quot;8.10&quot;</span></span><br><span class="line">PLATFORM_ID=<span class="string">&quot;platform:el8&quot;</span></span><br><span class="line">PRETTY_NAME=<span class="string">&quot;Rocky Linux 8.10 (Green Obsidian)&quot;</span></span><br><span class="line">ANSI_COLOR=<span class="string">&quot;0;32&quot;</span></span><br><span class="line">LOGO=<span class="string">&quot;fedora-logo-icon&quot;</span></span><br><span class="line">CPE_NAME=<span class="string">&quot;cpe:/o:rocky:rocky:8:GA&quot;</span></span><br><span class="line">HOME_URL=<span class="string">&quot;https://rockylinux.org/&quot;</span></span><br><span class="line">BUG_REPORT_URL=<span class="string">&quot;https://bugs.rockylinux.org/&quot;</span></span><br><span class="line">SUPPORT_END=<span class="string">&quot;2029-05-31&quot;</span></span><br><span class="line">ROCKY_SUPPORT_PRODUCT=<span class="string">&quot;Rocky-Linux-8&quot;</span></span><br><span class="line">ROCKY_SUPPORT_PRODUCT_VERSION=<span class="string">&quot;8.10&quot;</span></span><br><span class="line">REDHAT_SUPPORT_PRODUCT=<span class="string">&quot;Rocky Linux&quot;</span></span><br><span class="line">REDHAT_SUPPORT_PRODUCT_VERSION=<span class="string">&quot;8.10&quot;</span></span><br><span class="line">Rocky Linux release 8.10 (Green Obsidian)</span><br><span class="line">Rocky Linux release 8.10 (Green Obsidian)</span><br><span class="line">Derived from Red Hat Enterprise Linux 8.10</span><br><span class="line">Rocky Linux release 8.10 (Green Obsidian)</span><br><span class="line">cpe:/o:rocky:rocky:8:GA</span><br></pre></td></tr></table></figure><p>之后再打开<code>/etc/yum.repos.d</code>并将<code>CentOS-*.repo</code>删除</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">rm</span> -rf /etc/yum.repos.d/CentOS-*</span><br><span class="line"><span class="comment"># 或不加f 可以确认删除的文件</span></span><br><span class="line"><span class="built_in">rm</span> -r /etc/yum.repos.d/CentOS-*</span><br></pre></td></tr></table></figure><h2 id="使用ELevate-leapp升级系统">使用ELevate leapp升级系统</h2><p>Rocky Linux 8 to 9方法<br><a href="https://wiki.almalinux.org/elevate/ELevate-quickstart-guide.html">AlmaLinux leaapp Upgrade</a><br><a href="https://wiki.crowncloud.net/?How_to_upgrade_from_RockyLinux_8_to_RockyLinux_9">leaapp Upgrade</a></p><p>如果直接是<code>CentOS 8</code>也可以直接使用这个方式升级。</p><p>下载这个rpm, 就会在<code>/etc/yum.repos.d</code>安装<code>Elevate repo</code>，也可以使用<code>wget</code>下载后安装。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> yum install -y http://repo.almalinux.org/elevate/elevate-release-latest-el$(rpm --<span class="built_in">eval</span> %rhel).noarch.rpm</span><br></pre></td></tr></table></figure><p><code>Elevate Repo</code>内容：(该repo无镜像站)</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">[elevate]</span><br><span class="line">name=ELevate</span><br><span class="line">baseurl=https://repo.almalinux.org/elevate/el8/<span class="variable">$basearch</span>/</span><br><span class="line">...</span><br></pre></td></tr></table></figure><p>因为Elevate无镜像站资源，leapp-data-rocky就无法下载，即使预先先从官网下载依然是不行的。<br>leapp-data-rocky最新版地址：<a href="https://repo.almalinux.org/elevate/el8/x86_64/leapp-data-rocky-0.2-7.el8.noarch.rpm">https://repo.almalinux.org/elevate/el8/x86_64/leapp-data-rocky-0.2-7.el8.noarch.rpm</a><br>因为默认的<code>leapp-upgrade</code>只支持<code>CentOS</code>，不支持其他升级。所以<code>leapp-upgrade</code>和<code>leapp-data-rocky</code>都需要。如果使用<code>leapp-data</code>,只支持从<code>Rocky 8</code>升级到<code>Rocky 9</code>,不支持<code>CentOS 8</code>升级并迁移为<code>Rocky 9</code>或<code>CentOS 8</code>升级并迁移为<code>AlmaLinux 9</code>。<br>因此需要直接VPN到<code>https://repo.almalinux.org/elevate/</code>这个源里安装依赖。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">yum install -y leapp-upgrade leapp-data-rocky</span><br><span class="line">leapp preupgrade</span><br></pre></td></tr></table></figure><p>然后查看<code>answerfile</code>，我的<code>answerfile</code>中只有<code>vdo</code>问题，所以直接使用以下命令覆盖即可。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">leapp answer --section check_vdo.no_vdo_devices=True</span><br></pre></td></tr></table></figure><p>后面步骤不展示了，因为没成功。(需要VPN连，太慢了。)</p><h2 id="Rocky-Linux-8-到Rocky-Linux-9-非leapp方式">Rocky Linux 8 到Rocky Linux 9 (非leapp方式)</h2><p><a href="https://linuxiac.com/upgrade-rocky-linux-8-to-rocky-linux-9/">RL8 to RL9</a><br>可以参考浙江大学的镜像源</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">dnf install https://mirror.nju.edu.cn/rocky-vault/9.3/BaseOS/x86_64/os/Packages/r/&#123;rocky-repos-9.3-1.3.el9.noarch.rpm,rocky-release-9.3-1.3.el9.noarch.rpm,rocky-gpg-keys-9.3-1.3.el9.noarch.rpm&#125; -y</span><br><span class="line">dnf -y --releasever=9 --allowerasing --<span class="built_in">setopt</span>=deltarpm=<span class="literal">false</span> distro-sync</span><br></pre></td></tr></table></figure><p>应该会报iptable的错误,通过以下方式解决</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">yum remove iptables-ebtables make-devel</span><br></pre></td></tr></table></figure><p>然后再来一次升级后<code>重建rpmdb</code>。这是因为9版本不再使用<code>Berkeley DB(bdb_ro)</code>而是使用<code>SQLite</code></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">rpm --rebuilddb</span><br></pre></td></tr></table></figure><p>安装CentOS 9 的最小版本之后重启。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">dnf -y groupupdate <span class="string">&quot;Core&quot;</span> <span class="string">&quot;Minimal Install&quot;</span></span><br></pre></td></tr></table></figure><p>升级如果遇到以下问题，需要用<code>dnf module disable</code>禁用。</p><figure class="highlight plaintext"><figcaption><span>Text</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">Problem 1: conflicting requests</span><br><span class="line"> - nothing provides module(platform:el8) needed by module mariadb:10.3:8080020230920001707:fd72936b.x86_64 from @modulefailsafe</span><br><span class="line">Problem 2: conflicting requests</span><br><span class="line"> - nothing provides module(platform:el8) needed by module python27:2.7:8100020240523105808:5f0f67de.x86_64 from @modulefailsafe</span><br><span class="line">Problem 3: conflicting requests</span><br><span class="line"> - nothing provides module(platform:el8) needed by module python36:3.6:8100020231207204726:5ae887d0.x86_64 from @modulefailsafe</span><br></pre></td></tr></table></figure><p>我们根据上面的信息禁用对应的模块，并且是同时输入</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">dnf module <span class="built_in">disable</span> mariadb:10.3 python27:2.7 python36:3.6</span><br></pre></td></tr></table></figure><p>我们当然也可以使用<code>dnf module list</code>的方式查看模块并禁用。</p><p>这时如果<code>dnf update -y</code>或者<code>dnf upgrade</code>已经无报错代表升级成功了，可以重启使用了。<br>不过如果你查看<code>dnf list |grep el8</code>可能还会找到有软件包是el8的<br>你可以按需看情况使用<code>dnf remove</code>卸载掉。<br>如果遇到<code>kernel-core</code>在的情况下，则需要</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">rpm -e --nodeps `rpm -qa|grep -i kernel|grep 4.18`</span><br></pre></td></tr></table></figure><p>因为卸载的有点多，我为了确保稳定性将系统环境改为<code>Server</code>（你也可以用<code>Server with GUI</code>）</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">dnf groupinstall <span class="string">&quot;Server&quot;</span></span><br><span class="line"><span class="comment"># dnf grouplist 查看可选安装环境</span></span><br></pre></td></tr></table></figure><p>这样他会安装很多组件，应该来说就比较稳定了。<br>当然我们都知道，重新安装才是最稳定的。这是一个迁移临时方案。</p><p>–<br>来源： <a href="https://cloud.tencent.com/developer/article/2442737">https://cloud.tencent.com/developer/article/2442737</a></p></div><script src="https://cdn.jsdelivr.net/lightgallery.js/1.0.1/js/lightgallery.min.js"></script><script>if (typeof lightGallery !== 'undefined') {        var options = {            selector: '.gallery-item'        };        lightGallery(document.getElementsByClassName('.article-gallery')[0], options);        }</script>]]></content>
    
    
    <summary type="html">介绍CentOS7的新特性。包括文件系统、GRUB2、内核版本、集群、防火墙、服务管理、网络管理、运行级别等。</summary>
    
    
    
    <category term="资讯" scheme="https://opsuri.com/categories/%E8%B5%84%E8%AE%AF/"/>
    
    
    <category term="Linux" scheme="https://opsuri.com/tags/Linux/"/>
    
    <category term="资讯" scheme="https://opsuri.com/tags/%E8%B5%84%E8%AE%AF/"/>
    
    <category term="RockyLinux" scheme="https://opsuri.com/tags/RockyLinux/"/>
    
    <category term="迁移" scheme="https://opsuri.com/tags/%E8%BF%81%E7%A7%BB/"/>
    
  </entry>
  
  <entry>
    <title>13个实用的Kubernetes技巧</title>
    <link href="https://opsuri.com/2025/02/15/13-Practical-Kubernetes-Tips/"/>
    <id>https://opsuri.com/2025/02/15/13-Practical-Kubernetes-Tips/</id>
    <published>2025-02-15T09:04:52.000Z</published>
    <updated>2025-02-23T04:20:01.941Z</updated>
    
    <content type="html"><![CDATA[<div class="hbe hbe-container" id="hexo-blog-encrypt" data-wpm="抱歉，您输入的密码错误，请检查后重新输入。" data-whm="抱歉, 当前文章不能被校验, 不过您还是可以看看解密后的内容。">  <script id="hbeData" type="hbeData" data-hmacdigest="8a8bb7adf8ff24d94218406cdedf081547f83e623793193124e97dd198a808f6">94d68333146fbfa95448021018c520949b75ceb39054c1487ddd74709f245f40d148ddb6d442970ccb05a637146ac8058c13b4a9cb780ced71925a295bf3ff97946b910ca45432bd4f4b0b63050ec2dd85c6c19a1865e62d651893b166c5252cc51d6adcce3646f61c8d51d681be91ded30732787f108bec9f9c124ca033ad1d737d1ebaec950ab3a95597d9c0dbb29aceff4a525fc2bf05c299d5b2b876419be9bbd1c31334a96a76dc9c2c23160049bacf41e0668100929f0f1268b4d292943ac5aa9d4e07daa00a3ae92fe68d3b0b7cac1f9acbf5763815e64fdf17b67d21152976f5f6c11451998f77c717c7f017c9b5755f848b09fec441a40b703061da1266f8696a0c0602ff4d52b26201749ffbc694d10026b22f3076cd39b3f353b390695cc7017a34f44651bb071ec3bbde0b6ebdb9dd75005786504ee09c6fe2190395646d79121158d18f7039aeb760d7a96e40cf2aa888e1c832811a37132f1df936537b8fbf7486036776773df49afc933621c561b037df6277aaafeef1d9d368226af7b3d48076d89614542eb52170242f3052378bfa2ef37994b5b41a543aef7748b79afc6b7c3e5ef53f57547558fae0c6b4d549a10636f3b9bbb2b09fd2429203c00d2d3a2c15552ead7085b77ba18342a46c726d984845391444709a7b6e4d1e1d72da424b11c22f650a386a758d557775a6e9238070e7c8e1e7f9713b4a040e470961280813c44ca9df2567a5eaa23a7d5d2db11d0b19f48991917991f7fe257c9b6172a4aed976eb3a7cdfd58ddfd5ed9195199e1be48759b3647d2cc95c51c2ab7188351da74b7277aaf3bbad5382f569a5e64a1ed6b74c9e9fadd6f0edf98e1cc48862409ea8b30ed061b3f342f2b275651914b20eb8a3c0ce148ae41b192d572c419d527021b04bf16da450e2a6b6d890e9f9e9a5c376c147e8b3c5382ec09be11ba4e677d05d64dcd5a6209995560f51be9218a64854f376513a0784dff067b4f4057237a60344e2b6ebcfea833d0ad7d14e52b094def53a53456d7abf02e64c2977783c20f99ac4b9782fdf3eb23e56e134b2ef02477965fc08dba9c2345cbeb94f2517adb8299209396215b9b96e357dc5f0d999f194fa55acf1b1219aa2181276ee238ea45c79fc00630ddbc2c2e2e4bafc8368cabe5239d219014399ba0a4ead6936b3ae90149feb13258ad531535571b57a8fc88e0efa30a534ff882d23557b84e7916b751dabc1e9968a00d0a6d1f6c9e991575e6b430b031d1bdf3c7c1914b7457c5b3461a4016e7e6faa2caaae41e34b2430706614a0b249259f631b83a117a809bbbf85bc6784ce3dee1938feb057ac0ccb3cfbedba48c63ab56a7212b471ca816c7a9dcad51e4e6026c34d6af3741913a857bc3bfba4f26a77b1d4ce74a61d5f40313666c6a2b0de3512aec2c78b928fc197431f47401548391acd6fc174616e39fea52f131fa16f4bc18b86798f2c3e79da489e0ae6b2b9b82789dc934fd0d60c0ba3701966fe6e9285c5a1e1310da9db973f33a66c8b9a79629c69b44a938157362fe7cb59e922b2328e93e2dab5c12ddb4f598d5081db11f48eede28e83a9402b711b4a29093ea4953311e02eea0eaed24908f56074abe785082142b4bc5f79b22cd38917ea3b80a0f057aa762bbfdfbb7b35b1f6f2a5e4a0fcd76b2727c9b0541287e7e70ee61db7d7681451775fdd0f34d2d217ff45b4b5e4955e38fd09444dd66a267f2f2adc81ecffc3839908ab7fe3c6b9a063524c8af8e02db0cf89affc208186059ca2a70adfc8e29d4a83c704194c2bd729d26995f0dbc4e61256d8429319d738921d574e4049bce0d207c27a90be6a5ed2a671479363b2fb053036d74e91083b8f79984adde62ac64e482df2c7cbaa583356e8c24a3400633ef348aaa39f6f0400fa165eabf7daacd7270aa6c6598c8d49f16abd5d021a93f1f2d36ac42fb670543a6252ec1433aedc65247e3c79cd7ed25badfe5a55f098376c254ad6d0af5a0b8fbc329d3d6541b6191bcb9e51a88faccbd8863d255764f59899fe868131683602c5b06e469850ac2961bb6f3acfa74236b9fe4d896f7a0fe40b3b0f36f2ac69b13595e1c5dd6feeb0a77ef30dd957da6c43e32053489d54af4e98d9a6ba13063d74ebd803042233bac9d1b501d3e9f9ace7c0d171dc1622e7ad05c16d4124c888f5ebca349e085b60edeabc5788e15900f929daf636a58f465f443d9d25ba2eb0a2827f49d485ab379b45b22c264ea03b429523bc35e970cb8fe12bcb6d85151545a7551ca2022713f7c61aa21a3521ac96fbc86cb0bbade1162572d095d94fff26efbeb7524156c1c700b2a78fd817549e73158981655c7b4becb13f313112eb17facb94bd206a683450b87ff7f4a85e2040425bc7143cd1614323cf01c43d5bc8db57f7aaab28d999e4680fb7f7c3a428923dab57f4146e1a843a25e5ed41a0144fcba1a05dbbd163b0657b2822ae9802d3eb7d93cb408ea7fcba6ecf97277d479e44c165e79d54efd75eed4a83d7f6911c7d550432b60e8b99e0c20ac2a23ff592ce2b0eda061b2314706499bcff1ec7f1f0c48dd19fccef662b35606e1b397d39de88903b120eaa261fa16d0833c3ff7a3d60789fc3d1d8ed9ce99bb38f830794af02c03a19a60a67b1b83c22e6f174512f2b6935a3f17786b157b6845674e2a32147dde6c0c25c12fdac4e032e93783b08e0ff3c0d822a6fb66110524e1ca9f133cbf9447bec2dee0c1b7ebf5e305d15739a4b7ac496d1cc3f5e77686636c9758f53f555265d3e405df1b88bdd9607d85e635a127c3ab450329bbbb349d4df2624616f271df369eb146e0617508eb16e4dbe297a0062010ff5601031fe610a0c2872438724b257319aba212a04cafb9d69011d22e052c16d1fd55145f06e07aa93e0ffc1158ce8185a34287a581d004afce148fdc6b1539c4897125a81c93a6281280e4d93bec9225175056ec517a9e4563f5d14ee9cf954bc520f70025a4d3365e2c1afc485647d67503dec5dd10cea58ededb2e455f5a5ea84391d76105397cc2bcc5d6e56db0959f300b19271b68042c0e02dc60e7ddcb32ca1472e843cfd69eb63d9e8d304a51cba738dd9fa6e214a1c3b8ea692b2a5293c84b11b638dbe4976ceb6b4d82878950412298976f75834f462bdce927273bfee348255b1d17f2f0fe341ef3579e6ba8fc755aac494b0e5778a4df0699ab8d05a191d2d40230fb6182833726b807e6a56aab486b4ce93826aaa422ecb65705ca6bc5001265ef510de76fc2d57dbfe2527c517ce988c8961258183da873de78a77e3d6392ea8bc31679bc5327fd679b2311f805afc8f67780da476fc4bae18987c9736a5d0a277a332d1d76e3b9983685c29da785bf52ba2f50b54620231d609ddb0f32a95bda49219b16776b38eb427e48b6d3a7200c63ba180a61b68fdff22eebfcc3f471cb7a1ce766721593849111d4b65367082ce260fbfb1d1fe5295614e6679071d478c76b9a1aee9fa4d614b4691b913986b375619971be48eb3ca02978fb6c8dc982e4fc6c4420f00a7ab7dc3e06ea69057b7fd6cfd24acde8f558993d6f1de19a9a94621d7bc50d3c9b5b6b717a943790d350a0ad8fdf25289b47913b5051cbb1ad9dfd74caf758c8992e1741854e5f73d1862b929b9425912776d8cd377486ab95cd18691077417ae3b95fcad1a33dfcfbd99f8a0c5a667548c287d47c50074fc992a8346e1ba48030d711e6fae1cd8efd4b168d9d141f31797414b0e81780c031f2603a06b0eef6dc3d044c0a938718568d43ee58bc96a4934fb942006c97f31afaee794fb5a2bf5607df74353bea0445c7a47ab4c13a2ec08c83de4a2daa4bde584f1b1408abcc3ee08efb3d5784b123a73c4dadf376b18d0510db67b9f5db1da0ce03de1253447eb43c19ea55d87ded7efa6acb4a6aed5480bd544e3e09a56b901ca09422412ff97daceae8c7a36d151c02f793d18d2c3622c3a30a53ec8a198e74b502acc7fed33972d8c014d5cb19917df194580a7acce6efeab66de50967308b5e9716dd70960c4ff8d25dcb0ad2c4d0e15acd5f1c257b427e9016f4e4662ac9bbc287cb08052a280c0c18124745d4e6b857927bbb1d771501b63e40f0c2c83d5088a1a3809faee56f8733c681c335b4beed62d4d3bfe369fd2d73770a688432add4c1f27d20111aca691e1e31de49cbfaafc991e61545830122af5ecc55d46eabc403b431716d9042d04a754a84ab2afc46a6c9aee32297486c5c62cd49d0d2dfb5452451b58bfc01c5f7d93013e318a41b4d8a5c80871ffc827c04189ed4c56ff403af250f00d9d41db02e68fb79666d1e600737630aaf0276500e767f97876c25a232c476b95b81f059f4e8b31cf4923480f64a9dc7e0f3fe07273ec302cd452147bb49036e99628f4c78345b56ef8792fa748616a7e84b102e3e26e8f9c249ec032122fc4e4b90015ecd8a08bdb1723d0aba6535671ec79e690418e063880d63eeb5d841645882f2aba52a1bcc3af95616c203dca7972b39be48f46ec320508a387fdbcb00d4ccca23869357fd9247c5efe24256f6e3e06e21b8c9440f368fd83a7e0f9830d0c373ea86e05234611aaa0b9d0335fd8c55d666dc7e332919e1a787fd90d5d4e481fc6c1b025fe0af3775862df213b25041e72484b83b10585dae08159c0d54f3a34e97c37570c2095abe0182dbbad1aeedd1ebac9821768e3d87bf458dd063cef45935433cacf70bdb734b444e417eb4e4a2e6b245522588ed726203114e9400149b94b6b9726eee10099a6ac3116fceb4d23705597a39561097fab796450431b738f05fdd4633f3a2016a85d3ecb80eb811688ad94b9865dd61034c72b7096c7db0fccf1002e562c04af0fa7cd23df81663098b1d04aeb92b3cfea896b721e77fb7537e0f8d710abdf2c61adb31f096a45c0c301843469fe4f64b821bb3e810aac57ef0aaeced7d2ef7bca0e45f8d060a0491f52fb876b25fbef5f724aa0b9c9f4223376bcca20f30278c83719ab2ff4c9dd7d80b8371065664aa192f02d36fe8cf1d52ca8a773890fda53bb2e62efa2776f1675452e5adfc246fb4b8b257e7ddcc662894e2a95b94cda25a56b07b50063f47279a9942fdda1d15bac0dd79cd8be45c8138db4b6b69f479def5f02e5688330d6f401b1fe79a09f58ffdb70d1521502fe8630c1d17933e4519aa9c3c2771975ef758b504052f3e593a4a51364e7424385b5404b30903626f7dff7b181ecd02953248de08b4242618ab47c36f4ab48e92ec5c704302a3f5e64aa4d0cf98cae11ca7f8c746046cb165464cd96e9b829999e6221b4e4df31334f6b07cb3af28878919d94f138f6872bf8d4e0ec9ece5d60698c0b5efa0b09e2d0cef948f1f98fe9523707ef2e096cece7c9bfa1e513ea7ff781198cb32317ce1de22e967cd289f138aea8ff57ace76161e6e39132b4a72dfe767a9ba3292be435d9929dbbc11f4a88966e9df0351bb6422299d698f03ca6472361967aa4997a8e614f8ce2f0425f31e9ebca76af1cf94a15c3299e88f9b1e803b097eb963cbdd43e973b6a07d4d5f8a940cbca115aa2db17bc03f820e4216e3d1b28e00bc2d8f21c40091ada87c59318c4c6d39e1b9e64cca6c083cd0d93a4406172f6cf44593e5e7001307127b89eaeddf56e138ec6a9618740a6baef894e912babaca4ced16ce5557bfe227a4fff6f568e2186ece0ab35854136f5377401f4413df0e176c13b88a01eb3b449381f1a662a0f3aea045f631186c75ab9203de12d68b9dd7fd8b6c7898ac5f654443977c2c757c5faff07ba631957a78d904cee44519eaf3e904b9b79d07a409ef55de1d4a8b6f4b4d90aba2d52c5d492dcdacfe7c1d7c2732e133ca20b7685607e6ec071e094eeb7e1daf6a20093e422a2e590337fe56579170616ab8ca09316eeba6661b0447d095a839fa0ec786a61527dcb9010d2e9795a369169ddaf11aee0c141e5acf61a3c162c21f52de3c66eea9ab5a33d2b58d8444050abf0c316053224e3b07f8c0da694d8f002e9d8199094506a3c004ba4cfec1f17011bc1daedd3362f4dc2d112f27eb22e06b23d6c25434ba44dc5be9a694b2d4385a8eb41a2feb8bbfad6eaa7ae499f772b74d1d9ea86043308386c6216d8724a538546f0abc79c3baea92125b0bc675ed85e2a79a2a449b72864ea12db62ee5ffc8d528b22462940e4a992f95224b1fa095d7182d5728fa34a879e6029dd3095b6bbf12dc4be21cacb7415b7599df50078d24fdc815f30f4e82354cff96a9ddad0103624d90fd42205b94543c2d0fc49f08514f131e20af1e0e601bc3233714a0c88b3efdfb547a7ba03e57e59d8174c1a066cd372b2fafa33da972041a75d2a1eb4bfb3dc3f7c0f1ad87303b2c96efd13eea6daebe14878f9d3f8741ccbf22fbfea843377eac2dc9b9645c05cf2726a3ef1953c4ae8a3c48c8124ee02b13c7487b833cec1f3d40a125513320b9d38e7bc486acf13ad16fdbd33913fb5886ee35e2fd229f58958e312286acb13b3f65cb6390fa224e013bd0e5fa904f6a4d35ffd17bab3ddc16a6c759505f0439fcb1134f3a8730f3a3cf0564da43323eab33dcaec864fb7bffce5b15cc663c4ad775a42f0538fcb88eac6b3881f1ea264d2d0f2f78e77d19e745467b433a9b580cad28426c4f5a4fbe9bf246b873cab1693bd64e49be860a693aa60d78195ff9bd65e95a4924c53d9797c618e99bc71ce433b116b244e209d17313c56e15888c9cc84cf59a7c4e4490fc99302939bb68eaabf80797de2db28714409f06797ab9e995a23e13629c706ebe67ad8924a08ee681c3c27967bfd8bd64a8c8b9d00155dcbc48d1fefcde5c35060faa64350fca2bfb56659f046f7c0c1aa244e4b781d80c275601814acfd2d3c57b0b8a2e8e981785bf2414556d532035ea8e0b822851cff0765a77592bf1b272cb2f13e8b424cdd894a53b06736b52e901d9fd1a31558ebf5947f4af16755c7e4549631555ce7e9e83b1e6c582cb0550c13ab2d4dfd5d15b38939d2d7fe2daf24a9240996e18344b96d2d555c9c75b7062c0de2dd0080b54de22cf879371086ec87502f2140c198215b05ab62d418849f79537311bc8bb4858b4aeed9947594339de13828f9ceed8d3d418ae268f2ebbabe24ba36817ff6a75d5145c6a0bf24d6c44ee166c60262e10a5c81bde03d77688c324e46bc0fb4ad03cf5889a74e38c4bbc99083cbda048d7b1454008f14d5277e0d621cbcbd6132240e6f10ff09717300d31d615e69a2e5998a4a941cba471a96554c122accbe8a1a00fb9ffe6e55b877781d09df7224bcb11058d722231f3cefd12cc5614b697b253ecc477989c507235b780b76dc0078eecbae0a9ac370a5a35af700e097c9a45f977904b33b8f17f39b5f80775c58f1f8a2463a76af8dde000835276ca46c32564cc6f66e91f4b42b0815e8ca139872e27ad3b30a53677607aa965a686e112331370c1544221a9d609a275164624d7dc73149f2b5cc94bda670f769fe35f4f585ed33ab188aa024a05ee254aaa644156fb25a43b00f5d8285576a1a6534f274c6d0f8a8b93bca10fc409d5607235b2bc2c0e1af030c78529cc37dacaa9175d86658105cdae738ab86e059940a3126deede7c4e409ca32fd4f8dd33c021d5f68a98751bc723b6a3bc1db58445b6b5ea0b1311d82d0dda91b974ad9cfc37815ef019b3eeccdb90c45c9f748a8de474c8c89e0f1520ea46ff001945cd3dac33547dde45e1f46243153492aa26d778b85541c1b139509e198f8b483e3cf2fae3a45b9efbbb6ed76cab71f41ed95da67ee5ae94b1b4237a28d81973a252c8234e51f4b7f3438759a60e8329b3f69eda0280bbc0637cd0c95b0314c3d4bf83f0d2589312f2d4707bffdb47d87289b867dbff842a089196a134dc6ddd25f28787fe959a8be30604cf7f7c39098c133fc719e896342d5fee538c592bcd58b979bdc52c71aa587382db92fc3d5122ef8412574e00815f9fd113023a33cab918b70517108c283ebcb56e2c681b6438d189e43bdf69cd0802654c844767e93730bbc0ebf1f8e84d13cab94086ac5210436d9c914a543fa419c8ac32e198421489c0408d8d1ba9d3b8ca7c44c220d4307634a9179a3e5a7b4d2d1bc71a98bd9f5291691986aee467d08bca90b2eb0cb4e7ad017640d9cd161845c3b267e0768b9aa784adebc6c4f017e11cc58f68be4bad7e091705ada69bb93823d75282e88ef7c3fc4915d2e75a15b0d6a145bde9f5910f0cee0df8ce8686ff019ce7b97be9835d9358a5ddd6c2773a258fc16b561a1dcdc22767da4d8c0c48608f61dc45cb01d79cca8341e1f81a2409f97acc80ba050ff1ee9232890d2e9654f5975d13bfefdac44fce0eadc40a44a2de4d2d56b35c38dcd56d1d94625bab2bf7402db26c40b770fbe528b56792431a819565935bd01e9eb9d897e107cb594f291959066445d3e57367a84eefafd0adb19e446b31754c033c68fb2240d9632a9919eb6f6cb622f2b85926dbe16af3aad5be443b14320259b0b740f60ae9f42e5029e4e0f50533ded757ff9572bef1ce2946d360c36912a012698db8d994e8b583ec5be62e9bd6323f074fedc1536716a9c86f23fa4d1491132122f330436b7cb71d075674bafe37a897c72b013a901d8c66b8b6377edac3e86bbee1487ba70c2e739f1066cb5901247cd4fe4b1f00afad70818e999810f56c35b855855b2b0ba171a8d09671bb90cc9122c2993337884f0d42ef9996a1cc962da1cd88af61a28bf2b8f3ec7bcd92d767e54503d8b9906e50fd4f3ec3e6bd1b0b5a706413d8f64aa1ad38b2692336d06d01dd1339ea96aea49fe13629107d0532944e5e7144e30f092a7ca508714dfc383a5a63bdd2049d6a6245f821ebc9603c85d21a8d7514a3c8671893df5e406c379d3d7477b8b7c6f6aa7d4b3681f5e9766c3ecba4fe51f13088a604d1abf6e64eb016aca4f387f4589e8876d4ffecd37e94534c7933e1950dc3d4281781fe934c95118642f91741006d9296ea68060e304d8753a7c7a21516d1303731bc2bfb479a46620fe7027c72550c733807975a0f749c7a186d81961575f59c81510a6f3f388259bcb5469a5ab667bc7c814756873eee7311fea39d167c8682ffcea0d9da71e9ee73339037ed6139d10e7ac886e0fad3372eb963433b79a8762b1ae94b097b1fb2e419f26e4cf9a75c1c65f46167a27db1a3c9d818e0323dd4cb52112fec06fd313dc7e57d380234a3efad4df90f93181dec7eb6e9d9bd79c4ef5388012e8fb2ea13ca3c05ad8e92b2e457af5d63bae5b719d05575eb926a496100c6cb34864f1d46f5e5b2ea94e99ca65e292bf1ae1b9e5eb9ac8d60d05a6f315e02ea9ee88a3265ac9d5a7004389fa8543c84e4821cc23cbd2a86fa9e51d621be62e10c95141d41fd0d136b876ec217054de4bf52d7eb212d4141acf82d3c26587a11c5744fbd2c1ef941a2a9a6bb8ca7bee376555f4842edf356ecf88418ba04e037204e4f62672c52399ff8a1ff93fa72f118609c598acd379f9f50b5e817f0dd0b4e3258084aa563098c085f6dcca7212419f14ff8a26d3cd7f586986db7488aafac647743cea9210d107c0feb73b0bbc959b43bf0531a0d1798f4fd9583820c37130a69810717890fbdae0a51b3c18d92be25ca681e069fb0abc03d29ba0415c495abe0f14c4e417c6f2eb7f88f2f6a699beef1a8554da8080222b56745a1c2a189af33791a04ef3e347543851004d0fba4d9423a7024d5f45062190d01a0c0b2517b32caf83d435176551eee697a42fffcb346ecd108d874e9bed2ffc935dca9ac848dec9fddd24e1f477226bbe103075a08670637652b036e5d37971f7fcac2ee0a19521226d05e5ecd78d15d6f5fb6ab3a5fcf89ed32aaa7bd1fdb75c4c4bd93fc1d15d8d556a92b958208bd1cab5f90289ef7f68f546b673eec0c0052e96b288fd59d98550727b2433c744d4a039658e349007809ac5b82c4f66fc20642a52292d7137bfda2a347a9b254aaaae4b83764e2528979eacb249fd25ca655dc239c3b1bf01f795ea012ef4c58d935c127ad46b18b1d49cda3ce921a4a53ece5ed081a59b701141a17dc5650bd5d8d7b4ebe2928f0951c5ecae71220e84d246f7bdb1c424c0070e928a5a07bf02fe3c89181051def82bb3a8145acc27e28ae67aeeddf5f73bfed468855e620e1c0283b5b1fa7a05db7ceac60423bcc773850ac686ba1d4106b179207776f50d9fb67290341275905fdbc7c54a8e5f308e35bbea2b6acdc4c8e88496a7a613d45e6f4067316f98cc879b1ea0c30f3eda12800e990810e1c0f978b8270c9422bc32ad66230697b09ce989fe895730821792b50bcbd0db77f59c192768e57dba66caf31402913493d52683030f1a009c0e5484ed4f2f5b188b4ce7e0658cc5611812261900b6da30985007bb3bc7c5270a49e5321ecb4fa39f6aa74727df5eacb9d7aa692f4c8e1b4b1ff71f94e57b26c6a31dc032af8ec3e4123704cf388f95a99c75cdec139c98841301b61ab7b686a8c51fc7f8dd9d3778ee873cc05eeabe4002a967cf4494ebc20622c2f65b0ef48773517a87e6962b8775fc45469a4644d535b4c4a4b9353f8198ee224536c4b87033f4a51018a18ec9a7c7c9f598370cabac28238d82f211ac346c7ff3e186b9bf5cc09c689c2c044e55a598d6a9b35420f83e3c69511bbfd860b8b78bf26106728b890a2031c2aa96dc7bde5a759e068edd315647cf0056b5a5c2d965dd605a41c9ca89b2527812162cf038812fc033b9b92593b297b6612fcdb70199ebd3e516f56dcb8f001cbc77684be370c7a99691d47b33f8681dffb2eb3ef27d2fa7ea7583d5f58df32b9d78c4f719bcecae1cbf6699938827919f1d8a212510407255c2522123e790afe3ca6e3360aa4afddfe21e17df5b2458a6b0abc33a432778ab40f1827ffeb8d84c450439c0db0de767ada0c47d8039394f24c8d4d7970c0d29688e690392590444ae0e5eb462596a19f7b3734be6bdc748f865b0df7d3b8603f048f24641eaaea39ebf92139b26b1fa7b410a38f4220be0294c17c32500f3018d1a49bc474672edfe8181ebe154f84903282112ba902d9081d0cb701bc04390081e6255ce27331bd10c158dff4b4b468206052ef0f7a443dedb55850f21c2fddee774f45502070398c359d5b765a667dffe1a07c82da99bce3dc8eae2b9311a461766589d8cd55b33cebbf4e9105a85e770239bdc6013f371fe587b0414eb681ec52a516db47a2ded75f867ed57f9a137e286d6c64107d660440c85123ab80091985cfad5f007beb8c13c5304b854bbefd049a3408bf387cc03b9b0912070cee95338f63a2686d79ece0c085031a92e15003b8e1738274b49139d7e51ba8f63694960b3466c9ac4dd7c7b25db335f1b7ba3ddf30d37cb887afa0fb53da6e9af03bdef036275c19d6947d172ec4f284ddcc3784a127e13fd5853999fdebd826fb4e79e8cfbb1266ae9c2035572acb8a93db30049270dc0f7287893c992ee7cb22fd3949218be989e44f58975b24e7f376d3b9f603bea7b33ab511b5f44c22fa8954ef7a6413ef8a1b4ab49f53934d5b2a5fc33b44942be0cd37dc8ed39d504ef905eca1175fd1cafc894b672054e22a55c694837287b5b62ddb92b81c2593271d881e5b2198fa3a9f17c7a7763313e032d20deb61f988c90f8e3ad3b9cc6ee7b4ca6ce94e779cf03c1f961b3fd5f2348e424c2df1abe0e3ff64c772da0d3c0ca1e5d59897052f3735a22736cb7f382b0a9a2eb11280ca81bdfdef27d48330c4e3a627514c9fc69c405ae55bb21aca7ab04102c4b2abd4010f06df2ba983839b7fae82ad048f70209b39a3297d5a4af4dfa2a90ddc30436b43c6d603f3ca787b44adc7566497c59ae84200ede333ec2cd7665a254acc64e981af8d24886f8595d513dda2be22b1c656addaf9b7fe693cf28cccf914a2c0b633a6e48c20ba6fcdcb8e99bca995a3c60b50e48d45d9b7c9b61cbbbfe2878de25a10959e5d957d1af615d2f189d286990f53cd405873792c2c62e33dd1db43bb9bdcb02db369db92c27b9a50aa224f50754aaec67401a6078f3b5ce4e46bbf16eefb537a0b5152206d04629186bcbdfbc1339cbea91442dd84da5167d4074cb906cbdb4e8a804e291d1106801ebb0d1463f9364f0bbc1c29f0d744a4af5f2d410e4b022966e756e9ede8460eff83f83f62d46a6eb37c5c0cdf07c4183424b927e62b913ae0d7af2844bed9717a7c21f9a6a311871d564ed8f70934b43af15191efdac7e4bac09e8dfde0656eacb4839a31f9b6bd8b0d1a1a1caa0c920566c0fdd656fb61779d5450a29e5d4be5709d5ab7005b5fdc6b35159055d3818b5917053093ebff5413a97defe9dca2aee583a7a5800db2c0119520b5c305d73549e7ce2e0ceddfb6a993ae808603d072a983cb7bc068df7432a8518760a5882773823909984c7d11e4deada42c2c7b09100677aaa389ea93dcd006a8890004e15d84bd142817a1b848af87cd648242814e5b7b816382760a7815393ddfaf76e1f77658fadcbbffbf4b86f440a6892645bb947fec0cb1842ae053892aa40fb597ab230336de576113caec03608bd963ac92a3dab448c0492caa6ef665b9f15145f21773d3c7cc492cbc02a4974a0dc4a780091474eb125fc2d993d78132ded0085152c7fba1bc0328848cdb376a591b5a55194cb429af3fc24d34dc0a3c79a6b55f5c8c565d4120eb3ec536a9af31f1a7d88b581319ea78b541265ed5ddbd9f90679b32122dc03b49285032a03dddfd9fbb58e3b4ffe356981fe0a7f9dc1016c099bede4dec0ce4519792dcb9a7a29086cfeef911ffedf94ff8eb8c7881c38f36fe95d0155f1894368c206b7b905067b0bd1f8e174e34a1f8e71601ae7df04878b750c930590275dfcb18dfae6f8cb07933f79170a87162c8fa22121d322ec4c3a0ed089fef9c39034d0a399bbfaf4983f85b01fb7a92ef5e853bff6419ddbe518e6ce8aac12d805f95b11eee912e8b52eed771c170d1f59e3a08d8099dac5734edf9b16bb28c50d3967a36a9d6d730dc6781d3babd7b33f99004ed5c3b09a4fd924c00454024dd7f9180f9cf395fa30ca0d4d6e251102882289429a54a9aac007e27718a755807631e0d24b060c4a749b6d135c80c5799f93cd95fe025bf719d3f35aa0e751bae11eb0aa13493512e03d2f51619a775010cfe3e8c8b21f1e8a8581a36c4c935cd159a293ac6af0870e5fa82b61a97041280d7b5dfb4f0944efa7f39b556beff66f7bb57e9ec1bb694b1e94c1167a314877f7d7c964e71d4e3cfbd61e8bfbd505aa550ddeeb5463a884b5cc66ab0e9f2f66e2b985bdb39fb9a136981538c2d3a8e52dfe7f0aa879a6f3e93745f06c6dfd150acf2df2b4e0c9912d5abad9d1b4d87a0ef65bdba9aeb65ee1b335f3b6fba35ee0ace755adb662979e53fc59085844cc45240f763f25cf07369422b913893cbb1560f0bc85555af4e2ed5627ea4314d5c4279b311bf9496f439cb8971512cc471ece0b27b105dd1b0c754548017d0c549bfbd8893a8444896a9b9eeeb09acab215c748a5e34ba1deb91f4047dc5b5984a1ad83855ac38aaba3d70d65d8d40375190158a082bdb4f9c32c65d1fca6c2829060f7b47fe263d88b9cc6eadf4ded9c39c0ca03d889ffe97e8b1373c8cbc8e0d0c48c98069c6c4dcfc8a4b79a1e5938b9878b54174d2a1cd5132e75c56be2f042f812e28d17ca0578ea926539c905896ab5ff3fe57aaa9dd693521ea0b6c563a389d3dd6ef32db5e29c957a2db42c0878a00dbc67978003242a968fc63793f68b5818009c60fffcc413148fcea776f2b54485185a4639a637d596cb0a6deb26c2cf437bd8f963aa856f73530be99d9fa9111a5a5ff964cc4a29c9b1afaec3285efb312e7a61fa9ab60e222927f1378e99afa8a070d2d7ec24b7c6495f103ab5d121a6cc724d903cd413a0feb44ffad227a433331bc7ce6aab215475a55e299c3ce37e440af083173689c18c42dfac757b0bbbe213460dffc209cfcf68785020c97d37048a335b74974c1143ce0dad90f07715cc6ec978ed81f78aab3032cbe89f7b83f6b009b88c0ae865f10ec5aa1ddf027b4adca94747d927e39abf014f5add9aae36292c3ee04ee7ff588c29fe5ced190895f3bfa26326adac2ed3e7a932b1b05711eafbff4d5d76b7ae80b12ee49f6ced57a1b2fd200cd9d68608db8ae6349e3b88e678cf2803879893ab22c450991cdf8dd1a7f3b506e1a686459daf2e46e174d5579b235157b8b177b4d08c0fecb66d175a4ce42968d2314ccd77c63085c80c134d6a62af7c38a26938d722cd23fecf00f97b5845373811d2eecad5a3bd852911afd932da5c3e74ed9cc8e8bf2b15d4f2488de883b056be15e5c49fadc1103feaf3314d37f8465f7ed7d6bc98885a3bed8f805951d27200e510ab3d958ff6cb635afb7e4d70b1c01f3b373dfa34e8544f249f7115ab30631940158935860fd6b007d3aad3457b0fdca60e6b41494def747e455284b2bdb65291074e9eb9a559b0b15b2975f8cd541b6084bcece3c98b4ed42c9275b9101d28500fda5232a91d3ac72e4dad1b234b92642072d19866f23b664d788384a02c99b8b736fd4e010c71d4932c85228bb55d298738e8197822c69ae42a11c718ffc1ce827ccca3a1773dcfe3767d9097f3b08237b9f30d68a10dff4a5cc58e4682517de4983d1eae2fbadf74b94683dc41ca54fa71791fa9dff86b9035fe0903607fc05c3b318a61f5014cdf86b5be83a5870264552cd80468faf91bb70291abe0c165e03aa7e008b19004ed873ed65abdbd23b01f2d4e34cdcc3d4a103b66fe7e380f8d66224ffa995b13cc67d39757d7859a6c9f216649c7f72e52b91563457861ad6c60662e4d38ccc26bf67d7dc0df1d133977448e53ed7c89381d6be95da3fe58446a4a7ae6b57fc8aa48974bee6b8d6c9ea0466ceaa79e54b1bae89cafa7ff1b8042af76f1e8364e9caa1e02f7c59d7b3ea879c7b647ce716b617bfb651c7dc65658140d4e8c0171e2bc8718f1ad632ebd8c52b9f32b95375903451d777bdf42476b63ee0d6d0954c59d3e03966b078084ecb4c902135d395bf2fa032182efa17780e9249f55384acb50b5bf0c8d1d5b112140d001d9cd3a334826a7fdc825b6c1e0e27d426f926efa7a8766d5fe150fe56e4785802f3cb284f12751dff2196b9b25e2e926de16b96c05b01c2e6a9ce7bd6f0234848978d1c7165254ab107c717bdff916a2a4a01b3c49dc54916dc49153c6a5c3d7f3696cebdf8166aa3b80cee5d35ae92945cf979390c352f5f4ebb3e9930f2f43ae11c7ea0bbf66802f2ad87bceef6431d3e050674a9552cc807f7f056c2156b128fbfa92cb0877d8b923e87668f6523621ed2039487c5eb78e92d88559fdf9a496cb99a52dc225a083a80b5750bac86816b764e5a91af58baad6ed3e7dbf40c3d566a15f15b2160c8f625354b239d98596fea32c3410ac10d01b34d19148b6d63d07fa815c4fa59e4a308800f6144b6ca0f1d9eb50bcab48f01ca3664fdd5ed793c5a1e67653317176abbd1ee0e7dc8ca0b077e894c88c91ea12d19635be7a3f582ff102da870a4d52567ff14df20f9528a637811fb9c7e4e726f2b46c4952f0b94172a713d6e8294f7ebb7ffd33bd398c7cfb4bae82d6e3854f6d8fb9ecc9a671f4410bd5b0ffcfac2d4e06dc092165b34c6454808e8e23fddd1cd595ba340db4551ef87b692d886843fcccc1387c3986958d04b93d1cdebf9fd71abf1672c6023c58e82b278356dbf4619786f8974401a795ce1b3009107990ef9f77b130a5ea8262b0da8720780988d2330767a311b5d3e2a59b8c812465b2138bcea25e420abb6e1ff03b42122c75c71c37034476eedc1203d5ca0097e708f809470a6a78ebb16db9ad9599417835466543f85d796ef11c6f8dca057d7857992efe791fc7f07fdb39847f180638c4bb1c30973eb28c16638339b83a30524d9be14eb665add623155be00c6a1772d8f80ef45a4fea1227c3ebb897800fa4255212e6e493e3ee985affc3d7fd855c8ac2af97e61f6046b747223c762f2bc9e70cf86ab8748d251400560e440307c7d01b685268ea2e549514a3c8ef557cb27fc6751a31979c2dd1458b0d40dbb5668d4c7f89dbc42ad6e4a5288e6b5a4210c23fcd7f50ee3949c2a264f6572d780093a7e4b2091312b8a5f945eba47fe3ae8d56c6b269cdb20c87f62532641435eff48aa98bd26d356d59204f3350d88fe48b8c4dc3d5cbcc96ac4c02f751ca27bea51dd30e4fd8855d0b8f84ca52c0cf3614bf3c87050294282f64906170364a177430f20c42c88f96a9c039784e48fd0148a5ece5d97360ea319934579f57a7cf781f1ff43cbe79096b3e5849eca3d87c438ec714968a8d2b40ed9189fff6a3f694542a9977845da0bd94836b1b1a4ec7f658a2ed2e51414775cb41d2f35f8bc95e85f94bc8c3dd4b48a0eb1a49795b9e8d45f21ecf61123818403fbf55ce6b945172ad54c5d9322dfbd5c1d9ac317a42d8e7c6978401bdb73cca54baef4229d0fb0b6a59903efcae2603965c53ffab7aff8741dd7db14b9fc0f262fda608619ad2fee09f84e5c858e365462a8923d9f7d7ac7527af24f68ae6771fb4646b4b4d43efaeeb265e119c9866d8e6e8d4588246576ebee311543e8dd7b7749b2a5f3d97e27063cffde0b3024de6772253fae55198172c30adbfe9620ccbc85ec92854f08c6097d13cf772bdb7618d9d5a48f2c9787a5a6f396469f1a3ffc13a35ec1758575960fbb386d0b8c0a4cd1361922e88865a0db3fbc83417e97177a33f9fce66ba36d65b83c63a470135f5e1ae768628c747426e7ffb56090ca103b36b2b1f17fea7449065a96f9786a89c512bc78671a5195ba82996ca7cf5815a6754d048d23cf4cca8dcf8f5b58a8043e6694b27cc9ee78f53c762ee5757320786d52023cea10475a415f48550781afba56b25af082b83874255fc806b4fc537f538ce1c03c91c44634950a5ed2717cb3a679d644cc9e34ef9508beedac3521da1385a5357c0cf2fb268849c92a61e1ee8287969ea412826272f32d9f6e7871a9bc5ecdbe368a688ac155d1c0e643b33850a60d44aa577adad2556aafa47354741312a72bb6fcba3a3729ff0319f67441ad862867a4c5417b3df6c5532e75c9471aabb615320490bde9c2f2195d5411e12592191bf9264ac68e5cbd285717332ee1b6533aa6383d2bfea71e1472fe3b1883ff38d02ea4d1d83a862f00e53827545496801c4d65e60edd7ac488b77c1178cdbb15030f895f60355f526399a495e4a8686db2db87b98766ed168de91e84ee508d63b5e61018d9c6ebe19f3a2a2e3748f64e49c48f8d18db68ac75d055e5e19eba5d06b232e4945e94a119413b6227f42d37dba751bc0eaa9f908f9e1ccd611e86963e2e91c1b4d09af5d33a172b481067c7850f00e9b22d95a4ba70589089d3bbe872948f1f564165b4e77655e6f3b64f67b83b7c3f78f0204d05de93f76b5aefd825f8bcb989c73d46b443b4024490d7be6f24d8463c0bca75d1a22f38546f5ef13b03f530c154e3888edbe3dedf5ada5a39a1307caa501522a0f5d977928301f14b59b231f30b638bfa7dbc0e44e7f5643e6d63daa52c352d82ffa70e97e978a6acbae13d3c0b907173ff965297434a767415b2a6a5812b1f691e5ae829b19ccd62d14781fc5f0e7ee995a9bce5ced44f382cb9293d7b6a90c0937256955ede43e4c737c4b8d260369f1cf56d04d73a0db5483579642d915f0d1d41e35c970ddb91bcc1abfe9b7be062625dd8fbb8397e5189a57a5fa5336725a8e0648fbb537267a15fb0a1102b3ae1f60d4db985c1b38451ac8efddcdd81e455892b0586350092257b0604a0256c8ae06b4e2b49660b2a3d5ba6bd618601a5a4ccf16b1ec8ff2ca4b9fad6160dd17d1647705d8bba73054272dafe1bf0e206167802b715e465eb4650a4feb4906a9c59115f159967a7f6071fa2e88cde24d1645acf0672a73e8110ce9cc36d2aa662a89c78a8cd919e19535e22663a5d1a65631b8b043ae3ca192ec5180eda89c79329699252f5d6cf8a80a2292367a796ba9c3fb70e924c76c2cf405a670a3411d58c58690145e033f92c73201f6f0897ffa37d5036f7053c59179ae0b44df20a2a4dcc7f3e5548f9e03477835a6ede8666273948f6430fa4e2a489fa40fe9b88ba8b624f16ec75cf9c8749625be68d89327cc9c3a7534cd1e075d7788d326da9e2600de8710238783cafb50e69c5107cc53d76d5fa7c0605b663ebd3dc0ea278cfd9e9c20c563c3a4af2c8efa5f6ae24f3324f2eca68f0408bd297f991e79dff885135482cc526b68103b19c86eee25805c0fae0e5e12620dc2fd6370bee303cc9cca9232017267fee2eb010fe9e0fbb9a48bd53a5db690c4eb05257a66dc11b23764cd19cdf171ef25dd3a9e8803f544e032502d2bfd156c962b7365c94b6bc479a588f13326b393c8cd4ee3bb62740fe800719ec86ec0a39aa1e19936a1a117734180e9f04be98f7610e79661555fe863bb1bbc83e3456116eb5b94dd2bc6ec2ad24a685bad2d485655b9c03e4e13254a36cc33104f73df9112ef41293036a941d0bbc42fa61f3f7754834c7bd75558029389187bc56ae32d57cc138542d6e950e8ed4c041958741189d1affad15c8c637e63f7d39a2e9d4f8f7897c0a5a53c1958ca5900652e04b84998fea5dc15cfd6f959d697e4c1da02bbf25446e5667156c77509626ce7ef9feef39a4e2aecf2edf91522d7e5ba1f268fdc72b8ecac2adf59268e569abf8100e2b2c4b2ced90c47d0479b6d63e8db588c54dce95c3155ce21ffc49d278a5c8ec87a5ddaa6ed7bedaccd8bd829b31f2f10e33d890939bf7fb061491205dfcb0c0dee967b29fcce67399683680c80741bf99a660b22bba7101b275bd775a7a2d1fef5e5622dee19811a25ce138a6d2eac3a50608f76b7672d0dd8a792cfb88e3dbaaa0028ea8a917c516456ac1f5ad18020f5c4207bcfccc8355fc6fb823173dd6a3bfbc40286e1bc0bc4aaf9a3771cbb92a31b344fb58cf6aa8a00cf086cd63d1e65320a062ea572572ac7baad79f2c58add702caf8898380a82a414b8553cfc31c393df37a60793acf1a8c519452a4708694a16983d5565f73cb7568a231efd9383a997da11c3c9638ba4fa9cb98a92c6c901d0c8696edd0e6f3a701d2f3d311faf231952d98be8e1ddcae2bf18d6f318151f63fd468b76cdf754ce0a42094a3caafa72022b909a68de73246bd43e9b3fabde2d7ecfc545d49729b5894699431dab2383cf47f6b13f6e784544559798f95b8c7d57c6da7e8ee979982b4955bc1abd6cfb19ed9915399f5dd1f13271deb15246c5327012dc43c6d15b16fdcb775e1f07602779350f171749418148a9d50734b6b0f30b0e849d9e7da28bc61be072b3349bbc1502f5f1f2ec3b16ee81b7aaf05f251fbc41649036642425965f3cf3fc45c609849f15afae98157c9758bbeca70f052eb2274c30b2dfe8d6879ec8c15f78ed1f193faabb964cf312a35ed15dc595178cb13d7973e14adc68c8841b50d811521efed6a3a661a901f023c161414737f538d02dbbb62ea0c636be5e2878cdf697f6086817834b72b28cc0c03a687cf0953e7c9319773071856d140e232b042d549a7e10de2c9da5635a75e9bf00d08e0fb3dce009219a59652b9a0cbfe04c5f70b1984f95c90002c5c77a07f8355bf9456508dfdc8e11c43720f4c22716c571f286057145014d07024df83e462037ebe6adb51ab8103e90e80cfb18e0b1140fad8b463d36f440f4e9b8a90b8c09ab75d9d58a622d97a8e9b0623bb49f52e0e14c11e6dc4e6329eb6ab35057c1a36ccda2a422d5f9a44f69209fdb1c95bf01768231de5756aa2d91fe33e7d0c90186123380a95b0a4388e7df66ffb5e71c618322178aae2128e14f8e9fe1dca19d32e0f40f9d84fd8d207991f445a163dc3f43d7a1b8442ac5d5313bffbd8674ee3f8940498b589ef6402b1d5507d1cb4618930c8ad726fc6d54cdafd948815fd5b45bb70ba618db6195bae5297e8a7d23a0c69337ee49c1a1fe0814057dd0038ec8cb1ba19fb185896d70030f7a3c372f9d4ff5df40a0650e6e46cf6bcf8170b9bdddbc3b485e720e7f333a33db7a5256ddf2cc80589765b9d01cd4f78a3146107edaa3d853c3441172502c207fedd690402a4e20bef41d0ce7d20214cf575b71a255501c5ea7bd0e3ccdcb70774ae840ac4348356bdbdade6e811b46a1e8e22d90bdf1ddfe4ed505e46621740834c01d6839813c78f3c5b22e23850772ae3e82ab7e56e4c2a0f9182bbcf77b63af07cfce46d3da4f05a3dc5855d796624bdc57943cd22259ee1b25ff12c649677c1e4f2dcaa3aaa4a0c7dee2e897f170d247985fda6e9ae9f488ee1c01bf07ea89895524b633419a9da8f33269bc7212199de7f450d5960a815e8608c5de9ba81faf1106589404fdc2d2e3a386d8c8ea22f8e6085284eaa90d1c6328d48e8b0516a0a4f94e458e97900db9eb42d6b5b926735707f9492ff316235886dfc0d7a8b9dba277daba71afdc69f02322af072237c737dbf6c28735e12271b63e7b0e0d59ef86d3910060f49456b075a76ed8b5d6b981ce8c8d076ec11fffed2574dd8e53f8442b10f01a966b6739bcf4c75dc4bcbebea47838888f17fad9f8a128a5961eb0c3cac88c67d775d190295715168df6ac5d637646e1de52a549e4391186412f9298aff4da86438f3a179f46287f5ee12d21ab175b47adc1b701b77262dd196ee206fa959bc63050dd2601f6c47c9f56eda436b5835f1c3021ea94731fcb0954fdec8fd49eecdf322849da64ed47a7de19b49888b0c175fd158c18efc6b9dcf6bac1019fa26491c1aa24a0468049d09b3c56a45dfd5c2e6fd43776e6dd3711436eea12b86a924ea3944dc426e8ce23217696f6498cbaf9933d7dad7a18faaa18de2252e99945db6c4edd7bb81314b434a2807519e831a4f1c9ca8be126a48623fe3b91534ac4d53a6f9a3ad6d33d3f010247ef6639327e0399263d9a434e03c0a3146149a3204f0f61504f1dd6d97afa3149f95ddcacab84541a77349e7cd16b32a46c42298b08cce7e07150b40b8ee702d7823e7212967e93ed07bcad679e6869298d7bdd1e9846cde2a9f87274a2c485927e5b6009b1b7e8a8e7802caaf63a7147cc922d5b9f85d492a4ef23f434028ca3aa2335904f3dd86c2bfd2532b0dfbf1804e38fab200e8fdfef4df83e0f3e9ae032c2c495b969924b373fd524696f5df8efe78ee2776285cdd0d362911869abb79ac6e63aba01edcaee7e50bdf9f06ad1299bcc45f6c7981e7d37970c0f67dbba0d6c6de2b59535324b892d5ff625307c604be9bb0f97ebf5b402f3afd01bf23bc0cb8ad717e67872f84df8cf35fca1320ca763ee742af3e1d39904ae738f5e14edc5cded325376f16a340460311b54d1528b61868a9ea6ae03b26a93f3523c4b197fe8f33dadff4bc17c30b50cb04d5c59afc8d23c54e9f00933604b564aa98eb871ed6e577c262675724645fbe95051a9702c51cbe29a115c07b80a488a43420b92c1471d503deddd765ae8149174604e723ed69f5b659d0ebfa0f146264b1242898daf66fdcec7e06f450ee8041023b799aa96d9bfddd736d5398b9ac25e8d89d081673f106fa950f3566f4d093a10c93e653b444258aa9e71be7f85e0d3daa730a39e3ed372bb24cc1b0931be8fbbf5c36045e7f305a002d3db3c0f6f3103cbfb6ac0de9993674b3f3b84f76583ebe094b13834567159aede7f91ed6cb8dcd106c2fee0c15d736d12ea58de0906534170b0e43d9d7d0aa4011a29f6da5f57be8a2a0839812278862abb9232f2fb1e81d539d6553e060906433341be2af65b8f53100d8c51012a448bdd64bd7540d494f0a633564f0e47d28ef83ff2e5d6c0de274dbe24cd7aabbaa4ece6c4d054b652f67d3c64f0a1ee8e9bd33887099005aa09e2d1de5128d4263879903971e6919078c51ba590a61d14b9a23bf23529adb77d0dabfd758bc7283fad58b05f6c994b1fc35a7bda34d0049965635c1abd92ef2e0b36b2f9f0cf67658e777258724bb4937cff84d32fdd7f2ad8f9023df61f8cc9e7766d141102b7162197498f5521c17401bb88e425805bd5383e409ec298290f03ce428f004586cab0adbb180553f24b00fef5a437972ea7f02e10bd4c3421044a9ddd450196c6f483e4afc63191695095a4479151d02e8c0d44574a6310788504c4ebfcac5b34e18f45d430c2cf2a9df1c6a8d1af1532782f1ae059f40f05c6426440f975e044f09be867f23ccf35e4b6564117b334136537d05d3554095b90fc9a8a2d0b442aa6828fa1bf69f7eed3998b5238cb4c9c7083ce9f6a1f750e21aad051b7e4e5c4580e3267f06691feaa2638c08deec36c4ff3787eedd17470f6c824e00675ea67319ea5b99655bd35138579363f0afbaf50264055cbc14feeaa0dcccd1a5b2a8d50fb784a5c82b5c6e47e6ecb99bf09be79817bd0b37aedafb565ed2af301faa14849db53324e022aeebf94ae5691467e16e70c7c55f1c85481d039eb439fd874539d43f203b0f7f912f86c293e946f5fd4da8c0c91ce6db63e4929790aca7907534de367e0eb713f3a7c67264012ff22255c8f4d26135c464a9159c788aec210ef857001e3745ceeaf4c64919aa0f99cc48b6e4f3547e010c8eb6848a3f684c0972af94696b8ee24c6e531446887a738e19416ed0fcb6eadec4209b5eb931c94427cbc1537b9b608c84a9854eefbfd69311ea9a70c40440b9065b0ffc1cf0163668c323d887a9ce5159ca2abdc0f07b3b1173b535d26b40e43acde97672b91b60a74be9e735eb3a61d0b6ed9f37d4903bee231895c438acb0986b5dc972fba716c1c765b6fb1dc19383f7afc93a9bc54670707854af9420a17febba176e418eef485ae01fa6e18b5875dea10b2468599c37a6fa252999dfcb74651e34464574acfc31f27067761accd5d133a807d965a1223da7a7c9b2c093d27095b33fbdb3d68d246f7649aec93c4d9b7ebc70853335c3aac89b97d8e026b3523604f5ea00fe85e4d2c5f4bcf82608989e7b9467bf5ef30e7576725c9639475b1cefed5fbf86c887912ccaed532cb3c765ad57a26d6a8661ee2ea21f295464f9f72b284866d2270227aeb5ddf010cb91882fd31dec07731d4a5fbf48b732e7d378f05093f334bb2081c469866a5f78bc9f524ba51d26f3d8f3e89a9f458cc8ca27da182e2139544e0505a2da6bcd07183f368a209f8a45f1d3568270d8c798fe7431c0c114e8a97113fee3a29ba7ed11aa53fa0408df70d345fb8c1f2a4b774c4066191566472d741fc107ff977f284c22c046ebe3474dbe0bd81cfce35332b4dd4cd0a496d7e4ae766c1e3defe91cf629bb6c36de8bc586c9118d9e45a5939474d7d5970b9f242e5550e672b4de665d7992deb33d8b2d5bf398078ef72adf2d07df6372f74cdbff1a2e367de452c3c1045940458e9adb3bfec9cbf38e3ff7abb93b3c16a697895561aac0b61519f4273e24eceb705d22a46d9886bed0b5e0cd2e418090e299fd134c26d0285bade0db4b38f743d4464810bef3a3706029d9714a545497bb0754afb4d44b6663bb7a3b383d7b4d219da586c7cd7d444a86a9b0d01e644fc8cc0e84aa409ce6c9201fda2144c20b19f68867748cd6fb9ce3762fe324023afae2639180404b26028de6584d7fe7ba4106eace0395375422ed06e7ee321cf9fcff233e5390b8bcf410bd441230d7b03bbb07e165f9f3ebd27899c1db209bc7d2d40fd7e2d319a3b75de76f599b1b59237d92e5b779cef517dd24bcfcf58fc2deeabc57cc1856fe5a6f55dca244c1296e1f6300540adc2a1f21dfd6deb8e90bd8a2bc6e6d6839f96005b4aeeb14c4714d8393d771eec3dbcb2290ac8c504aa65c9f4639523a92e2db27a6e482bdb5f5fa4789af8d0633ed7503f37e8b252db3e539f4f58d655904d456bbff4b32f4932fd4c36c53794e026d8300ea9882ab864c28610552319bf80b3c8bb09d850d3f9c46105a43bf15f485852169c7507e48e4aa35e5b969fa1205ecafab31795260dba30747db9423da5856543aac820dc0c327670f909e64a433a8a8155c0874ea90591adf28c575a7eec0dda18ad1553391b5709d08b0f07983caf0e0cbb631fdea1a43124fc717b3c2063508790ff274ce91e9a10a7a41ffb48bd770c93f129b7e76bb3d609196288fbccc696cd3e9fb51875ff612ba02a54bbff5a04b006f002e52976fd9ed61fb00308f191c4e9ec3b6f71b00ce0f51b0d22d6c37a84c424d6748307b7b4ce9e01ff457c3425cd570412c8a522e4a2e35d404ed505ffff28fdacfb2f6dddf8c52ea76c2fef9e212c00cd1f8557c35817ee38ec10ce1c2ce8105d07b6e500977ce8f7791a11bcbf3b6a118df7b106ee8e45ce35d2f86e5675127c2d682840e50bbb8937bb81076ff3c1bc2d4b9e84ac12f718022fb4e840d59b6b3eb420f03c8f8deec92fe0505cc8507e5109d1de23fb5d00f82730a15099dcb8ecdd0e33acab40e43bc7ede76c44c56d138b988f86e97a6fa057c58357e390519b41cdbf443a834af38245fcdd798048b67cae38698bb40c73e2071017e86e7914fab08f676c89f27348c198ddd2527d36e00506e9cca7bc76412a2b917e2e7efe752a2b23a60c16cd7a15c63031ea1a2c8d0baeba9c090e79c601904fb406cf1d7e9ef710a68eaa615058f40a64cc1c48cae3c8d4d76c4d8bd8f14e1a8b31e88a68e44cbe0c4534261ed96251b7def17f29753cf6510e48d9016c32debfe7e0d6b40341e92842cd4d7a8805e902dcdcfa065b389b9a73f7f1527ceb9e92ac19873e9c67cdd3c3e77fb9298d0389c719856c2c50e969f6cc1f1bdb3ea058e3f39568c1abe4c98efd9e43c6aa7123d2ff4cf7e5427355ead660134617b7177591023659a064f8d72f5e32ea10000ce920248b4298bf39130873c246582ab907b1a144f6779a0deb74e1cfc53c7fcfef39e11af114cf865f318780e7473b6275fdd2f2387ed9884d2e211ad4595a530d16648e3efcc68269cabc56f6cc113ddecba78ce9bc39d579039894ace17e40741ec8886fe26c6de4442f619133d6a5a637d2084c124230d01607ef1010a07db8550152553e2f70ed0418453f341f2fd1ece800ac6442bfd4cf424b6f9c49ed8618be4769a3c0e68c4d074baabb7f79156155a05201cda7fdaef20adc1fda0241df287528fefb867477f766d0d957a90aed684f3f7314d3a6e0d30cc7f24ff6590c32ab1b206cc9c26fcafd6f391b303ed85bd42a6aa1bdbd65d4ed118cf50e83e5f1746ff57e7ef398cf88dd18f0087104dc718f85a7339c5e04c11f8206a64ff315f5df60ef932ea0e71794b5a0e18dd00bfdc27502aec94cbdc958403837e96d8151614f29ac890bba7d6e5c657d8a7f5fc4fa0816f160bce24b646e23ac13f7ebca6c0242323b198884b0bb9da0ea1e55bd8d10e0fe7b01debc31691b777db158d4610985c44a0c3790d3110d7ecb454bd0a3d91d53be32e94f5e6ba5a83cb3d24263b6cf5a3ad0d887d15332343df599f494f09f4ccd02b83a7abf7d332c88716c920b6c2799a671f1134a0fd764ef983ad78a0af7876cbc9a43a385e3ce5df13b0fc991e6c4342adba6338fdaf0185edc8b909b7e7207a184435bc48ee748c0a464553166e1c4e3795be364210216348f1d6916345c85a779bd034576c895b63c38a2232947dd2890441f941030baa6f56154a83f179242212609a1d971e37b7068765adb9ecc47519a9834382ac6b785494824c45c64301284808a0250db7555b1531c8806cf73c39a9b26f98fe175a05f8c63bff781dbc6403a13c0d771cf8cdc7d1f8adf724499485a8bd75153eaf35ca3dea3a09c57fb50cd8433e750d45394b6b48e6ddb2d1e8fc10facf8ebe2e219d0f4d5da9f8659b10af538292e0cfd4f195630948f6bddee17da1a17189b5efaadd35d03270a08de08603d2259eef28980eca947a26d889309d017f2b54ba718bedd422dadf33ddc024af94412d9258a02c4d2b4df5c746e9511b0f7031069513682a46220dc91e8aceb7d1b21114fbe9aa3809cc78abcbe89453ff7144cdfeb6faefae6c4f06949499f9598a29099ecf8c80861e8ce6247bcb108a7efeef168c74a7426182490f60323dc24690cb8fb2fa7d3ba4da7cef6f5f94a66f457d30dcce253b053530d7249c8c435fa74fec6107660a3feb52df1f9ccba6e7f23278acd8b11e08025414ac50970c2d8d63ed139558bf7bba3b968cfe87389081222e598b6964602194877f3802e46f6f77d2491757f8e253686afcdcc984316f8848e5b2aa262433cb9f7c6a8544a7863f5ea97d8795b5ca5eb201e5593ed5789451db94e4b15ea824f633b7c052daadb0a190c76ed4ca9ec946678ef36bc3cb4fc96b079ea4ec97cd3f0e2e17bdf5da5cb49df59e9c02ebee396327094b4c3e311639aecb21fec025054add7ddbc35c9fa1e36ab9049f74ee94ca38bcbe1bc9c83c1c631cbd9f29e4c4916ba8695b24f30452b9dfddf53c79f686fcc08c5ba637dafd9ce76704693e4bf297cb93d3ffd0e9f46b3ddd5b2b872a4904b363f5458c5f4ae92c8db50967b91302c8c5a49f2eb7bb13a4d65423f69e2d1b2ef7680010fb47a51713c1ec274e5b885afce1b6aa27bfad5bcf98e7bd2cf36644820afa57b576e93d0dc3405d420ff45d9c01cf3012747bca33f3c1b63311c91987c1e0d9858d0fb2023c71f4230720ede8ca06150f18df5a4e54657d705373334a703c703bd5f5382e5f78cea9b13f9ea22b9f9b4d5925fad6885e92cb60169fc3165b0d823e64ce27766933e5a4fb2fc672666ef6dffb8d7cfa742486fa99a29f29d4e34c878574be474bcb8ef94398c9bbaa0a621c5124d77c30f6763c3becaf901a67e7b800bf03b55cd0eaf8022f38d37d6c4a275ada413eff60c16d6a62d065d426134cdf33a5184a7f87ab8f49c891870a7ee4e1f21755a32afcd61a07df8f4d96f6d9cebf3ce841d8af6f508b961b3a7df8d888c0372bcf220824262bd1c7852b5338c383e68a53b1369a8357fefcc17ba79f90bbb2da14212edec482bd1e6b92f464d388c5ba3d08329684254f44cf399f148c40eaf96b07b14eec535e5843010ff555a1ab1ec1182de23e3153ee7511bbd32c46d603692ff73344b5dedb77ed30a4d894324033300d02a5a735ec11a136c44058e00c0dbe5503c2fb61ca470363306ef8795f63eaef9bd70965ea0f67196b201ffdb874c4f63b0b25a9d16674e9a8535525dba6aa387846e68d6c1cb594db7804c03cfef4b8a3d3d49d177c34aa720ebb3633f4c8915b3313a67d03e11e48e176b4d4d0a1650b025223ec7ced2355bcc3ad345fc4397ba0fd7da7275b84baef3456c5ed016b6f31bc5146f53b70c714bd4d12f99bbc2e6b01d0b99d0f2dffd3bf965a9921a3bcb9b420276979f892b074820420e2fce4867111d29ecdddc1f41eb9524adaef94a0cf64fd485f9a534d884c4f9e3cd49c1c557cb253e1e03e97c0db6890124ba1bf40d2d33ba8031d098c2b173f8b581d7d2f34bc367c94c2008b21d38d78880712d14906736cfcaf36f44c79ff45f5cd659d2ff19209bc8d6d957f1178fa2117ea8babb4edbf0d4adfb23a4f795a0028149548593bea0cdfcaca97af6b5acae93bc849c07f95198845c2f3cb253f6712bdf83a64d333eefe1e9b834e5bfcc492abf1562e6c7e2a7a78b08793274437c94e5895b94348be2a821e44666ef8dae7a89af7fc277891da4815b7d0db8d184c889ea8032988e7265e35824c616e48c11fb7110206789e2f1d04ee43e2490b85c0c3e174fdb99580eb8ff68dc65946a28aaa26ec2e0fd82058e3e84c17b804a7d03e8a05aee3e460a946863ed5aa4c51fa9b7dab02159b0985fda4aa30596081899b4fce84a987018fb3612c6225669b55d9c71fa325acf9ecd2631a26e83913081f28c5e2f90fcf98c1f6fd103ce9abf6c2aeb59c951f9a8e42e2dbcb3df2bd856e14afca8ef15dfadc07bddfa5e561b9b3d53e755f501d99613e578144fd95c9174e67baa87e20528d7247bc75d575642acf4a80309326c3384bef8c1c8ad1f0f301975b32f2efabf88a350d1de8492930c346415a65ce5fccd04bcf71d61a144c74ebba2636568e269e40129496f09c32eaa2dc7a505fc4442521a71719de440ae41305ee525edd0a45184f704b07fd9afc91fb95e097e30e68a9652798d572e83253473c1980a90aa97135f15c747cf156769a2abc7693f228247b66b025fa9c10dc00214a271ef95ef0b16c1948d578effa6eff60a163d7189c9ddf56cc24435e7244a35f70f481930bbc7a1e7ec3a5e4a891dcd4eb5a83245faca6f90e6f1291ca37f4fc2f78e825b4d26f9b1d5c077a4b1a9916941dab3a473fd4cee4e125565321c88398ad6a3f844af6ea2e373cedd7b63a1ccb8929d0107adddbc7967cdaa39f3c1c088e235c62e74871e3f4127597655b66b13bdcbfb54a32c3bf8369b0f494a7396552ee0fd363ab7a23f06bcbd7b200d113c942c937a9dd2433e828fe71df5c40203f5ea12970efd7441f62f6e4cfc7ea8106d4059a8dd9f20345cb4c96248bb1b410520383ba34541003a3ee05ff224a6369f1d0ec5262cd66fc858a94cc7e8cecfed72a8bc8d237138b2cb71b1e8f60366d48cef2f2e8443bf01f0848b8a01d692232920f23202b8bfb0903e29844753d54d8978dd353ae40279129128ad96c54dc67d5b41207d33791a3b00f7c792bcf581717f64a421c936aabf9883d7b54d7008857a14870e931f22be546ec06b49b67dbb81d9ffeae11725051c249ecc180872981f581df76b1fae0f96209225a9e3bff8fdf2da502fda01b2de4de391d317eed72d017f03cc3dbb7414ce7c9f3569982477d582192bd49d25509cb92b727e50a5f8b03cc50660664edfe287ddda8e08f9cb71a6891a62b1267951db146b558079289d8d198eba9a9b370e4c0a20c6a0c47b9c0f3888de86d18e031479908c35cb64045dc8fe4458960e9cad7eb6f9dfc398a5326a7395ae1884373b0899a66a11370f8fcd610e6dd0afae21be715d7a029c4108c270bd76c361a629c3884406a26656897be405b062a1dec27d05ebda5f7b4756ef6d59e88de501363d47769692334675d9cbc4fee8e841aeee00f65255d258f0f9fce6987f5c572f296ee8fbbc12aa56c3f09bafff035c813e64e33ff93fbb865f978ee9d1b346b15b98c9c4c30b90e2002f4bd185df9067ba8082460f8fe38d7276ea68c8a50d97f6ea9bc28e8f4d6e926f5ef1108c6538d7e70eddade76569019b64d6d6c752c67fe3f9f169d9fbb01e4801656a12acf0f70b139f1fdc97a060d600007f98cc245c9e423eae2161a27abc7f22ac3d39f4e242e1ae1ee0e4b1a537df427a9f51937c0d1a98165e02c446ae451faedb9aff4751f96b824a11abe3dd8a49c5bdb75d810c1968984afb4237ffd8d1232ffd819ff9453c0774e4c28387c7fa16bdfdce7fddac2b9e7c54ceb20ce005bd6b86563f9fcc33dc0c73156f7c4030d944407d84a79e2d5ea178df01fe92c6dfa7d708d883142efa0aeeee3bc8eec8cbf8e47a157160e3e9429e25767af106f6f253110253a990e753efe1bca42d792d78721188a7569d8ed721efba16b011a8da4b7389303aac88440f74663d05cbe32977c25b61394e2f11ed965b36c809b7448c94f9bced1d34f7efe112495b02cfb0983869b16aeb9bcb32536bf5401da070b3b5e727a18570969d7789c5dd3971c4132d23d2355018c7a3bb688139a779f17d23a21947420102c8a57e1e82ed86adeab869b681c0967ddc9ff1fdf4cb6857a2e7c77c5b5f5af8688b2681fbd75b45314baf27c26aff8db02debfe1ecea0bcc0219cc19a587dbe029bb526df96b7b7c58ad6d3f40285835cbe15e357ad24849e6eaa862dac643822d4e927d34fbb549626e4e4394a7457800d2dfe520e499e14862375fcaa2b63bb3f705601ca7738bdb484c506ab0f3414a3a019904d5dc1d2b7f9a5552f57956c838766866dde8c4f65b9846699922c96ba5edc1304b69711fcb32a13b468cc91c4d32be43034888f7e6efa771a2bf69b27fc35e9b87db2c0cd056c2ec6066546e5700c8c4c55d3efbddb347f1e91184cb7c5ecd5fe450d9027b167aa6200c33ccd9ffce82647b382ef17350e9ca34857b0c5004b042a7f7b63b0d0d2265995178ec2ac384b53ba62c621ac7915bc5b9b92ec086239601ff836b9406ebe9e2942d3d1d0108e56bf67b1bbf00bf2d051e3e1f2d4d89a05cdecd935f0df1b8fd94e65a1770404b5a9c40925e20b16818e0e6255db6b021b6904447f1b7ee386d0abf1d8aadf96a5f04d5640fa5cd97c7c1072afda3a94a2cdcbb2471d03b6a67b1861bf2f6d38f20ebb44abe2509391ddb48094d2e46031f43269ccdd1ec7b7ede13077a00cae9a80d7386a1bf7c1b09c2c3d39b28dab4a0b2023524efc5178a7c0f617932602404ba581269920fb91aba695e77a99464ddedb55fd0f752b73db34adef6d41d6c30de74a92e697591453872764eab886b9e245cf0412f285e76a0787fdf3c3515092076532ef53003334072486ccd7ed3de6836ebd4c7bf69ce73becc2d3660335001bfb03a2b97467b536f1747ab4bc1b43c95164d3e4ef80779fb961ab9f9f4b51358e2ecb3e5356ba66b588362790b42ef43500abe3124443dc41dfc2e231fef8cef4de7e183de9e4ae5816569feba984e6e50858ada335c69fcc1618e85da0471cb2379eeaebc5dcc2097ba9809b176942d6c47e5292d54e1bd0c1e8d9b476ba797ccf3c12945db1aac55b96fb3eb61c5cbf19db904251250245c31ce81632a38a25df259ccf7ffab02e316e542ca9a6ea98952373ce70ce679a7f749597a17ed76f941ec8dfb1fca658130606d2f3565c5e627f45981859c7619c99c5c4b67f83c144c1cefae5257fc941add5f6b952291f9f847c518afc7fcd3ff97a769c2141b74ac90c72fa2593e591c33733c4bebe73f991e0e787a24a6a41cab7b5ade36ba9ac7ef04f9e1041550d08fd2bf2f6da74470352f39a811ac1cf9dd198f9f848ae979d8e6fd8af98959092a0ad26100360447dd95d66ce15108fe744b0a7b2670ec88e0a70460c47df9d4a52154532472099cf0423a53a0a7445570983493d62b98c0b245432ac9807145b88f57e7aabb6b05ebe7687195e7a30956f9ccf4b43e6da18fc48657e0717079c669d4b0471eda08e0c74abe4dae02e741f14aad2585aa0625634a08851304fcaec1e43c2d3e8b1091341f80e76eed4201d13a841e12d5f5df53f9ffeb3565a431d449f1f8fbeef56db7f36716ab6425072299b1a1ab5dbca794d3e7e1ccf99b97065ab0f307397e6ab4d0b76ae4be5aa348f53d7368d08febff689df2726abcf254f445946f8066403fb78a5ce627c2ccc84442461556430f319e801882d9f63041d989c418c6788e57a17aa721449ddb9af99ef78137ce675bde9e5c64350f410913410c4ce2c43f807dd7e93611214d6f4e8377ef0e1c4dbf2c13175c4372d2f2414f668ea836dbc25ce537d00b97470cc4d7c32904365b11950f0ba7516ea23787e1cd84d2c6fbd80d5a428a8b7bdd45b26c5c682e1aa6913e5bbf983ea7f87539530460a74444dadfbaf071ee0842c288ea0a3477792a61e603fdef8d54be1167bdcfa1568e06f0e2ec90613aaaa063ac2dab067a4606f9c2a46dc927500c392816f44fb5dc4848244ce70a59c9c7337cb1cd9944230ba7d412af74d03f8d0843705eace265fe9b598acbfbbbf0cca1ad9d12041cb4c9f90e36e78ff521f68a4c38c71b5d474bcf3f55b00d6e885485ac09acaaf3f297353eb58292332d3521af17afa772ec5e62d160a1326c717443799eb4c7d553cabc657273480b078e49a2b174adbe678ffe40d105410c14e7ff6e42ebd6355ca2587066e7fce3accce5412ba680c76937ca0d9ad7cd56fe66df2faf03e431efff0d0a128d614b024e9d5155dbb67f04cc53bbd9f69591e781b2789f7cba1d8193e6efb2c824812a21be10a5aab00d4d72c914daeec207c3dab2ac2ed92bfadeb1a356c632fad5c6203696d44410772cdf4d71df623c7edea2fc53577289f3f86ce2253deb0dc756426cee1045fbb75e148ffbf01355f450a9c6f01db9e209caeb58f4b059c48af89d264d5f3e9bcd2bc278a2400f7c62c2f340cc590d91ff715389026a84af6ab63af3df3fe3ac6a74d97ab05accfd3600bdc5a036953b81f5aceddb5ac0acadb74793b769e8f245fdaca1312d7256a25708f8f867774cafbf8e9d5e13426ae3bf2e02b1e9ecb904b1048ab6d3cbceca1877011ccd9a8477180153e659c28bb37631e49703216bef05627754f11ab879f6477595af4547a9ea6e28b094121c9bd5cfd2db9c43e234ffeb4a4117779277f34ec3c2b19031b447197dac42311624307e46a2118423f0d0cb836f927314fa9ef8aa9c93340380b112d438c881aaff2a77ebe3dfde4289d14921dc015ca4f99b9846293e697d8acfbc905377cf15a0e38de8df5a0fa4f51a49a3ac441883f61734f1c377828e78c44ba012ca6c12fdc9610d075124f667cbdcc1e6b3db2b6e2d7b45d4af31d3d074761505b9648ff7a67bf9da5fdf9fdc1bebcb9c548eb93529bccdb3cc6235536f26d4b3cb9f9d1c9a3b40fad517e3eb7a72f148610275ebdfaca666962743a494ed46748cb8afb1a06ef17245925e6931190e217acd0ed0bbdbdd369c5d3995abdfb2add00ec8785a36abe176828e25109bcba25b2d544fdf61352f9ee7f4e0a9accc55aa4d83825a71af21fc20717c0ee69adc38df392e062a82f288fd799dc26c04a4e632cfc0b6510a73b0cc15363bf4cead28c20da537a2272e3a260c94eb88239e19bcd014f55c721daf05f01800fdba8e408ecdb9ccbe3d7b62bf699b7fb12ce51b2c942eb3d0abaa15fc1f145f6e6ec78f420c69099f13987e81a41fcac028eba92d6c019bab6bdd73e27a8ef3f2fbd6774da81eeb83aca10f9647faf1a7abba41cbce171acc856ea2e730eadda6d1aa32521950d5d9020387f83e415f65e818722668d098a965b900d81a9fee21184e1000117bc9b14fde47def465fa2bb36748b1bf23d64660b1b35fc7ed583091526098ec9c854d97fccc1bbb06f6bcc2bd508a70835a91a23f458d0adb797c5770a34814e71955fc93a686fe9782955b7a3aeb4da76fd688f5828b61547700098283dc032b3c504199c58cfa5f0647cc4a48c8938c8b1b8b316f343a6afd00577c2d1b41f7498297eb9bca0a95c0e1c06064a5560f29f72f672e81b3a4fba0428ee3dc66d122c0c230d349239b988f11c90923e3e8743002ab5532d63824be1772406a15cb1c1d883e1c3a100713b7a2479efa7e52aed01ee8ab43e47ae0a97cd17d4ab658c1f0b7029d32b373ab0c1e6284e0d9adbdf2031d6f9ce93f51087a5f228403a2d198fda0c9dbf31c9ceec0df6c7e88120f18bd29bdc0a925e89279ad0116b6b2032a53be5e765856c773a0c40828f42132a8de2b5ee6e2f8df567e39f43424f3252fb5946feff2a198236833cfe29f4dea2498c25a8536e7d45046e3e21b6361589b4ee485cfc12c6c88f40e314b8683cdccb403b34a4529f915b5e188db44c2c56c6bc7b1eac3073b0a7ae9baa8fea85cb9c853d18614ce00b8b6d94714f5fadae0edabfbb13951bbf6cfe2d2565d7334f3dd65c3808d1b7de37163f70c7192abdbc21413844e0af4abe65f7838716d384bb0b39591d9dfcf6b1bd6daab14262091bd78227ccc4b2fe67e147c04a0658c5d65faf0b9874c1a4747abd9e5c50d139fb54d7cb8dc7ea0a02c82d13496d192e5086a1048803382fc7b67e814addff41c237a32ac9fd30cb1ac8ca90c76713a3ca365f18ec7aa9ced31ab33e69172d4ea43cc4e9a9e0ef2cc4de93c9bc6dc357a33c463939f23799153fd14f1649f3e85e50f03dce9f64b5f842a1b3c228043706ece6aa99cce840066337c622afc2f8a28af8a8d216a031865889952b3aa43c13da927e34f35852083c0d5b1cd52e73fc6319b2329bcf81f6781bf84b2233473789eb5d1ad4239bd039808957ccddebf0072ce3d9805849d7da89492334805d901660c8af62c0538fbde35c5a679ffdc6eadb4498ca06c45045a957f3032f50445681853cfcd413255e32f2945cd94d5a4dc0889814bacf0fb164e7f3135b8969f8643f1dabf909e88093d92945cb1a0428649e044d046e6bd0ebbc9d6e0ccec9fda02cc831d588b863ff0747aa577d8df30addcab966035aee607ece2c2e05f45fa6b80aa5323d684e5a02306ca0b255e92e79328188f087872f630c8284f7d91b8c1faa2736a9a856896cd0e3ee75c7e3ed7acf6a99ebd45e0f969722d963c9c383745ef4e0742e09ca1797e27e076481d050b6d643058565b609c48d0ab3af13f58f52c5f2d26ba84492f2ecb091da525bb37d915f5ccc0e4a154819517d180f43cd97c40893832f38b7c8ef8323838b9defd0836ee9bf15db884425215da2b126e856a4c4e52bc83564f872355e3b0f6db8679f87610f2616d72c1547202f26456f63cfb2ce36bef1413f30dbb0834c795aaec9be9f91de31be31d157ef59fe8552eae9a57eed8ac353068e025652c3da57ff10d6354152d37d918728eccfca49a53e006f18ff81e5949b6eb631f931cb526963f8486236882fa47df83a0ddf98a48bac221112649e3477172d0feb6aa8905a26f4e7d930b680ec07e4e8130dabfbfd617768236b756a5b98f2706bb41967dd52530355a28d28cc128a902700590aa11c450aed69c93b3118207c4e5f72d1ff7d6111aea0e42af9d2c0ea4a3b8828e8827554fb8b0a86e58458e57b83dfeb9a56d3022a913ee9bff6395f044fa01f23793e015931a30e2f4f320984c0b98e68054898f8bc4e28e17ada4fad5895d866b58eaf951bc13a0e9dd0cab239b523cc909abbe1e5af7e7040ff7959ac02d6cfb02b0deecc26e2f2527434b915bdc96b091ab0eda612c2a617eac043ace5530b0fadb21b7570ed294c39792aac32d443481cd4eb9d7ced1e07bff6604f0ff5d692347126d331f2e89d0abb7d7f99792f041bc27e8a544455c1d3f64cab8a31967938f6f58975d71089775d36edf27599216f1960420c8c9842ebbb74b5a1b649a5d88c513788d70f1400b706527722e1ecbe66cb1863e19b7081126c5080d03f73176996130043a97b5c7dc552dfe680d0146ed7c2deade536d9a74e69c9b58f0d07d8964c319e84babfdaa40d1b61669c19bfe7468e356d6de298c2792f043cc8ccf31ab3197ee9e4f597e0c061f5d9ab97797bb491d182767883581b2748a73f5aa68bf3968eac8f8a5732e349bb6a2bcab90582dc24986b03028f2ab29cdfba2ed82746cb26d0b9aca5a45eef86954ff1c286e3455e1eb862085218a74daae6cb741313fd446b74e542b9a667c1c245ee5ce923e53d912c2d9fba664002518be336525646368ca788a461a3e1e21adb49abe8cd9c44cf572b1ca74438681fa6325ba1ae0f87fa5ca510917ff5b9893f548c6df04cdc59d99f4b023ac5bd9001bb156975140640d36ff4d0973b7062a44dbae2029ccca5aa7149f9d9e02a60f2e38fa0ac75c1c7fc1bfff646ea8ee3e50107e7f65c7fcc73e4a18b158398d4a82ee211bcc8af271a9ddcbe4488cb27803043f2569b4fd227f9252f3ece02a77cf18875b79d17029f0b8fce4b9dc7b62a2411ef22bbd798b0bd3dc63c5e4c870052a5a9fc7547d483fa331331bcd01625e987dba8af2668e29414d8dcebb4ce853ca4e1c290841bd628296132252ac794d873877e9e72228b0e2fd3a392eaa6e53fb7eff5ca23e597737cde998705cf0cecde20c1ef59c688d63663a4303e47bdefbc8962473f7bda20d86ac7a49965c2fb507066c4c4f7893d0aa9da9c7e5f5fce836186f5482bff45276de1e1dda3484a7fd0ebb1e852319694f7450187d1c6b9d7ffc5ba2228da2f80a3d958564556a590650c2ee06635a3b046e6d2a955ab57eb30dcf776d2742d8d1f4823c6e137c4cccb70c4b21e70cfd6768242fae152342d9585d506fe20210307f1ce2674842b2c8b573d7c1c327aa20c574dcdb3db26fb3a2f37d9b790eb007f4f28008b00c6bb80a80788694551a043ef0992b21feb81b3a0de432da1194a6fe652ce0ad5dbf035739f87b72249efafa4d519c4a73bcfc04e2460986e04e0da4098de22f066118085d7f564d69820961b150c1067e578acb312b4d6523ac82fbb4e92d72a458f1ef347166fc6e7499643085c2ec47ba0929be564819d8ac8740d2fe0a312d14ad1a82632e28ad12dcf92e44640dfe62246e106a699a79ae378a9e8c0b9282192a0a91d363c7e9c8b3b4c67c7f73a40221ddbe197ebcaa3d3ebd042df7778daf38ef15f89c82e0314c64d3eba931d0d80d0a31ce965da413abdc8a22fa665dcf022f697dc4d980d39786dfb3c787e58036c4974ab727f3c1c3328ae00abc89cdf93e4c45fede34e636ef75a2aa45941b8d90dce6a4e80e295b6febb6acb9d8fb5a3acaa0e3762066670844be799e246a606d90893e3c8545ca580d8964e82ffd889d4fc08890edf63d99269c9ee1bacc48e6e952d9d20b01ae84f46ccb9b4700d9cac33b034679b4ab580d9ce4d43870e4c329d3fbf0bfb91a6f9aeef5621091d74f390d2a149b000941f134b7d6bd56dc95af52592728f74c22982028a5a6852e44b27a25992ecfccce3f280347c5142cd72aa649f921c12cb63becc1b9ccdf76d0a94b95539365639f38b2ac33f0c362529acb324af628b9fa87c809364e353c6a15fdbeeea736804106b3d9be4d5f335d61b47fb5db42d0b7e43b03ded903d4348ca4a2bfe3334106c8d0a0071b9bbddc36b6765149ba70a689902f4c89d5ead49e6ac9a91a89919c1c1268a34dd4c6240c678bd733ffc4ac2586786545301df0518ae2cb477b049210993cfeead1a5684e203e39f64ea969104d5dcca3ef274d556812bdb67c86054db0c2ef24a88fb42cbba265ae02db42a7e71e08ddc57235f44d41990c4cb30945261893ca7cbc4c7e0ada6a613ad0e2cf8837bd08cd277579da86ca63054fbb83fe7dab5f174e20dc03fff0ff61ad2dfd2e14af4dff0e74a136bbf85a897f9ed75ccf77f35c23e07ce64ea4b08668eace3cc0ddb4c7dd9ff98538a8f168bbeabf105913eb5a428dd547832b941856767b0f84d63fe183327b608a32f6aee4d3c5411d8c35351d95b224cdf0e83e03a1056ab04c0db14e4172c304011b0ddd98668132345dd3859e9c00d7b2e0c1fa9eef8ddfb3c0237a88bc67cc734c668c509f434dc5f336d9ee92b3c42fa7c81bcb266cc045deda10584ec92d44ae62d0dc85efe6f740916b4c14013fd1b8d9c668e96175e54a313a1b77a67d053b591cac9ad711a1a2b52865f1d3f3c6c8776c483fc2ff45de00b0de799b1735ef91c05c5ecd597941b893b3b1196cbf85852f6e0fec30a527b95daf2ce4865f6988c2ca9f6f641da47d424b2fbe62592679ed1ec9264650cfcaddefb6e1acab88577e51871a42b84c978bda01a3008b946a58aae5908fd23db73356fe2cbea564d3c67015839b2caad4019f1d7a7320f5c336c54732b718b3b4a0a6901a56e1845aadc3a56e39566d9c0da5994a9d6d7e7d648d67824a94c3317faa1818692868ac917c38f233cf70996949fec137d249ca6594accb6789da2d4c469ea6335fc933d7a9b799db4986c4b56b3676ec1690316f9863504802afdc90d66390d50f73f9adf42a6deed1c8a1e86aba43e5da39c8d7cde51600f6f610596aba995319f80c9c56865dd3eb7ba7d8db2949aaf6dffc936b53f06a38808a9e88d34af6e951901330657555a0b79fd1f100fb927df8155b13466db1531119f164110c669a2a641364c190f7948e022d7e963a2a3eb842037e0317f35ca56f166f33e00a287d4fb48b4c5c2c8929ce37c8fa006d8328b980f5c838f383fc31cf7256a7da07cd304c38cc05af2228f34a5be52d2d1c7aa0c339907eca54615ccce0ac01ff1a7165537d2ba15f5395aa245d17e039c6c67b61b51803ade96e11f98f0bedefdc732de306fcb40c2f0e86d541f565eec4c3f6cccb077e2f74fe5a2d374beafbb030a7ccd61532195d48fc920491a2d461b28c10ff76467679fd9d96c43d4d4a02cc5df954e8163ad937cc4dab750a0c87bbde9db53c9dee6ecc6bee2a6ccca569584482855c26d411509aeea54ed7f7e55307aad4683021dfbedc379d67fbc2997229ba5eccbe5bbcddd5b1d825c2efd99301bbccc85aefe16ad722b4d96be7bbb9c145774bcc259caa9ab98581cb111111cc89a62edb5a3014c99e038d7c81bb0cc128c9a71ea5e266075a16674600c2561e0a09c184d4dd128e13acef338f1eabdf66b01744f1f51c0ca7ada61530951618158f64dda9b3e0c9594af08d2557ca9f75c5f9ca042851f3611a59ca28050b79af5fd041c9633a9570d4ad75c809d874ea88f7dc634b498f288022da356b361f1c449f877efee351de388f4139ed7e13102040d5850cfe0f92312675a753d1e324b2240f1db1c70dba266120007a17eb82b1e4f2e4187ea4f4092014bd72c2fbb9d005efb18f8f1edc27f04495819f662e6a712ec2cab2b0b03571a98076c9503fc6bda8ca03761e2dee76d5255d66a586d5d33ce9aae9f92582f714ae8982dd5ec785de073383f726d8921da893475ef08f506783e696fbcfedf8988fe390ae602a508c4726917ddf2f95d8707faeaf56f4afddc20590379089185b25a0fec218d73af75213d042407e596787fbdf39bb887ef94f2b4ca338298fceccc97d90cb84edb05c09dc33799a74aa5dff7126b8dc3cd03b0c5b64d11b7de0a87bedbe1edb865cb79c46685da347c7615ceafc945cf57154143696298ca716cf46fff7213eecee1bae5dc52a8f07b7dc567eef020f20c7335b9d9ed751801b8d7997fd821069ca85f8e24fe3a1d11d89e4cd4d8de94c266ccabb60314521af21eebc57188a470b33ea665c6c8967e5de9a7de16c9180b9703a42b31fc8ecef1f96713581fb4d37d5f1a5154d25af97228bee418d3519dd2b809f82f46a82c7cc82f31839837e745cf3b6ce2d52874968f327aad9135ca3c8997ceeab66efa5669a0ef45dd3b010c5d2500c896e434f702c7b45faf6034f6495a2dac57cae3246ed6c132ebbe14464acd69c6a2e24d1d37a1cc98f7816a7ea878666a75d4fb0775d35ae8a65f32560ed1a75641ee31e79353d7a8608914803b073ca1588a264dadab2204c3fe58c96c77ffcc066b401d9b5340b4d734d955e7dcae313f61677281eaa7c1985c6b5ba2f680c747e7f486df9d3bf59cd0481253b991477013696ac347a56ea9b3679d301a663793d25613c0653c745a99d6ceec0d7a8459f8035d71b9d6faa690d7129691e38fc5047e5e200f816100623c42feb3c28c4f64ef6dd23f531818a0f5108c00d02852e15405dbad5470b4fbf7abebc5479cd3f3f689c28607978d620c035915f83d66e6c6f18a5fda176a40200816135d3ccc42061d78e87d99f4f108d5e40d00bdac2033ae02f11c6e8374876a161d10e065970ec95c2307a375f49f638bae1e8360e4d59703d902251480047b0116204303d17e958d020608623b90bdd6c651a5f992a386e9a1835b47aeb6ac62b871b0aeabe038444358f096b1047604e627e511c65621bc295608d7228cb93311e3fdf2fc356c15a0e616a5115dd306c4f2c342b83feba648c65bde9792dbe12bcc853f6bc567fd3a0fb1cca6f7c4292e2b4ac878458927119ca9a6f35800c94eca433fde2c80509274e1b4333fae695f41e25bc7d6b0fb85ac9eea2156eb2b2b8ff4bcd8291c964bb063f9584606d067da31a4a92eda51e2159f3e8edc21ca2637e8f9df2d588d892c8824f0f49597552b435c101c24554379350f74b4b2a66743cc5d11fa7a4a2eee9d1a87cca369066339275ac1b3e051a707b941fa890264494312776c39d6b724a06ea098c25c8e62a8cd77e9984979c8925fbcab3644f88b0161df5c71e37861a50bb53b0b16b0ad1ad89523ae63cf5937ed0603f7a9300bc5f6e0aa042a15fa3decfad5c251c8785fa4db8d76f625582646aeaa6e73819d92b58b2cf32afd9cab92505911e561f1ee7e96be7b198356c4c2a10bed852f001eedc781b56cfbf80db4f11a55160b9e97f785287b4c3405edbe41e467b66091bc8344c8e34af33d7d3b5e471567f16f303577c690e4bdc80179af39d0203e1359873c426dfdd5e9a8a776273f146fcdf8cb7929dbdb9dcbf983eddef493314236a45b402a4b87ca4c9b2aa16c7a9c8bb5a14b2b7edf6be073852008a4a5ad4b277eca28fc110c0007c9b5285d5aeac1502d35ae6cfed6c5f1a3b12c31bd8f89eecb46b90c9a0cffc2b07a4dfa28be6a2f1325945dc644ff6bcdf87b60080aba989a29ca614e95b92c73644aa8da4622b192c0ee6941865815232eb94d6a25f0a1ab421fcdd29654f9b7d4091274e56cb4e13dff6d30474e5400af9aeefdcc84f3924464fe2a3a60c56c7697f1397dd93a65dc2ba84038d5d66b4369075f4a0899165c671983017794aef823ecda87d52d956321f9d6c0f35561ea3e35d726f9e2deff7e739dc6f939a66567b742dc5e4bb9ea617eeff64536de53ddea3d24667f110a8c8b4f76e9b47b968ee120e5cc4bdcff88204653f34cbdbf85712dc98b1812c70aaeed8c5ddfde7a21ea6b3c950d88917630bb48dbd01539375c87de443982545a167461ce8e6b5a59e0b0ffd08ebfdab6b14241b790281ec81a448fbab9c69262e9670eec9134c13a0bb39557271272b79dc04eeb3c6305cbaf406f5de11e1abb7c3810f7e1105d2645aaf1f32f2841226672fefb177c9d2c5713892d5576a7b146cb0b2ede704bc379ea315395a21b6d3f75273274278cd69608a2f15071842aa975743929f6aadf6646356f7cab286348b2b6130a4db98630beff3e44693fab145c0fe9c5ff5657e403665e33508450561b8216fd9422ad2afc164ddbc0aebfcdd33315793932c171fd0af6a479a85fcde6c4d53d6cd66d979a0a38ef9d0ca220c33852cc22c79b68251326a70bf4dc1dbef0aba8836d09b4e66d1ea41a7ad7fa7778a35999face1e10bf412f06a9355f38bd7a60c9b0ec86c5bc0c76e841bb5672de04ae369b7a4a33007ccde286025ea2de3542d4a1a486dad92e1dca729fcbf0d11a1872eeeb8ae0d78ad4900402cdfb3a644e14ca7780deccd2916995281b5e54639df39dd0eddb227fdc36a16d26e5c2f882d705410903cf0f6feb2f89b5d642ab597a47a102bae42490eb9fb3116342febe95b18d5a6301df8b374b5c1df75afc5cfe3547d3247473c5d7b37418c7d5fa0db5ada39bebfaf645b0b0b5c63cb3a7c1678c8e935de8e728913fd81607f072321abd3944a02d40e130cbf720c6ad908ed9530ff588a7de133172153d3ac0f657d590bfcf1ed854950cf924c80b49b0711cca2fcc8a22270091c8572c78c33b90e6d8a7abca8d4510c4eb3623756e83b51d4cb26d1ed4c512d3846331cfbdb656dea005c45e84985567e3a0f2efc1f67df5d71a506c307601a9edff2ecd0f262a095f2d40dedf3672dd43d7653c13d31d0da78903ec1dd25ac2feae73722c72b7f04e295fbbd1a4d81aa873aff5648a682207cff62d47681f3e80862bcd87d98dae848a84ca9c7be8da4740979f9a3491ace85ded29f53915368855ee36b82beaded2e231972422016d794c95c7d1eae53a7ca56c68eed8a29adb82879819a3e2e516ce685a31c2f1c3ebd372d85ab7a0d703b8a57702750e2837d4dc6e1ea4923614a4ffa58eb937fcc02838914dd02372ceb88f198924ead9898820a92f4fce9e39b46058693bfd39ec2be91edfbd241328228ddf016d0e677a59ea42cfd7f700ca17edb15119643e0283cdfebb9355efd04a05c2a75dd133ee64e5177a711e79c1015bf2e7928644b912b66a8280fd83398e086ca2025511cbf4a9fba30843592c87bf23f48b70865fa8ade3ba6d86674e2e21131413c77e6b5dd44066f07a04f0123e0befc73ca409a21137942d50606c7076011ab018e14d5a407427456c8a7e06324659a453a412283f081e3094e020a61a302cd3bdc6dc8f9edaac17641f56adc1fd58747d1ae79d8175ebf6b6f6e13d4514e39f5cb4d12a71273e624c5b2fdad9615ea7db7a294e415f4eee85ef422c9f79ac47d9d22c8a4416669e4bd9959489de167268c357cab996b5fb37353408511e1aa938d53cea7ef73e6ab013fafc20c00d378c5517346dc7102ad3c6eab3db2dcccc843ccc5adfb67afc330024b958348cbdf959e306f5053173c143838bc72481928fa3ef509d4ce791f7f23f3e92e1bcd533918de7c1da07c7193539422a551f5d4726c9183c3dd12c07a847b000dc38d598018e85de8a4c5b491af1f665eeefe33274d1c3382e1b5ddc0d0c6ee08d2322e9221ef64cb7d7d0f31c4588bc2eda65380caf1ba05aaaaa9e575a50f4f9f3fc390b737a5771aeeb023bdced17d04aa057c43f301a5a7d722dd6b5de5474f5913ce035c9967e92356d2852803e282f31161121590a8ff605915a9668d1d3533d4e61934ac6169273b56785bc8d1563c758c04a84a99ed88727001a8af7fafd6f66f913e0f0e86bad70bf06916a391e41c73b62657d24a488ff3669636460be6389702e74936633beeebac9984057613a07918344dd516e2301bff90c2347bcb35bf870a58aa4386df46e792a7198fa25ec4c83432d7c23200c266bf179b2a2c97440deadcad358548573f60e47c85b769091a1e3ac607e4d7243187d9a92d89eb376cb43f65c9ab76190759ad7c2ad957ac4c4520e0baa599b6b53d3cf64c33deb49ba0a45f3f7dbb092a3012417cb95a1058d82fc623b10a71eb10551c4ed13c0ddbb8bead3b1997d70210e5f4b3ca6dbfc9724586ac56be70905e1b928ad8b54bf5994d575fce777433904c5a15c148b51ca95571966798b0bdba5aac1fd3dd7c8eb913a75104ec92914fe41a418d87adf90c1a4c2d5d0e5c1b490373c2d7d52cb17a4add180e55cce2f38b943702331defefc130c99d3b07897c00349ae0eea735dfd27de72b75afd15cd8033416205884630e4e761e6ecdc8dde2b1ac6c9d04967d61f423d5a0f1494b7dd0d3a74e9c73eb564347c467542c0c0660a953d733f134f3536a712bedb8d388cf4afe18c34ae7a6be7907cdddffbce8d0ea5717ebce8bfa263e355bb3cac2a394685c09096882d65eb511913c83d720766c8225cec78f9a15f79fc2acac7505af0b6336a6529f70ccf6a966c72c924acfddd9200f330f6484e4eb2ed86c546217889bd4f645f0bfb91ca711d4ba23d64d6c5b28cc66f8b07deebd6a77a602f556f32d6b845e4570700ad7621f96cb36f30f0ab3a56f4542d109baa712a2484dd73c844d469d6aa6f14402e5f63868d6d7afbed3c8df3420995a72b1ebfdb4eb9401273e533df18b2536a74e62db2450ca7697a76733cfcfc3a88aa4167030ba928a7ac0798d679a4cbcb69a45c8a60e1f718727ad1953b90c29adaea739097f4a5b7b8dd5fbe6bd94c5a2e69d917412df1e1713dc97fb968cfbb6d191abf3a2a0f98e71d654769c9d285da76e3b781af4881c0c0bb478f1dd43d9a989fdddc12e03b8c6b6522e137903dbaee41d4c2b4cf50a22baef9505d5caee754aeb5d9c4f574bf6ffb0886a489825c0305a4fe980dbbf24b82cbe9fcb13cb0d1c20907e8b5bcc47c7da9b68d176d0780a3ec67f5fb82061c0431b7648616988df3917aa2f4400886d504baeb3ed603f2b09c603a03f00055f5d33602cb80b0076ec404f4c3a94e874981a92255b19d8bcfc0c94b4e6f280bc49860d9dfa6bd2a97e8e3409395f1ef7d78a8ea7507907a892af7387c06afbfc9eb7999128ff111a68e0caeb85ce92f51d8c0e8d341d6fc508e489c2d2ebe95a6c8df69489ba9f39d2d022f028efc45e5a337cfe7ca6950e7d8da02bf8a04b44b2a4c7724f3a5ef36cb788c34e046ef6f12deecd43c56fe9751b19d400c9db1123ab86d42d28c325ef76c85f36f340ef9b59a0f3d49c004c12db062fa99b42dcf37e54f04765b89682d58e6a2ee56c2b0060e235f24dc90cff588ba95610a9629357c800dd8cad28deb67ab2db7cf7258b38f9c043cc7cf045318b5615f5f70278b70c86b761dc13a2d06a18fd86ce01cf0138b84f9fa2412973bc1d53aa5a9340a78791bb6d16e99ef48c3fc8c3394aab505c350da6dc22da0cef437bb1ee58edbc096077a6277857e2e090e37ada2ea970d2a7d65d081a513bb8bdf6ef06ce63d443a38d16f5280e496865b30c722b06f79a8b67074d4dd292529b31b5c1c7f0a5d26de924593bd024f1a46983851026a540f1eb2b075450689981ac9e618fe4cccdaa199525a222d3bec9b6a7f129f600d3e3459dda065c0ec04c267f15ff1016e71e1b4b446739e64c993939e061529094e37dd288201d62e9e1f59e08e7a8796ddad3f06f0174b875a292ac8f1c3d2388d4082293040a06ba01ffd9c9a9608bb0381ecb46acb6ad5d96b24a2629cc1968921a3d52499ac29ac0ae05e0f0dd42fc4a4c62d52589dca30044f2e4ed41acfaba4b481270b59a19bfc5ce608b8d23f7f9df48940abb411783fcc038f3c2a37aab83f40e2cafd8cd487b255626f34bb13a2f7c11cede16c38e946a221c912e1b2877885b5c34b9cee6e8cf47605b661ffc97a84f9aa51c2d145ff2f6650d735f43ea87a0e7323f1948ab3e82f3872bfad5c1197f607e5d9a88718148b20da7618f0cf252fd3d53c5ed6c0b081ae0621caf71389b340fa4c2d87d482ede0b819db134ac95e1f964dcce6834aa4e45292b78ffa2772f55e0ec67e21337b4595d1f4ea1b2abdf9f7892371004ad6a10466702716c901796415f3c845dc3cc6b8d3b669b126941f4c4117405cd7e7412b5d9513fe9ba02b3516f01b66779bca41e7d34420c384862020bb2cadd1ec5d44920fc3d45e8f58883289d38fe2b1f7d0ee3705fd164510e0540e9ddd5ec75dba50b1291084af89e1b466bffd2cda8964b0e0cef2e13657c9a450d801174679a51915f70206f9c6a4fb68366ba55f478b5bbbf34d374e5d597c8823f6d1b601af8bb694e3d1ab6be426962a38662985a2c13f3473354ac5702d91275bb9b7b15b6336906664d3324bba2d25a810be4a81e79fb6ee591ecf800913bcfc612319bdf96b52c9d07ea21b5aa3a88c3b8a4fe965a678e43f739fed72f4a676afb7125879b68fd09b26e29e9038acfcad058805855bc8c146c95bc6a5cca0fced2339a2e99c52d83c0fdb08c4ae8170ba3da01df39dce5a9ac2a8ee924586c480cd367e06f9bf26ba99162dd8ccbd6db1090b81adb0d433d5a23e056857aded32c0b24392e7281bf308f23ce9e7fab804796bcda5da6d7c5facc657bd6ec51a8bbb6a581052cd426c5dc382ccc4801e06eddeb96993f3726b3115e59e57288d6b3b7fd2cd2d3a9d83b14562fb948dfa22c354489614e42a5c1c2cc4916f995842422cf3b889ebbeedc2c7ea3437efc97d5b99a500e5f8b8419a4cc87940a145af85df3308da97cc09832fb5a3e68e8c13247f4714a7356b18d4eb9db5c0acc6f0bd2ac61dd8d6694c7bb3a80c13a469544026d091085b9ab26a7330f711636759c56a000a83bb4a9ad8eb73bd09b95dcfde221fa14712342d287cde42c849c6c9f0f6239ea7b3bf1ec9687b2ad2206dc7613fd949cabdf4aa4d3ddbec429a9dc4d21273b53ca519f2016907c11cf66701095831af77d56b4ed2b714efb8bccc15bfb23bc1d1b2292d2fef96408edae2214b1e7ddeeea3f2653fd05c640899114d742d72a4e4bfdcf569820376d4c205a78129303e6ce245c672ef7f3fd42f23509e3b5bf86a1bc614fd99bd45d44eb8dac73c06b020a1904e54e7aec967b71a649734e3b9597a8edf85abeaf6468919915ed7b1d08dfa4de5d2a2a1583df802aa5aef694eda02a1cd486e4a97e10f8ee98ec49c2a8220ccd58e3fdd94ac2c073be2a9c47921a6256a75e757fa722473bcf62f3e0a7fc36505dece0a11c6c5f8a2561f5b3e24b2027a9eb5b99fe6049c667b3f41202fe9e00b0da5cb6e647743a4db3f7e7ebf3f4daebb6aa02a524433420523b9b06d34e42a98fbe6807bebf7e1832899d8fb6838f6755bd2817570b4b6f6f4fc51b283c5228ea5fc467aac95634bc718a958e6529d5042765310a4aa4ec91107b59178903a2798abbf34b3e2267c513c906b9fae8fffd5b3611dc4f4f7ae2acc57d3601abb7924676fcda06b0d279991a84ab3cf7ace5c86b5d2365b3746c6262288d0f61f690a90459d268f3d2d6a2e19c4052e0d3539c84eb5aa6a9c4d332559371cba5a6b7b99d4c845fe48373368e2b0e4870ca9b42d19b704eb9a17e48e883905ef08933542886de0f9c4498fffcc31e019883feb7e0aaabce05d4e546b0317cfc1f5ccee7bfd0ce666370260e70a0103f3096d2e2eb2eee7a532ec75ec5a1ab2dc12143813c9b5e0962a4c0fb4786ce0db230061ec5a7de6e7dcf972519d1307bdfb793f2c4413b79a690ff4b92eced5cea5fa0a9b3d63af88548e18ab81fd65d79a65f4f9079fba26da73967580f7438a2f51a66f03f2b4b2d8ae40a2bf0cb1d8b451c0ad9c901fdf5de1f4f8f4a990977d0db13f85508811e0850feff2c15971f960385ef0a8e7f9f1a9e16d966184e47f9633a591dfa8195329b43969ed4f611a22625ee9cd860e2f4f299277479064894f4e5cd4924b8e6788570a2111934584ddeba1be4b615939da380c57d8858a3b9db5838059ef4d3e592615adaf05e230d053e5b94e7fc22ef37584d33bdcc3a86ee15564f71ee0a7bce5cbf98679809eebee4c4a8373c0b52f1fab96eaf6e8cd73fde6767f23ffe4f91f971095557a63d897686911f0a558b4531a243685358df090f9f4a7dd628c9b19c96dcd765355512705808520ae84dcea27cac0986812126bde58a1d6b69f1917d42d7155065ee5ec315be272008bb5faf03d995b3b687bca66953748394753ce8a4eacfb752d1d4e2b52baf280f0b3e3b2386566694016162fe8176b4ae49f64a69c29ab8b54c7071cbe8fd964fa341865df77f5a2109a264938ae9e9b8fb5add543939800ac0cf8459e448383ea572bb15bf96245a75eaf451e9674ea065db0af6bd152f2bca37b9f9ee95e2a131ab11149397c0fbb4922bd7a7e7063a9864283caf435f7bbbc3126621e1114c767dd1ea8fa1c044f898f17014b4184ba1c7409da68fadfd079fc7b766dc8738c83d94bc837151657fdf9115cb307890ed254cd1c28dc721d319cc593ced480a2073c880f8dd4f5276137706ca27963ad4c3ed111ccf34622f4781c478115871bfb2d2947ac29fd4031c854a6bebf331d22dbc5df94c34272ecd138010870b4e53c2b4c4f2ff9cc815092e72882877d5a838793cbb2321c882bfabfc49a4bee1e769610186237918ffc2ea2a3621f5841102f73785a5cc4eb395a4db16e5670ec8ad3fe6e65a0b06e47f1c54a962d2732b89161cae7816880be1f9d39012e8944e7d4b101e02bbac631e9885dca1f7b6d6dd22b1ff2eed034b965c16ad0b12334e452146c3a71054becc70084020394b13d6d52697ff4da0ee62ca984d01abe57e37bdc9343ea64825c3da557e19e65471f07ef5368c8be358e905c3416abfa69144ab435d8f5a8b6b828aa55f816024e03b4fa906a835c85175ae1f884844ddb36d803429e330cc603af44ba7758539153353b79c0ec38b658863d0c9d7c29977c6f33f7c0e05bc88df6b59ee5115bde23121bda78738c0a4a0e792baaa09b849e3a475afe29b484477cb90b68433dbe8a9eb636fb3e1b6c597e6532e805cafde16ed13bd25a0ed9942a3b053b49b192fe4cfdd59f3554fec1755b7573cfc2d81376911f8089287cee09879e2d3ec7dd375b85243b7538c1ee973e9448bc3c5a9fc76d550ba9843d513cd631b19301c5c1ba03e28338f35605db7dbbd0ad7d3753c1c9de9ad2321d6d1ffe80deb8ad6548d950a3c2ead696b97914b8d43561253f17837fef85be13627ffc92bd74e9025beff0e44066adcd64f5cf7d5ee75aed7d49c0ef0a33a04a6da3b9dc04c5228d65009ce14c41941f5a4a6aed8855efb0b99e734a3c24937fe3ca94d9052e0278b2c504d4605a39a9adc8b0606c434f91b8faf84721e413b720a1a93de66586d97f1bb55eb6e853a48389d28e508adce6e72fd1423c00df973f35a632d8f36d5ca792e1834a6e3f33d0a901e29a03a74ff616af731704752915aed99262de421a4069e37a57bf25e22da61e2ba568813aa063e2a2e3b1c71b157e546efc2cee41cf7228fd5b4e507367fb34dd07983e03e54afeeab83d232f7092481b61980ca4669645a2dfca297de8c81bdd09336a5579c67b46f8deb06787e480a72b9c1e596a5d75414757188d2802ed91277eac6958a707e62e2dc97ceb0784d0565eeee2440fe326f020f291bdb044a3ea089e03ec73093f849f3bf0c9baa3dbc57a7d6517e9289e24b9533646e4526bf9f6441eacdb1ace1b0d61becc878bddc9fd4421d27ffd164dd863d2b8e5d985c9846a81aee17d53e445921f0b7502bd5515e099d0bdf4180bcf487fff989eba991dd1b69cff228635404679f45238dd9d31f8e102ab7f97b2fdbe0a8e074dbaff521049b39aa4334aba78bb874e3fbd2e29292108008067447352eca338cb468ab6f740cde12ec8da5eb14e19ca3357e851ce3c462aa42fc4ec4ea6683437e90adab49beb2d8b654a4de69655175201835fae714d5c47c0d9b6d93018c16646698048d235f7c5715c7b802f915d7606dbf46a998fbefee3bf7040389e9657feb754f0b28dcbefee7d2a39adb15c50f40441aa9d1c0d243eab28adccefd7b2f8637f79de4b1a1d08b05dfc69e8bbad0b5354ddb05341862c39195c51853111df1e8f655e4ad7d3efc89ddd89d25ba8fedda87306629cf4950d85096834bed0a45c62016f8b7dd94fdf4ebfccc44279e2ea34a9144d7f82f8771fff981bcb97a86a9f2dc2c70f5125c7cc049fd306ab0db4cdb6b10bd33d6b40d26976bad3dce55cb726557235194cc8cc12fa39e2249edfc0ce038722f8d0316e22a2c47ab0ee931215c2bcfd2ae05021eee5eb1adec609da5cbcbebab4d7d7632c9a490e01d262e58b50065cb171065a78ffa029b203441c84909a0e0d2f8e32e41b6a22efd44aa99b63456a2bb6b2c73bfcfab9595979bc69126a52d504bad3a9fc01cd379069d3f95da7a6622b1db86542a307b0bb538dc020dbb2423dadfa25ef0e0a1d124cd88fec7e0954cee0fe98ec7e7a43b94e22b1b39010be8a8f519dcbeb7639e9fedf109c01ce425a8cee34b713c5eba04565a194fbba2e7dd58417ace1dbf25c2d5b6759f53141bbb46a560ac69891ef869203d70ef481ec034bdd81f0c64ace2572a22dcba50e3a45fbbb61c22cb5a95f77e67ec0f3a95012679c6972a38e22d0368f8c74524f151dbe4f918a1f4cb0def2f6a43543608c8d85d214baaa4d406a901e5bf3ea6d23e9050d19a8aa3f7872aee4967b32c839796a177d54f63651bae5c7eb934a59e1d88ded4a09474b6d0eef4b28a41dd7f8269b4891d2500448f32d3bbc693b79c46ed3f439295e9432ab7e6ccc04057816966374cda0eff8fe64666dd327f84404278863666f64ffab84345020f909788c98922679a61f2e73481906f54848ec340cc4a1cbc239805f1d53f33c82d3e1fd281d217fb187ec723f0c525475bb7e8294d8f21f0f7ba0cdbce48d98524466db4c1bbf8f7a06fe8902a8aff1d2482216b4520e4e59dd03628af6a04f3d7366d8c545cdfbc2df6607a9d4ab3bb00f1c126d00c32349bf00657c7e81874713a897c35668efec4e9efab27cb3486fe9a109df39039f9cbd518d64266d3f4f6cebe810527af2eaa04722968f11ae742a79dfde202d48384dbf5e5b217334c1c91cf6451d28a514b8a6c3661f0f5da1b17ca0cdbe1fe714836564e517c6f7040ed0b006ae9bc4735daf0beb02c52a0869a02236544ab7ff19a6c0be0b3dbb1a2240d8247a56749b815b3277a089587664112e425b40186ee15f6bbe386bb822f6ffced4ce4ac47663a061eb87fd3c35f20caac696756c120059fe8ce62d26dc932afe9abf612d1e8d39806e6057c11b57e502ace913d4fb545ab6ae2718871eebfa1039df2374f8832eb6381e253d2cb59a888e05d151f57725525b2f58aabdc4fcc63f3ded1fefb1460cd0c7a603c22d8c3166abcd774a5deb5c72b186edde8f86d921dcf961fd6ada3104682c10ec1ab6fcec8c65ffabcf7bd811a2a471a41405adfab8b8416a79707db4039703a2f2117e88f17f6dc1609c988b8b4db25f09137b47b2d645a572f161bfff30501fa3bce059f66bb6544c4280619645ef11dd2154a5b3096697eb624d998649411cb988557c3529be67ddefef298f2434371c9bdb9aca58de703ac2d49faf70ec35d78c137b287aa950f93fc4d14e0886240ead82a345d32a749a7c9fbc37e9dcbf9908602b2c4c7324ad341dc9a2232e1d29966cec40411530de5bfc34d18afebce7fa6a5ca8e404c32d24a4146a9a36556a6027495dd9cf6790382cd75862b921855b072512493ca256624b5ab2a55bffe993f567ee764ea9149f79ea8c5868c088a87febcfb4c673b8bb08bd634e33973c80a469072f33eb17b9d49c89c36d31dd89cb6e08eaf0abb0a8ae151521f138a5988bc43ede9212f62985f864a815b3ef22862876d6c9d3580e15f19d04d5dbcab68ebdb417ba52c520ce37e97c4ecd4b81fd100791ffee5ec5c1013a8107cf4bb91701b2fb24d04e7bfa9ec3fed468ab3aab3bc65890df410d577ebd959ce69c390a839cd05ee55cf468c98ef9f7859dbb9ee56373f525ff451a8516ba41a55e8622397b0dd4342ae6d9f0a25fdce3ac2a8b14cd0768bbb6808599ed5165d266f8ea876380ea068c259c8f8ef38b096b0f27dac2a7f8fbb50c956ac8c56e667a3e24e8af7456929ff67fab8ec4c115ad0cf231eef8fdfbf92fb2d5b5d43e146d4c8ad51c1f3da8d9f3e9278201eb7d8b2644895e132737ea06bfdfa9de7d5e43e44a41e43a979050ce51e61eac010dccf01254ada64a30419b42d3e1e5081bd38afae9fdb4d570fbfd57cc62346ec65d48222af1ac2f250681d94bbc04bf2a9bcd31f99fd509c177de54530c02284d754e6ce6e6485b01a9078748055365c0fabe61cdbaf30bf2a6cef67e273a1f4c7a3ac47549b4b645ea5ff7fe519f8f0bea756c27c16a637920291c4fb7ab0514bf2635fbe0c220f27112aae8782476140e1a08f69ecadd38a98f8fc5f487deca98dcc96e6ebadf0dda2e7c5636d3822a5ab00cf477ee78a69decb1eba3dec345667bcd3687769ee9feaa64862b2b230da2265f2351f70ea509dac18280041f20f0f1bc68837a0fbd09d23936ccb4bbd73b83483203ed8e1de93deebf05340f36e44dede79e0be9cb052262efb2fdc7917f48a9e39c55d1f7818eb12d8911e4b3ee5f0a93ee78012e8ef9557f767bf0fbb8a44d1a281c221832af1ed7f46002e708057b250e0901d584536a8414b3f24aeb9e36ece5e07a5bb017909a62b2e97ce4c4787ced1ba5f8764ff658aff8a5e253e566564aed8a3b48cf618ae9bf1a2fa890866c3412014282ed5504fb4e0c5a1a8f243953d72a6480217bf695edd50d5aba1333619a667febd553a272f2677400938ba3ed40557132ae31e3b25ff04b07a1b335ac1afcf785acb51cb459326f28834f44334b2050840fb45815c0444eca49da662f9667680a674b59f4bff77eaa6294523a2eabe2300316c62fd93c0ae0b0fb7731bfb29641390040a710599f99a51af9e920f21116559bcdfceb8e6c5cf7c273d51c970416da205263772ecc01ad2c6abaf3f86a674f45b464d77c5278e64f02ddb1b29043e0ee41b4924db88c4eff38912d539985b5329fc7f14a610e4fb1f92a780c81cc0a468e606aadd7b5a4031e4f2f11525905f524702b436bddf58c95e7c0e062d331b724ebbcf6bbdb81444a6dde85b9de389571c4babfad97b3d713419acf8cd3927fdc8bf99412a34e1a719595f155bc0d714cc25014c362f2c520d3aaced0c994731c490d15dd6089570eff5d6c91317ba53bd6bb231e039e0124b2346749a558eb2effdd5bac71cce21068a19b21040b46ceed322405d83d24fe0c6b743a22806fa9697d4e62f1510bcc9d51fc75d189a0693928ec7203da0f6b101a6e0c6f06335d84ef45e5e9e1b0358cacdbc67a5feaba8f76ac4b35ab5a78c0d149311b7ca5dc295e4e6c91b236cb1caf2b3f4326b7db4a51ef60d04aa1ed0c10da90d587d980aae5ebf61736beb7e71629f79e04a31b0bbfeb6a46756706f83b05e670abf04f858c5336b8a29eba6361f1cb9a2ee74710245573d32ea9b70c4ddaa8f4e4d95fe30ded30e82a10479a5e9cad9a39882e9cadd1ba27a61f9a6c191634a591910adbb64308ebcfa275e0b4efef8c76547f6b18368413eec50c796ec776f23ce7492674ec0cf02ffeb5b1ed1f6a81b26717a5465c18bbe45aad3d1b73abb60298609b775c96adac6572ef938576600e4841e59869df89ebdab36a6e90f5f8963dbe79d7f52cdddebf98b94afcda589c45cefcc36cbfaa5d6d760f2c40aaf54700da5f23db99cf1c15ab484ae0a7cb0079526375d0c8fad5a2f0cae247014652d8773f3b3f746393e6f06d9557aef9da988807179ca7c2c2f101dee5653985c4ea8ad63d8fee778c49270576614cc73f72f88cbddf57f76218bbff139c45ffcc2abd35862730627e73bb42994207a0314aacf087457da7a3a42a3cf2ca3c39300eae262e9c9e5f847ede62b281af9cd3346d5e286fcbb3d59fccbb8abff11400fbdec0ec12f6549bec0375f80671c3721c0bfc22adf861e2f3db4d5ae9c96a38271a8f55f6a799ce5cf31087b6b58cf59f9cb41d7314a317fee1f37dd2243a5abac74eb956b9471614a57b0e90f17adf400c8482b6abdc0d2c110f933692bbae8681d08113beb0f3fd9015002978dd9f37da83da300ea44446888f7cdad8d202e67c85efa230e59c783bf0b5012ef36c1f44da97ab71e2a7d331e0f6f10c810551bad92299c54114c76113322b435fc6c5a8999f9b319203a31a58cb1c4a7f98479b3052dae1ebc7836ccca760fbe896f25d9d63720b11985603a90550ecaad2569b5889c0bafca19b76bfaef2226fd5815e8484193dcf5eb23b3e12e0a736870d2e250215b1b6b4d9df8a0346121082ad034e08d0d212daee2c40cf48d741f1be0601dc5bcbb2e7c8a2d945a99a59dc789aaf4851a0a782f292e831be5f679ed7ee6607ed27062d9fba87d4f90ebd5a3ff2b427fb7b2a7b1933fe9a9a4e10cdc420f531e11e42ac01634524a2b61c9d6079b392f218c5e25021a9ba0f4b2ec785c23939d8c978f07aca6e82cd0ca872fc0921f208826adf1c828e897be48ebd1f62a5682de86b870277a49b910ed44ab4333530433adc829da91632d66fa661b390e1d49f01ec5ba142b8bda97b8e3521db0f6535438d3a7234c057d6ea6820d1f350ce961f8db1a62a2d087d</script>  <div class="hbe hbe-content">    <div class="hbe hbe-input hbe-input-default">      <input class="hbe hbe-input-field hbe-input-field-default" type="password" id="hbePass">      <label class="hbe hbe-input-label hbe-input-label-default" for="hbePass">        <span class="hbe hbe-input-label-content hbe-input-label-content-default">当前文章暂不对外可见，请输入密码后查看！</span>      </label>    </div>  </div></div><script data-pjax src="/lib/hbe.js"></script><link href="/css/hbe.style.css" rel="stylesheet" type="text/css">]]></content>
    
    
    <summary type="html">Kubernetes，凭借其完善的生态系统，提供了许多功能，可以显著增强容器化应用程序的管理、可伸缩性和安全性。以下是13个技巧，每个技巧都有详细的解释、使用示例、上下文应用和需要注意的预防措施。</summary>
    
    
    
    <category term="容器与虚拟化" scheme="https://opsuri.com/categories/%E5%AE%B9%E5%99%A8%E4%B8%8E%E8%99%9A%E6%8B%9F%E5%8C%96/"/>
    
    
    <category term="private" scheme="https://opsuri.com/tags/private/"/>
    
  </entry>
  
  <entry>
    <title>git常用操作总结</title>
    <link href="https://opsuri.com/2025/01/12/Summary-of-common-git-operations/"/>
    <id>https://opsuri.com/2025/01/12/Summary-of-common-git-operations/</id>
    <published>2025-01-12T07:31:37.000Z</published>
    <updated>2025-02-22T16:26:42.888Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/lightgallery.js/1.0.1/css/lightgallery.min.css" /><div class=".article-gallery"><h1>1、初始化用户</h1><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">$ git config --global user.email <span class="string">&quot;your email&quot;</span></span><br><span class="line">$ git config –-global user.name <span class="string">&quot;your name&quot;</span></span><br></pre></td></tr></table></figure><span id="more"></span><h1>2、秘钥</h1><p>查看是否存在秘钥</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ <span class="built_in">ls</span> -al ~/.ssh</span><br></pre></td></tr></table></figure><p><code>id_rsa</code>是私钥，<code>id_rsa.pub</code>是公钥<br><code>id_rsa.pub</code>是你需要上传到git仓库的<code>SSH KEY</code></p><p><strong>生成秘钥</strong></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ ssh-keygen -t rsa -b 4096 -C <span class="string">&quot;your_email@example.com&quot;</span></span><br></pre></td></tr></table></figure><h1>3、本地库和远程库</h1><h2 id="①已创建有远程库，未创建本地库">①已创建有远程库，未创建本地库</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ git <span class="built_in">clone</span> <span class="string">&quot;your repo&quot;</span></span><br></pre></td></tr></table></figure><h2 id="②已创建本地库，未创建远程库">②已创建本地库，未创建远程库</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 新建文件夹</span></span><br><span class="line">$ <span class="built_in">mkdir</span> <span class="built_in">test</span>                </span><br><span class="line"><span class="comment"># 初始化 git </span></span><br><span class="line">$ git init</span><br><span class="line"><span class="comment"># 移除原有的 origin                    </span></span><br><span class="line">$ git remote <span class="built_in">rm</span> origin</span><br><span class="line"><span class="comment"># 添加你的远程库(SSH地址)</span></span><br><span class="line">$ git remote add origin <span class="string">&quot;your remote repo&quot;</span></span><br><span class="line"><span class="comment"># 更新本地库</span></span><br><span class="line">$ git pull</span><br><span class="line"><span class="comment"># 首次推送与远程库建立关联，以后直接git push就可以</span></span><br><span class="line">$ git push --set-upstream origin master </span><br></pre></td></tr></table></figure><h1>4、分支操作</h1><p>查看、新建、切换、删除分支</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 查看当前所在分支</span></span><br><span class="line">$ git branch</span><br><span class="line"><span class="comment"># 查看所有分支</span></span><br><span class="line">$ git branch -a</span><br><span class="line"><span class="comment"># 查看远程库信息</span></span><br><span class="line">$ git remote -v</span><br><span class="line"><span class="comment"># 新建分支</span></span><br><span class="line">$ git branch <span class="string">&quot;new branch&quot;</span></span><br><span class="line"><span class="comment"># 切换分支</span></span><br><span class="line">$ git checkout <span class="string">&quot;target branch&quot;</span></span><br><span class="line"><span class="comment"># 新建并切换到新分支</span></span><br><span class="line">$ git checkout -b <span class="string">&quot;new branch&quot;</span></span><br><span class="line"><span class="comment"># 新建分支并和远程分支进行关联</span></span><br><span class="line">$ git checkout -b <span class="string">&quot;new branch&quot;</span> origin/<span class="string">&quot;new branch&quot;</span></span><br><span class="line"><span class="comment"># 合并分支到当前所处分支上</span></span><br><span class="line">$ git merge <span class="string">&quot;your branch&quot;</span></span><br><span class="line"><span class="comment"># 删除分支</span></span><br><span class="line">$ git branch -d <span class="string">&quot;your branch&quot;</span>  </span><br><span class="line"><span class="comment"># 强制删除未 commit 的分支</span></span><br><span class="line">$ git branch -D <span class="string">&quot;your branch&quot;</span></span><br></pre></td></tr></table></figure><h1>5、正常流程</h1><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 查看当前工作区状态</span></span><br><span class="line">$ git status</span><br><span class="line"><span class="comment"># 添加单个文件到暂存区</span></span><br><span class="line">$ git add xxx.txt</span><br><span class="line"><span class="comment"># 一次性添加所有改动文件</span></span><br><span class="line">$ git add .</span><br><span class="line"><span class="comment"># 提交文件到本地版本库</span></span><br><span class="line">$ git commit -m <span class="string">&quot;I add a file.&quot;</span></span><br><span class="line"><span class="comment"># 推送本地更新到远程版本库</span></span><br><span class="line">$ git push</span><br><span class="line"><span class="comment"># 本地库关联远程库</span></span><br><span class="line">$ git push --set-upstream origin master</span><br></pre></td></tr></table></figure><h1>6、对比文件</h1><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 工作区和暂存区之间差异对比</span></span><br><span class="line">$ git diff <span class="string">&quot;xxx.txt&quot;</span></span><br><span class="line"><span class="comment"># 暂存区和版本库之间差异对比</span></span><br><span class="line">$ git diff --cached(--staged) <span class="string">&quot;xxx.txt&quot;</span></span><br><span class="line"><span class="comment"># 工作区和版本库之间差异对比</span></span><br><span class="line">$ git diff master</span><br></pre></td></tr></table></figure><h1>7、查看历史提交记录</h1><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ git <span class="built_in">log</span></span><br></pre></td></tr></table></figure><h1>8、版本回退</h1><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># HEAD 是最新版本，HEAD^ 是上一个版本</span></span><br><span class="line">$ git reset --hard HEAD^</span><br><span class="line"><span class="comment"># 回退到指定id，git log 查看版本id，版本id不用全部输入，取头几位就可以</span></span><br><span class="line">$ git reset –hard cb926e7e</span><br></pre></td></tr></table></figure><h1>9、撤销工作区修改</h1><p>使用版本库中的文件或者暂存区中的文件替换工作区的文件<br>让文件回到最近一次 git commit 或 git add 时的状态</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ git checkout -- <span class="string">&quot;xxx.txt&quot;</span></span><br></pre></td></tr></table></figure><h1>10、删除文件</h1><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 删除工作区中的文件</span></span><br><span class="line">$ <span class="built_in">rm</span> <span class="string">&quot;xxx.txt&quot;</span></span><br><span class="line"><span class="comment"># 提交删除操作到暂存区</span></span><br><span class="line">$ git <span class="built_in">rm</span> <span class="string">&quot;xxx.txt&quot;</span></span><br><span class="line"><span class="comment"># 提交删除到版本库，在版本库中彻底删除文件</span></span><br><span class="line">$ git commit -m <span class="string">&quot;remove file&quot;</span></span><br></pre></td></tr></table></figure><h1>11、分支管理策略</h1><p>在实际开发中，我们应该按照几个基本原则进行分支管理：</p><blockquote><p>master分支应该是非常稳定的，也就是仅用来发布新版本，平时不能在上面干活<br>developer分支用来干活，也就是说，developer分支是不稳定的，到某个时候，比如1.0版本发布时，再把developer分支合并到master上，在master分支发布1.0版本<br>你和你的小伙伴们每个人都在developer分支上干活，每个人都有自己的分支，时不时地往developer分支上合并就可以了<br>所以，团队合作的分支看起来就像这样：</p></blockquote><p><a href="/assets/blogImg/git-1.png" title="团队合作分支" class="gallery-item"><img src="/assets/blogImg/git-1.png" alt="团队合作分支"></a></p><h1>12、储藏工作现场</h1><p><code>修复bug</code>时，我们会通过创建新的<code>bug分支</code>进行修复，然后合并，最后删除；<br>当手头工作没有完成时，先把工作现场<code>git stash</code>一下，然后去<code>修复bug</code>，修复后，再<code>git stash pop</code>，回到工作现场</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 储存工作现场</span></span><br><span class="line">$ git stash</span><br><span class="line"><span class="comment"># 工作现场列表</span></span><br><span class="line">$ git stash list</span><br><span class="line"><span class="comment"># 恢复但不删除储藏栈的工作现场</span></span><br><span class="line">$ git stash apply</span><br><span class="line"><span class="comment"># 恢复并删除储藏栈中的工作现场</span></span><br><span class="line">$ git stash pop</span><br></pre></td></tr></table></figure><h1>13、多人协作工作模式</h1><blockquote><p>试图用<code>git push origin branch-name</code>推送自己的修改<br>如果推送失败，则因为远程分支比你的本地更新，需要先用<code>git pull</code>试图合并<br>如果合并有冲突，则解决冲突，并在本地提交<br>没有冲突或者解决掉冲突后，再用<code>git push origin branch-name</code>推送就能成功</p></blockquote><h1>14、创建.gitignore</h1><blockquote><p>在<code>git</code>工作区根目录下创建<code>.gitignore</code>文件，把要忽略的文件名写进去，<code>git</code>就会自动忽略这些文件</p></blockquote><h1>15、创建别名</h1><p>给<code>status</code>创建别名<code>st</code></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ git config --global alias.st status</span><br></pre></td></tr></table></figure><h1>16、git 配置文件</h1><blockquote><p>配置文件放在<code>~/.gitconfig</code></p></blockquote><h1>17、<code>git fetch</code>和<code>git pull</code>区别</h1><p>要讲清楚这两个命令的区别，就需要从<code>git clone</code>开始讲起<br>假设你在github上有一个远程仓库地址是xxx，然后你从<code>远程仓库</code>clone到<code>本地仓库</code></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ git <span class="built_in">clone</span> xxx</span><br></pre></td></tr></table></figure><p>执行完此命令后：</p><ul><li>①Git会自动为你将远程仓库命名为origin，并下载其中所有的数据到本地；</li><li>②在本地建立所有远程存在的分支，并且命名为origin/xxx，例如远程分支有master、developer，那么本地就会建立origin/master分支、origin/developer分支，并且它们都是处于remotes目录下，是隐藏的。使用命令git branch -a就可以看到隐藏目录remotes，结果显示为remotes/origin/master以及remotes/origin/developer。</li><li>③接着，Git会继续建立一个属于你的本地master和developer分支，位置和远程origin/master、origin/developer分支处于相同的位置，你就可以开始工作了。<br>这样，我们在本地仓库的本地分支和远程分支就都有了，并且始于同一位置。</li></ul><p>如果其他人向github上xxx分支推送了他们的更新，那么服务器上的相应分支就会向前推进。<br>如果在本地的相应分支进行了commit提交到本地代码库，那么本地的master或者developer分支也会向前推进，不过只要你不和服务器通信数据，那么本地的remotes/origin/master（developer）指针仍然会在原地不动。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ git fetch origin</span><br></pre></td></tr></table></figure><p>运行<code>git fetch origin</code>命令后，会同步远程服务器上的数据到本地；</p><p>该命令首先找到origin是哪个服务器，从上面获取你未曾拥有的数据，更新到你的本地<code>remotes/origin/master（developer）</code>，然后把<code>remotes/origin/master(developer)</code>的指针移动到最新的位置上：</p><p>比较本地<code>master分支</code>和<code>origin/master分支</code>有什么区别</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ git <span class="built_in">log</span> master..origin/master </span><br></pre></td></tr></table></figure><p>切换到<code>本地master</code>分支下</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ git checkout master </span><br></pre></td></tr></table></figure><p>合并<code>origin/master分支</code>到<code>本地master分支</code></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ git merge origin master</span><br></pre></td></tr></table></figure><p><code>git pull</code>相当于<code>git fetch origin</code>和<code>git merge</code><br><code>git fetch</code>相当于先将服务器上的<code>origin分支</code>更新到<code>本地remotes/origin分支</code>上，然后手动去<code>merge</code>合并<code>origin分支</code>到<code>本地分支</code>上<br>这就是<code>git pull</code>和<code>git fetch</code>的区别</p><h1>18、git删除未跟踪文件</h1><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 删除未跟踪文件</span></span><br><span class="line">$ git clean -f</span><br><span class="line"><span class="comment"># 删除未跟踪文件目录</span></span><br><span class="line">$ git clean -fd</span><br><span class="line"><span class="comment"># 正式删除文件以前先查看哪些会被删除</span></span><br><span class="line">$ git clean -nf</span><br><span class="line">$ git clean -nfd</span><br></pre></td></tr></table></figure><h1>19、在本地删除远程已经没有的分支</h1><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ git fetch -p origin</span><br></pre></td></tr></table></figure><h1>20、重命名本地分支</h1><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ git branch -m old-local-branch-name new-local-branch-name</span><br></pre></td></tr></table></figure><h1>21、删除远程分支</h1><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ git push origin :old-remote-branch-name</span><br></pre></td></tr></table></figure><h1>22、本地分支与远程分支建立关联（远程分支不存在也可以）</h1><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 切换到本地分支</span></span><br><span class="line">$ git checkout local-branch</span><br><span class="line"><span class="comment"># push 到想要建立关联的远程分支</span></span><br><span class="line">$ git push -u origin/remote-branch</span><br></pre></td></tr></table></figure><h1>23、重新跟踪远程文件</h1><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 先删除远程文件</span></span><br><span class="line">$ git remote <span class="built_in">rm</span> origin</span><br><span class="line"><span class="comment"># 跟踪新远程文件</span></span><br><span class="line">$ git remote add origin https://xxx.git</span><br><span class="line"><span class="comment"># 或者合并成一条命令</span></span><br><span class="line">$ git remote origin set-url https://xxx.git</span><br></pre></td></tr></table></figure><hr><p>来源： <a href="https://www.cnblogs.com/hls-code/p/15428026.html">https://www.cnblogs.com/hls-code/p/15428026.html</a></p></div><script src="https://cdn.jsdelivr.net/lightgallery.js/1.0.1/js/lightgallery.min.js"></script><script>if (typeof lightGallery !== 'undefined') {        var options = {            selector: '.gallery-item'        };        lightGallery(document.getElementsByClassName('.article-gallery')[0], options);        }</script>]]></content>
    
    
    <summary type="html">git使用详解：全局/本地配置、版本库管理、分支管理、远程库管理等。</summary>
    
    
    
    <category term="学习笔记" scheme="https://opsuri.com/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="git" scheme="https://opsuri.com/tags/git/"/>
    
  </entry>
  
  <entry>
    <title>在debian 12上安装shadowsocks</title>
    <link href="https://opsuri.com/2024/11/28/Install-shadowsocks-on-debian12/"/>
    <id>https://opsuri.com/2024/11/28/Install-shadowsocks-on-debian12/</id>
    <published>2024-11-28T10:54:38.000Z</published>
    <updated>2025-02-22T14:17:03.402Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/lightgallery.js/1.0.1/css/lightgallery.min.css" /><div class=".article-gallery"><h1>1、服务端安装配置</h1><h2 id="1-1、安装配置shadowsocks-libev">1.1、安装配置shadowsocks-libev</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cd</span> /usr/local/src</span><br><span class="line">wget https://github.com/shadowsocks/shadowsocks-libev/releases/download/v3.3.5/shadowsocks-libev-3.3.5.tar.gz</span><br><span class="line">ll</span><br><span class="line">tar xf shadowsocks-libev-3.3.5.tar.gz</span><br><span class="line">ll</span><br><span class="line"><span class="built_in">cd</span> shadowsocks-libev-3.3.5</span><br><span class="line">ll</span><br><span class="line">apt install libpcre3 libpcre3-dev libmbedtls-dev libsodium-dev cmake libc-ares2 libc-ares-dev libev-dev</span><br><span class="line">./configure --disable-documentation</span><br><span class="line">make &amp;&amp; make install</span><br></pre></td></tr></table></figure><p>文件默认安装在<code>/usr/local</code>目录下。按照如下方法为shadowsocks-libev创建systemd服务。<br>编辑<code>/usr/local/src/shadowsocks-libev-3.3.5/debian/shadowsocks-libev.service</code>文件，改成如下</p><span id="more"></span><figure class="highlight plaintext"><figcaption><span>Text</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line">#  This file is part of shadowsocks-libev.</span><br><span class="line">#</span><br><span class="line">#  Shadowsocks-libev is free software; you can redistribute it and/or modify</span><br><span class="line">#  it under the terms of the GNU General Public License as published by</span><br><span class="line">#  the Free Software Foundation; either version 3 of the License, or</span><br><span class="line">#  (at your option) any later version.</span><br><span class="line">#</span><br><span class="line">#  This file is default for Debian packaging. See also</span><br><span class="line">#  /etc/default/shadowsocks-libev for environment variables.</span><br><span class="line"></span><br><span class="line">[Unit]</span><br><span class="line">Description=Shadowsocks-libev Default Server Service</span><br><span class="line">Documentation=man:shadowsocks-libev(8)</span><br><span class="line">After=network-online.target</span><br><span class="line"></span><br><span class="line">[Service]</span><br><span class="line">Type=simple</span><br><span class="line">CapabilityBoundingSet=CAP_NET_BIND_SERVICE</span><br><span class="line">AmbientCapabilities=CAP_NET_BIND_SERVICE</span><br><span class="line">DynamicUser=true</span><br><span class="line">EnvironmentFile=/etc/default/shadowsocks-libev</span><br><span class="line">LimitNOFILE=32768</span><br><span class="line">ExecStart=/usr/local/bin/ss-server -c $CONFFILE $DAEMON_ARGS</span><br><span class="line"></span><br><span class="line">[Install]</span><br><span class="line">WantedBy=multi-user.target</span><br></pre></td></tr></table></figure><p>编辑<code>/usr/local/src/shadowsocks-libev-3.3.5/debian/shadowsocks-libev.default</code>文件，把</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">DAEMON_ARGS=</span><br></pre></td></tr></table></figure><p>改成</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">DAEMON_ARGS=&quot;-d 8.8.8.8 -d 8.8.4.4 -u&quot;</span><br></pre></td></tr></table></figure><p>然后将相应文件cp到对应目录</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cp</span> /usr/local/src/shadowsocks-libev-3.3.5/debian/shadowsocks-libev.service /usr/lib/systemd/system</span><br><span class="line"><span class="built_in">cp</span> /usr/local/src/shadowsocks-libev-3.3.5/debian/shadowsocks-libev.default /etc/default/shadowsocks-libev</span><br></pre></td></tr></table></figure><p>为<code>shadowsocks-libev</code>配置证书：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">mkdir</span> -p /etc/certs</span><br></pre></td></tr></table></figure><p>将申请的<code>RSA证书</code>（以域名<code>dmit.example.com</code>为例）放置至<code>/etc/certs</code>目录，并配置权限为<code>644</code>。其中<code>example.com.pem</code>为公钥，<code>example.com.key</code>为私钥。<br>为<code>shadowsocks-libev</code>创建主配置文件：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">mkdir</span> -p /etc/shadowsocks-libev</span><br><span class="line"><span class="built_in">cat</span>  &gt; /etc/shadowsocks-libev/config.json  &lt; EOF</span><br><span class="line">&#123;</span><br><span class="line">    <span class="string">&quot;server&quot;</span>: [<span class="string">&quot;::&quot;</span>, <span class="string">&quot;0.0.0.0&quot;</span>],</span><br><span class="line">    <span class="string">&quot;mode&quot;</span>: <span class="string">&quot;tcp_and_udp&quot;</span>,</span><br><span class="line">    <span class="string">&quot;server_port&quot;</span>: 443,</span><br><span class="line">    <span class="string">&quot;local_port&quot;</span>: 1080,</span><br><span class="line">    <span class="string">&quot;password&quot;</span>: <span class="string">&quot;Gpb2xUPArG82bExG&quot;</span>,</span><br><span class="line">    <span class="string">&quot;timeout&quot;</span>: 300,</span><br><span class="line">    <span class="string">&quot;reuse-port&quot;</span>: <span class="literal">true</span>,</span><br><span class="line">    <span class="string">&quot;method&quot;</span>: <span class="string">&quot;chacha20-ietf-poly1305&quot;</span>,</span><br><span class="line">    <span class="string">&quot;plugin&quot;</span>: <span class="string">&quot;/usr/local/bin/v2ray-plugin&quot;</span>,</span><br><span class="line">    <span class="string">&quot;plugin_opts&quot;</span>: <span class="string">&quot;server;tls;host=dmit.example.com;cert=/etc/certs/example.com.pem;key=/etc/certs/example.com.key;loglevel=none&quot;</span></span><br><span class="line">&#125;</span><br><span class="line">EOF</span><br></pre></td></tr></table></figure><p>因为启动用户为nobody，启动端口为小于1024的443端口，所以需要为ss-server赋予以下权限：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">setcap</span> CAP_NET_BIND_SERVICE=+eip /usr/local/bin/ss-server</span><br></pre></td></tr></table></figure><p>将shadowsocks-libev服务设置开机自启并启动：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">systemctl <span class="built_in">enable</span> shadowsocks-libev.service</span><br><span class="line">systemctl start shadowsocks-libev.service</span><br><span class="line">systemctl status shadowsocks-libev.service</span><br></pre></td></tr></table></figure><p>查看状态当然是失败的，因为缺少<code>v2ray-plugin</code>插件。</p><h2 id="1-2、安装v2ray-plugin插件">1.2、安装<code>v2ray-plugin</code>插件</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cd</span> /usr/local/src</span><br><span class="line">wget https://github.com/shadowsocks/v2ray-plugin/releases/download/v1.3.2/v2ray-plugin-linux-amd64-v1.3.2.tar.gz</span><br><span class="line"><span class="comment"># wget https://github.com/teddysun/v2ray-plugin/releases/download/v5.17.0/v2ray-plugin-linux-amd64-v5.17.0.tar.gz</span></span><br><span class="line">tar xf v2ray-plugin-linux-amd64-v1.3.2.tar.gz</span><br><span class="line"><span class="built_in">cp</span> v2ray-plugin_linux_amd64 /usr/local/bin/v2ray-plugin</span><br><span class="line"><span class="built_in">setcap</span> CAP_NET_BIND_SERVICE=+eip /usr/local/bin/v2ray-plugin</span><br></pre></td></tr></table></figure><p>再次启动<code>shadowsocks-libev</code>：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">systemctl start shadowsocks-libev.service</span><br><span class="line">systemctl status shadowsocks-libev.service</span><br></pre></td></tr></table></figure><p>发现已经正常启动。</p><h1>2、PC端安装配置</h1><h2 id="2-1、配置ShadowsocksX-NG">2.1、配置ShadowsocksX-NG</h2><p>下载以下版本的ShadowsocksX-NG及最新版的v2ray-plugin<br>MacOS版：<a href="https://github.com/shadowsocks/ShadowsocksX-NG/releases/download/v1.9.4/ShadowsocksX-NG.1.9.4.zip">https://github.com/shadowsocks/ShadowsocksX-NG/releases/download/v1.9.4/ShadowsocksX-NG.1.9.4.zip</a> （最新版的配置完成后始终不能正常使用）<br><a href="https://github.com/teddysun/v2ray-plugin/releases/download/v5.17.0/v2ray-plugin-darwin-amd64-v5.17.0.tar.gz">https://github.com/teddysun/v2ray-plugin/releases/download/v5.17.0/v2ray-plugin-darwin-amd64-v5.17.0.tar.gz</a> （插件版本号同服务端）<br>如果MacOS在启动Shadowsocks时提示未验证的发布者请在终端执行<code>sudo spctl --master-disable</code>即可正常运行。</p><blockquote><p>主机名：     <a href="http://dmit.example.com">dmit.example.com</a><br>端口：       443<br>加密方法：   chacha20-ietf-poly1305<br>密码：      Gpb2xUPArG82bExG  [ 你的密码，配置同服务端 ]<br>插件：      v2ray-plugin<br>插件选项：   tls;<a href="http://host=dmit.example.com">host=dmit.example.com</a></p></blockquote></div><script src="https://cdn.jsdelivr.net/lightgallery.js/1.0.1/js/lightgallery.min.js"></script><script>if (typeof lightGallery !== 'undefined') {        var options = {            selector: '.gallery-item'        };        lightGallery(document.getElementsByClassName('.article-gallery')[0], options);        }</script>]]></content>
    
    
    <summary type="html">手把手教你使用Debian12主机配置Shadowsocks(小飞机)</summary>
    
    
    
    <category term="备忘录" scheme="https://opsuri.com/categories/%E5%A4%87%E5%BF%98%E5%BD%95/"/>
    
    
    <category term="Linux" scheme="https://opsuri.com/tags/Linux/"/>
    
    <category term="Shadowsocks" scheme="https://opsuri.com/tags/Shadowsocks/"/>
    
    <category term="小飞机" scheme="https://opsuri.com/tags/%E5%B0%8F%E9%A3%9E%E6%9C%BA/"/>
    
    <category term="VPN" scheme="https://opsuri.com/tags/VPN/"/>
    
  </entry>
  
  <entry>
    <title>公有云迁移至kubernetes需要做哪些准备？有哪些坑需要注意的？</title>
    <link href="https://opsuri.com/2023/05/17/Preparations-for-Migrating-from-Public-Cloud-to-Kubernetes/"/>
    <id>https://opsuri.com/2023/05/17/Preparations-for-Migrating-from-Public-Cloud-to-Kubernetes/</id>
    <published>2023-05-17T11:04:51.000Z</published>
    <updated>2025-02-22T16:09:47.704Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/lightgallery.js/1.0.1/css/lightgallery.min.css" /><div class=".article-gallery"><p>将应用从公有云迁移到 Kubernetes 是一个复杂的过程，需要充分的准备和规划。以下是迁移过程中需要做的准备工作以及需要注意的潜在问题：</p><hr><h1>迁移前的准备工作</h1><h2 id="评估应用架构">评估应用架构</h2><p>• 分析现有应用的架构，确定是否适合容器化。<br>• 识别有状态服务（如数据库）和无状态服务，确定哪些服务可以迁移到 Kubernetes。<br>• 检查应用是否依赖特定的云服务（如云数据库、消息队列等），并评估是否需要替换或适配。</p><h2 id="容器化应用">容器化应用</h2><p>• 将应用打包为 Docker 镜像，确保镜像轻量化、安全且符合最佳实践。</p><span id="more"></span><p>• 编写 Dockerfile 和容器启动脚本。<br>• 测试容器化后的应用，确保其行为与原有环境一致。</p><h2 id="设计-Kubernetes-架构">设计 Kubernetes 架构</h2><p>• 确定 Kubernetes 集群的规模、节点类型和网络架构。<br>• 设计 Pod、Deployment、Service、Ingress 等资源的配置。<br>• 规划存储方案，特别是对有状态服务（如使用 Persistent Volume）。</p><h2 id="配置管理">配置管理</h2><p>• 将应用的配置外置，使用 ConfigMap 或 Secret 管理。<br>• 确保敏感信息（如密码、密钥）通过 Kubernetes Secret 安全存储。</p><h2 id="CI-CD-流水线">CI/CD 流水线</h2><p>• 搭建 CI/CD 流水线，实现镜像构建、测试和部署的自动化。<br>• 集成 Kubernetes 部署工具（如 Helm、Kustomize）以简化部署流程。</p><h2 id="监控与日志">监控与日志</h2><p>• 部署监控工具（如 Prometheus、Grafana）以监控集群和应用状态。<br>• 配置日志收集系统（如 ELK、Fluentd）以集中管理日志。</p><h2 id="网络与安全">网络与安全</h2><p>• 规划 Kubernetes 网络模型（如 CNI 插件选择）。<br>• 配置网络策略（Network Policies）以限制 Pod 之间的通信。<br>• 确保集群的安全性，包括 RBAC、Pod 安全策略等。</p><h2 id="备份与恢复">备份与恢复</h2><p>• 制定数据备份和恢复策略，特别是对有状态服务。<br>• 测试备份和恢复流程，确保其可靠性。</p><hr><h1>迁移过程中需要注意的“坑”</h1><h2 id="资源分配问题">资源分配问题</h2><p>• Kubernetes 需要合理分配 CPU、内存等资源，否则可能导致 Pod 被驱逐或节点资源耗尽。<br>• 使用 Resource Requests 和 Limits 来管理资源分配。</p><h2 id="网络性能问题">网络性能问题</h2><p>• Kubernetes 的网络模型可能引入额外的网络延迟或复杂性。<br>• 确保 CNI 插件和网络配置能够满足应用的性能需求。</p><h2 id="存储管理问题">存储管理问题</h2><p>• 有状态服务的存储迁移可能比较复杂，特别是涉及数据一致性和持久化时。<br>• 确保 Persistent Volume 的配置正确，并测试存储的性能和可靠性。</p><h2 id="应用依赖问题">应用依赖问题</h2><p>• 如果应用依赖公有云的特定服务（如云数据库、对象存储），迁移时需要找到替代方案或进行适配。<br>• 可能需要重构部分代码或引入新的中间件。</p><h2 id="配置管理问题">配置管理问题</h2><p>• 配置文件的动态更新可能导致应用行为不一致。<br>• 使用 ConfigMap 和 Secret 时，确保配置变更能够正确传递给 Pod。</p><h2 id="安全性问题">安全性问题</h2><p>• Kubernetes 集群的安全性需要特别关注，包括 RBAC、网络策略、镜像安全等。<br>• 避免使用特权容器，限制 Pod 的权限。</p><h2 id="监控与日志问题">监控与日志问题</h2><p>• 如果没有完善的监控和日志系统，可能难以排查问题。<br>• 确保监控覆盖集群、节点、Pod 和应用的各个层面。</p><h2 id="版本兼容性问题">版本兼容性问题</h2><p>• Kubernetes 的版本更新较快，确保使用的工具和插件与 Kubernetes 版本兼容。<br>• 测试新版本的 Kubernetes 以确保其稳定性。</p><h2 id="迁移过程中的停机时间">迁移过程中的停机时间</h2><p>• 迁移可能导致应用停机，需要制定详细的迁移计划，尽量减少对业务的影响。<br>• 可以使用蓝绿部署或金丝雀发布策略逐步迁移。</p><h2 id="团队技能问题">团队技能问题</h2><p>• Kubernetes 的学习曲线较陡，确保团队具备足够的 Kubernetes 运维和开发能力。<br>• 提供培训或引入外部专家支持。</p><hr><h1>迁移后的优化与验证</h1><h2 id="性能优化">性能优化</h2><p>• 根据监控数据优化资源分配和调度策略。<br>• 调整 HPA（Horizontal Pod Autoscaler）以实现自动扩缩容。</p><h2 id="稳定性验证">稳定性验证</h2><p>• 进行压力测试，确保应用在 Kubernetes 上稳定运行。<br>• 验证高可用性和故障恢复能力。</p><h2 id="成本优化">成本优化</h2><p>• 分析 Kubernetes 集群的资源使用情况，优化节点规模和资源分配。<br>• 使用 Spot 实例或预留实例以降低成本。</p><h2 id="持续改进">持续改进</h2><p>• 根据运行情况持续优化 Kubernetes 配置和应用架构。<br>• 定期更新 Kubernetes 版本和相关组件。</p><hr><h1>总结</h1><p>迁移到 Kubernetes 需要从技术、流程和团队能力等多个方面进行准备。关键是要充分评估现有应用、设计合理的架构、解决潜在问题，并在迁移后进行持续优化。通过细致的规划和执行，可以最大限度地减少迁移风险，充分发挥 Kubernetes 的优势。</p></div><script src="https://cdn.jsdelivr.net/lightgallery.js/1.0.1/js/lightgallery.min.js"></script><script>if (typeof lightGallery !== 'undefined') {        var options = {            selector: '.gallery-item'        };        lightGallery(document.getElementsByClassName('.article-gallery')[0], options);        }</script>]]></content>
    
    
    <summary type="html">迁移至容器前的准备工作以及避坑</summary>
    
    
    
    <category term="容器与虚拟化" scheme="https://opsuri.com/categories/%E5%AE%B9%E5%99%A8%E4%B8%8E%E8%99%9A%E6%8B%9F%E5%8C%96/"/>
    
    
    <category term="Kubernetes" scheme="https://opsuri.com/tags/Kubernetes/"/>
    
    <category term="虚拟化" scheme="https://opsuri.com/tags/%E8%99%9A%E6%8B%9F%E5%8C%96/"/>
    
    <category term="容器化应用" scheme="https://opsuri.com/tags/%E5%AE%B9%E5%99%A8%E5%8C%96%E5%BA%94%E7%94%A8/"/>
    
    <category term="公有云" scheme="https://opsuri.com/tags/%E5%85%AC%E6%9C%89%E4%BA%91/"/>
    
  </entry>
  
  <entry>
    <title>都有哪些常见的容器引擎</title>
    <link href="https://opsuri.com/2022/10/23/Several-Common-Container-Engines/"/>
    <id>https://opsuri.com/2022/10/23/Several-Common-Container-Engines/</id>
    <published>2022-10-23T10:48:07.000Z</published>
    <updated>2025-02-22T14:33:39.971Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/lightgallery.js/1.0.1/css/lightgallery.min.css" /><div class=".article-gallery"><p>许多其他常见的容器技术，它们在容器化应用的构建、运行和管理方面各有特色。以下是一些常见的容器技术：</p><h1>容器运行时</h1><h2 id="Docker-Engine">Docker Engine</h2><p>特点：最流行的容器引擎，提供完整的工具链，用于构建、运行和管理容器。<br>优势：轻量级、可移植性、快速启动和关闭、提高开发效率、简化部署和管理、资源利用率高、隔离性好、可扩展性强。<br>适用场景：开发团队稳定，软件运行在不同的环境中，软件由多部分组成，软件可扩展。</p><h2 id="containerd">containerd</h2><p>特点：Docker 的核心容器运行时，轻量级，专注于容器的生命周期管理。<br>优势：高性能，被 Kubernetes 和其他容器平台广泛使用。<br>适用场景：生产环境，尤其是 Kubernetes 集群。</p><h2 id="CRI-O">CRI-O</h2><p>特点：专为 Kubernetes 设计，符合 CRI（Container Runtime Interface）标准。<br>优势：轻量级，专注于 Kubernetes 集成。<br>适用场景：Kubernetes 环境，替代 Docker 作为容器运行时。</p><h2 id="rkt（Rocket）">rkt（Rocket）</h2><span id="more"></span><p>特点：由 CoreOS 开发，强调安全性和开放性。<br>优势：支持多种容器格式（如 Docker 镜像），安全性高。<br>适用场景：需要高安全性和开放标准的场景。</p><h2 id="Windows-Containers">Windows Containers</h2><p>特点：微软为 Windows 系统提供的容器引擎。<br>优势：支持 Windows 应用程序。<br>适用场景：Windows 环境下的容器化。</p><h2 id="OpenVZ">OpenVZ</h2><p>特点：基于 Linux 的容器化虚拟化解决方案。<br>优势：轻量级，适合 VPS（虚拟专用服务器）。<br>适用场景：虚拟化和 VPS 环境。</p><h2 id="Buildah">Buildah</h2><p>特点：专注于构建容器镜像，无需守护进程。<br>优势：轻量级，适合 CI/CD 流水线。<br>适用场景：容器镜像构建和 CI/CD 流程。</p><h1>容器编排与管理</h1><h2 id="Kubernetes">Kubernetes</h2><p>• 简介：开源的容器编排平台，用于自动化容器的部署、扩展和管理。<br>• 特点：支持多种容器运行时，包括 Docker、containerd 和 CRI-O。</p><h2 id="Apache-Mesos">Apache Mesos</h2><p>• 简介：分布式系统内核，用于管理集群资源。<br>• 特点：支持容器化应用和其他工作负载的统一管理。</p><h2 id="Nomad">Nomad</h2><p>• 简介：HashiCorp 开发的简单灵活的调度器和编排器。<br>• 特点：支持多种工作负载类型，包括容器、虚拟机和独立应用。</p><h1>容器镜像构建</h1><h2 id="Buildah-2">Buildah</h2><p>• 简介：用于构建 OCI（Open Container Initiative）容器镜像的工具。<br>• 特点：无需运行完整的容器引擎即可构建镜像。</p><h2 id="Kaniko">Kaniko</h2><p>• 简介：Google 开发的开源工具，用于在 Kubernetes 集群中构建容器镜像。<br>• 特点：无需特权模式即可构建镜像，适合在 CI/CD 管道中使用。</p><h2 id="Podman">Podman</h2><p>• 简介：Red Hat 开发的无守护进程容器引擎。<br>• 特点：支持构建、运行和管理容器，兼容 Docker CLI。</p><h1>容器安全</h1><h2 id="gVisor">gVisor</h2><p>• 简介：Google 开发的容器沙箱运行时，提供额外的安全隔离层。<br>• 特点：通过用户空间内核模拟减少攻击面。</p><h2 id="Kata-Containers">Kata Containers</h2><p>• 简介：开源的轻量级虚拟机（VM）运行时，提供类似容器的体验。<br>• 特点：结合了容器的速度和虚拟机的安全性。</p><h2 id="Falco">Falco</h2><p>• 简介：云原生运行时安全工具，用于检测容器中的异常行为。<br>• 特点：支持实时监控和警报。</p><h1>容器网络与存储</h1><h2 id="Flannel">Flannel</h2><p>• 简介：为 Kubernetes 设计的简单网络解决方案。<br>• 特点：提供跨节点的容器网络通信。</p><h2 id="Calico">Calico</h2><p>• 简介：开源的网络和网络安全解决方案，支持 Kubernetes。<br>• 特点：提供高性能的网络策略和安全功能。</p><h2 id="Rook">Rook</h2><p>• 简介：开源的云原生存储编排器。<br>• 特点：支持多种存储系统，如 Ceph、EdgeFS 等。</p><h1>其他容器技术</h1><h2 id="LXC-LXD">LXC/LXD</h2><p>• 简介：Linux 容器（LXC）是一种操作系统级别的虚拟化技术，LXD 是其管理工具。<br>• 特点：提供类似虚拟机的隔离性，但性能接近裸机。</p><h2 id="Singularity">Singularity</h2><p>• 简介：专为高性能计算（HPC）环境设计的容器平台。<br>• 特点：支持运行科学计算应用，强调安全性和可移植性。</p><h2 id="Firecracker">Firecracker</h2><p>• 简介：Amazon 开发的轻量级虚拟机管理器，用于运行微虚拟机（microVM）。<br>• 特点：结合了容器的速度和虚拟机的安全性，适合无服务器计算。</p><h1>总结</h1><p>除了 Docker，还有许多其他容器技术在容器化应用的构建、运行和管理方面提供了丰富的选择。这些技术各有特色，适用于不同的应用场景和需求。通过了解和掌握这些技术，您可以更好地应对复杂的容器化环境，提高系统的灵活性和可维护性。<br>这些容器引擎各有特点，适合不同的场景：</p><blockquote><p>Podman 和 containerd 是 Docker 的直接替代品。<br>CRI-O 和 Kata Containers 更适合 Kubernetes 环境。<br>Singularity 和 gVisor 适合高性能计算和安全敏感场景。<br>LXD 和 Windows Containers 适合运行完整操作系统的场景。<br>根据具体需求选择合适的容器引擎。</p></blockquote></div><script src="https://cdn.jsdelivr.net/lightgallery.js/1.0.1/js/lightgallery.min.js"></script><script>if (typeof lightGallery !== 'undefined') {        var options = {            selector: '.gallery-item'        };        lightGallery(document.getElementsByClassName('.article-gallery')[0], options);        }</script>]]></content>
    
    
    <summary type="html">几种常见的容器类引擎</summary>
    
    
    
    <category term="容器与虚拟化" scheme="https://opsuri.com/categories/%E5%AE%B9%E5%99%A8%E4%B8%8E%E8%99%9A%E6%8B%9F%E5%8C%96/"/>
    
    
    <category term="虚拟化" scheme="https://opsuri.com/tags/%E8%99%9A%E6%8B%9F%E5%8C%96/"/>
    
    <category term="容器" scheme="https://opsuri.com/tags/%E5%AE%B9%E5%99%A8/"/>
    
    <category term="容器编排和管理" scheme="https://opsuri.com/tags/%E5%AE%B9%E5%99%A8%E7%BC%96%E6%8E%92%E5%92%8C%E7%AE%A1%E7%90%86/"/>
    
  </entry>
  
  <entry>
    <title>几种常见的容器</title>
    <link href="https://opsuri.com/2021/09/28/Several-Common-Containers/"/>
    <id>https://opsuri.com/2021/09/28/Several-Common-Containers/</id>
    <published>2021-09-28T11:03:19.000Z</published>
    <updated>2025-02-22T14:35:53.135Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/lightgallery.js/1.0.1/css/lightgallery.min.css" /><div class=".article-gallery"><p>容器技术在现代软件开发和部署中扮演着重要角色，常见的容器类型和应用场景多种多样。以下是一些常见的容器类型及其用途：</p><h1>应用容器</h1><h2 id="Web服务器容器">Web服务器容器</h2><ul><li>Nginx</li></ul><p>高性能的HTTP服务器和反向代理服务器。</p><ul><li>Apache HTTP Server</li></ul><p>广泛使用的开源Web服务器。</p><h2 id="应用服务器容器">应用服务器容器</h2><ul><li>Tomcat</li></ul><p>用于运行Java Servlet和JSP的Web应用服务器。</p><ul><li>Jetty</li></ul><p>轻量级的Java Web服务器和Servlet容器。</p><h2 id="数据库容器">数据库容器</h2><ul><li>MySQL</li></ul><p>流行的开源关系型数据库。</p><span id="more"></span><ul><li>PostgreSQL</li></ul><p>功能强大的开源关系型数据库。</p><ul><li>MongoDB</li></ul><p>NoSQL 文档数据库。</p><h1>中间件容器</h1><h2 id="消息队列容器">消息队列容器</h2><ul><li>RabbitMQ</li></ul><p>开源消息代理软件，支持多种消息协议。</p><ul><li>Kafka</li></ul><p>分布式流处理平台，用于构建实时数据管道和流应用。</p><h2 id="缓存容器">缓存容器</h2><ul><li>Redis</li></ul><p>开源的内存数据结构存储，用作数据库、缓存和消息中间件。</p><ul><li>Memcached</li></ul><p>高性能的分布式内存对象缓存系统。</p><h1>开发与测试容器</h1><h2 id="开发环境容器">开发环境容器</h2><ul><li>Node.js</li></ul><p>用于构建快速、可扩展的网络应用的JavaScript运行时。</p><ul><li>Python</li></ul><p>广泛使用的高级编程语言，适用于多种应用场景。</p><h2 id="测试环境容器">测试环境容器</h2><ul><li>Selenium</li></ul><p>用于自动化Web浏览器测试的工具。</p><ul><li>JUnit</li></ul><p>Java编程语言的单元测试框架。</p><h1>数据科学与机器学习容器</h1><h2 id="数据处理容器">数据处理容器</h2><ul><li>Jupyter Notebook</li></ul><p>开源的Web应用程序，用于创建和共享包含实时代码、方程、可视化和文本的文档。</p><ul><li>Apache Spark</li></ul><p>用于大规模数据处理的统一分析引擎。</p><h2 id="机器学习容器">机器学习容器</h2><ul><li>TensorFlow</li></ul><p>开源机器学习框架，广泛用于深度学习。</p><ul><li>PyTorch</li></ul><p>开源的机器学习库，广泛用于研究和生产。</p><h1>安全与监控容器</h1><h2 id="安全容器">安全容器</h2><ul><li>ClamAV</li></ul><p>开源的防病毒软件工具包。</p><ul><li>OpenVAS</li></ul><p>全功能的漏洞扫描器。</p><h2 id="监控容器">监控容器</h2><ul><li>Prometheus</li></ul><p>开源的系统监控和警报工具包。</p><ul><li>Grafana</li></ul><p>开源的可视化和分析平台。</p><h1>存储与备份容器</h1><h2 id="存储容器">存储容器</h2><ul><li>MinIO</li></ul><p><code>高性能的对象存储</code>服务器，兼容<code>Amazon S3 API</code>。</p><ul><li>Ceph</li></ul><p>分布式存储系统，提供对象、块和文件存储。</p><h2 id="备份容器">备份容器</h2><ul><li>Bacula</li></ul><p>开源的网络备份解决方案。</p><ul><li>Duplicati</li></ul><p>开源的备份软件，支持加密和压缩。</p><h1>网络与通信容器</h1><h2 id="网络容器">网络容器</h2><ul><li>OpenVPN</li></ul><p>开源的<code>虚拟专用网络（VPN）</code>解决方案。</p><ul><li>HAProxy</li></ul><p><code>高性能的TCP/HTTP负载均衡器</code>和<code>代理服务器</code>。</p><h2 id="通信容器">通信容器</h2><ul><li>Ejabberd</li></ul><p>开源的<code>XMPP服务器</code>，用于<code>即时消息</code>和<code>在线状态</code>。</p><ul><li>Matrix Synapse</li></ul><p>开源的即时消息服务器，支持<code>Matrix协议</code>。</p><h1>其他常见容器</h1><h2 id="工具容器">工具容器</h2><ul><li>BusyBox</li></ul><p>集成了许多常用 UNIX 工具的单一可执行文件。</p><ul><li>Alpine Linux</li></ul><p>基于musl libc和busybox的轻量级Linux发行版。</p><h2 id="游戏服务器容器">游戏服务器容器</h2><ul><li>Minecraft Server</li></ul><p>流行的沙盒游戏Minecraft的服务器。</p><ul><li>SteamCMD</li></ul><p>用于管理和更新Steam游戏服务器的命令行工具。</p><h1>总结</h1><p>容器技术为各种应用场景提供了灵活、高效的解决方案。通过使用这些常见的容器，您可以快速搭建和部署各种应用和服务，提高开发和运维效率。随着容器生态系统的不断发展，新的容器类型和工具也在不断涌现，为开发者提供了更多选择。</p></div><script src="https://cdn.jsdelivr.net/lightgallery.js/1.0.1/js/lightgallery.min.js"></script><script>if (typeof lightGallery !== 'undefined') {        var options = {            selector: '.gallery-item'        };        lightGallery(document.getElementsByClassName('.article-gallery')[0], options);        }</script>]]></content>
    
    
    <summary type="html">几种常见的容器类型机器用途</summary>
    
    
    
    <category term="容器与虚拟化" scheme="https://opsuri.com/categories/%E5%AE%B9%E5%99%A8%E4%B8%8E%E8%99%9A%E6%8B%9F%E5%8C%96/"/>
    
    
    <category term="Kubernetes" scheme="https://opsuri.com/tags/Kubernetes/"/>
    
    <category term="虚拟化" scheme="https://opsuri.com/tags/%E8%99%9A%E6%8B%9F%E5%8C%96/"/>
    
    <category term="容器" scheme="https://opsuri.com/tags/%E5%AE%B9%E5%99%A8/"/>
    
    <category term="containers" scheme="https://opsuri.com/tags/containers/"/>
    
  </entry>
  
  <entry>
    <title>快速入门kubernetes</title>
    <link href="https://opsuri.com/2020/07/14/Quick-Start-Kubernetes/"/>
    <id>https://opsuri.com/2020/07/14/Quick-Start-Kubernetes/</id>
    <published>2020-07-14T10:54:38.000Z</published>
    <updated>2025-02-22T14:27:21.693Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/lightgallery.js/1.0.1/css/lightgallery.min.css" /><div class=".article-gallery"><h1>理解 Kubernetes 核心概念</h1><h2 id="集群（Cluster）">集群（Cluster）</h2><ul><li><code>Master节点</code></li></ul><p>负责管理整个集群，包括调度、监控、维护集群状态等。</p><ul><li><code>Node节点</code></li></ul><p>运行容器化应用的机器，每个节点上都有 Kubelet 和容器运行时（如 Docker）。</p><h2 id="Pod">Pod</h2><ul><li>最小部署单元：一个 Pod 可以包含一个或多个容器，这些容器共享网络和存储资源。</li></ul><h2 id="服务（Service）">服务（Service）</h2><ul><li>服务发现与负载均衡：Service 为一组 Pod 提供稳定的网络端点，实现负载均衡和服务发现。</li></ul><h2 id="部署（Deployment）">部署（Deployment）</h2><span id="more"></span><ul><li>声明式更新：Deployment 用于定义 Pod 的部署和更新策略，支持滚动更新和回滚。</li></ul><h2 id="配置管理">配置管理</h2><ul><li>ConfigMap：用于存储非敏感的配置数据。</li><li>Secret：用于存储敏感信息，如密码、密钥等。</li></ul><h1>安装 Kubernetes</h1><h2 id="本地环境">本地环境</h2><ul><li>Minikube</li></ul><p>用于在本地快速搭建单节点 Kubernetes 集群。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">brew install minikube</span><br><span class="line">minikube start</span><br></pre></td></tr></table></figure><ul><li>kubectl</li></ul><p>Kubernetes 命令行工具，用于与集群交互。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">brew install kubectl</span><br></pre></td></tr></table></figure><h2 id="生产环境">生产环境</h2><ul><li><code>kubeadm</code></li></ul><p>用于在生产环境中快速搭建多节点 Kubernetes 集群。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> apt-get update &amp;&amp; <span class="built_in">sudo</span> apt-get install -y kubeadm kubelet kubectl</span><br><span class="line"><span class="built_in">sudo</span> kubeadm init</span><br></pre></td></tr></table></figure><h1>基本操作</h1><h2 id="创建Pod">创建<code>Pod</code></h2><ul><li><code>YAML文件</code></li></ul><p>定义一个简单的 Pod。</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">apiVersion:</span> <span class="string">v1</span></span><br><span class="line"><span class="attr">kind:</span> <span class="string">Pod</span></span><br><span class="line"><span class="attr">metadata:</span></span><br><span class="line">  <span class="attr">name:</span> <span class="string">my-pod</span></span><br><span class="line"><span class="attr">spec:</span></span><br><span class="line">  <span class="attr">containers:</span></span><br><span class="line">  <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">my-container</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">nginx</span></span><br></pre></td></tr></table></figure><ul><li>创建Pod</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kubectl apply -f pod.yaml</span><br></pre></td></tr></table></figure><h2 id="创建Deployment">创建<code>Deployment</code></h2><ul><li>YAML文件<br>定义一个简单的 Deployment。</li></ul><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">apiVersion:</span> <span class="string">apps/v1</span></span><br><span class="line"><span class="attr">kind:</span> <span class="string">Deployment</span></span><br><span class="line"><span class="attr">metadata:</span></span><br><span class="line">  <span class="attr">name:</span> <span class="string">my-deployment</span></span><br><span class="line"><span class="attr">spec:</span></span><br><span class="line">  <span class="attr">replicas:</span> <span class="number">3</span></span><br><span class="line">  <span class="attr">selector:</span></span><br><span class="line">    <span class="attr">matchLabels:</span></span><br><span class="line">      <span class="attr">app:</span> <span class="string">my-app</span></span><br><span class="line">  <span class="attr">template:</span></span><br><span class="line">    <span class="attr">metadata:</span></span><br><span class="line">      <span class="attr">labels:</span></span><br><span class="line">        <span class="attr">app:</span> <span class="string">my-app</span></span><br><span class="line">    <span class="attr">spec:</span></span><br><span class="line">      <span class="attr">containers:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">my-container</span></span><br><span class="line">        <span class="attr">image:</span> <span class="string">nginx</span></span><br></pre></td></tr></table></figure><ul><li>创建<code>Deployment</code></li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kubectl apply -f deployment.yaml</span><br></pre></td></tr></table></figure><h2 id="创建Service">创建<code>Service</code></h2><ul><li>YAML 文件<br>定义一个简单的<code>Service</code>。</li></ul><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">apiVersion:</span> <span class="string">v1</span></span><br><span class="line"><span class="attr">kind:</span> <span class="string">Service</span></span><br><span class="line"><span class="attr">metadata:</span></span><br><span class="line">  <span class="attr">name:</span> <span class="string">my-service</span></span><br><span class="line"><span class="attr">spec:</span></span><br><span class="line">  <span class="attr">selector:</span></span><br><span class="line">    <span class="attr">app:</span> <span class="string">my-app</span></span><br><span class="line">  <span class="attr">ports:</span></span><br><span class="line">  <span class="bullet">-</span> <span class="attr">protocol:</span> <span class="string">TCP</span></span><br><span class="line">    <span class="attr">port:</span> <span class="number">80</span></span><br><span class="line">    <span class="attr">targetPort:</span> <span class="number">80</span></span><br></pre></td></tr></table></figure><p>创建<code>Service</code></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kubectl apply -f service.yaml</span><br></pre></td></tr></table></figure><h1>常用命令</h1><h2 id="查看资源状态">查看资源状态</h2><ul><li>查看<code>Pod</code></li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kubectl get pods</span><br></pre></td></tr></table></figure><ul><li>查看<code>Deployment</code></li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kubectl get deployments</span><br></pre></td></tr></table></figure><ul><li>查看<code>Service</code></li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kubectl get services</span><br></pre></td></tr></table></figure><h2 id="日志与调试">日志与调试</h2><ul><li>查看<code>Pod日志</code></li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kubectl logs &lt;pod-name&gt;</span><br></pre></td></tr></table></figure><ul><li>进入<code>Pod容器</code></li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kubectl <span class="built_in">exec</span> -it &lt;pod-name&gt; -- /bin/bash</span><br></pre></td></tr></table></figure><h2 id="删除资源">删除资源</h2><ul><li>删除<code>Pod</code></li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kubectl delete pod &lt;pod-name&gt;</span><br></pre></td></tr></table></figure><ul><li>删除<code>Deployment</code></li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kubectl delete deployment &lt;deployment-name&gt;</span><br></pre></td></tr></table></figure><ul><li>删除<code>Service</code></li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kubectl delete service &lt;service-name&gt;</span><br></pre></td></tr></table></figure><h1>进阶学习</h1><h2 id="配置管理-2">配置管理</h2><ul><li><code>ConfigMap</code></li></ul><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">apiVersion:</span> <span class="string">v1</span></span><br><span class="line"><span class="attr">kind:</span> <span class="string">ConfigMap</span></span><br><span class="line"><span class="attr">metadata:</span></span><br><span class="line">  <span class="attr">name:</span> <span class="string">my-config</span></span><br><span class="line"><span class="attr">data:</span></span><br><span class="line">  <span class="attr">key:</span> <span class="string">value</span></span><br></pre></td></tr></table></figure><ul><li><code>Secret</code></li></ul><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">apiVersion:</span> <span class="string">v1</span></span><br><span class="line"><span class="attr">kind:</span> <span class="string">Secret</span></span><br><span class="line"><span class="attr">metadata:</span></span><br><span class="line">  <span class="attr">name:</span> <span class="string">my-secret</span></span><br><span class="line"><span class="attr">type:</span> <span class="string">Opaque</span></span><br><span class="line"><span class="attr">data:</span></span><br><span class="line">  <span class="attr">username:</span> <span class="string">&lt;base64-encoded-username&gt;</span></span><br><span class="line">  <span class="attr">password:</span> <span class="string">&lt;base64-encoded-password&gt;</span></span><br></pre></td></tr></table></figure><h2 id="持久化存储">持久化存储</h2><ul><li><code>PersistentVolume</code>(PV)</li></ul><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">apiVersion:</span> <span class="string">v1</span></span><br><span class="line"><span class="attr">kind:</span> <span class="string">PersistentVolume</span></span><br><span class="line"><span class="attr">metadata:</span></span><br><span class="line">  <span class="attr">name:</span> <span class="string">my-pv</span></span><br><span class="line"><span class="attr">spec:</span></span><br><span class="line">  <span class="attr">capacity:</span></span><br><span class="line">    <span class="attr">storage:</span> <span class="string">10Gi</span></span><br><span class="line">  <span class="attr">accessModes:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">ReadWriteOnce</span></span><br><span class="line">  <span class="attr">hostPath:</span></span><br><span class="line">    <span class="attr">path:</span> <span class="string">/mnt/data</span></span><br></pre></td></tr></table></figure><ul><li><code>PersistentVolumeClaim</code>(PVC)</li></ul><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">apiVersion:</span> <span class="string">v1</span></span><br><span class="line"><span class="attr">kind:</span> <span class="string">PersistentVolumeClaim</span></span><br><span class="line"><span class="attr">metadata:</span></span><br><span class="line">  <span class="attr">name:</span> <span class="string">my-pvc</span></span><br><span class="line"><span class="attr">spec:</span></span><br><span class="line">  <span class="attr">accessModes:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">ReadWriteOnce</span></span><br><span class="line">  <span class="attr">resources:</span></span><br><span class="line">    <span class="attr">requests:</span></span><br><span class="line">      <span class="attr">storage:</span> <span class="string">10Gi</span></span><br></pre></td></tr></table></figure><h2 id="自动扩展">自动扩展</h2><ul><li>Horizontal Pod Autoscaler (HPA)</li></ul><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">apiVersion:</span> <span class="string">autoscaling/v1</span></span><br><span class="line"><span class="attr">kind:</span> <span class="string">HorizontalPodAutoscaler</span></span><br><span class="line"><span class="attr">metadata:</span></span><br><span class="line">  <span class="attr">name:</span> <span class="string">my-hpa</span></span><br><span class="line"><span class="attr">spec:</span></span><br><span class="line">  <span class="attr">scaleTargetRef:</span></span><br><span class="line">    <span class="attr">apiVersion:</span> <span class="string">apps/v1</span></span><br><span class="line">    <span class="attr">kind:</span> <span class="string">Deployment</span></span><br><span class="line">    <span class="attr">name:</span> <span class="string">my-deployment</span></span><br><span class="line">  <span class="attr">minReplicas:</span> <span class="number">1</span></span><br><span class="line">  <span class="attr">maxReplicas:</span> <span class="number">10</span></span><br><span class="line">  <span class="attr">targetCPUUtilizationPercentage:</span> <span class="number">80</span></span><br></pre></td></tr></table></figure><h1>学习资源</h1><ul><li>官方文档：<a href="https://kubernetes.io/zh-cn/docs/">Kubernetes 官方文档</a></li><li>在线课程：Coursera、Udemy 等平台上的 Kubernetes 课程。</li><li>书籍：《Kubernetes in Action》、《Kubernetes Up &amp; Running》等。<br>通过以上步骤，您可以快速入门 Kubernetes，并逐步掌握其核心概念和基本操作。随着实践的深入，您将能够更好地理解和应用 Kubernetes 的强大功能。</li></ul></div><script src="https://cdn.jsdelivr.net/lightgallery.js/1.0.1/js/lightgallery.min.js"></script><script>if (typeof lightGallery !== 'undefined') {        var options = {            selector: '.gallery-item'        };        lightGallery(document.getElementsByClassName('.article-gallery')[0], options);        }</script>]]></content>
    
    
    <summary type="html">快速入门kubernetes，快速上手kubernetes。</summary>
    
    
    
    <category term="容器与虚拟化" scheme="https://opsuri.com/categories/%E5%AE%B9%E5%99%A8%E4%B8%8E%E8%99%9A%E6%8B%9F%E5%8C%96/"/>
    
    
    <category term="Kubernetes" scheme="https://opsuri.com/tags/Kubernetes/"/>
    
    <category term="虚拟化" scheme="https://opsuri.com/tags/%E8%99%9A%E6%8B%9F%E5%8C%96/"/>
    
  </entry>
  
  <entry>
    <title>编译安装最新版Grafana v6.6.0-pre</title>
    <link href="https://opsuri.com/2019/12/02/Building-Install-Grafana-WeChat-Image-Renderer/"/>
    <id>https://opsuri.com/2019/12/02/Building-Install-Grafana-WeChat-Image-Renderer/</id>
    <published>2019-12-02T11:15:14.000Z</published>
    <updated>2025-02-22T12:55:35.027Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/lightgallery.js/1.0.1/css/lightgallery.min.css" /><div class=".article-gallery"><p>编译安装最新版Grafana v6.6.0-pre<br>–含企业微信告警及告警图片</p><h1>安装go及node</h1><p>版本需求：go1.13.3<br>node12.13.1<br>配置好$NODE_HOME、$GOROOT变量，请不要配置$GOPATH变量。具体配置请参阅其他资料。这里就不再赘述了。<br>检查输出：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">[root@opstrip grafana]# go version</span><br><span class="line">go version go1.13.3 linux/amd64</span><br><span class="line">[root@opstrip grafana]# node -v</span><br><span class="line">v12.13.1</span><br></pre></td></tr></table></figure><h1>编译安装Grafana</h1><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">[root@opstrip ~]# cd /usr/local</span><br><span class="line">[root@opstrip local]# git clone https://github.com/grafana/grafana.git     # 拉取grafana项目源码</span><br></pre></td></tr></table></figure><span id="more"></span><h3 id="添加企业微信告警模块">添加企业微信告警模块</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">[root@opstrip local]# cd /usr/local/grafana/pkg/services/alerting/notifiers</span><br></pre></td></tr></table></figure><p>分别将下面2个文件放入到该目录下：<br><code>wechat.go</code></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br><span class="line">297</span><br><span class="line">298</span><br><span class="line">299</span><br><span class="line">300</span><br><span class="line">301</span><br><span class="line">302</span><br><span class="line">303</span><br><span class="line">304</span><br><span class="line">305</span><br><span class="line">306</span><br><span class="line">307</span><br><span class="line">308</span><br><span class="line">309</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> notifiers</span><br><span class="line">    </span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line">    <span class="string">&quot;bytes&quot;</span></span><br><span class="line">    <span class="string">&quot;encoding/json&quot;</span></span><br><span class="line">    <span class="string">&quot;fmt&quot;</span></span><br><span class="line">    <span class="string">&quot;io&quot;</span></span><br><span class="line">    <span class="string">&quot;mime/multipart&quot;</span></span><br><span class="line">    <span class="string">&quot;net/http&quot;</span></span><br><span class="line">    <span class="string">&quot;os&quot;</span></span><br><span class="line">    <span class="string">&quot;strconv&quot;</span></span><br><span class="line">    </span><br><span class="line">    <span class="string">&quot;golang.org/x/net/context&quot;</span></span><br><span class="line">    <span class="string">&quot;golang.org/x/net/context/ctxhttp&quot;</span></span><br><span class="line">    </span><br><span class="line">    <span class="string">&quot;github.com/grafana/grafana/pkg/bus&quot;</span></span><br><span class="line">    <span class="string">&quot;github.com/grafana/grafana/pkg/components/simplejson&quot;</span></span><br><span class="line">    <span class="string">&quot;github.com/grafana/grafana/pkg/infra/log&quot;</span></span><br><span class="line">    m <span class="string">&quot;github.com/grafana/grafana/pkg/models&quot;</span></span><br><span class="line">    <span class="string">&quot;github.com/grafana/grafana/pkg/services/alerting&quot;</span></span><br><span class="line">)</span><br><span class="line">    </span><br><span class="line"><span class="keyword">type</span> WeChatToken <span class="keyword">struct</span> &#123;</span><br><span class="line">    AccessToken <span class="type">string</span> <span class="string">`json:&quot;access_token&quot;`</span></span><br><span class="line">    ErrMsg      <span class="type">string</span> <span class="string">`json:&quot;errmsg&quot;`</span></span><br><span class="line">    ErrCode     <span class="type">int</span>    <span class="string">`json:&quot;errcode&quot;`</span></span><br><span class="line">    ExpireIn    <span class="type">int</span>    <span class="string">`json:&quot;expire_in&quot;`</span></span><br><span class="line">&#125;</span><br><span class="line">    </span><br><span class="line"><span class="keyword">type</span> WeChatMediaId <span class="keyword">struct</span> &#123;</span><br><span class="line">    MediaId <span class="type">string</span> <span class="string">`json:&quot;media_id&quot;`</span></span><br><span class="line">    ErrMsg  <span class="type">string</span> <span class="string">`json:&quot;errmsg&quot;`</span></span><br><span class="line">    ErrCode <span class="type">int</span>    <span class="string">`json:&quot;errcode&quot;`</span></span><br><span class="line">    CreatAt <span class="type">string</span> <span class="string">`json:&quot;created_at&quot;`</span></span><br><span class="line">    Type    <span class="type">string</span> <span class="string">`json:&quot;type&quot;`</span></span><br><span class="line">&#125;</span><br><span class="line">    </span><br><span class="line"><span class="keyword">const</span> (</span><br><span class="line">    SEND_MESSAGE_ENDPOINT <span class="type">string</span> = <span class="string">&quot;https://qyapi.weixin.qq.com/cgi-bin/message/send&quot;</span></span><br><span class="line">    UPLOAD_IMAGE_ENDPOINT <span class="type">string</span> = <span class="string">&quot;https://qyapi.weixin.qq.com/cgi-bin/media/upload&quot;</span></span><br><span class="line">    GET_TOKEN_ENDPOINT    <span class="type">string</span> = <span class="string">&quot;https://qyapi.weixin.qq.com/cgi-bin/gettoken&quot;</span></span><br><span class="line">)</span><br><span class="line">    </span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">init</span><span class="params">()</span></span> &#123;</span><br><span class="line">    alerting.RegisterNotifier(&amp;alerting.NotifierPlugin&#123;</span><br><span class="line">        Type:        <span class="string">&quot;wechat&quot;</span>,</span><br><span class="line">        Name:        <span class="string">&quot;WeChat&quot;</span>,</span><br><span class="line">        Description: <span class="string">&quot;Sends HTTP POST request to WeChat&quot;</span>,</span><br><span class="line">        Factory:     NewWeChatNotifier,</span><br><span class="line">        OptionsTemplate: <span class="string">`</span></span><br><span class="line"><span class="string">      &lt;h3 class=&quot;page-heading&quot;&gt;WeChat settings&lt;/h3&gt;</span></span><br><span class="line"><span class="string">      &lt;div class=&quot;gf-form&quot;&gt;</span></span><br><span class="line"><span class="string">        &lt;span class=&quot;gf-form-label width-10&quot;&gt;AgentId&lt;/span&gt;</span></span><br><span class="line"><span class="string">        &lt;input type=&quot;text&quot; required class=&quot;gf-form-input max-width-26&quot; ng-model=&quot;ctrl.model.settings.agentid&quot;&gt;&lt;/input&gt;</span></span><br><span class="line"><span class="string">      &lt;/div&gt;</span></span><br><span class="line"><span class="string">      &lt;div class=&quot;gf-form&quot;&gt;</span></span><br><span class="line"><span class="string">        &lt;span class=&quot;gf-form-label width-10&quot;&gt;CorpId&lt;/span&gt;</span></span><br><span class="line"><span class="string">        &lt;input type=&quot;text&quot; required class=&quot;gf-form-input max-width-26&quot; ng-model=&quot;ctrl.model.settings.corpid&quot;&gt;&lt;/input&gt;</span></span><br><span class="line"><span class="string">      &lt;/div&gt;</span></span><br><span class="line"><span class="string">      &lt;div class=&quot;gf-form&quot;&gt;</span></span><br><span class="line"><span class="string">        &lt;span class=&quot;gf-form-label width-10&quot;&gt;Secret&lt;/span&gt;</span></span><br><span class="line"><span class="string">        &lt;input type=&quot;text&quot; required class=&quot;gf-form-input max-width-26&quot; ng-model=&quot;ctrl.model.settings.secret&quot;&gt;&lt;/input&gt;</span></span><br><span class="line"><span class="string">      &lt;/div&gt;</span></span><br><span class="line"><span class="string">      &lt;div class=&quot;gf-form&quot;&gt;</span></span><br><span class="line"><span class="string">        &lt;span class=&quot;gf-form-label width-10&quot;&gt;ToUser&lt;/span&gt;</span></span><br><span class="line"><span class="string">        &lt;input type=&quot;text&quot; required class=&quot;gf-form-input max-width-26&quot; ng-model=&quot;ctrl.model.settings.touser&quot;&gt;&lt;/input&gt;</span></span><br><span class="line"><span class="string">      &lt;/div&gt;</span></span><br><span class="line"><span class="string">    `</span>,</span><br><span class="line">    &#125;)</span><br><span class="line">&#125;</span><br><span class="line">    </span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">NewWeChatNotifier</span><span class="params">(model *m.AlertNotification)</span></span> (alerting.Notifier, <span class="type">error</span>) &#123;</span><br><span class="line">    agentid := model.Settings.Get(<span class="string">&quot;agentid&quot;</span>).MustString()</span><br><span class="line">    <span class="keyword">if</span> agentid == <span class="string">&quot;&quot;</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">nil</span>, alerting.ValidationError&#123;Reason: <span class="string">&quot;Could not find agentid property in settings&quot;</span>&#125;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    corpid := model.Settings.Get(<span class="string">&quot;corpid&quot;</span>).MustString()</span><br><span class="line">    <span class="keyword">if</span> corpid == <span class="string">&quot;&quot;</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">nil</span>, alerting.ValidationError&#123;Reason: <span class="string">&quot;Could not find corpid property in settings&quot;</span>&#125;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    secret := model.Settings.Get(<span class="string">&quot;secret&quot;</span>).MustString()</span><br><span class="line">    <span class="keyword">if</span> secret == <span class="string">&quot;&quot;</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">nil</span>, alerting.ValidationError&#123;Reason: <span class="string">&quot;Could not find secret property in settings&quot;</span>&#125;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    touser := model.Settings.Get(<span class="string">&quot;touser&quot;</span>).MustString()</span><br><span class="line">    <span class="keyword">if</span> touser == <span class="string">&quot;&quot;</span> &#123;</span><br><span class="line">        touser = <span class="string">&quot;@all&quot;</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">return</span> &amp;WeChatNotifier&#123;</span><br><span class="line">        NotifierBase: NewNotifierBase(model),</span><br><span class="line">        AgentId:      agentid,</span><br><span class="line">        CorpId:       corpid,</span><br><span class="line">        Secret:       secret,</span><br><span class="line">        ToUser:       touser,</span><br><span class="line">        log:          log.New(<span class="string">&quot;alerting.notifier.wechat&quot;</span>),</span><br><span class="line">    &#125;, <span class="literal">nil</span></span><br><span class="line">&#125;</span><br><span class="line">    </span><br><span class="line"><span class="keyword">type</span> WeChatNotifier <span class="keyword">struct</span> &#123;</span><br><span class="line">    NotifierBase</span><br><span class="line">    AgentId <span class="type">string</span></span><br><span class="line">    CorpId  <span class="type">string</span></span><br><span class="line">    Secret  <span class="type">string</span></span><br><span class="line">    ToUser  <span class="type">string</span></span><br><span class="line">    log     log.Logger</span><br><span class="line">&#125;</span><br><span class="line">    </span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(this *WeChatNotifier)</span></span> GetMediaId(path, token <span class="type">string</span>) (<span class="type">string</span>, <span class="type">error</span>) &#123;</span><br><span class="line">    <span class="keyword">var</span> mediaId <span class="type">string</span></span><br><span class="line">    </span><br><span class="line">    <span class="keyword">var</span> b bytes.Buffer</span><br><span class="line">    w := multipart.NewWriter(&amp;b)</span><br><span class="line">    </span><br><span class="line">    f, err := os.Open(path)</span><br><span class="line">    <span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> mediaId, err</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">defer</span> f.Close()</span><br><span class="line">    </span><br><span class="line">    fw, err := w.CreateFormFile(<span class="string">&quot;media&quot;</span>, path)</span><br><span class="line">    <span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> mediaId, err</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    _, err = io.Copy(fw, f)</span><br><span class="line">    <span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> mediaId, err</span><br><span class="line">    &#125;</span><br><span class="line">    w.Close()</span><br><span class="line">    </span><br><span class="line">    url := fmt.Sprintf(UPLOAD_IMAGE_ENDPOINT+<span class="string">&quot;?access_token=%s&amp;type=image&quot;</span>, token)</span><br><span class="line">    request, err := http.NewRequest(http.MethodPost, url, &amp;b)</span><br><span class="line">    <span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> mediaId, err</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    request.Header.Add(<span class="string">&quot;Content-Type&quot;</span>, w.FormDataContentType())</span><br><span class="line">    request.Header.Add(<span class="string">&quot;User-Agent&quot;</span>, <span class="string">&quot;Grafana&quot;</span>)</span><br><span class="line">    </span><br><span class="line">    resp, err := ctxhttp.Do(context.TODO(), http.DefaultClient, request)</span><br><span class="line">    <span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> mediaId, err</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">if</span> resp.StatusCode/<span class="number">100</span> != <span class="number">2</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> mediaId, fmt.Errorf(<span class="string">&quot;WeChat returned statuscode invalid status code: %v&quot;</span>, resp.Status)</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">defer</span> resp.Body.Close()</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">var</span> wechatMediaId WeChatMediaId</span><br><span class="line">    err = json.NewDecoder(resp.Body).Decode(&amp;wechatMediaId)</span><br><span class="line">    <span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> mediaId, err</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">if</span> wechatMediaId.ErrCode != <span class="number">0</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> mediaId, fmt.Errorf(<span class="string">&quot;WeChat returned errmsg: %s&quot;</span>, wechatMediaId.ErrMsg)</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">return</span> wechatMediaId.MediaId, <span class="literal">nil</span></span><br><span class="line">&#125;</span><br><span class="line">    </span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(this *WeChatNotifier)</span></span> GetAccessToken() (<span class="type">string</span>, <span class="type">error</span>) &#123;</span><br><span class="line">    <span class="keyword">var</span> token <span class="type">string</span></span><br><span class="line">    </span><br><span class="line">    url := fmt.Sprintf(GET_TOKEN_ENDPOINT+<span class="string">&quot;?corpid=%s&amp;corpsecret=%s&quot;</span>, this.CorpId, this.Secret)</span><br><span class="line">    request, err := http.NewRequest(http.MethodPost, url, <span class="literal">nil</span>)</span><br><span class="line">    <span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> token, err</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    request.Header.Add(<span class="string">&quot;Content-Type&quot;</span>, <span class="string">&quot;application/json&quot;</span>)</span><br><span class="line">    request.Header.Add(<span class="string">&quot;User-Agent&quot;</span>, <span class="string">&quot;Grafana&quot;</span>)</span><br><span class="line">    </span><br><span class="line">    resp, err := ctxhttp.Do(context.TODO(), http.DefaultClient, request)</span><br><span class="line">    <span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> token, err</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">if</span> resp.StatusCode/<span class="number">100</span> != <span class="number">2</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> token, fmt.Errorf(<span class="string">&quot;WeChat returned statuscode invalid status code: %v&quot;</span>, resp.Status)</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">defer</span> resp.Body.Close()</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">var</span> wechatToken WeChatToken</span><br><span class="line">    err = json.NewDecoder(resp.Body).Decode(&amp;wechatToken)</span><br><span class="line">    <span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> token, err</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">if</span> wechatToken.ErrCode != <span class="number">0</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> token, fmt.Errorf(<span class="string">&quot;WeChat returned errmsg: %s&quot;</span>, wechatToken.ErrMsg)</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> wechatToken.AccessToken, <span class="literal">nil</span></span><br><span class="line">&#125;</span><br><span class="line">    </span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(this *WeChatNotifier)</span></span> PushImage(evalContext *alerting.EvalContext, token <span class="type">string</span>) <span class="type">error</span> &#123;</span><br><span class="line">    mediaId, err := this.GetMediaId(evalContext.ImageOnDiskPath, token)</span><br><span class="line">    <span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> err</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    bodyJSON, err := simplejson.NewJson([]<span class="type">byte</span>(<span class="string">`&#123;</span></span><br><span class="line"><span class="string">        &quot;touser&quot;: &quot;`</span> + this.ToUser + <span class="string">`&quot;,</span></span><br><span class="line"><span class="string">        &quot;msgtype&quot; : &quot;image&quot;,</span></span><br><span class="line"><span class="string">        &quot;agentid&quot;: &quot;`</span> + this.AgentId + <span class="string">`&quot;,</span></span><br><span class="line"><span class="string">        &quot;image&quot; : &#123;</span></span><br><span class="line"><span class="string">                &quot;media_id&quot;: &quot;`</span> + mediaId + <span class="string">`&quot;</span></span><br><span class="line"><span class="string">        &#125;</span></span><br><span class="line"><span class="string">    &#125;`</span>))</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">        this.log.Error(<span class="string">&quot;Failed to create Json data&quot;</span>, <span class="string">&quot;error&quot;</span>, err, <span class="string">&quot;wechat&quot;</span>, this.Name)</span><br><span class="line">        <span class="keyword">return</span> err</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    body, _ := bodyJSON.MarshalJSON()</span><br><span class="line">    </span><br><span class="line">    url := fmt.Sprintf(SEND_MESSAGE_ENDPOINT+<span class="string">&quot;?access_token=%s&quot;</span>, token)</span><br><span class="line">    cmd := &amp;m.SendWebhookSync&#123;</span><br><span class="line">        Url:  url,</span><br><span class="line">        Body: <span class="type">string</span>(body),</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">if</span> err := bus.DispatchCtx(evalContext.Ctx, cmd); err != <span class="literal">nil</span> &#123;</span><br><span class="line">        this.log.Error(<span class="string">&quot;Failed to send WeChat&quot;</span>, <span class="string">&quot;error&quot;</span>, err, <span class="string">&quot;wechat&quot;</span>, this.Name)</span><br><span class="line">        <span class="keyword">return</span> err</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">return</span> <span class="literal">nil</span></span><br><span class="line">&#125;</span><br><span class="line">    </span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(this *WeChatNotifier)</span></span> Notify(evalContext *alerting.EvalContext) <span class="type">error</span> &#123;</span><br><span class="line">    this.log.Info(<span class="string">&quot;Sending wechat&quot;</span>)</span><br><span class="line">    </span><br><span class="line">    token, err := this.GetAccessToken()</span><br><span class="line">    <span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">        this.log.Error(<span class="string">&quot;Get AccessToken failed&quot;</span>, err)</span><br><span class="line">        <span class="keyword">return</span> err</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    content := evalContext.GetNotificationTitle()</span><br><span class="line">    content += <span class="string">&quot;\\n\\n&quot;</span></span><br><span class="line">    </span><br><span class="line">    <span class="keyword">if</span> evalContext.Rule.State != m.AlertStateOK &#123;</span><br><span class="line">        content += <span class="string">&quot;Message:\\n  &quot;</span> + evalContext.Rule.Message + <span class="string">&quot;\\n\\n&quot;</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">for</span> index, evt := <span class="keyword">range</span> evalContext.EvalMatches &#123;</span><br><span class="line">        <span class="keyword">if</span> index == <span class="number">0</span> &#123;</span><br><span class="line">            content += <span class="string">&quot;Metric:\\n&quot;</span></span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">if</span> index &gt; <span class="number">4</span> &#123;</span><br><span class="line">            content += <span class="string">&quot;  ...\\n&quot;</span></span><br><span class="line">            <span class="keyword">break</span></span><br><span class="line">        &#125;</span><br><span class="line">        content += <span class="string">&quot;  &quot;</span> + evt.Metric + <span class="string">&quot;=&quot;</span> + strconv.FormatFloat(evt.Value.Float64, <span class="string">&#x27;f&#x27;</span>, <span class="number">-1</span>, <span class="number">64</span>) + <span class="string">&quot;\\n&quot;</span></span><br><span class="line">    &#125;</span><br><span class="line">    content += <span class="string">&quot;\\n&quot;</span></span><br><span class="line">    </span><br><span class="line">    <span class="keyword">if</span> evalContext.Error != <span class="literal">nil</span> &#123;</span><br><span class="line">        content += <span class="string">&quot;Error:\\n  &quot;</span> + evalContext.Error.Error() + <span class="string">&quot;\\n\\n&quot;</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">if</span> evalContext.ImageOnDiskPath == <span class="string">&quot;&quot;</span> &amp;&amp; evalContext.ImagePublicURL != <span class="string">&quot;&quot;</span> &#123;</span><br><span class="line">        content += <span class="string">&quot;ImageUrl:\\n  &quot;</span> + evalContext.ImagePublicURL + <span class="string">&quot;\\n&quot;</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    bodyJSON, err := simplejson.NewJson([]<span class="type">byte</span>(<span class="string">`&#123;</span></span><br><span class="line"><span class="string">        &quot;touser&quot;: &quot;`</span> + this.ToUser + <span class="string">`&quot;,</span></span><br><span class="line"><span class="string">        &quot;msgtype&quot; : &quot;text&quot;,</span></span><br><span class="line"><span class="string">        &quot;agentid&quot;: &quot;`</span> + this.AgentId + <span class="string">`&quot;,</span></span><br><span class="line"><span class="string">        &quot;text&quot; : &#123;</span></span><br><span class="line"><span class="string">                &quot;content&quot;: &quot;`</span> + content + <span class="string">`&quot;</span></span><br><span class="line"><span class="string">        &#125;</span></span><br><span class="line"><span class="string">    &#125;`</span>))</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">        this.log.Error(<span class="string">&quot;Failed to create Json data&quot;</span>, <span class="string">&quot;error&quot;</span>, err, <span class="string">&quot;wechat&quot;</span>, this.Name)</span><br><span class="line">        <span class="keyword">return</span> err</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    body, _ := bodyJSON.MarshalJSON()</span><br><span class="line">    </span><br><span class="line">    url := fmt.Sprintf(SEND_MESSAGE_ENDPOINT+<span class="string">&quot;?access_token=%s&quot;</span>, token)</span><br><span class="line">    cmd := &amp;m.SendWebhookSync&#123;</span><br><span class="line">        Url:  url,</span><br><span class="line">        Body: <span class="type">string</span>(body),</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">if</span> err := bus.DispatchCtx(evalContext.Ctx, cmd); err != <span class="literal">nil</span> &#123;</span><br><span class="line">        this.log.Error(<span class="string">&quot;Failed to send WeChat&quot;</span>, <span class="string">&quot;error&quot;</span>, err, <span class="string">&quot;wechat&quot;</span>, this.Name)</span><br><span class="line">        <span class="keyword">return</span> err</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">if</span> evalContext.ImageOnDiskPath != <span class="string">&quot;&quot;</span> &#123;</span><br><span class="line">        err := this.PushImage(evalContext, token)</span><br><span class="line">        <span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">            this.log.Error(<span class="string">&quot;Failed to Push Image&quot;</span>, <span class="string">&quot;error&quot;</span>, err, <span class="string">&quot;path&quot;</span>, evalContext.ImageOnDiskPath)</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">return</span> <span class="literal">nil</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><code>wechat_test.go</code></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> notifiers</span><br><span class="line">    </span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line">    <span class="string">&quot;testing&quot;</span></span><br><span class="line">    </span><br><span class="line">    <span class="string">&quot;github.com/grafana/grafana/pkg/components/simplejson&quot;</span></span><br><span class="line">    m <span class="string">&quot;github.com/grafana/grafana/pkg/models&quot;</span></span><br><span class="line">    . <span class="string">&quot;github.com/smartystreets/goconvey/convey&quot;</span></span><br><span class="line">)</span><br><span class="line">    </span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">TestWeChatNotifier</span><span class="params">(t *testing.T)</span></span> &#123;</span><br><span class="line">    Convey(<span class="string">&quot;WeChat notifier tests&quot;</span>, t, <span class="function"><span class="keyword">func</span><span class="params">()</span></span> &#123;</span><br><span class="line">        </span><br><span class="line">        Convey(<span class="string">&quot;Parsing alert notification from settings&quot;</span>, <span class="function"><span class="keyword">func</span><span class="params">()</span></span> &#123;</span><br><span class="line">            Convey(<span class="string">&quot;empty settings should return error&quot;</span>, <span class="function"><span class="keyword">func</span><span class="params">()</span></span> &#123;</span><br><span class="line">                json := <span class="string">`&#123; &#125;`</span></span><br><span class="line">                </span><br><span class="line">                settingsJSON, _ := simplejson.NewJson([]<span class="type">byte</span>(json))</span><br><span class="line">                model := &amp;m.AlertNotification&#123;</span><br><span class="line">                    Name:     <span class="string">&quot;wechat_testing&quot;</span>,</span><br><span class="line">                    Type:     <span class="string">&quot;wechat&quot;</span>,</span><br><span class="line">                    Settings: settingsJSON,</span><br><span class="line">                &#125;</span><br><span class="line">                </span><br><span class="line">                _, err := NewWeChatNotifier(model)</span><br><span class="line">                So(err, ShouldNotBeNil)</span><br><span class="line">            &#125;)</span><br><span class="line">            </span><br><span class="line">            Convey(<span class="string">&quot;from settings with agentid, corpid, secret, touser&quot;</span>, <span class="function"><span class="keyword">func</span><span class="params">()</span></span> &#123;</span><br><span class="line">                json := <span class="string">`</span></span><br><span class="line"><span class="string">                &#123;</span></span><br><span class="line"><span class="string">                    &quot;agentid&quot;: &quot;xxxx1&quot;,</span></span><br><span class="line"><span class="string">                    &quot;corpid&quot;: &quot;####1&quot;,</span></span><br><span class="line"><span class="string">                    &quot;secret&quot;: &quot;@@@@1&quot;,</span></span><br><span class="line"><span class="string">                    &quot;touser&quot;: &quot;oooo1&quot;</span></span><br><span class="line"><span class="string">                &#125;`</span></span><br><span class="line">                </span><br><span class="line">                settingsJSON, _ := simplejson.NewJson([]<span class="type">byte</span>(json))</span><br><span class="line">                model := &amp;m.AlertNotification&#123;</span><br><span class="line">                    Name:     <span class="string">&quot;wechat_testing&quot;</span>,</span><br><span class="line">                    Type:     <span class="string">&quot;wechat&quot;</span>,</span><br><span class="line">                    Settings: settingsJSON,</span><br><span class="line">                &#125;</span><br><span class="line">                </span><br><span class="line">                not, err := NewWeChatNotifier(model)</span><br><span class="line">                wechatNotifier := not.(*WeChatNotifier)</span><br><span class="line">                </span><br><span class="line">                So(err, ShouldBeNil)</span><br><span class="line">                So(wechatNotifier.Name, ShouldEqual, <span class="string">&quot;wechat_testing&quot;</span>)</span><br><span class="line">                So(wechatNotifier.Type, ShouldEqual, <span class="string">&quot;wechat&quot;</span>)</span><br><span class="line">                So(wechatNotifier.AgentId, ShouldEqual, <span class="string">&quot;xxxx1&quot;</span>)</span><br><span class="line">                So(wechatNotifier.CorpId, ShouldEqual, <span class="string">&quot;####1&quot;</span>)</span><br><span class="line">                So(wechatNotifier.Secret, ShouldEqual, <span class="string">&quot;@@@@1&quot;</span>)</span><br><span class="line">                So(wechatNotifier.ToUser, ShouldEqual, <span class="string">&quot;oooo1&quot;</span>)</span><br><span class="line">            &#125;)</span><br><span class="line">        &#125;)</span><br><span class="line">    &#125;)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>详见：<a href="https://github.com/wangriyu/docker-grafana">https://github.com/wangriyu/docker-grafana</a> ，以上文件有修改</p><h3 id="构建后端">构建后端</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">[root@opstrip notifiers]# cd /usr/local/grafana</span><br><span class="line">[root@opstrip grafana]# go run build.go setup</span><br><span class="line">[root@opstrip grafana]# go run build.go build</span><br></pre></td></tr></table></figure><p>编译完成后的二进制文件如下：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">[root@opstrip grafana]# pwd</span><br><span class="line">/usr/local/grafana</span><br><span class="line">[root@opstrip grafana]# ll bin/linux-amd64/</span><br><span class="line">总用量 63952</span><br><span class="line">-rwxr-xr-x 1 root root 19121704 11月 22 14:18 grafana-cli</span><br><span class="line">-rw-r--r-- 1 root root       33 11月 22 14:18 grafana-cli.md5</span><br><span class="line">-rwxr-xr-x 1 root root 46352720 11月 22 14:18 grafana-server</span><br><span class="line">-rw-r--r-- 1 root root       33 11月 22 14:18 grafana-server.md5</span><br><span class="line">[root@opstrip grafana]# </span><br></pre></td></tr></table></figure><h3 id="构建前端">构建前端</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">[root@opstrip grafana]# npm install -g yarn</span><br><span class="line">[root@opstrip grafana]# yum -y install bzip2</span><br><span class="line">[root@opstrip grafana]# yarn install --pure-lockfile</span><br><span class="line">[root@opstrip grafana]# npm run build</span><br></pre></td></tr></table></figure><p><strong>注意</strong>：这里可能会因为软件源及墙的问题导致的连接超时而出现依赖下载失败的问题，请根据报错更换为国内源或使用代理，更好的体验还是在国外机器上编译。机器要求至少有2GiB或以上的空闲内存。</p><h3 id="尝试运行Grafana">尝试运行Grafana</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">[root@opstrip grafana]# bin/linux-amd64/grafana-server</span><br></pre></td></tr></table></figure><p>若输出无报错则编译成功，否则请按错误提示逐一处理。</p><h1>将Grafana服务化以便于管理</h1><p>如果习惯了之前rpm安装的Grafana配置或者基于不影响编译环境的考虑，可以将编译的Grafana相应文件放到指定路径。以下操作仅供参考。<br>标准化Grafana：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">[root@opstrip grafana]# pwd</span><br><span class="line">/usr/local/grafana</span><br><span class="line">[root@opstrip grafana]# groupadd grafana &amp;&amp; useradd -d /usr/share/grafana -g grafana -s /sbin/nologin -c &quot;grafana user&quot; grafana</span><br><span class="line">[root@opstrip grafana]# mkdir -p /usr/share/grafana/&#123;conf,public,scripts,tools&#125; /var/lib/grafana/&#123;plugins,png&#125; /etc/grafana</span><br><span class="line">[root@opstrip grafana]# cp bin/linux-amd64/grafana-* /usr/sbin</span><br><span class="line">[root@opstrip grafana]# rsync -avz conf/* /etc/grafana/</span><br><span class="line">[root@opstrip grafana]# rsync -avz conf/* /usr/share/grafana/conf/</span><br><span class="line">[root@opstrip grafana]# rsync -avz public/* /usr/share/grafana/public/</span><br><span class="line">[root@opstrip grafana]# rsync -avz scripts/* /usr/share/grafana/scripts/</span><br><span class="line">[root@opstrip grafana]# rsync -avz tools/* /usr/share/grafana/tools/</span><br><span class="line">[root@opstrip grafana]# rsync -avz data/grafana.db /var/lib/grafana/</span><br><span class="line">[root@opstrip grafana]# chmod -R grafana:grafana /usr/share/grafana /var/lib/grafana</span><br></pre></td></tr></table></figure><h3 id="grafana-server环境变量">grafana-server环境变量</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line">[root@opstrip ~]# cat /etc/sysconfig/grafana-server </span><br><span class="line">GRAFANA_USER=grafana</span><br><span class="line"></span><br><span class="line">GRAFANA_GROUP=grafana</span><br><span class="line"></span><br><span class="line">GRAFANA_HOME=/usr/share/grafana</span><br><span class="line"></span><br><span class="line">LOG_DIR=/var/log/grafana</span><br><span class="line"></span><br><span class="line">DATA_DIR=/var/lib/grafana</span><br><span class="line"></span><br><span class="line">MAX_OPEN_FILES=10000</span><br><span class="line"></span><br><span class="line">CONF_DIR=/etc/grafana</span><br><span class="line"></span><br><span class="line">CONF_FILE=/etc/grafana/grafana.ini</span><br><span class="line"></span><br><span class="line">RESTART_ON_UPGRADE=true</span><br><span class="line"></span><br><span class="line">PLUGINS_DIR=/var/lib/grafana/plugins</span><br><span class="line"></span><br><span class="line">PROVISIONING_CFG_DIR=/etc/grafana/provisioning</span><br><span class="line"></span><br><span class="line"># Only used on systemd systems</span><br><span class="line">PID_FILE_DIR=/var/run/grafana</span><br></pre></td></tr></table></figure><h3 id="grafana-ini配置参考">grafana.ini配置参考</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br></pre></td><td class="code"><pre><span class="line">[root@opstrip ~]# egrep -v &quot;^#|^;|^$&quot; /etc/grafana/grafana.ini </span><br><span class="line">app_mode = production</span><br><span class="line">[paths]</span><br><span class="line">data = /var/lib/grafana</span><br><span class="line">temp_data_lifetime = 24h</span><br><span class="line">logs = /var/log/grafana</span><br><span class="line">plugins = /var/lib/grafana/plugins</span><br><span class="line">provisioning = /etc/grafana/provisioning</span><br><span class="line">[server]</span><br><span class="line">protocol = http</span><br><span class="line">http_addr =</span><br><span class="line">http_port = 3000</span><br><span class="line">domain = g.opstrip.com</span><br><span class="line">root_url = http://g.opstrip.com/</span><br><span class="line">serve_from_sub_path = false</span><br><span class="line">router_logging = false</span><br><span class="line">static_root_path = public</span><br><span class="line">enable_gzip = false</span><br><span class="line">socket = /var/run/grafana/grafana.sock</span><br><span class="line">[database]</span><br><span class="line">type = sqlite3</span><br><span class="line">host = 127.0.0.1:3306</span><br><span class="line">name = grafana</span><br><span class="line">user = root</span><br><span class="line">ssl_mode = disable</span><br><span class="line">path = /var/lib/grafana/grafana.db</span><br><span class="line">cache_mode = private</span><br><span class="line">[remote_cache]</span><br><span class="line">type = database</span><br><span class="line">[dataproxy]</span><br><span class="line">[analytics]</span><br><span class="line">[security]</span><br><span class="line">[snapshots]</span><br><span class="line">[dashboards]</span><br><span class="line">[users]</span><br><span class="line">[auth]</span><br><span class="line">[auth.anonymous]</span><br><span class="line">[auth.github]</span><br><span class="line">[auth.gitlab]</span><br><span class="line">[auth.google]</span><br><span class="line">[auth.grafananet]</span><br><span class="line">[auth.grafana_com]</span><br><span class="line">[auth.generic_oauth]</span><br><span class="line">[auth.saml] # Enterprise only</span><br><span class="line">[auth.basic]</span><br><span class="line">[auth.proxy]</span><br><span class="line">[auth.ldap]</span><br><span class="line">[smtp]</span><br><span class="line">enabled = true</span><br><span class="line">host = mail.xxx.com:587</span><br><span class="line">user = opstrip@xxx.com</span><br><span class="line">password = **********</span><br><span class="line">skip_verify = true</span><br><span class="line">from_address = postmaster@xxx.com</span><br><span class="line">from_name = opstrip</span><br><span class="line">ehlo_identity = g.opstrip.com</span><br><span class="line">[emails]</span><br><span class="line">[log]</span><br><span class="line">mode = console file</span><br><span class="line">level = info</span><br><span class="line">filters = rendering:debug</span><br><span class="line">[log.console]</span><br><span class="line">[log.file]</span><br><span class="line">[log.syslog]</span><br><span class="line">[quota]</span><br><span class="line">[alerting]</span><br><span class="line">enabled = true</span><br><span class="line">execute_alerts = true</span><br><span class="line">error_or_timeout = alerting</span><br><span class="line">nodata_or_nullvalues = no_data</span><br><span class="line">concurrent_render_limit = 5</span><br><span class="line">evaluation_timeout_seconds = 30</span><br><span class="line">notification_timeout_seconds = 30</span><br><span class="line">max_attempts = 3</span><br><span class="line">[explore]</span><br><span class="line">[metrics]</span><br><span class="line">[metrics.graphite]</span><br><span class="line">[grafana_net]</span><br><span class="line">[grafana_com]</span><br><span class="line">[tracing.jaeger]</span><br><span class="line">[external_image_storage]</span><br><span class="line">[external_image_storage.s3]</span><br><span class="line">[external_image_storage.webdav]</span><br><span class="line">[external_image_storage.gcs]</span><br><span class="line">[external_image_storage.azure_blob]</span><br><span class="line">[external_image_storage.local]</span><br><span class="line">[rendering]</span><br><span class="line">server_url = http://localhost:8081/render</span><br><span class="line">callback_url = http://localhost:3000/</span><br><span class="line">[panels]</span><br><span class="line">[plugins]</span><br><span class="line">[enterprise]</span><br><span class="line">[feature_toggles]</span><br></pre></td></tr></table></figure><p>说明：<code>[rendering]</code>项是<code>grafana-image-renderer</code>插件的配置。<code>[database]</code>是<code>Grafana</code>使用的数据库，请根据需要选择<code>MySQL</code>或<code>SQLite</code>。<code>[smtp]</code>是发送邮件的配置，请根据实际情况填写。</p><h3 id="使用systemd接管Grafana">使用systemd接管Grafana</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line">[root@opstrip ~]# cat /usr/lib/systemd/system/grafana-server.service </span><br><span class="line">[Unit]</span><br><span class="line">Description=Grafana instance</span><br><span class="line">Documentation=http://docs.grafana.org</span><br><span class="line">Wants=network-online.target</span><br><span class="line">After=network-online.target</span><br><span class="line">After=postgresql.service mariadb.service mysql.service</span><br><span class="line"></span><br><span class="line">[Service]</span><br><span class="line">EnvironmentFile=/etc/sysconfig/grafana-server</span><br><span class="line">User=grafana</span><br><span class="line">Group=grafana</span><br><span class="line">Type=notify</span><br><span class="line">Restart=on-failure</span><br><span class="line">WorkingDirectory=/usr/share/grafana</span><br><span class="line">RuntimeDirectory=grafana</span><br><span class="line">RuntimeDirectoryMode=0750</span><br><span class="line">ExecStart=/usr/sbin/grafana-server                                                  \</span><br><span class="line">                            --homepath=$&#123;GRAFANA_HOME&#125;                              \</span><br><span class="line">                            --config=$&#123;CONF_FILE&#125;                                   \</span><br><span class="line">                            --pidfile=$&#123;PID_FILE_DIR&#125;/grafana-server.pid            \</span><br><span class="line">                            --packaging=build                                       \</span><br><span class="line">                            cfg:default.paths.logs=$&#123;LOG_DIR&#125;                       \</span><br><span class="line">                            cfg:default.paths.data=$&#123;DATA_DIR&#125;                      \</span><br><span class="line">                            cfg:default.paths.plugins=$&#123;PLUGINS_DIR&#125;                \</span><br><span class="line">                            cfg:default.paths.provisioning=$&#123;PROVISIONING_CFG_DIR&#125;  </span><br><span class="line"></span><br><span class="line">LimitNOFILE=10000</span><br><span class="line">TimeoutStopSec=20</span><br><span class="line"></span><br><span class="line">[Install]</span><br><span class="line">WantedBy=multi-user.target</span><br><span class="line">[root@opstrip ~]# systemctl enable grafana-server.service</span><br><span class="line">Created symlink from /etc/systemd/system/multi-user.target.wants/grafana-server.service to /usr/lib/systemd/system/grafana-server.service.</span><br><span class="line">[root@opstrip ~]# systemctl start grafana-server.service</span><br><span class="line">[root@opstrip ~]# ps -ef | grep grafana-server | grep -v grep</span><br><span class="line">grafana   4746     1  0 12月03 ?      00:01:47 /usr/sbin/grafana-server --homepath=/usr/share/grafana --config=/etc/grafana/grafana.ini --pidfile=/var/run/grafana/grafana-server.pid --packaging=build cfg:default.paths.logs=/var/log/grafana cfg:default.paths.data=/var/lib/grafana cfg:default.paths.plugins=/var/lib/grafana/plugins cfg:default.paths.provisioning=/etc/grafana/provisioning</span><br><span class="line">[root@opstrip ~]# </span><br></pre></td></tr></table></figure><h1>编译安装grafana-image-renderer图像渲染</h1><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">### 安装`grafana-image-renderer`插件用于在告警中插入截图。</span><br><span class="line">[root@opstrip grafana]# grafana-cli plugins install grafana-image-renderer        # 或者在plugins目录下直接拉取源码git clone https://github.com/grafana/grafana-image-renderer.git</span><br><span class="line">[root@opstrip grafana]# echo &quot;export GF_RENDERER_PLUGIN_IGNORE_HTTPS_ERRORS=true&quot; &gt;&gt; /etc/profile &amp;&amp; source /etc/profile</span><br><span class="line">[root@opstrip grafana]# cd plugins/grafana-image-renderer/</span><br><span class="line">[root@opstrip grafana]# make deps &amp;&amp; make build_package ARCH=linux-x64-glibc</span><br><span class="line">[root@opstrip grafana]# npm install -g node-pre-gyp node-gyp                      # 安装依赖</span><br><span class="line">[root@opstrip grafana]# npm install                                               # 该操作会自动下载安装Chromium及grpc模块等</span><br><span class="line">[root@opstrip grafana]# yarn install --pure-lockfile                              # 安装依赖</span><br><span class="line">[root@opstrip grafana]# yarn run build                                            # 构建项目</span><br><span class="line">[root@opstrip grafana]# node build/app.js server --port=8081                      # 测试启动。如有报错，请按报错逐一排除。一般是依赖问题。</span><br></pre></td></tr></table></figure><p><strong>说明</strong>：后台启动 <code>/usr/bin/nohup /usr/local/node/bin/node /var/lib/grafana/plugins/grafana-image-renderer/build/app.js server --port=8081 &amp;</code>还可以用supervisord来管理grafana-image-renderer服务。<br><strong>其他问题</strong>请参考：<a href="https://s0grafana0com.icopy.site/docs/administration/image_rendering/">https://s0grafana0com.icopy.site/docs/administration/image_rendering/</a></p><h1>配置企业微信告警</h1><h3 id="配置告警渠道Notification-Channels">配置告警渠道<code>Notification Channels</code></h3><p>在左侧导航栏中依次选择<code>Alerting</code>→<code>Notification Channels</code>，在<code>New channel</code>新建告警渠道。选择<code>Type</code>为<code>WeChat</code>，选中<code>Include image</code>，再根据配置其他选项。如下图：</p><center>![企微告警渠道配置](/assets/blogImg/grafana-1.png)</center>**说明**：关于`AgentId`、`CorpId`、`Secret`及`ToUser`请联系你的企业微信管理员获取。<h3 id="在Dashboards中配置告警">在Dashboards中配置告警</h3><p>在Dashboards→Panel→Edit→Alert中，配置相应的告警规则及阈值。如下图：</p><center>![配置告警规则及阈值](/assets/blogImg/grafana-2.png)</center>对上面几个字段的解释：<center>![告警字段解释](/assets/blogImg/grafana-3.png)</center>告警接收验证。企业微信告警接收：<center>![企微告警](/assets/blogImg/grafana-4.png)</center>邮件告警接收：<center>![邮件告警](/assets/blogImg/grafana-5.png)</center>可以看到，企微跟邮件都收到了带图片的告警截图。只是目前图片中出现中文的地方还是会显示乱码。也请知道怎么解决这个问题的小伙伴M我，谢谢</div><script src="https://cdn.jsdelivr.net/lightgallery.js/1.0.1/js/lightgallery.min.js"></script><script>if (typeof lightGallery !== 'undefined') {        var options = {            selector: '.gallery-item'        };        lightGallery(document.getElementsByClassName('.article-gallery')[0], options);        }</script>]]></content>
    
    
    <summary type="html">介绍编译安装最新版本Grafana v6.6.0-pre并添加企业微信模块及grafana-image-renderer图片渲染模块，以做备忘。</summary>
    
    
    
    <category term="监控与告警" scheme="https://opsuri.com/categories/%E7%9B%91%E6%8E%A7%E4%B8%8E%E5%91%8A%E8%AD%A6/"/>
    
    
    <category term="Grafana" scheme="https://opsuri.com/tags/Grafana/"/>
    
    <category term="监控" scheme="https://opsuri.com/tags/%E7%9B%91%E6%8E%A7/"/>
    
  </entry>
  
  <entry>
    <title>实战：Redis数据的导出和导入（dump和load方式）</title>
    <link href="https://opsuri.com/2019/06/06/Redis-import-export-migration/"/>
    <id>https://opsuri.com/2019/06/06/Redis-import-export-migration/</id>
    <published>2019-06-06T02:27:19.000Z</published>
    <updated>2025-02-22T14:29:20.522Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/lightgallery.js/1.0.1/css/lightgallery.min.css" /><div class=".article-gallery"><p>上次做了下<code>redis</code>数据迁移，中间踩了些坑，后来用了下面的方法完成的。以此备忘。迁移redis数据一般有如下3种方式：</p><ul><li>第三方工具<code>redis-dump/redis-load</code></li><li><code>aof</code>机制，需要开启<code>aof功能</code></li><li><code>rdb</code>存储机制<br>这里介绍第一种方式，通过<code>redis-dump</code>导出数据，再通过<code>redis-load</code>导入。开始吧。</li></ul><h2 id="安装gcc">安装gcc</h2><p>安装gcc以继续以下操作</p><span id="more"></span><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">yum -y install gcc automake autoconf libtool make ruby rubygems ruby-devel</span><br></pre></td></tr></table></figure><h2 id="配置Ruby官网源地址">配置Ruby官网源地址</h2><p>因为默认的Ruby官网源地址在国外，访问速度很慢，所以需要配置成国内的源地址</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">gem sources -a http://gems.ruby-china.com/          添加国内源地址</span><br><span class="line">gem <span class="built_in">source</span> -l                                       查看是否添加成功</span><br><span class="line">gem <span class="built_in">source</span> --remove https://rubygems.org/           去掉国外源地址</span><br><span class="line">gem <span class="built_in">source</span> -l                                       确认现在的源地址只有国内</span><br></pre></td></tr></table></figure><h2 id="安装rvm命令">安装rvm命令</h2><h3 id="配置Google-DNS">配置Google DNS</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">echo</span> <span class="string">&quot;nameserver 8.8.8.8&quot;</span> &gt;&gt; /etc/resolv.conf</span><br></pre></td></tr></table></figure><h3 id="导入key">导入<code>key</code></h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">gpg2 --keyserver hkp://pool.sks-keyservers.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB</span><br></pre></td></tr></table></figure><p>或</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">curl -sSL https://rvm.io/mpapis.asc | gpg2 --import -</span><br><span class="line">curl -sSL https://rvm.io/pkuczynski.asc | gpg2 --import -</span><br></pre></td></tr></table></figure><h3 id="安装rvm">安装<code>rvm</code></h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">curl -L get.rvm.io | bash -s stable</span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;export rvm_max_time_flag=20&quot;</span> &gt;&gt; ~/.rvmrc</span><br></pre></td></tr></table></figure><h2 id="安装Ruby">安装<code>Ruby</code></h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">find / -iname rvm -<span class="built_in">type</span> f</span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;export PATH=<span class="variable">$PATH</span>:/usr/local/rvm/bin&quot;</span> &gt;&gt; /etc/profile &amp;&amp; <span class="built_in">source</span> /etc/profile</span><br><span class="line">rvm install 2.3.3</span><br></pre></td></tr></table></figure><p><strong>确认<code>Ruby</code>版本</strong></p><p>因为<code>redis-dump</code>必须要求ruby的版本不低于2.2.2</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">ruby -v                    <span class="comment"># 如果输出信息是ruby 2.3.3xxx，说明现在用的版本是正确的，直接跳到下一步。否则还要执行以下操作：</span></span><br><span class="line">rvm use 2.3.3 --default    <span class="comment"># 将默认使用ruby的版本设置为2.3.3</span></span><br><span class="line">rvm remove <span class="variable">$version</span>        <span class="comment"># 删除旧版本，$version就是ruby -v查到的版本，只需要指定前面的数字版本号就行</span></span><br></pre></td></tr></table></figure><h2 id="安装redis-dump">安装<code>redis-dump</code></h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">gem install redis-dump -V</span><br></pre></td></tr></table></figure><h2 id="确认redis-dump安装成功">确认<code>redis-dump</code>安装成功</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">find / -iname redis-dump</span><br><span class="line">```      </span><br><span class="line"><span class="comment">## `redis-dump`导出数据</span></span><br><span class="line"></span><br><span class="line">用`redis-dump`导出的数据格式都是json格式</span><br><span class="line">```bash</span><br><span class="line">redis-dump -u :yourpassword@127.0.0.1:6379 &gt; /tmp/redis-mv.json   <span class="comment"># 注意换成自己的密码，如果没有密码就去掉</span></span><br></pre></td></tr></table></figure><h2 id="将导出的数据文件移动到导入的redis服务器上去">将导出的数据文件移动到导入的redis服务器上去</h2><h2 id="redis-load导入数据"><code>redis-load</code>导入数据</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cat</span> redis-mv.json | redis-load -u :yourpassword@127.0.0.1:6379    <span class="comment"># 注意换成自己的密码，如果没有密码就去掉</span></span><br></pre></td></tr></table></figure><p>到此数据就迁移完了。别忘了去导入的redis查看验证下。</p></div><script src="https://cdn.jsdelivr.net/lightgallery.js/1.0.1/js/lightgallery.min.js"></script><script>if (typeof lightGallery !== 'undefined') {        var options = {            selector: '.gallery-item'        };        lightGallery(document.getElementsByClassName('.article-gallery')[0], options);        }</script>]]></content>
    
    
    <summary type="html">Redis数据导入导出备忘。</summary>
    
    
    
    <category term="WEB中间件" scheme="https://opsuri.com/categories/WEB%E4%B8%AD%E9%97%B4%E4%BB%B6/"/>
    
    <category term="数据库" scheme="https://opsuri.com/categories/WEB%E4%B8%AD%E9%97%B4%E4%BB%B6/%E6%95%B0%E6%8D%AE%E5%BA%93/"/>
    
    
    <category term="数据库" scheme="https://opsuri.com/tags/%E6%95%B0%E6%8D%AE%E5%BA%93/"/>
    
    <category term="Redis" scheme="https://opsuri.com/tags/Redis/"/>
    
    <category term="NoSQL" scheme="https://opsuri.com/tags/NoSQL/"/>
    
  </entry>
  
  <entry>
    <title>nginx安全配置规范</title>
    <link href="https://opsuri.com/2019/05/20/Nginx-security-configuration-specification/"/>
    <id>https://opsuri.com/2019/05/20/Nginx-security-configuration-specification/</id>
    <published>2019-05-20T05:48:22.000Z</published>
    <updated>2025-02-22T14:22:47.603Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/lightgallery.js/1.0.1/css/lightgallery.min.css" /><div class=".article-gallery"><p>说起网络攻击，可能很多人只知道大名鼎鼎的<code>DDoS</code>攻击，这种攻击廉价且效果出众，直接通过第四层网络协议用他的带宽把你的带宽顶掉，造成网路阻塞，防不胜防。不过还有一种网络攻击其实比起DDOS更频繁出现，就是<code>CC（Challenge Collapsar）</code>攻击，一般来说是利用网站代码漏洞，不停地发大量数据包请求，造成对方服务器回应这些请求导致资源耗尽，一直到宕机崩溃。这种攻击属于第七层的网络协议，一方面在服务器层面是正常的请求，所以这种情况想根本解决问题，只能从代码入手。但是另一方面，也就可以用其他来限制他访问，例如nginx的配置上也是能稍微防一下。</p><h2 id="隐藏版本号">隐藏版本号</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">http &#123;</span><br><span class="line">    server_tokens off;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>经常会有针对某个版本的nginx安全漏洞出现，隐藏nginx版本号就成了主要的安全优化手段之一，当然最重要的是及时升级修复漏洞。</p><h2 id="开启HTTPS">开启HTTPS</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">server &#123;</span><br><span class="line">    listen 443;</span><br><span class="line">    server_name opstrip.com;</span><br><span class="line">    </span><br><span class="line">    ssl on;</span><br><span class="line">    ssl_certificate /etc/nginx/certs/opstrip.com.pem;</span><br><span class="line">    ssl_certificate_key /etc/nginx/certs/opstrip.com.key;</span><br><span class="line">    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;</span><br><span class="line">    ssl_ciphers HIGH:!aNULL:!MD5;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><span id="more"></span><p><code>ssl on</code>： 开启https<br><code>ssl_certificate</code>： 配置nginx ssl证书的路径<br><code>ssl_certificate_key</code>： 配置nginx ssl证书key的路径<br><code>ssl_protocols</code>： 指定客户端建立连接时使用的ssl协议版本，如果不需要兼容TSLv1，直接去掉即可<br><code>ssl_ciphers</code>： 指定客户端连接时所使用的加密算法，你可以再这里配置更高安全的算法</p><h2 id="黑白名单配置">黑白名单配置</h2><h3 id="白名单配置">白名单配置</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">location /admin/ &#123;</span><br><span class="line">    allow 192.168.1.0/24;</span><br><span class="line">    deny all;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>上边表示只允许<code>192.168.1.0/24</code>网段的主机访问，拒绝其他所有。</p><h3 id="黑名单配置">黑名单配置</h3><p>也可以写成黑名单的方式禁止某些地址访问，允许其他所有，例如：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">location /uploads/ &#123;</span><br><span class="line">    deny 192.168.1.0/24;</span><br><span class="line">    allow all;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>更多的时候客户端请求会经过层层代理，我们需要通过<code>$http_x_forwarded_for</code>来进行限制，可以这样写：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">set $allow false;</span><br><span class="line">if ($http_x_forwarded_for = &quot;211.144.204.2&quot;) &#123; set $allow true; &#125;</span><br><span class="line">if ($http_x_forwarded_for ~ &quot;108.2.66.[89]&quot;) &#123; set $allow true; &#125;</span><br><span class="line">if ($allow = false) &#123; return 404; &#125;</span><br></pre></td></tr></table></figure><h2 id="账号认证">账号认证</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">server &#123;</span><br><span class="line">    location / &#123;</span><br><span class="line">    auth_basic &quot;please input user&amp;passwd&quot;;</span><br><span class="line">    auth_basic_user_file key/auth.key;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="限制请求方法">限制请求方法</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">if ($request_method !~ ^(GET|POST)$ ) &#123;</span><br><span class="line">    return 405;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><code>$request_method</code>能够获取到请求<code>nginx</code>的<code>method</code>。这里配置只允许<code>GET/POST</code>方法访问，其他的<code>method</code>返回<code>405</code></p><h2 id="拒绝User-Agent">拒绝User-Agent</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">if ($http_user_agent ~* LWP::Simple|BBBike|wget|curl) &#123;</span><br><span class="line">    return 444;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>可能有一些不法者会利用<code>wget/curl</code>等工具扫描我们的网站，我们可以通过禁止相应的<code>user-agent</code>来简单的防范<br>Nginx的444状态比较特殊，如果返回444那么客户端将不会收到服务端返回的信息，就像是网站无法连接一样</p><h2 id="图片防盗链">图片防盗链</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">location /images/ &#123;</span><br><span class="line">    valid_referers none blocked www.opstrip.com opstrip.com;</span><br><span class="line">    if ($invalid_referer) &#123;</span><br><span class="line">    return 403;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><code>valid_referers</code>： 验证referer，其中none允许referer为空，blocked允许不带协议的请求，除了以上两类外仅允许referer为 <a href="http://www.opstrip.com">www.opstrip.com</a> 或opstrip.com时访问images下的图片资源，否则返回403</p><p>当然你也可以给不符合referer规则的请求重定向到一个默认的图片，比如下边这样</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">location /images/ &#123;</span><br><span class="line">    valid_referers blocked www.opstrip.com opstrip.com</span><br><span class="line">    if ($invalid_referer) &#123;</span><br><span class="line">    rewrite ^/images/.*.(gif|jpg|jpeg|png)$ /static/qrcode.jpg last;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="控制并发连接数">控制并发连接数</h2><p>可以通过<code>ngx_http_limit_conn_module</code>模块限制一个IP的并发连接数</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">http &#123;</span><br><span class="line">    limit_conn_zone $binary_remote_addr zone=ops:10m;</span><br><span class="line"></span><br><span class="line">    server &#123;</span><br><span class="line">        listen 80;</span><br><span class="line">        server_name opstrip.com;</span><br><span class="line">           </span><br><span class="line">        root /home/project/webapp;</span><br><span class="line">        index index.html;</span><br><span class="line">        location / &#123;</span><br><span class="line">            limit_conn ops 10;</span><br><span class="line">        &#125;</span><br><span class="line">        access_log /var/log/nginx/nginx_access.log main;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><code>limit_conn_zone</code>： 设定保存各个键(例如$binary_remote_addr)状态的共享内存空间的参数，zone=空间名字:大小<br>大小的计算与变量有关，例如**$binary_remote_addr**变量的大小对于记录IPV4地址是固定的4 bytes，而记录IPV6地址时固定的16 bytes，存储状态在32位平台中占用32或者64 bytes，在64位平台中占用64 bytes。1m的共享内存空间可以保存大约3.2万个32位的状态，1.6万个64位的状态<br><code>limit_conn</code>： 指定一块已经设定的共享内存空间(例如name为ops的空间)，以及每个给定键值的最大连接数</p><p>上边的例子表示同一IP同一时间只允许10个连接</p><p>当有多个<code>limit_conn</code>指令被配置时，所有的连接数限制都会生效</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">http &#123;</span><br><span class="line">    limit_conn_zone $binary_remote_addr zone=ops:10m;</span><br><span class="line">    limit_conn_zone $server_name zone=coffee:10m;</span><br><span class="line">    </span><br><span class="line">    server &#123;</span><br><span class="line">        listen 80;</span><br><span class="line">        server_name opstrip.com;</span><br><span class="line">        </span><br><span class="line">        root /data/www/webapp;</span><br><span class="line">        index index.html;</span><br><span class="line">        </span><br><span class="line">        location / &#123;</span><br><span class="line">            limit_conn ops 10;</span><br><span class="line">            limit_conn coffee 2000;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>上边的配置不仅会限制单一IP来源的连接数为10，同时也会限制单一虚拟服务器的总连接数为2000</p><h2 id="连接权限控制">连接权限控制</h2><p><strong>连接权限控制</strong></p><p>实际上nginx的最大连接数是<strong>worker_processes</strong>乘以<strong>worker_connections</strong>的总数。</p><p>也就是说，下面的这个配置，就是4X65535，一般来说，我们会强调<code>worker_processes</code>设置成和核数相等，<code>worker_connections</code>并没有要求。但是同时这个设置其实给了攻击者空间，攻击者是可以同时发起这么多个连接，把你服务器搞跨。所以，我们应该更合理的配置这两个参数。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">user  www;</span><br><span class="line">worker_processes  4;</span><br><span class="line">error_log  /var/log/nginx/nginx_error.log  crit;</span><br><span class="line">pid        /var/nginx/nginx.pid;</span><br><span class="line">events &#123;</span><br><span class="line">    use epoll;</span><br><span class="line">    worker_connections 65535;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>不过，也不是完全没有办法限制，在nginx0.7开始，出了两个新的模块：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">HttpLimitReqModul：    限制单个 IP 每秒请求数</span><br><span class="line">HttpLimitZoneModule：     限制单个 IP 的连接数</span><br></pre></td></tr></table></figure><p>这两个模块，要先在http层定义，然后在 location, server, http上下文中作限制，他们用的是限制单ip访问的漏桶算法，也就是说超过定义的限制会报503错误，这样爆发的cc攻击就全部被限制住了。当然，有些时候可能是某个公司同一个ip有几十人一起访问网站，这是有可能被误伤的，做好503报错回调是很有必要的。</p><p>先看<code>HttpLimitReqModul</code>：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">http &#123;</span><br><span class="line">    limit_req_zone $binary_remote_addr zone=test_req:10m rate=20r/s;</span><br><span class="line">     …</span><br><span class="line">     server &#123;</span><br><span class="line">         …</span><br><span class="line">         location /download/ &#123;</span><br><span class="line">            limit_req zone=test_req burst=5 nodelay;</span><br><span class="line">         &#125;</span><br><span class="line">     &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>上面http层的就是定义，这是一个名为<code>test_req的limit_req_zone</code>空间，用来存储<code>session</code>数据，大小是10M内存，1M大约可以存16000个ip回话，看你访问量有多少就设多少。以**$binary_remote_addr**为key,这个定义是客户端IP，可以改成<code>$server_name</code>等其他，限制平均每秒的请求为20个，写成<code>20r/m</code>就是每分钟了，也是看你访问量。</p><p>下面location层就是应用这个限制了，对应上面的定义，对访问download文件夹的请求，限制每个ip每秒不超过20个请求，漏桶数burst为5，brust的意思就是，如果第1,2,3,4秒请求为19个，第5秒的请求为25个是被允许的。但是如果你第1秒就25个请求，第2秒超过20的请求返回503错误。nodelay，如果不设置该选项，第1秒25个请求时，5个请求放到第2秒执行，设置nodelay，25个请求将在第1秒执行。</p><p>就这个限制定义而言，把每个IP限制了请求数，对于海量的cc请求攻击，效果明显，例如限制到<code>1r/s</code>每秒一次请求，那就更明显了，不过也正如开头所说，对于大公司多人统一IP同时访问，难免出现误伤，所以还是得多考虑。</p><p>然后再看<code>HttpLimitZoneModule</code>：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">http &#123;</span><br><span class="line">    limit_conn_zone test_zone $binary_remote_addr 10m;</span><br><span class="line">    server &#123;</span><br><span class="line">        location /download/ &#123;</span><br><span class="line">            limit_conn test_zone 10;</span><br><span class="line">            limit_rate 500k;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>和上面的类似，上面http层就是总定义，这是一个名为<code>test_zone</code>的<code>limit_conn_zone</code>空间，大小也是10M，key还是客户端IP地址，不过这个没有限制次数，改下面定义去了。</p><p>下面location层就是真正定义了，因为<code>key</code>定义是客户端ip，所以<code>limit_conn</code>就是一个IP限制了10个连接，如果是<code>$server_name</code>，那就是一个域名10个连接。然后下面<code>limit_rate</code>就是限制一个连接的带宽，如果一个ip两个连接，就是500x2k，这里是10，那就是最多可以有5000K速度给到这个ip了。</p><h2 id="缓冲区溢出攻击">缓冲区溢出攻击</h2><p><strong>缓冲区溢出攻击</strong> 是通过将数据写入缓冲区并超出缓冲区边界和重写内存片段来实现的，限制缓冲区大小可有效防止</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">client_body_buffer_size 1K;</span><br><span class="line">client_header_buffer_size 1k;</span><br><span class="line">client_max_body_size 1k;</span><br><span class="line">large_client_header_buffers 2 1k;</span><br></pre></td></tr></table></figure><p><code>client_body_buffer_size</code>： 默认8k或16k，表示客户端请求body占用缓冲区大小。如果连接请求超过缓存区指定的值，那么这些请求实体的整体或部分将尝试写入一个临时文件。<br><code>client_header_buffer_size</code>： 表示客户端请求头部的缓冲区大小。绝大多数情况下一个请求头不会大于1k，不过如果有来自于wap客户端的较大的cookie它可能会大于 1k，Nginx将分配给它一个更大的缓冲区，这个值可以在large_client_header_buffers里面设置<br><code>client_max_body_size</code>： 表示客户端请求的最大可接受body大小，它出现在请求头部的Content-Length字段， 如果请求大于指定的值，客户端将收到一个**“Request Entity Too Large” (413)<strong>错误，通常在上传文件到服务器时会受到限制<br><code>large_client_header_buffers</code>：表示一些比较大的请求头使用的缓冲区数量和大小，默认一个缓冲区大小为操作系统中分页文件大小，通常是4k或8k，请求字段不能大于一个缓冲区大小，如果客户端发送一个比较大的头，nginx将返回</strong>&quot;Request URI too large&quot; (414)<strong>，请求的头部最长字段不能大于一个缓冲区，否则服务器将返回</strong>&quot;Bad request&quot; (400)**</p><p><strong>同时需要修改几个超时时间的配置</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">client_body_timeout 10;</span><br><span class="line">client_header_timeout 10;</span><br><span class="line">keepalive_timeout 5 5;</span><br><span class="line">send_timeout 10;</span><br></pre></td></tr></table></figure><p><code>client_body_timeout</code>： 表示读取请求body的超时时间，如果连接超过这个时间而客户端没有任何响应，Nginx将返回**“Request time out” (408)<strong>错误<br><code>client_header_timeout</code>： 表示读取客户端请求头的超时时间，如果连接超过这个时间而客户端没有任何响应，Nginx将返回</strong>&quot;Request time out&quot; (408)<strong>错误<br><code>keepalive_timeout</code>： 参数的第一个值表示客户端与服务器长连接的超时时间，超过这个时间，服务器将关闭连接，可选的第二个参数参数表示Response头中Keep-Alive: timeout=time的time值，这个值可以使一些浏览器知道什么时候关闭连接，以便服务器不用重复关闭，如果不指定这个参数，nginx不会在应Response头中发送Keep-Alive信息<br><code>send_timeout</code>： 表示发送给客户端应答后的超时时间，Timeout是指没有进入完整</strong>established**状态，只完成了两次握手，如果超过这个时间客户端没有任何响应，nginx将关闭连接</p><h2 id="Header头设置">Header头设置</h2><p>通过以下设置可有效防止<code>XSS攻击</code></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">add_header X-Frame-Options &quot;SAMEORIGIN&quot;;</span><br><span class="line">add_header X-XSS-Protection &quot;1; mode=block&quot;;</span><br><span class="line">add_header X-Content-Type-Options &quot;nosniff&quot;;</span><br></pre></td></tr></table></figure><p><code>X-Frame-Options</code>： 响应头表示是否允许浏览器加载frame等属性，有三个配置DENY禁止任何网页被嵌入,SAMEORIGIN只允许本网站的嵌套,ALLOW-FROM允许指定地址的嵌套<br><code>X-XSS-Protection</code>： 表示启用XSS过滤（禁用过滤为X-XSS-Protection: 0），mode=block表示若检查到XSS攻击则停止渲染页面<br><code>X-Content-Type-Options</code>： 响应头用来指定浏览器对未指定或错误指定Content-Type资源真正类型的猜测行为，<strong>nosniff</strong> 表示不允许任何猜测<br>在通常的请求响应中，浏览器会根据Content-Type来分辨响应的类型，但当响应类型未指定或错误指定时，浏览会尝试启用<strong>MIME-sniffing</strong>来猜测资源的响应类型，这是非常危险的</p><p>例如一个.jpg的图片文件被恶意嵌入了可执行的js代码，在开启资源类型猜测的情况下，浏览器将执行嵌入的js代码，可能会有意想不到的后果</p><h2 id="其他的Header头配置">其他的Header头配置</h2><p>另外还有几个关于请求头的安全配置需要注意<br><code>Content-Security-Policy</code>： 定义页面可以加载哪些资源，</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">add_header Content-Security-Policy &quot;default-src &#x27;self&#x27;&quot;;</span><br></pre></td></tr></table></figure><p>上边的配置会限制所有的外部资源，都只能从当前域名加载，其中default-src定义针对所有类型资源的默认加载策略，self允许来自相同来源的内容</p><p><code>Strict-Transport-Security</code>： 会告诉浏览器用HTTPS协议代替HTTP来访问目标站点</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">add_header Strict-Transport-Security &quot;max-age=31536000; includeSubDomains&quot;;</span><br></pre></td></tr></table></figure><p>上边的配置表示当用户第一次访问后，会返回一个包含了<code>Strict-Transport-Security</code>响应头的字段，这个字段会告诉浏览器，在接下来的<code>31536000</code>秒内，当前网站的所有请求都使用<code>https</code>协议访问，参数<code>includeSubDomains</code>是可选的，表示所有子域名也将采用同样的规则</p></div><script src="https://cdn.jsdelivr.net/lightgallery.js/1.0.1/js/lightgallery.min.js"></script><script>if (typeof lightGallery !== 'undefined') {        var options = {            selector: '.gallery-item'        };        lightGallery(document.getElementsByClassName('.article-gallery')[0], options);        }</script>]]></content>
    
    
    <summary type="html">安全无小事。安全规范，从NGINX配置开始做起。</summary>
    
    
    
    <category term="中间件" scheme="https://opsuri.com/categories/%E4%B8%AD%E9%97%B4%E4%BB%B6/"/>
    
    <category term="网络安全" scheme="https://opsuri.com/categories/%E4%B8%AD%E9%97%B4%E4%BB%B6/%E7%BD%91%E7%BB%9C%E5%AE%89%E5%85%A8/"/>
    
    
    <category term="Nginx" scheme="https://opsuri.com/tags/Nginx/"/>
    
    <category term="安全运维" scheme="https://opsuri.com/tags/%E5%AE%89%E5%85%A8%E8%BF%90%E7%BB%B4/"/>
    
  </entry>
  
  <entry>
    <title>Letsencrypt通过DNS的TXT记录来验证域名有效性</title>
    <link href="https://opsuri.com/2018/12/28/Getting-Letsencrypt-Certificate-with-DNS-TXT/"/>
    <id>https://opsuri.com/2018/12/28/Getting-Letsencrypt-Certificate-with-DNS-TXT/</id>
    <published>2018-12-28T12:15:14.000Z</published>
    <updated>2025-02-22T14:07:38.996Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/lightgallery.js/1.0.1/css/lightgallery.min.css" /><div class=".article-gallery"><h2 id="说明">说明</h2><p>我们在使用letsencrypt获取免费的HTTPS证书的时候，letsencrypt需要对域名进行验证。默认情况下它的验证方式是这样的：</p><p>certbot程序在web目录的根目录下放置一个文件。<br>letsencrypt的服务器通过域名来访问这个文件，来验证你申请的域名是属于你的<br>但有时候我们想为内网的某台主机设置HTTPS，因为内网的主机无法被<code>letsencrypt</code>的服务器访问到，<code>certbot --nginx certonly</code>就会出现<code>Connection refused</code>的错误。</p><p>为了解决上述问题，我们可以更改验证方式，使用DNS记录来验证域名。</p><h2 id="安装部署">安装部署</h2><span id="more"></span><p>参考<a href="https://certbot.eff.org/lets-encrypt/centosrhel7-nginx">官方文档</a>依次进行以下操作：</p><h3 id="安装第三方软件源：">安装第三方软件源：</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">$ <span class="built_in">sudo</span> yum -y install yum-utils</span><br><span class="line">$ <span class="built_in">sudo</span> yum-config-manager --<span class="built_in">enable</span> rhui-REGION-rhel-server-extras rhui-REGION-rhel-server-optional</span><br></pre></td></tr></table></figure><h3 id="安装python2-certbot-nginx">安装python2-certbot-nginx</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ <span class="built_in">sudo</span> yum install python2-certbot-nginx</span><br></pre></td></tr></table></figure><h2 id="测试certbot">测试certbot</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ <span class="built_in">sudo</span> certbot --nginx</span><br></pre></td></tr></table></figure><p>如有报错则执行以下操作修复：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">$ <span class="built_in">sudo</span> pip install requests urllib3 pyOpenSSL --force --upgrade</span><br><span class="line">$ <span class="built_in">sudo</span> pip install --upgrade --force-reinstall <span class="string">&#x27;requests==2.6.0&#x27;</span></span><br><span class="line">$ <span class="built_in">sudo</span> pip install idna==2.6 urllib3==1.22</span><br></pre></td></tr></table></figure><h2 id="手动配置DNS的TXT记录验证域名">手动配置DNS的TXT记录验证域名</h2><p>运行</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ <span class="built_in">sudo</span> certbot --manual --preferred-challenges dns certonly</span><br></pre></td></tr></table></figure><p>输入域名（多个域名需以逗号或空格分开）并同意记录本机IP</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">[root@MyPrecious ~]# certbot --manual --preferred-challenges dns certonly</span><br><span class="line">Saving debug <span class="built_in">log</span> to /var/log/letsencrypt/letsencrypt.log</span><br><span class="line">Plugins selected: Authenticator manual, Installer None</span><br><span class="line">Starting new HTTPS connection (1): acme-v02.api.letsencrypt.org</span><br><span class="line">Please enter <span class="keyword">in</span> your domain name(s) (comma and/or space separated)  (Enter <span class="string">&#x27;c&#x27;</span></span><br><span class="line">to cancel): *.opstrip.com,opstrip.com</span><br><span class="line">Obtaining a new certificate</span><br><span class="line">Performing the following challenges:</span><br><span class="line">dns-01 challenge <span class="keyword">for</span> opstrip.com</span><br><span class="line">    </span><br><span class="line">- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -</span><br><span class="line">NOTE: The IP of this machine will be publicly logged as having requested this</span><br><span class="line">certificate. If you<span class="string">&#x27;re running certbot in manual mode on a machine that is not</span></span><br><span class="line"><span class="string">your server, please ensure you&#x27;</span>re okay with that.</span><br><span class="line">    </span><br><span class="line">Are you OK with your IP being logged?</span><br><span class="line">- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -</span><br><span class="line">(Y)es/(N)o: y</span><br></pre></td></tr></table></figure><p>后开始获取证书，会有类似以下提示：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -</span><br><span class="line">Please deploy a DNS TXT record under the name</span><br><span class="line">_acme-challenge.opstrip.com with the following value:</span><br><span class="line">    </span><br><span class="line">On6MxDvMMz-nRST-PAu3VHQoMQ2nuzYbvtA4Gw13EiM</span><br><span class="line">    </span><br><span class="line">Before continuing, verify the record is deployed.</span><br><span class="line">- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -</span><br><span class="line">Press Enter to Continue</span><br><span class="line">    </span><br></pre></td></tr></table></figure><p>此时certbot程序就会暂停，等待我们去添加DNS记录。</p><p>根据以上提示，在opstrip.com域名解析下，新增一条TXT解析，<br>解析类型为<code>TXT</code><br>主机记录为<code>_acme-challenge</code><br>记录值为<code>On6MxDvMMz-nRST-PAu3VHQoMQ2nuzYbvtA4Gw13EiM</code><br>添加完成后执行</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">dig -t txt _acme-challenge.opstrip.com</span><br></pre></td></tr></table></figure><p>若返回有以上记录值则配置生效。回车以继续下一个域名。<br>当依次完成所有的域名验证时，返回以下内容</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line">Waiting <span class="keyword">for</span> verification...</span><br><span class="line">Resetting dropped connection: acme-v02.api.letsencrypt.org</span><br><span class="line">Resetting dropped connection: acme-v02.api.letsencrypt.org</span><br><span class="line"></span><br><span class="line">Cleaning up challenges</span><br><span class="line">Resetting dropped connection: acme-v02.api.letsencrypt.org</span><br><span class="line"></span><br><span class="line">IMPORTANT NOTES:</span><br><span class="line"> - Congratulations! Your certificate and chain have been saved at:</span><br><span class="line">   /etc/letsencrypt/live/opstrip.com/fullchain.pem</span><br><span class="line">   Your key file has been saved at:</span><br><span class="line">   /etc/letsencrypt/live/opstrip.com/privkey.pem</span><br><span class="line">   Your cert will expire on 2019-03-28. To obtain a new or tweaked</span><br><span class="line">   version of this certificate <span class="keyword">in</span> the future, simply run certbot</span><br><span class="line">   again. To non-interactively renew *all* of your certificates, run</span><br><span class="line">   <span class="string">&quot;certbot renew&quot;</span></span><br><span class="line"> - If you like Certbot, please consider supporting our work by:</span><br><span class="line">    </span><br><span class="line">   Donating to ISRG / Let<span class="string">&#x27;s Encrypt:   https://letsencrypt.org/donate</span></span><br><span class="line"><span class="string">   Donating to EFF:                    https://eff.org/donate-le</span></span><br><span class="line"><span class="string">    </span></span><br></pre></td></tr></table></figure><p>表示证书已成功获取。如果验证失败请等待DNS记录更新并多试几次。<br>其中，<code>/etc/letsencrypt/live/opstrip.com/fullchain.pem</code>为带证书链的公钥，<code>/etc/letsencrypt/live/opstrip.com/privkey.pem</code>为对应的私钥。</p><h2 id="证书续签">证书续签</h2><p>在crontab中添加以下任务</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">0 0,12 * * * python -c <span class="string">&#x27;import random; import time; time.sleep(random.random() * 3600)&#x27;</span> &amp;&amp; certbot renew </span><br></pre></td></tr></table></figure><p>官方建议每天运行两次，是站点保持在线状态以免证书被吊销。在证书到期或续订之前不会执行任何操作。</p><hr><p>参考来源：</p><ul><li><a href="https://certbot.eff.org/lets-encrypt/centosrhel7-nginx">https://certbot.eff.org/lets-encrypt/centosrhel7-nginx</a></li><li><a href="https://www.52zheteng.info/%E6%9C%8D%E5%8A%A1%E5%99%A8/centos7-%E4%BD%BF%E7%94%A8certbot-%E5%87%BA%E7%8E%B0-requests-packages-urllib3-%E9%94%99%E8%AF%AF-%E7%9A%84%E5%A4%84%E7%90%86/">https://www.52zheteng.info/服务器/centos7-使用certbot-出现-requests-packages-urllib3-错误-的处理/</a></li><li><a href="https://www.wuqianlin.cn/api/blogs/001531210108886b84da3190d3448e7a43685f05c3fb30f000">https://www.wuqianlin.cn/api/blogs/001531210108886b84da3190d3448e7a43685f05c3fb30f000</a></li></ul></div><script src="https://cdn.jsdelivr.net/lightgallery.js/1.0.1/js/lightgallery.min.js"></script><script>if (typeof lightGallery !== 'undefined') {        var options = {            selector: '.gallery-item'        };        lightGallery(document.getElementsByClassName('.article-gallery')[0], options);        }</script>]]></content>
    
    
    <summary type="html">Letsencrypt通过DNS的TXT记录来验证域名</summary>
    
    
    
    <category term="备忘录" scheme="https://opsuri.com/categories/%E5%A4%87%E5%BF%98%E5%BD%95/"/>
    
    
    <category term="Linux" scheme="https://opsuri.com/tags/Linux/"/>
    
    <category term="Certificate" scheme="https://opsuri.com/tags/Certificate/"/>
    
  </entry>
  
  <entry>
    <title>macOS High Sierra上使用 ntfs-3g读取 NTFS 格式磁盘</title>
    <link href="https://opsuri.com/2018/05/06/Using-ntfs-3g-on-macOS-High-Sierra/"/>
    <id>https://opsuri.com/2018/05/06/Using-ntfs-3g-on-macOS-High-Sierra/</id>
    <published>2018-05-06T02:18:26.000Z</published>
    <updated>2025-02-22T14:50:27.464Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/lightgallery.js/1.0.1/css/lightgallery.min.css" /><div class=".article-gallery"><p>使用开源方案ntfs-3g解决macOS挂载NTFS只读的问题</p><h2 id="安装-brew">安装 brew</h2><p>普通用户下：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ /usr/bin/ruby -e <span class="string">&quot;<span class="subst">$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)</span>&quot;</span></span><br></pre></td></tr></table></figure><h2 id="安装-osxfuse-工具">安装 osxfuse 工具</h2><span id="more"></span><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ brew cask install osxfuse</span><br></pre></td></tr></table></figure><p>注，不安装 osxfuse 直接安装 ntfs-3g 会有以下报错：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">ntfs-3g: OsxfuseRequirement unsatisfied!</span><br><span class="line">You can install with Homebrew-Cask:</span><br><span class="line"> brew cask install osxfuse</span><br><span class="line">You can download from:</span><br><span class="line"> https://osxfuse.github.io/</span><br><span class="line">Error: An unsatisfied requirement failed this build.</span><br></pre></td></tr></table></figure><h2 id="安装-ntfs-3g">安装 ntfs-3g</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ brew install ntfs-3g</span><br></pre></td></tr></table></figure><h2 id="查看-windows-分区">查看 windows 分区</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">$ diskutil list</span><br><span class="line">    </span><br><span class="line">……</span><br><span class="line">    </span><br><span class="line">/dev/disk3 (external, physical):</span><br><span class="line">   <span class="comment">#:                       TYPE NAME                    SIZE       IDENTIFIER</span></span><br><span class="line">   0:     FDisk_partition_scheme                        *320.1 GB   disk3</span><br><span class="line">   1:               Windows_NTFS                         104.9 MB   disk3s1</span><br><span class="line">   2:               Windows_NTFS                         78.5 GB    disk3s2</span><br><span class="line">   3:               Windows_NTFS                         78.6 GB    disk3s3</span><br><span class="line">   4:               Windows_NTFS                         78.6 GB    disk3s5</span><br><span class="line">   5:               Windows_NTFS                         84.1 GB    disk3s6</span><br></pre></td></tr></table></figure><h2 id="将-windows-分区挂载至-macOS">将 windows 分区挂载至 macOS</h2><p>这里只挂载disk3s2、disk3s3、disk3s5、disk3s6这四个分区，分别对应 Windows 系统的 C、D、E、F 盘，挂载点分别为/Volumes下的 System、Documents、Downloads、Tools</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">$ <span class="built_in">sudo</span> <span class="built_in">mkdir</span> -p /Volumes/&#123;System,Documents,Downloads,Tools&#125;</span><br><span class="line">$ <span class="built_in">sudo</span> /usr/local/bin/ntfs-3g /dev/disk3s2 /Volumes/System -olocal -oallow_other</span><br><span class="line">$ <span class="built_in">sudo</span> /usr/local/bin/ntfs-3g /dev/disk3s3 /Volumes/Documents -olocal -oallow_other</span><br><span class="line">$ <span class="built_in">sudo</span> /usr/local/bin/ntfs-3g /dev/disk3s5 /Volumes/Downloads -olocal -oallow_other</span><br><span class="line">$ <span class="built_in">sudo</span> /usr/local/bin/ntfs-3g /dev/disk3s6 /Volumes/Tools -olocal -oallow_other</span><br></pre></td></tr></table></figure><p>参考：<a href="https://github.com/osxfuse/osxfuse/wiki/NTFS-3G">https://github.com/osxfuse/osxfuse/wiki/NTFS-3G</a></p><h2 id="访问-windows-分区">访问 windows 分区</h2><p>使用以上的命令执行挂载操作后，挂载点并不会在 Finder 上显示出来，但是通过 df 可以看到挂载点：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">df</span> -h</span><br><span class="line">Filesystem      Size   Used  Avail Capacity iused               ifree %iused  Mounted on</span><br><span class="line"></span><br><span class="line">……</span><br><span class="line"></span><br><span class="line">/dev/disk3s2    73Gi   73Gi  499Mi   100%  183749              589451   24%   /Volumes/System</span><br><span class="line">/dev/disk3s3    73Gi   71Gi  2.1Gi    98%   39749             2303375    2%   /Volumes/Documents</span><br><span class="line">/dev/disk3s5    73Gi   72Gi  1.6Gi    98%    5556             1694008    0%   /Volumes/Downloads</span><br><span class="line">/dev/disk3s6    78Gi   78Gi  872Mi    99%    2706              955830    0%   /Volumes/Tools</span><br></pre></td></tr></table></figure><p>可以在当前用户的桌面上创建软链接来访问：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ <span class="built_in">sudo</span> <span class="built_in">ln</span> -sf /Volumes ~/Desktop/Volumes</span><br></pre></td></tr></table></figure><p>下图：<br><a href="/assets/blogImg/ntfs-3g.png" title="快捷方式访问" class="gallery-item"><img src="/assets/blogImg/ntfs-3g.png" alt="快捷方式访问"></a><br>Volume 0/1/2/3分别代表System、Documents、Downloads、Tools</p><h2 id="后记">后记</h2><p>后来发现只要将 macOS 中的文件拷贝至挂载的 windows 分区就会报““访达”不能完成该操作，因为不能读取或写入“XXX”中的数据。（错误代码 -36）”<br>使用 cp 命令复制会报“cp: XXX: could not copy extended attributes to ./XXX: Operation not supported on socket” 的错误，但实际文件已经正确拷贝过去了。<br>查了下载 macOS 与 NTFS 之间进行文件交互的确会有这个问题，目前没找到很好的解决办法。</p></div><script src="https://cdn.jsdelivr.net/lightgallery.js/1.0.1/js/lightgallery.min.js"></script><script>if (typeof lightGallery !== 'undefined') {        var options = {            selector: '.gallery-item'        };        lightGallery(document.getElementsByClassName('.article-gallery')[0], options);        }</script>]]></content>
    
    
    <summary type="html">使用开源方案ntfs-3g解决macOS挂载NTFS只读的问题</summary>
    
    
    
    <category term="操作系统" scheme="https://opsuri.com/categories/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/"/>
    
    <category term="备忘录" scheme="https://opsuri.com/categories/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/%E5%A4%87%E5%BF%98%E5%BD%95/"/>
    
    
    <category term="备忘录" scheme="https://opsuri.com/tags/%E5%A4%87%E5%BF%98%E5%BD%95/"/>
    
    <category term="操作系统" scheme="https://opsuri.com/tags/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/"/>
    
    <category term="macOS" scheme="https://opsuri.com/tags/macOS/"/>
    
  </entry>
  
  <entry>
    <title>实战：在 CentOS7上部署 Jumpserver1.2</title>
    <link href="https://opsuri.com/2018/04/20/Deploying-latest-jumpserver-on-CentOS7/"/>
    <id>https://opsuri.com/2018/04/20/Deploying-latest-jumpserver-on-CentOS7/</id>
    <published>2018-04-20T05:48:22.000Z</published>
    <updated>2025-02-22T13:59:13.973Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/lightgallery.js/1.0.1/css/lightgallery.min.css" /><div class=".article-gallery"><p>实战：CentOS7 一步步部署安装 jumpserver1.2，看看都踩过哪些坑。<br>Jumpserver 终于升级到1.2版本了！之前试用了1.0版本，由于 Bug 太多，搭建的时候各种报错，简直噩梦。搭建后还是有乱码等问题，因时间关系就没继续折腾了。这次听说1.2版本修复了不少 Bug，效果不错就决定继续折腾了。</p><h2 id="部署环境">部署环境</h2><blockquote><p>系统：CentOS7.4<br>IP： 172.31.12.12<br>关闭 selinux 及防火墙</p></blockquote><span id="more"></span><h2 id="准备">准备</h2><p>安装前准备，selinux，防火墙及字符集配置</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">## 关闭 selinux 及防火墙</span></span><br><span class="line">$ <span class="built_in">sudo</span> sed -i <span class="string">&#x27;s/^SELINUX=enforcing/SELINUX=disabled/&#x27;</span> /etc/selinux/config</span><br><span class="line">$ <span class="built_in">sudo</span> setenforce 0</span><br><span class="line">$ <span class="built_in">sudo</span> systemctl stop iptables firewalld</span><br><span class="line">$ <span class="built_in">sudo</span> systemctl <span class="built_in">disable</span> iptables firewalld</span><br><span class="line"><span class="comment">## 更改系统默认语言字符集</span></span><br><span class="line">localedef -c -f UTF-8 -i zh_CN zh_CN.UTF-8</span><br><span class="line"><span class="comment">## 永久生效</span></span><br><span class="line"><span class="built_in">echo</span> &gt; /etc/profile.d/locale.sh &lt;&lt; <span class="string">EOF</span></span><br><span class="line"><span class="string">export LC_CTYPE=zh_CN.UTF-8</span></span><br><span class="line"><span class="string">export LC_ALL=zh_CN.UTF-8</span></span><br><span class="line"><span class="string">EOF</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&#x27;LANG=zh_CN.UTF-8&#x27;</span> &gt; /etc/locale.conf</span><br><span class="line"><span class="comment">## 临时生效</span></span><br><span class="line"><span class="built_in">export</span> LC_ALL=zh_CN.UTF-8</span><br><span class="line"><span class="comment">## 安装必须软件包</span></span><br><span class="line">yum -y install wget sqlite-devel xz gcc automake zlib-devel openssl-devel epel-release git</span><br></pre></td></tr></table></figure><h2 id="Python3">Python3</h2><p>将 python 由2.7升级至3.6.5。本次安装目录为 <code>/usr/local/python</code>。本机只用来做跳板机，没有其他的项目，配置的是 <code>Python3</code> 的真实环境。所以需保留 <code>python2</code> 并将系统默认 <code>Python</code> 版本改为 <code>python3</code> 。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line">## 下载安装 Python3</span><br><span class="line">$ wget https://www.python.org/ftp/python/3.6.5/Python-3.6.5.tar.xz</span><br><span class="line">$ sudo tar xf Python-3.6.5.tar.xz -C /usr/local</span><br><span class="line">$ cd /usr/local/Python-3.6.5/</span><br><span class="line">$ sudo ./configure --prefix=/usr/local/python &amp;&amp; make &amp;&amp; make install</span><br><span class="line">## 修改系统 python 默认版本为 python3 并保留 python2.7</span><br><span class="line">$ which -a python</span><br><span class="line">$ ll /usr/bin/py*</span><br><span class="line">$ ll /usr/bin/easy*</span><br><span class="line">$ sudo mv /usr/bin/pydoc&#123;,2&#125;</span><br><span class="line">$ sudo mv /usr/bin/python&#123;,.old&#125;</span><br><span class="line">$ sudo mv /usr/bin/easy_install&#123;,2&#125;</span><br><span class="line">$ sudo mv /usr/bin/pip&#123;,.old&#125;</span><br><span class="line">$ sudo ln -sf /usr/local/python/bin/python3 /usr/bin/python</span><br><span class="line">$ sudo ln -sf /usr/local/python/bin/pydoc3 /usr/bin/pydoc</span><br><span class="line">$ sudo ln -sf /usr/local/python/bin/easy_install-3.6 /usr/bin/easy_install</span><br><span class="line">$ sudo ln -sf /usr/local/python/bin/idle3 /usr/bin/idle3</span><br><span class="line">$ sudo ln -sf /usr/local/python/bin/pip3 /usr/bin/pip</span><br><span class="line">## 对以下软件使用 python2.7</span><br><span class="line">$ sudo sed -i &#x27;s@#!/usr/bin/python@#!/usr/bin/python2.7@&#x27; /usr/bin/yum</span><br><span class="line">$ sudo sed -i &#x27;s@#!/usr/bin/python@#!/usr/bin/python2.7@&#x27; /usr/libexec/urlgrabber-ext-down</span><br><span class="line">## 升级 pip3 </span><br><span class="line">$ sudo pip install --upgrade pip</span><br></pre></td></tr></table></figure><h2 id="Jumpserver">Jumpserver</h2><h3 id="下载或克隆-jumpserver-项目">下载或克隆 jumpserver 项目</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">$ <span class="built_in">cd</span> /opt</span><br><span class="line">$ git <span class="built_in">clone</span> --depth=1 https://github.com/jumpserver/jumpserver.git &amp;&amp; <span class="built_in">cd</span> jumpserver &amp;&amp; git checkout master</span><br></pre></td></tr></table></figure><h3 id="安装-YUM-包依赖及-Python-库依赖">安装 YUM 包依赖及 Python 库依赖</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">$ <span class="built_in">cd</span> /opt/jumpserver/requirements</span><br><span class="line">$ <span class="built_in">sudo</span> yum -y install $(<span class="built_in">cat</span> rpm_requirements.txt)  <span class="comment"># 如果没有任何报错请继续</span></span><br></pre></td></tr></table></figure><h3 id="使-boto3-botocore-certifi-版本以兼容-jms-storage">使 boto3/botocore/certifi 版本以兼容 jms-storage</h3><p>此坑一。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">$ sed -e <span class="string">&#x27;s/boto3==1.6.4/boto3==1.6.5/&#x27;</span> -e <span class="string">&#x27;s/botocore==1.9.4/botocore==1.9.5/&#x27;</span> -e <span class="string">&#x27;s/certifi==2017.11.5/certifi==2018.1.18/&#x27;</span> /opt/jumpserver/requirements/requirements.txt</span><br><span class="line">$ <span class="built_in">sudo</span> pip install -r requirements.txt  <span class="comment"># 不要指定-i参数，因为镜像上可能没有最新的包，如果没有任何报错请继续</span></span><br></pre></td></tr></table></figure><p>备注：<a href="http://mirrors.aliyun.com/pypi/simple/">http://mirrors.aliyun.com/pypi/simple/</a></p><h2 id="数据库-MySQL-及-Redis">数据库 MySQL 及 Redis</h2><h3 id="数据库搭建">数据库搭建</h3><p>创建并配置数据库 mysql/redis 做 <code>cache</code> 和 <code>celery broke</code><br>这里使用的是云数据库 <code>RDS</code> 和 <code>Redis</code>，就不写创建过程了。相关配置可参考<a href="/2018/02/01/How-to-install-latest-jumpserver/#%E5%AE%89%E8%A3%85Redis-jumpserver%E4%BD%BF%E7%94%A8redis%E5%81%9Acache%E5%92%8Ccelery-broker">之前博客</a>，创建完毕后配置数据库白名单记录下数据库连接地址及配置信息备用。</p><h3 id="配置-Jumpserver-数据库连接信息">配置 Jumpserver 数据库连接信息</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">$ <span class="built_in">cd</span> /opt/jumpserver</span><br><span class="line">$ <span class="built_in">cp</span> config_example.py config.py</span><br><span class="line">$ vi config.py</span><br><span class="line">    </span><br><span class="line"><span class="comment"># 我们计划修改 DevelopmentConfig 中的配置，因为默认 Jumpserver 使用该配置，它继承自 Config</span></span><br></pre></td></tr></table></figure><p><strong>注意: 配置文件是 Python 格式，不要用 TAB，而要用空格</strong></p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">DevelopmentConfig</span>(<span class="title class_ inherited__">Config</span>):</span><br><span class="line">    </span><br><span class="line">    ...</span><br><span class="line"></span><br><span class="line">    <span class="comment"># MySQL or postgres setting like:</span></span><br><span class="line">    DB_ENGINE = <span class="string">&#x27;mysql&#x27;</span></span><br><span class="line">    DB_HOST = <span class="string">&#x27;rm-xxxxxxxoooooo.mysql.rds.aliyuncs.com&#x27;</span></span><br><span class="line">    DB_PORT = <span class="number">3306</span></span><br><span class="line">    DB_USER = <span class="string">&#x27;jumpserver&#x27;</span></span><br><span class="line">    DB_PASSWORD = <span class="string">&#x27;somepassword&#x27;</span></span><br><span class="line">    DB_NAME = <span class="string">&#x27;jumpserver&#x27;</span></span><br><span class="line"></span><br><span class="line">    <span class="comment"># When Django start it will bind this host and port</span></span><br><span class="line">    <span class="comment"># ./manage.py runserver 127.0.0.1:8080</span></span><br><span class="line">    HTTP_BIND_HOST = <span class="string">&#x27;0.0.0.0&#x27;</span></span><br><span class="line">    HTTP_LISTEN_PORT = <span class="number">8080</span></span><br><span class="line"></span><br><span class="line">    <span class="comment"># Use Redis as broker for celery and web socket</span></span><br><span class="line">    REDIS_HOST = <span class="string">&#x27;r-xoxoxoxoxoxo.redis.rds.aliyuncs.com&#x27;</span></span><br><span class="line">    REDIS_PORT = <span class="number">6379</span></span><br><span class="line">    REDIS_PASSWORD = <span class="string">&#x27;somepassword&#x27;</span></span><br><span class="line">    BROKER_URL = <span class="string">&#x27;redis://%(password)s%(host)s:%(port)s/3&#x27;</span> % &#123;</span><br><span class="line">        <span class="string">&#x27;password&#x27;</span>: REDIS_PASSWORD,</span><br><span class="line">        <span class="string">&#x27;host&#x27;</span>: REDIS_HOST,</span><br><span class="line">        <span class="string">&#x27;port&#x27;</span>: REDIS_PORT,</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">...</span><br><span class="line">    </span><br><span class="line">config = DevelopmentConfig()  <span class="comment"># 确保使用的是刚才设置的配置文件</span></span><br></pre></td></tr></table></figure><h3 id="生成数据库表结构和初始化数据">生成数据库表结构和初始化数据</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">$ cd /opt/jumpserver/utils</span><br><span class="line">$ bash make_migrations.sh</span><br></pre></td></tr></table></figure><p><strong>导入 sql 时遇到的问题</strong>：<br>此坑二。</p><blockquote><p>ln -sf /usr/local/python/bin/gunicorn /usr/bin/gunicorn<br><strong>注</strong>：修复 <code>FileNotFoundError: [Errno 2] No such file or directory: 'gunicorn': 'gunicorn'</code> 报错。<br>ln -sf /usr/local/python/bin/celery /usr/bin/celery<br><strong>注</strong>：修复 <code>FileNotFoundError: [Errno 2] No such file or directory: 'celery': 'celery'</code> 报错。</p></blockquote><h3 id="启动验证-Jumpserver">启动验证 Jumpserver</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">$ <span class="built_in">cd</span> /opt/jumpserver</span><br><span class="line">$ ./jms start all  <span class="comment"># 后台运行使用 -d 参数./jms start all -d</span></span><br><span class="line">    </span><br><span class="line"><span class="comment"># 新版本更新了运行脚本，使用方式./jms start|stop|status|restart all  后台运行请添加 -d 参数</span></span><br></pre></td></tr></table></figure><p>运行不报错，请浏览器访问 <a href="http://172.31.12.12:8080/">http://172.31.12.12:8080/</a> 默认账号: <code>admin</code> 密码: <code>admin</code> 页面显示不正常先不用处理，搭建 <code>nginx</code> 代理就可以正常访问了</p><h2 id="安装-SSH-Server-和-WebSocket-Server-Coco">安装 SSH Server 和 WebSocket Server: Coco</h2><h3 id="下载或获取项目">下载或获取项目</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">$ <span class="built_in">cd</span> /opt</span><br><span class="line">$ git <span class="built_in">clone</span> https://github.com/jumpserver/coco.git &amp;&amp; <span class="built_in">cd</span> coco &amp;&amp; git checkout master</span><br><span class="line"><span class="comment">## 安装依赖</span></span><br><span class="line">$ <span class="built_in">cd</span> /opt/coco/requirements</span><br><span class="line">$ <span class="built_in">sudo</span> yum -y  install $(<span class="built_in">cat</span> rpm_requirements.txt)</span><br><span class="line"><span class="comment">## 修复不兼容问题，提示paramiko不兼容问题请忽略</span></span><br><span class="line">$ <span class="built_in">sudo</span> sed -e <span class="string">&#x27;s/paramiko==2.4.0/paramiko==2.4.0/&#x27;</span> -e <span class="string">&#x27;s/pyte==0.7.0/pyte==0.5.2/&#x27;</span> -e <span class="string">&#x27;s/pytz==2017.3/pytz==2017.2/&#x27;</span> /opt/coco/requirements/requirements.txt</span><br><span class="line">$ <span class="built_in">sudo</span> pip install -r requirements.txt</span><br></pre></td></tr></table></figure><h3 id="查看配置文件并运行">查看配置文件并运行</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">$ <span class="built_in">cd</span> /opt/coco</span><br><span class="line">$ <span class="built_in">cp</span> conf_example.py conf.py  <span class="comment"># 如果 coco 与 jumpserver 分开部署，请手动修改 conf.py</span></span><br><span class="line">$ <span class="built_in">sudo</span> ./cocod start  <span class="comment"># 后台运行使用 -d 参数./cocod start -d</span></span><br><span class="line">    </span><br><span class="line"><span class="comment"># 新版本更新了运行脚本，使用方式./cocod start|stop|status|restart  后台运行请添加 -d 参数</span></span><br></pre></td></tr></table></figure><h3 id="接受注册">接受注册</h3><p>启动成功后去<code>Jumpserver</code>→<code>会话管理</code>→<code>终端管理</code>（ <a href="http://172.31.12.12:8080/terminal/terminal/">http://172.31.12.12:8080/terminal/terminal/</a> ）接受coco的注册，如果页面不正常可以等部署完成后再处理</p><h2 id="安装-Web-Terminal-前端-Luna">安装 Web Terminal 前端 Luna</h2><p>Luna 已改为纯前端，需要 Nginx 来运行访问。</p><p>访问（ <a href="https://github.com/jumpserver/luna/releases">https://github.com/jumpserver/luna/releases</a> ）下载对应版本的 release 包，直接解压，不需要编译</p><h3 id="解压-Luna">解压 Luna</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">$ <span class="built_in">cd</span> /opt/</span><br><span class="line">$ wget https://github.com/jumpserver/luna/releases/download/v1.0.0/luna.tar.gz</span><br><span class="line">$ tar xvf luna.tar.gz</span><br><span class="line">$ <span class="built_in">ls</span> /opt/luna</span><br></pre></td></tr></table></figure><h3 id="配置-Nginx-整合各组件">配置 Nginx 整合各组件</h3><p>可以直接 yum 安装 nginx。编译安装的话请参考<a href="/2017/04/05/LNMP-on-CentOS7-01/#%E5%AE%89%E8%A3%85Nginx">之前博客</a></p><p>准备配置文件 修改 /etc/nginx/nginx.conf将以下代码替换文件中的 server 模块：</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">server</span> &#123;</span><br><span class="line">    <span class="string">listen</span> <span class="number">80</span><span class="string">;</span></span><br><span class="line">    <span class="comment">#listen [::]:80 ssl ipv6only=on; </span></span><br><span class="line">    <span class="string">server_name</span> <span class="string">j1.opstrip.com;</span></span><br><span class="line"></span><br><span class="line">    <span class="string">proxy_set_header</span> <span class="string">X-Real-IP</span> <span class="string">$remote_addr;</span></span><br><span class="line">    <span class="string">proxy_set_header</span> <span class="string">Host</span> <span class="string">$host;</span></span><br><span class="line">    <span class="string">proxy_set_header</span> <span class="string">X-Forwarded-For</span> <span class="string">$proxy_add_x_forwarded_for;</span></span><br><span class="line"></span><br><span class="line">    <span class="string">if</span> <span class="string">(</span> <span class="string">$scheme</span> <span class="string">=</span> <span class="string">http</span> <span class="string">)</span>&#123;</span><br><span class="line">        <span class="string">return</span> <span class="number">301</span> <span class="string">https://j1.opstrip.com$request_uri;</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">#rewrite ^(.*)$  https://$host$1 permanent;</span></span><br><span class="line">&#125;</span><br><span class="line">    </span><br><span class="line"><span class="comment"># HTTPS server</span></span><br><span class="line">    </span><br><span class="line"><span class="string">server</span> &#123;</span><br><span class="line">    <span class="string">listen</span> <span class="number">443</span><span class="string">;</span></span><br><span class="line">    <span class="string">server_name</span> <span class="string">j1.opstrip.com;</span></span><br><span class="line"></span><br><span class="line">    <span class="comment"># 启用HSTS协议</span></span><br><span class="line">    <span class="comment">#add_header Strict-Transport-Security &quot;max-age=63072000; includeSubdomains; preload&quot;;</span></span><br><span class="line"></span><br><span class="line">    <span class="string">ssl</span> <span class="string">on;</span></span><br><span class="line">    <span class="string">ssl_certificate</span>       <span class="string">/etc/nginx/cert.d/opstrip.com/opstrip.com.crt;</span></span><br><span class="line">    <span class="string">ssl_certificate_key</span>   <span class="string">/etc/nginx/cert.d/opstrip.com/opstrip.com.key;</span></span><br><span class="line"></span><br><span class="line">    <span class="string">ssl_session_cache</span>    <span class="string">shared:SSL:1m;</span></span><br><span class="line">    <span class="string">ssl_session_timeout</span>  <span class="string">5m;</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">#ssl_ciphers  HIGH:!aNULL:!MD5;</span></span><br><span class="line">    <span class="comment">#ssl_prefer_server_ciphers  on;</span></span><br><span class="line"></span><br><span class="line">    <span class="string">proxy_set_header</span> <span class="string">X-Real-IP</span> <span class="string">$remote_addr;</span></span><br><span class="line">    <span class="string">proxy_set_header</span> <span class="string">Host</span> <span class="string">$host;</span></span><br><span class="line">    <span class="string">proxy_set_header</span> <span class="string">X-Forwarded-For</span> <span class="string">$proxy_add_x_forwarded_for;</span></span><br><span class="line"></span><br><span class="line">    <span class="string">location</span> <span class="string">/luna/</span> &#123;</span><br><span class="line">        <span class="string">try_files</span> <span class="string">$uri</span> <span class="string">/</span> <span class="string">/index.html;</span></span><br><span class="line">        <span class="string">alias</span> <span class="string">/opt/luna/;</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="string">location</span> <span class="string">/media/</span> &#123;</span><br><span class="line">        <span class="string">add_header</span> <span class="string">Content-Encoding</span> <span class="string">gzip;</span></span><br><span class="line">        <span class="string">root</span> <span class="string">/opt/jumpserver/data/;</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="string">location</span> <span class="string">/static/</span> &#123;</span><br><span class="line">        <span class="string">root</span> <span class="string">/opt/jumpserver/data/;</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="string">location</span> <span class="string">/socket.io/</span> &#123;</span><br><span class="line">        <span class="string">proxy_pass</span>       <span class="string">http://localhost:5000/socket.io/;</span>  <span class="comment"># 如果coco安装在别的服务器，请填写它的ip</span></span><br><span class="line">        <span class="string">proxy_buffering</span> <span class="string">off;</span></span><br><span class="line">        <span class="string">proxy_http_version</span> <span class="number">1.1</span><span class="string">;</span></span><br><span class="line">        <span class="string">proxy_set_header</span> <span class="string">Upgrade</span> <span class="string">$http_upgrade;</span></span><br><span class="line">        <span class="string">proxy_set_header</span> <span class="string">Connection</span> <span class="string">&quot;upgrade&quot;</span><span class="string">;</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">#location /guacamole/ &#123;</span></span><br><span class="line">    <span class="comment">#    proxy_pass       http://localhost:8081/;  # 如果guacamole安装在别的服务器，请填写它的ip</span></span><br><span class="line">    <span class="comment">#    proxy_buffering off;</span></span><br><span class="line">    <span class="comment">#    proxy_http_version 1.1;</span></span><br><span class="line">    <span class="comment">#    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;</span></span><br><span class="line">    <span class="comment">#    proxy_set_header Upgrade $http_upgrade;</span></span><br><span class="line">    <span class="comment">#    proxy_set_header Connection $http_connection;</span></span><br><span class="line">    <span class="comment">#    access_log off;</span></span><br><span class="line">    <span class="comment">#&#125;</span></span><br><span class="line"></span><br><span class="line">    <span class="string">location</span> <span class="string">/</span> &#123;</span><br><span class="line">        <span class="string">proxy_pass</span> <span class="string">http://localhost:8080;</span>  <span class="comment"># 如果jumpserver安装在别的服务器，请填写它的ip</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="string">access_log</span> <span class="string">/var/log/nginx/access_jumpserver.log;</span></span><br><span class="line">    <span class="string">error_log</span> <span class="string">/var/log/nginx/error_jumpserver.log;</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>将 SSL 证书放入到相应位置。启动 nginx 与 jumpserver 等组件。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">## 启动 nginx</span></span><br><span class="line">$ <span class="built_in">sudo</span> systemctl <span class="built_in">enable</span> nginx</span><br><span class="line">$ <span class="built_in">sudo</span> systemctl start nginx</span><br><span class="line">$ nginx -t</span><br><span class="line"><span class="comment">## 启动 jumpserver</span></span><br><span class="line">$ <span class="built_in">cd</span> /opt/jumpserver</span><br><span class="line">$ ./jms start all -d</span><br><span class="line"><span class="comment">## 启动 coco</span></span><br><span class="line">$ <span class="built_in">cd</span> /opt/coco</span><br><span class="line">$ ./cocod start -d</span><br></pre></td></tr></table></figure><p>服务全部启动后，访问域名 (<a href="https://j1.opstrip.com">https://j1.opstrip.com</a>) 就可以访问跳板机了。<br>默认账号: <code>admin</code> 密码: <code>admin</code> 见下图：<br><a href="/assets/blogImg/jumpserver.png" title="跳板机仪表盘" class="gallery-item"><img src="/assets/blogImg/jumpserver.png" alt="跳板机仪表盘"></a><br>如果部署过程中没有接受应用的注册，需要到<code>Jumpserver</code>→<code>会话管理</code>→<code>终端管理</code> 接受 <code>Coco Guacamole</code> 等应用的注册。</p><p><strong>测试连接</strong></p><blockquote><ul><li><p>如果登录客户端是 macOS 或 Linux ，登录语法如下<br>$ ssh -p2222 <a href="mailto:admin@j1.opstrip.com">admin@j1.opstrip.com</a><br>$ sftp -P2222 <a href="mailto:admin@j1.opstrip.com">admin@j1.opstrip.com</a><br>密码: <code>admin</code> 如果没有更改<code>coco</code>的配置文件<code>conf.py</code>下面的<code>SSHD_PORT</code>参数，就是默认的<code>2222</code>端口。</p></li><li><p>如果登录客户端是 Windows ，Xshell Terminal 登录语法如下<br>$ ssh <a href="mailto:admin@192.168.244.144">admin@192.168.244.144</a> 2222<br>$ sftp <a href="mailto:admin@192.168.244.144">admin@192.168.244.144</a> 2222<br>密码: <code>admin</code><br>如果能登陆代表部署成功</p></li></ul></blockquote><p>也可以添加 ssh 的 key 来登录验证，这样就不需要每次登录输入密码了。enjoy it！</p></div><script src="https://cdn.jsdelivr.net/lightgallery.js/1.0.1/js/lightgallery.min.js"></script><script>if (typeof lightGallery !== 'undefined') {        var options = {            selector: '.gallery-item'        };        lightGallery(document.getElementsByClassName('.article-gallery')[0], options);        }</script>]]></content>
    
    
    <summary type="html">实战：一步步部署安装 jumpserver1.2，看看都踩过哪些坑。</summary>
    
    
    
    <category term="备忘录" scheme="https://opsuri.com/categories/%E5%A4%87%E5%BF%98%E5%BD%95/"/>
    
    
    <category term="Linux" scheme="https://opsuri.com/tags/Linux/"/>
    
    <category term="Jumpserver" scheme="https://opsuri.com/tags/Jumpserver/"/>
    
  </entry>
  
  <entry>
    <title>Centos7.3 Kubernetes集群部署</title>
    <link href="https://opsuri.com/2018/03/28/Deploying-Kubernetes-cluster-on-CentOS7/"/>
    <id>https://opsuri.com/2018/03/28/Deploying-Kubernetes-cluster-on-CentOS7/</id>
    <published>2018-03-28T09:24:24.000Z</published>
    <updated>2025-02-22T13:58:37.341Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/lightgallery.js/1.0.1/css/lightgallery.min.css" /><div class=".article-gallery"><p>下午抽空整了下Kubernetes环境，限于资源的原因，这个环境比较简单：一台master，两台node。搞起！</p><h2 id="环境介绍及准备">环境介绍及准备</h2><h3 id="物理机操作系统">物理机操作系统</h3><p>物理机操作系统采用CentOS7.4 64位，细节如下。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">[root@opstrip.com ~]# <span class="built_in">uname</span> -a</span><br><span class="line">Linux opstrip.com 3.10.0-693.2.2.el7.x86_64 <span class="comment">#1 SMP Tue Sep 12 22:26:13 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux</span></span><br><span class="line">[root@opstrip.com ~]# <span class="built_in">cat</span> /etc/redhat-release </span><br><span class="line">CentOS Linux release 7.4.1708 (Core)</span><br></pre></td></tr></table></figure><h3 id="主机信息">主机信息</h3><p>本文准备了三台机器用于部署k8s的运行环境，细节如下：</p><table><thead><tr><th style="text-align:center">HostName</th><th style="text-align:center">IP</th><th style="text-align:center">Node/function</th></tr></thead><tbody><tr><td style="text-align:center">K8s-master</td><td style="text-align:center">172.31.12.12</td><td style="text-align:center">kubernetes, etcd</td></tr><tr><td style="text-align:center">K8s-node1</td><td style="text-align:center">172.31.12.13</td><td style="text-align:center">kubernetes-node, flannel</td></tr><tr><td style="text-align:center">K8s-node1</td><td style="text-align:center">172.31.12.14</td><td style="text-align:center">kubernetes-node, flannel</td></tr></tbody></table><h3 id="环境准备">环境准备</h3><h4 id="主机名修改">主机名修改</h4><span id="more"></span><p><strong>Master：</strong></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">[root@ip-172-31-12-12 ~]#  hostnamectl --static set-hostname  k8s-master</span><br></pre></td></tr></table></figure><p><strong>Node1:</strong></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">[root@ip-172-31-12-13 ~]#  hostnamectl --static set-hostname  k8s-node1</span><br></pre></td></tr></table></figure><p><strong>Node2:</strong></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">[root@ip-172-31-12-14 ~]#  hostnamectl --static set-hostname  k8s-node2</span><br></pre></td></tr></table></figure><h4 id="安装docker及iptables">安装docker及iptables</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">yum install docker iptables-services.x86_64 -y</span><br></pre></td></tr></table></figure><h4 id="关闭默认firewalld启动iptables并清除默认规则">关闭默认firewalld启动iptables并清除默认规则</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">systemctl stop firewalld</span><br><span class="line">systemctl <span class="built_in">disable</span> firewalld</span><br><span class="line">systemctl start iptables</span><br><span class="line">systemctl <span class="built_in">enable</span> iptables</span><br><span class="line">iptables -F</span><br><span class="line">service iptables save</span><br></pre></td></tr></table></figure><h4 id="启动docker并加入开机自启动">启动docker并加入开机自启动</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">systemctl start docker</span><br><span class="line">systemctl <span class="built_in">enable</span> docker</span><br></pre></td></tr></table></figure><h2 id="K8S集群部署">K8S集群部署</h2><p><strong>MASTER</strong></p><h3 id="master安装kubernetes，etcd">master安装kubernetes，etcd</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">[root@k8s-master ~]# yum install kubernetes etcd -y</span><br></pre></td></tr></table></figure><h3 id="配置">配置</h3><p><strong>etcd</strong></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 修改</span></span><br><span class="line">[root@k8s-master ~]# <span class="built_in">cd</span> /etc/etcd/</span><br><span class="line">[root@k8s-master etcd]# vim etcd.conf </span><br><span class="line">9:ETCD_LISTEN_CLIENT_URLS=<span class="string">&quot;http://0.0.0.0:2379&quot;</span></span><br><span class="line">20:ETCD_ADVERTISE_CLIENT_URLS=<span class="string">&quot;http://0.0.0.0:2379&quot;</span></span><br><span class="line">    </span><br><span class="line"><span class="comment"># 启动并加入开机自启动</span></span><br><span class="line">[root@k8s-master etcd]# systemctl start etcd</span><br><span class="line">[root@k8s-master etcd]# systemctl <span class="built_in">enable</span> etcd</span><br><span class="line">kubernetes</span><br><span class="line">    </span><br><span class="line"><span class="comment"># 修改</span></span><br><span class="line">[root@k8s-master ~]# <span class="built_in">cd</span> /etc/kubernetes/</span><br><span class="line">[root@k8s-master kubernetes]# ll</span><br><span class="line">total 24</span><br><span class="line">-rw-r--r-- 1 root root 767 Jul  3 23:33 apiserver          <span class="comment">#需要配置</span></span><br><span class="line">-rw-r--r-- 1 root root 655 Jul  3 23:33 config             <span class="comment">#需要配置</span></span><br><span class="line">-rw-r--r-- 1 root root 189 Jul  3 23:33 controller-manager <span class="comment">#需要配置</span></span><br><span class="line">-rw-r--r-- 1 root root 615 Jul  3 23:33 kubelet</span><br><span class="line">-rw-r--r-- 1 root root 103 Jul  3 23:33 proxy</span><br><span class="line">-rw-r--r-- 1 root root 111 Jul  3 23:33 scheduler          <span class="comment">#需要配置</span></span><br><span class="line">    </span><br><span class="line"><span class="comment"># 配置config</span></span><br><span class="line">[root@k8s-master kubernetes]# vim config </span><br><span class="line">22:KUBE_MASTER=<span class="string">&quot;--master=http://172.31.12.12:8080&quot;</span></span><br><span class="line">    </span><br><span class="line"><span class="comment"># apiserver</span></span><br><span class="line">[root@k8s-master kubernetes]# vim apiserver </span><br><span class="line">8:KUBE_API_ADDRESS=<span class="string">&quot;--insecure-bind-address=0.0.0.0&quot;</span></span><br><span class="line">11:KUBE_API_PORT=<span class="string">&quot;--port=8080&quot;</span></span><br><span class="line">14:KUBELET_PORT=<span class="string">&quot;--kubelet-port=10250&quot;</span></span><br><span class="line">17:KUBE_ETCD_SERVERS=<span class="string">&quot;--etcd-servers=http://127.0.0.1:2379&quot;</span></span><br><span class="line">23:KUBE_ADMISSION_CONTROL=<span class="string">&quot;--admission-control=NamespaceLifecycle,NamespaceExists,LimitRanger,ResourceQuota&quot;</span></span><br><span class="line">    </span><br><span class="line"><span class="comment"># controller-manager </span></span><br><span class="line">[root@k8s-master kubernetes]# vim  controller-manager </span><br><span class="line">8:KUBELET_ADDRESSES=<span class="string">&quot;--machines=172.31.12.13,172.31.12.14&quot;</span>  <span class="comment">#增加配置</span></span><br><span class="line">    </span><br><span class="line"><span class="comment"># 启动服务并加入开机自启动</span></span><br><span class="line">[root@k8s-master ~]# systemctl list-unit-files |grep kube</span><br><span class="line">kube-apiserver.service                      disabled     <span class="comment">#需要启动</span></span><br><span class="line">kube-controller-manager.service             disabled     <span class="comment">#需要启动</span></span><br><span class="line">kube-proxy.service                          disabled</span><br><span class="line">kube-scheduler.service                      disabled     <span class="comment">#需要启动 </span></span><br><span class="line">kubelet.service                             disabled    </span><br><span class="line"><span class="comment"># 启动</span></span><br><span class="line">[root@k8s-master ~]# systemctl start kube-apiserver.service kube-controller-manager.service  kube-scheduler.service  </span><br><span class="line"><span class="comment"># 查看是否启动</span></span><br><span class="line">[root@k8s-master ~]# systemctl is-active  kube-apiserver.service kube-controller-manager.service kube-scheduler.service </span><br><span class="line">active</span><br><span class="line">active</span><br><span class="line">active</span><br><span class="line"><span class="comment"># 开机启动</span></span><br><span class="line">[root@k8s-master ~]# systemctl <span class="built_in">enable</span> kube-apiserver.service kube-controller-manager.service  kube-scheduler.service</span><br></pre></td></tr></table></figure><p><code>注意：启动顺序 etcd--&gt;kubernetes*</code></p><p>** SLAVE 两个节点相同 **</p><h3 id="slave-安装-kubernetes-node">slave 安装 kubernetes-node</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">yum install kubernetes-node.x86_64 flannel -y</span><br></pre></td></tr></table></figure><h3 id="slave配置">slave配置</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line">[root@k8s-node1 ~]# <span class="built_in">cd</span> /etc/kubernetes/</span><br><span class="line">[root@k8s-node1 kubernetes]# ll</span><br><span class="line">total 12</span><br><span class="line">-rw-r--r-- 1 root root 655 Jul  3 23:33 config  <span class="comment">#需要配置</span></span><br><span class="line">-rw-r--r-- 1 root root 615 Jul  3 23:33 kubelet <span class="comment">#需要配置</span></span><br><span class="line">-rw-r--r-- 1 root root 103 Jul  3 23:33 proxy</span><br><span class="line">    </span><br><span class="line"><span class="comment"># config </span></span><br><span class="line">[root@k8s-node1 kubernetes]# vim config </span><br><span class="line">22:KUBE_MASTER=<span class="string">&quot;--master=http://172.31.12.12:8080&quot;</span></span><br><span class="line">    </span><br><span class="line"><span class="comment"># kubelet</span></span><br><span class="line">5:KUBELET_ADDRESS=<span class="string">&quot;--address=0.0.0.0&quot;</span></span><br><span class="line">8:KUBELET_PORT=<span class="string">&quot;--port=10250&quot;</span></span><br><span class="line">11:KUBELET_HOSTNAME=<span class="string">&quot;--hostname-override=172.31.12.13&quot;</span></span><br><span class="line">14:KUBELET_API_SERVER=<span class="string">&quot;--api-servers=http://172.31.12.12:8080&quot;</span></span><br><span class="line">    </span><br><span class="line">启动并加入开机自启动</span><br><span class="line">[root@k8s-node1 ~]# systemctl list-unit-files |grep kube</span><br><span class="line">kube-proxy.service                          disabled</span><br><span class="line">kubelet.service                             disabled</span><br><span class="line">[root@k8s-node1 ~]# systemctl start kube-proxy.service kubelet.service </span><br><span class="line">[root@k8s-node1 ~]# systemctl is-active kube-proxy.service kubelet.service </span><br><span class="line">active</span><br><span class="line">active</span><br><span class="line">[root@k8s-node1 ~]# systemctl <span class="built_in">enable</span> kube-proxy.service kubelet.service </span><br><span class="line">    </span><br><span class="line"><span class="comment"># flannel配置</span></span><br><span class="line">[root@k8s-node1 kubernetes]# <span class="built_in">cd</span> /etc/sysconfig/</span><br><span class="line">[root@k8s-node1 sysconfig]# vim flanneld </span><br><span class="line">4:FLANNEL_ETCD_ENDPOINTS=<span class="string">&quot;http://172.31.12.12:2379&quot;</span></span><br><span class="line">    </span><br><span class="line"><span class="comment"># 启动并加入开机自动：</span></span><br><span class="line">systemctl start flanneld.service</span><br><span class="line">systemctl <span class="built_in">enable</span> flanneld.service</span><br><span class="line">    </span><br><span class="line"><span class="comment"># 查看flannel状态</span></span><br><span class="line">[root@k8s-node1 sysconfig]# systemctl is-active flanneld.service</span><br><span class="line">active</span><br></pre></td></tr></table></figure><p><code>注意：此时flannel启动不了，之所以启动不起来是因为etcd里面没有flannel所需要的网络信息，此时我们需要在etcd里面创建flannel所需要的网络信息</code></p><p>master创建 flannel所需要的网络信息：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">[root@k8s-master ~]# etcdctl <span class="built_in">set</span> /atomic.io/network/config <span class="string">&#x27;&#123; &quot;Network&quot;: &quot;172.17.0.0/16&quot; &#125;&#x27;</span></span><br><span class="line">&#123; <span class="string">&quot;Network&quot;</span>: <span class="string">&quot;172.17.0.0/16&quot;</span> &#125;</span><br></pre></td></tr></table></figure><h3 id="集群检查">集群检查</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">[root@k8s-master ~]# kubectl get node</span><br><span class="line">NAME             STATUS    AGE</span><br><span class="line">172.31.12.13   Ready     56m</span><br><span class="line">172.31.12.14   Ready     54m</span><br></pre></td></tr></table></figure><p>kubernetes集群配置完成！</p></div><script src="https://cdn.jsdelivr.net/lightgallery.js/1.0.1/js/lightgallery.min.js"></script><script>if (typeof lightGallery !== 'undefined') {        var options = {            selector: '.gallery-item'        };        lightGallery(document.getElementsByClassName('.article-gallery')[0], options);        }</script>]]></content>
    
    
    <summary type="html">初步学习Kubernetes在CentOS7.3上的部署，了解K8s集群概念。</summary>
    
    
    
    <category term="学习笔记" scheme="https://opsuri.com/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="Linux" scheme="https://opsuri.com/tags/Linux/"/>
    
    <category term="Kubernetes" scheme="https://opsuri.com/tags/Kubernetes/"/>
    
  </entry>
  
  <entry>
    <title>安装最新版jumpserver</title>
    <link href="https://opsuri.com/2018/02/01/How-to-install-latest-jumpserver/"/>
    <id>https://opsuri.com/2018/02/01/How-to-install-latest-jumpserver/</id>
    <published>2018-02-01T07:27:01.000Z</published>
    <updated>2025-02-22T14:13:06.358Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/lightgallery.js/1.0.1/css/lightgallery.min.css" /><div class=".article-gallery"><p>线上一直在使用0.3.2版本的jumpserver。随着机器与人员的增多，跳板机的可用性也越来越低了。今天抽空测试了下新版本的jumpserver0.5.0，发现居然增加了redis做celery broker，性能应该有所提升。至于提升多少性能，还要用过一段时间才知道。今天先部署吧。</p><h2 id="环境">环境</h2><blockquote><p>系统: CentOS 7<br>IP: 172.31.12.12<br>关闭 selinux和防火墙</p></blockquote><ul><li><h3 id="CentOS-7">CentOS 7</h3></li></ul><blockquote><p>$ setenforce 0  # 可以设置配置文件永久关闭<br>$ systemctl stop iptables.service<br>$ systemctl stop firewalld.service</p></blockquote><ul><li><h3 id="CentOS-6">CentOS 6</h3></li></ul><blockquote><p>$ setenforce 0<br>$ service iptables stop</p></blockquote><h2 id="准备Python3和Python虚拟环境">准备Python3和Python虚拟环境</h2><h3 id="安装依赖包">安装依赖包</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ yum -y install wget sqlite-devel xz gcc automake zlib-devel openssl-devel epel-release</span><br></pre></td></tr></table></figure><h3 id="编译安装">编译安装</h3><span id="more"></span><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">$ wget https://www.python.org/ftp/python/3.6.4/Python-3.6.4.tar.xz</span><br><span class="line">$ tar xvf Python-3.6.4.tar.xz  &amp;&amp; <span class="built_in">cd</span> Python-3.6.4</span><br><span class="line">$ ./configure &amp;&amp; make &amp;&amp; make install</span><br></pre></td></tr></table></figure><h3 id="建立python虚拟环境">建立python虚拟环境</h3><p>因为CentOS 6/7自带的是<code>Python2</code>，而<code>yum</code>等工具依赖原来的<code>Python</code>，为了不扰乱原来的环境我们来使用<code>Python虚拟环境</code></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">$ <span class="built_in">cd</span> /opt</span><br><span class="line">$ python3 -m venv py3</span><br><span class="line">$ <span class="built_in">source</span> /opt/py3/bin/activate</span><br></pre></td></tr></table></figure><p>看到下面的提示符代表成功，以后运行<code>jumpserver</code>都要先运行以上<code>source</code>命令，以下所有命令均在该<code>虚拟环境</code>中运行</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">(py3) [root@localhost py3]#</span><br></pre></td></tr></table></figure><h2 id="安装Jumpserver-0-5-0">安装Jumpserver 0.5.0</h2><h3 id="下载或clone项目">下载或clone项目</h3><p>项目提交较多<code>git clone</code>时较大，你可以选择去<code>github项目</code>页面直接下载 zip包，我的网速好，我直接clone了</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">$ <span class="built_in">cd</span> /opt/</span><br><span class="line">$ git <span class="built_in">clone</span> --depth=1 https://github.com/jumpserver/jumpserver.git &amp;&amp; <span class="built_in">cd</span> jumpserver &amp;&amp; git checkout dev</span><br></pre></td></tr></table></figure><h3 id="安装依赖rpm包">安装依赖rpm包</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">$ <span class="built_in">cd</span> /opt/jumpserver/requirements</span><br><span class="line">$ yum -y install $(<span class="built_in">cat</span> rpm_requirements.txt)  <span class="comment"># 如果没有任何报错请继续</span></span><br></pre></td></tr></table></figure><h3 id="安装python库依赖">安装python库依赖</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ pip install -r requirements.txt  <span class="comment"># 不要指定-i参数，因为镜像上可能没有最新的包，如果没有任何报错请继续</span></span><br></pre></td></tr></table></figure><h3 id="安装Redis-jumpserver使用redis做cache和celery-broker">安装<code>Redis</code>, <code>jumpserver</code>使用redis做<code>cache</code>和<code>celery broker</code></h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">$ yum -y install redis</span><br><span class="line">$ service redis start</span><br></pre></td></tr></table></figure><h3 id="安装MySQL">安装MySQL</h3><p>本教程使用mysql作为数据库，如果不使用mysql可以跳过相关mysql安装和配置</p><ul><li><h3 id="centos7">centos7</h3></li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">$ yum -y install mariadb mariadb-devel mariadb-server <span class="comment"># centos7下安装的是mariadb</span></span><br><span class="line">$ service mariadb start</span><br></pre></td></tr></table></figure><ul><li><h3 id="centos6">centos6</h3></li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">$ yum -y install mysql mysql-devel mysql-server</span><br><span class="line">$ service mysqld start</span><br></pre></td></tr></table></figure><p>我是用的是AWS的ElastiCache和RDS服务，因此这里跳过安装Redis/MySQL与授权的操作。</p><h3 id="创建数据库-jumpserver并授权">创建数据库 jumpserver并授权</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">$ mysql</span><br><span class="line">&gt; create database jumpserver default charset <span class="string">&#x27;utf8&#x27;</span>;</span><br><span class="line">&gt; grant all on jumpserver.* to <span class="string">&#x27;jumpserver&#x27;</span>@<span class="string">&#x27;127.0.0.1&#x27;</span> identified by <span class="string">&#x27;somepassword&#x27;</span>;</span><br></pre></td></tr></table></figure><h3 id="修改jumpserver配置文件">修改jumpserver配置文件</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">$ <span class="built_in">cd</span> /opt/jumpserver</span><br><span class="line">$ <span class="built_in">cp</span> config_example.py config.py</span><br><span class="line">$ vi config.py  <span class="comment"># 我们计划修改 DevelopmentConfig中的配置，因为默认jumpserver是使用该配置，它继承自Config</span></span><br></pre></td></tr></table></figure><p><strong>注意: 配置文件是python格式，不要用tab，而要用空格 注意: 配置文件是python格式，不要用tab，而要用空格 注意: 配置文件是python格式，不要用tab，而要用空格</strong></p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">DevelopmentConfig</span>(<span class="title class_ inherited__">Config</span>):</span><br><span class="line">    DEBUG = <span class="literal">True</span></span><br><span class="line">    DB_ENGINE = <span class="string">&#x27;mysql&#x27;</span></span><br><span class="line">    DB_HOST = <span class="string">&#x27;127.0.0.1&#x27;</span></span><br><span class="line">    DB_PORT = <span class="number">3306</span></span><br><span class="line">    DB_USER = <span class="string">&#x27;jumpserver&#x27;</span></span><br><span class="line">    DB_PASSWORD = <span class="string">&#x27;somepassword&#x27;</span></span><br><span class="line">    DB_NAME = <span class="string">&#x27;jumpserver&#x27;</span></span><br><span class="line">    EMAIL_HOST = <span class="string">&#x27;smtp.exmail.qq.com&#x27;</span></span><br><span class="line">    EMAIL_PORT = <span class="number">465</span></span><br><span class="line">    EMAIL_HOST_USER = <span class="string">&#x27;a@jumpserver.org&#x27;</span></span><br><span class="line">    EMAIL_HOST_PASSWORD = <span class="string">&#x27;somepasswrd&#x27;</span></span><br><span class="line">    EMAIL_USE_SSL = <span class="literal">True</span></span><br><span class="line">    EMAIL_USE_TLS = <span class="literal">False</span></span><br><span class="line">    EMAIL_SUBJECT_PREFIX = <span class="string">&#x27;[Jumpserver] &#x27;</span></span><br><span class="line">    SITE_URL = <span class="string">&#x27;http://172.31.12.12:8080&#x27;</span>   <span class="comment"># 用户收到的邮件，会使用该地址访问</span></span><br><span class="line">    </span><br><span class="line">...</span><br><span class="line">    </span><br><span class="line">config = DevelopmentConfig()  <span class="comment"># 确保使用的是刚才设置的配置文件</span></span><br></pre></td></tr></table></figure><h3 id="生成数据库表结构和初始化数据">生成数据库表结构和初始化数据</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">$ <span class="built_in">cd</span> /opt/jumpserver/utils</span><br><span class="line">$ bash make_migrations.sh</span><br></pre></td></tr></table></figure><h3 id="运行Jumpserver">运行Jumpserver</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">$ <span class="built_in">cd</span> /opt/jumpserver</span><br><span class="line">$ python run_server.py all</span><br></pre></td></tr></table></figure><p>运行不报错，请浏览器访问 <a href="http://172.31.12.12:8080/">http://172.31.12.12:8080/</a> (这里只是jumpserver, 没有web terminal,所以访问web terminal会报错) 初始账号: admin 初始密码: admin</p><h2 id="安装SSH-Server和Web-Socket-Server-Coco">安装<code>SSH Server</code>和<code>Web Socket Server: Coco</code></h2><h3 id="下载clone项目">下载clone项目</h3><p>新开一个终端，连接测试机，别忘了<code>source /opt/py3/bin/activate</code></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">$ <span class="built_in">cd</span> /opt</span><br><span class="line">$ git <span class="built_in">clone</span> https://github.com/jumpserver/coco.git &amp;&amp; <span class="built_in">cd</span> coco &amp;&amp; git checkout dev</span><br></pre></td></tr></table></figure><h3 id="安装依赖">安装依赖</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">$ <span class="built_in">cd</span> /opt/coco/requirements</span><br><span class="line">$ yum -y  install $(<span class="built_in">cat</span> rpm_requirements.txt)</span><br><span class="line">$ pip install -r requirements.txt</span><br></pre></td></tr></table></figure><h3 id="查看配置文件并运行">查看配置文件并运行</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">$ <span class="built_in">cd</span> /opt/coco</span><br><span class="line">$ <span class="built_in">cp</span> conf_example.py conf.py</span><br><span class="line">$ python run_server.py</span><br></pre></td></tr></table></figure><p>这时需要去 jumpserver管理后台-终端-终端<a href="http://172.31.12.12:8080/terminal/terminal/">http://172.31.12.12:8080/terminal/terminal/</a>接受coco的注册</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">Coco version 0.4.0, more see https://www.jumpserver.org</span><br><span class="line">Starting ssh server at 0.0.0.0:2222</span><br><span class="line">Quit the server with CONTROL-C.</span><br></pre></td></tr></table></figure><h3 id="测试连接">测试连接</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ ssh -p2222 admin@172.31.12.12    <span class="comment">#  密码: admin</span></span><br></pre></td></tr></table></figure><p>如果是用在windows下，<code>Xshell terminal</code>登录语法如下</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ ssh admin@172.31.12.12 2222      <span class="comment">#  密码: admin</span></span><br></pre></td></tr></table></figure><p>如果能登录代表部署成功</p><h2 id="安装Web-Terminal前端Luna">安装<code>Web Terminal</code>前端<code>Luna</code></h2><p>Luna已改为纯前端，需要nginx来运行访问</p><p>下载 release包，直接解压，不需要编译</p><p>访问<a href="https://github.com/jumpserver/luna/releases">https://github.com/jumpserver/luna/releases</a>，下载对应release包</p><h3 id="解压luna">解压luna</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">$ <span class="built_in">pwd</span> </span><br><span class="line">/opt/</span><br><span class="line">    </span><br><span class="line">$ tar xvf luna.tar.gz</span><br><span class="line">$ <span class="built_in">ls</span> /opt/luna</span><br><span class="line">...</span><br></pre></td></tr></table></figure><h2 id="配置nginx整合各组件">配置<code>nginx</code>整合各组件</h2><h3 id="安装nginx-根据喜好选择安装方式和版本">安装nginx 根据喜好选择安装方式和版本</h3><p>详见<a href="https://opstrip.com/2017/04/05/LNMP-on-CentOS7-01/">Nginx安装</a>。</p><h3 id="配置文件">配置文件</h3><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">server</span> &#123;</span><br><span class="line">    <span class="string">listen</span> <span class="number">80</span><span class="string">;</span></span><br><span class="line">    <span class="string">server_name</span>  <span class="string">j2.opstrip.com;</span></span><br><span class="line">    </span><br><span class="line">    <span class="string">proxy_set_header</span> <span class="string">X-Real-IP</span> <span class="string">$remote_addr;</span></span><br><span class="line">    <span class="string">proxy_set_header</span> <span class="string">Host</span> <span class="string">$host;</span></span><br><span class="line">    <span class="string">proxy_set_header</span> <span class="string">X-Forwarded-For</span> <span class="string">$proxy_add_x_forwarded_for;</span></span><br><span class="line">    </span><br><span class="line">    <span class="string">location</span> <span class="string">/luna/</span> &#123;</span><br><span class="line">        <span class="string">try_files</span> <span class="string">$uri</span> <span class="string">/</span> <span class="string">/index.html;</span></span><br><span class="line">        <span class="string">alias</span> <span class="string">/opt/luna/;</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="string">location</span> <span class="string">/media/</span> &#123;</span><br><span class="line">        <span class="string">add_header</span> <span class="string">Content-Encoding</span> <span class="string">gzip;</span></span><br><span class="line">        <span class="string">root</span> <span class="string">/opt/jumpserver/data/;</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="string">location</span> <span class="string">/static/</span> &#123;</span><br><span class="line">        <span class="string">root</span> <span class="string">/opt/jumpserver/data/;</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="string">location</span> <span class="string">/socket.io/</span> &#123;</span><br><span class="line">        <span class="string">proxy_pass</span>       <span class="string">http://localhost:5000/socket.io/;</span></span><br><span class="line">        <span class="string">proxy_http_version</span> <span class="number">1.1</span><span class="string">;</span></span><br><span class="line">        <span class="string">proxy_set_header</span> <span class="string">Upgrade</span> <span class="string">$http_upgrade;</span></span><br><span class="line">        <span class="string">proxy_set_header</span> <span class="string">Connection</span> <span class="string">&quot;upgrade&quot;</span><span class="string">;</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="string">location</span> <span class="string">/</span> &#123;</span><br><span class="line">        <span class="string">proxy_pass</span> <span class="string">http://localhost:8080;</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="string">access_log</span> <span class="string">/var/log/nginx/jumpserver_access.log;</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="运行-nginx">运行 nginx</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># systemctl start nginx</span></span><br></pre></td></tr></table></figure><h3 id="访问-http-j2-opstrip-com">访问 <a href="http://j2.opstrip.com">http://j2.opstrip.com</a></h3><h2 id="升级">升级</h2><h3 id="升级jumpserver">升级jumpserver</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ git pull &amp;&amp; pip install -r requirements/requirements.txt &amp;&amp; <span class="built_in">cd</span> utils &amp;&amp; sh make_migrations.sh</span><br></pre></td></tr></table></figure><h3 id="升级coco">升级coco</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ git pull &amp;&amp; <span class="built_in">cd</span> requirements &amp;&amp; pip install -r requirements.txt   <span class="comment"># 不要指定 -i参数</span></span><br></pre></td></tr></table></figure><h3 id="升级luna">升级luna</h3><p>重新下载release包</p><hr><p>参考来源：<a href="https://github.com/jumpserver/jumpserver/wiki/v0.5.0-%E5%9F%BA%E4%BA%8E-CentOS7">https://github.com/jumpserver/jumpserver/wiki/v0.5.0-基于-CentOS7</a></p></div><script src="https://cdn.jsdelivr.net/lightgallery.js/1.0.1/js/lightgallery.min.js"></script><script>if (typeof lightGallery !== 'undefined') {        var options = {            selector: '.gallery-item'        };        lightGallery(document.getElementsByClassName('.article-gallery')[0], options);        }</script>]]></content>
    
    
    <summary type="html">官方文档：基于CentOS7一步步安装Jumpserver0.5.0，支持redis与集群。</summary>
    
    
    
    <category term="备忘录" scheme="https://opsuri.com/categories/%E5%A4%87%E5%BF%98%E5%BD%95/"/>
    
    
    <category term="Linux" scheme="https://opsuri.com/tags/Linux/"/>
    
    <category term="Jumpserver" scheme="https://opsuri.com/tags/Jumpserver/"/>
    
    <category term="LNMP" scheme="https://opsuri.com/tags/LNMP/"/>
    
  </entry>
  
  <entry>
    <title>升级安装Python3</title>
    <link href="https://opsuri.com/2018/01/23/Upgrade-python-to-Python3/"/>
    <id>https://opsuri.com/2018/01/23/Upgrade-python-to-Python3/</id>
    <published>2018-01-23T09:37:51.000Z</published>
    <updated>2025-02-22T14:39:58.286Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/lightgallery.js/1.0.1/css/lightgallery.min.css" /><div class=".article-gallery"><h2 id="创建安装目录">创建安装目录</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">[root@myprecious opt]# mkdir /usr/local/python3</span><br></pre></td></tr></table></figure><h2 id="下载Python3">下载Python3</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">[root@myprecious opt]# wget https://www.python.org/ftp/python/3.6.4/Python-3.6.4.tar.xz</span><br></pre></td></tr></table></figure><h2 id="编译安装">编译安装</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">[root@myprecious opt]# tar xf Python-3.6.4.tar.xz &amp;&amp; cd Python-3.6.4</span><br><span class="line">[root@myprecious Python-3.6.4]# ./configure --prefix=/usr/local/python3</span><br><span class="line">[root@myprecious Python-3.6.4]# make</span><br><span class="line">[root@myprecious Python-3.6.4]# make install</span><br></pre></td></tr></table></figure><span id="more"></span><h2 id="更改链接使Python2-3两版本共存">更改链接使Python2/3两版本共存</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">[root@myprecious Python-3.6.4]# mv /usr/bin/python&#123;,_bak&#125;</span><br><span class="line">[root@myprecious Python-3.6.4]# mv /usr/bin/pip&#123;,_bak&#125;</span><br><span class="line">[root@myprecious Python-3.6.4]# ln -s /usr/local/python3/bin/python3 /usr/bin/python</span><br><span class="line">[root@myprecious Python-3.6.4]# ln -s /usr/local/python3/bin/pip3 /usr/bin/pip</span><br></pre></td></tr></table></figure><h2 id="使常用工具继续使用python2-7版本">使常用工具继续使用python2.7版本</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">[root@myprecious Python-3.6.4]# sed -i &#x27;s@#!/usr/bin/python@#!/usr/bin/python2.7@&#x27; /usr/bin/yum</span><br><span class="line">[root@myprecious Python-3.6.4]# sed -i &#x27;s@#!/usr/bin/python@#!/usr/bin/python2.7@&#x27; /usr/libexec/urlgrabber-ext-down</span><br></pre></td></tr></table></figure><p><code>注：以后碰到其他由python写的工具不能正常工作时也可以先尝试此操作，比如supervisor。</code></p><h2 id="验证python及pip版本">验证python及pip版本</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">[root@myprecious install]# python -V</span><br><span class="line">Python 3.6.4</span><br><span class="line">[root@myprecious install]# pip -V</span><br><span class="line">pip 9.0.1 from /usr/local/python3/lib/python3.6/site-packages (python 3.6)</span><br></pre></td></tr></table></figure></div><script src="https://cdn.jsdelivr.net/lightgallery.js/1.0.1/js/lightgallery.min.js"></script><script>if (typeof lightGallery !== 'undefined') {        var options = {            selector: '.gallery-item'        };        lightGallery(document.getElementsByClassName('.article-gallery')[0], options);        }</script>]]></content>
    
    
    <summary type="html">在CentOS7上升级Python至Python3，备忘。</summary>
    
    
    
    <category term="Python3" scheme="https://opsuri.com/categories/Python3/"/>
    
    <category term="Python升级" scheme="https://opsuri.com/categories/Python3/Python%E5%8D%87%E7%BA%A7/"/>
    
    <category term="Linux" scheme="https://opsuri.com/categories/Python3/Python%E5%8D%87%E7%BA%A7/Linux/"/>
    
    <category term="备忘录" scheme="https://opsuri.com/categories/Python3/Python%E5%8D%87%E7%BA%A7/Linux/%E5%A4%87%E5%BF%98%E5%BD%95/"/>
    
    
    <category term="备忘录" scheme="https://opsuri.com/tags/%E5%A4%87%E5%BF%98%E5%BD%95/"/>
    
    <category term="Python" scheme="https://opsuri.com/tags/Python/"/>
    
  </entry>
  
  <entry>
    <title>在LINUX下如何查找CC攻击</title>
    <link href="https://opsuri.com/2018/01/12/How-to-find-CCattack-in-Linux/"/>
    <id>https://opsuri.com/2018/01/12/How-to-find-CCattack-in-Linux/</id>
    <published>2018-01-12T06:47:17.000Z</published>
    <updated>2025-02-23T02:28:03.861Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/lightgallery.js/1.0.1/css/lightgallery.min.css" /><div class=".article-gallery"><p>什么是CC攻击?CC攻击就是利用大量代理服务器对目标计算机发起大量连接，导致目标服务器资源枯竭造成拒绝服务。那么如何判断查询CC攻击呢?本文主要介绍了一些Linux下判断CC攻击的命令。</p><h3 id="查看所有80端口的连接数">查看所有80端口的连接数</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">netstat -nat|grep -i <span class="string">&quot;80&quot;</span>|<span class="built_in">wc</span> -l</span><br></pre></td></tr></table></figure><h3 id="对连接的IP按连接数量进行排序">对连接的IP按连接数量进行排序</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">netstat -anp | grep <span class="string">&#x27;tcp\|udp&#x27;</span> | awk <span class="string">&#x27;&#123;print $5&#125;&#x27;</span> | <span class="built_in">cut</span> -d: -f1 | <span class="built_in">sort</span> | <span class="built_in">uniq</span> -c | <span class="built_in">sort</span> -n</span><br></pre></td></tr></table></figure><span id="more"></span><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">netstat -ntu | awk <span class="string">&#x27;&#123;print $5&#125;&#x27;</span> | <span class="built_in">cut</span> -d: -f1 | <span class="built_in">sort</span> | <span class="built_in">uniq</span> -c | <span class="built_in">sort</span> -n</span><br><span class="line">netstat -ntu | awk <span class="string">&#x27;&#123;print $5&#125;&#x27;</span> | egrep -o <span class="string">&quot;0-9]&#123;1,3&#125;\.[0-9]&#123;1,3&#125;\.[0-9]&#123;1,3&#125;\.[0-9]&#123;1,3&#125;&quot;</span> | <span class="built_in">sort</span> | <span class="built_in">uniq</span> -c | <span class="built_in">sort</span> -nr</span><br></pre></td></tr></table></figure><h3 id="查看TCP连接状态">查看TCP连接状态</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">netstat -nat |awk <span class="string">&#x27;&#123;print $6&#125;&#x27;</span>|<span class="built_in">sort</span>|<span class="built_in">uniq</span> -c|<span class="built_in">sort</span> -rn</span><br><span class="line"></span><br><span class="line">netstat -n | awk <span class="string">&#x27;/^tcp/ &#123;print $NF&#125;&#x27;</span>|<span class="built_in">sort</span>|<span class="built_in">uniq</span> -c|<span class="built_in">sort</span> -rn</span><br><span class="line"></span><br><span class="line">netstat -n | awk <span class="string">&#x27;/^tcp/ &#123;++S[$NF]&#125;;END &#123;for(a in S) print a, S[a]&#125;&#x27;</span></span><br><span class="line"></span><br><span class="line">netstat -n | awk <span class="string">&#x27;/^tcp/ &#123;++state[$NF]&#125;; END &#123;for(key in state) print key,&quot;\t&quot;,state[key]&#125;&#x27;</span></span><br><span class="line"></span><br><span class="line">netstat -n | awk <span class="string">&#x27;/^tcp/ &#123;++arr[$NF]&#125;;END &#123;for(k in arr) print k,&quot;\t&quot;,arr[k]&#125;&#x27;</span></span><br><span class="line"></span><br><span class="line">netstat -ant | awk <span class="string">&#x27;&#123;print $NF&#125;&#x27;</span> | grep -v <span class="string">&#x27;[a-z]&#x27;</span> | <span class="built_in">sort</span> | <span class="built_in">uniq</span> -c</span><br></pre></td></tr></table></figure><h3 id="查看80端口连接数最多的20个IP">查看80端口连接数最多的20个IP</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cat</span> /var/log/nginx/opstrip.com_access.log|awk <span class="string">&#x27;&#123;print $1&#125;&#x27;</span>|<span class="built_in">sort</span>|<span class="built_in">uniq</span> -c|<span class="built_in">sort</span> -nr|<span class="built_in">head</span> -100</span><br><span class="line"></span><br><span class="line"><span class="built_in">tail</span> -n 10000 /var/log/nginx/opstrip.com_access.log|awk <span class="string">&#x27;&#123;print $1&#125;&#x27;</span>|<span class="built_in">sort</span>|<span class="built_in">uniq</span> -c|<span class="built_in">sort</span> -nr|<span class="built_in">head</span> -100</span><br><span class="line"></span><br><span class="line"><span class="built_in">cat</span> /var/log/nginx/opstrip.com_access.log|awk <span class="string">&#x27;&#123;print $1&#125;&#x27;</span>|<span class="built_in">sort</span>|<span class="built_in">uniq</span> -c|<span class="built_in">sort</span> -nr|<span class="built_in">head</span> -100</span><br><span class="line"></span><br><span class="line">netstat -anlp|grep 80|grep tcp|awk <span class="string">&#x27;&#123;print $5&#125;&#x27;</span>|awk -F: <span class="string">&#x27;&#123;print $1&#125;&#x27;</span>|<span class="built_in">sort</span>|<span class="built_in">uniq</span> -c|<span class="built_in">sort</span> -nr|<span class="built_in">head</span> -n20</span><br><span class="line"></span><br><span class="line">netstat -ant |awk <span class="string">&#x27;/:80/&#123;split($5,ip,&quot;:&quot;);++A[ip[1]]&#125;END&#123;for(i in A) print A,i&#125;&#x27;</span> |<span class="built_in">sort</span> -rn|<span class="built_in">head</span> -n20</span><br></pre></td></tr></table></figure><h3 id="用tcpdump嗅探80端口的访问看看谁最高">用<code>tcpdump</code>嗅探<code>80端口</code>的访问看看谁最高</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">tcpdump -i eth0 -tnn dst port 80 -c 1000 | awk -F<span class="string">&quot;.&quot;</span> <span class="string">&#x27;&#123;print $1″.&quot;$2″.&quot;$3″.&quot;$4&#125;&#x27;</span> | <span class="built_in">sort</span> | <span class="built_in">uniq</span> -c | <span class="built_in">sort</span> -nr |<span class="built_in">head</span> -20</span><br></pre></td></tr></table></figure><h3 id="查找较多time-wait连接">查找较多<code>time_wait</code>连接</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">netstat -n|grep TIME_WAIT|awk <span class="string">&#x27;&#123;print $5&#125;&#x27;</span>|<span class="built_in">sort</span>|<span class="built_in">uniq</span> -c|<span class="built_in">sort</span> -rn|<span class="built_in">head</span> -n20</span><br></pre></td></tr></table></figure><h3 id="查找较多的SYN连接">查找较多的SYN连接</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">netstat -an | grep SYN | awk <span class="string">&#x27;&#123;print $5&#125;&#x27;</span> | awk -F: <span class="string">&#x27;&#123;print $1&#125;&#x27;</span> | <span class="built_in">sort</span> | <span class="built_in">uniq</span> -c | <span class="built_in">sort</span> -nr | more</span><br></pre></td></tr></table></figure><p>linux下实用iptables封ip段的一些常见命令：</p><h3 id="封单个IP的命令">封单个IP的命令</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">iptables -I INPUT -s 180.169.3.4 -j DROP</span><br></pre></td></tr></table></figure><h3 id="封IP段的命令：">封IP段的命令：</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">iptables -I INPUT -s 180.167.0.0/16 -j DROP</span><br><span class="line">iptables -I INPUT -s 180.168.0.0/16 -j DROP</span><br><span class="line">iptables -I INPUT -s 180.169.0.0/16 -j DROP</span><br></pre></td></tr></table></figure><h3 id="封整个段的命令">封整个段的命令</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">iptables -I INPUT -s 180.0.0.0/8 -j DROP</span><br></pre></td></tr></table></figure><h3 id="封几个段的命令">封几个段的命令</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">iptables -I INPUT -s 180.169.3.0/24 -j DROP</span><br><span class="line">iptables -I INPUT -s 180.169.4.0/24 -j DROP</span><br></pre></td></tr></table></figure><h3 id="想在服务器启动自运行的话有三个方法">想在服务器启动自运行的话有三个方法</h3><ul><li>把它加到/etc/rc.local中</li><li><code>iptables-save &gt;/etc/sysconfig/iptables</code>可以把你当前的<code>iptables规则</code>放到<code>/etc/sysconfig/iptables</code>中，系统启动<code>iptables</code>时自动执行</li><li><code>service iptables save</code>也可以把你当前的<code>iptables规则</code>放<code>/etc/sysconfig/iptables</code>中，系统启动<code>iptables</code>时自动执行</li></ul><p>后两种更好此，一般iptables服务会在network服务之前启来，更安全。</p></div><script src="https://cdn.jsdelivr.net/lightgallery.js/1.0.1/js/lightgallery.min.js"></script><script>if (typeof lightGallery !== 'undefined') {        var options = {            selector: '.gallery-item'        };        lightGallery(document.getElementsByClassName('.article-gallery')[0], options);        }</script>]]></content>
    
    
    <summary type="html">什么是CC攻击?CC攻击就是利用大量代理服务器对目标计算机发起大量连接，导致目标服务器资源枯竭造成拒绝服务.</summary>
    
    
    
    <category term="安全运维" scheme="https://opsuri.com/categories/%E5%AE%89%E5%85%A8%E8%BF%90%E7%BB%B4/"/>
    
    
    <category term="Linux" scheme="https://opsuri.com/tags/Linux/"/>
    
    <category term="安全运维" scheme="https://opsuri.com/tags/%E5%AE%89%E5%85%A8%E8%BF%90%E7%BB%B4/"/>
    
    <category term="防火墙" scheme="https://opsuri.com/tags/%E9%98%B2%E7%81%AB%E5%A2%99/"/>
    
  </entry>
  
  <entry>
    <title>英特尔、谷歌和AWS回应CPU安全事件：AMD和ARM也有问题，影响巨大</title>
    <link href="https://opsuri.com/2018/01/08/Intel-Google-AWS-CPU-AMD-ARM/"/>
    <id>https://opsuri.com/2018/01/08/Intel-Google-AWS-CPU-AMD-ARM/</id>
    <published>2018-01-08T10:34:58.000Z</published>
    <updated>2025-02-22T14:17:36.088Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/lightgallery.js/1.0.1/css/lightgallery.min.css" /><div class=".article-gallery"><p>英特尔方面解释称，其已经向 <code>ARM</code> 、<code>AMD</code> 以及其它多家操作系统供应商报告了此项漏洞。该方同时强调，该漏洞最初是由谷歌公司的 <code>Zero</code> 项目安全小组所发现，这一说法也得到了谷歌方面的证实。</p><p>英特尔公司指出，其将发布微代码更新以解决此项问题，而随时间推移这些修复补丁中的一部分亦将被引入硬件当中。</p><p>据英特尔所说，本来他们是计划下周当软件和固件都比较完善的时候向用户披露这个信息的，但是由于媒体的报道不准确，引起舆论哗然才让其不得不提前发布声明。在回应时，Intel 表示，这些漏洞不存在被攻击、修改或删除数据的可能，还表示 <strong>媒体报道此“漏洞”或“缺陷”是英特尔的产品独有的问题这一说法是不准确的</strong>。基于目前为止的分析，许多类型的计算设备（不同供应商的处理器和操作系统）也很容易受到这些攻击。</p><p>微软公司拒绝就此事发表评论，不过预计微软也将推出自己的对应补丁。此外，AWS、谷歌公司也发布了自己的报告（<strong>见下文</strong>）。</p><p><strong>意味着什么</strong>: 就目前来讲，我们可以看到各大主要芯片与操作系统供应商已经意识到问题的存在，并努力发布修复程序。第一款补丁很可能被纳入微软的新一轮补丁周二发布。<strong>目前还不清楚这批补丁会影响到多少不同类型的软件与 CPU 架构，也不明确具体将给 PC 性能造成怎样的影响</strong>。</p><p>但是，补丁带来的影响会不会比安全问题本身更令人难以接受？根据初步报道，取决于具体任务与处理器型号的不同，<strong>PC 用户可能因此遭遇<code>“5% 到 30% 之间的性能衰减”</code></strong>。</p><p>英特尔方面似乎 <strong>坚信普通用户不会受到任何负面影响</strong>。其在一份声明中指出：“与一部分报道相反，任何潜在的性能影响都将取决于实际工作负载。而对普通计算机用户而言，其不会产生任何显著的影响，且性能衰减将随时间推移而得到缓解。”</p><span id="more"></span><p>英特尔公司进一步作出解释，即“具体取决于实际工作负载”，但客户仍然无法借此对影响作出准确的判断。</p><p>高管们表示，英特尔公司在研究这项漏洞的影响时，并没有将客户 PC 与数据中心服务器区分开来。事实上，普通用户所使用的应用程序可能遭受 0% 到 2% 的性能影响，但调整依赖应用程序与操作系统间交互的综合性工作负载则可能遭遇最高 30% 的性能衰减。</p><ul><li><strong>我们可以做点什么</strong>？</li></ul><p>英特尔公司给出的建议是补丁、补丁、还是补丁。相信大家已经对这样的陈词滥调非常熟悉：“请咨询您的操作系统供应商或系统制造商，并尽快应用所有可用更新。遵循良好的安全措施以防范恶意软件，这将有助于预防可能的恶意利用活动直到更新工作全面完成。”</p><ul><li><strong>机器学习会受到影响吗</strong>？</li></ul><p>据部分专家分析，这取决于集成模型，对模型每个部分的调用都可能产生影响。此外，生成一个新程序将产生新的开销，内存释放 / 分配算法将更复杂，而 CPU 处理器将成为深度学习 GPU 图像加载的瓶颈。</p><ul><li><strong>谷歌回应：Chrome 浏览器将受影响，请按操作更新</strong></li></ul><p>谷歌公司则报告称，其 Chrome 浏览器将受到影响，但用户可以采取两步走解决战略：首先，确保您的浏览器更新至版本 63; 其次，可以启用一项名为站点隔离的可选功能，从而将各站点隔离在独立的地址空间内。此可选项目可在 chrome://flags/#enable-site-per-process 当中开启。最后，计划于今年 1 月 23 日发布的 Chrome 64 将能够保护用户免受旁路攻击的侵扰。</p><p>受影响设备完整清单如下：</p><p>以下未明确列出的所有 Google 产品都不需要用户进行操作。</p><ul><li><strong>Android</strong></li></ul><blockquote><p>最新安全更新的设备受到保护。此外，目前我们还未发现此漏洞成功再复制，即未经 ARM Android 设备的授权泄露信息。<br>最新安全更新的 Nexus 和 Pixel 设备受到保护。</p></blockquote><ul><li><strong>Google Apps / G Suite（Gmail，日历，云端硬盘，网站等）</strong>：</li></ul><blockquote><p>无需额外的用户或客户操作。</p></blockquote><ul><li><strong>谷歌浏览器</strong>：</li></ul><blockquote><p>一些用户或客户需要采取措施。</p></blockquote><ul><li><strong>Google Chrome 操作系统（例如 Chromebook）</strong>：</li></ul><blockquote><p>需要一些额外的用户或客户操作。</p></blockquote><ul><li><strong>Google 云端平台</strong></li></ul><blockquote><p>Google App 引擎：无需额外操作。<br>Google 计算引擎：需要一些额外操作。<br>Google Kubernetes 引擎：需要一些额外操作。<br>Google Cloud Dataflow：需要一些额外操作。<br>Google Cloud Dataproc：需要一些额外操作。<br>所有其他 Google 云产品和服务：无需其他操作。<br>Google 主页 / Chromecast：无需额外操作。<br>Google Wifi / OnHub：无需额外的用户操作。</p></blockquote><p>具体操作请参考：</p><p><a href="https://security.googleblog.com/2018/01/todays-cpu-vulnerability-what-you-need.html">https://security.googleblog.com/2018/01/todays-cpu-vulnerability-what-you-need.html</a></p><ul><li><strong>亚马逊回应：此 bug 已存在 20 余年，发布新版 Linux 系统</strong></li></ul><p>昨日，亚马逊也作出回应，称这个 bug 其实是 Intel、AMD 等现代处理器存在了 20 多年的问题，目前亚马逊 MC2 fleet 只有一小部分产品是可以抵御攻击的，在未来的几小时之内将会被修复。</p><p>Amazon Linux 存储库中提供了更新的 Amazon Linux 内核。2018 年 1 月 3 日下午 10:45（GMT）之后使用默认的 Amazon Linux 配置启动将自动包含更新的软件包。Amazon Linux AMI 用户可以运行以下命令，确保收到更新的软件包：</p><p><a href="https://alas.aws.amazon.com/">https://alas.aws.amazon.com/</a></p><ul><li><strong>旁路分析利用是什么</strong>？</li></ul><p>根据英特尔方面的说法，攻击者可以通过观察高权限内存中的内容利用名为“推测性执行”的 CPU 技术规避必要的权限级别约束。如此一来，攻击者将能够访问其正常情况下无法访问的数据。不过英特尔公司表示其无法对数据内容进行删除或者修改。</p><p>事实上，英特尔与研究人员们发现了<strong>三种漏洞利用变种，分别为“边界检查旁路”、“分支目标注入”以及“流氓数据加载”，三者在具体攻击手段方面略有不同。但通过操作系统更新，三种问题都能够得到有效缓解</strong>。</p><p>英特尔公司工程技术负责人 Steve Smith 报告了这一重要发现，并补充称目前还没有观察到对该项漏洞的任何实际利用行为。他同时否认了此项漏洞属于缺陷的说法，亦不承认其出现是为了专门针对英特尔。在本次电话会议上，Smith 向投资者们强调“处理器的运作方式仍然严格遵循我们的设计预期。”</p><p>Smith 同时表示，这一发现敦促全球各硬件制造商以“负责任的方式”应对此项漏洞。</p><ul><li><strong>这是一个影响到全行业的问题</strong></li></ul><p>前文提到的各家企业已经计划在未来一周内陆续发布相关补丁。而英特尔方面则表示，其提前作出评论的原因在于“目前存在诸多不够准确的媒体报道”——但需要强调的是，芯片巨头的声明当中并没有对这些报道作出任何否定。英特尔只是首先向媒体发布了一份声明，而后即召开电话会议。</p><p>英特尔公司指出，“英特尔与其它技术企业已经意识到用于描述软件分析方法的新型安全研究成果一旦出于恶意目的而遭利用，可能导致从计算设备上收集敏感数据。”</p><p>英特尔公司认为，此项漏洞与其它类型架构同样存在密切关联——这里所指的肯定是 AMD（尽管其否认自家芯片会因此受到影响）以及作为大多数智能手机核心的 ARM。除此之外，另有几家厂商以及操作系统供应商的产品“易受影响”。</p><p>微软公司的一位发言人在接受邮件采访时解释称，“我们已经意识到这一影响整个行业的问题，并一直与芯片制造商开展密切合作，旨在开发并测试缓解措施以保护我们的客户。我们正在为云服务部署缓解措施，同时亦发布了对应安全更新，希望保护 Windows 客户免受英特尔、ARM 以及 AMD 支持型硬件芯片内相关漏洞的影响。”</p><p>AMD 方面否认其处理器产品受到影响，并在采访中强调称目前 AMD 处理器所面临的风险“几乎为零”。</p><p>英特尔则试图解释其为何没有主动站出来曝光问题——芯片巨头宣称，就在此次消息传出之时，其几乎已经完成了漏洞的内部解决。英特尔公司指出，“我们致力于通过负责任的方式披露安全问题，也正因为如此，英特尔与其它供应商才计划在下周公布相关软件与固件更新时正式披露这一问题。”</p><ul><li><strong>英特尔回应存疑，网友不买账</strong></li></ul><p>虽然官方做出了回应，但是网友们似乎并不买账，大多数网友对这一回应都持怀疑的态度，认为英特尔不够诚实，这样的做法是自欺欺人。知名社交网站 Reddit 上有关英特尔的讨论同样在如火如荼进行着，除了疯狂 diss 英特尔之外，也有网友给出了自己的分析。</p><p>我们摘录了部分网友的讨论内容：</p><p><strong>网友观点一</strong>：</p><blockquote><p>对于有独立数据中心的企业来说可能没太大影响，因为他们不会受到这个漏洞带来的安全问题影响，因此肯定会在没有内核补丁的情况下继续运行他们的数据中心。但对于学术研究人员来说，这可能（会？）确实是一个更大的问题，因为他们通常不管理自己的内核，而是云上运行计算任务。不过 CPU 一般很少成为性能瓶颈，现在大多数 BLAS 密集型计算是在 GPU 上完成的，数据集通常被完全加载到 RAM 中，而在现代库中不会经常产生新的线程。</p></blockquote><p><strong>网友观点二</strong>：</p><blockquote><p>这几乎肯定会导致产品召回，并最终从 Linux 内核中删除该内核补丁。</p></blockquote><p><strong>网友观点三</strong>：</p><blockquote><p>几乎所有在过去20年中生产的英特尔处理器都受到了影响，许多目前还有人在使用的处理器很可能早已停产，并且没办法快速生产出可以兼容的主板。英特尔可能会召回最近的一款处理器，但是全面召回受影响的处理器将需要数年时间，甚至可能导致公司破产。所以用户只能继续忍受这个内核补丁，直到购买一个新的处理器，由于这个问题补丁导致的性能下降，可能得比计划更早去购买新处理器。也许英特尔会给因为这个原因购买新芯片的客户适当的折扣，以恢复客户对他们的信任。</p></blockquote><p><strong>网友观点四</strong>：</p><blockquote><p>或许是时候该买点 AMD 的股票了。</p></blockquote><p><strong>网友观点五</strong>：</p><blockquote><p>或者卖掉 Intel 的股票。<br><a href="https://www.fool.com/investing/2017/12/19/intels-ceo-just-sold-a-lot-of-stock.aspx">https://www.fool.com/investing/2017/12/19/intels-ceo-just-sold-a-lot-of-stock.aspx</a>（英特尔的 CEO 在 12 月中下旬卖掉了大量英特尔的股票）</p></blockquote><p><strong>网友观点六</strong>：</p><blockquote><p>他不仅卖掉了一堆股票，而且还卖掉了所有可以卖出的股票（附例说 CEO 必须拥有 25 万股股票——于是他把 25 万股以外的股票全卖掉了…）</p></blockquote><p><strong>网友观点七</strong>：</p><blockquote><p>这可能就是为什么微软发布了一个通知，说 Azure 中的一些虚拟机必须先重启，否则将会在 1 月 10 日自动重启。 当然，这可能只是标准的维护，因为它不像他们发布大量的信息。补充：这下有趣了，微软刚刚发出了警告，强制要求所有还没重新部署的人立即重新部署。看来是因为 Project Zero 刚刚发布的消息：<br><a href="https://googleprojectzero.blogspot.com/2018/01/reading-privileged-memory-with-side.html">https://googleprojectzero.blogspot.com/2018/01/reading-privileged-memory-with-side.html</a></p></blockquote><p><strong>网友观点八</strong>：</p><blockquote><p>我不是这方面的专家，但是这听起来像是跳过了数据结构的边界检查——检查肯定会花费更多时间和资源，如果你确信检查是不必要的，那么直接省略这个步骤可以节省时钟周期。<br>这听起来像是和推测执行有关。如果你正在推测性地执行一条指令，那么你最终可能会舍弃它的结果，所以执行这个指令花费的代价越少越好。也许英特尔认为他们可以在推测执行的时候跳过priv检查，如果最终发现确实需要这条指令，就在实际执行结果之前执行指令。 然而，也许事实证明，这种推测性执行打开了一些通过后门获取数据的方法，比如通过缓存、定时等等，如果异常提前被发现，这个问题就不会暴露了。</p></blockquote><p><strong>网友观点九</strong>：</p><blockquote><p>这个修复补丁对于性能到底有多大影响会根据具体的计算任务而有所不同，但不可能全部是 34％。这个补丁确实会损害内核的上下文切换性能。如果你的应用程序一直在做大量的系统调用，这对你的性能影响可能会非常大。然而，直到我们真的看到实际的案例，才能真正了解影响到底有多大。</p></blockquote><p><strong>网友观点十</strong>：</p><blockquote><p>这里有两篇文章，他们在集成并启用了该修复补丁的 Windows 10 Insider 上进行了测试，测试结果显示，普通用户其实无需担心。在合成、实际工作负载以及游戏中的 CPU 性能基本未受影响，基准测试中的差异都还在误差范围内。可能唯一有影响的是使用了 NVMe 驱动的用户，比如 960 Pro 这种速度非常快的驱动器，性能损失约 5％，对大多数人来说可以忽略不计。而像基于 NVME 和 SATA 的 SSD，性能损失几乎为 0%，因为这些驱动器的速度没有快到会被影响到。<br>7700K + 1080 Ti：<br><a href="https://www.computerbase.de/2018-01/intel-cpu-pti-sicherheitsluecke/#update2">https://www.computerbase.de/2018-01/intel-cpu-pti-sicherheitsluecke/#update2</a><br>3930K + 1080 Ti：<br><a href="https://www.hardwareluxx.de/index.php/news/hardware/prozessoren/45319-intel-kaempft-mit-schwerer-sicherheitsluecke-im-prozessor-design.html">https://www.hardwareluxx.de/index.php/news/hardware/prozessoren/45319-intel-kaempft-mit-schwerer-sicherheitsluecke-im-prozessor-design.html</a></p></blockquote><p><strong>网友观点十一</strong>：</p><blockquote><p>欸等等，AMD 也被报告“不安全”？ 哦，哦，哦，是<strong>修复补丁把 AMD 视为不安全，而不是 AMD 实际上不安全。补充</strong>：Bug 不会影响 AMD。 但显然，他们正在向所有架构都推送补丁，而不只是英特尔，这又反过来影响了 AMD 的性能。也许在经过全面测试之后，AMD 会回滚到打补丁之前的版本。补充吐槽：<strong>简直是天才，当你出了问题，就强制让别人也出问题</strong>。</p></blockquote><p><strong>网友观点十二</strong>：</p><blockquote><p>免责声明：我是一名英特尔的工程师，但是我的发言仅代表我个人意见，而且我没有直接参与这项调查。<br>我已经阅读了谷歌的 Meltdown 论文，可以分享一些想法。我也可以回答大家的问题，但显然我不会分享任何英特尔内部消息。<br>攻击主要利用了推测性执行（speculative execution），并依赖于缓存方攻击。其实并不是一个真正意义上的“bug”，因为推测性执行就是按照设计工作的，也就是说它不会影响寄存器或内存（除非已提交），但可能会影响缓存。因此，这种攻击会导致 CPU 首先进入某种故障或陷阱，然后按照程序的顺序执行一些访问特权内存的指令。这些指令永远不会退出，因为陷阱会导致他们中断，但可能会推测性地执行，这就可能影响缓存。然后这个攻击会使用一个旁道攻击（side channel attack）来获取缓存的内容，于是就可能在里面发现特权数据。<br>基本上任何支持推测性执行的硬件都可能被攻击。在操作系统层面可以解决大部分问题，当然从硬件层面上也有很多修复的方法。但是目前这个缺陷的严重程度，与乱序引擎的深度和其他结构的大小基本上是直接相关的。非常糟糕的是，这基本上意味着一个更快的内核就会更脆弱，更容易受到影响。谷歌的这篇文章称，他们发现<strong>所有的英特尔、AMD 和 ARM 都存在问题，但他们无法对 AMD 或者 ARM 进行攻击，这可能是因为 AMD 和 ARM 没有那么复杂或者乱序引擎的深度更小（虽然这看起来似乎 ARM 存在另一个相关的问题）</strong>。所以英特尔暴露的问题最为严重，因为英特尔的乱序引擎有更高的性能。<br>Spectre 攻击要少见得多，但对所有 CPU 供应商的影响是一样的。风险较小是因为攻击必须针对一个特定的过程，但是相应的修复起来也很困难。</p></blockquote><ul><li><strong>参考文章</strong></li></ul><blockquote><p><a href="https://www.pcworld.com/article/3245508/components-processors/intel-responds-to-the-cpu-kernel-bug.html">https://www.pcworld.com/article/3245508/components-processors/intel-responds-to-the-cpu-kernel-bug.html</a><br><a href="https://www.reddit.com/r/sysadmin/comments/7nl8r0/intel_bug_incoming/">https://www.reddit.com/r/sysadmin/comments/7nl8r0/intel_bug_incoming/</a><br><a href="https://www.reddit.com/r/MachineLearning/comments/7ny7kx/n_considering_the_bug_find_in_intel_processors/">https://www.reddit.com/r/MachineLearning/comments/7ny7kx/n_considering_the_bug_find_in_intel_processors/</a><br><a href="https://security.googleblog.com/2018/01/todays-cpu-vulnerability-what-you-need.html">https://security.googleblog.com/2018/01/todays-cpu-vulnerability-what-you-need.html</a><br><a href="https://amazonaws-china.com/cn/security/security-bulletins/AWS-2018-013/?from=timeline">https://amazonaws-china.com/cn/security/security-bulletins/AWS-2018-013/?from=timeline</a><br><a href="https://newsroom.intel.com/news/intel-responds-to-security-research-findings/">https://newsroom.intel.com/news/intel-responds-to-security-research-findings/</a></p></blockquote><hr><p>本文转载于：<a href="http://www.infoq.com/cn/news/2018/01/Intel-Google-AWS-CPU-AMD-ARM">http://www.infoq.com/cn/news/2018/01/Intel-Google-AWS-CPU-AMD-ARM</a></p></div><script src="https://cdn.jsdelivr.net/lightgallery.js/1.0.1/js/lightgallery.min.js"></script><script>if (typeof lightGallery !== 'undefined') {        var options = {            selector: '.gallery-item'        };        lightGallery(document.getElementsByClassName('.article-gallery')[0], options);        }</script>]]></content>
    
    
    <summary type="html">英特尔方面解释称，其已经向ARM、AMD以及其它多家操作系统供应商报告了此项漏洞。该方同时强调，该漏洞最初是由谷歌公司的Zero项目安全小组所发现，这一说法也得到了谷歌方面的证实。</summary>
    
    
    
    <category term="资讯" scheme="https://opsuri.com/categories/%E8%B5%84%E8%AE%AF/"/>
    
    
    <category term="资讯" scheme="https://opsuri.com/tags/%E8%B5%84%E8%AE%AF/"/>
    
    <category term="硬件" scheme="https://opsuri.com/tags/%E7%A1%AC%E4%BB%B6/"/>
    
  </entry>
  
  <entry>
    <title>CentOS 7 rsync+inotify实现实时同步</title>
    <link href="https://opsuri.com/2017/12/23/CentOS7-rsync-inotify-for-real-time-sysnchronization/"/>
    <id>https://opsuri.com/2017/12/23/CentOS7-rsync-inotify-for-real-time-sysnchronization/</id>
    <published>2017-12-23T08:15:14.000Z</published>
    <updated>2025-02-22T12:57:28.662Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/lightgallery.js/1.0.1/css/lightgallery.min.css" /><div class=".article-gallery"><h2 id="环境准备">环境准备</h2><h3 id="测试环境如下：">测试环境如下：</h3><blockquote><p>inotify-slave IP : 172.31.15.10<br>inotify-master IP : 172.31.15.11</p></blockquote><h3 id="对两台机的要求：">对两台机的要求：</h3><ul><li>安装依赖包gcc: yum install gcc –y</li><li>关闭selinux</li><li>开放端口873</li></ul><h2 id="inotify-slave部署">inotify slave部署</h2><span id="more"></span><h3 id="安装rsync：">安装rsync：</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">[root@opstrip opt]# yum install rsync –y</span><br></pre></td></tr></table></figure><h3 id="添加用户和模块目录，并更改用户和组">添加用户和模块目录，并更改用户和组</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">[root@opstrip opt]# useradd rsync –s /sbin/nologin –M</span><br><span class="line">[root@opstrip opt]# mkdir /data/back</span><br><span class="line">[root@opstrip opt]# chown rsync.rsync /data/back/</span><br></pre></td></tr></table></figure><h3 id="修改配置文件-etc-rsyncd-conf，内容如下：">修改配置文件<code>/etc/rsyncd.conf</code>，内容如下：</h3><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">uid</span> <span class="string">=</span> <span class="string">rsync</span></span><br><span class="line"><span class="string">gid</span> <span class="string">=</span> <span class="string">rsync</span></span><br><span class="line"><span class="string">use</span> <span class="string">chroot</span> <span class="string">=</span> <span class="literal">no</span></span><br><span class="line"><span class="string">max</span> <span class="string">connections</span> <span class="string">=</span> <span class="number">200</span></span><br><span class="line"><span class="string">timeout</span> <span class="string">=</span> <span class="number">300</span></span><br><span class="line"><span class="string">pid</span> <span class="string">file</span> <span class="string">=</span> <span class="string">/var/run/rsyncd.pid</span></span><br><span class="line"><span class="string">lock</span> <span class="string">file</span> <span class="string">=</span> <span class="string">/var/run/rsync.lock</span></span><br><span class="line"><span class="string">log</span> <span class="string">file</span> <span class="string">=</span> <span class="string">/var/log/rsyncd.log</span></span><br><span class="line">    </span><br><span class="line">[<span class="string">backup</span>]</span><br><span class="line">    <span class="string">path</span> <span class="string">=</span> <span class="string">/data/back/</span></span><br><span class="line">    <span class="string">ignore</span> <span class="string">errors</span></span><br><span class="line">    <span class="string">read</span> <span class="string">only</span> <span class="string">=</span> <span class="literal">no</span></span><br><span class="line">    <span class="string">write</span> <span class="string">only</span> <span class="string">=</span> <span class="literal">no</span></span><br><span class="line">    <span class="string">list</span> <span class="string">=</span> <span class="literal">false</span></span><br><span class="line">    <span class="string">hosts</span> <span class="string">allow</span> <span class="string">=</span> <span class="number">172.31</span><span class="number">.15</span><span class="number">.0</span><span class="string">/24</span></span><br><span class="line">    <span class="string">hosts</span> <span class="string">deny</span> <span class="string">=</span> <span class="number">0.0</span><span class="number">.0</span><span class="number">.0</span><span class="string">/0</span></span><br><span class="line">    <span class="string">auth</span> <span class="string">users</span> <span class="string">=</span> <span class="string">rsync_backup</span></span><br><span class="line">    <span class="string">secrets</span> <span class="string">file</span> <span class="string">=</span> <span class="string">/etc/rsync.password</span></span><br></pre></td></tr></table></figure><p>**注：ubuntu系统的文件路径一般为<code>/usr/share/doc/rsync/examples/rsyncd.conf</code>，可以创建软链接，结果都一样。**创建方法如下：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">[root@opstrip opt]# ln -s /usr/share/doc/rsync/examples/rsyncd.conf /etc/rsyncd.conf</span><br></pre></td></tr></table></figure><h3 id="配置虚拟用户的密码文件">配置虚拟用户的密码文件</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">[root@opstrip opt]# echo &#x27;rsync_backup:jeff&#x27; &gt;&gt;/etc/rsync.password</span><br><span class="line">[root@opstrip opt]# chmod 600 /etc/rsync.password</span><br><span class="line">[root@opstrip opt]# rsync --daemon</span><br><span class="line">[root@opstrip opt]# ss -tulpn |grep rsync </span><br></pre></td></tr></table></figure><h3 id="加入开机启动">加入开机启动</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">[root@opstrip opt]# echo &#x27;/usr/bin/rsync --daemon&#x27; &gt;&gt;/etc/rc.local</span><br></pre></td></tr></table></figure><h2 id="部署服务器（inotify-master）">部署服务器（inotify-master）</h2><h3 id="查看系统是否支持inotity">查看系统是否支持inotity</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">[root@opstrip opt]# ll /proc/sys/fs/inotify</span><br><span class="line">total 0</span><br><span class="line">-rw-r--r-- 1 root root 0 Jan 24 17:15 max_queued_events</span><br><span class="line">-rw-r--r-- 1 root root 0 Jan 24 17:15 max_user_instances</span><br><span class="line">-rw-r--r-- 1 root root 0 Jan 24 17:15 max_user_watches</span><br></pre></td></tr></table></figure><p><strong>Tips：如果显示<code>max_queued_events</code>、<code>max_user_instances</code>、<code>max_user_watches</code>就证明支持<code>inotify</code></strong>。</p><h3 id="安装inotify-3-14">安装inotify 3.14</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">[root@opstrip opt]# wget http://github.com/downloads/rvoicilas/inotify-tools/inotify-tools-3.14.tar.gz</span><br><span class="line">[root@opstrip opt]# tar zxf inotify-tools-3.14.tar.gz</span><br><span class="line">[root@opstrip inotify-tools-3.14]# cd inotify-tools-3.14</span><br><span class="line">[root@opstrip inotify-tools-3.14]# ./configure --prefix=/usr/local/inotify</span><br><span class="line">[root@opstrip inotify-tools-3.14]# make &amp;&amp; sudo make install</span><br></pre></td></tr></table></figure><h3 id="创建备份目录">创建备份目录</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">[root@opstrip opt]# mkdir /opt/back/</span><br></pre></td></tr></table></figure><h3 id="创建rsync服务的密码文件">创建rsync服务的密码文件</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">[root@opstrip opt]# echo &quot;jeff&quot; &gt;/etc/rsync.password      //此处只写密码即可</span><br><span class="line">[root@opstrip opt]# chmod 600 /etc/rsync.password </span><br></pre></td></tr></table></figure><h3 id="编写执行脚本">编写执行脚本</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">[root@opstrip opt]# vim /usr/local/inotify.sh</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#!/bin/bash</span></span><br><span class="line">host01=172.31.15.10                    //inotify-slaver的IP地址</span><br><span class="line">src=/opt/back                          //本地监控的目录</span><br><span class="line">dst=backup                             //inotify-slave的服务模块名</span><br><span class="line">user=rsync_backup                      //inotify-slave的rsync虚拟用户</span><br><span class="line">rsync_passfile=/etc/rsync.password     //本地调用的rsync密码文件</span><br><span class="line">inotify_home=/usr/local/inotify        //inotify安装目录</span><br><span class="line">    </span><br><span class="line"><span class="comment">#judge</span></span><br><span class="line"><span class="keyword">if</span> [ ! -e <span class="string">&quot;<span class="variable">$src</span>&quot;</span> ] || [ ! -e <span class="string">&quot;<span class="variable">$&#123;rsync_passfile&#125;</span>&quot;</span> ] || [ ! -e <span class="string">&quot;<span class="variable">$&#123;inotify_home&#125;</span>/bin/inotifywait&quot;</span> ] || [ ! -e <span class="string">&quot;/usr/bin/rsync&quot;</span> ]; <span class="keyword">then</span></span><br><span class="line">    <span class="built_in">echo</span> <span class="string">&quot;Check File and Folder&quot;</span></span><br><span class="line">    <span class="built_in">exit</span> 9</span><br><span class="line"><span class="keyword">fi</span></span><br><span class="line">    </span><br><span class="line"><span class="variable">$&#123;inotify_home&#125;</span>/bin/inotifywait -mrq --timefmt <span class="string">&#x27;%d/%m/%y %H:%M&#x27;</span> --format <span class="string">&#x27;%T %w%f&#x27;</span> -e close_write,delete,create,attrib <span class="variable">$src</span> | <span class="keyword">while</span> <span class="built_in">read</span> file</span><br><span class="line"><span class="keyword">do</span></span><br><span class="line">    <span class="comment">#  rsync -avzP --delete --timeout=100 --password-file=$&#123;rsync_passfile&#125; $src $user@$host01::$dst &gt;/dev/null 2&gt;&amp;1</span></span><br><span class="line">    <span class="built_in">cd</span> <span class="variable">$src</span> &amp;&amp; rsync -aruz -R --delete ./  --<span class="built_in">timeout</span>=100 <span class="variable">$user</span>@<span class="variable">$host01</span>::<span class="variable">$dst</span> --password-file=<span class="variable">$&#123;rsync_passfile&#125;</span> &gt;/dev/null 2&gt;&amp;1</span><br><span class="line"><span class="keyword">done</span></span><br><span class="line"><span class="built_in">exit</span> 0</span><br></pre></td></tr></table></figure><h3 id="将脚本加入后台执行">将脚本加入后台执行</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">[root@opstrip opt]# sh inotify.sh &amp;</span><br></pre></td></tr></table></figure><h3 id="加入开机启动-2">加入开机启动</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">[root@opstrip opt]# echo &#x27;/bin/bash /opt/inotify.sh &amp;&#x27; &gt;&gt;/etc/rc.local</span><br></pre></td></tr></table></figure><h2 id="测试实时同步">测试实时同步</h2><p>部署前建议先运行这一步验证，然后再执行第二步</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">[root@opstrip opt]# rsync -avz /opt/back/test.txt rsync_backup@172.31.15.10::backup --password-file=/etc/rsync.password</span><br></pre></td></tr></table></figure><h2 id="改变SSH的默认端口为3333时，rsync的连接方法如下">改变SSH的默认端口为3333时，rsync的连接方法如下</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 此处用`-e &#x27;ssh -p 3333&#x27;`来指定SSH连接端口</span></span><br><span class="line">[root@opstrip opt]# /usr/bin/rsync -av /backup/* -e <span class="string">&#x27;ssh -p 3333&#x27;</span> root@172.31.15.10:/backup/</span><br></pre></td></tr></table></figure></div><script src="https://cdn.jsdelivr.net/lightgallery.js/1.0.1/js/lightgallery.min.js"></script><script>if (typeof lightGallery !== 'undefined') {        var options = {            selector: '.gallery-item'        };        lightGallery(document.getElementsByClassName('.article-gallery')[0], options);        }</script>]]></content>
    
    
    <summary type="html">备忘录，centos7下rsync+inotify以实现实时同步问题。</summary>
    
    
    
    <category term="操作系统" scheme="https://opsuri.com/categories/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/"/>
    
    
    <category term="Linux" scheme="https://opsuri.com/tags/Linux/"/>
    
    <category term="Rsync" scheme="https://opsuri.com/tags/Rsync/"/>
    
  </entry>
  
</feed>
