Git自动化部署

本文介绍了如何搭建自己的Git服务器,包括安装配置gitosis、管理公钥和权限,以及使用Git Hooks实现自动化部署。详细步骤涵盖了从安装openssh-server到配置gitosis-admin,以及设置post-update钩子脚本来自动构建和部署Java代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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">-->
            <!--&lt;!&ndash; 将非jar和非class文件拷贝到war包的对应路径下。 &ndash;&gt;-->
            <!--<fileset dir="${basedir}/target">-->
                <!--<include name="**/**.*" />-->
                <!--<exclude name="WEB-INF/classes/*.*"/>-->
                <!--<exclude name="**/*.jar"/>-->
                <!--<exclude name="**/*.class"/>-->
            <!--</fileset>-->
            <!--&lt;!&ndash; 将jar和class文件拷贝到war包的对应路径下。 &ndash;&gt;-->
            <!--<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

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值