Ansible服务部署与使用-Ansible介绍

第2章 Ansible软件介绍

  • python 语言是运维人员必须会的语言
  • ansible 是一个基于python 开发的自动化运维工具
  • 其功能实现基于ssh远程连接服务
  • ansible 可以实现批量系统配置,批量软件部署,批量文件拷贝,批量运行命令等功能

除了ansible之外,还有saltstack 等批量管理软件

2.1 自动化批量管理方式说明

2.1.1 ssh+key方式的说明

免密码登录验证是单向的,方向从私钥(钥匙) >==> 公钥(锁)

SSH免密码登录基于用户的,最好不要跨不同的用户

SSH连接慢解决;即修改sshd_config配罝文件参数信息

批量分发1000台初始都需要输入一次密码,并且第一次连接要确认(expect/sshpass)

expect批量管理服务器参考 http://www.linuxidc.com/Linux/2017-10/148048.htm

2.1.2 企业级生产场景批量管理-自动化管理方案

①.最简单/最常用/最强大的选择是ssh key+shell/pssh方案,一般中小型企业会用(50-100台以下规模企业)

a.利用ssh key执行命令,并将命令放在脚本里面

b.利用ssh key执行命令,将命令放在脚本里面,并加上相应循环语句或判断语句

②.sina cfengine/puppet较早的批量管理工具;现在基本上没有企业用

③.门户级别比较流行的,puppet批量管理工具(复杂/笨重)

④.saltstack批量管理工具;特点:简单,功能强大(配罝复杂>—赶集网/小米/一些CDN公司 批量管理路线:ssh key–>cfengine–>puppet–>saltstack/ansible

PS:使用ansible软件的前提是ssh key公钥分发充成

2.1.3 如何完成成集群规模架构一键自动化实现(步骤说明)

①.1台服务器先配置好(kickstart,cobbler无人值守安装)。高级实现云计算(按需分配,动态调整)(openstack,kvm)

②.linux基本优化,包括ssh服务(可以自动化实现)。

创建密钥信息(自动化免交互创建)

ssh-keygen -t dsa -P "" -f ~/.ssh/id_dsa >/dev/null 2>&1

进行批量分发密钥(sshpass,expect自动化实现)

⑤.ansible软件安装(可以自动化实现)

⑥.网络服务自动化安装(ansible实现)

(搭建yum仓库,定制rpm包)

2.2 ansible软件特点概述

  • 不需要单独安装客户端(no agents),基于系统自带的sshd服务,sshd就相当于ansible的客户端

  • 不需要服务端(no sever)

  • 需要依靠大量的模块实现批量管理

  • 配置文件 /etc/ansible/ansible.cfg (前期不用配置)

ansible软件相关参考链接信息

http://docs.ansible.com/ansible/intro_installation.html

http://www.ansible.com.cn/

http://docs.ansible.com/modules_by_category.html

http://www.ansible.cn/docs/

2.2.1 ansible软件中查看模块相关信息方法

[root@m01 ~]# ansible-doc -l

列出所有模块信息

[root@m01 ~]# ansible-doc -s cron 

参看指定模块的帮助

2.3 部署ansible软件

2.3.1 第一个里里程碑:部署ssh+key免密码登录方式

参见第一章内容

2.3.2 第二个里程碑:被管理端安装ansible相关管理软件

[root@m01 ~]# yum install libselinux-python -y

该软件是用来对selinux进行设置的,确保即使服务器selinux服务开启,依旧能够通过ansible 软件管理。

2.3.3 第三个里程碑:管理端安装ansible软件,配置hosts文件

[root@m01 ~]# yum install ansible -y

软件安装完成,进行修改ansible下的hosts文件,注意文件的路径

[root@m01 ~]# vim /etc/ansible/hosts
[linuxidc]
172.16.1.31
172.16.1.41
172.16.1.8

文件信息说明:

  • 中括号中的名字代表组名

  • 主机(hosts)部分可以使用域名、主机名、IP地址表示;一般此类配置中多使用IP地址;

  • 组名下的主机地址就是ansible可以管理的地址

至此ansible 服务就部署完成 ↑

2.4 查看ansible软件相关信息

2.4.1 ansible实践部署地址规划

未分类

2.4.2 ansible软件的版本信息

[root@m01 ~]# ansible --version
ansible 2.3.2.0
  config file = /etc/ansible/ansible.cfg
  configured module search path = Default w/o overrides
  python version = 2.6.6 (r266:84292, Aug 18 2016, 15:13:37) [GCC 4.4.7 20120313 (Red Hat 4.4.7-17)]

2.4.3 软件目前主要会用到的文件

[root@m01 ~]# rpm -ql ansible
/etc/ansible/hosts            #定义anisble软件可以管理的主机信息
/usr/bin/ansible              #ansible执行命令
/usr/bin/ansible-playboot   # ansible执行剧本命令

2.4.4 /etc/ansible下的文件

[root@m01 ansible]# ll
total 28
-rw-r--r-- 1 root root 18066 Sep  6 06:38 ansible.cfg  #ansible配置文件
-rw-r--r-- 1 root root  1016 Sep  6 06:38 hosts       #定义ansible可以管理的主机信息
drwxr-xr-x 2 root root  4096 Sep  6 06:38 roles   #主要在自动化的时候部署多台主机时使用

2.5 ansible软件的使用/参数

2.5.1 ansible远程批量执行命令

语法:

ansible linuxidc -a "uptime"

ansible linuxidc -m command -a "uptime"

ansible 定义的组/单个ip/域名/all  -m command -a "uptime"

说明:

-m 指定使用的模块

-a 指定使用模块中相应的命令参数

命令参数只能是基本命令,并不支持管道操作

all 为hosts文件中的组全部管理

未分类
图2-1 ansible命令语法格式示意图

2.5.2 未分发公钥如何实现远程管理主机及指定ansible端口信息

配置hosts文件时配置上密码

vim /etc/ansible/hosts
[linuxidc]
172.16.1.31:52113  ansible_ssh_user=root ansible_ssh_pass=123456
172.16.1.41
172.16.1.8

IP:端口 用户 密码

[linuxidc]
www.linuxidc.com:52113 ansible_ssh_user=linuxidc

指定端口 用户名

测试修改端口后的结果 使用ping 模块

[root@m01 ~]# ansible linuxidc -m ping
www.linuxidc.com | SUCCESS => {
    "changed": false,
    "ping": "pong"
}

2.6 ansible软件常用参数表

未分类

2.6.1 ansible命令执行结果色彩说明

绿色:表示没有发生任何改变

红色:执行命令操作出现异常

黄色:执行命令后,对受控主机产生影响,发生了配置改变

Ansible服务部署与使用-Ansible使用前提

第1章 SSH+Key实现基于密钥连接(Ansible使用前提)

说明:

Ansible其功能实现基于SSH远程连接服务

使用Ansible需要首先实现SSH密钥连接

1.1 部署SSH Key

1.1.1 第一个里程碑: 创建密钥对

ssh-keygen

-t 指定密钥类型 rsa1 dsa(常用) ecdsa

语法:

SYNOPSIS
     ssh-keygen [-q] [-b bits] -t type [-N new_passphrase] [-C comment]
                [-f output_keyfile]
     ssh-keygen -p [-P old_passphrase] [-N new_passphrase] [-f keyfile]
     ssh-keygen -i [-f input_keyfile]
     ssh-keygen -e [-f input_keyfile]
     ssh-keygen -y [-f input_keyfile]
     ssh-keygen -c [-P passphrase] [-C comment] [-f keyfile]
     ssh-keygen -l [-f input_keyfile]
     ssh-keygen -B [-f input_keyfile]
     ssh-keygen -D pkcs11
     ssh-keygen -F hostname [-f known_hosts_file] [-l]
     ssh-keygen -H [-f known_hosts_file]
     ssh-keygen -R hostname [-f known_hosts_file]
     ssh-keygen -r hostname [-f input_keyfile] [-g]
     ssh-keygen -G output_file [-v] [-b bits] [-M memory] [-S start_point]
     ssh-keygen -T output_file -f input_file [-v] [-a num_trials]
                [-W generator]
     ssh-keygen [-n] [-D smartcard]
     ssh-keygen -s ca_key -I certificate_identity [-h] [-Z principals]
                [-O option] [-V validity_interval] [-z serial_number] file ...
     ssh-keygen -L [-f input_keyfile]

创建密钥的过程

[root@m01 ~]# ssh-keygen -t dsa
Generating public/private dsa key pair.
Enter file in which to save the key (/root/.ssh/id_dsa):  #私钥创建后保存的路径
Created directory '/root/.ssh'.
Enter passphrase (empty for no passphrase):             #私钥需不需进行加密,设置密码
Enter same passphrase again:   #私钥需不需进行加密,再次输入密码确认
Your identification has been saved in /root/.ssh/id_dsa.
Your public key has been saved in /root/.ssh/id_dsa.pub.
The key fingerprint is:
31:4a:4f:9f:97:b0:b6:ca:4c:53:78:70:89:83:5f:16 root@m01
The key's randomart image is:
+--[ DSA 1024]----+
|          E      |
|       . . o     |
|      o B *      |
|     . = @ + .   |
|      . S B o    |
|         + o     |
|        o .      |
|       + o       |
|        +        |
+-----------------+

创建出来的文件:

[root@m01 ~]# ll /root/.ssh/
total 8
-rw------- 1 root root 668 Oct 17 18:55 id_dsa       #创建出来的私钥
-rw-r--r-- 1 root root 598 Oct 17 18:55 id_dsa.pub  #创建出来的公钥

1.1.2 第二个里程碑: 分发公钥文件

[root@m01 ~]# man ssh-copy-id
ssh-copy-id  -  install  your  public  key in a remote machine’s autho-rized_keys

注意:密钥分发命令属于openssh-clients软件包

[root@nfs01 ~]# rpm -qf `which ssh-copy-id`
openssh-clients-5.3p1-122.el6.x86_64

语法格式

ssh-copy-id [-i [identity_file]] [user@]machine

-i 指定要分发的公钥文件以及路径信息
[user@] 以什么用户身份进行分发
machine 将公钥分发到哪台主机上,远程主机IP地址

[root@m01 ~]# ssh-copy-id  -i /root/.ssh/id_dsa.pub  [email protected]
The authenticity of host '172.16.1.41 (172.16.1.41)' can't be established.
RSA key fingerprint is d3:41:bb:0d:43:88:da:a3:2c:e8:36:91:11:c9:e4:9c.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '172.16.1.41' (RSA) to the list of known hosts.
[email protected]'s password:
Now try logging into the machine, with "ssh '[email protected]'", and check in

  .ssh/authorized_keys

to make sure we haven't added extra keys that you weren't expecting. 

1.1.3 第三个里程碑: 基于密钥登陆测试

[root@m01 ~]# ssh 172.16.1.41
Last login: Tue Oct 17 18:38:47 2017 from 10.0.0.1
[root@backup ~]#

基于密钥登陆方式成功↑

[root@m01 ~]# ssh [email protected] "hostname -i"
172.16.1.41

不用的登陆到远程主机直接执行命令,返回输出结果↑

说明:

管理主机一旦创建好秘钥对文件,给多个主机分发公钥时,公钥文件相同

1.1.4 ssh服务分发公钥实质执行过程

①. 管理服务器创建私钥和公钥(密钥对)

②. 将公钥文件远程传送复制到被管理服务器相应用户~/.ssh/id_dsa.pub下,并修改.ssh目录权限为700

③. 修改公钥文件文件名称为authorized_keys,授权权限为600

④. 利用ssh服务配置文件的配置参数,进行识别公钥文件authorized_keys

⑤. 进而实现基于密钥远程登录服务器(免密码登录/非交互方式登录)

1.2 默认端口号不是22,如何分发公钥

1.2.1 查询ssh-copy-id命令可以得知这是个脚本文件

[root@m01 ~]# file `which ssh-copy-id `
/usr/bin/ssh-copy-id: POSIX shell script text executable

看看脚本内容发现传输方式

[root@m01 ~]# cat `which ssh-copy-id`|grep ssh
ssh $1 "exec sh -c 'cd; umask 077; test -d .ssh || mkdir .ssh ; cat >> .ssh/authorized_keys && (test -x /sbin/restorecon && /sbin/restorecon .ssh .ssh/authorized_keys >/dev/null 2>&1 || true)'" || exit 1

说明:

1、切换用户到家目录下,临时设置umask值

2、判断客户端相应用户中有没有.ssh目录,如果没有.ssh 目录就进行创建

3、将管理端公钥文件内容添加到客户端~./ssh/authorized_keys, 默认authorized_keys文件不存在,需要创建,文件权限600

1.2.2 实现非22端口的分发

方法一: 修改脚本内容

ssh -p52113 $1 "exec sh -c 'cd; umask 077; test -d .ssh || mkdir .ssh ; cat >> .ssh/authorized_keys && (test -x /sbin/restorecon && /sbin/restorecon .ssh .ssh/authorized_keys >/dev/null 2>&1 || true)'" || exit 1

说明:根据命令脚本,修改$1传参信息,从而实现根据ssh不同端口传送公钥文件

方法二:将传入的参数上添加上端口信息(推荐)

[root@m01 scripts]# ssh-copy-id -i /root/.ssh/id_dsa.pub "-p 52113 [email protected]"
Now try logging into the machine, with "ssh '-p 52113 [email protected]'", and check in:

  .ssh/authorized_keys

to make sure we haven't added extra keys that you weren't expecting.

1.2.3 关于 /usr/bin/ssh-copy-id 脚本中 $1的说明

1.2.3.1 编写脚本shift

[root@m01 scripts]# cat shift.sh
#!/bin/bash

until [ $# -eq 0 ]
do
echo $*
shift
done

测试

[root@m01 scripts]# sh shift.sh 1 2 3 4 5 6
1 2 3 4 5 6
2 3 4 5 6
3 4 5 6
4 5 6
5 6
6

说明:

shift命令用于对参数的移动(左移),通常用于在不知道传入参数个数的情况下依次遍历每个参数然后进行相应处理(常见于Linux中各种程序的启动脚本)。

ssh-copy-id -i /root/.ssh/id_dsa.pub "-p 52113 [email protected]"

由于/usr/bin/ssh-copy-id 脚本中前面使用了两个shift 所有原本该为的参数变为了 3的参数变为了 1.

if [ "-i" = "$1" ]; then
  shift
  # check if we have 2 parameters left, if so the first is the new ID file
  if [ -n "$2" ]; then
    if expr "$1" : ".*.pub" > /dev/null ; then
      ID_FILE="$1"
    else
      ID_FILE="$1.pub"
    fi
    shift         # and this should leave $1 as the target name
  fi
else

1.3 实现自动分发公钥,远程管理多台主机

1.3.1 【预备知识】shell中三种循环

#for 循环

for n in (1..100)
do
      xxx
done

#while循环:循环条件为真时,一直循环;为假时,停止循环

while [ture]
do
      xxx
done

#until 循环: 循环条件为假时,一直循环;为真时,停止循环

until [ture]
do
   xxx
done

1.3.2 实现自动分发公钥,远程管理多台主机的阻碍因素?

01.创建秘钥对需要进行交互

a.需要确认秘钥保存路径

b.需要确认密码信息

02.分发公钥时需要进行交互

a.需要进行确认yes|no

b.第一次分发公钥需要进行密码认证

1.3.3 解决阻碍因素

  • 自动保存路径,并且不密码
ssh-keygen -t rsa -f ~/.ssh/id_rsa -N "" -q

参数说明:

-f filename    Specifies the filename of the key file.

指定密钥文件保存的路径信息(免交互)

-P passphrase      Provides the (old) passphrase.

提供一个密码信息

-N new_passphrase      Provides the new passphrase.

-P -N 都是免交互方式指定密码信息

-q 安静的 不输出信息,减少信息输出

  • 解决分发公钥时需要进行的交互
sshpass -p123456 ssh-copy-id -i ~/.ssh/id_rsa.pub " [email protected].$ip  -o StrictHostKeyChecking=no "

参数说明:

-o option 选择 (man 手册中可以查到有很多选项)
StrictHostKeyChecking=no 对询问的回应(不进行对密钥检查)
要实现免密码,需要一款软件 sshpass 该软件就是为ssh提供密码使用的

[root@m01 ~]# yum install  sshpass  -y

注意:密码与 -p之间不能有空格

1.3.4 最终批量分发脚本内容

[root@m01 scripts]# vim ssh-key.sh 
#!/bin/bash
. /etc/rc.d/init.d/functions

# 创建密钥
rm ~/.ssh/id_rsa* -f
ssh-keygen -t rsa -f ~/.ssh/id_rsa -N "" -q
# 分发公钥
for ip in 31 41 8
do
sshpass -p123456 ssh-copy-id -i ~/.ssh/id_rsa.pub " [email protected].$ip  -o StrictHostKeyChecking=no " &>/dev/null
if [ $? -eq 0 ];then
action  "fenfa 172.16.1.$ip"  /bin/true
else
action  "fenfa 172.16.1.$ip"  /bin/false
fi
echo ""
done

脚本执行效果:

[root@m01 scripts]# sh ssh-key.sh
fenfa 172.16.1.31                                          [  OK  ]
fenfa 172.16.1.41                                          [  OK  ]
fenfa 172.16.1.8                                           [  OK  ]

说明:

脚本中引用 . /etc/rc.d/init.d/functions 函数,可以显示执行结果的判断。

使用if语句进行判断,action 执行相应的动作。true/false

1.3.5 实现基于密钥的批量管理脚本

[root@m01 scripts]# vim piliang_guanli.sh 
#!/bin/bash
CMD=$1

for ip in 8 31 41
do
echo ========host 172.16.1.$ip=======
ssh [email protected].$ip "$CMD"
echo ============END===============
echo ""
done

脚本执行效果:

[root@m01 scripts]# sh piliang_guanli.sh  date
======172.16.1.8======
Thu Oct 19 16:25:08 CST 2017
=========END=============
======172.16.1.31======
Thu Oct 19 16:25:08 CST 2017
=========END=============
======172.16.1.41======
Thu Oct 19 16:25:08 CST 2017
=========END=============

基于密钥登陆方式,分发的公钥文件会识别用户信息,所以能够实现免密码批量管理。

Gitlab 安装配置管理实例

一、安装gitlab服务

因为github在美国有点慢,连接和推送不方便。国内众多的代码管理平台也是非常的不错,例如:coding,码云,码市等。但是有些企业为了方便自己去搭建一个基于web界面的代码管理平台gitlab!

建议后期搭建Gitlab平台,一定要让其服务独立运行在一台机器上,两方面: ①机器比较耗费硬件资源。 ②一旦出现问题维护起来困难比较大,为了不造成冲突!

二、安装配置

yum install -y curl policycoreutils-python openssh-server openssh-clients

yum install postfix

systemctl enable postfix

systemctl start postfix

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

EXTERNAL_URL="http://gitlab.example.com" yum install -y gitlab-ce

gitlab-ctl reconfigure      //因为数据包比较大 所以需要安装一会(安装完毕之后会自动启动相关服务)

虽然说安装比较容易,但是不建议安装gitlab的服务再次安装其它服务,因为后期的维护成本很高!

养成好的习惯,定期去备份数据!!!

netstat -lnpt  //查看监听端口

gitlab-ctl stop/restart/start/status        //启动,停止,重启

[root@zhdy01 src]# netstat -lntp
tcp        0      0 127.0.0.1:9168          0.0.0.0:*               LISTEN      5076/ruby 

从服务端口我们可以看出,安装gitlab默认帮我们安装了Redis logrotate nginx 等

[root@zhdy01 src]# free -h
              total        used        free      shared  buff/cache   available
Mem:           1.8G        1.5G         79M         28M        197M         65M
Swap:          1.9G        109M        1.8G

硬件资源占用的不少,所以官方建议我们至少需要内存4G。

2.1 登录GitLab

浏览器访问gitlab,输入ip即可。

一定要先关闭iptables规则和firewall以及selinux规则!

第一次登录,一定要确保本机器没有存在nginx以及redis服务。有的话关闭!

第一次登录会先让你创建一个长度不低于8位字符的密码。

默认管理员root,你自己创建的密码

登录后的界面:

未分类

2.2 登录GitLabgitlab常用命令

再启动服务:

gitlab-ctl start

2.3 Gitlab基础命令操作:

在现实的运维工作中,我们一般都是用nginx搞个代理,当我们输入公网的域名就可以解析到本地的gitlab web页面。肯定不是简简单单的一个ip地址!

因为安装gitlab服务自动帮我们安装了nginx,也许你会有疑问,在那个位置呢?

[root@zhdy01 ~]# vim /var/opt/gitlab/nginx/conf/nginx.conf

如果你需要修改监听端口或者绑定域名就要用到:

[root@zhdy01 ~]# vim /var/opt/gitlab/nginx/conf/gitlab-http.conf

未分类

在开始之前,我们先创建一个group,并设置组的是私有的还是public的,也可以添加组员,并创建相对应的project。

未分类

未分类

当我们创建好了之后,会出现如下:(是不是和Git很相似?)但是如上提示,需要我们增加一个SSH key。这样我们才可以连接并克隆!

未分类

点击如下各个位置去添加ssh key

未分类

作为一个运维,我们最常用的就是,创建用户,创建组,设置一个新的project。

未分类

当我们创建了一个用户,密码会直接发送一封邮件,里面就有设置密码的连接,如果用户想着直接让你创建,当我们完成之后,点击右上角的编辑即可再次编辑!然后用户首次登陆自己的账号会提示输入当前密码和修改一个密码!

载入配置服务(初始化和修改/etc/gitlab/gitlab.rb 后需要重新载入)

sudo gitlab-ctl reconfigure

启动服务

sudo gitlab-ctl start

停止服务

sudo gitlab-ctl stop

重启服务

sudo gitlab-ctl restart

检查服务的日志信息:

检查redis的日志

sudo gitlab-ctl tail redis

检查postgresql的日志

sudo gitlab-ctl tail postgresql

检查gitlab-workhorse的日志

sudo gitlab-ctl tail gitlab-workhorse

检查logrotate的日志

sudo gitlab-ctl tail logrotate

检查nginx的日志

sudo gitlab-ctl tail nginx

检查sidekiq的日志

sudo gitlab-ctl tail sidekiq

检查unicorn的日志

sudo gitlab-ctl tail unicorn

检查服务状态

sudo gitlab-ctl status

三、gitlab 备份和恢复

3.1 备份

gitlab-rake gitlab:backup:create

备份目录在

[root@zhdy01 ~]# ls /var/opt/gitlab/backups
1509073999_2017_10_27_10.1.0_gitlab_backup.tar

gitlab 恢复

恢复的时候如果你的版本是9是不可以直接恢复到10版本里面去的,解决方法先升级9到10,然后备份,再次导入即可!

先停服务

gitlab-ctl stop unicorn ; gitlab-ctl stop sidekiq

再次恢复

gitlab-rake gitlab:backup:restore BACKUP=xxxxx

(这里是一个编号,即备份文件的前缀)输入两次 yes 即可 恢复!!

docker镜像搭建gitlab服务

利用docker镜像搭建gitlab服务。

1、创建gitlab服务:

docker run –detach –hostname gitlab.example.com –publish 6443:443 –publish 8083:80 –publish 622:22 –name gitlab –restart always –volume /home/opt/gitlab/config:/etc/gitlab –volume /home/opt/gitlab/logs:/var/log/gitlab –volume /home/opt/gitlab/data:/var/opt/gitlab gitlab/gitlab-ce

等待docker启动正常

2、配置gitlab服务器的访问地址

按照上面的方式,让gitlab容器运行起来是没有问题的,但是当在gitlab上创建项目的时候,生成项目的URL访问地址是按容器的hostname来生成的,即容器的id。作为gitlab服务器,当然是需要一个固定的URL访问地址,于是需要配置gitlab.rb(宿主机上的路径为:/home/opt/gitlab/config/gitlab.rb)配置文件里面的参数, 162.3.160.60是你宿主机的ip。

配置http协议所使用的访问地址

external_url ‘http://162.3.160.60:8083’

配置ssh协议所使用的访问地址和端口

gitlab_rails[‘gitlab_ssh_host’] = ‘162.3.160.60’
gitlab_rails[‘gitlab_shell_ssh_port’] = 622

为了方便,这里直接用宿主机ip来指定。ssh默认使用的端口号是22,但是为了避开与宿主机22端口的冲突,这里用了622。在修改的过程中,一定要去掉配置项前面的#,配置才能生效,docker restart 重启gitlab容器

3、我们做了端口映射,可以输入http://node_ip:8083进行页面访问

未分类

4、第一次登录,设置管理员的密码

未分类

5、注册一个用户

未分类

6、创建一个组

未分类

7、创建一个工程

未分类

8、配置ssh key

未分类

你PC机,进入git bash,获取得到id_rsa.pub 密钥,加入到上图中

未分类

9、clone 代码

未分类

至此,gitlab搭建成功,并且能够正常使用。

gitlab API使用批量创建用户

gitlab有api的接口,网上搜索了一下使用的情况,貌似不多,找到的文章主要是用来批量操作用户。

下面就这个批量创建用户来测试一下

获取Access Token

未分类

【Settings】

未分类

【Access Tokens】

最后点击创建

之后会出现Access Token

未分类

我这里的Access Token为PknmemyqpPumLsKq_ytW,记录一下,下面的sh脚本里要使用

批量创建用户脚本

创建userinfo.txt

12345678 [email protected] test1 张三
12345678 [email protected] test2 李四

对应的列分别是密码,邮箱,gitlab用户名,别名,一行对应一个用户

创建gitlabAddUser.sh

#!/bin/bash
#gitlab用户文本
userinfo="userinfo.txt"
while read line 
do
    password=`echo $line | awk '{print $1}'`
    mail=`echo $line | awk '{print $2}'`
    username=`echo $line | awk '{print $3}'`
    name=`echo $line | awk '{print $4}'`
    curl -d "password=$password&email=$mail&username=$username&name=$name&private_token=PknmemyqpPumLsKq_ytW" "http://gitlab.phpsong.com/api/v4/users"

done <$userinfo

执行脚本

chmod +x gitlabAddUser.sh 
sh gitlabAddUser.sh

之后去gitlab查用户就能看到用户

未分类

用 Docker Compose 部署 PySpider

PySpider 是一个国人编写的强大的网络爬虫系统并带有强大的 WebUI。采用 Python 语言编写,分布式架构,支持多种数据库后端,强大的 WebUI 支持脚本编辑器,任务监视器,项目管理器以及结果查看器。

上面这段是从「PySpider 中文网」摘录的。总而言之,它就是一个 All-in-one 的爬虫系统,比 Scrapy 强的地方,主要就是上手更容易,打开 web 页面就可以开始写爬虫。但「开包即食」这一点,仅限于 demo 阶段,比如在 http://demo.pyspider.org 试用一下。真正到自己用的时候,还是要考虑一个部署的问题。尤其是要充分利用它的分布式架构的时候,怎么部署更是一个避不过去的问题。

我之前做过一个 side project,功能是从国内各大视频网站抓取动漫新番,如果发现更新,就推送通知到 iOS 客户端,iOS 客户端仅展示订阅的动漫列表,观看还需要跳转到各官方应用去。

做这个的动机是现在各大视频网站的版权竞争,导致要追一季新番,不得不来回切换各个视频网站,我又不想打开一堆通知,让它们给我推垃圾信息。所以就搞一个只推送动漫更新的应用吧。

这个项目爬虫端已经完成,iOS 客户端也提交了审核,然而就是审核没有通过,没过的原因有以下三点:

  • 用了一些版权图片
  • 在 webView 预览动漫的时候,某视频网站乱跳红包
  • 审核人员不看动漫,把鸣人的儿子当成了我山寨的一个动漫形象。

后来发现自己已经有点脱宅了,也就没有再去和审核人员争论了,项目就这么流产,和许多其他 side project 一样。

下面是我在做这个 side project 的时候,部署 PySpider 的方案。

Docker + LeanCloud

现在要部署一个 web 项目,用 Docker 已经是首选了,可以节约不少时间。iOS 后端用现成的 LeanCloud 来做,不用写后端代码,又可以节约不少时间。

要用 LeanCloud,需要引入 LeanCloud 的 SDK,而 binux/pyspider 这个 image 并不包含。所以需要自己 build 一个 image 了。方法就是写一个 Dockerfile,内容如下:

FROM binux/pyspider:latest
MAINTAINER suosuopuo <[email protected]>

# include the LeanCloud SDK
RUN pip install leancloud-sdk

然后执行 docker build -t my/pyspider – < Dockerfile,如果需要用到 LeanCloud SDK,只要用 my/pyspider 代替 binux/pyspider 就好了。

数据库和消息队列

尽管最终结果放在 LeanCloud 上,但 PySpider 各个组件运行还是需要数据库支持的。这部分主要参考这个 Deployment of demo.pyspider.org。数据库是 postgresql,消息队列用 redis。

数据库和消息队列手动用 docker 启动,不用 docker-compose 管理,这和 Deployment of demo.pyspider.org 也是一致的。

启动就两条命令:

docker run --name redis -d -p 6379:6379 redis

docker run --name postgres -v /data/postgres/:/var/lib/postgresql/data -d -e POSTGRES_PASSWORD="" postgres

数据库和用户需要手动创建:

docker exec -it postgres bash

然后输入:

psql -U postgres

CREATE USER myname  WITH PASSWORD ‘mypassword’;

CREATE DATABASE taskdb WITH OWNER= myname LC_COLLATE='en_US.utf8' LC_CTYPE='en_US.utf8' ENCODING='UTF8' TEMPLATE=template0;

CREATE DATABASE projectdb WITH OWNER= myname LC_COLLATE='en_US.utf8' LC_CTYPE='en_US.utf8' ENCODING='UTF8' TEMPLATE=template0;

CREATE DATABASE resultdb WITH OWNER= myname LC_COLLATE='en_US.utf8' LC_CTYPE='en_US.utf8' ENCODING='UTF8' TEMPLATE=template0;

Docker Compose

除了数据库和消息队列,其他组件都用 docker-compose 来管理了,
docker-compose.yml 的内容主要参考这个 Running pyspider with Docker,和这个 Deployment of demo.pyspider.org。

主要是让各个组件连接外部的数据库和消息队列,限制一下内存占用,另外设置一个 WebUI 的用户名和密码。Result worker 要使用之前 build 的 image,因为它需要用到 LeanCloud。

然后 docker-compose up -d 就可以启动各组件了。

phantomjs:
  image: binux/pyspider:latest
  command: phantomjs
  mem_limit: 256m
  restart: always
result:
  image: my/pyspider
  external_links:
    - postgres
    - redis
  volumes:
    - ./share:/opt/share
  working_dir: /opt/share
  command: '--taskdb "sqlalchemy+postgresql+taskdb://username:password@postgres/taskdb"  --projectdb "sqlalchemy+postgresql+projectdb://username:password@postgres/projectdb" --resultdb "sqlalchemy+postgresql+resultdb://username:password@postgres/resultdb" --message-queue "redis://redis:6379/1" result_worker --result-cls=resultWorker.VResultWorker'
  mem_limit: 128m
  restart: always
processor:
  image: binux/pyspider:latest
  external_links:
    - postgres
    - redis
  command: '--projectdb "sqlalchemy+postgresql+projectdb://username:password@postgres/projectdb" --message-queue "redis://redis:6379/1" processor'
  mem_limit: 128m
  restart: always
fetcher:
  image: binux/pyspider:latest
  external_links:
    - redis
  links:
    - phantomjs
  command : '--message-queue "redis://redis:6379/1" --phantomjs-proxy "phantomjs:80" fetcher --xmlrpc'
  mem_limit: 128m
  restart: always
scheduler:
  image: binux/pyspider:latest
  external_links:
    - postgres
    - redis
  command: '--taskdb "sqlalchemy+postgresql+taskdb://username:password@postgres/taskdb"  --projectdb "sqlalchemy+postgresql+projectdb://username:password@postgres/projectdb" --resultdb "sqlalchemy+postgresql+resultdb://username:password@postgres/resultdb" --message-queue "redis://redis:6379/1" scheduler'
  restart: always
webui:
  image: binux/pyspider:latest
  external_links:
    - postgres
    - redis
  links:
    - scheduler
    - phantomjs
  command: '--taskdb "sqlalchemy+postgresql+taskdb://username:password@postgres/taskdb"  --projectdb "sqlalchemy+postgresql+projectdb://username:password@postgres/projectdb" --resultdb "sqlalchemy+postgresql+resultdb://username:password@postgres/resultdb" --message-queue "redis://redis:6379/1" webui --need-auth --username ui_username --password ui_password'
  ports:
    - "5000:5000"

ResultWorker

关于 result worker,官方文档并没有给出 demo,我这里贴一下我的 result worker。首先初始化 LeanCloud SDK,每次抓到数据的时候,去 LeanCloud 查询是不是已经存在同名的动漫(一个动漫可以有多个别名)。如果不存在,就创建这个别名,如果已经存在,就继续执行其他的逻辑(简洁起见,不全部贴出了)。

resultWorker.py 放在和 docker-compose.yml 相同的位置,在启动 result worker 的时候已经通过选项指定自定义的 VResultWorker

#!/usr/bin/env python
# -*- encoding: utf-8 -*-
# vim: set et sw=4 ts=4 sts=4 ff=unix fenc=utf8:
# Author: suosuopuo<[email protected]>
#
# Created on 2017-06-15 15:37:46

from pyspider.result import ResultWorker
import leancloud
from datetime import datetime

appKey = ''
appID  = ''

class VResultWorker(ResultWorker):
  def __init__(self, resultdb, inqueue):
    self.resultdb = resultdb
    self.inqueue = inqueue
    self._quit = False

    leancloud.init(appID, appKey)
    leancloud.use_region('CN')

  def on_result(self, task, result):
    if result['type'] == 'anime-update':
      self.handle_anime_update(task, result)

  def handle_anime_update(self, task, result):
    title = result['title']

    try:
      alias_query = leancloud.Query('Alias')
      alias_query.include('anime')
      alias_query.equal_to('title', title)

      alias = alias_query.first()
    except leancloud.LeanCloudError as e:
      if e.code == 101:
        Alias = leancloud.Object.extend('Alias')
        Anime = leancloud.Object.extend('Anime')

        alias = Alias()
        alias.set('title', title)

        anime = Anime()
        anime.set('title', title)
        anime.set('area', result['area'])
        anime.set('cover', result['cover'])
        anime.set('weekday', result['weekday'])
        anime.set('ep_num', 12)
        anime.set('is_finished', result['is_finished'])
        anime.set('verified', False)

        anime.save(fetch_when_save = True)

        alias.set('targetAnime', anime)
        alias.save()
      return

...

还有话说

我是很喜欢这样的「全家桶」式的方案的,可以快速地试验一些想法,但是很遗憾 PySpider 的代码已经很久没有更新了。好在目前为止 PySpider 还足够强大。

我没有解释每一条命令、每一个选项,因为这不是 PySpider 的文档,如果需要更详细的解释,还是需要去挖掘官方文档。

写这篇的时间距离写这个 side project 已经隔了几个月。我也懒到没有去再次验证各个配置和命令,所以「仅供参考」。

另外提醒一下,如果有人也打算用 LeanCloud 做后端,需要注意 LeanCloud 是有访问次数限制的。可以根据抓取的页面特点,用 age, itag等功能减少对 LeanCloud 的访问次数。

不过就算没有访问次数限制,对一个远程服务高频访问,也不是好的策略。

在ubuntu中安装Docker Compose

首先是一个例子,命令:

sudo curl -L https://github.com/docker/compose/releases/download/1.16.1/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose

上面的只是一个例子,需要下载最新的版本,可以去这个网站:

https://github.com/docker/compose/releases

接下来授予权限,命令:

sudo chmod +x /usr/local/bin/docker-compose

最后测试,命令:

$ docker-compose --version
docker-compose version 1.16.1, build 1719ceb

如果出现版本信息,说明安装成功。

以上就是在ubuntu中安装Docker Compose的方法。

logstash笔记(二)——grok之match

官方文档:

https://www.elastic.co/guide/en/logstash/current/plugins-filters-grok.html

基本语法:

%{SYNTAX:SEMANTIC}

SYNTAX:定义的正则表达式名字(系统插件自带的默认位置:$HOME/vendor/bundle/jruby/1.9/gems/logstash-patterns-core-2.0.2/patterns)

SEMANTIC:匹配结果的标识

grok{
  match=>{
    "message"=>"%{IP:clientip}"
  }
}

输入结果

{
  "message" => "192.168.1.1 abc",
  "@version" => "1",
  "@timestamp" => "2016-03-30T02:15:31.242Z",
  "host" => "master",
  "clientip" => "192.168.1.1"
}

clientip就是semantic

每个%{IP:clientip}表达式只能匹配到message中第一次出现的结果,可用如下方式匹配多个相同类型结果

%{IP:clientip}s+%{IP:clientip1}…,如果SEMANTIC定义的相同名字,结果为数组形式,如:

{
  "message" => "12.12.12.12 32.32.32.32",
  "@version" => "1",
  "@timestamp" => "2016-03-30T02:26:31.077Z",
  "host" => "master",
  "clientip" => [
    [0] "12.12.12.12",
    [1] "32.32.32.32"
  ]
}

自定义grok表达式

语法:(?the pattern here)

eg:

grok{
  match=>{
    "message"=>"%{IP:clientip}s+(?<mypattern>[A-Z]+)"
  }
}

rs:

{
  "message" => "12.12.12.12 ABC",
  "@version" => "1",
  "@timestamp" => "2016-03-30T03:22:04.466Z",
  "host" => "master",
  "clientip" => "12.12.12.12",
  "mypattern" => "ABC"
}

创建自定义grok文件

在/home/hadoop/mylogstash/mypatterns_dir创建文件mypatterns_file,内容如下:

MY_PATTERN [A-Z]+

保存!

修改filter

grok{
  patterns_dir=>["/home/hadoop/mylogstash/mypatterns_dir"]
  match=>{
    "message"=>"%{IP:clientip}s+%{MY_PATTERN:mypattern}"
  }
}

结果同上。

logstash解析naxsi日志的问题

目前在用naxsi防火墙,使用elk来做一个日志分析,遇到问题如下:

naxsi作为waf会产生error日志,目前我打开了NAXSI_EXLOG日志选项,因为这个选项可以看到具体的请求内容。

对于同一个请求,naxsi会产生2行或者3行的日志,格式如下:

2017/10/23 17:45:36 [error] 744#0: *19 NAXSI_EXLOG: ip=192.168.141.232&server=192.168.182.141&uri=/sqli-labs/Less-11/&id=1009&zone=BODY&var_name=passwd&content=admin'%20or%20'1'='1'%20xxxxxxxxxx, client: 192.168.141.232, server: _, request: "POST /sqli-labs/Less-11/ HTTP/1.1", host: "192.168.182.141:8000", referrer: "1.1.1.1"
2017/10/23 17:45:36 [error] 744#0: *19 NAXSI_EXLOG: ip=192.168.141.232&server=192.168.182.141&uri=/sqli-labs/Less-11/&id=1013&zone=BODY&var_name=passwd&content=admin'%20or%20'1'='1'%20xxxxxxxxxx, client: 192.168.141.232, server: _, request: "POST /sqli-labs/Less-11/ HTTP/1.1", host: "192.168.182.141:8000", referrer: "1.1.1.1"
2017/10/23 17:45:36 [error] 744#0: *19 NAXSI_FMT: ip=192.168.141.232&server=192.168.182.141&uri=/sqli-labs/Less-11/&learning=0&vers=0.55.3&total_processed=4&total_blocked=4&block=1&cscore0=$SQL&score0=22&cscore1=$XSS&score1=40&zone0=BODY&id0=1009&var_name0=passwd&zone1=BODY&id1=1013&var_name1=passwd, client: 192.168.141.232, server: _, request: "POST /sqli-labs/Less-11/ HTTP/1.1", host: "192.168.182.141:8000", referrer: "1.1.1.1"

这是同一个请求产生的结果,因为每次请求都会有一个id值在里面,这个是19:

未分类

问题:如何取出NAXSI_EXLOG里面的content,跟NAXSI_FMT里面的结果合并到一起?

我写的logstash和正则如下:

DA1 d{4}/d{2}/d{2}
TM1 d{2}:d{2}:d{2}
LEVEL (w+)
NUM1 d+(?:#0: *)
NUM2 d+
EXLOG NAXSI_EXLOG
FMT NAXSI_FMT
ID1 (d+)
ZONE w+
VAR1  (.*)
CONTENT (.*)
T3 w+
T4 HTTP/1.1", host: "(.*)", referrer: "
HOST (.*)

NAXSI %{DA1:date1}s%{TM1:time}s[%{LEVEL:level}]s%{NUM1:num1}%{NUM2:num2}s(?<logtype>NAXSI_EXLOG):sw+=%{HOST:client_ip}&server=%{HOST:hostname}&uri=%{PROG:filepath}&id=%{ID1:id}&zone=%{ZONE:zone}&var_name=%{VAR1:var}&content=%{CONTENT:content},sclient:s%{HOST:ip3},sserver:s(.*)srequest:s"%{T3:method}s%{HOST:uri}sHTTP/1.1",shost:s"%{HOST:host22}"

NAXSI2 %{DA1:date1}s%{TM1:time}s[%{LEVEL:level}]s%{NUM1:num1}%{NUM2:num2}s(?<logtype>NAXSI_EXLOG):sw+=%{HOST:client_ip}&server=%{HOST:hostname}&uri=%{PROG:filepath}&id=%{ID1:id}&zone=%{ZONE:zone}&var_name=%{VAR1:var}&content=%{CONTENT:content},sclient:s%{HOST:ip3},sserver:s(.*)srequest:s"%{T3:method}s%{HOST:uri}sHTTP/1.1",shost:s"%{HOST:host22}",sreferrer:s"(?<referrer>(.*))

FMT %{DA1:date1}s%{TM1:time}s[%{LEVEL:level}]s%{NUM1:num1}%{NUM2:num2}s(?<logtype>NAXSI_FMT):sip=%{HOST:ip}&server=%{HOST:server}&uri=%{UNIXPATH:uri}&learning=%{HOST:learing}&vers=%{HOST:vers}&total_processed=%{HOST:toal_processed}&total_blocked=%{HOST:blocked}&block=%{HOST:block}&cscore0=%{HOST:attack}&score0=%{HOST:score0}&cscore1=%{HOST:xss}&score1=%{HOST:score}&zone0=%{WORD:args}&id0=%{NUMBER:id}&var_name0=%{HOST:varname},sclient:s%{HOST:ip3},sserver:s(.*)srequest:s"%{T3:method}s%{HOST:uri}sHTTP/1.1",shost:s"%{HOST:host22}

logstash.conf:

input {
 file {
       path => "/usr/local/nginx/logs/naxsi.err"
       type => "naxsi-error"
       start_position => "beginning"
   }
   }
   filter {
    if [type] == "naxsi-error" {
    grok {
        patterns_dir => "/opt/logstash-5.5.1/pattern"
        match => [ "message" , "%{NAXSI2}",
               "message" , "%{NAXSI}",
               "message" , "%{FMT}"
            ]

    }
    # aggregate {
    #   task_id => "%{num2}"
    #       code => "map['sql_duration'] = 0"
    #   end_of_task => true
    #   }

}  }
output {
  if [type] == "naxsi-error" {
    elasticsearch {
       hosts => ["localhost"]
       index => "nxapi"
           document_id => "%{num2}"
        }
     }
}

linux三大利器–grep|sed|awk

  • grep 文本查找
  • sed 行编辑器
  • awk 文本处理工具

grep

grep 比较简单 查找文本离不开正则 具体用法如从简单到复杂如

grep '[1-9]' 文件名 //匹配含有1到9数字
grep '[^1-9]' 文件名 //匹配除了1-9数字的其他字符
grep '^root' 文件名 //^变成头字符 以root开头
grep '^$' 文件名 //头和尾加起来 匹配空行
grep '.' 文件名 //匹配.
grep 'w' 文件名 //等同([a-zA-Z1-9_])
grep 'W' 文件名 //等同([^a-zA-Z1-9_])
grep 'b' 文件名 //表示单词分隔 如 b[a]b 就是a
grep 'sb+' 文件名 //匹配至少出现一次的sb
grep 'sb*' 文件名 //有s或者b都可以
grep '.' 文件名 //匹配任意字符

sed

  • 可用自动处理文件
  • 分析日志文件
  • 修改配置文件

  • sed的处理原则是行处理,而且不改变源文件

sed的格式

sed [options] ‘command’ file(s) //命令行格式
sed 'p' passwd #会打印出两行,因为sed的原理是读入一行,输出一行,此处再加上p命令打印出来的一行,所以最后会打印出两行
sed -n 'p'passwd #加了-n选项之后,只会打印出相关的行,那些不相关的行则不会打印出来