作者:wiLdGoose
发布时间:December 17, 2018
分类:技术 Technology
前阵子折腾了一个 Git 仓库迁移,觉得有必要自行马克一下。
需求背景:老的版本库在一台 Windows 主机上,用 Gitblit 搭建;我在某云用一台独立主机新搭建了一套 Gitlab,前端由另一台主机部署 Nginx 反向代理。
需求内容:将老版本库的所有仓库平滑迁移到新的版本库中。
任务拆解:部署并配置 Gitlab、创建项目仓库、镜像推送、将原先指向到 Gitblit 的域名解析修改到 Gitlab、导入账户,完成。
在一切都顺利进行的时候遇到一个大小为 2G 多的仓库,零碎文件较多,最大的单文件也就几百兆。由于我本地没有这个仓库,于是:
$ git clone https://path.to.git/repo.git
进度到 20% 多的时候,死活就断开了,反复尝试无效:
Cloning into 'repo'...
remote: Counting objects: 27709, done
remote: Finding sources: 100% (27709/27709)
remote: Getting sizes: 100% (16855/16855)
remote: Compressing objects: 23% (69/300)
error: RPC failed; curl 18 transfer closed with outstanding read data remaining
fatal: The remote end hung up unexpectedly
fatal: early EOF
fatal: index-pack failed
网上找到有人说需要更改一下 Git 客户端的上传限制大小:
$ git config http.postBuffer 524288000
或者直接修改 .gitconfig 文件,修改 [http] 段:
postBuffer = 524288000
好了,依然失败。万般无奈之下找同事 copy 了整个 Git 文件夹到我本地,修改 Git 用户配置文件,git pull,成功。接着修改配置文件到新的版本库地址,然后就是见证奇迹的时刻:
$ git push -u origin --all
Enumerating objects: 27705, done.
Counting objects: 100% (27705/27705), done.
Delta compression using up to 4 threads.
Compressing objects: 100% (12552/12552), done.
error: RPC failed; HTTP 413 curl 22 The requested URL returned error: 413 Request Entity Too Large
fatal: The remote end hung up unexpectedly
Writing objects: 100% (27705/27705), 1.97 GiB | 2.17 MiB/s, done.
Total 27705 (delta 12742), reused 27100 (delta 12209)
fatal: The remote end hung up unexpectedly
Everything up-to-date
与 clone 的时候一样,push 到一定程度就断开,反复尝试死活不行。想了半天不得其解,考虑到前端用 Nginx 做了反代,Google 之。有人说:
在服务器上面配置了 Nginx 之后,使用 Git 上传大文件的时候会出现“HTTP 413 curl 22 The requested URL returned error: 413 Request Entity Too Large”。
嗯,好像是找到问题了?于是修改 Nginx 的配置文件 nginx.conf,在 http 段加入:
client_max_body_size 1024m;
原文说 2m 够了,我贪心,直接加到 1024m。重启 Nginx,哈哈……特么的还是失败了。
眼睛盯着别人的仓库 URL 和我的 URL,总觉得哪里不对劲。原来 git@path.to.git/repo.git 走的是 SSH 协议,我的 https://path.to.git/repo.git 走的是 HTTP 协议。
改!一顿操作,改 sshd 端口号,配置 Gitlab 为 SSH 方式,到 Gitlab 后台对项目启用 SSH 方式,再次尝试……激动得眼泪都留下来了,成功。
结论:HTTP 协议不适合于大型项目的仓库,能走 SSH 就走 SSH 吧。
作者:wiLdGoose
发布时间:September 30, 2018
分类:技术 Technology
好久不在贵行混,殊不知原先那套 LAMP 或 LNMP 的架构早已奥特且随着岁月流逝慢慢发生了升级与变迁。
这次要玩的是一套提供前端服务的架构。大致交代一下故事背景:
1、负载机绑定了 1 个公网 IP 与 1 个私网 IP(VIP地址、私网 IP 漂移、HAProxy 高可用啥的需要运营商配合,正在准备,以后玩过了再写),部署 Nginx 用于反向代理;
2、前端服务所在主机与负载机在同一私网网段内。
好了,故事开始。
首先部署完负载机的 Nginx 服务,用于监听负载机的 TCP 80 及 443 端口。值得注意的是若使用源码编译方式安装 Nginx,记得添加:
--with-http_ssl_module --with-http_realip_module
其实直接 yum 也阔以。安装后对配置文件 nginx.conf 进行调整:
user www www;
worker_processes auto;
error_log /path/to/logs/error.log;
pid /path/to/logs/nginx.pid;
worker_rlimit_nofile 65535;
events {
use epoll;
worker_connections 65535;
}
http {
include mime.types;
default_type application/octet-stream;
include /usr/local/nginx/conf/reverse-proxy.conf;
sendfile on;
keepalive_timeout 65;
gzip on;
client_max_body_size 50m; #缓冲区代理缓冲用户端请求的最大字节数,可以理解为保存到本地再传给用户
client_body_buffer_size 256k;
client_header_timeout 3m;
client_body_timeout 3m;
send_timeout 3m;
proxy_connect_timeout 300s; #nginx跟后端服务器连接超时时间(代理连接超时)
proxy_read_timeout 300s; #连接成功后,后端服务器响应时间(代理接收超时)
proxy_send_timeout 300s;
proxy_buffer_size 64k; #设置代理服务器(nginx)保存用户头信息的缓冲区大小
proxy_buffers 4 32k; #proxy_buffers缓冲区,网页平均在32k以下的话,这样设置
proxy_busy_buffers_size 64k; #高负荷下缓冲大小(proxy_buffers*2)
proxy_temp_file_write_size 64k; #设定缓存文件夹大小,大于这个值,将从upstream服务器传递请求,而不缓冲到磁盘
proxy_ignore_client_abort on; #不允许代理端主动关闭连接
server {
listen 80;
server_name _;
location / {
root html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
记得打开防火墙端口,若还有上级网络安全策略等,更新配置。
前端机 Web 服务因人而异了,这里假定还是由 Nginx 提供前端服务,部署过程略,监听前端机的 TCP 80 端口。值得注意的是需要在 Nginx 配置文件中定义日志格式:
log_format access '$HTTP_X_REAL_IP - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" $HTTP_X_Forwarded_For';
access_log /path/to/logs/access.log access;
在负载机上编辑反向代理的配置文件:
vim /usr/local/nginx/conf/reverse-proxy.conf
若有多个 server 可再行扩展:
server
{
listen 80;
server_name sub.domain.com;
location / {
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://192.168.x.x;
}
access_log /path/to/logs/sub.domain.com_access.log;
}
截至目前,http 协议的转发已经完成。域名解析完成且生效后,访问应该会从负载机走私网定向到前端机。看了一圈日志没问题后,继续折腾 https。
SSL 证书提供商毫无疑问是 Let's Encrypt。据我所知有 certbot-auto 与 acme.sh 两种方式来实现证书自动申请与续展,前者貌似只能支持单个域名,而后者目前已支持泛域名证书。因此我选择后者。
配置过程就不展开了,中文版引导在这里。值得注意的是,若使用 certbot-auto,则需要修改负载机 Nginx 的反向代理配置文件,将 .well-known 目录指向本地:
server {
listen 80;
server_name sub.domain.com;
[…]
location /.well-known {
alias /path/to/sub.domain.com/.well-known;
}
location / {
# proxy commands go here
[…]
}
}
若使用 acme.sh,则既可通过 .well-known 目录来验证,也可通过 DNS 解析来验证(需提前向域名注册商申请 API)。可参考这里。
好了,到这里,证书更新的事儿也是自动的。
去喝杯咖啡吧~
Update:
已实现客户端到负载机的访问是公网 https,负载机转发到前端机走私网 http。已遇到一个问题,最新版的 phpMyAdmin 会提示:
服务器和客户端上指示的 HTTPS 之间不匹配。这可能导致 phpMyAdmin 无法正常工作或存在安全风险。请修复您的服务器配置以正确指示 HTTPS。
嗯~有待进一步解决。
Update:
上述问题解决方案:在 phpMyAdmin 的配置文件中添加:
$cfg['PmaAbsoluteUri'] = 'https://pma.xxx.com';
即可。
作者:wiLdGoose
发布时间:September 27, 2018
分类:技术 Technology
还是那堆联通云机,交付前 LVM 也不给搞好,云盘默认也不挂载,特别吐槽一下。怀念某云的傻瓜式服务,前者到底是国有,揍是硬气。
这是扩容前的情况:
[root@centos7 ~]# df -h
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/rootvg-rootlv 10G 10G 20K 100% /
devtmpfs 3.9G 0 3.9G 0% /dev
tmpfs 3.9G 0 3.9G 0% /dev/shm
tmpfs 3.9G 369M 3.5G 10% /run
tmpfs 3.9G 0 3.9G 0% /sys/fs/cgroup
/dev/vda1 485M 166M 319M 35% /boot
tmpfs 783M 0 783M 0% /run/user/0
用 vgs 和 lvs 看一下可用空间,并根据实际情况构造如下命令:
[root@centos7 ~]# lvresize -L +37.51G /dev/rootvg/rootlv
Rounding size to boundary between physical extents: 37.51 GiB.
Size of logical volume rootvg/rootlv changed from 10.00 GiB (2560 extents) to 47.51 GiB (12163 extents).
Logical volume rootvg/rootlv successfully resized.
最后同步一下文件系统就搞定了:
[root@centos7 ~]# xfs_growfs /dev/rootvg/rootlv
meta-data=/dev/mapper/rootvg-rootlv isize=512 agcount=4, agsize=655360 blks
= sectsz=512 attr=2, projid32bit=1
= crc=1 finobt=0 spinodes=0
data = bsize=4096 blocks=2621440, imaxpct=25
= sunit=0 swidth=0 blks
naming =version 2 bsize=4096 ascii-ci=0 ftype=1
log =internal bsize=4096 blocks=2560, version=2
= sectsz=512 sunit=0 blks, lazy-count=1
realtime =none extsz=4096 blocks=0, rtextents=0
data blocks changed from 2621440 to 12454912
验证:
[root@centos7 ~]# df -h
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/rootvg-rootlv 48G 9.8G 38G 21% /
devtmpfs 3.9G 0 3.9G 0% /dev
tmpfs 3.9G 0 3.9G 0% /dev/shm
tmpfs 3.9G 369M 3.5G 10% /run
tmpfs 3.9G 0 3.9G 0% /sys/fs/cgroup
/dev/vda1 485M 166M 319M 35% /boot
tmpfs 783M 0 783M 0% /run/user/0
自己马克一下。
作者:wiLdGoose
发布时间:September 3, 2018
分类:技术 Technology
最近接手了一堆联通 IDC 的云主机(数量真的很多),也分配了云盘资源。看了一下需要手动挂载,对于懒癌重度患者亟须解放劳动力。
以下是笔记。
首先确认云盘资源是否已分配关联:
[root@centos7 ~]# fdisk -l
结果:
磁盘 /dev/vda:53.7 GB, 53687091200 字节,104857600 个扇区
Units = 扇区 of 1 * 512 = 512 bytes
扇区大小(逻辑/物理):512 字节 / 512 字节
I/O 大小(最小/最佳):512 字节 / 512 字节
磁盘标签类型:dos
磁盘标识符:0x000d3443
设备 Boot Start End Blocks Id System
/dev/vda1 * 2048 1001471 499712 83 Linux
/dev/vda2 1001472 104857599 51928064 8e Linux LVM
磁盘 /dev/vdb:429.5 GB, 429496729600 字节,838860800 个扇区
Units = 扇区 of 1 * 512 = 512 bytes
扇区大小(逻辑/物理):512 字节 / 512 字节
I/O 大小(最小/最佳):512 字节 / 512 字节
磁盘 /dev/mapper/rootvg-rootlv:10.7 GB, 10737418240 字节,20971520 个扇区
Units = 扇区 of 1 * 512 = 512 bytes
扇区大小(逻辑/物理):512 字节 / 512 字节
I/O 大小(最小/最佳):512 字节 / 512 字节
磁盘 /dev/mapper/rootvg-swaplv:2147 MB, 2147483648 字节,4194304 个扇区
Units = 扇区 of 1 * 512 = 512 bytes
扇区大小(逻辑/物理):512 字节 / 512 字节
I/O 大小(最小/最佳):512 字节 / 512 字节
因此确定云盘设备路径为:
/dev/vdb
初始化:
[root@centos7 ~]# fdisk /dev/vdb
可按需进行分区,我这边只设置一个主分区。
接着以 ext4 格式对其进行格式化:
[root@centos7 ~]# mkfs.ext4 /dev/vdb
其结果:
mke2fs 1.42.9 (28-Dec-2013)
文件系统标签=
OS type: Linux
块大小=4096 (log=2)
分块大小=4096 (log=2)
Stride=0 blocks, Stripe width=0 blocks
26214400 inodes, 104857600 blocks
5242880 blocks (5.00%) reserved for the super user
第一个数据块=0
Maximum filesystem blocks=2252341248
3200 block groups
32768 blocks per group, 32768 fragments per group
8192 inodes per group
Superblock backups stored on blocks:
32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208,
4096000, 7962624, 11239424, 20480000, 23887872, 71663616, 78675968,
102400000
Allocating group tables: 完成
正在写入inode表: 完成
Creating journal (32768 blocks): 完成
Writing superblocks and filesystem accounting information: 完成
下一步对其进行手动挂载:
[root@centos7 ~]# mkdir /data
[root@centos7 ~]# mount /dev/vdb /data
行了,看看是否挂载正确:
[root@centos7 ~]# df -h
没问题的话,最后配置自动挂载:
[root@centos7 ~]# vim /etc/fstab
在文件最后添加一行:
/dev/vdb /data ext4 defaults 0 0
连在一起就是:
#!/bin/bash
fdisk /dev/vdb <<EOF
n
p
1
wq
EOF
mkfs.ext4 /dev/vdb && mkdir /data && mount /dev/vdb /data
echo '/dev/vdb /data ext4 defaults 0 0' >> /etc/fstab
然后用 pssh 之类的,哗啦一下都搞定。
- EOF -
作者:wiLdGoose
发布时间:October 2, 2016
分类:技术 Technology
这是在一个 BT 的运行环境下诞生的需求,折腾数日,写下来自己马克一下。
1、需求:
1.1、表单上传本地图片;
1.2、以指定最大宽或指定最大高处理缩略图;
1.3、以指定最大宽高缩放原图并添加图片水印;
1.4、缩略图及水印图须连同原图一同入库存储。
2、函数部分:
2.1、获取图片信息函数
function get_image_info($file) {
$result = getimagesize($file);
$info = array();
$info['width'] = $result[0];
$info['height'] = $result[1];
$info['type'] = $result[2];
return $info;
}
2.2、原图宽高与缩放宽高运算函数
function fix_image_size($source_width, $source_height, $max_width, $max_height) {
$size = array();
if ($max_width == false) {
if ($max_height < $source_height) {
$size['width'] = $max_width < $source_width ? floor($max_height / ($source_height / $source_width)) : $source_width;
$size['height'] = $max_height;
}
else {
$size['width'] = $source_width;
$size['height'] = $source_height;
}
}
elseif ($max_height == false) {
if ($max_width < $source_width) {
$size['width'] = $max_width;
$size['height'] = $max_height < $source_height ? floor($max_width / ($source_width / $source_height)) : $source_height;
}
else {
$size['width'] = $source_width;
$size['height'] = $source_height;
}
}
else {
if (($max_width && $source_width > $max_width) || ($max_height && $source_height > $max_height)) {
if ($max_width && $source_width > $max_width) {
$width_ratio = $max_width / $source_width;
$resize_width_tag = true;
}
if ($max_height && $source_height > $max_height) {
$height_ratio = $max_height / $source_height;
$resize_height_tag = true;
}
if ($resize_width_tag && $resize_height_tag) $ratio = $width_ratio < $height_ratio ? $width_ratio : $height_ratio;
if ($resize_width_tag && !$resize_height_tag) $ratio = $width_ratio;
if ($resize_height_tag && !$resize_width_tag) $ratio = $height_ratio;
$size['width'] = floor($source_width * $ratio);
$size['height'] = floor($source_height * $ratio);
}
else {
$size['width'] = $source_width;
$size['height'] = $source_height;
}
}
return $size;
}
2.3、缩略图处理函数
function resize_image($source_image_string, $source_width, $source_height, $resize_width, $resize_height) {
if (!empty($source_image_string) && !empty($source_width) && !empty($source_height) && (!empty($resize_width) || !empty($resize_height))) {
$resize_image = imagecreatetruecolor($resize_width, $resize_height);
$source_image = imagecreatefromstring(base64_decode($source_image_string));
if (function_exists('imagecopyresampled')) imagecopyresampled($resize_image, $source_image, 0, 0, 0, 0, $resize_width, $resize_height, $source_width, $source_height);
else imagecopyresized($resize_image, $source_image, 0, 0, 0, 0, $resize_width, $resize_height, $source_width, $source_height);
$image_stream = array();
ob_start();
imagejpeg($resize_image, null, 100);
$image_stream['data'] = ob_get_contents();
$image_stream['length'] = ob_get_length();
ob_end_clean();
if (!empty($image_stream['data']) && $image_stream['length'] > 0) {
imagedestroy($source_image);
imagedestroy($resize_image);
return $image_stream;
}
else return false;
}
else return false;
}
2.4、图片水印处理函数
function watermark_image($source_image_string, $source_width, $source_height, $watermark_image_file) {
if (!empty($source_image_string) && !empty($source_width) && !empty($source_height) && !empty($watermark_image_file)) {
$source_image = imagecreatefromstring(base64_decode($source_image_string));
$watermark_image_info = get_image_info($watermark_image_file);
if ($watermark_image_info['type'] == 1) $watermark_image = imagecreatefromgif($watermark_image_file);
elseif ($watermark_image_info['type'] == 2) $watermark_image = imagecreatefromjpeg($watermark_image_file);
elseif ($watermark_image_info['type'] == 3) $watermark_image = imagecreateFrompng($watermark_image_file);
else return false;
if (empty($watermark_image)) return false;
$x = $source_width - $watermark_image_info['width'];
$y = $source_height - $watermark_image_info['height'];
imagecopy($source_image, $watermark_image, $x, $y, 0, 0, $watermark_image_info['width'], $watermark_image_info['height']) or die('Error');
ob_start();
imagejpeg($source_image, null, 100);
$image_stream['data'] = ob_get_contents();
$image_stream['length'] = ob_get_length();
ob_end_clean();
if (!empty($image_stream['data']) && $image_stream['length'] > 0) {
imagedestroy($source_image);
imagedestroy($watermark_image);
return $image_stream;
}
else return false;
}
return false;
}
3、调用部分
3.1、表单数据获取
$attach_type = $_FILES['attach']['type'];
$attach_tmp_name = $_FILES['attach']['tmp_name'];
$attach_error = $_FILES['attach']['error'];
$attach_size = $_FILES['attach']['size'];
3.2、元数据处理
$source_image_file = $attach_tmp_name;
$source_image_info = get_image_info($source_image_file);
$source_image_string = base64_encode(file_get_contents($source_image_file));
3.3、入库原图处理
$fp_original_image = fopen($attach_tmp_name, 'rb');
if (!$fp_original_image) die('Error');
$original_image_content = addslashes(fread($fp_original_image, filesize($attach_tmp_name)));
fclose($fp_original_image);
unlink($attach_tmp_name);
3.4、缩略图处理
$thumbnail_image_width = 300;
$thumbnail_image_height = false;
$thumbnail_image_size = fix_image_size($source_image_info['width'], $source_image_info['height'], $thumbnail_image_width, $thumbnail_image_height);
$thumbnail_image = resize_image($source_image_string, $source_image_info['width'], $source_image_info['height'], $thumbnail_image_size['width'], $thumbnail_image_size['height']);
if (empty($thumbnail_image['data']) || $thumbnail_image['length'] <= 0) die('Error');
3.5、图片水印定义
$watermark_image_file = 'path/to/watermark.png';
$watermark_image_width = 900;
$watermark_image_height = 600;
$watermark_image_size = fix_image_size($source_image_info['width'], $source_image_info['height'], $watermark_image_width, $watermark_image_height);
3.6、处理水印前缩放处理
$watermark_resize_image = resize_image($source_image_string, $source_image_info['width'], $source_image_info['height'], $watermark_image_size['width'], $watermark_image_size['height']);
if (empty($watermark_resize_image['data']) || $watermark_resize_image['length'] <= 0) die('Error');
3.7、水印处理
$watermark_image = watermark_image(base64_encode($watermark_resize_image['data']), $watermark_image_size['width'], $watermark_image_size['height'], $watermark_image_file);
if (empty($watermark_image['data']) || $watermark_image['length'] <= 0) die('Error');
4、返回值
4.1、图片类型
$attach_type
4.2、原图
4.2.1、原图二进制数据
$original_image_content
4.2.2、原图大小
$attach_size
4.3、缩略图
4.3.1、缩略图二进制数据
addslashes($thumbnail_image['data'])
4.3.2、缩略图大小
$thumbnail_image['length']
4.4、水印图
4.4.1、水印图二进制数据
addslashes($watermark_image['data'])
4.4.2、水印图大小
$watermark_image['length']
5、入库 SQL 构造
略。
- EOF -
- «
- 1
- 2
- 3
- 4
- 5
- 6
- ...
- 14
- »