一、前言
因某集成商管理的客户资源涉及4A接入管控要求,其中密码必须3个月更新一次,随着纳管主机的数量增多,手动去修改密码变得不现实,考虑无侵入性和资源耗用,便捷性等因素,首先选用Ansible作为此需求的首要解决方案,ansible是agentless的且仅需依靠ssh就能管理目标,这减少了开销和安全漏洞,但因Ansible主要还是一个命令行工具,这种命令行操作,剧本编写不是特别直观,导致Ansible在项目的应用推广并不十分顺利,故此,特采用一个可视化web图形界面来改善Ansible的易用性,本文对此记录以作参考。
相关资源:ansible Wiki、playbooks、Ansible Community、Vagrant
二、产品对比和说明
2.1、Ansible常用可视化图形界面
Ansible Web UI目前主流有:Redhat官方商业版Tower、官方开源版AWX 和 开源版semaphore。
1)Ansible Tower
Ansible官方Web UI,支持docker-compose部署,Tower 是 Red Hat 提供的企业级Ansible自动化平台,提供了高级功能,如角色基础的访问控制、详细的审计日志和集成支持。
关联资源: 文档、安装包下载、Ansible Web UI Guide、社区驱动的Ansible角色库
2)Ansible AWX
AWX是由Red Hat赞助的Ansible Tower的免费开源版本,也支持docker-compose部署,它是Red Hat Ansible Tower产品最终衍生的上游项目,提供了一个完整的Web界面来管理Ansible任务、库存、项目和作业,支持REST API,允许你自动化和扩展Ansible的自动化功能。AWX是一个基于Docker容器的可视化平台,它提供了Web界面和REST API,可以帮助用户更加方便地管理Ansible playbook和任务。在AWX的Web界面中,用户可以方便地创建、编辑和运行Ansible playbook。还可以查看任务的执行结果、日志和报告。此外,AWX还支持团队和项目的管理,可以方便地与团队成员协作,并将任务和playbook组织起来。
关联资源:GitHub、软件下载、ansible-ui、Ansible automation controller advanced 、wx-operator-2.19.1.tgz、ansible-hub-ui
Ansible AWX服务部署在容器内,因此需要先将Docker安装在部署AWX的服务器机器上,还需要Python 3。
它是一个基于GO语言编写的开源 Ansible-Web UI系统,也支持docker-compose部署。它提供了一个优雅的web界面,用于执行Ansible剧本、Terraform、OpenTofu、Pulumi代码和Bash脚本。Ansible Semaphore易于安装和配置,比较友好。
关联资源:GitHub、安装文档、semaphoreui官网、
4)ManageIQ(redhat)
ManageIQ 实际是一个开源的混合云管理平台,采用 Apache-2.0 license授权,用Ruby编写,并使用Ruby on Rails框架。但它提供了对Ansible的集成,允许通过Web界面执行Ansible任务。它支持容器、虚拟机、网络及存储的全面监控与控制。通过集成工作负载管理、编排、事件控制台、配置管理数据库(CMDB)、规则基础自动化(RBA)和Web服务,ManageIQ使IT团队更高效执行策略,确保合规性,并实现资源优化。
官网了解到,ManageIQ 部署过程中以appliance部署到云平台或其他平台,部署配置相对较复杂,不适合上述简单场景。ManageIQ更侧重做一个强大的开源云管理平台,管理虚拟基础设施,包括混合公共云和私有云。其中,可使用ManageIQ自动化(自动化模型)功能,您创建可自动扩展的云应用程序,在配置虚拟机和云实例时消除手动决策和操作,并管理完整的虚拟机生命周期。
关联资源:Github、文档、国内镜像、软件下载、文档
5)Ansible-Web
Ansible-Web 是一个基于Django构建的简单 Web 应用程序,用于运行 Ansible 剧本。它提供了一个基本的Web界面来管理Ansible作业。
相关资源:ansibleguy、ansible web ui、Ansible Web方案、/ansible-webui、轻量级ansible UI
6)Rundeck
Rundeck社区版为用户提供了在UI中执行剧本所需的基本功能,就像Ansible Semaphore一样,它非常易于安装、启动和运行。Rundeck是一个通用的自动化工具,因此我们不仅仅可执行ansible剧本,但仪表板并不像ansible Semaphore那样易于使用,而且视觉上也不那么吸引人。Rundeck CE的一些功能包括创建多步骤作业、运行shell命令和执行本地命令。虽然社区版拥有许多功能,而不仅仅是运行Ansible剧本,但最受欢迎的功能,如高可用性和经过认证的企业插件,是为企业版或云版保留的。
7)自开发的web UI
如果想为UI提供一些利基功能,比如“还原操作”,可以撤消之前运行的剧本或显示正在进行的作业的完成百分比,那么自定义UI可能是你最好的选择。然而,与其他选项相比,这种方法需要付出巨大的努力。我们研究的一种方法是为后端服务和在同一主机上运行的web前端构建一个运行在可响应的远程主机上的健壮REST API。然后,应用程序的两个组件可以使用HTTP请求进行通信,并在服务器上本地运行和/或修改相关文件。
相关资源:ansible的web管理平台
三、服务部署及应用
综上,本次选择Semaphore 作为Ansible UI,安装它之前需要先安装Python3(包括python3-pip)和Ansible,y因Ansible是使用Python3编程语言构建的。semaphore无论是采用rpm/deb包还是二进制压缩包,当然也支持docker和sanp安装。
#安装Python3和Ansible
#创建服务用户
useradd -M semaphore -s /usr/sbin/nologin
四、附录
4.1、通过脚本来实现
这里要用到一个expect工具,expect 是基于Tcl(Tool Command Language )语言开发的,是一个自动化交互套件,主要应用于自动化交互式操作的场景,执行命令时,以交互形式按照要求输入指定字符串,实现自动交互。借助Expect处理交互的命令,我们可以将交互过程如:ssh登录,ftp登录等写在一个脚本里,使之自动化完成,尤其适用于需要对多台服务器执行相同操作的环境中。 典型使用场景:
(1)根据预定标准回答其问题,回答“是”、“否”或将控制权交还给您
(2)远程连接设备并执行自动化操作
(3)需要人机交互的地方,如果提前知道应该输入什么指令都可以使用expect 工具
相关资源:expect Linux7手册、expect教程中文版、expect说明、expect v5
expect 自动交互流程可简单归结如下:
spawn 启动指定命令 —> expect 获取指定关键字 —> send 发送指定字符串 ----> 执行完成退出。
其中:
- expect命令:用于等候一个相匹配内容的输出,一旦匹配则执行expect后面的动作命令;脚本中当spawn命令执行完成后,expect就会匹配捕捉spawn命令执行后的输出,匹配到后就会执行expect后面包含在{}中的send或exp_send动作,匹配后动作也可以放在下一行,就可以省略expect中的{};其中exp_send是expect的子命令,用在expect的{}中,但其可发送一些特殊符号:\r(回车)、\n(换行)、\t(制表符),eg:
expect {"yes/no" { exp_send "yes\r"; exp_continue }}
;注意的是,send、exp_send都是将参数输出到程序中去,还有一个命令是输出的stdout,即send_user命令可用于把后面的参数输出到标准输出中去,比如:send_user “please input password:”。- spawn命令:是expect的初始命令,用来启动新的进程的。spawn后的send和expect命令都是和spawn打开的进程进行交互的;后跟 -open 启动文件进程;-ignore 忽略某些信号
\- send命令:用于接收一个字符串参数,并将该参数发送到进程,这个过程类似模拟人类输入密码
\- interact命令:用于配合spawn、expect、send自动化的完成多任务,interact命令可以在适当的时候进行任务的干预,比如下载完ftp文件时,仍可以停留在ftp命令行状态,以便等待用户手动的执行后续命令。
yum install -y expect
#命令格式:expect [选项] 参数
expect 表达式 动作 表达式 动作 ... ...
expect [ -dDinN ] [ -c cmds ] [ [ -[f|b] ] cmdfile ] [ args ]#参数
-d 启用一些诊断输出,主要报告 expect 和 interaction 等命令的内部活动。
-D 启用交互式调试器。后面应该是一个整数值。如果值非零或按下^C(或击中断点,或脚本中出现其他适当的调试器命令),调试器将在下一个 Tcl(Tool Command Language) 过程之前接管控制。
-i 交互式输入 expect 命令,而不是从文件中读取。通过 exit 命令或 EOF 终止。
-n 不使用 ~/.expect.rc 脚本。
-N 不使用 $exp_library/expect.rc 脚本。
-c <cmds> 指定要执行的 expect 命令。命令应该加引号,以防止被 Shell 分解。此选项可使用多次或用一个 -c 选项指定多个命令,命令之间用分号分隔。命令按照它们出现的顺序执行。
-f 从文件读取命令,仅用于使用#!时。如果文件名为"-",则从stdin读取(使用"./-"从文件名为-的文件读取)。
-b 默认情况下,命令文件被读入内存并完整地执行。有时需要一次读取一行。例如,stdin 是这样读取的。为了强制任意文件以这种方式处理,请使用 -b 选项。
-re:表示使用正则表达式进行内容匹配,eg:expect -re ".*password" {send "D1234\r"}
exp_continue [-continue_timer] :允许 expect 自身继续执行,而不是像通常那样返回。默认情况下,exp_continue 重置超时计时器,-continue_timer 标志防止定时器重启#expect其他命令
set 变量名 变量值 # 设置变量的方法
set timeout N #设置超时时间为 N 秒
puts $变量名 # 读取变量的方法
spawn [args] program [args] #启动交互程序 program [args]
send [-flags] string #用于发送指定的字符串信息
send_user [-flags] string #用来打印指定字符串到标准输出,相当于 Shell 中的 echo
exit [-opts] [status] #退出 expect 脚本
interact [string1 body1] ... #执行完成后保持交互状态,控制权交给控制台(用户手工操作),否则完成后会退出。#expect脚本示例:
#!/usr/bin/expect
set ip [lindex $argv 0 ] # 接收第1个参数,作为IP
set username [lindex $argv 1 ] # 接收第2个参数,作为username
set password [lindex $argv 2 ] # 接收第3个参数,作为密码
set CMD [lindex $argv 3]
set timeout 30 # 设置超时时间 spawn ssh -p1122 $username@$ip $CMD # 发送ssh请求
expect { # 返回信息匹配 -timeout 1"*yes/no" { send "yes\r"; exp_continue} # 第一次ssh连接会提示yes/no,发送yes然后继续"*password:" { send "$password\r" } # 出现密码提示,发送密码 timeout { puts "expect was timeout"; return }
}
send_user "$argv0 [lrange $argv 0 2]\n"
send_user "It's OK\r"
interact # 交互模式,用户会停留在远程服务器上面#Shell 脚本中嵌入执行expect 命令
#!/bin/bashuser=root
ip=192.168.10.3
passwd='P123456'
#嵌入expect
expect <<-EOF
set time 30
spawn ssh -p1122 $user@$ip
expect {"*yes/no" { send "yes\r"; exp_continue }"*password" { send "$passwd\r" }
}
interact
EOF
#示例2:shell+expect进行数据库自动备份
#一、编写备份驱动脚本,该脚本写入计划任务,定期执行
#!/bin/bash
#指定要备份的数据库,这里写死了
mysql_username=root
backup_databases=school
backup_path=$HOME/backup_data/${backup_databases}.sql#运行expect脚本
expect $HOME/backup_script/single_cold_backup/single_cold_backup_service.exp ${mysql_username} ${backup_databases} ${backup_path}#二、编写备份的expect脚本
#!/usr/bin/expect
set timeout 5
#设置传参,从驱动脚本里读取
set mysql_username [lindex $argv 0]
set backup_database [lindex $argv 1]
set backup_path [lindex $argv 2] #utils路径
set utils_path /home/hadoop/backup_script/utils
spawn bash ${utils_path}/backup.sh ${mysql_username} ${backup_database} ${backup_path}expect {"*assword*" {send "nimabidecao1\r"} #输入密码
}
expect eof#三、编写执行的程序脚本
#!/bin/bashmysql_username=$1
backup_databases=$2
backup_path=$3mysqldump -u ${mysql_username} -p --databases ${backup_databases} > ${backup_path}