0%

subversion

subversion

Subversion是一个开源的版本控制系统。与git类似,但git更适合用于做代码仓库的版本控制系统,而svn更适合储存文件的版本控制系统。

svn与git差异

差异性转自互联网

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
两者差异在于:

1. SVN是集中式版本控制系统,Git是分布式版本控制系统;

2. SVN记录差异比较,Git是对新版本直接做快照;

3. SVN的提交会出现冲突的概率随着同一时间工作人数的增加而增加,Git鼓励多建分支使得冲突几率减小,且冲突解决机制更好(待分析);

4. SVN可以通过权限控制使得部分代码的安全性,Git 则是完全clone整个仓库到本地,任何人均可以访问任何部分的代码。

1.SVN优缺点

优点:
1、 管理方便,逻辑明确,符合一般人思维习惯。
2、 易于管理,集中式服务器更能保证安全性。
3、 代码一致性非常高。
4、 适合开发人数不多的项目开发。
缺点:
1、 服务器压力太大,数据库容量暴增。
2、 如果不能连接到服务器上,基本上不可以工作,看上面第二步,如果服务器不能连接上,就不能提交,还原,对比等等。
3、 不适合开源开发(开发人数非常非常多,但是Google app engine就是用svn的)。但是一般集中式管理的有非常明确的权限管理机制(例如分支访问限制),可以实现分层管理,从而很好的解决开发人数众多的问题。

2.Git优缺点
优点:
1、适合分布式开发,强调个体。
2、公共服务器压力和数据量都不会太大。
3、速度快、灵活。
4、任意两个开发者之间可以很容易的解决冲突。
5、离线工作。
缺点:
1、学习周期相对而言比较长。
2、不符合常规思维。
3、代码保密性差,一旦开发者把整个库克隆下来就可以完全公开所有代码和版本信息。

svn架构

image-20230301153242578

图中的一端是保存所有版本数据的Subversion版本库,另一端是Subvesion的客户程序,管理着所有版本数据的本地影射(称为“工作拷贝”),在这两极之间是各种各样的版本库访问(RA)层,某些使用电脑网络通过网络服务器访问版本库,某些则绕过网络服务器直接访问版本库,还可以通过apache的mod_dav_svn模块来访问svn。

svn相关命令

1
2
3
4
5
6
7
8
svn——命令行客户端程序。
svnversion——此工具用来显示工作拷贝的状态(用术语来说,就是当前项目的修订版本)。
svnlook——直接查看Subversion版本库的工具。
svnadmin——建立、调整和修复Subversion版本库的工具。
svndumpfilter——过滤Subversion版本库转储数据流的工具。
mod_dav_svn——Apache HTTP服务器的一个插件,使版本库可以通过网络访问。
svnserve——一个单独运行的服务器程序,可以作为守护进程或由SSH调用。这是另一种使版本库可以通过网络访问的方式。
svnsync——一个通过网络增量镜像版本库的程序。

svn部署

snv部署安装

svn官网:https://subversion.apache.org/

centos或红帽直接使用yum可以部署svn

1
yum -y install subversion

如果是windows需要在官方下载安装包,ubuntu可以使用apt直接安装svn。

svn创建仓库

第一步我们先创建一个仓库,创建了该仓库以后该目录下会生成该仓库的数据文件、配置文件等相关文件。

1
2
3
4
5
使用svnadmin命令创建svn仓库
[root@1ef3598b0b11 /]# mkdir /data/svn/ -p
[root@1ef3598b0b11 /]# svnadmin create /data/svn/test 创建一个名为test的svn仓库
[root@1ef3598b0b11 /]# ls /data/svn/test/
README.txt conf db format hooks lock

仓库结构图

image-20230301154019028

svn配置文件

svn配置文件默认是svnadmin创建的svn仓库下面的config目录中,svn配置文件名称为:svnserve.conf。passwd是默认用户名密码认证文件,auzhz是权限配置文件。

这里需要注意的是svn使用中最重要的三个配置文件为:svnserve.conf、passwd、authz。其中svnserve.conf是svn服务启动指定的配置文件,定义了用户权限以及认证文件的路径,而passwd和zuth分别是用户账号密码管理文件以及用户权限文件。每当使用svnadmin创建一个仓库的时候,都会在仓库根路径的conf目录下生成这三个文件,需要手动修改(默认所有配置都是注释的)。并且这里如果有创建及管理多个仓库的需求建议统一将其放在一个路径,例如/etc/subversion下面,而不是具体放在某一个仓库的conf下面(因为这里虽然每个仓库都有自己的配置文件,但实际上svn服务启动的时候只能指定一个配置文件,而配置文件里面的passwd和authz也只能指定一个)。

svnserve.conf

该文件为svn配置文件,默认为config/svnserve.conf,通过–config-file可以手动指定配置文件路径

1
2
3
4
5
6
7
8
9
10
11
[general]
anon-access = none
#禁止匿名用户访问,还可以设置为read 或者write ,缺省值:read
auth-access = write
#配置可写权限,还可以设置为read或者none,缺省值:write
password-db = passwd
#指定用户配置文件路径,这里是./passwd, 缺省值:passwd
authz-db = authz
#指定权限配置文件,这里是./authz,缺省值:authz
realm = Local or LDAP Account
# 认证命名空间,会在认证提示界面显示,并作为凭证缓存的关键字,可以写仓库名称比如svn。这个配置可不填,非必选项

passwd

该文件为svn服务的用户账号密码管理配置文件,如果上面的配置文件中没有指定路径,只写了文件名,则应该放在与配置文件同级目录下,这里应当为/data/svn/config/passwd(这里的/data/svn是上面通过svnadmin create /svn/data创建的仓库)。

配置文件语法为 一个[users]配置段,然后输入用户名 = 密码即可

1
2
[users]
admin = 123456

authz

该文件为svn的用户权限配置文件,是配置用户对于文件目录的权限的,例如我设置根目录[/]配置段,admin = rw则为在根下面,admin拥有读写权限。该文件和passwd一样,如果没有在svn配置文件中指定其路径,只写了文件名,则应当放于配置文件同级目录下,这里应当是/data/svn/config/authz(这里的/data/svn是上面通过svnadmin create /svn/data创建的仓库)

1
2
[/]
admin = rw

这个配置文件的权限使用较为复杂,下面详细说明

目录权限及授权
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
authz文件示例:
[/]
admin = rw
[svn:/]
admin = rw
[svn2:/]
admin = r
[svn:/manager]
admin =

语法:
这里授权的语法为:
[仓库名:路径]
用户 = 权限
以上面的文件示例为例子,[/]表示根路径,admin=rw表示拥有读写权限,则前两行的配置定义了admin在根路径下面拥有读写权限,这里需要注意,子目录在默认不配置权限则会继承父目录的权限。
然后[svn:/]和[svn2:/]这里时表示名为svn的仓库与名为svn2的仓库权限配置,例如我通过 svnadmin create /svn 以及svnadmin create /svn2创建了两个仓库,这里就可以通过配置这两项来定义其权限。
最后一个配置为[svn:/manager],表示名为svn的仓库下面的/manager路径的权限,这里admin = 后面没有跟任何值则表示admin在该路径下无任何权限。

关于仓库名:
这里需要注意的是这里的仓库名仅限于以svn根路径为单位,其下一级路径的仓库。也就是假如我这里在启动时定义了-r /data,则此时svn的根路径为/data,我这个时候通过svnadmin create /data/svn创建了一个名为svn的仓库,则这里的/data/svn仓库匹配的权限也就是上面的定义的 [svn:/]权限,访问地址为svn://ip/svn,svn2同理。但如果我启动svn为参数 -r /data/svn,这个时候由于根路径是/data/svn,所以[svn:/]的权限配置是不匹配的,匹配的权限应该是[/],并且这里访问地址也变成了svn://ip/。

关于多仓库的管理:
如果需要管理多个仓库,建议将这些仓库的上一级设置为svn根路径。例如我在/data下面通过svnadmin create 创建了svn1、svn2到svn10这10个仓库。这里在启动的时候就需要通过指定参数-r /data,将/data指定为根路径,此时authz配置文件的里面通过设置[auth1:/]、[auth2:/]...[auth10:/]来定义这10个仓库的用户权限,访问地址这时候为svn://ip/svn1、svn://ip/svn2...。默认情况多仓库模式下会读取各自仓库的config/svnserve.conf配置文件,但为了管理方便,最好在svn启动时通过svnserve --config-file=/etc/subversion/svnverve.conf指定一个配置文件,统一管理仓库的配置、用户、权限。

根路径:
根路径[/] 拥有所有仓库的权限。
组授权
1
2
3
4
5
6
7
8
9
10
11
在实际生产环境中,会给不同的人首先分配不同的组,然后根据组来统一授权管理。例如公司有部门,就会根据部分划分不同的目录权限。
定义组及其组成员:
在authz文件中定义一个[groups]配置段,然后和其他配置项一样通过 group = user1,user2这种方式定义用户,例子如下:
[groups]
开发部 = zhangsan,lisi,wangwu
品牌部 = liuer,cendy,jack
定义了组以后将组授权给目录的方式与用户授权有点不同,需要在组名前面加一个@符号,例子如下:
[svn:/]
@开发部 = rw
[svn:/project]
@品牌部 = r

完整授权zuthz示例文件如下,可供参考

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
[groups]
管理员 = admin,lisi
开发部 = zhangsan,lisi,wangwu
品牌部 = liuer,cendy,jack
[/]
* =
@管理员 = rw
[develop:/]
* = r
@管理员 = rw
[develop:/algorithm]
@开发部 = rw
* =
[develop:/delivery]
@开发部 = rw
* =
[develop:/firmware]
@品牌部 = rw
* =
[develop:/product]
@开发部 = rw
* =
[develop:/omg]
* =
@管理员 = rw
[develop:/omg/secret]
@管理员 = rw
* =
[develop:/management]
* =
ztianchang = rw

svn启动

启动的前提是配置文件和仓库都配置创建好了。

启动有两种方式:

1
2
1.svnserve -d #通过svn服务命令启动服务,-d为daemon模式启动。
2.systemctl start svnserve #通过systemd启动服务。

需要注意的点:

1
2
3
1.默认部署时系统并不会自动创建配置文件,所以这里配置文件需要手动创建(或者使用通过svnadmin创建了仓库以后生成的配置文件),然后使用--config-file=指定配置文件路径。
2.如果我通过svnadmin create /data/svn 创建了一个仓库,则这里仓库的访问地址应当为svn://ip:/data/svn。但这里的问题是其实真正生产使用场景应该使用根目录访问才对,所以这里可以在启动时指定 -r /data/svn 参数,意味以/data/svn作为根目录(家目录),然后启动时通过-r参数指定家目录位置:svnserve -r /data/svn -d ,则访问地址为:svn://ip/ 。如果要使用多仓库,启动命令可以改为:svnserve -r /data -d,然后将仓库都创建与/data下面,访问地址为: svn://ip/仓库名
3.默认用yum安装的使用systemd来启动控制svn服务,其参数只跟了-d,没有其他参数,需要手动更改其service文件。

svn-ldap

svn本身不支持ldap。有两种方式可以支持ldap:1.sasl 2.apache-httpd

sasl

这里的sasl方式转自互联网

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
一、安装sasl相关组件
#yum install -y cyrus-sasl cyrus-sasl-lib cyrus-sasl-plain
二、查看SASL版本和提供的验证模块
#saslauthd -v


三、修改sasl的用户验证方式为ldap
#cp /etc/sysconfig/saslauthd /etc/sysconfig/saslauthd.save
#sed -i 's/MECH=pam/MECH=ldap/' /etc/sysconfig/saslauthd


四、修改sasl配置文件(不存在则新建)
#vi /etc/saslauthd.conf (以下信息根据ldap服务来配置)
ldap_servers: ldap://192.168.1.2
ldap_bind_dn: cn=chengdu,dc=sichuan,dc=com
ldap_bind_pw: xxxxxx
ldap_search_base: dc=sichuan,dc=com
ldap_filter: uid=%U
ldap_deref: never
ldap_restart: yes
ldap_scope: sub
ldap_use_sasl: no
ldap_start_tls: no
ldap_version: 3
ldap_auth_method: bind
ldap_mech: DIGEST-MD5
ldap_password_attr: userPassword
ldap_timeout: 10
ldap_cache_ttl: 30
ldap_cache_mem: 32786
五、重启sasl服务,测试是否通过
# systemctl restart saslauthd
# testsaslauthd -u 用户 -p 密码


六、修改配置文件svn.conf,不存在则新建,目前不知此文件的作用
#vi /etc/sasl2/svn.conf
pwcheck_method:saslauthd
mech_list:plain login
七、重启sasl服务,并做好svn的相关配置
#cat svnserve.conf
[general]
anon-access = none
auth-access = write
#password-db = passwd
authz-db = authz
realm = /opt/svn/migu/SPMS
[sasl]
use-sasl = true
httpd

使用apache代理的方式来访问svn以及通过apache ldap模块实现ldap认证。需要注意的是httpd不支持根路径访问,详情见下面SVNParentPath的注释说明。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
安装
yum -y install httpd subversion mod_dav_svn mod_ldap httpd-devel php php-ldap #安装http和svn以及ldap相关模块
mkdir -p /data/svn && svnadmin create /data/svn/test #创建一个测试的仓库 && chown apache:apache -R /data/svn/ #创建svn仓库

写入svn用户和权限配置文件(根据自己使用的需求写入)
cat >> /data/svn/authz << EOF
[/]
* = rw
EOF


写入httpd的ldap配置
cat > /etc/httpd/conf.d/ldap.conf << EOF
LoadModule ldap_module modules/mod_ldap.so
LoadModule authnz_ldap_module modules/mod_authnz_ldap.so

<AuthnProviderAlias ldap directory>
AuthLDAPURL ldap://192.168.110.29:30389/dc=finsiot,dc=com?uid?sub?
#AuthLDAPURL ldap://ldap地址:端口/ldap资源路径?uid?sub?
AuthLDAPBindDN cn=admin,dc=finsiot,dc=com
#AuthLDAPBindDN ldap admin的路径
AuthLDAPBindPassword 123456
#AuthLDAPBindPassword ldap admin的密码
AuthLDAPBindAuthoritative off
</AuthnProviderAlias>
EOF


subversion httpd代理配置文件
cat > /etc/httpd/conf.d/subversion.conf << EOF

LoadModule dav_module modules/mod_dav.so
LoadModule dav_fs_module modules/mod_dav_fs.so

LoadModule dav_svn_module modules/mod_dav_svn.so
LoadModule authz_svn_module modules/mod_authz_svn.so

LoadModule rewrite_module modules/mod_rewrite.so

<IfModule mod_dav_fs.c>
# Location of the WebDAV lock database.
DAVLockDB /var/lib/dav/lockdb
</IfModule>

BrowserMatch "Microsoft Data Access Internet Publishing Provider" redirect-carefully
BrowserMatch "MS FrontPage" redirect-carefully
BrowserMatch "^WebDrive" redirect-carefully
BrowserMatch "^WebDAVFS/1.[01234]" redirect-carefully
BrowserMatch "^gnome-vfs/1.0" redirect-carefully
BrowserMatch "^XML Spy" redirect-carefully
BrowserMatch "^Dreamweaver-WebDAV-SCM1" redirect-carefully
BrowserMatch " Konqueror/4" redirect-carefully

BrowserMatch "MSIE [1-4]" nokeepalive ssl-unclean-shutdown downgrade-1.0 force-response-1.0
BrowserMatch "MSIE [5-9]" ssl-unclean-shutdown
BrowserMatch "^SVN" redirect-carefully


LogFormat "%t %u %{SVN-REPOS}e: %{SVN-ACTION}e" subversion

CustomLog logs/subversion.log subversion env=SVN-ACTION




<Location "/">
AuthType Basic
AuthName "Local or LDAP Account"
AuthBasicProvider file directory
AuthUserFile /data/svn/.htpasswd
# AuthLDAPBindAuthoritative off
Require valid-user

DAV svn
DavMinTimeout 300
SVNParentPath /data/svn
SVNListParentPath on
SVNIndexXSLT /repos/.svnindex.xsl
AuthzSVNAccessFile /data/svn/authz

</Location>


EOF
1
2
3
4
配置完以后启动httpd:systemctl start httpd ,然后通过客户端访问http://ip/仓库名即可。文档里面仅作为测试创建了一个test的库,在生产使用中请根据自己需求创建对应的库。
需要注意的是这里访问要使用http协议,而不是之前的svn协议,并且原来的svnserve服务是不需要启动的。第二个是配置文件里面定义用户权限也是直接使用ldap的登录用户名来定义,例如我有一个manager的ldap用户,权限示例:
[/]
manager = rw

tortoisesvn(client)

svn客户端可以使用tortoisesvn,官网下载地址:https://tortoisesvn.net/downloads.html

但默认是英文,如想使用中文需要额外下载中文包。安装完重启以后,鼠标右键就可以看到如下:

image-20230302104328519

svn检出和导出是一样,选择svn检出,输入要检出的服务器url以及本地目录,然后认证登录

image-20230302104448409

image-20230302104519270

然后就可以看到导出的svn服务器文件

image-20230302104621503

如有增删改操作,可以直接操作文件夹或文件,然后右键svn提交,选择要提交的文件就行。

image-20230302104801021

image-20230302104811311

docker部署svn

首先如果没有头绪,可以现在dockerhub上找一下subversion的镜像。这些下载排名比较靠前的镜像都可以直接使用,一般是没问题的,主要需要注意的就是挂载其数据目录。但svn本身比较简单,也可以自己制作svn的镜像然后部署

关于docker(k8s)中svn的持久化存储

1
2
3
4
5
6
7
这个我自己研究了一下,只需要挂载svn的数据目录就行。例如我这里用svnadmin create创建了一个 /data/svn。那么访问地址应该为svn://svn_url:3690/data/svn。所以这里svn的访问路径是对应linux目录路径的,再比如svnadmin create /usr/local/svn ,访问地址就是svn://svn_url:3690/usr/local/svn。而这里也应该将创建的svn目录挂载出去,以实现数据持久化。

再一个就是svn的配置文件以及用户认证配置:从上面svn部署中可以知道,用svnadmin create创建了一个svn数据目录以后,该目录下面有config文件夹,svnserve.conf、passwd、authz存放在这里就行了(默认也是存放在这里),没有必要去/etc/subversion中配置该文件,不然还需要多挂载一个目录。

最后是启动svnserve的时候需要指定配置文件路径,例如我这里的svn数据文件目录为/data/svn,那么启动命令应该为:svnserve -d --config-file /data/svn/config/svnserve.conf。需要手动指定配置文件路径,不然默认找不到。

总结:挂载用svnadmin创建的数据文件目录,启动时指定配置文件路径,客户端访问的时候访问路径与linux本身目录路径一致。

svn docker镜像制作

这里用centos7作为基础镜像

Dokcerfile

1
2
3
4
5
6
7
from centos:7
RUN yum -y install subversion vim kde-l10n-Chinese iproute
RUN localedef -c -f UTF-8 -i zh_CN zh_CN.utf8
ENV LANG=zh_CN.utf8 TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
COPY start.sh /
CMD ["/bin/bash","/start.sh"]

这里的start.sh是启动脚本,首先判断/data/svn这个目录是否是空目录,如果为空则自动创建成svn数据目录,主要简化了操作,避免第一次运行镜像时挂载目录没有数据,还需要主动创建数据目录,第二个是保证docker有一个主进程在运行,因为docker没有主进程会挂掉,当然svnserve前台启动也可以,但在k8s中这样是不行的(原因未知)。有很多服务在自制镜像时都会遇到这个问题,我的建议是最后运行程序阶段都可以使用这种方式来保证有一个服务是主进程且不会挂掉。这里启动脚本设置了一个探测端口是否监听的任务,直接while true sleep其实也可以。

start.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
data_directory='/data/svn' #svn在容器启动时会自动创建第一个svn家目录,这里可以修改为指定的家目录。
if [[ `ls $data_directory | wc -L` < 1 ]]
then
mkdir -p $data_directory && svnadmin create $data_directory
echo "svn ${data_directory} directory is not exist,it will create now"
cat > //data/svn/conf/svnserve.conf << EOF
[general]
authz-db=authz
password-db=passwd
auth-access=write
anon-access=none
EOF
cat >> /data/svn/conf/authz << EOF
[/]
* = rw
EOF
cat >> /data/svn/conf/passwd << EOF
[users]
admin = 123456
EOF
#这里设置了默认的账号和密码
else
echo "svn ${data_directory} directory is exist,do nothing"
fi
/usr/bin/svnserve -d -r /data/svn --config-file=/data/svn/conf/svnserve.conf
a=0
b=0
while true
do
if [[ `ss -tunl | grep :3690 | wc -l` == 1 ]]
then
echo 'subersion is health'
b+=1
if (( b>=3 ));
then
a=0
fi
sleep 30s
else
echo 'subersion is not running'
a+=1
sleep 30s
if (( a>=3 ));
then
break
fi
fi
done

dockerfile build

1
2
3
docker build -t svn:latest .
docker run -it --rm -p 3690:3690 -v /c/docker/svn:/data/svn svn:latest #测试运行
备注:在生产及正式使用时,请务必将/data/svn和/etc/subversion/做持久化存储挂载。该镜像为单仓库镜像,仓库名为svn,如果需要多仓库的话需要自行更改。

客户端测试

image-20230727162804493

image-20230727162829476

image-20230727162954519

svn-ldap docker

这里主要以集成apache-httpd的方式实现ldap,需要用到httpd以及httpd的ldap、svn插件。

文件共分为:Dockerfile、httpd-subversion.conf、httpd-ldap.conf、start.sh

Dockerfile

1
2
3
4
5
6
7
8
9
10
11
12
FROM centos:7
RUN yum -y install httpd subversion mod_dav_svn mod_ldap httpd-devel iproute vim kde-l10n-Chinese telnet
RUN localedef -c -f UTF-8 -i zh_CN zh_CN.utf8
ENV LANG=zh_CN.utf8 TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
RUN mkdir -p /data/svn && mkdir -p /etc/subversion && chown apache:apache -R /data/svn/
COPY subversion.conf /etc/httpd/conf.d/
COPY ldap.conf /etc/subversion/
COPY authz /data/svn
COPY .htpasswd /data/svn
COPY start.sh /
CMD ["/bin/sh" "-c" "bash /start.sh"]
subversion.conf

http的svn配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
LoadModule dav_module modules/mod_dav.so
LoadModule dav_fs_module modules/mod_dav_fs.so

LoadModule dav_svn_module modules/mod_dav_svn.so
LoadModule authz_svn_module modules/mod_authz_svn.so

LoadModule rewrite_module modules/mod_rewrite.so

<IfModule mod_dav_fs.c>
# Location of the WebDAV lock database.
DAVLockDB /var/lib/dav/lockdb
</IfModule>

BrowserMatch "Microsoft Data Access Internet Publishing Provider" redirect-carefully
BrowserMatch "MS FrontPage" redirect-carefully
BrowserMatch "^WebDrive" redirect-carefully
BrowserMatch "^WebDAVFS/1.[01234]" redirect-carefully
BrowserMatch "^gnome-vfs/1.0" redirect-carefully
BrowserMatch "^XML Spy" redirect-carefully
BrowserMatch "^Dreamweaver-WebDAV-SCM1" redirect-carefully
BrowserMatch " Konqueror/4" redirect-carefully

BrowserMatch "MSIE [1-4]" nokeepalive ssl-unclean-shutdown downgrade-1.0 force-response-1.0
BrowserMatch "MSIE [5-9]" ssl-unclean-shutdown
BrowserMatch "^SVN" redirect-carefully

LogFormat "%t %u %{SVN-REPOS}e: %{SVN-ACTION}e" subversion

CustomLog logs/subversion.log subversion env=SVN-ACTION

<Location "/"> #根路径做ldap认证
AuthType Basic
AuthName "Local or LDAP Account"
AuthBasicProvider file directory

# AuthLDAPBindAuthoritative off
Require valid-user

DAV svn
DavMinTimeout 300
SVNParentPath /data/svn
SVNListParentPath on
SVNIndexXSLT /repos/.svnindex.xsl
AuthzSVNAccessFile /data/svn/authz
</Location>

.htpasswd

httpd认证文件

1
admin:$apr1$4hsCKNwI$6d0BcYJup.OevhlchSdxS/
ldap.conf

httpd的ldap认证配置文件

1
2
3
4
5
6
<AuthnProviderAlias ldap directory>
AuthLDAPURL ldap://192.168.110.29:30389/dc=finsiot,dc=com?uid?sub?
AuthLDAPBindDN cn=admin,dc=finsiot,dc=com
AuthLDAPBindPassword 123456
AuthLDAPBindAuthoritative off
</AuthnProviderAlias>
authz

根据需求配置用户权限

1
2
[/]
* = rw
start.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/usr/sbin/httpd 
a=0
b=0
while true
do
if [[ `ss -tunl | grep :80 |wc -l` == 1 ]]
then
echo 'subersion is health'
b+=1
if (( b>=3 ));
then
a=0
fi
sleep 30s
else
echo 'subersion is not running'
a+=1
sleep 30s
if (( a>=3 ));
then
break
fi
fi
done

1
2
3
4
5
docker build . -t subversion-ldap
docker run -it --name subversion-ldap -p 80:80 subversion-ldap
备注:
1.在生产及正式使用时,请务必将/data/svn做持久化存储挂载,并将原本写入的.htpasswd和authz复制到/data/svn,或者重新生成也可以。
2.默认没有创建svn仓库,请手动创建,创建后访问地址为 http://ip/仓库名

k8s部署svn

镜像以上面制作的为基准,或者用dockerhub开源的镜像也可(但需要根据镜像实际情况配置挂载路径或容器运行参数),下面是yaml文件

svn.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
apiVersion: apps/v1
kind: Deployment
metadata:
name: svn
namespace: devops
spec:
replicas: 1
selector:
matchLabels:
tier: svn
template:
metadata:
labels:
tier: svn
spec:
containers:
- name: svn
image: docker-registry.finsiot.com/finsiot/subversion-finsiot:v1.0
imagePullPolicy: Always
ports:
- containerPort: 3690
volumeMounts: #容器内挂载点的定义部分
- name: svn-pvc #容器内挂载点名称
mountPath: /data/svn #容器内挂载点路径,可以是文件或目录
subPath: svn
volumes:
- name: svn-pvc
persistentVolumeClaim:
claimName: svn

---
apiVersion: v1
kind: Service
metadata:
name: svn-svc
namespace: devops
spec:
externalIPs:
- 192.168.110.29
ports:
- port: 3690
name: tcp
targetPort: 3690
protocol: TCP
selector:
tier: svn
type: ClusterIP

k8s部署ldap的svn

svn-ldap.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
apiVersion: apps/v1
kind: Deployment
metadata:
name: svn
namespace: devops
spec:
replicas: 1
selector:
matchLabels:
tier: svn
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
template:
metadata:
creationTimestamp: null
labels:
tier: svn
spec:
containers:
- image: docker-registry.finsiot.com/finsiot/subversion-finsiot:v1.1
imagePullPolicy: Always
name: svn
ports:
- containerPort: 80
protocol: TCP
volumeMounts:
- mountPath: /data/svn
name: svn-pvc
subPath: svn
#需要将原本写入的.htpasswd和authz复制到/data/svn,或者重新生成也可以。并且需要手动创建svn仓库。
volumes:
- name: svn-pvc
persistentVolumeClaim:
claimName: svn
---
apiVersion: v1
kind: Service
metadata:
name: svn-svc
namespace: devops
spec:
ports:
- name: http
nodePort: 32630
port: 80
protocol: TCP
targetPort: 80
selector:
tier: svn
type: NodePort
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/ingress-class: traefik
nginx.ingress.kubernetes.io/proxy-body-size: 999M
nginx.ingress.kubernetes.io/proxy-read-timeout: 1800s
nginx.ingress.kubernetes.io/proxy-send-timeout: 1800s
name: svn
namespace: devops
spec:
ingressClassName: traefik
rules:
- host: svn.finsiot.com
http:
paths:
- backend:
service:
name: svn-svc
port:
number: 80
path: /
pathType: Prefix
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: svn
namespace: devops
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 600Gi
storageClassName: csi-rbd-sc
volumeMode: Filesystem

iF.SVNadmin

if.svnadmin是svn最常用的一种web管理工具。

部署

其部署需要和svn同服务器。if.svnadmin本身是php程序,通过apache及其php模块部署访问。

1
2
3
4
5
6
7
8
9
10
11
# yum install httpd subversion php php-ldap mod_ldap php-json php-xml php-pdo mod_ssl mod_dav_svn -y

# cd /usr/src && wget https://udomain.dl.sourceforge.net/project/ifsvnadmin/svnadmin-1.6.2.zip --no-check-certificate
# unzip svnadmin-1.6.2.zip
# mv iF.SVNAdmin-stable-1.6.2/ /var/www/html/svnadmin
# chmod -R 777 /var/www/html/svnadmin/data/

# chown -R apache:apache /var/www/html/svnadmin/
# chown -R apache:apache /data/svn/
# systemctl enable httpd
# systemctl start httpd

访问:http://ip/svnadmin

这里一般情况下可以直接访问,但如果是按上面的步骤部署的svn的话,其httpd的subversion配置需要修改一下(因其本身只访问指向了svn),这里可以将其svn和if.svnadmin配置成两个域名进行访问(也可以两个端口)。

subversion.conf

这里以配置了两个VirtualHost,其中svn-web.example.com是if.svnadmin访问域名,svn.example.com是svn访问域名,可以将这两个域名改成使用时对应的域名,也可以通过不同端口来划分。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
LoadModule dav_module modules/mod_dav.so
LoadModule dav_fs_module modules/mod_dav_fs.so

LoadModule dav_svn_module modules/mod_dav_svn.so
LoadModule authz_svn_module modules/mod_authz_svn.so

LoadModule rewrite_module modules/mod_rewrite.so

<IfModule mod_dav_fs.c>
# Location of the WebDAV lock database.
DAVLockDB /var/lib/dav/lockdb
</IfModule>

BrowserMatch "Microsoft Data Access Internet Publishing Provider" redirect-carefully
BrowserMatch "MS FrontPage" redirect-carefully
BrowserMatch "^WebDrive" redirect-carefully
BrowserMatch "^WebDAVFS/1.[01234]" redirect-carefully
BrowserMatch "^gnome-vfs/1.0" redirect-carefully
BrowserMatch "^XML Spy" redirect-carefully
BrowserMatch "^Dreamweaver-WebDAV-SCM1" redirect-carefully
BrowserMatch " Konqueror/4" redirect-carefully

BrowserMatch "MSIE [1-4]" nokeepalive ssl-unclean-shutdown downgrade-1.0 force-response-1.0
BrowserMatch "MSIE [5-9]" ssl-unclean-shutdown
BrowserMatch "^SVN" redirect-carefully


LogFormat "%t %u %{SVN-REPOS}e: %{SVN-ACTION}e" subversion

CustomLog logs/subversion.log subversion env=SVN-ACTION

<VirtualHost *:80>
ServerName svn-web.example.com
DocumentRoot /var/www/html/svnadmin
<Directory /var/www/html/svnadmin>
Order Deny,Allow
Allow from All
</Directory>
<FilesMatch \.php$>
SetHandler application/x-httpd-php
</FilesMatch>
</VirtualHost>

<VirtualHost *:80>
ServerName svn.example.com
<Location "/">
AuthType Basic
AuthName "Local or LDAP Account"
AuthBasicProvider file directory
AuthUserFile /etc/subversion/passwd
# AuthUserFile svn用户认证文件路径
Require valid-user

DAV svn
DavMinTimeout 300
SVNParentPath /data/svn
#SVNParentPath svn仓库的上级路径。这个配置需要注意,例如这里我的仓库路径是/data/svn,在这里配置的时候只能写上级目录/data,然后访问的时候是http://ip/svn ,不能写成SVNParentPath /data/svn通过根路径http://ip/直接访问到/data/svn仓库。
#这里由于httpd本身的限制,无法将svn仓库根路径作为http访问的根路径,所以httpd可以直接做svn多仓库,并通过http://svn/仓库名 访问对应的仓库。
SVNListParentPath on
SVNIndexXSLT /repos/.svnindex.xsl
AuthzSVNAccessFile /etc/subversion/authz
#AuthzSVNAccessFile svn用户权限路径
</Location>
</VirtualHost>

这里不能做成一个访问入口的主要原因是原来svn的根路径都用于匹配访问svn去了,如果要做就只能将其做成二级路径访问,简单来说就是分成两个uri:/svnadmin和/svn 。但这里问题是httpd的svn本身没办法指向仓库根路径,那访问svn仓库则变成了三级路径,例如我本身有一个名为svn的仓库,此时访问地址就变成了http://ip/svn/svn ,这样访问就没问题了,但从使用角度的问题来说主要还是访问路径多了不适合生产使用,用户不方便区分。

if.svnadmin集成并部署于k8s上

这里主要将if.svnadmin集成于svn上(带有ldap的svn)。

镜像制作

Dockerfile

这里需要提前准备好svnadmin的部署包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
FROM centos:7
RUN yum -y install psmisc httpd subversion mod_dav_svn mod_ldap httpd-devel iproute vim kde-l10n-Chinese telnet php php-ldap
RUN localedef -c -f UTF-8 -i zh_CN zh_CN.utf8
ENV LANG=zh_CN.utf8 TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
RUN mkdir -p /data/svn && mkdir -p /etc/subversion && chown apache:apache -R /data/svn/
ADD svnadmin.tar.gz /var/www/html/

RUN chmod -R 777 /var/www/html/svnadmin/ && chown -R apache:apache /var/www/html/svnadmin/
COPY .htpasswd /data/svn/
COPY authz /data/svn/
COPY ldap.conf /etc/httpd/conf.d/
COPY subversion.conf /etc/httpd/conf.d/
COPY start.sh /
CMD bash /start.sh
.htpasswd
1
admin:$apr1$4hsCKNwI$6d0BcYJup.OevhlchSdxS/
authz
1
2
[/]
* = rw
ldap.conf
1
2
3
4
5
6
7
8
9
LoadModule ldap_module modules/mod_ldap.so
LoadModule authnz_ldap_module modules/mod_authnz_ldap.so

<AuthnProviderAlias ldap directory>
AuthLDAPURL ldap://192.168.110.29:30389/dc=finsiot,dc=com?uid?sub?
AuthLDAPBindDN cn=admin,dc=finsiot,dc=com
AuthLDAPBindPassword 123456
AuthLDAPBindAuthoritative off
</AuthnProviderAlias>
subversion.conf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
LoadModule dav_module modules/mod_dav.so
LoadModule dav_fs_module modules/mod_dav_fs.so

LoadModule dav_svn_module modules/mod_dav_svn.so
LoadModule authz_svn_module modules/mod_authz_svn.so

LoadModule rewrite_module modules/mod_rewrite.so

<IfModule mod_dav_fs.c>
# Location of the WebDAV lock database.
DAVLockDB /var/lib/dav/lockdb
</IfModule>

BrowserMatch "Microsoft Data Access Internet Publishing Provider" redirect-carefully
BrowserMatch "MS FrontPage" redirect-carefully
BrowserMatch "^WebDrive" redirect-carefully
BrowserMatch "^WebDAVFS/1.[01234]" redirect-carefully
BrowserMatch "^gnome-vfs/1.0" redirect-carefully
BrowserMatch "^XML Spy" redirect-carefully
BrowserMatch "^Dreamweaver-WebDAV-SCM1" redirect-carefully
BrowserMatch " Konqueror/4" redirect-carefully

BrowserMatch "MSIE [1-4]" nokeepalive ssl-unclean-shutdown downgrade-1.0 force-response-1.0
BrowserMatch "MSIE [5-9]" ssl-unclean-shutdown
BrowserMatch "^SVN" redirect-carefully


LogFormat "%t %u %{SVN-REPOS}e: %{SVN-ACTION}e" subversion

CustomLog logs/subversion.log subversion env=SVN-ACTION

<VirtualHost *:80>
ServerName svn-web.example.com
DocumentRoot /var/www/html/svnadmin
<Directory /var/www/html/svnadmin>
Order Deny,Allow
Allow from All
</Directory>
<FilesMatch \.php$>
SetHandler application/x-httpd-php
</FilesMatch>
</VirtualHost>

<VirtualHost *:80>
ServerName svn.example.com
<Location "/">
AuthType Basic
AuthName "Local or LDAP Account"
AuthBasicProvider file directory
AuthUserFile /data/svn/.htpasswd
# AuthLDAPBindAuthoritative off
Require valid-user

DAV svn
DavMinTimeout 300
SVNParentPath /data/svn
SVNListParentPath on
SVNIndexXSLT /repos/.svnindex.xsl
AuthzSVNAccessFile /data/svn/authz
</Location>
</VirtualHost>
start.sh

启动时需要传递svn以及if.svnadmin的变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#!/bin/bash
if [[ -z "$SVN" ]]; then
echo "未设置 \$SVN 变量"
exit 1
fi

# 检查 $SVN_WEB 变量是否设置
if [[ -z "$SVN_WEB" ]]; then
echo "未设置 \$SVN_WEB 变量"
exit 1
fi

# 替换 subversion.conf 中的 svn.example.com
sed -i "s/svn.example.com/$SVN/g" /etc/httpd/conf.d/subversion.conf

# 替换 subversion.conf 中的 svn-web.example.com
sed -i "s/svn-web.example.com/$SVN_WEB/g" /etc/httpd/conf.d/subversion.conf


/usr/sbin/httpd
a=0
b=0
while true
do
if [[ `ss -tunl | grep :80| wc -l` == 1 ]]
then
echo 'subersion is health'
b+=1
if (( b>=3 ));
then
a=0
fi
sleep 30s
else
echo 'subersion is not running'
a+=1
sleep 30s
if (( a>=3 ));
then
break
fi
fi
done

部署

svn.yaml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
apiVersion: apps/v1
kind: Deployment
metadata:
name: svn
namespace: devops
spec:
replicas: 1
selector:
matchLabels:
tier: svn
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
template:
metadata:
creationTimestamp: null
labels:
tier: svn
spec:
containers:
- image: docker-registry.finsiot.com/finsiot/subversion-finsiot:v1.1
imagePullPolicy: Always
name: svn
env:
- name: SVN
value: 'svn.finsiot.com'
- name: SVN_WEB
value: 'svn-manager.finsiot.com'
ports:
- containerPort: 80
protocol: TCP
volumeMounts:
- mountPath: /data/svn
name: svn-pvc
subPath: svn
#需要将原本写入的.htpasswd和authz复制到/data/svn,或者重新生成也可以。并且需要手动创建svn仓库。
- mountPath: /var/www/html/svnadmin
name: svn-pvc
subPath: svnadmin
#请手动将svnadmin的文件复制到这个挂载路径(一旦持久化挂载了该目录原来镜像目录里面的文件就不存在了)。
volumes:
- name: svn-pvc
persistentVolumeClaim:
claimName: svn
---
apiVersion: v1
kind: Service
metadata:
name: svn-svc
namespace: devops
spec:
ports:
- name: http
nodePort: 32630
port: 80
protocol: TCP
targetPort: 80
selector:
tier: svn
type: NodePort
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/ingress-class: traefik
nginx.ingress.kubernetes.io/proxy-body-size: 999M
nginx.ingress.kubernetes.io/proxy-read-timeout: 1800s
nginx.ingress.kubernetes.io/proxy-send-timeout: 1800s
name: svn
namespace: devops
spec:
ingressClassName: traefik
rules:
- host: svn.finsiot.com
http:
paths:
- backend:
service:
name: svn-svc
port:
number: 80
path: /
pathType: Prefix
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/ingress-class: traefik
nginx.ingress.kubernetes.io/proxy-body-size: 999M
nginx.ingress.kubernetes.io/proxy-read-timeout: 1800s
nginx.ingress.kubernetes.io/proxy-send-timeout: 1800s
name: svn-manager
namespace: devops
spec:
ingressClassName: traefik
rules:
- host: svn-manager.finsiot.com
http:
paths:
- backend:
service:
name: svn-svc
port:
number: 80
path: /
pathType: Prefix
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: svn
namespace: devops
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 600Gi
storageClassName: csi-rbd-sc
volumeMode: Filesystem