作为背锅侠运维工作的基本流程
系统安装(物理机、虚拟机)-->程序包安装、配置、服务启动 --> 对主机批量操作 --> 程序版本更新 -->监控
OS Provisioning:
物理机:PXE、Cobbler
虚拟机:Image、Templates
Configuration:
puppet工具(ruby开发)
Saltstack(python开发)
chef
Command and Concrol:
fabric
预发布环境验证:
新版本的代码先发布到内网测试服务器(跟线上环境配置完全相同,只是未介入到调度器);
程序发布:
不能影响用户体验;
系统不能停机;
不能导致系统故障或造成系统完全不可用;
灰度发布:
一种发布模式;在调度器上下线一批主机 --> 关闭服务 --> 部署新版本的应用程序 --> 启动服务 --> 在调度器上启用这一批主机;
自动化灰度发布机制:可通过脚本或公司自己的发布平台发布;
运维工具的分类 :
agent:代理工具:puppet,func
agentless:无代理工具:ansible,fabric;agentless类工具必须依赖ssh服务;
ansible的模块化:
模块化:调用特定的模块来完成特定的任务;
基于python语言实现,由paramaiko、pyYAML和jinja2三个关键模块
部署简单:agentless类工具
主从模式:
支持自定义模块:
支持playbook:
ansible密钥登陆
ansible是通过ssh实现配置管理、应用部署、任务执行等功能,因此,需要事先配置ansible端能基于密钥认证的方式联系各个被管理节点;
ansible管理端做密钥:ssh-keygen -t rsa -P ‘’
将密钥拷贝到各个被控节点:ssh-copy-id root@192.168.4.41
ssh远程连接测试:ssh root@192.168.4.41 ##应该不需要密码就可以直接远程进被控端
ansible安装
## wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-6.repo
## yum -y install ansible
配置文件:/etc/ansible/ansible.cfg
主机清单:/etc/ansible/hosts
ansible的简单使用
1、修改/etc/ansible/hosts文件,添加ansible被控主机或被控组;
##必须先在hosts文件添加主机ip,不然远程控制被控端时会报错: [WARNING]: No hosts matched, nothing to do
2、执行一个简单的ansible命令:
在ansible控制端执行:
ansible 192.168.4.41 -m command -a 'ifconfig'会显示被控端的网卡信息
ansible常用模块
可以使用‘ansible-doc -s 模块名 ’来查看模块的详细用法
ansible用法:ansible [-f forks] [-m module_name] [-a args]
user模块:
示例:ansible test -m user -a 'name=wuyongfeng state=present system=yes'
在test组包含的被控端上创建用户,name为wuyongfeng;
state=present表示创建用户,state=absent时表示删除用户;
system=yes表示创建系统用户;
group模块:
示例:ansible test -m group -a 'name =testgroup gid=111 state=present system=yes'
在test组包含的被控端上创建组testgroup;```
组id为111;
state=present表示创建组,state=absent时表示删除组;
syste=yes表示创建系统组,system=no表示创建的不是系统组;
cron模块:
示例:ansible test -m cron -a 'name="wuyongfeng crontab list" minute="*/20" job="/sbin/ntpdate 192.168.4.40 &>/dev/null"'
在test组包含的被控端添加任务计划,每20分钟向192.168.4.40同步时间,并把输出丢如/dev/null;
name:计划任务的描述信息;
minute:分钟;
job:要进行的操作;
day:日(1-31,*,*/2,……);
hour:小时(0-23,*,*/2,……);
month:月(1-12,*,*/2,……);
weekday:周(0-7,*,……);
user:以哪个用户的身份执行;
若要删除之前在被控端部署的计划任务,只需指定name和state=absent即可;
例如:
ansible test -m cron -a 'name="wuyongfeng crontab list" state=absent'
copy模块:
示例:ansible test -m copy -a 'src=/data/wyf.txt dest=/tmp/wyf.txt mode=600'
复制ansible控制端的wyf.txt文件到test组所指定的被控端的主机的/tmp目录下
src:源路径
dest:目标路径
mode:文件权限
file模块:
专门用来设定文件属性;
ansible test -m file -a 'path=/tmp/www state=directory'
在test组定义的被控端的/tmp/下创建www目录,state指定文件属性为目录
group:定义文件/目录的属组
mode:定义文件/目录的权限
owner:定义文件/目录的属主
path:必选项,定义文件/目录的路径
recurse:递归的设置文件的属性,只对目录有效
dest:被链接到的路径,只应用于state=link的情况
state:
=directory:如果目录不存在,创建目录
=file:即使文件不存在,也不会被创建
=link:创建软链接
=hard:创建硬链接
=touch:如果文件不存在,则会创建一个新的文件,如果文件或目录已存在,则更新其最后修改时间
=absent:删除目录、文件或者取消链接文件
ping模块:
用于确认和对象机器之间是否能够ping通,正常情况会返回pong;
示例:ansible test -m ping
ping test组定义的被控端;如果是可以通的则返回pong;
yum模块:
示例:ansible test -m yum -a 'name=httpd state=present'
在test组的被控端yum安装httpd;
config_file:yum的配置文件
disable_gpg_check:关闭gpg_check
disablerepo:不启用某个源
enablerepo:启用某个源
name:要进行操作的软件包的名字,也可以传递一个url或者一个本地的rpm包的路径
state:状态(present安装,absent卸载,latest最新的)
service模块:
示例:ansible test -m service -a 'name=httpd state=started enabled=yes'
test组的所有被控端,启动httpd服务,开机启动(enabled)
enabled:[yes/no] 启动os后启动对应service的选项;是否开机启动
name:需要进行操作的service名字
state:[stared/stoped/restarted/reloaded] 服务最终操作后的状态。
shell模块:
示例:ansible test -m shell -a 'sh /date/1.sh chdir=/date/www creates=/date/www/1.txt'
执行test组所有被控端,先切换到/date/www目录,如果/date/www/1.txt不存在,则执行/data/1.sh,
chdir:command一样的,运行shell之前cd到某个目录;
creates:跟command一样的,如果某个文件存在则不运行shell;
removes:跟command一样的,如果某个文件不存在则不运行shell;
script模块:
可以实现被控端上可以执行ansible控制端的脚本。
示例:ansible test -m script -a '/4.40/www/2.sh'
在test组所有被控端执行ansible控制端中/4.40./www/目录下的2.sh
setup模块:
用于收集远程主机的一些基本信息。
示例:ansible test -m setup
收集test组所有主机的基本信息
Ansible Playbooks
playbook的核心元素:
Tasks:任务
Variables:变量
Templates:模板
Handlers:处理器
Roles:角色
ansible --yaml语法
一:介绍:
YAML是一个可读性高的用来表达资料序列的格式。YAML参考了其他多种语言,包括:XML、C语言、 Python、Perl等。
YAML不是XML,不过,在开发的这种语言时,YAML的意思其实是:“Yet Another Makup Language”(仍是一种标记语言)
特点:
1、可读性好
2、和脚本的交互性好
3、使用实现怨言的数据类型
4、有一个一致的信息模型
5、易于实现。
6、可以基于流来处理。
7、表达能力强,扩展性好。
二:yaml语法
yaml的语法和其他高阶语言类似,并且可以简单表达清单,散列表,标量等数据结构,其结构通过空格来展示,序列里的项目用“-”来表示,map里的键值对用“:”分隔,下面是一个示例:
name:john smith
age:41
gender:male
spouse:
name:jane smith
age:37
gender:female
children:
- name:jimmy smith
age:17
gender:male
- name:jenny smith
age:14
gender:female
列表: 也叫做序列
列表中的所有元素都用“-”打头,例如:
- apple
- orange
- mango
字典:
字典通过key与value进行标识,例如:
name:example developer
job:developer
skill:elite
也可以将key:value放置与{}中表示,例如:
{name:example developer,job:developer,skill:elite}
Ansible基础元素
1.变量
1.1 变量命名
变量名仅能由字母,数字和下划线组成,且只能以字母开头
1.2 facts
facts是由正在通信的远程目标主机返回的信息,这些信息能保存在ansible变量中,要获取指定的远程主机所支持的素有的facts,可使用如下命令进行
#ansible hostname -m setup
1.3 register
注册器:把任务的输出定义为变量,然后用于其他任务,示例如下:
tasks:
- shell:/usr/bin/foo
register:foo_result
ignore_errors:True
1.4 通过命令行传递变量
在运行playbooks的时候也可以传递一些变量供playboo使用:示例如下:
ansible-playbook test.yml --extra-vars"hosts=www user=mageedu"
1.5 通过roles传递变量
当给一个主机应用角色的时候可以传递变量,然后在角色内使用这些变量,示例如下:
- hosts:webservers
roles:
- common
- { roles:foo_app_instance,dir:'/web/htdocs/a.com',port 8000 }
2.Inventory
ansible的主要功用在于批量主机操作,为了便捷地使用其中的部分主机,可以在inventory file中将其分组命名,默认的inventory file为/etc/ansible/hosts
Inventory file可以有多个,且也可以通过Dynamic Inventory动态生成;
2.1 Inventory文件格式
Inventory文件INI文件风格,中括号中的字符为组名,可以将同一个主机分配到多个不同的组,此外,当被控制的主机使用了非默认的ssh 22端口时,还可以在主机ip或主机名之后使用冒号加端口号标明;示例:
[webservers] ##被控组组名
192.168.1.100 ##使用ip添加被控端主机
www.erlang.com:222 ##如果被控端没有使用默认的ssh端口,可用冒号加端口号注明
如果主机名称遵循相似的命名格式,还可以使用列表的方式标识主机,示例:
[webservers]
www[1:50].example.com ##表示www1.example.com-www50.example.com的主机
2.2 主机变量
可以在Inventory中定义主机时为其添加主机变量以便于在playbook中使用,例如:
[webservers]
www1.erlang.com http_port-80 maxRequestsPerChild-808
www2.erlang.com http_port-8080 maxRequestsPerChild-909
2.3 组变量
组变量是指赋予给指定组内所有主机上的在playbook中可用的变量,例如:
[webservers]
www1.erlang.com
www2.erlang.com
[webservers:vars] :vars是固定写法,指定下边两行都可以分别对应给webservers组的两台主机
ntp_server-ntp.erlang.com
nfs_server-nfs.erlang.com
2.4 组嵌套
Inventory中,组还可以包含其他的组,并且也可以向组中的主机指定变量,不过,这些变量只能在ansible-playbook中使用,而ansible不支持,例如:
[apache]
httpd1.erlang.com
httpd2.erlang.com
[nginx]
nginx1.erlang.com
nginx2.erlang.com
[webservers:children] webservers组内包含apache和nginx两个组,:children表示引用了其他组用来做webservers组的子组
apache
nginx
[webservers:vars]
ntp_server-ntp_erlang.com
2.5 Inventory参数
ansible基于ssh连接Inventory中指定的远程主机时,还可以通过参数指定其交互方式,这些参数如下所示:
> ansible_ssh_host
> ansible_ssh_port
> ansible_ssh_user
> ansible_ssh_pass
> ansible_sudo_pass
> ansible_connection
> ansible_ssh_pricate_key_file
> ansible_shell_type
> ansible_python_interpreter
> ansible\_\*\_interpreter
Ansible playbooks
playbooks是一个或多个“play”组成的列表,play的主要功能在于将事先归并为一组的主机装扮成事先通过ansible中的tasks定义好的角色,从根本上来讲,所谓task无非是调用ansible的一个module,将多个play组织在一个playbook中,即可以让他们连同起来按事先编排的机制同唱一台大戏,下面是一个简单示例:
- hosts:webservers ##定义inventory,主机组
vars:
http_port:80
max_clients:256
remote_user:root ##定义连接到远程主机时,以哪个用户的身份执行
tasks:
- name:install apache is at the latest version ##描述,可随意写
yum:name=httpd state=latest ##使用yum模块,指定选项,安装最新版本的httpd
- name: ensure apache is running ##描述信息
service:name=httpd state=started ##使用service模块,指定httpd状态
handlers: ##处理器
- name:restart apache
service:name=httpd state=restarted
playbook组成结构:
Inventory
Modules
Ad Hoc Commands
Playbooks
Tasks:任务,即调用模块完成的某操作
Variables:变量
Templates:模板
Handlers:处理器,在某条件满足时,会由某事件触发执行的操作
Roles:角色
hosts和remote_user:
playbook中的每一个play的目的都是为了让某个或某些主机以某个指定的用户身份执行任务,hosts即用于指定要执行指定任务的主机,其可以是一个或多个由冒号分隔主机组,remote_user则用于指定远程主机上的执行任务的用户,如以上示例中的
- hosts:webservers
remote_user:root
不过,remote_user也可以用于各个tasks中(可能每个tasks指定的用户不一样),也可以指定其通过sudo的方式在远程主机上执行操作,其可用于play全局或某任务,此外,甚至可以在sudo时使用sudo_user指定sudo时切换的用户;
- hosts:webservers
remote_user:mageedu
tasks:
- name:test connection
ping:
remote_user:mageedu
sudo:yes ##以remote_user指定的用户切入进去,然后以这个用户的身份sudo到root用户去
任务列表和action:
play的主体部分是task、list、task list中的各任务按次序逐个在hosts中指定的所有主机上执行,即在所有主机上完成第一个任务后再执行第二个任务,在运行自上而下某playbook时,如果中途发生错误,所有已执行任务都可能回滚,因此,在更正playbook后重新执行一次即可;
task的目的是使用指定的参数执行模块,而在模块参数中可以使用变量,模块执行是幂等的,这意味这多次执行是安全的,因为其结果均一致;
每个task都应该有个name,用于playbook的执行结果输出,建议其内容尽可能清晰地描述任务执行步骤,如果为提供name,则执行action的结果将用于输出;
定义task的可以使用"action:module option"或"module:option"的格式,推荐使用后者以实现向后兼容;
tasks:
- name:make sure apache is running
service:name=httpd state=running
在众多模块中,只有command和shell模块仅需要给定一个列表而无需使用key:value格式,例如:
tasks:
- name:disable selinux
command:/sbin/setenforce 0
如果命令或脚本的退出码不为零,可以使用如下方式替代:
tasks:
- name:run this command and ignore the result
shell:/usr/bin/SOME COMMAND||/bin/true
在执行/usr/bin/下的某条命令时,如果报错了,但是这不影响我们本身意愿或者执行结果时,可以使用/bin/true将退出码强制改为true
或者使用ignore_errors来忽略错误信息:
tasks:
- name:run this command and ignore the result
shell:/usr/bin/SOME COMMAND
ignore_errors:True
Handlers:处理器
用于当关注的资源发生变化时采取一定的操作:
“notify”这个action可用于在每个play的最后被触发,这样可以避免多次有改变发生时每次都执行指定的操作,取而代之, 仅在所有的变化发生完成后一次性的执行指定操作,在notify中列出的操作成为Handlers,也即notify中调用handlers中定义的操作;
示例:
- hosts: test #\\主机组,在/etc/ansible/hosts定义
remote_user: root # \\远端执行任务的用户
tasks: #\\任务
- name: install httpd #\\任务描述
command: yum -y install httpd #\\调用ansible的command模块安装httpd
- name: install configuration file for httpd #\\任务描述
copy: src=/data/httpd.conf dest=/etc/httpd/conf/httpd.conf #\\调用ansible的copy模块复制ansible管理端的文件到被控端
notify: #\\定义一个notify,当执行copy这个模块的命令时执行notify
- restart httpd #\\ notify引用的handlers的名字为restart httpd(必须跟handlers的名字一样)
handlers: #\\ 定义一个handlers
- name: restart httpd #\\名字为restart httpd
service: name=httpd state=restarted #\\调用ansible的service模块,重启httpd服务
playbook的一个简单实例:
- hosts: test #\\主机组,在/etc/ansible/hosts定义
remote_user: root # \\远端执行任务的用户
tasks: #\\任务
- name: install httpd #\\任务描述
command: yum -y install httpd #\\调用ansible的command模块安装httpd
###### 在playbook中使用变量:
- hosts: test #\\主机组,在/etc/ansible/hosts定义
remote_user: root # \\远端执行任务的用户
vars: ##定义变量package和service
- package: httpd
- service: httpd
tasks: #\\任务
- name: rpm -e httpd
command: rpm -e httpd
- name: install {{ package }} #\\任务描述 调用变量用{{ }}引用
command: yum -y install httpd #\\调用ansible的command模块安装httpd
- name: install configuration file for httpd
copy: src=/data/httpd.conf dest=/etc/httpd/conf/httpd.conf
notify:
- restart httpd
handlers:
- name: restart httpd
service: name=httpd state=restarted
Ansible使用条件测试
如果需要根据变量、facts或此前任务的执行结果来做为某task执行还是不执行的前提时需要用到条件测试;
1.when语句
在task后添加when子句即可使用条件测试,when语句支持jinja2表达式语法,例如:
tasks:
- name: "shutdown debian system"
command: /sbin/shutdown -h now
when: ansible_os_family == "Debian"
当系统为debian系统时,则关机
- hosts: test
remote_user: root
tasks:
- name: yum httpd
command: yum -y install httpd
when: ansible_fqdn == "wwww"
当test组的某台主机的主机名为wwww时,才给符合条件的主机安装httpd
Ansible playbook使用迭代(循环)
当有需要重复性执行的任务时,可以使用迭代机制,其使用格式为将需要迭代的内容定义为item变量引用,并通过with_item语句来指明迭代的元素列表即可,例如:
- hosts: test
remote_user: root
tasks:
- name: touch file
file: name={{ item }} state=directory ##循环创建ietm,而item对应的值为with_items中指定的
with_items: ##列出item索要对应的值
- file1
- file2
事实上,with_items中可以使用元素还可为hashes,例如:
- hosts: test
remote_user: root
tasks:
- name: touch file
user: name={{ item.name}} state=present groups={{ item.groups }} ##在各个主机创建用户,以及指定用户的基本组
with_items:
- { name: 'testuser1', groups: 'nginx' }
- { name: 'testuser2', groups: 'apache' }
Ansible中使用Templates
http://blog.csdn.net/modoo_junko/article/details/45460693