Ansible
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等
-
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
常用模块
-
ping:探测目标主机是否存活;
-
command:在远程主机执行命令;默认的module
ansible all -m command -a "hostname "
-
shell:在远程主机上调用shell解释器运行命令,支持shell的各种功能,例如管道等 ;
ansible all -m shell -a "cat /etc/passwd| grep root "
注意:command和shell模块的核心参数直接为命令本身;而其它模块的参数通常为“key=action”格式; -
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, … -
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“ -
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
-
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} -
hostname:M a n a g e h o s t n a m e
name= -
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 -
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= -
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'
-
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'
-
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] }} -
template
template使用了Jinjia2格式作为文件模板,进行文档内变量的替换的模块。他的每次使用都会被ansible标记为changed状态。 -
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内容组成
-
核心元素:
-
tasks:任务,有模块定义的操作列表
-
vas:变量
-
tempaltes:模板,使用了Jinjia2格式作为文件模板
-
handlers:由特定条件触发的Tasks;
-
roles:角色
-
基本组件
-
Hosts:指定目标主机
-
remote_user:在远程主机上以哪个用户身份执行;
sudo_user:非管理员需要用于sudo权限 -
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.ansible-playbook -e VAR=VALUE playbook.yml
-
Inventory还可以使用参数:
用于定义ansible远程连接目标主机时使用的属性,而非传递给playbook的变量;
1. ansible_ssh_host
2. ansible_ssh_port
3. ansible_ssh_user
4. ansible_ssh_pass
5. ansible_sudo_pass
6. ...
-
在playbook中定义变量
1. - hosts: webservers
2. vars:
3. http_port: 80
-
在hosts Inventory中为每个主机定义专用变量值;
(a) 向不同的主机传递不同的变量 ;IP/HOSTNAME variable_name=value
(b) 向组内的所有主机传递相同的变量 ;[groupname:vars]
variable_name=value
-
在角色调用时传递
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传递的变量,具体如下: -
extra vars (在命令行中使用 -e)优先级最高
-
然后是在inventory中定义的连接变量(比如ansible_ssh_user)
-
接着是大多数的其它变量(命令行转换,play中的变量,included的变量,role中的变量等)
-
然后是在inventory定义的其它变量
-
然后是由系统发现的facts
-
然后是 “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}}
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
-
使用yum模块安装httpd、php、php-mysql
-
根据
DBName
变量安装mysql程序 -
根据
HttpConf
变量并使用模板向httpd.conf文件传递变量,同时触发重载httpd服务 -
启动httpd服务(省略php.ini文件的复制)
-
根据
DBService
变量启动mysql服务 -
根据fact变量定制每台web服务器的index.html
-
创建测试数据库,授权
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/
-
vi httpd-2.2.conf.j2
1.Listen {{ htport }};
-
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
访问we1和web2
访问测试数据库
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
-
根据
rpmName
变量复制nginx程序包到目标主机 -
根据
rpmName
安装nginx程序包 -
基于模板复制nginx.conf和default.conf文件到目标主机,并触发重载nginx服务,且已经配置好upstrem server
-
启动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/
-
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.}
-
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/
-
nginx-1.10.0-1.el7.ngx.x86_64.rpm
-
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
访问两台代理服务器均能轮询web1、web2
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
-
使用yum安装keepalivcd
-
基于模板复制keepalived.conf和notify.sh脚本到目标主机,并触发重载keepalived服务,且已经配置好了双主模型的keepalived
-
启动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/
-
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.}
-
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
访问VIP1与VIP2均能轮询web1、web2
合并调用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