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)"
  1. 检查/etc/ansible/hosts文件是否正确配置主机
  2. 删除/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 模块:解包解压缩
  1. 将ansible主机上的压缩包传到远程主机后解压缩到特定目录,设置copy=yes
  2. 将远程主机上的某个压缩包解压缩到指定路径下,设置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 介绍

ansible shell 返回结果stderr_lines从中获取某一行开头的内容 ansible shell例子_运维

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 }}调用变量

变量来源:

  1. ansible的setup facts远程主机的所有变量都可直接调用,ansible命令方式不能调用
  2. 通过命令行指定变量,优先级最高
ansible-playbook -e varname=value
  1. 在playbook文件中定义
vars:
  - var1: value1
  - var2: value2
  1. 在独立的变量YAML文件中定义
  2. 在主机文件/etc/ansible/hoosts中定义
    主机(普通)变量:主机组中主机单独定义,优先级高与公共变量
    组(公共)变量:针对主机组中所有主机定义统一变量
  3. 在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目录结构如下:

ansible shell 返回结果stderr_lines从中获取某一行开头的内容 ansible shell例子_linux_02

roles各目录作用:

roles/project/:项目名称

  • files/:存放由copyscript模块等调用的文件
  • 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"