2014年7月

深入理解yum工作原理

前言

在前面一篇rpm包制作描述了rpm的打包过程,这篇文章主要讲述yum的工作原理。

yum 运行原理

yum的工作需要两部分来合作,一部分是yum服务器,还有就是client的yum工具。下面分别介绍两部分工作原理。

  • yum服务器

    所有要发行的rpm包都放在yum服务器上以提供别人来下载,rpm包根据kernel的版本号,cpu的版本号分别编译发布。yum服务器只要提供简单的下载就可以了,ftp或者httpd的形式都可以。yum服务器有一个最重要的环节就是整理出每个rpm包的基本信息,包括rpm包对应的版本号,conf文件,binary信息,以及很关键的依赖信息。在yum服务器上提供了createrepo工具,用于把rpm包的基本概要信息做成一张"清单",这张"清单""就是描述每个rpm包的spec文件中信息。

  • yum client端

    client每次调用yum install或者search的时候,都会去解析/etc/yum.repos.d下面所有以.repo结尾的配置文件,这些配置文件指定了yum服务器的地址。yum会定期去"更新"yum服务器上的rpm包"清单",然后把"清单"下载保存到yum自己的cache里面,根据/etc/yum.conf里配置(默认是在/var/cache/yum下面),每次调用yum装包的时候都会去这个cache目录下去找"清单",根据"清单"里的rpm包描述从而来确定安装包的名字,版本号,所需要的依赖包等,然后再去yum服务器下载rpm包安装。(前提是不存在rpm包的cache)

- 阅读剩余部分 -

rpm包制作

rpm包命名规范

对于rpm包的命名符合如下规范。

%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}.rpm

NAME: rpm包名字
VERSION: rpm包版本号(主版本号.次版本号.测试号)
RELEASE: rpm包编译发布次数(第几次编译发布)
ARCH: cpu架构(比如i386和x86_64,i386兼容x86_64,noarch的代表一些列脚本)

比如nginx-1.4.0-24.x86.rpm,nginx-1.4.0-24.x86_64.rpm

实现目标

有一个test.py,去读取当前conf目录下的test.conf文件中的版本号,然后1秒打印一次日志到/tmp/test_rpm.log

---------test.py------------
#!/usr/bin/python

print "Hello World"
    
--------conf/test.conf------------
Version=0.1

再看下路径结构

.
|-- conf
|   `-- test.conf
`-- test.py

制作成一个rpm包,安装之后出现这样的目录结构

/usr/local/rpm_test
.
|-- conf
|   `-- test.conf
`-- test.py

基础环境

制作rpm包是通过rpmbuild来生成的。

安装rpmbuild工具
$ sudo yum install rpm-build

$ rpmbuild --version
RPM version 4.4.2.3

建立独立的打包目录
$ cat >${HOME}/.rpmmacros << EOF
%_topdir $HOME/rpmbuild
EOF
$ mkdir ${HOME}/rpmbuild/
$ cd ${HOME}/rpmbuild/
$ mkdir BUILD  RPMS  SOURCES  SPECS  SRPMS

1. 把要打包的配置文件放到 ${HOME}/rpmbuild/SOURCES/ 下面
2. 在${HOME}/rpmbuild/SPEC下面建立一个test.spec文件,建立好后目录如下
.
|-- BUILD
|-- RPMS
|-- SOURCES
|   |-- test.conf
|   `-- test.py
|-- SPECS
|   `-- test.spec
`-- SRPMS

编写spec文件

spec文件是打rpm包的关键环节,spec文件里指定了rpm包的基本信息,安装好后的环境

Name:         rpm_test
Version:      0.0.1
Release:      3
Buildarch:    noarch
Group:        tools
Summary:      rpm_test
License:      Commercial
BuildArch:     noarch
BuildRoot:    %{_buildrootdir}
Prefix:       /usr/local/rpm_test
AutoReqProv:  no

%define _build_name_fmt     %%{NAME}-%%{VERSION}-%%{RELEASE}-%%{ARCH}.rpm
#编译需要的依赖
#BuildRequires: gcc,make,gcc-c++,pcre-devel
#安装运行需要的依赖
Requires:     python >= 2.4.3

Source0:           test.py
Source1:           test.conf

#description 软件详细描述,可多行
%description
rpm_test by Wanghua

#解压源文件
%prep
#%setup -q

#build 开始编译软件,如make
%build

#install 开始安装软件,如make install
%install
rm -rf ${buildroot}

#建立目录
install -p -d -m 0755 %{buildroot}%{prefix}
install -p -d -m 0755 %{buildroot}%{prefix}/conf

#copy文件
install -p -m 0755 %{SOURCE0} %{buildroot}%{prefix}
install -p -m 0755 %{SOURCE1} %{buildroot}%{prefix}/conf

%files
%defattr(-,root,root,-)
%{prefix}/conf
%{prefix}/test.py

#%config(noreplace) %{prefix}/conf/test.conf

#封装rpm包后清空虚拟根目录
%clean
rm -rf %{buildroot}
 
#rpm安装前执行命令,$1==1其中1代表安装,0代表卸载
%pre
if [ $1==1 ]; then
   echo "Now start install rpm package."
fi
 
#rpm包安装后执行命令
%post
if [ $1==1 ]; then
   echo "/sbin/chkconfig --add rpm_test"
fi

#rpm包卸载前
%postun
rm -rf %{prefix}

#rpm包卸载后执行命令
%preun
if [ $1==0 ]; then
    echo "rpm pkg has been remove"
    echo "/sbin/chkconfig --del rpm_test"
fi

%changelog
* Tue Jul 17 2014 firefoxbug
+ rpm test

生成rpm包

$ rpmbuild -bb test.spec

.
|-- BUILD
|-- RPMS
|   `-- noarch
|       `-- rpm_test-0.1-20140716.noarch.rpm
|-- SOURCES
|   |-- test.conf
|   `-- test.py
|-- SPECS
|   `-- test.spec
`-- SRPMS

查看rpm包相关信息

查看安装信息(已经安装)
$ rpm -ql rpm_test
/usr/local/rpm_test/conf
/usr/local/rpm_test/conf/test.conf
/usr/local/rpm_test/test.py

查看rpm包
$rpm -qlp rpm_test-0.1-20140716.noarch.rpm
/usr/local/rpm_test/conf
/usr/local/rpm_test/conf/test.conf
/usr/local/rpm_test/test.py

查看rpm包安装前后执行的脚本,其实就是spec文件的几个部分

$ rpm -qpl --scripts rpm_test-0.1-20140716.noarch.rpm
preinstall scriptlet (using /bin/sh):
if [ $1==1 ]; then
   echo "Now start install rpm package."
fi

#rpm包安装后执行命令
postinstall scriptlet (using /bin/sh):
if [ $1==1 ]; then
   echo "/sbin/chkconfig --add rpm_test"
fi

#rpm包卸载前
preuninstall scriptlet (using /bin/sh):
if [ $1==0 ]; then
    echo "rpm pkg has been remove"
    echo "/sbin/chkconfig --del rpm_test"
fi
postuninstall scriptlet (using /bin/sh):
rm -rf /usr/local/rpm_test

#rpm包卸载后执行命令
/usr/local/rpm_test/conf
/usr/local/rpm_test/conf/test.conf
/usr/local/rpm_test/test.py

rpm包指定格式输出

$ rpm -qa --queryformat  "%{NAME}_|-%{VERSION}_|-%{RELEASE}_|-%{ARCH}\n"
python-simplejson_|-2.0.3_|-3.el5_|-x86_64

根据文件查询所在的rpmbao

$rpm -qf /path/nginx.conf

参考文档

rpm包制作 http://my.oschina.net/sylee/blog/167640

RPM包制作原理 http://my.oschina.net/guol/blog/182310

Nginx实现TCP反向代理

之前对于Nginx的理解一直都是认为是基于HTTP层的反向代理+负载均衡,今天想用Nginx实现TCP层的反向代理,实现基于TCP的端口转发,之前一篇文章iptables实现tcp端口转发已经用iptables实现了。

安装

$ git clone git@github.com:yaoweibin/nginx_tcp_proxy_module.git
$ wget http://tengine.taobao.org/download/tengine-2.0.3.tar.gz
$ tar -zxvf  tengine-2.0.3.tar.gz
$ cd tengine-2.0.3
这一步很重要,根据Ngx的源码打patch,不然就会编译失败
$ patch –p1 < /path/nginx_tcp_proxy_module
$ ./configure  --user=www --group=www --prefix=/opt/nginx --with-syslog --add-module=/path/nginx_tcp_proxy_module/
$ make && sudo make install

TCP反向代理配置

模块指令是TCP,它是不属于HTTP框架内的,所以和HTTP{}同级别。

events {
    worker_connections  1024;
}

http {
    ...
}

tcp {

    upstream firefoxbug {
        # simple round-robin
        server localhost:2221;
        server localhost:2222;
        check interval=3000 rise=2 fall=5 timeout=1000;

        #check interval=3000 rise=2 fall=5 timeout=1000 type=ssl_hello;

        #check interval=3000 rise=2 fall=5 timeout=1000 type=http;
        #check_http_send "GET / HTTP/1.0\r\n\r\n";
        #check_http_expect_alive http_2xx http_3xx;
    }

    server {
        listen 9999;
        proxy_pass firefoxbug;
    }
}

upstream的模块依赖是Ngx之前HTTP反向代理的模块,对于负载均衡的方式配置可以查看Nginx Upstream负载均衡模块

结果

所有到Nginx的9999端口都被转发到22221和22222端口,实现了forward功能。