 | 级别: 初级 吴 志勇, 软件工程师, IBM
2009 年 10 月 21 日 系统升级与更新是 Unix/Linux 系统管理中一个非常重要的组成部分。它可以增强系统的功能,让系统更好地发挥起最大性能,同时也能修补系统的漏洞 , 增强系统的稳定性和安全性,防止系统遭到病毒或黑客的攻击与破坏。一般来说,不同的操作系统系统都采用了不一样的系统升级与更新方法。本文将介绍 Unix/Linux 操作系统上几种常用的系统升级与更新方法,并在针对于它们的自动化脚本实现方面作了一些尝试,希望对读者能起到一些抛砖引玉的作用。
 | |
您可以通过访问"系列文章:Unix/Linux 系统自动化管理”来了解更多和自动化管理相关的内容:
|
|
几种升级与更新方法介绍
系统自动化升级与更新是操作系统所应具备的一项目重要功能。Unix/Linux 当前主流的系统更新方式主要有以下几种:
NIM
NIM(Network Installation Manager),是 AIX 系统上提供的管理软件安装的服务器。NIM 采用的是常见的 server/client 架构,一个 NIM 环境中需要至少一台 master 控制机,以及另外的需要安装部署的客户机。其中,master 上包含了安装所需要的各种资源,比如安装介质,客户机信息,安装配置文件等等,主控机就根据这些资源,为不同的客户机安装不同的操作系统及软件。
NIM 安装管理器不仅仅能够按照 AIX 操作系统,还可以按照 linux 操作系统及 rpm 软件包,其他的操作系统还不能支持。因此,NIM 可以支持 bff 和 rpm 软件包的安装与更新。
与其他操作系统所提供的自动安装程序相比,NIM 带有更为强大的功能,它不仅能够实现操作系统的自动安装,还可以任意安装任意的第三方程序,既可以在客户机安装操作系统的时候安装,也可以在操作系统安装后安装,只需要在 master 上指定软件包的位置和安装列表,所有的客户机可以同时安装它们。此外,NIM 还支持使用操作系统镜像来安装,NIM 会备份一个已经装好的操作系统的 rootvg,然后将其恢复到其他的客户机上,并且根据客户机的定义,更新主机名、IP 等信息,而且可以使用备份包含的其他软件程序。
在 NIM 中,所有的东西都是资源(resource):客户机是资源,里面包含了客户机的主机名、IP 等信息;安装介质是资源,包含了安装介质的位置;bundle 是资源,决定了安装软件包的列表,脚本也是资源,决定了安装工程中或者系统启动过程中执行的脚本。NIM 就是由这许许多多的资源组合起来的安装环境,用户可以将指定的资源部署到指定的客户机上。
nim -o <operation> [-F] [-t <type>] [ -S <YYMMDDhhmm> ] [-a <attr=value>]... <object name>
NIM 命令各选项含义如下:
|
列 名
|
含 义
|
|---|
|
-o <operation>
|
要进行的操作
| |
[-t <type>]
|
资源的类型
| |
[ -S <YYMMDDhhmm> ]
|
指明时间
| |
[-a <attr=value>]
|
资源属性
| |
<object name>
|
对象名
|
NIM 命令使用示例:
localhost# nim -o define -t lpp_source -a server=master -a \
location==/export/lpp_source/lpp_aix5.3 lpp_aix5.3
|
Yum
Yum 是 RedHat/Fedora 推荐、SuSE 也支持的一种升级与更新软件包的管理工具,在系统安装时一般都默认安装,包括文本命令行式与图形化两种操作模式。
它的主要功能包括:安装软件、更新、移除、搜索软件包与更新系统。
使用 Yum 时,应指定一个操作,以及一个或多个软件包 / 软件组。你可以对不同的软件来源进行选择:软件仓库或者单独的软件包;当选择从软件仓库进行安装新软件时,对于每个操作,Yum 都要从已配置的仓库中下载最新的软件包信息。如果网络连接比较慢,yum 会用数秒钟来下载仓库的索引以及软件包的文件头。
为得到所需的结果,Yum 工具搜索这些数据文件,产生最好的动作集合,然后显示待处理的事务,您可以批准是否继续。事务可能会包含安装,更新或删除额外的软件,以此来满足软件依赖关系。
yum [options] [command] [package ...]
Yum 命令主要选项的含义如下:
|
列 名
|
含 义
|
|---|
|
Install
|
安装新软件
| |
groupinstall
|
安装新软件组
| |
update
|
更新软件
| |
groupupdate
|
更新软件组
| |
remove
|
系统采用的时区
| |
list
|
搜索软件,
| |
Search
|
检测所有可用的软件的名称、描述、概述和已列出的维护者,查找匹配的值
| |
Provides
|
检测软件包中包含的文件以及软件提供的功能
| |
localinstall
|
从单独的软件包进行新软件
| |
Clean
|
清空 Yum 缓存
|
Yum 命令使用示例:
localhost# yum install scim
|
自动化更新具体实现
在大规模、多节点的 AIX/Linux 环境下,更新每个节点上的软件包或系统的时候,如果按照通常手动操作,先创建一个公共的软件仓库,然后在每个节点上添加软件仓库后,通过 nim/yum/yast 更新所指定的软件包或系统,就显得重复性比较多,工作量比较大,工作效率比较低;这个时候就需要一种新的效率更高,更便于操作的自动化升级与更新方法,它能在管理站上自动创建软件仓库,然后以多线程的方式远程并发地在每个节点上添加软件仓库,运行 nim/yum/yast 更新所指定的软件包或系统。
本章节将针对上面方法给出两个比较具体的自动化示例,分别用来进行 AIX、Redhat Enterprise Linux、SuSE 自动化升级与更新的示范;用户可以根据自身需求,在这些脚本的基础上进行扩展,实现更加复杂的管理功能。
图 1 上方 3 台为将要被远程部署节点,下方 1 台为管理站
图 1. 示范场景拓扑图
注意:对于在下面实现脚本文件中调用的函数,为了文章的组织,都被统一放到了 updateScriptLib.perl 文件中,假如读者想运行下面的脚本,请先将使用的函数拷贝到相应的脚本文件中。
基于 NIM
在 AIX 系统上运行的自动化代码由两个文件组成:(1)updateSW.conf、(2)updateAIXSW.pl。其中 updateSW.conf 存在于管理站上,包含需要更新的软件包的配置信息;updateAIXSW.pl 是一个可执行的 perl 代码,也运行于管理站上,主要解析 updateSW.conf,将获取的配置信息存于 hash 列表中,然后根据 hash 列表中的软件配置信息,启动多个进程分别通过 NIM 对每个节点进行远程自动化软件升级与更新。
-
updateSW.conf
该文件主要包含软件包更新配置信息,其文件内容格式如下:
# 更新软件包名:其所处位置:依赖列表:
openssh:/usr/sys/inst.images:/usr/sys/inst.data/user_bundles/openssh.bnd
openssl:/usr/sys/inst.images1: /usr/sys/inst.data/user_bundles1/openssl.bnd
-
updateAIXSW.pl 文件
命令格式:updateAIXSW.pl – c SWConfName – n nodeName1, nodeName2, … .
该可执行文件主要包含自动化升级与更新软件包代码:
#!/usr/bin/perl
use strict;
#main()
my $updateSWConf;
my $pid;
my @children;
# 命令行参数解析
if ($ARGV[0] eq "-c")
{
$updateSWConf = $ARGV[1];
if( $updateSWConf eq "" )
{
$updateSWConf = "/etc/updateSW.conf";
}
}
# 检查是否指定需要进行更新的节点
if ( ($ARGV[2] ne "-n") || ($ARGV[2] eq "") || ($ARGV[3] eq "") )
{
print "pls specify the updated nodes with – n.\n";
}
my $argLine = $ARGV[3];
chomp($argLine);
my @nodeNameArray = split ",", $argLine;
my %confHash = parseSWConf($updateSWConf);
# 对节点列表进行轮循
foreach my $nodeName (@nodeNameArray)
{
if ($nodeName eq "")
continue;
FORK:
{
# 针对每个节点创建多进程
if ($pid = fork)
{
#parent, store pid in array
push(@children, $pid);
}
elsif (defined $pid)
{
# 针对需要安装的包列表,进行轮循
foreach my $SWPkgName (keys %confHash)
{
my $location = $confHash{$SWPkgName}{"loc"};
my $bndLocation = $confHash{$SWPkgName}{"bnd"};
my $bundleName = $SWPkgName . "_bundle";
my %failNodes = {};
my $tmpVal = 0;
# 定义类型为 lpp_source 的资源
runCmd("nim -o define -t lpp_source -a server=master -a \
location=$location $SWPkgName");
$tmpVal = $::RETVAL;
goto ERROR1 if $tmpVal;
# 定义类型为 installp_bundle 的资源
runCmd("nim -o define -t installp_bundle -a server=master -a \
location=$bndLocation $bundleName");
$tmpVal = $tmpVal || $::RETVAL;
goto ERROR2 if $tmpVal;
# 分配资源
runCmd("nim -o allocate -a lpp_source=$SWPkgName -a \
installp_bundle=$bundleName $nodeName");
$tmpVal = $tmpVal || $::RETVAL;
goto ERROR3 if $tmpVal
# 进行节点更新
runCmd("nim -o update $nodeName");
$tmpVal = $tmpVal || $::RETVAL;
goto ERROR4 if $tmpVal;
print "Successfully update $SWPkgName on $nodeName.\n";
next;
# 根据实际情况,进行错误处理
ERROR4:
runCmd("nim -o deallocate $nodeName");
ERROR3:
runCmd("nim -o remove $SWPkgName");
ERROR2:
runCmd("nim -o remove $SWPkgName");
ERROR1:
print " Fail to update $SWPkgName on $nodeName.\n";
exit $tmpVal;
}
exit 0;
}
else
{
#couldn't fork, can't use msg catalog since no
# procs are available.
printf "updateLinuxSW: Unable to fork child process.\n";
}
}#end of the fork
}
#wait until all children processes have ended.
foreach $pid (@children)
{
waitpid($pid, 0);
}
undef @children;
exit 0;
|
基于 yum
在 RedHat/SuSE 系统上运行的自动化代码由三个文件组成:(1)updateSW.conf、(2)updateLinuxSW.pl、(3)updateSWorSys.pl。
其中 updateSW.conf 存在于管理站上,包含需要更新的软件包的配置信息。
updateAIXSW.pl 是一个可执行的 perl 代码,也运行于管理站上,主要创建 yum 配置文件,构建软件仓库,解析 updateSW.conf,以获取需要被升级与更新的软件包列表,然后针对每个节点启动一个进程,从管理站上远程拷贝 yum 配置文件、updateSWorSys.pl 到节点上,然后通过 ssh 远程登陆到节点上执行 updateSWorSys.pl,以实现远程自动化软件升级与更新的功能。
updateSWorSys.pl 是运行于各个节点上的可执行的 perl 代码,被 updateAIXSW.pl 远程调用,主要根据 yum 配置文件与软件更新列表完成本地节点的软件自动化升级与更新。
-
updateSW.conf
该文件主要软件包更新配置信息,其文件内容格式如下:
kernel
SysVinit
basesystem
bash
redhat-release
chkconfig
… .
ethtool
filesystem
findutils
gawk
glib2
…… .
-
updateLinuxSW.pl 文件
命令格式:updateLinuxSW.pl – c updateSWConf – n nodeName1, nodeName2, … .
该可执行文件主要包含在管理站上远程并发地启动多节点更新软件包或系统的代码,由下面几部分构成:
(1)全局变量代码清单
!/usr/bin/perl
use strict;
# Some global variables declaration
$::RETVAL;
$::VERBOSE;
$::distro_name = RedHatEL-Server
$::repo_base_url = "http://172.20.3.27/data/RedHatEL-Server5.4-GA-x86_64/",
$::repo_base_name = RedHatEL-Server5.4-GA-x86_64;
$::NODE_RPM_LIST_FILE = "/var/opt/yum/rpmlist";
$::NODE_YUM_TMPL_DIR = "/var/opt/yum/tmpl";
$::NODE_YUM_CONF_DIR = "/var/opt/yum/config/";
$::NODE_YUM_CONF_FILE = "/var/opt/yum/config/yum.conf";
$::CREATEREPOCMD = "/usr/bin/createrepo";
$::DIRNAME = "/usr/bin/dirname";
$::NODE_UPDATESWCMD_DIR = "/var/opt/bin/";
$::NODEUPDATESWCMD = "/var/opt/bin/updateSWorSys.pl";
|
(2)公共函数接口代码清单
请将 updateScriptLib.perl 中的定义的的函数包含在 updateLinuxSW.pl 文件中
(3)创建 yum 配置文件代码清单
sub createyumConf
{
my ($distro_name, $repo_base_url, $repo_base_name) = @_;
my $yumconf_ref = {
# keyword vaule
'#DistroVerPkg#' => $distro_name =~ /SLES/ ? 'sles-release' : 'redhat-release',
'#BaseName#'=> "$repo_base_name",
'#BaseUrl#' => "file://$repo_base_url"
};
if ( ! -d $::NODE_YUM_CONF_DIR )
{
mkpath($::NODE_YUM_CONF_DIR, $::VERBOSE, 0755);
}
# 根据具体的参数,创建 yum 配置文件
substFile($::NODE_YUM_TMPL_DIR . "/yum.conf",
"/var/opt/csm/yum/yum.conf",
$yumconf_ref);
}
|
(4)创建 yum 软件仓库代码清单
Sub createRepo
{
my $yumConfile = @_;
my $retVal = 0;
if ($yumConfile eq "")
{
print "pls specify the yum configuration file.\n";
$retVal = 1;
return $retVal;
}
my $yumconf = getConfig($yumConfile);
delete $$yumconf{'main'};
my %repoHash;
# Filter yum config hash and extract dirlist
foreach my $section (keys %$yumconf) {
foreach my $entry (keys %{ $$yumconf{$section} } ) {
if ($entry eq "baseurl")
{
my $value = $$yumconf{$section}{$entry};
$value =~ s/file:\/\///g;
if ($value =~ /yumrepo/)
{
chomp($value = runCmd("$::DIRNAME $value",-1) );
$repoHash{$value}{output} = "$value/yumrepo";
}
else
{
$repoHash{$value} = undef;
}
}
}
}
my $repo_out;
foreach my $repo (keys %repoHash)
{
$repo_out = undef;
$repo_out = $repoHash{$repo}{output} || $repo_out;
$retVal || = createRepoDB($repo, $repo_out);
}
return $retVal;
}
|
(5)获取需要在节点上进行安装的 rpm 包代码清单
sub getNodeRpmList
{
my ($rpmlistfile) = @_;
my @shortnamelist;
open(RPMLIST,"<$rpmlistfile")
|| print "Fail to open rpm list file.\n";
while (<RPMLIST>) {
chomp;
if ( $_ =~ /^#.*$/ ) {
next;
}
#$rpmliststring = $rpmliststring ." " . $_;
push @shortnamelist , $_;
}
close(RPMLIST);
my %temphash;
#Remove repeated entry from namelist
foreach my $rpmname (@shortnamelist)
{
$temphash{$rpmname} = 1 if (defined $rpmname);
}
@shortnamelist = keys %temphash;
$rpmliststring = join(" ",@shortnamelist);
print "rpmliststring = $rpmliststring \n" if $::DEBUG;
return $rpmliststring;
}
|
(6)main 入口主体部分 .
#!/usr/bin/perl
use strict;
#main()
my $updateSWConf;
my @children = ();
my $pid;
my $retVal = 0;
# 命令行参数解析
if ($ARGV[0] eq "-c")
{
$updateSWConf = $ARGV[1];
if( $updateSWConf eq "" )
{
$updateSWConf = "/etc/updateSW.conf";
}
}
# 检查是否指定需要更新的节点
if ( ($ARGV[2] ne "-n") || ($ARGV[2] eq "") || ($ARGV[3] eq "") )
{
print "pls specify the updated nodes with – n.\n";
}
my $argLine = $ARGV[3];
chomp($argLine);
my @nodeNameArray = split ",", $argLine;
# 创建 yum 配置文件
createyumConf($::distro_name, $::repo_base_url, $::repo_base_name);
# 创建 yum 软件仓库
$retVal = createRepo($::NODE_YUM_CONF_FILE)
if ($retVal == 1) exit 1;
# 获取每个节点需要更新的软件包的列表
my $rpmList = getNodeRpmList($updateSWConf);
# 对每个节点进行轮循
foreach my $nodeName (@nodeNameArray)
{
if ($nodeName eq "")
continue;
FORK:
{
# 针对每个节点创建进程
if ($pid = fork)
{
#parent, store pid in array
push(@children, $pid);
}
elsif (defined $pid)
{
# 将创建的 yum 配置文件传送到需要被远程部署的节点上
#child, issue the update command
$retVal = runCmd("scp $::NODE_YUM_CONF_FILE \
root@nodeName:$::NODE_YUM_CONF_DIR");
if ($retVal)
{
$retVal = 1;
exit $retVal;
}
# 将需要运行的更新脚本文件传送到需要被远程部署的节点上
$retVal = runCmd("scp $::NODEUPDATESWCMD \
root@nodeName:$::NODE_UPDATESWCMD_DIR");
if ($retVal)
{
$retVal = 1;
exit $retVal;
}
# 通过 shh 在远程节点上执行更新脚本,进行软件更新
$retVal = runCmd("ssh root@nodeName '$::NODEUPDATESWCMD – s 1 – c \
$::NODE_YUM_CONF_FILE – n $rpmList'");
if ($retVal)
{
$retVal = 1;
}
exit $retVal;
}
else
{
#couldn't fork, can't use msg catalog since no
# procs are available.
printf "updateLinuxSW: Unable to fork child process.\n";
}
}
}
#wait until all children processes have ended.
foreach $pid (@children)
{
waitpid($pid, 0);
}
undef @children;
exit 0;
|
-
updateSWorSys.pl 文件
命令格式:updateSWorSys.pl – s IsUpdateSWFlag – c nodeyumConfile – p rpmList
该可执行文件主要包含在各节点上执行的 yum 进行升级与更新软件包或系统代码。
#!/usr/bin/perl
use strict;
#main()
my $IsUpdateSW;
my $nodeyumConfile;
my $output;
# 命令行参数解析
if ($ARGV[0] eq "-s")
{
$IsUpdatSW = $ARGV[1];
if( $IsUpdatSW eq "" )
{
$IsUpdatSW = 1;
}
}
else
{
$IsUpdatSW = 1;
}
# 检查是否指定了 yum 配置文件
if ($ARGV[2] eq "-c")
{
$nodeyumConfile = $ARGV[3];
if( $nodeyumConfile eq "" )
{
$nodeyumConfile = "/var/opt/yum/config/yum.conf";
}
}
# 检查是否指定了需要更新的软件名
if ( ($ARGV[4] ne "-p") || ($ARGV[4] eq "") || ($ARGV[4] eq "") )
{
print "pls specify the updated software name with – p.\n";
}
my $nodeSWName = $ARGV[5];
# 判断是进行软件更新还是系统更新
if ($IsUpdateSW)
{
$output = runCmd("yum -y -c $nodeyumConfile update $nodeSWName", -1);
}
else
{
$output = runCmd("yum -y -t -d 2 -c $nodeyumConfile update", -1);
}
if ( defined($::DEBUG) )
{
print "The yum output: $output\n";
}
if ($::RETVAL)
{
print "yum errors, please refer to the yum output for details";
$$::RETVAL = 1;
}
exit $::RETVAL;
|

 |

|
小结
本文介绍了 Unix/Linux 上几种常见的系统更新方法,并通过几种具体的脚本详细介绍了如何基于不同的方法实现系统自动化更新。如何在现实的工作中灵活多变的运用它们以大大减轻我们的工作量,还需要读者自己去多积累、学习与揣摩。
下载 | 描述 | 名字 | 大小 | 下载方法 |
|---|
| 实例代码 | updateScriptLib.perl | 4KB | HTTP |
|---|
参考资料 学习
-
本系列文章主要关注于实现 Unix/Linux 系统上的管理自动化,让读者了解到脚本语言以及相关的工具可以让日常的管理工作变得更加轻松。
-
OpenSSH 组织的官方网站: 从这里可以找到 openSSH 相关的资料。
-
Expect.pm 的使用手册:介绍了 Expect 的 Perl 语言接口。
-
EXPECT 的主页:从这里可以找到几乎所有关于 EXPECT 的资料,包括文档、FAQ、Wiki 和有用的链接。
-
Expect 超出预期:一种不为人知但功能强大的流行工具,文章介绍了 Expect 的基本功能。
-
IBM Publication:《命令参考大全,卷 5:s - u 》:AIX 6.1 信息中心文档,系统管理类。
-
有关 Perl 信息及其相关资源,请查看 Perl.com。
-
Programming Perl Third Edition(Larry Wall、Tom Christiansen 和 Jon Orwant 著;O'Reilly & Associates,2000)是当今最好的 Perl 指南,现在已经更新到 5.005 和 5.6.0。
-
Perl Cookbook(Tom Christiansen 和 Nathan Torkington 著;O'Reilly & Associates,1998)是关于所有 Perl 问题的权威性入门书籍。
- AIX and Unix 专区:developerWorks 的“AIX and Unix 专区”提供了大量与 AIX 系统管理的所有方面相关的信息,您可以利用它们来扩展自己的 Unix 技能。
- AIX and Unix 新手入门:访问“AIX and Unix 新手入门”页面可了解更多关于 AIX 和 Unix 的内容。
- AIX and Unix 专题汇总:AIX and Unix 专区已经为您推出了很多的技术专题,为您总结了很多热门的知识点。我们在后面还会继续推出很多相关的热门专题给您,为了方便您的访问,我们在这里为您把本专区的所有专题进行汇总,让您更方便的找到您需要的内容。
- developerWorks 技术活动和 网络广播:随时关注 developerWorks 技术活动和网络广播。
获得产品和技术
-
IBM
试用软件:使用可从 developerWorks 直接下载的软件构建您的下一个开发项目。
讨论
关于作者  | |  | 吴志勇,IBM 中国软件开发中心 HPC 部门的软件工程师,主要从事集群系统管理软件的相关研发工作。 |
对本文的评价
|  |