Ansible入门实践

Ansible是什么

Ansible是一个流行的自动化运维工具,基于Python开发,分布式,无需客户端,轻量级,配置语法使用YMALJinja2模板语言。
利用它可以做的事情:批量部署,服务安装,日常备份等。

Ansible的特性:

  1. 无需客户端,通过ssh协议进行通信
  2. 安装后无需启动服务
  3. 依赖大量的python模块扩展功能
  4. Ansible的配置文件:/etc/ansible/ansible.cfg

Ansible的组件架构如下图:

由上图可以看到Ansible由5个部分组成:

  1. Ansible:Ansible核心
  2. Modules:包括Ansible自带的核心模块及自定义模块
  3. Plugins:完成模块功能的补充,包括连接插件、邮件插件等
  4. Playbooks:定义Ansible多任务配置文件,由Ansible自动执行
  5. Inventory:定义Ansible管理主机的清单

Asible无需客户端,只需要在管理节点安装Ansible即可,其工作模式如下图所示:

Ansible实践

实践环境拓扑图:

首先需要在管理节点上安装Ansible。

安装Ansible

如下安装基于CentOS 7.8。

$ cat /etc/redhat-release 
CentOS Linux release 7.8.2003 (Core)

第一步:添加yum源

# epel源(扩展包)
wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo

# linux镜像源
wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo

第二步:安装Ansible。

yum -y install ansible

成功安装好Ansible之后,查看版本信息:

$ ansible --version
ansible 2.9.27
  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 = /usr/bin/ansible
  python version = 2.7.5 (default, Apr  2 2020, 13:16:51) [GCC 4.8.5 20150623 (Red Hat 4.8.5-39)]

在管理节点安装完Ansible后,还需要做一些基础配置(如下示例均以主机192.168.3.141作为被管理端)。

(1)编辑ansible主机清单

$ vim cat /etc/ansible/hosts
[web]            # 指定主机分组标签
192.168.3.141

[benet:children] # 包含多个主机标签
web

(2)将管理节点的ssh公钥复制到被管理节点

$ ssh-keygen -t rsa    # 执行后按三次回车键
$ ssh-copy-id root@192.168.3.141 # 该操作需要输入被管理节点的root用户密码

调用Ansible模块

当需要在被管理节点执行某些操作时,可以通过调用Ansible的模块来实现。
调用Ansible模块的执行结果会显示不同的颜色,它们的含义如下:

  • 黄色:更改成功
  • 绿色:没有更改(例如:被管理节点已经安装好了nginx组件,再次安装时返回结果显示绿色)
  • 红色:错误
  • 紫色:警告

Ansible的自带的核心模块已经非常多了,可以通过命令:ansible-doc --list或者ansible-doc -l查看。
ansible 2.9.27中自带的核心模块数量已经有3387个了:

$ ansible-doc --list|wc -l
3387

如果需要查看模块的帮助文档,执行命令:ansible-doc <模块>

# 查看yum模块帮助信息
$ ansible-doc yum

可以使用-s选项查看模块的片段信息,看起来比较简洁一些。

$ ansible-doc -s yum

在管理节点成功安装好Ansible之后,通过ansible命令调用Ansible模块,语法如下:

$ ansible [-i 主机文件] [-f 批次] [组名] [-m 模块名称] [-a 模块参数] pattern

ansible命令参数含义如下:

-i PATH, -inventory=PATH    # 指定host文件的路径,默认是在/etc/ansible/hosts
-f NUM,-forks=NUM           # NUM是指定一个整数,默认是5,指定fork开启同步进程的个数
-m NAME,-module-name=NAME   # 指定使用的模块名称,默认使用command模块
-a MODULE_ARGS              # 指定模块的参数
-k,-ask-pass                # 提示输入ssh的密码,而不是使用基于ssh的密钥认证
-sudo                       # 指定使用sudo获得root权限
-K,-ask-sudo-pass           # 提示输入sudo密码,与-sudo一起使用
-u USERNAME,-user=USERNAME  # 指定被管理端的执行用户
-C,–check                   # 测试此命令执行会改变什么内容,不会真正的去执行
pattern                     # 指定执行命令的主机标签,这个标签是在ansible主机清单文件中指定的;如果指定为"all"表示对主机清单中的所有主机执行命令

如下介绍常用的Asible模块。

command模块

仅支持简单的语法命令,语句中不能包含管道符等复杂元素。

(1)查看web主机的主机名

$ ansible web -m command -a "hostname"
192.168.3.141 | CHANGED | rc=0 >>
192.168.3.141

执行成功,返回结果显示黄色

(2)在web主机上创建用户“zhangsan”

$ ansible web -m command -a "useradd zhangsan"
192.168.3.141 | CHANGED | rc=0 >>

shell模块

shell模块是command模块的升级版,支持复杂语句,但不支持别名。
通常使用shell模块就可以了,command模块了解即可。

# 修改web主机上新建的zhangsan用户密码为123
$ ansible web -m shell -a "echo 123|passwd --stdin zhangsan"
192.168.3.141 | CHANGED | rc=0 >>
Changing password for user zhangsan.
passwd: all authentication tokens updated successfully.

yum模块

yum模块用于在被管理节点上安装组件。

# 在web主机上安装nginx
$ ansible web -m yum -a "name=nginx state=installed"

yum模块参数含义:

  • name: 安装的软件包名
  • state:服务状态,可选值:
    installed,present:安装软件包
    removed,absent:卸载软件包
    latest:安装最新软件包

service模块

service模块用于控制被管理节点上的服务。

# 关闭web主机上的nginx服务,并设置开机启动
$ ansible web -m service -a "name=nginx state=stopped enabled=yes"

service模块参数含义:

  • name:指定服务名
  • state:指定服务运行状态,可选值:
    started:开启服务
    stopped:关闭服务
    reloaded:重载服务
    restarted:重启服务
  • enabled:是否开机自启

systemd模块

service模块一样,systemd模块也是用于控制被管理节点上的服务。

# 启动web主机上的nginx服务,并取消开机启动
ansible web -m systemd -a "name=nginx state=started enabled=no"

这里有一个疑问:为什么已经有了service模块,又存在一个与其功能相同的systemd模块呢?
在StackOverflow上也有人提出了这个问题In Ansible, what is the difference between the service and the systemd modules?,甚至在github上还有一个issuesystemd模块是service模块的替代品。

实际上,我的理解是systemd模块是对service模块的补充和完善。为什么这么说呢?因为在systemd模块的帮助信息中明确说明了使用systemd模块的要求:

# 需要被管理节点是使用systemd来管理服务的,此时才能在ansible中使用systemd模块
REQUIREMENTS:  A system managed by systemd.

group模块

group模块用于在被管理节点上进行用户组管理。

# (1)在所有清单主机上创建组www,gid 666
$ ansible all -m group -a "name=www gid=666"

# (2)在所有清单主机删除组www
$ ansible all -m group -a "name=www gid=666 state=absent"

grouo模块参数含义:

  • name:用户组名
  • gid:用户组标志
  • state:添加或删除用户组,默认值为present,可选值:
    absent:删除用户组
    present:添加用户组

user模块

user模块用于在被管理节点上实现用户管理。

# 所有主机创建用户zhangsan
$ ansible all -m user -a "name=zhangsan"

user模块参数含义:

  • name: 用户名

file模块

file模块用于在被管理节点进行文件管理操作,如:创建文件/目录,设置文件权限等

#(1)在web主机上创建backup目录,并赋权,更改属主属组
$ ansible web -m file -a "path=/backup owner=root group=root recurse=yes mode=777"

# (2)在web主机上创建test.txt文件,file模块可以创建目录又能创建文件
$ ansible web -m file -a "path=/test.txt owner=root group=root state=touch mode=777"

file模块参数含义;

  • path:文件或目录路径
  • owner:文件或目录所属用户
  • group:文件或目录所属用户组
  • recurse:为yes时表示可以递归地修改目录中文件的属性
  • mode:文件目录的操作权限
  • state:操作文件或目录状态,可选值:
    absent:递归删除目录
    hard:创建硬链接
    link:创建符号链接
    touch:创建一个空文件

copy模块

copy模块用于从Ansible管理节点本地复制文件到被管理节点。

# 复制本地hosts文件到web主机,并且备份web主机之前的hosts文件
$ ansible web -m copy -a "src=/etc/hosts dest=/etc/hosts backup=yes"

执行完上述操作后,在被管理节点web主机上可以看到之前的hosts文件被保存成了一个新的文件。

$ ll /etc/hosts*
-rw-r--r--  1 root root 214 Sep  3 15:36 /etc/hosts
-rw-r--r--  1 root root 158 Jun  7  2013 /etc/hosts.22105.2023-09-03@15:36:44~ # 这个文件是复制之前web主机本身的hosts文件

copy模块参数含义:

  • src:源文件路径
  • dest:目标文件路径
  • backup:覆盖到目标文件前,是否提前备份
  • content:添加文件内容
  • group:指定属组
  • owner:指定属主
  • mode:指定权限

fetch模块

从被管理主机获取文件到Ansible管理节点。

# 将web主机上的nginx配置文件获取到Ansible管理节点上
$ ansible web -m fetch -a "src=/etc/nginx/nginx.conf dest=/root/ansible"

执行上述命令之后:会将web主机上的/etc/nginx/nginx.conf下载到Ansible管理节点上的/root/ansible/目录下,同时注意:获取到的文件会自动创建原来的目录结构。

$ pwd
/root/ansible
$ tree .
.
├── 192.168.3.141  # 注意:这个目录结构是自动创建的
│   └── etc
│       └── nginx
│           └── nginx.conf
└── script.sh

2 directories, 2 files

mount模块

mount模块用于在被管理节点上进行设备的挂载或卸载操作。

# 将web主机上的/nfs目录使用nfs协议挂载到/usr/share/nginx/html,这样/nfs路径下的内容与/usr/share/nginx/html路径下的内容就是相同的了
$ ansible web -m mount -a "src=nfs:/nfs path=/usr/share/nginx/html fstype=nfs state=mounted"

mount模块参数含义:

  • src:需要挂载的设备
  • path:设备挂载挂载路径
  • state:对设备的操作,可选值:
    mounted:挂载
    unmounted:卸载

script模块

scritp模块可用于将Ansible管理节点上的脚本应用到被管理节点上去执行。
假设Ansible管理节点上存在一个脚本:

$ vim /root/ansible/script.sh
ping -c 4 baidu.com

使用script模块在被管理节点上指定该脚本:

$ ansible web -m script -a "/root/ansible/script.sh"

使用Playbook实现多任务操作

在上述实践操作中可以知道,使用Ansible模块可以很方便地实现对被管理节点的操作。但是存在一个问题:每一个模块都是单独使用的,而如果在一个业务部署中需要执行多个操作怎么办呢?当然,需要多次执行相应的模块命令,但是这不利于对操作进行复用和管理。
可以使用Ansible的Playbook来解决这个问题,具体来说就是:将多个模块命令操作编写在一个yaml文件中,这个yaml文件就是一个Playbook。
如下使用Playbook在web主机上实现nginx的安装,配置和启动。

$ cat nginx.yaml 
---
- name: install nginx and start
  hosts: web

  tasks:
    - name: install nginx
      yum: 
        name: nginx
        state: latest

    - name: config nginx
      copy: 
        src: /usr/share/nginx/html/index.html
        dest: /usr/share/nginx/html/
      notify: restart nginx

    - name: start nginx
      service: 
        name: nginx
        state: started
        enabled: yes

  handlers:
    - name: restart nginx
      service: 
        name: nginx
        state: restarted

编写好Playbook文件之后,可以执行测试:

# 测试Playbook文件的编排是否存在问题
$ ansible-playbook -C nginx.yaml

# 如果Playbook文件编写没有问题,就可以真正执行
$ ansible-playbook nginx.yaml

关于Palybook的具体用法详见:Ansible playbooks

虽然Playbook很好地解决了Ansible模块的编排问题,但是当需要配置更加复杂的被控端环境,那么单单的将所有的配置命令写成一个Playbook文件就可多达成百上千行,这极不利于Playbook的管理和维护。
Ansible自1.2版本之后,可以使用Roles来解决这个问题。

使用Roles实现更加复杂的编排

详见:Roles

在Terraform中调用Ansible

详见:Terraform Ansible Provider

【参考】
Ansible自动化运维工具
CloudIaC Ansible 介绍
快速上手Ansible以及常见模块应用
3分钟了解Ansible是什么?
Ansible 的自动化运维(四)条件判断
Ansible 的自动化运维(五)角色
Ansible 批量100台服务器添加 Crontab
Ansible Playbook快速部署一主多从MySQL集群
一个现代化的 Ansible 用户界面
Ansbile官方文档


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达,在下面评论区告诉我^_^^_^