1.ansible的发展与简介
纯手工阶段--》脚本阶段--》工具阶段(脚本:不能集中获得日志,传入变量的不太灵活)
-一款简单的自动化工具
-无代理(无需要所要管理系统上安装任何软件,ssh和python就可以,windows安装powershell)
-开源,免费使用
2.ansible功能实现
-应用部署
-配置管理
-任务自动化
特点:
-无客户端
-简单,易懂
-扩展性强,可管理从几十台到数千台节点
-ssh连接,安全
-强大社区,大量module,role拿来即用
-幂等性,不会重复执行
3.puppet vs saltstack vs ansible
saltstack: 依赖于agent,量上升后,管理的难度会上升
4.Ansible工作原理
描述:模块包含inventory、api、modules、plugins,inventory是目标机器的管理清单,保存了SSH连接的信息,可以在模块上操作取决于modules,是执行任务的管理模块,playbook是剧本文件,用户可以通过访问清单来调用module实现任务执行,也可以通过playbook对任务进行编排,api是可以与其他系统做整合
Inventory: 定义ansible被管理主机的清单
modules: 包括ansible自带的核心模块及自定义模块
playbooks: 剧本,定义ansible多任务配置文件,由ansible自动执行
api: python接口,提供二次开发及系统整合能力
plugins: 完成模块功能补充,包括连接插件、邮件插件等
5.Ansible安装
[root@ansible1 ~]# yum install epel-release [root@ansible1 ~]# yum install ansible -y [root@ansible1 ~]# ansible --version ansible 2.4.2.0 config file = /etc/ansible/ansible.cfg configured module search path = [u'/root/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules'] ansible python module location = /usr/lib/python2.7/site-packages/ansible executable location = /bin/ansible python version = 2.7.5 (default, Aug 4 2017, 00:39:18) [GCC 4.8.5 20150623 (Red Hat 4.8.5-16)]
6.ansible文件组成
-可执行文件:/usr/bin/ansible* -配置文件目录:/etc/ansible/ -ansible-config -hosts -roles/ -Python lib文件:/usr/lib/python2.7/site-packages/ansible -Help文档 注意:host_key_checking一般用于ssh的认证,要关闭,如访问一台新的主机会提示输入yes/or,实际是把远程主机的公钥复制到本地, 会对管理带来很大的麻烦 [root@ansible1 ~]# vim /etc/ansible/ansible.cfg ##修改配置文件不用重启进度 host_key_checking = False
7.Ansible ad-hoc
ad-hoc:完成实时的,一次性的,简单的工作 ad-hoc语法规则 ansible -i iventory group -m module -a "mod_args" 主机文件 组名 模块 模块参数 [root@ansible1 inventory]# ansible -i reid reid -m ping 10.0.1.5 | SUCCESS => { "changed": false, "ping": "pong" } 10.0.1.6 | SUCCESS => { "changed": false, "ping": "pong" } 常用参数: -i 指定inventory文件 -m 指定模块 -a 参数命令 -u 指定访问用户 -k 输入密码 -K 输入sudo密码 -f 指定并行数量(默认5)
8.Ansible Inventory模块
ansible通过读取默认的主机清单配置/etc/ansible/hosts,可以同时连接到多个远程主机上执行任务,也可以同时使用多个清单文件,甚至可以动态地或者从云资源中拉取清单,inventory可以通过[startend]指定连续的地址,ssh连接时指定参数如非默认端口
[root@ansible1 ~]# mkdir ansible_test/inventory -pv [root@ansible1 inventory]# pwd /root/ansible_test/inventory [root@ansible1 inventory]# cat reid [reid] 10.0.1.5 10.0.1.6 [reid:vars] ansible_ssh_user=root ansible_ssh_pass=reid
9.ansible常用执行命令
ansible_module_address
[root@ansible1 ~]# ansible-doc -l [root@ansible1 ~]# ansible-doc shell -ping 用于检测远程主机是否存活 -shell 在远程主机上执行shell命令 -script 在远端机器执行本地脚本 -yum/apt 用于安装软件包 -service 用于管理服务 -file 用于配置文件属性 -copy 复制文件到远程主机 -setup 查看远程主机的基本信息
ping 检查目标主机是否存活(目标是否可达,信息是否正确)
[root@ansible1 inventory]# cat reid [reid] 10.0.1.8 ##不存在ip 10.0.1.6 [reid:vars] ansible_ssh_user=roor #错的账户 ansible_ssh_pass=reid [root@ansible1 inventory]# ansible -i reid reid -m ping 10.0.1.8 | UNREACHABLE! => { "changed": false, ##ip不可达 "msg": "Failed to connect to the host via ssh: ssh: connect to host 10.0.1.8 port 22: No route to host\r\n", "unreachable": true } 10.0.1.6 | UNREACHABLE! => { "changed": false, "msg": "Authentication failure.", ##认证有问题 "unreachable": true }
shell 在目标主机执行shell命令
chdir: 运行shell之前cd到某个目录
[root@ansible1 inventory]# ansible -i reid reid -m script -a "/root/ansible_test/script/test.sh" 10.0.1.5 | SUCCESS => { "changed": true, "rc": 0, "stderr": "Shared connection to 10.0.1.5 closed.\r\n", "stdout": "ansible test\r\n", "stdout_lines": [ "ansible test" ] } 10.0.1.6 | SUCCESS => { "changed": true, "rc": 0, "stderr": "Shared connection to 10.0.1.6 closed.\r\n", "stdout": "ansible test\r\n", "stdout_lines": [ "ansible test" ] }
apt/yum 模块分别用于管理ubuntut和redhat系列软件包
-name 软件包名 -state 软件包的状态(present/installed/absent/removed) 安装(`present' or `installed', `latest') 删除(`absent' or `removed') [root@ansible1 inventory]# ansible -i /root/ansible_test/inventory/reid reid -m yum -a "name=httpd state=present" \n\nComplete!\n
service 管理目标机器的状态
-name: 必选项,服务名称 -state: 当前服务执行启动、停止、重启(started,stopped,restarted,reloaded) -enabled: 是否开机启动 yes|no -runlevel: 运行级别 -arguments: 给命令行提供一些选项 [root@ansible1 inventory]# ansible -i reid reid -m service -a "name=httpd state=started"
copy 将文件从ansible管理机拷贝到目标机器(空的文件夹不生效)
-src 源文件 -dest 目标路径 -backup 覆盖之前,是否备份原文件 -owner 设定文件/目录的属主 -group 设定文件/目录的属组 -mode 设定文件/目录的权限 [root@ansible1 ansible_test]# mkdir file [root@ansible1 ansible_test]# echo hello > file/hello_world [root@ansible1 inventory]# ansible -i reid reid -m copy -a "src=/root/ansible_test/file/hello_world dest=/tmp owner=1002 group=1002 mode=777" [root@ansible2 ~]# ll /tmp/hello_world -rwxrwxrwx 1 1002 1002 6 Mar 13 06:19 /tmp/hello_world [root@ansible3 ~]# ll /tmp/hello_world -rwxrwxrwx 1 1002 1002 6 Mar 13 06:19 /tmp/hello_world
file 操作目标机器文件属性,新建/删除文件,文件夹及链接文件
-group:定义文件/目录的属组 -owner: 定义文件/目录的属主 -mode: 定义文件/目录的权限 -path: 必选项,定义文件/目录的路径 -state:定义文件状态(directory/link/absent/touch/hard) [root@ansible1 ansible_test]# ansible -i inventory/reid reid -m file -a "path=/tmp/file state=directory" [root@ansible2 ~]# ls -ld /tmp/file drwxr-xr-x 2 root root 6 Mar 16 02:00 /tmp/file
setup 搜索系统信息
场景使用:CMDB可以使用setup模块来获取硬件信息
-搜集主机的所有系统信息 ansible all -m setup -搜索系统信息并以主机名为文件名分别保存在/tmp/facts ansible all -m setup --tree /tmp/facts -搜集和内存相关的信息 ansible all -m setup -a "filter=ansibel_*_mb" -搜集网卡信息 ansible all -m setup -a "filter=ansible_eth[0-2]" [root@ansible1 ansible_test]# ansible -i inventory/reid reid -m setup
10.Ansible Playbook(剧本)
Playbooks 与 adhoc 相比,是一种完全不同的运用 ansible 的方式,是非常之强大的.
简单来说,playbooks 是一种简单的配置管理系统与多机器部署系统的基础.与现有的其他系统有不同之处,且非常适合于复杂应用的部署.
Playbooks 可用于声明配置,更强大的地方在于,在 playbooks 中可以编排有序的执行过程,甚至于做到在多组机器间,来回有序的执行特别指定的步骤.并且可以同步或异步的发起任务.
-以YAML文件作为载体
-描述多个任务的集合
-使用目标主机按照既定顺序执行任务以达到期望状态
-通过ansible-playbook命令执行
11.YAML语言
一种人性化数据格式定义语言
YAML: YAML Ain't a Markup Language
-结构感强,可读性好
-通用的数据串行化格式
(1)、语法要求
-以'---'作为起始句
-大小写敏感
-使用缩进表示层级关系
-缩进时不允许使用Tab键许使用空格
-缩进的空格数目不重要,相同层级元素左侧对齐即可
(2)、数据类型
-对象:键值对集合,又称为映射(mapping)/哈希(hashes)/字典(dictionary)
-数组:一组按次序排列的值,又称为序列(sequence)/列表(list)
-纯量(scalars):单个的、不可再分的值,组成数组和字典的数
(3)、YAML语法检查
Python
python -c 'import yaml,sys;print yaml.load(sys.stdin)'<test.yaml
YAML Lint
link_address
Ansible命令工具
ansible-playbook test.yaml --syntax-check
12.Play组成部分
-Target section: 定义将要执行playbook的远程主机组及属性
-Variable section: 定义playbook运行时需要使用的变量
-Task section: 定义将要在远程主机上执行的任务列表
Target section:
-hosts: 定义远程的主机组
-remote_user: 执行该任务组的用户,用什么用户执行
-sudo: 如果设置为yes,以sudo权限执行命令,一般在ubuntu上,默认是root没密码
-gather_facts: 默认收集setup模块传递来的变量,可禁止
Variable section:
-vars: 直接写入对象形式的变量名及其值
-var_files: 引入变量所在的文件,变量都写在文件中
系统变量:
-Setup模块(默认gather_facts=yes) 包括组和主机里所有信息
[root@ansible1 ~]# ansible -i ansible_test/inventory/reid reid -m setup
自定义变量:
-Iventory文件
-Playbook文件
-变量文件
在playbook中引用变量:{{var}}双大括号
Task section:
-由任务组成的列表,其中包含任务名,模块以及模块参数
运行Playbook: -i指定inventory文件,后面不接组名
ansible-playbook -i hosts playbook.yml ansible-playbook -i hosts playbook.yml --syntax-check #检查语法 ansible-playbook -i hosts playbook.yml --list-hosts #显示作用于的机器 ansible-playbook -i hosts playbook.yml --list-tasks #所执行的任务
13.Playbook实例
1).搭建http服务:要求在目标机器安装Http服务,修改主面,使用能显示自己的IP及主机名,运行httpd并设置为开机启动
步骤:
a.安装httpd包
b.将Index.html到远端服务器
c.使用setup获取的变量,修改index.html的内容
d.启动Httpd服务
先清除之前的安装包
[root@ansible1 ~]# ansible -i ansible_test/inventory/reid reid -m yum -a "name=httpd state=absent"
编写Yaml
[root@ansible1 ~]# cat /root/ansible_test/yaml/httpd.yml --- - hosts: reid gather_facts: yes remote_user: root tasks: - name: install apache yum: name: httpd state: present - name: copy index copy: src: ../file/index.html dest: /var/www/html - name: edit index shell: sed -i 's/ipaddr/{{ ansible_default_ipv4.address }}/;s/hostname/{{ ansible_hostname }}/' /var/www/html/index.html - name: start service service: name: httpd state: started enabled: yes
提供index页面
[root@ansible1 ansible_test]# cat /root/ansible_test/file/index.html <html> <body> <h1>hello, my ip is ipaddr,my name is hostname.</h1> </body> </html>
执行playbook,-v详细输出
[root@ansible1 ~]# ansible-playbook -i /root/ansible_test/inventory/reid /root/ansible_test/yaml/httpd.yml -v 运行结果颜色说明 -黄色:执行成功,目录机器状态改变 -绿色:执行成功,目标机器状态不改变 -红色:执行失败
14.Playbook高级技巧
-with_items: 任务循环
-when: 条件判断
-register: 变量注册
-template: jinja2模板
-include: 任务引用
-tags: 任务标签
with_items
描述:在一个任务task中,遍历with_items内列表中的元素(由纯量或对象集合组成),循环执行任务,直到遍历结束,with_items本身是一个对象,它的值由列表组成,列表中的元素是纯量和对象的集合
如:在playbook中通过yum模块来安装很多包,但只能接收一个包名,所以只能在Playbook里写多个Yum的任务,来安装每个包,这样会让playbook显得很繁琐和笨重,这时可以通过with_items来构建循环,把要安装的包放在一个列表,只需要一个yum任务对列表里的包名进行遍历执行安装,直到所有包安装完成.
变量引用
-纯量: {{item}}
-对象: {{item.vars}}
纯量遍历
对象遍历
实例
[root@ansible1 yaml]# cat dict.yml --- - hosts: all tasks: - name: create folder file: dest: /tmp/{{ item }} state: directory with_items: - test_folder1 - test_folder2 [root@ansible1 yaml]# ansible-playbook dict.yml --syntax-check [root@ansible1 yaml]# ansible-playbook -i /root/ansible_test/inventory/reid dict.yml -v [root@ansible2 ~]# ls /tmp/test_folder* /tmp/test_folder1: /tmp/test_folder2:
register
描述:将任务运行结果注册为变量,多用于将shell执行结果注册
-命令: register: vars
-任务结果是字典,其中包含:
-changed 状态是否改变
-failed 是否失败
-stdout 标准输出
-stderr 标准错误
[root@ansible1 yaml]# cat register.yml --- - hosts: all tasks: - name: test output shell: echo 'hello' #把所有结果注册成运行变量 [root@ansible1 yaml]# cat register.yml --- - hosts: all tasks: - name: test output shell: echo 'hello' register: test - name: test output shell: echo {{ test }} ##也就是引用上一个shell的结果 [root@ansible1 yaml]# cat register.yml --- - hosts: all tasks: - name: test output shell: echo 'hello' register: test - name: test output shell: echo {{ test.stdout }} ##直接引用输出的结果hello
when
描述:根据变量判断任务是否执行和register是最佳搭配,变量包括setup、自定义、register中的变量,如通过系统变量来获取操作系统类型,返回是redhat就使用yum,返回ubuntu就使用apt安装,通过register来获取软件版本,因为有些是要通过shell来获取的,可以把这些命令返回的结果注册在一个变量里,判断软件版本是否某个版本用于对其作升级
变量判断形式:注意使用双引号
-变量是否等于某个值 when: "vars == 'str" -变量是否有某个值 when: "'str' in vars" -变量是否存在 when: vars
实例:判断目标机器是否ansible2,是的就执行一个echo
[root@ansible1 yaml]# cat when.yml --- - hosts: all tasks: - name: get hostname shell: hostname register: hostname - name: echo shell: echo 'I''m ok' when: " hostname.stdout == 'ansible2'" [root@ansible1 yaml]# ansible-playbook -i /root/ansible_test/inventory/reid when.yml -v TASK [echo] *********************************************************************************************** skipping: [10.0.1.6] => {"changed": false, "skip_reason": "Conditional result was False"} changed: [10.0.1.5] => {"changed": true, "cmd": "echo 'I''m ok'", "delta": "0:00:00.006962", "end": "2018-03-21 06:33:50.032821", "rc": 0, "start": "2018-03-21 06:33:50.025859", "stderr": "", "stderr_lines": [], "stdout": "Im ok", "stdout_lines": ["Im ok"]}
template
描述:使用jinja2模板,将模板文件从ansible控制机发送到控制机,并对变量赋值,使用场景是有时可能需要修改很多机器的系统和配置文件,一般修改后传到目标机器或者在目标机器直接修改,这两种都不能很好的识别ansible的变量,使用shell可能会很繁琐,所以使用template可以使用变量替代修改项,直接在目标机器替换值,这样可以非常方便发送自定义的配置文件,还可以使用if和for循环来灵活制定
参数:
-src: 本地jinjia2模板的template文件位置
-dest: 远程节点上的绝对路径,用于放置template文件
-mode/owner/group/backup
例子:
- template: src: /mytemplates/foo.conf.j2 #通常j2结尾 dest: /etc/foo.conf mode: 644
需求:创建模板文件,分配到两台机器上
[root@ansible1 ~]# cat ansible_test/inventory/reid [reid] 10.0.1.5 name=client1 # 10.0.1.6 name=client2 #会使用到name [reid:vars] ansible_ssh_user=root ansible_ssh_pass=reid [root@ansible1 ~]# mkdir ansible_test/template [root@ansible1 ~]# vim ansible_test/template/test.conf.j2 hostname: {{ name }} ##引用inventory的name ssh_port: {{ sshport }} http_port: {{ httpport }} [root@ansible1 ~]# cat ansible_test/yaml/template.yml --- - hosts: all vars: - sshport: 8022 - httpport: 8080 tasks: - name: create config template: src: /root/ansible_test/template/test.conf.j2 dest: /tmp/ [root@ansible1 ~]# ansible-playbook -i /root/ansible_test/inventory/reid /root/ansible_test/yaml/template.yml -v [root@ansible2 ~]# cat /tmp/test.conf.j2 hostname: client1 ##inventory中的变量 ssh_port: 8022 http_port: 8080
Include
描述:调用外部任务文件,便于任务集统一更新,维护,如果服务器集群越来越大,playbook越来越多,如修改服务器密码ssh,会放在许多的playbook中,因为这些playbook需要使用这些功能,一旦发生密码要更新和配置改变,就要修改每个playbook里的配置,这种强度和容错率是无法估计的,使用include就可以直接调用外部任务文件
- hosts: all tasks: - include: /ansible/tasks/change_pwd.yml
任务文件只有task section
- name: aaa module 1: - name: bbb module 2: - name: ccc module 3:
实例:任务文件只是任务级,没有host section
[root@ansible1 ~]# cat ansible_test/yaml/when.yml ##把两个tasks放在一个新的yml中 --- - hosts: all tasks: - name: get hostname shell: hostname register: hostname - name: echo shell: echo 'I''m ok' when: " hostname.stdout == 'ansible2'" [root@ansible1 ~]# cat ansible_test/yaml/hostname.yml - name: get hostname shell: hostname register: hostname - name: echo shell: echo 'I''m ok' when: " hostname.stdout == 'ansible2'"
在when.yml中使用include
[root@ansible1 ~]# cat ansible_test/yaml/when.yml --- - hosts: all tasks: - include: hostname.yml #可以使用绝对路径 [root@ansible1 ~]# ansible-playbook -i ansible_test/inventory/reid ansible_test/yaml/when.yml -v TASK [echo] ************************************************************************************************************************* skipping: [10.0.1.6] => {"changed": false, "skip_reason": "Conditional result was False"} changed: [10.0.1.5] => {"changed": true, "cmd": "echo 'I''m ok'", "delta": "0:00:00.005941", "end": "2018-03-21 07:34:17.458820", "rc": 0, "start": "2018-03-21 07:34:17.452879", "stderr": "", "stderr_lines": [], "stdout": "Im ok", "stdout_lines": ["Im ok"]}
tags
描述:为任务打标签,执行playbook可以选择或路过指定tag任务,如果Playbook实现很多功能,建议相同功能的打同一个标签,后期方便调用
- name: print sth shell: echo 'hello' tags: aaa - 只执行带aaa标签的任务 ansible-playbook test.yml --tags aaa - 只执行带aaa,bbb标签的任务 ansible-playbook test.yml --tags aaa,bbb - 跳过带aaa标签的任务 ansible-play test.yml --skip-tags aaa
实例:新一个Playbook,写两个任务,打tags,再执行任务来查看
[root@ansible1 ~]# vim ansible_test/yaml/tag.yml --- - hosts: all tasks: - name: task1 shell: echo 'hello reid' tags: task1 - name: task2 shell: echo 'hello reid2' tags: task2
顺序执行
[root@ansible1 ~]# ansible-playbook -i ansible_test/inventory/reid ansible_test/yaml/tag.yml -v
只执行task1
[root@ansible1 ~]# ansible-playbook -i ansible_test/inventory/reid ansible_test/yaml/tag.yml --tags task1 -v
跳过
[root@ansible1 ~]# ansible-playbook -i ansible_test/inventory/reid ansible_test/yaml/tag.yml --skip-tags task1 -v
15.实战playbook
搭建HTTP,NFS服务器
-要求:在目标机器中安装apche&nfs服务,修改主页使用其能显示自己的IP,OS版本,主机名以及创建时间,在目标服务器建立两rw和ro属性的文件夹并将其通过nfs共享,启动apache&nfs服务
-步骤:
1.针对不同系统,安装apache
2.将当前的时间注册成变量(register)
3.使用模板文件在目标机器生成Index.html
4.启动apache服务
5.include nfs安装yml文件
6.在Nfs yml文件里针对不同系统安装nfs服务
7.新建不同权限的共享文件夹
8.添加文件夹到nfs exports
9.启动nfs服务
[root@ansible1 ~]# vim ansible_test/yaml/general.yml

1 --- 2 - hosts: all 3 tasks: 4 - name: install apache in centos 5 yum: 6 name: httpd 7 state: present 8 when: "ansible_distribution == 'CentOS'" 9 tags: apache 10 - name: install apache in ubuntu 11 apt: 12 name: apache2 13 state: present 14 when: "ansible_distribution == 'Ubuntu'" 15 tags: apache 16 - name: regisger time 17 shell: date 18 register: cur_time 19 tags: apache 20 - name: transfer file 21 template: 22 src: ../template/index.html.j2 23 dest: /var/www/html/index.html 24 tags: apache 25 - name: start apache 26 service: 27 name: httpd 28 state: started 29 when: "ansible_distribution == 'CentOS'" 30 tags: apache 31 - name: start apache in ubuntu 32 service: 33 name: apache2 34 state: started 35 when: "ansible_distribution == 'Ubuntu'" 36 tags: apache 37 - include: nfs.yml 38 tags: nfs
[root@ansible1 ~]# cat ansible_test/yaml/nfs.yml

1 --- 2 - name: install nfs in centos 3 yum: 4 name: nfs-utils 5 state: present 6 when: "ansible_distribution == 'CentOS'" 7 - name: install nfs in ubuntu 8 apt: 9 name: nfs-kernel-server 10 state: present 11 when: "ansible_distribution == 'Ubuntu'" 12 - name: create folder 13 file: 14 dest: "/{{ item.folder }}" 15 mode: "{{ item.mode }}" 16 state: directory 17 with_items: 18 - { folder: data_rw, mode: 777 } 19 - { folder: data_ro, mode: 755 } 20 - name: export folder 21 shell: echo '/{{ item }} *(rw,sync,no_subtree_check,no_root_squash)' >> /etc/exports 22 with_items: 23 - data_rw 24 - data_ro 25 - name: start nfs service in centos 26 service: 27 name: nfs 28 state: started 29 when: "ansible_distribution == 'CentOS'" 30 - name: start nfs service in ubuntu 31 service: 32 name: nfs-kernel-service 33 state: started 34 when: "ansible_distribution == 'Ubuntu'"
挂载
[root@ansible1 ~]# mkdir /data_rw /data_ro [root@ansible1 ~]# mount -t nfs 10.0.1.5:/data_rw /data_rw [root@ansible1 ~]# mount -t nfs 10.0.1.6:/data_ro /data_ro [root@ansible1 ~]# df -h Filesystem Size Used Avail Use% Mounted on 10.0.1.5:/data_rw 30G 1.4G 29G 5% /data_rw 10.0.1.6:/data_ro 30G 1.3G 29G 5% /data_ro [root@ansible1 ~]# ls -ld /data_r* drwxr-xr-x 2 root root 6 Mar 22 01:44 /data_ro ##777 drwxrwxrwx 2 root root 18 Mar 22 01:58 /data_rw ##755 [root@ansible1 ~]# ls -ld /data_r* drwxr-xr-x 2 root root 6 Mar 22 01:44 /data_ro drwxrwxrwx 2 root root 18 Mar 22 01:58 /data_rw
测试
[root@ansible1 ~]# touch /data_rw/reid [root@ansible2 ~]# ls /data_rw reid
16.Ansible Roles
-用于实现某特定功能(高级的include)
-是变量,模板,文件,任务的集合
-强依赖文件目录结构
-默认目录是:/etc/ansible/roles
-使用:如有docker和k8s两个role
--- - hosts: all roles: - docker - k8s
从ansible galaxy网站下载roles : ansible_web ansible_explore
下载role(如ceph.ceph-defaults:ceph是username,ceph-defaults是rolename,-p是保存的位置)
ansible-galaxy install -p ./role username.rolename
查看role的具体信息
ansible-galaxy info username.rolename