ansible简单使用
- ansible配置文件要注意的几个参数:
- 配置公钥,之后就可以免密登陆:
配置用户组至hosts文件中
- ansible指令格式:
- setup:用于获取主机信息,在playbooks里经常用到的一个参数
- ansible的简单模块简介:
- ping:测试用户主机是否是通的
- command:在指定节点上运行相关命令:
- shell:在指定节点上运行相关命令,但是shell支持管道符 | :
- copy:复制文件到远程主机
- src:要复制到远程文件 在本地的地址,可以是绝对路径,也可以是相对路径。如果路径是一个目录,它将递归复制。在这种情况下,如果路径使用“/”来结尾,则只复制目录里的内容,如果没有使用"/"来结尾,则包含目录在内的整个内容全部复制,类似于rsync
- det:必选项,要将源文件复制到的远程主机的绝对路径,如果源文件是一个目录,那么该路径也必须是个目录
- content:用于替代"src",可以直接设定指定文件的值
- owner:传输过去后,所属者
- group:传输过去后,所属组
- mode:设定目录和文件的权限
- backup:在覆盖之前将原文件备份,备份文件包含时间信息,不写默认为不备份
- cron:用于管理计划任务包含如下选项:
- backup:对远程主机上的原任务计划内容修改之前做备份
- cron_file:如果指定该选项,则会用该文件替换远程主机上的cron.d目录下的用户的任务计划
- name:定时任务的描述
- special_time:指定什么时候运行,参数:
reboot,yearly,annually(每年),monthly,weekly,daily,hourly - state:指定状态,prsent给添加定时任务,也是默认值,absent表示删除定时任务
- user:以哪个用户的身份执行
- job:指明运行的命令是什么
- minute:分
- hour:时
- day:日
- week:周
- month:月
- file:主要用于远程主机上的文件操作
- force:需要在两中情况下强制创建软链接,一种是源文件不存在但之后会建立的情况下;另一中是目标软链接已存在,需要先取消之前的软链,然后创建新的软链,有两个选项:yes|no
- group:定义文件/目录的属组
- mode:定义文件/目录的权限
- owner:定义文件/目录的属主
- path:必先项,定义文件/目录的路径
- recurse:递归的设置文件的属性,只对目录有效state=directory
- src:要被链接的源文件的路径,只应用于state=link的情况
- dest:被链接到的路径,只应用于state=link的情况
- state:
- directory:如果目录不存在,创建目录
- file:即使文件不存在,也不会被创建
- link:创建软链接
- hard:创建硬链接
- touch:如果文件不存在,则会创建一个新的文件,如果文件或目录已存在,则更新其最后修改时间
- absent:删除目录、文件或者取消链接文件
- hostname:修改主名称
- name:更改名称
- yum:使用yum包管理器来管理软件包
- config_file:yum的配置文件
- disable_gpg_check:关闭gpg_check
- disablerepo:不启用某个源
- enablerepo:启用某个源
- name:要进行操作的软件包的名字,也可以传递一个url或者一个本地的rpm包的路径
- state:
- present:安装,默认
- latest:安装最新版
- absent:卸载程序包
- service:用于管理服务
- arguments:给命令提供一些选项
- enabled:是否开机启动 yes|no
- name:必选项,服务名称
- pattern:定义一个模式,如果通过status指令来查看服务的状态时,没有响应,就会通过ps指令在进程中根据该模式进行查找,如果匹配到,则认为该服务依然在运行
- runlevel:运行级别
- sleep:如果执行了restarted,则在stop和start之间沉睡几秒钟
- state:对当前服务执行启动,停止,重启,重新加载等操作(started,stopped,restarted,reloaded)
- user,group:useradd,userdel,usermod,groupadd,groupdel,groupmod六个指令
- comment:用户的描述信息
- home:指定用户的家目录,需要与createhome配合使用
- groups:指定用户的属组
- uid:指定用的uid
- password:指定用户的密码
- name:指定用户名
- createhome:是否创建家目录
- system:是否为系统用户
- remove:当state=absent时,remove=yes则表示连同家目录一起删除,等价于userdel --force
- state:是创建还是删除,不指定为创建,absent表示删除
- shell:指定用户的shell环境
- password:指定用记密码
- update_password:更新用户密码
- script:脚本模块
- creates:一个文件名,当这个文件存在,则该命令不执行
- free_form:本地脚本路径
- removes:一个文件名,这个文件不存在,则该命令不执行
- synchronize:使用rsync同步文件
- archive:归档,相当于同时开启recursive(递归),links,perms,itmes,owner,group,-D选项都为yes,默认该选项为开启
- checksum:跳过检测sum值,默认关闭
- compress:是不开启压缩,默认开启
- copy_links:复制链接文件,默认为no,注意后面还有一个links参数
- delete:删除不存在的文件,默认为no
- dest:目录路径
- dest_prot:默认为22,ssh协议
mode:push和pull模块,push模块的话,一般用于从本机向远程主机上传文件,pull模式用于从远程主机上取文件
- ansible-palybook:
- 首先以"---"3个减号形如,且需要顶行写
- 使用#注释代码
- 缩进必须统一,不能空格和tab混用
- 缩进的级别也必须一致,同样的缩进代表同样的级别
- 区别大小写
- 使用:分隔,换行写需要以-分隔
- 一个完整的代码块功能需要最少元素包括name:task
- playbook语法及示例:
- playbook核心元素:
- hosts:运行指定任务的目标主机
- tasks:任务列表
- varniables:变量
- tempaltes:模版
- handlers:由特定条件触发的任务,监控资源改变时才会触发改变
- roles:playbook按固定目录结构组成
- 示例1:
- handler:
- 用于当关注的资源发生变化时采取一定的操作。
- "notify"这个action可用于在每个play的最后被触发这样可以避免多次有改变发生时每次都执行指定的操作取而代之仅在所有的变化发生完成后一次性地执行指定操作
- 在notify中列出的操作称为handler也即notify中调用handler中定义的操作
- template:模版for,if,when(上面的示例中有演示)语句
- 迭代with_items:重复执行的任务,对迭代项的引用,固定变量名为item,而后在task中使用with_items给定迭代的元素列表
- roles应用
Roles用于层次性,结构化地组织playbook,roles能够根据层次型结构自动装载变量文件、tasks以及handlers等。要使用roles只需要在playbook中使用include指令即可。简单来讲,roles就是通过分别将变量、文件、任务、模板及处理器放置于单独的目录中并可以便捷地include他们的一种机制,角色一般用于主机构建服务的场景中,但也可以是用于构建守护进程等场景中。
- 目录简介:
- 实验安装jdk:
- 首先提供jdk的rpm包文件及环境配置文件:
- 文件提供好后,就可以写tasks了:
- 提供handlers的配置文件:
- 在roles同级中创建site.yml文件:
- 执行操作:
- 最后来查看是否安装成功且环境变量也成功读取了:
- 突然想起来,我的CLASSPATH环境变量还没有设:
~]# vim /etc/ansible/ansible.cfg
[defaults]
# uncomment this to disable SSH key host checking
host_key_checking = False //第一次连接别的机器的时候,都会出现保存密钥指纹的提示,这里False的意思是免去第一次连接出现这个麻烦的问题
#SSH timeout
timeout = 2 //ssh连接超时时长,因为是内网传输,所以可以设置的小点,默认为10s
[ssh_connection]
# Control the mechanism for transfering files
# * smart = try sftp and then try scp [default]
# * True = use scp only
# * False = use sftp only
scp_if_ssh = True //使用scp来传输
[root@localhost ~]# ssh-keygen //生成公钥和私钥
[root@localhost ~]# ssh-copy-id root@172.16.9.2 //分发公钥至对端主机上
[root@localhost ~]# ansible 172.16.9.8 -m ping
[WARNING]: No hosts matched, nothing to do
当出现这种状态时,私钥已经发给对端了,那就是hosts文件里没有写对应的ip地址,写上就好了。
[root@localhost ~]# cd .ssh/
[root@localhost .ssh]# ls //在本地路径下生成相应的文件来支持免密交互
authorized_keys id_rsa id_rsa.pub known_hosts
[root@localhost .ssh]# cat known_hosts
172.16.9.4 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBBYMef7fW7y5uM+vQtdQUuYyMNiY9UWNj9YMpWTZUPrE+jbUiFp3u3JnMfqBdJ9gI/1gqIrVBh6YEgeEfUrZVeM=
172.16.9.3 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBOMXVpFc5Hfu814Xz1KOfWVAIpQaX1en7uaiNpRh25JHU/sUWInI7ggCHphPg9FIx/i3GgzH7Wa+XjHjeIpx/TU=
172.16.9.2 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBPssRsKsOpds0BWjuvH272Ym9CBjqKGbQzGjKs7cdSy7hv4VRyLDT8BBY8cPlb9lvKXtqrdWd3rJ68HNIFqMLDc=
172.16.9.1 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBPBmV6HJ92KTxueEYjxQZQmbFjB4NY2/eqq5WPxkt/RiL/H7cZmoXkpWV80tyLq9vx1Uq+2Bac8n8cJXkZG/VMQ=
~]# vim /etc/ansible/hosts //在最后一行你所需要管理的服务器地址
[web] //名称就叫web组
172.16.9.1
172.16.9.2
172.16.9.3
172.16.9.4
ansible [-f forks] [-m module_name] [-a args]
-f forks:启动的并发线程数
-m module_name:要使用的模块
-a args: 模块特有的参数
-C 干跑一遍,就是测试一下
~]# ansible 172.16.9.2 -m setup //查看某一台主机的信息,然后从中挑选所需要关注的就好
~]# ansible 172.16.9.2 -m setup | grep processor
"ansible_processor": [
"ansible_processor_cores": 1,
"ansible_processor_count": 1,
"ansible_processor_threads_per_core": 1,
"ansible_processor_vcpus": 1, //这个变量就能知道我的机器有多少个核心,也就可以用来定义nginx的工作核心
~]# ansible all -m ping
~]# ansible web -m command -a 'ls'
172.16.9.3 | SUCCESS | rc=0 >>
anaconda-ks.cfg
172.16.9.2 | SUCCESS | rc=0 >>
172.16.9.3
anaconda-ks.cfg
~]# ansible web -m shell -a 'useradd natasha && echo natasha | passwd --stdin natasha'
172.16.9.3 | SUCCESS | rc=0 >>
Changing password for user natasha.
passwd: all authentication tokens updated successfully.
172.16.9.2 | SUCCESS | rc=0 >>
Changing password for user natasha.
passwd: all authentication tokens updated successfully.
~]# ansible web -m copy -a 'src=/etc/fstab dest=/ mode=777 backup=yes'
~]# ls
-rwxrwxrwx. 1 root root 465 Jul 8 08:05 fstab
-rw-r--r--. 1 root root 465 Jul 8 08:04 fstab.2717.2017-07-08@08:05:29~
生成的备份文件
~]# ansible web -m copy -a 'content="Hello World!" dest=/world'
将"Hello World!" 放入/world文件中,文件不存在会自动创建
~]# ansible web -m cron -a 'name="check dirs" minute="0" hour="5,2" job="ls -alh > /dev/null"'
~]# crontab -l
#Ansible: check dirs
0 5,2 * * * ls -alh > /dev/null
~]# ansible web -m file -a 'src=/fstab dest=/fstab.link state=link'
将目标主机上的/fstab 创建一个软链接
~]# ansible web -m file -a 'path=/fstab.link state=absent'
删除链接
~]# ansible web -m file -a 'path=/new.xx src=/new state=link owner=tom group=tom mode=777'
将/new生成一个/new.xx的链接,并且属主属组都为tom且权限为777
~]# ansible web -m hostname -a 'name=niao'
修改web组的成员的hostname=niao
~]# ansible web -m yum -a 'name=nginx state=latest' //安装最新版nginx
~]# ansible web -m yum -a 'name=nginx state=absent' //卸载nginx
~]# ansible test -m yum -a 'name=http://nginx.org/packages/centos/6/noarch/RPMS/nginx-release-centos-6-0.el6.ngx.noarch.rpm state=present' //直接下载安装
~]# ansible web -m service -a 'name=nginx state=started enabled=yes runlevel=2345 ' //开启nginx服务,并且开机启动,运行级别2345
~]# ansible web -m service -a 'name=network state=restarted args=eth0'
//重启网卡
~]# ansible web -m user -a 'name=jerry password="$1$9DgSSTxd$zJE2FHK1rxtyQhkzeHzk50"' //创建用记,并给定密码
~]#
~]# echo "jerry" | openssl passwd -1 -salt $(< /dev/urandom tr -dc '[:alnum:]' | head -c 32) -stdin //md5加密,如果不生成密码,而是直接在ansible中写的话,密码会以明文的方式记录在passwd文件中
$1$9DgSSTxd$zJE2FHK1rxtyQhkzeHzk50
~]# ansible web -m user -a 'name=josn uid=10000 groups=tom,jerry shell=/bin/zsh '
~]# ansible web -m user -a 'name=jerry state=absent remove=yes' //删除用户的同时 ,删除用记家目录
~]# ansible web -m script -a '/root/a.sh' //将本地的脚本在别的主机上执行
~]# ansible 172.16.9.2 -m synchronize -a 'mode=pull src=/ming dest=/'
从9.2的主机/ming目录拉取到本机上
~]# ansible 172.16.9.2 -m synchronize -a ' src=/ming dest=/ '
将ming目录推送至9.2的主机上
~]# vim nginx.yml
---
#This is admin nginx.
- hosts: web
remote_user: root
tasks:
- name: install nginx
yum: name=nginx state=latest //一个命令对应一个name
- name: start nginx
command: systemctl start nginx
- name: ever nginx
command: systemctl enable nginx
<br .>
---
- hosts: web //操作的主机组,在/etc/ansible/hosts中定义
remote_user: root //操作的用户
# gather_facts: No #禁止ansible收集setup信息,默认是开启的,只有是开启的,才能判断when条件
tasks: //任务
- name: install nginx
yum: name=nginx state=latest
tags: install //打标记,可以单独执行
- name: 9.3 start nignx //任务描述
service: name=nginx state=restarted //调用ansible的service模块重启nginx
when: ansible_hostname == "dai" //条件判断,符合就执行service 模块操作,可用and或or。可使用ansible 172.16.9.3 -m setup 就可以获取整个主机的所有信息
tags: restart nginx
~]# ansible-playbook --tags="restart nginx" setup.yml //执行playbook中指定的tags
~]# ansible-playbook --skip-tags="install" setup.yml //也可以跳过tags
注意:在notify中定义内容一定要和tasks中定义的- name内容一样,这样才能达到 触发的效果,否则会不生效
---
#This is admin nginx.
- hosts: web
remote_user: root
vars:
- filename: "nginx.conf.j2"
tasks:
- name: deliver config
template: src={{ filename }} dest=/etc/nginx/nginx.conf //用的是模块,且调用两次变量,一次是本地filename,每二次是/etc/ansible/hosts中的web_ports
notify: restart nginx //要和handler中的name相同
handlers:
- name: restart nginx
service: name=nginx state=restarted
~]# vim /etc/ansible/hosts
...
[web:vars] //某个组中的变量,如果不在这定义变量,也可以执行命令的时候跟上 -e 选项在赋值也是可以的,并且在命令行中优先级高
web_ports=10000 //给变量赋值
..
~]# cp /etc/nginx/nginx.conf /nginx.conf.j2
~]# vim nginx.conf.j2 //ansible中模版文件要以.j2格式结尾,才能使用
...
worker_processes {{ ansible_processor_vcpus }}; //这个值是自动去操作的主机上获取相应的参数来设定的,
...
listen {{ web_ports+1 }} default_server; //调用变量,变量要用{{ }},也可使用各类运算符
...
~]# vim nginx.conf.j2 //在http中添加for循环
{% for vhost in xiaoniao %} //xiaoniao是数组,要在yml文件中定义,vhost是变量
server {
{% if http_port is defined %} //条件判断,http_port有没定义变量值,有的话就替换该值,没有就该行
listen {{ http_port }};
{% endif %} //结束条件判断
server_name {{ vhost }}.xiaoniao.com; //每次都引用
root /web;
location / {
}
}
{% endfor%} //结束循环
如果此处的vhost变量是ip地址的话,正常的赋值是不成功的,必须加上“[]”才行,因为其中有点号
[172.16.9.1]
} //这个括号是http的
~]# vim template.yml
---
- hosts: web
remote_user: root
vars: //在语法中添加变量的成员
- xiaoniao:
- www
- new
- girl
- photo
- http_port: "1000" //定义条件判断的值,也可在hosts中定义变量
tasks:
- name: template config
template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
notify: restart nginx
handlers:
- name: restart nginx
service: name=nginx state=restarted
---
- hosts: web
remote_user: root
tasks:
- name: install app
yum: name={{ item }} state=present //固定的变量名
with_items: //元素列表
- httpd
- php
with_items字典:
---
- hosts: web
remote_user: root
tasks:
- name: add user
user: name={{ item.name }} groups={{ item.group }} //字典功能,可有多个值
with_items:
- { name: "niao" , group: "natasha" } //为一组
- { name: "xiao" , group: "root"}
[root@localhost ansible]# tree roles/
roles/
├── httpd //服务名称,直接用include调用
│ ├── default //为当前角色设定默认变量时使用此目录
│ ├── files //存放由copy或script等模块调用的文件
│ ├── handlers //此目录中应当包含一个main.yml,用于定义此角色用到的和handler;也可包含其它文件
│ ├── meta //应当包含一个main.yml,用于定义此角色的特殊设定及其依赖关系
│ ├── tasks //至少包含一个名为main.yml的文件,其定义了此角色的任务列表;此文件可以使用include包含其它的位于此目录中的task文件
│ ├── templates //template模块会自动在此目录中寻找Jinja2模板文件
│ └── vars //应当包含一个main.yml文件,用于定义此角色用到的变量
~]# mkdir -pv /etc/ansible/roles/jdk/{vars,templates,handlers,meta,default,tasks,files}
~]# cd /etc/ansible/roles/jdk/
~]# cp jdk-7u79-linux-x64.rpm /etc/ansible/roles/jdk/files/
~]# vim files/java.sh
exprot JAVA_HOME=/usr/java/latest
export PATH=$JAVA_HOME/bin:$PATH
~]# vim tasks/main.yml
- name: copy jdk.rpm file
copy: src=jdk-7u79-linux-x64.rpm dest=/
- name: install jdk
shell: yum -y install /jdk-7u79-linux-x64.rpm
- name: provides jdk.sh
copy: src=java.sh dest=/etc/profile.d/java.sh
tags: jdksh //只要是提供文件的,最好都给个tags,以免下次要重新执行全部
notify:
- source /etc/profile.d/java.sh //当提供的文件出现改动时,就可以触发条件,在去读取一下;所以就需要在handlers下提供配置文件
- name: read /etc/profile.d/java.sh //提供完文件要重新读取环境变量
shell: source /etc/profile.d/java.sh
- name: source /etc/profile.d/java.sh //这里的名称要和notify一致,方才能匹配到
shell: source /etc/profile.d/java.sh
~]# vim /etc/ansible/site.yml
~]# cat ../../site.yml
- hosts: jdk //对哪个组进行工作
remote_user: root
roles: //哪个角色
- jdk //jdk目录
~]# vim /etc/anisble/hosts
...
[jdk] //给这四个主机定义为一个组
172.16.9.1
172.16.9.2
172.16.9.3
172.16.9.4
~]# ansible-playbook site.yml
PLAY [jdk] *********************************************************************
TASK [setup] *******************************************************************
ok: [172.16.9.1]
ok: [172.16.9.4]
ok: [172.16.9.3]
ok: [172.16.9.2]
TASK [jdk : install jdk] *******************************************************
changed: [172.16.9.4]
[WARNING]: Consider using yum module rather than running yum //这个报错,只是想提示,用yum最好,但是我就是要用shell模块
changed: [172.16.9.2]
changed: [172.16.9.3]
changed: [172.16.9.1]
TASK [jdk : provides jdk.sh] ***************************************************
changed: [172.16.9.2]
changed: [172.16.9.3]
changed: [172.16.9.4]
changed: [172.16.9.1]
TASK [jdk : read /etc/profile.d/java.sh] ***************************************
changed: [172.16.9.2]
changed: [172.16.9.3]
changed: [172.16.9.4]
changed: [172.16.9.1]
RUNNING HANDLER [jdk : source /etc/profile.d/java.sh] **************************
changed: [172.16.9.3]
changed: [172.16.9.4]
changed: [172.16.9.2]
changed: [172.16.9.1]
PLAY RECAP *********************************************************************
172.16.9.1 : ok=5 changed=4 unreachable=0 failed=0
172.16.9.2 : ok=5 changed=4 unreachable=0 failed=0
172.16.9.3 : ok=5 changed=4 unreachable=0 failed=0
172.16.9.4 : ok=5 changed=4 unreachable=0 failed=0
~]# echo $JAVA_HOME
//这里的JAVA_HOME没有读出来,不知道为什么,我用的source啊,待我在查查资料,如果有朋友知道,也可以告诉我一下
~]# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin //PATH环境变量倒是读出来了,真是奇怪了
但是,我重开一个会话,JAVA_HOME变量就可以读出来了
~]# echo $JAVA_HOME
/usr/java/latest //想不明白
vim /etc/ansible/roles/jdk/files/java.sh
...
export CLASSPATH=.:$JAVA_HOME/lib/tools.jar:$JAVA_HOME/lib/dt.jar //添加一行
还好我的tasks中传送文件那里做了tags和notify,就是为了等这个机会呢
~]# ansible-playbook --tags="jdksh" /etc/ansible/site.yml
//这次操作只发送了java.sh并且重读了一下,多方便
总结就到这了,有什么问题,欢迎讨论,知无不言。