Ansible运维神器详解

如果做过运维或者网站开发的朋友,一定接触过服务部署,那么一般的服务部署流程是什么呢?找一台Linux机器,安装好运行环境所需要的软件,然后把服务部署上去。一台机器可以这么做,如果是集群呢?每一台都要这么做。加入我们管理了几百台机器,突然有一天公司要求在所有机器上都安装某一款软件,那么手动显然是不行的,这个时候就必须要借助自动化脚本来完成这项任务了。自动化执行的方式有很多种,最原始的就是shell脚本,但是显然它不能满足我们的需求。常见自动化配置管理工具有很多种,slatstack和ansible是比较流行的两种,而且它们都是用python开发的,但是相对来讲ansible的优势更加明显,主要是因为它拥有大量的模块和插件,而且你在GitHub和gitee上也可以找到很多别人写好的编排剧本,基本拿过来就可以使用了。

Ansible运维神器详解_第1张图片
image-20200815232045597

Ansible简介

尽管我认为当你看这篇文章的时候,可能对ansible有了至少一丁丁了解,但是简单的介绍还是要说一下的。Ansible是一个开源配置管理工具,可以使用它来自动化任务,部署应用程序实现IT基础架构。Ansible可以用来自动化日常任务,比如,服务器的初始化配置、安全基线配置、更新和打补丁系统,安装软件包等。

Ansible安装

  • Centos

    wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
    
    wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
    
    yum clean all
    yum makecache
    
    ansible install -y ansible
    
  • Ubuntu

    apt-get install software-properties-common
    apt-add-repository ppa:ansible/ansible
    apt-get update
    apt-get install ansible
    
  • pip安装

    pip install ansible
    

    pip这种方式是最方便的,毕竟我们一般都安装了Python,但是可能会有一个问题,安装完以后,我们找不到配置文件,使用ansible --version查看发现config file是none,导致我们没法正常使用,这是为什么呢?因为ansible加载配置文件的路径是有顺序的。

ansible.cfg文件加载顺序

ansible.cfg文件作为配置文件,ansible会在多个路径下进行读取,读取的顺序如下:

  • ANSIBLE_CONFIG:环境变量
  • ansible.cfg:当前执行目录下
  • .ansible.cfg:~/.ansible.cfg
  • /etc/ansible/ansible.cfg

所以推荐使用方式是创建一个工程目录,将所有的配置文件都放置在此目录下,这样更方便移植。在ansible.cfg中有如下内容:

[defaults]
inventory = ./hosts
host_key_checking = False

所以我们使用pip安装后,在主机上通过find命令查找到ansible.cfg,默认会安装到python目录下,将其复制到当前执行目录即可。

配置文件有三个:

  1. ansible.cfg --ansible的配置文件,一般我们都使用默认配置,只需要改增加一个host_key_checking=False,不使用指纹验证。指纹验证就是当我们在一台Linux机器上ssh登录另一台Linux时,第一次连接会让我们输入Yes/No
  2. hosts --主机文件清单
  3. roles --一个配置角色的文件夹,默认里面是空的

配置Ansible主机清单

清单配置中文文档

主机清单通常用来定义要管理的主机信息,包括IP、用户、密码以及SSH key配置。可以分组配置,组与组之间可以配置包含关系,使我们可以按组分配操作主机。配置文件的路径为:/etc/ansible/hosts

基于密码的方式连接

vim /etc/ansible/hosts

# 方式一
[web]
192.168.133.111 ansible_ssh_user=root ansible_ssh_pass=123456
192.168.133.112 ansible_ssh_user=root ansible_ssh_pass=123456
192.168.133.123 ansible_ssh_user=root ansible_ssh_pass=123456

# 方式二
[web]
192.168.133.111
192.168.133.112
192.168.133.123

[web:vars]
ansible_ssh_user=root 
ansible_ssh_pass=123456

# 方式三
[web]
192.168.133.111
192.168.133.112
192.168.133.123

# 在/etc/ansible目录下创建目录group_vars,然后再创建文件web.yml,以组名命名的yml文件
vim /etc/ansible/group_vars/web.yml

# 内容如下
ansible_ssh_user: root
ansible_ssh_pass: 123456

测试命令

ansible web -a 'ls /'
Ansible运维神器详解_第2张图片
image-20200815120413285

基于SSH key方式连接

以下命令均在ansible主机执行,无需到被管理机器操作

# 生成ssh key,一路回车,默认生成在/root/.ssh目录下id_rsa和id_rsa.pub
ssh-keygen

# 将公钥拷贝到目标主机
ssh-copy-id [email protected]

# 执行以上语句,并输入密码,会在目标主机生成一个文件/root/.ssh/authorized_keys,之后再连接目标主机就不需要密码了

ad-hoc命令

ad-hoc是临时命令,就像我们执行的shell命令一样,执行完即结束,ad-hoc模式的命令格式如下:

ansible web -m command -a 'df -h'

命令解释:

  • ansible:命令

  • web:主机名/IP/分组

  • -m:指定模块(默认是command,所以可以把-m command这个去掉)

  • command:模块名称

  • -a:模块参数

  • 'df -h':参数值

执行命令返回的结果颜色代表的含义:

绿色:被管理端没有被修改

黄色:被管理端发生变更

红色:执行出现故障

常用模块介绍

ansible官方存在大量的模块,我们使用ansible主要使用的也是因为它有大量的模块和插件,虽然模块很多,但是我们常用的模块就那么几种,下面介绍以下常用模块:

模块名 说明
command(默认) 不支持管道过滤grep
shell 支持管道过滤grep
script 不用把脚本复制到远程主机就可以在远程主机执行脚本
yum 安装软件
yum_repository 配置yum源
copy 拷贝文件到远程主机
file 在远程主机创建目录或者文件
service 启动或停止服务
mount 挂载设备
cron 执行定时任务
firewalld 防火墙设置
get_url 下载软件或访问网页
git 执行git命令

yum命令

参数 选项 含义
name nginx、git、... 软件包名称或url
state present(默认)、absent、latest 安装、删除、最新版
enablerepo epel、base 允许从哪些仓库获取软件
disablerepo epel、base 进制从哪些仓库获取软件
exclude kernel、...... 排除哪些软件包
download_only Yes、no 仅下载软件包,不安装

示例:

# 安装最新版的Apache
ansible web -m yum -a "name=httpd state=latest"

# congepel仓库安装罪行的Apache
ansible web -m yum -a "name=httpd state=latest enablerepo=epel"

# 删除Apache软件包
ansible web -m yum -a "name=httpd state=absent"

copy命令

参数 选项 含义
src 源目录或文件
dest 目标目录或文件
remote_src True、False src是远程主机上还是在当前主机上,仅在mode=preserve有效
owner 所属用户
group 所属组
mode 0655、u=rw、u+rw 设置文件权限
backup yes、no 是否备份目标文件
content 写入目标文件的内容

示例:

# 拷贝apache配置文件到目标机器
ansible web -m copy -a "src=httpd.conf dest=/etc/httpd/conf/httpd.conf owner=root group=root mode=644"

# 拷贝apache配置文件到目标机器,并备份目标文件
ansible web -m copy -a "src=httpd.conf dest=/etc/httpd/conf/httpd.conf owner=root group=root mode=644 backup=yes"

# 在远程主机创建一个文件并写入内容
ansible web -m copy -a "content=HelloWorld dest=/home/index.html"

get_url命令

参数 含义
url 地址
dest 目标文件
mode 文件权限
# 下载文件到本地
ansible web -m get_url -a "url=http://xx.xx.xx/ssss.txt dest=/home/xx.txt mode=655"

file命令

# 创建文件
ansible web -m file -a "path=/home/aaa.txt state=touch"

# 创建目录
ansible web -m file -a "path=/home/test state=directory"

# 递归修改目录权限
ansible web -m file -a "path=/home owner=nginx group=nginx mode=766 recurse=yes"

git命令

参数 含义
repo 远程库下载地址
dest 更新目录
version 分支
update yes、no,不更新代码,只确定库存在
clone yes、no,不下载代码,获取本地已存在仓库的信息

以上是部分常用模块的解释与示例,因为ansible的模块和参数很多,我们就不做详细解释了。但是这里要说一个非常非常重要的一点,以上全都是废话,任何一个模块,ansible都为我们提供了非常详细的解释文档,例如查看cron模块的用法,查询命令如下:

ansible-doc cron

Ansible运维神器详解_第3张图片
image-20200815203621446

不仅有参数解释,还有执行示例:

Ansible运维神器详解_第4张图片
image-20200815203709278

如果想查询都有哪些模块,ansible-doc -l > ansible.doc,当然了,执行示例是按照ansible-playbook的方式显示的,但是我们稍微改一下就可以用ad-doc的方式执行了

报错处理

[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'
[WARNING]: Could not match supplied host pattern, ignoring: oldboy

这个问题一般是没有在ansible.cfg内指定主机清单文件导致的,配置正确的inventory路径即可,还可以通过在ansible命令后面加-i来指定。

playbook

Playbookad-hoc相比,是一种完全不同的运用ansible的方式,类似与saltstackstate状态文件。ad-hoc无法持久使用,playbook可以持久使用。playbook是由一个或多个play组成的列表,play的主要功能在于将事先归并为一组的主机装扮成事先通过ansible中的task定义好的角色。从根本上来讲,所谓的task无非是调用ansible的一个module。将多个play组织在一个playbook中,即可以让它们联合起来按事先编排的机制完成某一任务。

Playbook是通过yml语法进行编排的,使用起来非常简单,我们只需要知道一些基本的关键字就可以实现了。

  • hosts:
  • tasks:
  • vars:
  • templates:
  • handlers:
  • tags:

下面给一个简单的例子:

# httpd.yaml

- hosts: web
  tasks:
    - name: install httpd server
      yum: name=httpd state=present
      
    - name: configure httpd server
      copy: src=httpd.conf dest=/etc/httpd/conf/httpd.conf
      
    - name: configure httpd server
      copy: src=index.html dest=/var/www/html/index.html
      
    - name: service httpd server
      service: name=httpd state=started enabled=yes

这是一个安装Apache、配置、启动的流程,我们看一下其中的关键字。

  • hosts:需要执行的主机、组、IP
  • tasks:执行的任务
    • name:任务描述
    • yum/copy/service:执行模块(上面我们介绍过的)

这就是最基础的Playbook的结构,也是一个Playbook所必备的结构,当然还有更多高级的操作,我们下面通过更多的示例来给大家讲解。

搭建nginx服务

- hosts: web
  vars:
    hello: Ansible
    
  tasks:
    # 配置软件源
    - name: Configure Yum Repo
      yum_repository: 
        name: nginx
        description: nginx repo
        baseurl: http://nginx.org/packages/centos/7/$basearch/
        gpgcheck: yes
        enabled: yes

    # 安装nginx    
    - name: Install Nginx
      yum: name=ningx state=present
    
    # 替换配置文件
    - name: Configure Nginx
      copy: 
        src: nginx.conf
        dest: /etc/nginx/conf/nginx.conf
        
    # 修改首页
    - name: Change Home
      copy: 
        content: "Hello {{hello}}"
        dest: /var/www/html/index.html
        
    # 启动nginx
    - name: Start Nginx
      service:
        name: nginx
        state: started

上面这个例子在模块使用时,我用了两种例子

yum: name=nginx state=present

copy:
  src: nginx.conf
  dest: /etc/nginx/conf/nginx.conf

这两种方式都是可以的,只是写法不同,希望不要有人被误导,另外在这里例子中我们还引入了下一个知识点-变量

Ansible中的变量

为什么要使用变量?

首先我们要明确为什么使用变量?变量这个词在编程当中经常用到,我们一直强调在编程中不要使用魔法数字,尽量使用宏或者变量代替,魔法数字一方面意义不够明确,另外一方面在修改的时候,要涉及到很多地方,会出现纰漏。那么在ansible中使用变量的意义也是一样的,明确意义、方便修改

怎么定义变量和使用变量?

  • 在playbook文件中的hosts下使用vars进行定义

    1. 在playbook文件中直接定义变量
    - hosts: web
      vars:
        web_pack: httpd-2.4.6
        ftp_pack: vsftpd
        # - web_pack: httpd-2.4.6  与上面等同
        
      tasks:
        - name: Install {{pack_name}}
          yum: 
            name:
              - "{{web_pack}}"
              - "{{ftp_pack}}" 
            state: present
    
    1. 额外定义一个变量文件

      如果是在多个文件中使用同样的变量,可以定义一个变量文件,在playbook中使用vars_files中引入即可

    # vars.yml
    web_pack: httpd-2.4.6
    ftp_pack: vsftpd
    
    - hosts: web
      vars_files: 
        - ./vars.yml
    
  • 在主机清单文件中进行定义

    1. 在主机清单文件中定义
    # hosts
    [web]
    192.168.143.122
    
    [web:vars]
    pack_name=httpd
    
    # playbook中使用,可以直接使用,如果当前文件中搜索不到,就去主机清单中搜搜
    - hosts: web
      tasks:
        - name: isntall {{pack_name}}
          yum: name={{pack_name}} state=present
    
    1. 单独定义group_vars和host_vars目录

      group_vars是为组定义的变量目录,其下文件名为组名,例如group_vars/web,host_vars是为主机定义的变量目录,其下文件名为IP,例如host_vars/192.168.143.122。

      注意:默认情况下,group_vars目录中文件名与hosts清单中的组名保持一致,因此在使用的时候,只对本组有效,其他组不能使用,但是系统还提供了一个特殊的组-all,在group_vars新建一个all文件,所有组都可以使用

      # web文件
      pack_name: httpd
      
  • 执行playbook时使用-e参数指定变量

    ansible-playbook httpd.yml -e "pack_name=httpd" -e "hosts=web"
    

    hosts变量通过-e传递是比较常见的,我们可以区分测试环境和生产环境,当然你也可以定义不同的文件来区分

ansible 变量的优先级

上面我们介绍了多种变量的定义方式,那么如果在多个地方定义了相同的变量,优先会使用哪个呢?这就涉及到变量优先级的问题了。

  • 通过执行命令传递的变量
  • 在playbook中引入vars_files中的变量
  • 在playbook中定义的vars变量
  • 在host_vars中定义的变量
  • 在group_vars中组名文件中定义的变量
  • 在group_vars中all文件中定义的变量

ansible resister注册变量

在我们使用ansible-playbook的时候,它的输出是固定的格式的,假如我们启动了httpd服务以后,想要看一下这个服务的状态,我们不能登录到目标主机去查看,那么ansible有什么方式可以查看吗?

- hosts: web
  tasks:
    - name: install httpd server
      yum: name=httpd state=present
      
    - name: service httpd server
      service: name=httpd state=started enabled=yes
      
    - name: check httpd state
      shell: ps aux|grep httpd
      register: httpd_status
      
    - name: output httpd_status variable
      debug:
        msg: "{{httpd_status}}"
Ansible运维神器详解_第5张图片
image-20200816103513010

上面是输出了所有的内容,如果需要输出部分内容,只要用变量.属性就行了,属性就是msg下的字典

ansible facts变量的意义

Ansible运维神器详解_第6张图片
image-20200816100759497

这是我们安装Apache的打印,可以看到分为几个过程:PLAY、TASK、PLAY RECAP,在TASK的第一个打印我们看到是Gathering Facts,但是我们并没有添加这个任务,这是ansible自动为我们添加的,这个任务是做什么用的呢?我们在执行的过程中发现这一块执行时间还比较长。这个任务的主要作用是获取目标主机的信息,我们看一下都能获取哪些信息,可以通过以下语句打印:ansible web -m setup

Ansible运维神器详解_第7张图片
image-20200816134619812

包括CUP、内存、硬盘、网络、主机名、绑定信息、系统版本信息等等,非常多的信息,这些信息都可以在playbook中当做变量使用。

- hosts: web
  tasks:
    - name: Query Host Info
      debug:
        msg: IP address is {{ansible_default_ipv4.address}} in hosts {{ansible_distribution}}
Ansible运维神器详解_第8张图片
image-20200816135438185

那么这个可以在什么情况下使用呢?例如根据目标主机的CPU数,配置nginx并发进程数量,当然如果不使用,我们也可以关闭它。

- hosts: web
  gather_facts: no
  
  tasks:
    - name: install httpd server
      yum: name=httpd state=present
      
    - name: service httpd server
      service: name=httpd state=started enabled=yes
Ansible运维神器详解_第9张图片
image-20200816140007136

下面看一个例子:安装memcache

# memcache.yml
- hosts: web
  tasks:
    - name: install memcached server
      yum: name=memcached state=present
      
    - name: configure memcached server
      template: src=./memcached.j2 dest=/etc/sysconfig/memcached
      
    - name: service memcached server
      service: name=memcached state=started enabled=yes
      
    - name: check memcached server
      shell: ps aux|grep memcached
      register: check_mem
      
    - name: debug memcached variables
      debug:
        msg: "{{check_mem.stdout_lines}}"
# memcached.j2,通过facts获取的目标主机内存总量
PORT="11211"
USER="memcached"
MAXCONN="1024"
CACHESIZE="{{ansible_memtotal_mb // 2}}"
OPTIONS=""

这里我们用到了一个新的模块:template,这个相当于Django的模板语法,支持Jinjia2渲染引擎和语法。以上实现了playbook的大部分操作,但是那只是常规操作,还有一些更加灵活的问题需要处理,例如:

我们只想要执行一个playbook中的某个任务?

检测nginx状态,如果正常就启动或重启,不正常就忽略,执行其他任务

如果nginx的配置文件没有变化,我们就不执行启动或重启命令

以上这些情况都需要进行逻辑判断,ansible强大的地方也正是这里,下面我们看一下task的任务控制流程

Task任务控制

任务控制包括以下逻辑关键字:

  1. 条件判断 when
  2. 循环语句 with_items
  3. 触发器 handlers
  4. 标签 tags
  5. 包含 include
  6. 忽略错误 ignore_error
  7. 错误处理 change

条件判断

假设我们安装Apache,在centos上安装的是httpd,在Ubuntu上安装的是httpd2,因此我们需要判断主机信息,安装不同的软件。

- hosts: web
  tasks:
    - name: Install CentOS Httpd
      yum: name=httpd state=present
      when: ( ansible_distribution == "CentOS" )
      
    - name: Install Ubuntu Httpd
      yum: name=httpd2 state=present
      when: ( ansible_distribution == "Ubuntu" )

给task加上when条件,在执行的时候,就会先判断条件是否满足,如果满足则执行任务,不满足就不执行此任务。我们再看一个例子:如果Apache服务不正常就重启,否则跳过。

- hosts: web
  tasks:
    - name: check httpd server
      command: systemctl is-active httpd
      register: check_httpd
      
    - name: httpd restart
      service: name=httpd state=restarted
      when: check_httpd.rc == 0

循环命令 with_items

启动多个服务,例如nginx、httpd

- hosts: web
  tasks:
    - name: Service Start
      service: name={{item}} state=restarted
      with_items:
        - nginx
        - httpd

拷贝多个配置文件

- hosts: web
  tasks:
    - name: Copy Configure File
      copy: 
        src: {{item.src}}
        dest: {{item.dest}}
        mode: {{item.mode}}
      with_items:
        - { src: './nginx.conf', dest: '/etc/nginx/conf/nginx.conf' }
        - { src: './httpd.conf', dest: '/etc/httpd/conf/httpd.conf' }

触发器 handlers

当某个任务发生变化时,触发另一个任务的执行,例如如果httpd的配置文件发生了变化,就执行重启任务

- hosts: web
  tasks:
    - name: install httpd server
      yum: name=httpd state=present
      
    - name: configure httpd server
      copy: src=httpd.conf dest=/etc/httpd/conf/httpd.conf
      notify: # 条用名称为Restart Httpd Server的handlers,可以写多个
        - Restart Httpd Server
        
    - name: service httpd server
      service: name=httpd state=started enabled=yes
      
  handlers:
    - name: Restart Httpd Server
      service: name=httpd state=restarted

handlers执行的时候需要注意,虽然是在某个任务被触发的,但是它必须等到所有的task执行完成后,才会执行handlers里面被触发过的命令,如果在执行前,有另一个task执行失败了,那么被触发的handlers也不会执行。

tags标签

对任务指定标签后,我们在使用ansible-playbook执行的时候就可以指定标签来执行任务,不需要执行所有的任务,标签的设置有三种情况:1. 一个任务设置一个标签 2.一个任务设置多个标签 3. 多个任务设置一个标签

- hosts: web
  tasks:
    - name: install httpd server
      yum: name=httpd state=present
      tags: install
      
    - name: configure httpd server
      copy: src=httpd.conf dest=/etc/httpd/conf/httpd.conf
      notify: # 条用名称为Restart Httpd Server的handlers,可以写多个
        - Restart Httpd Server
      tags: configure
      
    - name: service httpd server
      service: name=httpd state=started enabled=yes
      tags: start
      
  handlers:
    - name: Restart Httpd Server
      service: name=httpd state=restarted

执行指定tags的命令:ansible-playbook httpd.yml -t "configure"

跳过指定tags的命令:ansible-playbook httpd.yml --skip-tags "install"

include包含

我们可以把任务单独写在一个yaml文件中,然后在其他需要用到的任务中通过include_tasks: xxx.yml引入,举例如下:

# a.yml
- name: restart httpd service
  service: name=httpd state=restarted
# b.yml
- hosts: web
  tasks:
    - name: configure httpd server
      copy: src=httpd.conf dest=/etc/httpd/conf/httpd.conf
      
    - name: restat httpd
      include_tasks: ./a.yml

当然我们也可以把两个完整的playbook合并起来

# a.yml
- hosts: web
  tasks:
    - name: install httpd server
      yum: name=httpd state=present
# b.yml
- hosts: web
  tasks:
    - name: configure httpd server
      copy: src=httpd.conf dest=/etc/httpd/conf/httpd.conf
# total.yml
- import_playbook: ./a.yml
- import_playbook: ./b.yml

在执行total.yml的时候,实际上就是先执行a.yml,然后再执行b.yml,里面的内容实际并不是真正的合并

忽略错误ignore_errors

我们知道,在执行playbook的时候,如果其中某个任务失败了,它下面的任务就不会再执行了,但是有时候我们并不需要所有任务都成功,某些任务是可以失败的,那么这个时候就需要进行容错,就是在这个任务失败的时候,不影响它后面的任务执行。

- hosts: web
  tasks:
    - name: check httpd status
      command: ps aux|grep httpd
      register: httpd_status
      ignore_errors: yes # 如果查询语句执行失败,继续向下执行重启任务
      
    - name: restart httpd
      service: name=httpd state=restarted

错误处理

  • force_handlers: yes 强制调用handlers

    只要handlers被触发过,无论是否有任务失败,均调用handlers

    - hosts: web
      force_handlers: yes
      
      tasks:
        - name: install httpd
          yum: name=httpd state=present
          
        - name: install fuck
          yum: name=fuck state=present
      
      handlers:
        - name: restart httpd
          service: name=httpd state=restarted
    
  • change_when

    当任务执行的时候,如果被控主机端发生了变化,change就会变化,但是某些命令,比如一些shell命令,只是查询信息,并没有做什么修改,但是一直会显示change状态,这个时候我们就可以强制把change状态关掉。

    - hosts: web
      tasks:
        - name: test task
          shell: ps aux
          change_when: false
    

    再看一个例子,加入我们修改配置文件成功了,就执行重启命令,否则不执行重启

    - hosts: web
      tasks:
        - name: install nginx server
          yum: name=nginx state=present
          
        - name: configure nginx 
          copy: src=./nginx.conf dest=/etc/nginx/conf/nginx.conf
        
        # 执行nginx检查配置文件命令
        - name: check nginx configure
          command: /usr/sbin/nginx -t
          register: check_nginx
          changed_when: ( check_nginx.stdout.find('successful') )
          
        - name: service nginx server
          service: name=nginx state=restarted
    

    Jinja模板

    jinja模板是类似Django的模板,如果做过Django的同学应该是比较熟悉的,我们使用jinja来配置一下nginx的负载均衡

    - hosts: web
      vars:
        - http_port: 80
        - server_name: web.com
        
      tasks:
        - name: instal nginx server
          yum: name=nginx state=present
          
        - name: configure nginx
          template: src=./nginx.conf dest=/etc/nginx/conf/nginx.conf
          
        - name: start nginx
          service: name=nginx state=started enabled=yes
    

    要使Jinja语法生效,必须使用template模块处理,这个模块和copy类似,但是它支持Jinja语法渲染

    # nginx.conf
    upstream {{server_name}} {
      {% for i in range(2) %}
        server 192.168.143.12{{i}}:{{http_port}};
        server 192.168.143.12{{i}}:{{http_port}};
      {% endfor %}
    }
    
    server {
      listen {{http_port}};
      server_name {{server_name}}
      location / {
        proxy_pass http://web.com;
        include proxy_params;
      }
    }
    

    在配置文件中就可以使用playbook中定义的变量,我们在配置MySQL主从复制集群的时候,对于my.cnf文件,master主机和slave主机的配置是不同的,这样就可以根据主机名,使用Jinja中的if语法进行条件渲染

    [mysqld]
    {% if ansible_fqdn == "mysql_master" %}
      log-bin=mysql-bin
      server-id=1
    {% else %}
      server-id=2
    {% endif %}
    

    这样就完成了配置区分,执行同样的template拷贝命令,在不同的机器上是不同的配置文件。

    PS:

    ansible_fqdn: 这个是gather_facts任务获取的变量,我们也可以使用其他变量进行判断

    mysql_master: 这个是需要配置主从复制的master主机hostname,需要提前设置,也是可以用ansible设置的

    Ansible Roles

    最后我们要讲一下ansible中最重要的一个概念-roles,如果前面的你都搞清楚了,那么roles是非常简单的。总的来说roles就是把我们前面讲过的东西进行了一个排版,它规定了严格的目录格式,我们必须按照目录结构和文件名进行创建,否则它的文件系统就加载不到。目录格式如下:

    Ansible运维神器详解_第10张图片
    image-20200816183102510
  • mysql.yml:playbook文件

  • mysql:roles目录,也是角色名

    • files:存放文件、压缩包、安装包等
    • handlers:触发任务放在这里
    • tasks:具体任务
    • templates:存放通过template渲染的模板文件
    • vars:定义变量
    • meta:任务依赖关系

那些main.yml也是必须的,名字必须是这样,目录名称也必须相同,但是不是每个目录都是必须的,下面我们把httpd的那个例子用roles写一下:

- hosts: web
  tasks:
    - name: install httpd server
      yum: name=httpd state=present
      tags: install
      
    - name: configure httpd server
      template: src=httpd.conf dest=/etc/httpd/conf/httpd.conf
      notify: # 条用名称为Restart Httpd Server的handlers,可以写多个
        - Restart Httpd Server
      tags: configure
      
    - name: service httpd server
      service: name=httpd state=started enabled=yes
      tags: start
      
  handlers:
    - name: Restart Httpd Server
      service: name=httpd state=restarted

就把上面这一段改成roles的格式,目录结构如下:

Ansible运维神器详解_第11张图片
image-20200816190629006
# httpd/handlers/main.yml
- name: Restart Httpd Server
  service: name=httpd state=restarted
# httpd/tasks/config.xml
- name: configure httpd server
  template: src=httpd.conf dest=/etc/httpd/conf/httpd.conf
  notify: # 条用名称为Restart Httpd Server的handlers,可以写多个
    - Restart Httpd Server
  tags: configure
# httpd/tasks/install.yml
- name: install httpd server
  yum: name=httpd state=present
  tags: install
# httpd/tasks/start.yml
- name: service httpd server
  service: name=httpd state=started enabled=yes
  tags: start
# httpd/tasks/main.yml
- include_tasks: install.yml
- include_tasks: config.yml
- include_tasks: start.yml
# httpd1.yml
- hosts: web
  roles:
    - role: nginx
    # - nginx 与上面是等价的,但是上面的可以增加tags

最后再与httpd1.yml同级目录下执行ansible-playbook httpd1.yml即可(我这里实际是httpd2.yml,不要在意这些细节)

Ansible运维神器详解_第12张图片
image-20200816191306993

Galaxy

最后我们再介绍一个官方网站:Galaxy

这是一个类似GitHub和docker一样的网站,我的网太烂了,打不开,它上面是别人写好的roles,比如你想要安装Nginx,那么在上面搜索nginx,然后会提供一个下载命令:ansible-galaxy install geerlingguy.nginx,执行以后,会把它虾藻到/root/.ansible/roles这个目录下。

到这里,ansible的讲解我们就写完了,ansible是用python开发的,所以我们经常会把它和python结合起来使用,后面我们会把python操作ansible写一下。

你可能感兴趣的:(Ansible运维神器详解)