01 . Ansible原理部署及简单应用
介绍:
Ansible是什么?
Ansible 是个与 Puppet, SaltStack, Chef 并驾齐驱的组态设定 (Infrastructure as Code) 工具,其简单易用的特性让人爱不释手,在 DevOps 界更佔有一席之地。
Ansible 提供一种最简单的方式用于发布、管理和编排计算机系统的工具,你可在数分钟内搞定。
Ansible 是一个模型驱动的配置管理器,支持多节点发布、远程任务执行。默认使用 SSH 进行远程连接。无需在被管理节点上安装附加软件,可使用各种编程语言进行扩展。
Ansible特性
# 拥有模块化的设计,Ansible能够调用特定的模块来完成特定任务 ,本身是核心组件,短小精悍 ;
# Ansible是基于**Python语言**实现的,由Paramiko (python 的一个可并发连接 ssh 主机功能库 ) , PyYAML和Jinja2 ( 模板化 ) 三个关键模块实现;
# Ansible的部署比较简单,agentless 无客户端工具;
# 以主从模式工作;
# 支持自定义模块功能;
# 支持playbook剧本,连续任务按先后设置顺序完成;
# 期望每个命令具有**幂等性**:
Ansible 的命名由来?
# 此名取自 Ansible 作者最喜爱的[《安德的游戏》
# 大家或许早在电影中就已看过[安塞波 (Ansible)**](http://enderverse.wikia.com/wiki/Ansible),它是虚构的超光速通讯装置。
# 片中主角安德 (Ender) 和他的伙伴们透过 Ansible 跨越时空指挥无数的战舰,就好比我们操控海量的远端服务器一样。
前人怎么说 Ansible?
摘至[《奔跑吧 Ansible》](http://www.phei.com.cn/module/goods/wssd_content.jsp?bookid=44223)第 ix 页的推荐序二。
运维自动化工具本来是用来简化维运工作的,但如果工具本身比较复杂,甚至需要一定的程序开发能力,就会增加使用和推广的难度。Ansible 有三个最吸引人的地方:无客户端、简单易用和日志集中控管。
Ansible 很简单,上手方便,不需要啃一本很大本的书才能学会使用 (从这一点来看,这可谓业界良心)。
- 萧田国 (开放运维联盟联合主席,高效运维社区发起人)
我希望自动化的事情尽快完成,这样我就能有更多时间投入在我更该关注的事情上面。Ansible 并不是一个你需要整天和它打交道的系统。你可以很快地把它拿起来,很快地搞定,然后又很快地回到你更该关心的事情上面。
# 1. Python 阵营的组态管理工具!个人对 Python 熟悉度大于 Ruby。[3](https://www.w3cschool.cn/automate_with_ansible/automate_with_ansible-atvo27or.html#fn_3)
# 2. 不用帮每台机器 (instance) 预载 agent [4](https://www.w3cschool.cn/automate_with_ansible/automate_with_ansible-atvo27or.html#fn_4),只要有 SSH 和 Python 就可以闯天下!
# 3. 在台湾的市占率较高
# 4. 在目前 4 大主流的组态管理工具 (Puppet, SaltStack, Chef, Ansible) 中, Ansible 是最容易上手,且马上就可以用的工具。(自己说)
使用 Ansible 需要具备什么基础知识?
1. 具备 Linux 服务器 (server) 基础操作和管理经验。
2. 会使用 ssh 远端连线至 server。
3. 知道基本的标准输入 (stdin) 输出 (stdout) 等观念
4. 会安装 Linux 套件。
5. 知道 `sudo` 指令在做什么,并且会使用它
6. 知道什么是档案权限,并且会修改它。
7. 知道如何启用和停止系统服务 (Daemon / Service)。
8. 会撰写简易的脚本 (Script)。
# 您已成功踏入 Ansible 的大门,恭喜你!
Ansible环境部署?
Ansible 是怎么运作的?
在 Ansible 的世界里,我们会通过 **inventory 档案**来定义有哪些 **Managed node** (被控端),并借由 **SSH** 和 **Python** 进行沟通。
换句话说,当 Control Machine (主控端) 可以用 SSH 连上 Managed node,且被连上的机器里有预载 Python 时,Ansible 就可以运作了!
Control Machine
指的是我们主要会在上面操作 Ansible 的机器,冻仁喜欢用主控端来形容它。它可以是我们平时用的电脑、手机 1 或机房里的某一台机器,也可以把它想成是一般 Lab 练习里的Workstation
。Managed node
则是被 Ansible 操纵的机器,冻仁喜欢用被控端来形容它。在很多的 Lab 练习里会用Server
来称呼它。
怎么安装 Ansible?
在一般的情况下,**我们只需在 Control Machine 里安装 Ansible 即可**,因为 GNU/Linux 和 macOS 的 Managed node 都早已预载了 Python 2.5 以上的版本,且开通了 SSH 连线的条件。
CentOS(Yum)
[root@node1 ~]# yum -y install epel-release
[root@node1 ~]# yum -y install ansible
# Ansible 近来的释出速度很快,若想追求较新的版本可改用 Pip 的方式进行安装,较不建议初学者使用。
# 需请先安装 pip,已安装者请略过。
[root@node1 ~]# yum -y install python-pip
[root@node1 ~]# pip install -U pip
[root@node1 ~]# pip install ansible
# 关闭SE,防火墙
systemctl stop firewalld
systemctl disable firewalld &>/dev/null
setenforce 0
sed -i '/^SELINUX=/ s/enforcing/disabled/' /etc/selinux/config
sed -i '/^GSSAPIAu/ s/yes/no/' /etc/ssh/sshd_config
sed -i '/^#UseDNS/ {s/^#//;s/yes/no/}' /etc/ssh/sshd_config
# 域名解析
[root@node1 ~]# cat /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
39.108.140.0 node1
49.233.69.195 node2
47.92.24.137 master
报错整理
# 如果执行ansible命令老是报错以下版本不匹配
/usr/lib/python2.7/site-packages/requests/__init__.py:80: RequestsDependencyWarning: urllib3 (1.22) or chardet (2.2.1) doesn't match a supported version!
RequestsDependencyWarning)
# 解决办法
pip uninstall urllib3
pip uninstall chardet
pip install requests
定义主机清单
# ssh-key(可选,免密码)
ssh-keygen
ssh-copy-id IP地址 # 推送公钥
vim /etc/ansible/hosts
[webserver] # 增加主机组
master
node2
去掉(yes/no)的询问
vim /etc/ssh/ssh_config
StrictHostKeyChecking no
# systemctl restart sshd
[root@node1 ~]# ansible webserver -m ping -k -o # 并不是真的ping,只是检查客户端的22号端口是否在提供工作.
# -o 简介输出
# -k 输入密码
# -m 指定模块
SSH password:
node2 | SUCCESS => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": false, "ping": "pong"}
master | SUCCESS => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": false, "ping": "pong"}
# 增加用户名 密码
vim /etc/ansible/hosts
[webserver]
node1 ansible_ssh_user='root' ansible_ssh_pass='flying' # 此处可以加上ansible本机,也可以不加
master ansible_ssh_user='root' ansible_ssh_pass='flying'
node2 ansible_user='root' ansible_ssh_pass='flying'
# 此处如果有node3,node4可以这样写
# node[2:5] ansible_ssh_user='root' ansible_ssh_pass='flying'
# 如果默认端口sshd端口不一样需要修改,需要指定端口
# node2 ansible_ssh_user='root' ansible_ssh_pass='flying' ansible_ssh_port='2222'
[root@node1 ~]# ansible webserver -m ping -o
node2 | SUCCESS => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": false, "ping": "pong"}
master | SUCCESS => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": false, "ping": "pong"}
# 免密成功
# 自定义主机列表
vim /opt/hosts
[webserver]
node2
master
[webserver:vars]
ansible_ssh_user='root'
ansible_ssh_pass='flying'
[root@node1 ~]# ansible -i /opt/hostlist webserver -m ping -o
node2 | SUCCESS => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": false, "ping": "pong"}
master | SUCCESS => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": false, "ping": "pong"}
Ansible模块(Ad-Hoc)
# ad hoc 临时的点对点模式,在ansible中只需要快速执行一条简单的命令,不需要保存起来,对于复杂的命令则为playbook剧本,剧本就是ad hoc的集合
Shell模块
# shell模块
# 执行远程命令
# 获取主机名
[root@node1 ~]# ansible webserver -m shell -a 'hostname' -o -f 3
node1 | CHANGED | rc=0 | (stdout) node1
node2 | CHANGED | rc=0 | (stdout) node2
master | CHANGED | rc=0 | (stdout) master
# -f 指定线程数,默认为5
# 查询系统负载
[root@node1 ~]# ansible webserver -m shell -a "uptime" -o
node1 | CHANGED | rc=0 | (stdout) 18:26:58 up 2 days, 5:44, 2 users, load average: 0.26, 0.13, 0.09
node2 | CHANGED | rc=0 | (stdout) 18:26:59 up 1:36, 2 users, load average: 0.00, 0.01, 0.05
master | CHANGED | rc=0 | (stdout) 18:26:59 up 152 days, 5:07, 3 users, load average: 0.05, 0.05, 0.05
# -a 单条指令
[root@node1 ~]# ansible webserver -m shell -a 'date' -o
node1 | CHANGED | rc=0 | (stdout) 2019年 10月 19日 星期六 18:30:43 CST
node2 | CHANGED | rc=0 | (stdout) 2019年 10月 19日 星期六 18:30:44 CST
master | CHANGED | rc=0 | (stdout) 2019年 10月 19日 星期六 18:30:44 CST
[root@node1 ~]# ansible-doc -l
# A10、华为、docker、EC2、aws等等广大厂商设备都可以使用ansible配置
Yum模块
# yum模块
# ansible-doc yum
[root@node1 ~]# ansible webserver -m yum -a 'name=httpd state=latest'
[root@node1 ~]# ansible webserver -m shell -a 'yum -y install httpd'
[root@node1 ~]# ansible webserver -m yum -a 'name=git state=latest'
软件包管理
[root@node1 ~]# ansible webserver -m yum -a 'name='*' state=latest'
Copy模块
# copy模块
# 帮助 ansible-doc copy
[root@node1 LinuxBasicsScript]# ansible webserver -m copy -a 'src=/root/Shell-Script/LinuxBasicsScript/SystemInit.sh dest=/tmp/init.sh owner=root group=bin mode=777'
[root@node1 LinuxBasicsScript]# webserver -m copy -a 'src=/root/Shell-Script/LinuxBasicsScript/SystemInit.sh dest=/tmp/init.sh owner=root group=bin mode=777 backup=yes'
用户模块
# 用户模块
# 帮助 ansible-doc user
[root@node1 LinuxBasicsScript]# ansible webserver -m user -a 'name=you-men state=present' # 创建用户
[root@node1 LinuxBasicsScript]# ansible webserver -m shell -a 'id you-men' -o
node1 | CHANGED | rc=0 | (stdout) uid=1001(you-men) gid=1001(you-men) 组=1001(you-men)
node2 | CHANGED | rc=0 | (stdout) uid=1000(you-men) gid=1000(you-men) 组=1000(you-men)
master | CHANGED | rc=0 | (stdout) uid=1000(you-men) gid=1000(you-men) 组=1000(you-men)
[root@node1 LinuxBasicsScript]# ansible webserver -m user -a 'name=you-men state=absent' # 删除用户
[root@node1 LinuxBasicsScript]# echo 'flying' |openssl passwd -1 -stdin
$1$.S0IFUnt$fBzDPKxWW.LA.Lk9uY/uU/
[root@node1 LinuxBasicsScript]# ansible webserver -m user -a 'name=you-men password="$1$m7aHxxyj$t87ouiCD4TFcVp66UPsOI/"'
# 修改密码
[root@node1 LinuxBasicsScript]# ssh you-men@47.92.24.137
you-men@47.92.24.137's password:
Last login: Sat Oct 19 19:05:29 2019 from 39.108.140.0
Welcome to Alibaba Cloud Elastic Compute Service !
[you-men@master ~]$
-----------------------------------------------------------
[root@node1 LinuxBasicsScript]# ansible webserver -m user -a 'name=you-men shell=/sbin/nologin append=yes' # 修改shell
[root@node1 LinuxBasicsScript]# ssh you-men@47.92.24.137
you-men@47.92.24.137's password:
Last login: Sat Oct 19 19:10:17 2019 from 39.108.140.0
Welcome to Alibaba Cloud Elastic Compute Service !
This account is currently not available.
Connection to 47.92.24.137 closed.
# 只需要将shell修改为/bin/bash即可恢复正常用户
服务模块
# 帮助 ansible-doc service
[root@node1 ~]# ansible webserver -m service -a 'name=httpd state=started enabled=yes' # 启动服务并设置开机自启动
[root@node1 LinuxBasicsScript]# ansible webserver -m shell -a 'curl -I http://localhost:80'
[root@node1 LinuxBasicsScript]# ansible webserver -m service -a 'name=httpd state=stopped' # 停止服务
[root@node1 LinuxBasicsScript]# ansible webserver -m service -a 'name=httpd state=restarted' # 重启服务
[root@node1 LinuxBasicsScript]# ansible webserver -m service -a 'name=httpd state=started enabled=no' # 开机不启动
文件模块
# 帮助 ansible-doc file
[root@node1 LinuxBasicsScript]# ansible webserver -m file -a 'path=/tmp/88.txt mode=777 state=touch' # 创建文件
[root@node1 LinuxBasicsScript]# ansible webserver -m file -a 'path=/tmp/99.txt mode=777 state=directory' # 创建目录
[root@node1 LinuxBasicsScript]# ansible webserver -m shell -a 'ls -l /tmp/88.txt' -o
node1 | CHANGED | rc=0 | (stdout) -rwxrwxrwx 1 root root 0 10月 19 19:39 /tmp/88.txt
node2 | CHANGED | rc=0 | (stdout) -rwxrwxrwx 1 root root 0 10月 19 19:39 /tmp/88.txt
master | CHANGED | rc=0 | (stdout) -rwxrwxrwx 1 root root 0 10月 19 19:39 /tmp/88.txt
解压模块
[root@node1 ~]# ansible all -m get_url -a "url=http://nginx.org/download/nginx-1.17.4.tar.gz dest=/root mode=0440 force=yes"
# 下载文件到指定目录
[root@node1 ~]# ansible all -m unarchive -a "src=/root/nginx-1.17.4.tar.gz dest=/tmp/ mode=0755 copy=yes"
# 解压ansible管理机上的压缩文件到远程主机
[root@node1 ~]# ansible all -m unarchive -a "src=/root/nginx-1.17.4.tar.gz dest=/opt/ mode=0755 copy=no"
# 解压远程主机上的文件到目录
收集模块
# 帮助 ansible-doc setup
[root@node1 ~]# ansible webserver -m setup # 查询所有信息
[root@node1 ~]# ansible webserver -m setup -a 'filter=ansible_all_ipv4_addresses' -o # 收集各个主机的内网ip地址
node1 | SUCCESS => {"ansible_facts": {"ansible_all_ipv4_addresses": ["172.17.23.57"], "discovered_interpreter_python": "/usr/bin/python"}, "changed": false}
master | SUCCESS => {"ansible_facts": {"ansible_all_ipv4_addresses": ["172.26.251.11"], "discovered_interpreter_python": "/usr/bin/python"}, "changed": false}
node2 | SUCCESS => {"ansible_facts": {"ansible_all_ipv4_addresses": ["172.21.0.5"], "discovered_interpreter_python": "/usr/bin/python"}, "changed": false}
[root@node1 ~]# ansible webserver -m setup -a 'filter=ansible_processor_cores' -o # 收集cpu数量,可以设置nginx启动的线程数
node1 | SUCCESS => {"ansible_facts": {"ansible_processor_cores": 1, "discovered_interpreter_python": "/usr/bin/python"}, "changed": false}
master | SUCCESS => {"ansible_facts": {"ansible_processor_cores": 1, "discovered_interpreter_python": "/usr/bin/python"}, "changed": false}
node2 | SUCCESS => {"ansible_facts": {"ansible_processor_cores": 1, "discovered_interpreter_python": "/usr/bin/python"}, "changed": false}
Playbook
# 语法的注意事项
# yaml语言使用空格进行分割,不可以使用tab键,否则会报错
# yaml语言通常是---开始的,也可以不写
# playbook是由一个或多个'play'组成的列表,play的主要功能在于将事先归并于一组的主机装扮成事先通过ansible中的task定义好的角色,从根本上来讲,所谓task无非是调用ansible的一个module,将多个play组织在一个playbook中,即可以让他们联合起来按实现编排的机制完成某一个任务.
apache Demo
# 清除环境
[root@node1 ~]# ansible all -m yum -a 'name=httpd state=absent'
# 编写apache安装启动修改配置文件全套动作的剧本
[root@node1 ~]# mkdir /apache
[root@node1 ~]# cd /apache
[root@node1 apache]# cp /etc/httpd/conf/httpd.conf .
[root@node1 apache]# grep '^Listen' httpd.conf
Listen 8080
[root@node1 apache]# cat apache.yaml # 名字自定义
---
- hosts: webserver
tasks: # 这个任务是主机,不能加-,是隶属关系
- name: Install Apache Package # 自定义task下面一个任务的名字
yum: name=httpd state=present
- name: Copy Apache Conf
copy: src=/apache/httpd.conf dest=/etc/httpd/conf/conf/httpd.conf
- name: ensure apache is running
service: name=httpd state=started enabled=yes
[root@node1 apache]# ansible-playbook apache.yaml --syntax-check
# 检查是否有语法错误
playbook: apache.yaml
[root@node1 apache]# echo $?
0
# 列出任务列表
[root@node1 apache]# ansible-playbook apache.yaml --list-task
playbook: apache.yaml
play #1 (webserver): webserver TAGS: []
tasks:
Install Apache Package TAGS: []
Copy Apache Conf TAGS: []
ensure apache is running TAGS: []
[root@node1 apache]# ansible-playbook apache.yaml --list-hosts
playbook: apache.yaml # 列出执行任务的主机列表
play #1 (webserver): webserver TAGS: []
pattern: [u'webserver']
hosts (3):
node1
node2
master
[root@node1 apache]# cat apache.yaml
---
- hosts: webserver
tasks:
- name: Install Apache Package
yum: name=httpd state=present
- name: Copy Apache Conf
copy: src=/apache/httpd.conf dest=/etc/httpd/conf/httpd.conf
- name: ensure apache is running
service: name=httpd state=started enabled=yes
handlers: # 当配置文件发生更改之后,处理器需要被触发从而产生一个事件,重新加载进程,handlers和tasks是并列关系.
- name: Restart Apache Service
service: name=httpd state=restarted
# 如果服务原来就是启动的,那个修改配置文件之后的再次启动是不生效的,所以需要有一个触发器,一旦修改了配置文件,那个就触发重启服务的操作:
[root@node1 apache]# ansible-playbook apache.yaml
# 执行时会先搜集任务信息
PLAY [webserver] ***************************************************************************
TASK [Gathering Facts] *********************************************************************
ok: [node1]
ok: [node2]
ok: [master]
TASK [Install Apache Package] **************************************************************
ok: [node1]
changed: [node2]
changed: [master]
TASK [Copy Apache Conf] ********************************************************************
fatal: [node1]: FAILED! => {"changed": false, "checksum": "1fb15fc07df5cace0db41401584e59bcb72ecc04", "msg": "Destination directory /etc/httpd/conf/conf does not exist"}
fatal: [node2]: FAILED! => {"changed": false, "checksum": "1fb15fc07df5cace0db41401584e59bcb72ecc04", "msg": "Destination directory /etc/httpd/conf/conf does not exist"}
fatal: [master]: FAILED! => {"changed": false, "checksum": "1fb15fc07df5cace0db41401584e59bcb72ecc04", "msg": "Destination directory /etc/httpd/conf/conf does not exist"}
PLAY RECAP *********************************************************************************
master : ok=2 changed=1 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
node1 : ok=2 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
node2 : ok=2 changed=1 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
[root@node1 apache]# ansible webserver -m shell -a 'ss -antp |grep :8080'
Role角色扮演
# roles实在ansible中,playbooks的目录组织结构。
# 将代码或文件进行模块化,成为roles的文件目录组织结构,易读,代码可重用,层次清晰.
通过role远程部署Nginx并部署
[root@node1 ~]# mkdir /role
[root@node1 ~]# cd /role
[root@node1 role]# mkdir nginx/{files,handlers,vars,tasks,templates} -p
[root@node1 role]# touch nginx/{tasks,handlers,vars}/main.yaml
[root@node1 role]# touch /role/site.yaml
[root@node1 role]# echo welcome to nginx > /role/nginx/index.html
[root@node1 role]# tree /role/
/role/
├── nginx
│ ├── files
│ ├── handlers
│ │ └── main.yaml
│ ├── index.html
│ ├── tasks
│ │ └── main.yaml
│ ├── templates
│ └── vars
│ └── main.yaml
└── site.yaml
6 directories, 5 files
# 将每一个功能分离出来定义成角色更有条理性
# site.yaml: 是一个习惯性的命名方式,存放在那个主机用那个角色
# vars: 用于存放变量,这个变量是用在整个角色中的,如果没有变量,此目录不需要创建.
# templates: ansible的jinja2模板就是template模板,该模板和copy模板作用基本一样,都是把某个文件复制到远端主机上,但是区别在于template模板可以获取变量的值,而copy则是原封不动的把文件内容复制过去.
# files: 存放一些配置文件,源,包,不需要传参的文件
# handlers: 运行任务后的触发动作
# tasks: 运行任务列表
# ansible机器准备nginx源
cat /etc/yum.repos.d/nginx.repo
[nginx-stable]
name=nginx stable repo
baseurl=http://nginx.org/packages/centos/$releasever/$basearch/
gpgcheck=1
enabled=1
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true
[root@node1 role]# cp /etc/yum.repos.d/nginx.repo /role/nginx/files/
[root@node1 role]# yum -y install nginx
[root@node1 role]# cp /etc/nginx/nginx.conf /role/nginx/templates/nginx.conf.j2 # j2是一个Jinja模板文件
# 修改配置文件
[root@node1 role]# grep {{ nginx/templates/nginx.conf.j2
worker_processes {{ ansible_processor_cores }};
worker_connections {{worker_connections}};
[root@node1 role]# grep {{ nginx/templates/default.conf.j2
listen {{ ports }};
# 第一个变量是ansible中的facts中自带的变量,用于获取cpu的总数,可以不定义
# 第二个变量需要自己定义
[root@node1 role]# ls
nginx site.yaml
[root@node1 role]# cat site.yaml
---
- hosts: webserver
roles:
- nginx # 此处的nginx对应/role/nginx,相当于一个角色,可以再来php,mysql,这样就条理很清晰
# 写tasks角色中的yaml文件
[root@node1 role]# cat nginx/tasks/main.yaml
---
- name: Copy Nginx Source
copy: src=nginx.repo dest=/etc/yum.repos.d/nginx.repo
- name: Install Nginx Package
yum: name=nginx state=present
- name: Copy Nginx.conf Template
template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
notify: restart nginx
- name: Copy Default.conf Template
template: src=default.conf.j2 dest=/etc/nginx/conf.d/default.conf
notify: restart nginx
- name: Copy index.html
copy: src=index.html dest=/usr/share/nginx/html/index.html
- name: make sure nginx service running
service: name=nginx state=started enabled=yes
# 写handlers角色中的yaml文件
[root@node1 role]# cat nginx/handlers/main.yaml
---
- name: restart nginx
service: name=nginx state=restarted
# 写vars角色中定义变量
[root@node1 role]# cat nginx/vars/main.yaml
worker_connections: 10240
ports: 8080
# 演ansible的剧本
[root@node1 role]# ansible-playbook site.yaml # 注意路径
# 检测剧本是否成功
[root@node1 role]# ansible webserver -m shell -a 'ss -antp |grep nginx' -o
node1 | CHANGED | rc=0 | (stdout) LISTEN 0 128 *:8080 *:* users:(("nginx",pid=11230,fd=6),("nginx",pid=11229,fd=6))
node2 | CHANGED | rc=0 | (stdout) LISTEN 0 128 *:8080 *:* users:(("nginx",pid=2407,fd=6),("nginx",pid=2406,fd=6))
master | CHANGED | rc=0 | (stdout) LISTEN 0 128 *:8080 *:* users:(("nginx",pid=26325,fd=6),("nginx",pid=26324,fd=6))
[root@node1 role]# ansible webserver -m shell -a 'cat /usr/share/nginx/html/index.html' -o
node1 | CHANGED | rc=0 | (stdout) welcome to nginx
node2 | CHANGED | rc=0 | (stdout) welcome to nginx
master | CHANGED | rc=0 | (stdout) welcome to nginx
# 修改nginx的端口,检查handlers重启nginx的效果
[root@node1 role]# cat nginx/vars/main.yaml
worker_connections: 10240
ports: 80
[root@node1 role]# ansible webserver -m shell -a 'ss -antp |grep nginx' -o
node1 | CHANGED | rc=0 | (stdout) LISTEN 0 128 *:80 *:* users:(("nginx",pid=12690,fd=6),("nginx",pid=12689,fd=6))
node2 | CHANGED | rc=0 | (stdout) LISTEN 0 128 *:80 *:* users:(("nginx",pid=3905,fd=6),("nginx",pid=3904,fd=6))
master | CHANGED | rc=0 | (stdout) LISTEN 0 128 *:80 *:* users:(("nginx",pid=27081,fd=6),("nginx",pid=27080,fd=6))
Vault管理敏感资料
# Vault:
# 加密已存在host明文主机清单档案
[root@node1 role]# ansible-vault encrypt /etc/ansible/hosts
New Vault password:
Confirm New Vault password:
Encryption successful
# 建立加密档案
[root@node1 ~]# ansible-vault create foo.yml
# 编辑加密档案
[root@node1 ~]# ansible-vault edit foo.yml
Vault password:
[root@node1 ~]# ansible-vault rekey foo.yml
Vault password:
New Vault password:
Confirm New Vault password:
Rekey successful # 更换加密金匙
[root@node1 ~]# ansible-vault decrypt /etc/ansible/hosts # 解密
# 检视已加密的档案内容
[root@node1 ~]# ansible-vault view foo.yml
Vault password:
you-men
# 此时哪怕使用root用户访问也是乱码
[root@node1 role]# cat /etc/ansible/hosts |head -5
$ANSIBLE_VAULT;1.1;AES256
34346531613430326665616466346366636138633038333765633731366531306539386331363261
3834613435373234663136323239626438663738313234340a336365666536396565306133373337
37633430393966636665306434316235383138326134393336373966646266316139316363376436
6364323261303464620a346434343630333263303935343134306232386636383938363232656163
# 编辑加密后的主机清单文件
[root@node1 role]# ansible-vault edit /etc/ansible/hosts --ask-vault-pass
Vault password:
# 使用加密文件运行任务
[root@node1 role]# ansible webserver -i /etc/ansible/hosts -m ping
# 如果不输入加密密码是无法运行的
# 只有指定密码
#[root@node1 role]# ansible -i /etc/ansible/hosts webserver -m ping --ask-vault-pass -o
Vault password:
node1 | SUCCESS => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": false, "ping": "pong"}
node2 | SUCCESS => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": false, "ping": "pong"}
master | SUCCESS => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": false, "ping": "pong"}
手动输入金钥 (密码) 解密
执行 Playbook 并搭配 --ask-vault-pass 参数手动输入密码。
$ ansible-playbook hello_world.yml --ask-vault-pass
或通过 ansible.cfg 启用 ask_vault_pass,其预设值为 false。
设定 ansible.cfg。
$ vi ansible.cfg
[defaults]
ask_vault_pass = true
执行 Playbook。
$ ansible-playbook hello_world.yml
透过金钥 (密码) 档解密
建立密码档:此例用的密码为 bGpvxx。
$ echo 'bGpvxx' > secret.txt
执行 Playbook 并搭配 --vault-password-file 参数指定金钥路径。
$ ansible-playbook hello_world.yml --vault-password-file secret.txt
或于 ansible.cfg 里新增 vault_password_file 参数,并指定金钥路径。
$ vi ansible.cfg
[defaults]
vault_password_file = secret.txt
冷知识:
# 如何让不同用户登录不同的主机?
# 在主机清单里设置
[webservers`]
you-men.com ansible_port=5000 ansible_user=alice ansible_pass=123456
flying.com ansible_port=5001 ansible_user=bob ansible_pass=654321
# 判断主机地址为49.233.69.195的主机,关闭该主机
- hosts: webserver
tasks:
- name: "shut down 49.233.69.195 system"
command: /usr/sbin/init 0
when: ansible_all_ipv4_addresses == "49.233.69.195"
# 循环创建多个用户
- hosts: webserver
tasks:
- name: add several users
user: name={{ item }} state=present groups=wheel
with_items:
- you-men
- you-men