0
点赞
收藏
分享

微信扫一扫

Ansible 学习总结(3)—— Ansible 常用模块与 playbook 实例讲解

一、Ansible 安装

下载安装并解压 python 3.7 包

编译并安装

注意:编译的时候可能提示 error: no acceptable C compiler found in $PATH,此时需安装 gcc yum -y install gcc,然后再执行;make install 的时候可能提示 zipimport.ZipImportError: can’t decompress data; zlib not available ,此时需安装 yum -y install zlib*,再执行,如果提示 ModuleNotFoundError: No module named ‘_ctypes’ make: *** [install] Error 1,此时需安装yum install libffi-devel -y,再执行。

修改默认版本

恢复 yum

  1. 修改完 python 的默认版本后,yum 命令无法再执行。
  2. vim /usr/bin/yum 将文件第一行改为 /usr/bin/python2.7。(2.7.x也改为2.7)
  3. vim /usr/libexec/urlgrabber-ext-down 将文件第一行改为 /usr/bin/python2.7
  4. 这样 python3.7 就安装在 CentOS 上,同时又能够使用 yum 来安装软件了。

安装 pip

curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
//如果离线安装的话可以预先把压缩包准备好
sudo python3 get-pip.py

通过 pip 安装 ansible

python -m pip install ansible

使用 ansible --version 测试安装是否成功

ansible 2.9.6
  config file = /etc/ansible/ansible.cfg
  configured module search path = ['/root/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python3/dist-packages/ansible
  executable location = /usr/bin/ansible
  python version = 3.8.5 (default, Jan 27 2021, 15:41:15) [GCC 9.3.0]

二、Ansible 基础

ansible 是基于ssh 隧道进行连接运行的,故只要系统得 ssh 可以使用则 ansible 就可以使用。

配置文件

ansible 在使用配置文件时按照以下顺序优先配置:

export ANSIBLE_CONFIG

./ansible.cfg

~/.ansible.cfg

/etc/ansible/ansible.cfg

如果以上顺序没有找到配置文件 ansible 会自动使用默认配置,可以去 github 上把默认配置拿下来: 

https://raw.githubusercontent.com/ansible/ansible/devel/examples/ansible.cfg。把它放到 /etc/ansible/ 目录,配置文件主要配置:

 # 默认配置项

 [defaults]
 ask_pass:控制 Ansible 剧本 playbook 是否会自动默认弹出密码
 ask_sudo_pass:用户系统开启了sudo 的密码需要开启这个参数
 gather_subset 设置收集的内容

 #要自动化处理的客户端的信息
 remote_port 客户机 ssh 端口
 remote_tmp 客户机目录
 remote_user 客户机目录
 sudo_exe sudo 命令的路径
 sudo_flags sudo 命令的参数
 sudo_user  可以使用 sudo 的用户
 
 # 开发者中心的插件相关功能,开发者可以开发相应的插件完成自己的功能
 action_plugins     激活事件
 callback_plugins     回调
 connection_plugins 连接插件
 lookup_plugins    加载路径
 vars_plugins       任何地方加载
 filter_plugins     过滤器
 forks 最大开辟的子进程数,过大会导致性能耗费高,过小的话并发性低,一般来说是 CPU 核数 * 2
 module_name /usr/bin/ansible 默认模块名
 pattern playbook 要通信的默认主机组
 inventory 存放可通信主机的目录
 library Ansibl e默认搜寻模块路径
 
 #用户权限设置
 [privilege_escalation]
 #paramiko 插件配置(不是所有情况都启用插件) 
 [paramiko_connection]
 
 #ssh连接设置
 [ssh_connection]

添加一台机器

1.编辑 /etc/ansible/hosts,194.168.0.46 将 46 的控制权限添加到列表中;

2.添加控制机的 public SSH key 到被控制机器的 authorized_keys 中,cat .ssh/id_rsa.pub 查看公钥(没有的话:ssh-keygen -t rsa )

 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC39Ob41GSi4Yxuy1BaKnBON1LPUyP9SN4wv4IWi+xJ99aOa5iuafoH3KLIA8RIVw0BY50zFhlghCktqcBtaH6UT7KG27+G7GWOzI7gwKKg1ajGtYRQ+7x+WN123oUk+p1aiaxvYrhukSqwYyomKJFDL74CYXU4H5EfOAg6jhYIDD/K63VYIw6KdEiiyBAR6RqdmRFd9ozxwH/5uLD5PDKlpo753QHyubk4XyKil2WVREWREosZTZ5L5QqQf2kAJTyV09LxBhg6vNXr6pHbPi5mizgd7rmyVpIiJjh+R5Xw54igBMskICePFPiS9+wLITyoO5qptnJdeiJ2LTOvlhvt root@ebb7023

将194.168.0.23 的公钥添加到 194.168.0.64 的 authorized_keys 中。

3.添加本机的私钥到 Ansible(可省略)

4.运行 ansible all -m ping 测试是否添加成功

[root@host ~]# ansible all -m ping
10.1.114.53 | SUCCESS => {
    "changed": false, 
    "ping": "pong"
}

success 表示了操作的成功与否。这里 changed 为 false 时,表示 ansible 没有进行任何操作,因为当前的被操作主机已经是我们想要达到的目标状态了。changed 为 true 时,表示 ansible 执行了操作,"当前状态"已经被 ansible 改变成了"目标状态"。

简单操作

举例:

ansible all -a 'ls'

相当于在所有的被控制机上执行命令 ‘ls’ 即将 ls 这个参数传给要使用的模块,让它在被控制机器上执行。

对主机分组

Ansible 可同时操作属于一个组的多台主机,组合主机之间的关系通过 inventory 文件配置,默认的文件路径为 /etc/ansible/hosts

[webservers]
194.168.0.23
194.168.0.46

也就是说,194.168.0.23 和 194.168.0.46 同属于 webservers 组中,当对该组操作时,会同时操作 194.168.0.23 和 194.168.0.46.

 ansible webservers-a 'ls'

如果出现了主机之间端口不一致可以在 host 文件中注明端口号

194.168.0.23:8080

机器如果有连着的,可以使用以下方式(也支持字母表):

[vim]

194.168.0.[1:50]

分文件管理

/etc/ansible/group_vars/vim

/etc/ansible/group_vars/webservers

/etc/ansible/group_vars/test

vim 文件大致内容:

ntp_server:194.168.0.23

database_server:194.168.0.24

这时的文件名就是组名

ansible payerns

ad-Hoc

如果我们可以使用一些命令去比较快的完成一些事情,而不需要将这些执行命令特别的保存下来,这样的命令就是 ad-hoc,即临时命令。

ansible 中的变量

变量是应用于多个主机的便捷方式; 实际在主机执行之前,变量会对每个主机添加,然后在执行中引用

  • 命令行传递
-e VAR=VALUE
  • 配置文件中针对某个主机或者某个组的变量
 [webservers]
 192.168.1.100 ansible_ssh_user=root hostname=web1
 192.168.1.100 ansible_ssh_user=root hostname=web2
 ​
 [webservers:vars]
 ansible_ssh_user=root hostname=web1
  • 文件存储的变量

Ansible 中的首选做法是不将变量存储在配置文件 (hosts) 中。除了将变量直接存储在配置文件 (hosts) 之外,主机和组变量还可以存储在相对于配置文件 (hosts) 的单个文件中。组变量:

 # vi /etc/ansible/group_vars/all.yml
 work_dir: /data
 # vi /etc/ansible/host_vars/webservers.yml
 nginx_port: 80

三、ansible 模块

command 模块

command 模块可以帮助我们在远程主机上执行命令

注意:使用 command 模块在远程主机中执行命令时,不会经过远程主机的 shell 处理,在使用 command 模块时,如果需要执行的命令中含有重定向、管道符等操作时,这些符号也会失效,比如 "<", ">", "|", ";" 和 "&" 这些符号,如果你需要这些功能,可以参考后面介绍的 shell 模块,还有一点需要注意,如果远程节点是 windows 操作系统,则需要使用 win_command 模块。

ansible test -m command -a "ls"
#在 test 主机上执行 ls 命令,因为我使用的是 root 用户,所以默认情况下,ls 出的结果是 test70 主机中 root 用户家目录中的文件列表。
 ​
ansible test -m command -a "chdir=/testdir ls"
#chdir 参数表示执行命令之前,会先进入到指定的目录中,所以如下命令表示查看 test 主机上 /testdir 目录中的文件列表

shell 模块

shell 模块可以帮助我们在远程主机上执行命令,与 command 模块不同的是,shell 模块在远程主机中执行命令时,会经过远程主机上的 /bin/sh 程序处理。

#使用 shell 模块可以在远程服务器上执行命令,它支持管道与重定向等符号。
ansible test -m shell -a "chdir=/testdir echo test > test"

script 模块

script 模块可以帮助我们在远程主机上执行 ansible 主机上的脚本,也就是说,脚本一直存在于 ansible 主机本地,不需要手动拷贝到远程主机后再执行。

如下命令表示 ansible 主机中的 /testdir/atest.sh 脚本将在 test70 主机中执行,执行此脚本之前,会先进入到 test70 主机中的 /opt 目录

#如下命令表示ansible主机中的/testdir/atest.sh脚本将在test主机中执行,执行此脚本之前,会先进入到 test 主机中的 /opt 目录
ansible test -m script -a "chdir=/opt /testdir/atest.sh"

copy 模块

copy 模块的作用就是拷贝文件,它与之前介绍过的 fetch 模块类似,不过,fetch 模块是从远程主机中拉取文件到 ansible 管理主机,而 copy 模块是将 ansible 管理主机上的文件拷贝到远程主机中

ansible test -m copy -a "src=/etc/ansible/hosts  dest=/"
#文件分发:源文件及路径 /etc/ansible/hosts ,目标路径/,目标主机:test 分组的所有主机

file 模块

file 模块以完成创建文件或目录、删除文件或目录、修改文件权限等操作

# 在创建文件或目录的时候指定属组或者修改远程主机上的文件或目录的属组。
ansible test -m file -a "path=/testdir/abb state=touch group=zsy"

blockinfile 模块

blockinfile 模块可以在指定的文件中插入一段文本,而且这段文本会被标记,以后的操作可以找到这段文本修改或者删除

#假如,我们想要在 test 的主机中的 /testdir/rc.local 文件尾部插入如下两行
systemctl start mariadb
systemctl start httpd

#可以使用如下命令
ansible test -m blockinfile -a 'path=/testdir/rc.local block="systemctl start mariadb\nsystemctl start httpd" '

lineinfile 模块

lineinfile 模块,用于对文件内容的修改

举例:

# cat /testdir/test
This is a file
The file is very simple
hello world!

# 如果指定的文本本来就存在于文件中,则不做任何操作,如果不存在,默认在文件的末尾插入这行文本
ansible 194.168.0.46 -m lineinfile -a 'path=/testdir/test line="hello text"'

yum_repository 模块

yum_repository 模块用于管理远程主机上的 yum 仓库

#在 test 主机上设置 ID 为 aliEpel 的 yum 源,仓库配置文件路径为 /etc/yum.repos.d/aliEpel.repo
ansible test -m yum_repository -a 'name=aliEpel description="alibaba EPEL" baseurl=https://mirrors.aliyun.com/epel/$releasever\Server/$basearch/'

yum 模块

yum 模块可以帮助我们在远程主机上通过 yum 源管理软件包

ansible test -m yum -a"name=acme state = present"
#确认一个软件包已经安装,但是不升级它
 ​
ansible webservers -m yum -a "name=nginx state=latest"
#安装nginx,最新版本,安装过程中的信息会全部输出值屏幕端

unarchive 模块

unarchive  模块用于解压文件

service 模块

ansible webservers -m service -a "name=nginx enabled=true state=started"
#开启 nginx 服务,并设置成开机自启

四、ansible playbook 介绍

ansible playbook 概述

当我们要安装某个软件并启动时,我们需要很多条命令,以 nginx 为例:

#配置对应的yum源
ansible test -m yum_repository -a 'name=aliEpel description="alibaba EPEL" baseurl=https://mirrors.aliyun.com/epel/$releasever\Server/$basearch/'

#使用yum模块安装nginx
ansible test -m yum -a 'name=nginx disable_gpg_check=yes enablerepo=aliEpel'

#使用service模块启动nginx
ansible test -m service -a "name=nginx state=started"

但是在工作中如果有新机器加入进来,每次用命令显得有些繁琐,如果是一些安装起来较为复杂的软件,环境配置要求很多的情况下会非常麻烦,故 ansible 提供了剧本:playbook,将 ad-hoc 命令按照顺序编写在在一个可执行文件中,语法遵循 yaml 语法。

示例:

#原 ad-hoc 命令
#使用 ping 模块去 ping 主机 test70
ansible 194.168.0.46 -m ping

#再用 file 模块在 test70 主机上创建目录
ansible 194.168.0.46 -m file -a "path=/testdir/test state=directory"

#test.yaml
---
- hosts: 194.168.0.46
  remote_user: root
  tasks:
  - name: ping46
  	ping:
  - name: mkdir test
  	file:
  	  path: /testdir/test
  	  state: directory 

在YAML语法中:--- 表示文档开始。下面开头(有空格),表示一个块的节点,host 表明要操作的主机,host 关键字对应值为 194.168.0.22,表示在该主机上操作。下面的 remote_user 表示远程操作时使用的用户,这里我们使用 194.168.0.22 的 root 用户。这行要与 host 对齐,yaml 中不识别 tab,tasts 表示要执行的任务列表,每个 play 包含一系列任务。这些任务按照顺序执行,在 play 中,所有主机都会执行相同的任务指令。play 目的是将选择的主机映射到任务。任务列表的起名比较随意。每个任务以 - 开头,上面的语法中 ping 模块没有指定参数,而使用 file 模块时制定了 path 和 state 的值。

[root@ohost ~]# ansible-playbook test.yml 

PLAY [etcd] ********************************************************************

TASK [Gathering Facts] *********************************************************
ok: [194.168.0.46]

TASK [ping64] ******************************************************************
ok: [194.168.0.46]

TASK [mkdir test] **************************************************************
changed: [194.168.0.46]

PLAY RECAP *********************************************************************
194.168.0.46                 : ok=3    changed=1    unreachable=0    failed=0  
#检查 yaml 有没有语法错误
ansible-playbook --syntax-check test.yaml

#模拟运行(不会真的运行,只是帮助我们预估该 yml 文件能不能运行,但是如果 yaml 中的任务有前后依赖关系,那模拟执行会失败)
ansible-playbook --check test.yaml

看下面的例子:

 tasks:
 - name: make testfile
   file:
     path: /testdir/testfile
     state: touch
     mode: 0700 #设置权限为0700

也可以编写成如下格式:

 tasks:
 - name: make testfile
   file: path=/testdir/testfile state=touch mode=0700

常用模块的 playbook 语法

该处用到的参数均可在上面的模块介绍中找到,也可以在安装了 ansible 的机器上查看帮助文档。这里以几个常用的模块为例示范对应的 playbook 语法

shell

 - name: 将命令结果输出到指定文件
   shell: somescript.sh >> somelog.txt
 - name: 切换目录执行命令
   shell:
     cmd: ls -l | grep log
     chdir: somedir/
 - name: 编写脚本
   shell: |
       if [ 0 -eq 0 ]; then     # 比较0和0 的值,一致则输出yes到result,否则输出no
          echo yes > /tmp/result
       else
          echo no > /tmp/result
       fi
   args:
     executable: /bin/bash  #用什么执行脚本

copy

 - name: 拷贝文件
   copy:
     src: /srv/myfiles/myfile.conf
     dest: /etc/myfile.conf
     owner: wang
     group: wang
     mode: u=rw,g=r,o=r #相当于命令中的u+rw,g-wx,o-rwx 或者使用mode: '0644'
     backup: yes

file

 - name: 创建目录
   file:
     path: /etc/some_directory
     state: directory
     mode: '0755'
 - name: 删除文件
   file:
     path: /etc/foo.txt
     state: absent
 - name: 递归删除目录
   file:
     path: /etc/foo
     state: absent

yum

 - name: 安装最新版apache
   yum:
     name: httpd
     state: latest
 - name: 安装列表中所有包
   yum:
     name:
       - nginx
       - postgresql
       - postgresql-server
     state: present
 - name: 卸载apache包
   yum:
     name: httpd
     state: absent 
 - name: 更新所有包
   yum:
     name: '*'
     state: latest
 - name: 安装nginx来自远程repo
   yum:
     name: http://nginx.org/packages/rhel/7/x86_64/RPMS/nginx-1.14.0-1.el7_4.ngx.x86_64.rpm
     # name: /usr/local/src/nginx-release-centos-6-0.el6.ngx.noarch.rpm
     state: present
 - name: 安装nginx最新版
   yum: pkg=nginx state=latest

unarchive

 - name: 解压文件/tmp/test.tar.gz 
   unarchive: 
     src: test.tar.gz 
     dest: /tmp/

service

 - name: 服务管理
   service:
     name: etcd
     state: started
     #state: stopped
     #state: restarted
     #state: reloaded
 - name: 设置开机启动
   service:
     name: httpd
     enabled: yes

debug

将上一步任务执行的结果打印出来,在这一步会将 4 台主机的执行结果都返回,不管成功或是失败都会显示出来。

 - hosts: all
   remote_user: root
   tasks:
   - name: 查看root目录下的文件
     shell:
       cmd: ls -l
       chdir: /root/
   - name: 输出的结果
     debug:
       var: result

playbook 中的变量

全局变量/组变量/主机变量

 ---
 - hosts: webservers
   vars: # 这种变量对于hosts组都有效
     http_port: 80
     server_name: www.ctnrs.com

响应变量 接收任务的响应

 tasks:
 - name: 只在192.168.1.100运行任务
   shell: 
     cmd: ls -l | grep log
     chdir: somedir/
     register: result

五、playbook 常用流程控制

条件

 tasks:
 - name: 只在192.168.1.100运行任务
   shell: 
     cmd: ls -l | grep log
     chdir: somedir/
     register: result
   - debug: var=result
   when: ansible_default_ipv4.address == '192.168.1.100'

循环

 tasks:
 - name: 批量创建用户
   user: name={{ item }} state=present groups=wheel
   with_items:
      - testuser1
      - testuser2
 - name: 遍历/temp中所有txt文件的文件名
   copy: src={{ item }} dest=/tmp
   with_fileglob:
     - "*.txt"

常用循环语句:语句描述 with_items 标准循环 with_fileglob 遍历文件名称 with_dict 遍历字典 with_file 遍历文件内容。注意这里 with_file 和 with_fileglob 的区别,如果我们用 debug 输出结果会发现,with_file 中 debug 打出来的是文件内容,而 with_fileglob 打出来的是文件名称。

任务控制

当某个剧本中有很多任务时,可能我们只要执行其中的某个步骤,那么我们可以给它打标签:

   tasks:
   - name: 安装nginx最新版
     yum: pkg=nginx state=latest
     tags: install
   - name: 写入nginx配置文件
     template: src=/srv/httpd.j2 dest=/etc/nginx/nginx.conf
     tags: config
   - name: 批量创建用户
     user: name={{ item }} state=present groups=wheel
     with_items:
        - testuser1
        - testuser2
     tags: adduser

使用如下命令可以只执行打了某个标签的任务,或者跳过某个标签的任务

 ansible-playbook test.yml --tags "install"
 ansible-playbook test.yml --tags "install,config"
 ansible-playbook test.yml --skip-tags "install"

模板

Jinja2 是基于 python 的模板引擎

  vars:
     domain: "www.ctnrs.com"
  tasks:
   - name: 写入nginx配置文件
     template: src=/srv/server.j2 dest=/etc/nginx/conf.d/server.conf
 # server.j2
 {% set domain_name = domain %}
 server {
    listen 80;
    server_name {{ domain_name }};
    location / {
         root /usr/share/html;
    }
 }

在 jinja 里使用 ansible 变量直接 {{ }} 引用。使用 ansible 变量赋值 jinja 变量不用 {{ }} 引用,生成的文件:

 server {
    listen 80;
    server_name www.ctnr.com;
    location / {
         root /usr/share/html;
    }
 }

如果使用程序流程语句:

定义变量:{% set local_ip = inventory_hostname %}

条件和循环:

 {% set list=['one', 'two', 'three'] %}
 {% for i in list %}
     {% if i == 'two' %}
         -> two
     {% elif loop.index == 3 %}
         -> 3
     {% else %}
         {{i}}
     {% endif %}
 {% endfor %}

文件执行结果:

 [root@myhost ~]# vim server.conf 
 ​
                         one
                                 -> two
                                 -> 3

忽略执行出现的错误

ignore_errors: true 是忽略出现的问题 ,不加默认为 false,任务运行出 bug 时不会执行目标主机的后续任务

   - name: 安装nginx最新版
     yum: pkg=nginx state=latest
     tags: install
     ignore_errors: true

六、Docker 安装实例

在 files/ 文件目录放 docker 的二级制包,这是相对于 yml 文件的相对路径

 ---
 #指定安装docker的主机组
 - hosts: docker 
 #安装目录
   vars:
     tmp_dir: '/tmp/docker'
   remote_user: root
   gather_facts: false
   
   tasks:
   
   - name: 创建临时目录放配置文件和二进制包
     file: dest={{ tmp_dir }} state=directory
     
   - name: 分发并解压docker二进制包(去官网随便选个版本下就行了)
     unarchive: src={{ item }} dest={{ tmp_dir }}
     with_fileglob:
       - "files/docker-*.tgz"
 ​
   - name: 移动docker二进制文件
     shell: cp -rf {{ tmp_dir }}/docker/* /usr/bin
 ​
   - name: 分发service文件
     copy: src=files/docker.service dest=/usr/lib/systemd/system/
 ​
   - name: 创建目录
     file: dest=/etc/docker state=directory
 ​
   - name: 配置docker
     copy: src=files/daemon.json dest=/etc/docker/daemon.json
 ​
   - name: 启动docker
     systemd: name=docker state=restarted enabled=yes daemon_reload=yes
 ​
   - name: 查看状态
     shell: docker info
     register: docker 
   - debug: var=docker.stdout_lines
举报

相关推荐

0 条评论