centos部署django项目的详细总结

前期准备

yum groupinstall 'Development Tools'
yum install zlib-devel bzip2-devel openssl-devel ncurses-devel

一、pyen安装

一键安装环境:

curl -L https://raw.githubusercontent.com/yyuu/pyenv-installer/master/bin/pyenv-installer | bash

国内镜像
wget http://mirrors.sohu.com/python/3.6.2/Python-3.6.2.tar.xz -P ~/.pyenv/cache/;pyenv install 3.6.2
  • 切换版本 pyenv global
  • 切换python shell版本 pyenv shell

二、MySQL 安装设置

#yum install mysql
#yum install mysql-server
#yum install mysql-devel

mysql-server 安装失败,可以使用mariadb 代替

# yum install mariadb-server mariadb 

相关的命令:

mariadb数据库的相关命令是:

systemctl start mariadb  #启动MariaDB

systemctl stop mariadb  #停止MariaDB

systemctl restart mariadb  #重启MariaDB

systemctl enable mariadb  #设置开机启动

修改root密码

  • 以root身份在终端登陆,必须

  • 输入 mysqladmin -u root -p password root
    后面的 root 是要设置的密码

  • 回车后出现 Enter password
    输入就密码,如果没有,直接回车

创建用户

//创建用户
mysql> insert into mysql.user(Host,User,Password) values("localhost","admin",password("admin"));
//刷新系统权限表
mysql>flush privileges;

这样就创建了一个名为:admin 密码为:admin 的用户。

创建数据库(在root权限下)

create database mydb;
//授权admin用户拥有mydb数据库的所有权限。
>grant all privileges on mydb.* to admin@localhost identified by 'admin';
//刷新系统权限表
mysql>flush privileges;

三、Nginx 安装配置

官网下载

  • 直接下载.tar.gz安装包,地址:https://nginx.org/en/download.html

  • 使用wget命令下载(推荐)。

wget -c https://nginx.org/download/nginx*.tar.gz *替换具体的版本

解压

依然是直接命令:

tar -zxvf nginx-1.10.1.tar.gz
cd nginx-1.10.1

配置

其实在 nginx-1.10.1 版本中你就不需要去配置相关东西,默认就可以了。当然,如果你要自己配置目录也是可以的。

  • 使用默认配置
./configure

编译安装

make
make install

查找安装路径:

whereis nginx

启动、停止nginx

cd /usr/local/nginx/sbin/
./nginx 
./nginx -s stop
./nginx -s quit
./nginx -s reload
  • ./nginx -s quit:此方式停止步骤是待nginx进程处理任务完毕进行停止。

  • ./nginx -s stop:此方式相当于先查出nginx进程id再使用kill命令强制杀掉进程。

查询nginx进程:

ps aux|grep nginx

重启 nginx

  • 先停止再启动(推荐):
    对 nginx 进行重启相当于先停止再启动,即先执行停止命令再执行启动命令。如下:
./nginx -s quit
./nginx
  • 重新加载配置文件:

当 ngin x的配置文件 nginx.conf 修改后,要想让配置生效需要重启 nginx,使用-s reload不用先停止 ngin x再启动 nginx 即可将配置信息在 nginx 中生效,如下:

./nginx -s reload

开机自启动

即在rc.local增加启动代码就可以了。

vi /etc/rc.local

增加一行 /usr/local/nginx/sbin/nginx
设置执行权限:

chmod 755 rc.local

最终nginx配置文件:

server {
  listen 8080;  #启动的nginx进程监听请求的端口
  server_name localhost;  #域名
  error_log /var/log/xxx/error.log;   #nginx错误日志,可自行设置,但必须保证提前建立好该目录和文件
  location / {
    include /path/nginx/uwsgi_params;  
    uwsgi_pass 127.0.0.1:9090;  #对于动态请求,转发到本机的9090端口,也就是uwsgi监听的端口
  }
  #error_page 404 /404.html;
  error_page 500 502 503 504 /50x.html;  
  location = /50x.html {
     root /usr/share/nginx/html;
  }
  location /static/ {
    alias /var/www/xxx/static/;   #设定静态文件所在目录
  }
  location /media/ {  
    alias /var/www/xxx/media/;    #同样自行设置,要保证目录已经建好
  }
}

四、使用uwsgi提供服务

  • 安装uwsgi
sudo pip install uwsgi
  • 启动uwsgi

切换到项目目录下,会有 proj_name/wsgi.py 文件,执行一下命令:

uwsgi --http :8080 --module your_proj_name.wsgi

就可以运行你的web项目了,这时如果在浏览其中输入127.0.0.1:8080 能够成功访问,说明你的应用服务器部署成功,已经可以对外提供服务。

这种提供服务的方式可以表示为:

the web client <-> uWSGI <-> Django

多数情况下我们不会让浏览器直接与uwsgi交互,而是加入nginx作为中间设备转发或处理请求。

后面介绍只用配置文件启动,可以后台运行
配置在项目目录新建配置文件 uwsgi_config.ini,内容如下:

[uwsgi]
socket = 127.0.0.1:8080
workers = 4
chdir = /root/www/Shop_Coupon
touch-reload = /root/www/Shop_Coupon
py-auto-reload = 1
module= shop_coupon.wsgi
pidfile = /var/run/uwsgi.pid
daemonize = /var/log/uwsgi.log

然后执行命令:

uwsgi --ini mysite_uwsgi.ini # the --ini option is used to specify a file

更加详细的可以参考:http://uwsgi-docs-zh.readthedocs.io/zh_CN/latest/tutorials/Django_and_nginx.html

CentOS系统的监控进程状态并自动重启的shell脚本

在CentOS系统中利用Crontab监控进程是否被结束并自动重启。

附加每天凌晨4点自动重启服务器。

1、编辑Crontab

crontab -e

2、按i进行编辑

*/1 * * * * /root/monitor.sh     # 每分钟运行一遍monitor.sh脚本
0 5 * * * /sbin/reboot           # 每天凌晨5点自动重启服务器
1
2
*/1 * * * * /root/monitor.sh     # 每分钟运行一遍monitor.sh脚本
0 5 * * * /sbin/reboot           # 每天凌晨5点自动重启服务器

3、root下创建monitor.sh脚本

#! /bin/sh 

host_dir=`echo ~`                         # 当前用户根目录  
proc_name="net_speeder"                   # 进程名  
file_name="/root/log/netspeed.log"        # 日志文件 
pid=0  

proc_num()                                # 计算进程数  
{  
    num=`ps -ef | grep $proc_name | grep -v grep | wc -l`  
    return $num  
}  

proc_id()                                 # 进程号  
{  
    pid=`ps -ef | grep $proc_name | grep -v grep | awk '{print $2}'`  
}  

proc_num  
number=$?  
if [ $number -eq 0 ]                      # 判断进程是否存在  
then   
    ~/net-speeder-master/net_speeder venet0 "tcp src port 443" >/dev/null 2>&1 &                         # 重启进程的命令
    proc_id                               # 获取新进程号 
    echo ${pid}, `date` >> $host_dir$file_name    # 将新进程号和重启时间记录
fi

4、赋予脚本执行权限

chmod 777 /root/monitor.sh

5、添加log文件夹及log文件并赋予权限

mkdir 777 /root/log
touch /root/log/netspeed.log create file
chmod 646 /root/log/netspeed.log

6、重启服务器以应用更改

7、重启后有可能出现crond进程没有运行的问题,需要在rc.local增加crond随系统启动

vi /etc/rc.local

键入

nohup /etc/init.d/crond restart

利用:wq命令保存。

8、设置每次重启后清除log文件

在步骤7中键入

nohup echo '' > /root/log/netspeed.log

9、需要删除文件夹或文件

rm -rf /root/log/netspeed.log

Centos 7系统开启nginx的HTTP/2教程

  • HTTP 2.0即超文本传输协议 2.0,是下一代HTTP协议。是由互联网工程任务组(IETF)的Hypertext Transfer Protocol Bis (httpbis)工作小组进行开发。是自1999年http1.1发布后的首个更新。

  • HTTP/2 协议是从 SPDY 演变而来,SPDY 已经完成了使命并很快就会退出历史舞台(例如 Chrome 将在「2016 年初结束对 SPDY 的支持」;Nginx、Apache 也已经全面支持 HTTP/2 ,并也不再支持 SPDY)。一般的大家把 HTTP2 简称为 h2,尽管有些朋友可能不怎么愿意,但是这个简称已经默认化了,特别是体现在浏览器对 HTTP2 都是这个简写的。普通的 HTTPS 网站浏览会比 HTTP 网站稍微慢一些,因为需要处理加密任务,而配置了 h2 的 HTTPS,在低延时的情况下速度会比 HTTP 更快更稳定!

未分类

从 Nginx 1.9.5 开始,http_v2_module 已经替换了 ngx_http_spdy_module,建议直接去 Nginx 官网(https://www.91linux.org/go/?url=http://nginx.org/) 下载最新源码包

  • 要开启HTTP/2需要nginx版本在1.9.5以上且需要openssl版本在1.0.2以上编译。
  • http2.0只支持开启了https的网站

OpenSSL

由于 OpenSSL 是系统基础库,大量其他软件都对它有依赖,如果直接升级系统自带的 OpenSSL,很容易引发各种问题。更为稳妥的做法是在编译 Web Server 时自己指定 OpenSSL 的位置。也就是通过 –with-openssl 指定了新版 OpenSSL 源码路径,这样编译出来的 Nginx 就会用上最新的 OpenSSL 库。

本站目前使用 OpenSSL 1.0.2l:

wget -O openssl.tar.gz -c https://github.com/openssl/openssl/archive/OpenSSL_1_0_2l.tar.gz
tar zxf openssl.tar.gz
mv openssl-OpenSSL_1_0_2l/ openssl

打上 ChaCha20/Poly1305 补丁:

git clone https://github.com/cloudflare/sslconfig.git
cd openssl
patch -p1 < ../sslconfig/patches/openssl__chacha20_poly1305_draft_and_rfc_ossl102j.patch
cd ../

编译并安装 Nginx

接着就可以获取 Nginx 源码,并打上 Dynamic TLS Records 补丁:

wget -c https://nginx.org/download/nginx-1.11.13.tar.gz
tar zxf nginx-1.11.13.tar.gz

cd nginx-1.11.13/
patch -p1 < ../sslconfig/patches/nginx__1.11.5_dynamic_tls_records.patch

cd ../

编译和安装:

cd nginx-1.11.13/
./configure --user=www --group=www --prefix=/usr/local/nginx --with-openssl=../openssl --with-http_v2_module --with-http_ssl_module  --with-http_gzip_static_module --with-http_stub_status_module --with-http_sub_module

make
sudo make install

除了 http_v2 和 http_ssl 这两个 HTTP/2 必备模块之外,我还额外启用了 http_gzip_static,需要启用哪些模块需要根据自己实际情况来决定(注:从 Nginx 1.11.5 开始,ipv6 模块已经内置,故 –with-ipv6 配置项已被移除)。

以上步骤会把 Nginx 装到 /usr/local/nginx/ 目录,如需更改路径可以在 –prefix指定。

设置nginx启动脚本

编辑 vi /lib/systemd/system/nginx.service 文件,没有创建一个 touch nginx.service 然后将如下内容根据具体情况进行修改后,添加到nginx.service文件中:

[Unit]
Description=nginx
After=network.target remote-fs.target nss-lookup.target

[Service]

Type=forking
PIDFile=/var/run/nginx.pid
ExecStartPre=/usr/local/nginx/sbin/nginx -t -c /usr/local/nginx/conf/nginx.conf
ExecStart=/usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s QUIT $MAINPID
PrivateTmp=true

[Install]
WantedBy=multi-user.target

设置开机启动:systemctl enable nginx
立即启动:systemctl start nginx

配置HTTP/2

配置Nginx开启http 2.0特别简单,只要在Nginx配置文件中找到你要开启http2.0的域名server模块,然后将 listen 443 ssl;改成 listen 443 ssl http2; 即可。

server {
    listen 443 ssl http2 default_server;

    ssl_certificate    server.crt;
    ssl_certificate_key server.key;
    ...
}

保存配置文件之后,重启或重载Nginx即可生效:systemctl restart nginx

Centos系统连接ssh服务器缓慢的解决办法

现象

在机房内网中,用ssh连某台服务器非常慢,基本需要等待15-30秒才会提示让输入密码,但是ping目标机器,延时都是微秒级别,可见并非网络原因造成连接缓慢。

解决办法

方法一

修改本机的客户端配置文件ssh_conf,注意,不是sshd_conf

# vi /etc/ssh/ssh_config

找到:

GSSAPIAuthentication yes

改为:

GSSAPIAuthentication no

保存退出:

# service sshd restart

再连目标机器,速度就飞快了。

解释:GSSAPI ( Generic Security Services Application Programming Interface) 是一套类似Kerberos 5 的通用网络安全系统接口。该接口是对各种不同的客户端服务器安全机制的封装,以消除安全接口的不同,降低编程难度。但该接口在目标机器无域名解析时会有问题。

/etc/ssh/ssh_conf配置实例:

Host    *
GSSAPIAuthentication        no
GSSAPIDelegateCredentials   yes
PasswordAuthentication      yes
RSAAuthentication           yes
StrictHostKeyChecking       no
Port                        22

SendEnv LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES 
SendEnv LC_IDENTIFICATION LC_ALL
SendEnv LC_IDENTIFICATION LC_ALL LANGUAGE
SendEnv LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT 
SendEnv XMODIFIERS

方法二

如果你连接缓慢的目标机器是新添加,那么可以使用本方法,修改目标机器的sshd_conf配置文件

#  vi /etc/ssh/sshd_config

找到:

#UseDNS yes
GSSAPIAuthentication yes

修改为:

UseDNS no
GSSAPIAuthentication no

保存退出

# service sshd restar

然后,我们再使用ssh连接服务器发现速度飞快!

解释:

UseDNS选项来决定是否对远程主机名进行反向解析,以检查此主机名是否与其IP地址真实对应.默认值为”yes”.
如果采用UseDNS yes,客户端登录时,SSH服务端将会打开/etc/hosts,找对映的ip/hostname的解析记录,如果没有找到,这时将会用利用/lib/libnss_dns.so.2动态链接库去/etc/resolv.conf中找DNS服务器做反向解析查询。
如果我们关闭反向解析查询,即UseDNS = no,此时则不会用/etc/host.conf等文件进行hosts/bind反向解析查询,因此会加快连接的速度。

利用ansible和jenkins实现tomcat应用的持续交付

在做持续交付这件事,想必大家都是用jenkins这款程序来做基石。当然,我们这次也是用jenkins作为承载工具,jenkins强大的插件是有目共睹的,有些ansible做起来不容易的事情交给jenkins反而简单有效。下面我会详细说明怎么持续交付tomcat应用。

应用架构

本次使用的应用架构是常见的负载均衡实例。

未分类

软件版本

  • os: centos 6.7 X64
  • ansible: 2.3.1.0
  • python: 2.6.6
  • ant: 10.1
  • java: 1.8.0_13
  • tomcat: 8.5.14
  • jenkins: 2.73

Ansible roles

  • Ansible Role 系统环境 之【ant】 (http://www.jianshu.com/p/75a129e71685)
  • Ansible Role 系统环境 之【java】(http://www.jianshu.com/p/1be92c3f65ec)
  • Ansible Role 系统环境 之【iptables】 (http://www.jianshu.com/p/1ce357af03bf)
  • Ansible Role WEB 之【tomcat】 (http://www.jianshu.com/p/fd7cca20c227)
  • Ansible Role WEB 之【nginx】 (http://www.jianshu.com/p/447df6f2335a)
  • Ansible Role 持续集成 之【jenkins】 (http://www.jianshu.com/p/f4bac35454b4)
  • Ansible Role 持续交付 之【deploy-tomcat】 (http://www.jianshu.com/p/eadbdb861fa2)

服务器角色

未分类

集群搭建

本次使用anisble playbook

---

- hosts: node130 node131
  vars:
   - java_version: "1.8"
   - tomcat_version: "8.5.14"
   - iptables_allowed_tcp_ports: ["8080"]
  roles:
  - java
  - { role: tomcat, java_home: "/usr/java/jdk1.8.0_131" }
  - iptables

- hosts: node1
  vars:
   - java_version: "1.8"
   - nginx_version: "1.12.1"
   - nginx_upstreams:
     - name: upstremtest
       servers:
       - 192.168.77.130:8080 max_fails=2 fail_timeout=2
       - 192.168.77.131:8080 max_fails=2 fail_timeout=2
   - nginx_vhosts:
     - listen: 80
       locations:
       - name: /
         proxy_pass: http://upstremtest
   - jenkins_version: "2.73"
   - jenkins_plugins_extra:
     - ansible
     - ansicolor
   - iptables_allowed_tcp_ports: ["80","8080"]
  roles:
  - ant
  - java
  - nginx
  - jenkins
  - iptables
  tasks:
  - name: install ansible
    package: name=ansible

怎么使用ansible roles,请移步到 Ansible Role【怎么用?】

确保正常访问以下服务:

  • nginx http://192.168.77.129/lework
  • jenkins http://192.168.77.129:8080 帐号密码:admin/admin
  • tomcat http://192.168.77.130:8080/lework http://192.168.77.131:8080/lework

node1服务器操作

在服务器上配置ansible playbook

# cd /etc/ansible/
# cat tomcat-deploy.yml
---

- hosts: all
  serial: 1
  roles:
   - deploy-tomcat

# cat hosts
[node130]
192.168.77.130

[node131]
192.168.77.131

[testservers:children]
node130
node131

[testservers:vars]
ansible_ssh_user=root
ansible_ssh_pass=123456

# git clone https://github.com/kuailemy123/Ansible-roles.git /etc/ansible/roles/
# chown jenkins.jenkins /etc/ansible/

jenkins 操作

登录jenkins之后,设置工具

点击“系统管理”==》“Global Tool Configuration”

未分类

未分类

未分类

创建发布项目

未分类

配置参数化构建

未分类

配置源码仓库地址

未分类

repo: https://github.com/kuailemy123/AntSpringMVC.git

配置构建环境

未分类

配置编译

未分类

配置ansible

未分类

配置ansible变量

未分类

这里就不配置邮件通知了。

创建回滚项目

未分类

配置参数化构建

未分类

配置构建环境

未分类

配置ansible

未分类

配置anisble变量

未分类

测试

执行tomcat_deploy任务

未分类

选择发布的节点,默认all

任务执行的日志

Started by user admin
Building in workspace /var/lib/jenkins/workspace/tomcat_deploy
Cloning the remote Git repository
Cloning repository https://github.com/kuailemy123/AntSpringMVC.git
 > git init /var/lib/jenkins/workspace/tomcat_deploy # timeout=10
Fetching upstream changes from https://github.com/kuailemy123/AntSpringMVC.git
 > git --version # timeout=10
 > git fetch --tags --progress https://github.com/kuailemy123/AntSpringMVC.git +refs/heads/*:refs/remotes/origin/*
 > git config remote.origin.url https://github.com/kuailemy123/AntSpringMVC.git # timeout=10
 > git config --add remote.origin.fetch +refs/heads/*:refs/remotes/origin/* # timeout=10
 > git config remote.origin.url https://github.com/kuailemy123/AntSpringMVC.git # timeout=10
Fetching upstream changes from https://github.com/kuailemy123/AntSpringMVC.git
 > git fetch --tags --progress https://github.com/kuailemy123/AntSpringMVC.git +refs/heads/*:refs/remotes/origin/*
 > git rev-parse refs/remotes/origin/master^{commit} # timeout=10
 > git rev-parse refs/remotes/origin/origin/master^{commit} # timeout=10
Checking out Revision 989ea3a6549e16e3dd4cd329ab969b47658c9d67 (refs/remotes/origin/master)
Commit message: "Create README.md"
 > git config core.sparsecheckout # timeout=10
 > git checkout -f 989ea3a6549e16e3dd4cd329ab969b47658c9d67
First time build. Skipping changelog.
[tomcat_deploy] $ ant -file build.xml -Ddeploy_node=all
Buildfile: /var/lib/jenkins/workspace/tomcat_deploy/build.xml

clean:
   [delete] Deleting directory /var/lib/jenkins/workspace/tomcat_deploy/war/WEB-INF/classes

init:
    [mkdir] Created dir: /var/lib/jenkins/workspace/tomcat_deploy/target
    [mkdir] Created dir: /var/lib/jenkins/workspace/tomcat_deploy/war/WEB-INF/classes

resolve:
     [echo] Getting dependencies...
[ivy:retrieve] :: Apache Ivy 2.4.0 - 20141213170938 :: http://ant.apache.org/ivy/ ::
[ivy:retrieve] :: loading settings :: url = jar:file:/usr/local/ant/lib/ivy-2.4.0.jar!/org/apache/ivy/core/settings/ivysettings.xml
[ivy:retrieve] :: resolving dependencies :: org.apache#WebProject;working@node1
[ivy:retrieve]  confs: [compile, runtime, test]
[ivy:retrieve]  found org.slf4j#slf4j-api;1.7.6 in public
[ivy:retrieve]  found jstl#jstl;1.2 in public
[ivy:retrieve]  found ch.qos.logback#logback-classic;1.1.2 in public
[ivy:retrieve]  found ch.qos.logback#logback-core;1.1.2 in public
[ivy:retrieve]  found org.springframework#spring-core;4.1.3.RELEASE in public
[ivy:retrieve]  found commons-logging#commons-logging;1.2 in public
[ivy:retrieve]  found org.springframework#spring-beans;4.1.3.RELEASE in public
[ivy:retrieve]  found org.springframework#spring-context;4.1.3.RELEASE in public
[ivy:retrieve]  found org.springframework#spring-aop;4.1.3.RELEASE in public
[ivy:retrieve]  found aopalliance#aopalliance;1.0 in public
[ivy:retrieve]  found org.springframework#spring-expression;4.1.3.RELEASE in public
[ivy:retrieve]  found org.springframework#spring-web;4.1.3.RELEASE in public
[ivy:retrieve]  found org.springframework#spring-webmvc;4.1.3.RELEASE in public
[ivy:retrieve] downloading https://repo1.maven.org/maven2/org/slf4j/slf4j-api/1.7.6/slf4j-api-1.7.6.jar ...
[ivy:retrieve] ............ (28kB)
[ivy:retrieve] .. (0kB)
..... 省略下载的信息
[ivy:retrieve] :: resolution report :: resolve 74135ms :: artifacts dl 120701ms
    ---------------------------------------------------------------------
    |                  |            modules            ||   artifacts   |
    |       conf       | number| search|dwnlded|evicted|| number|dwnlded|
    ---------------------------------------------------------------------
    |      compile     |   13  |   13  |   13  |   0   ||   13  |   13  |
    |      runtime     |   13  |   13  |   13  |   0   ||   13  |   13  |
    |       test       |   13  |   13  |   13  |   0   ||   13  |   13  |
    ---------------------------------------------------------------------
[ivy:retrieve] :: retrieving :: org.apache#WebProject
[ivy:retrieve]  confs: [compile, runtime, test]
[ivy:retrieve]  13 artifacts copied, 0 already retrieved (5920kB/79ms)

compile:
    [javac] Compiling 1 source file to /var/lib/jenkins/workspace/tomcat_deploy/war/WEB-INF/classes
copy-resources:
     [copy] Copying 1 file to /var/lib/jenkins/workspace/tomcat_deploy/war/WEB-INF/classes
package:
[ivy:retrieve] :: retrieving :: org.apache#WebProject
[ivy:retrieve]  confs: [runtime]
[ivy:retrieve]  0 artifacts copied, 13 already retrieved (0kB/5ms)
      [war] Building war: /var/lib/jenkins/workspace/tomcat_deploy/target/helloproject-20170819172002.war

main:

BUILD SUCCESSFUL
Total time: 3 minutes 19 seconds
[tomcat_deploy] $ /usr/bin/ansible-playbook /etc/ansible/tomcat-deploy.yml -i /etc/ansible/hosts -l all -f 5 -e deploy_port=8080 -e deploy_file=/var/lib/jenkins/workspace/tomcat_deploy/target/helloproject-*.war

PLAY [all] *********************************************************************

TASK [Gathering Facts] *********************************************************
ok: [192.168.77.130]

TASK [deploy-tomcat : check | 发布文件是否存在] ****************************************
ok: [192.168.77.130]

TASK [deploy-tomcat : check | 目标应用服务的家目录是否存在] **********************************
ok: [192.168.77.130]

TASK [deploy-tomcat : check | 工作目录如果不存在则创建] ************************************
changed: [192.168.77.130] => (item=/tmp/tomcat-ansible-snap/new)
changed: [192.168.77.130] => (item=/tmp/tomcat-ansible-snap/pre)
changed: [192.168.77.130] => (item=/tmp/tomcat-ansible-snap/old)

TASK [deploy-tomcat : deloy | 解压代码至目标服务器] **************************************
changed: [192.168.77.130]

TASK [deploy-tomcat : deloy | 关闭服务] ********************************************
changed: [192.168.77.130]

TASK [deploy-tomcat : deloy | 等待端口关闭] ******************************************
ok: [192.168.77.130]

TASK [deploy-tomcat : deloy | 移动线上代码] ******************************************
changed: [192.168.77.130]

TASK [deploy-tomcat : deloy | 部署最新代码] ******************************************
changed: [192.168.77.130]

TASK [deploy-tomcat : deloy | 启动服务] ********************************************
changed: [192.168.77.130]

TASK [deploy-tomcat : deloy | 等待端口开启] ******************************************
ok: [192.168.77.130]

TASK [deploy-tomcat : verify | 查看http状态.] **************************************
ok: [192.168.77.130]

TASK [deploy-tomcat : backup | 创建存储备份的文件夹] *************************************
changed: [192.168.77.130]

TASK [deploy-tomcat : backup | 备份上线的代码] ****************************************
changed: [192.168.77.130]

TASK [deploy-tomcat : rollback | 检查/tmp/tomcat-ansible-snap/old是否存在代码] *********
skipping: [192.168.77.130]

TASK [deploy-tomcat : rollback | 关闭服务] *****************************************
skipping: [192.168.77.130]

TASK [deploy-tomcat : rollback | 等待端口关闭] ***************************************
skipping: [192.168.77.130]

TASK [deploy-tomcat : rollback | 部署上一版代码] **************************************
skipping: [192.168.77.130]

TASK [deploy-tomcat : rollback | 启动服务] *****************************************
skipping: [192.168.77.130]

TASK [deploy-tomcat : rollback | 等待端口开启] ***************************************
skipping: [192.168.77.130]

TASK [deploy-tomcat : verify | 查看http状态.] **************************************
skipping: [192.168.77.130]

PLAY [all] *********************************************************************

TASK [Gathering Facts] *********************************************************
ok: [192.168.77.131]

TASK [deploy-tomcat : check | 发布文件是否存在] ****************************************
ok: [192.168.77.131]

TASK [deploy-tomcat : check | 目标应用服务的家目录是否存在] **********************************
ok: [192.168.77.131]

TASK [deploy-tomcat : check | 工作目录如果不存在则创建] ************************************
ok: [192.168.77.131] => (item=/tmp/tomcat-ansible-snap/new)
ok: [192.168.77.131] => (item=/tmp/tomcat-ansible-snap/pre)
ok: [192.168.77.131] => (item=/tmp/tomcat-ansible-snap/old)

TASK [deploy-tomcat : deloy | 解压代码至目标服务器] **************************************
changed: [192.168.77.131]

TASK [deploy-tomcat : deloy | 关闭服务] ********************************************
changed: [192.168.77.131]

TASK [deploy-tomcat : deloy | 等待端口关闭] ******************************************
ok: [192.168.77.131]

TASK [deploy-tomcat : deloy | 移动线上代码] ******************************************
changed: [192.168.77.131]

TASK [deploy-tomcat : deloy | 部署最新代码] ******************************************
changed: [192.168.77.131]

TASK [deploy-tomcat : deloy | 启动服务] ********************************************
changed: [192.168.77.131]

TASK [deploy-tomcat : deloy | 等待端口开启] ******************************************
ok: [192.168.77.131]

TASK [deploy-tomcat : verify | 查看http状态.] **************************************
ok: [192.168.77.131]

TASK [deploy-tomcat : backup | 创建存储备份的文件夹] *************************************
changed: [192.168.77.131]

TASK [deploy-tomcat : backup | 备份上线的代码] ****************************************
changed: [192.168.77.131]

TASK [deploy-tomcat : rollback | 检查/tmp/tomcat-ansible-snap/old是否存在代码] *********
skipping: [192.168.77.131]

TASK [deploy-tomcat : rollback | 关闭服务] *****************************************
skipping: [192.168.77.131]

TASK [deploy-tomcat : rollback | 等待端口关闭] ***************************************
skipping: [192.168.77.131]

TASK [deploy-tomcat : rollback | 部署上一版代码] **************************************
skipping: [192.168.77.131]

TASK [deploy-tomcat : rollback | 启动服务] *****************************************
skipping: [192.168.77.131]

TASK [deploy-tomcat : rollback | 等待端口开启] ***************************************
skipping: [192.168.77.131]

TASK [deploy-tomcat : verify | 查看http状态.] **************************************
skipping: [192.168.77.131]

PLAY RECAP *********************************************************************
192.168.77.130             : ok=14   changed=8    unreachable=0    failed=0   
192.168.77.131             : ok=14   changed=7    unreachable=0    failed=0   

Finished: SUCCESS

执行tomcat_rollback任务

未分类

选择回滚的节点,默认all

执行的日志

Started by user admin
Building in workspace /var/lib/jenkins/workspace/tomcat_rollback
[tomcat_rollback] $ /usr/bin/ansible-playbook /etc/ansible/tomcat-deploy.yml -i /etc/ansible/hosts -l all -f 5 -e deploy_rollback=true

PLAY [all] *********************************************************************

TASK [Gathering Facts] *********************************************************
ok: [192.168.77.130]

TASK [deploy-tomcat : check | 发布文件是否存在] ****************************************
skipping: [192.168.77.130]

TASK [deploy-tomcat : check | 目标应用服务的家目录是否存在] **********************************
skipping: [192.168.77.130]

TASK [deploy-tomcat : check | 工作目录如果不存在则创建] ************************************
skipping: [192.168.77.130] => (item=/tmp/tomcat-ansible-snap/new) 
skipping: [192.168.77.130] => (item=/tmp/tomcat-ansible-snap/pre) 
skipping: [192.168.77.130] => (item=/tmp/tomcat-ansible-snap/old) 

TASK [deploy-tomcat : deloy | 解压代码至目标服务器] **************************************
skipping: [192.168.77.130]

TASK [deploy-tomcat : deloy | 关闭服务] ********************************************
skipping: [192.168.77.130]

TASK [deploy-tomcat : deloy | 等待端口关闭] ******************************************
skipping: [192.168.77.130]

TASK [deploy-tomcat : deloy | 移动线上代码] ******************************************
skipping: [192.168.77.130]

TASK [deploy-tomcat : deloy | 部署最新代码] ******************************************
skipping: [192.168.77.130]

TASK [deploy-tomcat : deloy | 启动服务] ********************************************
skipping: [192.168.77.130]

TASK [deploy-tomcat : deloy | 等待端口开启] ******************************************
skipping: [192.168.77.130]

TASK [deploy-tomcat : verify | 查看http状态.] **************************************
skipping: [192.168.77.130]

TASK [deploy-tomcat : backup | 创建存储备份的文件夹] *************************************
skipping: [192.168.77.130]

TASK [deploy-tomcat : backup | 备份上线的代码] ****************************************
skipping: [192.168.77.130]

TASK [deploy-tomcat : rollback | 检查/tmp/tomcat-ansible-snap/old是否存在代码] *********
changed: [192.168.77.130]

TASK [deploy-tomcat : rollback | 关闭服务] *****************************************
changed: [192.168.77.130]

TASK [deploy-tomcat : rollback | 等待端口关闭] ***************************************
ok: [192.168.77.130]

TASK [deploy-tomcat : rollback | 部署上一版代码] **************************************
changed: [192.168.77.130]

TASK [deploy-tomcat : rollback | 启动服务] *****************************************
fatal: [192.168.77.130]: FAILED! => {"changed": true, "cmd": "/etc/init.d/tomcat start", "delta": "0:00:20.035003", "end": "2017-08-19 17:24:47.586469", "failed": true, "rc": 1, "start": "2017-08-19 17:24:27.551466", "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []}
...ignoring

TASK [deploy-tomcat : rollback | 等待端口开启] ***************************************
ok: [192.168.77.130]

TASK [deploy-tomcat : verify | 查看http状态.] **************************************
ok: [192.168.77.130]

PLAY [all] *********************************************************************

TASK [Gathering Facts] *********************************************************
ok: [192.168.77.131]

TASK [deploy-tomcat : check | 发布文件是否存在] ****************************************
skipping: [192.168.77.131]

TASK [deploy-tomcat : check | 目标应用服务的家目录是否存在] **********************************
skipping: [192.168.77.131]

TASK [deploy-tomcat : check | 工作目录如果不存在则创建] ************************************
skipping: [192.168.77.131] => (item=/tmp/tomcat-ansible-snap/new) 
skipping: [192.168.77.131] => (item=/tmp/tomcat-ansible-snap/pre) 
skipping: [192.168.77.131] => (item=/tmp/tomcat-ansible-snap/old) 

TASK [deploy-tomcat : deloy | 解压代码至目标服务器] **************************************
skipping: [192.168.77.131]

TASK [deploy-tomcat : deloy | 关闭服务] ********************************************
skipping: [192.168.77.131]

TASK [deploy-tomcat : deloy | 等待端口关闭] ******************************************
skipping: [192.168.77.131]

TASK [deploy-tomcat : deloy | 移动线上代码] ******************************************
skipping: [192.168.77.131]

TASK [deploy-tomcat : deloy | 部署最新代码] ******************************************
skipping: [192.168.77.131]

TASK [deploy-tomcat : deloy | 启动服务] ********************************************
skipping: [192.168.77.131]

TASK [deploy-tomcat : deloy | 等待端口开启] ******************************************
skipping: [192.168.77.131]

TASK [deploy-tomcat : verify | 查看http状态.] **************************************
skipping: [192.168.77.131]

TASK [deploy-tomcat : backup | 创建存储备份的文件夹] *************************************
skipping: [192.168.77.131]

TASK [deploy-tomcat : backup | 备份上线的代码] ****************************************
skipping: [192.168.77.131]

TASK [deploy-tomcat : rollback | 检查/tmp/tomcat-ansible-snap/old是否存在代码] *********
changed: [192.168.77.131]

TASK [deploy-tomcat : rollback | 关闭服务] *****************************************
changed: [192.168.77.131]

TASK [deploy-tomcat : rollback | 等待端口关闭] ***************************************
ok: [192.168.77.131]

TASK [deploy-tomcat : rollback | 部署上一版代码] **************************************
changed: [192.168.77.131]

TASK [deploy-tomcat : rollback | 启动服务] *****************************************
changed: [192.168.77.131]

TASK [deploy-tomcat : rollback | 等待端口开启] ***************************************
ok: [192.168.77.131]

TASK [deploy-tomcat : verify | 查看http状态.] **************************************
ok: [192.168.77.131]

PLAY RECAP *********************************************************************
192.168.77.130             : ok=8    changed=4    unreachable=0    failed=0   
192.168.77.131             : ok=8    changed=4    unreachable=0    failed=0   

Finished: SUCCESS

至此,持续交付实验就完成了,但是持续之路还是很漫长了。望大家永远前进。 大家也可在发的过程中,测试发布是否是灰度发布。

for i in `seq 10000`;do curl -s -I http://192.168.77.129 | head -1;sleep 1;done;

Centos安装配置gitlab

一、安装HTTP和SSH、postfix服务

1、命令如下

sudo yum install curl openssh-server openssh-clients postfix cronie -y
sudo service postfix start
sudo chkconfig postfix on
sudo lokkit -s http -s ssh

二、下载gitlab安装文件和安装gitlab

1、系统默认下载

curl -sS https://packages.gitlab.com/install/repositories/gitlab/gitlab-ce/script.rpm.sh | sudo bash
sudo yum install gitlab-ce -y

2、指定版本下载

选择版本连接,源文件下载渠道1 (https://packages.gitlab.com/gitlab/gitlab-ce) 和 源文件下载渠道2 (https://about.gitlab.com/downloads/archives/)

curl -LJO https://packages.gitlab.com/gitlab/gitlab-ce/packages/el/6/gitlab-ce-XXX.rpm/download
rpm -i gitlab-ce-XXX.rpm

我下载版本7.5.3

wget https://downloads-packages.s3.amazonaws.com/centos-6.6/gitlab-7.5.3_omnibus.5.2.1.ci-1.el6.x86_64.rpm
sudo rpm -i gitlab-7.5.3_omnibus.5.2.1.ci-1.el6.x86_64.rpm

三、启动gitlab

命令如下:

//启动、并且查看配置
sudo gitlab-ctl reconfigure
//查看状态
sudo gitlab-ctl status
//启动Gitlab所有组件
sudo gitlab-ctl start
//停止Gitlab所有组件
sudo gitlab-ctl stop
//重启Gitlab所有组件
sudo gitlab-ctl restart

可能会出现ChildConvergeError异常 (http://yanmin99.com/test)

四、访问服务器

1、默认用户名和密码

username:root
password:5iveL!fe

2、访问gitlab

地址http:ip,gitlab默认nginx是80端口

  • 登陆页面

未分类

  • 修改密码

未分类

  • 主页面

未分类

Logstash匹配request_time 字段错误解决方法

区配错误原因

匹配规则:

%{IPORHOST:client_ip} (%{WORD:ident}|-) (%{WORD:auth}|-) [%{HTTPDATE:timestamp}] "%{WORD:method} %{URIPATHPARAM:request} HTTP/%{NUMBER:httpversion}" %{NUMBER:response_status} (?:%{NUMBER:response_bytes}|-) (?:"(?:%{URI:referrer}|-)"|%{QS:referrer}) %{QS:agent} %{QS:xforwardedfor} %{NUMBER:request_time} %{NUMBER:upstream_response_time}

当日志中 upstream_response_time 或 request_time 字段出现 – 字符,而不是数字时,以上匹配规则会出现匹配错误, 改进如下:

%{IPORHOST:client_ip} (%{WORD:ident}|-) (%{WORD:auth}|-) [%{HTTPDATE:timestamp}] "%{WORD:method} %{URIPATHPARAM:request} HTTP/%{NUMBER:httpversion}" %{NUMBER:response_status} (?:%{NUMBER:response_bytes}|-) (?:"(?:%{URI:referrer}|-)"|%{QS:referrer}) %{QS:agent} %{QS:xforwardedfor} (%{NUMBER:request_time}|-) (%{NUMBER:upstream_response_time}|-)

以上两条规则不同之处:

%{NUMBER:request_time} %{NUMBER:upstream_response_time}

更换为:

(%{NUMBER:request_time}|-) (%{NUMBER:upstream_response_time}|-)

但是,还是这样匹配到的字段会有 – 字符,而es中使用的字段类型是数字类型,所以需要以下解决办法:

解决方法

filter {
    if [upstream_response_time] == "-" {
            mutate {
                    replace => { "upstream_response_time" => 0 }
            }
        }
    if [request_time] == "-" {
            mutate {
                    replace => { "request_time" => 0 }
            }
    }
}

centos 7基于虚拟用户配置vsftpd

虽然很简单的一个软件但长时间不接触再次安装还是会碰到坑,然后就记录一下吧。

首先设置Selinux

setsebool -P ftp_home_dir=1   //设置ftp可以使用home目录
sersebool -P allow_ftpd_full_access=1   //设置ftp用户可以有所有权限

设置防火墙

打开/etc/sysconfig/iptables

在“-A INPUT –m state –state NEW –m tcp –p –dport 22 –j ACCEPT”,下添加:

-A INPUT -m state --state NEW -m tcp -p -dport 21 -j ACCEPT

然后保存,并关闭该文件,在终端内运行下面的命令,刷新防火墙配置:

service iptables restart

CentOS 7中默认使用Firewalld做防火墙,所以修改iptables后,在重启系统后,根本不管用。

Firewalld中添加端口方法如下:

firewall-cmd --zone=public --add-port=3306/tcp --permanent
firewall-cmd --reload

安装,并设置开机启动

yum -y install vsftpd
chkconfig vsftpd on

基于虚拟用户的配置

所谓虚拟用户就是没有使用真实的帐户,只是通过映射到真实帐户和设置权限的目的。虚拟用户不能登录CentOS系统。

修改配置文件

打开/etc/vsftpd/vsftpd.conf,做如下配置

anonymous_enable=NO //设定不允许匿名访问
local_enable=YES //设定本地用户可以访问。注:如使用虚拟宿主用户,在该项目设定为NO的情况下所有虚拟用户将无法访问
chroot_list_enable=YES //使用户不能离开主目录
ascii_upload_enable=YES
ascii_download_enable=YES //设定支持ASCII模式的上传和下载功能
pam_service_name=vsftpd //PAM认证文件名。PAM将根据/etc/pam.d/vsftpd进行认证

以下这些是关于vsftpd虚拟用户支持的重要配置项,默认vsftpd.conf中不包含这些设定项目,需要自己手动添加

guest_enable=YES //设定启用虚拟用户功能
guest_username=ftp //指定虚拟用户的宿主用户,CentOS中已经有内置的ftp用户了
user_config_dir=/etc/vsftpd/vuser_conf //设定虚拟用户个人vsftp的CentOS FTP服务文件存放路径。存放虚拟用户个性的CentOS FTP服务文件(配置文件名=虚拟用户名)进行认证

首先,安装Berkeley DB工具

yum install db4 db4-utils

然后,创建用户密码文本/etc/vsftpd/vuser_passwd.txt ,注意奇行是用户名,偶行是密码

test
123456

接着,生成虚拟用户认证的db文件

db_load -T -t hash -f /etc/vsftpd/vuser_passwd.txt /etc/vsftpd/vuser_passwd.db

随后,编辑认证文件/etc/pam.d/vsftpd,全部注释掉原来语句,再增加以下两句:

auth required pam_userdb.so db=/etc/vsftpd/vuser_passwd
account required pam_userdb.so db=/etc/vsftpd/vuser_passwd

最后,创建虚拟用户配置文件

mkdir /etc/vsftpd/vuser_conf/
vi /etc/vsftpd/vuser_conf/test  //文件名等于vuser_passwd.txt里`面的账户名,否则下面设置无效

内容如下

local_root=/data/ftp  //虚拟用户根目录,根据实际情况修改
write_enable=YES  //可写
anon_umask=022 //掩码
anon_world_readable_only=NO
anon_upload_enable=YES
anon_mkdir_write_enable=YES
anon_other_write_enable=YES

设置FTP根目录权限

mkdir /data/ftp   //创建目录
chmod R 755 /data
chmod R 777 /data/ftp

最新的vsftpd要求对主目录不能有写的权限所以data为755,主目录下面的子目录再设置777权限

配置PASV模式

vsftpd默认没有开启PASV模式,现在FTP只能通过PORT模式连接,要开启PASV默认需要通过下面的配置

打开/etc/vsftpd/vsftpd.conf,在末尾添加

pasv_enable=YES   //开启PASV模式
pasv_min_port=40000   //最小端口号
pasv_max_port=40080   //最大端口号
pasv_promiscuous=YES

在防火墙配置内开启40000到40080端口

-A INPUT -m state --state NEW -m tcp -p -dport 40000:40080 -j ACCEPT

重启iptabls和vsftpd

service iptables restart
service vsftpd restart

使用RedisLive实时监控Redis服务

RedisLive是由python编写的并且开源的图形化监控工具,非常轻量级,核心服务部分只包含一个web服务和一个基于redis自带的info命令以及monitor命令的监控服务,界面上只有一个基于BootStrap的web界面,非常简洁明了。除此之外,它还支持多实例监控,切换方便,而且配置起来也非常容易。监控信息支持redis存储和持久化存储(sqlite)两种方式。

注意:RedisLive是使用Python2.x编写,建议使用2.7,本次环境为Centos 7.2,默认Python版本2.7。

一、基础环境

1、实验环境

未分类

2、安装pip工具

wget https://bootstrap.pypa.io/get-pip.py

未分类

3、安装相关软件

pip install redis
pip install tornado
pip install python-dateutil
wKioL1mTCRjAXn9aAAEe--rjkY4165.png

未分类

二、安装Redis Live

1、下载软件

wget 
unzip master
mv RedisLive-master/ /usr/local/
cd /usr/local/RedisLive-master/src/
cp redis-live.conf.example redis-live.conf

2、修改配置文件

{
    "RedisServers":        
    [ 
        {
              "server": "127.0.0.1",                #redis监听地址,此处为本机
              "port" : 6379,                        #redis端口号
              "password" : "redispassword"          #redis认证密码
        }        
    ],

    "DataStoreType" : "redis",        

    "RedisStatsServer":    
    {
        "server" : "127.0.0.1",
        "port" : 6379,
        "password" : "redispassword"
    },

    "SqliteStatsStore" :
    {
        "path":  "db/redislive.sqlite"    #redis数据文件
    }
}

注意:RedisServers,段可以写多个,因此可以监控多个redis服务

3、启动服务

./redis-monitor.py --duration=30 &    //启动监控,duration是心跳时间 &放置在后台执行
./redis-live.py                       //启动web服务,默认监听8888端口,可以进行修改

默认web监听在8888,可进行修改,启动redis-monitor.py脚本,并将duration参数设置为 30
秒。duration参数指定了监控脚本的运行持续时间,例如设置为 30 秒,即经过 30 秒后,监控脚本会自动退出,并在终端打印 shutting down… 的提示。

未分类

4、制作定时任务

*/5 * * * * cd /usr/local/RedisLive-master/src/; ./redis-monitor.py --duration 20 >/dev/null 2>&1

三、查看图表

访问http://localhost:8888/index.html

未分类

20条实用的git命令介绍

个人总结出的一些实用的 git 命令,分享给大家。

git config --global color.ui true 

让 git 命令默认使用彩色输出。 这条命令在 git 2 之后已经成为默认配置,但如果你还在用比较老的版本(例如 CentOS 上的默认的 git 版本),建议把这项配置加上去。

git branch -av 

显示所有本地即远程分支,并显示最后提交的 Commit 信息。如果不加参数,则只会显示所有本地分支的名字。

git checkout -b <NAME> [<START POINT>] 

创建,并切换到新分支。git branch 只会创建分支而不会切换到新分支,可以用它备份当前分支。

git tag -L <PATTERN> 

列出所有符合条件的标签。如果你的项目严格按照 Major.Minor.Update 作为版本名称,那么这条命令就非常有用。它可以直接列出来当前版本下有那些小的 bugfix 版本。当然如果你非要 grep 一下我也没意见。

git diff -w 

显示未提交的更改,忽略空格。人们往往注重实际代码的改变而不注重缩进的变化。如果某个文件有大量缩进改变,-w 这个参数就非常有用。

git commit --amend 

修补前一次提交。相当于撤销前一次提交,做更改后重新提交。这也是一条非常实用的命令。当你发现前一次提交有一些小问题的时候(比如说漏提交了新创建的文件,或者有一些小的拼写错误),可以用这条命令修正前一次提交。它对 merge 提交友好,而且可以用于修正前一次提交的 message 信息。需要注意的是:如果你已经推送了前一次提交,amend 之后需要强推,这一点需要注意。

git log --graph --oneline --no-merge 

显示当前仓库的提交历史。git log 大家都用过,但真正研究过 git log 后面参数的人可能就不多。git log 后面可以接很多实用的参数,示例中的让提交历史以单行模式显示、显示提交历史树并删除 merge 提交。

git log -p --follow --stat -- <PATH> 

显示某个文件的提交历史。在 git 中,– 后接文件路径就代表对单个文件的操作。-p 可以显示具体修改的行,–follow 可以跟踪文件的移动和重命名,–stat 用于显示添加、删除行的数量。

git config --global alias.xx "<COMMAND>" 

给某 git 命令创建别名。对于一些比较长的命令,可以创建别名。以后只需要 git xx 即可执行 COMMAND 这条命令

git pull --rebase, --rebase 

可以简写为 -r
使用 git rebase 代替 git merge 执行 pull 操作。git pull –rebase 可以构造出非常整齐的提交历史树,强迫症的福利。git 的官方文档一再提醒这是个危险操作,因为它会修改你的代码提交历史。git rebase 的本质是撤销指定的提交,然后以指定的方式重新提交他们。git pull -r 就相当于首先撤销没有推送到远端的 commit,将远程代码覆盖到本地之后,重新提交所有之前撤销的 commit。与 git merge 不同,当有冲突产生时,git rebase 不会为你的 merge 操作生成一个新的提交。所以一旦 git pull –rebase 执行完毕就无法撤销。

git config --global pull.rebase true 

默认使用 git rebase 代替 git merge 执行 pull 操作。git 提供了一系列配置 git pull –rebase 操作:branch..rebase、branch.autosetuprebase。这条是最简单的全局配置项。尽管配置了默认使用 rebase,你可以使用 –merge 开关强制使用 git merge 执行 git pull。

git rebase -i 

交互式变基操作。git 中最强大的修改提交历史的操作,当然也是最危险的操作。它可以让你修改 commit 说明、让几个 commit 合并、交换 commit、删除 commit,甚至在提交某 commit 前执行一段 shell 命令。非常有用、非常强大、同时也是极其危险的操作。强烈建议在执行 git rebase -i 之前先使用 git branch 备份当前分支。

git push <remote> [<commit>]:<branch> 

推送指定的 commit 到远程。有时候你某个工作做到一半,然后来了一个bug要修。当然最好的做法是基于最新的远端分支新开一个分支,基于这个分支开发。但是如果你忘了新开分支,直接把代码提交到了当前分支怎么办?在你需要 push 的分支之前又有别的不需要的 commit。这时就可以先用 git rebase 交换 commit 的顺序,然后推送单个提交。如果你写了冒号但是不写 commit 号,就会变成删除某个远端分支。这是完全不同的而且可能有危险操作,需要注意。

git blame <PATH> [-L <M,N>] 

逐行检查某文件的提交人、提交时间和 commit 号。blame 的中文意思是追责,大家顾名思义,撕逼甩锅时用。 -L 可以指定要检查的行号。

git stash [push] [-u] 

贮存当前工作区的更改。经常有这样的事情发生,当你正在进行项目中某一部分的工作,里面的东西处于一个比较杂乱的状态,而你想转到其他分支上进行一些工作。问题是你还不想提交这些代码,这是就可以用 git stash 命令将未提交的更改临时保存到一个贮存项中。-u 表示将未加入版本管理的文件也保存(比如新建的一些文件)

git stash apply <INDEX>、git stash pop <INDEX> 

将最后一次保存的(或指定的某个)贮存项应用至当前工作区。与前面的 git stash [push] 配套使用。 apply 与 pop 的区别是:pop 会在应用更改的同时把所应用的贮存项删除,而 apply 不会。

git cherry-pick -x <COMMIT>.. 

摘取 某些提交。即把另一个本地分支的 commit 应用到当前分支。如果我们同时维护多个分支,这个操作就很有用。比如说你在主干 master 分支上修复了一个 bug,然后你想把这个修复应用到一个旧版本的分支上,但是你又不想把其他 master 分支的新功能拉进来,这时就可以用 cherry-pick。-x:在提交记录中添加一行 (cherry picked from commit ),让两个提交关联起来。

git revert <COMMIT> 

回滚某个提交。即提交某个 COMMIT 的反提交。最快修复某个 bug 的方式就是把引入 bug 的代码干掉。注意干掉代码不代表就要用 git rebase -i 把提交本身也干掉。

git grep <PATTERN> 

在当前加入版本管理的文件中全文检索某字符串。类似于 grep 操作,但是会忽略不需要的(加入 .gitignore 的)文件,非常实用的命令。

git bisect 

实用二分查找的方式定位引入问题的提交。快速定位 bug 的方式。在找不到 bug 出现的原因时,不妨用 git bisect 将 bug 先锁定到某个 commit 上。

brew install tig 

美化 git 输出,重度终端用户的福利。这个其实是工具安利了,它用图形化的方式(ncurses)美化 git 输出,谁用谁知道。