1.背景
网上有很多文章描述svn下如何使用hooks来实现自动化部署。本文侧重描述在docker环境的具体实现(其中也会包含非docker的实现方法)
相关环境:
- svn的docker容器
- 应用的docker容器
- 宿主机本地目录
- /XX/svn:存放svn相关配置、库数据
- /XX/app:存放应用相关的程序、配置
2.SVN的配置修改
2.1.镜像
可通过【docker pull docker.io/elleflorio/svn-server:latest】下载一个svn的镜像,或者下载其他镜像,先按官方说明调试通过。
2.2.配置
2.2.1.SVN本地目录结构
/XX/svn的目录结构:
ubuntu@VM:~/svn$ ls -lrt
total 24
-rw-rw-r-- 1 ubuntu ubuntu 384 May 11 22:17 dav_svn.conf
-rw-rw-r-- 1 ubuntu ubuntu 125 May 11 22:24 passwd.conf
-rw-rw-r-- 1 ubuntu ubuntu 1142 May 11 22:26 auth.conf
drwxr-xr-x 6 root root 4096 May 11 22:26 seventy
-rwxrwxr-x 1 ubuntu ubuntu 381 Jun 6 10:59 start.sh
其中seventy目录需在容器运行前先手工创建,然后在svn容器中执行svn建库命令,此目录只存放svn的库数据。
另外几个文件说明如下:
- httpd的配置文件dav_svn.conf:
LoadModule dav_svn_module /usr/lib/apache2/mod_dav_svn.so
LoadModule authz_svn_module /usr/lib/apache2/mod_authz_svn.so
<Location /svn>
DAV svn
SVNParentPath /home/svn
SVNListParentPath On
AuthType Basic
AuthName "Subversion Repository"
AuthUserFile /home/svn/passwd.conf
AuthzSVNAccessFile /home/svn/auth.conf
Require valid-user
</Location>
此项为针对apache的httpd配置,具体配置说明,可参考我的另一篇linux+httpd+svn实现http访问及修改口令,重点是其中的AuthUserFile和AuthzSVNAccessFile,其路径均指向/home/svn目录,此目录将会被挂载到宿主机上,因此/home/svn/passwd.conf也就是/XX/svn/passwd.conf,同理auth.conf。
- SVN密码设置passwd.conf:
ubuntu@VM:~/svn$ cat passwd.conf
view:$apr1$/iL9B/Dn$UMyhxjh04gmtN7qSbo/K20
此文件需使用svn命令htpasswd生成,请不要手工编写。
- SVN权限配置auth.conf:
[reps:/]
view=r
表示svn的URL中/svn/reps目录对view用户开放只读权限。读者可根据实际情况进行配置。
- 容器启动脚本start.sh:
#!/bin/bash
# 先后台启动容器
# 将svn和app的本地目录分别映射到容器的/home/svn和/home/app目录中
docker run --name svns \
-v /XX/svn:/home/svn \
-v /XX/app:/home/app \
-h svns \
-p 3380:80 \
-p 3360:3960 \
-m 305m \
-d docker.io/elleflorio/svn-server:latest
# 再在容器中执行一下配置数据命令
docker exec -d svns sh -c "cp /home/svn/dav_svn.conf /etc/apache2/conf.d/dav_svn.conf && chown -R apache:apache /home/app/"
说明:
1)启动容器时指定的参数,也可参考elleflorio/svn-server的官方说明,如果是其他镜像,请参考其具体的参数说明;
2)重点讲解下两个-v参数,前者是专用于存放svn自己的库文件、配置的目录,后者是专用于存放app的程序代码或配置,下节会详细说明。
3)最后的cp命令是将容器中已经存在的httpd配置进行覆盖,然后再修改/home/app目录的所属者为apache用户。
重点:需要修改/home/app为apache的所属者,原因为svn容器中实际执行时,是先通过apache用户来执行svn相关操作的,而不是容器默认的root用户,必须保证apache用户有权限往/home/app目录里写文件,否则后期的hooks在执行时就会出错。
2.2.2.钩子
前述操作完后,假设您已经调通svn了,可以通过http://<IP>:3380/svn/reps方式访问svn库了(可在浏览器中测试验证)。
下面开始真正的自动化部署实现。
- 先在/XX/app或/home/app下创建程序包的复本
上述是在svn容器中执行的,如果在宿主机上执行,则需修改下IP和端口。svn co http://localhost:80/svn/reps /home/app/ --username 'view' --password 'xxxxxx'
但无论如何,请记得在co完后,执行【chown -R apache:apache /home/app/】,因为默认这些文件的所属者多半不是apache的。 - 编写钩子post-commit。
将/home/svn/reps/hooks下的post-commit.tmpl复制一份,并重命名为post-commit:
post-commit文件内容:cd /home/svn/reps/hooks cp post-commit.tmpl post-commit chown apache:apache post-commit # 此步最好一起做下,以防万一 chmod u+x post-commit touch /home/svn/hooks_commit.log # 用来查看hook的执行日志 chown apache:apache /home/svn/hooks_commit.log
此处重点是svn的update,与前文的svn的co形成前后呼应。## 省略默认的模板部分 TXN_NAME="$3" # mailer.py commit "$REPOS" "$REV" /path/to/mailer.conf logs="/home/svn/hooks_commit.log" ## 此日志文件需有apache:apache写入权限,否则会看不到日志记录 echo "${REPOS},${REV},${TXN_NAME}" >> ${logs} export LANG=en_US.utf8 SVN_PATH="/usr/bin/svn" APP_PATH="/home/app/" ${SVN_PATH} update ${APP_PATH} --username 'view' --password 'xxxxxx' --no-auth-cache 1>>${logs} 2>&1 echo "Updated. ${APP_PATH}" >> ${logs}
可手工先验证下post-commit脚本是否有问题
当然这个执行是在svn容器里面,表示使用apache用户和/bin/sh这个shell(如果镜像中有bash也可替换使用),来执行post-commit这个脚本,若在hooks_commit.log中未显示异常报错,则应该没有什么问题。su -s /bin/sh -c '/home/svn/reps/hooks/post-commit' apache
- 验证hooks
先【tail -f /home/svn/hooks_commit.log】,再随便在svn库中更新一个文件,看日志文件是否有更新,如果有报错,则改正。 - 常见异常
表明/home/app版本的所属者不是apache,请使用chown进行修改。svn: E155004: Run 'svn cleanup' to remove locks (type 'svn help cleanup' for details) svn: E155004: Failed to lock working copy '/home/app'. svn: E200031: sqlite[S8]: attempt to write a readonly database svn: E200042: Additional errors: svn: E200031: sqlite[S8]: attempt to write a readonly database
3.应用app
应用app可能有多种,假设您已经下载到一个合适的镜像,本文以python3.6+django2.0.5镜像为例,启动app镜像的start.sh
#!/bin/bash
#
docker run --name app \
-v /XX/app:/datavol \
-h appserver \
-p 8089:8089 \
-m 500m \
--entrypoint /datavol/entrypoint-docker.sh \ # 重点
-d py365django205:latest # app的镜像
其中/XX/app/entrypoint-docker.sh脚本如下:
#!/bin/sh
tail -f /dev/null
其实也就是不让容器停止而已,当然也可以编写自己的启动脚本。
对于django来说,当使用manage.py runserver方式来启动时,若程序代码有更新,django服务器会自动重启。
对于其他程序,读者可查阅相关文档,找到一种合理的方式去自动更新服务器状态。
4.完成
至此,所有的配置就已经完成了。当我们开发完代码,提交svn(http://xxx:xx/svn/reps/)完成后,svn容器就会主动去执行post-commit脚本,然后就会主动在/XX/app/目录下更新对应的工程代码,最后是应用app容器中自动重启服务,最终达到最精简的自动化部署的目的。
核心思想:通过宿主机的/XX/app目录来实现svn容器和app容器间代码的共享,形成生产者-消费者关系;/XX/app目录需apache用户权限。