To be free as in freedom
2015-01-26T16:46:14+08:00
/Manual-Installation-of-Staypuft
手动安装 Staypuft
2015-01-22T00:33:53+08:00
2015-01-22T00:33:53+08:00
<p>一晃,上一篇博客已经是四个月之前的事了,时间的魔力正是这样,一切的一切,当反转头再一次往后看的时候,都变得似乎没有丁点重量,不留一丝痕迹……</p>
<p>言归正传,通过前面两篇博客“<a href="/2014-09-26-OpenStack-Foreman-installer.html">OpenStack Foreman Installer 安装及基本使用</a>”和“<a href="/2014-09-29-OpenStack-Foreman-installer-staypuft.html">OpenStack Foreman Installer —— staypuft</a>”只能搭建一个基本可用的基于 Foreman 的 OpenStack 布署工具,但是对 Foreman 和 Staypuft 其实并没有多少了解,更不用说上手做些调整和修改了,所以便有这第三篇,“手动安装 Staypuft”,只是过程记录(包括遇到问题的处理和说明):</p>
<h4>1、准备 Foreman 服务器环境</h4>
<p>一个 CentOS 7.0.1406 的系统,配置好 YUM REPO,最少需要有 CentOS 、EPEL 、RDO 、Foreman(包括 release 和 plugins 目录)。</p>
<p>其它的:</p>
<ul>
<li>防火墙,firewalld 这个服务还是关掉(当然也许只是因为我还没研究过,所以还不会用……)</li>
<li>SELinux,如果怕麻烦,也可设置 permissive。我自己测试时和上一篇博客类似,都是顺手生成了规则。</li>
</ul>
<h4>2、安装软件包</h4>
<ul>
<li><p>安装 SCL Repo 软件包</p>
<div class="highlight"><pre><code class="language-text" data-lang="text"># yum install rhscl-ruby193-epel-7-x86_64 rhscl-v8314-epel-7-x86_64
</code></pre></div></li>
<li><p>安装 foreman 、foreman-installer 、 foreman-proxy 、 foreman-discovery</p>
<div class="highlight"><pre><code class="language-text" data-lang="text"># yum install foreman foreman-installer foreman-proxy \
ruby193-rubygem-foreman_discovery
</code></pre></div></li>
</ul>
<h4>3、配置 foreman</h4>
<p>执行 <code>foreman-installer</code>:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text"># foreman-installer -i
</code></pre></div>
<p>需要改动的配置有:</p>
<ul>
<li> 在 <strong>Configure foreman</strong> 中将 <strong>configure_epel_repo</strong> 和 <strong>configure_scl_repo</strong> 设置为 <code>false</code> ;</li>
<li>启用 <strong>Configure foreman_plugin_discovery</strong>,不过其中关于 discovery 镜像的下载地址、 initrd 和 vmlinuz 的文件名都不对,所以暂时不用设置 <strong>install_images</strong> (默认是 <code>false</code> ),后面手动下载新版本的 discovery 镜像;</li>
<li><strong>Configure foreman_plugin_tasks</strong> 对应 <strong>foreman-tasks</strong> 软件包,是 Staypuft 的依赖之一,不过由于目前 CentOS 、 EPEL 和 Foreman 上游 YUM 源中都没有 rpm 包,所以只能留待后面手动安装。</li>
</ul>
<p><code>foreman-installer</code> 配置成之后,会提示 foreman Web 界面的访问地址,以及 <code>admin</code> 用户的密码(自动生动的随机字符串,建议第一次登陆之后修改密码)。</p>
<h4>4、手动安装 Puppet 模块</h4>
<p>Staypuft 需要的 Puppet 模块来源包括 foreman-installer 、 astapor 、 foreman-installer-staypuft:</p>
<ul>
<li><p>openstack-puppet-modules 中的模块:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text"># yum install openstack-puppet-modules
# for dir in /usr/share/openstack-puppet/modules/*
> do ln -sf "$dir" /etc/puppet/environments/production/modules/
> done
</code></pre></div></li>
<li><p>quickstack 模块(来自 astapor 项目):</p>
<div class="highlight"><pre><code class="language-text" data-lang="text"># git clone https://github.com/redhat-openstack/astapor.git
# cd astapor
# cp -r puppet/modules/quickstack /usr/share/foreman-installer/modules/
# ln -sf /usr/share/foreman-installer/modules/quickstack \
/etc/puppet/environments/production/modules/
</code></pre></div></li>
<li><p>foreman-installer 和 foreman-installer-staypuft 中的部份模块:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text"># git clone https://github.com/theforeman/foreman-installer-staypuft.git
# cd foreman-installer-staypuft
# rsync -az modules/foreman/ /usr/share/foreman-installer/modules/foreman/
# ln -sf /usr/share/foreman-installer/modules/foreman \
/etc/puppet/environments/production/modules/
</code></pre></div></li>
</ul>
<p>将这些 puppet 模块导入到 foreman 中,有两种方法:</p>
<ul>
<li><p>命令行:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text"># foreman-rake puppet:import:puppet_classes[batch]
</code></pre></div></li>
<li><p>通过 Foreman Web 界面:</p>
<p>点击 “Configure”(菜单) --> “Puppetclass”(菜单) --> “Import from ...”(按钮)。</p></li>
</ul>
<h4>5、配置 foreman-discovery</h4>
<p>foreman-discovery 是 foreman 用于实现主机发现的插件,可以使 foreman OS provision 的过程自动化程序更高。</p>
<ul>
<li><p>首先,在 foreman 中创建一个新的 <code>environment</code>,名字是 <code>discovery</code> (这是 Staypuft 的要求,目前应该是固定的);</p></li>
<li><p>下载 discovery 引导镜像,并建立 PXE 引导会用到的 tftp 目录:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text"># wget http://downloads.theforeman.org/discovery/releases/latest/fdi-image-latest.tar \
-O - | tar x --overwrite -C /var/lib/tftpboot/boot
# cd /var/lib/tftpboot/boot/fdi-image
# sha256sum -c SHA256SUM
</code></pre></div></li>
<li><p>在 foreman 中创建新的 <code>installation media</code> ,最简单的方法是将 CentOS 安装光盘挂载到一个目录,将这个目录通过 HTTP 分享,然后基于这个 HTTP url 创建 <code>installation media</code>。不过这种方法有一个明显的不足: CentOS 安装光盘中没有 puppet 软件包,导致 foreman 在 OS provision 过程中基本系统装完之后,需要手动进行 Kickstart 脚本中的一些步骤,包括通知 foreman 系统安统完成。当然解决方法也很多,比如复制一份 CentOS 安装光盘的目录结构,加上 puppet 包,然后更新目录的 YUM repo metadata;或者在 kickstart 或者配置 staypuft deployment 是指定外部软件源;…… (参见后文 <strong>“遇到的其它问题”</strong>)</p></li>
<li><p>配置 <code>Provisioning Template</code>。在 foreman Web 界面的 <code>Provisioning Template</code> 页面中找到 <strong>PXELinux global default</strong> ,增加以下内容:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">LABEL discovery
MENU LABEL Foreman Discovery
MENU DEFAULT
KERNEL boot/fdi-image/vmlinuz0
APPEND initrd=boot/fdi-image/initrd0.img rootflags=loop root=live:/fdi.iso rootfstype=auto ro rd.live.image acpi=force rd.luks=0 rd.md=0 rd.dm=0 rd.lvm=0 rd.bootif=0 rd.neednet=0 nomodeset foreman.url=http://xyz
IPAPPEND 2
</code></pre></div>
<p>其中,<code>foreman.url=http://xyz</code> 使用 foreman 服务器的真实地址。</p>
<p>上述配置无误之后,再加上下面这一行,以保证新服务器默认从 foreman 引导项启动:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">ONTIMEOUT discovery
</code></pre></div>
<p>最后,在 <code>Provisioning Template</code> 页面中点击 ”<strong>Build PXE Default</strong>” 生成默认的 PXE 引导选项。</p></li>
</ul>
<h4>6、配置 <code>Provision</code></h4>
<p>由于 foreman 的 bug ,新主机向 foreman 发送 facts 时会出错,下面是该 bug 的具体信息:</p>
<p><a href="http://projects.theforeman.org/issues/8377">http://projects.theforeman.org/issues/8377</a></p>
<p>为 foreman 打上补丁之后,记得重启 httpd 服务。</p>
<p><em>这里可以把 /etc/puppet/autosign.conf 也修改一下,参见后文 <strong>“遇到的其它问题”</strong>;</em></p>
<p>点击 “Infrastructure” --> “Provisioning Setup” ,然后根据向导创建新的 Provision 。</p>
<p>一个比较容易出现的问题是,dhcpd 服务启动不成功,原因是我的 foreman OS provision 网络会对应 OpenStack 的管理网络,不会设置网关,所以 dhcpd.conf 里面的 “option routers” 配置项没有具体的值,删除这一行,重启 dhcpd 就行。</p>
<p>最后,启动 OS Provision 所在网络上的一台服务器,确认从网络启动时,是否进入 foreman 引导项。</p>
<h4>7、安装 Staypuft</h4>
<div class="highlight"><pre><code class="language-text" data-lang="text"># yum install gcc gcc-c++ glibc-headers libxml2-devel zlib-devel \
ruby193-ruby-devel ruby193-rubygems-devel \
ruby193-rubygem-jquery-rails ruby193-rubygem-jquery-ui-rails \
ruby193-rubygem-bootstrap-sass ruby193-rubygem-sass-rails \
ruby193-rubygem-uglifier ruby193-rubygem-therubyracer \
ruby193-rubygem-apipie-params ruby193-rubygem-algebrick \
ruby193-rubygem-sequel ruby193-rubygem-sinatra \
ruby193-rubygem-daemons ruby193-rubygem-wicked \
ruby193-rubygem-ipaddress
# scl enable ruby193 v8314 "gem install --ignore-dependencies foreman-tasks staypuft dynflow"
</code></pre></div>
<p>在 /usr/share/foreman/bundler.d/ 下新建一个文件,如 <code>staypuft.rb</code> ,内容如下:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">gem 'staypuft'
gem 'sass-rails'
gem 'bootstrap-sass'
gem 'jquery-rails'
gem 'jquery-ui-rails'
gem 'uglifier'
</code></pre></div>
<p>最后执行:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text"># foreman-rake db:migrate
# foreman-rake db:seed
</code></pre></div>
<p><em>检查 Staypuft 数据是否初始化成功,可以参考后文 <strong>“遇到的其它问题”</strong>;</em></p>
<p>重启 Foreman :</p>
<div class="highlight"><pre><code class="language-text" data-lang="text"># systemctl restart httpd
</code></pre></div>
<h4>8、配置 foreman-tasks</h4>
<div class="highlight"><pre><code class="language-text" data-lang="text"># cp /opt/rh/ruby193/root/usr/local/share/gems/gems/foreman-tasks-x.x.x/deploy/foreman-tasks.sysconfig /etc/sysconfig/foreman-tasks
# cp /opt/rh/ruby193/root/usr/local/share/gems/gems/foreman-tasks-x.x.x/deploy/foreman-tasks.service /usr/lib/systemd/system/
# cp /opt/rh/ruby193/root/usr/local/share/gems/gems/foreman-tasks-x.x.x/bin/foreman-tasks /usr/bin/
</code></pre></div>
<p>编辑 /usr/lib/systemd/system/foreman-tasks.service ,在 ExecStart 和 ExecStop 的命令中加上 scl 前缀,即</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">ExecStart=/usr/bin/scl enable ruby193 v8314 '/usr/bin/foreman-tasks start'
ExecStop=/usr/bin/scl enable ruby193 v8314 '/usr/bin/foreman-tasks stop'
</code></pre></div>
<p>然后执行:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text"># systemctl daemon-reload
</code></pre></div>
<p>手动测试 foreman-tasks 能否启动:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text"># /usr/bin/scl enable ruby193 v8314 '/usr/bin/foreman-tasks start'
</code></pre></div>
<p>如果启动正常,则配置为随系统启动,并重新通过 systemctl 启动:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text"># /usr/bin/scl enable ruby193 v8314 '/usr/bin/foreman-tasks stop'
# systemctl enable foreman-tasks
# systemctl start foreman-tasks
</code></pre></div>
<p>这里如果之前手动启动成功,但是 systemctl 启动失败,可能有 2 个原因:</p>
<ul>
<li><p>SELinux :这里重新贴一下顺手生成的规则,供参考</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">require {
type passenger_t;
type puppet_etc_t;
class process execmem;
class lnk_file read;
}
#============= passenger_t ==============
allow passenger_t puppet_etc_t:lnk_file read;
allow passenger_t self:process execmem;
init_stream_connect_script(passenger_t)
</code></pre></div></li>
<li><p>foreman-tasks pid 目录和文件的权限,保证 foreman 用户对 <code>/var/run/foreman</code> 目录及其下的文件和子目录有读写权限。</p></li>
</ul>
<h4>9、创建 Staypuft deployment</h4>
<ul>
<li><p>首先,在 foreman 界面上,点击 “Administer” --> “Setting” --> “StayPuftProvioning” ,将 <code>base_hostgroup</code> 设置为前面创建 <code>Provision</code> 时自动生成的 <code>hostgroup</code> ;</p></li>
<li><p>在 “Infrastructure” --> “Subnets” 页面中为 OpenStack 创建必要的网络;我测试时,OS provison 对应的网络是 OpenStack 管理网络,还需要建立外部网络和租户网络;</p></li>
<li><p>点击 “OpenStack Installer” --> “New deployment” ,按装向导创建新的 Staypuft 布署方案;</p></li>
<li><p>在 “Configure” --> “Hostgroups” 页面检查默认的 base_hostgroup 的 <code>environment</code> 参数是 <code>production</code> ,并为 OS provision 配置默认的系统 root 用户密码;</p></li>
<li><p>在 OS provions 对应的网络中,启动一台服务器,被 foreman 发现后,在 Staypuft 布署方案中添加并分配角色,尝试布署。</p></li>
</ul>
<h4>10、遇到的其它问题</h4>
<ul>
<li><p>OS provision 完成之后,主机无法从 foreman 服务器获取 puppet catalog :</p>
<p>foreman 服务器上,puppet 服务应该配置自动为新的 puppet agent 作证书签名:</p>
<p>编辑 /etc/puppet/autosign.conf ,在其中加上一行:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">*
</code></pre></div>
<p>重启 httpd 服务。</p>
<p>如果以前出现节点证书没有签名的情况,可以通过下面的命令手动签名(在 foreman 服务器上执行):</p>
<div class="highlight"><pre><code class="language-text" data-lang="text"># puppet cert list
# puppet cert sign <puppet agent 所在服务器的 fqdn>
</code></pre></div></li>
<li><p>Staypuft 布署方案中的 puppet 模块不正确</p>
<p>foreman 是 rails 应用,staypuft 是 foreman 的一个插件,布署方案中服务器角色和 OpenStack 服务 、Puppet 模块之间的关系也保在 foreman 数据库中,初始数据是在装完 Staypuft 之后,执行 <code>foreman-rake db:migrate</code> 和 <code>foreman-rake db:seed</code> 写入数据库的。如果 Staypuft 布署方案中 puppet 模块不正确,说明数据初始化出现问题,必须检查 Staypuft 安装过程是否出现问题,然后再次执行上述 2 条 <code>foreman-rake</code> 命令(多次执行这两条命令不会影响 foreman 数据库中已有数据)。</p>
<p>另外也可以手动检查 foreman 数据库,确认 staypuft 相关数据已正确初始化:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text"># sudo -u postgres psql foreman
foreman=# select * from staypuft_role_services;
foreman=# select * from staypuft_service_classes;
</code></pre></div>
<p>如果 role (服务器角色) 和 services ( OpenStack 服务) 、 service 和 classes ( Puppet 模块)的数据都存在,说明 Staypuft 数据库数据初始化没有问题。</p></li>
<li><p>查看服务器 OS Provision 的具体配置,以及手动通知 Foreman 服务器 OS Provision 已经完成</p>
<p>服务器在 OS Provision 阶段的 Kickstart 配置可以通过访问下面的 url 查看:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">http://foreman/unattended/provision?spoof=xxx.xxx.xxx.xxx ( xxx.xxx.xxx.xxx 是该服务器的 ip 地址)
</code></pre></div>
<p>如果由于 <code>installation media</code> 中没有 puppet 软件包,基本系统装完可手动完成 Kickstart 配置没有完成的操作,然后通知 Foreman 服务器 OS Provision 已经完成,该命令也在 Kickstart 配置的最后:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">wget -q -O /dev/null --no-check-certificate http://foreman/unattended/built?token=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
</code></pre></div>
<p>url 后面的 token 可以省略。</p></li>
</ul>
<h4>相关链接</h4>
<ul>
<li><p><a href="http://blog.apporc.org">apporc</a> 的 2 篇博客</p>
<ul>
<li><a href="http://blog.apporc.org/?p=660">openstack部署实践-foreman(rhel-osp)硬件部分</a></li>
<li><a href="http://blog.apporc.org/?p=655">openstack部署实践-foreman(rhel-osp)软件部分</a></li>
</ul></li>
</ul>
/OpenStack-Foreman-installer-staypuft
OpenStack Foreman Installer —— staypuft
2014-09-29T02:53:43+08:00
2014-09-29T02:53:43+08:00
<p>在<a href="/2014-09-26-OpenStack-Foreman-installer.html">前一篇博客</a>中对 astapor 的基本安装和使用进行了一些说明,但是只有 astapor 是实现不了 RedHat OpenStack Platform Installer 文档中提到的“部署过程的统筹和排序”这个特性的,本来准备过段时间再回来调查下,不过稍微搜索了一下,就发现了这个项目:</p>
<p><a href="https://github.com/theforeman/staypuft">https://github.com/theforeman/staypuft</a></p>
<p>相关的介绍可以看下面这些链接:</p>
<ul>
<li><a href="https://www.openstack.org/summit/openstack-summit-atlanta-2014/session-videos/presentation/project-staypuft-an-introduction-to-the-foreman-openstack-installer">Project Staypuft: An Introduction to the Foreman OpenStack Installer</a></li>
<li><p><a href="http://allthingsopen.com/2014/06/10/openstack-foreman-installer/">Public OpenStack Foreman Installer</a></p>
<p><em>这个是 RedHat 的演示文档,不得不说他们的文档做得不错,产品本身先不说,光看演示文档就比较能吸引和打动目标客户。。。</em></p></li>
</ul>
<p>staypuft 是 foreman 自行维护的插件,但是目前没有 for el7 的 rpm 安装包,不过安装也不是太麻烦,有 3 种选择:</p>
<ol>
<li><a href="https://github.com/theforeman/foreman-packaging">Foreman pakcaging</a>,提供了打包所需要的东西,可以自行打包;</li>
<li><a href="https://github.com/theforeman/foreman-installer-staypuft">foreman-installer-staypuft</a>,这个应该是社区比较推荐的方式,可以处理好一些数据初始化相关的工作;</li>
<li>使用 gem 安装。</li>
</ol>
<p>由于目前主要目的是简单测试和体验一下 starpuft,因此直接使用 gem 安装。这种方式不太方便,安装过程出现问题的可能性比较大。下面是这次测试的一些记录:</p>
<h4>1、安装(依赖和 staypuft 本身)</h4>
<p>具体的依赖没有仔细研究,不过使用 gem 安装 staypuft 时有依赖的 gem 包需要对 c 和 c++ 代码进行编译,因此首先需要保证系统具备开发编译环境。</p>
<div class="highlight"><pre><code class="language-text" data-lang="text"># yum install gcc gcc-c++ glibc-headers libxml2-devel zlib-devel \
ruby193-ruby-devel ruby193-rubygems-devel \
ruby193-rubygem-sass-rails ruby193-rubygem-uglifier \
ruby193-rubygem-therubyracer
# scl enable ruby193 'gem install staypuft'
</code></pre></div>
<h3>2、配置 foreman</h3>
<p>首先配置 foreman 调用 staypuft,使用的方法是在 foreman 目录下的 bundler.d 增加配置文件:</p>
<p>/usr/share/foreman/bundler.d/staypuft.rb</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">gem 'staypuft'
</code></pre></div>
<p>/usr/share/foreman/bundler.d/assets.rb</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">gem 'sass-rails'
gem 'therubyracer'
gem 'bootstrap-sass'
gem 'jquery-rails'
gem 'jquery-ui-rails'
gem 'uglifier'
</code></pre></div>
<h3>3、初始化数据</h3>
<p>执行命令:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">sudo -u foreman scl enable ruby193 'cd /usr/share/foreman; rake db:migrate RAILS_ENV=production'
</code></pre></div>
<p>或者:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">foreman-rake db:migrate
</code></pre></div>
<p>不过目前 softwarecollections 提供的 therubyracer 有点问题,会提供无法加载 therubyracer 库,解决的方法是通过 gem 重新安装更新版本:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">scl enable ruby193 'gem install therubyracer'
</code></pre></div>
<h3>4、添加 SELinux 策略</h3>
<p>上述的问题解决完了之后,foreman Web 界面的 Openstack Installer 页面仍然会出现问题,foreman 日志中会出现这样的信息:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">No such file or directory - "/usr/share/foreman/tmp/sockets/dynflow_socket" (Errno::ENOENT)
</code></pre></div>
<p>查了很久不能确认问题,还是怀疑是 SELinux 的问题,看了下 /var/log/audit/audit.log ,的确有相关报错:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text"># ausearch -m avc -c ruby -ts 18:01:00 | audit2allow -R
</code></pre></div>
<p>根据上述命令生成的 SELinux 策略,进行调整精简,可以得到这样的策略文件:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">require {
type passenger_t;
class process execmem;
}
#============= passenger_t ==============
allow passenger_t self:process execmem;
</code></pre></div>
<p>可以手动编译成 SELinux 模块,或者直接使用</p>
<div class="highlight"><pre><code class="language-text" data-lang="text"># ausearch -m avc -c ruby -ts 18:01:00 | audit2allow -M passenger-execmem
</code></pre></div>
<p>最后加载 SELinux 模块:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text"># semodule -i passenger-execmem.pp
</code></pre></div>
<h3>5、设置 base_hostgroup</h3>
<p>Foreman Web 界面的 “OpenStack Installer” 可以访问之后,可以通过 “New Deployment” 来配置自定义的 OpenStack 部署流程或者方式,正是我们需要的“部署过程的统筹和排序”这一特性。但是点击 “New Deployment” 会提示:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">missing base_hostgroup
</code></pre></div>
<p>原因可能是 staypuft 数据初始化的过程仍然存在问题,不过可以手动做一些处理,比如自己定义 “base_hostgroup” :</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">Foreman Web 界面 --> “Administre” 菜单 --> “settings”
--> “StaypuftProvisioning” --> 修改 “base_hostgroup” 的值
</code></pre></div>
<p>至此,staypuft 基本可用了(当然仍然需要保证基本的 puppet 模块是可用的),由于能够自定义部署架构和流程,所以相对来说是目前最理想的 OpenStack 部署方式。</p>
/OpenStack-Foreman-installer
OpenStack Foreman Installer 安装及基本使用
2014-09-26T20:10:33+08:00
2014-09-26T20:10:33+08:00
<p>OpenStack 的部署方式有很多,基础文档可以从这里获取:</p>
<p><a href="http://docs.openstack.org">http://docs.openstack.org</a></p>
<p>RedHat 有一篇文档对不同的部署方式做了整理和对比,不过需要订阅访问:</p>
<p><a href="https://access.redhat.com/articles/1140323">Evaluating OpenStack: Deployment Types and Tools</a></p>
<p>不过 RedHat 在其他的 Deploying OpenStack 系列文档里面大概说明了一下他们提供的3种部署方式的区别:</p>
<ol>
<li><p>手动部署</p>
<p>纯学习目的,了解 OpenStack 的结构以及各组件的安装和基本配置。</p></li>
<li><p>PackStack</p>
<p>验证性质的部署方式( proof-of-concept )。PackStack 提供了命令行工具,使用 Puppet 模块完成(在已经安装了操作系统的服务器上) OpenStack 的快速部署,除了使用命令行工具,也可以使用 annswer 文件这种形式完成非交互式的自动部署。</p>
<p>RedHat 的建议是不应使用 PackStack 来进行生产环境的 OpenStack 部署,原因是 PackStack 为了简化部署流程,对 OpenStack 各组件的配置项做了很多预设定,导致无法实现 HA 、 Load Balance 等结构,配置复杂网络拓扑也会比较麻烦。</p>
<p>不过说起来,PackStack 是使用 Puppet 的,对于有经验的用户来说,自行修改相关模块的配置,应该不会特别困难。</p></li>
<li><p>RHEL OpenStack Platform Installer</p>
<p>这是 RedHat OpenStack Platform 产品的部署工具,提供了 Web 界面、向导式的自动化部署方式(基于 Foreman 和 Puppet )。包含了一些更好的特性,比如 LiveCD ,部署过程的统筹、排序,裸机自动发现等。</p>
<p>不过 RedHat 的文档里面说明, RHEL OpenStack Platform Installer 目前只能在 RHEL 6.5 上使用(用来部署 RHEL 7 以及 在 RHEL 7 上部署 RHEL OpenStack Platform 5 则是没问题的)。</p>
<p>关于 RHEL OpenStack Platform 5 的文档参见:</p>
<p><a href="https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux_OpenStack_Platform/5/index.html">Red Hat Enterprise Linux OpenStack Platform 5</a></p></li>
</ol>
<p>从特性上看,当然是最后一种比较吸引人,不过更详细的文档可能不太容易找到了。我们能找到的是这个:</p>
<p><a href="https://github.com/redhat-openstack/astapor">https://github.com/redhat-openstack/astapor</a></p>
<p>我并没有做深入的调查,所以不能确认 RHEL OpenStack Installer 的上游项目就是这个 astapor,但是从项目的 README 、脚本以及 Puppet 模块可以看出,两者重合度还是很高。</p>
<p>astapor 的 README 文件写的比较清楚,主要的步骤如下:</p>
<ol>
<li>执行 foreman_server.sh ;</li>
<li>安装完成之后,访问 https://FQDN 就可打开 foreman 的 Web 界面;</li>
<li>将 foreman<em>server.sh 生成的 /tmp/foreman</em>client.sh 复制到的准备部署为 OpenStack Controller 的服务器并执行,这个脚本会安装 puppet 并主动向 foreman 服务器注册;</li>
<li>在 foreman 的 Web 管理界面上,可以看到新注册的服务器,编辑该服务器,选择“主机组”;</li>
<li>回到准备安装 OpenStack 组件的服务器,执行 puppet agent -tv,会自动开始部署 OpenStack Controller 相关软件并进行配置;</li>
<li>对其他 OpenStack 节点服务器,重复上述第 3 - 5 步,根据服务器角色不同选择主机组。</li>
</ol>
<p>具体的操作流程这里不在一一说明,说一下在 CentOS 7 中遇到的问题:</p>
<h4>1、安装依赖的软件包和配置 YUM 仓库</h4>
<p>要使用 astapor ,首先还是需要安装一些依赖的软件包的:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text"># yum install puppet openstack-puppet-modules foreman foreman-mysql \
foreman-installer ruby193-rubygem-foreman_simplify \
mysql-server augeas
</code></pre></div>
<p>不过 foreman 安装过程会有不少包不在 foreman 自己的 YUM 仓库,也不在 CentOS 和 EPEL 的仓库里面,需要从 SCL 软件集获取,这些包目录可以从下面的网站获取:</p>
<p><a href="https://www.softwarecollections.org">https://www.softwarecollections.org</a></p>
<p>在我的测试过程需要安装的软件包都在 Ruby193 和 V8314 这两个集合中,给个YUM repo 文件的例子:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">[softwarecollections-ruby193]
name=Ruby192 packages from softwarecollections.org
baseurl=https://www.softwarecollections.org/repos/rhscl/ruby193/epel-7-x86_64/
gpgcheck=0
[softwarecollections-v8314]
name=V8314 packates from softwarecollections.org
baseurl=https://www.softwarecollections.org/repos/rhscl/v8314/epel-7-x86_64/
gpgcheck=0
</code></pre></div>
<h4>2、跳过系统 release 信息检测</h4>
<p><code>foreman_server.sh</code> 中以下几行:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">if [ ! -f /etc/redhat-release ] || \
cat /etc/redhat-release | grep -v -q -P 'release 6.[456789]'; then
echo "This installer is only supported on RHEL 6.4 or greater."
exit 1
fi
</code></pre></div>
<p>对于 CentOS 7 来说就没有什么意义了,直接可以去掉。</p>
<h4>3、禁止自动添加外部 YUM 仓库</h4>
<p><code>foreman-installer</code> 默认会自动添加 EPEL 和 SCL 的 YUM 仓库,不过在获取 repodata 可能会出错,导致 <code>foreman_server.sh</code> 无法完成,因此在 <code>foreman_server.sh</code> 生成 <code>install.pp</code> 的地方加上 2 行配置:</p>
<p>将</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">class { 'foreman':
db_type => 'mysql',
custom_repo => true,
}
</code></pre></div>
<p>修改为</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">class { 'foreman':
db_type => 'mysql',
custom_repo => true,
configure_epel_repo => false,
configure_scl_repo => false
}
</code></pre></div>
<h4>4、修改 seeds.rb</h4>
<p>seeds.rb 中包含了在 foreman 的数据库初始化和 astapor 提供的 puppet 模块信息,因此比较重要。但是由于 foreman 给 el7 打的rpm 包还是使用 ruby193,在 seeds.rb 中调用 facter 时很多系统信息无法获取,会导致执行 <code>rake db:seed</code> 时出错。</p>
<p>下面是我拿系统基本命令替换 facter 的 patch ,可能比较难看,但是可以用:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">@@ -183,8 +183,13 @@ if ENV["FOREMAN_PROVISIONING"] == "true" then
# Subnets - use Import Subnet code
s=Subnet.find_or_create_by_name "OpenStack"
- s.network=Facter.value("network_#{secondary_int}")
- s.mask=Facter.value("netmask_#{secondary_int}")
+ #s.network=Facter.value("network_#{secondary_int}")
+ #s.mask=Facter.value("netmask_#{secondary_int}")
+ t_ip=`ifconfig #{secondary_int} | awk '/netmask/ {print $2}'`.chomp
+ t_mask=`ifconfig #{secondary_int} | awk '/netmask/ {print $4}'`.chomp
+ t_network=`ipcalc -n #{t_ip} #{t_mask} | awk -F'=' '{print $2}'`.chomp
+ s.network=t_network
+ s.mask=t_mask
s.dhcp = Feature.find_by_name("DHCP").smart_proxies.first
s.dns = Feature.find_by_name("DNS").smart_proxies.first
s.tftp = Feature.find_by_name("TFTP").smart_proxies.first
@@ -237,10 +242,12 @@ if ENV["FOREMAN_PROVISIONING"] == "true" then
# Override all the puppet class params for quickstack
primary_int=`route|grep default|awk ' { print ( $(NF) ) }'`.chomp
- primary_prefix=Facter.value("network_#{primary_int}").split('.')[0..2].join('.')
- sec_int_hash=Facter.to_hash.reject { |k| k !~ /^ipaddress_/ }.reject { |k| k =~ /lo|#{primary_int}/ }.first
- secondary_int=sec_int_hash[0].split('_').last
- secondary_prefix=sec_int_hash[1].split('.')[0..2].join('.')
+ #primary_prefix=Facter.value("network_#{primary_int}").split('.')[0..2].join('.')
+ primary_ip=`ifconfig #{primary_int} | awk '/netmask/ {print $2}'`.chomp
+ primary_mask=`ifconfig #{primary_int} | awk '/netmask/ {print $4}'`.chomp
+ primary_network=`ipcalc -n #{primary_ip} #{primary_mask} | awk -F'=' '{print $2}'`.chomp
+ primary_prefix=primary_network.split('.')[0..2].join('.')
+ secondary_prefix=t_network.split('.')[0..2].join('.')
end
</code></pre></div>
<h4>5、完善 foreman-installer 中对系统 release 版本的检测</h4>
<p>foreman-installer 中对于 CentOS 等 RHEL 克隆发行版的检测还是不太完善,比如</p>
<p>/usr/share/foreman-installer/modules/mysql/manifests/params.pp,需要将:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">'RedHat': {
if $::operatingsystemlease >= 7 {
$provider = 'mariadb'
} else {
$provider = 'mysql'
}
}
</code></pre></div>
<p>修改为:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">/^(RedHat|CentOS|Scientific)$/: {
if $::operatingsystemmajrelease >= 7 {
$provider = 'mariadb'
} else {
$provider = 'mysql'
}
}
</code></pre></div>
<p>其他的模块,碰到类似问题的话,也需要进行修改。</p>
<h4>6、执行 foreman_server.sh</h4>
<p>astapor 提供了 quickstack ( 部署 OpenStack 平台的 puppet 模块),其路径最后会写入到 puppet 的系统配置中,因此建议把 git clone 下来的代码放到比较固定、不容易干扰的目录,比如:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text"># mv astapor /usr/share/openstack-foreman-installer
</code></pre></div>
<p>另外由于 CentOS 7 中 SELinux 默认是启用的,需要恢复下目录的安全上下文:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text"># restorecon -RFv /usr/share/openstack-foreman-installer
</code></pre></div>
<p>还需要做的是,要为主机设置好主机名并正确配置 /etc/hosts :</p>
<div class="highlight"><pre><code class="language-text" data-lang="text"># hostnamectl set-hostname foreman.zhaochao.eayunstack.eayun.com
# echo "xxx.xxx.xxx.xxx foreman.zhaochao.eayunstack.eayun.com" >> /etc/hosts
</code></pre></div>
<p>最后,执行 foreman<em>server.sh 时,需要为 FOREMAN</em>GATEWAY 环境变量赋值(指定 foreman 服务器的 IP 地址即可,脚本会检测系统的网络配置,并且使用非默认路由对应的网卡给后续的 privison 使用,因此 FOREMAN_GATEWAY 可以使用前期配置好的内部 IP 地址):</p>
<div class="highlight"><pre><code class="language-text" data-lang="text"># FOREMAN_GATEWAY=xxx.xxx.xxx.xxx ./foreman_server.sh
</code></pre></div>
<h4>7、foreman_proxy 注册不成功</h4>
<p><code>foreman_server.sh</code> 脚本如果由于前期配置和环境准备不完善,多次执行之后仍然可能会碰到一些问题,比如</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">Info: Class[Foreman_proxy::Register]: Scheduling refresh of Foreman_smartproxy[foreman.zhaochao.eayunstack.eayun.com]
E, [2014-09-26T18:04:53.419648 #26850] ERROR -- : 404 Resource Not Found
</code></pre></div>
<p>跟踪脚本执行,可以看到是下面这条命令出错:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">puppet apply --verbose installer.pp --modulepath=modules
</code></pre></div>
<p>而从后面的详细输出可以看到,原因是,访问</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">https://foreman.zhaochao.eayunstack.eayun.com/apidoc/v2.json
</code></pre></div>
<p>时返回了 HTTP 404。</p>
<p>而根据 foreman 的日志提示,可能需要执行 <code>rake apipie:cache</code>,参考 <code>foreman_server.sh</code> 脚本中的方式执行:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">sudo -u foreman scl enable ruby193 \
'cd /usr/share/foreman; rake apipie:cache RAILS_ENV=production'
</code></pre></div>
<p>之后,可以重新执行 <code>foreman_server.sh</code> 。</p>
<h4>8、无法使用 admin 登录 foreman</h4>
<p><code>foreman_server.sh</code> 执行成功之后,使用 admin/changeme 总是提示验证失败,具体原因不明,应该是 foreman installer 的 puppet 模块还存在一些问题,没有具体研究。可以使用下面的命令,重置 admin 用户的密码:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text"># foreman-rake permissions:reset
</code></pre></div>
<h4>9、foreman 中没有 qickstack 相关的模块和主机组信息</h4>
<p>最开始由于对 puppet 完全没概念,以为是配置问题,所以直接的解决方法时,把 astapor 提供的 puppet 模块全部复制一份到 puppet 的默认目录中去,比如 <code>/etc/puppet/environments/production/modules/</code> ,的确重新执行 <code>foreman_server.sh</code> 或者使用 <code>rake</code> 命令手动导入 puppet 模块,在 foreman 中就可以看到 quickstack 的模块和主机组了。</p>
<p>但是问题依然存在,在 provision 服务器节点时,puppet agent 总是提供找不到对应的 qickstack 模块中的组件,最后无奈使用了 <code>strace</code>,确认原因是 puppet-master 对于 quickstack 模块的目录和文件没有权限访问。</p>
<p>而基本 rwx 权限是没有问题,/var/log/audit/audit.log 竟然没有 AVC 的报错,但是使用 <code>restorecon</code> 恢复这些文件默认的安全上下文之后,puppet agent 就可以正常运行了。</p>
<h4>10、对裸机进行部署</h4>
<p>foreman 安装完整之后,PXE 、DHCPD 、 TFTPD 等服务已经配置好了,需要做的事情比较简单,准备安装界面和 pxelinux 配置文件。</p>
<p>不过 RHEL OpenStack Platform Installer 中提到 bare metal provision 则是使用了 <code>foreman_discovery</code> 插件,仍然是基于上述几个服务,但是在 foreman 界面上多了类似“主机扫描”的页面,而且对于 PXE 提供的安装介质有一定的要求,需要在 initrd 中使用 <code>foreman_discovery</code> 提供的脚本向 foreman 服务器提交注册请求。</p>
<h3>写这篇博客的过程中,搜到的一些 slide :</h3>
<ul>
<li><a href="http://www.slideshare.net/domcleal/cfgmgmt-2014-rdo">http://www.slideshare.net/domcleal/cfgmgmt-2014-rdo</a></li>
<li><a href="http://rhsummit.files.wordpress.com/2014/04/summit2014_scale_cloud_infra-20140416_wfoster_kambiz.pdf">http://rhsummit.files.wordpress.com/2014/04/summit2014_scale_cloud_infra-20140416_wfoster_kambiz.pdf</a></li>
</ul>
/Koji-documents
Koji 文档整理
2014-08-18T23:49:48+08:00
2014-08-18T23:49:48+08:00
<p>这是关于 Koji 软件包构建系统的文档整理,绝大多数文字都从项目 wiki 以及相关技术文档翻译而来,参见结尾的<a href="#%E5%8E%9F%E6%96%87%E9%93%BE%E6%8E%A5">原文链接</a>。</p>
<p>对于这些文档中中不是很清晰的地方补充了一些内容和实际的例子。</p>
<h2>Koji 基本概念</h2>
<h3>Koji 简介</h3>
<p>Koji 是 Fedora 项目的编译打包系统,使用 mock 产生 chroot 环境并在其中完成具体的编译打包任务。</p>
<h4>主要的特性</h4>
<ul>
<li>每一次构建过程都会创建新的 buildroot 环境;</li>
<li>提供可靠的 XML-RPC api,和其他工具整合很容易;</li>
<li>Web 用户界面,提供 SSL 和 Kerberos 验证机制;</li>
<li>简洁可移植的命令行客户端程序;</li>
<li>用户可以创建自己的 buildroot ;</li>
<li>buildroot 之下内容的信息会记录在数据库中;</li>
<li>版本化的数据。</li>
</ul>
<h3>Koji 架构</h3>
<h4>术语</h4>
<ul>
<li><p>Package</p>
<p>source rpm 包的名称,这是软件包的通用名称,不包括特定的构建信息或者次级软件包,如: kernel 、 glibc 等;</p></li>
<li><p>Build</p>
<p>软件包的特定构建,包括所有构建平台上可能产生的结果以及所有次级软件包,如: kernel-2.6.9-34.EL、 glibc-2.3.4-2.19;</p></li>
<li><p>RPM</p>
<p>软件包构建完成之后产生的具体RPM,如: kernel-2.6.9-34.EL.x86_64 、 kernel-devel-2.6.9-34.EL.s390 、 glibc-2.3.4-2.19.i686 、 glibc-common-2.3.4-2.19.ia64 。</p></li>
</ul>
<h3>Koji 组件</h3>
<p>Koji 由以下部分组成:</p>
<h4>Koji-hub</h4>
<p>Koji-hub 是所有 Koji 操作的中心,是运行在 apache 服务的 mod<em>wsgi 模块之上的 XML</em>RPC 服务程序。Koji-hub 只被动地接受 XML_RPC 请求,依赖于 build daemon 和其他组件完成通信交互过程。Koji-hub 也是唯一可以访问数据库的组件,同时是2个对文件系统有写入权限的组件之一。</p>
<h4>Kojid</h4>
<p>Kojid 是 build daemon,需要在所有的构建服务器上运行。它主要的工作是获取构建请求并对这些请求进行相应的处理。Kojid 实际上是从 Koji-hub 那里获取任务,Koji 也支持构建之外的其他任务,比如创建安装介质镜像。Kojid 使用 mock 来完成构建任务,每次构建都会创建新的 buildroot。Kojid 是使用 Python 语言开发的,和 Koji-hub 之间通过 XML_RPC 协议进行通信。</p>
<h4>Koji-web</h4>
<p>Koji-web 是运行在 mod_python 模块之上的一系列脚本,加上 Cheetah 模板引擎提供了一套基于 Web 的交互界面。Koji-web 是 Koji-hub 的客户端,为最终用户提供了可视化的操作界面,在该界面上可以完成有限的管理操作。Koji-Web 展示了 Koji 系统中大量的信息,同时也支持完成特定的操作,如终止构建任务等。</p>
<h4>Koji-client</h4>
<p>Koji-client 是使用 Python 语言编写的命令行工具,也提供了可以和 Koji 交换的大量 hook 接口。使用 Koji-client 可以直接查询 Koji 系统中很多数据,也可以完成不少操作,如添加用户、提交新的构建任务等。</p>
<h4>Kojira</h4>
<p>Kojira 是维护由构建结果组成的仓库的 daemon 程序,负责清楚冗余的 build root 目录以及构建任务完成之后的清理工作。</p>
<h3>软件包的组织方式</h3>
<h4>tag 和 target</h4>
<p>Koji 通过 tag 对软件包组织管理:</p>
<ul>
<li>tag 相关信息在数据库中进行维护,而不是在硬盘上;</li>
<li>tag 之间可以形成多重继承关系;</li>
<li>每个 tag 都拥有自己的 package 列表(该列表可以继承);</li>
<li>package 的所有者可以根据 tag 进行设置(所有者属性也可以继承);</li>
<li>tag 之间的继承关系可以进行配置;</li>
<li>构建软件包时需要指定的是 target , 而不是 tag。</li>
</ul>
<p>target 用来确认软件包的构建过程在何处进行,构建完成之后如何对软件包进行标记( tag )。这样,在软件的发布周期之间,tag 可以不断进行变化,而 target 则可以保持不变。使用下面的命令可以获取 Koji 系统中所有的 target 列表:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">$ koji list-targets
</code></pre></div>
<p>加上 <code>--name</code> 选项可以针对指定的 target 进行查询:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">$ koji list-targets --name EayunOS-4-0
Name Buildroot Destination
----------------------------------------------------------------------------
EayunOS-4-0 EayunOS-4-0-build EayunOS-4-0
</code></pre></div>
<p>上述示例的含义是: EayunOS-4-0 ( target ) 构建时使用 EayunOS-4-0-build ( tag )中的软件包列表并创建 buildroot ,生成的软件包的标签为 EayunOS-4-0 ( tag )。</p>
<p>要获取 Koji 系统中所有的 tag 列表,使用下面的命令:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">$ koji list-tags
</code></pre></div>
<h4>软件包列表</h4>
<p>每一个 tag 都有自己的软件包列表,使用 <code>list-pkgs</code> 命令获取软件包列表(需要指定 tag 名称):</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">$ koji list-pkgs --tag EayunOS-4-0
Package Tag Extra Arches Owner
----------------------- ----------------------- ---------------- ---------
eayunos-release EayunOS-4-0 zhaochao
eayunos-lic EayunOS-4-0 zhaochao
virt-viewer-win EayunOS-4-0 zhaochao
</code></pre></div>
<p>命令输出结果中,第一列是软件包的名称,第二列显示软件包列表的继承关系,最后一列则显示软件包的所有者。</p>
<h4>最近的构建任务</h4>
<p>使用 latest-pkg 命令可以查看最近的构建任务:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">$ koji latest-pkg --all EayunOS-4-0
Build Tag Built by
---------------------------------------- -------------------- -----------
eayunos-lic-0.0.1-3 EayunOS-4-0 zhaochao
eayunos-release-4-0.el6.2 EayunOS-4-0 zhaochao
virt-viewer-win-0.0.1-4.el6 EayunOS-4-0 kojiadmin
</code></pre></div>
<p>命令的输出结果中会显示最近的构建任务,所属的 tag ,以及提交任务的用户。</p>
<h2>Koji 部署</h2>
<h3>选择安全验证方式</h3>
<p>Koji 支持 2 种安全验证方式: SSL 和 Kerberos 。如果只是使用 koji 命令行工具也可以直接使用用户名和密码登录这种方式,但是 kojiweb 不支持这种方式,而且一旦 kojiweb 配置了 SSL 或者 Kerberos 验证,则用户名和密码登录这种方式将会失效,因此在进行 Koji 部署之前需要首先确定安全验证的方式。</p>
<p><strong>Kerberos验证</strong>,前提是已经具备了可用的 Kerberos 环境,初始化 Koji 用户数据时必须已经建立好管理用户的安全凭证;</p>
<p><strong>SSL验证</strong>,需要为 xmlrpc 服务程序、Koji 其他各组件、管理用户准备好 SSL 证书。</p>
<h4>准备 SSL 安全验证的环境</h4>
<ul>
<li><p>生成证书</p>
<p>可以考虑建立 <code>/etc/pki/koji</code> 目录,创建 <code>ssl.cnf</code>,然后使用 <code>openssl</code> 命令生成证书。</p>
<p>在 <code>ssl.cnf</code> 中添加个性化的设置可以简化证书的生成。</p></li>
<li><p>生成 CA 证书</p>
<p>CA 证书是用来签发其他 SSL 证书的密钥/证书对。在对 Koji 各组件进行配置时,客户端和服务端程序要用到的 CA 证书都来自这一步骤生成的 CA 证书。CA 证书放在 <code>/etc/pki/koji</code> 目录下,其他各组件的证书则放在 <code>/etc/pki/koji/certs</code> 目录下。<code>index.txt</code> 中会记录所有签发证书的相关信息。</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">cd /etc/pki/koji/
mkdir {certs,private,confs}
touch index.txt
echo 01 > serial
openssl genrsa -out private/koji_ca_cert.key 2048
openssl req -config ssl.cnf -new -x509 -days 3650 -key \
private/koji_ca_cert.key -out koji_ca_cert.crt -extensions v3_ca
</code></pre></div>
<p>上述最后一条命令会要求对证书相关的信息进行确认或者输入。其中 organizationUnitName 和 commonName 在生成不同组件的证书是需要进行相应调整。对于 CA 证书本身,这些信息没有特殊限制,建议使用使用服务器的 FQDN 作为 commonName 。</p>
<p>如果使用配置管理工具来自动化证书生成,可以参考使用下面的命令:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">openssl req -config ssl.cnf -new -x509 \
-subj "/C=CN/ST=Beijing/L=Beijing/O=Eayun/CN=koji.eayunci.eayun.com" \
-days 3650 -key private/koji_ca_cert.key -out koji_ca_cert.crt \
-extensions v3_ca
</code></pre></div></li>
<li><p>为 Koji 各组件以及管理用户生成证书</p>
<p>Koji 每一个组件都需要单独的证书来标识自身。其中 kojihub 和 kojiweb 的证书是作为服务端证书需要通过客户端验证的,因此应将证书的 CN ( common name ) 配置为服务器的 FQDN,这样客户端程序就不会提示证书的 common name 和服务器主机名不匹配了。为了方便识别,可以将这2个证书的 OU ( organization name )分别配置为 kojihub 和 kojiweb 。</p>
<p>其他证书(如 kojira、kojid、管理用户以及其他用户)作为客户端证书,CN 只需要设置为这些对象用来登录的服务端的用户名即可,如 kojira 的证书 CN 应该设置为 kojira。原因是证书的 CN 需要和 koji 数据库中的用户名进行匹配。如果这些组件和服务端程序通信时,在数据库中找不到和证书 CN 对应的用户时,验证将无法通过,客户端访问将会被拒绝。</p>
<p>当使用 <code>koji add-host</code> 命令添加构建主机时,会在 koji 数据库中添加一个用户(这个用户不会出现在用户列表中)。这个用户的名称需要和主机使用的证书的 CN 保持一致,否则构建主机将会无法访问 kojihub 服务器。而生成 kojiweb 的证书时,证书的所有相关信息(如,C、ST、L、O、CN 等)都需要加入到 /etc/koji-hub/hub.conf 中的 <code>ProxyDNs</code> 配置中去。</p>
<p>要生成很多证书时将上述手动执行的命令编写为循环或者脚本是比较便捷的方式,下面是一个例子:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">#!/bin/bash
# if you change your certificate authority name to something else you will
# need to change the caname value to reflect the change.
caname=koji
# user is equal to parameter one or the first argument when you actually
# run the script
user=$1
openssl genrsa -out private/${user}.key 2048
cat ssl.cnf | sed 's/insert_hostname/'${user}'/'> ssl2.cnf
openssl req -config ssl2.cnf -new -nodes -out certs/${user}.csr \
-key private/${user}.key
openssl ca -config ssl2.cnf -keyfile private/${caname}_ca_cert.key \
-cert ${caname}_ca_cert.crt -out certs/${user}.crt -outdir certs \
-infiles certs/${user}.csr
cat certs/${user}.crt private/${user}.key > ${user}.pem
mv ssl2.cnf confs/${user}-ssl.cnf
</code></pre></div></li>
<li><p>生成 PKCS12 用户证书 (供网页浏览器使用)</p>
<p>PKCS12 用户证书是为了用户登录 kojiweb 的站点准备的。</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">openssl pkcs12 -export -inkey private/${user}.key -in certs/${user}.crt \
-CAfile ${caname}_ca_cert.crt -out certs/${user}_browser_cert.p12
</code></pre></div></li>
<li><p>将 kojiadmin (管理用户)的证书复制到用户的 <code>~/.koji</code> 目录之下</p>
<p>管理用户使用 koji 命令行工具可以对 koji 系统进行管理。创建 kojiadmin 用户(koji 系统中的用户,并生成用户证书)之后,将 CA 证书 和 kojiadmin 用户证书复制到系统用户(普通用户也可以)的 <code>~/.koji</code> 目录之下:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">$ mkdir ~/.koji
$ cp /etc/pki/koji/kojiadmin.pem ~/.koji/client.crt
# 注意:用户证书需要用 PEM 文件而不是 CRT
$ cp /etc/pki/koji/koji_ca_cert.crt ~/.koji/clientca.crt
$ cp /etc/pki/koji/koji_ca_cert.crt ~/.koji/serverca.crt
</code></pre></div>
<p>koji 命令行工具默认使用全局配置文件 /etc/koji.conf ,将该文件复制到 ~/.koji/ 目录下,并根据情况进行调整。</p></li>
</ul>
<h4>准备 Kerberos 安全验证环境</h4>
<p>Kerberos 环境的部署需要参考其他文档,和 Koji 系统相关的内容说明如下:</p>
<ul>
<li><p>DNS</p>
<p>Koji 构建服务器(kojid)通过 DNS 查找特定 realm 中的 kerberos 服务器,如:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">_kerberos._udp IN SRV 0 100 88 ipa-server.zhaochao.eayunos.eayun.com.
</code></pre></div></li>
<li><p>Principal 和 Keytab</p>
<p>需要注意的是,在为 Koji 各组件生成 keytab 时,需要使用组件所在服务器的 FQDN。</p>
<p>以下 principal 需要导出到 keytab 文件中,其中 kojihub 要用到的 主机 principal 的名称部分(host/kojihub)目前是直接固定写在 koji 命令行工具的代码中的,不过更改。</p>
<ul>
<li>host/kojihub@EXAMPLE.COM
<ul>
<li>kojihub 在和 koji 命令行工具通信时需要用到。</li>
</ul></li>
<li>HTTP/kojiweb@EXAMPLE.COM
<ul>
<li>kojiweb 在和网络浏览器之间进行 kerberos 验证时需要用到,也是 apache 的 mod<em>auth</em>kerb 使用的服务 principal 。</li>
</ul></li>
<li>koji/kojiweb@EXAMPLE.COM
<ul>
<li>kojiweb 在和 kojihub 通信时需要用到。这是一个用户 principal,即 kojiweb 在 kerberos 环境使用的是该用户。kojiweb 将会把 mod<em>auth</em>kerb 中用户信息(用户登录 Web 界面登录的情况)转发到 kojihub ( kojihub 配置文件中的 ProxyPrincipals 选项)。</li>
</ul></li>
<li>koji/kojira@EXAMPLE.COM
<ul>
<li>kojira 和 kojihub 通信时使用。</li>
</ul></li>
<li>compile/builder1@EXAMPLE.COM
<ul>
<li>构建服务器 builder1 (服务器的主机名)和 kojihub 通信时使用。</li>
</ul></li>
</ul></li>
<li><p>Kerberos 环境示例</p>
<p>上面关于“准备 Kerberos 安全验证环境”的说明均来自官方的 wiki 页面,但是其实有不少含糊不清的地方,在实际部署的过程会碰到不少问题,下面做一些说明:</p>
<p>测试的环境中使用 FreeIPA,对于 DNS 记录在初始化时已经建立,不用额外配置,但是由于测试环境只用了一台虚拟机,Koji 所有的组件都跑在该虚拟机上,因此 principal 建立就会产生不同。</p>
<ul>
<li><p>所有 Koji 组件运行在同一台服务器上,在 FreeIPA 中建立对应的 Principal</p>
<ul>
<li>host/koji.zhaochao.eayunos.eayun.com@ZHAOCHAO.EAYUNOS.EAYUN.COM</li>
<li>HTTP/koji.zhaochao.eayunos.eayun.com@ZHAOCHAO.EAYUNOS.EAYUN.COM</li>
<li>kojiweb/koji.zhaochao.eayunos.eayun.com@ZHAOCHAO.EAYUNOS.EAYUN.COM</li>
<li>kojira/ipa-server.zhaochao.eayunos.eayun.com@ZHAOCHAO.EAYUNOS.EAYUN.COM</li>
<li>compile/koji.zhaochao.eayunos.eayun.com@ZHAOCHAO.EAYUNOS.EAYUN.COM</li>
</ul></li>
</ul>
<p>也就是说 Principal 中除去前面的关键字前缀,在 realm 之前应该使用的是服务器的 FQDN。</p></li>
</ul>
<h3>初始化数据库</h3>
<p>这里略去了 Postgres 数据库服务自身的初始化过程。</p>
<h4>创建 koji 系统用户</h4>
<div class="highlight"><pre><code class="language-text" data-lang="text"># useradd koji
# password koji
</code></pre></div>
<h4>建立数据库环境</h4>
<p>分为以下几步:</p>
<ul>
<li>建立 koji 数据库用户</li>
<li>建立 koji 数据库</li>
<li>为 koji 数据库用户设置密码</li>
<li><p>导入 koji 数据库的 schema</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">root@localhost$ su - postgres
postgres@localhost$ createuser koji
Shall the new role be a superuser? (y/n) n
Shall the new role be allowed to create databases? (y/n) n
Shall the new role be allowed to create more new roles? (y/n) n
postgres@localhost$ createdb -O koji koji
postgres@localhost$ psql -c "alter user koji with encrypted password \
'mypassword';"
postgres@localhost$ logout
root@localhost$ su - koji
koji@localhost$ psql koji koji < /usr/share/doc/koji*/docs/schema.sql
koji@localhost$ exit
</code></pre></div></li>
</ul>
<h4>设置数据库允许 koji-web 和 koji-hub 访问</h4>
<p>/var/lib/pgsql/data/pg_hba.conf :</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">#TYPE DATABASE USER CIDR-ADDRESS METHOD
host koji koji 127.0.0.1/32 trust
host koji koji ::1/128 trust
</code></pre></div>
<p>如果服务器还有外部 IP 地址的话,可以再加上:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">host koji koji $IP_ADDRESS/32 trust
</code></pre></div>
<p>如果要使用 UNIX socket 和数据库通信(这种方式下,Koji 组件的配置文件中 DBHost 选项不能进行设备),可以使用这样的配置:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">local koji apache trust
local koji koji trust
</code></pre></div>
<p><strong>注意:</strong> 如果强制要求使用密码验证访问数据,可以将上述配置中的 <code>trust</code> 改为 <code>md5</code>:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">#TYPE DATABASE USER CIDR-ADDRESS METHOD
host koji koji 127.0.0.1/32 md5
host koji koji ::1/128 md5
host koji koji $IP_ADDRESS/32 md5
</code></pre></div>
<p>为了配置生效,让数据库重新读取配置文件:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text"># service postgresql reload
</code></pre></div>
<h4>在数据库中添加 Koji 管理用户</h4>
<p>Koji 管理用户需要手动通过 sql 语句添加到数据库中。当管理用户添加成功之后,其他的用户操作(增加、删除用户,修改用户权限等)可以通过 koji 命令完成。</p>
<p>不过,如果使用简单的用户名和密码验证方式,则配置或者修改用户密码仍然需要通过 sql 语句直接操作数据库完成,因为 koji 命令没有提供对用户密码进行操作的接口。</p>
<p>针对不同的验证方式,添加 Koji 管理用户的 sql 语句也不同:</p>
<ul>
<li><p>用户名和密码验证:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">root@localhost$ su - koji
koji@localhost$ psql
koji=> insert into users (name, password, status, usertype)
koji-> values ('admin-user-name', 'admin-password-in-plain-text', 0, 0);
</code></pre></div></li>
<li><p>Kerberos 验证:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">root@localhost$ su - koji
koji@localhost$ psql
koji=> insert into users (name, krb_principal, status, usertype)
koji-> values ('admin-user-name', 'admin@EXAMPLE.COM', 0, 0);
</code></pre></div></li>
<li><p>SSL 证书验证:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">root@localhost$ su - koji
koji@localhost$ psql
koji=> insert into users (name, status, usertype)
koji-> values ('admin-user-name', 0, 0);
</code></pre></div></li>
</ul>
<h4>赋予指定用户管理权限</h4>
<p>使用下面的 sql 语句可以为指定用户(需要知道用户的 ID)赋予管理管线:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">koji=> insert into user_perms (user_id, perm_id, creator_id)
koji-> values (<用户 ID >, 1, <用户 ID >);
</code></pre></div>
<h4>让 Postgresql 数据库监听所有地址</h4>
<ul>
<li>编辑 <code>/var/lib/pgsql/data/postgresql.conf</code></li>
<li>修改配置项,<code>listen_addresses = '*'</code></li>
<li><p>重启数据库</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">service postgresql restart
</code></pre></div></li>
</ul>
<h3>安装配置 Koji-hub</h3>
<h4>安装 Koji-hub</h4>
<div class="highlight"><pre><code class="language-text" data-lang="text"># yum install koji-hub httpd mod_ssl mod_auth_kerb
</code></pre></div>
<h4>基本配置</h4>
<ul>
<li><p>/etc/httpd/conf/httpd.conf</p>
<p>apache 有2处配置对最大可处理的请求数进行限制,koji-hub 的 xmlrpc 接口是一个 python 程序,可能由于没有及时回收内存而出现问题,因此强烈建议对2处 <code>MaxRequestsPerChild</code> 都进行限制(该值设为 100 时,httpd 大约在占用大约 75 MB 物理内存之后会创建新的进程):</p>
<div class="highlight"><pre><code class="language-text" data-lang="text"><IfModule prefork.c>
...
MaxRequestsPerChild 100
</IfModule>
<IfModule worker.c>
...
MaxRequestsPerChild 100
</IfModule>
</code></pre></div></li>
<li><p>/etc/httpd/conf.d/kojihub.conf</p>
<p>该文件需要针对安全验证方案进行一些调整,不过需要改动的地方不多,参阅配置文件中的注释信息即可。</p></li>
<li><p>/etc/httpd/conf.d/ssl.conf</p>
<ul>
<li><p>如果使用 SSL 证书验证的话,需要指定证书文件所在位置,以及强制要求对客户端进行 SSL 证书限制,如:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">SSLCertificateFile /etc/pki/koji/certs/kojihub.crt
SSLCertificateKeyFile /etc/pki/koji/certs/kojihub.key
SSLCertificateChainFile /etc/pki/koji/koji_ca_cert.crt
SSLCACertificateFile /etc/pki/koji/koji_ca_cert.crt
SSLVerifyClient require
SSLVerifyDepth 10
</code></pre></div></li>
<li><p>如果使用 Kerberos 验证,则由于没有 SSL 证书,需要调整 SSLVerifyClient 配置项:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">SSLVerifyClient optional
</code></pre></div></li>
</ul></li>
<li><p>/etc/koji-hub/hub.conf</p>
<p>该文件是 Koji-hub 的主要配置文件,首先需要数据库、KojiWebURL等基本信息。关于安全验证方面也在该文件中,后面将进行详细说明。</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">DBName = koji
DBUser = koji
DBPass = mypassword
DBHost = db.example.com
KojiDir = /mnt/koji
LoginCreatesUser = On
KojiWebURL = http://kojiweb.example.com/koji
</code></pre></div></li>
</ul>
<h4>安全验证配置</h4>
<ul>
<li><p>/etc/koji-hub/hub.conf</p>
<ul>
<li><p>使用 Kerberos 验证时</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">AuthPrincipal host/kojihub@EXAMPLE.COM
AuthKeytab /etc/koji.keytab
ProxyPrincipals koji/kojiweb@EXAMPLE.COM
HostPrincipalFormat compile/%s@EXAMPLE.COM
</code></pre></div></li>
<li><p>使用 SSL 证书验证时</p>
<ul>
<li><p>mod_ssl 版本低于 2.3.11 的情况下:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">DNUsernameComponent = CN
ProxyDNs = /C=US/ST=Massachusetts/O=Example Org/OU=kojiweb/CN=example/emailAddress=example@example.com
</code></pre></div></li>
<li><p>mod_ssl 版本不低于 2.3.11 的情况下:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">DNUsernameComponent = CN
ProxyDNs = CN=example.com,OU=kojiweb,O=Example Org,ST=Massachusetts,C=US
</code></pre></div></li>
</ul></li>
</ul></li>
</ul>
<h4>Koji 文件目录</h4>
<p>在上面的配置示例中,<code>KojiDir</code> 设置为 /mnt/koji,如果更改了该路径,仍然需要建立一个 /mnt/koji 软连接指向实际的 Koji 文件目录。在部署 Koji 其他组件之前需要为该目录建立基本的结构,并配置好权限:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">cd /mnt
mkdir koji
cd koji
mkdir {packages,repos,work,scratch}
chown apache.apache *
</code></pre></div>
<h4>配置 SELinux</h4>
<p>如果服务器系统中 SELinux 以 Enforcing 模式运行,则进行一些配置:</p>
<ul>
<li>允许 apache 访问 Postgresql 数据库;</li>
<li>允许 apache 在磁盘上写入某些文件。</li>
</ul>
<p>配置方法参考:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">root@localhost$ setsebool -P httpd_can_network_connect_db=1 allow_httpd_anon_write=1
root@localhost$ chcon -R -t public_content_rw_t /mnt/koji/*
</code></pre></div>
<p>如果 /mnt/koji 是挂载的 NFS 共享目录,则还需要设置 <code>httpd_use_nfs</code>:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">root@localhost$ setsebool -P httpd_use_nfs=1
</code></pre></div>
<h4>检查配置并重启 httpd</h4>
<p>完成上述配置之后,理论上重新启动 apache 服务之后,Koji-hub 应该可以正常工作,可以通过下文即将提到的 koji 命令进行检测。</p>
<h3>koji 命令行工具</h3>
<p>koji 命令行工具是 Koji 系统的标准客户端工具,使用 koji 命令可以完成大部分的工作。</p>
<p>koji 命令默认使用用户配置文件 ~/.koji/config 和全局配置文件 /etc/koji.conf 。</p>
<h4>配置 koji 命令使用 SSL 证书验证</h4>
<p>主要的配置项是 <code>cert</code> 、 <code>ca</code> 、 <code>serverca</code>。举例如下:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">; configuration for SSL athentication
;client certificate
cert = ~/.koji/client.crt
;certificate of the CA that issued the client certificate
ca = ~/.koji/clientca.crt
;certificate of the CA that issued the HTTP server certificate
serverca = ~/.koji/serverca.crt
</code></pre></div>
<p>使用 SSL 验证时,url 地址可以直接使用 ip 地址(如,127.0.0.1):</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">;;url of XMLRPC server
server = http://127.0.0.1/kojihub
;;url of web interface
weburl = http://127.0.0.1/koji
;;url of package download site
topurl = http://127.0.0.1/kojifiles
</code></pre></div>
<h4>配置 koji 命令使用 Kerberos 验证</h4>
<p>使用 Kerberos 验证时,koji 命令的配置文件其实不用做修改,只需要将 SSL 验证相关部分(如果曾经开启的话)注释即可,举例如下:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">[koji]
server = http://koji.zhaochao.eayunos.eayun.com/kojihub
weburl = http://koji.zhaochao.eayunos.eayun.com/koji
topurl = http://koji.zhaochao.eayunos.eayun.com/kojifiles
topdir = /mnt/koji
;the service name of the principal being used by the hub
;krbservice = host
;client certificate
;cert = ~/.koji/client.crt
;certificate of the CA that issued the client certificate
;ca = ~/.koji/clientca.crt
;certificate of the CA that issued the HTTP server certificate
;serverca = ~/.koji/serverca.crt
</code></pre></div>
<p>但是使用 koji 命令之前必须首先完成 Kerberos 的身份验证,获取相关凭证,如:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">$ kinit kadmin
Password for kojiadmin@ZHAOCHAO.EAYUNOS.EAYUN.COM:
# klist
Ticket cache: FILE:/tmp/krb5cc_0
Default principal: kojiadmin@ZHAOCHAO.EAYUNOS.EAYUN.COM
Valid starting Expires Service principal
08/14/14 12:00:58 08/15/14 12:00:55 krbtgt/ZHAOCHAO.EAYUNOS.EAYUN.COM@ZHAOCHAO.EAYUNOS.EAYUN.COM
renew until 08/21/14 12:00:55
</code></pre></div>
<h4>尝试登录 Koji-hub</h4>
<p>使用 koji moshimoshi 命令测试是否可能正常登录到 Koji-hub:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">$ koji moshimoshi
</code></pre></div>
<h3>安装配置 Koji-web</h3>
<h4>安装 koji-web</h4>
<div class="highlight"><pre><code class="language-text" data-lang="text"># yum install koji-web mod_ssl mod_auth_kerb
</code></pre></div>
<h4>基本配置</h4>
<ul>
<li><p>/etc/httpd/conf.d/kojiweb.conf</p>
<p>根据安全验证的类型进行调整,根据配置文件中提供的注释信息进行配置即可。</p>
<ul>
<li><p>koji-web Kerberos 配置</p>
<p>确保 <code>KrbServiceName</code> 、 <code>KrbAuthRealm</code> 、 <code>Krb5Keytab</code> 几项准确无误。</p></li>
<li><p>koji-web SSL 验证</p>
<p>开启 /koji/login 的 SSL 验证。</p></li>
</ul></li>
<li><p>/etc/kojiweb/web.conf</p>
<p>koji-web 的主要配置文件,需要指明 koji-hub 服务、koji 文件目录以及 kojiweb 自身的 url 地址,另外关于安全验证相关的配置也是必须的。</p>
<p>配置文件中的 <code>Secret</code> 需要需要进行配置,指定一个特定的字符串即可。</p>
<ul>
<li><p>配置 Koji-web 使用 SSL 验证</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">WebCert = /etc/pki/koji/kojiweb.pem
ClientCA = /etc/pki/koji/koji_ca_cert.crt
KojiHubCA = /etc/pki/koji/koji_ca_cert.crt
</code></pre></div>
<p>其中 <code>WebCert</code> 对应的文件必须同时包含公钥和私钥信息。</p></li>
<li><p>配置 Koji-web 使用 Kerberos 验证</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">WebPrincipal = kojiweb/koji.zhaochao.eayunos.eayun.com@ZHAOCHAO.EAYUNOS.EAYUN.COM
WebKeytab = /etc/koji.keytab
WebCCache = /var/tmp/kojiweb.ccache
</code></pre></div></li>
</ul></li>
<li><p>文件系统相关配置</p>
<p>为了 Koji-web 可以正常工作,需要对 /mnt/koji 目录的访问权限进行修改,使得不同的组件都可以访问该目录。该目录会在下面这些配置文件中出现:</p>
<ul>
<li>/etc/kojiweb/web.conf 中的 <code>KojiFilesURL</code></li>
<li>/etc/kojid/kojid.conf 中的 <code>topurl</code></li>
<li>/etc/koji.conf 中的 <code>topurl</code></li>
</ul>
<p>apache 的配置如下(注意:针对 apache 的版本不同,访问控制配置的格式也有不同)</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">Alias /kojifiles/ /mnt/koji/
<Directory "/mnt/koji/">
Options Indexes
AllowOverride None
# Apache < 2.4
# Order allow,deny
# Allow from all
# Apache >= 2.4
Require all granted
</Directory>
</code></pre></div></li>
</ul>
<h4>验证 Koji-web 是否可以正常工作</h4>
<p>重启 httpd 服务之后,访问 koji-web 的地址,确认是否可以正常访问、登录以及完成各种操作。</p>
<h3>安装配置Kojid</h3>
<h4>安装 Kojid</h4>
<div class="highlight"><pre><code class="language-text" data-lang="text"># yum install koji-builder
</code></pre></div>
<h4>基本配置</h4>
<ul>
<li><p>将构建主机的信息添加到数据库</p>
<p>使用 koji add-host 命令可以将构建主机的信息添加到 Koji 数据库之后,需要注意的是这一步操作必须在构建主机上 kojid 服务启动之前进行;否则 kojid 启动之后,再想添加主机时,需要手动清理数据库中 sessions 和 users 表中的相关条目,才能成功。</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">$ koji add-host kojibuilder1.example.com i386 x86_64
</code></pre></div>
<p><code>add-host</code> 之后第一个参数时 kojid 使用的用户名,第二部分是 kojid 执行构建任务时支持哪些 cpu 架构。</p></li>
<li><p>/etc/kojid/kojid.conf</p>
<p>kojid 的配置文件。首先需要明确指定 koji-hub 的 url 地址,以及 kojid 访问 koji-hub 使用的用户名:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">; The URL for the xmlrpc server
server=http://hub.example.com/kojihub
; the username has to be the same as what you used with add-host
; in this example follow as below
user = kojibuilder1.example.com
</code></pre></div>
<p>koji 文件目录也需要通过 http 进行访问:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text"># The URL for the file access
topurl=http://koji-filesystem.example.com/kojifiles
</code></pre></div>
<p>kojid 的工作目录可以根据需要更改:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">; The directory root for temporary storage
workdir=/tmp/koji
</code></pre></div>
<p>kojid 的构建根目录也必须该构建服务器上挂载。使用只读挂载的 NFS 目录是比较简单的方案。</p>
<div class="highlight"><pre><code class="language-text" data-lang="text"># The directory root where work data can be found from the koji hub
topdir=/mnt/koji
</code></pre></div></li>
</ul>
<h4>安全验证配置</h4>
<ul>
<li><p>使用 SSL 证书验证</p>
<p>使用 SSL 证书验证时,要在配置文件中指明所有相关的证书文件。</p>
<p>/etc/kojid/kojid.conf:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">;client certificate
; This should reference the builder certificate we created on the kojihub CA, for kojibuilder1.example.com
; ALSO NOTE: This is the PEM file, NOT the crt
cert = /etc/kojid/kojid.pem
;certificate of the CA that issued the client certificate
ca = /etc/kojid/koji_ca_cert.crt
;certificate of the CA that issued the HTTP server certificate
serverca = /etc/kojid/koji_ca_cert.crt
</code></pre></div></li>
<li><p>使用 Kerberos 验证</p>
<p>/etc/kojid/kojid.conf:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">; the username has to be the same as what you used with add-host
;user =
host_principal_format=compile/%s@EXAMPLE.COM
</code></pre></div>
<p>注意:要将 <code>user</code> 注释掉,<code>user</code> 配置项保留的情况下, kojid 不会使用 Kerberos 验证。</p>
<p>默认 kojid 会从 /etc/kojid/kojid.keytab 中获取 Principal 信息然后和 koji-hub 进行通信,可以根据实际情况调整 keytab 文件位置:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">keytab = /etc/kojid/kojid.keytab
</code></pre></div></li>
</ul>
<h4>配置通过 SCM 构建软件包(可选)</h4>
<ul>
<li><p>/etc/kojid/kojid.conf</p>
<p>SCM 地址的格式是: hostname:/path/match:checkout /common?, hostname2:/path/match:checkout /common?</p>
<p>checkout /common 是一个布尔值,默认为 true,举例如下:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">allowed_scms=scm-server.example.com:/repo/base/repos*/:false
</code></pre></div>
<p>使用上述配置时,当 kojid 把代码库 checkout 之后,会进行下面的操作:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">make sources
mv *.spec <rpmbuild>/SPECS
mv * <rpmbuild>/SOURCES
rpmbuild -bs <rpmbuild>/SPECS/*.spec
</code></pre></div></li>
</ul>
<h4>将主机添加到 createrepo 通道(channel)中</h4>
<p>通道(channel) 是用来控制构建主机可以执行哪些构建任务的。默认情况下,所有构建主机都会加入到 <code>default</code> 通道。但是至少需要一些构建主机加入到 <code>createrepo</code> 通道,它们可以完成 kojira 发起的创建软件包仓库的任务。</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">$ koji add-host-to-channel kojibuilder1.example.com createrepo
</code></pre></div>
<h4>关于构建主机容量( capacity )参数的说明</h4>
<p>添加构建主机时,默认的容量为 2 ,含义是如果该构建主机的 load average 大于 2 时, kojid 将不再接受新的任务。该配置和 kojid 配置文件中的 <code>maxjobs</code> 配置项是不同的。当 kojid 接受新的任务时,需要满足系统 load average 小于 capacity,同时同时执行的任务数不能超过 maxjobs 。不过由于服务器硬件配置的不断增强,可以根据实际情况调整 capacity 的大小:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">koji edit-host --capacity=16 kojibuilder1.example.com
</code></pre></div>
<h4>启动 kojid</h4>
<p>当构建主机添加到 Koji 系统,配置完成之后,可以启动 kojid 服务:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text"># service kojid start
</code></pre></div>
<p>检查 kojid 的日志文件 <code>/var/log/kojid.log</code> 确认 kojid 是否已经启动成功。启动成功之后,可以通过 koji-web 的界面查看主机列表中各构建主机的状态和信息。</p>
<h3>安装配置 Kojira</h3>
<h4>安装 Kojira</h4>
<div class="highlight"><pre><code class="language-text" data-lang="text"># yum install koji-utils
</code></pre></div>
<h4>基本配置</h4>
<ul>
<li><p>为 kojira 添加用户</p>
<p>kojira 用户需要拥有 <code>repo</code> 权限:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">$ koji add-user kojira
$ koji grant-permission repo kojira
</code></pre></div>
<p>在 /etc/kojira/kojira.conf 中添加 koji-hub 的 url 地址:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">; The URL for the xmlrpc server
server=http://koji-hub.example.com/kojihub
</code></pre></div></li>
<li><p>其他说明:</p>
<ul>
<li>kojira 对 /mnt/koji 要有读写权限;</li>
<li>kojira 只能同时运行一个示例;</li>
<li>不建议将 kojira 和 kojid 放在相同的服务器,因为 kojid 对 /mnt/koji 只需要读权限;</li>
<li>添加新的 tag 时,kojira 可能需要重启才能正确识别。</li>
</ul></li>
</ul>
<h4>安全验证配置</h4>
<ul>
<li><p>使用 SSL 证书验证</p>
<p>/etc/kojira/kojira.conf 示例:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">;client certificate
; This should reference the kojira certificate we created above
cert = /etc/pki/koji/kojira.pem
;certificate of the CA that issued the client certificate
ca = /etc/pki/koji/koji_ca_cert.crt
;certificate of the CA that issued the HTTP server certificate
serverca = /etc/pki/koji/koji_ca_cert.crt
</code></pre></div></li>
<li><p>使用 Kerberos 验证</p>
<p>/etc/kojira/kojira.conf 示例:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">; For Kerberos authentication
; the principal to connect with
principal=koji/kojira@EXAMPLE.COM
; The location of the keytab for the principal above
keytab=/etc/kojira.keytab
</code></pre></div></li>
<li><p>/etc/sysconfig/kojira</p>
<p>kojira 程序对 /mnt/koji/repos 目录要有读写权限,如果该目录的权限无法调整(比如配置了 root_squash 的 NFS 共享目录等),可以在 /etc/sysconfig/kojira 中配置 RUNAS= 指定的用户来获取需要的权限。</p></li>
</ul>
<h4>启动 Kojira</h4>
<div class="highlight"><pre><code class="language-text" data-lang="text">$ service kojira start
检查 kojira 日志 `/var/log/kojira.log` 确认是否已经正常启动。
</code></pre></div>
<h2>使用 Koji</h2>
<p>Koji 提供的功能不少,根据不同的环境、不同的需求可以设计不同的系统方案,这里只对最基本的使用进行介绍。</p>
<h3>确定是否使用外部软件仓库</h3>
<p>Koji 构建软件包时使用 mock,构建过程中利用了 chroot 环境,因此涉及到构建过程依赖的软件包如何安装的问题。有 2 种情况:</p>
<ul>
<li><p>导入已有的软件包</p>
<p>使用 koji import 命令可以将已有的 srpm 和 rpm 包导入到 Koji 系统,其他软件包基于这些软件包进行构建;</p></li>
<li><p>使用外部软件仓库</p>
<p>使用 koji add-external-repo 命令添加外部软件仓库,构建软件包时依赖的软件包从外部仓库中获取并安装。</p></li>
</ul>
<p>使用哪一种方式要根据具体的需求决定,后面的文档将基于使用外部软件仓库的情形进行说明。</p>
<h3>建立 tag 和 target</h3>
<p>tag 是用来建立 Koji 工作流程的,对于最建单的情况,需要建立软件包最终发布所属的 tag :</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">$ koji add-tag EayunOS-4-0
</code></pre></div>
<p>接下来为具体的构建过程创建 tag :</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">$ koji add-tag --parent EayunOS-4-0 --arches "i686 x86_64" EayunOS-4-0-build
</code></pre></div>
<p>Koji 构建软件包时使用的是 target,target 决定了构建过程在何处进行(构建过程对应的 tag ),以及构建产生的结果如何标记(目标 tag),所以需要继续建立 target :</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">$ koji add-target EayunOS-4-0 EayunOS-4-0-build
</code></pre></div>
<p>使用 koji add-target 时,最多可以使用 3 个参数,分别对应 target 名称、构建过程对应的 tag、目标 tag。在上面的示例中,最后的目标 tag 省略了,这时目标 tag 默认使用和 target 名称相同的 tag ,即,上述命令中 EayunOS-4-0 是 target,该命令其实表示的是:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">$ koji add-target EayunOS-4-0 EayunOS-4-0-build EayunOS-4-0
</code></pre></div>
<h3>添加外部软件仓库</h3>
<p>外部软件仓库需要添加到构建过程对应的 tag :</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">$ koji add-external-repo -t EayunOS-4-0-build centos6-base-repo \
http://192.168.3.239/mirrors/CentOS/6.5/os/$arch/
$ koji add-external-repo -t EayunOS-4-0-build centos6-update-repo \
http://192.168.3.239/mirrors/CentOS/6.5/updates/$arch/
</code></pre></div>
<h3>创建构建相关的软件包组</h3>
<p>在 Koji 系统中可以对软件包进行分组,其中有 2 个比较特殊的软件包组: <code>build</code> 和 <code>srpm-build</code> 。Koji 的构建过程使用 chroot 环境,建立该 chroot 环境时需要要装一些基本的软件包才能完成构建工作。根据构建任务的不同(这里只说明 rpm 和 source rpm 的情况),构建 rpm 包时,建立 chroot 环境的过程中会安装 build 软件包组的所有软件包;构建 source rpm 包时,建立 chroot 环境的过程中会安装 srpm-build 软件包组中的所有软件包。</p>
<p>因此必须首先建立这 2 个软件组,同时软件组中的软件包选择也需要注意。因此 koji 每次构建都会新建 chroot 环境,如果要安装太多的软件包,会影响整个构建过程的时间,当然如果构建过程中需要的软件包不会在创建 chroot 环境时安装(而且也不在该软件包的依赖关系中)则构建过程会失败。</p>
<h4>创建 build 和 srpm-build 软件包组</h4>
<div class="highlight"><pre><code class="language-text" data-lang="text">$ koji add-group EayunOS-4-0-build build
$ koji add-group EayunOS-4-0-build srpm-build
</code></pre></div>
<h4>为 build 和 srpm-build 添加软件包</h4>
<div class="highlight"><pre><code class="language-text" data-lang="text">$ koji add-group-pkg EayunOS-4-0-build build bash bzip2 coreutils diffutils \
findutils gawk gcc grep gzip make patch rpm-build shadow-utils tar \
util-linux-ng which
$ koji add-group-pkg EayunOS-4-0-build srpm-build bash bzip2 gzip rpm-build \
rpmdevtools shadow-utils tar
</code></pre></div>
<h4>为构建过程 tag 重建 repo 信息</h4>
<div class="highlight"><pre><code class="language-text" data-lang="text">$ koji regen-repo EayunOS-4-0-build
</code></pre></div>
<h3>测试构建环境是否可用</h3>
<p>koji build 命令会创建并启动软件包构建任务,加上 --scratch 参数可以用来测试构建任务,而不会干扰正常的 koji 工作流程。</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">$ koji build --scratch eayunos-release-4-0.el6.2.src.rpm
</code></pre></div>
<h3>开始构建软件包</h3>
<p>首先将软件包添加到目标 tag 的软件包列表(注意只需要软件包名称即可,即 Koji 架构术语中的 Package ):</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">$ koji add-pkg --owner zhaochao EayunOS-4-0 eayunos-release
</code></pre></div>
<p>然后就可以开始构建软件包了</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">$ koji build EayunOS-4-0 eayunos-release-4-0.el6.2.src.rpm
</code></pre></div>
<h3>从 SCM 代码仓库构建软件包</h3>
<p>除了只是通过 srpm 构建软件包之外,Koji 系统还是从 SCM 代码仓库中构建软件包。要从 SCM 代码仓库中构建软件包,首先需要对 kojid 进行配置,允许 kojid 从指定的 SCM 地址构建,配置方法见 kojid 的安装配置部分。</p>
<p>举例说明:</p>
<p>/etc/kojid/kojid.conf</p>
<div class="highlight"><pre><code class="language-text" data-lang="text"> allowed_scms=192.168.3.239:*:no
</code></pre></div>
<p>koji build 从 SCM 代码仓库构建软件包的命令中,url 地址的格式是:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">scheme://[user@]host/path/to/repo?path/to/module#revision_or_tag_identifier
</code></pre></div>
<p>举例说明:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">koji build --scratch EayunOS-4-0 'git+http://192.168.3.239/git/virt-viewer-win-koji.git?.#HEAD'
</code></pre></div>
<p>需要注意的是,url 地址中除了代码仓库的地址以外需要指定代码所在的目录以及代码 revision 。另外地址的协议头也有特定的格式,目前支持以下组合:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">cvs://, cvs+ssh://
git://, git+http://, git+https://, git+rsync://, git+ssh://
svn://, svn+http://, svn+https://, svn+ssh://
</code></pre></div>
<p>在 kojid 安装配置部分已经说过代码从 SCM 服务器 checkout 之后,会自动完成一些操作,其中第一步是生成构建 srpm 需要的压缩包。 kojid 默认执行的命令是 make source,当然可以通过配置让 kojid 执行其他的命令,比如 <code>fedpkg sources</code>,那么上例就改成:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">allowed_scms=192.168.3.239:*:no:fedpkg,sources
</code></pre></div>
<p>默认的情况下 kojid 执行 make sources ,因此需要在代码所在的目录下编写一个 Makefile,例如如:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">package = virt-viewer-win
src_pkgs = $(shell spectool -l $(package).spec | awk '{print $$NF}')
sources:
tar zcf $(src_pkgs) virt-viewer-win
</code></pre></div>
<h2>原文链接</h2>
<ol>
<li><a href="https://fedorahosted.org/koji/wiki">koji - RPM building and tracking system</a></li>
<li><a href="https://fedoraproject.org/wiki/Koji">Koji wiki</a></li>
<li><a href="https://fedoraproject.org/wiki/Koji/ServerHowTo">Koji/ServerHowTo</a></li>
<li><a href="http://www.devops-blog.net/category/koji">devops-blog 上的 koji系列博客</a></li>
</ol>
/Ceph-Calamari
(旧文)安装部署Ceph Calamari
2014-07-29T15:32:01+08:00
2014-07-29T15:32:01+08:00
<p>本文最开始提交在这里:</p>
<p><a href="http://ovirt-china.org/mediawiki/index.php/%E5%AE%89%E8%A3%85%E9%83%A8%E7%BD%B2Ceph_Calamari">http://ovirt-china.org/mediawiki/index.php/安装部署Ceph_Calamari</a></p>
<h3>一、安装</h3>
<h4>1、获取calamari相关代码</h4>
<div class="highlight"><pre><code class="language-text" data-lang="text"># git clone https://github.com/ceph/calamari.git
# git clone https://github.com/ceph/calamari-clients.git
# git clone https://github.com/ceph/Diamond
</code></pre></div>
<h4>2、生成calamari-server安装包</h4>
<div class="highlight"><pre><code class="language-text" data-lang="text"># yum install gcc gcc-c++ postgresql-libs python-virtualenv
# cd calamari && ./build-rpm.sh
</code></pre></div>
<h4>3、安装calamari-server</h4>
<div class="highlight"><pre><code class="language-text" data-lang="text"># yum localinstall ../rpmbuild/RPMS/x86_64/calamari-server-<version>.rpm
</code></pre></div>
<p>使用yum可以自动解决依赖,如果手动安装依赖的可以这样:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text"># yum install postgresql-server salt-master salt-minion supervisor
# rpm -ivh ../rpmbuild/RPMS/x86_64/calamari-server-<version>.rpm
</code></pre></div>
<h4>4、生成calamari-clients安装包</h4>
<div class="highlight"><pre><code class="language-text" data-lang="text"># yum install npm ruby rubygems
# npm install -g grunt grunt-cli bower grunt-contrib-compass
# gem update --sytem && gem install compass
# cd calamari-clients
# make build-real
# make dist
</code></pre></div>
<p>make dist会在上级目录生成calamari-client的压缩包</p>
<p>手动解压缩,建立mkdir -p opt/calamari/webapp</p>
<p>在解压生成的目录下,手动更新目录结构和内容</p>
<div class="highlight"><pre><code class="language-text" data-lang="text"># for dir in manage admin login dashboard
> do
> mkdir -p ../opt/calamari/webapp/content/"$dir"
> cp -pr "$dir"/dist/* ../opt/calamari/webapp/content/"$dir"/
> done
</code></pre></div>
<p>重新制作压缩包,然后根据Makefile里面的rpm target手动执行rpmbuild</p>
<div class="highlight"><pre><code class="language-text" data-lang="text"># rpmbuild -bb --define "_topdir /xxx/calamari-clients/../rpmbuild" \
--define "version 1.2" --define "revision rc2_49_g3e3686d" --define \
"tarname /xxx/rpmbuild/SOURCES/calamari-clients_product_1.2.tar.gz" \
SPECS/clients.spec
</code></pre></div>
<h4>5、安装calamari-clients</h4>
<div class="highlight"><pre><code class="language-text" data-lang="text"># yum localinstall RPMS/x86_64/calamari-clients-1.2-rc2_49_g3e3686d.el6.x86_64.rpm
</code></pre></div>
<h4>6、初始化calamari</h4>
<div class="highlight"><pre><code class="language-text" data-lang="text"># calamari-ctl initialize
</code></pre></div>
<p>这一步在最后重启服务(主要是cthulhu)的时候一直没有结束,根据搜索到的信息,说是supervisord的问题,升级到3.0以上就不会有问题了。</p>
<h4>7、生成diamond安装包</h4>
<div class="highlight"><pre><code class="language-text" data-lang="text"># cd ../Diamond
# git checkout origin/calamari
# make rpm
</code></pre></div>
<h4>8、将diamond-<version>.noarch.rpm复制到所有的ceph服务器</h4>
<p>使用<code>yum localinstall</code>安装,或者<code>yum install python-configobj</code>然后使用<code>rpm -ivh</code>安装。</p>
<h4>9、在所有的ceph服务器上安装salt-minion,创建/etc/salt/minion.d/calamari.conf,内容为:</h4>
<div class="highlight"><pre><code class="language-text" data-lang="text">master: {fqdn}
</code></pre></div>
<p>{fqdn}对应calamari服务器的域名。</p>
<p>启动salt-minion服务:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text"># service salt-minion restart
</code></pre></div>
<h4>10、在Calamari服务器上配置防火墙和saltstack认证</h4>
<p>防火墙(允许ceph服务器访问salt-master和carbon):</p>
<p><strong>salt-master</strong></p>
<div class="highlight"><pre><code class="language-text" data-lang="text"># iptables -A INPUT -m state --state NEW -m tcp -p tcp --dport 4505 -j ACCEPT
# iptables -A INPUT -m state --state NEW -m tcp -p tcp --dport 4506 -j ACCEPT
</code></pre></div>
<p><strong>carbon</strong></p>
<div class="highlight"><pre><code class="language-text" data-lang="text"># iptables -A INPUT -m state --state NEW -m tcp -p tcp --dport 2003 -j ACCEPT
# iptables -A INPUT -m state --state NEW -m tcp -p tcp --dport 2004 -j ACCEPT
</code></pre></div>
<p><strong>saltstack认证:</strong></p>
<p>当ceph服务器上的salt-minion服务启动之后,会自动向salt-master请求认证。</p>
<p>在Calamari服务器上可以通过下面的命令查看salt-minion密钥的列表:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text"># salt-key -L
</code></pre></div>
<p>刚刚启动salt-minion服务的ceph服务器会出现在Unaccepted Keys列表之后,要使得Calamari能够通过saltstack管理ceph服务器,需要对这些密钥进行认证:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text"># salt-key -A
</code></pre></div>
<h4>11、部署完成之后,可以访问calamari</h4>
<h3>二、后期发现的问题:</h3>
<h4>1、SELinux导致500错误:</h4>
<p>由于SELinux的限制,访问页面时会出现500错误,原因是httpd<em>t对于anon</em>inodefs_t没有写入权限,可以根据审计日志生成SELinux模块:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text"># ausearch -m avc -c httpd -se httpd_t -o anon_inodefs_t | audit2allow \
-R -M httpd_anon_inodefs
# semodule -i httpd_anon_inodefs.pp
</code></pre></div>
<p>生成的SELinux模块规则如下:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">require {
type httpd_t;
}
#============= httpd_t ==============
fs_rw_anon_inodefs_files(httpd_t)
</code></pre></div>
<h4>2、打开Manage --> OSD页面无内容</h4>
<p>查看calamari.log看到了异常,原因是httpd没有权限访问/etc/salt/master,修改权限临时解决。</p>
<h4>3、打开Manage --> Logs页面无内容</h4>
<p>查看日志,发现是访问http://xxx.xxx.xxx.xxx/api/v2/cluster/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/log发生503错误:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">HTTP 503 SERVICE UNAVAILABLE
Vary: Accept
Content-Type: text/html; charset=utf-8
Allow: GET, HEAD, OPTIONS
{
"detail": "No mon servers are responding"
}
</code></pre></div>
<p>经过研究还是SELinux的限制,通过ausearch配合audit2allow生成相应的模块,可以解决问题。</p>
<p>生成的SELinux模块的规则如下:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">require {
type var_run_t;
type httpd_t;
class sock_file { write getattr };
}
#============= httpd_t ==============
allow httpd_t var_run_t:sock_file { write getattr };
files_read_var_files(httpd_t)
init_stream_connect_script(httpd_t)
</code></pre></div>
<h4>4、打开graphite/dashboard/页面出现HTTP 500错误</h4>
<p>日志中提示找不到graphite的模板,在calamari的bug列表中找到对应的说明——<a href="http://tracker.ceph.com/issues/8669">http://tracker.ceph.com/issues/8669</a>。</p>
<p>解决方法是:</p>
<p>在/opt/calamari/venv/lib/python2.6/site-packages下找到<code>calamari_web</code>的egg文件,解压缩之后手动修改calamari_web/settings.py,然后重新打包。</p>
<p>重启apache之后可以访问graphite/dashboard/。 </p>
/TeX-export-to-pictures
Tip:将TeX绘制的图像输出成图片文件
2014-07-16T16:41:57+08:00
2014-07-16T16:41:57+08:00
<p>画图并是不每个人都擅长的事情,很多时候更希望关注于内容,而不是展现的形式,所以连画图都希望使用TeX解决。</p>
<p>主要的参考在这里:</p>
<p><a href="http://tex.stackexchange.com/questions/51757/how-can-i-use-tikz-to-make-standalone-svg-graphics">http://tex.stackexchange.com/questions/51757/how-can-i-use-tikz-to-make-standalone-svg-graphics</a></p>
<p>大概说明一下:</p>
<ul>
<li>使用 <code>standalone</code> 包,加上 <code>convert</code> 选项,在生成pdf时自动完成 pdf --> png、svg 等的转换;</li>
<li>转换为 svg 时,使用 <code>convert=pdf2svg</code> ,系统要安装 <code>pdf2svg</code> 软件包,一张图片的话(即 TeX 文档只有一页)再加上 <code>multi=false</code> ;</li>
<li>使用 pdflatex ( xelatex )时,加上 <code>-shell-escape</code> 参数。</li>
</ul>
<p>举个例子:</p>
<p>test.tex:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">\documentclass[tikz,convert=pdf2svg,multi=false]{standalone}
%\usetikzlibrary{...}% tikz package already loaded by 'tikz' option
\begin{document}
\begin{tikzpicture}% Example:
\draw (0,0) -- (10,10); % ...
\draw (10,0) -- (0,10); % ...
\node at (5,5) {Lorem ipsum at domine standalonus};
\end{tikzpicture}
\end{document}
</code></pre></div>
<p>生成 pdf 和 svg:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">$ xelatex -shell-escape test.tex
</code></pre></div>
/sphinx-xetex
使用 XeTeX 为 Sphnix 输出 PDF 格式的文档
2014-07-10T23:33:36+08:00
2014-07-10T23:33:36+08:00
<p>Sphinx 生成 PDF 输出时,使用的pdflatex + inputenc,当文档出现 UTF8 字符时,make latexpdf 就会出错,如:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">! Package inputenc Error: Unicode char \u8:工 not set up for use with LaTeX.
</code></pre></div>
<p>解决的办法是使用 XeTeX 替换 pdflatex:</p>
<ul>
<li><p>从 TeX 源文件中删去 inputenc 相关的配置</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">\usepackage[utf8]{inputenc}
\DeclareUnicodeCharacter{00A0}{\nobreakspace}
</code></pre></div></li>
<li><p>在 TeX 源文件的 <code>\title</code> 之前加入 XeTeX 相关的配置</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">\usepackage{xeCJK}
\setCJKmainfont{WenQuanYi Micro Hei}
\setCJKmonofont{WenQuanYi Micro Hei Mono}
</code></pre></div>
<p>后面2行中的字体名称根据环境中实际安装的字体进行调整。</p></li>
<li><p>最后,使用 xelatex 命令生成 PDF 文件</p>
<div class="highlight"><pre><code class="language-text" data-lang="text"># xelatex *.tex
</code></pre></div></li>
</ul>
<p>上述步骤中对 TeX 源文件的修改也可以通过修改配置在 sphnix 生成 TeX 源文件时完成。</p>
<p>修改 conf.py 中 latex_elements 配置项,如:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">latex_elements = {
'inputenc': '',
'preamble': '''
\usepackage{xeCJK}
\setCJKmainfont{WenQuanYi Micro Hei}
\setCJKmonofont{WenQuanYi Micro Hei Mono}
''',
}
</code></pre></div>
<p>不过使用上述配置时,生成的 TeX 源文件中</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">\DeclareUnicodeCharacter{00A0}{\nobreakspace}
</code></pre></div>
<p>会保留,导致 xelatex 执行失败,仍然需要手动删除。</p>