CentOS上用Squid搭建HTTP代理小结

1、安装Squid

yum install squid -y

# -y 代表自动选择y,全自动安装

2、安装后,可以自定义http代理端口,设置来源IP白名单等

vi /etc/squid/squid.conf

# ------ 自定义http端口:

# Squid normally listens to port 3128
http_port 8088

# ------ 设置来源IP白名单,增加的这两行要在 http_access deny all 前面

acl client src 122.55.87.125
http_access allow client

# And finally deny all other access to this proxy
http_access deny all

3、默认squid的access日志里的时间为unix时间戳,不方便阅读,可以通过在 /etc/squid/squid.conf 增加一行logformat配置:

#此行加在配置文件末尾即可
#access log time human-readable
logformat squid %tl.%03tu %6tr %>a %Ss/%03>Hs %<st %rm %ru %un %Sh/%<A %mt

4、修改完配置文件后,reload即可生效:

/etc/init.d/squid reload

#另外启动和重启命令
/etc/init.d/squid start
/etc/init.d/squid restart

5、如果想在防火墙级别就限定只允许白名单IP访问代理端口:

vi /etc/sysconfig/iptables

-A INPUT -s 122.55.87.125 -p tcp -m tcp --dport 8088 -j ACCEPT

service iptables restart

Linux文本过滤命令grep|awk|sed小结

grep的使用

一、grep一般格式

grep [选项] 基本正则表达式 [文件]

这里的正则表达式可以为字符串。在grep命令中输入字符串参数时,最好将其用双引号括起来。调用变量时也可以使用双引号。在调用模式匹配事,应使用单引号。

二、grep常用选项

-c 只输出匹配行的计数。
-i 不区分大小写(只用于单字符)。
-h 查询多文件时不显示文件名。
-l 查询多文件时只输出包含匹配字符的文件名。
-n 显示匹配行及行号。
-s 不显示不存在或无匹配文本的错误信息。
-v 显示不包含匹配文本的所有行。

三、常用选项的使用

1、 查询多个文件:

$grep  “hello” *.doc
num.doc:hello
sum.doc:hello world

说明在num.doc 和sum.doc中有字符串“hello“。

2、 行匹配:

$grep -c “123” *.doc
num.doc:2
sum.doc:2

说明在num.doc 和sum.doc中有字符串“123“各为两行。

3、 显示满足匹配模式的所有行数:

$grep –n “123” *.doc
num.doc:1:hao 123
num.doc:2:hao 123
sum.doc:2:hao 123
sum.doc:4:hao 1234

4、 显示所有不包含“123“的行:

$grep  -v “123” *.doc
num.doc:hello
num.doc:world
sum.doc:hello world
sum.doc:sui yue

5、 精确匹配:

如第三点,匹配“123”时,结果返回了“1234”的其它字符串。

$grep -n “123>” *.doc
num.doc:1:hao 123
num.doc:2:hao 123
sum.doc:2:hao 123

6、 大小写敏感:

缺省情况下,grep是大小写敏感的,如果要查询大小写不敏感的字符串,必须

使用-i选项。

$grep -i “just” *.doc 
num.doc:Just
num.doc:just

四、grep和正则表达式

1、模式范围:

$ grep  ‘48[34]’ mydata.doc

此命令在mydata.doc中匹配字符串“483”和“484”。

2、 不匹配行首:

$ grep  ‘^[^48]’ mydata.doc

此命令在mydata.doc中匹配除4或者8开头的行。

3、 设置大小写:

$ grep  ‘[Ss]ept’  mydata.doc

此命令在mydata.doc中匹配字符串“Sept”和“sept”。

4、匹配任意字符:

$ grep  ‘a…z’ mydata.doc

此命令在mydata.doc中匹配字符串以字符a开头和字符z结尾,中间为任意三个字符。

5、 模式出现的机率

$ grep ‘1{2,}’ mydata.doc

此命令说明数字1至少出现两次


awk的使用

一、awk的调用格式

awk的调用格式有三种:

第一种是命令行的方式,如下:

awk [-F field-separator] ‘commands’ input-file

[-F]域分隔符,是可选的,awk使用空格作为缺省的域分隔符。

第二种方法是将awk命令插入到一个文件,并使awk程序可以执行,然后用awk命令解释器作为脚本的首行,以便通过键入脚本名称来调用它。

第三种方法是将所有的awk命令插入一个单独文件,然后调用:

awk –f awk-script-file input-file

二、动作和模式

任何awk语句都有模式和动作组成。模式部分决定动作语句何时触发及触发事件。

模式包括两个特殊字段BEGIN和END.,BEGIN语句使用在任何文本浏览动作之前,之后文本浏览动作依据输入文件开始执行,END语句用来在awk完成文本浏览动作后打印输出文本中输出和结尾状态标志。实际动作在大括号内指明。

三、域和记录

awk执行时,其浏览域标记为$1,$2 ….$n.。这种方法称为域标识。

1、保存awk输出

第一种方法:

$awk ‘{print $0}’ mydata.txt >newfile.txt

显示屏上不会输出结果。

第二种方法:

$awk ‘{print $0}’ mydata.txt | tee newfile.txt

输出到文件中,同时显示在显示器上。

2、使用标准输入

第一种方法:使用awk脚本输入文件格式

$myawk.awk inputfile.txt

第二种方法:使用重定向

$myawk.awk < inputfile.txt

第三种方法:使用管道

$inputfile.txt | myawk.awk

3、打印所有记录

$awk ‘{print $0}’ myfile.txt

由于没有模式部分,只有动作部分,动作必须用花括号括起来。

Lisi 25 wuhan
Wangjian 33 shanghai
Caiming 55 shenzhen

4、打印单独记录

要用逗号分隔域

$awk ‘{print $1,$2}’ myfile.txt
Lisi 25
Wangjian 33
Caiming 55

5、打印报告头

$awk ‘BEGIN {print “Name Agen******************“} {print $1”t”$2}’ mfile.txt

Name    Age
***************
Lisi      25
Wangjian 33
Caiming 55

6、打印信息尾

$awk ‘BEGIN {print “Name n****** “} {print $1 } END {“end of reportn”}’ mfile.txt

sed的使用

一、sed调用格式

sed调用格式有三种:

第一种命令行方式:

sed [option] ‘command’ inputfile

ommand要加单引号,也允许加双引号。

第二种使用sed脚本文件:

sed  [option]  –f  sed-script-file inputfile

第三种使用第一行具有sed命令解释器的sed脚本文件:

sed-script-file [option] inputfile

二、sed选项

n 不打印:sed不写编辑行到标准输出,缺省为打印所有行。P命令可以用来打印编辑行。
c 下一命令是编辑命令。使用多项编辑时加入选项。
f 如果正在调用sed脚本文件,使用此选项。此选项通知sed脚本文件支持所有的sed命令。

三、sed常规用法

1、 保存sed 输出

$ sed  ‘command’ inputfile > outfile

2、 sed在文件中查找文本的方式

sed浏览文件时,默认从第一行开始,有两种方法定位文本:
第一种:使用行号,可以用简单数字或是一个行号范围。
第二种:使用正则表达式。

Sed定位文本的一些方式,如下:

x x表示行号。 
x,y 表示行号范围从x到y。 
/pattern/ 查找包含模式的行。 
x,/pattern 通过行号和模式查询匹配行。 
x,y! 查找不包含指定行号x到y的行。 

3、 sed编辑命令

p 打印匹配行 
= 显示文件行号 
a 在定位行号后附加拳文本信息 
i 在定位行号后插入拳文本信息 
d 删除定位行 
c 用拳文本替换定位文本 
s 使用替换模式替换相应模式 
r 从另一个文件中读文本 
w 写文本到一个文件 
q 第一个模式匹配完成后推出或立即推出 
l 显示与八进制ASCII代码造价的控制字符 
{} 在定位行执行的命令组 
n 从另一个文件中读文本下一行,并附加在下一行 
g 将模式2粘贴到/pattern n/ 
y 传送字符 
n 延续到下一输入行;允许跨行的模式匹配语句。 

4、 使用p显示行

$sed -n ‘2p’ myfile.txt
Hello world!

-n选项,显示打印定位行。

5、 打印范围

$sed -n ‘1,3p’ myfile.txt
Hao 123
Hello world!
Ni hao ma?

打印1到3行。

6、 打印模式

$sed -n ‘/123/’p myfile.txt
Hao 123

匹配

7、 在指定行号匹配模式

$sed -n ‘5,/Hao/’p myfile.txt
Hao ma?

【Linux】cat、tail、head、grep、sed查看文件任意几行的数据

grep结果太多, 可否只取前面10行匹配的结果

grep ...... | head -10

一、使用cat、tail、head组合

1、查看最后1000行的数据

cat filename | tail -n 1000

2、查看1000到3000行的数据

cat filename | head -n 3000 | tail -n +1000

1、cat filename 打印文件所有内容
2、tail -n 1000 打印文件最后1000行的数据
3、tail -n +1000 打印文件第1000行开始以后的内容
4、head -n 1000 打印前1000的内容

二、使用sed命令

显示1000到300行的数据

sed -n '1000,3000p' filename

============================================
输入ps,它就是我们今天的主角,ps是linux操作系统中最基本同时也是非常强大的进程查看命令,如果你对此命令不是十分了解,我们可以输入ps
–help命令来查看此命令的帮助信息。
通过帮助信息我们可以看到,ps命令的相关参数有很多,很多初学的朋友可能会看的一头雾水,不知道该怎么组合这些参数,下面小编就举一些实际应用例子,来介绍一些比较常用的查看进程的固定命令组合。
我们先来看第一个命令,ps

-l命令。这个命令和直接使用ps效果类似,但是不同之处在于使用ps命令获得结果很短,而使用-l参数之后将会较长、较详细的列出该PID的的信息列出,由于参数较多,小编就不一一介绍各个参数的含义了,如果想要了解参数的具体含义可以上网查看相关信息。
接着我们来看第二个命令ps

aux,有“-”符号和没有两者是有区别的,这个命令应该是比较常用的一个命令,作用就是列出目前所有的正在内存当中的程序,其中a表示显示现行终端机下的所有程序,包括其他用户的程序,u表示以用户为主的格式来显示程序状况,x表示显示所有程序,不以终端机来区分,它的相关参数也不少,例如user,表示属于那个使用者账号的,%CPU表示使用掉的CPU资源百分比,其他的参数就不一一的介绍了,有兴趣可以自行查看。

============================================
rl+ 是什么状态 linux ?是串联和是并联。

saltstack mutilmaster的具体配置和实现

简介:在上一篇讲完了salt-master的HA整体架构之后,再来看看它的多master的实现方案。该文档参考saltstack官方文档:
https://docs.saltstack.com/en/develop/topics/tutorials/multimaster.html

步骤:

  1. 创建一个master服务的备份节点
  2. copy 主master节点的key到备节点
  3. 启用备master节点
  4. 重启minions
  5. 在备节点接受key

step1 -2:

默认的master的private key是在目录: /etc/salt/pki/master. 将该目录下的master.pem拷贝到备master节点的同一位置,对master的public key文件master.pub做同样的操作。

step3:

注意,一旦新的key被备份节点接受后,要进行安全的一些操作 。:
配置minions:

master:
  - saltmaster1.example.com  #或者IP地址
  - saltmaster2.example.com

配置完成后,minion将会核对主master和备master进行核对,并且两个master都对minion有操作权限。
注意:minion可以自动检测失败的master,并且尝试重连到一个更快的master,将minion端的参数master_alive_interval 设置为true,即可开启该功能。

在master之间共享文件:
salt本身在master之间没有共享文件的功能,共享能力需要考虑。
那么需要分别在每一个master节点上面进行手动接受key,才可以实现双节点的备份,这明显不方便。
但是也可以通过共享文件:/etc/salt/pki/master/{minions,minions_pre,minions_rejected}来实现。
file_roots:
共享文件如何共享呢,那么可以选择简单易用的gitfs,来同步多master之间的文件共享。

saltstack的HA高可用架构方案

saltstack集群管理简介:saltstack的常规方案为 ‘单master-多minions’ 架构 ,如下图左,对批量节点进行管理和操作;在较大规模的集群系统下,常用的为三层架构,‘单master-单syndic-多minions’架构,对集群进行分块管理,如下图右,三层架构可以通过master节点将任务分发到syndic节点,对各个syndic管理的区域的minion机器进行操作,之后结果返回到syndic节点,并二次返回到master节点,可以再master节点一并获取返回结果。

问题:上述架构中的高可用性方案是没有的,仅仅作为一个管理工具,上述架构已经可以满足基本要求;
然而因为公司更多的业务系统通过调用saltstack来进行集群管理,那么对salt的要求也从工具到了基础架构组件的层面,因此,对服务可用性方面的要求
就更高了,salt原生默认‘单master-minion’架构,salt-api也是daemon方式运行,因此,在推广到生产环境之后,可用性就遭到了极其严重的考验,
比如,单master故障整个集群的操作就实现不了,如何实时迁移恢复,如何对文件进行备份,如何对master节点和syndic节点做主备方案,如何使得主备管理均可访问到
minion节点,又如何对三层架构syndic节点存储的文件做到统一管理,并且进行文件主备方案,高可用性也是在生产环境中任何系统所必须的一项内容。

方案:mutil-master,mutil-syndic,以及使用gitfs对syndic节点的文件进行同步到服务器。并将服务器做好两城主备。

官方相关参考文档:http://docs.saltstack.com/en/latest/topics/highavailability/index.html
在参考了几个成功案例之后,最后的架构参考了:MultiSyndic、MultiMaster、Failover Minion、Ext Job Cache
博客地址:http://openskill.cn/article/181

mutil-syndic
首先是mutil-syndic,mutil-syndic是指一台syndic节点同时被多台MOfM(master of masters)管理,官方文档对简单的配置做了一些介绍:
https://docs.saltstack.com/en/latest/topics/topology/syndic.html
具体的源码则是放到了minion.py,本身原理便是MultiSYndic会去复用一些Syndic的功能,然后做一些转发的处理。
具体的设置综合mutil-master,需要设置syndic_master为一个list,另外key等文件要做共享设置,其次就是写入一些必要
的syndic本身的配置。

Failover Minion or MultiMinion
这是salt在minion端实现的特性,它允许minion定期的去探测当前master的存活性,一旦发现master不可用,就在一定时间
内做出切换,从而提供整体服务调用的可用性。
具体配置参考官网内容:https://docs.saltstack.com/en/develop/topics/tutorials/multimaster_pki.html
需要注意的是配置multi-master或者multimaster PKI都可以使用failover特性。minion的具体配置内容如下:

# multi-master  
master:    
    - 172.16.0.10  
    - 172.16.0.11  
    - 172.16.0.12  

# 设置为failover minion  
master_type: failover  

# 设置启动时随机选择一台master  
master_shuffle: True  

# 探测master是否存活的schedule job  
# 即使用salt schedule特性实现的功能  
master_alive_interval: <seconds>  

但是上述架构也是有弊端的,正如开端描述的,MOfM在下发命令的时候,所有的节点都通过syndic节点在短时间内大量返回,MofM就等于承受了一次短时间的数据流量的
冲击,1W台minion就是1W条minion job数据,再加上find job任务,理论上产生的数据量和计算能力的消耗是巨大的。
因而在生产环境中,我们目前基本上是在采用,对于某些区域的机器,直接在syndic节点进行操作。这样就避免造成master巨大的处理能力。
然而,我们在master节点进行全区域操作的情况下,master并非是对所有区域同时进行访问,而是在等待单syndic节点返回结束后,开始进行下一个syndic节点的返回。

GitLab+Jenkins+Rsync+PM2实现Node项目的持续集成与自动部署

前言

最原始的软件开发流程是,在本地搭建好环境,进行开发测试,然后去服务器上搭建环境,手动上传代码,运行测试,然后启动服务。实际上,近些年来出现了很多的工具,使得这些步骤可以自动化,大大降低人工出错的概率,提高生产效率。下面,我就把GitLab+Jenkins+Rsync+PM2实现的Node项目的持续集成以及自动部署的实验过程记录下来。

搭建环境

需要两台服务器作为演示,A主要进行代码管理、构建和分发,B主要运行实际应用。我这边系统使用的是Debian系的。

服务器A

GitLab

准备工作:

apt-get update
apt-get install curl openssh-server ca-certificates postfix

安装postfix的时候,选internet site,之后的 system mail name 填写你的服务器的IP地址。

准备好后开始安装:

curl https://packages.gitlab.com/install/repositories/gitlab/gitlab-ee/script.deb.sh | sudo bash
apt-get install gitlab-ee

如果 apt 下载很慢可以手动下载 https://packages.gitlab.com/gitlab/gitlab-ee/packages/ubuntu/trusty/gitlab-ee_10.2.2-ee.0_amd64.deb 然后用 dpkg -i 的方式安装。装了这个过后 NGINX, Postgres, Redis 就都装好了。

配置:

GitLab默认会占用80、8080和9090端口,Jenkins默认也会使用8080端口,所以将GitLab的默认端口为60200、60201、60202(你可以随意定制)

vim /etc/gitlab/gitlab.rb 修改

external_url 'http://<你的服务器ip>:60200'
unicorn['port'] = 60201
prometheus['listen_address'] = 'localhost:60202'

注意不能有多余空格。gitlab-ctl reconfigure生效配置,gitlab-ctl start启动。
如果要想发邮件的话还要配置第三方邮件 vim /etc/gitlab/gitlab.rb

gitlab_rails['smtp_enable'] = true 
gitlab_rails['smtp_address'] = "smtp.exmail.qq.com"
gitlab_rails['smtp_port'] = 465
gitlab_rails['smtp_user_name'] = "***#**"
gitlab_rails['smtp_password'] = "**************"
gitlab_rails['smtp_domain'] = "qq.com"
gitlab_rails['smtp_authentication'] = :login 
gitlab_rails['smtp_enable_starttls_auto'] = true
gitlab_rails['smtp_tls'] = true
gitlab_rails['gitlab_email_from'] = "***#**"
user["git_user_email"] = "***#**"

然后生效重启,打开http://<你的服务器IP>:60200访问,

Jenkins

准备工作:

wget --no-cookies --no-check-certificate --header "Cookie: gpw_e24=http%3A%2F%2Fwww.oracle.com%2F; oraclelicense=accept-securebackup-cookie" "http://download.oracle.com/otn-pub/java/jdk/8u151-b12/e758a0de34e24606bca991d704f6dcbf/jdk-8u151-linux-x64.tar.gz"
tar xzvf jdk-8u151-linux-x64.tar.gz -C /usr/local/  
vim /etc/profile #(加入环境变量)
    export JAVA_HOME=/usr/local/jdk1.8.0_151
    export PATH=$JAVA_HOME/bin:$PATH

退出,source /etc/profile 生效,用 java -version 验证是否装好java。

开始安装:

curl -O http://mirrors.jenkins.io/war-stable/latest/jenkins.war 下载Jenkins,
nohup java -jar jenkins.war –httpPort=60203 & 后台启动并指定端口。
至此,Jenkins安装成功,可以用浏览器打开 http://<你的服务器ip>:60203
然后安装必要的插件(会提示你),依次点击 “系统管理” “管理插件”。
切换到“可选插件”,分别搜索“GitLab Plugin”和“Git Plugin”,然后点击“直接安装”。如果在“可选插件”里没有搜到,可能自带安装了

Node

apt-get update
apt-get install -y build-essential curl
curl -sL https://deb.nodesource.com/setup_8.x | bash 
apt-get install -y nodejs
node -v
v8.9.2
npm -v
5.5.1

Rsync

这个服务器主要使用Rsync来发布文件,所以不需要特殊配置,一般Linux都默认安装了,如果没有,则使用 apt-get install rsync。然后配置Rsync密码

echo "123" >> /etc/rsync.password
chmod -R 600 /etc/rsync.password

服务器B

Node

如A

PM2

npm install -g pm2
pm2 -v
2.8.0

Rsync

为了安全性不要直接使用ssh账号密码或者公钥私钥,而是构建Rsync服务。vim /etc/rsyncd.conf,修改配置,下面的配置只是一个示例,生产环境还要更安全的策略。

##rsyncd.conf start##
uid = root
gid = root
use chroot = yes
max connections = 200
timeout = 300
pid file = /var/run/rsyncd.pid
lock file = /var/run/rsync.lock
log file = /var/log/rsyncd.log
ignore errors
read only = false
list = false
hosts allow = * 
hosts deny =10.0.8.9
auth users = backuser
secrets file = /etc/rsync.password
[webapp]
path = /var/webapp/

上面的的路径path不存在则需要创建 mkdir /var/webapp
echo “backuser:123” >> /etc/rsync.password 添加账号和密码,密码要与客户端(A)一直
chmod -R 600 /etc/rsync.password 修改权限
rsync –daemon 以守护进程方式来启动rsync服务
chkconfig rsync on将此服务设置成为开机自启动

应用开发

用express开发一个 hello world 作为演示,在本地工程目录

npm init #(按照提示输入参数)
npm install express --save  #(安装express)

然后创建app.js

var express = require('express');
var app = express();

app.get('/', function (req, res) {
  res.send('Hello World!');
});

var server = app.listen(3000, function () {
  var host = server.address().address;
  var port = server.address().port;

  console.log('Example app listening at http://%s:%s', host, port);
});

node app.js 运行,然后http://localhost:3000/ 会得到 hello world

新建app.json

{
    "apps" : [
        {
            "name"        : "app",
            "script"      : "app.js",
            "log_date_format"  : "YYYY-MM-DD HH:mm:SS",
            "env": {
                "NODE_ENV": "production"
            },
            "watch" : [
                "app.js",
                "router",
                "util"
            ],
            "ignore_watch" : [
                "logs",
                "node_modules",
                "test"
            ]
        }
    ]
}

将代码上传至服务器B,然后 pm2 start app.json 运行 即可在浏览器访问 http://B-ip:3000 得到 hello world

持续集成和自动部署

配置 Gitlab

首次登陆的密码是会提示你去服务器找,用户是root,然后修改你的用户账号信息,添加你自己常用的电脑上的git公钥。
创建一个新项目 webapp ,创建好过后项目会显示该项目对应的用户信息(会提示你修改)

Git global setup

git config --global user.name "MageekChiu"
git config --global user.email "mageekchiu@mail.**.cn"

在本地项目目录下,新建 .gitignore 文件(window 要用 命令行 rename才可以)

### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr

node_modules/

然后执行

git init
git remote add origin git@A-ip:root/webapp.git
git add .
git commit -m "Initial commit"
git push -u origin master

即可提交服务器仓库,以后每次修改都要

git add .
git commit -m "修改备注"

配置 jenkins

首先配置GitLab插件:

打开GitLab,点击“setting”——“Account”,复制“Private token”,或者应该首先生成personal access token。
打开Jenkins,点击“系统管理”——“系统设置”,点击“配置”下拉框,点击“Gitlab”选项配置GitLab
Connection Name 随便,如 gitlab,“Git Host URL”填GitLab的访问地址,
然后Credentials点“Add”——“jenkins”,在弹出框里,“kind”选择“GitLab API Token”,将先前复制的“Private token”粘贴到“API token”输入框中,然后点击“Add”,添加后,Credentials选择刚刚新建的gitlab,
最后点击“test connection”,看到“Success”就成功了。然后点击页面底下的“apply”,再点击“save”

然后配置Git插件:

需要注意的是装Jenkins的机器上一定要装git: apt-get install git 这样Jenkins才能去 gitlab 拉取文件。
打开Jenkins,点击“系统管理”——“系统设置”,点击“配置”下拉框,选择“Git plugin”选项,设置Git插件的全局配置,填入上面的 global setting 如 global user.name等,然后点击“apply”——“save”

成访问Gitlab的ssh秘钥:

打开GitLab,点击右上角的“setting”—— SSH Keys,就可以进入到添加界面。
在jenkins所在服务器上生成密钥
ssh-keygen -t rsa -C “root@<你服务器的ip地址>” -b 4096
ssh-keygen -t rsa -C “root@” -b 4096
全部按 Enter 使用默认值,这会生成一对公钥和私钥。打开公钥复制到gitlab的添加界面,然后点击“add key”,并记住私钥的存放路径。

创建一个Jenkins Job:

直接点新建,“item name”可以随便起,然后点击“构建一个自由风格的软件项目”,点击“OK”,至此,创建一个Job成功了。然后配置这个job,选择“源码管理”,选择“Git”,然后去GitLab中复制项目地址,粘贴到“Repository URL”,然后点击“credentials”后面的“Add”按钮

在弹出页面里面:
● Kind 选择 SSH Username with private key
● Username 填 root
● PrivateKey 选择 From a file on jenkins master ,然后将服务器的 私钥的存放路径(/root/.ssh/id_rsa ) 粘贴进去
然后点击“Add”,在“credentials”里选择我们刚刚创建的认证方式。如果没报错,说明成功了,点击页面底部的“apply”。如果出错了,会在“Repository URL”和“Credentials”之间显示红色的错误信息。

选择 构建触发器:
选择 Build when a change is pushed to GitLab. 记住这个 GitLab CI Service URL ,点击高级
Secret token 那一行下面 点击 generate。记住这个token
选择 构建:
选择 execute shell

npm install 
WEB_SERVER_IP=B的ip
PROJECT=webapp/
rsync -arqz --delete-before $WORKSPACE/ $WEB_SERVER_IP::$PROJECT --exclude ".git" --password-file=/etc/rsync.password 

这一段代码的主要目的是构建,并分发代码,如果有多个应用服务器就要分发到多个服务器上。

配置gitab的webhook:

点击webapp 项目下面的setting的integrations 输入刚才的 GitLab CI Service URL 和 Secret Token
然后点击add webhook ,再测试一下选择 push events 如果显示Hook executed successfully: HTTP 200 即成功,然后在jenkins里面查看是有一次构建记录的。

这样jenkins就会在代码发生变化时自动拉取代码到本地,构建,然后用rsync分发给各个应用服务器,结合PM2的watch功能实现自动发现代码更新并重启的功能,达到自动部署的目的

最终效果测试

修改代码,把hello world改为hello gitlab+enkins然后 add、commit、push 。在A上面gitlab有提交记录,jenkins有构建记录,在B上面用 pm2 ls 发现项目是restart了,浏览器查看也变成hello gitlab+enkins 了。
尝试成功!
虽然这个配置比较麻烦,但是持续集成和自动部署的带来的好处是更大的:代码有版本管理,可以快速迭代、快速回滚,同时保持高质量、自动多机部署防止人工错误,每次构建都有记录,构建幂等……

后记

这个过程已经比较自动化了,但是还是有太多的环境搭建过程,比如webapp一般都会用到mysql、redis、MongoDB等等,一个更自动化的过程应该引入docker,这方面以后有机会再尝试。

使用rsync完成内网数据备份

最近在搞公司内网数据备份,在此记录下。拓扑如下:

未分类

环境描述:web服务器为lnmp环境,其中attachment目录是用户数据,大约有300G,很重要。mysql服务器每天零时备份数据库,备份的数据也需要推到异地。备份软件选用rsync,原因如下:

能更新整个目录和树和文件系统;
有选择性的保持符号链链、硬链接、文件属于、权限、设备以及时间等;
对于安装来说,无任何特殊权限要求;
对于多个文件来说,内部流水线减少文件等待的延时;

只同步增加的数据,效率更高;

搭建过程:

1,rsync服务端安装:

[root@backup ~]# rpm -qa rsync 
rsync-3.0.9-18.el7.x86_64

这里已经安装rsync,如果没有安装,则使用下面的命令安装:

[root@backup ~]# yum install rsync -y

2,编辑rsync配置文件:

由于我是使用daemon模式去启动rsync,因此需要一个配置文件,位置为/etc/rsyncd.conf,以下是配置文件的内容:

# Rsync configuration file
uid = root
gid = root
port = 873
address = 192.168.1.222
max connections = 200
use chroot = yes
timeout = 200
log file = /var/log/rsyncd.log
pid file = /var/run/rsyncd.pid
lock file = /var/run/rsyncd.lock
log format = %t %a %m %f %b
auth users = bkuser
secrets file = /etc/rsyncd.secrets

[attachment]
path = /backup/1/attachment/
comment = "Poplar web data"
list = yes
read only = no
ignore errors = yes
hosts allow = 192.168.1.126/24
hosts deny = *


[dbm]
path = /backup/1/mysql/db.pop.cn/
comment = "database backup"
list = yes
read only = no
ignore errors = yes
hosts allow = 192.168.1.137/24
hosts deny = *

3,创建相应的模块挂载点:

由于数据量比较大,所以我加了一块2T的磁盘单独做备份,挂载点为/disk/1,同时为了防止数据误删,我又在/下创建了backup目录,通过这个入口去链接真正的备份数据。结构如下:

[root@backup ~]# mkdir /backup
[root@backup ~]# mount /dev/sdb /disk/1/        #把2T的磁盘挂载到/disk/1/下
[root@backup ~]# ln -sv /disk/1/ /backup/1        #将/backup/1链接到/disk/1/
  ‘/backup/1’ -> ‘/disk/1/’

4,设置服务器端权限:

[root@backup ~]# echo ‘bkuser:123456’ > /etc/rsyncd.secrets
[root@backup ~]# chmod 600 /etc/rsyncd.secrets

这里一定要将密码权限设置为600,否则后面推送文件时会报错。

5,启动rsync服务:

[root@backup ~]# rsync --daemon --config=/etc/rsyncd.conf
#检查rsync启动情况
[root@backup ~]# netstat -tnlp | grep rsync 
tcp        0      0 192.168.1.222:873       0.0.0.0:*               LISTEN      1073/rsync 
[root@backup ~]# ps -ef | grep -v grep | grep rsync 
root      1073     1  0 03:51 ?        00:00:00 rsync --daemon --config=/etc/rsyncd.conf

可以看到rsync服务已经启动成功。

6,设置rsync开机自启动:

[root@backup ~]# echo '/usr/bin/rsync --daemon --config=/etc/rsyncd.conf' >> /etc/rc.d/rc.local
#这里要注意,/etc/rc.d/rc.local这个文件一定要有可执行权限 chmod +x /etc/rc.d/rc.local
#尽量使用命令的绝对路径。

7,客户端配置权限:

#web主机
[root@web ~]# echo '123456' > /etc/rsync.passwd
[root@web ~]# chmod 600 /etc/rsync.passwd

#mysql主机
[root@mysql ~]# echo '123456' > /etc/rsync.passwd
[root@mysql ~]# chmod 600 /etc/rsync.passwd

8,客户端推送命令:

[root@web ~]# rsync -avz /mnt/wwwroot/poplar/public/attachment/ [email protected]::attachment --password-file=/etc/rsync.passwd 
rsync: failed to connect to 192.168.1.222 (192.168.1.222): No route to host (113)
rsync error: error in socket IO (code 10) at clientserver.c(122) [sender=3.0.9]

报错,No route to host,首先想到的就是防火墙,查看rsync服务端:

[root@backup ~]# iptables -L 
Chain INPUT (policy ACCEPT)
target     prot opt source               destination         
ACCEPT     all  --  anywhere             anywhere             ctstate RELATED,ESTABLISHED
ACCEPT     all  --  anywhere             anywhere            
INPUT_direct  all  --  anywhere             anywhere            
INPUT_ZONES_SOURCE  all  --  anywhere             anywhere            
INPUT_ZONES  all  --  anywhere             anywhere            
DROP       all  --  anywhere             anywhere             ctstate INVALID
REJECT     all  --  anywhere             anywhere             reject-with icmp-host-prohibited
#果然有策略
[root@backup ~]# iptables -F
[root@backup ~]# service iptables save
The service command supports only basic LSB actions (start, stop, restart, try-restart, reload, force-reload, status). For other actions, please try to use systemctl.
#又报错,这里需要安装iptables-services服务
[root@backup ~]# yum install iptables-services
[root@web ~]# systemctl enable iptables 
Created symlink from /etc/systemd/system/basic.target.wants/iptables.service to /usr/lib/systemd/system/iptables.service.
[root@web ~]# systemctl start iptables 
[root@web ~]# service iptables save
iptables: Saving firewall rules to /etc/sysconfig/iptables:[  OK  ]

#再次推送:
[root@web ~]# rsync -avz /mnt/wwwroot/poplar/public/attachment/ [email protected]::attachment --password-file=/etc/rsync.passwd 
...
sent 1044543 bytes  received 9553 bytes  2108192.00 bytes/sec
total size is 4351974  speedup is 4.13
#推送成功

查看服务器端备份情况:

[root@backup ~]# ll /backup/1/attachment/
#发现有一个软链接文件的源文件没有同步过来(不停的闪红色)

查看rsync的帮助信息:

-L, --copy-links            transform symlink into referent file/dir

使用-L 选项可以备份软链接文件的源文件,于是我们的推送命令变成了这样:

[root@web ~]# rsync -avzLP /mnt/wwwroot/poplar/public/attachment/ [email protected]::attachment --password-file=/etc/rsync.passwd

数据库端的推送命令和web端类似,只是不需要-L参数,这里就不演示了。

Python 动态生成变量名

如果你想生成v1,v2…v100这一百个变量,使用其他静态编译语言只能在代码中手动写出这100个变量名,但是在python中可以使用循环方便地动态生成。
python中有一个函数locals(),定义是:

locals(...)
    locals() -> dictionary

    Update and return a dictionary containing the current scope's local variables.

即返回当前作用域的所有变量
所以可以用这个函数来创建变量

代码:

for i in range(4):  
    name='v'+str(i)  
    locals()['v'+str(i)]=i  

print v1,v2,v3  

输出为1 2 3

实时查看php-fpm的状态

在nginx里面加一个location就可以了,具体设置如下:

location ~ ^/status$ {
                include fastcgi_params;
                fastcgi_pass 127.0.0.1:9000;
                fastcgi_param SCRIPT_FILENAME $fastcgi_script_name;
        }

然后在php-fpm.conf里面打开选项

pm.status_path = /status

这样的话通过http://域名/status就可以看到当前的php情况,以前之知道可以配置location来看nginx的状态,没想到还可以看php-fpm的状态,,真的是学习了,,看到的状态如下:

pool: www php运行的组
process manager: dynamic php-fpm运行的方式
start time: 04/Jun/2012:16:05:32 +0800 开始时间
start since: 5932
accepted conn: 65678 接受链接
listen queue: 0 监听队列
max listen queue: 1 最大监听队列
listen queue len: 128 监听队列len
idle processes: 82 空闲进程
active processes: 4 活动进程
total processes: 86 总进程
max active processes: 25 最大活动进程
max children reached: 0 最大的子进程达到

有了这个,就可以实时的查看php-fpm的状态,进而优化php-fpm

docker搭建nginx+php-fpm开发环境

一、创建目录

mkdir -p /data1/www/app;
mkdir -p /data1/www/logs;
mkdir -p /data1/www/php;
mkdir -p /data1/www/nginx;
mkdir -p /data1/www/php/fpm.d;
mkdir -p /data1/www/nginx/vhost;
chmod 777 -R /data1/www;

添加项目:

vim /data1/www/app/www.mydemo.com/index.php
<?php
    echo 22;
    phpinfo();

二、启动容器

docker run -it --name=web_container --net=host -v /data1:/data1 centos /bin/bash;
yum -y install wget;
yum -y install initscripts;

三、安装nginx

依赖说明:

  • zlib: Nginx提供gzip模块,需要zlib库支持。
  • openssl: Nginx提供SSL功能
  • pcre: 支持地址重写rewrite功能

依赖安装:

yum -y install zlib zlib-devel openssl openssl-devel pcre-devel;

依赖检测:

rpm -qa  zlib;
rpm -qa  openssl;
rmp -qa  pcre;

nginx安装

wget http://nginx.org/download/nginx-1.10.3.tar.gz
tar -zxvf nginx-1.10.3.tar.gz;
cd nginx-1.10.3;
./configure --prefix=/usr/local/nginx --with-http_ssl_module --with-http_flv_module;
make && make install;

创建用户

groupadd  www
useradd -r -g www  www

在宿主机上修改添加配置文件: vim /data1/www/nginx/mime.types

types {
    text/html                             html htm shtml;
    text/css                              css;
    text/xml                              xml;
    image/gif                             gif;
    image/jpeg                            jpeg jpg;
    application/javascript                js;
    application/atom+xml                  atom;
    application/rss+xml                   rss;

    text/mathml                           mml;
    text/plain                            txt;
    text/vnd.sun.j2me.app-descriptor      jad;
    text/vnd.wap.wml                      wml;
    text/x-component                      htc;

    image/png                             png;
    image/tiff                            tif tiff;
    image/vnd.wap.wbmp                    wbmp;
    image/x-icon                          ico;
    image/x-jng                           jng;
    image/x-ms-bmp                        bmp;
    image/svg+xml                         svg svgz;
    image/webp                            webp;

    application/font-woff                 woff;
    application/java-archive              jar war ear;
    application/json                      json;
    application/mac-binhex40              hqx;
    application/msword                    doc;
    application/pdf                       pdf;
    application/postscript                ps eps ai;
    application/rtf                       rtf;
    application/vnd.apple.mpegurl         m3u8;
    application/vnd.ms-excel              xls;
    application/vnd.ms-fontobject         eot;
    application/vnd.ms-powerpoint         ppt;
    application/vnd.wap.wmlc              wmlc;
    application/vnd.google-earth.kml+xml  kml;
    application/vnd.google-earth.kmz      kmz;
    application/x-7z-compressed           7z;
    application/x-cocoa                   cco;
    application/x-java-archive-diff       jardiff;
    application/x-java-jnlp-file          jnlp;
    application/x-makeself                run;
    application/x-perl                    pl pm;
    application/x-pilot                   prc pdb;
    application/x-rar-compressed          rar;
    application/x-redhat-package-manager  rpm;
    application/x-sea                     sea;
    application/x-shockwave-flash         swf;
    application/x-stuffit                 sit;
    application/x-tcl                     tcl tk;
    application/x-x509-ca-cert            der pem crt;
    application/x-xpinstall               xpi;
    application/xhtml+xml                 xhtml;
    application/xspf+xml                  xspf;
    application/zip                       zip;

    application/octet-stream              bin exe dll;
    application/octet-stream              deb;
    application/octet-stream              dmg;
    application/octet-stream              iso img;
    application/octet-stream              msi msp msm;

    application/vnd.openxmlformats-officedocument.wordprocessingml.document    docx;
    application/vnd.openxmlformats-officedocument.spreadsheetml.sheet          xlsx;
    application/vnd.openxmlformats-officedocument.presentationml.presentation  pptx;

    audio/midi                            mid midi kar;
    audio/mpeg                            mp3;
    audio/ogg                             ogg;
    audio/x-m4a                           m4a;
    audio/x-realaudio                     ra;

    video/3gpp                            3gpp 3gp;
    video/mp2t                            ts;
    video/mp4                             mp4;
    video/mpeg                            mpeg mpg;
    video/quicktime                       mov;
    video/webm                            webm;
    video/x-flv                           flv;
    video/x-m4v                           m4v;
    video/x-mng                           mng;
    video/x-ms-asf                        asx asf;
    video/x-ms-wmv                        wmv;
    video/x-msvideo                       avi;
}

新增fast_cig: vim /data1/www/nginx/fastcgi_params

fastcgi_param  QUERY_STRING       $query_string;
fastcgi_param  REQUEST_METHOD     $request_method;
fastcgi_param  CONTENT_TYPE       $content_type;
fastcgi_param  CONTENT_LENGTH     $content_length;

fastcgi_param  SCRIPT_NAME        $fastcgi_script_name;
fastcgi_param  REQUEST_URI        $request_uri;
fastcgi_param  DOCUMENT_URI       $document_uri;
fastcgi_param  DOCUMENT_ROOT      $document_root;
fastcgi_param  SERVER_PROTOCOL    $server_protocol;
fastcgi_param  REQUEST_SCHEME     $scheme;
fastcgi_param  HTTPS              $https if_not_empty;

fastcgi_param  GATEWAY_INTERFACE  CGI/1.1;
fastcgi_param  SERVER_SOFTWARE    nginx/$nginx_version;

fastcgi_param  REMOTE_ADDR        $remote_addr;
fastcgi_param  REMOTE_PORT        $remote_port;
fastcgi_param  SERVER_ADDR        $server_addr;
fastcgi_param  SERVER_PORT        $server_port;
fastcgi_param  SERVER_NAME        $server_name;

# PHP only, required if PHP was built with --enable-force-cgi-redirect
fastcgi_param  REDIRECT_STATUS    200;

vim /data1/www/nginx/nginx.conf

user  www;
worker_processes  5;

error_log  logs/nginx-error.log;
pid        nginx/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';
    client_body_temp_path /tmp/client_body_temp_path;
    fastcgi_temp_path /tmp/fastcgi_temp_path;
    proxy_temp_path /tmp/proxy_temp_path;
    scgi_temp_path /tmp/scgi_temp;
    uwsgi_temp_path /tmp/uwsgi_temp_path;

    sendfile        on;
    keepalive_timeout  65;
    gzip  on;
    include vhost/*.conf;
}

配置文件检测

/usr/local/nginx/sbin/nginx -c /data1/www/nginx/nginx.conf -p /data1/www -t

新增项目配置: vim /data1/www/nginx/vhost/mydemo.com.conf

server {
         listen       80 ;
         root /data1/www/app/www.mydemo.com/;
         server_name  www.mydemo.com mydemo.com;

         access_log   logs/nginx_www.mydemo.com-access_log  main;
         error_log    logs/nginx_www.mydemo.com-error_log;
         rewrite  "^/(.*)" /index.php/$1 last;

         location  / {
                   proxy_ignore_client_abort on;
                   fastcgi_pass 127.0.0.1:9023;
                   fastcgi_index index.php;
                   fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
                   #fastcgi_param  SCRIPT_URL         $script_uri;
                   #fastcgi_param  REQUEST_ID           $request_uid;
                   include fastcgi_params;
         }
}

启动nginx:

/usr/local/nginx/sbin/nginx -c /data1/www/nginx/nginx.conf -p /data1/www

平滑重启

Kill -HUP  ${nginx_pid}

四、安装php-fpm

yum -y install gd-devel zlib-devel libjpeg-devel libpng-devel libiconv-devel freetype-devel libxml2 libxml2-devel openssl openssl-devel curl-devel libxslt-devel libmcrypt-devel mhash mcrypt
wget http://am1.php.net/get/php-7.2.0.tar.bz2/from/this/mirror ;
tar -jxvf mirror;
cd php-7.2.0;
./configure  --prefix=/usr/local/php --enable-fpm --enable-cli --enable-pcntl --with-curl;
make && make install; 

新增配置文件: vim /data1/www/php/php-fpm.conf

[global]
pid = php/php-fpm.pid
error_log = logs/php-fpm.log
emergency_restart_threshold = 20
emergency_restart_interval = 60s
process_control_timeout = 0
process.max = 2048
daemonize = yes
rlimit_files = 65535
rlimit_core = 67108864
events.mechanism = epoll

; auto include phpfpm configure
include = php/fpm.d/*.conf

vim /data1/www/php/php.ini

[PHP]
engine = On
short_open_tag = Off
precision = 14
output_buffering = 4096
zlib.output_compression = Off
implicit_flush = Off
unserialize_callback_func =
serialize_precision = -1
disable_functions =
disable_classes =
zend.enable_gc = On
expose_php = On
max_execution_time = 30
max_input_time = 60
memory_limit = 128M
error_reporting = E_ALL
display_errors = On
display_startup_errors = On
log_errors = On
log_errors_max_len = 1024
ignore_repeated_errors = Off
ignore_repeated_source = Off
report_memleaks = On
html_errors = On
variables_order = "GPCS"
request_order = "GP"
register_argc_argv = Off
auto_globals_jit = On
post_max_size = 8M
auto_prepend_file =
auto_append_file =
default_mimetype = "text/html"
default_charset = "UTF-8"
doc_root =
user_dir =
enable_dl = Off
file_uploads = On
upload_max_filesize = 2M
max_file_uploads = 20
allow_url_fopen = On
allow_url_include = Off
default_socket_timeout = 60
[CLI Server]
cli_server.color = On
[Date]
[filter]
[iconv]
[intl]
[sqlite3]
[Pcre]
[Pdo]
[Pdo_mysql]
pdo_mysql.cache_size = 2000
pdo_mysql.default_socket=
[Phar]
[mail function]
SMTP = localhost
smtp_port = 25
mail.add_x_header = On
[ODBC]
odbc.allow_persistent = On
odbc.check_persistent = On
odbc.max_persistent = -1
odbc.max_links = -1
odbc.defaultlrl = 4096
odbc.defaultbinmode = 1
[Interbase]
ibase.allow_persistent = 1
ibase.max_persistent = -1
ibase.max_links = -1
ibase.timestampformat = "%Y-%m-%d %H:%M:%S"
ibase.dateformat = "%Y-%m-%d"
ibase.timeformat = "%H:%M:%S"
[MySQLi]
mysqli.max_persistent = -1
mysqli.allow_persistent = On
mysqli.max_links = -1
mysqli.cache_size = 2000
mysqli.default_port = 3306
mysqli.default_socket =
mysqli.default_host =
mysqli.default_user =
mysqli.default_pw =
mysqli.reconnect = Off
[mysqlnd]
mysqlnd.collect_statistics = On
mysqlnd.collect_memory_statistics = On
[OCI8]
[PostgreSQL]
pgsql.allow_persistent = On
pgsql.auto_reset_persistent = Off
pgsql.max_persistent = -1
pgsql.max_links = -1
pgsql.ignore_notice = 0
pgsql.log_notice = 0
[bcmath]
bcmath.scale = 0
[browscap]
[Session]
session.save_handler = files
session.use_strict_mode = 0
session.use_cookies = 1
session.use_only_cookies = 1
session.name = PHPSESSID
session.auto_start = 0
session.cookie_lifetime = 0
session.cookie_path = /
session.cookie_domain =
session.cookie_httponly =
session.serialize_handler = php
session.gc_probability = 1
session.gc_divisor = 1000
session.gc_maxlifetime = 1440
session.referer_check =
session.cache_limiter = nocache
session.cache_expire = 180
session.use_trans_sid = 0
session.sid_length = 26
session.trans_sid_tags = "a=href,area=href,frame=src,form="
session.sid_bits_per_character = 5
[Assertion]
zend.assertions = 1
[COM]
[mbstring]
[gd]
[exif]
[Tidy]
tidy.clean_output = Off
[soap]
soap.wsdl_cache_enabled=1
soap.wsdl_cache_dir="/tmp"
soap.wsdl_cache_ttl=86400
soap.wsdl_cache_limit = 5
[sysvshm]
[ldap]
ldap.max_links = -1
[dba]
[opcache]
[curl]
[openssl]

新增项目配置:

vim /data1/www/php/fpm.d/mydemo.com.conf

 [mydemo.com]
user = www
group = www
listen = 127.0.0.1:9023
listen.allowed_clients = 127.0.0.1
pm = dynamic
pm.max_children = 512
pm.start_servers = 5
pm.min_spare_servers = 4
pm.max_spare_servers = 64
pm.max_requests = 1500

;pm.status_path = /dpool_monitor


slowlog = logs/$pool-slow_log
request_slowlog_timeout = 2

request_terminate_timeout = 30
catch_workers_output = no
security.limit_extensions = ""

access.log=logs/php-fpm_$pool.access.log
access.format = "%R - %u %t "%m %r%Q%q" %s %f %{mili}d %{kilo}M %C%%"

启动命令:

/usr/local/php/sbin/php-fpm -c /data1/www/php/php.ini  -y /data1/www/php/php-fpm.conf  -p /data1/www

平滑重启:

kill -USR2  fpm-pid