III(二十)SVN

 

svnsubversion版本管理工具:

安装优化软件环境,如httpd,lvs等(运维工程师);

程序代码(不断更新)(开发工程师,开发+运维);

配置变更(不断变更)(运维工程师)

 

SVN是近年来崛起的非常优秀的版本管理工具,与CVS管理工具类似,SVN是新开发的版本控制系统,修正了CVS所未解决的问题;

SVN是一个跨平台的开源的版本控制系统,是一个非常通用的软件系统,它常被用来管理程序源码,但它可管理任何类型的文件,如文本、视频、图片等等,管理着随时间变化的各种数据,这些数据放置在一个叫中央资料库repository中,这个档案库很像一个普通的file serverFTP server),但不同的是SVN会备份并记录每个文件每一次的修改更新变动,这样我们就可把任意一个时间点的档案恢复到想要的之前的版本,也可直接浏览指定文件的更新历史记录;

http://subversion.tigris.org/

http://subversion.apache.org/

 

版本管理软件有:VSSmicrosoft)、CVSSVNgit

 

SVN是集中式的数据管理,存在一个中央版本库,所有开发人员本地开发所使用的代码都是来自于这个版本库,提交代码也都必须提交到这个中央版本库,其工作流程:

在中央版本库上创建或从主干上复制一个分支;

从中央库check out下这个分支的代码;

增加自己的代码文件,修改现存的代码或删除代码文件;

commit代码,假设有人在刚刚的分支上提交了代码,你就会被提示代码过期,你得先update你的代码后再commit,若update时有冲突要解决好冲突再commit

注:当由于网络原因无法连接到中央版本库的环境下,则无法commit代码,无法查看代码的历史版本及版本的变化过程;由于代码集中管理,因此需要对中央版本库的存储做备份,在这点上分布式版本控制系统要好些,对SVN的备份要备份所有代码数据还有所有更改的版本记录

 

git分布式版本控制,linux开发,gitlinuxFS结合紧密,在win上要使用cygwin才能完美工作,git没有中央版本库的概念,但为了开发小组的代码共享,通常还是会搭建一个远程的git仓库,gitsvn不同的是,使用git开发者在本地也包含了一个完整的git仓库,本地的仓库和远程的仓库在身份上是等价的,没有主从之分,若使用gitsvn那样集中管理的话,步骤如下:

在本地创建一个git仓库,并将其add到远程git库中;

在本地修改代码、添加或删除文件,再commit提交到本地的git仓库中,具体位置是git/objects/下;

将本地git库的分支push到远程git库的分支,若远程git库中已有人push过则不允许你push,这时你要先pull,在处理好冲突后,commit到本地再push到远程git

注:每个开发人员的本地都有一个git库,可随时commit到本地的git库,可随时查看历史版本,当某一个功能点开发完了之后将commit后的内容push到远程git库,如果远程git库的版本在你上次clonepull之后发生了变化,那这时要先pull并处理冲突,再次commit之后再push到远程git

 

运维人员掌握版本管理:

安装、部署、维护、排障;

简单使用,很多公司都由开发管理,包括建立仓库、添加删除帐号;

对于版本控制系统,运维人员相当于开发商,开发人员是业主,运维搭建的系统为开发人员服务的

 

SVN服务端访问方式(3种):

svn://svn.mydomain.com/sadoc(独立服务器访问);

http://svn.mydomain.com/sadoc(借助httpd服务,用CSVN这是个单独的整合了httpdsvn的软件;或者分别单独安装httpdsvn);

file:///application/svdata/sadoc(本地直接访问)

 

SVN客户端的访问方式:

svn://(通过tcp/ip自定义协议访问svnserver);

http://(通过WEBDAV协议访问支持subversionhttpd server);

svn+ssh://(通过认证并加密的tcp/ip自定义协议访问svnserver);

https://ssl加密的http);

file://(直接通过本地磁盘或网络磁盘)

 

SVN档案库数据格式(2种,BDBFSFS):

BDBBerkeley DB,事务安全型表类型,一种经过充分测试的后台数据库实现,不能在网络共享的文件系统上使用,是subversion1.2版本之前的默认版本库格式,BDB格式方式在服务器中断时有可能锁住数据,还是使用FSFS更安全些);

FSFS(专用于subversion版本库的文件系统后端,可使用网络文件系统,如NFSSMBFS,是1.2版本之后的默认版本库格式)

注:SVN是基于关系数据的BDB或一系列二进制文件的FSFS,这解决了一些问题,如并行读写共享文件和运行时的事务特性,由此数据存储变得不透明,像分布式文件系统那样要通过API接口才能访问,不能像FTPsambaNFS一样看不到实体文件(不能直接查看文件);MySQL5.5之前默认storage engineMyISAM,而5.5之后默认是InnoDB

 

SVN系统逻辑架构图:

注:集中式代码管理的核心是SVN server,所有开发者在开始新一天的工作之前必须从server获取代码,然后进行开发,最后解决冲突、提交,所有的版本信息都放在SVN server上,若脱离了SVN server,开发者就无法进行提交代码工作

 

 

[root@localhost ~]# uname -a

Linux localhost.localdomain2.6.32-431.el6.x86_64 #1 SMP Sun Nov 10 22:19:54 EST 2013 x86_64 x86_64 x86_64GNU/Linux

[root@localhost ~]# uname -rm

2.6.32-431.el6.x86_64 x86_64

[root@localhost ~]# cat /etc/redhat-release

Red Hat Enterprise Linux Server release 6.5(Santiago)

[root@localhost ~]# rpm -qa subversion   #(若对功能无特殊要求,首选使用yum方式安装rpm二进制软件包,这样最便捷)

subversion-1.6.11-9.el6_4.x86_64

[root@localhost ~]# sed -i 's/keepcache=0/keepcache=1/g' /etc/yum.conf  #(若用的是网络yum源,yum方式安装rpm包后本地不清除rpm二进制包,方便以后使用)

[root@localhost ~]# grep 'keepcache' /etc/yum.conf

keepcache=1

[root@localhost ~]# rpm -ql subversion

/etc/bash_completion.d

/etc/bash_completion.d/subversion

/etc/rc.d/init.d/svnserve

/etc/subversion

/usr/bin/svn

/usr/bin/svnadmin

/usr/bin/svndumpfilter

/usr/bin/svnlook

/usr/bin/svnserve

/usr/bin/svnsync

/usr/bin/svnversion

 

[root@localhost ~]# mkdir -pv /application/{svndata/,svnpasswd/}   #(创建SVN server数据存储根目录、用户密码权限目录使密码集中存放)

mkdir: created directory `/application'

mkdir: created directory`/application/svndata/'

mkdir: created directory`/application/svnpasswd/'

[root@localhost ~]# tree /application

/application

├── svndata

└── svnpasswd

2 directories, 0 files

 

[root@localhost ~]# svnserve --help

usage: svnserve [-d | -i | -t | -X][options]

Valid options:

  -d [--daemon]            : daemon mode

  -i[--inetd]             : inetd mode

  -t[--tunnel]            : tunnel mode

  -X[--listen-once]       : listen-once mode(useful for debugging)

  -r [--root] ARG          : root of directory to serve

  -R[--read-only]         : force read only,overriding repository config file

 --config-file ARG        : readconfiguration from file ARG

  --listen-port ARG        : listen port

                             [mode: daemon,listen-once]

 --listen-host ARG        : listenhostname or IP address

                             [mode: daemon, listen-once]

  -T[--threads]           : use threadsinstead of fork [mode: daemon]

 --foreground             : run inforeground (useful for debugging)

                             [mode: daemon]

 --log-file ARG           :svnserve log file

  --pid-file ARG           : write server process ID to file ARG

                             [mode: daemon,listen-once]

 --tunnel-user ARG        : tunnelusername (default is current uid's name)

                             [mode: tunnel]

  -h[--help]              : display this help

 --version                : showprogram version information

 

[root@localhost ~]# svnadmin help   #(与mysqladmin命令类似)

general usage: svnadmin SUBCOMMANDREPOS_PATH  [ARGS & OPTIONS ...]

Type 'svnadmin help <subcommand>' forhelp on a specific subcommand.

Type 'svnadmin --version' to see theprogram version and FS modules.

Available subcommands:

  crashtest

   create

  deltify

  dump

  help (?, h)

  hotcopy

  list-dblogs

  list-unused-dblogs

  load

   lslocks

  lstxns

  pack

  recover

  rmlocks

  rmtxns

  setlog

  setrevprop

  setuuid

  upgrade

  verify

 

[root@localhost ~]# svnadmin help create   #(创建版本库,相当于站点目录)

create: usage:svnadmin create REPOS_PATH

Create a new, empty repository at REPOS_PATH.

Valid options:

 --bdb-txn-nosync         : disablefsync at transaction commit [Berkeley DB]

 --bdb-log-keep           : disableautomatic log file removal [Berkeley DB]

 --config-dir ARG         : readuser configuration files from directory ARG

 --fs-type ARG            : type ofrepository: 'fsfs' (default) or 'bdb'

 --pre-1.4-compatible     : useformat compatible with Subversion versions

                             earlier than 1.4

 --pre-1.5-compatible     : useformat compatible with Subversion versions

                             earlier than 1.5

 --pre-1.6-compatible     : useformat compatible with Subversion versions

                             earlier than 1.6

 

[root@localhost ~]# svnserve -d -r /application/svndata   #(或使用#service svnserve start

注:若在开启进程时使用了选项--pid-file /application/svndata/svn.pid,使用脚本关闭进程时用kill -9 `cat /application/svndata/svn.pid`

[root@localhost ~]# ps aux | grep svnserve

root     14564  0.0  0.4 165132  952 ?        Ss   18:39  0:00 svnserve -d -r /application/svndata

root     14568  0.0  0.3 103252  828 pts/0    S+   18:39  0:00 grep svnserve

[root@localhost ~]# netstat -tnulp | grep :3690   #(服务端默认端口3690

tcp       0      0 0.0.0.0:3690                0.0.0.0:*                   LISTEN      14564/svnserve    

[root@localhost ~]# lsof -i :3690

COMMAND   PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME

svnserve 14564 root    3u IPv4 230894      0t0  TCP *:svn (LISTEN)

[root@localhost ~]# svnadmin create /application/svndata/sadoc   #(默认已指定为--fs-typeFSFS,若要用bdb可在创建时指定--fs-type bdb

[root@localhost ~]# tree /application/svndata/sadoc   #conf/,db/,hooks/等)

/application/svndata/sadoc

├── conf

   ├── authz

   ├── passwd

   └── svnserve.conf

├── db

   ├── current

   ├── format

   ├── fsfs.conf

   ├── fs-type

   ├── min-unpacked-rev

   ├── rep-cache.db

   ├── revprops

      └── 0

          └── 0

   ├── revs

      └── 0

          └── 0

   ├── transactions

   ├── txn-current

   ├── txn-current-lock

   ├── txn-protorevs

   ├── uuid

   └── write-lock

├── format

├── hooks

   ├── post-commit.tmpl

   ├── post-lock.tmpl

   ├── post-revprop-change.tmpl

   ├── post-unlock.tmpl

   ├── pre-commit.tmpl

   ├── pre-lock.tmpl

   ├── pre-revprop-change.tmpl

   ├── pre-unlock.tmpl

   └── start-commit.tmpl

├── locks

   ├── db.lock

   └── db-logs.lock

└── README.txt

[root@localhost ~]# cd /application/svndata/sadoc/conf   #svnserve.conf包含了authzpasswd,默认每个版本库下会有自己的密码文件,为统一管理指定密码文件位置,将authzpasswd放到/application/svnpasswd/下)

[root@localhost conf]# ll

total 12

-rw-r--r--. 1 root root 1080 Jun 22 18:57authz

-rw-r--r--. 1 root root  309 Jun 22 18:57 passwd

-rw-r--r--. 1 root root 2279 Jun 22 18:57svnserve.conf

[root@localhost conf]# cp svnserve.conf svnserve.conf.ori   #(备份,两个目的:改错了恢复;对比改过什么)

[root@localhost conf]# cp authz passwd /application/svnpasswd/   #(将authzpasswd放到/application/svnpasswd/下)

[root@localhost conf]# chmod 700 /application/svnpasswd/*

[root@localhost conf]# vim svnserve.conf  

[general]

anon-access = none

auth-access = write

password-db =/application/svnpasswd/passwd

authz-db =/application/svnpasswd/authz

[root@localhost conf]# diff svnserve.conf svnserve.conf.ori   #(用diff命令比较,或使用egrep查看)

12,13c12,13

< anon-access = none

< auth-access = write

---

> # anon-access = read

> # auth-access = write

20c20

< password-db =/application/svnpasswd/passwd

---

> # password-db = passwd

27c27

< authz-db =/application/svnpasswd/authz

---

> # authz-db = authz

[root@localhost conf]# egrep '\-access|\-db' svnserve.conf

anon-access = none

auth-access = write

### The password-db option controls thelocation of the password

password-db = /application/svnpasswd/passwd

### The authz-db option controls thelocation of the authorization

### authz-db, no path-based access controlis done.

authz-db = /application/svnpasswd/authz

[root@localhost conf]# cd /application/svnpasswd/

[root@localhost svnpasswd]# vim passwd   #(在users段添加用户名和密码,密码明文,注意权限700

[users]

root = chai

snow = snow123

[root@localhost svnpasswd]# vim authz  

[groups]

sagroup = root,snow

[sadoc:/]

@sagroup = r

root = rw

snow = r

[root@localhost svnpasswd]# pkill svnserve

[root@localhost svnpasswd]# lsof -i :3690

[root@localhost sadoc]# svnserve -d -r /application/svndata   #(修改svnserve.conf后要重启svnserv,修改authzpasswd则不需重启)

[root@localhost svnpasswd]# lsof -i :3690

COMMAND   PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME

svnserve 14802 root    3u IPv4 237048      0t0  TCP *:svn (LISTEN)

 

authz文件:

一个用户组可包含1个或多个用户,各用户间用逗号分隔,用户要在passwd文件中存在;

版本库目录格式为:

[<版本库>:/项目名/目录]

@<用户组名> = <权限>

<用户名> = <权限>

权限有rwrw和空

 

 

win下的客户端软件TortoiseSVN

win下任意位置创建一目录例如svndata/,右键该目录选SVN checkout(仅第一次是checkout,之后都是SVN update):

URL of repository填:svn://192.168.194.128/sadoc

Checkout directory填:本地的目录;-->OK

右键该目录,选TortoiseSVN-->常用的有:Repo-browser(直接查看SVNserver上的版本库)、Setting-->Saved data(可清空所有保存的密码记录)、ShowLogRelocateSVNserver改变了);

注:

目录颜色(绿色对号(正常)、蓝色问号(不同步状态));

提交过程中显示的颜色(蓝色(提交一个修改);紫色(提交一个新增项);深红(提交一个删除或替换);黑色(所有其它项));

在运行中输入%APPDATA%\Subversion\auth,可在此目录下删除指定的密码文件

 

 

Linux下客户端使用:

[root@localhost ~]# rpm -q subversion

subversion-1.6.11-9.el6_4.x86_64

[root@localhost ~]# svn --help

usage: svn<subcommand> [options] [args]

……

Available subcommands:

   add

  blame (praise, annotate, ann)

   cat

  changelist (cl)

   checkout (co)

   cleanup

   commit (ci)

  copy (cp)

  delete (del, remove, rm)

  diff (di)

  export

  help (?, h)

  import

  info

   list (ls)

  lock

  log

  merge

  mergeinfo

  mkdir

  move (mv, rename, ren)

  propdel (pdel, pd)

  propedit (pedit, pe)

  propget (pget, pg)

  proplist (plist, pl)

  propset (pset, ps)

  resolve

  resolved

  revert

  status (stat, st)

  switch (sw)

  unlock

   update (up)

注:常用的subcommand

add(添加本地文件到本地的版本库,通过commit才能到SVNserver的中央版本库);

checkoutco(从源码库取出一个工作版本的拷贝);

commitci(提交当前工作拷贝的更改,有可能会有冲突);

updateup(将SVNserver端文件同步到本地);

listls(查看)

[root@localhost ~]# svn --help add

usage: add PATH...

[root@localhost ~]# svn --help checkout

usage: checkoutURL[@REV]... [PATH]

[root@localhost ~]# svn --help commit

usage: commit [PATH...]

[root@localhost ~]# svn --help update

usage: update [PATH...]

[root@localhost ~]# svn --help list

usage: list[TARGET[@REV]...]

[root@localhost ~]# svn --help cat

cat: Output the content of specified filesor URLs.

usage: catTARGET[@REV]...

 

svn-client

[root@localhost ~]# mkdir /svndata   #client创建此目录存放checkout的数据)

[root@localhost ~]# svn checkout svn://192.168.194.128/sadoc/ /svndata --username root --password chai   #(从SVNserver库提取数据,若有中文名称的文件可能会报错,此报错是linux不支持中文编码,要做字符集调整,包括系统字符集和终端的编码,#export LC_CTYPE="en_US.UTF-8";export LC_ALL=;locale

A   /svndata/test.txt

Checked out revision 3.  

[root@localhost ~]# svn list svn://192.168.194.128/sadoc/ --username root --password chai

test.txt

[root@localhost ~]# svn list svn://192.168.194.128/sadoc/ --verbose --username root --password chai

     3 root                  Jun 2222:13 ./

     2 root                0 Jun 2222:12 test.txt

[root@localhost ~]# svn cat svn://192.168.194.128/sadoc/test.txt

[root@localhost ~]# cd /svndata

[root@localhost svndata]# touch {a,b,c,d}.txt

[root@localhost svndata]# svn add a.txt b.txt c.txt d.txt

A        a.txt

A        b.txt

A        c.txt

A        d.txt

[root@localhost svndata]# svn commit -m 'svn commit data'   #(只有输入信息才能提交成功)

Adding         a.txt

Adding        b.txt

Adding         c.txt

Adding         d.txt

Transmitting file data ....

Committed revision 4.

 

 

svn import(用于将client的一组文件添加到SVNserver上):

[root@localhost svndata]# svn help import

import: Commit an unversioned file or treeinto the repository.

usage: import [PATH] URL

 Recursively commit a copy of PATH to URL.

 

SVNserver-side

[root@localhost svndata]# pwd

/application/svndata

[root@localhost svndata]# svnadmin create /application/svndata/project1   #(先在服务端创建项目版本库)

[root@localhost svndata]# ll

total 8

drwxr-xr-x. 6 root root 4096 Jun 22 22:40project1

drwxr-xr-x. 6 root root 4096 Jun 22 18:57sadoc

[root@localhost ~]# vim /application/svndata/project1/conf/svnserve.conf   #(要记得修改此文件,否则client会报错svn:Authorization failed

[general]

anon-access = none

auth-access = write

password-db = /application/svnpasswd/passwd

authz-db = /application/svnpasswd/authz

[root@localhost ~]# vim /application/svnpasswd/authz

--------------------------file start--------------------

sagroup = root,snow

[sadoc:/]

@sagroup = r

root = rw

snow = r

 

[project1:/]

@sagroup = r

root = rw

snow = r

 

[/]

@sagroup = r

root = rw

snow = r

---------------------file end------------------

[root@localhost ~]# pkill svnserve

[root@localhost ~]# svnserve -d -r /application/svndata

 

client-side

[root@localhost svndata]# mkdir -pv /svn/{trunk/,branch/,tag}   #(开发人员经常用这三个目录,trunk/保存开发的主线,branch/存放分支,tag/保存标签)

mkdir: created directory `/svn'

mkdir: created directory `/svn/trunk/'

mkdir: created directory `/svn/branch/'

mkdir: created directory `/svn/tag'

注:

trunk/(主线,与正式线相对应,当天不上线的文件不允许提交);

branch/(分去,测试用,几天以上的项目必须开分支,测试需要此分支通过,主线合并到分支通过,才能合并到主线进行测试);

tags/(版本记录用);

[root@localhost ~]# svn import /svn svn://192.168.194.128/project1/ -m 'initial import'

Authentication realm:<svn://192.168.194.128:3690> 93e7f148-de67-418e-9ada-6d669fb6087d

Password for 'root':

-----------------------------------------------------------------------

ATTENTION! Your password for authentication realm:

  <svn://192.168.194.128:3690> 93e7f148-de67-418e-9ada-6d669fb6087d

can only be stored to diskunencrypted!  You are advised toconfigure

your system so that Subversion can storepasswords encrypted, if

possible. See the documentation for details.

You can avoid future appearances of thiswarning by setting the value

of the 'store-plaintext-passwords' optionto either 'yes' or 'no' in

'/root/.subversion/servers'.

-----------------------------------------------------------------------

Store password unencrypted (yes/no)? yes

Adding         /svn/trunk

Adding         /svn/tag

Adding         /svn/branch

Committed revision 1.

[root@localhost ~]# svn list svn://192.168.194.128/project1 --username root --password chai

branch/

tag/

trunk/

 

 

svn copy(将主干拷贝到分支):

[root@localhost ~]# svn copy svn://192.168.194.128/project1/trunk svn://192.168.194.128/project1/branch/branch_cms -m 'create branch by jowin' --username root --password chai

Committed revision 2.

[root@localhost ~]# svn list svn://192.168.194.128/project1/branch --username root --password chai

branch_cms/

 

 

SVN钩子hooks

钩子脚本如同shell脚本,钩子脚本是被某些版本库事件触发的程序,类似inotifysersync,例如创建新版本或修改未被版本控制的属性,每个钩子都能掌管足够的信息来了解发生了什么事件、操作对象是什么及触发事件用户的帐号,根据钩子输出和返回状态,钩子程序能够以某种方式控制该动作继续执行、停止或挂起;

在某一项目目录的hooks/下有模板文件,以.tmpl为扩展名,去掉其扩展名即可使用;确保脚本正常运行:脚本中一定要设置好环境变量或使用命令时一律用绝对路径,否则会怪样百出,因为它不会继承系统的环境变量;

常用的钩子脚本:

post-commit(在提交后成功创建版本,再执行该钩子,提交已经完成不可更改,因此脚本的返回值被忽略,提交完成时触发事务);

pre-commit(提交完成前触发使用该脚本);

start-commit(在client还没向server提交数据之前,即还没有建立subversion transaction(txn)之前执行该脚本,提交前触发事务);

pre-revprop-change(在修改revision属性之前,执行该脚本);

post-revprop-change

pre-unlock(对文件进行解锁操作之前执行该脚本);

post-unlock

pre-lock(对文件进行加锁操作之前执行该脚本)

post-lock

SVN钩子生产应用场景:

pre-commit(限制上传文件扩展名(如压缩包、视频不能上传)、限制上传文件大小、控制提交时要输入的信息);

post-commit(提交后通过邮件、MSN告知指定人,SVN更新触发checkout程序,定时rsync推送到指定服务器);

 

[root@localhost ~]# cd /application/svndata/project1/hooks/

[root@localhost hooks]# ll

total 36

-rw-r--r--. 1 root root 1977 Jun 22 22:40post-commit.tmpl

-rw-r--r--. 1 root root 1638 Jun 22 22:40post-lock.tmpl

-rw-r--r--. 1 root root 2289 Jun 22 22:40post-revprop-change.tmpl

-rw-r--r--. 1 root root 1567 Jun 22 22:40post-unlock.tmpl

-rw-r--r--. 1 root root 3426 Jun 22 22:40pre-commit.tmpl

-rw-r--r--. 1 root root 2410 Jun 22 22:40pre-lock.tmpl

-rw-r--r--. 1 root root 2786 Jun 22 22:40pre-revprop-change.tmpl

-rw-r--r--. 1 root root 2100 Jun 22 22:40pre-unlock.tmpl

-rw-r--r--. 1 root root 2780 Jun 22 22:40start-commit.tmpl

 

 

案例一(rsyncsvn hookspost-commit实现数据实时同步,此例是将SVNserver上的数据同步至本地/tmp下):

[root@localhost ~]# mkdir -pv /data/www   #(在SVNserver上操作)

mkdir: created directory `/data'

mkdir: created directory `/data/www'

[root@localhost ~]# svn checkout svn://192.168.194.128/sadoc /data/www/ --username root --password chai

A   /data/www/2.txt

A   /data/www/b.txt

A   /data/www/3.txt

A   /data/www/c.txt

A   /data/www/d.txt

A   /data/www/test.txt

A   /data/www/1.txt

A   /data/www/a.txt

Checked out revision 5.

[root@localhost ~]# ifconfig | grep -A 1eth0

eth0     Link encap:Ethernet  HWaddr00:0C:29:1F:B6:AC 

         inet addr:192.168.194.128 Bcast:192.168.194.255 Mask:255.255.255.0

[root@localhost ~]# cd/application/svndata/sadoc/hooks

[root@localhost hooks]# cp post-commit.tmpl post-commit

[root@localhost hooks]# vim post-commit

---------------------script start-------------------

#!/bin/sh

REPOS="$1"

REV="$2"

mailer.py commit "$REPOS""$REV" /path/to/mailer.conf

 

export LANG="en_US.UTF-8"

export LC_CTYPE="en_US.UTF-8"

export LC_ALL=

 

LOGPATH="/app/log"

 

[ ! -d $LOGPATH ] && mkdir -p $LOGPATH

/usr/bin/svn update /data/www --username root --password chai

 

if [ $? -eq 0 ] ; then

        /usr/bin/rsync -az --delete /data/www /tmp

fi

----------------------script end---------------------

[root@localhost hooks]# chmod 755 !$   #(注意钩子脚本要有执行权限,一般为755,且脚本中的路径最好用绝对路径,因为它不会继承系统环境变量,使用时要在脚本中重新设定环境变量,脚本svn update执行前要先手动svn checkout下)

chmod 755 post-commit

[root@localhost hooks]# ll post-commit

-rwxr-xr-x. 1 root root 2242 Jun 23 00:32post-commit

 

winclient增删(或在Linuxclient操作均可):

右键svndatacommitOK

SVNserver端查看:

[root@localhost hooks]# ll /tmp/www

total 0

-rw-r--r--. 1 root root 0 Jul 13 02:241.txt

-rw-r--r--. 1 root root 0 Jul 13 02:242.txt

-rw-r--r--. 1 root root 0 Jul 13 02:243.txt

-rw-r--r--. 1 root root 0 Jul 13 02:24a.txt

-rw-r--r--. 1 root root 0 Jul 13 02:24b.txt

-rw-r--r--. 1 root root 0 Jul 13 02:24c.txt

-rw-r--r--. 1 root root 0 Jul 13 02:24d.txt

-rw-r--r--. 1 root root 0 Jul 13 02:33rsync_test.txt

-rw-r--r--. 1 root root 0 Jul 13 02:24test.txt

 

或在Linuxclient操作:

[root@localhost ~]# mkdir -p /data/www

[root@localhost ~]# svn checkout svn://192.168.194.128/sadoc/ /data/www --username root --password chai

[root@localhost ~]# cd /data/www

[root@localhost www]# ll

total 0

-rw-r--r--. 1 root root 0 Jun 23 00:181.txt

-rw-r--r--. 1 root root 0 Jun 23 00:182.txt

-rw-r--r--. 1 root root 0 Jun 23 00:183.txt

-rw-r--r--. 1 root root 0 Jun 23 00:18a.txt

-rw-r--r--. 1 root root 0 Jun 23 00:18b.txt

-rw-r--r--. 1 root root 0 Jun 23 00:18c.txt

-rw-r--r--. 1 root root 0 Jun 23 00:18d.txt

-rw-r--r--. 1 root root 0 Jul 13 02:57rsync_test.txt

-rw-r--r--. 1 root root 0 Jun 23 00:18 test.txt

[root@localhost www]# touch rsync.txt

[root@localhost www]# svn add rsync.txt

A        rsync.txt

[root@localhost www]# svn commit -m 'svncommit data'   #(只有输入信息才能提交成功)

Adding         rsync.txt

Transmitting file data .

Committed revision 10.

[root@localhost www]# ll

total 0

-rw-r--r--. 1 root root 0 Jun 23 00:181.txt

-rw-r--r--. 1 root root 0 Jun 23 00:182.txt

-rw-r--r--. 1 root root 0 Jun 23 00:183.txt

-rw-r--r--. 1 root root 0 Jun 23 00:18a.txt

-rw-r--r--. 1 root root 0 Jun 23 00:18b.txt

-rw-r--r--. 1 root root 0 Jun 23 00:18c.txt

-rw-r--r--. 1 root root 0 Jun 23 00:18d.txt

-rw-r--r--. 1 root root 0 Jul 13 02:57rsync_test.txt

-rw-r--r--. 1 root root 0 Jul 13 03:05rsync.txt

-rw-r--r--. 1 root root 0 Jun 23 00:18test.txt

[root@localhost www]# svn list svn://192.168.194.128/sadoc/ --verbose --username root --password chai

    10 root                  Jul 1302:46 ./

     5 root                0 Jun 2223:00 1.txt

     5 root                0 Jun 2223:00 2.txt

     5 root                0 Jun 22 23:00 3.txt

     4 root                0 Jun 2222:29 a.txt

     4 root                0 Jun 2222:29 b.txt

     4 root                0 Jun 2222:29 c.txt

     4 root                0 Jun 2222:29 d.txt

    10 root                0 Jul 13 03:05rsync.txt

     9 root                0 Jul 13 02:57rsync_test.txt

     2 root                0 Jun 2222:12 test.txt

 

注:SVN hook案例逻辑架构

 

 

案例二(利用svn hookspre-commit限制上传文件扩展名及大小):

[root@localhost hooks]# vim pre-commit

--------------script start------------------

#!/bin/sh

REPOS="$1"

TXN="$2"

MAX_SIZE=5242880

FILTER='\.(zip|rar|o|obj|tar|gz)$'

SVNLOOK=/usr/bin/svnlook

LOGMSG=`$SVNLOOK log -t "$TXN""$REPOS" | grep "[a-zA-Z0-9]" | wc -c`

if [ "$LOGMSG" -lt 9 ];then

       echo -e "nLog message can't be empty!you must input more than 8 chars as comment!" 1>&2

       exit 1

fi

 

files=$($SVNLOOK changed -t $TXN $REPOS |cut -d" " -f 4-)

rc=0

echo "$files" | while read f;do

       if echo $f | tr A-Z a-z | grep -Eq $FILTER;then

                echo "File $f is not allow($FILTER) file" >& 2

                exit 1;

       fi

filesize=`$SVNLOOK cat -t "$TXN""$REPOS" "$f" | wc -c`

       if [ "$filesize" -gt "$MAX_SIZE" ];then

                echo "File $f is too large(must <= $MAX_SIZE) B" >& 2

                exit 1;

       fi

done

if [ $? -eq 1 ];then

       exit 1

else

       exit 0

fi-------------script end--------------

[root@localhost hooks]# chmod 755 pre-commit

[root@localhost hooks]# ll pre-commit

-rwxr-xr-x. 1 root root 4087 Jul 13 03:57pre-commit

 

win client试验:

SVN commit时没写comment注释会提示报错;

SVN commit压缩文档时提示报错;

SVN commit大于5M的文件时,提示报错;

 

 

 

小型企业上线解决方案:

小型企业一般几个开发人员,且网站核心程序大多数都是php开发,为方便,会直接通过FTP上传程序代码到线上server,随时随地上线更新,此方案的问题:

发布快、及时、随时随地可发布代码;

开发人员发布的代码不经过测试人员的测试,且用户访问页面刷新后页面即改变,也可能刷新瞬间程序在更新,导致用户可能无法正常访问,对网站用户的体验较差,如果开发写错了代码,会造成更大的影响,这是拿用户作为测试的上线方案;

网站50%以上的故障是和开发程序代码有关的,例如代码中的死循环导致server内存资源耗尽引起宕机;

中小公司网站出问题一般是运维人员的问题,导致的原因大多可能与开发人员的代码有关,好的策略是开发项目负责制思想;

 

建议:

开发人员需在个人电脑搭建LAMP环境用以测试开发好的网站代码,并在办公室或IDC机房的测试环境下通过,最好有专职测试人员;

程序代码上线公布时间,如三天上线一次,如果网站需经常更新可每天17:00上线,具体看网站业务性质而定,原则是影响用户体验降至最低;

代码上线前需备份,网站程序出了问题方便回退,从上线技巧上,上传代码时尽可能先传到服务器网站临时目录,传完整后再mv过去,或通过ln做软链接,如果再严格些,应把应用服务器从集群节点平滑下线,然后更新;

务必由运维人员管理上线,开发人员在意的是代码的功能性,运维在意的是代码的性能和上线后服务器的稳定,如果网站问题归运维管,就要让运维负责上线,这样更规范科学,否则开发随意更新,出问题由运维负责这不妥当;

 

 

中型企业上线解决方案:

一般是规范运维人员操作步骤,制定统一的上线操作脚本,备份文件名称、备份文件路径,使操作人性化、统一化、自动化;

web代码上线流程:

 

 

大型企业上线解决方案:

统一制度和流程控制较多,较严谨,下图是java代码上线方案,在流量代谷下线进行;

注:

打包由mvnants工具打包,格式为war,如idc_dep.waridc_test.waridc_product.war

ITILBSW等运维规范;

SVN server上存放的有:程序代码、服务的配置、项目文档、设计文档、运维部署优化文档;

大型企业有配置管理员这一岗位,负责SVN管理、上线管理、申请协调(协调开发人员和运维人员),图中第5步骤由配置管理员负责;

Jenkins可将SVNserver的代码自动的发布到办公开发环境(依据脚本编译JAVA程序、重启tomcat等),常用于测试;

IDC上测试有问题,说明IDC测试环境与本地的软硬件环境不一致;

从测试到上线至少要在办公开发环境、IDC测试环境通过后才允许最后在正式环境上线;

IDC统一分发管理server上的程序代码和各服务的配置文件是从SVN server上来的,若直接从正式服务器上改配置文件内容,统一分发管理server会自动将自己获取到的配置文件覆盖掉已更新的文件导致更改无效,在此架构下若要更改配置文件要走正式流程(要经过配置管理员等);

IDC统一分发控制管理(secboy,secureCRT,ssh+sudo+rsync,expect,puppet,cfengine,sersync,lsyncd)

越靠近用户上线频率越高,越底层上线频率越低;

注:

web serverAB两组,将A组停服,从正式的LVS卸下,挂至测试用的LVS上,待测试OKA组运行换B组上线,无论webserver有多少只能分两组上线,否则代码会有新有旧,用户会明显感知到;

 

 

程序代码上线具体方案:

1、本地开发人员从SVNserver中获取代码,当天上线的提交到trunk,否则长期项目要单开分支开发,然后再合并到trunk主线;

2、办公内网开发时,由开发人员或配置管理员通过部署平台Jenkins实现统一部署(即在部署平台上控制开发机器从SVN取代码、编译、打包、发布到开发机,包名idc_dep.war);

3、开发人员通知或和测试人员一直测试程序,没问题后,由配置管理员打上新的tag

4、配置管理员根据上步的tagcheckout出上线代码,并配置好IDC测试环境的所有配置,执行编译、打包(mvn,ant),php则不需要,然后发布到IDC内的统一分发server,注意不同环境的配置文件是随代码同时发布的;

5、配置管理员或SA上线人员,把分发的程序代码内容推送到相关测试服务器(包名idc_test.war),然后通知开发和测试人员进行测试,若有问题向上回退,继续修改;

6、若IDC测试没问题,继续打好tag,此时配置管理员根据上步的tagcheckout出测试好的代码,并配置好IDC正式环境的所有配置,执行编译、打包(mvn,ant)php则不需要,然后发布到IDC内的统一分发server主机,准备指发布;

7、配置管理员或SA上线人员,把分发的内容推送到相关正式服务器(包名idc_product.war),然后通知开发人员进行测试,若有问题直接发布回滚指令;

注:

IDC正式上线的过程对于JAVA程序,可以是AB组分组上线的思路(即平滑下线一半的服务器),然后发布更新代码测试,重启,测试没问题后,挂上服务器,同时再平滑下线另一半的server,再发布更新代码测试(或直接发布后重启挂上线);

注:

php程序代码上线(测试完毕,发布代码时可以发布到正式线临时目录,再mvln发布到正式线目录,不需重启httpd服务,这是sinaganji的上线方案);

注:

JAVA程序代码上线(较大公司(独立IP100w以上)需要分组平滑上线,先从LB器上摘掉一半server,发布代码后重启server测试,没问题后挂上,再下另一半,如果前端有DNS智能解析,上线还可以分地区上线若干服务器,逐渐普及到全国的server,这个被称为灰度发布);

 

代码上线解决方案注意事项:

1、上线的流程里,办公测试环境-->IDC测试环境-->正式生产环境,这三个环境中的所有软件均应版本统一,否则后患无穷,如OSwebserverjdkphptomcatresin等;

2、办公测试环境由开发小组维护,定时自动更新代码,有问题反馈给某开发人员重新开发;

3、有专门的测试工程师,程序有问题直接返回给开发人员(此时的问题一般为BUG,称BUG库),无问题再进行IDC测试;

4IDC测试由测试人员和运维人员共同参与,叫IDC test,进行程序的压力测试,有问题直接返回给开发人员,无问题再上线;

5、数台server代码分发上线方案(JAVA程序):假如业务server有六台,将其分为AB两组,先对A组进行从LB器上平滑下线,B组正常提供服务,避免影响线上业务;下线过程一般在夜晚网络流量少时,通过脚本将AserverRS池(LVSnginxhaproxyF5等均有平滑下线方案)中踢出,避免LB器将请求发给Aserver;将代码分发到Aserver的站点目录下,对Aserver上线并重启服务,由测试人员测试成功后,挂上Aserver,同时下线BserverA组之前操作一样;

6、若是php程序,上线可简单化,直接将线上代码(最好全量)发布到所有上线server的特定目录后,一次性mvln到站点目录,测试成功后即可(各种测试脚本测试各个相关业务接口);

7、大多数门户公司的前端页面都已静态化或cache了,因此动态的部分平时访问的量少,网站流量低时更少,再加上平滑上下线,基本上对用户体验无影响,也有出问题这避免不了;

8SVN上包含代码和配置:程序代码(不含资源,大公司网站资源和程序是分离的);所有服务的配置文件(开发小组测试环境使用的配置文件、办公测试环境使用的配置文件、IDC测试环境使用的配置文件、线上应用使用的配置文件);

注:在上线不同环境时,由配置管理员协调上线;尽可能全量上线的原因:务必要保证SVN的代码是最新的

注:自动化部署及代码发布管理平台(中大型公司都有,自己开发的web页面)

 

开发及运维人员业务变更管理平台:

优点:变更管理制度流程有利于业务稳定;保留变更业务历史,便于检查发现的问题;故障跟踪平台,有利于跟踪问题的解决进度,而不是半途而废;相关常用软件

 

JIRA用于缺陷跟踪、客户服务、需求收集、流程审批、任务跟踪、项目跟踪、敏捷管理等荼领域;

Mantis是一款php开源bug跟踪系统,适合中小型项目的管理及跟踪,特性:易于安装,易操作,基于web,支持任何可运行的php平台

 

软件设计流程(按30天):

需要分析阶段(7天)-->软件设计阶段(逻辑图、建模,7-10天)-->编码阶段(3-7天)-->软件测试(7天)-->发布市场

 

Linux运维工程师(一线):使用软件的阶段(架构师提供的文档),包括内部开发的软件工具,安装、搭建、简单调优;

Linux架构师(二线):把一堆软件整合在一起,满足某个项目需求;需求分析,项目架构方案设计,写架构文档,推进项目进度、培训,架构问题的顾问;

python运维开发-->C语言运维系统开发(软件开发、工具开发、创新、编写部署使用文档、培训、顾问)