??xml version="1.0" encoding="utf-8" standalone="yes"?>
CVS 是一U客hQ服务器pȝQ可以让开发h员将他们的项目存储在UCؓ资源库的中央位置。?cvs 客户机工P开发h员可以对资源库的内容q行更改。CVS 资源库会依次记录Ҏ个文件所做的每个更改Qƈ创徏一个完整的目开发进展历双Ӏ开发h员可以请求特定源文g的旧版本、查看更Ҏ志,q根据需要执行其它一些有用的d?BR>
许多开放Y仉目都有他们自q CVS 服务器,目开发h员把q些服务器作Z们工作的源码仓库。源码仓库的源码目录中保存的都是实现版本控制的历史文?history file)Q历史文件名为filename,v。历史文件包含用来恢复所有版本文件的_信息、所有提交的信息以及提交者信息。历史文件常常被UCRCS文gQ因为最早是RCSE序用这U格式来保存文g的所有修改信息,可以从man rcsfile得到历史文g的?BR>
开发h员每天都会改q?CVS 资源库内的源码,且他们往往分布在世界各圎ͼ?CVS 提供了一U必要的机制Q将他们的项目联合成一个集中的、协作的整体。CVS 创徏?l织_和?Q可以让q些开发h员改q代码而不会干扰别人、丢失重要数据或遗漏彼此对特定源文g的重要更新?BR>
当开发h员准备好以后Q他们把 CVS 上部分当前工作打包成 .tar.gz 文gQ作Y件包的新官方版本来发布它。然而,׃U种原因Q最新的官方发行版有时ƈ不是最新的。在本教E的W一部分首先介l如何用CVSZZ用获取最新和最高开发h员版本的源码?BR>
CVSROOT
在开始前Q您需要了解一?CVS 的基知识。首先,Zq接?CVS 资源库,您需要知道称?"CVSROOT" 的\径。CVSROOT 是一个字W串Q就?URLQ它告诉 cvs 命oq程资源库在哪里Q以及如何连接它。不仅如此,Ҏ CVS 资源库是本地的还是远E的Q以及连接到它的不同方式QCVS q有许多不同?CVSROOT 格式。这里有一些带有解释的 CVSROOT CZ?BR>
本地 CVSROOT
CVSROOT=/home/cvsroot
q是一个本?CVSROOT 路径的示例;如果您想q接?/home/cvsroot 中存在的本地资源库,或者有一个经 NFS 安装?/home/cvsroot 的资源库Q需要象q样使用 CSROOOT?BR>
q程密码服务?CVSROOT
CVSROOT=:pserver:cvs@foo.bar.com:/home/cvsroot
q里是一个远E资源库?CVSROOT CZQ该资源库位?foo.bar.com L上,q在q台机器?/home/cvsroot 目录中活动。前?":pserver:" 告诉我们的客h使用 CVS 密码服务器协议连接到q台q程机器Q该协议内置?CVS 中。一般情况下Q公?CVS 资源库用密码服务器协议以允许匿名用戯问?BR>
q程 rsh/ssh CVSROOT
CVSROOT=drobbins@foo.bar.com:/data/cvs
q是一个?RSH ?SSH 协议?CVSROOT 的示例;在该例中QCVS 服务器尝试?drobbing 帐户来访问在 foo.bar.com 上的资源库。如?CVS_RSH 的环境变量设|成 "ssh"Q那么我们的客户机就试?ssh 去连接;否则׃?rsh。那些关注安全性的用户往往使用 ssh 讉K法;但是Q无论是 RSH q是 SSH Ҏ都不能对匿名用户提供一U获取源码的方式。ؓ了用这U方法,您在 foo.bar.com 上必L个登录帐戗?BR>
除了 CVSROOT 之外Q您q需要知道要出的模块Q源码集合)的名Uͼ以及d?CVS 密码服务器的匿名密码。与匿名 ftp 不同Q匿名密码没有什?标准"格式Q所以您需要从开发h员网站或开发h员那里获得具体的密码。一旦知道了所有这些信息,可以开始了?BR>
?CVS 交互
获取源码需要两个步骤。首先,以远E密码服务器的方式登录到CVS服务器。然后,使用"checkout"命o获取源码。这里有一l命令的CZQ用于检出最新的 Samba 源码Q一个流行的 UNIX/Windows 集成目Q:
# export CVSROOT=:pserver:cvs@pserver.samba.org:/cvsroot
W一个命令设|?CVSROOT 环境变量。如果没有设|这个变量,下面两个命o需要跟?"cvs" 命o后再加上 "-d :pserver:cvs@pserver.samba.org:/cvsroot"。设?CVSROOT 环境变量省去了一些输入?BR>
# cvs login
(Logging in to cvs@pserver.samba.org)
CVS passwordQ(在此输入密码Q?BR># cvs -z5 checkout samba
U samba/COPYING
U samba/Manifest
U samba/README
U samba/Read-Manifest-Now
U samba/Roadmap
U samba/WHATSNEW.txt
Q这只是完整?cvs check 输出的一段摘录Q?BR>
上面W一?cvs 命o是让我们d?pserverQ第二个命o告诉 CVS 客户Z?gzip 压羃U?5 ("-z5") 在慢速连接上加快传输速度Q来?("checkout") samba 模块。对于每个在本地创徏的新文gQcvs 都会打印 "U [path]" 表明q个特定的文件已l在盘上更新过了?BR>
一旦检出命令完成,在包含最新源码的当前工作目录中看?"samba" 目录。还会注意到每个子目录下都有一?CVS"目录 -- CVS 在这些目录中存储帐户信息Q可以放心地忽略它们。一旦检出结束,用户无需担心是否讄?CVSROOT 环境变量Q也无需再在命o行上指定它,因ؓ现在所有额外的 "CVS" 目录里都有它的缓存?BR>
C -- 只需要ؓ初始d和检|?CVSROOT?BR>
更新源码
现在已经有了源码Q就可以l箋~译和安装它们、检查它们,或者对它们执行M操作?BR>
偶尔Q也需要将已检(checkout)出的源目录与 CVS 上的当前版本保持同步。ؓ了做到这一点,您无需再次d?pserverQcvs 会将您的认证信息~存到那?"CVS"帐户目录中。首先,q入L出目录(在这里是 "samba"Q,然后输入Q?BR>
# cvs update -dP
如果有Q何新文gQcvs׃在更新每一行的时候输?"U [path]" 行。另外,如果本地~译了源码,您有可能会看到许?"? [path]" 行;cvs 指出q些目标文g不来自于q程资源库?BR>
另外Q请注意我们用于 "cvs update" 的两个命令行选项?-d" 告诉 cvs 创徏可能已添加到资源库的新目录(~省情况下,q不会发生)Q?-P" 告诉 cvs 从本地已出的源码副本中除L有空目录?-P" 是个不错的选择Q因?cvs 們于收集许多随旉产生的空Q曾l用过Q但现在已经攑ּQ目录树?BR>
如果只是要获得最新的源码Q这些就是您所需要了解的。现在,来看一下作Z个开发h员如何与 CVS 交互?BR>
修改文g
作ؓ一名开发h员,您需要修?CVS 上的文g。要修改文gQ只需要对资源库的本地副本q行适当的更攏V在您明地告诉 cvs "提交"更改之前Q您Ҏ码做的更改不会应用到q程资源库。测试过所有修改以保它们可以正常q作之后Q就可以准备这些更改运用到资源库中Q遵循下面的两个步骤。首先,在主源码目录中输入以下命令来更新源码Q?BR>
# cvs update -dP
CVS 合ƈ其他人的更改
我们在前面已l看刎ͼ"cvs update"用资源库中的当前版本您的源码保持最新状?-- 但对您已l做q的更改会发生什么情况呢Q不要担心,它们不会被丢弃。如果另一个开发h员对您没动过的文件做了一些更改,您的本地文g进行更C使它与资源库中的版本保持同步?BR>
如果您修改了本地文g中的W?1-10 行,而另一个开发h员删除了W?40-50 行,在文件末添加了 12 行新行,同时修改?30-40 行,然后在您之前他向资源库提交了他的更改Qcvs 会智能地这些更改合q到您本地已修改的副本中Q这样你们的更改都不会丢失。这可以让两个或更多开发h员针对同一文g的不同部分同时操作?BR>
然而,如果两个或多个开发h员更改同一文g的同一部分Q那么事情就有些复杂了。如果发生这U情况,cvs 会告诉您有冲H发生。所做的工作不会丢失Q但需要手工干预,因ؓ cvs 需要您提供意见来决定如何合q这些有冲突的更攏V?BR>
提交
我们q一会儿来看看冲H究竟是如何解决的,但现在,先让我们假设在输?"cvs update -dP" 后没有冲H?-- 通常都没有冲H。由于没有冲H,本地源码是最新的。可以在L码目录中输入以下命o来提交对资源库的更改Q?BR>
# cvs commit
提交所L作用
"cvs commit" 不只您的更改应用到资源库。在真正您的更Ҏ交给q程资源库之前,cvs 会调用缺省编辑器Q可以让您输入修改的描述。输入了注解后,保存该文Ӟ退出编辑器Q您的更改(和注解)׃应用到远E资源库Q小l中的其他开发h员可以看到这些更攏V?BR>
查看日志
要查看某个特定文件完整的历史以及提交时开发h员(包括您)所加的注解是很Ҏ的。要查看q些信息Q输入:
# cvs log myfile.c
"cvs log" 命o是递归的,所以如果您x看整个目录树的完整日志,只需要进入该目录Q输入:
# cvs log | less
提交选项
您可能想要用另一个输?"cvs commit" ?cvs 在缺省情况下启动的编辑器。如果是q样Q只需要把您希望用的~辑器的名称放进 EDITOR 环境变量中。另外,也可以将更新日志消息作ؓ命o行选项指定Q这P cvs ׃需要一上来p入编辑器Q?BR>
# cvs commit -m 'I fixed a few silly bugs in portage.py'
.cvsrc 文g
在l了解其?cvs 命o前,讄 ~/.cvsrc 文g。通过在您ȝ录中创徏 .cvsrc 文gQ可以告?cvs 在缺省情况下使用您所需的命令行选项Q这样就不必每次都输入它们。这里有一个推荐的~省 .cvsrc 文gQ?BR>
cvs -q
diff -u -b -B
checkout -P
update -d -P
除了Zl?cvs 命o讄有用的选项以外Q?cvsrc 的第一行将 cvs |于安静模式下,它的主要好处是 "cvs update" 输出更简z,更具可读性。另外,一旦完?.cvsrc 后,可以输?"cvs update" 而不?"cvs update -dP"?BR>
文件添加到资源?BR>
要将源文件添加到 CVS 很容易。首先,用您喜爱的文本编辑器创徏该文件。然后,输入以下命oQ?BR>
# cvs add myfile.c
cvs server: use 'cvs commit' to add this file permanently
q将告诉 cvs 在您下次执行 "cvs commit" Ӟ该文gd到资源库。在那之前,其它开发h员看不它?BR>
目录添加到资源?BR>
目录添加到 CVS 的过E类gQ?BR>
# mkdir foo
# cvs add foo
Directory /home/cvsroot/mycode/foo added to the repository
与添加文件不同,当您d目录Ӟ它会立即出现在资源库中;不需?cvs commit。将本地目录d?cvs 后,您会注意到在q程cvs服务器的对应目录中创Z一?"CVS" 目录Q它作ؓ包含 cvs 帐户数据的容器。因而,您只要看一下其中是否有 "CVS" 目录Q就可以很容易地知道某个目录是否已添加到q程cvs服务器的 cvs中了
在将文g或目录添加到资源库之前,您必ȝ保它的父目录已经d?CVS。否则,您会看到cM于下面的错误Q?BR>
# cvs add myfile.c cvs add: cannot open CVS/Entries for
reading: No such file or directory cvs [add aborted]: no repository
熟悉 "cvs update"
在了解如何解军_H之前,先让我们熟悉一?"cvs update" 命o的输出。如果创Z一个包?"cvs -q" 行的 ~/.cvsrc 文gQ您会发?"cvs update" 的输出相当容易理解?cvs update" 通过打印单个字符、空格和文g名告诉您它都做些什么,看到些什么;如下例所C:
# cvs update -dP
? distfiles
? packages
? profiles
"cvs update" ?"?" 字符指示在地副本中找到的q些Ҏ文g。它们不是资源库的正式部分,也不是计划要d的部分。这里有一个CVS使用的所有其它单字符信息性消息的列表Q?BR>
U [path]
在本地资源库中创建新文gQ或者更C您没有动q的文g时用?BR>
A [path]
该文件是计划要添加的Q?"cvs commit" Ӟ它被正式d到资源库?BR>
R [path]
?"A" 一P"R" 让您知道该文件计划要除去。输?"cvs commit" 后,该文件就会从资源库中除去?BR>
M [path]
q意味着您已l修改过该文件了Q而且Q有可能资源库中新的更改已成功地合ƈ到该文g?BR>
C [path]
"C" 字符表明该文件存在冲H,需要在使用 "cvs commit" 提交更改前手工修改它?BR>
如何解决冲突
现在Q让我们看一下如何解军_H。我参与了大部分?Gentoo Linux 目Q我们在 cvs.gentoo.org 上设|了自己?cvs 服务器。我们这些开发h员花了绝大部分时间来修改 "gentoo-x86" 模块内部的源码。在 gentoo-x86 模块中,有一个叫 "ChangeLog" 的文Ӟ它包含了Q您猜一下它Q我们对资源库中该文件做的主要更改的描述?BR>
冲突的示?BR>
因ؓ几乎每次开发h员对 CVS q行主要更改旉会对该文件做一些修改,q就成ؓ冲突的主要根?-- q里有冲H的一个示例。假设我?ChangeLog 的顶部添加了以下行:
date 25 Feb 2001
This is the thing I added myself
然而,在我提交q二新行之前Q另一个开发h员也?ChangeLog 的顶部添加了q些行ƈ提交了他的更改:
date 25 Feb 2001
This is the part added by another developer
现在Q当我运?"cvs update -dP" Q每ơ提交前您都应该q么做)Qcvs 不能把他的更改合q到我的 ChangeLog 本地副本Q因为我们俩都向文g的同一部分d了行 -- cvs 怎么知道用哪个版本?所以,CVS 会出C下错误:
RCS file: /home/cvsroot/gentoo-x86/ChangeLog,v
retrieving revision 1.362
retrieving revision 1.363
Merging differences between 1.362 and 1.363 into ChangeLog
rcsmerge: warning: conflicts during merge
cvs server: conflicts found in ChangeLog
C ChangeLog
?-- 有冲H!q好消除q些冲突很容易。如果我启动我喜q文本~辑器,会?ChangeLog 文g的顶部看C下文本:
<<<<<<< ChangeLog
date 25 Feb 2001
This is the thing I added myself
=======
date 25 Feb 2001
This is the part added by another developer
>>>>>>> 1.363
cvs 不是选其中一个而舍弃另一个,而是把两个版本都加进 ChangeLog 文gQƈ用特D的分隔W将它们圈vQ以明确地标记出有问题的冲突。现在,我要用一个应该出现在 ChangeLog 里的文本来替换这部分Q在q种情况下,替换的文本既不是我的版本也不是他的版本,而是两者的l合Q?BR>
date 25 Feb 2001
This is the thing I added myself
This is the part added by another developer
我用适当的文本替换掉了有冲突的部分(qM "=======" {标讎ͼQ可以顺利地我的更Ҏ交给 cvs?BR>
无论什么时候需要编辑文件来解决冲突Ӟ都要保已经览q整个文Ӟ以便您知道所有内容;如果您忘记解x个冲H,那么在这个冲H解决之前,cvs 是不允许您提交的Q很昄Q除?cvs d到冲H文件中的特D标记是很重要的?BR>
如果您在解决某个冲突时犯了错误,然后意外C存了您所作的更改Q那么您可以?".#filename.version" 文g中找到您的原始副本?BR>
删除文g
现在应该学习关于 CVS 的最后一个技?-- 从资源库中除L件。除L件是一个两阶段q程。首先,从源码的本地副本删除该文Ӟ然后执行相应?"cvs remove" 命oQ?BR>
# rm myoldfile.c
# cvs remove myoldfile.c
在您下次提交Ӟ该文件计划将从资源库中除厅R一旦提交,该文件会从资源库当前的版本中正式删除。然而, cvs 不会该文g抛弃Q而是仍然完整C留该文g的内容及其历Ԍ以备您以后需要它。这只是 cvs 保护您有价值的源代码的众多Ҏ之一?BR>
"cvs remove" 是递归的,q意味着您可以删除一ҎӞ然后从父目录q行不带其它自变量的 "cvs remove" 命o。这样做会在下次提交时标记所有已删除的文件?BR>
如果您想除去整个目录Q我推荐使用下列q程。首先,从物理上删除Q?cvs remove" 删除目录中的所有文Ӟ
# rm *.c
# cvs remove
然后执行提交Q?BR>
# cvs commit
q里有一个诀H。执行以下步骤删除目录:
# cd ..
# cvs remove mydir
# rm -rf mydir
h意,除去目录不需要另一ơ提?-- 把目录添加到资源库和从资源库除去目录是实时的?BR>
修订?BR>
源码仓库中的一个文件可以有多个版本Q同样一个Y件可能有多个版本。一般在CVS中前一U意义上的版本(源码仓库中文件的版本Q一般称Z订号(revisions)Q而对软g的版本一般称为发?release)?BR>
一个文件的修订号一般是依次递增的,一般以偶数个通过"."q接的十q制C来表C,如:`1.1', `1.2', `1.3.2.2'甚至`1.3.2.2.4.5
标签的定义和使用
源码仓库中各个文件的修订h独立增加的,怺之间没有M兌关系Q和软g的发布号也没有Q何关p,例如一个项目中的各个文件的修订号可能是q样的:
ci.c 5.21
co.c 5.9
ident.c 5.3
rcs.c 5.12
rcsbase.h 5.11
rcsdiff.c 5.10
rcsedit.c 5.11
rcsfcmp.c 5.9
rcsgen.c 5.10
rcslex.c 5.11
rcsmap.c 5.2
rcsutil.c 5.10
Z便于标记Q可以用标{来为某个特定版本的特定文g讑֮一个标C方便讉KQ可以用cvs tag和cvs rtag来定义标{,其中cvs tag用来Z库中当前工作文g(或文仉?指定一个符h讎ͼcvs rtag用来昑ּCؓ源码仓库的特定修订号的文件定义一个标记。例如下面的例子是l文件backend.c的当前修订号定义一个标{,然后察看该文件的状态:
$ cvs tag rel-0-4 backend.c
T backend.c
$ cvs status -v backend.c
===========================================================
File: backend.c Status: Up-to-date
Version: 1.4 Tue Dec 1 14:39:01 1992
RCS Version: 1.4 /u/cvsroot/yoyodyne/tc/backend.c,v
Sticky Tag: (none)
Sticky Date: (none)
Sticky Options: (none)
Existing Tags:
rel-0-4 (revision: 1.4)
但是在实际应用中很少会ؓ特定文g定义一个标{,而往往是在开发过E中的特定阶Dؓ特定目的所有文件定义一个标{,以方便发布或者定义分支,例如Q?BR>
$ cvs tag rel-1-0 .
cvs tag: Tagging .
T Makefile
T backend.c
T driver.c
T frontend.c
T parser.c
定义标签以后Q可以在随后的Q何时候访问对应该标签的项目文Ӟ例如下面q个命oq来实现检出对应于标签rel-1-0的所有文?可能是Y件的1.0发布)Q?BR>
$ cvs checkout -r rel-1-0 tc
可以惛_标签pȝ定修订号文g的曲U烦引,例如Q?BR>
q里表示在Y件开发过E中的定义了标签*Q也可这L待标{:
当然也可以删除标{,例如Q?BR>
cvs rtag(/tag) -d rel-0-4 tc 删除模块tc的rel-0-4标记
备䆾源码仓库
备䆾Q?首先断开所有的cvsq接Q然后用cp命o备䆾卛_
分支
通过CVS可以实现对源码的修Ҏ交给一个独立的开发线Q被UCؓ分支(branch)。当对分支的文gq行修改Ӟq些修改不会对主分支和其他分支生媄响?BR>
随后可以将一个分支的修改合ƈ(merging)到其他分支。合q是通过cvs update -j来合q修改到当前工作目录(本地)Q然后就可以提交修改来媄响其他分支了?BR>
分支的重要?BR>
让我们假设这U情况,目tc?.0版本已经搞定Q你l开发tc目Q计划在几个月内发布1.1版本Q但是客h怨Y件中有致命的错误。因此你?.0版本(q里是需要用标记的原因)q发Cq个bug的原因。然而当前的源码处于1.0?.1版本之间因此代码处于混ؕ状态,而且在一个月内不大可能出现稳定版本,因此不大可能Ҏ当前的版本得C个修复错误的版本来发布?BR>
对于q种情况q就需要创Z个包含错误修改的1.0分支发布Q而不需要媄响当前的开发,在合适的时候可以将修正合ƈ的主发布中去?BR>
创徏分支
创徏分支首先为拟修改的某些文件创Z个标{?tag)Q标{是赋于一个文件或一l文件的W号.在源代码的生命周期里Q组成一l模块的文g被赋于相同的标签?BR>
创徏标签Q在工作目录里执行cvs tag ?BR>
? 为src创徏标签Q?BR>
cvs checkout src(/update亦可Q用来更新本地的源代?
cvs tag release-1-0(为当前最新源码加一个标{?
标签创徏? 可以ؓ其创Z个分支:
cvs rtag -b -r release-1-0 release-1-0-path print
-b :创徏分支
-r release-1-0Q?r参数用来标记那些包含指定的标{文g
releas-1-0-patch:分支
print: 模块?BR>
可以使用tag -b来创建分支,例如在工作目录中Q?BR>
$ cvs tag -b rel-1-0-patches
会Z当前工作的分支分M个分支,q将该分支命名ؓ`rel-1-0-patches'。应该理解分支是在cvs的源码仓库中创徏的,而不是当前工作目录,Z当前修正创徏分支不会当前工作拷贝自动{换ؓ新的分支Q需要手工来实现的。也可以通过使用rtag命o实现不涉及工作目录的分支Q?BR>
$ cvs rtag -b -r rel-1-0 rel-1-0-patches tc
`-r rel-1-0'指示创徏的新分支应该以标记`rel-1-0'指定的修订ؓ基础Q而不是基于当前的工作d支。这主要是用来从旧版本中创徏一个分?例如上面的例??BR>
rtag -b指示创徏分支(而不是仅仅创建标?。应该注意的是`rel-1-0'包含的各个文件的修订号可能是不一L?BR>
所以该命o的效果是为工Etc创徏一个新分支-名字为`rel-1-0-patches'Q以标记`rel-1-0'为基?BR>
讉K分支
可以以两U方式访问分支:从源码仓库中出分支代码,或者将当前的工作拷贝切换ؓ分支?BR>
从源码仓库中创检出新分支可以使用命o'checkout -r release-tag'命oQ?BR>
$ cvs checkout -r rel-1-0-patches tc
当前分支切换到分支命oQ?BR>
$ cvs update -r rel-1-0-patches tc
或?BR>
$ cd tc
$ cvs update -r rel-1-0-patches
随后的提交等影响源码仓库的操作都仅仅对分支v作用Q而不会媄响主分支和其他分支。可以用status命o来察看当前工作拷贝属于哪个分支。输Z察看'sticky tag'信息Q这是cvs昄当前工作拯是在哪个分支上:
$ cvs status -v driver.c backend.c
=============================================================
File: driver.c Status: Up-to-date
Version: 1.7 Sat Dec 5 18:25:54 1992
RCS Version: 1.7 /u/cvsroot/yoyodyne/tc/driver.c,v
Sticky Tag: rel-1-0-patches (branch: 1.7.2)
Sticky Date: (none)
Sticky Options: (none)
Existing Tags:
rel-1-0-patches (branch: 1.7.2)
rel-1-0 (revision: 1.7)
=============================================================
File: backend.c Status: Up-to-date
Version: 1.4 Tue Dec 1 14:39:01 1992
RCS Version: 1.4 /u/cvsroot/yoyodyne/tc/backend.c,v
Sticky Tag: rel-1-0-patches (branch: 1.4.2)
Sticky Date: (none)
Sticky Options: (none)
Existing Tags:
rel-1-0-patches (branch: 1.4.2)
rel-1-0 (revision: 1.4)
rel-0-4 (revision: 1.4)
不要被每个文件的分支L不同(`1.7.2'和`1.4.2')所qhQ分支是由分支标记来军_的这里都? rel-1-0-patches'。这里的分支号仅仅表C当生成该分支时每个文g的修订号?BR>
分支和修订号
通常情况下源码库中文件的修订h以线性增大的:
+-----+ +-----+ +-----+ +-----+ +-----+
! 1.1 !----! 1.2 !----! 1.3 !----! 1.4 !----! 1.5 !
+-----+ +-----+ +-----+ +-----+ +-----+
但是CVSq不局限于U性开发,源码树可能出现分支,每个分支是一个对立的开发线。对分支的修改会很容易地被加入到d支中来?BR>
每个分支都拥有一个分支号Q由使用"."分隔的奇C数组成的C来表C。分支号是通过在生分支处的修订号后添加一个整数来实现得到的。通过定义分支号得从同一个分支点分出多个开发分支成为可能?BR>
分支的修订号是通过在分支号后顺序添加数字后~得到的,如下图所C:
分支号生的详细l节其实是不必详l了解的Q但是了解其工作原理是必要的Q当CVS创徏一个分支时Q其选择一个最的偶数作ؓ分支号后~。因此当希望从修订号6.4分出一个分支时Q新分支的分支号?.4.2。所有以0作ؓ分支号后~的分支号都被CVS自己保留使用(例如6.4.0)?BR>
合ƈ分支
分支开发一D|间以后往往需要将修订合ƈC分支中来Q可以通过`-j branchname'参数实现合ƈ分支。用该参数分支和其父分支合ƈ?BR>
考虑下面的源码修订树Q?BR>
分支1.2.2被定义ؓ标记R1fix。下面的例子假设模块mod仅仅包含一个文件m.c:
$ cvs checkout mod #获取最新的1.4版本
$ cvs update -j R1fix m.c # 合ƈ分支的所有更新到d?BR>
# 也就?.2?.2.2.2的修改合q到当前工作拯
$ cvs commit -m "Included R1fix" # 创徏修订版本1.5.
合ƈ时可能出现冲H情况,如果发生冲突Q应该在提交以前手工处理冲突?BR>
出命?checkout)命o同样支持参数 `-j branchname'Q上面的操作可以通过下面的命令实玎ͼ
$ cvs checkout -j R1fix mod
$ cvs commit -m "Included R1fix"
一个需要注意的问题?update -j tagname"同样?img src ="http://www.aygfsteel.com/nighTuner/aggbug/3878.html" width = "1" height = "1" />
]]>
|络服务器的资料L量(|卡的资料传送LQ、CPU使用率以及特D服务(例如Squid的代理服务){的包传送率Q或者说是流量)是网l管理h员所必须要注意的事项。因为当L的CPU使用率过高时Q系l可能呈CE_的状态,q就需要注意是哪一个服务或者谁在尝试窃取我们的资料。因此,|络理斚wQ有必要了解我们L的流量状态,q视量来加以限制或者是加大带宽?
我们可以从MRTG的主:http://www.mrtg.org下蝲MRTG软g。在|站Qhttp://www.stat.ee.ethz.ch/mrtg/可以得到MRTG量监测囄输出l果。示例如?所C?
? MRTG量监测囄输出l果
MRTG是用Perl写成的,q且使用了zlib、gd以及png{函敎ͼzlib用来压羃图表、gd用来l制图表Q。服务器中已l含有下列的软gQperl(perl-5.0xx以上)、zlib(zlib-1.1.3-xx以上)、gd(gd-1.3.xx以上)、libpng和Apache?
可以用RPM来确认它们:
另外Q由于MRTG以HTTP的格式输出成图表来显C,因此必须要安装好Apache。以下,我们使用了预讄Apache路径Qؓ/usr/local/apache/htdocsq个路径来安装MRTG输出的图表。要注意Q如果没有ApacheQ虽然仍可以执行MRTGQ但那就无法昄图表了?
安装MRTG
׃MRTG是通过SNMP通讯协议来要求资料,因此Linux上需要先安装相应的YӞ通常是安装ucd-snmpq套软g?
1Q下载ucd-snmp-4.2.1.tar.gz,mrtg-2.9.17.tar.gz?
2Q安装ucd-snmp-4.2.1.tar.gz?
3Q启动ucd-snmp?
直接在shell下面打上/usr/local/snmp/sbin/snmpd卛_Q或者直接加?etc/rc.d/rc.local当中Q就可以自动开机启动了?
4Q安装?
到现在我们就已经正确地安装了MRTGpȝ?
网卡流?/B>
要用MRTG来作N常简单,只要几个步骤就可以自动监测量。首先以MRTG附的E序来制作一个参数项Q预设ؓmrtg.cfgQ,然后修改一下mrtg.cfgq个参数,再直接执行三ơ参数文Ӟ之后用MRTGE序的小软g直接制作成首,可以察看图表了?
讑֮MRTG的方法如下:
public@vbird.adsldns.org
[root@tsaibin]# vi/usr/local/apache/htdocs/mrtg/net/mrtg.cfg
不过׃E序自动讑֮的mrtg.cfg会有问题Q因此,请将下面q三行修Ҏ你自q样式?
开始测试你的参数项Q要执行三次Q就可以正常工作了,不过Q若是有问题的话Q就需要改mrtg.cfgQ再执行直到没有错误发生为止?
/usr/local/apache/htdocs/mrtg/net/mrtg.cfg
上面q个E序indexmaker是在制作首页。会自动地输Z个index.html的文件中?/PRE>
注意Q在public@vbird. adsldns.orgq一行,public是有其意义的Q在SNMPq个通讯服务里面的预设搜ȝ一个代码)。如果主机的动态DNS名称为your.domain.nameQ则׃定要写成public@your. domain.name才行?
在设定五分钟一ơ之后,可以开始检。然后就可以通过览器访问地址http://192.168.0.1/mrtg/Q选择适当的接口地址察看量信息了。如果希望生成类ghttp://www.stat.ee.ethz.ch/mrtg/的信息,需要自己手工编辑一个index.html文档Q存攑֜/var/www/html/mrtg目录下,内容为接口说明以及该接口的日l计信息的图表?
CPU负蝲?
CPU负蝲量时Q需要用到额外的外挂程序,是sysstatq个E序?
1Q下载ƈ安装sysstat-4.0.2-1.i386.rpmQ?
2Q?~写外挂E序
可以应用安装完sysstat套g后生的/usr/bin/sarE序q行外挂E序的编写,也可以用bash写一个监CPU的小E序。示例如下:
3Q开始设定MRTG参数,Ҏ如下Q?
q之后开始执行参数项Q注意,要执行三ơ以上:
4Q写入到/etc/crontab当中Q?
q样OK了,直接Web指向http://your.host.domain/mrtg/cpu/localhost.html?
再来说说sar。基本上Qsar可以用来很多的东西Q例如:sarQ?u 1 5,每一U钟一ơCPUQ共计五ơ后^均;sarr 3 3,每三U看一ơ实体与虚拟内存用量Q三ơ后^均?
]]>
proc文gpȝ是一个伪文gpȝQ它只存在内存当中,而不占用外存I间。它以文件系l的方式问系l内核数据的操作提供接口。用户和应用E序可以通过proc得到pȝ的信息,q可以改变内核的某些参数。由于系l的信息Q如q程Q是动态改变的Q所以用h应用E序dproc文gӞproc文gpȝ是动态从pȝ内核d所需信息q提交的。它的目录结构如下:
目录名称 目录内容
apm 高甉|理信息
cmdline 内核命o?nbsp;
Cpuinfo 关于Cpu信息
Devices 可以用到的设备(块设?字符讑֤Q?nbsp;
Dma 使用的DMA通道
Filesystems 支持的文件系l?nbsp;
Interrupts 中断的?nbsp;
Ioports I/O端口的?nbsp;
Kcore 内核核心印象
Kmsg 内核消息
Ksyms 内核W号?nbsp;
Loadavg 负蝲均衡
Locks 内核?nbsp;
Meminfo 内存信息
Misc 杂项
Modules 加蝲模块列表
Mounts 加蝲的文件系l?nbsp;
Partitions pȝ识别的分
Rtc 实时旉
Slabinfo Slab池信?
Stat 全面l计状态表
Swaps ҎI间的利用情?nbsp;
Version 内核版本
Uptime pȝ正常q行旉
q不是所有这些目录在你的pȝ中都有,q取决于你的内核配置和装载的模块。另外,?proc下还有三个很重要的目录:netQscsi和sys。Sys目录是可写的Q可以通过它来讉K或修改内核的参数Q见下一部分Q,而net和scsi则依赖于内核配置。例如,如果pȝ不支持scsiQ则scsi目录不存在?nbsp;
除了以上介绍的这些,q有的是一些以数字命名的目录,它们是进E目录。系l中当前q行的每一个进E都有对应的一个目录在/proc下,以进E的PID号ؓ目录名,它们是读取进E信息的接口。而self目录则是dq程本n的信息接口,是一个link。Proc文gpȝ的名字就是由之而v。进E目录的l构如下Q?nbsp;
目录名称 目录内容
Cmdline 命o行参?nbsp;
Environ 环境变量?nbsp;
Fd 一个包含所有文件描q符的目?nbsp;
Mem q程的内存被利用情况
Stat q程状?nbsp;
Status q程当前状态,以可ȝ方式昄出来
Cwd 当前工作目录的链?nbsp;
Exe 指向该进E的执行命o文g
Maps 内存映象
Statm q程内存状态信?nbsp;
Root 链接此进E的root目录
用户如果要查看系l信息,可以用cat命o。例如:
# cat /proc/interrupts
CPU0
0: 8728810 XT-PIC timer
1: 895 XT-PIC keyboard
2: 0 XT-PIC cascade
3: 531695 XT-PIC aha152x
4: 2014133 XT-PIC serial
5: 44401 XT-PIC pcnet_cs
8: 2 XT-PIC rtc
11: 8 XT-PIC i82365
12: 182918 XT-PIC Mouse
13: 1 XT-PIC fpu PS/2
14: 1232265 XT-PIC ide0
15: 7 XT-PIC ide1
NMI: 0
用户q可以实C改内核参数。在/proc文gpȝ中有一个有的目录Q?proc/sys。它不仅提供了内怿息,而且可以通过它修改内核参敎ͼ来优化你的系l。但是你必须很小心,因ؓ可能会造成pȝ崩溃。最好是先找一台无关紧要的机子Q调试成功后再应用到你的pȝ上?
要改变内核的参数Q只要用vi~辑或echo参数重定向到文g中即可。下面有一个例子:
# cat /proc/sys/fs/file-max
4096
# echo 8192 > /proc/sys/fs/file-max
# cat /proc/sys/fs/file-max
8192
如果你优化了参数Q则可以把它们写成添加到文grc.local中,使它在系l启动时自动完成修改?
/proc文gpȝ中网l参?
?proc/sys/net/ipv4/目录下,包含的是和tcp/ip协议相关的各U参敎ͼ下面我们对q些|络参数加以详细的说明?
ip_forward 参数cdQBOOLEAN
0 - 关闭(默认?
not 0 - 打开ip转发
在网l本地接口之间{发数据报。该参数非常ҎQ对该参数的修改导致其它所有相关配|参数恢复其默认?对于L参阅RFC1122Q对于\由器参见RFC1812)
ip_default_ttl 参数cdQINTEGER
默认gؓ 64 。表CIP数据报的Time To Live倹{?
ip_no_pmtu_disc 参数cdQBOOLEAN
关闭路径MTU探测Q默认gؓFALSE
ipfrag_high_thresh 参数cdQ整?
用来l装分段的IP包的最大内存量。当ipfrag_high_thresh数量的内存被分配来用来组装IP包,则IP分片处理器将丢弃数据报直到ipfrag_low_thresh数量的内存被用来l装IP包?
ipfrag_low_thresh 参数cdQ整?
参见ipfrag_high_thresh?
ipfrag_time 参数cdQ整?
保存一个IP分片在内存中的时间?
inet_peer_threshold 参数cdQ整?
INET对端存储器某个合适|当超q该阀值条目将被丢弃。该阀值同样决定生存时间以及废物收集通过的时间间隔。条目越多﹐存活期越低﹐GC 间隔短
inet_peer_minttl 参数cdQ整?
条目的最低存zL。在重组端必要有够的片(fragment)存活期。这个最低存zL必须保证~冲池容U是否少?inet_peer_threshold。该g jiffies为单位测量?
inet_peer_maxttl 参数cdQ整?
条目的最大存zL。在此期限到达之后﹐如果~冲池没有耗尽压力的话(例如H缓冲池中的条目数目非常?H不使用的条目将会超时。该g jiffies为单位测量?
inet_peer_gc_mintime 参数cdQ整?
废物攉(GC)通过的最短间隔。这个间隔会影响到缓冲池中内存的高压力?该g jiffies为单位测量?
inet_peer_gc_maxtime 参数cdQ整?
废物攉(GC)通过的最大间隔,q个间隔会媄响到~冲池中内存的低压力?该g jiffies为单位测量?
tcp_syn_retries 参数cdQ整?
对于一个新接,内核要发送多个 SYN q接h才决定放弃。不应该大于255Q默认值是5Q对应于180U左叟?
tcp_synack_retries 参数cdQ整?
对于q端的连接请求SYNQ内怼发送SYN Q?ACK数据报,以确认收C一?SYNq接h包。这是所谓的三次握手( threeway handshake)机制的第二个步骤。这里决定内核在攑ּq接之前所送出?SYN+ACK 数目?nbsp;
tcp_keepalive_time 参数cdQ整?
当keepalive打开的情况下QTCP发送keepalive消息的频率,默认值是2个小时?
tcp_keepalive_probes 参数cdQ整?
TCP发送keepalive探测以确定该q接已经断开的次敎ͼ默认值是9?
tcp_keepalive_interval 参数cdQ整?
探测消息发送的频率Q乘以tcp_keepalive_probes得到对于从开始探以来没有响应的q接杀除的旉。默认gؓ75U,也就是没有活动的q接在大约11分钟以后被丢弃?
tcp_retries1 参数cdQ整?
当出现可疑情况而必d|络层报告这个可疑状况之前﹐需要进行多次重试。最低的 RFC 数值是 3 H这也是默认|ҎRTO的值大U在3U?- 8分钟之间?
tcp_retries2 参数cdQ整?
在丢弃激zȝTCPq接之前H需要进行多次重试。RFC1122规定Q该值必d?00U。默认gؓ15Q根据RTO的值来军_Q相当于13-30分钟Q?
tcp_orphan_retries 参数cdQ整?
在近端丢弃TCPq接之前H要q行多少ơ重试。默认值是 7 个﹐相当?50U?- 16分钟H视 RTO 而定。如果您的系l是负蝲很大的web服务器﹐那么也许需要降低该|q类 sockets 可能会耗费大量的资源。另外参的?tcp_max_orphans ?
tcp_fin_timeout 参数cdQ整?
对于本端断开的socketq接QTCP保持在FIN-WAIT-2状态的旉。对方可能会断开q接或一直不l束q接或不可预料的q程M。默认gؓ 60 U。过d2.2版本的内怸?180 U。您可以讄该|但需要注意﹐如果您的机器载很重的web服务器﹐您可能要冒内存被大量无效数据报填满的风险HFIN-WAIT-2 sockets 的危险性低?FIN-WAIT-1 H因为它们最多只?1.5K 的内存﹐但是它们存在旉更长。另外参?tcp_max_orphans?nbsp;
tcp_max_tw_buckets 参数cdQ整?
pȝ在同时所处理的最大timewait sockets 数目。如果超q此数的话﹐time-wait socket 会被立即砍除q且昄警告信息。之所以要讑֮q个限制H纯_ؓ了抵御那些简单的 DoS dH千万不要h为的降低q个限制H不q﹐如果|络条g需要比默认值更多﹐则可以提高它(或许q要增加内存)?nbsp;
tcp_tw_recycle 参数cdQ布?
打开快?TIME-WAIT sockets 回收。默认值是1。除非得到技术专家的或要求﹐请不要随意修改这个倹{?nbsp;
tcp_max_orphans 参数cdQ整?
pȝ所能处理不属于Mq程的TCP sockets最大数量。假如超q这个数量﹐那么不属于Q何进E的q接会被立即resetQƈ同时昄警告信息。之所以要讑֮q个限制H纯_ؓ了抵御那些简单的 DoS dH千万不要依赖这个或是h为的降低q个限制
tcp_abort_on_overflow 参数cdQ布?
当守护进E太忙而不能接受新的连接,pҎ发送reset消息Q默认值是false。这意味着当溢出的原因是因Z个偶然的猝发Q那么连接将恢复状态。只有在你确信守护进E真的不能完成连接请求时才打开该选项Q该选项会媄响客L使用?
tcp_syncookies 参数cdQ整?
只有在内核编译时选择了CONFIG_SYNCOOKIES时才会发生作用。当出现syn{候队列出现溢出时象对方发送syncookies。目的是Z防止syn floodd。默认值是false?
注意Q该选项千万不能用于那些没有收到d的高负蝲服务器,如果在日志中出现synflood消息Q但是调查发现没有收到synflooddQ而是合法用户的连接负载过高的原因Q你应该调整其它参数来提高服务器性能。参? tcp_max_syn_backlog, tcp_synack_retries, tcp_abort_on_overflow.
syncookie严重的违背TCP协议Q不允许使用TCP扩展Q可能对某些服务D严重的性能影响(如SMTP转发)?
tcp_stdurg 参数cdQ整?
使用 TCP urg pointer 字段中的Lh解释功能。大部䆾的主机都使用老旧?BSD解释Q因此如果您?Linux 打开它﹐或会D不能和它们正沟通。默认gؓ为﹕FALSE
tcp_max_syn_backlog 参数cdQ整?
对于那些依然q未获得客户端确认的q接hH需要保存在队列中最大数目。对于超q?128Mb 内存的系l﹐默认值是 1024 H低?128Mb 的则?128。如果服务器l常出现q蝲H可以尝试增加这个数字。警告﹗假如您将此D为大?1024H最好修?include/net/tcp.h 里面?TCP_SYNQ_HSIZE H以保持 TCP_SYNQ_HSIZE*16<=tcp_max_syn_backlog Hƈ且编q核心之内?nbsp;
tcp_window_scaling 参数cdQ布?
正常来说QTCP/IP 可以接受最大到65535字节?windows。对于宽带网l,该值可能是不够的,通过调整该参数有助于提高宽带服务器性能?
tcp_timestamps 参数cdQ布?
Timestamps 用在其它一些东西中H可以防范那些伪造的 sequence L。一?G的宽带线路或怼重遇到带 out-of-line数值的旧sequence L(假如它是׃上次产生?。Timestamp 会让它知道这是个 '旧封??nbsp;
tcp_sack 参数cdQ布?
使用 Selective ACKH它可以用来查找特定的遗q数据?-- 因此有助于快速恢复状态?
tcp_fack 参数cdQ布?
打开FACK拥塞避免和快速重传功能?
tcp_dsack 参数cdQ布?
允许TCP发?两个完全相同"的SACK?
tcp_ecn 参数cdQ布?
打开TCP的直接拥塞通告功能?
tcp_reordering 参数cdQ整?
TCP中重排序的数据报最大数量默认值是 3 ?
tcp_retrans_collapse 参数cdQ布?
对于某些有bug的打印机提供针对其bug的兼Ҏ?
tcp_wmem - 三个整数的向量: min, default, max
minQؓTCP socket预留用于发送缓冲的内存最倹{每个tcp socket都可以在以后都可以用它。默认gؓ4K?
defaultQؓTCP socket预留用于发送缓冲的内存数量Q默认情况下该g影响其它协议使用的net.core.wmem_default |一般要低于net.core.wmem_default的倹{默认gؓ16K?
max: 用于TCP socket发送缓冲的内存最大倹{该g会媄响net.core.wmem_maxQ今天选择参数SO_SNDBUF则不受该值媄响。默认gؓ128K?
tcp_rmem - 三个整数的向量: min, default, max
minQؓTCP socket预留用于接收~冲的内存数量,即在内存出现紧张情况下tcp socket都至会有这么多数量的内存用于接收缓Ԍ默认gؓ8K?
defaultQؓTCP socket预留用于接收~冲的内存数量,默认情况下该值媄响其它协议用的 net.core.wmem_default 倹{该值决定了在tcp_adv_win_scale、tcp_app_win和tcp_app_win:0是默认值情况下Qtcp H口大小?5535?
maxQ用于TCP socket接收~冲的内存最大倹{该g会媄?net.core.wmem_maxQ今天选择参数 SO_SNDBUF则不受该值媄响。默认gؓ 128K。默认gؓ87380*2 bytes?
tcp_mem - 三个整数的向量: low, pressure, high
lowQ当TCP使用了低于该值的内存面数时QTCP不会考虑释放内存?
pressureQ当TCP使用了超q该值的内存面数量ӞTCP试图E_其内存用,q入pressure模式Q当内存消耗低于low值时则退出pressure状态?
highQ允许所有tcp sockets用于排队~冲数据报的面量?
一般情况下q些值是在系l启动时Ҏpȝ内存数量计算得到的?
tcp_app_win - 整数
保留max(window/2^tcp_app_win, mss)数量的窗口由于应用缓册Ӏ当?时表CZ需要缓册Ӏ默认值是31?
tcp_adv_win_scale - 整数
计算~冲开销bytes/2^tcp_adv_win_scale(如果tcp_adv_win_scale > 0)或者bytes-bytes/2^(-tcp_adv_win_scale)(如果tcp_adv_win_scale <= 0Q,默认gؓ2?
ip_local_port_range - 两个整数
定于TCP和UDP使用的本地端口范_W一个数是开始,W二个数是最后端口号Q默认g赖于pȝ中可用的内存敎ͼ
> 128Mb 32768-61000
< 128Mb 1024-4999 or even less.
该值决定了zdq接的数量,也就是系l可以ƈ发的q接?
icmp_echo_ignore_all - 布尔cd
icmp_echo_ignore_broadcasts - 布尔cd
如果M一个设|ؓtrue(>0)则系l将忽略所有发送给自己的ICMP ECHOh或那些广播地址的请求?
icmp_destunreach_rate - 整数
icmp_paramprob_rate - 整数
icmp_timeexceed_rate - 整数
icmp_echoreply_rate - 整数(not enabled per default)
限制发向特定目标的ICMP数据报的最大速率?表示没有M限制Q否则表Cjiffies数据单位中允许发送的个数?
icmp_ignore_bogus_error_responses - 布尔cd
某些路由器违背RFC1122标准Q其对广播发送伪造的响应来应{。这U违背行为通常会被以告警的方式记录在系l日志中。如果该选项讄为TrueQ内怸会记录这U警告信息。默认gؓFalse?
(1) Jiffie: 内核使用的内部时间单位,在i386pȝ上大ؓ1/100sQ在Alpha中ؓ1/1024S。在/usr/include/asm/param.h中的HZ定义有特定系l的倹{?
conf/interface/*:
conf/all/*是特定的Q用来修Ҏ有接口的讄Qis special and changes the settings for all interfaces.
Change special settings per interface.
log_martians - 布尔cd
记录带有不允许的地址的数据报到内核日志中?
accept_redirects - 布尔cd
收发接收ICMP重定向消息。对于主机来说默认ؓTrueQ对于用作\由器旉认gؓFalse?
forwarding - 布尔cd
在该接口打开转发功能
mc_forwarding - 布尔cd
是否q行多播路由。只有内核编译有CONFIG_MROUTEq且有\由服务程序在q行该参数才有效?
proxy_arp - 布尔cd
打开proxy arp功能?
shared_media - 布尔cd
发?路由?或接?L) RFC1620 ׃n媒体重定向。覆盖ip_secure_redirects的倹{默认ؓTrue?
secure_redirects - 布尔cd
仅仅接收发给默认|关列表中网关的ICMP重定向消息,默认值是TRUE?
send_redirects - 布尔cd
如果是routerQ发送重定向消息Q默认值是TRUE
bootp_relay - 布尔cd
接收源地址?.b.c.dQ目的地址不是本机的数据报。用来支持BOOTP转发服务q程Q该q程捕获ƈ转发该包。默认ؓFalseQ目前还没有实现?
accept_source_route - 布尔cd
接收带有SRR选项的数据报。对于主机来说默认ؓFalseQ对于用作\由器旉认gؓTrue?
rp_filter 参数cd
1 - 通过反向路径回溯q行源地址验证(在RFC1812中定?。对于单I主机和stub|络路由器推荐用该选项?
0 - 不通过反向路径回溯q行源地址验证?
默认gؓ0。某些发布在启动时自动将其打开?/P>
无Y驱和光驱Q很多公ؓ了节省成本,计算Z般都不带光驱或Y驱,q样无法通过本地安装LinuxQ?
非标准的软驱和光驱:虽然W记本都会配|光驱,但是q不一定都是标准的IDE讑֤Q有些是通过USB接口Q有些是通过1394接口Q例如Samsung的Q10Q。在Linux安装时所引导的Linux内核一般都不会带这些接口的驱动Q所以也无法通过本地安装LinuxQ?
另外Q在一些场合,如机房中Q有大量的计机需要同时安装LinuxQ如果通过光驱的方式一个个安装Q不仅效率低Q也不利于维护?
W者在工作q程中,遇到过W二U情c一台Samsung的Q10W记本需要安装Redhat Linux 8.0Q但是通过光驱引导后发玎ͼ安装E序无法讉K光盘。针对这个问题,W者经q查阅资料和摸烦Q找C在Q10上安装Linux的方法。在下面的讨ZQ如不做特别声明Q都以Q10ZQ介l如何通过PXE Bootrom来远E安装Linux?/P>
2Q?基本原理
1Q?什么是PXE
PXE(Pre-boot Execution Environment)是由Intel设计的协议,它可以计算机通过|络启动。协议分为client和server两端QPXE client在网卡的ROM中,当计机引导ӞBIOS把PXE client调入内存执行Qƈ昄出命令菜单,l用户选择后,PXE client放|在q端的操作系l通过|络下蝲到本地运行?/P>
PXE协议的成功运行需要解决以下两个问题:
既然是通过|络传输Q那么计机在启动时Q它的IP地址p来配|;
通过什么协议下载Linux内核和根文gpȝ
对于W一个问题,可以通过DHCP Server解决Q由DHCP server来给PXE client分配一个IP地址QDHCP Server是用来给DHCP Client动态分配IP地址的协议,不过׃q里是给PXE Client分配IP地址Q所以在配置DHCP ServerӞ需要增加相应的PXEҎ配置?/P>
至于W二个问题,在PXE client所在的ROM中,已经存在了TFTP Client。PXE Client使用TFTP ClientQ通过TFTP协议到TFTP Server上下载所需的文件?/P>
q样QPXE协议q行的条件就具备了,下面我们来看看PXE协议的工作过E?/P>
2Q?工作q程
在上图中QPXE client是需要安装Linux的计机QTFTP Server和DHCP Serverq行在另外一台Linux Server上。Bootstrap文g、配|文件、Linux内核以及LinuxҎ件系l都攄在Linux Server上TFTP服务器的根目录下?/P>
PXE client在工作过E中Q需要三个二q制文gQbootstrap、Linux 内核和LinuxҎ件系l。Bootstrap文g是可执行E序Q它向用h供简单的控制界面QƈҎ用户的选择Q下载合适的Linux内核以及LinuxҎ件系l?/P>
3Q?步骤
有了前面的背景知识,接下来就可以正式操作了,下面按照序l出了操作步骤:
1Q?配置DHCP Server
选用ISC dhcp-3.0QDHCP Server的配|文件是/etc/dhcpd.confQ配|文件的内容如下Q?/P>
option space PXE;
option PXE.mtftp-ip code 1 = ip-address;
option PXE.mtftp-cport code 2 = unsigned integer 16;
option PXE.mtftp-sport code 3 = unsigned integer 16;
option PXE.mtftp-tmout code 4 = unsigned integer 8;
option PXE.mtftp-delay code 5 = unsigned integer 8;
option PXE.discovery-control code 6 = unsigned integer 8;
option PXE.discovery-mcast-addr code 7 = ip-address;
class "pxeclients" {
match if substring (option vendor-class-identifier, 0, 9) = "PXEClient";
option vendor-class-identifier "PXEClient";
vendor-option-space PXE;
# At least one of the vendor-specific PXE options must be set in
# order for the client boot ROMs to realize that we are a PXE-compliant
# server. We set the MCAST IP address to 0.0.0.0 to tell the boot ROM
# that we can't provide multicast TFTP (address 0.0.0.0 means no
# address).
option PXE.mtftp-ip 0.0.0.0;
# This is the name of the file the boot ROMs should download.
filename "pxelinux.0";
# This is the name of the server they should get it from.
next-server 192.168.0.1;
}
ddns-update-style interim;
ignore client-updates;
default-lease-time 1200;
max-lease-time 9200;
option subnet-mask 255.255.255.0;
option broadcast-address 192.168.0.255;
option routers 192.168.0.254;
option domain-name-servers 192.168.0.1,192.168.0.2;
option domain-name "mydomain.org";
subnet 192.168.0.0 netmask 255.255.255.0 {
range 192.168.0.10 192.168.0.100;
}
host q10 {
hardware ethernet 00:00:F0:6B:38:5B;
fixed-address 192.168.0.22;
}
dhcpd.conf配置文g中几个关键部分说明如下:host q10{…}定义了笔记本Q10|卡的MAC地址与IP地址的对应关p,表明DHCP Server为Q10分配一个固定的IPQ?92.168.0.22Qfilename ""指定bootstrap的文件名Qnetx-server指定TFTP Server的地址。其它的配置误者参考DHCP Server的手册?/P>
2Q?配置TFTP server
选用tftp-hpaQTFTP Server的配|文件是/etc/xinetd.d/tftpQ配|文件的内容如下Q?/P>
service tftp
{
socket_type = dgram
protocol = udp
wait = yes
user = root
server = /usr/sbin/in.tftpd
server_args = -u nobody -s /tftpboot
disable = no
per_source = 11
cps = 100 2
}
q里制定?tftpboot为TFTP Server的根目录位置?/P>
3Q?配置bootstrap
bootstrap文g在dhcpd.conf中被指定为pxelinux.0文gQ放|在/tftpboot。Linux内核以及LinuxҎ件系l也攄?tftpboot。pxelinux.0在执行过E中Q要读配|文Ӟ所有的配置文g都放?tftpboot/pxelinux.cfg/目录下。由于PXElinuxhZ同的PXE Client提供不同的Linux内核以及Ҏ件系l的功能Q所以要通过不同的配|文件名来区分出不同的PXE Client的需求。比如一个PXE Client由DHCP Server分配的IP地址?92.168.0.22Q那么相对应的配|文件名?tftpboot/pxelinux.cfg/C0A80016Q注QC0A80016为IP地址192.168.0.22的十六进制表C)。如果找不到Q就按照序C0A80016-> C0A8001-> C0A800-> C0A80-> C0A8-> C0A-> C0-> C->default查找配置文g?/P>
/tftpboot/pxelinux.cft/C0A80001配置文g的具体内容如下:
DEFAULT install
PROMPT 1
LABEL install
KERNEL vmlinuz
APPEND initrd=initrd.img devfs=nomount ramdisk_size=16384
此配|文件指定了Linux内核以及Ҏ件系l的名称Qƈl内怼递了一些参敎ͼ其中ramdisk_size参数要非常注意,它指定Linux内核启动后徏立ramdisk的大,如果讄太小QLinux的安装过E就可能无法q行?/P>
4Q?制作Linux内核/Ҏ件系l?/P>
因ؓ需要通过|络安装Q所有选择Redhat Linux 8.0安装盘(disk #1Q中E:\images\bootnet.imgQ光q盘符为E:Q。bootnet.img包括Linux内核、LinuxҎ件系l(有安装程序在内)。用bootnet.img制作一张引DY盘,Ҏ在DOS命o行运行E:\dosutils\rawrite E:\images\bootnet.imgQ根据提C制作。制作完毕后Q将引导软盘中的vmlinuzQLinux内核Q和initrd.imgQLinuxҎ件系l)拯到Linux Server?tftpboot下?/P>
5Q?启动DHCP Server/TFTP Server
在Linux Server上,q行service dhcpd start和service xinetd restart?/P>
6Q?启动Q10
Q10加电后,在出现Samsung公司徽标Ӟ在左下角会提C用hF12q入|络引导。按F12后,Q10q入|络引导q程。首先通过DHCP Server获得了IP地址Q然后下载ƈ执行bootstrap文gpxelinux.0Q在执行中,d配置文g/tftpboot/pxelinux.cfg/C0A80016。此时屏q上出现boot:Q敲入installQ就q入了Redhat Linux 8.0的网l安装界面,一切OK!
安装
可以从Squid站点www.squid-cache.org获取该Y件的源代...的发行版Q如Red Hat提供的RPM包?
RPM方式安装很简单,命o如下Q?
$ rpm -ivh Squid-2.x.STALBx.i386.rpm
不过W者认为,即便是系l中已经默认安装了SquidQ也应当先删掉然后安装最新的源代码包。因为开源Y件会不断修正问题、提供更新的功能Q用最新版本可以保证最高的性能及安全,而且源代码方式可以完全定制系l。不qSTABLEE_版、DEVEL版通常是提供给开发h员测试程序的Q假定下载了最新的E_版squid-2.5.STABLE2.tar.gzQ用以下命o解开压羃包:
$ tar xvfz squid-2.5.STABLE.tar.gz
用bz2方式压羃的包可能体积更小Q相应的命o是:
$ tar xvfj squid-2.5.STABLE.tar.bz2
然后Q进入相应目录对源代码进行配|和~译Q命令如下:
$ cd squid-2.5.STABLE2
配置命oconfigure有很多选项Q如果不清楚可先用?help”查看。通常情况下,用到的选项有以下几个:
--prefix=/web/squid
#指定Squid的安装位|,如果只指定这一选项Q那么该目录下会有bin、sbin、man、conf{目录,而主要的配置文g此时在conf子目录中。ؓ便于理Q最好用参数--sysconfdir=/etc把这个文件位|配|ؓ/etc?
--enable-storeio=ufs,null
#使用的文件系l通常是默认的ufsQ不q如果想要做一个不~存M文g的代理服
务器Q就需要加上null文gpȝ?
--enable-arp-acl
#q样可以在规则设|中直接通过客户端的MAC地址q行理Q防止客户用IPƺ骗?
--enable-err-languages="Simplify_Chinese"
--enable-default-err-languages="Simplify_Chinese"
#上面两个选项告诉Squid~入q用简体中文错误信息?
--enable-linux-netfilter
#允许使用Linux的透明代理功能?
--enable-underscore
#允许解析的URL中出C划线Q因为默认情况下Squid会认为带下划U的URL?
非法的,q拒l访问该地址?
整个配置~译q程如下Q?
./configure --prefix=/var/squid
--sysconfdir=/etc
--enable-arp-acl
--enable-linux-netfilter
--enable-pthreads
--enable-err-language="Simplify_Chinese"
--enable-storeio=ufs,null
--enable-default-err-language="Simplify_Chinese"
--enable-auth="basic"
--enable-baisc-auth-helpers="NCSA"
--enable-underscore
其中一些选项有特D作用,在下面介绍它们?
最后执行make和make install两条命oQ将源代码编译ؓ可执行文Ӟq拷贝到指定位置?
基本配置
安装完成后,接下来要对Squid的运行进行配|(不是前面安装时的配置Q。所有项目都在squid.conf中完成。Squid自带的squid.conf包括非常详尽的说明,相当于一用h册,寚w|有M疑问都可以参照解冟?
在这个例子中Q代理服务器同时也是|关Q内部网l接口eth0的IP地址?92.168.0.1Q外部网l接口eth1的IP地址?02.103.x.x。下面是一个基本的代理所需要配|选项Q?
http_port 192.168.0.1:3128
默认端口?128Q当然也可以是Q何其它端口,只要不与其它服务发生冲突卛_。ؓ了安全v见,在前面加上IP地址QSquid׃会监听外部的|络接口?
下面的配|选项是服务器理者的电子邮gQ当错误发生Ӟ该地址会显C在错误面上,便于用户联系Q?
cache_mgr start@soocol.com
以下q些参数告诉Squid~存的文件系l、位|和~存{略Q?
cache_dir ufs /var/squid
cache_mem 32MB
cache_swap_low 90
cache_swap_high 95
在这里,Squid会将/var/squid目录作ؓ保存~存数据的目录,每次处理的缓存大是32兆字节,当缓存空间用达?5%Ӟ新的内容取代旧的而不直接d到目录中Q直到空间又下降?0%才停止这一zd。如果不想Squid~存M文gQ如某些存储I间有限的专有系l,可以使用null文gpȝQ这样不需要那些缓存策略)Q?
cache_dir null /tmp
下面的几个关于缓存的{略配置中,较主要的是第一行,即用L讉K记录Q可以通过分析它来了解所有用戯问的详尽地址Q?
cache_access_log /var/squid/access.log
cache_log /var/squid/cache.log
cache_store_log /var/squid/store.log
下面q行配置是在较新版本中出现的参数Q告诉Squid在错误页面中昄的服务器名称Q?
visible_hostname No1.proxy
以下配置告诉Squid如何处理用户Q对每个h的IP地址作ؓ单独地址处理Q?
client_mask 255.255.255.255
如果是普通代理服务器Q以上的配置已经_。但是很多Squid都被用来做透明代理。所谓透明代理Q就是客L不知道有代理服务器的存在Q当然也不需要进行Q何与代理有关的设|,从而大大方便了pȝ理员。相关的选项有以下几个:
httpd_accel_host virtual
httpd_accel_port 80
httpd_accel_with_proxy on
httpd_accel_user_host_header on
在Linux上,可以用iptables/ipchains直接对Web端口80的请求直接{发到Squid端口3128Q由Squid接手Q而用h览器仍然认ؓ它访问的是对方的80端口。例如以下这条命令:
iptables -t nat -A PREROUTING -s 192.168.0.200/32 -p tcp --dport 80 -j REDIRECT 3128
是?92.168.0.200的所有针?0端口的访问重定向?128端口?
所有设|完成后Q关键且重要的Q务是讉K控制。Squid支持的管理方式很多,使用h也非常简单(q也是有人宁愿用不做Q何缓存的SquidQ也不愿意单独用iptables的原因)。Squid可以通过IP地址、主机名、MAC地址、用?密码认证{识别用P也可以通过域名、域后缀、文件类型、IP地址、端口、URL匚w{控制用L讉KQ还可以使用旉区间对用戯行管理,所以访问控制是Squid配置中的重点。Squid用ACLQAccess Control ListQ访问控制列表)对访问类型进行划分,用http_access deny 或allowq行控制。根据需求首先定义两l用户advance和normalQ还有代表所有未指明的用Lall及不允许上网的baduserQ配|代码如下:
acl advance 192.168.0.2-192.168.0.10/32
acl normal src 192.168.0.11-192.168.0.200/32
acl baduser src 192.168.0.100/32
acl baddst dst www.soocol.com
acl all src 0.0.0.0/0
http_access deny baduser
http_access allow advance
http_access allow normal
可以看出QACL的基本格式如下:
acl 列表名称 控制方式 控制目标
比如acl all src 0.0.0.0/0Q其名称是allQ控制方式是src源IP地址Q控制目标是0.0.0.0/0的IP地址Q即所有未定义的用戗出于安全考虑QL在最后禁止这个列表?
下面q个列表代表高用户Q包括IP地址?92.168.0.2?92.168.0.10的所有计机Q?
acl advance 192.168.0.2-192.168.0.20/32
下面q个baduser列表只包含一台计机Q其IP地址?92.168.0.100Q?
acl baduser 192.168.0.100/32
ACL写完后,接下来要对它们分别进行管理,代码如下Q?
http_access deny baduser
http_access allow advance
http_access allow normal
上面几行代码告诉Squid不允许baduserl访问InternetQ但advance、normall允许(此时q没有指定详l的权限Q。由于Squid是按照顺序读取规则,会首先禁止baduserQ然后允许normal。如果将两条规则序颠倒,׃baduser在normal范围中,Squid先允怺所有的normalQ那么再止baduser׃会v作用?
特别要注意的是,Squid用allow-deny-allow-deny……这L序套用规则。例如,当一个用戯问代理服务器ӞSquid会顺序测试Squid中定义的所有规则列表,当所有规则都不匹配时QSquid会用与最后一条相反的规则。就像上面这个例子,假设有一个用LIP地址?92.168.0.201Q他试图通过q台代理服务器访问InternetQ会发生什么情况呢Q我们会发现Q他能够正常讉KQ因为SquidN所有访问列表也没有?92.168.0.201有关的定义,便开始应用规则,而最后一条是denyQ那么Squid默认的下一条处理规则是allowQ所?92.168.0.201反而能够访问Internet了,q显然不是我们希望的。所以在所有squid.conf中,最后一条规则永q是http_access deny allQ而all是前面定义的“src 0.0.0.0”?
高控制
前面说过QSquid的控制功能非常强大,只要理解Squid的行为方式,基本上就能够满所有的控制要求。下面就一步一步来了解Squid是如何进行控制管理的?
通过IP地址来识别用户很不可靠,比IP地址更好的是|卡的MAC物理地址。要在Squid中用MAC地址识别Q必d~译时加上?-enable-arp-acl”选项Q然后可以通过以下的语句来识别用户Q?
acl advance arp 00:01:02:1f:2c:3e 00:01:02:3c:1a:8b ...
它直接用用LMAC地址Q而MAC地址一般是不易修改的,即有普通用户将自己的IP地址改ؓ高用户也无法通过Q所以这U方式比IP地址可靠得多?
假如不想让用戯问某个网站应该怎么做呢Q可以分ZU情况:一U是不允许访问某个站点的某个LQ比如ok的主机是ok.sina.com.cnQ而其它的新浪资源却是允许讉K的,那么ACL可以q样写:
acl sinapage dstdomain ok.sina.com.cn
... ...
http_access deny ok
... ...
由此可以看到Q除了okQ其它如www.sina.com.cn、news.sina.com.cn都可以正常访问?
另一U情冉|整个|站都不许访问,那么只需要写个网站共有的域名卛_Q配|如下:
acl qq dstdomain .tcccent.com.cn
注意tcccent前面的?”,正是它指Z此域名结所有主机都不可讉KQ否则就只有tcccent.com.cnq一CZ能访问?
如果想禁止对某个IP地址的访问,?02.118.2.182Q可以用dst来控Ӟ代码如下Q?
acl badaddr dst 202.118.2.182
当然Q这个dst也可以是域名Q由Squid查询DNS服务器将其{换ؓIP?
q有一U比较广泛的控制是文件类型。如果不希望普通用户通过代理服务器下载MP3、AVI{文Ӟ完全可以对他们进行限Ӟ代码如下Q?
acl mmxfile urlpath_regex \.mp3$ \.avi$ \.exe$
http_access deny mmxfile
看到regexQ很多读者应该心领神会,因ؓq条语句使用了标准的规则表达式(又叫正则表达式)。它匹配所有以.mp3?avi{结URLhQ还可以?i参数忽略大小写,例如以下代码Q?
acl mmxfile urlpath_regex -i \.mp3$
q样Q无论是.mp3q是.MP3都会被拒l。当Ӟ-i参数适用于Q何可能需要区分大写的地方,如前面的域名控制?
如果惌普通用户只在上班时间可以上|,而且是每周的工作日,用Squid应当如何处理呢?看看下面的ACL定义Q?
acl worktime time MTWHF 8:30-12:00 14:00-18:00
http_access deny !worktime
首先定义允许上网的时间是每周工作日(星期一x期五Q的上午和下午的固定时段Q然后用http_access 定义所有不在这个时间段内的h都是不允许的?
或者ؓ了保证高U用L带宽Q希望每个用Lq发q接不能太多Q以免媄响他人,也可以通过Squid控制Q代码如下:
acl conncount maxconn 3
http_access deny conncount normal
http_access allow normal
q样Q普通用户在某个固定时刻只能同时发v三个q接Q从W四个开始,q接被拒绝?
MQSquid的ACL配置非常灉|、强大,更多的控制方式可以参考squid.conf.default?
认证
用户/密码认证为Squid理提供了更多便利,最常用的认证方式是NCSA。从Squid 2.5版本开始,NCSA认证包含在了basic中,而非以前单独的认证模块。下面来看看实现认证的具体操作?
首先在编译时配置选项应包括以下配|:
--enable-auth="basic" --enable-basic-auth-helpers="NCSA"
“make install”以后,需要将“helpers/basic_auth/NCSA/ncsa_auth”拷贝到用户可执行目录中Q如/usr/binQ如果在该目录中找不到这个执行文Ӟ在编译时请用make all而不是makeQ或者直接在该目录中执行makeQ,然后需要借助Apache的密码管理程序htpasswd来生成用户名/密码对应的文Ӟ像下面q行代码Q?
htpasswd -c /var/squid/etc/password guest
在输入两遍guest用户的密码后Q一个guest用户q成了。如果以后需要添加用P把上面的命oL-c参数再运行即可?
Squid 2.5在认证处理上有了较大的改变,q里只讨论2.5版本的处理方法,2.4及以下版本请参考squid.conf.default。在2.5版的squid.conf中,包括以下几个相关选项Q?
#该选项指出了认证方式(basic)、需要的E序Qncsa_authQ和
对应的密码文ӞpasswordQ?
auth_param basic program /usr/bin/ncsa_auth /var/squid/etc/password
# 指定认证E序的进E数
auth_param basic children 5
# 览器显C入用?密码对话框时的领域内?
auth_param basic realm My Proxy Caching Domain
# 基本的认证有效时?
auth_param basic credentialsttl 2 hours
# 普通用户需要通过认证才能讉KInternet
acl normal proxy_auth REQUIRED
http_access allow normal
通过以上的配|即可完成认证工作。有的读者可能要问:认证只针Ҏ通用P而高U用h直接上网的,该怎么处理呢?其实Q这两种用户是可以共存的。如前所qͼSquid是顺序处理http_access的,所以在http_access处理q程中,如果先处理normal用户Q那么当前用h论是否属于高U用P都会被要求进行认证;相反如果先处理高U用P剩下的就只有需要认证的普通用户了。例如以下配|代码:
...
http_access allow normal (需要认?
http_access allow advance Q不需要认证)
...
不管是否为noauth用户Q都要求q行用户?密码验证。正的Ҏ是将二者位|交换,代码如下Q?
...
http_access allow advance
http_access allow normal
...
q时Q高U用户不会受CQ何媄响?
ȝ
下面把整个squid.confȝ一下:
# 服务器配|?
http_port 192.168.0.1:3128
cache_mgr start@soocol.com
cache_dir null /tmp
cache_access_log /var/squid/access.log
cache_log /var/squid/cache.log
cache_store_log /var/squid/store.log
visible_hostname No1.proxy
client_mask 255.255.255.255
httpd_accel_host virtual
httpd_accel_port 80
httpd_accel_with_proxy on
httpd_accel_user_host_header on
# 用户分类
acl advance arp 00:01:02:1f:2c:3e 00:01:02:3c:1a:8b ...
acl normal proxy_auth REQUIED
acl all src 0.0.0.0
# 行ؓ分类
acl mmxfile urlpath_regex \.mp3$ \.avi$ \.exe$
acl conncount maxconn 3
acl worktime time MTWHF 8:30-12:00 14:00-18:00
acl sinapage dstdomain ok.sina.com.cn
acl qq dstdomain .tcccent.com.cn
# 处理
http_access allow advance
http_access deny conncount normal
http_access deny !worktime
http_access deny mmxfile
http_access deny sinapage
http_access deny qq
http_access allow normal
配置后的状况是,advancel可以不受Q何限制地讉KInternetQ而normall则只能在工作时间上|,而且不能下蝲多媒体文Ӟ不能讉K某些特定的站点,而且发送请求不能超q?个?
通过本文的介l,它可以了解Squid的基本能力。当Ӟ它的能力q不止此Q可以徏立强大的代理服务器阵列,可以帮助本地的Web服务器提高性能Q可以提高本地网l的安全性等。要惛_挥它的功效,q需要进一步控制?BR>
配置环境变量
~辑/etc/profile 加入下面句:
PATH=/usr/j2se/bin Q改Z安装j2sdk的\径)
JAVA_HOME=/usr/j2se Q改Z安装j2sdk的\径)
CLASSPATH=/usr/j2se/lib/tools.jar:/usr/j2se/lib/dt.jar Q改Z安装j2sdk的\径)
export PATH JAVA_HOME CLASSPATH
重新启动使之生效
_________________________________________________________________
Tomcat 5.0.25
?A >http://www.apache.org下蝲得到jakart...t-5.0.25.tar.gz
#gunzip jakarta-tomcat-5.0.25.tar.gz
#tar xvf jakarta-tomcat-5.0.25.tar
#mv jakarta-tomcat-5.0.25 /usr/local/tomcat5.0.25
#cd /usr/local/tomcat5.0.25/bin
#./catalina.sh start
然后试 http://localhost:8080 看到那个猫了吧,恭喜你tomcat安装ok
_____________________________________________________________________
安装apache2.0.50
估计用到的工hQgcc,automake,autoconfig;libtools,m4 大家可以M载rpm包安装就行了Q别忘了写h环境变量?:-P
?A >http://www.apache.org下蝲?/P>
gunzip httpd-2.0.50.tar.gz
tar xvf httpd-2.0.50.tar
cd httpd-2.0.50/bin
./configure -prefix=/usr/local/apache2 -enable-so (可改Z自己的目录;-enable-so用于加蝲connectorQ不可省略,你还可以加上你自q其他模块)
make
make install
cd /usr/local/apache2/conf
vi httpd.conf
更改Qservername 你的机器ip或域?BR>group nobody
listen yourip:80 Qapache2以后把port已经Ҏ了listenQ?/P>
保存后,cd ../bin
./apachectl start
试Q?A href="http://localhost">http://localhost 看到apache的欢q界面了吧,ok
_____________________________________________________________________________________
整合apache2与tomcat5.0.25
用连接器jakarta-tomcat-connectors-jk2-src-current.tar.gzQ就是jk2Q,大家可到http://jakarta.apache.org/site/sourceindex.cgi下蝲
gunzip jakarta-tomcat-connectors-jk2-src-current.tar.gz
tar xvf jakarta-tomcat-connectors-jk2-src-current.tar
cd jakarta-tomcat-connectors-jk2-src-current/jk/native2
./configure --with-apxs2=/usr/local/apache2/bin/apxs (注意改ؓ你的apache安装目录)
make
cd ../build/jk2/apache2
/usr/local/apache2/bin/apxs -n jk2 -i mod_jk2.so
现在大家可以看到mod_jk2.so文g已经在你的apache/modules/ 中了
~辑apache/conf/httpd.conf
LoadModule jk2_module modules/mod_jk2.so 保存
在apache/conf/中新建文件workers2.propertiesQ内容ؓ下(注意其中目录要改Z的目录噢Q:
[shm]
file=/usr/local/apache2/logs/shm.file
size=1048576
# Example socket channelQ?override port and host.
[channel.socket:localhost:8009]
port=8009
host=127.0.0.1
# define the worker
[ajp13:localhost:8009]
channel=channel.socket:localhost:8009
# Uri mapping
[uri:/*]
worker=ajp13:localhost:8009
保存后,快大功告成啦,呵呵
cd apache2/bin
./apachectl start
试Q?A href="http://localhost">http://localhost
使用LVS架设的服务器集群pȝ从体pȝ构上看是透明的,最l用户只感觉C个虚拟服务器.物理服务器之间可以通过高速的LAN或分布在各地的WAN相连。最前端是负载均衡器Q它负责各U服务请求分发给后面的物理服务器Q让整个集群表现得象一个服务于同一IP地址的虚拟服务器?
LVS集群pȝh良好的可扩展性和高可用性?
可扩展性是指,LVS集群建立后,可以很容易地Ҏ实际的需要增加或减少物理服务器。而高可用性是指当到服务器节Ҏ服务q程出错、失效时Q集系l能够自动进行适当的重新调整系l?
cente2.LVS是如何工作的
Linux Virtual Server的主要是在负载均衡器上实现的Q负载均衡器是一台加了LVS Patch?.2.x版内核的Linuxpȝ。LVS Patch可以通过重新~译内核的方法加入内核,也可以当作一个动态的模块插入现在的内怸?
负蝲均衡器可以运行在以下三种模式下中的一U或几种Q?1QVirtual Server via NATQVS-NATQ:用地址译实现虚拟服务器;2QVirtual Server via IP Tunneling QVS-TUNQ:用IP隧道技术实现虚拟服务器Q?QVirtual Server via Direct RoutingQVS-DRQ:用直接\由技术实现虚拟服务器?
另外Q还需要根据LVS应用对物理服务器q行恰当的配|?
以下分别讲qC下三U模式的工作原理和优~点?
2.1.Virtual server via NATQVS-NATQ?
Virtual Server via NATҎ的最大优Ҏ集群中的物理服务器可以用Q何支持TCP/IP操作pȝQ物理服务器可以分配Internet的保留私有地址Q只有负载均衡器需要一个合法的IP地址?
q种实现Ҏ的最大的~点是扩展性有限。当服务器节点(普通PC服务器)数据增长?0个或更多?负蝲均衡器将成ؓ整个pȝ的瓶颈,因ؓ所有的h包和应答包都需要经q负载均衡器再生。假使TCP包的q_长度?36字节的话Q^均包再生延迟旉大约?0usQ在Pentium处理器上计算的,采用更快的处理器得这个gq时间变短)Q负载均衡器的最大容许能力ؓ8.93M/sQ假定每台物理服务器的^台容许能力ؓ400K/s来计,负责均衡器能?2台物理服务器计算?
Virtual Server via NAT能够满许多服务器的服务性能需求。即使是是负载均衡器成ؓ整个pȝ的瓶颈,如果是这样也有两U方法来解决它。一U是混合处理Q另一U是采用Virtual Server via IP tunneling或Virtual Server via direct routing。如果采用合处理的ҎQ将需要许多同属单一的RR DNS域。你采用Virtual Server via IP tunneling或Virtual Server via direct routing以获得更好的可扩展性。也可以嵌套使用负蝲均衡器,在最前端的是VS-Tunneling或VS-Drouting的负载均衡器Q然后后面采用VS-NAT的负载均衡器?
2.2.Virtual server via IP tunnelingQVS-TUNQ?
采用VS-NAT方式Q请求与应答包都需要经q负载均衡器Q那么当服务器节点增长到20个或更多Ӟq个负蝲均衡器就可能成ؓ新的瓉。我们发玎ͼ许多Internet服务Q例如WEB服务器)的请求包很短,而应{包通常很大?
而用VS-TUN方式的话Q负载均衡器只负责将h包分发给物理服务器,而物理服务器应{包直接发给用户。所以,负蝲均衡器能处理很巨大的h量,q种方式Q一台负载均衡能q?00台的物理服务器服务,负蝲均衡器不再是pȝ的瓶颈。用VS-TUN方式Q如果你的负载均衡器拥有100M的全双工|卡的话Q就能得整个Virtual Server能达?G的吞吐量?
IP tunnelingQIP隧道Q能够用于架构一个高性能的virtual serverQ非帔R合构徏virtual proxy serverQ因为当代理服务器收ChQ能够让最l用L接与服务器联pR?
但是Q这U方式需要所有的服务器支持IP Tunneling(IP Encapsulation)协议Q我仅在Linuxpȝ上实Cq个Q如果你能让其它操作pȝ支持Q还在探索之中?
2.3.Virtual Server via Direct RoutingQVS-DRQ?
pVS-TUN一下,在VS-DR方式下,负蝲均衡器也只是分发hQ应{包通过单独的\由方法返回给客户端。这U方式能够大大提高Virtual Server的可扩展性。与VS-TUN相比QVS-DRq种实现方式不需要隧道结构,但它要求负蝲均衡器的|卡必须与物理网卡在一个物理段上?
而且VS-DR模式Q可以用大多数操作pȝ做ؓ物理服务器,其中包括QLinux 2.0.36?.2.9?.2.10?.2.12QSolaris 2.5.1?.6?.7QFreeBSD 3.1?.2?.3QNT4.0无需打补丁;IRIX 6.5QHPUX11{?
3.安装配置LVS
LVS的安装配|主要可以分成以下三个步骤:
1Q?下蝲LVS软gQ?
2Q?安装、配|负载均衡器Q?
3Q?安装、配|物理服务器Q?
3.1. 安装前的准备
1).下蝲LVS软gQ?
大家可以到LVS的主(http://www.linuxvirtualserver.orgQ,选择“Software”链接,选取最新版的补丁包Qtar包)下蝲。这个包里包含了内核补丁和源E序?
2).安装的指导思想
如果你选用了VS-NAT模式的话Q则可以使用所有支持TCP/IP协议的操作系l构建的机器作物理服务器Qƈ且无dM修改?
如果你选用了VS-TUN模式的话Q则选择Linux作物理服务器的操作系l,q根据后面的介绍做相应的讄?
如果你选用了VS-DR模式的话Q则可以选择大多数操作系l(如上节所qͼ作物理服务器QƈҎ后面的介l做相应的设|?
3).各种操作pȝ作物理服务器的要点详?
aQLinux 2.0.36
q种操作pȝ无需做Q何修改,可以运行在VS-NAT、VS-Tun、VS-DR三种模式下?
bQLinux 2.2.x
无需M修改可q行VS-NAT模式。而用VS-DR和VS-Tun两种模式可能会引起ARP问题。这U情?
必:t ?.2.x内核打补?
· Stephen WillIams的补丁包Q?
你可以在http://www.linuxvirtualserver.org/sdw_fullarpfix.patch获取Q它的原理十分简单:让物理服务器不响应对虚拟IP的ARPh?
· Julian Anastasov的补丁包Q?
你可以在http://www.linuxvirtualserver.org/arp_invisible-2213-2.diff处获取,然后用以下方法其生效:
echo 1 /proc/sys/net/ipv4/conf/interface_name/arp_invisible
t 新添一块网卡承载虚拟IP地址Q?
你可以选择一块ISA|卡或廉LPCI|卡来用于这个功能。你可以这个接口的ARP功能关闭?
t 物理服务器攄于与虚拟IP地址不同的网l上Qƈ且确认客L无法直接路由到物理服务器所在网Dc这U方法需要在负蝲均衡器上有两块网卡象防火墙一样工作?
t 在客L或\由器虚拟IP地址与负载均衡器的物理MAC地址l定?
t 使用IPCHINA重写每一个进入的包,其从lo接口送入?
cQ其它操作系l?
如果是VS-NAT的话Q无需修改。如果是VS-DR的话Q需要采取一些相应的配置Ҏ讄物理服务器的IP地址Q其拥有LVS的虚拟IP地址。用其它操作pȝ的话不能使用VS-TunҎ?
4).准备g环境
构徏服务器集系l,臛_需?台机器,1台用于负载均衡器Q?台用于物理服务器。少于这个数字的话就没有意义了?
负蝲均衡器:q行在打了补丁的2.2.x核心Linuxpȝ?
物理服务器:
VS-NATQQ何机器、Q何操作系l,q行Internet|络服务Q如 HTTP、FTP、Telnet、SMTP、NNTP、DNS{?
VS-TUNQQ何机器、支持IP隧道的操作系l(q今为止仅有LinuxQ?
VS-DRQQ何机器、大多操作系l?
3.2. 理解LVS的相x?
1).ipvsadm
ipvsadm是LVS的一个用L面。在负蝲均衡器上~译、安装ipvsadmQ?
ipvsadm sets
2).调度法
LVS的负载均衡器有以下几U调度规则:
Round-robinQ简UrrQweighted Round-robinQ简UwrrQ每个新的连接被轮流指派到每个物理服务器?
Least-connectedQ简UlcQweighted Least-connectedQ简UwlcQ每个新的连接被分配到负担最的服务器?
Persistent client connectionQ简UpccQ(持箋的客Lq接Q内?.2.10版以后才支持Q。所有来自同一个IP的客L一直连接到同一个物理服务器。超时时间被讄?60U。Pcc是ؓhttps和cookie服务讄的。在q处调度规则下,W一ơ连接后Q所有以后来自相同客L的连接(包括来自其它端口Q将会发送到相同的物理服务器。但q也会带来一个问题,大约?5Q的Internet可能h相同的IP地址QAOL?
客户是通过位于国弗吉gz的一台服务器q入Internet的)Q这U情况下只要有一个AOL的客戯接到一个物理服务器上,那么所有来自AOL的客戯接将都被q到q一台物理服务器上。这多么可怕呀Q?
3).Persistent port connection调度法
在内?.2.12版以后,pcc功能已从一个调度算法(你可以选择不同的调度算法:rr、wrr、lc、wlc、pccQ演变成Z一个开关选项Q你可以让rr?wrr、lc、wlc具备pcc的属性)。在讄Ӟ如果你没有选择调度法Ӟipvsadm默认ؓwlc法?
在Persistent port connection(ppc)法下,q接的指z是Z端口的,例如Q来自相同终端的80端口?43端口的请求,被分配C同的物理服务器上?
不幸的是Q如果你需要在的网站上采用cookies时将出问题,因ؓhttp是?0端口Q然而cookies需要?43端口Q这U方法下Q很可能会出现cookies不正常的情况?
3.3. 配置实例
1).例一Qhttps only
aQ在lvs_dr.conf 文g写入Q?
SERVICE=t https ppc 192.168.1.1
bQIpvsadm讄Q?
IP Virtual Server version 0.9.4 (size=4096)
Prot LocalAddress:Port Scheduler Flags
- RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP ssl.mack.net:https wlc persistent 360
- di.mack.net:https Route 1 0 0
2).例二QAll ports stickyQ超时ؓ30分,wrr调度法
aQ在lvs_dr.conf 文g写入Q?
SERVICE=t 0 wrr ppc -t 1800 192.168.1.1
#ppc persistent connection, timeout 1800 sec
/sbin/ipvsadm -A -t 192.168.1.110:0 -s wrr -p 1800
echo adding service 0 to realserver 192.168.1.1 using connection
Q接上行Q?type dr weight 1\"
/sbin/ipvsadm -a -t 192.168.1.110:0 -R 192.168.1.1 -g -w 1
bQIpvsadm讄Q?
# ipvsadm
IP Virtual Server version 0.9.4 (size=4096)
Prot LocalAddress:Port Scheduler Flags
- RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP ssl.mack.net:https wrr persistent 1800
- di.mack.net:https Route 1 0 0
3.4. 配置Ҏ
1).准备
用配|脚?.conf作ؓ输入产生rc.lvs脚本Q然后放|在/etc/init.d?etc/rc.d目录下?
早期版本的配|脚本可以运行在M机器上。然而现在的配置脚本Q针对不同的内核版本是有些不同的。你必须在负载均衡器上运行、检内核版本。将在负载均衡器上的配置文g和目录,通过nfs输出q个
目录到物理服务器上以供配|需要?必须先在负蝲均衡器上q行脚本rc.lvsQ然后在物理服务器上q行?
Ҏ你选择的LVS工作模式QVS-NAT、VS-Tun、VS-DRQ选择适当的conf文g模板Qlvs_nat.conf?
lvs_tun.conf、lvs_dr.confQ,然后Ҏ实际情况修改IP地址与服务。在~省状态下只配|了telnet服务?
telnet服务能够很方便地用于试Q当客户机telnetdӞҎ提示W就可以知道d到的是哪一台物?
服务器?
你可以编辑conf配置文g来增加其它的服务。在配置文g中提供了集群内部的IP地址?
Q?92.168.1.x/24?0.1.1.x/24Q?
在配|文件中Q你可以使用名称Q如telnetQ或端口Q如23Q来标识服务。用名U时要注意,M
/etc/services中匹配?etc/services文g内容如下所C:
ssh 22/tcp
domain 53/tcp nameserver dns #the string dns needs to be added here
domain 53/tcp nameserver dns #and here
https 443/tcp
https 443/udp
在多U情况下Q一台机器常需要多个IP地址Q你可以使用IP别名Q内核支持的可选项Q一般情况下已含在内怸Q来Z块网卡指定多个IP地址?
2).q行配置脚本
$ ./configure.pl lvs_nat.conf
q将产生一个rc.lvs_xxx脚本Q例如:rc.lvs_nat、rc.lvs_tun、rc.lvs_drQ以及mon_xxx.cf脚本。(E后rc.lvs_xxx攑ֈ/etc/rc.d?etc/init.d中去Q将mon_xxx.cf攑֜/etc/mon目录下)?
3).rc.lvs脚本选项
a). 载均衡器与物理服务器增加以太|设备和路由器;
b).使用fping查连接;
c).q行ipchainsQVS-NAT方式Q;
d).ȀzipforwardQ?
e).关闭ICMP重定向功能(VS-DR和VS-Tun方式Q;
f).增加ipvsadm服务?
4).l箋
在物理服务器上运行:
$ . ./rc.lvs_nat ?
$sh rc.lvs_nat
rc.lvs脚本能够自动判断是运行在负蝲均衡器(tests x /sbin/ipvsadmQ还是物理服务器上(查ifconfigQ?
查ipvsadm、ifconfig a和netstat rn的输出,查服?IP地址是否正确。如果不正确的话Q请?
新编辑然后再q行一ơ?
3.5.试LVS
查每一台物理服务器上运行的服务Q看它们的IP是不是LVS的虚拟IP—VIPQ用netstat anQ。如果运行rc.lvs_xxx脚本没有出错的话Q你从客Ltelnet到VIPQ在本文中是192.168.1.110Q,你将会登录到其中的一台物理服务器上,q看到这台物理服务器的登录提C?
在负载均衡器上查看ipvsadm的输出,你会?3端口上看C个与物理服务器的q接。而在物理服务器上执行Q? netstat -an | grep 23命o查看到相关信息。客Llogout退出后Q再ơ登录虚拟IPӞ你将会看到另一台物理服务器的登录提C符?
4 VS-NAT模式
VS-NAT是基于CISCO的负载均衡器QLocalDirector实现的?
4.1.安装VS-NAT
Ҏ下表讄客户端、负载均衡器、物理服务器的IP地址Q?
?1-2.客户端、负载均衡器、物理服务器的IP地址
??IP地址
客户?192.168.1.254
负蝲均衡器的虚拟IP 192.168.1.110(LVS表现的IP)
负蝲均衡器内部网?10.1.1.1
物理服务? 10.1.1.2
物理服务? 10.1.1.3
物理服务? 10.1.1.4
…?…?
物理服务器n 10.1.1.n+1
物理服务器的默认
|关 10.1.1.1
对于VS-NATҎ来说Q物理服务器必须位于与客h、LVS的虚拟IP地址不同的网D上Q也是说在物理服务器上不能直接PING通客h?
׃负蝲均衡器有两个IP地址Q一个是LVS的虚拟IP地址Q另一个IP地址是内部地址--所有物理服务器默认|关。当数据包从物理服务器发送到负蝲均衡器时Q负载均衡器Ҏ地址译QNATQ规则将包{发到客户端。(׃负蝲均衡器是一个地址译器,所以ICMP的重定向功能失效QPING无法应用Q。可以采用IP别名的方法,也可以用双|卡Ҏ来实现这个?
配置脚本会配置IP伪装。以下是在configure.pl脚本中的E序D:
echo turning on masquerading
#setup masquerading
echo 1 /proc/sys/net/ipv4/ip_forward
echo installing ipchain rules
/sbin/ipchains -A forward -j MASQ -s 10.1.1.0/24 -d 0.0.0.0/0
echo ipchain rules
/sbin/ipchains L
所有与NAT有关的规则设|都在rc.lvs_nat文g中表现?
4.2.配置VS-NAT
在负载均衡器以及每一台物理服务器上分别执行rc.lvs_xxx脚本E序Q用lvs_nat.confq个模板来生成rc.lvs_nat配置文g?
VS-NAT会对端口重新映,一个来自于80端口的请求,负蝲均衡器会其发给物理服务器的8000端口。由于数据包的源地址和目标地址已经被重写,所以无需寚w新端口增加额外的开销。很低的重写数据包速度Q?0us/包)限制了VS-NAT的最大处理能力,而且VS-NAT的最大处理能力不是与增加的物理服务器成正比的?
VS-NAT实现Ҏ的最大优Ҏ物理服务器可以是M一U操作系l,无需Z完成LVS而作M修改Q而且可以实现一些在Linux上不存在服务?
4.33.VS-NAT与Linux核心支持的NAT
当然可以使用ipchains或ipfw构徏ZLinux内核的NAT防火墙。而用了Z2.0.36版内核的LVS补丁包后Q常规的内核模块Q如ip_masq_ftp{)不再工作Q而且不再需要装载)?
5.VS-DR模式
5.1.总论
VS-DR是基于IBM的NetDispathcer实现的。NetDispatcher位于WEB服务器的前端Q对于客L来说p一台WEB服务器。NetDispatcher曾服务于奥运会、卡斯帕|夫与深蓝电脑的国际象棋比赛?
q里有一个VS-DR的IP地址讄的实例。注意:物理服务器与VIP位于同一个网l上?
VS-DR模式在以下几斚w受到了限?
1Q?物理服务器和负蝲均衡器必d同一个网D上Q它们之间必能使用arp协议Q,它们之间在数据链路层上传递数据包Q?
2Q?客户端必通过负蝲均衡器的VIP讉K集群Q?
3Q?物理服务器必L到客L的\由(即客户端没有到物理服务器的路由Q。因Z物理服务器返回到客户商的包,直接发送,无须通过负蝲均衡器{发?
VS-DR模式下,客户端通常与负载均衡器和物理服务器位于不同的网l中Q而且每一个物理服务器拥有自己对外的\p。在下面q个单的例子中,所有的机器都在192.168.1.0q个|络Q物理服务器不需要设|默认\。网l拓扑结构如下图所C:
IP分配如下表所C:
?1-3 .IP分配
??IP ?址
客户?本机IPQCIP 192.168.1.254
负蝲均衡?本机IPQDIP 192.168.1.1
虚拟IPQVIP 192.168.1.110QARP与客L使用Q?
物理服务? 本机IPQRIP 192.168.1.2
虚拟IPQVIP 192.168.1.110Q不ARPQ?
物理服务? 本机IPQRIP 192.168.1.3
虚拟IPQVIP 192.168.1.110Q不ARPQ?
物理服务? 本机IPQRIP 192.168.1.4
虚拟IPQVIP 192.168.1.110Q不ARPQ?
5.2.VS-DR良好的扩展?
VS-NATҎ受限于经q负载均衡器的每一包都必须重写Q用q种Ҏ最大的数据吞吐量受限于负蝲均衡器的环境。(如一台Pentium机器Q快速以太网Q最大的数据吞吐量ؓ80M/U)而且增加物理服务器的数量q不能增加这个最大数据吞吐量。而用VS-DR模式Q速度限制则在每个物理服务器与Internetq接的包处理能力Q而对负蝲均衡器的要求不大Q因为其只需处理单的包。在VS-DR的模式下Q能够增加更多物理服务器以提高系l能力?
6 VS-TUN模式
6.1.总论
VS-Tun是LVS独创的的Q它是基于VS-DR发展的。具有良好的可扩展性和服务吞吐量?
使用VS-Tun方式的话Q必采Linux作ؓ物理服务器,而负载均衡器IPh重新包装成IPIP包后发给
物理服务器。所以物理服务器必须能够解IPIP包装才能Q现在只有Linux操作pȝ能处理IPIP包(IP隧道技
术)?
不同于VS-DRQVS-TunҎ允许物理服务器与负蝲均衡器在不同的网l上Q甚臛_许所有的机器都在
单独的网l上Q那怕物理服务器位于不同的国Ӟ例如Q做一个项目的FTP站点镜像Q。在q种情况下物?
服务器将产生源地址=虚拟IP地址Q目标地址=客户机IP地址的IP包?
如果物理服务器与负蝲均衡器位于相同的|络上,那么VS-DR和VS-Tun是等L。VS-DR更具有灵z?
性,因ؓ大多数操作系l都可以用来构徏物理服务器?
6.2. VS-Tun实例
以下是一个VS-Tun的IP配置实例。VS-Tun提供的最大方便性就是不需要服务器与客L位于同一个网l上Q仅需要客L能寻径(有\由)到负载均衡器Q物理服务器能寻径(有\由)到客h。(q回的包直接从物理服务器到客LQ无dl过负蝲均衡器)
通常使用VS-Tun模式Ӟ客户端是与负载均衡器、物理服务器位于不同|络上的Q而且每一台服务器
有一个通往外界的\由?
IP分配如下表所C:
?1-4.IP分配
??IP ?址
客户?本机IPQCIP 192.168.1.254
负蝲均衡?本机IPQDIP 192.168.1.1
虚拟IPQVIP 192.168.1.110QARP与客L使用Q?
物理服务? 本机IPQRIP 192.168.1.2
虚拟IPQVIP 192.168.1.110Q隧道技术,不ARPQ?
物理服务? 本机IPQRIP 192.168.1.3
虚拟IPQVIP 192.168.1.110Q隧道技术,不ARPQ?
物理服务? 本机IPQRIP 192.168.1.4
虚拟IPQVIP 192.168.1.110Q隧道技术,不ARPQ?
…?…?…?
物理服务器n 本机IPQRIP 192.168.1.n+1
虚拟IPQVIP 192.168.1.110Q隧道技术,不ARPQ?
6.3.配置VS-Tun
1Q编辑配|文件模板lvs_tun.conf后,q行配置Q?
$ ./configure_lvs.pl lvs_nat.conf
2Q在物理服务器上q行Q?
$ . ./etc/rc.d/rc.lvs_tun
3Q将配置文g攑ֈ/etc/rc.d?etc/init.d目录下?
4Q检查ipvsadm、ifconfig a和netstat rn的输出,查服?IP地址是否正确Q如果有误,请修改后重新q行脚本?
Java servlets are a powerful tool for building websites and web based applications. One skill that every Java web developer should have is the ability to install and configure the Tomcat servlet engine. Many thanks to the Apache Software Foundation for providing this mbature, stable, open source software. It was recently voted the Best Application Server of 2003 by InfoWorld readers.
This article discusses how to integrate Tomcat with the Apache web server on Red Hat Linux 9 or Red Hat Enterprise Linux 3. The goal is to provide a simple, stable configuration that will allow users to gain confidence using Tomcat.
Please note the following code conventions:I chose to install Apache using the Red Hat RPM. Using the RPM instead of compiling Apache from source simplifies system administration in the following ways:
I recommend using the Red Hat up2date command line utility to install Red Hat RPMs. It eliminates a multitude of headaches by ensuring the software you install is the correct version and you have the right dependencies installed on your system.
Red Hat RPMs that must be installed:
To install these packages using up2date, make sure you are connected to the Internet, and enter the following:
up2date -i httpd up2date -i httpd-devel
You should now be able to start/stop/restart Apache as follows:
service httpd start service httpd stop service httpd restart
Verify that Apache is working by starting Apache and typing http://localhost/ into your browser. You should see the default Apache install page with links to documentation.
The only requirements to run Tomcat are that a Java Development Kit (JDK), also called a Java Software Development Kit (SDK), be installed and the JAVA_HOME environment variable be set.
I chose to install Sun's Java 2 Platform, Standard Edition, which can be downloaded from http://java.sun.com/j2se/). I chose the J2SE v1.4.2 SDK Linux self-extracting binary file.
Change to the directory where you downloaded the SDK and make the self-extracting binary executable:
chmod +x j2sdk-1_4_2-linux-i586.bin
Run the self-extracting binary:
./j2sdk-1_4_2-linux-i586.bin
There should now be a directory called j2sdk1.4.2 in the download directory. Move the SDK directory to where you want it to be installed. I chose to install it in /usr/java. Create /usr/java if it doesn't exist. Here is the command I used from inside the download directory:
mv j2sdk1.4.2 /usr/java
Set the JAVA_HOME environment variable, by modifying /etc/profile so it includes the following:
JAVA_HOME="/usr/java/j2sdk1.4.2" export JAVA_HOME
/etc/profile is run at startup and when a user logs into the system, so you will need to log out and log back in for JAVA_HOME to be defined.
exit su -
Check to make sure JAVA_HOME is defined correctly using the command below. You should see the path to your Java SDK.
echo $JAVA_HOME
You will install and configure Tomcat as root; however, you should create a group and user account for Tomcat to run under as follows:
groupadd tomcat useradd -g tomcat tomcat
This will create the /home/tomcat directory, where I will install my Tomcat applications.
Download the latest release binary build from http://www.apache.org/dist/jakarta/tomcat-4/. Since Tomcat runs directly on top of a standard JDK, I cannot think of any reason to building it from source.
The Tomcat binary is available in two different flavors:
There are a number of different download formats. I chose the LE version gnu zipped tar file (jakarta-tomcat-4.1.31-LE-jdk14.tar.gz).
Unzip Tomcat by issuing the following command from your download directory:
tar xvzf jakarta-tomcat-4.1.31-LE-jdk14.tar.gz
This will create a directory called jakarta-tomcat-4.1.31. Move this directory to wherever you would like to install Tomcat. I chose /usr/local. Here is the command I issued from inside the download directory:
mv jakarta-tomcat-4.1.31 /usr/local/
The directory where Tomcat is installed is referred to as CATALINA_HOME in the Tomcat documentation. In this case CATALINA_HOME=/usr/local/jakarta-tomcat-4.1.31.
I recommend setting up a symbolic link to point to your current Tomcat version. This will save you from having to change your startup and shutdown scripts each time you upgrade Tomcat or set a CATALINA_HOME environment variable. It also allows you to keep several versions of Tomcat on your system and easily switch amongst them. Here is the command I issued from inside /usr/local to create a symbolic link called /usr/local/jakarta-tomcat that points to /usr/local/jakarta-tomcat-4.1.31:
ln -s jakarta-tomcat-4.1.31 jakarta-tomcat
Change the group and owner of the /usr/local/jakarta-tomcat and /usr/local/jakarta-tomcat-4.1.31 directories to tomcat:
chown tomcat.tomcat /usr/local/jakarta-tomcat chown -R tomcat.tomcat /usr/local/jakarta-tomcat-4.1.31
It is not necessary to set the CATALINA_HOME environment variable. Tomcat is smart enough to figure out CATALINA_HOME on its own.
You should now be able to start and stop Tomcat from the CATALINA_HOME/bin directory by typing ./startup.sh and ./shutdown.sh respectively. Test that Tomcat is working by starting it and typing http://localhost:8080 into your browser. You should see the Tomcat welcome page with links to documentation and sample code. Verify Tomcat is working by clicking on some of the examples links.
At this point, Apache and Tomcat should be working separately in standalone mode. You can run Tomcat in standalone mode as an alternative to Apache. In fact, in some cases, it is said that Tomcat standalone is faster than serving static content from Apache and dynamic content from Tomcat. However, there are compelling reasons to use Apache as the front end. If you run Tomcat standalone:
I think the increased functionality obtained by using Apache on the front end far outweighs the effort required to install and configure a connector.
Development on the mod_jk2 connector was shut down on 11/15/2004; therefore, you no longer have to decide between the mod_jk and mod_jk2 connectors. Use the mod_jk connector. It has been around a long while and is very stable.
The mod_jk connector is the communication link between Apache and Tomcat. It listens on a defined port for requests from Apache.
Download the jk connector source from http://www.apache.org/dist/jakarta/tomcat-connectors/jk/. I used jakarta-tomcat-connectors-1.2.8-src.tar.gz.
Unzip the contents of the file into your download directory as follows:
tar xvzf jakarta-tomcat-connectors-1.2.8-src.tar.gz
This will create a folder called jakarta-tomcat-connectors-1.2.8-src. Move this folder to wherever you store source files on your system. I chose /usr/src. Here is the command I issued from inside the download directory:
mv jakarta-tomcat-connectors-1.2.8-src /usr/src
I refer to the folder where the connector source is installed as CONN_SRC_HOME. In my case CONN_SRC_HOME = /usr/src/jakarta-tomcat-connectors-1.2.8-src.
Run the buildconf script to to create the CONN_SRC_HOME/jk/native/configure file.
CONN_SRC_HOME/jk/native/buildconf.sh
Run the configure script with the path to the apxs file on your system and the options below:
./configure --with-apxs=/usr/sbin/apxs
Build mod_jk with the following command:
make
If you see missing object errors, try this alternate command:
make LIBTOOL=/etc/httpd/build/libtool
If all went well, the mod_jk.so file was successfully created. Manually copy it to Apache's shared object files directory:
cp CONN_SRC_HOME/jk/native/apache-2.0/mod_jk.so /etc/httpd/modules
The workers.properties file contains information so mod_jk can connect to the Tomcat worker processes.
Place the following workers.properties file in the /etc/httpd/conf directory:
# workers.properties - ajp13 # # List workers worker.list=wrkr # # Define wrkr worker.wrkr.port=8009 worker.wrkr.host=localhost worker.wrkr.type=ajp13 worker.wrkr.cachesize=10 worker.wrkr.cache_timeout=600 worker.wrkr.socket_timeout=300
Notes
The server.xml file contains Tomcat server configuration information. The default CATALINA_HOME/conf/server.xml file that comes with Tomcat contains so much information that I recommend saving it for future reference (e.g. server.xml.bak) and starting from scratch. The default server.xml is great for verifying that Tomcat works in standalone mode and for viewing the examples that come with the application, but I have found it is not the best starting point when you want to integrate Apache with Tomcat. Instead, create a bare bones server.xml file as follows:
your_domain"> your_application" debug="0" reloadable="true" />
This setup assumes you will put your Tomcat applications in /home/tomcat, not CATALINA_HOME/webapps. This will allow you to easily upgrade Tomcat and back up your Tomcat applications.
If you do keep the default server.xml, make sure you comment out any other connectors besides mod_jk that are listening on port 8009. The default file comes with the Coyote/JK2 connector enabled for the Tomcat-Standalone service. This will conflict with the mod_jk connector in your Tomcat-Apache service. You should comment this connector out. It isn't needed when you connect directly to Tomcat in standalone mode (port 8080), so I'm not sure why this connector is enabled by default.
The Server address defines the interface that Tomcat will listen on for mod_jk requests from Apache. In my configuration, Apache and Tomcat reside on the same box, so I have set the address to the loopback address. The default is for Tomcat to listen on all interfaces, so restricting it to the loopback interface improves security.
The Server shutdown property is the text string that is sent over a socket connection to stop Tomcat. The default value is "SHUTDOWN". The shutdown port is always on the loopback interface, which provides host-level protection. However, there is the possibility that the host could be compromised and someone could send the command SHUTDOWN to all ports and knock Tomcat offline. To prevent this, replace the default value with one that is difficult to guess. Do not use the example string above. Create your own by feeding random bytes into md5sum as follows:
Setting the Context reloadable property to true tells Tomcat to automatically load new and changed application class files found in /WEB-INF/classes and /WEB-INF/lib. This feature is very useful during development. However, it is recommended to set reloadable to false in production environments because monitoring class file changes requires significant server resources.
head -1024c /dev/random | md5sum
Change the permissions on server.xml so no one can read the shutdown string:
chmod 600 $CATALINA_HOME/conf/server.xml
Apache is configured with directives placed in the main Apache configuration file, /etc/httpd/conf/httpd.conf. In addition, Apache 2 has configuration files for perl, php, and ssl located in /etc/httpd/conf.d/.>
Rename the /etc/httpd/conf.d/ssl.conf file to ssl.conf.bak. The default Red Hat Apache 2 installation comes with ssl support enabled. If ssl is needed, you can re-enable it after you have successfully integrated Apache and Tomcat.
You will notice that there are three sections labeled in the httpd.conf file supplied by Red Hat: (1) Global Environment, (2) Main Server Configuration, and (3) Virtual Hosts.
Add the following to the bottom of the existing LoadModule directives in the Global Environment section:
LoadModule jk_module modules/mod_jk.so
Add the following to the bottom of the Main Server Configuration section:
JkWorkersFile "/etc/httpd/conf/workers.properties" JkLogFile "/etc/httpd/logs/mod_jk.log" JkLogLevel info JkLogStampFormat "[%a %b %d %H:%M:%S %Y]"
Set up a Virtual Host directive in the Virtual Hosts section of httpd.conf. Below is an example of how to set up the your_domain website so Tomcat handles all jsp pages and requests with "servlet" in the path:
NameVirtualHost 127.0.0.1:80ServerAdmin webmaster@your_domain ServerName your_domain DocumentRoot /usr/www/your_domain/html ErrorLog /usr/www/your_domain/logs/error_log CustomLog /usr/www/your_domain/logs/access_log common JkMount /*.jsp wrkr JkMount /servlet/* wrkr # Deny direct access to WEB-INF AllowOverride None deny from all
The configuration above assumes that your application's static html files will be served from the /usr/www/your_domain/html directory.
I have deliberately chosen to serve static html files and servlets/jsps from different locations for learning purposes (so there was no confusion over which server is serving which files). Typically, all application files would be located in the same directory tree.
The argument for the NameVirtualHost directive must match exactly the argument for the VirtualHost directive (127.0.0.1:80).
You can test your Apache configuration by typing the following:
httpd -t -D DUMP_VHOSTS
You should get something like the following response:
127.0.0.1:80 is a NameVirtualHost default server your_domain (/etc/httpd/conf/httpd.conf:1056) port 80 namevhost your_domain (/etc/httpd/conf/httpd.conf:1056) Syntax OK
your_domain does not need to be a domain name with a DNS entry. For testing purposes, you can set up any domain you want in the /etc/hosts file of the machine that you will be using to access your_application.
The example below shows the entry for your_domain when running Apache and Tomcat on a single machine, typical for a development computer.
127.0.0.1 your_domain
We will create and install a simple Hello World html page so we can test to make sure Apache handles requests for static html pages.
Copy the following text into a file called HelloWorld.html and install the file in the /usr/www/your_domain/html directory.
Hello World HTML!
If Apache has not been restarted since you added your virtual host, do so as follows:
service httpd restart
You should now be able to type http://your_domain/HelloWorld.html into your browser and see the always-exciting "Hello World" message.
We will create and install a simple Hello World servlet so we can test to make sure Apache forwards servlet requests to Tomcat for handling.
Copy the following into a file called HelloWorld.jsp:
<%@ page contentType="text/html;charset=WINDOWS-1252"%><% out.println(" Hello World JSP!"); %>
Copy the HelloWorld.jsp file to the /home/tomcat/your_application/ directory.
Copy the following into a file called HelloWorld.java:
import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class HelloWorld extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println("Hello World Servlet!"); } }
Compile the source into a class file as follows:
javac -classpath /usr/local/jakarta-tomcat/common/lib/servlet.jar HelloWorld.java
This will create a file called HelloWorld.class. Copy the HelloWorld.class file to the /home/tomcat/your_application/WEB-INF/classes directory.
Create the following directories and files in /home/tomcat/your_application:
/home/tomcat/your_application/WEB-INF /home/tomcat/your_application/WEB-INF/classes /home/tomcat/your_application/WEB-INF/web.xml
The web.xml file is where you map the name of your servlet to a URL pattern so Tomcat can run your servlet when requested. Below is the web.xml file that runs the HelloWorld servlet whenever the URL http://your_domain/servlet/HelloWorld is entered in the browser:
HelloWorld HelloWorld HelloWorld /servlet/HelloWorld
Restart Tomcat as follows:
/CATALINA_HOME/bin/shutdown.sh /CATALINA_HOME/bin/startup.sh
Restart Apache as follows:
service httpd restart
You should now be able to type the following into your browser and see the always-exciting "Hello World" message:
http://your_domain/HelloWorld.jsp
http://your_domain/servlet/HelloWorld
The following steps are not mandatory, but are suggested for a better, tighter Tomcat installation.
If you want to automatically start Tomcat when your system boots and manage it using the service command as we do Apache, you must create an initialization script.
Create the following Tomcat initialization script as /etc/rc.d/init.d/tomcat
#!/bin/sh # # Startup script for Tomcat, the Apache Servlet Engine # # chkconfig: 345 80 20 # description: Tomcat is the Apache Servlet Engine # processname: tomcat # pidfile: /var/run/tomcat.pid # # Mike Millson# # version 1.02 - Clear work directory on shutdown per John Turner suggestion. # version 1.01 - Cross between Red Hat Tomcat RPM and Chris Bush scripts # Tomcat name :) TOMCAT_PROG=tomcat # if TOMCAT_USER is not set, use tomcat like Apache HTTP server if [ -z "$TOMCAT_USER" ]; then TOMCAT_USER="tomcat" fi RETVAL=0 # start and stop functions start() { echo -n "Starting tomcat: " chown -R $TOMCAT_USER:$TOMCAT_USER /usr/local/jakarta-tomcat/* chown -R $TOMCAT_USER:$TOMCAT_USER /home/tomcat/* su -l $TOMCAT_USER -c '/usr/local/jakarta-tomcat/bin/startup.sh' RETVAL=$? echo [ $RETVAL = 0 ] && touch /var/lock/subsys/tomcat return $RETVAL } stop() { echo -n "Stopping tomcat: " su -l $TOMCAT_USER -c '/usr/local/jakarta-tomcat/bin/shutdown.sh' RETVAL=$? echo [ $RETVAL = 0 ] && rm -f /var/lock/subsys/tomcat /var/run/tomcat.pid rm -rf /usr/local/jakarta-tomcat/work/* } # See how we were called. case "$1" in start) start ;; stop) stop ;; restart) stop # Ugly hack # We should really make sure tomcat # is stopped before leaving stop sleep 2 start ;; *) echo "Usage: $0 {start|stop|restart}" exit 1 esac exit $RETVAL
Add the startup script to your system as follows:
chkconfig --add tomcat
You will be able to start/stop/restart it using the following commands:
service tomcat start service tomcat stop service tomcat restart
If you want Tomcat to start automatically when your system boots, you need to add tomcat to your runlevel as follows:
chkconfig --level 5 tomcat on
Runlevel 5 is the X Window System, typical for a development computer. Runlevel 3 is typical for a dedicated web server.
Apache and Tomcat can be started and restarted in any order. In the past (specifically with the 1.2.5 connector), if Tomcat was restarted, Apache would have to be restarted. This was because the AJP13 protocol maintains open sockets between Apache and Tomcat, and when Tomcat was restarted the connections would be hung in CLOSE_WAIT status until Apache was restarted. This has been fixed starting with the 1.2.6 connector.
During development, you will need access to your tomcat application directory. Add the user account under which you will be doing development to the tomcat group in /etc/group. For example, this is what the tomcat entry might look like in /etc/group if you do development under the yourname account:
tomcat:x:502:yourname
Make sure the tomcat group has permission to publish files (e.g. using ant) to your Tomcat application in /home/tomcat/your_application. Issue the following command as root:
chmod g+rw /home/tomcat
Look here for clues to Apache httpd.conf configuration issues, for example VirtualHost setup.
Look here for clues to Tomcat server.xml configuration issues. This file is written to when Tomcat starts and stops. It also catches System.out and System.err.
Look here for clues to mod_jk configuration issues.
The following command can be used to monitor the Apache, Tomcat, and mod_jk connections:
netstat -vatn | grep 80
Below is output from running this command. Line numbers have been added to the beginning of each line for discussion purposes.
1 tcp 0 0 127.0.0.1:8005 0.0.0.0:* LISTEN 2 tcp 0 0 127.0.0.1:8009 0.0.0.0:* LISTEN 3 tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 4 tcp 0 0 127.0.0.1:8009 127.0.0.1:34449 ESTABLISHED 5 tcp 0 0 127.0.0.1:34449 127.0.0.1:8009 ESTABLISHED
Notes