☞Ansible

Ansible


ansible简介

ansible playbooks

ansible部署{keepalived+nginx{httpd, mysql, php}}


ansible简介

Ansible is a radically simple configuration-management, application deployment, task-execution, and multinode orchestration engine. 
Ansible是一款轻量级自动化运维工具,由Python语言开发,结合了多种自动化运维工具的特性,实现了批量系统配置、批量应用部署、批量命令执行等功能;ansible是基于模块化实现批量操作的。

ansible特点: 
模块化、部署简单、工作于agentless模式、默认使用ssh协议、支持自定义模块、支持Palybook等 

ansiblestruct.png

  • Ansible: 核心程序;

  • Modules: 包括 Ansible 自带的核心模块及自定义模块;

  • Plugins: 完成模块功能的补充,包括连接插件、邮件插件等;

  • Playbooks: 网上很多翻译为剧本,个人觉得理解为编排更为合理;定义 Ansible 多任务配置文件,有 Ansible 自动执行;

  • Host Inventory: 定义 Ansible 管理主机的清单,ansible只能管理Inventory中定义的主机

使用Paramiko,PyYAML和Jinja2三个Python的核心库实现 
部署简单:agentless; 
支持自定义模块,使用任意语言编写

问题:不同环境的目标系统如何对相同服务定制不同配置 
如让httpd侦听在不同的端口之上。

安装ansible

解决依赖关系

1.yum -y install python-jinja2 PyYAML python-paramiko python-babel python-crypto

ansible程序包被Fedora-epel所收入,因此安装前需配置好epel仓库的yum源;

1.yum install ansible

使用ansible前提条件

ansible基于SSH连接至host,因此有必要让ansible通过ssh-key连接主机。为了避免Ansible下发指令时输入目标主机密码,通过证书签名达到SSH无密码是一个好的方案,推荐使用ssh-keygen与ssh- copy-id来实现快速证书的生成和公钥下发,其中ssh-keygen生成一对密钥,使用ssh-copy-id来下发生成的公钥。具体操作如下:

  • 生成 SSH公玥和私钥文件 
    ssh-kengen -t rsa -P ' '

  • 拷贝公玥文件到目标主机的ssh认证文件中 
    ssh-copy-id -i ~/.ssh/id_rsa.pub root@HostIP

  • 连接测试 
    ssh root@HostIP

注意: 如果不配置主机免密钥登录,可以在/etc/ansible/hosts中定义用户和密码,主机ip地址,和ssh端口,这样也可以进行免密码访问,但是这个/hosts文件要保护好。

主要文件

程序:/usr/bin/ansible/usr/bin/ansible-playbook/usr/bin/ansible-doc 
配置文件:/etc/ansible/ansible.cfg 
主机清单:/etc/ansible/hosts 
插件目录:/usr/share/ansible_plugins

配置文件

Host Inventory

Inventory是一个简单的从外部资源寻找主机,主机组的成员,和变量信息的程序 – 可以是个 SQL 数据库,一个 CMDB 解决方案,或者是 LDAP。这个概念来自 Puppet (叫”External Nodes Classifier”),工作方式也是类似的。

Ansible 通过读取默认的主机清单配置/etc/ansible/hosts,可以同时连接到多个远程主机上执行任务,默认路径可以通过修改 ansible.cfg 的 hostfile 参数指定路径。

在主机清单文件中定义host组,便于执行命令时指定在哪些主机使用,也可在palybook文件调用这些定义好的主机名称。

1.[dbserver]  []表示主机的分组名,可以按照功能,系统进行分类,便于进行操作
2.192.168.10.2
3.one.example.com
4.www.bds.com:5309         #支持指定ssh端口5309
5.jumper ansible_ssh_port=5309 ansible_ssh_host=192.168.10.2   #设置主机别名为jumper
6.www[01:50].bds.com       #支持通配符匹配www01.bds.com www02.bds.com
7.[web]                    #提醒下这里面字母是随便定义的
8.web-[a:f].bds.com        #支持字母匹配 web-a.bds.com ..web-f.bds.com
9.
10.# 为主机指定类型和连接用户
11.[bds]
12.Localhost  ansible_connection=local
13.other1.example.com ansible_connection=ssh ansible_ssh_user=deploy
14.other2.example.com ansible_connection=ssh ansible_ssh_user=deploy
15.ansible hosts配置文件中支持指令等

1, ansible_ssh_host : 
指定主机别名对应的真实 IP,如:100 ansible_ssh_host=192.168.1.100,随后连接该主机无须指定完整 IP,只需指定 100 即可 
2, ansible_ssh_port : 
指定连接到这个主机的 ssh 端口,默认 22 
3, ansible_ssh_user: 
连接到该主机的 ssh 用户 
4, ansible_ssh_pass: 
连接到该主机的 ssh 密码(连-k 选项都省了),安全考虑还是建议使用私钥或在命令行指定-k 选项输入 
5, ansible_sudo_pass: sudo 密码 
6, ansible_sudo_exe: sudo 命令路径 
7, ansible_connection : 
连接类型,可以是 local、ssh 或 paramiko,ansible1.2 之前默认为 paramiko 
8, ansible_ssh_private_key_file : 私钥文件路径 
9, ansible_shell_type : 
目标系统的 shell 类型,默认为 sh,如果设置 csh/fish,那么命令需要遵循它们语法 
10, ansible_python_interpreter : 
python 解释器路径,默认是/usr/bin/python,但是如要要连BSD系统的话,就需要该指令修改 python 路径 
11, ansible__interpreter : 
这里的”*”可以是 ruby 或 perl 或其他语言的解释器,作用和 ansible_python_interpreter 类似

ansible.cfg

默认的forks=5,即一次fork 5个ansible进程与目标主机通信,fact缓存路径等 
如:

1.[defaults]
2.gathering = smart
3.fact_caching = redis
4.fact_caching_timeout = 86400
5.# seconds

命令使用

ansible

1.ansible <host-pattern> [-f forks] [-m module_name] [-a "args"]
2.    -m MODULE_NAME # 默认为command,可省略
3.
   -a MODULE_ARGS, --args=MODULE_ARGS # 除了shell和command以为的模块都有内置的Args
4.
   -k,-ask-pass # 提示输入ssh的密码,而不是使用基于ssh的密钥认证
5.
   -sudo # 指定使用sudo获得root权限
6.
   -K,-ask-sudo-pass # 提示输入sudo密码,与–sudo一起使用
7.
   -C,-check # 测试此命令执行会改变什么内容,不会真正的去执行

ansible-doc

Show Ansible module documentation

1.ansible-doc -h
2.ansible-doc -l # List available modules
3.ansible-doc -s module_name # Show playbook snippet for specified module(s)

ansible-playbook

1.ansible-playbook [options] <filename.yml>
2.
3.#tags指定与查看
4.     --list-tags
5.
    -t, TAGS_NAME, --tags=TAGS
6.
    --skip-tags=SKIP_TAGS
7.
    --start-at-task=START_AT
8.

9.#测试执行    
10.     --list-hosts # 受影响的host
11.
    --list-tasks # 会执行的tasks
12.

13.#传递变量
14.     -e VARNAME=VALUE, --extra-vars=VARS #内部预制变量可被-e覆盖
15.

16.#额外的主机清单、fork进程数    
17.     -i PATH, --inventory=PATH
18.
    -f NUM, --forks=NUM
19.

20.#检查语法,模拟执行  
21.     --syntax-check # perform a syntax check on the playbook
22.
    -C, --check # don't make any changes; instead, try to predict some of the changes that may occur

常用模块

  1. ping:探测目标主机是否存活;

  2. command:在远程主机执行命令;默认的module 
    ansible all -m command -a "hostname "

  3. shell:在远程主机上调用shell解释器运行命令,支持shell的各种功能,例如管道等 ; 
    ansible all -m shell -a "cat /etc/passwd| grep root " 
    注意:command和shell模块的核心参数直接为命令本身;而其它模块的参数通常为“key=action”格式;

  4. copy: C o p i e s f i l e s t o r e m o t e l o c a t i o n s . 
    用法: 
    (1) 复制文件:-a “src= dest= ” 
    (2) 给定内容生成文件:-a “content= dest= ” 
    其它参数:mode, owner, group, …

  5. file:S e t s a t t r i b u t e s o f f i l e s 
    用法: 
    (1) 创建目录:-a “path= state=directory” 
    (2) 创建链接文件:-a “path= src= state=link” 
    (3) 删除文件:-a “path= state=absent“

  6. fetch:F e t c h e s a f i l e f r o m r e m o t e n o d e s

  7. cron:M a n a g e c r o n . d a n d c r o n t a b e n t r i e s . 
    -a ” ” 
    minute= 
    hour= 
    day= 
    month= 
    weekday= 
    job= 
    name= 
    user= 
    state={present|absent}

  8. hostname:M a n a g e h o s t n a m e 
    name=

  9. yum:M a n a g e s p a c k a g e s w i t h t h e I ( y u m ) p a c k a g e m a n a g e r 
    (1) name= state={present|latest} 
    (2) name= state=absent

  10. service:M a n a g e s e r v i c e s . 
    name= 
    state={started|restarted|stoped|reloaded} 
    started 
    stopped 
    restarted 
    enabled= 
    runlevel=

  11. group: A d d o r r e m o v e g r o u p s 
    name= 
    state= 
    system= 
    gid= 
    state={present|absent} 
    ansible db -m group -a 'name=test gid=1000'

  12. user:M a n a g e u s e r a c c o u n t s 
    name= 
    group= 
    groups= 
    comment= 
    uid= 
    system= 
    shell= 
    expires= 
    home= 
    state={present|absent} 
    ansible all -m user -a 'name=DBA uid=505 home=/Data/dba shell=/sbin/nologin' 
    ansible db -m user -a 'name=budongshu uid=506 state=absent'

  13. setup:G a t h e r s f a c t s a b o u t r e m o t e h o s t s 
    收集系统信息,作为可用的变量: 
    “device”: “eno16777736” 
    “address”: “10.1.22.106” 
    “ansible_distribution”: “CentOS” 
    “ansible_distribution_major_version”: “7” 
    “ansible_fqdn”: “localhost.localdomain”, 
    “ansible_hostname”: “cent6”, 
    “ansible_interfaces”: [ 
    “lo”, 
    “eth1”, 
    “eth0” 
    ], 
    …… 
    结构体类型的fact引用: 
    {{ ansible_eth0.ipv4.address }} 
    {{ ansible_eth0[“ipv4”][“address”] }} 
    {{ ansible_all_ipv4_addresses[0] }}

  14. template 
    template使用了Jinjia2格式作为文件模板,进行文档内变量的替换的模块。他的每次使用都会被ansible标记为changed状态。

  15. script:自动复制脚本到远程节点,并运行 
    ansible all -m script -a 'ansible_test.sh'

ansible各模块简单示例

1.ansible websrv -m ping
2.ansible all -m command -a "ifconfig"
3.ansible all -m shell -a "echo alice|passwd --stdin alice"
4.ansible all -m copy -a "content='hello\n1' dest=/tmp/test.ansible mode=640"
5.
6.ansible all -m file -a "path=/tmp/test.ansible mode=777"
7.ansible all -m file -a "path=/tmp/test.ansible state=absent"
8.ansible all -m file -a "path=/tmp/testdir state=directory"
9.ansible all -m file -a "path=/tmp/test.ansible.link src=/tmp/test.ansible state=link"
10.
11.ansible all -m cron -a "minute=*/5 job='/usr/sbin/ntpdate 10.1.0.1 &> /dev/null' name=ntptime"
12.ansible all -m cron -a "name=ntptime state=absent"
13.
14.ansible all 10.1.0.68 -m setup
15.
16.ansible websrv -m yum -a "name=httpd state=present"
17.
18.ansible websrv -m service -a "name=httpd state=started enabled=true"

ansible playbooks

playbook是由一个或多个“play”组成的列表。play的主要功能在于将事先归并为一组的主机装扮成事先通过ansible中的task定义好的角色。从根本上来讲,所谓task无非是调用ansible的一个module。将多个play组织在一个playbook中,即可以让它们联同起来按事先编排的任务一项一项执行,一项task可能指定了多个host,且默认并行执行5个fork进程。

playbook内容组成

  • 核心元素: 

    1. tasks:任务,有模块定义的操作列表

    2. vas:变量

    3. tempaltes:模板,使用了Jinjia2格式作为文件模板

    4. handlers:由特定条件触发的Tasks;

    5. roles:角色

  • 基本组件 

    1. Hosts:指定目标主机

    2. remote_user:在远程主机上以哪个用户身份执行; 
      sudo_user:非管理员需要用于sudo权限

    3. tasks:任务列表 
      模块:模块参数 
      格式: 
      (1)action: module arguments 
      如: name、tags、with_items、notify、when、…… 
      (2)module: arguments 
      如: yum、copy、template、service、command、shell、……

host、user

playbook中的每一个play的目的都是为了让某个或某些主机以某个指定的用户身份执行任务。hosts用于指定要执行指定任务的主机,其可以是一个或多个由冒号分隔主机组;remote_user则用于指定远程主机上的执行任务的用户,如

1.- hosts: webnodes
2.
   remote_user: root

remote_user也可用于各task中。也可以通过指定其通过sudo的方式在远程主机上执行任务,其可用于play全局或某任务;此外,甚至可以在sudo时使用sudo_user指定sudo时切换的用户。

1.- hosts: webnodes
2.
 remote_user: root
3.  tasks:
4.    - name: test connection
5.
     ping:
6.      remote_user: alice
7.      sudo: yes

vars

和 Facts 相反, 变量是一些值,或字典,列表的名称(可以是标量值–整数,布尔型,或字符串,字典,列表),然后变量可以应用在模板和剧本里面。他们是声明的东西,不是获取远程系统的当前状态或性质(这是Facts)

(1) 内置的facts变量通过 setup 模块获取; 
(2) 自定义变量:

  1. 命令行传递;

1.ansible-playbook -e VAR=VALUE playbook.yml
  1. Inventory还可以使用参数: 
    用于定义ansible远程连接目标主机时使用的属性,而非传递给playbook的变量;

1.    ansible_ssh_host
2.    ansible_ssh_port
3.    ansible_ssh_user
4.    ansible_ssh_pass
5.    ansible_sudo_pass
6.    ...
  1. 在playbook中定义变量

1. - hosts: webservers
2.    vars:
3.    http_port: 80
  1. 在hosts Inventory中为每个主机定义专用变量值; 
    (a) 向不同的主机传递不同的变量 ; 
    IP/HOSTNAME variable_name=value 
    (b) 向组内的所有主机传递相同的变量 ; 
    [groupname:vars] 
    variable_name=value

  2. 在角色调用时传递

1.roles:
2.- { role: ROLE_NAME, var: value, ...}
  • 调用方式: 
    {{ var_name }}

  • 结构体类型的fact变量引用: 
    {{ ansible_eth0.ipv4.address }} 
    {{ ansible_eth0[“ipv4”][“address”] }} 
    {{ ansible_all_ipv4_addresses[0] }}

  • 变量优先级总结: 
    命令行传递的外部变量优先级高;vars定义的变量优先级大于host Iventroy传递的变量,具体如下: 

    1. extra vars (在命令行中使用 -e)优先级最高

    2. 然后是在inventory中定义的连接变量(比如ansible_ssh_user)

    3. 接着是大多数的其它变量(命令行转换,play中的变量,included的变量,role中的变量等)

    4. 然后是在inventory定义的其它变量

    5. 然后是由系统发现的facts

    6. 然后是 “role默认变量”, 这个是最默认的值,很容易丧失优先权

命令行传递变量

1.- hosts: websrv
2.   remote_user: root
3.   tasks:
4.   - name: install rpm
5.   yum: name={{ rpmName }} state=
6.
7.ansible-playbook -C -e rpmName=vsftpd web.yml

playbook文件定义变量

1.- hosts: websrv
2.   remote_user: root
3.   vars:
4.   - rpmName=memcached
5.   - rpmName=mysql
6.   tasks:
7.   - name: install rpm
8.   yum: name={{ rpmName }}

hosts Inventory传递变量

1.[websrv]
2.10.1.0.6 rpmName=httpd
3.10.1.0.7 rpmName=nginx

Inventory组共用变量

1.[websrv]
2.10.1.0.6 rpmName=httpd
3.10.1.0.7 rpmName=nginx
4.
5.[websrv:vars]
6.rpmName=nginx

用于定义ansible远程连接目标主机时使用的属性,而非传递给playbook的变量

1.[websrv]
2.10.1.0.6 ansible_ssh_user= ansible_ssh_pass= ansible_sudo_pass=
3.10.1.0.7 rpmName=nginx

调用role时传递变量

1.roles:
2.   - { role: apache, http_port: 8080 }
3.   - { role: app_user, name: Terry  }
4.   - { role: app_user, name: John   }

handlers

用于当关注的资源发生变化时采取一定的操作。“notify”这个action可用于在每个play的最后被触发,这样可以避免多次有改变发生时每次都执行指定的操作,取而代之,仅在所有的变化发生完成后一次性地执行指定操作。在notify中列出的操作称为handler,也即notify中调用handler中定义的操作。这意味着服务可以被反弹仅仅他们需要重启的时候。Handler 不仅仅可以用于重启服务,但是重启服务是最通用的用法。

1.- name: template configuration file
2.          template: src=template.j2 dest=/etc/foo.conf
3.          notify:
4.             - restart memcached
5.             - restart apache  
6.
7.#handler是task列表,这些task与前述的task并没有本质上的不同。
8.        handlers:
9.            - name: restart memcached
10.              service:  name=memcached state=restarted
11.            - name: restart apache
12.              service: name=apache state=restarted

tasks

play的主体部分是task list。task list中的各任务按次序逐个在hosts中指定的所有主机上执行,即在所有主机上完成第一个任务后再开始第二个。在运行自下而下某playbook时,如果中途发生错误,所有已执行任务都将回滚,因此,在更正playbook后重新执行一次即可。

task的目的是使用指定的参数执行模块,而在模块参数中可以使用变量。模块执行是幂等的,这意味着多次执行是安全的,因为其结果均一致。

每个task都应该有其name,用于playbook的执行结果输出,建议其内容尽可能清晰地描述任务执行步骤。如果未提供name,则action的结果将用于输出。

Tags

Ansible 允许给playbook里面的资源通过自定义的关键字打上标签,然后只运行与关键字一致的部分代码。 例如,可能有个完成的 OS 配置,然后特定的步骤标记为 “ntp” ,然后运行 “ntp” 步骤来重新配置时间服务器信息。

1.tasks: 
2.    tags: ntp

template

Ansible 很容易的传输文件到远端系统上面,但是它经常需要替换一些变量在其它的文件里面。变量可以来自 清单文件,Host Vars, Group Vars,或者 Facts。Templates 使用 Jinja2 模板引擎同样可以包含逻辑控制像循环和 if 语句。

Jinja2 is a template engine written in pure Python. It provides a Django inspired non-XML syntax but supports inline expressions and an optional sandboxed environment.

Jinja2语法介绍:

  • 字面量: 
    字符串:使用单引号或双引号; 
    数字:整数、浮点数; 
    列表:[item1, item2, …] 
    元组:(item1, item2, …) 
    字典:{key1:value1, key2:value2, …} 
    布尔型:true/false

  • 算术运算: 
    +, -, , /, //, %, *

  • 比较操作: 
    ==, !=, >, <, >=, <=

  • 逻辑运算:and, or, not

执行模板文件中的脚本,并生成结果数据流,需要使用template模块;

1.template:
2.        src=
3.        dest=
4.        mode=
5.        onwer=
6.        group=

此外,template模块只能在playbook文件中使用,不能在命令行调用 
【nothing】ansible websrvs -m copy -a “src=/root/nginx.conf dest=/tmp/nginx.conf” 
【error】ansible websrvs -m template -a “src=/root/nginx.conf dest=/tmp/nginx.conf”

例:在nginx配置文件中使用模板变量

1.- hosts: wevsrv
2.   remote_user: root
3.   tasks:
4.    - name: install rpm
5.       yum: name=nginx state=latest
6.       template: src=/root/nginx.conf.j2 dest=/etc/nginx/nginx.conf
7.       tags: newconf
8.       notify: reload nginx
9.    - name: start nginx
10.       service: name=nginx state=started enabled=true
11.    handlers:
12.    - name: relaod nginx
13.       shell: /usr/sbin/nginx
-s reload
14.
15.vi nginx.conf
16.    worker_processes {{ ansible_process_vcpus }}

when条件测试

一个可选的关键字来决定这个任务是不是应该指向,如果再 “when:” 关键字这里的表达式是是不正确的,这个任务会被忽略。When语句包含Jinja2表达式。

1.tasks:
2.    - name:
3.      when: ansible_distribution == "CentOS" and ansible_distribution_major_version == "6"
4.
5.tasks:
6.    - command: echo {{ item }}
7.      with_items: [ 0, 2, 4, 6, 8, 10 ]
8.      when: item > 5
9.
10.roles:
11.  - { role: amp, DBName: mysql, DBService: mysqld, HttpConf: httpd-2.2.conf.j2, when: ansible_distribution == "CentOS" and ansible_distribution_major_version == "6" }

item循环

需要重复执行的任务,如同时安装一组程序或者重复一个轮询步骤直到收到某个特定结果。 
对迭代项的引用,固定变量名为”item”,使用with_item属性给定所有的元素列表:

  • 元素列表:字符串字典

(1)基于字符串的循环列表(行值)

1.  - hosts: wevsrv
2.
   remote_user: root
3.    tasks:
4.    - name: install rpm
5.
     yum: name={{ item }} state=latest
6.      with_items:
7.      - httpd
8.
     - php
9.
     - php-mysql
10.
     - php-mbstring
11.
     - php-gd
12.
     - mysql-server
13.
     - mysql

(2) 基于字典的循环列表 
相当于给同一个action设定不同的值(列值)

1.  - hosts: all
2.    remote_user: root
3.    tasks:
4.    - name: create groups
5.      yum: name={{ item }} state=present
6.      with_items:
7.      - ops1
8.      - ops2
9.    - name: create users
10.      user: name={{ item.name }} group={{ item.group }} state=present
11.      with_items:
12.      - { name: 'h1', group: 'ops1' }
13.      - { name: 'h2', group: 'ops2' }

PyYAML库

YAML is a data serialization format designed for human readability and interaction with scripting languages.

YAML是一个可读性高的用来表达资料序列的格式。YAML参考了其他多种语言,包括:XML、C语言、Python、Perl以及电子邮件格式RFC2822等。Clark Evans在2001年在首次发表了这种语言,另外Ingy döt Net与Oren Ben-Kiki也是这语言的共同设计者。

YAML Ain’t Markup Language,即YAML不是XML。不过,在开发的这种语言时,YAML的意思其实是:”Yet Another Markup Language”(仍是一种标记语言)。其特性有:

YAML的可读性好 
YAML和脚本语言的交互性好 
YAML使用实现语言的数据类型 
YAML有一个一致的信息模型 
YAML易于实现 
YAML可以基于流来处理 
YAML表达能力强,扩展性好

更多的内容及规范参见:http://www.yaml.org

YAML语法

YAML的语法和其他高阶语言类似,并且可以简单表达清单、散列表、标量等数据结构。其结构(Structure)通过空格来展示,序列(Sequence)里的项用”-“来代表,Map里的键值对用”:”分隔。下面是一个示例:

1.  - hosts: 
2.
   remote_user:root
3.    vars:
4.     var_name: value
5.     http_port: 80
6.     max_clients: 256
7.     ……
8.    tasks:
9.    - name: ensure apache is at the latest version
10.
     yum: name=httpd state=latest
11.      tags: tag_name
12.      notify: handler_name
13.    - name:
14.
     ……
15.    handlers:
16.    - name: handler_name
17.
     MODULE

playbook中的每一个play的目的都是为了让某个或某些主机以某个指定的用户身份执行任务。hosts用于指定要执行指定任务的主机,其可以是一个或多个由冒号分隔主机组;remote_user则用于指定远程主机上的执行任务的用户。

YAML文件扩展名通常为.yaml,如example.yaml或main.yml;

YAML坑

YAML语法要求如果值以{{ foo }}开头的话我们需要将整行用双引号包起来. 
错误:

1.- hosts: app_servers
2.  vars:
3.      app_path: {{ base_path }}/22

正确:

1.- hosts: app_servers
2.  vars:
3.       app_path: "{{ base_path }}/22"

palybook文件示例

(1)增加用户并指定组

1.vi addgrp.yml
2.- hosts:websrv
3.  remote_user:root
4.  tasks:
5.  - name: create group ops
6.    group: name=ops system=true
7.  - name: create user alice
8.    user: name=alice group=ops system

(2)安装httpd程序

1.vi httpd.yml
2.- hosts: websrv
3.
 remote_user: root
4.  tasks:
5.  - name: install httpd.
6.
   yum: name=httpd
7.  - name: conf
8.
   copy: src=./src/httpd.conf dest=/etc/httpd/conf/httpd.conf
9.    tages: newconf
10.    notify: restart httpd..
11.  - name: start
12.
   service: name=httpd state=started  
13.  handlers:
14.  - name: restart httpd..
15.
   service: name=httpd state=restarted
16.  handlers:
17.  - name: reload httpd..
18.
   shell: /usr/sbin/service httpd reload

roles

一个 Role 可以包含特定的变量值,特定的任务,特定的触发器等东西。因为 Role 的文件结构,roles 可以是再次利用的单元,可以让你在其它 playbooks 中共享一些行为。

一个完整的role以特定的层级目录结构进行组织的tasks、variables、handlers、templates、files等;
role_struct: 
files/:存放有copy或script等模块调用的文件; 
tasks/:至少有一个main.yml用于定义主task,其他文件应被main.yml包含调用; 
handlers/:至少有一个main.yml用于定义主handler,其他文件应被main.yml包含调用; 
templates/:存放有template模块调用的模板文件; 
meta/:至少有一个main.yml用于定义当前role的特殊设定及依赖关系,其他文件应被main.yml包含调用 
default/:至少有一个main.yml用于定义默认的变量;

简单的role示例

  • 创建roles目录结构 
    mkdri -p /etc/ansible/roles/{nginx,mysql,httpd}/{files,tasks,handlers,vars,templates,meta,default}

  • 编辑任务文件:vi /nginx/tasks/main.yml

1.- name: copy nginx
2.   copy: src=nginx-1.10   dest=/tmp/
3.- name: install nginx
4.   yum: name=/tmp/nginx-1.10
5.- name: install conf file
6.  template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
7.  tags: newconf
8.  notify: reload nginx
9.- name: install conf file
10.  template: src=default.conf.j2 dest=/etc/nginx/conf.d/default.conf
11.  tags: newconf
12.  notify: reload nginx
13.- name: start nginx
14.  service: name=nginx state=started

  • 编辑关联任务:vi /nginx/handlers/main.yml

1.- name: reload nginx
2.    shell: nginx -s reload
  • 编辑playbook变量:vi vars/main.yml

1.nginxport: "8080"
  • 编辑模板文件:vi nginx.conf.j2 default.conf.j2 
    cp /etc/nginx/nginx.conf roles/nginx/templates/nginx.conf.j2 
    cp /etc/nginx/conf.d/default.conf roles/nginx/templates/default.conf.j2

1.worker_processes  {{ ansible_processor_vcpus }};
2.listen       {{ ngxport }};
  • 编辑role调用文件:vi palynginx.yml

1.- hosts: websrv
2.
 remote_user: root
3.  roles:
4.  - { playnginx, var_name:value,…… }
5.
 - memcache
  • 检查整个role语法、测试执行 
    ansible-playbook --syntax-check playnginx.yml 
    ansible-playbook -C playnginx.yml

  • 调用执行playbook文件 
    ansible-playbook playnginx.yml

总结

    ansible作为运维工具中远程命令执行工具,能够实现:批量部署应用程序、系统配置、批量命令执行等功能,是一款较轻量化的Python程序。ansible经过不断的发展,具有模块化、部署简单、工作于agentless模式、使用ssh协议、支持自定义模块、支持Palybook等特点。 
    Playbooks 可用于收集主机配置信息,更强大的地方在于 playbooks 中可以编排有序的任务执行过程,甚至于做到在多组机器间来回有序的执行指定步骤任务,且可以同步或异步的发起任务。

更多信息:http://www.ansible.com.cn/docs/

ansible部署{keepalived+nginx+{httpd, mysql, php}}

架构图.jpg

ansible部署AMP环境

同时兼容CentOS 6 与Cent OS 7系统

目录结构

1./etc/ansible/roles/lamp/
2.├── default
3.├── files
4.├── handlers
5.│   └── main.yml
6.├── meta
7.├── tasks
8.│   └── main.yml
9.├── templates
10.│   ├── httpd-2.2.conf.j2
11.│   └── httpd-2.4.conf.j2
12.└── vars
13.    └── main.yml

tasks/main.yml

  1. 使用yum模块安装httpd、php、php-mysql

  2. 根据DBName变量安装mysql程序

  3. 根据HttpConf变量并使用模板向httpd.conf文件传递变量,同时触发重载httpd服务

  4. 启动httpd服务(省略php.ini文件的复制)

  5. 根据DBService变量启动mysql服务

  6. 根据fact变量定制每台web服务器的index.html

  7. 创建测试数据库,授权LocalIP变量,即ansible主机的变量

1.- name: install httpd php
2.  yum: name={{ item }} state=present
3.  with_items:
4.  - httpd
5.  - php
6.  - php-mysql
7.- name: install mysql
8.  yum: name={{ DBName }}-server state=present
9.- name: copy httpd.conf
10.  template: src={{ HttpConf }} dest=/etc/httpd/conf/httpd.conf
11.  tags: NewHttpConf
12.  notify: reload httpd
13.- name: start httpd
14.  command: /usr/sbin/apachectl start
15.- name: start mysql
16.  service: name={{ DBService }} state=started
27.- name: create index.html
28.  copy: content='<h1> Web Servers in {{ ansible_hostname }}, Host IP is {{ ansible_all_ipv4_addresses[0] }}, System Version is {{ ansible_distribution }} {{ ansible_distribution_version }} </h1>' dest=/var/www/html/index.html
31.- name: create testdb
32.  command: mysql -e 'CREATE DATABASE testdb;GRANT ALL ON testdb.* TO "testuser"@"{{ LocalIP }}" IDENTIFIED BY "mage";FLUSH PRIVILEGES'

handlers/main.yml

1.- name: reload httpd
2.  service: name=httpd state=reloaded

vars/main.yml

1.htport: 80

templates/

  1. vi httpd-2.2.conf.j2

1.Listen       {{ htport }};
  1. vi httpd-2.4.conf.j2

1.Listen       {{ htport }};

host iventory

/etc/ansible/hosts

1.[websrv]
2.10.1.22.105
3.10.1.22.100
4.
5.[websrv:vars]
6.LocalIP=10.1.253.29

roles调用

ngxproxy.yml

1.- hosts: websrv
2.  remote_user: root
3.  tags: amp
4.  roles:
5.  - { role: lamp, DBName: mysql, DBService: mysqld, HttpConf: httpd-2.2.conf.j2, when: ansible_distribution == "CentOS" and ansible_distribution_major_version == "6" }
6.  - { role: lamp, DBName: mariadb, DBService: mariadb, HttpConf: httpd-2.4.conf.j2, when: ansible_distribution == "CentOS" and ansible_distribution_major_version == "7" }
7.#  - { role: httpd, tags: start mysql, DBName: mysqld, HttpConf: httpd-2.2.conf.j2, when: ansible_distribution == "CentOS" and ansible_distribution_major_version == "6" }

play and check

执行playbook 

play.jpg

 
访问we1和web2 

test.jpg

 
访问测试数据库 

TEST2.jpg

ansible部署nginx反代服务器

同时兼容 CentOS 6 与 CentOS 7 系统

目录结构

1./etc/ansible/roles/ngxproxy/
2.├── default
3.├── files
4.│   ├── nginx-1.10.0-1.el7.ngx.x86_64.rpm
5.│   └── nginx-1.10.2-1.el6.ngx.x86_64.rpm
6.├── handlers
7.│   └── main.yml
8.├── meta
9.├── tasks
10.│   └── main.yml
11.├── templates
12.│   ├── default.conf.j2
13.│   └── nginx.conf.j2
14.└── vars
15.     └── main.yml

tasks/main.yml

  1. 根据rpmName变量复制nginx程序包到目标主机

  2. 根据rpmName安装nginx程序包

  3. 基于模板复制nginx.conf和default.conf文件到目标主机,并触发重载nginx服务,且已经配置好upstrem server

  4. 启动nginx服务

1.- name: copy nginx rpm
2.  copy: src={{ rpmName }} dest=/tmp
3.- name: install nginx
4.  yum: name=/tmp/{{ rpmName }} state=present
5.  tags: copyrpm
6.  notify: remove rpm
9.
- name: install conf
10.  template: src={{ item.src }} dest={{ item.dest }}
12.
 notify: nginx reload
13.  with_items:
14.  - { src: 'nginx.conf.j2', dest: '/etc/nginx/nginx.conf' }
15.  - { src: 'default.conf.j2', dest: '/etc/nginx/conf.d/default.conf' }
16.- name: start nginx
17.  service: name=nginx state=started

handlers/main.yml

1.- name: nginx reload
2.  shell: "/usr/sbin/nginx -s reload"
3.- name: remove rpm
4.  shell: "/bin/rm /tmp/{{ rpmName }}"

vars/main.yml

1.ngxport: 80

templates/

  1. vi default.conf.j2

1.listen       {{ ngxport }};
2.location / {
3.    #root   /usr/share/nginx/html;
4.    index  index.html index.htm;
5.    proxy_pass http://websrv;
6.}

  1. vi nginx.conf.j2

1.worker_processes  {{ ansible_processor_vcpus }};
2.http{
3.    upstream websrv {
4.        server 10.1.22.105;
5.        server 10.1.22.100;
6.        }
7.}

files/

  1. nginx-1.10.0-1.el7.ngx.x86_64.rpm

  2. nginx-1.10.2-1.el6.ngx.x86_64.rpm

host iventory

/etc/ansible/hosts

1.[ngxproxy]
2.10.1.253.66 rpmName=nginx-1.10.2-1.el6.ngx.x86_64.rpm
3.10.1.22.106 rpmName=nginx-1.10.0-1.el7.ngx.x86_64.rpm

roles调用

ngxproxy.yml

1.- hosts: ngxproxy
2.
 remote_user: root
3.  tags: ngxproxy
4.  roles:
5.  - ngxproxy

play and check

执行playbook 

play.jpg

 
访问两台代理服务器均能轮询web1、web2 

test.jpg

ansible部署keepalived

同时兼容 CentOS 6 与 CentOS 7 系统,采用双主模型的keepalived配置高可用nginx代理服务器。

目录结构

1./etc/ansible/roles/keepalived/
2.├── default
3.├── files
4.├── handlers
5.│   └── main.yml
6.├── meta
7.├── tasks
8.│   └── main.yml
9.├── templates
10.│   ├── keepalived.conf.j2
11.│   └── notify.sh
12.└── vars

tasks/main.yml

  1. 使用yum安装keepalivcd

  2. 基于模板复制keepalived.conf和notify.sh脚本到目标主机,并触发重载keepalived服务,且已经配置好了双主模型的keepalived

  3. 启动keepalived服务

1.- name: install keepalived
2.  yum: name=keepalived state=present
3.- name: copy keepalived.conf,notify script
4.  template: src={{ item.src }} dest=/etc/keepalived/{{ item.dest }}
5.  tags: NewConf
6.  notify: reload keepalived
7.  with_items:
8.  - { src: keepalived.conf.j2, dest: keepalived.conf }
9.  - { src: notify.sh, dest: notify.sh }
10.- name: start keepalived
11.  service: name=keepalived state=started

handlers/main.yml

1.- name: reload keepalived
2.  service: name=keepalived state=reloaded

templates/

  1. vi keepalived.conf.j2

1.! Configuration File for keepalived
2.
3.global_defs {
4.   notification_email {
5.     root@localhost
6.   }
7.   notification_email_from keepalived@jasonmc.com
8.   smtp_server localhost
9.   smtp_connect_timeout 30
10.   router_id node1
11.   vrrp_mcast_group4 224.22.29.1
12.}
13.vrrp_script chk_down {
14.    script "[[ -f /etc/keepalived/down ]]&& exit 1 || exit 0"
15.    interval 1
16.    weight -5
17.}
18.vrrp_script chk_nginx {
19.    script "killall -0 nginx && exit 0 || exit 1"
20.    interval 1
21.    weight -5
22.}
23.
24.vrrp_instance VI_1 {
25.    state {{ VI_1 }}
26.    interface {{ IFACE }}
27.    virtual_router_id 10
28.    priority 96
29.    advert_int 10
30.    authentication {
31.        auth_type PASS
32.        auth_pass 1a7b2ce6
33.    }
34.    virtual_ipaddress {
35.        10.1.253.11 dev {{ IFACE }}
36.    }
37.    track_script {
38.    chk_down
39.    chk_nginx
40.    }
41.    notify_master "/etc/keepalived/notify.sh master"
42.    notify_backup "/etc/keepalived/notify.sh backup"
43.    notify_fault "/etc/keepalived/notify.sh fault"
44.}
45.
46.vrrp_instance VI_2 {
47.    state {{ VI_2 }}
48.    interface {{ IFACE }}
49.    virtual_router_id 11
50.    priority 100
51.    advert_int 11
52.    authentication {
53.        auth_type PASS
54.        auth_pass a3d1e9b0
55.    }
56.    virtual_ipaddress {
57.        10.1.253.12 dev {{ IFACE }}
58.    }
59.    track_script {
60.    chk_down
61.    chk_nginx
62.    }
63.    notify_master "/etc/keepalived/notify.sh master"
64.    notify_backup "/etc/keepalived/notify.sh backup"
65.    notify_fault "/etc/keepalived/notify.sh fault"
66.}
  1. vi notify.sh

1.#!/bin/bash
2.#
3.receiver='root@localhost'
4.notify() {
5.    mailsubject="$(hostname) to $1,vip floating."
6.    content="$(date '+%F %T') vrrp state transion, $(hostname) changed to be $1"
7.    echo "$content" | mail -s "$mailsubject" $receiver
8.}
9.case $1 in
10.    master)
11.        notify master
12.        ;;
13.    backup)
14.        notify backup
15.        ;;
16.    fault)
17.        notify fault
18.        ;;
19.    *)
20.        echo "Usage $(basename $0) {master|backup|fault}"
21.        exit 1
22.        ;;
23.esac

host iventory

/etc/ansible/hosts

1.[ngxproxy]
2.10.1.253.66
3.10.1.22.106

roles调用

ngxproxy.yml

1.- hosts: ngxproxy
2.  remote_user: root
3.  tags: ngxproxy
4.  roles:
5.  - { role: keepalived, VI_1: MASTER, VI_2: BACKUP, IFACE: eno16777736, when: ansible_distribution == "CentOS" and ansible_distribution_major_version == "7" }
6.  - { role: keepalived, VI_1: BACKUP, VI_2: MASTER, IFACE: eth0, when: ansible_distribution == "CentOS" and ansible_distribution_major_version == "6" }

play and check

执行playbook 

play.jpg

 
访问VIP1与VIP2均能轮询web1、web2 

test.jpg

合并调用roles的palybook

hosts

1.[ngxproxy]
2.10.1.253.66 rpmName=nginx-1.10.2-1.el6.ngx.x86_64.rpm
3.10.1.22.106 rpmName=nginx-1.10.0-1.el7.ngx.x86_64.rpm
4.
5.[websrv]
6.10.1.22.105
7.10.1.22.100
8.
9.[websrv:vars]
10.LocalIP=10.1.253.29

keneweb.yml

1.- hosts: websrv
2.  remote_user: root
3.  tags: amp
4.  roles:
5.  - { role: lamp, DBName: mysql, DBService: mysqld, HttpConf: httpd-2.2.conf.j2, when: ansible_distribution == "CentOS" and ansible_distribution_major_version == "6" }
6.  - { role: lamp, DBName: mariadb, DBService: mariadb, HttpConf: httpd-2.4.conf.j2, when: ansible_distribution == "CentOS" and ansible_distribution_major_version == "7" }
7.#  - { role: httpd, tags: start mysql, DBName: mysqld, HttpConf: httpd-2.2.conf.j2, when: ansible_distribution == "CentOS" and ansible_distribution_major_version == "6" }
8.
9.- hosts: ngxproxy
10.  remote_user: root
11.  tags: ngxproxy
12.  roles:
13.  - ngxproxy
14.  - { role: keepalived, VI_1: MASTER, VI_2: BACKUP, IFACE: eno16777736, when: ansible_distribution == "CentOS" and ansible_distribution_major_version == "7" }
15.  - { role: keepalived, VI_1: BACKUP, VI_2: MASTER, IFACE: eth0, when: ansible_distribution == "CentOS" and ansible_distribution_major_version == "6" }

原创文章,作者:helloc,如若转载,请注明出处:http://www.178linux.com/58041

(0)
上一篇 2016-11-06 20:51
下一篇 2016-11-06 21:15

相关推荐

  • linux基础命令

    1. 属主 属组 其他人    当一个进程访问文件时,首先匹配的是uid,其次是gid,最后是other 2. 认证信息库存储位置:    用户的认证信息库:/etc/shadow    组的认证信息库:/etc/gsh…

    Linux干货 2017-09-03
  • 运维自动化之系统安装

    自动化安装系统,cobbler的安装使用

    Linux干货 2018-01-15
  • 第二周作业

    Linux上的文件管理类命令都有哪些,其常用的使用方法及其相关示例演示。 cp 文件复制     常用选项:            -i:交互式        …

    Linux干货 2016-11-06
  • 萝卜运维记–第一周

    part1— ①描述计算机的组成及功能 ▲计算机是什么? 计算机(ENIAC):简述—-接收用户的指令,经过中央处理器处理过后,产生对使用者有用的信息。具有存储记忆,处理复杂数据运算的计算机器 Ⅰ 计算机组成及功能 ☆硬件部分: 1.中央处理器CPU(Central Processing Unit)↓↓↓↓:  &n…

    Linux干货 2016-12-06
  • 计算机的组成以及OS的发展历程

        根据冯诺依曼提出的体系架构,计算机基本上可以分为五大部件。这五大部件分别为运算器,控制器,内存,输入设备与输出设备,其中运算器与控制器是CPU的重要组成部分。下面分别介绍这5大部件:     CPU:运算器、控制器、寄存器、缓存      &…

    Linux干货 2016-10-30
  • 上下文管理练习(为加法函数计时)

    上下文管理(为加法函数计时) 为加法函数计时 使用装饰器显示该函数的执行时长 使用上下文管理显示该函数的执行时长 装饰器实现 import time import datetime from functools import wraps def logger(fn): @wraps(fn) # wraps(fn)(wrapper) def wrapper(*…

    2017-11-18