Ansible 基础

配置文件常用参数

/etc/ansible/ansible.cfg

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[defaults]
inventory = /etc/ansible/hosts
# 多进程
forks = 5
# 提权,新版本参数为 become
sudo_user = root
# 目标主机默认SSH端口
remote_port = 22
# 主机Key检查
host_key_checking = False
# 连接目标主机超时时间
timeout = 10
# 日志路径
log_path = /var/log/ansible.log
# 私钥路径
private_key_file = /root/.ssh/id_rsa

inventory-主机清单

文件 /etc/ansible/hosts

未分组主机,默认会分配到all的分组中

主机

1
2
3
4
green.example.com
blue.example.com
192.168.100.1
192.168.100.10

分组主机

1
2
3
4
5
6
7
8
[webservers]
alpha.example.org
beta.example.org
192.168.1.100
192.168.1.110
# 简写语法
www[001:006].example.com
db-[99:101]-node.example.com

指定主机登录方式

1
2
192.168.2.61 ansible_ssh_user=root ansible_ssh_pass=123456
192.168.2.62 ansible_ssh_user=root ansible_ssh_pass=654321

变量

主机变量

1
192.168.2.61 ansible_ssh_user=root ansible_ssh_pass=123456 http_port=80

主机组变量

1
2
3
4
5
[web]
192.168.2.6[2:4] ansible_ssh_user=root ansible_ssh_pass=......
[web:vars]
http_port=80
server_name=www.baidu.com

使用变量

1
2
ansible web -a "echo {{http_port}}"
ansible web -a "echo {{server_name}}"

主机和主机组同时配置变量,主机变量优先

Ansible-doc模式

常用参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 选项
-a 指定模块参数
-C 检查而不做其他操作
-e 传入变量
-f 指定并发数
-i 指定主机清单
--list-host 查看主机列表
-m 使用模块名称,默认command
--syntax-check 语法检查,用于playbook
-t 结果输出到目录,以主机名为文件名
-vvvv 没加一个v会显示更详细的输出结果
# 连接主机
-k 交互式输入密码
--private-key=PRIVATE_KEY_FILE 指定私钥
-u 指定用户去连接目标主机
-T 连接超时时间
# 提权选项
-b, --become 提权,默认sudo
-K 交互输入提权密码

SSH密码认证方式

配置文件

1
2
192.168.2.61 ansible_ssh_user=root ansible_ssh_pass=123456
192.168.2.62 ansible_ssh_user=root ansible_ssh_pass=654321

交互式

1
ansible web -m shell -a "ls /root" -u wangshui -k

常用模块

https://docs.ansible.com/ansible/latest/user_guide/intro_adhoc.html

  • 执行shell命令(command和shell)
  • 文件传输(copy和file)
  • 管理软件包(yum)
  • 用户和组(user)
  • 从源码管理系统部署(git)
  • 管理服务(service)
  • 收集目标主机信息(setup)
  • 解压模块unarchive

Shell 模块

1
ansible web -m shell -a "df -h"

sudo使用

1
ansible web -m shell -a "ls /root" -u wangshui -k --become --become-user root --ask-become-pass

两次交互输入密码,第一次为连接用户的密码,第二次为sudo密码,两个密码一致

Copy 模块

1
ansible web -m copy -a "src=/root/1.txt dest=/root/2.txt"

常用参数:

dest 目标绝对路径。如果src是一个目录,dest也必须是一个目录。如果dest是不存在的路径,并且如果dest以/结尾或者src是目录,则dest被创建。如果srcdest是文件,如果dest的父目录不存在,任务将失败

src 将本地路径复制到远程服务器; 可以是绝对路径或相对的。如果是一个目录,它将被递归地复制。如果路径以/结尾,则只有该目录下内容被复制到目的地,如果没有使用/来结尾,则包含目录在内的整个内容全部复制

mode 设置文件权限,模式实际上是八进制数字(如0644),少了前面的零可能会有意想不到的结果。从版本1.8开始,可以将模式指定为符号模式(例如u+rwx或u=rw,g=r,o=r)

owner 设置文件/目录的所属用户,将被馈送到chown

group 设置文件/目录的所属组,将被馈送到chown

force(默认no) 当内容不同于源时,将替换远程文件。设置为no,则只有在目标不存在的情况下才会传输文件

backup(默认no) 在覆盖之前将原文件备份,备份文件包含时间信息

content(默认no) 当用content代替src参数的时候,可以把文档的内容设置到特定的值

remote_src(2.0+) 如果yes它会从目标机上搜索src文件

validate(默认no) 复制前是否检验需要复制目的地的路径

local_follow(默认no) 是否遵循本地机器中的文件系统链接

File 模块

1
ansible web -m file -a "dest=/tmp/abc mode=600 state=directory"

常用状态:

  • absent 删除目标文件
  • touch 如果目标文件不存在,则创建文件;如果存在,则更改目标文件的时间戳
  • directory 创建目录
  • hard 给目标文件创建硬链接(与src一起使用)
  • link 给目标文件创建软链接(与src一起使用)

Yum模块

1
ansible web -m yum -a "name=vim state=present"

几种状态:

  • present(安装)
  • installed(安装)
  • latest(安装最新版)
  • removed(卸载)
  • absent(卸载)

User 模块

1
ansible web -m user -a 'name=wangshui898 password="$6$r3c6EgoL20n7ufsZ$/mgd7wpVJB4Dm2X3xA.PsfjXV7SydTMrNCpUQFoIdquI5B1ZNLoKvrNzv0AJWQGaxrBPgSwX54F51YAHA57MJ."'

密码加密方式:

1
2
3
4
5
6
7
8
# python
Python 2.7.5 (default, Apr 2 2020, 13:16:51)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-39)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import crypt
>>> crypt.crypt('Abc123')
'$6$r3c6EgoL20n7ufsZ$/mgd7wpVJB4Dm2X3xA.PsfjXV7SydTMrNCpUQFoIdquI5B1ZNLoKvrNzv0AJWQGaxrBPgSwX54F51YAHA57MJ.'
>>>

创建服务用户

1
ansible web -m user -a 'name=msyql shell=/sbin/nologin'

Git 模块

拉取git代码

1
ansible web -m git -a "repo=https://github.com/ansible/ansible.git dest=/usr/local/src/ansible"

要求目标主机有git命令

Service模块

启动服务

1
ansible web -m service -a "name=memcached state=started"

几种状态:

  • reloaded
  • restarted
  • started
  • stopped

加入开机启动

1
ansible web -m service -a "name=memcached enabled=true"

Setup模块

1
ansible web -m setup

过滤信息

1
ansible web -m setup -a "filter=ansible_os_family"

常用信息:

1
2
3
4
5
6
7
8
9
ansible_all_ipv4_addresses		所有IPV4地址
ansible_default_ipv4 默认IPV4地址
ansible_nodename 主机名称
ansible_os_family 系统
ansible_processor_cores CPU核数
ansible_processor CPU线程数
ansible_date_time 时间
ansible_pkg_mgr 包管理
filter=ansible_*_mb 内存相关信息

unarchive模块

在远程主机上解压文件并设置权限

1
ansible web -m unarchive -a 'src=/srv/tomcat8/apache-tomcat-8.0.29.tar.gz dest=/usr/local mode=0755'

解压ansible管理机上的压缩文件到远程主机并设置权限

1
ansible web -m unarchive -a "src=/tmp/install/zabbix-3.0.4.tar.gz dest=/tmp/ mode=0755 copy=no"

常用参数:

creates:一个文件名,当它已经存在时,这个步骤将不会被运行。
copy:默认为yes,拷贝的文件从ansible主机复制到远程主机,no在远程主机上寻找src源文件解压
src:tar源路径,可以是ansible主机上的路径,也可以是远程主机上的路径,如果是远程主机上的路径,则需设置copy=no
dest:远程主机上的目标绝对路径
mode:设置解压缩后的文件权限
exec:列出需要排除的目录和文件
remote_src:设置remote_src=yes为解包目标上已经存在的档案。对于Windows目标,改用win_unzip模块。
owner:解压后文件或目录的属主
group:解压后的目录或文件的属组

lineinfile模块

  • 替换匹配的目标值…

  • 在匹配值之前增加行…

  • 需求:在匹配值之后增加行…

  • 需求:匹配到就替换行,未匹配到就新增行…

常用参数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
path参数 :必须参数,指定要操作的文件。

line参数 : 使用此参数指定文本内容。

regexp参数 :使用正则表达式匹配对应的行,当替换文本时,如果有多行文本都能被匹配,则只有最后面被匹配到的那行文本才会被替换,当删除文本时,如果有多行文本都能被匹配,这么这些行都会被删除。

state参数:当想要删除对应的文本时,需要将state参数的值设置为absent,absent为缺席之意,表示删除,state的默认值为present。

backrefs参数:默认情况下,当根据正则替换文本时,即使regexp参数中的正则存在分组,在line参数中也不能对正则中的分组进行引用,除非将backrefs参数的值设置为yes。backrefs=yes表示开启后向引用,这样,line参数中就能对regexp参数中的分组进行后向引用了,这样说不太容易明白,可以参考后面的示例命令理解。backrefs=yes除了能够开启后向引用功能,还有另一个作用,默认情况下,当使用正则表达式替换对应行时,如果正则没有匹配到任何的行,那么line对应的内容会被插入到文本的末尾,不过,如果使用了backrefs=yes,情况就不一样了,当使用正则表达式替换对应行时,同时设置了backrefs=yes,那么当正则没有匹配到任何的行时,则不会对文件进行任何操作,相当于保持原文件不变。

insertafter参数:借助insertafter参数可以将文本插入到“指定的行”之后,insertafter参数的值可以设置为EOF或者正则表达式,EOF为End Of File之意,表示插入到文档的末尾,默认情况下insertafter的值为EOF,如果将insertafter的值设置为正则表达式,表示将文本插入到匹配到正则的行之后,如果正则没有匹配到任何行,则插入到文件末尾,当使用backrefs参数时,此参数会被忽略。

insertbefore参数:借助insertbefore参数可以将文本插入到“指定的行”之前,insertbefore参数的值可以设置为BOF或者正则表达式,BOF为Begin Of File之意,表示插入到文档的开头,如果将insertbefore的值设置为正则表达式,表示将文本插入到匹配到正则的行之前,如果正则没有匹配到任何行,则插入到文件末尾,当使用backrefs参数时,此参数会被忽略。

backup参数:是否在修改文件之前对文件进行备份。

create参数 :当要操作的文件并不存在时,是否创建对应的文件。

示例1: 在文件后面添加一行

1
2
3
4
5
6
- name: add a line
lineinfile:
dest: /opt/playbook/test/hosts
line: '192.168.1.2 foo.lab.net foo'
tags:
- add_a_line

示例2: 修改某行内容-关闭selinux

1
2
3
4
5
- name: 关闭selinux
lineinfile:
dest: /etc/selinux/config
regexp: "^SELINUX="
line: "SELINUX=disabled"

在文件”dest”中,用正则表达式匹配“regexp”值:

若匹配到“regexp”的值=1:替换“regexp”值所在行为 “line”;

若匹配到“regexp”的值>1:只替换最后一个匹配的有效值;

若匹配到“regexp”的值=0:检查是否存在“backrefs”,并且值等于yes,若是则不做任何操作;否则在文件末尾新增行“line”;

示例3: 在匹配的行后面添加内容

1
2
3
4
5
6
7
8
- name: httpd.conf modify 8080
lineinfile:
dest: /opt/playbook/test/http.conf
regexp: '^Listen'
insertbefore: '^#Port'
line: 'Listen 8080'
tags:
- http8080

示例4: 如果有内容,则进行替换,没有内容,做添加操作–添加sudo用户

1
2
3
4
5
6
7
8
9
- name: Fully quoted a line
lineinfile:
dest: /opt/playbook/test/testfile
state: present
regexp: '^%wheel'
backrefs: yes
line: '%wheel ALL=(ALL) NOPASSWD: ALL'
tags:
- testfile

backrefs为no时,如果没有匹配,则添加一行line。如果匹配了,则把匹配内容替被换为line内容。

backrefs为yes时,如果没有匹配,则文件保持不变。如果匹配了,把匹配内容替被换为line内容。

backrefs默认值为no

replace模块

path参数 :必须参数,指定要操作的文件,2.3版本之前,只能使用 dest, destfile, name指定要操作的文件,2.4版本中,仍然可以使用这些参数名,这些参数名作为 path 参数的别名使用。

regexp参数 : 必须参数,指定一个 python 正则表达式,文件中与正则匹配的字符串将会被替换。

replace参数 : 指定最终要替换成的字符串。

backup参数 :是否在修改文件之前对文件进行备份,最好设置为yes。

示例: 修改mysql启动脚本

1
2
3
4
5
6
7
- name: change the start script
#shell: sed -i "s/^datadir=/datadir=\/data\/mysql/" /etc/init.d/mysqld
replace:
path=/etc/init.d/mysqld
regexp="^datadir="
replace="datadir={{ datadir_name }}"
backup=yes

Playbook

基本语法

安装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
---
- name: nginx_install
hosts: web
gather_facts: no
remote_user: root
vars:
nginx_packages:
- nginx
hello: Ansible
tasks:
- name: Add epel
yum_repository:
name: epel-release
description: epel7 on CentOS 7
baseurl: http://mirrors.aliyun.com/epel/7/$basearch/
gpgcheck: no
enabled: 1

- name: add user www
user:
name: www
state: present

- name: install nginx
yum:
name: "{{ nginx_packages }}"
state: present
with_items: "{{ nginx_packages }}"

- name: start nginx
service:
name: "{{ item }}"
state: started
loop:
- nginx

- name: create index index.html
file:
dest: /usr/share/nginx/html/index.html
state: touch
owner: www
group: www
mode: 0755

- name: change index.html
shell: echo "hello {{hello}}" > /usr/share/nginx/html/index.html

- name: configure nginx
copy:
src: conf/index.conf
dest: /etc/nginx/conf.d/index.conf
owner: root
group: root
mode: 0644
notify: reload nginx

handlers:
- name: reload nginx
service:
name: nginx
state: reloaded

语法检测

1
ansible-playbook playbook.yml --syntax-check

执行playbook

1
ansible-playbook playbook.yml

批量设置主机名

1
2
3
4
5
6
7
8
9
10
11
12
13
14
---
- hosts: web
gather_facts: yes
remote_user: root

tasks:
- name: set hostname
raw: hostnamectl set-hostname {{host_name}} &&
hostname {{host_name}}

- name: set hosts
lineinfile:
dest: /etc/hosts
line: "{{ansible_all_ipv4_addresses[0]}} {{host_name}}"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
- hosts: web
gather_facts: yes
remote_user: root

tasks:
- name: set hostname
raw: hostnamectl set-hostname {{host_name}} &&
hostname {{host_name}}

- name: 获取主机名变量
set_fact:
cluster_host_name={{hostvars[inventory_hostname].ansible_facts.hostname}}
- name: 获取主机IP变量
set_fact:
cluster_ip_addr={{hostvars[inventory_hostname].ansible_default_ipv4.address}}

- name: 设置hosts
lineinfile:
dest: /etc/hosts
line: "{{cluster_ip_addr}} {{cluster_host_name}}"

任务触发-handlers

用途: 在变更时触发操作,配合notify使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
- name: nginx_install
hosts: web
gather_facts: no
remote_user: root

tasks:
- name: configure nginx
copy:
src: conf/index.conf
dest: /etc/nginx/conf.d/index.conf
owner: root
group: root
mode: 0644
notify: restart nginx
handlers:
- name: restart nginx
service:
name: nginx
state: reloaded

任务控制-tags

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
---
- name: nginx_install
hosts: web
gather_facts: no
remote_user: root
vars:
nginx_packages:
- nginx
hello: Ansible
tasks:
- name: Add epel
tags: add_repo
yum_repository:
name: epel-release
description: epel7 on CentOS 7
baseurl: http://mirrors.aliyun.com/epel/7/$basearch/
gpgcheck: no
enabled: 1

- name: add user www
tags: add_user
user:
name: www
state: present

- name: install nginx
tags: install_nginx
yum:
name: "{{ nginx_packages }}"
state: present
with_items: "{{ nginx_packages }}"

- name: start nginx
tags: start_nginx
service:
name: "{{ item }}"
state: started
loop:
- nginx

使用方法-使用标签

1
ansible-playbook tags.yml --tags "add_user"

使用方法-跳过标签

1
ansible-playbook tags.yml --skip-tags "add_user"

debug文件调试

语法

1
2
3
4
5
6
7
8
9
---
- hosts: web
tasks:
- debug:
msg: {{group_names}}
- debug:
msg: {{inventory_hostname}}
- debug:
msg: {{ansible_hostname}}

参数:

msg(string) 输出自定义信息,如果不指定或不写msg的话,默认也会输出“Hello world”, 默认输出:“Hello world”

var(string) var与msg相互冲突,var涉及到变量的使用

verbosity(integer) debug的调试级别,默认0是全部显示,级别调整到3是忽略内容不显示,如果verbosity参数设置为3还想像是debug内容的话,需要在命令后面加入 -vvv参数,默认:0

样例-部署tomcat

步骤梳理

1
2
3
1. 上传JDK->部署JDK
2. 上传tomcat-解压-部署
3. 启动

YAML文件

1
2
3
4
5
6
7
tree
.
├── conf
├── deploy_tomcat.yml
└── tar
├── apache-tomcat-8.5.61.tar.gz
└── jdk-8u251-linux-x64.tar.gz

yml文件

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
---
- name: 部署tomcat
hosts: web
gather_facts: no
remote_user: root
vars:
tomcat_version: 8.5.61
tomcat_install_dir: /usr/local
jdk_version: jdk-8u251-linux-x64.tar.gz
jdk_dir: jdk1.8.0_251
java_home: /usr/local/java
listen_port: 8099
ajp_port: 8099
shutdown_port: 8095
tasks:
- name: 安装解压,下载应用
tags: install_libs
yum:
name: "{{ item }}"
state: present
loop:
- unzip
- wget

- name: 创建JAVA目录
tags: create_java_home
file:
dest: /usr/local/java
state: directory

- name: 拷贝源码包
tags: upload_tars
copy:
src: "{{ item.src }}"
dest: "{{ item.dest }}"
with_items:
- { src: "tar/apache-tomcat-{{ tomcat_version }}.tar.gz",dest: /usr/local/src }
- { src: "tar/{{ jdk_version }}",dest: /usr/local/src }

- name: 解压源码包
tags: unzip_tars
unarchive:
src: "{{ item.src }}"
dest: "{{ item.dest }}"
remote_src: yes
with_items:
- { src: "/usr/local/src/apache-tomcat-{{ tomcat_version }}.tar.gz",dest: "{{ tomcat_install_dir }}" }
- { src: "/usr/local/src/{{ jdk_version }}",dest: "{{ java_home }}" }

- name: 创建JAVA环境变量文件
tags: add_java_profile
file:
dest: /etc/profile.d/java.sh
state: touch
mode: 0755

- name: 配置AVA环境变量文件
tags: configure_java_profile
shell: echo "# JAVA" >> /etc/profile.d/java.sh &&
echo "JAVA_HOME={{ java_home }}/{{ jdk_dir }}" >> /etc/profile.d/java.sh &&
echo "JRE_HOME={{ java_home }}/{{ jdk_dir }}/jre" >> /etc/profile.d/java.sh &&
echo 'CLASSPATH=.:$JAVA_HOME/lib:$JAVA_HOME/lib' >> /etc/profile.d/java.sh &&
echo 'PATH=$JAVA_HOME/bin:$JRE_HOME/bin:$PATH' >> /etc/profile.d/java.sh &&
echo 'export JAVA_HOME JRE_HOME CLASSPATH PATH '>> /etc/profile.d/java.sh &&
source /etc/profile

- name: 部署tomcat
tags: deploy_tomcat
shell: cd {{ tomcat_install_dir }} &&
mv apache-tomcat-{{ tomcat_version }} tomcat{{ listen_port }} &&
cd {{ tomcat_install_dir }}/tomcat{{ listen_port }}/conf &&
sed -i "s#8080#{{ listen_port }}#g" server.xml &&
sed -i "s#8009#{{ ajp_port }}#g" server.xml &&
sed -i "s#8005#{{ shutdown_port }}#g" server.xml

- name: 启动tomcat
tags: start_tomcat
shell: cd {{ tomcat_install_dir }}/tomcat{{ listen_port }}/bin &&
nohup ./startup.sh &

变量定义与使用

变量获取

1
ansible web -m setup

命令行传入变量

编辑YAML文件

1
2
3
4
5
6
7
8
---
- hosts: web
gather_facts: no
remote_user: root

tasks:
- name: test var
- debug: msg="install_dir"

使用命令行传入变量

1
ansible-playbook test_var.yml -e install_dir=/usr/local/tomcat

输出结果

1
2
3
4
5
6
7
8
9
10
11
12
PLAY [web] ************************************************************************************

TASK [test var] *********************************************************************
ok: [192.168.2.62] => {
"msg": "install_dir"
}
ok: [192.168.2.63] => {
"msg": "install_dir"
}
ok: [192.168.2.64] => {
"msg": "install_dir"
}

注册变量

register

1
2
3
4
5
6
7
8
9
10
11
12
---
- hosts: web
gather_facts: no
remote_user: root

tasks:
- name: register var
command: date "+%F %T"
register: datetime
- name: touch file
#file: dest=/tmp/r_{{ datetime.stdout }} state=touch
debug: msg={{ datetime }}

set_fact

1
2
3
4
5
6
7
8
---
- hosts: testB
remote_user: root
tasks:
- set_fact: # 在tasks内部调用变量,使用set_fact
testvar: "test"
- debug:
msg: "{{testvar}}"

只有set_fact定义的变量才能在不同的play中应用,而vars定义的变量不能在不同的play中应用

Playbook文件复用

include和import区别

  • include(动态): 在运行时导入

    –list-tags, –list-tasks不会显示到输出

    不能使用notify触发来自include内处理程序名称(handlers)

  • import(静态): 在Playbook解析时预先导入

    不能与循环一起使用

    将变量用于目标文件或角色名称时,不能使用inventory(主机/主机组等)中的变量

import_playbook

nginx.yml

1
2
3
4
5
6
7
---
- hosts: web
gather_facts: no
remote_user: root
tasks:
- name: Install Nginx
debug: msg="Install Nginx"

php.yml

1
2
3
4
5
6
7
---
- hosts: web
gather_facts: no
remote_user: root
tasks:
- name: Install PHP
debug: msg="Install PHP"

mysql.yml

1
2
3
4
5
6
7
---
- hosts: web
gather_facts: no
remote_user: root
tasks:
- name: Install Mysql
debug: msg="Install Mysql"

lnmp.yml

1
2
3
4
---
- import_playbook: nginx.yml
- import_playbook: mysql.yml
- import_playbook: php.yml

include_tasks

task1.yml

1
2
3
---
- name: test task1
debug: msg="task1"

task2.yml

1
2
3
---
- name: test task2
debug: msg="task2"

main.yml

1
2
3
4
5
6
7
8
---
- name: exec tasks
hosts: web
gather_facts: no
remote_user: root
tasks:
- include_tasks: task1.yml
- include_tasks: task2.yml

Playbook流程控制

条件

when

写法一:

1
2
3
4
5
tasks:
- name: "shutdown Debian systems"
command: /sbin/shutdown -t now
when: (ansible_distribution == "CentOS" and ansible_distribution_major_version == "6") or
(ansible_distribution == "Debian" and ansible_distribution_major_version == "7")

写法二:

1
2
3
4
5
6
tasks:
- name: "shutdown Debian systems"
command: /sbin/shutdown -t now
when:
- ansible_os_family == "Debian"
- ansible_distribution_major_version == "6"

指定主机:

1
2
3
4
5
6
7
8
---
- hosts: web
gather_facts: yes
remote_user: root
tasks:
- name: Install PHP
debug: msg={{ansible_default_ipv4.address}}
when: ansible_default_ipv4.address == "192.168.2.63"

循环

循环序列

with_list

1
2
3
4
5
6
7
8
9
10
11
12
- name: nginx_install
hosts: web
remote_user: root

tasks:
- name: install nginx
yum:
name: "{{ item }}"
state: present
with_list:
- epel-release
- nginx

loop

1
2
3
4
5
6
7
8
9
10
11
12
- name: nginx_install
hosts: web
remote_user: root

tasks:
- name: install nginx
yum:
name: "{{ item }}"
state: present
loop:
- epel-release
- nginx

with_items: 循环字典

1
2
3
4
5
6
7
8
9
10
11
---
- name: 解压源码包
unarchive:
src: "{{ item.src }}"
dest: "{{ item.dest }}"
remote_src: yes
with_items:
- { src: "/tmp/nginx-1.8.0.tar.gz",dest: "/opt/" }
- { src: "/tmp/openssl-1.0.1h.tar.gz",dest: "/opt/" }
- { src: "/tmp/pcre-8.12.tar.gz",dest: "/opt/" }
- { src: "/tmp/zlib-1.2.11.tar.gz",dest: "/opt/" }

冒号后面的要加双引号,等于号后面的不用

模版(jinja2)

templates模块

1
2
3
4
5
6
7
8
9
10
11
- name: nginx_install
hosts: web
remote_user: root
vars:
hello: Ansible

tasks:
- name: jinja2模版
templates:
src=f.j2
dest=/tmp/j2

jinja2基本语法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{% set list=[10, 12, 15, 18]%}
upstream {{server_name}}
{% for i in list %}
server 192.168.2.{{i}}
{%end for%}

server {
listen {{http_port}};
server_name {{server_name}};
root /data/htdocs;
index index.html index.php;
location / {

}

}

角色(Roles)

自动生成目录结构

1
ansible-galaxy init lnmp

目录结构

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
├── site.yml
├── hosts
├── fooservers.yml
├── webservers.yml
├── roles
│   ├── common
│   │   ├── defaults
│   │   ├── files
│   │   ├── handlers
│   │   ├── meta
│   │   ├── tasks
│   │   ├── templates
│   │   └── vars
│   └── webservers
│   ├── defaults
│   ├── files
│   ├── handlers
│   ├── meta
│   ├── tasks
│   ├── templates
├── └── vars
├── group_vars
│   ├── all
│   ├── fooservers
│   └── webservers

tasks: 包含角色要执行的主要任务列表

handlers: 包含角色使用的处理程序

defaults: 角色默认变量

files: 角色部署时用到的文件

templates: 角色部署时用到的模版

meta: 角色定义的一些元数据

案例:部署LNMP

结构梳理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
site.yml	-- 项目入口
hosts -- 主机清单
group_vars -- 服务组变量

roles -- 角色
roles/common -- 通用模块
roles/common/task/main.yml -- 编译安装时需要的依赖包

roles/nginx/tasks/main.yml -- 编译安装nginx
roles/nginx/handlers/main.yml
roles/nginx/files/{nginx1.18.tar.gz,nginx.service,nginx.conf}
roles/nginx/templates/index-php.conf

roles/php/main.yml -- 编译安装PHP
roles/php/tasks/main.yml
roles/files/{php-7.0.tar.gz,php-frm.service,php-fpm.conf,php.ini}

roles/wordpress
roles/wordpress/tasks/main.yml
roles/wordpress/templates/wp-config.php