当前位置: 首页 > news >正文

【云平台监控】安装应用Ansible服务

安装应用Ansible服务

文章目录

  • 安装应用Ansible服务
    • 资源列表
    • 基础环境
    • 一、安装Ansible
      • 1.1、部署Ansible
      • 1.2、配置主机清单
        • 1.2.1、方法1
        • 1.2.2、方法2
    • 二、Ansible命令应用基础
      • 2.1、ping模块
      • 2.2、command模块
      • 2.3、user模块
      • 2.4、group模块
      • 2.5、cron模块
      • 2.6、copy模块
      • 2.7、file模块
      • 2.8、service模块
      • 2.9、shell模块
      • 2.10、script模块
      • 2.11、yum模块
    • 三、YAML介绍
        • 3.1、介绍
        • 3.2、YAML语法
        • 3.3、常用的数据类型
          • 3.3.1、list
          • 3.3.2、dictionary
    • 四、Ansible基础元素介绍
      • 4.1、Inventory(主机清单)
      • 4.2、主机变量
      • 4.3、组变量
      • 4.4、组嵌套
      • 4.5、Inventory参数
    • 五、变量
      • 5.1、通过命令行传递变量
      • 5.2、通过roles传递变量
      • 5.3、条件测试
        • 5.3.1、when语句
        • 5.3.2、迭代
    • 六、Playbook介绍
      • 6.1、介绍
      • 6.2、Hosts和Users介绍
      • 6.3、任务列表和action介绍
      • 3.4、Handlers介绍
      • 3.5、Templates介绍
      • 3.6、Tages介绍
      • 3.7、Roles介绍
    • 备注
      • Playbook示例1
      • Playbook示例2
      • Playbook示例3
    • 官方文档

资源列表

操作系统配置主机名IP角色
CentOS 7.92C4Gansible-node1192.168.93.101控制主机
CentOS 7.92C4Gansible-node2192.168.93.102被管理主机
CentOS 7.92C4Gansible-node3192.168.93.103被管理主机

基础环境

  • 关闭防火墙
systemctl stop firewalld
systemctl disable firewalld
  • 关闭内核安全机制
setenforce 0
sed -i "s/^SELINUX=.*/SELINUX=disabled/g" /etc/selinux/config
  • 修改主机名
hostnamectl set-hostname ansible-node1
hostnamectl set-hostname ansible-node2
hostnamectl set-hostname ansible-node3
  • 绑定hosts解析
cat >> /etc/hosts << EOF
192.168.93.101 ansible-node1
192.168.93.102 ansible-node2
192.168.93.103 ansible-node3
EOF

一、安装Ansible

1.1、部署Ansible

  • Ansible可以使用源码方式进行安装,也可以使用操作系统YUM软件包管理工具进行安装。YUM方式安装Ansible,,需要依赖第三方EREL源,下面配置EPEL源作为部署Ansible的YUM源。
# 安装扩展源
[root@ansible-node1 ~]# yum -y install epel-release# 安装Ansible
[root@ansible-node1 ~]# yum -y install ansible# 查看Ansible版本信息,还会输出Python版本信息
[root@ansible-node1 ~]# ansible --version
ansible 2.9.27config file = /etc/ansible/ansible.cfgconfigured module search path = [u'/root/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']ansible python module location = /usr/lib/python2.7/site-packages/ansibleexecutable location = /usr/bin/ansiblepython version = 2.7.5 (default, Jun 28 2022, 15:30:04) [GCC 4.8.5 20150623 (Red Hat 4.8.5-44)]
# Ansible主要相关配置文件在/etc/ansible目录下
[root@ansible-node1 ~]# ll /etc/ansible/
总用量 24
-rw-r--r-- 1 root root 19985 116 2022 ansible.cfg  # 配置文件
-rw-r--r-- 1 root root  1016 116 2022 hosts  # 管理主机文件
drwxr-xr-x 2 root root     6 116 2022 roles

1.2、配置主机清单

  • /etc/ansible/hosts文件中可以定义被管理主机,Ansible通过读取/etc/ansible/hosts文件内定义的主机清单批量做一些操作。比如定义一个websrvs组,包含一台主机,再定义一个dbsrvs组,包含一台主机,
  • 注意:以下两种方式选择选择其中一个之后,就不要在去尝试使用第二个了
1.2.1、方法1
[root@ansible-node1 ~]# vim /etc/ansible/hosts
# 默认添加即可
[websrvs]
192.168.93.102 ansible_ssh_user=root ansible_ssh_pass=wzh.2005 ansible_ssh_port=22[dbsrvs]
192.168.93.103 ansible_ssh_user=root ansible_ssh_pass=wzh.2005 ansible_ssh_port=22[root@ansible-node1 ~]# vim /etc/ansible/ansible.cfg
# 默认大概在71行左右取消注释,使用ssh的时候第一次不用输入yes
host_key_checking = False# 测试Ansible是否可以正常管理被控主机
[root@ansible-node1 ~]# ansible all -m command -a 'date'
192.168.93.102 | CHANGED | rc=0 >>
2024年 07月 28日 星期日 12:43:16 CST
192.168.93.103 | CHANGED | rc=0 >>
2024年 07月 28日 星期日 12:43:16 CST# 备注:生产环境下不建议这样做。因为这样明文密码容易泄露,另外如果被控主机修改了密码,这里也要一起更改,不方便管理。
1.2.2、方法2
[root@ansible-node1 ~]# vim /etc/ansible/hosts
# 末尾添加即可
[websrvs]
192.168.93.102 [dbsrvs]
192.168.93.103# 设置SSH无密码登录
[root@ansible-node1 ~]# ssh-keygen -t rsa   # 一路回车
[root@ansible-node1 ~]# ssh-copy-id 192.168.93.102
[root@ansible-node1 ~]# ssh-copy-id 192.168.93.103# 测试Ansible是否可以正常管理被控主机
[root@ansible-node1 ~]# ansible all -m command -a 'date'
192.168.93.102 | CHANGED | rc=0 >>
2024年 07月 28日 星期日 12:47:24 CST
192.168.93.103 | CHANGED | rc=0 >>
2024年 07月 28日 星期日 12:47:24 CST

二、Ansible命令应用基础

  • Ansible可以使用命令行的方式进行自动化管理。命令的基本语法如下所示:
ansible <host-pattern> [-m module_name] [-a args]<hos-pattern>:指定被管理主机
<-m module_name>:指定所使用的模块
<-a args>:设置模块对应的参数
# Ansible的命令行管理工具都是由一系列模块、参数组成的,使用某些模块或参数之前,可以在命令后面加上-h或--help来获取帮助。例如,ansible-doc工具可以使用ansible-doc -h或者ansible-doc --help查看其帮助信息
# ansible-doc工具用于查看模块帮助信息。主要选择包括:
-l:用来列出可使用的模块
-s:用来列出某个模块的描述信息和使用示例# 例如:下面的操作可以列出yum模块的描述信息和操作动作
[root@ansible-node1 ~]# ansible-doc -s yum
- name: Manages packages with the `yum' package manageryum:allow_downgrade:       # Specify if the named package and version is
...

2.1、ping模块

  • Ansible中使用ping模块来检测主机的连通性
# 示例一:检测所有被管理主机的连通性
[root@ansible-node1 ~]# ansible all -m ping
192.168.93.102 | SUCCESS => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": false, "ping": "pong"
}
192.168.93.103 | SUCCESS => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": false, "ping": "pong"
}

2.2、command模块

  • Ansible管理工具使用-m 选择来指定所使用的模块,默认使用command模块,即-m 选项省略时会运行此模块,用于在被管理主机上运行命令。例如在被管理主机上执行date命令,限制被管理主机时间。有三种执行命令的方式来管理写入主机清单中的主机。
# 示例一:使用IP地址查看被管理主机日期
[root@ansible-node1 ~]# ansible 192.168.93.102 -m command -a 'date'
192.168.93.102 | CHANGED | rc=0 >>
2024年 07月 28日 星期日 12:57:48 CST
# 示例二:使用管控主机分别查看被管理websrvs和dbsrvs组里面所有主机的日期
[root@ansible-node1 ~]# ansible websrvs -m command -a 'date'
192.168.93.102 | CHANGED | rc=0 >>
2024年 07月 28日 星期日 12:58:40 CST[root@ansible-node1 ~]# ansible dbsrvs -m command -a 'date'
192.168.93.103 | CHANGED | rc=0 >>
2024年 07月 28日 星期日 12:58:46 CST
# 示例三:查看所有被管理主机上的日期
[root@ansible-node1 ~]# ansible all -m command -a 'date'
192.168.93.102 | CHANGED | rc=0 >>
2024年 07月 28日 星期日 12:59:24 CST
192.168.93.103 | CHANGED | rc=0 >>
2024年 07月 28日 星期日 12:59:24 CST
# 示例四:查看所有被管理主机的/etc/passwd的最后一行(若省略-m选择,默认运行command模块)
[root@ansible-node1 ~]# ansible all -a 'tail -1 /etc/passwd'
192.168.93.102 | CHANGED | rc=0 >>
wzh:x:1000:1000:wzh:/home/wzh:/bin/bash
192.168.93.103 | CHANGED | rc=0 >>
wzh:x:1000:1000:wzh:/home/wzh:/bin/bash

2.3、user模块

  • Ansible中的user模块用于创建和更改、删除已存在的用户。其中name选项用来指明创建的用户名称。主要包括两种状态(state)
    • present:表示添加(省略状态时默认使用)
    • absent:表示移除
# 示例一:在被管理组dbsrvs里所有主机上创建user1用户
[root@ansible-node1 ~]# ansible dbsrvs -m user -a 'name="user1"'
192.168.93.103 | CHANGED => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": true, "comment": "", "create_home": true, "group": 1001, "home": "/home/user1", "name": "user1", "shell": "/bin/bash", 
#############################################################"state": "present", 
#############################################################"system": false, "uid": 1001
}
# 示例二:删除上述创建的用户user1
[root@ansible-node1 ~]# ansible dbsrvs -m user -a 'name="user1" state=absent'
192.168.93.103 | CHANGED => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": true, "force": false, "name": "user1", "remove": false, 
#############################################################"state": "absent"
#############################################################
}

2.4、group模块

  • Ansible中的group模块用于对用户组进行管理。
# 示例一:被管理组dbsrvs里所有主机创建mysql组,gid为306,system=yes表示创建的是系统用户
[root@ansible-node1 ~]# ansible dbsrvs -m group -a 'name=mysql gid=306 system=yes'
192.168.93.103 | CHANGED => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": true, "gid": 306, "name": "mysql", "state": "present", "system": true
}
# 示例二:将被管理组dbsrvs里所有主机的mysql用户添加到mysql组中
[root@ansible-node1 ~]# ansible dbsrvs -m user -a 'name=mysql uid=306 system=yes group=mysql'
192.168.93.103 | CHANGED => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": true, "comment": "", "create_home": true, "group": 306, "home": "/home/mysql", "name": "mysql", "shell": "/bin/bash", "state": "present", "system": true, "uid": 306
}

2.5、cron模块

  • Ansible中的cron模块用于定义任务计划。主要包括两种状态(state):
    • present:表示添加(省略状态时默认使用)
    • absent:表示移除
# 示例一:添加任务计划,被管理组dbsrvs里所有主每1分钟输出hello字符串,输出到/root/cron.txt文件中,并且给这个任务计划起个命令叫test cron job
[root@ansible-node1 ~]# ansible dbsrvs -m cron -a 'minute="*/1" job="/bin/echo hello > /root/cron.txt" name="test cron job"'
192.168.93.103 | CHANGED => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": true, "envs": [], "jobs": ["test cron job"]
}minute:分
hour:小时
day:日
month:月
weekday:周# 查看dbsrvs组中的任务计划
[root@ansible-node1 ~]# ansible dbsrvs -a 'crontab -l'
192.168.93.103 | CHANGED | rc=0 >>
#Ansible: test cron job
*/1 * * * * /bin/echo hello > /root/cron.txt
# 示例二:移除上述添加的任务计划
[root@ansible-node1 ~]# ansible dbsrvs -m cron -a 'minute="*/1" job="/bin/echo hello > /root/cron.txt" name="test cron job" state=absent'
192.168.93.103 | CHANGED => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": true, "envs": [], "jobs": []
}

2.6、copy模块

  • Ansible中的copy模块用于实现文件复制和批量下发文件。其中使用src来定义本地源文件路径;使用dest定义被管理主机文件路径;使用content则是使用指定信息内容生成目标文件。
# 示例一:将本地文件/etc/fstab复制到被管理组dbsrvs里的所有主机的/tmp/fstab.ansible,并将所有者设置为mysql用户,权限设置为777
[root@ansible-node1 ~]# ansible dbsrvs -m copy -a 'src=/etc/fstab dest=/tmp/fstab.ansible owner=mysql mode=777'
192.168.93.103 | CHANGED => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": true, "checksum": "21a66bf28227cc91193220ea6aa775a0ee554d9c", "dest": "/tmp/fstab.ansible", "gid": 0, "group": "root", "md5sum": "efc3d9fc1633151408bc719c78625915", "mode": "0777", "owner": "mysql", "size": 541, "src": "/root/.ansible/tmp/ansible-tmp-1722144351.61-9212-220210651046554/source", "state": "file", "uid": 306
}# 验证上述命令执行结果
[root@ansible-node1 ~]# ansible dbsrvs -m command -a 'ls -l /tmp/fstab.ansible'
192.168.93.103 | CHANGED | rc=0 >>
-rwxrwxrwx 1 mysql root 541 728 13:25 /tmp/fstab.ansible# 如果出现以下的报错信息,是因为被管理主机开启了SELinux,需要在被管理机上安装libseliunx-python软件包,才可以使用Ansible中与copy、file相关的函数
"msg": "Aborting, target uses selinux but python bindings (libselinux-python) aren't installed
# 示例二:将文件内容“Hello Ansible Hi Ansible”写入到被管理组dbsrvs里所有主机上的/tmp/test.ansible文件中
[root@ansible-node1 ~]# ansible dbsrvs -m copy -a 'content="Hello Ansible Hi Ansible"  dest=/tmp/test.ansible'
192.168.93.103 | CHANGED => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": true, "checksum": "92978fdc1fb9252b5a52a8083eb49d577322d9af", "dest": "/tmp/test.ansible", "gid": 0, "group": "root", "md5sum": "0ba13acd0115be8c69a3b4babc2fb97a", "mode": "0644", "owner": "root", "size": 24, "src": "/root/.ansible/tmp/ansible-tmp-1722144706.16-9304-272775345967511/source", "state": "file", "uid": 0
}# 验证上述命令执行结果
[root@ansible-node1 ~]# ansible dbsrvs -m command -a 'cat /tmp/test.ansible'
192.168.93.103 | CHANGED | rc=0 >>
Hello Ansible Hi Ansible

2.7、file模块

  • Ansible中使用file模块设置文件属性。其中使用path指定文件路径;使用src定义源文件路径;使用name或dest来替换创建文件的符号链接。
# 示例一:设置被管理组dbsrvs里所有主机中/tmp/fstab.snaible文件所属主为root,所属组为root,权限设置为644
[root@ansible-node1 ~]# ansible dbsrvs -m file -a 'owner=root group=root mode=644 path=/tmp/fstab.ansible'
192.168.93.103 | CHANGED => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": true, "gid": 0, "group": "root", "mode": "0644", "owner": "root", "path": "/tmp/fstab.ansible", "size": 541, "state": "file", "uid": 0
}# 验证上述命令执行结果
[root@ansible-node1 ~]# ansible dbsrvs -m command -a 'ls -l /tmp/fstab.ansible'
192.168.93.103 | CHANGED | rc=0 >>
-rw-r--r-- 1 root root 541 728 13:25 /tmp/fstab.ansible
# 示例二:设置被管理组dbsrvs里的所有主机的/tmp/fstab.link文件为/tmp/fstab.ansible文件的链接文件
paht:被管理主机目标地址
src:被管理主机源地址
[root@ansible-node1 ~]# ansible dbsrvs -m file -a 'path=/tmp/fstab.link src=/tmp/fstab.ansible state=link'
192.168.93.103 | CHANGED => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": true, "dest": "/tmp/fstab.link", "gid": 0, "group": "root", "mode": "0777", "owner": "root", "size": 18, "src": "/tmp/fstab.ansible", "state": "link", "uid": 0
}# 验证上述命令指定结果
[root@ansible-node1 ~]# ansible dbsrvs -m command -a 'ls -l /tmp/fstab.link'
192.168.93.103 | CHANGED | rc=0 >>
lrwxrwxrwx 1 root root 18 728 13:37 /tmp/fstab.link -> /tmp/fstab.ansible

2.8、service模块

  • Ansible中使用service模块来控制管理服务的运行状态。其中使用enabled表示开启自动启动,取值为true或者false;使用name定义服务名称;使用state指定服务状态,取值有started、stopped、restarted。
# 示例一:将websrvs里所有主机的postfix服务状态设置为开机自动启动和开启服务
[root@ansible-node1 ~]# ansible websrvs -m service -a 'enabled=true name=postfix state=started'state=started'
192.168.93.102 | SUCCESS => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": false, "enabled": true, "name": "postfix", "state": "started", "status": {"ActiveEnterTimestamp": "日 2024-07-28 12:23:32 CST", "ActiveEnterTimestampMonotonic": "6418846", 
...# 验证上述命令执行结果
[root@ansible-node1 ~]# ansible websrvs -m command -a 'systemctl status postfix' 
192.168.93.102 | CHANGED | rc=0 >>
● postfix.service - Postfix Mail Transport AgentLoaded: loaded (/usr/lib/systemd/system/postfix.service; enabled; vendor preset: disabled)Active: active (running) since 日 2024-07-28 13:48:54 CST; 20s agoProcess: 9104 ExecStart=/usr/sbin/postfix start (code=exited, status=0/SUCCESS)
...# 查看服务是否为开机自启
[root@ansible-node1 ~]# ansible websrvs -m command -a 'systemctl is-enabled postfix'
192.168.93.102 | CHANGED | rc=0 >>
enabled

2.9、shell模块

  • Ansible中的shell模块可以在被管理主机上运行Linux系统命令,并支持像管道符等功能的复杂命令。
# 示例一:先创建一个用户,之后使用shell模块给用户设置密码
[root@ansible-node1 ~]# ansible dbsrvs -m user -a 'name=user1'
192.168.93.103 | CHANGED => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": true, "comment": "", "create_home": true, "group": 1001, "home": "/home/user1", "name": "user1", "shell": "/bin/bash", "state": "present", "stderr": "useradd:警告:此主目录已经存在。\n不从 skel 目录里向其中复制任何文件。\n正在创建信箱文件: 文件已存在\n", "stderr_lines": ["useradd:警告:此主目录已经存在。", "不从 skel 目录里向其中复制任何文件。", "正在创建信箱文件: 文件已存在"], "system": false, "uid": 1001
}
[root@ansible-node1 ~]# ansible dbsrvs -m shell -a 'echo "wzh.2005" | passwd --stdin user1'
192.168.93.103 | CHANGED | rc=0 >>
更改用户 user1 的密码 。
passwd:所有的身份验证令牌已经成功更新。

2.10、script模块

  • Ansible中的script模块可以将本地脚本复制到被管理主机上进行运行。需要注意的是使用相对路径指定脚本位置。
# 示例一:编辑一个本地脚本test.sh,复制到被管理组dbsrvs里所有主机上运行
[root@ansible-node1 ~]# cat test.sh 
#!/bin/bash
echo "hello ansible form script" > /tmp/script.ansible
[root@ansible-node1 ~]# chmod +x test.sh
[root@ansible-node1 ~]# ansible dbsrvs -m script -a 'test.sh'
192.168.93.103 | CHANGED => {"changed": true, "rc": 0, "stderr": "Shared connection to 192.168.93.103 closed.\r\n", "stderr_lines": ["Shared connection to 192.168.93.103 closed."], "stdout": "", "stdout_lines": []
}# 验证上述命令执行结果
[root@ansible-node1 ~]# ansible dbsrvs -m command -a 'cat /tmp/script.ansible'
192.168.93.103 | CHANGED | rc=0 >>
hello ansible form script

2.11、yum模块

  • Ansible中的yum模块负责在被管理主机上安装与卸载软件包,但是需要提前在每个节点配置自己的YUM仓库。其中:
    • 使用name指定要安装的软件包,还可以带上版本号;否则安装最新的软件包
    • 使用state指定安装软件包的状态,present、latest用来表示安装吗,ansent表示卸载
# 示例一:被管理组dbsrvs里所有主机安装zsh软件
[root@ansible-node1 ~]# ansible dbsrvs -m yum -a 'name=zsh'
192.168.93.103 | CHANGED => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": true, "changes": {"installed": ["zsh"]}, "msg": "http://mirrors.qlu.edu.cn/centos/7.9.2009/os/x86_64/Packages/zsh-5.0.2-34.el7_8.2.x86_64.rpm: [Errno 14] HTTP Error 404 - 
...# 验证上述命令结果
[root@ansible-node1 ~]# ansible dbsrvs -m command -a 'rpm -q zsh'
192.168.93.103 | CHANGED | rc=0 >>
zsh-5.0.2-34.el7_8.2.x86_64
# 示例二:卸载被管理组dbsrvs里所有主机上的zsh软件包
[root@ansible-node1 ~]# ansible dbsrvs -m yum -a 'name=zsh state=absent'
192.168.93.103 | CHANGED => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": true, "changes": {"removed": ["zsh"]}, "msg": "", "rc": 0, "results": ["已加载插件:fastestmirror\n正在解决依赖关系\n--> 正在检查事务\n---> 软件包 zsh.x86_64.0.5.0.2-34.el7_8.2 将被 删除\n--> 解决依赖关系完成\n\n依赖关系解决               \n\n完毕!\n"]
}
...# 验证上述命令执行结果
[root@ansible-node1 ~]# ansible dbsrvs -m command -a 'rpm -q zsh'
192.168.93.103 | FAILED | rc=1 >>
未安装软件包 zsh non-zero return code

三、YAML介绍

3.1、介绍
  • YAML是一种用来表达资源序列的格式,参考了其他很多种语言所以具有很高的可读性。YAML是YAML Ain t Markup Language的缩写,即YAML不是XML。不过在研发这种语言时,YAML的意思其实是“Yet Another Markup Language”(仍是一种标记语言)。其特性如下:
    • 具有很好的可读性,易于实现
    • 表达能力好,扩展性好
    • 和脚本语言的交互性好
    • 有一个一致的信息模型
    • 可以基于流来处理
3.2、YAML语法
  • YAML的语法和其他语言类似,也可以表达散列表、标量等数据结构。其中结构(structure)通过空格来展示;序列(swquence)里的项用“-”来代表;Map里的键值对用“:”分隔。YAML文件扩展名通常为:yaml,如example.yaml。下面是YAML的一个示例。
name: john smith
age: 41
gender: Male
spouse:
name: jane smith
age: 37
gender: Female
children:
- name: jimmy smithage: 17gender: Male- name: jenny smithage: 13gender: Female
3.3、常用的数据类型
  • YAML中有两种常用的数据类型:listdictionary
3.3.1、list
  • 列表(list)的所有元素均使用“-”开头,例如:
- Apple
- Orange
- Strawberry
- Mango
3.3.2、dictionary
  • 字典(dictionary)通过key与value进行标识,例如:
name: example developer
Job: developer
Skill: Elite
  • 也可以使用key:value的形式放置于{}中进行表示,例如:
{ name: example developer,Job: developer,Skill: Elite}

四、Ansible基础元素介绍

4.1、Inventory(主机清单)

  • Ansible为了更加便捷地管理主机,在主机清单中将被管理主机进行分组命名。默认的主机清单为/etc/ansible/hosts文件。主机清单可以设置为有多个,也可以通过Dynamic Inventory动态生成。
  • Inventory文件中以中括号中的字符标识为组名,将主机分组管理,也可以将同一主机同时划分到多个不同的组中。如果被管理使用非默认的SSH端口,还可以在主机名之后用冒号加端口的方式来进行标明,如下所示。
[root@ansible-node1 ~]# vim /etc/ansible/hosts
[websrvs]
192.168.93.102:6666[dbsrvs]
192.168.93.103:8888
  • 如果被管理主机的主机名遵循类似的命名规则,还可以使用列表的方式标识各个主机
[root@ansible-node1 ~]# vim /etc/ansible/hosts
[websrvs]
www[01-05].example.org	# 01:05 代表01-05台主机[dbsrvs]
db-[a-f].example.org

4.2、主机变量

  • 在定义主机时可以添加主机变量以便在后续的Playbook中使用,如下所示。
[root@ansible-node1 ~]# vim /etc/ansible/hosts
[websrvs]
www1.magedu.com http_port=80 maxRequestsChild=808
www2.magedu.com http_port=8080 maxRequestsChild=909

4.3、组变量

  • Ansible支持定义组变量,主要针对大量机器的变量定义需求,赋予指定组内所有主机在Playbook中可用的变量,等同于逐一给该组下的所有主机赋予同一变量如下所示。
[root@ansible-node1 ~]# vim /etc/ansible/hosts
[websrvs]
ntp_server=ntp.example.org  # 定义 server-vars组所有主机ntp_server值为ntp.example.org
nfs_server=nfs.example.org  # 定义 server-vars组中所有主机nfs_server值为nfs.example.org

4.4、组嵌套

  • 在Inventory中的组还可以嵌套其他的组,也可以向组中的主机指定变量。不过这些变量只能在ansible-playbook工具中使用,直接使用ansible工具不支持,如下所示。
[apache]
httpd1.example.org
httpd2.example.org[nginx]
ngx1.example.org
ngx2.example.org[webservers:children]   # 组嵌套
apache
nginx[webservers:vars]   # 向组中的主机指定变量
ntp_server=ntp1.aliyun.com

4.5、Inventory参数

  • Ansible基于SSH连接Inventory中指定的被管理主机时,还可以通过参数指定交互方式,这些参数如下表所示。
参数含义
ansible_ssh_port指定ssh端口
ansible_ssh_user指定ssh用户
ansible_ssh_pass指定ssh用户登录时认证密码,明文密码不安全
ansible_sudo_pass指明sudo时候的密码
ansible_connectionSSH连接的类型:local、ssh、paramiko
ansible_ssh_private_key_fileSSH连接的公钥文件
ansible_shell_type指定主机所使用的Shell解释器,默认是sh
ansible_python_interpreter用来指定Python解释器的路径
  • 如果不配置SSH密钥认证,可以对被管理主机进行认证:
[root@ansible-node1 ~]# vim /etc/ansible/hosts
[websrvs]
192.168.93.102 ansible_ssh_user=root ansible_ssh_pass=wzh.2005 ansible_ssh_port=22

五、变量

  • Ansible中变量明仅能由字母、数字和下划线组成,并且只能以字符开头。可以使用两种方式传递Ansible变量。

5.1、通过命令行传递变量

  • 在运行Playbook的时候,可以通过命令行的方式来传递一些变量提供Playbook使用。示例如下。
ansible-playbook test.yaml -extra-vars "hosts-www user-mageedu"

5.2、通过roles传递变量

  • 当给主机应用角色(roles)的时候可以传递变量,然后在角色内使用这些变量,示例如下。
- hosts: webserversroles:- common- {role: foo_app_instancem,dir:'/web/htdocs/a.com',port:8080}

5.3、条件测试

  • 如果需要根据变量、facts或之前任务的执行结果来作为某task执行与否的前提时就需要用到条件测试语句。
5.3.1、when语句
  • 使用条件测试只需要在task之后添加when语句就可以,when语句支持janjia2表达式语法,如下所示
tasks:
- name: "shutdown debin flavored systems"command: /sbin/shutdown -h nowwhen: ansible_os_family - "Debian"
  • when语句中还可以使用jinjia2的大多“filter”,例如要忽略此前某语句的错误并基于其结果(failed或者success)去运行后面执行的语句,可以使用类似如下形式。
tasks:
- command: /bin/falseregister: resultignore_errors: True
- command: /bin/somethingwhen: result|success
- command: /bin/still/something_elsewhen: result|skipped
  • 条件测试简单示例
[root@ansible-node1 ~]# vim cond.yaml
- hosts: all  # 指定在所有被管理主机执行remote_user: root   # 在远端执行任务时使用的用户为rootvars:  # 定义一个变量,名为username值为user10- username: user10tasks:  # 定义了一组要在目标主机上执行的任务- name: create {{ username }}user  # 任务名字,username是变量值为user10user: name={{ username }}  # 使用user模块创建用户when: ansible_fqdn == 'ansible-node3'  # 条件该任务只会在全域名为ansible-node3的主机上执行[root@ansible-node1 ~]# ansible-playbook cond.yaml PLAY [all] *********************************************************************TASK [Gathering Facts] *********************************************************
ok: [192.168.93.103]
ok: [192.168.93.102]TASK [create user10user] *******************************************************
skipping: [192.168.93.102]
changed: [192.168.93.103]PLAY RECAP *********************************************************************
192.168.93.102             : ok=1    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
192.168.93.103             : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
5.3.2、迭代
  • 当需要去执行重复任务时可以使用迭代机制,直接将需要迭代的内容定义为item变量进行引用,然后通过with_items语句来指明迭代的元素,如下所示。
- name: add serveral usersuser: name={{ item }} state=present groups=wheelwith_items:- testuser1- testuser2
  • 从功能来说,上面的语句等同于下面的语句:
- name: add user testuser1user: name=testuser1 state=present groups=wheel
- name: add user testuser2user: name=testuser2 state=present groups=wheel
  • 定义循环列表with_items如下:
- apache
- php
- mysql-server
  • 注意:with_items中的列表值也可以是字典,但引用时需要使用item.KEY格式
- { name: apache,conf: conffiles/httpd.conf}
- { name: php,conf:conffiles/php.ini}
- { name: mysql-server,conf:conffiles/my.cnf}
  • 事实上,with_items中可以使用元素还可为hashes,如下所示
- name: add serveral usersuser: name={{ item.name }} state=present groups={{ item.groups }}with_items:- { name: 'testuser1',groups:'wheel'}- { name: 'testuser2',groups:'wheel'}
  • Ansible的循环机制还有很多的功能,更具体内容可以参考官方文档:http://docs.ansible.com/playbook_loops.xml 。

六、Playbook介绍

6.1、介绍

  • Playbook(剧本)是ansible管理配置、部署应用和编排的文件,可用来描述你想在被控主机上执行的策略或者一组任务等。通常使用YAML语法,文件扩展名通常为.yaml或.yml。

  • Playbook本身由以下几部分组成:

    • Tasks:任务,即调用模块完成的某操作
    • Variables:变量
    • Templates:模板
    • Handlers:处理器,某条件满足时,触发执行的操作
    • Roles:角色
    # 示例:一个Playbook的简单示例
    - hosts: webnodes  # 定义的主机组,即应用的主机vars:   # 定义变量http_port: 80max_clients: 256remote_user: root
    tasks:   # 执行的任务- name: ensure apache is at the latest versionyum: name=httpd state=started
    handlers:  # 处理器- name: restart apacehservcei: name=httpd state=restarted
    

6.2、Hosts和Users介绍

  • Playbook的设计目的是为了让某个或某些主机以某个用户身份去执行完成相应的任务。其中用于指定要执行指定任务的主机用hosts定义,可以是一个也可以是由冒号分隔的多个主机组;用于指定被管理主机上执行任务的用户remote_user来定义,如下面示例所示。
- hosts: webnodesremote_user: root
  • remote_user也可定义指定用户通过sudo的方法在被管理主机上运行指令,甚至可以在使用sudo时用sudo_user指定sudo切换的用户
- hosts: webnodesremote_user: redhattasks:- name: test connectionping:remote_user: redhatsudo: yes

6.3、任务列表和action介绍

  • “Play”的主体是任务列表(Tasks list)。任务列表中的任务按照依次序逐个在hosts中指定的所有主机上执行,在顺序执行这些任务时,如果发生误会将所有已执行任务回滚。因此,需要在更正Playbook中的操作后重新执行这些任务。
  • Task的任务是按照指定的参数去执行模块。每个task使用name输出Playbook的运行结果,一般输出内容为该任务指定的步骤。如果没有提供将输出action的运行结果。
  • 定义task的格式可以用“action:module options”或"module:options"都可,其中后者可以实现向后兼容。如果action的内容过多,可在行首使用空白字符进行换行。
tasks:- name: make sure apache is runningservice: name=httpd state=runing
  • 在Ansible自带模块中,command模块和shell模块只需要一个列表定义,无需使用“key=values”格式,如下所示。
tasks:- name: disable selinuxcommand: /sbin/statenforce 0
  • 如果命令或脚本运行结束使执行结果为零,可以使用如下方式替代。
tasks:
- name: run this command and igenore the resultshell: /usr/bin/somecommand||/bin/true
  • 或者,使用ignore_errors来忽略错误信息
tasks:- name: run this command and igenore the resultshell: /usr/bin/somecommandignore_errors: True
  • 简单示例如下所示
[root@ansible-node1 ~]# vim nginx.yaml
- hosts: websrvsremote_user: roottasks:- name: create nginx groupgroup: name=nginx system=yes gid=208- name: create nginx useruser: name=nginx uid=208 group=nginx system=yes
- hosts: dbsrvsremote_user: roottasks:- name: copy file to dbsrvscopy: src=/etc/hosts dest=/tmp/hosts.bak[root@ansible-node1 ~]# ansible-playbook nginx.yaml PLAY [websrvs] *****************************************************************TASK [Gathering Facts] *********************************************************
ok: [192.168.93.102]TASK [create nginx group] ******************************************************
changed: [192.168.93.102]TASK [create nginx user] *******************************************************
changed: [192.168.93.102]PLAY [dbsrvs] ******************************************************************TASK [Gathering Facts] *********************************************************
ok: [192.168.93.103]TASK [copy file to dbsrvs] *****************************************************
changed: [192.168.93.103]PLAY RECAP *********************************************************************
192.168.93.102             : ok=3    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
192.168.93.103             : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

3.4、Handlers介绍

  • Handlers用于当关注的资源发生变化时所采取的操作。在notify中列出的操作便称为handler,也就是notify中需要调用handler中定义的操作。而notify这个工作用于在每个“play”的最后被触发,仅在所有的变化发生完成后一次性地执行指定操作
# 示例:当拷贝模板文件为/etc/foo.conf文件时,apache服务
- name: template config uration filetemplate: src-template.j2 dest=/etc/foo.confnotify:- restart httpd
  • handler也是task列表的格式,这些task的作用与上述的task并没有本质上的不同
handlers:
- name: restart apacheservice: name=httpd state=restarted
- name: restart nginxservice: name=nginx state=restarted
  • 简单示例如下所示
[root@ansible-node1 ~]# mkdir conf
[root@ansible-node1 ~]# yum -y install httpd
[root@ansible-node1 ~]# cp /etc/httpd/conf/httpd.conf conf/
[root@ansible-node1 ~]# vim conf/httpd.conf
Listen 8080
[root@ansible-node1 ~]# vim apache.yaml
- hosts: websrvsremote_user: roottasks:- name: install httpd packageyum: name=httpd state=latest- name: install configuration file or httpdcopy: src=/root/conf/httpd.conf dest=/etc/httpd/conf/httpd.conf- name: start httpd serviceservice: enabled=true name=httpd state=started[root@ansible-node1 ~]# grep -v '#' /etc/ansible/hosts
[websrvs]
192.168.93.102 [dbsrvs]
192.168.93.103 # 卸载被管理主机ansible-node2之前安装的httpd软件包(如果没有安装既不用做)
[root@ansible-node1 ~]# ansible websrvs -m yum -a 'name=httpd state=absent'[root@ansible-node1 ~]# ansible-playbook apache.yaml PLAY [websrvs] *****************************************************************TASK [Gathering Facts] *********************************************************
ok: [192.168.93.102]...# 查看上述命令执行结果
# 登录被管理主机ansible-node2进行查看执行结果
[root@ansible-node2 ~]# rpm -qa httpd
httpd-2.4.6-99.el7.centos.1.x86_64
[root@ansible-node2 ~]# grep "Listen" /etc/httpd/conf/httpd.conf | grep -v "#"
Listen 8080
[root@ansible-node2 ~]# systemctl status httpd | grep runningActive: active (running) since 日 2024-07-28 17:34:08 CST; 1min 41s ago
  • 如果配置文件有改动,如Apache端口号改变,则需要定义notify和handlers,触发更新相关执行操作
[root@ansible-node1 ~]# vim conf/httpd.conf
Listen 808
[root@ansible-node1 ~]# vim apache.yaml 
- hosts: websrvsremote_user: roottasks:- name: install httpd packageyum: name=httpd state=latest- name: install configuration file or httpdcopy: src=/root/conf/httpd.conf dest=/etc/httpd/conf/httpd.confnotify:   # 配置触发条件- restart httpd- name: start httpd serviceservice: enabled=true name=httpd state=startedhandlers: - name: restart httpd  # 指定触发器名称,要和notify中的触发器一样service: name=httpd state=restarted
[root@ansible-node1 ~]# ansible-playbook apache.yaml PLAY [websrvs] *****************************************************************TASK [Gathering Facts] *********************************************************
ok: [192.168.93.102]TASK [install httpd package] ***************************************************
ok: [192.168.93.102]TASK [install configuration file or httpd] *************************************
changed: [192.168.93.102]TASK [start httpd service] *****************************************************
ok: [192.168.93.102]
...# 登录被管理主机ansible-node2进行查看
[root@ansible-node2 ~]# lsof -i:808
COMMAND   PID   USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
httpd   10724   root    4u  IPv6  61117      0t0  TCP *:omirr (LISTEN)
httpd   10725 apache    4u  IPv6  61117      0t0  TCP *:omirr (LISTEN)
httpd   10726 apache    4u  IPv6  61117      0t0  TCP *:omirr (LISTEN)
httpd   10727 apache    4u  IPv6  61117      0t0  TCP *:omirr (LISTEN)
httpd   10728 apache    4u  IPv6  61117      0t0  TCP *:omirr (LISTEN)
httpd   10729 apache    4u  IPv6  61117      0t0  TCP *:omirr (LISTEN)
  • 如果想引入变量,则以上apache.yaml可以改写为如下内容
[root@ansible-node1 ~]# vim apache.yaml
- hosts: websrvsremote_user: rootvars:- package: httpd- service: httpdtasks:- name: install httpd packageyum: name={{ package }} state=latest- name: install configuration file or httpdcopy: src=/root/conf/httpd.conf dest=/etc/httpd/conf/httpd.confnotify:- restart httpd- name: start httpd serviceservice: enabled=true name={{ service }} state=startedhandlers:- name: restart httpdservice: name={{ service }} state=restarted
[root@ansible-node1 ~]# ansible-playbook apache.yaml PLAY [websrvs] *****************************************************************TASK [Gathering Facts] *********************************************************
ok: [192.168.93.102]TASK [install httpd package] ***************************************************
ok: [192.168.93.102]
...
  • 也可以直接引用Ansible的变量,如下所示。
[root@ansible-node1 ~]# vim test.yaml
- hosts: websrvsremote_user: roottasks:- name: copy filecopy: content="{{ ansible_all_ipv4_addresses }} dest=/tmp/vars.ans"
[root@ansible-node1 ~]# ansible-playbook test.yaml PLAY [websrvs] *****************************************************************TASK [Gathering Facts] *********************************************************
ok: [192.168.93.102]TASK [copy file] ***************************************************************
changed: [192.168.93.102]PLAY RECAP *********************************************************************
192.168.93.102             : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   # 查看上述命令执行结果
[root@ansible-node1 ~]# ansible websrvs -m command -a 'cat /tmp/vars.ans'
192.168.93.102 | CHANGED | rc=0 >>
["192.168.93.102"]
  • 引用Ansible主机变量的方法如下所示。
[root@ansible-node1 ~]# vim /etc/ansible/hosts 
[websrvs]
192.168.93.102 testvar="93.102"
[root@ansible-node1 ~]# vim test.yaml
- hosts: websrvsremote_user: roottasks:- name: copy filecopy: content="{{ ansible_all_ipv4_addresses }},{{ testvar }}" dest=/tmp/vars.ans
[root@ansible-node1 ~]# ansible-playbook test.yaml PLAY [websrvs] *****************************************************************TASK [Gathering Facts] *********************************************************
ok: [192.168.93.102]TASK [copy file] ***************************************************************
changed: [192.168.93.102]PLAY RECAP *********************************************************************
192.168.93.102             : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   # 查看上述命令执行结果
[root@ansible-node1 ~]# ansible websrvs -m command -a 'cat /tmp/vars.ans'
192.168.93.102 | CHANGED | rc=0 >>
([u'192.168.93.102'], 93.102)

3.5、Templates介绍

  • Jinja是基于Python的模板引擎。Template类似jinja的另一个重要组件,可以看作是一个编译过的模板文件。用来产生目标文本,传递Python的变量给模板去替换模板中的标记。
[root@ansible-node1 ~]# mkdir templates
[root@ansible-node1 ~]# cp conf/httpd.conf templates/httpd.conf.j2
[root@ansible-node1 ~]# vim templates/httpd.conf.j2
Listen {{ http_port }}
ServerName {{ ansible_fqdn }}
  • 使用主机变量定义一个变量名相同,值不同的变量的方法如下所示。
[root@ansible-node1 ~]# vim /etc/ansible/hosts
[websrvs]
192.168.93.102 http_port=8888[root@ansible-node1 ~]# vim apache.yaml
- hosts: websrvsremote_user: rootvars:- package: httpd- service: httpdtasks:- name: install httpd packageyum: name={{ package }} state=latest- name: install configuration file or httpdtemplate: src=/root/templates/httpd.conf.j2 dest=/etc/httpd/conf/httpd.confnotify:- restart httpd- name: start httpd serviceservice: enabled=true name={{ service }} state=startedhandlers:- name: restart httpdservice: name={{ service }} state=restarted
[root@ansible-node1 ~]# ansible-playbook apache.yaml PLAY [websrvs] *****************************************************************TASK [Gathering Facts] *********************************************************
ok: [192.168.93.102]TASK [install httpd package] ***************************************************
ok: [192.168.93.102]TASK [install configuration file or httpd] *************************************
changed: [192.168.93.102]TASK [start httpd service] *****************************************************
changed: [192.168.93.102]
...# 登录被管理主机ansible-node2,执行查看命令,如下所示
[root@ansible-node2 ~]# grep -i listen /etc/httpd/conf/httpd.conf | grep -v '#'
Listen 8888
[root@ansible-node2 ~]# grep -i servername /etc/httpd/conf/httpd.conf | grep -v '#'
ServerName ansible-node2

3.6、Tages介绍

  • 如果多次去执行修改的Playbook时,涉及到一些没有变化的代码,可以使用tages让用户选择跳过没有变化代码,只运行Playbook中发生变化的部署代码。可以在Playbook中为某个或某些任务定义“标签”,在执行此Playbook时通过ansible-playbook命令的–tags选项能实现仅运行指定的tasks而非所有的tasks。
# 示例:自动化部署Apache服务,并查看部署结果。然后修改Apache端口号,并重新自动化部署Apache服务,最后查看更新配置是否生效
[root@ansible-node1 ~]# vim apache.yaml 
- hosts: websrvsremote_user: rootvars:- package: httpd- service: httpdtasks:- name: install httpd packageyum: name={{ package }} state=latest- name: install configuration file or httpdtemplate: src=/root/templates/httpd.conf.j2 dest=/etc/httpd/conf/httpd.conftags:- confnotify:- restart httpd- name: start httpd serviceservice: enabled=true name={{ service }} state=startedhandlers:- name: restart httpdservice: name={{ service }} state=restarted# 修改被管理主机ansible-node2的httpd服务端口为9999,如下所示
[root@ansible-node1 ~]# vim /etc/ansible/hosts
[websrvs]
192.168.93.102 http_port=9999
[root@ansible-node1 ~]# ansible-playbook apache.yaml --tags="conf"PLAY [websrvs] *****************************************************************TASK [Gathering Facts] *********************************************************
ok: [192.168.93.102]TASK [install configuration file or httpd] *************************************
changed: [192.168.93.102]RUNNING HANDLER [restart httpd] ************************************************
changed: [192.168.93.102]PLAY RECAP *********************************************************************
192.168.93.102             : ok=3    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0  
  • 如果要始终在Playbook中运行某些代码,可以使用tags:always进行标注。示例如下
[root@ansible-node1 ~]# vim apache.yaml
- hosts: websrvsremote_user: rootvars:- package: httpd- service: httpdtasks:- name: install httpd packageyum: name={{ package }} state=latesttags:- always- name: install configuration file or httpdtemplate: src=/root/templates/httpd.conf.j2 dest=/etc/httpd/conf/httpd.conftags:- confnotify:- restart httpd- name: start httpd serviceservice: enabled=true name={{ service }} state=startedhandlers:- name: restart httpdservice: name={{ service }} state=restarted

3.7、Roles介绍

  • Ansible为了层次化、结构化地组织Playbook,使用了角色(roles),可以根据层次结构自动装载变量文件、tasks以及handlers等。只需要在Playbook中使用include指令便可使用roles。简单来将,roles就是分别将变量、文件、任务、模块及处理器设置于单独的目录中,便捷地使用它们。
# roles示例:
site.yaml  # 主接口
webservers.yaml
fooservers.yaml
roles/common/file/templates/tasks/handlers/vars/meta/webservers/files/templates/tasks/handlers/vars/meta/
  • 而在Playbook中,可以这样使用roles。
- hosts: webserversroles:- common- webservers
  • 也可以向roles传递参数,如下所示
- hosts: webserversroles:- common- { role: foo_app_instance,dir: '/opt/a',port: 5000}- { role: foo_app_instance,dir: '/opt/b',port: 5001}
  • 也可以条件地使用roles,如下所示
- hosts: webserverstoles:- { role: some_role,when: "ansible_os_family == 'RedHat'"}
  • 创建roles时一般分为如下的步骤:首先要创建已roles命名的目录,然后再roles目录中分别创建以各角色名称命名的目录,如webservers等。在每个角色命名的目录中分别创建files、handlers、meta、tasks、templatest和vars目录。用不到的目录可以创建为空目录,也可以不创建。最后在Playbook文件中调用各角色使用。

    • Role中各个目录中涉及的文件归纳如下:
      • tasks目录:至少应该包含一个名为main.yaml的文件,用来定义此角色的任务列表,此文件可以使用include包含其他的位于此目录中的task文件
      • files目录:存放由copy或script等模块调用的文件
      • templates目录:template模块会自动此目录中寻找jinja2模板文件
      • handlers目录:此目录中应用包含一个main
      • yaml文件:用于定义此角色用到的各handler,在handler中使用include包含的其他handler文件也应该位于此目录中
      • vars目录:应当包含一个main.yaml文件,用于定义此角色用到的变量
      • meta目录:应当包含一个main.yaml文件,用于定义此角色的特殊设定及其依赖关系,ansible1.3及其后的版本才支持
      • default目录:为当前角色默认变量时使用此目录:应当包含一个main.yaml文件
  • Role的简单示例如下所示:

# 创建所需目录
[root@ansible-node1 ~]# mkdir -p ansible_playbooks/roles/{websrvs,dbsrvs}/{tasks,files,templates.meta,handlers,vars}# 查看目录结构如下所示
[root@ansible-node1 ~]# tree ansible_playbooks/
ansible_playbooks/
└── roles├── dbsrvs│   ├── files│   ├── handlers│   ├── tasks│   ├── templates.meta│   └── vars└── websrvs├── files├── handlers├── tasks├── templates.meta└── vars13 directories, 0 files# 进入到websrvs组创建task
[root@ansible-node1 ~]# cd ansible_playbooks/roles/websrvs/
[root@ansible-node1 websrvs]# ls
files  handlers  tasks  templates.meta  vars
[root@ansible-node1 websrvs]# cp /etc/httpd/conf/httpd.conf files/
[root@ansible-node1 websrvs]# vim tasks/main.yml
- name: install httpd packageyum: name=httpd
- name: install configuration filecopy: src=httpd.conf dest=/etc/httpd/conf/httpd.conftags:- confnotify:- restart httpd
- name: start httpdservice: name=httpd state=started
[root@ansible-node1 websrvs]# vim handlers/main.yml
- name: restart httpdservice: name=httpd state=restarted
[root@ansible-node1 websrvs]# cd /root/ansible_playbooks/
[root@ansible-node1 ansible_playbooks]# ls
roles# 创建入口文件
[root@ansible-node1 ansible_playbooks]# vim site.yml
- hosts: websrvsremote_user: rootroles:- websrvs
[root@ansible-node1 ansible_playbooks]# ansible-playbook site.yml PLAY [websrvs] *****************************************************************TASK [Gathering Facts] *********************************************************
ok: [192.168.93.102]TASK [websrvs : install httpd package] *****************************************
ok: [192.168.93.102]TASK [websrvs : install configuration file] ************************************
changed: [192.168.93.102]
...# 为了更加直观修改site.yml,下面设置针对不同主机区调用不同的角色
[root@ansible-node1 ansible_playbooks]# vim site.yml 
- hosts: 192.168.93.102remote_user: rootroles:- websrvs
- hosts: 192.168.93.103remote_user: rootroles:- dbsrvs# 部署dbsrvs相关的组自动安装mariadb数据库
[root@ansible-node1 ansible_playbooks]# cd roles/dbsrvs/
[root@ansible-node1 dbsrvs]# cp /etc/my.cnf files/
[root@ansible-node1 dbsrvs]# vim tasks/main.yml
- name: install mariadb-server packageyum: name=mariadb-server state=latest
- name: install configuration filecopy: src=my.cnf dest=/etc/my.cnftags:- myconfnotify:- restart mariadb
- name: start mariadb-serivceservice: name=mariadb enabled=true state=started# 编辑配置文件变动触发重启mariadb服务
[root@ansible-node1 dbsrvs]# vim handlers/main.yml
- name: restart mariadbservice: name=mariadb state=restarted
[root@ansible-node1 dbsrvs]# cd /root/ansible_playbooks/
[root@ansible-node1 ansible_playbooks]# ansible-playbook site.yml PLAY [192.168.93.102] **********************************************************TASK [Gathering Facts] *********************************************************
ok: [192.168.93.102]TASK [websrvs : install httpd package] *****************************************
ok: [192.168.93.102]TASK [websrvs : install configuration file] ************************************
ok: [192.168.93.102]TASK [websrvs : start httpd] ***************************************************
ok: [192.168.93.102]PLAY [192.168.93.103] **********************************************************TASK [Gathering Facts] *********************************************************
ok: [192.168.93.103]TASK [dbsrvs : install mariadb-server package] *********************************
changed: [192.168.93.103]
...# 登录被管理主机ansible-node3查看数据库是否启动
[root@ansible-node3 ~]# netstat -anpt | grep 3306
tcp        0      0 0.0.0.0:3306            0.0.0.0:*               LISTEN      22262/mysqld
  • 下面是创建roles时的注意事项:
    • 目录名同角色名的定义
    • 目录结构有固定格式:
      • files:静态文件
      • templates:Jianjia2模板文件
      • tasks:至少有main.yml,定义各tasks
      • handlers:至少有一个main.yml,定义各handlers
      • vars:至少有一个main.yml,定义变量
      • meta:定义依赖关系等信息
    • 在roles之外,通过site.yml定义Playbook,额外也可以有其他的yml

备注

Playbook示例1

[root@ansible-node1 ~]# cat test.yaml 
---
- hosts: allremote_user: roottasks:# 安装模块- name: install httpd yum: name=httpd state=latest# 启动模块- name: start httpdservice: name=httpd state=started# shell模块- name: write htmlshell: echo ok > /tmp/index.html[root@ansible-node1 ~]# ansible-playbook test.yaml

Playbook示例2

[root@ansible-node1 ~]# cat test.yaml 
---
- hosts: allremote_user: roottasks:- name: install httpd yum: name=httpd state=latest- name: start httpdservice: name=httpd state=started- name: write htmlshell: echo ok > /tmp/index.html- name: config filetemplate: src=/root/httpd.conf.j2 dest=/tmp/httpd.confnotify:- restart httpdhandlers: - name: stop httpdservice: name=httpd state=stopped- name: restart httpdservice: name=httpd state=restarted# 创建j2文件
[root@ansible-node1 ~]# cat /root/httpd.conf.j2 
Listen 80[root@ansible-node1 ~]# ansible-playbook test.yaml

Playbook示例3

[root@ansible-node1 ~]# cat test.yaml 
---
- hosts: allremote_user: rootvars:- pkgs: - httpd- tree- telnettasks:- name: install packagesyum: name={{ item }} state=latestloop: "{{ pkgs }}"- name: start httpdservice: name=httpd state=started- name: write htmlshell: echo ok > /tmp/index.html- name: config filetemplate: src=/root/httpd.conf.j2 dest=/tmp/httpd.confnotify:- restart httpdhandlers: - name: stop httpdservice: name=httpd state=stopped- name: restart httpdservice: name=httpd state=restarted

官方文档

  • http://www.ansible.com.cn/docs/playbooks_loops.html

相关文章:

【云平台监控】安装应用Ansible服务

安装应用Ansible服务 文章目录 安装应用Ansible服务资源列表基础环境一、安装Ansible1.1、部署Ansible1.2、配置主机清单1.2.1、方法11.2.2、方法2 二、Ansible命令应用基础2.1、ping模块2.2、command模块2.3、user模块2.4、group模块2.5、cron模块2.6、copy模块2.7、file模块2…...

项目执行中的目标管理:从战略到落地的闭环实践

——如何让目标不“跑偏”、团队不“掉队”&#xff1f; 引言&#xff1a;为什么目标管理决定项目成败&#xff1f; 根据PMI研究&#xff0c;47%的项目失败源于目标模糊或频繁变更。在复杂多变的项目环境中&#xff0c;目标管理不仅是制定KPI&#xff0c;更是构建“方向感-执行…...

如何优雅地处理 API 版本控制?

API 会不断发展&#xff0c;而用户的需求也会随之变化。那么&#xff0c;如何确保你的 API 在升级时不会影响现有用户&#xff1f;答案就是&#xff1a;API 版本控制。就像你更新了一个应用程序&#xff0c;引入了新功能&#xff0c;但旧功能仍然保留&#xff0c;让老用户继续愉…...

如何通过Radius认证服务器实现虚拟云桌面安全登录认证:安当ASP身份认证系统解决方案

引言&#xff1a;虚拟化时代的安全挑战 随着云计算和远程办公的普及&#xff0c;虚拟云桌面&#xff08;如VMware Horizon、Citrix&#xff09;已成为企业数字化办公的核心基础设施。然而&#xff0c;传统的用户名密码认证方式暴露了诸多安全隐患&#xff1a;弱密码易被暴力破…...

自然语言处理spaCy

spaCy 是一个流行的开源 自然语言处理&#xff08;NLP&#xff09; 库&#xff0c;专注于 高效、易用和工业化应用。它由 Explosion AI 开发&#xff0c;广泛应用于文本处理、信息提取、机器翻译等领域。 zh_core_web_sm 是 spaCy 提供的一个小型中文预训练语言模型&#xff0…...

大语言模型(LLMs)中的强化学习(Reinforcement Learning, RL)

第一部分&#xff1a;强化学习基础回顾 在深入探讨LLMs中的强化学习之前&#xff0c;我们先快速回顾一下强化学习的核心概念&#xff0c;确保基础扎实。 1. 强化学习是什么&#xff1f; 强化学习是一种机器学习范式&#xff0c;目标是让智能体&#xff08;Agent&#xff09;…...

数字后端实现Innovus DRC Violation之如何利用脚本批量解决G4:M7i DRC Violation

大家在跑完物理验证calibre DRC之后&#xff0c;会发现DRC里面存在一种G4:M7i的DRC违例&#xff0c;这种违例一般都是出现在memory的边界。今天教大家如何利用脚本来批量处理这一类DRC问题的解决。 首先&#xff0c;我们需要把calibre的DRC结果读取到innovus里面来&#xff0c…...

Java版企业电子招标采购系统源业码Spring Cloud + Spring Boot +二次开发+ MybatisPlus + Redis

功能描述 1、门户管理&#xff1a;所有用户可在门户页面查看所有的公告信息及相关的通知信息。主要板块包含&#xff1a;招标公告、非招标公告、系统通知、政策法规。 2、立项管理&#xff1a;企业用户可对需要采购的项目进行立项申请&#xff0c;并提交审批&#xff0c;查看所…...

CTF web入门之文件上传

知识点 产生文件上传漏洞的原因 原因: 对于上传文件的后缀名(扩展名)没有做较为严格的限制 对于上传文件的MIMETYPE(用于描述文件的类型的一种表述方法) 没有做检查 权限上没有对于上传的文件目录设置不可执行权限,(尤其是对于shebang类型的文件) 对于web server对于上传…...

ArmSoM Sige5 CM5:RK3576 上 Ultralytics YOLOv11 边缘计算新标杆

在计算机视觉技术加速落地的今天&#xff0c;ArmSoM 正式宣布其基于 ​​Rockchip RK3576​​ 的旗舰产品 ​​Sige5 开发板​​ 和 ​​CM5 核心板​​ 全面支持 Ultralytics YOLOv11 模型的 RKNN 部署。这一突破标志着边缘计算领域迎来新一代高性能、低功耗的 AI 解决方案&am…...

游戏引擎学习第224天

回顾游戏运行并指出一个明显的图像问题。 回顾一下之前那个算法 我们今天要做一点预加载的处理。上周刚完成了游戏序章部分的所有剪辑内容。在运行这一部分时&#xff0c;如果观察得足够仔细&#xff0c;就会注意到一个问题。虽然因为视频流压缩质量较低&#xff0c;很难清楚…...

PN1-S25系列ProfiNet网关模组产品方案

PN1-S25系列ProfiNet网关模组是一款专为工业通信环境设计的先进设备&#xff0c;旨在实现ProfiNet与Modbus RTU协议之间的无缝转换&#xff0c;从而优化工业自动化系统中的数据传输效率。以下是对该系列ProfiNet网关模组产品的详细介绍&#xff1a; 一、ProfiNet网关模组功能特…...

提示工程指南学习记录(三)

提示词示例 文本概括 Explain the above in one sentence&#xff08;用一句话解释上面的信息&#xff09;&#xff1a; 提示词工程是一种用于自然语言处理的任务&#xff0c;目的是通过给定的文本或语音输入来生成相应的输出。它基于预训练的大型语言模型&#xff0c;例如通…...

04 GE - 钳制属性,等级

1.PostGameplayEffectExecute 1.作用&#xff1a;在这里对生命值进行最后的钳制防止越界。 2.参数中有什么&#xff1a; FGameplayEffectModCallbackData //传进来的值 {EffectSpec; //GESpecTargetASC //目标ASCFGameplayModifierEvaluatedData& EvaluatedData{Magni…...

【机器学习】机器学习笔记

1 机器学习定义 计算机程序从经验E中学习&#xff0c;解决某一任务T&#xff0c;进行某一性能P&#xff0c;通过P测定在T上的表现因经验E而提高。 eg&#xff1a;跳棋程序 E&#xff1a; 程序自身下的上万盘棋局 T&#xff1a; 下跳棋 P&#xff1a; 与新对手下跳棋时赢的概率…...

使用SSE实现实时消息推送并语音播报:从后端到前端的完整指南

前言 在现代Web应用中&#xff0c;实时消息推送已成为提升用户体验的关键功能。无论是即时聊天、通知提醒还是实时数据更新&#xff0c;都需要一种高效的服务器到客户端的通信机制。本文将详细介绍如何使用Server-Sent Events (SSE)技术实现后端向前端的实时消息推送&#xff…...

交通运输部4项网络与数据安全标准发布

近日&#xff0c;交通运输部审查通过并发布《交通运输数据安全风险评估指南》《交通运输行业网络安全实战演练工作规程》《交通运输电子证照数据交换与应用要求》《冷藏集装箱智能终端技术规范》等 4 项交通运输行业标准&#xff08;2025 年第 3 批&#xff09;。 ​其中&#…...

HarmonyOS-ArkUI V2装饰器: @Monitor装饰器:状态变量修改监听

Monitor作用 Monitor的作用就是来监听状态变量的值变化的。被Monitor修饰的函数,会在其对应监听的变量发生值的变化时,回调此函数,从而可以让您知道是什么值发生变化了,变化前是什么值,变化后是什么值。 V1版本的装饰器,有个叫@Watch的装饰器,其实也有监听变化的能力,…...

在Ubuntu系统中运行Windows程序

在Ubuntu系统中运行Windows程序可通过以下方法实现&#xff0c;根据使用场景和需求选择最适合的方案&#xff1a; 一、使用Wine兼容层&#xff08;推荐轻量级场景&#xff09; 原理&#xff1a;通过模拟Windows API环境直接运行.exe文件&#xff0c;无需安装完整系统。 步骤&a…...

七大数据库全面对比:ClickHouse、ES、MySQL等特性、优缺点及使用场景

七大数据库全面对比:ClickHouse、ES、MySQL等特性、优缺点及使用场景 引言 在数字化时代,数据库的选择对于业务的成功至关重要。本文将通过表格形式,对ClickHouse、Elasticsearch(ES)、MySQL、SQL Server、MongoDB、HBase、Cassandra这七大数据库进行特性、优缺点及使用…...

循环神经网络 - 门控循环单元网络之参数学习

GRU&#xff08;门控循环单元&#xff09;的参数学习与其他循环神经网络类似&#xff0c;主要依赖于梯度下降和反向传播通过时间&#xff08;BPTT&#xff09;算法。下面我们通过一个简单例子来说明 GRU 参数是如何在训练过程中“自适应”调整的。 一、GRU参数学习 假设我们的…...

Java并发编程面试题:内存模型(6题)

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家&#xff0c;历代文学网&#xff08;PC端可以访问&#xff1a;https://literature.sinhy.com/#/?__c1000&#xff0c;移动端可微信小程序搜索“历代文学”&#xff09;总架构师&#xff0c;15年工作经验&#xff0c;精通Java编…...

SpringBoot Starter自定义:创建可复用的自动配置模块

文章目录 引言一、自定义Starter基础知识二、创建自动配置模块2.1 项目结构搭建2.2 配置属性类2.3 服务接口及实现2.4 自动配置类2.5 spring.factories文件2.6 Maven依赖配置 三、创建Starter模块3.1 项目结构3.2 Maven依赖配置 四、使用自定义Starter4.1 添加依赖4.2 配置属性…...

服务器风扇故障导致过热问题的解决方案

# 服务器风扇故障导致过热问题的解决方案 ## 一、故障诊断与确认 ### 1. 确认风扇故障现象 bash # 检查系统日志中的硬件错误 dmesg | grep -i fan journalctl -b | grep -i thermal # 查看传感器数据&#xff08;需要安装lm-sensors&#xff09; sudo sensors-detect sudo …...

[OS] vDSO + vvar(频繁调用的处理) | 存储:寄存器(高效)和栈(空间大)| ELF标准包装规范(加速程序加载)

vDSO vvar 一、社区公告板系统&#xff08;类比 vDSO vvar&#xff09; 想象你住在一个大型社区&#xff0c;管理员&#xff08;内核&#xff09;需要向居民&#xff08;用户程序&#xff09;提供实时信息&#xff08;如天气预报、社区活动时间等&#xff09;。直接让每个居…...

SQL刷题日志(day1)

1、substring_index&#xff08;截取字符串&#xff09; 参数说明&#xff1a; profile&#xff1a;要处理的字符串字段。,&#xff1a;分隔符。-1&#xff1a;表示从字符串的右侧开始截取&#xff0c;第一个出现的分隔符后面的所有内容。 SELECT SUBSTRING_INDEX(profile, ,…...

爬虫:一文掌握 curl-cffi 的详细使用(支持 TLS/JA3 指纹仿真的 cURL 库)

更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 一、curl-cffi 概述1.1 curl-cffi介绍1.2 主要特性1.3 适用场景1.4 使用 curl-cffi 的注意事项1.5 与 requests 和 pycurl 对比1.6 curl-cffi 的安装二、基本使用2.1 同步请求2.2 异步请求三、高级功能3.1 模拟浏览器指…...

前端开发基础:HTML 与 CSS 入门详解

目录 一、HTML 基础 &#xff08;一&#xff09;HTML 概述 &#xff08;二&#xff09;HTML 标签 标签分类 常用标签详解 &#xff08;三&#xff09;HTML 注释 二、CSS 样式 &#xff08;一&#xff09;CSS 概述 &#xff08;二&#xff09;CSS 引入方式 &#xff0…...

实时语音交互数字人VideoChat,可自定义形象与音色,支持音色克隆,首包延迟低至3s

简介 实时语音交互数字人&#xff0c;支持端到端语音方案&#xff08;GLM-4-Voice - THG&#xff09;和级联方案&#xff08;ASR-LLM-TTS-THG&#xff09;。用户可通过麦克风或文本输入&#xff0c;与数字人进行语音或视频交互。 目前支持的功能 支持自定义形象TTS模块添加音…...

25.OpenCV中的霍夫圆变换

OpenCV中的霍夫圆变换 在图像处理与计算机视觉中&#xff0c;圆形检测是一项常见的任务&#xff0c;应用场景包括车牌识别、瞳孔检测、交通标志识别等。霍夫圆变换&#xff08;Hough Circle Transform&#xff09;是一种高效且鲁棒的算法&#xff0c;通过在参数空间中寻找局部…...

OpenTiny使用指南

最近项目里用到了一个新的组件库——OpenTiny&#xff0c;但是官方文档的使用指南的描述很复杂&#xff0c;花了一些时间尝试才正常使用。下面是一个使用步骤的描述&#xff0c;可放心食用&#xff1a; 一、安装 TinyVue 组件库同时支持 Vue 2.0 和 Vue 3.0 框架&#xff0c;…...

Uniapp: 大纲

目录 一、基础巩固1.1、Uniapp:下拉选择框ba-tree-picker 二、项目配置2.1、Uniapp&#xff1a;修改端口号2.2、Uniapp&#xff1a;本地存储 一、基础巩固 1.1、Uniapp:下拉选择框ba-tree-picker 二、项目配置 2.1、Uniapp&#xff1a;修改端口号 2.2、Uniapp&#xff1a;本…...

A2A协议实现详解及示例

A2A协议概述 A2A (Agent2Agent) 是Google推出的一个开放协议&#xff0c;旨在使AI智能体能够安全地相互通信和协作。该协议打破了孤立智能体系统之间的壁垒&#xff0c;实现了复杂的跨应用自动化。[1] A2A协议的核心目标是让不同的AI代理能够相互通信、安全地交换信息以及在各…...

HTTP协议入门

文章目录 1. 概述2. 请求协议2.1 Get 方式请求协议2.2 POST 方式的请求2.3 获取请求数据 3. 响应协议3.1 响应数据格式3.2 设置响应数据 1. 概述 概念 &#xff1a;Hyper Text Transfer Protocol&#xff0c;超文本传输协议&#xff0c;规定了浏览器和服务器之间数据传输的规则…...

远程控制Android手机(web-scrcpy)

最近有web远程查看和控制Android手机的需求&#xff0c;研究了一下scrcpy&#xff0c;发现还是比较容易实现远程控制&#xff0c;所以自己就用flask写了一个web远程控制的scrcpy&#xff0c;算是推荐一下自己的作品&#xff0c;作品地址&#xff1a;https://github.com/baixin1…...

在AWS EC2上部署网站的完整步骤指南

本文详细介绍如何从零开始在AWS EC2实例上部署静态/动态网站&#xff0c;涵盖实例创建、安全组配置、环境搭建及域名绑定等关键步骤。 一、准备工作 AWS账号&#xff1a;访问 AWS官网 注册账号并完成信用卡绑定 本地工具&#xff1a; SSH客户端&#xff08;Mac/Linux自带终端&…...

CentOS下,Xftp中文文件名乱码的处理方式

乱码原因 中文版Windows默认使用GBK编码&#xff0c;现代Linux发行版&#xff08;如CentOS、Ubuntu等&#xff09;默认使用UTF-8编码。Windows下正常的编码&#xff0c;可能在linux下无法识别&#xff0c;例如&#xff1a;Windows的GBK字节0xD6D0被Linux用UTF-8解码时&#xf…...

Linux vagrant 导入ubuntu到virtualbox

前言 vagrant 导入ubuntu虚拟机 前提要求 安装 virtualbox 和vagrant<vagrant-disksize> (Linux 方式 Windows 方式) 创建一键部署ubuntu虚拟机 /opt/vagrant 安装目录/opt/VirtualBox 安装目录/opt/ubuntu22/Vagrantfile &#xff08;可配置网络IP&#xff0c;内存…...

2025高频面试算法总结篇【动态规划】

文章目录 直接刷题链接直达编辑距离最长回文子串完全平方数最长递增子序列正则表达式匹配零钱兑换鸡蛋掉落单词拆分 直接刷题链接直达 动态规划&#xff08;Dynamic Programming, DP&#xff09;是一种通过拆解子问题并利用子问题的最优解来构建整体问题的最优解的方法&#x…...

FPGA_UART

1.UART 概述 &#xff08;通用异步收发传输器&#xff09; 1. 基本定义 UART&#xff08;Universal Asynchronous Receiver/Transmitter&#xff09;是一种常见的串行通信协议&#xff0c;用于在设备间通过异步串行通信传输数据。它不依赖独立的时钟信号&#xff0c;而是通过预…...

绿算轻舟系列FPGA加速卡:驱动数字化转型的核心动力

在数字化浪潮席卷全球的今天&#xff0c;算力已成为推动企业创新和行业升级的核心引擎。绿算轻舟系列FPGA加速卡凭借其高性能、低延迟、高能效比的独特优势&#xff0c;正成为各领域智能化转型的“隐形加速器”。它以灵活的硬件架构和强大的并行计算能力&#xff0c;为复杂场景…...

gitee基本使用

git实用手册 git全局设置 git config --global user.name "yourname" git config --global user.email "youremail"推代码时的账号&#xff08;email) 版本回退 git loggit reset –hard <码>git push -f HTTPS步骤(上传) 拉取项目 1、新建一个…...

最短路径介绍

最短路径是图论中的算法&#xff0c;下面将列举几个常见的算法&#xff1a; &#x1f697; 一、单源最短路径&#xff08;一个起点到所有点&#xff09; 1. Dijkstra 算法 适用图&#xff1a;非负权图&#xff08;不能有负权边&#xff09; 思路&#xff1a;贪心 最小堆&am…...

VRRP 基础全解析:从结构到配置

目录 VRRP基本概述 VRRP基本结构 状态机 ​编辑 负载分担 &#xff08;多个VRRP&#xff09; VRRP基本概述 VRRP能够在不改变组网的情况下&#xff0c;将多台路由器虚拟成一个虚拟路由器&#xff0c;通过配置虚拟路由器的IP地址为默认网关&#xff0c;实现网关的备份。协…...

【NIO番外篇】之组件 Buffer

目录 一、Buffer&#xff1a;数据界的“快递小哥”/“临时仓库管理员” &#x1f609;什么是 Buffer&#xff1f;它的作用是什么&#xff1f; 二、Buffer 的“三围”和“书签”&#x1f4cc;&#xff1a;核心属性1. Capacity (容量)&#xff1a;2. Position (位置)&#xff1a;…...

Python基础知识(一、基础语法)

Python基础知识&#xff08;一、基础语法&#xff09; 字面量注释单行注释多行注释 变量数据类型数据类型查看数据类型转换 标识符命名规范不可使用关键字 运算符算数运算符赋值运算符 字符串字符串的定义方式字符串拼接占位拼接数字精度控制快速格式化 数据输入逻辑运算比较运…...

C语言题目自增在前与在后

一、题目引入 谨记真言: i的值最终都会改变 只是表达式的值不同 二、分析题目 if判断语句里面要条件为真执行时 printf语句 i 变量在前 使用i的当前值是1 i的值就是1与1相等 所以&&左边的为真 但是&&存在 必须前后都为真才为真 所以还要看&&后面…...

【口腔粘膜鳞状细胞癌】文献阅读

写在前面 看看文章&#xff0c;看看有没有思路 文献 The regulatory role of cancer stem cell marker gene CXCR4 in the growth and metastasis of gastric cancer IF:6.8 中科院分区:1区 医学WOS分区: Q1 目的&#xff1a;通过 scRNA-seq 结合大量 RNA-seq 揭示癌症干细胞…...

如何撤回刚提交的 commit

如何撤回刚提交的 commit 如果刚刚执行了 git commit 但想撤销这个提交&#xff0c;有几种方法可以实现&#xff0c;具体取决于你想达到的效果&#xff1a; 1. 撤销 commit 但保留更改&#xff08;修改回到暂存区&#xff09; git reset --soft HEAD~1这会撤销最后一次提交提…...

deepin使用autokey添加微信快捷键一键显隐ctrl+alt+w

打开deepin商店&#xff0c;搜索快捷键&#xff0c;找到autokey 快捷键管理&#xff0c;点击安装 点击右键新建文件夹 点击右键新建脚本 打开脚本并添加以下内容 import subprocess import time# ------------------ 配置项 ------------------ WM_CLASS "wechat…...