Git 自动化部署
分两个部分:
搭建自己的git服务器
自动化部署
搭建自己的git服务器
一般的开源项目,我们都会把项目托管在第三方平台如github。 这样就省去了搭建git服务器的麻烦。
但如果你希望项目保密,或者很geek想自己搭建自己的git服务器那么就看下面的教程吧。
本人的服务器是 Ubuntu 12.04
1 首先在我们的服务器上面
sudo apt-get install git
sudo apt-get install openssh-server openssh-client
sudo /etc/init.d/ssh start
安装openssh-server和openssh-client是由于git需要通过ssh协议来在服务器与客户端之间传输文件。
用户信息
$ git config --global user.name "John Doe"
$ git config --global user.email johndoe@example.com
配置个人用户名和邮件地址。每次git提交都会引用这两条信息,说明是谁提交了更新,所以会随更新内容一起被永久纳入历史记录
创建一个git仓库的存储点:
sudo mkdir /var/deploy
sudo chown git:git /var/deploy
sudo chmod 755 /var/deploy
网上一堆教程让你groupadd user
useradd git ,其实只要安装了git,就会自动有git这个用户以及用户组生成。
2 客户端
大多数Git服务器都会选择SSH公钥来进行授权。系统中每个用户都必须提供一个公钥用于授权,没有的话就要生成一个。生成公钥的过程在所有OS上都类似:
ssh-keygen
然后查看~./ssh目录,是否有id_rsa.pub文件,然后拷贝到 服务器的 /home/git文件夹中。
或者拷贝到 服务器的 ~/.ssh 目录下。
然后执行以下的命令把公钥追加到authorized_keys文件尾部
服务端
$ cat /tmp/id_rsa.john.pub >> ~/.ssh/authorized_keys
$ cat /tmp/id_rsa.josie.pub >> ~/.ssh/authorized_keys
$ cat /tmp/id_rsa.jessica.pub >> ~/.ssh/authorized_keys
接着在我们的/home/git/repositories 目录下可以新建 一个裸仓库
cd /home/git/repositories
mkdir spw.git
cd spw.git
git init
回到客户端
我们此时就可以把它加为远程仓库,推送一个分支,从而把第一个版本的项目文件上传到仓库里。每次添加一个新项目都需要通过shell登入主机并创建一个裸仓库目录。
假设服务器ip为 192.168.1.196
在我们客户端,新建一个文件夹spw,作为要上传的文件夹
git init
git add .
git commit -m "No.1"
git remote add origin git@192.168.1.196:/home/git/repositories/spw.git
git push origin master
对于其他客户端来说,克隆和推送也非常简单:
git clone git@192.168.1.196:spw
3 安装配置gitosis
把所有用户的公钥都保存在authorized_keys文件的做法只能是暂时的,当用户数量达到几百人的规模,管理就会很痛苦。这种做法还缺少必要的权限管理-每个人都对所有项目拥有完整的读写权限。
Gitosis就是一套用来管理authorized_keys文件和实现简单连接限制的脚本。添加用户和设定权限只是管理一个特殊的Git仓库,我们只需要在这个仓库设定好,然后push到服务器上,Gitosis就会随之改变运行策略。
首先
安装python的setup tool.
sudo apt-get install python-setuptools
安装Gitosis
$ git clone https://github.com/tv42/gitosis.git
$ cd gitosis
$ sudo python setup.py install
默认Gitosis会把/home/git 作为存储所有Git仓库的根目录。 它会把帮我们管理用户公钥。
初始化
$ sudo -H -u git gitosis-init < /home/git/id_dsa.pub
这样公钥的拥有者就能修改用于配置Gitosis的那个特殊Git仓库。
本地计算机
$ git clone git@192.168.1.196:gitosis-admin.git
这就会得到一个#gitosis-admin#的工作目录。
$ cd gitosis-admin
$ find .
./gitosis.conf
./keydir
./keydir/scott.pub
gitosis.conf 文件时用来设置用户、仓库和权限的控制文件。 keydir目录保存所有具有访问权限的用户公钥的地方-每人一个。
Gitosis会自动从使用gitosis-init 脚本导入的公钥尾部的描述中获取该名字。
$ cat gitosis.conf
repo gitolite-admin
RW+ = id_rsa
repo testing
RW+ = @all
它显示用户id_rsa - 初始化Gitosis公钥的拥有者,是唯一能管理gitosisi-admin项目的人
我们添加新项目。 内容如下:
repo gitolite-admin
RW+ = id_rsa
repo testing
RW+ = @all
repo tomtest
RW+ = 201
repo spw
RW+ = jiaxing
RW+ = id_rsa
上面我们添加了两个新的项目,还有jiaxing这个心的用户 RW+ 表示允许读写这个项目。修改后,提交gitosis-admin里的改动,并push到服务器使其生效。
在新项目spw 里面首次push数据到服务器前,你需要设定该服务器地址为远程仓库。但你不用事先到服务器上手工创建该项目的裸仓库- Gitosis会在第一次遇到推送时自动创建!
$ git remote add origin git@192.168.1.196:spw.git
$ git push origin master
Initialized empty Git repository in /home/git/spw.git/
Counting objects: 3, done.
Writing objects: 100% (3/3), 230 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To git@192.168.1.196:spw.git
* [new branch] master -> master
我们不需要指明完整路径,只需要加一个冒号加项目名即可-Gitosis会自动帮你映射到实际位置!
其他人要管理这个项目,只需要把他们的公钥文件放到keydir目录下:
$ cp /tmp/id_rsa.john.pub keydir/john.pub
$ cp /tmp/id_rsa.josie.pub keydir/josie.pub
$ cp /tmp/id_rsa.jessica.pub keydir/jessica.pub
安装这个东西到你的服务器,其实这个是可选的,安装不安装都可以。 网上教程也很多。
自动化部署
关于部署,其实是自动化部署。我们一开始是想使用bash shell制定一个定时任务来不断git pull。但是这里会有很多问题,包括检测是否会错过。 所以还是选择Git Hooks比较好!
如果前面的步骤你完成好了,那么现在在你的服务器上面应该在/homt/git下面会有你的目录如下:
我把客户端的keys都备份放在这个目录下面了.
注意这个目录也需要修改成git用户。但是默认应该是属于git用户组以及git用户。
可以看到这是我们的几个项目对应的Git目录。(.git)
它是Git用来保存元数据和对象数据库的地方。
我们在客户端git init git add …创建的项目上传到的是这些文件夹当中,这些文件夹里面进入objects,有一堆看不懂的东西。其实这些就是git对象库
当你git push到服务器,其实就是更新这个Git目录的内容。
接着我们
git clone /home/git/repositories/spw.git /var/deploy
此时就把我们的项目克隆出来了。每次克隆镜像仓库的时候,实际拷贝的就是这个Git目录的数据。
而我们从项目中取出某个版本的所有文件和目录,用以开始后续工作的叫做工作目录。这些文件实际上都是从Git目录中的压缩对象数据库中提取出来的,接下来可以在工作目录中对这些文件进行编辑。
Git hook
介绍一下钩子,非常有用,当某些重要事件发生时候,Git调用自定义的脚本。 有两组挂钩:客户端和服务器端。 客户端挂钩用于客户端操作,如提交和合并。服务器端挂钩用于Git服务器端操作,如接受被推送的提交。
挂钩
挂钩在Git目录的hooks子目录中,Git会默认放置一些脚本样本在这个目录中,除了可以作为挂钩使用。这些样本本身是可以独立使用的。所有的样本都是shell脚本。在Git 1.6版本之后,这些样本名都是以.sample结尾,因此,你必须重新命名。
重新命名
cd /home/git/repositories/spw.git/hooks
mv post-update.sample post-update
这样就会激活这个挂钩。
Git的挂钩(Hook)主要包含:
- applypatch-msg
- post-update
- pre-rebase
- commit-msg
- pre-applypatch
- update
- post-commit
- pre-commit
- post-receive
- prepare-commit-msg
一般会用到的是 post-receive 或者 post-update
post-receive挂钩在整个过程完结以后运行,可以用来更新其他系统服务或者通知用户。
它接收与pre-receive相同的标准输入数据。
根据stackoverflow的解释:
post-receive:
当从本地版本库完成一个push后,在远程服务器上开始批量更新引用之前,该钩子脚本被触发执行。该钩子脚本的退出状态决定了更新引用的成功与否。
它的receive操作中只执行一次。该脚本胜过post-update的地方在于:它可以获得所有引用的老的和新的值,以及引用的名称。
post-update:
当从本地版本库完成一个push后,即当所有引用更新完毕后,在服务器上该钩子脚本被触发执行。
这个脚本能够提供哪些引用被更新了,但不知道引用更新前后的对象SHA1哈希值,所以在这个脚本中不能记录形如old…new的引用变更范围。 而钩子脚本 知道引用更新前后的对象ID,因此更适合这种场合!
总的来说就是post-receive比post-update功能更强大,但是对于我们当前这个项目来说两者都差不多。
以下是我的post-update脚本内容:
#!/bin/sh
#
# An example hook script to prepare a packed repository for use over
# dumb transports.
#
# To enable this hook, rename this file to "post-update".
#exec git update-server-info
#enable environment variable cause it's git
source /etc/profile
cd /home/git
rm -rf deploy
mkdir deploy
git clone /home/git/repositories/spw.git /home/git/deploy
cd /home/git/deploy
chmod a+x build.xml
ant -f build.xml
#chmod a+w /work/dist
cd /home/git/deploy/spw
cp -r * /usr/local/tomcat8/webapps/spw
cd /usr/local/tomcat8/bin
./shutdown.sh
./startup.sh
其实主要就是克隆出新的镜像并拷贝到一个特定的目录,当然这里我还用到了ant 构建工具,一个用于编译打包java代码的工具。 同时还包括一些权限设置,值得注意的是我们要读写操作的目录最好都放置在/home/git目录下,因为当post-update脚本执行的时候,其实是以git用户来执行的,所以必须要有git的权限:
#chown -R 用户名:用户组 目标文件夹
chown -R git:git post
Build Java代码并部署
build.xml内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<!-- 定义一个工程,默认任务为build。 -->
<project name="spw" default="build" basedir="./" >
<!-- 定义属性,目标文件夹 -->
<property name="targetPath" value="${basedir}/spw"/>
<!-- 定义路径,编译java文件时用到的jar包。 -->
<path id="project.lib">
<fileset dir="${basedir}/web/WEB-INF/lib">
<include name="**/*.jar"/>
</fileset>
</path>
<!-- 定义任务:创建新的目标文件夹target,复制web文件夹到target -->
<target name="create">
<delete dir="${targetPath}" />
<mkdir dir="${targetPath}" />
<copy todir="${targetPath}">
<fileset dir="${basedir}/web"/>
</copy>
<mkdir dir="${targetPath}/WEB-INF/classes" />
</target>
<!-- 定义任务,编译src文件夹中的java文件,编译后的class文件放到创建的文件夹下 -->
<target name="build" depends="create">
<javac srcdir="${basedir}/main/java" destdir="${targetPath}/WEB-INF/classes" includeantruntime="false"
debug="true" encoding="UTF-8" source="1.8" target="1.8">
<classpath refid="project.lib">
</classpath>
</javac>
<!--复制src/main/resources下非java文件到targetPath/WEB-INF/classes-->
<copy todir="${targetPath}/WEB-INF/classes">
<fileset dir="${basedir}/main/resources">
<include name="**/**.*" />
<exclude name="**/*.java"/>
</fileset>
</copy>
</target>
<!-- 定义默认任务,将class文件集合成jar包。 -->
<!--<target name="warFile" depends="build">-->
<!--将lib文件夹下的jar打包到WEB-INF/lib下 -->
<!--<copy todir="${basedir}/src/web/WEB-INF/lib">-->
<!--<fileset dir="${basedir}/src/web/WEB-INF/lib">-->
<!--</fileset>-->
<!--</copy>-->
<!-- 建立新war包。 -->
<!--<war destfile="${basedir}/${warFileName}" webxml="${basedir}/web/WEB-INF/web.xml">-->
<!--<!– 将非jar和非class文件拷贝到war包的对应路径下。 –>-->
<!--<fileset dir="${basedir}/target">-->
<!--<include name="**/**.*" />-->
<!--<exclude name="WEB-INF/classes/*.*"/>-->
<!--<exclude name="**/*.jar"/>-->
<!--<exclude name="**/*.class"/>-->
<!--</fileset>-->
<!--<!– 将jar和class文件拷贝到war包的对应路径下。 –>-->
<!--<lib dir="${basedir}/target/WEB-INF/lib" />-->
<!--<classes dir="${basedir}/target/WEB-INF/classes" />-->
<!--</war>-->
<!--</target>-->
</project>
当然你需要安装ant工具,不过这个很简单,安装好配置一下全局环境变量即可:
以下是我的服务器的环境变量配置 , tomcat服务器。并部署了后台java代码到tomcat上。
export JAVA_HOME=/usr/java8
export CLASSPATH=.:$JAVA_HOME/lib:$JAVA_HOME/jre/lib:$CLASSPATH
export PATH=$JAVA_HOME/bin:$JAVA_HOME/jre/bin:$PATH
#set tomcat environment
export CATALINA_HOME=/usr/local/tomcat8
#ANT environment
export ANT_HOME=/work/apache-ant-1.9.7
export PATH=$PATH:$ANT_HOME/bin
本文主要参考 《ProGit》
http://iissnan.com/progit/html/zh/ch7_3.html