苏苏的博客

简约至极

使用Docker快速搭建一个Git Server

使用gogs搭建git server

使用docker

如何搭建一个git server

以及升级,备份等

docker 方式安装

安装和运行docker就不说了.

1.首先docker pull gogs/gogs 拉取镜像

2.创建一个数据卷docker volume create --name gogs-data

要查看已有的数据卷,使用docker volume ls,数据卷用于保存数据,升级时数据不会丢,切勿删除此数据卷

3.启动服务

docker run -d --name=gogs --restart always -m 200m --log-opt max-size=2m  -p 10022:22 -p 10080:3000 -v gogs-data:/data gogs/gogs

使用-v gogs-data:/data挂载刚刚的数据卷,将数据卷内的数据映射到容器的/data路径下.

也可以前面添加一个nginx反向代理 /etc/nginx/conf.d/git.conf

server{
	listen 80;
	server_name git.xx.cn code.xx.cn;
	gzip on;
	gzip_min_length 1024;
	gzip_proxied any;
	gzip_comp_level 3;
	gzip_types text/plain text/javascript text/css text/json application/xml application/javascript application/x-javascript application/json;
	location / {
		client_max_body_size 10m;
		proxy_pass http://127.0.0.1:10080;
		proxy_set_header Host $host;
		proxy_set_header X-Forwarded-Ssl off;
		proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
		proxy_set_header X-Forwarded-Port 80;
	}
}

4.升级

docker stop gogsdocker rm gogs 然后执行步骤3就可以了

不放心的话,可以先stop,然后rename,再步骤三启动新版本的,启动成功后再删除旧版本的.

数据备份与恢复

备份docker volume数据

文件接收端执行 nc -l 9090 > data.tar.gz 有些nc(busybox里的nc)可能是 nc -l -p 9090 > data.tar.gz

以只读模式挂载数据卷,挂载数据卷到/data路径

docker run --rm -it -v gogs-data:/data:ro busybox sh -c "cd /data && tar czvf - . | nc host 9090"

挂载到本地文件夹并打包

docker run --rm -it -v gogs-data:/data:ro -v /data/backup:/backup busybox sh

cd /data && tar czvf /backup/gogs-data-2018.tgz .

使用crontab自动备份

/usr/cron/gogs.sh

docker run --rm -v gogs-data:/data:ro -v /data/backup:/backup -w /data busybox tar czvf /backup/gogs-data-$(date '+%Y%m%d').tgz .

为root用户添加crontab, 每5天进行一次备份

10 3 */5 * * /usr/cron/gogs.sh

打包文件并发送到目标主机

恢复docker volume数据

如果没有这个数据卷,先创建数据卷 docker volume create --name gogs-data

docker run --rm -it -v gogs-data:/data busybox sh -c "nc -l -p 9090 | tar -C /data -zxf -"

然后通过宿主机发送数据 nc host 9090 < data.tar.gz

如果两台电脑可以直接连通

发送方 docker run --rm -it -v gogs-data:/data:ro busybox sh -c "cd /data && tar czvf - . | nc host 9090"

接收方 docker run --rm -p 9090:9090 -it -v gogs-data:/data busybox sh -c "nc -l -p 9090 | tar -C /data -zxf -"

相关错误

remote: Counting objects: 860, done.
remote: aborting due to possible repository corruption on the remote side.
fatal: protocol error: bad pack header

由于服务器端在传送 git pull 或者 git clone时需提前压缩数据,这些数据是存放在内存中.(git pull时服务端内存不断增长,由于我使用的docker,只分配了60M内存);当内存不够使用时造成错误.

解决方案 1. 增加服务端内存. 或者 2. 修改git客户端配置 https://stackoverflow.com/questions/4170317/git-pull-error-remote-object-is-corrupted

即客户端执行

git config --global pack.windowMemory "100m"
git config --global pack.SizeLimit "100m"
git config --global pack.threads "1"

顺便说 docker 修改内存配置

docker update gogs -m 200m --memory-swap=400m

配置网络转发

容器的http端口和ssh分别映射到1008010022,我们使用域名和80端口对外服务.

添加nginx配置 git.conf

server{
		listen 80;
		server_name git.xx.cn code.xx.cn;
		gzip on;
		gzip_min_length 1024;
		gzip_proxied any;
		gzip_comp_level 3;
		gzip_types text/plain text/javascript text/css text/json application/xml application/javascript application/x-javascript application/json image/jpeg image/gif image/png;
		location / {
				client_max_body_size 10m;
				proxy_pass http://127.0.0.1:10080;
				proxy_set_header Host $host;
				proxy_set_header X-Forwarded-Ssl off;
				proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
				proxy_set_header X-Forwarded-Port 80;
		}
}

少许优化:gogs默认没有gzip,我们通过nginx添加了gzip;设置最大提交文件为10M

然后就可以使用域名直接访问,如果发现通过nginx代理后报 502 nginx erro log Permission denied, 可能是SELinux的问题

检查SELinux日志 sudo cat /var/log/audit/audit.log | grep nginx | grep denied

如果发现被 SELinux拦截, 可以执行setsebool -P httpd_can_network_connect 1开启此条规则

附:

getsebool -a | grep httpd 可以查看 SELinux 关于 http 的配置

setsebool httpd_can_network_connect on 使本次生效

setsebool httpd_can_network_connect on -Ppersist模式,永久生效

使用后立即生效,无需重启任何服务.

配合git hook 自动部署PHP和静态网页

写了一个server用于接受通知 https://github.com/suconghou/gitsync.git

主要是接收到用户推送代码后,不存在则clone项目,存在则更新项目.

启动服务gitsy > /var/log/gitsy.log 2>&1 &,然后由nginx代理隐藏端口,使用域名访问

server{
    server_name g.share.xx.cn;
    listen 80;
    gzip on;
    location / {
        proxy_pass http://127.0.0.1:19090;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Ssl off;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Port 80;
    }
}

gitsy 启动后可通过http查看loghttp://g.share.xx.cn/log

repos目录可由docker挂载只读,防止删除操作,请求都转发到docker内,由内部nginx-fpm运行代码

转发到docker里的nginx

server{
    server_name *.share.xx.cn;
    listen 80;
    gzip on;
    index index.html index.php;
    location / {
        proxy_pass http://127.0.0.1:18001;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Ssl off;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Port 80;
    }
}

docker目录的映射为docker run -v /data/share/runtime/:/www --name datafs busybox

docker run -d --name dev --restart always -m 100m --log-opt max-size=2m --volumes-from datafs -p 18001:80 -p 12201:22 suconghou/server

可以使用/data/share/runtime/:/www:ro使用只读

docker内部的nginx处理各个vhost的请求

server {
	listen  80;
	server_name 0.0.0.0;
	index index.html index.php;
	if ($host ~* ^(([\w\-]+)\.share\.ourwill\.cn)$) {
		set $subdomain $2;
	}
	root /www/$subdomain;
		if ( !-d $document_root ){
		return 404;
	}
	try_files $uri $uri/ /index.php?$args;
	location ~ \.php$ {
		try_files $uri =404;
		fastcgi_pass  127.0.0.1:9000;
		fastcgi_param debug 2;
		include        fastcgi.conf;
	}
}

也可以直接使用本地nginx+fpm请求,不使用docker,代码可本地读写

server{
	listen 80;
	server_name *.run.xx.cn;
	index index.php index.html;
	fastcgi_connect_timeout 2s;
	fastcgi_send_timeout 10s;
	fastcgi_read_timeout 5s;
	ssi on;
	gzip on;
	if ($host ~* ^(([\w\-]+)\.run\.ourwill\.cn)$) {
		set $subdomain $2;
	}
	root /data/share/runtime/$subdomain;
	if ( !-d $document_root){
		return 404;
	}
	add_header X-Root "$subdomain";
    try_files $uri $uri/ /index.php?$args;
	location ~ \.php$ {
        try_files $uri =404;
        client_max_body_size 10m;
        fastcgi_param debug 2;
		fastcgi_pass 127.0.0.1:9000;
        include        fastcgi.conf;
	}
}

此两种环境都传递了变量 debug 到php-fpm,php 代码中可使用 getenv('debug') 判断是何种环境.线上环境没有配置debug,得出false

可以通过另一容器挂载git的数据目录也可实现即时部署