[Ansible实践笔记]自动化运维工具Ansible(一):初探ansibleansible的点对点模式

文章目录

    • Ansible介绍
      • 核心组件
      • 任务执行方式
    • 实验前的准备
      • 更新拓展安装包仓库
      • 在ansible主机上配置ip与主机名的对应关系
      • 生成密钥对
      • 将公钥发送到被管理端,实现免密登录
      • 测试一下是否实现免密登录
    • 常用工具
        • ansible
        • ansible—doc
        • ansible—playbook
      • 主要配置文件
    • Ansible 模块
      • 配置主机清单
      • 配置主配置文件(默认可以不改)
      • Ansible的执行状态
      • Ansible常用模块
        • ping模块
        • group模块
          • 查看group模块的用法
          • 实例:对node1主机组的成员(即server1)创建一个ID为111、名称为IT的组
          • 创建一个gid已经存在的组
          • 删除刚刚创建的组
      • user模块
        • 查看user模块的用法
        • 实例:在主机组node1(server1)上创建一个系统用户zs,家目录为/home/zhangsan,uid为111,附加组为IT,以及给一个注释
        • 删除刚刚的用户zs
      • command模块
        • 查看command模块的使用
        • 实例
          • 1.在所有服务器上创建文件
          • 2.在所有服务器上查询所有以`_test`结尾的文件
          • 3.删除刚刚创建的/root/command_test
      • shell模块
        • 实例
      • script模块
        • 参数说明
        • 实例
      • copy模块
        • 参数解释
        • 实例:将本地/root目录下的文件复制到目标服务器,并改名
        • 将本地文件复制到目标服务器,并指定属组和属主
        • 传输文件时修改权限信息
        • 创建一个文件并直接编辑
      • file模块
        • 查看参数说明
        • 创建目录(指定属组属主以及权限)
        • 创建文件
        • 删除目录/文件
        • 创建软连接
        • 创建硬链接
      • yum模块
        • 查看参数
      • service模块
      • setup模块
      • Selinux模块
        • 参数

Ansible介绍

  • 通过一个机器控制若干个机器
  • 机器间通过ssh协议传送指令
  • 基于模块部署,ansible仅提供框架

核心组件

在这里插入图片描述

组件功能
Ansible核心程序
Host Inventory记录由ansible管理的主机信息(包括端口、密码、IP等)
Playbook存放多个任务的yaml格式文件,定义主机需要调用哪些模块完成功能
Core Modules通过调用核心模块完成ansible任务
Custom Modules完成核心模块不支持的功能
Connetion Plugins用于主机和远程服务器的连接

任务执行方式

  • 点对点

    • 使用单个模块,支持批量执行单条命令
    • 一般用于可快速执行的操作
    • 如对大量服务器执行shell或某个Linux命令
  • 剧本模式

    • 通过编写yaml文件组合多个任务(task)
    • 适用需要执行较为复杂的命令
    • 如对大量服务器配置Nginx的网站服务

实验前的准备

三台机器

主机名及作用IP
ansile(ansible主机)192.168.28.88
server1192.168.28.66
server2192.168.28.77
可以再加几台模拟大场景192.168.28.x

在这里插入图片描述

更新拓展安装包仓库

yum -y install epel-release

在ansible主机上配置ip与主机名的对应关系

# vim /etc/hosts
.....
192.168.28.66 server1
192.168.28.77 server2
.....

生成密钥对

# ansible主机上执行
ssh-keygen -P "" -t rsa # 注意这里的P是大写

在这里插入图片描述

将公钥发送到被管理端,实现免密登录

 ssh-copy-id -i /root/.ssh/id_rsa.pub root@server1ssh-copy-id -i /root/.ssh/id_rsa.pub root@server2ssh-copy-id -i /root/.ssh/id_rsa.pub root@server3

在这里插入图片描述

测试一下是否实现免密登录

ssh root@server1
exit
ssh root@server2
exit

在这里插入图片描述

常用工具

ansible

常用于执行临时命令

ansible—doc

常用于模块功能的查询

ansible—playbook

角色目录(剧本)

主要配置文件

  • /etc/ansible.cfg:主配置文件
  • /etc/ansible/hosts:主机清单文件
  • /etc/ansible/roles:角色目录

Ansible 模块

配置主机清单

编辑/etc/ansible/hosts文件,在最后面加上被管理端

vim /etc/ansible/hosts········繁杂的注释········
[all_servers]  # 这部分没配置主机与IP地址的对应关系时应填写服务器IP
server1        # 如192.168.28.66
server2			        # 如192.168.28.77[node1]        # ansible靠方框里的名称识别服务器
server1[node2]
server2
server1[node3]
server2
server3

配置主配置文件(默认可以不改)

编辑/etc/ansible/ansible.cfg

[defaults]# some basic default values...#inventory      = /etc/ansible/hosts             # 定义主机清单文件的位置
#library        = /usr/share/my_modules/          # 定义库文件的存放位置   
#remote_tmp     = ~/.ansible/tmp                # 临时文件的远程存放目录
#local_tmp      = ~/.ansible/tmp                 # 临时文件的本地存放目录
#sudo_user      = root   																		                        # 默认超级用户
#transport      = smart                        # 默认传输选项,smart选项自动选择合适的传输机制
#remote_port    = 22                          # 传输端口

Ansible的执行状态

  • 绿色——>执行成功且不需要做改变的操作
  • 黄色——>执行成功但对目标主机做变更
  • 红色——>执行失败
  • 粉色——>触发警告
  • 蓝色——>显示ansible命令的执行过程

Ansible常用模块

ping模块

测试与主机的联通性

例子

ansible -m ping all_servers

在这里插入图片描述

server2 | SUCCESS => { "ansible_facts": {  "discovered_interpreter_python": "/usr/bin/python"},"changed": false,"ping": "pong"
}
# "success"表示Ansible成功执行了任务
#  "ansible_facts"为一个字典,包含ansible任务执行期间收集到的所有事实
# "discovered_interpreter_python" 一个事实,指定目标主机上的python解释器目录为 "/usr/bin/python"
#  "changed": false 表示没有对主机进行任何更改
#  "ping": "pong",一个简单的回应,结果为pong,表示与目标主机连接正常

我们再把server1关掉试试

ansible -m ping all_servers

显示 server1不可达,并且显示红色
group模块

用于创建和修改用户组

查看group模块的用法
ansible-doc -s group

在这里插入图片描述

 gid   #设置用户组IDname  #设置组名称state #设置组状态,默认为创建,设置为absent为删除system #设置为yes表示创建系统组
实例:对node1主机组的成员(即server1)创建一个ID为111、名称为IT的组
 ansible -m group -a "name=IT gid=111 system=yes" node1

在这里插入图片描述

我们将上面的命令再执行一遍

在这里插入图片描述

发现结果由黄色变成了绿色的,这说明ansible具有幂等性,一种操作多次重复执行结果相同

我们到server1上看看 有没有成功

# 查看server1的组的后五行数据
tail -n 5 -f /etc/group
# 或者cat /etc/group

在这里插入图片描述

创建一个gid已经存在的组
 ansible -m group -a "name=false gid=1000 system=yes" node1

在这里插入图片描述

创建失败,并且返回msg"GID1000已经存在"
删除刚刚创建的组
 ansible node1 -m group -a 'name=IT state=absent'

在这里插入图片描述

user模块

用于对用户的创建,修改以及删除操作

查看user模块的用法
ansible-doc -s user

在这里插入图片描述

comment        # 用户的描述信息
create_home    # 是否创建家目录
force          # 在使用state=absent时,与usrdel --force作用一致
group          # 指定基本组
home           # 指定用户家目录
name           # 指定用户名
password       # 指定用户密码
state          # 指定用户状态,state=absent表示删除系统中的用户,但不删除家目录
remove         # 使用state=absent时,搭配使用remove=yes以删除用户家目录及邮件池
shell          # 指定默认shell
state          # 指定帐号状态,不指定为创建,指定为absent表示删除
system         # 创建用户并设置为系统用户
uid            # 指定用户的uid
upgrade_password # 更新用户密码
expires        # 指明密码的过期时间
实例:在主机组node1(server1)上创建一个系统用户zs,家目录为/home/zhangsan,uid为111,附加组为IT,以及给一个注释
 ansible node1 -m user -a "system=yes name=zs home=/home/zhangsan uid=111 group=IT comment='秃头张三'"

在这里插入图片描述

我们发现报错啦

"msg": "Group IT does not exist"
组不存在?想想,咱们刚刚确实把他删啦,那我们就用user组好了
ansible node1 -m user -a "system=yes name=zs home=/home/zhangsan uid=111 group=user comment='秃头张三'"

这回该成功了吧

在这里插入图片描述

到server1再看看

tail -n -10 -f /etc/passwd

在这里插入图片描述

user:x:1000:1000:user:/home/user:/bin/bash
zs:x:111:1000:秃头张三

不行,题目要求的是附加组,那我们要用groups=IT

ansible -m group -a "name=IT gid=111 system=yes" node1

在这里插入图片描述

ansible node1 -m user -a "system=yes name=zs home=/home/zhangsan uid=111 groups=IT  group=user comment='秃头张三'"

在这里插入图片描述

这不就好了吗

注意属组group和附属组groups的区别

我们可以发现passwd文件中是按照用户名:权限:附属组:属组的顺序来进行的

删除刚刚的用户zs
ansible node1 -m user -a "name=zs state=absent remove=yes"

在这里插入图片描述

在这里插入图片描述

command模块

  • Ansible默认使用模块,在远程服务器执行命令
  • 不支持shell特性(不支持管道,变量及重定向)
  • 适用于执行简单、直接的命令
查看command模块的使用
ansible-doc -s command

在这里插入图片描述

cmd        # (必需)要执行的命令
create     # 当指定的文件或目录存在时,不执行命令
removes    # 当指定的文件或目录不存在时,不执行命令
chdir      # 在执行命令前要切换到的目录
f          # 控制同一时间内并发执行的任务数,默认为5
实例
1.在所有服务器上创建文件
ansible all_servers  -a "touch /root/command_test"
# -m command 为默认模块,可缺省

在这里插入图片描述

我们再指定command模块执行一次

 ansible all_servers -m command  -a "touch /root/command_test"

在这里插入图片描述

结果还是执行了,并且是changed状态,这就说明command模块不是幂等的,系统发出警告建议我们用file模块来创建

2.在所有服务器上查询所有以_test结尾的文件
ansible -a "find / -name '*_test' " all_servers

在这里插入图片描述

3.删除刚刚创建的/root/command_test
 ansible -a "rm -r /root/command_test" all_servers

在这里插入图片描述

ansible -a "find / -name 'command_test' " all_servers

在这里插入图片描述

虽然没找到,但是还是显示changed,毕竟执行过find命令嘛,咱理解一下笨蛋模块

shell模块

  • 在远程主机上用shell解释器执行bash命令
  • 相比于command命令,支持性好一些
  • 对于复杂的命令考虑写入脚本,利用script脚本发送到远程主机来执行
实例
ansible -m shell -a"find / -name ifcfg*|grep ens33" all_servers
# shell模块支持管道符

在这里插入图片描述

script模块

发送脚本到远程主机上执行

参数说明
chdir     # 指定远程主机中的目录,执行脚本前会先进入该目录
create     # 当指定的文件存在时,不执行命令
removes    # 当指定的文件不存在时,不执行命令
实例
vim sc_test.sh
#! /bin/bash
for i in {0..5}
do
mkdir -p /root/script_test
touch  /root/script_test/${i}.txt
done
ansible -m script -a "/root/sc_test,sh" node2

在这里插入图片描述

再分别进入server1和server2看看

ssh root@server1
ls&&cd script_test&&ls
# 先查看当前目录(root目录)内容,再进入script_test目录查看其中内容

在这里插入图片描述

copy模块

复制文件到目标组中

参数解释
ansible-doc -s copy

在这里插入图片描述

backup           # 在覆盖之前,将源文件备份,备份文件包含时间信息
content           # 用于替代src,直接设定指定文件的值
dest             # 目的主机存放文件的位置,必填
mode              # 递归设定文件的权限,默认为属主可读可写、其他用户仅可读。可手动指定为777
force           # 强制覆盖目的文件内容,默认为yes
others         # 所有的file模块里的选项都可以使用
src           # 被复制的本地文件路径,路径为目录,则递归复制
ansible -m copy -a "src=/本地文件路径 dest=/远程文件的路径 " 执行的主机组
实例:将本地/root目录下的文件复制到目标服务器,并改名
 ansible node1  -m copy -a "src=/root/centos7.tar.gz  dest=/root/centos.tar.gz"

在这里插入图片描述

我们到node1对应的server1看看

在这里插入图片描述

将本地文件复制到目标服务器,并指定属组和属主

我们先创建一个用户李四(lisa)和组ansible

 ansible node1 -m group -a 'name=ansible system=yes' # 创建ansible组ansible node1 -m user -a "name=lisa system=yes home=/home/lisa password=1" # 创建用户lisa并指定密码和家目录
echo "i'am lisa">hello_lisa.txt

将创建的txt文件传输到目标主机的/home/lisa目录下,并指定属主为lisa,属组为ansible

ansible -m copy node1 -a "src=/root/hello_lisa.txt dest=/home/lisa owner=lisa group=ansible"

在这里插入图片描述

 cd /home/lisa&&cat hello_lisa.txt&&ll

在这里插入图片描述

传输文件时修改权限信息
ansible -m copy node1 -a "src=/root/hello_lisa.txt dest=/home/lisa/hello2.txt mode=777"

在这里插入图片描述

我们再到server1上看看

在这里插入图片描述

创建一个文件并直接编辑
ansible -m copy -a "content='hello lisa\n!' dest=/home/lisa/hello_test " node1

在这里插入图片描述

在这里插入图片描述

file模块

对文件进行操作

查看参数说明
ansible-doc -s file

在这里插入图片描述

force     # 两种情况下需要强制创建软连接# 一种是源文件不存在,但在之后会创建;另一种是目标软连接已存在,需要先取消之前的软链,创建新的软链#选项 yes|nogroup    # 定义属组mode       # 定义权限
owner     # 定义属主
path       # 定义文件(或目录)路径
recurse    # 递归设置目录的属性
src        #  被链接的源文件路径,只用于state=link的情况
dest       # 被链接到的路径,只用于state=link的情况

几种文件的state

absent         # 删除文件
directory      # 目录不存在则创建目录
file           # 检测文件是否存在,即使不存在,也不会被创建
link           # 创建软链接
hard           # 创建硬链接
touch          # 如果文件不存在则创建;文件已存在则更新修改时间
创建目录(指定属组属主以及权限)
ansible -m file -a "path=/root/test_directory owner=root group=root mode=644 state=directory" node3

在这里插入图片描述
在这里插入图片描述

创建文件
ansible -m file -a "path=/root/test_file owner=root group=root mode=644 state =touch"

在这里插入图片描述
在这里插入图片描述

删除目录/文件
 ansible -m file -a "path=/root/test_file  state=absent" node3ansible -m file -a "path=/root/test_directory state=absent" node3ansible -m file -a "path=/root/script_test  state=absent" node3

在这里插入图片描述在这里插入图片描述

测试script模块时用的是node1(server1和server2),所以server3本身就没有script_test目录

在这里插入图片描述在这里插入图片描述
在这里插入图片描述

创建软连接
ansible -m file -a "src=/root/test11 dest=/root/test22 state=link" node1

在这里插入图片描述

报错,refusing covert from directory to symlink for /root/test22。字面上看,操作试图将目录转换为符号链接,但是操作系统拒绝了这种转换。这是由于我们已经创建了目录test22了,以至于无法将其覆盖,从而报错

我们直接用上面的ansible指令删除这个不应该存在的目录

ansible -m file node1 -a "path=/root/test22 state=absent"

在这里插入图片描述

 ansible -m file -a "src=/root/test11 dest=/root/test22 state=link" node1

在这里插入图片描述

ssh root@server1
ll

在这里插入图片描述

创建硬链接

我们先在节点上做准备

ansible -m shell -a "cat /root/test.sh" node1# 查看在server1上创建好的用于被链接的sh文件

在这里插入图片描述

ansible -m file -a "src=/root/test.sh dest=/root/test3 state=hard" node1 

在这里插入图片描述

ansible -m shell -a "ls -l" node1
# 我们可以看到多了一个链接下面的图是原始的文件状态

在这里插入图片描述

在这里插入图片描述

yum模块

用于yum方式安装服务

查看参数
ansible-doc  -s yum >> yum.txt&&cat yum.txt

在这里插入图片描述

 conf_file            # 设定远程yum安装时所依赖的配置文件。如配置文件没有在默认的位置。 disable_gpg_check    # 是否禁止GPG checking,只用于`present' or `latest'。 disable repo    # 临时禁止使用yum库。 只用于安装或更新时。      enable repo     # 临时使用的yum库。只用于安装或更新时。      name            # 安装的包的名称      state           # present安装, latest安装新的, absent 卸载软件。      update_cache    # 强制更新yum的缓存
我们先看server1上没有tree命令,对该命令进行安装

在这里插入图片描述

ansible -m yum  -a "name=tree state=latest" node1

在这里插入图片描述

ansible -m command  -a "tree" node1

在这里插入图片描述

在server2上安装运行httpd服务

 ansible -m yum  -a "name=httpd state=latest" node2 ansible -m service -a "name=httpd state=started" node2

查看端口开放情况

ansible -m command -a "ss -ntl" node2

在这里插入图片描述

使用elinks工具检测是否安装成功(或者在浏览器输入服务器ip都可以实现同样的效果)

elinks 192.168.28.77 # server2 ip

在这里插入图片描述

service模块

用于配置服务

ansible-doc -s service

在这里插入图片描述

arguments         # 命令行提供额外的参数      enabled           # 设置开机启动,可以设置为yes或者no。      name=             # 服务名称      runlevel          # 开机启动的级别,一般不用指定。      sleep             # 在重启服务的过程中,是否等待。如在服务关闭以后等待2秒再启动。      state     	        # started启动服务, stopped停止服务, restarted重启服务, reloaded重载配置

实例:配置httpt进程开机启动

ansible -m service -a "name=httpd state=enable"

setup模块

获取远程主机的详细信息

ansible -m setup node2
[root@ansible ~]# cat setup.txt
server1 | SUCCESS => {"ansible_facts": {"ansible_all_ipv4_addresses": ["192.168.122.1","192.168.28.66"],"ansible_all_ipv6_addresses": ["fe80::2a43:1282:aff6:e078","fe80::6f22:d478:2b46:2ad5"],"ansible_apparmor": {"status": "disabled"},"ansible_architecture": "x86_64","ansible_bios_date": "11/12/2020","ansible_bios_version": "6.00","ansible_cmdline": {"BOOT_IMAGE": "/boot/vmlinuz-3.10.0-1160.71.1.el7.x86_64","LANG": "zh_CN.UTF-8","crashkernel": "auto","quiet": true,"rhgb": true,"ro": true,"root": "UUID=60bfdc34-a1ba-4afb-b440-d49f68e74eed"},"ansible_date_time": {"date": "2024-10-14","day": "14","epoch": "1728869204","hour": "09","iso8601": "2024-10-14T01:26:44Z","iso8601_basic": "20241014T092644335349","iso8601_basic_short": "20241014T092644","iso8601_micro": "2024-10-14T01:26:44.335349Z","minute": "26","month": "10","second": "44","time": "09:26:44","tz": "CST","tz_offset": "+0800","weekday": "星期一","weekday_number": "1","weeknumber": "42","year": "2024"},"ansible_default_ipv4": {"address": "192.168.28.66","alias": "ens33","broadcast": "192.168.28.255","gateway": "192.168.28.254","interface": "ens33","macaddress": "00:0c:29:1d:af:9f","mtu": 1500,"netmask": "255.255.255.0","network": "192.168.28.0","type": "ether"},"ansible_default_ipv6": {},"ansible_device_links": {"ids": {},"labels": {},"masters": {},"uuids": {"sda1": ["1a629aca-5f4e-446c-8e10-bdecd020da82"],"sda2": ["60bfdc34-a1ba-4afb-b440-d49f68e74eed"]}},"ansible_devices": {"sda": {"holders": [],"host": "SCSI storage controller: Broadcom / LSI 53c1030 PCI-X Fusion-MPT Dual Ultra320 SCSI (rev 01)","links": {"ids": [],"labels": [],"masters": [],"uuids": []},"model": "VMware Virtual S","partitions": {"sda1": {"holders": [],"links": {"ids": [],"labels": [],"masters": [],"uuids": ["1a629aca-5f4e-446c-8e10-bdecd020da82"]},"sectors": "16777216","sectorsize": 512,"size": "8.00 GB","start": "2048","uuid": "1a629aca-5f4e-446c-8e10-bdecd020da82"},"sda2": {"holders": [],"links": {"ids": [],"labels": [],"masters": [],"uuids": ["60bfdc34-a1ba-4afb-b440-d49f68e74eed"]},"sectors": "192935936","sectorsize": 512,"size": "92.00 GB","start": "16779264","uuid": "60bfdc34-a1ba-4afb-b440-d49f68e74eed"}},"removable": "0","rotational": "1","sas_address": null,"sas_device_handle": null,"scheduler_mode": "deadline","sectors": "209715200","sectorsize": "512","size": "100.00 GB","support_discard": "0","vendor": "VMware,","virtual": 1}},"ansible_distribution": "CentOS","ansible_distribution_file_parsed": true,"ansible_distribution_file_path": "/etc/redhat-release","ansible_distribution_file_variety": "RedHat","ansible_distribution_major_version": "7","ansible_distribution_release": "Core","ansible_distribution_version": "7.9","ansible_dns": {"nameservers": ["192.168.28.254"]},"ansible_domain": "","ansible_effective_group_id": 0,"ansible_effective_user_id": 0,"ansible_ens33": {"active": true,"device": "ens33","features": {"busy_poll": "off [fixed]","fcoe_mtu": "off [fixed]","generic_receive_offload": "on","generic_segmentation_offload": "on","highdma": "off [fixed]","hw_tc_offload": "off [fixed]","l2_fwd_offload": "off [fixed]","large_receive_offload": "off [fixed]","loopback": "off [fixed]","netns_local": "off [fixed]","ntuple_filters": "off [fixed]","receive_hashing": "off [fixed]","rx_all": "off","rx_checksumming": "off","rx_fcs": "off","rx_gro_hw": "off [fixed]","rx_udp_tunnel_port_offload": "off [fixed]","rx_vlan_filter": "on [fixed]","rx_vlan_offload": "on","rx_vlan_stag_filter": "off [fixed]","rx_vlan_stag_hw_parse": "off [fixed]","scatter_gather": "on","tcp_segmentation_offload": "on","tx_checksum_fcoe_crc": "off [fixed]","tx_checksum_ip_generic": "on","tx_checksum_ipv4": "off [fixed]","tx_checksum_ipv6": "off [fixed]","tx_checksum_sctp": "off [fixed]","tx_checksumming": "on","tx_fcoe_segmentation": "off [fixed]","tx_gre_csum_segmentation": "off [fixed]","tx_gre_segmentation": "off [fixed]","tx_gso_partial": "off [fixed]","tx_gso_robust": "off [fixed]","tx_ipip_segmentation": "off [fixed]","tx_lockless": "off [fixed]","tx_nocache_copy": "off","tx_scatter_gather": "on","tx_scatter_gather_fraglist": "off [fixed]","tx_sctp_segmentation": "off [fixed]","tx_sit_segmentation": "off [fixed]","tx_tcp6_segmentation": "off [fixed]","tx_tcp_ecn_segmentation": "off [fixed]","tx_tcp_mangleid_segmentation": "off","tx_tcp_segmentation": "on","tx_udp_tnl_csum_segmentation": "off [fixed]","tx_udp_tnl_segmentation": "off [fixed]","tx_vlan_offload": "on [fixed]","tx_vlan_stag_hw_insert": "off [fixed]","udp_fragmentation_offload": "off [fixed]","vlan_challenged": "off [fixed]"},"hw_timestamp_filters": [],"ipv4": {"address": "192.168.28.66","broadcast": "192.168.28.255","netmask": "255.255.255.0","network": "192.168.28.0"},"ipv6": [{"address": "fe80::2a43:1282:aff6:e078","prefix": "64","scope": "link"},{"address": "fe80::6f22:d478:2b46:2ad5","prefix": "64","scope": "link"}],"macaddress": "00:0c:29:1d:af:9f","module": "e1000","mtu": 1500,"pciid": "0000:02:01.0","promisc": false,"speed": 1000,"timestamping": ["tx_software","rx_software","software"],"type": "ether"},"ansible_env": {"HOME": "/root","KDEDIRS": "/usr","LANG": "zh_CN.UTF-8","LESSOPEN": "||/usr/bin/lesspipe.sh %s","LOGNAME": "root","LS_COLORS": "rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=01;05;37;41:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=01;36:*.au=01;36:*.flac=01;36:*.mid=01;36:*.midi=01;36:*.mka=01;36:*.mp3=01;36:*.mpc=01;36:*.ogg=01;36:*.ra=01;36:*.wav=01;36:*.axa=01;36:*.oga=01;36:*.spx=01;36:*.xspf=01;36:","MAIL": "/var/mail/root","PATH": "/usr/lib64/qt-3.3/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin","PWD": "/root","QTDIR": "/usr/lib64/qt-3.3","QTINC": "/usr/lib64/qt-3.3/include","QTLIB": "/usr/lib64/qt-3.3/lib","QT_GRAPHICSSYSTEM_CHECKED": "1","QT_PLUGIN_PATH": "/usr/lib64/kde4/plugins:/usr/lib/kde4/plugins","SELINUX_LEVEL_REQUESTED": "","SELINUX_ROLE_REQUESTED": "","SELINUX_USE_CURRENT_RANGE": "","SHELL": "/bin/bash","SHLVL": "2","SSH_CLIENT": "192.168.28.88 47342 22","SSH_CONNECTION": "192.168.28.88 47342 192.168.28.66 22","SSH_TTY": "/dev/pts/0","TERM": "xterm","USER": "root","XDG_DATA_DIRS": "/root/.local/share/flatpak/exports/share:/var/lib/flatpak/exports/share:/usr/local/share:/usr/share","XDG_RUNTIME_DIR": "/run/user/0","XDG_SESSION_ID": "30","_": "/usr/bin/python"},"ansible_fibre_channel_wwn": [],"ansible_fips": false,"ansible_form_factor": "Other","ansible_fqdn": "server1","ansible_hostname": "server1","ansible_hostnqn": "","ansible_interfaces": ["lo","virbr0","virbr0-nic","ens33"],"ansible_is_chroot": false,"ansible_iscsi_iqn": "iqn.1994-05.com.redhat:34b4de6c161","ansible_kernel": "3.10.0-1160.71.1.el7.x86_64","ansible_kernel_version": "#1 SMP Tue Jun 28 15:37:28 UTC 2022","ansible_lo": {"active": true,"device": "lo","features": {"busy_poll": "off [fixed]","fcoe_mtu": "off [fixed]","generic_receive_offload": "on","generic_segmentation_offload": "on","highdma": "on [fixed]","hw_tc_offload": "off [fixed]","l2_fwd_offload": "off [fixed]","large_receive_offload": "off [fixed]","loopback": "on [fixed]","netns_local": "on [fixed]","ntuple_filters": "off [fixed]","receive_hashing": "off [fixed]","rx_all": "off [fixed]","rx_checksumming": "on [fixed]","rx_fcs": "off [fixed]","rx_gro_hw": "off [fixed]","rx_udp_tunnel_port_offload": "off [fixed]","rx_vlan_filter": "off [fixed]","rx_vlan_offload": "off [fixed]","rx_vlan_stag_filter": "off [fixed]","rx_vlan_stag_hw_parse": "off [fixed]","scatter_gather": "on","tcp_segmentation_offload": "on","tx_checksum_fcoe_crc": "off [fixed]","tx_checksum_ip_generic": "on [fixed]","tx_checksum_ipv4": "off [fixed]","tx_checksum_ipv6": "off [fixed]","tx_checksum_sctp": "on [fixed]","tx_checksumming": "on","tx_fcoe_segmentation": "off [fixed]","tx_gre_csum_segmentation": "off [fixed]","tx_gre_segmentation": "off [fixed]","tx_gso_partial": "off [fixed]","tx_gso_robust": "off [fixed]","tx_ipip_segmentation": "off [fixed]","tx_lockless": "on [fixed]","tx_nocache_copy": "off [fixed]","tx_scatter_gather": "on [fixed]","tx_scatter_gather_fraglist": "on [fixed]","tx_sctp_segmentation": "on","tx_sit_segmentation": "off [fixed]","tx_tcp6_segmentation": "on","tx_tcp_ecn_segmentation": "on","tx_tcp_mangleid_segmentation": "on","tx_tcp_segmentation": "on","tx_udp_tnl_csum_segmentation": "off [fixed]","tx_udp_tnl_segmentation": "off [fixed]","tx_vlan_offload": "off [fixed]","tx_vlan_stag_hw_insert": "off [fixed]","udp_fragmentation_offload": "on","vlan_challenged": "on [fixed]"},"hw_timestamp_filters": [],"ipv4": {"address": "127.0.0.1","broadcast": "","netmask": "255.0.0.0","network": "127.0.0.0"},"ipv6": [{"address": "::1","prefix": "128","scope": "host"}],"mtu": 65536,"promisc": false,"timestamping": ["rx_software","software"],"type": "loopback"},"ansible_local": {},"ansible_lsb": {},"ansible_lvm": {"lvs": {},"pvs": {},"vgs": {}},"ansible_machine": "x86_64","ansible_machine_id": "0309088104324f4ebda76f55d891b515","ansible_memfree_mb": 2680,"ansible_memory_mb": {"nocache": {"free": 3285,"used": 485},"real": {"free": 2680,"total": 3770,"used": 1090},"swap": {"cached": 0,"free": 8191,"total": 8191,"used": 0}},"ansible_memtotal_mb": 3770,"ansible_mounts": [{"block_available": 22445186,"block_size": 4096,"block_total": 24105217,"block_used": 1660031,"device": "/dev/sda2","fstype": "xfs","inode_available": 48030369,"inode_total": 48233984,"inode_used": 203615,"mount": "/","options": "rw,seclabel,relatime,attr2,inode64,noquota","size_available": 91935481856,"size_total": 98734968832,"uuid": "60bfdc34-a1ba-4afb-b440-d49f68e74eed"}],"ansible_nodename": "server1","ansible_os_family": "RedHat","ansible_pkg_mgr": "yum","ansible_proc_cmdline": {"BOOT_IMAGE": "/boot/vmlinuz-3.10.0-1160.71.1.el7.x86_64","LANG": "zh_CN.UTF-8","crashkernel": "auto","quiet": true,"rhgb": true,"ro": true,"root": "UUID=60bfdc34-a1ba-4afb-b440-d49f68e74eed"},"ansible_processor": ["0","GenuineIntel","Intel(R) Core(TM) i5-10500H CPU @ 2.50GHz","1","GenuineIntel","Intel(R) Core(TM) i5-10500H CPU @ 2.50GHz"],"ansible_processor_cores": 2,"ansible_processor_count": 1,"ansible_processor_threads_per_core": 1,"ansible_processor_vcpus": 2,"ansible_product_name": "VMware Virtual Platform","ansible_product_serial": "VMware-56 4d 26 77 cf 39 92 a8-db f7 2d 99 b0 1d af 9f","ansible_product_uuid": "77264D56-39CF-A892-DBF7-2D99B01DAF9F","ansible_product_version": "None","ansible_python": {"executable": "/usr/bin/python","has_sslcontext": true,"type": "CPython","version": {"major": 2,"micro": 5,"minor": 7,"releaselevel": "final","serial": 0},"version_info": [2,7,5,"final",0]},"ansible_python_version": "2.7.5","ansible_real_group_id": 0,"ansible_real_user_id": 0,"ansible_selinux": {"config_mode": "enforcing","mode": "enforcing","policyvers": 31,"status": "enabled","type": "targeted"},"ansible_selinux_python_present": true,"ansible_service_mgr": "systemd","ansible_ssh_host_key_ecdsa_public": "AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBKc8z8qym5Z1/NG9cty+iY/wrzJvGwgnwh+WjAByC6xup2ZNw9AmRCORkvbYlLbd/mBX+ZV96FsZz4ag4WZtMMc=","ansible_ssh_host_key_ed25519_public": "AAAAC3NzaC1lZDI1NTE5AAAAIHw7Go3U36zwIxwqQiZRvB4N3SuJsXLQIR5Nzoi+6Y+K","ansible_ssh_host_key_rsa_public": "AAAAB3NzaC1yc2EAAAADAQABAAABAQCpLSb01Z88NmbW2ssqX3xgk3LxzJg3W6rhNj6xHd7m4o0S2QLIvA4ut51i+bQRrRE/JOqXgR7p2mUjod2RflrhBHTsBVzOdLtp5iz9k4GLUizajrK2orrey/FSFMcmVs27eeGSyd9Qukj4QfGxq/ydB/PoaYgv5T8zSVH9zcXAGkXsAyQtqFHDBbPSbqcnWAMjO/0+YL2eHOAKjaeJU434FbuRRdKP7UIE+ILeYkt6xPtJ+TRQPfXES62iRICUb46thcfFHDU7vVM+gcuLCtAO8W0aJXmJRaGZooDy0htAdRLlxc0tbeH3M+ksTuOKg+gyTXkKb5iSIwegJ10vYEN/","ansible_swapfree_mb": 8191,"ansible_swaptotal_mb": 8191,"ansible_system": "Linux","ansible_system_capabilities": ["cap_chown","cap_dac_override","cap_dac_read_search","cap_fowner","cap_fsetid","cap_kill","cap_setgid","cap_setuid","cap_setpcap","cap_linux_immutable","cap_net_bind_service","cap_net_broadcast","cap_net_admin","cap_net_raw","cap_ipc_lock","cap_ipc_owner","cap_sys_module","cap_sys_rawio","cap_sys_chroot","cap_sys_ptrace","cap_sys_pacct","cap_sys_admin","cap_sys_boot","cap_sys_nice","cap_sys_resource","cap_sys_time","cap_sys_tty_config","cap_mknod","cap_lease","cap_audit_write","cap_audit_control","cap_setfcap","cap_mac_override","cap_mac_admin","cap_syslog","35","36+ep"],"ansible_system_capabilities_enforced": "True","ansible_system_vendor": "VMware, Inc.","ansible_uptime_seconds": 5028,"ansible_user_dir": "/root","ansible_user_gecos": "root","ansible_user_gid": 0,"ansible_user_id": "root","ansible_user_shell": "/bin/bash","ansible_user_uid": 0,"ansible_userspace_architecture": "x86_64","ansible_userspace_bits": "64","ansible_virbr0": {"active": false,"device": "virbr0","features": {"busy_poll": "off [fixed]","fcoe_mtu": "off [fixed]","generic_receive_offload": "on","generic_segmentation_offload": "on","highdma": "off [requested on]","hw_tc_offload": "off [fixed]","l2_fwd_offload": "off [fixed]","large_receive_offload": "off [fixed]","loopback": "off [fixed]","netns_local": "on [fixed]","ntuple_filters": "off [fixed]","receive_hashing": "off [fixed]","rx_all": "off [fixed]","rx_checksumming": "off [fixed]","rx_fcs": "off [fixed]","rx_gro_hw": "off [fixed]","rx_udp_tunnel_port_offload": "off [fixed]","rx_vlan_filter": "off [fixed]","rx_vlan_offload": "off [fixed]","rx_vlan_stag_filter": "off [fixed]","rx_vlan_stag_hw_parse": "off [fixed]","scatter_gather": "on","tcp_segmentation_offload": "on","tx_checksum_fcoe_crc": "off [fixed]","tx_checksum_ip_generic": "on","tx_checksum_ipv4": "off [fixed]","tx_checksum_ipv6": "off [fixed]","tx_checksum_sctp": "off [fixed]","tx_checksumming": "on","tx_fcoe_segmentation": "off [requested on]","tx_gre_csum_segmentation": "on","tx_gre_segmentation": "on","tx_gso_partial": "on","tx_gso_robust": "off [requested on]","tx_ipip_segmentation": "on","tx_lockless": "on [fixed]","tx_nocache_copy": "off","tx_scatter_gather": "on","tx_scatter_gather_fraglist": "on","tx_sctp_segmentation": "off [requested on]","tx_sit_segmentation": "on","tx_tcp6_segmentation": "on","tx_tcp_ecn_segmentation": "on","tx_tcp_mangleid_segmentation": "on","tx_tcp_segmentation": "on","tx_udp_tnl_csum_segmentation": "on","tx_udp_tnl_segmentation": "on","tx_vlan_offload": "on","tx_vlan_stag_hw_insert": "on","udp_fragmentation_offload": "off [requested on]","vlan_challenged": "off [fixed]"},"hw_timestamp_filters": [],"id": "8000.5254002f459b","interfaces": ["virbr0-nic"],"ipv4": {"address": "192.168.122.1","broadcast": "192.168.122.255","netmask": "255.255.255.0","network": "192.168.122.0"},"macaddress": "52:54:00:2f:45:9b","mtu": 1500,"promisc": false,"stp": true,"timestamping": ["rx_software","software"],"type": "bridge"},"ansible_virbr0_nic": {"active": false,"device": "virbr0-nic","features": {"busy_poll": "off [fixed]","fcoe_mtu": "off [fixed]","generic_receive_offload": "on","generic_segmentation_offload": "on","highdma": "off [fixed]","hw_tc_offload": "off [fixed]","l2_fwd_offload": "off [fixed]","large_receive_offload": "off [fixed]","loopback": "off [fixed]","netns_local": "off [fixed]","ntuple_filters": "off [fixed]","receive_hashing": "off [fixed]","rx_all": "off [fixed]","rx_checksumming": "off [fixed]","rx_fcs": "off [fixed]","rx_gro_hw": "off [fixed]","rx_udp_tunnel_port_offload": "off [fixed]","rx_vlan_filter": "off [fixed]","rx_vlan_offload": "off [fixed]","rx_vlan_stag_filter": "off [fixed]","rx_vlan_stag_hw_parse": "off [fixed]","scatter_gather": "on","tcp_segmentation_offload": "off","tx_checksum_fcoe_crc": "off [fixed]","tx_checksum_ip_generic": "off [requested on]","tx_checksum_ipv4": "off [fixed]","tx_checksum_ipv6": "off [fixed]","tx_checksum_sctp": "off [fixed]","tx_checksumming": "off","tx_fcoe_segmentation": "off [fixed]","tx_gre_csum_segmentation": "off [fixed]","tx_gre_segmentation": "off [fixed]","tx_gso_partial": "off [fixed]","tx_gso_robust": "off [fixed]","tx_ipip_segmentation": "off [fixed]","tx_lockless": "on [fixed]","tx_nocache_copy": "off","tx_scatter_gather": "on","tx_scatter_gather_fraglist": "on","tx_sctp_segmentation": "off [fixed]","tx_sit_segmentation": "off [fixed]","tx_tcp6_segmentation": "off [requested on]","tx_tcp_ecn_segmentation": "off [requested on]","tx_tcp_mangleid_segmentation": "off","tx_tcp_segmentation": "off [requested on]","tx_udp_tnl_csum_segmentation": "off [fixed]","tx_udp_tnl_segmentation": "off [fixed]","tx_vlan_offload": "on","tx_vlan_stag_hw_insert": "on","udp_fragmentation_offload": "off [requested on]","vlan_challenged": "off [fixed]"},"hw_timestamp_filters": [],"macaddress": "52:54:00:2f:45:9b","mtu": 1500,"promisc": true,"timestamping": ["rx_software","software"],"type": "ether"},"ansible_virtualization_role": "guest","ansible_virtualization_type": "VMware","discovered_interpreter_python": "/usr/bin/python","gather_subset": ["all"],"module_setup": true},"changed": false
}

Selinux模块

管理远程主机的selinux配置

参数
ansible-doc -s selinux 

在这里插入图片描述

policy   # 要使用的selinux策略的名称
state     # 配置selinux的模式   enforcing(强制模式)、permissive(宽容模式)、disabled(禁用)三种模式
configfile # 配置selinux文件的路径

例子:设置selinux防火墙为强制模式

ansible -m selinux -a "policy=targeted state=enforcing" node1

在这里插入图片描述

可以看出来server1本身就是配置的enforcing模式

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/58368.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Hash表算法

哈希表 理论知识(本文来自于代码随想录摘抄)什么是哈希常见的三种哈希结数组:set:map:其他常用方法或者技巧(自己总结的) 练习题和讲解有效的字母移位词349. 两个数组的交集1. 两数之和454. 四数相加 II15. 三数之和 总…

如何选择适合自己的 Python IDE

集成开发环境(IDE)是指提供广泛软件开发能力的软件应用程序。IDE 通常包括源代码编辑器、构建自动化工具和调试器。大多数现代 IDE 都配备了智能代码补全功能。在本文中,你将发现目前市场上最好的 Python IDE。 什么是 IDE? IDE…

为什么架构设计禁止IP直连?

什么是IP直连? IP直连指应用程序直接在代码中硬编码IP地址,比如,连接mysql数据库的数据库链接,如下的定义方式,就属于IP直连。 这种写法在开发环境中很常见,但是,在正式生产环境中,…

Linux shell编程学习笔记87:blkid命令——获取块设备信息

0 引言 在进行系统安全检测时,我们需要收集块设备的信息,这些可以通过blkid命令来获取。 1 blkid命令的安装 blkid命令是基于libblkid库的命令行工具,可以在大多数Linux发行版中使用。 如果你的Linux系统中没有安装blkid命令,…

构建生产级的 RAG 系统

对 RAG 应用程序进行原型设计很容易,但要使其高性能、健壮且可扩展到大型知识语料库却很困难。 本指南包含各种提示和技巧,以提高 RAG 工作流程的性能。我们首先概述一些通用技术 - 它们按照简单到复杂的顺序进行排列。然后,我们将更深入地研…

【python实操】python小程序之测试报告

引言 python小程序之测试报告 文章目录 引言一、测试报告1.1 概念1.1.1 使用Pytest和Allure生成测试报告1.1.2 使用unittest和HTMLTestRunner生成测试报告1.1.3 总结 1.2 题目1.3 代码1.3 代码解释 二、思考 一、测试报告 1.1 概念 python生成测试报告,常用的方法包…

ELK之路第一步——Elasticsearch集群的搭建以及踩坑记录

elasticSearch集群 前言一、架构二、下载三、虚拟机相关设置3.1 创建es用户3.2 为建es用户赋权sudo3.3 更换es目录所属用户 四、Elasticsearch配置文件修改4.1 修改elasticsearch.yml4.2 修改jvm.options4.3 修改jdk路径 五、启动六、启动报错七、设置密码八、可视化界面cerebr…

Ubuntu22.04环境搭建MQTT服务器

官网: https://mosquitto.org 1.引入库 sudo apt-add-repository ppa:mosquitto-dev/mosquitto-ppa2.升级安装工具 sudo apt-get update 3.安装 sudo apt-get install mosquitto 4.安装客户端 sudo apt-get install mosquitto-clients5.添加修改配置文件 进…

力扣21 : 合并两个有序链表

链表style 描述: 将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 示例: 节点大小相同时,l1的节点在前 何解? 1,遍历两个链表,挨个比较节点大小 同时遍…

Python应用指南:利用高德地图API实现路径规划

高德路径规划API是一套基于HTTP协议的接口服务,旨在为开发者提供便捷的路径规划解决方案。该API支持多种出行方式,包括步行、公交和驾车,能够满足不同场景下的路径查询需求。通过调用这些API,用户可以获得从起点到终点的最优路径建…

深度学习数学基础之偏导数

深度学习数学基础之偏导数 偏导数的详细解释与实例 定义 偏导数是多变量函数对其中一个变量的导数,同时固定其他变量。它是研究函数在多维空间内各个方向上局部变化性质的基本工具。对于函数 ( f ( x 1 , x 2 , … , x n ) f(x_1, x_2, \dots, x_n) f(x1​,x2​…

论文阅读(二十三):Squeeze-and-Excitation Networks

文章目录 1.介绍2.原理3.代码4.SE模块的应用 论文:Squeeze-and-Excitation Networks   论文链接:Squeeze-and-Excitation Networks   代码链接:Github 1.介绍 卷积算子使网络能够在每一层的局部感受野中融合空间(spatial&…

视频智能分析平台LiteAIServer摄像机视频分析软件下载检测工业排污

在全球环境保护与可持续发展的大潮中,工业排污的有效监控与管理成为了衡量一个国家或地区绿色发展能力的重要指标。面对这一挑战,视频智能分析平台LiteAIServer以其创新的技术手段,为工业排污监管开辟了新路径,展现了科技在环保领…

【git】 git 删除了文件,如何找回

git 删除了文件,如何找回 使用 git revert 并不是恢复误删除文件的最佳方法,因为 git revert 通常用于撤销已经提交的更改(生成一个反向提交)。如果你误删除了文件,还未提交更改,或者已经提交但想恢复删除…

【Unity基础】初识UI Toolkit - 运行时UI

Unity中的UI工具包(UI Toolkit)不但可以用于创建编辑器UI,同样可以来创建运行时UI。 关于Unity中的UI系统以及使用UI工具包创建编辑器UI可以参见: 1. Unity中的UI系统 2. 初识UI Toolkit - 编辑器UI 本文将通过一个简单示例来…

Docker Compose一键部署Spring Boot + Vue项目

目录 前提条件 概述 Compose简介 Compose文件 Compose环境 Compose命令 帮助命令 关键命令 Compose部署项目 初始化环境 查看代码文件 sql数据准备 nginx配置文件准备 创建 compose.yaml 一键启动compose多个容器 浏览器访问虚拟机ip:80(可省略默认的80端口) …

动态代理:面向接口编程,屏蔽RPC处理过程

RPC远程调用 使用 RPC 时,一般的做法是先找服务提供方要接口,通过 Maven把接口依赖到项目中。在编写业务逻辑的时候,如果要调用提供方的接口,只需要通过依赖注入的方式把接口注入到项目中,然后在代码里面直接调用接口…

13.音乐管理系统(基于SpringBoot + Vue)

目录 1.系统的受众说明 ​​​​​​​ 2 需求分析 2.1用例图及用例分析 2.1.1 用户用例图及用例分析 2.1.2 管理员用例图及用例分析 2.2 系统结构图和流程图 2.2.1 音乐播放器的系统流程图(图2.2.1-1) 2.2.2 系统功能表(表2.2.2…

【HarmonyOS】鸿蒙应用低功耗蓝牙BLE的使用心得 (一)

【HarmonyOS】鸿蒙应用低功耗蓝牙BLE的使用心得(一) 一、前言 鸿蒙官网文档中蓝牙部分,对于之前没有开发过蓝牙的同学,使用和查阅起来不是很方便。因为只是API的调用说明。并没有蓝牙整个调用流程的讲解,所以看起来会…

Golang的多版本管理

Golang的多版本管理 一、 为什么需要多版本管理? 现代软件开发中,随着项目日益复杂,往往需要使用不同的Golang版本来适配不同的依赖库或者框架。同时,不同的项目也可能需要不同的Golang版本来编译和执行。因此,多版本管…