轻量级集群管理软件-Ansible
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的更多相关文章
- 轻量级集群管理软件-ClusterShell
如果集群数量不多的话,选择一个轻量级的集群管理软件就显得非常有必要了.ClusterShell就是这样一种小的集群管理工具,原理是利用ssh,可以说是Linux系统下非常好用的运维工具 cluste ...
- 集群管理软件clustershell
一.简介 1.安装方便.一条指令就能轻松安装. 2.配置方便.很多集群管理软件都需要在所有的服务器上都安装软件,而且还要进行很多的连接操作,clustershell就相当的方便了,仅仅需要所有机器能够 ...
- 深度学习GPU集群管理软件 OpenPAI 简介
OpenPAI:大规模人工智能集群管理平台 2018年5月22日,在微软举办的“新一代人工智能开放科研教育平台暨中国高校人工智能科研教育高峰论坛”上,微软亚洲研究院宣布,携手北京大学.中国科学技术大学 ...
- 运维利器-ClusterShell集群管理操作记录
在运维实战中,如果有若干台数据库服务器,想对这些服务器进行同等动作,比如查看它们当前的即时负载情况,查看它们的主机名,分发文件等等,这个时候该怎么办?一个个登陆服务器去操作,太傻帽了!写个shell去 ...
- Clustershell集群管理
在运维实战中,如果有若干台数据库服务器,想对这些服务器进行同等动作,比如查看它们当前的即时负载情况,查看它们的主机名,分发文件等等,这个时候该怎么办?一个个登陆服务器去操作,太傻帽了!写个shell去 ...
- 运维利器-ClusterShell集群管理
在运维实战中,如果有若干台数据库服务器,想对这些服务器进行同等动作,比如查看它们当前的即时负载情况,查看它们的主机名,分发文件等等,这个时候该怎么办?一个个登陆服务器去操作,太傻帽了!写个shell去 ...
- 译:Google的大规模集群管理工具Borg(一)------ 用户视角的Borg特性
概述 Google的Borg系统是一个集群管理工具,在它上面运行着成千上万的job,这些job来自许许多多不同的应用,并且跨越多个集群,而每个集群又由大量的机器构成. Borg通过组合准入控制,高效的 ...
- [转载] 一共81个,开源大数据处理工具汇总(下),包括日志收集系统/集群管理/RPC等
原文: http://www.36dsj.com/archives/25042 接上一部分:一共81个,开源大数据处理工具汇总(上),第二部分主要收集整理的内容主要有日志收集系统.消息系统.分布式服务 ...
- 大规模集群管理工具Borg
Google的大规模集群管理工具Borg 概述 Google的Borg系统是一个集群管理工具,在它上面运行着成千上万的job,这些job来自许许多多不同的应用,并且跨越多个集群,而每个集群又由大量的机 ...
随机推荐
- 一步一步安装SQL Server 2017
快速开始: 下载安装文件:https://www.microsoft.com/en-us/sql-server/sql-server-downloads-free-trial 应该选择哪个版本? Th ...
- gdb解决字符串打印果断措施
在我们进行gdb动态调试的时候,很多时间可能会遇到无法完全显示的情况 关于这种方法网上已经有解决方法 https://blog.csdn.net/shuizhizhiyin/article/detai ...
- 跑的飞快的dinic
orz kczno1 目前还是不知道怎么卡,也不会证明复杂度是正确的 其实我感觉卡不了
- python3 request模块初使用
import requests class Interface_Request: def __init__(self,url,mobilephone,pwd): '''login参数初始化''' se ...
- DWM1000 三基站一标签定位HEX
蓝点DWM1000 模块已经打样测试完毕,有兴趣的可以申请购买了,更多信息参见 蓝点论坛 HEX 下载链接参见论坛:http://bphero.com.cn/forum.php?mod=viewthr ...
- Thinkphp3.2.3加载外部类并调用类里面的方法 获取token
例如:加载七牛上传类(thinkphp自带的) $qiniu = new \Think\Upload\Driver\Qiniu\QiniuStorage($setting['driverConfig' ...
- NOIP-质因数分解
题目描述 已知正整数n是两个不同的质数的乘积,试求出较大的那个质数. 输入描述: 输入只有一行,包含一个正整数n. 输出描述: 输出只有一行,包含一个正整数p,即较大的那个质数. #include&l ...
- centos7安装nginx-1.13.6 新手入门,图文解析
系统环境 操作系统:64位CentOS Linux release 7.2.1511 (Core) 安装nginx依赖包 [root@localhost ~]# yum install gcc-c++ ...
- Django中Q搜索的简单应用
本节涉及: 1.Q搜索在前后端的设计 2.Django中Queryset对象的序列化(由后端扔给前端的数据必然会经过序列化) 3.前端动态地构造表格以便显示(动态创建DOM对象) 思路: 用户通过前端 ...
- mobile_视口
document.documentElement.clientWidth 不包含滚动条 window.innerWidth ...