服务器/网络/虚拟化/云平台自动化运维-ansible
ansible与netconf的对比
首先明确一个概念,netconf是协议,ansible是python编写的工具
netconf
使用YANG建模,XML进行数据填充,使用netconf协议进行传输,主要用于控制器南向接口使用,各主流厂商有自定义的YANG模型,可在官网进行下载,不过一些国内厂商对YANG的支持性并不好
https://datatracker.ietf.org/doc/html/rfc6020,公共YANG模型的RFC文档,很有阅读必要
python中主要使用ncclient模块,可以参考之前的一篇文章https://www.cnblogs.com/darkchen/p/15248377.html
ansible
功能更为广泛,可以用于网络自动化,云基础架构自动化,虚拟化和容器自动化
日常用模块底层使用python的paramiko模块通过ssh协议进行数据传输,适配性较好,(当然也可以自定义netconf协议模块调用ansible提供的api进行批量操作)对于不同的网络设备系统可以适配不同的
模块用于提交、查询配置,一些国产设备没有对应的模块,需要自己编写,主要是一些正则的使用,匹配不同的提示符做不同的交互,可以参考华为或思科的进行编写
也有基于各软件厂商所提供的API的模块,如AWS的EC2,zabbix所提供的API等
ansible安装
- 使用apt/yum 安装
yum install epel-release&&ansible -y
- 使用pip安装
pip3 install ansible
两者的区别
使用apt/yum安装后只有一些基础的模块,如command、shell、copy、file、cron等操作linux系统的模块,其他设备厂商模块需要手动下载安装,华为的ansible 模块提供的下载链接更新在n年前,一堆bug不能使用
使用pip安装会有很多各家厂商自定义的模块,如AWS的EC2、S3,zabbix相关模块,cisco的nxos、ios,juniper的junos等,但是没有ansible的配置文件,主机清单等配置,需要自定义
所以为了节省时间,我们可以两者都进行安装-_-
配置文件
/etc/ansible/
├── ansible.cfg
├── hosts
└── roles
配置文件常见参数如下,默认全部注释掉,调用相应模块是会依次查找环境变量
inventory = /etc/ansible/hosts #这个参数表示资源清单inventory文件的位置
library = /usr/share/ansible #指向存放Ansible模块的目录,支持多个目录方式,只要用冒号(:)隔开就可以
forks = 5 #并发连接数
sudo_user = root #设置默认执行命令的用户
remote_port = 22 #指定连接被管节点的管理端口,默认为22端口,建议修改,能够更加安全
host_key_checking = False #设置是否检查SSH主机的密钥,值为True/False。关闭后第一次连接不会提示配置实例
timeout = 60 #设置SSH连接的超时时间,单位为秒
log_path = /var/log/ansible.log #指定一个存储ansible日志的文件(默认不记录日志)
主机清单,可以定义单个主机也可以定义主机组,两者都可以分别定义变量供playbook使用,示例:
[rs]
10.0.3.105
[rs:vars]
ansible_connection=network_cli
ansible_network_os=ce
ansible_user=test
ansible_ssh_pass = 123456789!@a
[server]
12.5.21.8 ansible_ssh_user=ubuntu ansible_ssh_port=22
12.6.12.3
4.51.15.1
3.20.9.2
13.0.3.1 ansible_ssh_user=test
[server:vars]
ansible_ssh_user = root
ansible_ssh_port = 233
host_name = 1.1.1.1
apt/yum安装方式,模块目录,只有以下模块,里面有个test.py是自定义的测试模块
pip安装方式,截取一小部分
可以使用ansible-doc -l 查看所有模块
如,查看华为相关模块,其中左侧一列是模块路径右侧一列是描述
ansible-doc -l | grep HUAWEI
查看模块使用帮助
ansible的使用方式
常用以下三种方式
- ansible <host-pattern> [-f forks] [-m module_name] [-a args] 直接使用相应模块,传入参数,作用与host或group,该方式比较简单,在后续实例时展示,不再展开
- ansible-playbook 对于一些复杂的操作我们需要定义playbook
- roles 对于一些需要复用的操作,定义多个playbook费时又费力,我们可以通过定义roles来对playbook进行灵活的组合调用,需要定义固定目录与文件,后续展开
playbook的格式
Ansible Playbooks 提供了一个可重复、可重用、简单的配置管理和多机部署系统,非常适合部署复杂的应用程序。Playbook 以 YAML 格式表示
示例
---
- name: Update web servers
hosts: webservers
remote_user: root
gather_facts: True
vars:
listen_port: 8800
tasks:
- name: Ensure apache is at the latest version
yum:
name: httpd
state: latest
when: ansible_lsb.id == 'Centos'
apt:
name: httpd
state: latest
when: ansible_lsb.id == 'Ubuntu'
- name: Write the apache config file
template:
src: /srv/httpd.j2
dest: /etc/httpd.conf
notify: reload
handlers:
- name: reload
service:
name: httpd
state: restarted
tasks:
- name: unstall web packages
yum: name={{ item }} state=absent
with_items:
- httpd
- php
- php-mysql
以上示例展示了playbook的基本格式和两个关键字的使用when和with,前者是判断语句后者是循环
示例中定义的变量listen_port提供给httpd,j2配置文件使用,配置文件使用模板语句其中listen的值定义为{{ listen_port }},playbook中定义的变量会自动填充,模板使用Jinja2语法,同Django
也可以在执行ansible-playbook 语句时使用 -e listen=8800传入变量
定义变量的几种方式
- 内置变量直接调用
facts组件,ansible在运行模块是默认会调用facts组件来获取远程系统的一些基础信息,如系统版本、cpu内存磁盘使用率,网卡信息等,这些信息会包装在JSON格式的数据结构中,由一个个键值对构成,键就是变量的名字,可以在playbook中直接调用,如上述示例中的gather_facts=True选项,在该playbook中我们可以直接调用ansible_lsb.id变量来获取系统类型,当然如果不需要这些变量值可以设为False,可以极大提高命令执行速度
可以使用setup模块来调用facts组件来来获取所有的系统信息
- Inventory 文件中定义
在主机文件中定义变量,可以在为host单独定义变量,也可以定义主机组变量,示例如下
[rs]
10.0.3.105
[rs:vars]
ansible_connection=network_cli
ansible_network_os=ce
ansible_user=test
ansible_ssh_pass = 123456
[server]
123.58.201.8 ansible_ssh_user=ubuntu ansible_ssh_port=22
162.62.132.3
4.1.5.1
4.20.9.2
13.0.3.1 ansible_ssh_user=dark
[server:vars]
ansible_ssh_user = root
ansible_ssh_port = 2233
host_name = 1.1.1.1
- playbook中定义
在playbook中定义又有多种方式
1. 使用vars定义,该方式定义的变量只能在本play使用不能跨play使用,如下示例
---
- hosts: localhost
remote_user: root
gather_facts: no
vars:
testvar1: tv1
tasks:
- debug:
msg: "{{testvar1}}"
- hosts: localhost
remote_user: root
tasks:
- debug:
msg: "{{testvar1}}"
我们来运行看下
dark@dark:~/python/ansible$ ansible-playbook test.yml PLAY [localhost] ***************************************************************************************************************************************** TASK [debug] *********************************************************************************************************************************************
ok: [localhost] => {
"msg": "tv1"
} PLAY [localhost] ***************************************************************************************************************************************** TASK [Gathering Facts] ***********************************************************************************************************************************
ok: [localhost] TASK [debug] *********************************************************************************************************************************************
fatal: [localhost]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'testvar1' is undefined\n\nThe error appears to be in '/home/dark/python/ansible/test.yml': line 90, column 5, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n tasks:\n - debug:\n ^ here\n"} PLAY RECAP ***********************************************************************************************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
可以看到The error was: 'testvar1' is undefined这个报错信息,testvar1没有定义
2. 使用set_fact来设置变量,可以跨play使用,如下示例
- hosts: localhost
remote_user: root
gather_facts: no
tasks:
- set_fact:
testvar1: tv1
testvar2: tv2
- debug:
msg: "{{testvar1}} ----- {{testvar2}}"
- hosts: localhost
remote_user: root
tasks:
- name: other play get testvar2
debug:
msg: "{{testvar2}}"
- name: other play get testvar1
debug:
msg: "{{testvar1}}"
执行下
dark@dark:~/python/ansible$ ansible-playbook test.yml PLAY [localhost] ***************************************************************************************************************************************** TASK [set_fact] ******************************************************************************************************************************************
ok: [localhost] TASK [debug] *********************************************************************************************************************************************
ok: [localhost] => {
"msg": "tv1 ----- tv2"
} PLAY [localhost] ***************************************************************************************************************************************** TASK [Gathering Facts] ***********************************************************************************************************************************
ok: [localhost] TASK [other play get testvar2] ***************************************************************************************************************************
ok: [localhost] => {
"msg": "tv2"
} TASK [other play get testvar1] ***************************************************************************************************************************
ok: [localhost] => {
"msg": "tv1"
} PLAY RECAP ***********************************************************************************************************************************************
localhost : ok=5 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
3. 使用register注册变量,该变量的值是模块的return值,如下示例
- hosts: localhost
remote_user: root
gather_facts: no
tasks:
- set_fact:
testvar1: tv1
testvar2: tv2
- shell: "echo tv3"
register: testvar3
- debug:
msg: "{{testvar1}} ----- {{testvar2}}"
- hosts: localhost
remote_user: root
tasks:
- name: other play get testvar3
debug:
msg: "{{testvar3.stdout}}"
- name: other play get testvar2
debug:
msg: "{{testvar2}}"
- name: other play get testvar1
debug:
msg: "{{testvar1}}"
运行看下结果
dark@dark:~/python/ansible$ ansible-playbook test.yml PLAY [localhost] ***************************************************************************************************************************************** TASK [set_fact] ******************************************************************************************************************************************
ok: [localhost] TASK [shell] *********************************************************************************************************************************************
changed: [localhost] TASK [debug] *********************************************************************************************************************************************
ok: [localhost] => {
"msg": "tv1 ----- tv2"
} PLAY [localhost] ***************************************************************************************************************************************** TASK [Gathering Facts] ***********************************************************************************************************************************
ok: [localhost] TASK [other play get testvar3] ***************************************************************************************************************************
ok: [localhost] => {
"msg": "tv3"
} TASK [other play get testvar2] ***************************************************************************************************************************
ok: [localhost] => {
"msg": "tv2"
} TASK [other play get testvar1] ***************************************************************************************************************************
ok: [localhost] => {
"msg": "tv1"
} PLAY RECAP ***********************************************************************************************************************************************
localhost : ok=7 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
注册变量接收的是模块执行后的return值,是json格式,我们自定义变量如果需要return时也需要dumps成json格式输出,否则ansible无法解析会报错
- 执行语句时传入
执行时使用-e 传参,没什么好解释的
- roles vars/main.yml文件中定义
在写roles时再做介绍
ansible常用模块示例
主机联通性测试
使用ping模块来测试主机连通性
dark@dark:~$ ansible zb -m ping
49.23.3.9 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
1.15.9.2 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
apt 软件安装
常用参数
allow_unauthenticated= yes/no #如果无法验证包,则忽略。这对于管理自己的 apt-key 设置的引导环境很有用。
autoclean= yes/no #如果yes,则清除无法再下载的已检索包文件的本地存储库。
deb= #远程计算机上 .deb 包的路径。如果路径中有 ://,ansible 将在安装前尝试下载 deb
dpkg_options= (default force-confdef,force-confold) #将 dpkg 选项添加到 apt 命令。默认为 '-o "Dpkg::Options::=--force-confdef" -o "Dpkg::Options::=--force-confold"'选项应以逗号分隔的列表形式提供
name= #包名称,如foo,或带有版本的包说明符,如foo=1.0。还支持名称通配符 (fnmatch)apt*和版本通配符,不支持隐式正则表达式匹配
state= latest/absent/present/build-dep(default present)#指示所需的包状态。latest确保安装了最新版本。build-dep确保安装包构建依赖项。
update_cache= yes/no #运行相当于apt-get update之前的操作。可以作为软件包安装的一部分运行,也可以作为单独的步骤运行。
upgrade= no/yes/safe/full/dist #yes或safe,执行 aptitude 安全升级。full,则执行 aptitude 全面升级。如果是 dist,则执行 apt-get dist-upgrade。注意:这不会升级特定的包,为此使用 state=latest。注意:从 2.4 开始,如果 aptitude 不存在,则使用 apt-get 作为备用。
示例:
dark@dark:~$ ansible zb -m apt -a 'name=hping3 state=present'
49.23.3.9 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"cache_update_time": 1651712595,
"cache_updated": false,
"changed": true,
"stderr": "",
"stderr_lines": [],
"stdout": "Reading package lists...\nBuilding dependency tree...\nReading state information...\nThe following packages were automatically installed and are no longer required:\n apache2-bin apache2-data apache2-utils fontconfig hicolor-icon-theme libapr1\n libaprutil1 libaprutil1-dbd-sqlite3 libaprutil1-ldap libatk1.0-0\n libatk1.0-data libavahi-client3 libavahi-common-data libavahi-common3\n libcairo2 libcups2 libdatrie1 libgdk-pixbuf2.0-0 libgdk-pixbuf2.0-common\n libgraphite2-3 libgtk2.0-0 libgtk2.0-bin libgtk2.0-common libharfbuzz0b\n libjbig0 libjpeg-turbo8 libjpeg8 liblua5.1-0 libpango-1.0-0\n libpangocairo-1.0-0 libpangoft2-1.0-0 libpixman-1-0 libthai-data libthai0\n libtiff5 libxcb-render0 libxcb-shm0 libxcursor1 ssl-cert\nUse 'apt autoremove' to remove them.\nThe following NEW packages will be installed:\n hping3\n0 upgraded, 1 newly installed, 0 to remove and 223 not upgraded.\nNeed to get 107 kB of archives.\nAfter this operation, 284 kB of additional disk space will be used.\nGet:1 http://cn.archive.ubuntu.com/ubuntu xenial/universe amd64 hping3 amd64 3.a2.ds2-7 [107 kB]\nFetched 107 kB in 3s (33.0 kB/s)\nSelecting previously unselected package hping3.\r\n(Reading database ... \r(Reading database ... 5%\r(Reading database ... 10%\r(Reading database ... 15%\r(Reading database ... 20%\r(Reading database ... 25%\r(Reading database ... 30%\r(Reading database ... 35%\r(Reading database ... 40%\r(Reading database ... 45%\r(Reading database ... 50%\r(Reading database ... 55%\r(Reading database ... 60%\r(Reading database ... 65%\r(Reading database ... 70%\r(Reading database ... 75%\r(Reading database ... 80%\r(Reading database ... 85%\r(Reading database ... 90%\r(Reading database ... 95%\r(Reading database ... 100%\r(Reading database ... 109472 files and directories currently installed.)\r\nPreparing to unpack .../hping3_3.a2.ds2-7_amd64.deb ...\r\nUnpacking hping3 (3.a2.ds2-7) ...\r\nProcessing triggers for man-db (2.7.5-1) ...\r\nSetting up hping3 (3.a2.ds2-7) ...\r\n",
"stdout_lines": [
"Reading package lists...",
"Building dependency tree...",
"Reading state information...",
"The following packages were automatically installed and are no longer required:",
" apache2-bin apache2-data apache2-utils fontconfig hicolor-icon-theme libapr1",
" libaprutil1 libaprutil1-dbd-sqlite3 libaprutil1-ldap libatk1.0-0",
" libatk1.0-data libavahi-client3 libavahi-common-data libavahi-common3",
" libcairo2 libcups2 libdatrie1 libgdk-pixbuf2.0-0 libgdk-pixbuf2.0-common",
" libgraphite2-3 libgtk2.0-0 libgtk2.0-bin libgtk2.0-common libharfbuzz0b",
" libjbig0 libjpeg-turbo8 libjpeg8 liblua5.1-0 libpango-1.0-0",
" libpangocairo-1.0-0 libpangoft2-1.0-0 libpixman-1-0 libthai-data libthai0",
" libtiff5 libxcb-render0 libxcb-shm0 libxcursor1 ssl-cert",
"Use 'apt autoremove' to remove them.",
"The following NEW packages will be installed:",
" hping3",
"0 upgraded, 1 newly installed, 0 to remove and 223 not upgraded.",
"Need to get 107 kB of archives.",
"After this operation, 284 kB of additional disk space will be used.",
"Get:1 http://cn.archive.ubuntu.com/ubuntu xenial/universe amd64 hping3 amd64 3.a2.ds2-7 [107 kB]",
"Fetched 107 kB in 3s (33.0 kB/s)",
"Selecting previously unselected package hping3.",
"(Reading database ... ",
"(Reading database ... 5%",
........."(Reading database ... 100%",
"(Reading database ... 109472 files and directories currently installed.)",
"Preparing to unpack .../hping3_3.a2.ds2-7_amd64.deb ...",
"Unpacking hping3 (3.a2.ds2-7) ...",
"Processing triggers for man-db (2.7.5-1) ...",
"Setting up hping3 (3.a2.ds2-7) ..."
]
}
1.15.9.2 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"cache_update_time": 1651695647,
"cache_updated": false,
"changed": true,
"stderr": "",
"stderr_lines": [],
"stdout": "Reading package lists...\nBuilding dependency tree...\nReading state information...\nThe following NEW packages will be installed:\n hping3\n0 upgraded, 1 newly installed, 0 to remove and 234 not upgraded.\nNeed to get 107 kB of archives.\nAfter this operation, 284 kB of additional disk space will be used.\nGet:1 http://mirrors.tencentyun.com/ubuntu xenial/universe amd64 hping3 amd64 3.a2.ds2-7 [107 kB]\nFetched 107 kB in 0s (3207 kB/s)\nSelecting previously unselected package hping3.\r\n(Reading database ... \r(Reading database ... 5%\r(Reading database ... 10%\r(Reading database ... 15%\r(Reading database ... 20%\r(Reading database ... 25%\r(Reading database ... 30%\r(Reading database ... 35%\r(Reading database ... 40%\r(Reading database ... 45%\r(Reading database ... 50%\r(Reading database ... 55%\r(Reading database ... 60%\r(Reading database ... 65%\r(Reading database ... 70%\r(Reading database ... 75%\r(Reading database ... 80%\r(Reading database ... 85%\r(Reading database ... 90%\r(Reading database ... 95%\r(Reading database ... 100%\r(Reading database ... 108213 files and directories currently installed.)\r\nPreparing to unpack .../hping3_3.a2.ds2-7_amd64.deb ...\r\nUnpacking hping3 (3.a2.ds2-7) ...\r\nProcessing triggers for man-db (2.7.5-1) ...\r\nSetting up hping3 (3.a2.ds2-7) ...\r\n",
"stdout_lines": [
"Reading package lists...",
"Building dependency tree...",
"Reading state information...",
"The following NEW packages will be installed:",
" hping3",
"0 upgraded, 1 newly installed, 0 to remove and 234 not upgraded.",
"Need to get 107 kB of archives.",
"After this operation, 284 kB of additional disk space will be used.",
"Get:1 http://mirrors.tencentyun.com/ubuntu xenial/universe amd64 hping3 amd64 3.a2.ds2-7 [107 kB]",
"Fetched 107 kB in 0s (3207 kB/s)",
"Selecting previously unselected package hping3.",
"(Reading database ... ",
"(Reading database ... 5%",
..............."(Reading database ... 100%",
"(Reading database ... 108213 files and directories currently installed.)",
"Preparing to unpack .../hping3_3.a2.ds2-7_amd64.deb ...",
"Unpacking hping3 (3.a2.ds2-7) ...",
"Processing triggers for man-db (2.7.5-1) ...",
"Setting up hping3 (3.a2.ds2-7) ..."
]
}
playbook形式
---
- hosts: {{ group }}
remote_user: root
tasks:
- name: install hping3 on centos
yum: name=hping3 state=present
when: ansible_lsb.id == 'Centos'
- name: install hping3 on ubuntu
apt: name=hping3 state=present
when: ansible_lsb.id == 'Ubuntu'
执行
dark@dark:~/python/ansible$ ansible-playbook hping3.yml PLAY [zb] ************************************************************************************************************************************************ TASK [Gathering Facts] ***********************************************************************************************************************************
ok: [49.2.3.9]
ok: [1.15.9.2] TASK [install hping3 on centos] **************************************************************************************************************************
skipping: [49.2.3.9]
skipping: [1.15.9.2] TASK [install hping3 on ubuntu] **************************************************************************************************************************
changed: [49.2.3.9]
changed: [1.15.9.2] PLAY RECAP ***********************************************************************************************************************************************
1.15.9.2 : ok=2 changed=1 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
49.2.3.9 : ok=2 changed=1 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
command 远程执行命令
概要
- 该
command
模块采用命令名称,后跟以空格分隔的参数列表。 - 给定的命令将在所有选定的节点上执行。它不会通过 shell 处理,因此变量
$HOME
和操作,如"<"
,">"
,和将不起作用(如果需要这些功能,请使用 shell 模块"|"
) - 对于 Windows 目标,使用win_command模块
- 该
Options:
chdir 在执行命令前先切换至该目录
free_form 所执行的语句,必须包含,但是并没有这个参数名字,所需执行的命令直接跟在模块后,在使用ad-hoc命令时一般用-a代替
creates 一个文件名,用来做判断,当该文件存在时不执行命令
removes 同上取反
示例:
dark@dark:/usr/share/ansible$ ansible zb -m command -a 'ls'
49.2.3.9 | CHANGED | rc=0 >>
dark
dos
l2tp
monitor
ping_log
Python-3.6.3
Python-3.6.3.tgz
root@1.15.97.240
tra
udping.py
zabbix-release_3.2-1+xenial_all.deb
1.15.9.2 | CHANGED | rc=0 >>
ping_log
tcping.py
tcploss.py
udp
udping.py
vpn
zabbix-release_3.2-1+xenial_all.deb
chdir 参数
49.2.3.9 | CHANGED | rc=0 >>
bin
darkping
monitor
myping
zabbix_agentd.conf
zabbix_agentd.d
1.15.9.2 | CHANGED | rc=0 >>
bin
darkping
monitor
myping
zabbix_agentd.conf
zabbix_agentd.d
creates与removes参数
dark@dark:/usr/share/ansible$ ansible zb -m command -a 'chdir=/etc/zabbix creates=/root/dos ls'
1.15.9.2 | CHANGED | rc=0 >>
bin
darkping
monitor
myping
zabbix_agentd.conf
zabbix_agentd.d
49.2.3.9 | SUCCESS | rc=0 >>
skipped, since /root/dos existsDid not run command since '/root/dos' exists dark@dark:/usr/share/ansible$ ansible zb -m command -a 'chdir=/etc/zabbix removes=/root/dos ls'
49.2.3.9 | CHANGED | rc=0 >>
bin
darkping
monitor
myping
zabbix_agentd.conf
zabbix_agentd.d
1.15.9.2 | SUCCESS | rc=0 >>
skipped, since /root/dos does not existDid not run command since '/root/dos' does not exist
playbook文件
---
- hosts: zb
remote_user: root
gather_facts: False
tasks:
- name: file list
command: ls
chdir=/etc/zabbix
creates=/root/dos
register: var
- debug:
msg: '{{var.stdout_lines}}'
运行下
dark@dark:~/python/ansible$ ansible-playbook ls.yml PLAY [zb] ************************************************************************************************************************************************ TASK [file list] *****************************************************************************************************************************************
changed: [1.15.9.2]
ok: [49.2.3.9] TASK [debug] *********************************************************************************************************************************************
ok: [49.2.3.9] => {
"msg": [
"skipped, since /root/dos exists"
]
}
ok: [1.15.9.2] => {
"msg": [
"bin",
"darkping",
"monitor",
"myping",
"zabbix_agentd.conf",
"zabbix_agentd.d"
]
} PLAY RECAP ***********************************************************************************************************************************************
1.15.9.2 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
49.2.3.9 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
shell
选项同command,介绍command时说过它的局限性,例如不会执行命令中的>> | 等shell字符,用法同command,简单示例如下
dark@dark:~/python/ansible$ ansible zb -m shell -a 'more udping.py >> AnsibleShell'
49.2.3.9 | CHANGED | rc=0 >> 1.15.9.2 | CHANGED | rc=0 >>
dark@dark:~/python/ansible$ ansible zb -m shell -a 'ls AnsibleShell'
49.2.3.9 | CHANGED | rc=0 >>
AnsibleShell
1.15.9.2 | CHANGED | rc=0 >>
AnsibleShell
copy
复制本地或远程主机文件至远程主机的某个位置
选项
backup: yes/no 非必选项,当文件发生改变时创建一个包含时间戳的备份文件
content: 非必选项,当不使用src指定文件时,可以使用该选项来指定文件的值
dest: 必选项,远程主机的决定路径,如果src是一个目录dest也必须是目录,如果目录不存在则会创建,但如果src是文件,dest的目录不存在会报错
directory_mode: 非必选项,对目录设置权限,默认是系统默认权限
src: 非必选项,要复制到远程服务器的文件的本地路径;可以是绝对的或相对的。如果 path 是一个目录,它会被递归复制。在这种情况下,如果路径以“/”结尾,则仅将该目录的内部内容复制到目标。否则,如果它不以“/”结尾,则复制包含所有内容的目录本身。类似于 Rsync
remote_src: yes/no 如果是yes,会在远程主机上搜索文件,不支持递归
force: yes/no 默认是yes,当内容与源不同时,它将替换远程文件。如果否,则仅当目标不存在时才会传输文件
mode: 设置权限,八进制数(例如 0644)。省略前导零可能会产生意想不到的结果。从版本 1.8 开始,可以将模式指定为符号模式(例如,u+rwx 或 u=rw,g=r,o=r)
示例
复制文件
dark@dark:~/python/ansible$ ansible zb -m copy -a 'src=~/python/ansible/js dest=/root/ansible/'
49.2.3.9 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"checksum": "31d71223ba89a9e220e7dca3ada0e4c3e000fb7f",
"dest": "/root/ansible/js",
"gid": 0,
"group": "root",
"md5sum": "11285d0c79e95363f15486ed138c1d0f",
"mode": "0644",
"owner": "root",
"size": 34170,
"src": "/root/.ansible/tmp/ansible-tmp-1651900741.852927-748-95739589553200/source",
"state": "file",
"uid": 0
}
1.15.9.2 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"checksum": "31d71223ba89a9e220e7dca3ada0e4c3e000fb7f",
"dest": "/root/ansible/js",
"gid": 0,
"group": "root",
"md5sum": "11285d0c79e95363f15486ed138c1d0f",
"mode": "0644",
"owner": "root",
"size": 34170,
"src": "/root/.ansible/tmp/ansible-tmp-1651900741.896568-750-21994204903907/source",
"state": "file",
"uid": 0
}
不指定src,直接给定文件内容,并设置权限和backup选项
dark@dark:~/python/ansible$ ansible zb -m copy -a "content='this is ansible copy test' dest=/root/ansible/ansible_copy mode=0777"
49.2.3.9 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"checksum": "6decc680ae286b0252015da0c2ae02a8845b58f5",
"dest": "/root/ansible/ansible_copy",
"gid": 0,
"group": "root",
"mode": "0777",
"owner": "root",
"path": "/root/ansible/ansible_copy",
"size": 25,
"state": "file",
"uid": 0
}
1.15.9.2 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"checksum": "6decc680ae286b0252015da0c2ae02a8845b58f5",
"dest": "/root/ansible/ansible_copy",
"gid": 0,
"group": "root",
"mode": "0777",
"owner": "root",
"path": "/root/ansible/ansible_copy",
"size": 25,
"state": "file",
"uid": 0
}
dark@dark:~/python/ansible$ ansible zb -m copy -a "content='this is other ansible copy test' dest=/root/ansible/ansible_copy mode=0777 backup=yes"
49.2.3.9 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"backup_file": "/root/ansible/ansible_copy.24110.2022-05-07@13:25:15~",
"changed": true,
"checksum": "6163d92273dc839ef52cbcecccebb686fa96683e",
"dest": "/root/ansible/ansible_copy",
"gid": 0,
"group": "root",
"md5sum": "ecaf90417dee6b6caa57e48633fb5c03",
"mode": "0777",
"owner": "root",
"size": 31,
"src": "/root/.ansible/tmp/ansible-tmp-1651901114.3149083-8252-129355433903495/source",
"state": "file",
"uid": 0
}
1.15.9.2 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"backup_file": "/root/ansible/ansible_copy.25706.2022-05-07@13:25:16~",
"changed": true,
"checksum": "6163d92273dc839ef52cbcecccebb686fa96683e",
"dest": "/root/ansible/ansible_copy",
"gid": 0,
"group": "root",
"md5sum": "ecaf90417dee6b6caa57e48633fb5c03",
"mode": "0777",
"owner": "root",
"size": 31,
"src": "/root/.ansible/tmp/ansible-tmp-1651901114.3310552-8255-276726218449153/source",
"state": "file",
"uid": 0
}
dark@dark:~/python/ansible$ ansible zb -m command -a "ls /root/ansible"
49.2.3.9 | CHANGED | rc=0 >>
ansible_copy
ansible_copy.24110.2022-05-07@13:25:15~
js
1.15.9.2 | CHANGED | rc=0 >>
ansible_copy
ansible_copy.25706.2022-05-07@13:25:16~
js
template Jinja2 模板
用法同copy,不同处在于模块文件在经由template模块处理后会解析jinja2语法,替换成处理后的字符串再copy至远程主机
示例
#ansible_template.j2
this is ansible_template file at {{ time }} dark@dark:~/python/ansible$ ansible zb -m template -a "src=~/python/ansible/ansible_template.j2 dest=/root/ansible/ansible_template.conf" -e time=2022-05-07
49.2.3.9 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"checksum": "28f9535c00818bcf957494bf6086c1ebfe1c5c31",
"dest": "/root/ansible/ansible_template.conf",
"gid": 0,
"group": "root",
"md5sum": "e1eb156f348394a92c0fcb3f4fdbb30d",
"mode": "0644",
"owner": "root",
"size": 43,
"src": "/root/.ansible/tmp/ansible-tmp-1651909317.822977-30778-6091173137916/source",
"state": "file",
"uid": 0
}
1.15.9.2 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"checksum": "28f9535c00818bcf957494bf6086c1ebfe1c5c31",
"dest": "/root/ansible/ansible_template.conf",
"gid": 0,
"group": "root",
"md5sum": "e1eb156f348394a92c0fcb3f4fdbb30d",
"mode": "0644",
"owner": "root",
"size": 43,
"src": "/root/.ansible/tmp/ansible-tmp-1651909317.8367376-30780-231793051547939/source",
"state": "file",
"uid": 0
}
dark@dark:~/python/ansible$ ansible zb -m command -a "more /root/ansible/ansible_template.conf"
49.2.3.9 | CHANGED | rc=0 >>
this is ansible_template file at 2022-05-07
1.15.9.2 | CHANGED | rc=0 >>
this is ansible_template file at 2022-05-07
palybook
---
- hosts: server
remote_user: root
become: yes
become_method: sudo
become_user: root
tasks:
- name: install {{ rpmname }} on centos
yum: name={{ rpmname }} state=present
when: ansible_lsb.id == 'Centos'
- name: install {{ rpmname }} on ubuntu
apt: name={{ rpmname }} state=present
when: ansible_lsb.id == 'Ubuntu'
- name: copy {{ rpmname }}.conf
template: src={{ j2 }} dest={{ conf }}
notify: reload
tags: reload zabbix-agent
- name: start {{ rpmname }} service
service: name={{ rpmname }} state=started
tags: start {{ rpmname }}
handlers:
- name: reload
service: name={{ rpmname }} state=restarted
以上做了一个简单的示例,模板文件可以调用各种方式定义定义的变量
setup
该模块由 playbook 自动调用,以收集有关可在 playbook 中使用的远程主机的有用变量。它也可以直接通过/usr/bin/ansible
检查主机可用的变量来执行。
Windows 目标也支持此模块
可以使用filter来做结果的过滤
示例
dark@dark:~/python/ansible$ ansible localhost -m setup -a 'filter=*mem*' --tree ./
localhost | SUCCESS => {
"ansible_facts": {
"ansible_memfree_mb": 178,
"ansible_memory_mb": {
"nocache": {
"free": 2525,
"used": 1389
},
"real": {
"free": 178,
"total": 3914,
"used": 3736
},
"swap": {
"cached": 0,
"free": 3899,
"total": 3913,
"used": 14
}
},
"ansible_memtotal_mb": 3914
},
"changed": false
} dark@dark:~/python/ansible$ ansible localhost -m setup -a 'filter=ansible_interfaces'
localhost | SUCCESS => {
"ansible_facts": {
"ansible_interfaces": [
"eno1",
"enp1s0f0",
"docker0",
"veth0789055",
"br0",
"virbr0",
"eno2",
"enp1s0f2",
"enp1s0f3",
"enp1s0f1",
"virbr0-nic",
"lo"
]
},
"changed": false
}
dark@dark:~/python/ansible$ more localhost
{"ansible_facts": {"ansible_memfree_mb": 178, "ansible_memory_mb": {"nocache": {"free": 2525, "used": 1389}, "real": {"free": 178, "total": 3914, "used":
3736}, "swap": {"cached": 0, "free": 3899, "total": 3913, "used": 14}}, "ansible_memtotal_mb": 3914}, "changed": false}
可以使用--tree来保存json格式的结果
cli_command
选项
command: 需要执行的命令
示例
dark@dark:/etc/ansible$ ansible rs -m cli_command -a "command='dis version'"
10.0.3.105 | SUCCESS => {
"changed": false,
"stdout": "Huawei Versatile Routing Platform Software\nVRP (R) software, Version 5.170 (S6720 V200R019C10SPC500)\nCopyright (C) 2000-2020 HUAWEI TECH Co., Ltd.\nHUAWEI S6720-50L-HI-48S Routing Switch uptime is 1 week, 6 days, 7 hours, 46 minutes\n\nCEM48S4Q2CQP01 0(Master) : uptime is 1 week, 6 days, 7 hours, 44 minutes\nDDR Memory Size : 2048 M bytes\nFLASH Total Memory Size : 1024 M bytes\nFLASH Available Memory Size : 624 M bytes\nPcb Version : VER.C\nBootROM Version : 0213.0000\nBootLoad Version : 0213.0000\nCPLD Version : 0106 \nSoftware Version : VRP (R) Software, Version 5.170 (V200R019C10SPC500)\nFLASH Version : 0000.0000\nPWR2 information\nPcb Version : PWR VER.A\nFAN1 information\nPcb Version : NA\nFAN2 information\nPcb Version : NA",
"stdout_lines": [
"Huawei Versatile Routing Platform Software",
"VRP (R) software, Version 5.170 (S6720 V200R019C10SPC500)",
"Copyright (C) 2000-2020 HUAWEI TECH Co., Ltd.",
"HUAWEI S6720-50L-HI-48S Routing Switch uptime is 1 week, 6 days, 7 hours, 46 minutes",
"",
"CEM48S4Q2CQP01 0(Master) : uptime is 1 week, 6 days, 7 hours, 44 minutes",
"DDR Memory Size : 2048 M bytes",
"FLASH Total Memory Size : 1024 M bytes",
"FLASH Available Memory Size : 624 M bytes",
"Pcb Version : VER.C",
"BootROM Version : 0213.0000",
"BootLoad Version : 0213.0000",
"CPLD Version : 0106 ",
"Software Version : VRP (R) Software, Version 5.170 (V200R019C10SPC500)",
"FLASH Version : 0000.0000",
"PWR2 information",
"Pcb Version : PWR VER.A",
"FAN1 information",
"Pcb Version : NA",
"FAN2 information",
"Pcb Version : NA"
]
}
使用playbook来批量关闭端口
- hosts: rs
gather_facts: False
tasks:
- name: test-rs
ce_command:
commands:
- sys
- interface range XGigabitEthernet 0/0/25 to XGigabitEthernet 0/0/35
- shutdown
register: show
- name: test-rs
cli_command:
command: |
sys
interface range XGigabitEthernet 0/0/40 to XGigabitEthernet 0/0/44
shutdown
register: show2
- debug:
msg={{show}}
- debug:
msg={{show2}}
以上使用了cli_command和ce_command两个模块做展示,一个是共用的一个华为私有的,两个模块用法一样只是模块的选项稍有不同,commands和commad
执行命令进行回车换行是可以使用以上两种方法,其中第二种的|符号又分以下三种用法
文中自动换行 + 文末新增一空行
文中自动换行 + 文末新增两空行
文中自动换行 + 文末不新增行
执行下
dark@dark:~/python/ansible$ ansible-playbook test.yml PLAY [rs] ************************************************************************************************************************************* TASK [test-rs] ********************************************************************************************************************************
ok: [10.0.3.105] TASK [test-rs] ********************************************************************************************************************************
ok: [10.0.3.105] TASK [debug] **********************************************************************************************************************************
ok: [10.0.3.105] => {
"msg": {
"changed": false,
"failed": false,
"stdout": [
"Enter system view, return user view with Ctrl+Z.",
"",
"[test-XGigabitEthernet0/0/25]shutdown\n[test-XGigabitEthernet0/0/26]shutdown\n[test-XGigabitEthernet0/0/27]shutdown\n[test-XGigabitEthernet0/0/28]shutdown\n[test-XGigabitEthernet0/0/29]shutdown\n[test-XGigabitEthernet0/0/30]shutdown\n[test-XGigabitEthernet0/0/31]shutdown\n[test-XGigabitEthernet0/0/32]shutdown\n[test-XGigabitEthernet0/0/33]shutdown\n[test-XGigabitEthernet0/0/34]shutdown\n[test-XGigabitEthernet0/0/35]shutdown"
],
"stdout_lines": [
[
"Enter system view, return user view with Ctrl+Z."
],
[
""
],
[
"[test-XGigabitEthernet0/0/25]shutdown",
"[test-XGigabitEthernet0/0/26]shutdown",
"[test-XGigabitEthernet0/0/27]shutdown",
"[test-XGigabitEthernet0/0/28]shutdown",
"[test-XGigabitEthernet0/0/29]shutdown",
"[test-XGigabitEthernet0/0/30]shutdown",
"[test-XGigabitEthernet0/0/31]shutdown",
"[test-XGigabitEthernet0/0/32]shutdown",
"[test-XGigabitEthernet0/0/33]shutdown",
"[test-XGigabitEthernet0/0/34]shutdown",
"[test-XGigabitEthernet0/0/35]shutdown"
]
]
}
} TASK [debug] **********************************************************************************************************************************
ok: [10.0.3.105] => {
"msg": {
"changed": false,
"failed": false,
"stdout": "sys\nEnter system view, return user view with Ctrl+Z.\n[test]interface range XGigabitEthernet 0/0/40 to XGigabitEthernet 0/0/44\n[test-XGigabitEthernet0/0/40]shutdown\n[test-XGigabitEthernet0/0/41]shutdown\n[test-XGigabitEthernet0/0/42]shutdown\n[test-XGigabitEthernet0/0/43]shutdown\n[test-XGigabitEthernet0/0/44]shutdown",
"stdout_lines": [
"sys",
"Enter system view, return user view with Ctrl+Z.",
"[test]interface range XGigabitEthernet 0/0/40 to XGigabitEthernet 0/0/44",
"[test-XGigabitEthernet0/0/40]shutdown",
"[test-XGigabitEthernet0/0/41]shutdown",
"[test-XGigabitEthernet0/0/42]shutdown",
"[test-XGigabitEthernet0/0/43]shutdown",
"[test-XGigabitEthernet0/0/44]shutdown"
]
}
} PLAY RECAP ************************************************************************************************************************************
10.0.3.105 : ok=4 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
对网络设备的操作只举这一个例子,操作其他配置可以使用不同的细分模块如华为的community.network.ce*
个人感觉ansible对于下发网络设备配置使用场景有限,大多用于设备开局,在网设备下发配置还是多用netconf来做,使用起来更轻量一点
zabbix_host
使用zabbix-api创建host,需要先安装zabbix-api
pip3 install zabbix-api
选项
host_groups: #主机组
host_name: 主机名
login_user: #登录用户名,对应zabbix-api的user字段
login_password: #登录密码,对应zabbix-api的password字段
link_templates: #关联模板
macros: #宏
macro: #定义用户宏,可定义多组
value: #变量对应的值
interfaces: #主机接口列表,包含以下
type: #接口类型1 = agent 2 = snmp 3 = ipmi 4 = jmx
ip: #主机ip
port: #主机port
state: present/absent#状态,添加更新/删除
status: enabled/disabled#启用/禁用
proxy: #代理
示例
---
- hosts: localhost
connection: local
tasks:
- local_action:
module: community.zabbix.zabbix_host
server_url: http://10.0.3.108:6600
login_user: Admin
login_password: adminpass
host_name: ju_route
visible_name: ju_route
description: My ju_route Description
host_groups:
- switch
link_templates:
- Template Module Interfaces SNMPv2
status: enabled
state: present
interfaces:
- type: 2
main: 1
useip: 1
ip: 10.0.0.1
dns: ""
port: "161"
macros:
- macro: '{$SNMP_COMMUNITY}'
value: public
执行
dark@dark:~/python/ansible$ ansible-playbook test.yml PLAY [localhost] ********************************************************************************************************************* TASK [Gathering Facts] ***************************************************************************************************************
ok: [localhost] TASK [community.zabbix.zabbix_host] **************************************************************************************************
changed: [localhost -> localhost] PLAY RECAP ***************************************************************************************************************************
localhost : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
还有操作云平台的模块,我的AWS免费试用到期了,就不操作了-_-
其他软件的API操作类似zabbix,不再举例,模块示例就到这里,最后介绍下roles的用法
roles
roles的概念类似于定义多个角色,当需要演绎一出电影时,需要哪个角色就按顺序调用哪个
roles的目录是固定的,ansible内部已经做好了import,示例目录结构如下,其中main.yml是必要的,其他的文件根据自己的需求定义
roles目录结构
roles
└── zabbix-agent
├── default
├── files
│ └── darkping
│ ├── log
│ ├── mtr.py
│ └── newpingd.py
├── handlers
│ └── main.yml
├── meta
├── tasks
│ ├── centos-install.yml
│ ├── func.yml
│ ├── main.yml
│ ├── start.yml
│ ├── ubuntu-install.yml
│ └── zabbix_agentd.conf.yml
├── templates
│ └── zabbix_agentd.conf.j2
└── vars
└── main.yml
roles配置
定义vars/main.yml
rpmname: zabbix-agent
rpmname_local_conf: zabbix_agentd.conf.j2
rpmname_remote_conf: zabbix_agentd.conf
func_local_conf: darkping
func_remote_conf: /etc/zabbix
定义templates/zabbix_agent.conf.j2,只展示自定义脚本行
UserParameter=ping_pkloss[*],python3 /etc/zabbix/myping/newpingd.py -s {{ ansible_facts.eth0.ipv4.address }} -t $1 -I pkloss
UserParameter=ping_restime[*],python3 /etc/zabbix/myping/newpingd.py -s {{ ansible_facts.eth0.ipv4.address }} -t $1 -I restime
UserParameter=udp_ping_pkloss[*],/etc/zabbix/myping/newpingd.py -s {{ ansible_facts.eth0.ipv4.address }} -T udp -t $1 -p 4789 -I pkloss
UserParameter=udp_ping_restime[*],/etc/zabbix/myping/newpingd.py -s {{ ansible_facts.eth0.ipv4.address }} -T udp -t $1 -p 4789 -I restime
UserParameter=show_mtr,/etc/zabbix/bin/show_mtr.py
UserParameter=tcp_ping_pkloss[*],/etc/zabbix/myping/newpingd.py -s {{ ansible_facts.eth0.ipv4.address }} -T tcp -t $1 -p $2 -I pkloss
UserParameter=tcp_ping_restime[*],/etc/zabbix/myping/newpingd.py -s {{ ansible_facts.eth0.ipv4.address }} -T tcp -t $1 -p $2 -I restime
定义handlers
- name: reload
service: name={{ rpmname }} state=restarted
定义tasks
#ubuntu-install.yml
- name: install {{ rpmname }} on centos
yum: name={{ rpmname }} state=present
when: ansible_lsb.id == 'Centos'
#start.yml
- name: start {{ rpmname }} service
service: name={{ rpmname }} state=started
tags: start {{ rpmname }}
#func.yml
- name: copy func
copy: src={{ func_local_conf }} dest={{ func_remote_conf }}
#zabbix_agentd.conf.yml
- name: copy {{ rpmname }}.conf
template: src={{ rpmname_local_conf }} dest={{ rpmname_remote_conf }}
notify: reload
#main.yml 决定tasks执行顺序
- import_tasks: ubuntu-install.yml
- import_tasks: centos-install.yml
- import_tasks: uzabbix_agentd.conf.yaml
- import_tasks: func.yaml
- import_tasks: start.yaml
定义handlers
#handlers
- name: reload
service: name={{ rpmname }} state=restarted
定义rols.yml文件,和zabbix-agent同目录
- hosts: zb
remote_user: root
roles:
- zabbix-agent
执行时直接执行ansible-playbook rols.yml就行
以上做了个简单的roles示例,复杂了怕长时间不用再回头看时看不懂-_-!
还有过滤,自定义模块,此篇过长,下篇再写吧
ending.....
sleeping.......
服务器/网络/虚拟化/云平台自动化运维-ansible的更多相关文章
- 技术沙龙|京东云DevOps自动化运维技术实践
自动化测试体系不完善.缺少自助式的持续交付平台.系统间耦合度高服务拆分难度大.成熟的DevOps工程师稀缺,缺少敏捷文化--这些都是DevOps 在落地过程中,或多或少会碰到的问题,DevOps发展任 ...
- 沙龙报名 | 京东云DevOps——自动化运维技术实践
随着互联网技术的发展,越来越多企业开始认识DevOps重要性,在企业内部推进实施DevOps,期望获得更好的软件质量,缩短软件开发生命周期,提高服务稳定性.但在DevOps 的实施与落地的过程中,或多 ...
- 看DLI服务4核心如何提升云服务自动化运维
摘要:今天我们来说说DLI是如何实现监控告警来提升整体运维能力,从而为客户更好的提供Serverless的DLI. DLI是支持多模引擎的Serverless大数据计算服务,免运维也是其作为Serve ...
- 自动化运维 Ansible
自动化运维 Ansible 特性 (1).no agents:不需要在被管控主机上安装任何客户端: (2).no server:无服务器端,使用时直接运行命令即可: (3).modules in an ...
- 自动化运维Ansible安装篇
Ansible自动化工具之--部署篇 ansible是新出现的自动化运维工具,基于Python开发,集合了众多运维工具(puppet.cfengine.chef.func.fabric)的优点,实现了 ...
- 自动化运维—Ansible(上)
一:为什么选择Ansible 相对于puppet和saltstack,ansible无需客户端,更轻量级 ansible甚至都不用启动服务,仅仅只是一个工具,可以很轻松的实现分布式扩展 更强的远程命令 ...
- 自动化运维-ansible入门篇
1.ansible配置 什么是Ansible IT自动化工具 依赖于现有的操作系统凭证来访问控制远程机器 简单易用.安全可靠 Ansible可以完成哪些任务 配置系统 开发软件 编排高级的IT任务 A ...
- 自动化运维--ansible(2)
问题一:如何在多台服务器中配置Web项目上线的所有环境 解答: 1.使用ansible配置nginx服务 在安装前了解rpm与yum的区别 rpm是压缩包安装依赖包需要自己手动安装,yum安装解决依 ...
- 自动化运维--ansible(1)
前戏 ansible 批量在远程主机上执行命令 openpyxl 操作excel表格 puppet ansible slatstack ansible epel源 第一步: 下载epel源 wget ...
随机推荐
- 行内元素的padding和margin是否有效
行内元素的纵向padding和margin都是不考虑的,这是css规范定义的.inline元素确实可以设置垂直方向的padding和margin值,但是inline元素的margin和padding的 ...
- 一套Vue的单页模板:N3-admin
趁着周末偷来一点闲,总结近期的工作和学习,想着该花点心思把N3-admin这套基于N3-components的单页应用模板简单的给介绍一下. 首发于个人博客:blog.lxstart.net项目路径: ...
- 巧用CSS3:target 伪类制作Dropdown下拉菜单(无JS)
原文链接:http://devework.com/css3-target-dropdown.html :target 是CSS3 中新增的一个伪类,用以匹配当前页面的URI中某个标志符的目标元素(比如 ...
- Vue-cli的打包初体验
前言:我司是一个教育公司,最近要做一个入学诊断的项目,领导让我开始搭建一套基于vue的H5的开发环境.在网上搜集很多的适配方案,最终还是选定flexible方案.选择它的原因很简单: 它的github ...
- Java/C++实现代理模式---婚介所
婚介所其实就是找对象的一个代理,请仿照我们的课堂例子"论坛权限控制代理"完成这个实际问题,其中如果年纪小于18周岁,婚介所会提示"对不起,不能早恋!",并终止业 ...
- JavaScript 遍历对象、数组总结
在日常工作过程中,我们对于javaScript遍历对象.数组的操作是十分的频繁的,今天抽空把经常用到的方法小结一下,方便今后参考使用! javaScript遍历对象总结 1.使用Objec ...
- java中接口interface可以持有多个类的共享常量
3.接口持有多个类的共享常量 接口另一主要功能,马克-to-win: 可以使用接口来引入多个类的共享常量.所有的这些变量名都将作为常量看待.所有定义在接口中的常量都默认为public.static和 ...
- Qt QTableView 表格内添加控件
目录 Qt QTableView 表格内添加控件 1. QItemDelegate 2. setIndexWidget 3. setIndexWidget + setLayout Qt QTableV ...
- GEOS 使用记录
GEOS 使用记录 官网 https://trac.osgeo.org/geos/ https://libgeos.org/ 下载地址 https://libgeos.org/usage/downlo ...
- MassTransit 入门(一)
本文地址源码 MassTransit是一个面向.net的免费开源分布式应用程序框架. MassTransit使得创建应用程序和服务变得很容易,这些应用程序和服务利用基于消息的.松散耦合的异步通信来获得 ...