Ansible详细学习笔记和实战案例(容易忘记的内容)
一、主机清单
ansible localhost -m command -a "ls"
## 主机列表文件
cat /etc/ansible/hosts
主机描述形式:
- 主机IP地址和主机名
## blue.example.com
## 192.168.100.1
- 散列主机列表和主机组列表
散列主机列表 主机组列表 嵌套主机组列表
## blue.example.com ## [webservers] ## [server:children]
## 192.168.100.1:999 ## beta.example.com ## webservers
## 192.168.1.100
主机列表范围形式:[起始值:结束值]的ikey:value形式
## www[001:006].example.com 主机名方式表示6台目标主机
## 192.168.1.10[0:9] 主机IP地址表示10台目标主机
补充:利用sshpass
批量实现基于key验证
ssh-keygen -f /root/.ssh/id_isa -P ''
NET=192.168.100
export SSHPASS=magedu
for IP in {1..200};do
sshpass -e ssh-copy-id $NET.$IP
done
二、Ansible命令操作主机报错
2.1 错误1 Failed to connect to the host via ssh: Permission denied
"msg": "Failed to connect to the host via ssh: Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password)"
- 检查
/etc/ansible/hosts
文件是否正确配置主机 - 删除
/root/.sh/known_hosts
文件,这个文件存储了错误的凭证
2.2 错误2 Failed to connect to the host via ssh: Warning: Permanetly added
"msg": "Failed to connect to the host via ssh: Warning: Permanetly added "IP" (ECDSA) to the list of known hosts.\r\nPermission denied (publickey,gssapi-keyex,gssapi-with-mic,password)"
说明没有传入主机认证信息,添加-k
参数
ansible IP -m command -a "ls" -k
2.3 错误3 Using a SSH password instead of key is not possible
192.168.8.16 | FAILED | rc=-1 >>
Using a SSH passwork instead of a key is not possible because Host key checking is enabled and sshpass does not support this. Please add this hosts's fingerprint to your known_hosts file to manage this host.
可以从错误中得出,文件knwon_hosts
没有这个主机ssh记录
只需要在运行ansible IP -m command -a "ls"
添加主机记录
三、相关工具和常见模块
相关工具:
- ansible-doc
- ansible
- ansibe-galaxy
- ansible-pull
- ansible-playbook
- ansible-vault
- ansible-console
常见模块:https://doc.ansible.com/ansible/latest/modules/modules_by_category.heml
修改配置文件/etc/ansible/ansible.cfg
中的module_name=shell
可改变默认模块为shell
- Command模块:远程主机执行命令,默认模块,可忽略
-m
选项。不支持$VARNAME< > | ; &
等 - shell模块:和command相似,用shell执行命令
ansible websrvs -m shell -a 'echo centos | passwd --stdin wang'
- Script模块:远程主机上运行ansible服务器上的脚本
- Copy模块:从ansible服务器主控端复制文件到远程主机
- Fetch模块:从远程主机提取文件到ansible的主控端,copy相反,
src
目前不支持目录 - File模块:设置文件属性
# 创建空文件
ansible srv -m file -a 'path=/data/test.txt state=touch'
ansible srv -m file -a 'path=/data/test.txt state=absent' # absent 删除
absible srv -m file -a 'path=/root/test.sh owner=wang mode=755'
# 创建目录
ansible srv -m file -a "path=/data/mysql state=directory owner=mysql group=mysql"
# 创建软链接
ansible srv -m file -a 'src=/data/testfile dest=/data/testfile-link state=link'
- Unarchive 模块:解包解压缩
- 将ansible主机上的压缩包传到远程主机后解压缩到特定目录,设置copy=yes
- 将远程主机上的某个压缩包解压缩到指定路径下,设置copy=no
- Archive模块:打包压缩
- Hostname模块:管理主机名
- Cron模块:计划任务,支持时间
minute, hour, day, month, weekday
# 备份数据库脚本
~]# cat mysql_backup.sh
mysqldump -A -F --single-transaction --master-data=2 -q -uroot |gzip > /data/mysql_ `date+%F_%T`.sql.gz
# 创建任务
ansible 192.168.39.28 -m cron -a 'hour=2 minute=30 weekday=1-5 name="backup mysql" job=/root/mysql_backup.sh'
ansible srv -m cron -a "minute=*/5 job='/usr/sbin/ntpdate 172.20.0.1 &>/dev/null' name=Synctime"
# 禁用计划任务
ansible srv -m cron -a "minute=*/5 job='/usr/sbin/ntpdate 172.20.0.1 &>/dev/null' name=Synctime disabled=yes"
# 启用计划任务
ansible srv -m cron -a "minute=*/5 job='/usr/sbin/ntpdate 172.20.0.1 &>/dev/null' name=Synctime disabled=no"
# 删除任务
ansible srv -m cron -a "name='backup mysql' state=absent"
ansible srv -m cron -a 'state=absent name=Synctime'
- Yum模块:管理软件包,只支持RHEL,Centos,Fedora,不支持Ubuntu
ansible srv -m yum -a 'name=httpd state=present' # 安装,state默认安装
ansible srv -m yum -a 'name=httpd state=absent' # 删除
- Service模块:管理服务
ansible srv -m service -a 'name=httpd state=started enabled=yes'
ansible srv -m service -a 'name=httpd state=reloaded'
ansible srv -m shell -a "sed -i 's/^Listen 80/Listen 8080/' /etc/httpd/conf/httpd.conf"
ansible srv -m service -a 'name=httpd state=restarted'
- User模块:管理用户
# 创建用户
ansible srv -m user -a 'name=user1 comment="test user" uid=2048 home=/app/user1 group=root'
ansible srv -m user -a 'name=nginx comment=nginx uid=88 group=nginx groups="root,daemon" shell=/sbin/nologin system=yes create_home=no home=/data/nginx non_unique=yes'
# 删除用户及家目录等数据
ansible srv -m user -a 'name=nginx state=absent remove=yes'
- Group模块:管理组
- Lineinfile模块:ansible在使用sed进行替换时,经常会遇到需要转义的问题,而且ansible在遇到特殊符号进行替换时,存在问题,无法正常进行替换。其实在ansible自身提供了两个模块:lineinfile模块和replace模块,可以方便的进行替换。
相当于sed,可以修改文件内容 - Replace模块:该模块有点类似于sed命令,主要也是基于正则进行匹配和替换
- Setup模块:用来收集主机的系统信息,这些facts信息可以直接以变量形式使用,但是如果主机较多,会影响执行速度,可以使用
gather_facts: no
来禁止Ansible收集facts信息
四、Playbook
4.1 介绍
playbook剧本是由一个或多个"play"组成的列表
play的主要功能在于将预定义的一组主机,装扮成事先通过ansible中的task定义好的角色。Task实际是调用ansible的一个module,将多个play组织在一个playbook中,即可以让它们联合起来,按事先编排的机制执行预定义的动作
playbook文件是采用YAML语言编写
4.2 Playbook核心元素
- Hosts:执行的远程主机列表
- Tasks:任务集
- Variables:内置变量或自定义变量在playbook中调用
- Templates:模板,可替换模板文件中的变量并实现一些简单逻辑的文件
- Handlers和notify:结合使用,由特定条件触发的操作,满足条件才执行,否则不执行
- tags:标签,指定某条任务执行,用于选择运行playbook中的部分代码。ansible具有幂等性,因此会自动跳过没有变化的部分,即便如此,有些代码为测试其确实没有发生变化的时间依然会非常地长。可以通过tags跳过代码片段
4.3 实战简单案例
安装httpd
- hosts: webnsrvs
remote_user: root
tasks:
- name: install httpd
yum: name=httpd
- name: start httpd
service: name=httpd state=started enabled=yes
ShellScripts
VS Playbook
案例
# shell脚本实现
#!/bin/bash
# 安装Apache
yum install --quiet -y httpd
# 复制配置文件
cp /tmp/httpd.conf /etc/httpd/conf/httpd.conf
cp /tmp/vhosts.conf /etc/httpd/conf.d/
# 启动Apache,并设置开机启动
systemctl enable --now httpd
# playbook实现
---
- hosts: websrvs
remote_user: root
gather_facts: no # 不收集主机信息
tasks:
- name: "install Apache"
yum: name=httpd
- name: "copy config file"
copy: src=/tmp/httpd.conf dest=/etc/httpd/conf/
- name: "copy config file"
copy: src=/tmp/vhosts.conf dest=/etc/httpd/conf.d/
- name: "start Apache and set enable"
service: name=httpd state=started enable=yes
4.4 实战之handlers和notify
Handlers本质是task list,类似于MySQL中的触发器的行为,其中的task与前述的task并没有本质上的不同,主要用于当关注的资源发生变化时,才会采取一定的操作。而Notify对应的action可用于在每个play的最后被触发,这样可避免多次有改变发生时每次都执行指定的操作,仅在所有的变化发生完成后一次性地执行指定操作。
在notify中列出的操作称为handler,也即notify中调用handler中定义的操作
简单案例:
---
- hosts: websrvs
remote_user: root
tasks:
- name: Install gttpd
yum: name=httpd state=present
- name: Install configure file
copy: src=files/httpd.conf dest=/etc/httpd/conf/
notify: restart httpd
- name: ensure apache is running
service: name=httpd state=started enabled=yes
handlers:
- name: restart httpd
service: name=httpd state=restarted
4.5 Playbook变量
变量名:仅能由字母、数字和下划线组成,且只能以字母开头
变量定义:key=value
变量调用方式:通过{{ key }}
调用变量
变量来源:
- ansible的setup facts远程主机的所有变量都可直接调用,ansible命令方式不能调用
- 通过命令行指定变量,优先级最高
ansible-playbook -e varname=value
- 在playbook文件中定义
vars:
- var1: value1
- var2: value2
- 在独立的变量YAML文件中定义
- 在主机文件
/etc/ansible/hoosts
中定义
主机(普通)变量:主机组中主机单独定义,优先级高与公共变量
组(公共)变量:针对主机组中所有主机定义统一变量 - 在role中定义
4.6 template模板
模板是一个文本文件,可以作为生成文件的模板,模板文件使用jinja语法,以.j2
结尾
jinja官网:http://jinja.pocoo.org/docs/templates/
示例:
---
- hosts: websrvs
remote_user: root
gather_facts: no
tasks:
- name: template config to remote hosts
template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
流程控制for和if
{% for vhosts in nginx_vhosts %}
server {
listen {{ vhosts }}
}
{% endfor %}
{% for vhost in nginx_vhosts %}
server {
listen {{ vhost.listen }}
{% if vhost.server_name is defined %}
server_name {{ vhost.server_name }}
{% endif %}
root {{ vhost.root }}
}
{% endfor %}
4.7 Playbook中的when和with_items
when语句,实现条件测试。
---
- hosts: websrvs
remote_user: root
gather_facts: no
tasks:
- name: "shutdown RedHat flavored systems"
command: /sbin/shutdown -h now
when: ansible_os_family == "RedHat"
with_items
迭代:当有需要重复执行的任务时,可以使用迭代机制
示例:
---
- hosts: websrvs
remote_user: root
tasks:
- name: add several users
user: name={{ item }} state=present groups=wheel
with_items:
- testuser1
- testuser2
五、Roles角色
5.1 目录编排
Roles目录结构如下:
roles各目录作用:
roles/project/
:项目名称
-
files/
:存放由copy
或script
模块等调用的文件 -
templates/
:template模块查找所需要模板文件的目录 -
tasks/
:定义task,role的基本元素,至少应该包含一个名为main.yaml
的文件;其他文件由main文件通过include进行包含
-
handlers/
:至少包含一个main.yaml
文件;其他文件通过main文件include
进行包含 -
vars/
:定义变量,至少包含一个main.yaml
文件;其他文件通过main文件include
进行包含 -
meta/
:定义当前角色的特殊设定及其依赖关系,至少包含一个main.yaml
文件;其他文件通过main文件include
进行包含 -
default/
:设定默认变量时使用此目录中的main.yaml
文件,比vars的优先级低
5.2 实战之httpd角色
建议到ansible-galay官网下载优秀的模板学习
mkdir -pv /data/ansible/roles/httpd/{tasks,handlers,files}
# 创建角色相关的文件
cd /data/ansible/roles/httpd/
vim task/main.yml
- include: install.yml
- include: config.yml
- include: index.yml
- include: service.yml
vim tasks/install.yml
- name: install httpd package
yum: name=httpd
vim tasks/config.yml
- name: config file
copy: src=httpd.conf dest=/etc/httpd/conf/ backup=yes
notify: restart
vim tasks/index.yml
- name: index.html
copy: src=index.html dest=/var/www/html/
vim tasks/service.yml
- name: start service
service: name=httpd state=started enabled=yes
vim handlers/main.yaml
- name: restart
service: name=httpd state=restarted
# 在files目录下准备两个文件
ls files/
httpd.conf index.heml
# 在playbook中调用角色
vim /data/ansible/role_httpd.yaml
---
# httpd role
- hosts: appsrvs
remote_user: root
roles:
-role: httpd
5.3 实战多角色的选择
---
- hosts: websrvs
roles:
- role: http
tags: [httpd,web]
when: ansible_distribution_major_version="7"
- role: nginx
tags: [nginx,web]
when: ansible_distribution_major_version="8"