AnsibleTest

安装

准备三台主机,主机名与地址分别为:test1:10.5.5.158、test2:10.5.5.159、test3:10.5.5.160

1
2
3
4
5
6
7
8
9
10
11
12
13
14
yum install -y epel-release
yum install -y ansible
ssh-keygen -t rsa -P ''
# 生成私钥
ssh-copy-id -i ~/.ssh/id_rsa.pub [email protected]
ssh-copy-id -i ~/.ssh/id_rsa.pub [email protected]
# 将公钥传到另外两台主机,这样可以保证使用密钥连接远程主机
vim /etc/ansible/hosts
[websrvs]
10.5.5.159
10.5.5.160
[localhost]
10.5.5.158
# 设置主机分组

ansible配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
vim /etc/ansible/hosts
[websrvs]
www[1:7].ruopu.com
# 这样会列出www1.ruopu.com到www7.ruopu.com

vim /etc/ansible/hosts
[websrvs]
192.168.1.100 ansible_ssh_port=22 ansible_ssh_user=ruopu ansible_ssh_pass=centos
# 定义连接目标主机时用的端口,用户名和密码

vim /etc/ansible/hosts
[websrvs]
192.168.1.100 ansible_ssh_port=22 ansible_ssh_user=ruopu ansible_ssh_pass=centos
# 将websrvs中的10.5.5.159改为上面的样子,表示连接目标主机时用的端口,用户名和密码

vim /etc/ansible/hosts
[websrvs]
172.16.0.67 http_port=8080
172/16.0.68 http_port=8080

[websrvs:vars]
http_port=8080
# 这是定义组变量,因为上面的http_port的值是一样的,都是8080,所以可以定义这样的组,用中括号括起上面的组名+:vars,下面写上值,这时上面就不用再写http_port=8080了

[root@test playbooks]# vim /etc/ansible/ansible.cfg
deprecation_warnings = False
# 禁用警告通知

ansible命令

模块

1
2
3
4
语法:
ansible <host-pattern> [-f forks][-m module_name] [-a args]

ansible 主机组 -m 模块 -a "值"

ping模块

1
2
ansible all -m ping -C
# 测试是否可以连接到所有主机。ansible <host-pattern> [options];<host-pattern>表示指明要操作的一组主机,options指要执行的任务。-m指定模块,-a向模块发送指令,-f指定几台主机,-C干跳一次,不真正执行;--list-hosts表示查看可以匹配到多少台主机,但命令不会执行

查看组内主机

1
2
ansible websrvs --list-hosts 
# 使用--list-hosts选项,websrvs是组名

group模块,添加、删除组

1
2
3
4
5
6
7
8
9
10
group模块,gid=group id,name=group name,state=present(创建)/ansent(删除),system=0(非系统组)/1(系统组)

ansible all -m group -a "gid=3000 name=mygrp state=present system=0"
# 在目标主机上创建组,组ID是3000,组名是mygrp,present表示创建,如果是absent表示删除,system表示是否为系统组,这里是0表示不是,默认也是0。显示结果中的changed项变为了true,表示变更了
tail -1 /etc/group
# 到目标主机查看是否添加了组
ansible all -m group -a "gid=3000 name=mygrp state=absent"
# 删除刚创建的组
tail -1 /etc/group
# 到目标主机查看是否删除了组

user模块,添加、删除用户

1
2
3
4
user模块,uid=用户id,name=用户名,state=创建present/删除absent,groups=附加组,shell=SHELL 

ansible all -m user -a "uid=5000 name=testuser state=present groups=mygrp shell=/bin/bash"
# 创建用户,groups表示附加组,shell表示默认shell

copy模块

1
2
3
4
5
6
7
8
9
10
1. 复制文件,src=源目录,dest=目标文件,owner=复制过去的文件属主,group=复制过去的文件属组
ansible all -m copy -a "src=/etc/fstab dest=/tmp/fstab.ansible mode=600"
# 將本機/etc/fstab文件複製到所有主機的tmp目錄下叫fstab.ansible

2. 复制内容,content='内容',dest=目标文件,owner=复制过去的文件属主,group=复制过去的文件属组
ansible all -m copy -a "content='hi there\n' dest=/tmp/hi.txt owner=testuser group=mygrp"
# 将内容hi there写入/tmp目录下的hi.txt文件中,dest指定的文件可以是已經存在的文件

3. 复制目录或文件,src=/源目录/,dest=目录路径。如果源目录没有后面的斜线,就复制整个目录过去,如果有斜线,就复制目录下的文件过去
ansible all -m copy -a "src=/etc/pam.d/ dest=/tmp/"

fetch模块

1
2
3
4
这个模块是从远程主机将内容复制到本地,要先指明远程主机,可以是组或全部主机或单一主机IP,src=远程主机的目录(如果是多台主机,远程主机上要有相同的目录及文件),dest=本地路径。复制后,本地将以IP地址命名远程主机复制过来的内容 

ansible all -m fetch -a "src=/tmp/other dest=./"
# 因为共有三台主机,所以当前目录下会有三个以IP命名的目录

command模块

1
2
3
4
5
6
7
8
9
1. 因为在/etc/ansible/ansible.cfg配置文件中module_name = command指定了默认模块使用command,所以如果是command模块,可以不用-m指定。 

ansible all -m command -a "ifconfig"
# 在所有主机上执行ifconfig命令

2. chdir=到哪个目录执行,mkdir COMMAND。-m command省略了,不建议这样使用。

ansible all -a "chdir=/var/tmp mkdir hi.dir"
# 到远程主机的/var/tmp目录下创建一个叫hi.dir的目录

shell模块

1
2
3
4
用此模块执行shell命令,与command模块类似,但更强大。如果用ansible all -m command -a "echo 123456 | passwd --stdin testuser"命令,是不能将123456这个密码传递给testuser,而会将echo后的全部内容当密码传递给testuser 

ansible all -m shell -a "echo 123456 | passwd --stdin testuser"
# 在所有主机上执行,设置testuser用户密码为123456

file模块

1
2
3
4
创建符号链接;src=目标主机的文件,path=目标主机路径,state=link(符号链接模式) 

ansible all -m file -a "src=/tmp/fstab.ansible path=/var/tmp/fstab.link state=link"
# 这里主机应该靠state=link来定义是符号链接

cron模块

1
2
3
创建定时任务;minute=分钟,job='任务',name=任务名。有任务名方便删除 

ansible all -m cron -a "minute=*/3 job='/usr/sbin/ntpdate 192.168.1.64 &> /dev/null' name=None"

yum模块

1
2
3
4
在目标主机安装软件;name=软件包名,state=installed安装 

ansible all -m yum -a "name=nginx state=installed"
# 在所有主机上安装nginx

service模块

1
2
3
启动、重启、关闭服务;name=程序名,state=started启动、stopped停止、restarted重启、reloaded重新装载 

ansible all -m service -a "name=nginx state=started"

script模块

1
2
3
远程执行脚本,-a选项后直接指定路径。这只是在远程执行脚本,但脚本不会复制到远程主机 

ansible all -m script -a "/tmp/test.sh"

setup模块

1
2
3
4
获取远程主机上的变量,这会列出远程主机上的所有模块 

ansible 192.168.1.100 -m setup
# 命令会输出主机的很多属性信息,如内存信息,IP地址等

playbook剧本功能

playbook即剧本,让目标主机按照既定的剧本执行任务。playbook实为目录,在目录中创建相应的子目录,这些子目录就是一个个的角色。剧本中都用YAML格式文件,它是可读性高,用来表达数据序列的格式

  1. playbook的核心元素:

    Hosts:主机
    tasks: 任务列表
    variables: 变量
    templates: 包含了模板语法的文本文件
    handlers: 由特定条件触发的任务
    roles: 角色

  2. playbook的基本组件

    Hosts:运行指定任务的目标主机

    remoute_user:在远程主机上执行任务的用户

    sudo_user

    tasks:任务列表

     模块,模块参数
    
     格式
    
    • action
    • module
  3. 格式

1
2
3
4
5
6
7
8
9
- hosts: all
remote_user: root
# 文件开始都要设置在哪些主机上执行,远程执行者的身份这两行。另外,要以横线空格引导,后面是名字和冒号、空格,这是基本的语法

tasks
- name
copy:
handlers
# 上面两项是任务和特定条件触发任务。在它们的下面可以用横线空格名字冒号空格来定义一些要执行的内容。注意横线后都是name,说明其下面的内容是做什么的,另外横线与其上面的字母,如与tasks要对齐。横线下面的的字母与name的每一个字母对齐。

创建剧本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
mkdir /root/playbooks
cd playbooks
vim first.yaml
- hosts: all
# 定义哪台主机执行
remote_user: root
# 以谁的身份执行
tasks:
# 打算执行的任务。也就是-m选项指定的模块和-a选项指定的任务
- name: install redis
# 执行的任务的名字,自取。这是一个描述信息
yum: name=redis state=latest
# 安装redis,state=latest最新,latest与present相似,都是安装包的
- name: copy config file
copy: src=/root/playbooks/redis.conf dest=/etc/redis.conf owner=redis
# 复制配置文件到远程主机的etc目录下
- name: start redis
service: name=redis state=started enabled=true
# 启动redis,并开机启动
复制一个redis.conf配置文件到playbooks目录下
ansible-playbook --syntax-check first.yaml
# 检查first.yaml文件的语法是否有问题
ansible-playbook --list-hosts --list-tasks first.yaml
# --list-hosts表示可以在哪些主机上执行,--list-tasks表示都执行哪些任务。
ansible-playbook -C first.yaml
# 测试执行。按任务分别在每台主机上执行。-C选项是在目标主机上跑一次,但不真正执行
ansible-playbook first.yaml
# 这是在目标主机真正执行,redis需要使用epel库

条件触发脚本任务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
notify: restart redis表示当有变化时通知给name是restart redis的项,这个项是用handlers引导的。notify写在哪里,就是在哪里有变化时通知,如下面就是用notify监控着copy项,如果copy的配置文件有变化就通知给handlers,handlers也就是由特定条件触发的任务

vim first.yaml
- hosts: all
remote_user: root
tasks:
- name: install redis
yum: name=redis state=latest
- name: copy config file
copy: src=/root/playbooks/redis.conf dest=/etc/redis.conf owner=redis
notify: restart redis
- name: start redis
service: name=redis state=started enabled=true
handlers:
- name: restart redis
service: name=redis state=restarted
vim /root/playbooks/redis.conf
# 加入一些内容
ansible-playbook first.yaml
# 执行此命令时,因为配置文件有了变化,所以handlers会收到notify发的通知,并重启redis服务

tags标签,定义tags: configfile后可以在ansible-playbook使用中用-t选项指定标签,从而只执行这个有标签的任务。

vim first.yaml
- hosts: all
remote_user: root
tasks:
- name: install redis
yum: name=redis state=latest
- name: copy config file
copy: src=/root/playbooks/redis.conf dest=/etc/redis.conf owner=redis
notify: restart redis
tags: configfile
- name: start redis
service: name=redis state=started enabled=true
handlers:
- name: restart redis
service: name=redis state=restarted
vim redis.conf
# 再修改一下这个配置文件
ansible-playbook -t configfile first.yaml
# 用-t选项指定标签名,表示只执行这个有标签的任务。也就是执行copy config file段,因为配置文件有了变化,所以notify会触发下面的handlers重启redis服务。如果没有notify,那么就只会执行copy项。

定义变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
1. 使用现有变量
ansible 10.5.5.159 -m setup
# 获取159主机上的变量,setup是变量。下面准备用ansible_env变量
vim second.yaml
- hosts: 10.5.5.159
remote_user: root
tasks:
- name: copy file
copy: content={{ ansible_env }} dest=/tmp/ansible.env
# 调用159主机的ansible_env的值,保存在/tmp/ansible.env
ansible-playbook second.yaml
# 这样ansible_env的变量内容就会写入远程主机的/tmp/ansible.env文件中了

2. 自定义变量
vim fore.yaml
- hosts: all
remote_user: root
tasks:
- name: install package {{ pkgname }}
yum: name={{ pkgname }} state=latest
# yum的y要与name的n对齐,不然也会报语法错误。pkgname是自定义的变量
ansible-playbook -e pkgname=memcache fore.yaml
# 自定义变量,用-e调用,也就是pkgname,给它一个值,是软件包的名字,这样就能实现安装软件包了

3. 三种定义变量的方法
vim /etc/ansible/hosts
[websrvs]
172.16.0.67 http_port=8080
172/16.0.68 http_port=8080

[websrvs:vars]
http_port=8080
# 这是定义组变量,因为上面的http_port的值是一样的,都是8080,所以可以定义这样的组,用中括号括起上面的组名+:vars,下面写上值,这时上面就不用再写http_port=8080了

vim vars.yaml
- hosts: websrvs
remote_user: root
vars:
- pbvar: playbook variable testing
# 在这里定义变量名是pbvar,值是playbook variable testing。这是给下面定义的pbvar变量用的
tasks:
- name: command line variables
copy: content={{ cmdvar }} dest=/tmp/cmd.var
# 定义一个变量叫cmdvar,值保存在/tmp/cmd.var上
- name: playbook variables
copy: content={{ pbvar }} dest=/tmp/pb.var
- name: host iventory variables
copy: content={{ http_port }} dest=/tmp/hi.var
# 通过三种方式传递变量,pbvar是在yaml文件中定义;http_port是在文件中定义,就是/etc/ansible/hosts文件;还有cmdvar是在命令行中传递
ansible-playbook -e cmdvar="command line variable testing" vars.yaml
# 上面命令执行后的问题是,在目标主机上出现的cmdvar文件名只能识别到第一个单词,也就是command,不清楚空格后的内容如何能都显示
ansible websrvs -a "ls -l /tmp"
ansible websrvs -a "cat /tmp/cmd.var /tmp/hi.var /tmp/pb.var"
# 有这三个文件, cmd.var中只有command

设置登录远程主机的用户名和密码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
vim /etc/ansible/hosts
[websrvs]
192.168.1.100 ansible_ssh_port=22 ansible_ssh_user=ruopu ansible_ssh_pass=centos
# 将websrvs中的10.5.5.159改为上面的样子,表示连接目标主机时用的端口,用户名和密码
vim user.yaml
- hosts: all
remote_user: root
tasks:
- name: add user
user: name=ruopu system=no state=present
- name: set password
shell: echo centos | passwd --stdin ruopu
# 在远程主机上创建用户,并添加密码
ansible-playbook user.yaml
# 如果改了ansible的hosts目录,上面的剧本在10.5.5.159上是不能执行的,因为ruopu用户没有创建用户的权限。
ansible websrvs -m command -a "whoami"
# 查看在远程主机下是用哪个用户登录的,一个显示ruopu,一个显示root

jinja2模板语法

使用ansible变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
vim redis.conf.j2
bind {{ ansible_eno16777736.ipv4.address }}
# 内嵌了一个变量,解析ansible 172.16.0.68 -m setup | grep 查找到的IP地址变量,ansible_eno16777736是查到的变量名称,用点来调用ansible查找到的名称。这里主要是两个花括号中的内容,bind是自定义的名字
vim template.yaml
- hosts: 192.168.1.100
remote_user: root
tasks:
- name: install config file
template: src=/root/playbooks/redis.conf.j2 dest=/tmp/redis.conf
ansible-playbook template.yaml
到目标主机查看
less /tmp/redis.conf
# 这时这里的bind地址变了
vim template.yaml
- hosts: all
remote_user: root
tasks:
- name: install config file
template: src=/root/playbooks/redis.conf.j2 dest=/tmp/redis.conf
ansible-playbook template.yaml
# 在所有主机上执行一次,这时在不同主机上执行的结果是不一样的,因为不同主机的IP地址是不一样的。这就是模板的功能。只有那些定义了变量的内容才会变更

使用hosts中的变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
vim /etc/ansible/hosts
[websrvs]
10.5.5.160 http_port=8080
10.5.5.159 http_port=10080
vim mylisten.conf
Listen {{ http_port }}
# 文件名不用.j2结尾也可以,就是定义一个配置文件,在其中调用ansible的变量
vim httpd.yaml
- hosts: websrvs
remote_user: root
tasks:
- name: install httpd
yum: name=httpd state=latest
- name: install config file
template: src=/root/playbooks/mylisten.conf dest=/etc/httpd/conf.d/mylisten.conf
# template模板是调用上面定义的mylisten.conf文件,并会将此文件复制到远程主机的相应目录下
- name: start httpd
service: name=httpd state=started
ansible-playbook --syntax-check httpd.yaml
ansible-playbook httpd.yaml
ansible websrvs -a "ss -tln"
# 这时主机监听了除80的端口,一个8080,一个10080.因为在/etc/ansible/hosts文件中定义了http_port

条件判断

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
vim os.yaml
- hosts: websrvs
remote_user: root
tasks:
- name: install httpd
yum: name=httpd state=latest
# 将latest改为absent就是卸载软件包
when: ansible_os_family == "RedHat"
when: ansible_distribution_major_version == "7"
# 设置只有RedHat家族才能用这个模块来安装httpd,并且版本应该是7,如果是CentOS6的话也不会安装httpd
- name: start httpd
service: name=httpd state=started
when: ansible_distribution_major_version == "7"
# 如果不加判断条件,CentOS6也会启动httpd服务
- name: install httpd
apt: name=apache2 state=latest
when: ansible_os_family == "Debian"
ansible-playbook -C os.yaml
# 显示结果中有skipping表示跳过,用蓝色表示,因为条件不满足
ansible-playbook os.yaml

迭代

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
vim item.yaml
- hosts: websrvs
remote_user: root
tasks:
- name: install {{ item }} package
yum: name={{ item }} state=latest
with_items:
- nginx
- tomcat
- mariadb-server
- redis
# 用with_items指明变量,用yum中的name调用这些变量并安装。
ansible-playbook -C item.yaml
ansible-playbook item.yaml
ansible websrvs -a "rpm -q nginx"
# 查看刚才的包是否都安装了

测试角色

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
角色创建流程
1. 定义配置文件中roles的路径
2. 创建角色目录 --> 创建任务(可以通过when设置条件,调用模板,设置标签)
3. 创建调用任务的文件
4. 创建配置文件模板

vim /etc/ansible/ansible.cfg
roles_path = /etc/ansible/roles:/usr/share/ansible/roles
# 模块要放至的路径。这里定义了两个路径,用冒号相连,用哪个都可以。
mkdir -pv /etc/ansible/roles/nginx/{tasks,vars,templates,files,handlers,meta,default}
# 在配置文件中定义的roles路径下创建角色,就叫nginx。这些目录中只有tasks是必须有的。tasks定义任务,vars定义变量,templates定义模板,files定义配置文件

vim /etc/ansible/roles/nginx/tasks/main.yml
- name: install nginx
yum: name=nginx state=latest
when: ansible_os_family == "RedHat"
# 因为就是在tasks目录中,所以在配置文件中不用再写tasks了。所有的角色文件都要叫main.yml

vim nginx.yml
- hosts: websrvs
remote_user: root
roles: # 调用角色,可以调用多个,这里只调用上面定义的nginx角色
- nginx
ansible-playbook --syntax-check nginx.yml
ansible-playbook -C nginx.yml
ansible-playbook nginx.yml

vim /etc/ansible/roles/nginx/templates/vhost1.conf.j2
server {
listen 80;
server_name {{ ansible_fqdn }};
# 用ansible的setup获取到的ansible_fqdn变量的名字,这个变量就是主机名。这里的fqdn解析的是目标主机的主机名,但要在目标主机的/etc/hosts中加入对自己的解析,也就是IP到本机主机名的解析。如果不加,显示会有问题,测试中,用ansible 10.5.5.159 -m setup|grep ansible_fqdn查看到的fqdn都是www.master.com,在10.5.5.159的/etc/hosts文件中加入对自己的解析后,前面的命令可以正常显示。
location / {
root "/ngxdata/vhost1";
}
}
# 创建nginx的配置文件模板

vim /etc/ansible/roles/nginx/tasks/main.yml
- name: install nginx
yum: name=nginx state=latest
when: ansible_os_family == "RedHat"
- name: install conf
template: src=vhost1.conf.j2 dest=/etc/nginx/conf.d/vhost1.conf
# templates可以自动找到模板文件,不用写父目录,它会去templates目录查找
tags: conf
notify: restart nginx
# 这个名字要与handlers中的main.yml中的name定义的名字一致;这是当配置文件有变更时重启服务
- name: install site home directory
file: path={{ ngxroot }} state=directory
# 创建目录,ngxroot变量是在下面的vars子目录中创建的
- name: install index page
copy: src=index.html dest={{ ngxroot }}/
# index.html文件是在files子目录中创建的,运行时会在目标主机自动创建。运行时ansible会自动到files子目录中查找
- name: start nginx
service: name=nginx state=started

vim /etc/ansible/roles/nginx/handlers/main.yml
- name: restart nginx
service: name=nginx state=restarted
# handlers中是由特殊条件触发的任务,这里定义的是上面的配置文件如果有变化,会通知这里的restart nginx,在这里定义了会重启nginx服务。

vim /etc/ansible/roles/nginx/vars/main.yml
ngxroot: /ngxdata/vhost1
# 这里不能用-线,这表示字典模式。定义一个页面的目录路径,在tasks的main.yml中的file中调用

vim /etc/ansible/roles/nginx/files/index.html
vhosts1
ansible-playbook -C nginx.yml
ansible-playbook nginx.yml
# 完成后,目标主机就会安装上nginx,在nginx的配置目录conf.d中会有一个vhost1.conf的配置文件,在其中定义了内容是vhost1,这时只要将本机的hosts文件配置可以正确解析主机名到IP就可以访问了,如curl test3,会显示vhost1。
vim /etc/hosts
10.5.5.160 test3.ccjd.com
10.5.5.159 test2.ccjd.com
10.5.5.158 test1
scp /etc/hosts [email protected]:/etc
scp /etc/hosts [email protected]:/etc
# 最后修改hosts文件并复制到所有主机是必不可少的,因为如果不能解析本机的主机名,在ansible的setup模块中的ansible_fqdn就无法正解解析每台主机的主机名或fqdn。

部署测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
准备三台主机,主机信息如下
IP : 10.5.5.158 app : nginx、ansible;hostname : test1
IP : 10.5.5.159 app : tomcat、tomcat-admin-webapps、tomcat-webapps、tomcat-docs-webapp;hostname : test2.ccjd.com
IP : 10.5.5.160 app : tomcat、tomcat-admin-webapps、tomcat-webapps、tomcat-docs-webapp;hostname : test3.ccjd.com
效果:nginx反向代理到两台tomcat主机。还可以在tomcat上再部署httpd,nginx反代到httpd,再由httpd反代到tomcat上。

* test1
** 安装软件包、配置hosts文件
yum install -y epel-release
yum install -y ansible
vim /etc/hosts
10.5.5.160 test3.ccjd.com
10.5.5.159 test2.ccjd.com
10.5.5.158 test1
rsync -e ssh -avzr --progress /etc/hosts [email protected]:/etc/hosts
rsync -e ssh -avzr --progress /etc/hosts [email protected]:/etc/hosts

** 生成密钥,实现无密码访问
ssh-keygen -t rsa -P ''
ssh-copy-id -i ~/.ssh/id_rsa.pub root@test1
ssh-copy-id -i ~/.ssh/id_rsa.pub [email protected]
ssh-copy-id -i ~/.ssh/id_rsa.pub [email protected]

** 配置ansible地址
vim /etc/ansible.conf
[websrvs]
10.5.5.160
10.5.5.159
test[2:3].ccjd.com
# 写成IP或主机名均可,但最好只写一个。这里以主机名为例。
[localhost]
10.5.5.158
test1
ansible all --list-hosts
ansible test1 -a "hostname"
ansible test2.ccjd.com -a "hostname"
ansible test3.ccjd.com -a "hostname"
ansible localhost --list-hosts
ansible websrvs --list-hosts
mkdir -pv /etc/ansible/roles/{nginx,tomcat,jdk}/{files,templates,tasks,handlers,vars,meta,default}

** 设置ansible剧本
cd /etc/ansible/roles/nginx
vim tasks/main.yml
- name: install nginx
yum: name=nginx state=latest
when: ansible_os_family == "RedHat"
# 当系统是RedHat系列时,安装nginx
- name: install conf
copy: src=lb.conf dest=/etc/nginx/conf.d/
notify: restart redis
# 复制配置文件到目标路径
- name: start nginx
service: name=nginx state=started enabled=yes
# 启动nginx,并设置开机启动
vim handlers/main.yml
- name: restart nginx
service: name=nginx state=restarted
# 当有变更时,可调用此模块重启nginx服务
vim files/lb.conf //设置配置文件,以便在tasks中调用
upstream tcsrvs {
server test2.ccjd.com:8080;
server test3.ccjd.com:8080;
}
# 配置tomcat的两个地址和端口,之后会反代到这两个地址。
server {
listen 80;
server_name www.ruopu.com;
location / {
proxy_pass http://tcsrvs;
}
}
cd /etc/ansible/roles/tomcat
vim tasks/main.yml
- name: install package
yum: name={{ item }} state=latest
# 这里调用item函数,在下面设置item的内容
with_items:
- tomcat
- tomcat-admin-webapps
- tomcat-webapps
- tomcat-docs-webapp
when: ansible_os_family == "RedHat"
- name: start tomcat
service: name=tomcat state=started enabled=yes
cd /etc/ansible/roles/jdk
vim tasks/main.yml
- name: install openjdk
yum: name=java-{{ version }}-openjdk-devel state=latest
# 这里的version函数的内容可以在nginx.yml中定义,也可以在vars模块中定义。
- name: install env file
copy: src=java.sh dest=/etc/profile.d/
vim files/java.sh
export JAVA_HOME=/usr
vim vars/main.yml
version: 1.8.0
# 字典。这是在vars中定义version
vim balance.yml
- hosts: localhost
remote_user: root
roles:
- nginx
- hosts: websrvs
remote_user: root
roles:
- jdk
# 如果在这个文件中定义version函数,上面要写成"- { role: jdk, version: 1.8.0 }"
- tomcat
ansible-playbook -C /etc/ansible/roles/nginx/balance.yml
ansible-playbook /etc/ansible/roles/nginx/balance.yml
访问www.ruopu.com,这时显示的是tomcat页面。访问时出现问题,提示502 Bad Gateway,这是nginx反代服务器上的selinux没有关闭的问题
在node2和3节点上查看是否安装的是1.8.0版本的java
rpm -qa | grep "^java"或java -version

zk+kafka部署

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
准备三台主机,主机信息如下
IP : 10.5.5.158 app : zookeeper-3.4.9、kafka_2.12-0.10.2.0;hostname : kafka1
IP : 10.5.5.159 app : zookeeper-3.4.9、kafka_2.12-0.10.2.0;hostname : kafka2
IP : 10.5.5.160 app : zookeeper-3.4.9、kafka_2.12-0.10.2.0;hostname : kafka3
在158主机上安装ansible,实现zk+kafka集群

** kafka1
hostnamectl set-hostname kafka1
yum install -y ansible
vim /etc/hosts
10.5.5.158 kafka1
10.5.5.159 kafka2
10.5.5.160 kafka3
rsync -e ssh -arvz --progress /etc/hosts root@kafka2:/etc/hosts
rsync -e ssh -arvz --progress /etc/hosts root@kafka3:/etc/hosts
# 使用rsync的条件是两端都要安装此包,不然是不能使用的。
ssh-keygen -t rsa -P ''
ssh-copy-id -i ~/.ssh/id_rsa.pub root@kafka1
ssh-copy-id -i ~/.ssh/id_rsa.pub root@kafka2
ssh-copy-id -i ~/.ssh/id_rsa.pub root@kafka3
vim /etc/ansible/hosts
[kafka]
kafka[1:3]
mkdir -pv /etc/ansible/roles/{kafka,zk,jdk}/{files,templates,handlers,defaults,vars,tasks,meta}
cd /etc/ansible/roles/jdk
vim tasks/main.yml
- name: install openjdk
yum: name=java-{{ version }}-openjdk-devel state=latest
- name: install env file
copy: src=java.sh dest=/etc/profile.d/
vim files/java.sh
export JAVA_HOME=/usr
vim vars/main.yml
version: 1.8.0
cd /etc/ansible/roles/zk
vim tasks/main.yml
- name: install zookeeper
shell: tar xf /root/zookeeper-3.4.9.tar.gz -C /usr/local/ && ln -sv /usr/local/zookeeper-3.4.9 /usr/local/zookeeper
- name: Establish directory
shell: mkdir -pv /usr/local/zookeeper/{data,logs}
- name: install myid
template: src=myid.conf.j2 dest=/usr/local/zookeeper/data/myid
- name: install conf
copy: src=zoo.cfg dest=/usr/local/zookeeper/conf/
tags: zkconf
notify: restart zookeeper
- name: start zookeeper
shell: /usr/local/zookeeper/bin/zkServer.sh start
vim handlers/main.yml
- name: restart zookeeper
shell: /usr/local/zookeeper/bin/zkServer.sh restart
vim files/zoo.cfg
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/usr/local/zookeeper/data
dataLogDir=/usr/local/zookeeper/logs
clientPort=2181
server.1=10.5.5.158:2888:3888
server.2=10.5.5.159:2888:3888
server.3=10.5.5.160:2888:3888
vim templates/myid.conf.j2
{{ ansible_fqdn }}
cd /etc/ansible/roles/kafka
vim tasks/main.yml
- name: install kafka
shell: tar -zxf /root/kafka_2.12-0.10.2.0.tgz -C /usr/local && ln -sv /usr/local/kafka_2.12-0.10.2.0 /usr/local/kafka
- name: install conf
template: src=server.properties dest=/usr/local/kafka/config/server.properties
tags: kaconf
notify: restart kafka
- name: start kafka
shell: nohup /usr/local/kafka/bin/kafka-server-start.sh /usr/local/kafka/config/server.properties &
# 必须让kafka在后台运行,不然在执行剧本时会卡在最后的任务不能正确退出。
vim handlers/main.yml
- name: restart kafka
shell: /usr/local/kafka/bin/kafka-server-stop.sh && nohup /usr/local/kafka/bin/kafka-server-start.sh /usr/local/kafka/config/server.properties &
vim templates/server.properties
broker.id={{ ansible_fqdn }}
delete.topic.enable=true
host.name={{ ansible_default_ipv4[ "address"] }}
# 后面是一个引用setup模块输出的子模块的方法,前面要用主模块的名,后面跟[],在中括号中写上子模块的名字并用引号括起即可。
num.network.threads=3
num.io.threads=8
socket.send.buffer.bytes=102400
socket.receive.buffer.bytes=102400
socket.request.max.bytes=104857600
log.dirs=/usr/local/kafka/logs
num.partitions=1
num.recovery.threads.per.data.dir=1
log.retention.hours=168
log.segment.bytes=1073741824
log.retention.check.interval.ms=300000
zookeeper.connect=10.5.5.158:2181,10.5.5.159:2181,10.5.5.160:2181
zookeeper.connection.timeout.ms=6000
vim zk.yml
- hosts: kafka
remote_user: root
roles:
- jdk
- zk
- kafka
*** 在执行剧本前,先将kafka_2.12-0.10.2.0.tgz和zookeeper-3.4.9.tar.gz两个包复制到三台主机的root目录。另外,将三台主机的主机名分别改为1、2、3,这是为了在kafka的配置文件server.properties中引用fqdn参数时方便设置broker.id,没有想到其他办法将一个模板配置文件复制到不同主机时可以使用不同的id号,所以使用了此种方法。
ansible-playbook /etc/ansible/roles/kafka/zk.yml

普通用户管理ansible

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
useradd ccjd
echo 'centos'|passwd --stdin ccjd
vim /etc/sudoers
ccjd ALL=(ALL) NOPASSWD:ALL
# 每台远程主机都要修改此文件,因为在远程主机上要使用普通用户执行命令并无需输入密码。或可以使用命令完成:“sed -i '$a\ccjd ALL=(ALL) NOPASSWD: ALL' /etc/sudoers”,$a表示在新的一行加入其后面的内容,如果不加$a,那么文件中的所有内容都将被替换。$ 代表的是最后一行,而 a 的动作是新增,\c表示对c转义,如果不转义,c表示取代。
su - ccjd
ssh-keygen -t rsa -P ''
# 以普通用户身份生成私钥
ssh-copy-id -i ~/.ssh/id_rsa.pub 172.17.172.13
# 这要求远程主机上也有ccjd用户。只有这样,才能让自己以ccjd的身份在远程执行sudo命令。
vim /etc/ansible/ansible.cfg
private_key_file = /home/ccjd/.ssh/id_rsa
# remote_user = root
# remote一行默认就是注释的
chown -R ccjd.ccjd /etc/ansible
chown -R ccjd.ccjd /usr/share/ansible
# 第二个文件可能没有
ansible 172.17.172.13 -m shell -a "sudo yum install -y java-1.8.0-openjdk-devel"
# 执行远程命令时还要加上sudo命令,不然会报错的。

问题

  1. 执行中有主机提示“”msg”: “Aborting, target uses selinux but python bindings (libselinux-python) aren’t installed!””。

解决:给主机安装libselinux-python包,如还不能解决,就彻底关闭selinux并重启。

作者

John Doe

发布于

2018-07-16

更新于

2023-03-17

许可协议