ansible概述和运行机制

ansible概述

Ansible是一款为类Unix系统开发的自由开源的配置和自动化工具,  它用Python写成,类似于saltstack和Puppet,但是有一个不同和优点是我们不需要在节点中安装任何客户端 , 它使用SSH来和节点进行通信  Ansible基于 Python paramiko 开发,分布式,无需客户端,轻量级,配置语法使用 YMAL 及 Jinja2模板语言,更强的远程命令执行操作

官方网站 :https://www.ansible.com/

2015年10月,红帽(Red Hat)宣布收购软件开发公司 Ansible,消息称此次收购耗资逾 1亿美元,也有消息称接近 1.5亿美元

Ansible 成立于 2013年,总部设在北卡罗来纳州达勒姆,联合创始人 aïd Ziouani 和高级副总裁 Todd Barr 都是红帽的老员工 Ansible 旗下的开源软件 Ansible 十分流行 ,这家公司还提供 Tower 软件和咨询服务,这个款软件能使开发者轻松地建立和管理规模化应用程序的 IT 基础架构

ansiblle具有如下特点:

1、部署简单,只需在主控端部署Ansible环境,被控端无需做任何操作;

2、默认使用SSH协议对设备进行管理;

3、主从集中化管理;

4、配置简单、功能强大、扩展性强;

5、支持API及自定义模块,可通过Python轻松扩展;

6、通过Playbooks来定制强大的配置、状态管理

7、对云计算平台、大数据都有很好的支持;

 

Ansible 的组成由 5 个部分组成:

Ansible :     ansible核心

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

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

Playbooks :   剧本;定义 Ansible 多任务配置文件,由Ansible 自动执行

Inventory :    定义 Ansible 管理主机的清单

安装ansible服务

# 需要epel源
[root@Ansibel ~]# yum -y install ansible
[root@Ansibel ~]# ansible --version
ansible 2.6.
config file = /etc/ansible/ansible.cfg
configured module search path = [u'/root/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
ansible python module location = /usr/lib/python2./site-packages/ansible
executable location = /usr/bin/ansible
python version = 2.7. (default, Jul , ::) [GCC 4.8. (Red Hat 4.8.-)]

ansible命令参数

anisble命令语法: ansible [-i 主机文件] [-f 批次] [组名] [-m 模块名称] [-a 模块参数]

ansible详细参数:

 -v,–verbose           #  详细模式,如果命令执行成功,输出详细的结果 (-vv -vvv -vvvv)

 -i PATH, -inventory=PATH      #  指定 host 文件的路径,默认是在 /etc/ansible/hosts

 -f NUM,-forks=NUM         # NUM 是指定一个整数,默认是 5 ,指定 fork 开启同步进程的个数。

 -m NAME,-module-name=NAME    #   指定使用的 module 名称,默认使用 command模块

 -a,MODULE_ARGS         # 指定 module 模块的参数

 -k,-ask-pass                 # 提示输入 ssh 的密码,而不是使用基于 ssh 的密钥认证

 -s, sudo                  # 指定使用 sudo 获得 root 权限

 -K,-ask-sudo-pass               # 提示输入 sudo 密码,与 -sudo 一起使用

 -u USERNAME,-user=USERNAME          # 指定移动端的执行用户

 -C,–check                 # 测试此命令执行会改变什么内容,不会真正的去执行

ansible-doc详细参数:

ansible-doc -l             # 列出所有的模块列表

ansible-doc -s 模块名    # 查看指定模块的参数 

定义主机清单

基于端口,用户,密码定义主机清单

ansible基于ssh连接-i (inventory)参数后指定的远程主机时,也可以写端口,用户,密码。

格式:ansible_ssh_port:指定ssh端口   ansible_ssh_user:指定 ssh 用户 ansible_ssh_pass:指定 ssh 用户登录是认证密码(明文密码不安全)  ansible_sudo_pass:指明 sudo 时候的密码

/etc/ansible/hosts 文件维护着Ansible中服务器的清单

[root@Ansibel ~]# vim /etc/ansible/hosts
[web-servers]  # 主机组名
192.168.94.22 ansible_ssh_port= ansible_ssh_user=damowang ansible_ssh_pass= ansible_ssh_pass=
192.168.94.33 ansible_ssh_port= ansible_ssh_user=root ansible_ssh_pass=
# 测试连通性
[root@Ansibel ~]# ansible -i /etc/ansible/hosts web-servers -m ping
192.168.94.33 | SUCCESS => {
"changed": false,
"ping": "pong"
}
192.168.94.22 | SUCCESS => {
"changed": false,
"ping": "pong"
}

-i    #  指定 host 文件的路径,默认是在 /etc/ansible/hosts 定义的主机清单写在该文件下 , 那么可以不加 -i

 -m    #   指定使用的ping模块
# 如果报错 那么可以手动ssh到报错主机 , 原因是需要建立一个fingerprint(指纹) 需要交互 手动输入yes即可

因为明文密码并不安全 , 所以可以生成秘钥对在对下面管理的节点批量分发公钥

生成和批量分发 这里就不再重述了  在 <轻量级集群管理软件-ClusterShell> 中有讲

这里直接修改主机清单文件 把配置项里的密码部分删除

[root@Ansibel ~]# vim /etc/ansible/hosts
[web-servers]
192.168.94.22 ansible_ssh_port= ansible_ssh_user=damowang
192.168.94.33 ansible_ssh_port= ansible_ssh_user=root [root@Ansibel ~]# ansible -m command -a whoami web-servers
192.168.94.22 | SUCCESS | rc= >>
damowang 192.168.94.33 | SUCCESS | rc= >>
root

为节点创建用户

[root@Ansibel ~]# ansible -m user -s -a 'name=mingming shell=/bin/bash home=/home/mingming state=present' web-servers
192.168.94.33 | SUCCESS => {
"changed": true,
"comment": "",
"create_home": true,
"group": ,
"home": "/home/mingming",
"name": "mingming",
"shell": "/bin/bash",
"state": "present",
"system": false,
"uid":
}
192.168.94.22 | SUCCESS => {
"changed": true,
"comment": "",
"create_home": true,
"group": ,
"home": "/home/mingming",
"name": "mingming",
"shell": "/bin/bash",
"state": "present",
"system": false,
"uid":
}

为用户设置密码

安装 passlib 要求系统 python 版本在2.7以上

[root@Ansibel ~]# pip install passlib
-bash: pip: 未找到命令
[root@Ansibel ~]# yum -y install python-pip
[root@Ansibel ~]# pip install passlib
安装完 passlib 后,生成加密的密码
python .x 版本(sha512 加密算法):
[root@Ansibel ~]# python -c 'from passlib.hash import sha512_crypt; import getpass; print (sha512_crypt.encrypt(getpass.getpass()))'
Password:
$$rounds=$G5MXmLZ0J0e1ppzM$V4MGqttDX9LFB5FJPbhV4vqIz0KIzTbrUkx05QLG1mdbDH0e.rVQveAGCVNXiulrkWO/42Z68DVaeNRN3q4oH.
# 在Password 后输入我们的密码然后再按enter 键,就会生成经过加密的密码了
python .x 版本(普通加密算法):
[root@Ansibel ~]# python -c 'import crypt; print (crypt.crypt("475541270","apple"))'
apAM.814qQtJg

python .x 版本(sha512 加密算法):
[root@Ansibel ~]# python -c 'from passlib.hash import sha512_crypt; import getpass; print (sha512_crypt.encrypt(getpass.getpass()))'
Password:
$$rounds=$G5MXmLZ0J0e1ppzM$V4MGqttDX9LFB5FJPbhV4vqIz0KIzTbrUkx05QLG1mdbDH0e.rVQveAGCVNXiulrkWO/42Z68DVaeNRN3q4oH.
python .x 版本(普通加密算法):
[root@Ansibel ~]# python -c 'import crypt; print (crypt.crypt("475541270","apple"))'
apAM.814qQtJg
# 其实python3.x 和 python2.x 版本的区别不大,只是加密算法是用 sha512 还是用普通算法的区别而已

为新创建的用户设置密码

[root@Ansibel ~]# ansible -m user -s -a 'name=mingming password=apAM.814qQtJg update_password=always' web-servers
192.168.94.33 | SUCCESS => {
"append": false,
"changed": true,
"comment": "",
"group": ,
"home": "/home/mingming",
"move_home": false,
"name": "mingming",
"password": "NOT_LOGGING_PASSWORD",
"shell": "/bin/bash",
"state": "present",
"uid":
}
192.168.94.22 | SUCCESS => {
"append": false,
"changed": true,
"comment": "",
"group": ,
"home": "/home/mingming",
"move_home": false,
"name": "mingming",
"password": "NOT_LOGGING_PASSWORD",
"shell": "/bin/bash",
"state": "present",
"uid":
}

将df命令在所有节点执行后,重定向输出到本机的/tmp/command-output.txt文件中

[root@Ansibel ~]# ansible -m command -a 'df -Th' web-servers > /tmp/command-output.txt
[root@Ansibel ~]# cat /tmp/command-output.txt
192.168.94.33 | SUCCESS | rc= >>
文件系统 类型 容量 已用 可用 已用% 挂载点
/dev/mapper/centos-root xfs 17G .4G 15G % /
devtmpfs devtmpfs 476M 476M % /dev
tmpfs tmpfs 488M 488M % /dev/shm
tmpfs tmpfs 488M 7.7M 480M % /run
tmpfs tmpfs 488M 488M % /sys/fs/cgroup
/dev/sda1 xfs 1014M 130M 885M % /boot
tmpfs tmpfs 98M 98M % /run/user/
192.168.94.22 | SUCCESS | rc= >>
文件系统 类型 容量 已用 可用 已用% 挂载点
/dev/mapper/centos-root xfs 17G .4G 15G % /
devtmpfs devtmpfs 476M 476M % /dev
tmpfs tmpfs 488M 488M % /dev/shm
tmpfs tmpfs 488M 7.8M 480M % /run
tmpfs tmpfs 488M 488M % /sys/fs/cgroup
/dev/sda1 xfs 1014M 130M 885M % /boot
tmpfs tmpfs 98M 98M % /run/user/
tmpfs tmpfs 98M 98M % /run/user/

ansible常见模块高级使用方法

3个远程命令模块的区别

(1)、command模块为ansible默认模块,不指定-m参数时,使用的就是command模块; comand模块比较简单,常见的命令都可以使用,但其命令的执行不是通过shell执行的,所以,像这些 "<", ">", "|", and "&"操作都不可以,当然,也就不支持管道; 缺点:不支持管道,没法批量执行命令;

(2)、shell模块:使用shell模块,在远程命令通过/bin/sh来执行;所以,我们在终端输入的各种命令方式,都可以使用

(3)、scripts模块 :如果在远程待执行的语句比较多,可写成一个脚本,通过copy模块传到远端,然后再执行;但这样就又涉及到两次ansible调用;对于这种需求,ansible已经为我们考虑到了,script模块就是干这事的;

使用scripts模块可以在本地写一个脚本,在远程服务器上执行:

[root@Ansibel ~]# vim /etc/ansible/test.sh
#!/bin/bash
date
hostname
[root@Ansibel ~]# ansible -m script -a '/etc/ansible/test.sh' web-servers
192.168.94.33 | SUCCESS => {
"changed": true,
"rc": ,
"stderr": "Shared connection to 192.168.94.33 closed.\r\n",
"stderr_lines": [
"Shared connection to 192.168.94.33 closed."
],
"stdout": "2018年 09月 09日 星期日 00:15:44 CST\r\nhost2\r\n",
"stdout_lines": [
"2018年 09月 09日 星期日 00:15:44 CST",
"host2"
]
}
192.168.94.22 | SUCCESS => {
"changed": true,
"rc": ,
"stderr": "Shared connection to 192.168.94.22 closed.\r\n",
"stderr_lines": [
"Shared connection to 192.168.94.22 closed."
],
"stdout": "2018年 09月 09日 星期日 00:15:44 CST\r\nhost1\r\n",
"stdout_lines": [
"2018年 09月 09日 星期日 00:15:44 CST",
"host1"
]
}

copy模块:实现主控端向目标主机拷贝文件,类似scp功能

[root@Ansibel ~]# ansible -m copy -s -a 'src=/etc/hosts dest=/tmp owner=root group=root mode=755' web-servers
192.168.94.33 | SUCCESS => {
"changed": true,
"checksum": "bf651d9270aa5d2f73e1987c1bba58b3a7732e30",
"dest": "/tmp/hosts",
"gid": ,
"group": "root",
"md5sum": "da3395b279a7cd7a1187ae82acb24b2d",
"mode": "",
"owner": "root",
"size": ,
"src": "/root/.ansible/tmp/ansible-tmp-1536423509.88-40213567242184/source",
"state": "file",
"uid":
}
192.168.94.22 | SUCCESS => {
"changed": true,
"checksum": "bf651d9270aa5d2f73e1987c1bba58b3a7732e30",
"dest": "/tmp/hosts",
"gid": ,
"group": "root",
"md5sum": "da3395b279a7cd7a1187ae82acb24b2d",
"mode": "",
"owner": "root",
"size": ,
"src": "/home/damowang/.ansible/tmp/ansible-tmp-1536423509.88-138418725080513/source",
"state": "file",
"uid":
}
[root@Ansibel ~]# ansible -a 'ls -l /tmp/hosts' web-servers
192.168.94.33 | SUCCESS | rc= >>
-rwxr-xr-x root root 9月 : /tmp/hosts 192.168.94.22 | SUCCESS | rc= >>
-rwxr-xr-x root root 9月 : /tmp/hosts

file模块设置文件属性

[root@Ansibel ~]# ansible -m file -s -a 'path=/tmp/hosts mode=777' web-servers
192.168.94.33 | SUCCESS => {
"changed": true,
"gid": ,
"group": "root",
"mode": "",
"owner": "root",
"path": "/tmp/hosts",
"size": ,
"state": "file",
"uid":
}
192.168.94.22 | SUCCESS => {
"changed": true,
"gid": ,
"group": "root",
"mode": "",
"owner": "root",
"path": "/tmp/hosts",
"size": ,
"state": "file",
"uid":
}
[root@Ansibel ~]# ansible -a 'ls -l /tmp/hosts' web-servers
192.168.94.33 | SUCCESS | rc= >>
-rwxrwxrwx root root 9月 : /tmp/hosts 192.168.94.22 | SUCCESS | rc= >>
-rwxrwxrwx root root 9月 : /tmp/hosts

stat模块获取远程文件信息

[root@Ansibel ~]# ansible -m stat -a 'path=/tmp/hosts' web-servers
192.168.94.33 | SUCCESS => {
"changed": false,
"stat": {
"atime": 1536423510.9210756,
"attr_flags": "",
"attributes": [],
"block_size": ,
"blocks": ,
"charset": "us-ascii",
"checksum": "bf651d9270aa5d2f73e1987c1bba58b3a7732e30",
"ctime": 1536423695.9194686,
"dev": ,
"device_type": ,
"executable": true,
"exists": true,
"gid": ,
"gr_name": "root",
"inode": ,
"isblk": false,
"ischr": false,
"isdir": false,
"isfifo": false,
"isgid": false,
"islnk": false,
"isreg": true,
"issock": false,
"isuid": false,
"mimetype": "text/plain",
"mode": "",
"mtime": 1536423510.5610728,
"nlink": ,
"path": "/tmp/hosts",
"pw_name": "root",
"readable": true,
"rgrp": true,
"roth": true,
"rusr": true,
"size": ,
"uid": ,
"version": "",
"wgrp": true,
"woth": true,
"writeable": true,
"wusr": true,
"xgrp": true,
"xoth": true,
"xusr": true
}
}
192.168.94.22 | SUCCESS => {
"changed": false,
"stat": {
"atime": 1536423510.943854,
"attr_flags": "",
"attributes": [],
"block_size": ,
"blocks": ,
"charset": "us-ascii",
"checksum": "bf651d9270aa5d2f73e1987c1bba58b3a7732e30",
"ctime": 1536423695.9422553,
"dev": ,
"device_type": ,
"executable": true,
"exists": true,
"gid": ,
"gr_name": "root",
"inode": ,
"isblk": false,
"ischr": false,
"isdir": false,
"isfifo": false,
"isgid": false,
"islnk": false,
"isreg": true,
"issock": false,
"isuid": false,
"mimetype": "text/plain",
"mode": "",
"mtime": 1536423510.5838513,
"nlink": ,
"path": "/tmp/hosts",
"pw_name": "root",
"readable": true,
"rgrp": true,
"roth": true,
"rusr": true,
"size": ,
"uid": ,
"version": "",
"wgrp": true,
"woth": true,
"writeable": true,
"wusr": true,
"xgrp": true,
"xoth": true,
"xusr": true
}
}

get_url模块实现远程主机下载指定url到本地,支持sha256sum文件校验

[root@Ansibel ~]# ansible -m get_url -a 'url=https://mirrors.aliyun.com/epel/epel-release-latest-7.noarch.rpm dest=/tmp mode=0440 force=yes' web-servers
192.168.94.33 | SUCCESS => {
"changed": true,
"checksum_dest": null,
"checksum_src": "5512b80e5b71f2370d8419fa16a0bc14c5edf854",
"dest": "/tmp/epel-release-latest-7.noarch.rpm",
"gid": ,
"group": "root",
"md5sum": "d512508b8629428e7c3f535cc8012680",
"mode": "",
"msg": "OK (15080 bytes)",
"owner": "root",
"size": ,
"src": "/root/.ansible/tmp/ansible-tmp-1536424011.27-144130983589743/tmpJs0QN9",
"state": "file",
"status_code": ,
"uid": ,
"url": "https://mirrors.aliyun.com/epel/epel-release-latest-7.noarch.rpm"
}
192.168.94.22 | SUCCESS => {
"changed": true,
"checksum_dest": null,
"checksum_src": "5512b80e5b71f2370d8419fa16a0bc14c5edf854",
"dest": "/tmp/epel-release-latest-7.noarch.rpm",
"gid": ,
"group": "damowang",
"md5sum": "d512508b8629428e7c3f535cc8012680",
"mode": "",
"msg": "OK (15080 bytes)",
"owner": "damowang",
"size": ,
"src": "/home/damowang/.ansible/tmp/ansible-tmp-1536424011.25-163292980253597/tmpvx9BOK",
"state": "file",
"status_code": ,
"uid": ,
"url": "https://mirrors.aliyun.com/epel/epel-release-latest-7.noarch.rpm"
}
# force=yes,当下载文件时,如果所下的内容和原目录下的文件内容不一样,则替换原文件,如果一样,就不下载了
如果为“否”,则仅在目标不存在时才下载文件
一般来说,只有小型本地文件才应该为“是” 

在0.6之前,该模块默认为“是”
url=https://xxx  的等号=前后不能有空格

yum模块linux平台软件包管理

yum模块可以提供的status状态: latest ,present,installed 都是表示安装

removed, absent 表示卸载

为下面节点安装apache

ansible -m yum -s -a 'name=httpd state=latest' web-servers
192.168.94.33 | SUCCESS => {
"changed": true,
"msg": "",
"rc": ,
"results": [
"Loaded plugins: fastestmirror\nLoading mirror speeds from cached hostfile\n * base: mirrors.aliyun.com\n * extras: mirrors.aliyun.com\n * updates: mirrors.aliyun.com\nResolving Dependencies\n--> Running transaction check\n---> Package httpd.x86_64 0:2.4.6-80.el7.centos.1 will be installed\n--> Finished Dependency Resolution\n\nDependencies Resolved\n\n================================================================================\n Package Arch Version Repository Size\n================================================================================\nInstalling:\n httpd x86_64 2.4.6-80.el7.centos.1 updates 2.7 M\n\nTransaction Summary\n================================================================================\nInstall 1 Package\n\nTotal download size: 2.7 M\nInstalled size: 9.4 M\nDownloading packages:\nRunning transaction check\nRunning transaction test\nTransaction test succeeded\nRunning transaction\n Installing : httpd-2.4.6-80.el7.centos.1.x86_64 1/1 \n Verifying : httpd-2.4.6-80.el7.centos.1.x86_64 1/1 \n\nInstalled:\n httpd.x86_64 0:2.4.6-80.el7.centos.1 \n\nComplete!\n"
]
}
192.168.94.22 | SUCCESS => {
"changed": true,
"msg": "",
"rc": ,
"results": [
"Loaded plugins: fastestmirror\nLoading mirror speeds from cached hostfile\n * base: mirrors.aliyun.com\n * extras: mirrors.aliyun.com\n * updates: mirrors.aliyun.com\nResolving Dependencies\n--> Running transaction check\n---> Package httpd.x86_64 0:2.4.6-80.el7.centos will be updated\n---> Package httpd.x86_64 0:2.4.6-80.el7.centos.1 will be an update\n--> Processing Dependency: httpd-tools = 2.4.6-80.el7.centos.1 for package: httpd-2.4.6-80.el7.centos.1.x86_64\n--> Running transaction check\n---> Package httpd-tools.x86_64 0:2.4.6-80.el7.centos will be updated\n---> Package httpd-tools.x86_64 0:2.4.6-80.el7.centos.1 will be an update\n--> Finished Dependency Resolution\n\nDependencies Resolved\n\n================================================================================\n Package Arch Version Repository Size\n================================================================================\nUpdating:\n httpd x86_64 2.4.6-80.el7.centos.1 updates 2.7 M\nUpdating for dependencies:\n httpd-tools x86_64 2.4.6-80.el7.centos.1 updates 90 k\n\nTransaction Summary\n================================================================================\nUpgrade 1 Package (+1 Dependent package)\n\nTotal download size: 2.8 M\nDownloading packages:\nDelta RPMs disabled because /usr/bin/applydeltarpm not installed.\n--------------------------------------------------------------------------------\nTotal 5.6 MB/s | 2.8 MB 00:00 \nRunning transaction check\nRunning transaction test\nTransaction test succeeded\nRunning transaction\n Updating : httpd-tools-2.4.6-80.el7.centos.1.x86_64 1/4 \n Updating : httpd-2.4.6-80.el7.centos.1.x86_64 2/4 \n Cleanup : httpd-2.4.6-80.el7.centos.x86_64 3/4 \n Cleanup : httpd-tools-2.4.6-80.el7.centos.x86_64 4/4 \n Verifying : httpd-tools-2.4.6-80.el7.centos.1.x86_64 1/4 \n Verifying : httpd-2.4.6-80.el7.centos.1.x86_64 2/4 \n Verifying : httpd-tools-2.4.6-80.el7.centos.x86_64 3/4 \n Verifying : httpd-2.4.6-80.el7.centos.x86_64 4/4 \n\nUpdated:\n httpd.x86_64 0:2.4.6-80.el7.centos.1 \n\nDependency Updated:\n httpd-tools.x86_64 0:2.4.6-80.el7.centos.1 \n\nComplete!\n"
]
}

cron模块远程主机crontab配置

[root@Ansible ~]# ansible -m cron -s -a "name='My Wifi' minute='*/1' job='cat /root/mingming>/var/www/html/index.html'" web-servers
192.168.94.33 | SUCCESS => {
"changed": true,
"envs": [],
"jobs": [
"My Wifi"
]
}
192.168.94.22 | SUCCESS => {
"changed": true,
"envs": [],
"jobs": [
"My Wifi"
]
}
[root@Ansible ~]# ansible -m shell -s -a 'crontab -l' web-servers
192.168.94.33 | SUCCESS | rc= >>
#Ansible: My Wifi
*/ * * * * cat /root/mingming>/var/www/html/index.html 192.168.94.22 | SUCCESS | rc= >>
#Ansible: My Wifi
*/ * * * * cat /root/mingming>/var/www/html/index.html

service模块远程主机系统服务管理(CentOS7 中为systemd模块 用法基本一样)

service模块常用参数:

(1)name参数:此参数用于指定需要操作的服务名称,比如 nginx,httpd

(2)state参数:此参数用于指定服务的状态,比如,我们想要启动远程主机中的httpd,则可以将 state 的值设置为 started;如果想要停止远程主机中的服务,则可以将 state 的值设置为 stopped

此参数的可用值有 started、stopped、restarted(重启)、reloaded

enabled参数:此参数用于指定是否将服务设置为开机 启动项,设置为 yes 表示将对应服务设置为开机启动,设置为 no 表示不会开机启动

想使用service模块启动服务,被启动的服务,必须可以使用service 命令启动或关闭

[root@Ansible ~]# ansible -m systemd -s -a 'name=httpd state=started' web-servers
192.168.94.33 | SUCCESS => {
"changed": true,
"name": "httpd",
"state": "started",
"status": {
"ActiveEnterTimestampMonotonic": "",
"ActiveExitTimestampMonotonic": "",
"ActiveState": "inactive",
"After": "-.mount basic.target network.target tmp.mount remote-fs.target system.slice systemd-journald.socket nss-lookup.target",
"AllowIsolate": "no",
"AmbientCapabilities": "",
"AssertResult": "no",
"AssertTimestampMonotonic": "",
"Before": "shutdown.target",
"BlockIOAccounting": "no",
"BlockIOWeight": "",
"CPUAccounting": "no",
"CPUQuotaPerSecUSec": "infinity",
"CPUSchedulingPolicy": "",
"CPUSchedulingPriority": "",
"CPUSchedulingResetOnFork": "no",
"CPUShares": "",
"CanIsolate": "no",
"CanReload": "yes",
"CanStart": "yes",
"CanStop": "yes",
"CapabilityBoundingSet": "",
"ConditionResult": "no",
"ConditionTimestampMonotonic": "",
"Conflicts": "shutdown.target",
"ControlPID": "",
"DefaultDependencies": "yes",
"Delegate": "no",
"Description": "The Apache HTTP Server",
"DevicePolicy": "auto",
"Documentation": "man:httpd(8) man:apachectl(8)",
"EnvironmentFile": "/etc/sysconfig/httpd (ignore_errors=no)",
"ExecMainCode": "",
"ExecMainExitTimestampMonotonic": "",
"ExecMainPID": "",
"ExecMainStartTimestampMonotonic": "",
"ExecMainStatus": "",
"ExecReload": "{ path=/usr/sbin/httpd ; argv[]=/usr/sbin/httpd $OPTIONS -k graceful ; ignore_errors=no ; start_time=[n/a] ; stop_time=[n/a] ; pid=0 ; code=(null) ; status=0/0 }",
"ExecStart": "{ path=/usr/sbin/httpd ; argv[]=/usr/sbin/httpd $OPTIONS -DFOREGROUND ; ignore_errors=no ; start_time=[n/a] ; stop_time=[n/a] ; pid=0 ; code=(null) ; status=0/0 }",
"ExecStop": "{ path=/bin/kill ; argv[]=/bin/kill -WINCH ${MAINPID} ; ignore_errors=no ; start_time=[n/a] ; stop_time=[n/a] ; pid=0 ; code=(null) ; status=0/0 }",
"FailureAction": "none",
"FileDescriptorStoreMax": "",
"FragmentPath": "/usr/lib/systemd/system/httpd.service",
"GuessMainPID": "yes",
"IOScheduling": "",
"Id": "httpd.service",
"IgnoreOnIsolate": "no",
"IgnoreOnSnapshot": "no",
"IgnoreSIGPIPE": "yes",
"InactiveEnterTimestampMonotonic": "",
"InactiveExitTimestampMonotonic": "",
"JobTimeoutAction": "none",
"JobTimeoutUSec": "",
"KillMode": "control-group",
"KillSignal": "",
"LimitAS": "",
"LimitCORE": "",
"LimitCPU": "",
"LimitDATA": "",
"LimitFSIZE": "",
"LimitLOCKS": "",
"LimitMEMLOCK": "",
"LimitMSGQUEUE": "",
"LimitNICE": "",
"LimitNOFILE": "",
"LimitNPROC": "",
"LimitRSS": "",
"LimitRTPRIO": "",
"LimitRTTIME": "",
"LimitSIGPENDING": "",
"LimitSTACK": "",
"LoadState": "loaded",
"MainPID": "",
"MemoryAccounting": "no",
"MemoryCurrent": "",
"MemoryLimit": "",
"MountFlags": "",
"Names": "httpd.service",
"NeedDaemonReload": "no",
"Nice": "",
"NoNewPrivileges": "no",
"NonBlocking": "no",
"NotifyAccess": "main",
"OOMScoreAdjust": "",
"OnFailureJobMode": "replace",
"PermissionsStartOnly": "no",
"PrivateDevices": "no",
"PrivateNetwork": "no",
"PrivateTmp": "yes",
"ProtectHome": "no",
"ProtectSystem": "no",
"RefuseManualStart": "no",
"RefuseManualStop": "no",
"RemainAfterExit": "no",
"Requires": "-.mount basic.target",
"RequiresMountsFor": "/var/tmp",
"Restart": "no",
"RestartUSec": "100ms",
"Result": "success",
"RootDirectoryStartOnly": "no",
"RuntimeDirectoryMode": "",
"SameProcessGroup": "no",
"SecureBits": "",
"SendSIGHUP": "no",
"SendSIGKILL": "yes",
"Slice": "system.slice",
"StandardError": "inherit",
"StandardInput": "null",
"StandardOutput": "journal",
"StartLimitAction": "none",
"StartLimitBurst": "",
"StartLimitInterval": "",
"StartupBlockIOWeight": "",
"StartupCPUShares": "",
"StatusErrno": "",
"StopWhenUnneeded": "no",
"SubState": "dead",
"SyslogLevelPrefix": "yes",
"SyslogPriority": "",
"SystemCallErrorNumber": "",
"TTYReset": "no",
"TTYVHangup": "no",
"TTYVTDisallocate": "no",
"TasksAccounting": "no",
"TasksCurrent": "",
"TasksMax": "",
"TimeoutStartUSec": "1min 30s",
"TimeoutStopUSec": "1min 30s",
"TimerSlackNSec": "",
"Transient": "no",
"Type": "notify",
"UMask": "",
"UnitFilePreset": "disabled",
"UnitFileState": "disabled",
"Wants": "system.slice",
"WatchdogTimestampMonotonic": "",
"WatchdogUSec": ""
}
}
192.168.94.22 | SUCCESS => {
"changed": true,
"name": "httpd",
"state": "started",
"status": {
"ActiveEnterTimestampMonotonic": "",
"ActiveExitTimestampMonotonic": "",
"ActiveState": "inactive",
"After": "systemd-journald.socket nss-lookup.target network.target basic.target tmp.mount remote-fs.target system.slice -.mount",
"AllowIsolate": "no",
"AmbientCapabilities": "",
"AssertResult": "no",
"AssertTimestampMonotonic": "",
"Before": "shutdown.target",
"BlockIOAccounting": "no",
"BlockIOWeight": "",
"CPUAccounting": "no",
"CPUQuotaPerSecUSec": "infinity",
"CPUSchedulingPolicy": "",
"CPUSchedulingPriority": "",
"CPUSchedulingResetOnFork": "no",
"CPUShares": "",
"CanIsolate": "no",
"CanReload": "yes",
"CanStart": "yes",
"CanStop": "yes",
"CapabilityBoundingSet": "",
"ConditionResult": "no",
"ConditionTimestampMonotonic": "",
"Conflicts": "shutdown.target",
"ControlPID": "",
"DefaultDependencies": "yes",
"Delegate": "no",
"Description": "The Apache HTTP Server",
"DevicePolicy": "auto",
"Documentation": "man:httpd(8) man:apachectl(8)",
"EnvironmentFile": "/etc/sysconfig/httpd (ignore_errors=no)",
"ExecMainCode": "",
"ExecMainExitTimestampMonotonic": "",
"ExecMainPID": "",
"ExecMainStartTimestampMonotonic": "",
"ExecMainStatus": "",
"ExecReload": "{ path=/usr/sbin/httpd ; argv[]=/usr/sbin/httpd $OPTIONS -k graceful ; ignore_errors=no ; start_time=[n/a] ; stop_time=[n/a] ; pid=0 ; code=(null) ; status=0/0 }",
"ExecStart": "{ path=/usr/sbin/httpd ; argv[]=/usr/sbin/httpd $OPTIONS -DFOREGROUND ; ignore_errors=no ; start_time=[n/a] ; stop_time=[n/a] ; pid=0 ; code=(null) ; status=0/0 }",
"ExecStop": "{ path=/bin/kill ; argv[]=/bin/kill -WINCH ${MAINPID} ; ignore_errors=no ; start_time=[n/a] ; stop_time=[n/a] ; pid=0 ; code=(null) ; status=0/0 }",
"FailureAction": "none",
"FileDescriptorStoreMax": "",
"FragmentPath": "/usr/lib/systemd/system/httpd.service",
"GuessMainPID": "yes",
"IOScheduling": "",
"Id": "httpd.service",
"IgnoreOnIsolate": "no",
"IgnoreOnSnapshot": "no",
"IgnoreSIGPIPE": "yes",
"InactiveEnterTimestampMonotonic": "",
"InactiveExitTimestampMonotonic": "",
"JobTimeoutAction": "none",
"JobTimeoutUSec": "",
"KillMode": "control-group",
"KillSignal": "",
"LimitAS": "",
"LimitCORE": "",
"LimitCPU": "",
"LimitDATA": "",
"LimitFSIZE": "",
"LimitLOCKS": "",
"LimitMEMLOCK": "",
"LimitMSGQUEUE": "",
"LimitNICE": "",
"LimitNOFILE": "",
"LimitNPROC": "",
"LimitRSS": "",
"LimitRTPRIO": "",
"LimitRTTIME": "",
"LimitSIGPENDING": "",
"LimitSTACK": "",
"LoadState": "loaded",
"MainPID": "",
"MemoryAccounting": "no",
"MemoryCurrent": "",
"MemoryLimit": "",
"MountFlags": "",
"Names": "httpd.service",
"NeedDaemonReload": "no",
"Nice": "",
"NoNewPrivileges": "no",
"NonBlocking": "no",
"NotifyAccess": "main",
"OOMScoreAdjust": "",
"OnFailureJobMode": "replace",
"PermissionsStartOnly": "no",
"PrivateDevices": "no",
"PrivateNetwork": "no",
"PrivateTmp": "yes",
"ProtectHome": "no",
"ProtectSystem": "no",
"RefuseManualStart": "no",
"RefuseManualStop": "no",
"RemainAfterExit": "no",
"Requires": "-.mount basic.target",
"RequiresMountsFor": "/var/tmp",
"Restart": "no",
"RestartUSec": "100ms",
"Result": "success",
"RootDirectoryStartOnly": "no",
"RuntimeDirectoryMode": "",
"SameProcessGroup": "no",
"SecureBits": "",
"SendSIGHUP": "no",
"SendSIGKILL": "yes",
"Slice": "system.slice",
"StandardError": "inherit",
"StandardInput": "null",
"StandardOutput": "journal",
"StartLimitAction": "none",
"StartLimitBurst": "",
"StartLimitInterval": "",
"StartupBlockIOWeight": "",
"StartupCPUShares": "",
"StatusErrno": "",
"StopWhenUnneeded": "no",
"SubState": "dead",
"SyslogLevelPrefix": "yes",
"SyslogPriority": "",
"SystemCallErrorNumber": "",
"TTYReset": "no",
"TTYVHangup": "no",
"TTYVTDisallocate": "no",
"TasksAccounting": "no",
"TasksCurrent": "",
"TasksMax": "",
"TimeoutStartUSec": "1min 30s",
"TimeoutStopUSec": "1min 30s",
"TimerSlackNSec": "",
"Transient": "no",
"Type": "notify",
"UMask": "",
"UnitFilePreset": "disabled",
"UnitFileState": "disabled",
"Wants": "system.slice",
"WatchdogTimestampMonotonic": "",
"WatchdogUSec": ""
}
}

访问节点web页面

sysctl模块远程主机sysctl配置

# 开启路由转发功能
[root@Ansible ~]# ansible -m sysctl -s -a 'name=net.ipv4.ip_forward value=1 reload=yes' web-servers
192.168.94.33 | SUCCESS => {
"changed": true
}
192.168.94.22 | SUCCESS => {
"changed": true
}
[root@Ansible ~]# ansible -m shell -a "cat /proc/sys/net/ipv4/ip_forward" web-servers
192.168.94.33 | SUCCESS | rc= >> 192.168.94.22 | SUCCESS | rc= >>

Playbook是一个不同于使用ansible命令行执行方式的模式,功能更强大更灵活

playbooks使用步骤:

1、在playbooks 中定义任务:

- name: task description     #任务描述信息

 module_name: module_args    #需要使用的模块名字:  模块参数

2、ansible-playbook 执行 命令:

[root@Ansible ~]# ansible-playbook LAMP.yml

playbook是由一个或多个"play"组成的列表

play的主要功能在于将事先归为一组的主机装扮成事先通过ansible中的task定义好的角色

github上提供了大量的实例供大家参考  https://github.com/ansible/ansible-examples

使用Playbook批量部署多台LAMP环境

Playbook常用文件夹作用: 

files:存放需要同步到异地服务器的源码文件及配置文件; 

handlers:当服务的配置文件发生变化时需要进行的操作,比如:重启服务,重新加载配置文件; 

meta:角色定义,可留空;    

tasks:需要进行的执行的任务; 

templates:用于执行lamp安装的模板文件,一般为脚本;   

vars:本次安装定义的变量

我们可以在ansible服务器上安装LAMP环境,然后,再将配置文件通过ansible拷贝到远程主机上

[root@Ansible ~]# yum -y install httpd mariadb mariadb-server php php-mysql
[root@Ansible ~]# mkdir -p /mydata/data
[root@Ansible ~]# chown -R mysql:mysql /mydata/
[root@Ansible ~]# vim /etc/my.cnf
# 修改为 datadir=/mydata/data
[root@Ansible ~]# systemctl start mariadb
[root@Ansible ~]# echo "<?php phpinfo(); ?>" > /var/www/html/index.php
[root@Ansible ~]# systemctl start httpd

访问测试页面 确认MySQL已经被整合进来再进行下一步

使用playbook创建一个LAMP构建的任务

创建相关文件

[root@Ansible ~]# mkdir -pv /etc/ansible/lamp/roles/{prepare,httpd,mysql,php}/{tasks,files,templates,vars,meta,default,handlers}
mkdir: 已创建目录 "/etc/ansible/lamp"
mkdir: 已创建目录 "/etc/ansible/lamp/roles"
mkdir: 已创建目录 "/etc/ansible/lamp/roles/prepare"
mkdir: 已创建目录 "/etc/ansible/lamp/roles/prepare/tasks"
mkdir: 已创建目录 "/etc/ansible/lamp/roles/prepare/files"
mkdir: 已创建目录 "/etc/ansible/lamp/roles/prepare/templates"
mkdir: 已创建目录 "/etc/ansible/lamp/roles/prepare/vars"
mkdir: 已创建目录 "/etc/ansible/lamp/roles/prepare/meta"
mkdir: 已创建目录 "/etc/ansible/lamp/roles/prepare/default"
mkdir: 已创建目录 "/etc/ansible/lamp/roles/prepare/handlers"
mkdir: 已创建目录 "/etc/ansible/lamp/roles/httpd"
mkdir: 已创建目录 "/etc/ansible/lamp/roles/httpd/tasks"
mkdir: 已创建目录 "/etc/ansible/lamp/roles/httpd/files"
mkdir: 已创建目录 "/etc/ansible/lamp/roles/httpd/templates"
mkdir: 已创建目录 "/etc/ansible/lamp/roles/httpd/vars"
mkdir: 已创建目录 "/etc/ansible/lamp/roles/httpd/meta"
mkdir: 已创建目录 "/etc/ansible/lamp/roles/httpd/default"
mkdir: 已创建目录 "/etc/ansible/lamp/roles/httpd/handlers"
mkdir: 已创建目录 "/etc/ansible/lamp/roles/mysql"
mkdir: 已创建目录 "/etc/ansible/lamp/roles/mysql/tasks"
mkdir: 已创建目录 "/etc/ansible/lamp/roles/mysql/files"
mkdir: 已创建目录 "/etc/ansible/lamp/roles/mysql/templates"
mkdir: 已创建目录 "/etc/ansible/lamp/roles/mysql/vars"
mkdir: 已创建目录 "/etc/ansible/lamp/roles/mysql/meta"
mkdir: 已创建目录 "/etc/ansible/lamp/roles/mysql/default"
mkdir: 已创建目录 "/etc/ansible/lamp/roles/mysql/handlers"
mkdir: 已创建目录 "/etc/ansible/lamp/roles/php"
mkdir: 已创建目录 "/etc/ansible/lamp/roles/php/tasks"
mkdir: 已创建目录 "/etc/ansible/lamp/roles/php/files"
mkdir: 已创建目录 "/etc/ansible/lamp/roles/php/templates"
mkdir: 已创建目录 "/etc/ansible/lamp/roles/php/vars"
mkdir: 已创建目录 "/etc/ansible/lamp/roles/php/meta"
mkdir: 已创建目录 "/etc/ansible/lamp/roles/php/default"
mkdir: 已创建目录 "/etc/ansible/lamp/roles/php/handlers"

我们将上面搭建成功的LAMP环境的httpd和MySQL的配置文件拷贝到对应目录下

[root@Ansible ~]# cd /etc/ansible/
[root@Ansible ansible]# cp /etc/httpd/conf/httpd.conf lamp/roles/httpd/files/
[root@Ansible ansible]# cp /etc/my.cnf lamp/roles/mysql/files/

prepare(前期准备)角色的playbooks

[root@Ansible ansible]# vim lamp/roles/prepare/tasks/main.yml
- name: delete yum config
shell: rm -rf /etc/yum.repos.d/* #删除原有的yum配置文件
- name: provide yumrepo file
shell: wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo #下载新的yum配置文件
- name: clean the yum repo
shell: yum clean all #清除原有的yum缓存信息
- name: clean the iptables
shell: iptables -F #清除原有防火墙规则,不然后可能上不了网

构建httpd的任务

[root@Ansible ansible]# cd /etc/ansible/lamp/roles
[root@Ansible roles]# mv /var/www/html/index.php httpd/files/
[root@Ansible roles]# vim httpd/tasks/main.yml
- name: web server install
yum: name=httpd state=present #安装httpd服务
- name: provide test page
copy: src=index.php dest=/var/www/html #提供测试页
- name: delete apache config
shell: rm -rf /etc/httpd/conf/httpd.conf #删除原有的apache配置文件,如果不删除,下面的copy任务是不会执行的,因为当源文件httpd.conf和目标文件一样时,copy命令是不执行的。如果copy命令不执行,那么notify将不调用handler
- name: provide configuration file
copy: src=httpd.conf dest=/etc/httpd/conf/httpd.conf #提供httpd的配置文件
notify: restart httpd #当前面的copy复制成功后,通过notify通知名字为restart httpd的handlers运行。

notify: 这个action可用于在每个play的最后被触发,这样可以避免多次有改变发生时,每次都执行指定的操作,取而代之,仅在所有的变化发生完成后一次性地执行指定操作

在notify中列出的操作称为handler,也即notify中调用handler中定义的操作

---- name: test.yml just for test 

    hosts: testserver 

    vars:   

        region: ap-southeast-1 

    tasks:   

        - name: template configuration

          file      template: src=template.j2 dest=/etc/foo.conf     

    notify:         

        - restart memcached         

        - restart apache 

    handlers:   

          - name: restart memcached     

            service: name=memcached state=restarted   

          - name: restart apache      

            service: name=apache state=restarted

handlers概述:

Handlers 也是一些 task 的列表,通过名字来引用,它们和一般的 task 并没有什么区别

Handlers 是由通知者进行notify, 如果没有被 notify,handlers 不会执行

不管有多少个通知者进行了notify,等到 play 中的所有 task 执行完成之后,handlers 也只会被执行一次

Handlers 最佳的应用场景是用来重启服务,或者触发系统重启操作.除此以外很少用到了

构建httpd的handlers

[root@Ansible roles]# vim httpd/handlers/main.yml
- name: restart httpd
service: name=httpd enabled=yes state=restarted

部署mariadb数据库

创建MySQL服务的任务,需要安装MySQL服务,改变属主信息,启动MySQL

[root@Ansible roles]# cd /etc/ansible/lamp/roles
[root@Ansible roles]# vim mysql/tasks/main.yml
- name: install the mysql
yum: name=mariadb-server state=present #安装mysql服务
- name: mkdir date directory
shell: mkdir -p /mydata/data #创建挂载点目录
- name: provide configration file
copy: src=my.cnf dest=/etc/my.cnf #提供mysql的配置文件
- name: chage the owner
shell: chown -R mysql:mysql /mydata/* #更改属主和属组
- name: start mariadb
service: name=mariadb enabled=yes state=started #启动mysql服务

构建PHP的任务

[root@Ansible roles]# vim php/tasks/main.yml
- name: install php
yum: name=php state=present #安装php
- name: install php-mysql
yum: name=php-mysql state=present #安装php与mysql交互的插件

定义整个的任务

[root@Ansible roles]# cd /etc/ansible/lamp/roles
[root@Ansible roles]# vim site.yml
- name: LAMP build
remote_user: root
hosts: web-servers
roles:
- prepare
- mysql
- php
- httpd

所有yml的配置文件中,空格必须严格对齐

开始部署

[root@Ansible roles]# ansible-playbook -s /etc/ansible/lamp/roles/site.yml 

在浏览器中访问这两台节点主机 IP/index.php

特别注意 : 默认情况下,首次登陆一台服务器,系统会提示是否要记住对端的指纹,用ansible也会这样,这样会导致需要手工输入yes或no,ansible 才可以往下执行。如需避免这种情况,需要在 /etc/ansible/ansible.cfg 文件中设置 host_key_checking = False

轻量级集群管理软件-Ansible的更多相关文章

  1. 轻量级集群管理软件-ClusterShell

    如果集群数量不多的话,选择一个轻量级的集群管理软件就显得非常有必要了.ClusterShell就是这样一种小的集群管理工具,原理是利用ssh,可以说是Linux系统下非常好用的运维工具  cluste ...

  2. 集群管理软件clustershell

    一.简介 1.安装方便.一条指令就能轻松安装. 2.配置方便.很多集群管理软件都需要在所有的服务器上都安装软件,而且还要进行很多的连接操作,clustershell就相当的方便了,仅仅需要所有机器能够 ...

  3. 深度学习GPU集群管理软件 OpenPAI 简介

    OpenPAI:大规模人工智能集群管理平台 2018年5月22日,在微软举办的“新一代人工智能开放科研教育平台暨中国高校人工智能科研教育高峰论坛”上,微软亚洲研究院宣布,携手北京大学.中国科学技术大学 ...

  4. 运维利器-ClusterShell集群管理操作记录

    在运维实战中,如果有若干台数据库服务器,想对这些服务器进行同等动作,比如查看它们当前的即时负载情况,查看它们的主机名,分发文件等等,这个时候该怎么办?一个个登陆服务器去操作,太傻帽了!写个shell去 ...

  5. Clustershell集群管理

    在运维实战中,如果有若干台数据库服务器,想对这些服务器进行同等动作,比如查看它们当前的即时负载情况,查看它们的主机名,分发文件等等,这个时候该怎么办?一个个登陆服务器去操作,太傻帽了!写个shell去 ...

  6. 运维利器-ClusterShell集群管理

    在运维实战中,如果有若干台数据库服务器,想对这些服务器进行同等动作,比如查看它们当前的即时负载情况,查看它们的主机名,分发文件等等,这个时候该怎么办?一个个登陆服务器去操作,太傻帽了!写个shell去 ...

  7. 译:Google的大规模集群管理工具Borg(一)------ 用户视角的Borg特性

    概述 Google的Borg系统是一个集群管理工具,在它上面运行着成千上万的job,这些job来自许许多多不同的应用,并且跨越多个集群,而每个集群又由大量的机器构成. Borg通过组合准入控制,高效的 ...

  8. [转载] 一共81个,开源大数据处理工具汇总(下),包括日志收集系统/集群管理/RPC等

    原文: http://www.36dsj.com/archives/25042 接上一部分:一共81个,开源大数据处理工具汇总(上),第二部分主要收集整理的内容主要有日志收集系统.消息系统.分布式服务 ...

  9. 大规模集群管理工具Borg

    Google的大规模集群管理工具Borg 概述 Google的Borg系统是一个集群管理工具,在它上面运行着成千上万的job,这些job来自许许多多不同的应用,并且跨越多个集群,而每个集群又由大量的机 ...

随机推荐

  1. 一步一步安装SQL Server 2017

    快速开始: 下载安装文件:https://www.microsoft.com/en-us/sql-server/sql-server-downloads-free-trial 应该选择哪个版本? Th ...

  2. 安装Hive过程中报错:Unsupported major.minor version 52.0

    在安装hive的过程中,我觉得我是按照教程走的,但是在启动hive时还是报错了,错误如下 Exception in thread "main" java.lang.Unsuppor ...

  3. django中widget小部件

    1. 处理 input 的部件 TextInput    NumberInput EmailInput URLInput PasswordInput HiddenInput DateInput Dat ...

  4. python3 request模块初使用

    import requests class Interface_Request: def __init__(self,url,mobilephone,pwd): '''login参数初始化''' se ...

  5. 管理Android设备的唤醒状态

    当一个Android设备闲置时,首先它的屏幕将会变暗,然后关闭屏幕,最后关闭CPU. 这样可以防止设备的电量被迅速消耗殆尽.但是,有时候也会存在一些特例: Apps such as games or ...

  6. 认识vim 编辑器

    vim编辑器 vim编辑器的重点是光标的移动,模式切换,删除,查找,替换,复制,撤销命令的使用. vim 有三种模式: 命令模式,编辑模式,末行模式 vim打开方式: 语法: vim 文件路径 vim ...

  7. python飞机大战代码

    import pygame from pygame.locals import * from pygame.sprite import Sprite import random import time ...

  8. python学习:删除空白

    删除空白   删除尾部空白 确保字符串尾部没有空白,使用rstrip(); 删除字符串开头的空白,使用lstrip(); 同时删除字符串两端的空白,使用strip() 代码: >>> ...

  9. php 识别二维码(转载)

    近段需要写一个通过PHP来识别二维码的功能,在网上查了很久才解决问题.以此来记录下来解决问题的方法. 最开始找的方法是一个叫 php-zbarcode 的扩展,自己照着网上的安装步骤安装了 Image ...

  10. 剑指offer——python【第39题】平衡二叉树

    题目描述 输入一棵二叉树,判断该二叉树是否是平衡二叉树.   解题思路 平衡二叉树首先是二叉搜索树,且它每个节点的左子树和右子树高度差至多等于1:只要从根节点,依次递归判断每个节点是否满足如上条件即可 ...