运维自动化工具 Ansible 学习

编辑主机清单

$ vim /etc/ansible/hosts

直接在文件里面加IP地址。主机清单只是可以控制谁

ansible中有一个模块叫ping

$ ansible 10.10.108.91 -m ping -k
# -k 是手动输入密码
# -m 是执行模块

可以用都逗号分隔主机。如果有多个主机,密码只输入一次。

为了加速ssh连接,需要修改:

$ vim /etc/ssh/sshd_config
UseDNS no
GSSAPIAuthentication no
GSSAPICleanupCredentials no

查看ssh连接过程

$ ssh -v

主机清单可以分组。可以用ansible_password指定密码。使用密码需要安装yum install -y sshpass

[p9]
10.10.108.91 ansible_password=123456
10.10.108.93 ansible_password=123456
10.10.108.94 ansible_password=123456
[p7]
# 7[1:6]表示71到76
10.10.108.7[1:6] ansible_password=123456

不过上面加密码的方式不太安全

直接运行

$ ansible p9 -m ping

会出错,

10.10.108.93 | FAILED! => {
    "msg": "Using a SSH password instead of a key is not possible because Host Key checking is enabled and sshpass does not support this.  Please add this host's fingerprint to your known_hosts file to manage this host."
}
10.10.108.94 | FAILED! => {
    "msg": "Using a SSH password instead of a key is not possible because Host Key checking is enabled and sshpass does not support this.  Please add this host's fingerprint to your known_hosts file to manage this host."
}

解决方法:

$ vim /etc/ansible/ansible.cfg
# 取消注释下面一行:
#host_key_checking = False

# 在这个配置文件里面还有打开日志记录:
#log_path = /var/log/ansible.log

查看模块文档

$ ansible-doc ping
$ ansible-doc -l # 列出可用模块

命令解释

$ ansible <host-pattern> [-m module_name] [-a args]
  --version
  -v, -vv, -vvv, -vvvv 详细过程
  -u 用户名
  -k 手动输入密码
$ ansible all --list-hosts
$ ansible p9 --list-hosts # -list也行

直接执行命令 (command模块,默认模块,可以省略)

$ ansible p9 -u wang -k -m command -a'ls /root'
$ ansible p9 -a 'ls /root'

把对方的ssh公钥复制过来, 然后使用ansible就不用输入密码了

# 在控制端执行
$ ssh-copy-id 10.10.108.96

ansible支持通配符

$ ansible 10.10.108.* -m ping
$ ansible 10.10.108.* -m ping

ansible的host-pattern: 匹配主机的列表

# all: 表示所有清单中的所有主机
$ ansible all -m ping
# *: 通配符
$ ansible '*' -m ping
$ ansible 192.168.1.* -m ping
$ ansible '*srvs' -m ping
# 或关系
$ ansible 'p9:p7' -m ping
# 交集
$ ansible 'p9:&p7' -m ping
# 逻辑非
$ ansible 'p9:!p7' -m ping
# 综合逻辑
$ ansible 'p9:&p7:!p7' -m ping
# 正则表达式
$ ansible '~表达式' -m ping

执行状态:

  • 红色:错误
  • 绿色:没有修改任何内容
  • 蓝色:详细过程
  • 黄色:执行成功,并对目标主机做了变更

常见模块

command

$ ansible-doc command
# 可以看到支持很多选项
- argv  Passes the command as a list rather than a string.
- chdir  Change into this directory before running the command.
- creates  A filename or (since 2.0) glob pattern. If it already exists, this step won't be run.
- removes  A filename or (since 2.0) glob pattern. If it already exists, this step will be run.
- stdin  Set the stdin of the command directly to the specified value.
# 示例
$ ansible all -a 'removes=/etc/fs cat /etc/fstab'

command对重定向、管道、环境变量等都有问题,所以要用shell模块

shell

# 参数都放单引号里
$ ansible p9 -m shell -a 'echo $HOSTNAME'

script

运行脚本。在控制端写好脚本,不需要自己推送

$ vim /root/test.sh
#!/bin/bash
hostname # 查看主机名
$ ansible p9 -m script -a '/root/test.sh'

copy

从服务器复制文件到客户端

例子:查看selinux状态,然后全部关闭

$ ansible all -a 'getenforce'
# 查看ansible文档
$ ansible-doc -s copy
dest:
(required) Remote absolute path where the file should be copied to. If `src' is a directory, this must be a directory too. If
`dest' is a non-existent path and if either `dest' ends with "/" or `src' is a directory, `dest' is created. If `dest' is a relative path, the starting directory is determined by the remote host. If `src' and `dest' are files, the parent directory of `dest' is not created and the task fails if it does not already exist.
backup:
Create a backup file including the timestamp information so you can get the original file back if you somehow clobbered it incorrectly.
# 复制一下本地selinux配置
$ cp /etc/selinux/config /root/selinux
# 发送到每一个客户端
$ ansible all -m copy -a 'src=/root/selinux dest=/etc/selinux/config backup=yes'

fetch

从客户端取文件到服务器。目录可以先tar再传

参数:
dest: 要存文件的目录,文件被放到目录/主机名/文件名
src: 源文件

$ ansible all -m fetch -a 'src=/var/log/message dest=/root/logs'
$ tree /root/logs
logs
|-- 10.10.108.71
|   `-- var
|       `-- log
|           `-- messages
|-- 10.10.108.72
|   `-- var
|       `-- log
|           `-- messages
|-- 10.10.108.73
|   `-- var
|       `-- log
|           `-- messages
...

传输文件夹:先压缩再传

$ ansible all -m shell -a 'tar Jcf log.tar.xz /var/log/*.log'
# 有专门的压缩文件模块
$ ansible all -m fetch -a 'src=/root/log.tar.xz dest=/root/logs'
2、解压ansible管理机上的压缩文件到远程主机:
ansible all -m unarchive -a "src=/tmp/install/zabbix-3.0.4.tar.gz dest=/tmp/ mode=0755 copy=yes"
3、解压远程主机上的文件到目录:
ansible all -m unarchive -a "src=/tmp/install/zabbix-3.0.4.tar.gz dest=/tmp/ mode=0755 copy=no"

file

设置文件属性(创建文件夹等)

# 创建新文件
$ ansible all -m file -a 'name=/root/ANSIBLE_TEST state=touch'
# 删除文件或文件夹
$ ansible all -m file -a 'name=/root/ANSIBLE_TEST state=absent'
# 创建文件夹
$ ansible all -m file -a 'name=/root/FOLDER_TEST state=directory'

debug

---
- hosts: test70
  remote_user: root
  tasks:
  - set_fact:
      testvar: "testtest"
  - debug:
      msg: "{{testvar}}"

wait_for

检查端口是否打开/等待端口打开
等待文件出现等
参考资料:http://blog.timd.cn/ansible-wait-for/

- wait_for:
    timeout: 5
    connect_timeout: 5
    port: 80

其他模块

hostname: 管理主机名

cron: 计划任务

yum: 管理包

service: 管理服务

user: 管理用户

group: 管理组

playbook

galaxy 模块库

https://galaxy.ansible.com/

模块下载

# https://galaxy.ansible.com/geerlingguy/nginx
$ ansible-galaxy install geerlingguy.nginx

ansible-pull

推送命令到客户端,效率提升

ansible-vault

脚本加密

# 新建一个yaml文件 first.yaml
- hosts: p9
  remote_user: root

  tasks:
  - name: hello
    command: hostname

$ ansible-playbook first.yaml

# 加密yaml文件可能有敏感信息
$ ansible-vault encrypt first.yaml

# 解密
$ ansible-vault decrypt first.yaml

# 查看加密的内容
$ ansible-vault view xxx

# 编译
$ ansible-vault edit xxx

# 修改密码
$ ansible-vault rekey xxx

# 创建加密的文件
$ ansible-vault create xxx

ansible-console

交互执行命令。用于临时测试

$ ansible-console
Welcome to the ansible console.
Type help or ? to list commands.

root@all (9)[f:5]$ cd p9  # 通过进文件夹的方式切换主机
root@p9 (3)[f:5]$

playbook

tasks 顺序执行的任务

- hosts: p9
  remote_user: root

  tasks:
  - name: create new file
    file: name=/home/temp_by_ykh state=touch
    ignore_errors: True # 遇到错误继续(如果不加遇到错误就终止)
  - name: install package
    yum: name=ntp

ansible-playbook 常见选项

--check 只检测可能会发生的改变,但不真正执行操作
--list-hosts 列出运行任务的主机
--limit 主机列表 只针对主机列表的主机执行
--v 显示过程

示例:安装apache

- hosts: websrvs
  remote_user: root
  
  tasks:
  - name: install httpd
    yum: name=httpd state=present
    
  - name: install configure file
    copy: src=files/httpd.conf dest=/etc/httpd/conf
    
  - name: start service
    service: name=httpd state=started enabled=yes

handlers 指定任务的触发条件

- hosts: websrvs
  remote_user: root
  
  tasks:
  - name: install httpd package
    yum: name=httpd
    tags: inshttpd
  - name: copy conf files
    copy: src=files/httpd.conf dest=/etc/httpd/conf
    notify: restart service # 如果命令执行了(文件变化了)就重启服务
  - name: start service
    service: name=httpd state=started enabled=yes
    tags: rshttpd
    notify:
    - handler N # notify可以是列表,
    - check nginx process
    
  handlers:
  - name: restart service
    service: name=httpd state=started enabled=yes
  - name: check nginx process
    shell: killall -0 nginx > /tmp/nginx.log

tags 指定标签, 可以只执行标签

$ ansible -t rshttpd some.yaml
变量的指定
  1. ansible setup facts 远程主机的所有变量都可以直接调用

ansible XXX -m setup 查看ansible的参数(变量),里面也有系统变量

比如ansible_eth* 关于网卡的参数

  1. 在/etc/ansible/hosts中定义

普通变量:主机组中主机单独定义,优先级高于公共变量

公共(组)变量:针对主机组所有主机统一定义变量

[websrvs]
92.168.30.101 http_port=81
192.168.30.102 http_port=82
[dbsrvs]
92.168.30.101
192.168.30.103
[appsrvs]
192.168.30.10[1:3]
  1. 通过命令行指定变量,优先级最高

  2. 在playbook中定义:

- hosts: appsrvs
  remote_user: root
  
  vars:
  - pkname: vsftpd
  - key: value
  
  tasks:
  - name: install package
    yum: name={{ pkname }}
  - name: start service
    service: name= {{ pkname }} state=started enabled=yes
$ ansible-playbook -e 'pkname=vsftpd' test.yaml  # 覆盖脚本中的变量
  1. 可以单独创建变量文件,例如放在~/ansible/vars.yml文件中
var1: httpd
var2: vsftpd

创建一个Playbook,还在上面的目录中。

- hosts: websrvs
  remote_user: root
  vars_files:
  - vars.yml
  
  tasks:
  - name: install package
    yum: name={{ var1 }}
  - name: create file
    file: name=/data/{{ var2 }}.log state=touch

然后ansible-playbook -C 上面的.yaml

模板

文本文件,嵌套有脚本(使用模板编程语言编写)

Jinja2语言,使用字面量,有下面的形式

  • 字符串:使用单引号或双引号
  • 数字:整数,浮点数
  • 列表:[item1, item2]
  • 元组:(item1, item2)
  • 字典:{key1:value1, key2:value2}
  • 布尔型:true/false

算术运算:+ - * / // % **

比较操作:== != > >= < <=

逻辑比较:and or not

流表达式:for if when

一般在playbook脚本的同级目录中新建templates文件夹

示例:将nginx.conf作为模板

$ cp /etc/nginx/nginx.conf templates/nginx.conf.j2
$ vim !$
worker_processes {{ ansible_processor_vcpus*2 }}  # 修改这一行

# 创建Playbook
$ vim run.yml
- hosts: websrvs
  remote_user: root
  
  tasks:
  - name: install package
    yum: name=nginx
  - name: copy template
    # 自动前往templates目录查找,也可以用绝对路径。跟复制模块的语法类似。
    template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
    notify: restart service
  - name: start service
    service: name=nginx state=started enables=yes
    
  handlers:
  - name: restart service
    service: name=nginx state=restarted enables=yes
when关键字

条件测试:如果需要根据变量、facts或此前任务的执行结果来作为某task执行与否的前提,要用条件测试,通过when语句实现,在tasks中使用,jinja2的语法格式。

- hosts: websrvs
  remote_user: root
  
  tasks:
  - name: install package
    yum: name=nginx
  - name: copy template
    template: src=nginx7.conf.j2 dest=/etc/nginx/nginx.conf
    when: ansible_distribution_major_version == "7"
    notify: restart service
  - name: copy template
    template: src=nginx6.conf.j2 dest=/etc/nginx/nginx.conf
    when: ansible_distribution_major_version == "6"
    notify: restart service
  - name: start service
    service: name=nginx state=started enables=yes
    
  handlers:
  - name: restart service
    service: name=nginx state=restarted enables=yes
with_items

迭代

示例:创建多个文件,安装多个yum包

- hosts: websrvs
  remote_user: root
  
  tasks:
  - name: create some files
    # item是特殊变量,就是下面的列表项
    file: name=/data/{{ item }} state=touch
    with_items:
    - file1
    - file2
    - file3
  - name: install some packages
    yum: name={{ item }}
    with_items:
    - htop
    - dstat
    - hping3

嵌套子变量

- hosts: websrvs
  remote_user: root
  
  tasks:
  - name: create some users
    user: name={{ item.name }} group={{ item.group }}
    with_items:
    - { name: 'user1', group: 'g1' }
    - { name: 'user2', group: 'g2' }
for & if in template

for示例

- hosts: websrvs
  vars:
    ports:
    - 80
    - 81
    - 83
    key2:
    - p: 1
      k: 1
    - p: 2
      k: 2
  • 模板文件 xxx.j2
{% for port in ports %}
server {
    listen {{ port }}
}
{% endfor %}
  • 模板文件 yyy.j2
{% for key in key2 %}
server {
    listen {{ key.p }}
}
{% endfor %}

if示例

{% if xxx is defined %}

{% endif %}

roles

ansible子1.2版本开始引入的新特性,用于层次性、结构化地组织playbook。roles能够根据层次性结构自动装载所有变量文件、tasks以及handlers等。要使用roles只需要在playbook中使用include指令即可。简单来讲,roles就是通过分别将变量、文件、任务、模板及处理器放置于单独的目录中,并可以便捷地include他们的一种机制。角色一般用于基于主机构建服务的场景中,但也可以用于构建守护进程等场景中。

推荐把roles放到:/etc/ansible/roles

mkdir还可以用大括号表示集合 mkdir a/{1,2,3}

/
playbook.xml
roles
project
tasks
files
vars
default
templates
handlers
main.yml
main.yml
默认变量
main.yml
main.yml

示例

/roles/nginx/tasks/create-group.yml

- name: create group
  group: name=nginx

/roles/nginx/tasks/create-user.yml

- name: create user
  user: name=nginx group=nginx system=yes shell=/sbin/nologin

/roles/nginx/tasks/install-nginx.yml

- name: install package
  yum: name=nginx

/roles/nginx/template/nginx.conf.j2

同上

/roles/nginx/tasks/main.yml

- include: create-group.yml
- include: create-user.yml
- include: install-nginx.yml
# # 可以引用其它的roles, 但是复制文件可能有路径问题
- include: roles/project2/tasks/copyfile.yml

/nginx_role.yml

- hosts: websrvs
  remote_user: root
  roles:
  - role: nginx  # 从roles目录下查找
  - {role: httpd, tags: ['web', 'httpd'] }
  - role: app
    tags: ['web', 'app']
    when: ansible_distrubtion_major_version == "7"

可以用ansible-playbook -t 选择标签

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值