标签 原创 下的文章 - MemoryCloud Blog
首页
关于
推荐
Airport
SVG_
Gif_
API
搜 索
1
资源控制器之RS
51 阅读
2
Cgroups资源限制
48 阅读
3
扬帆起航
47 阅读
4
Kubernetes节点与 Pod 亲和性
42 阅读
5
Golang的原子属性
30 阅读
Default
Golang
Cloud Compute
Kubernetes
EveryDay
登录
/
注册
搜 索
标签搜索
原创
Kennedy
累计撰写
19
篇文章
累计收到
1
条评论
首页
栏目
Default
Golang
Cloud Compute
Kubernetes
EveryDay
页面
关于
推荐
Airport
SVG_
Gif_
API
用户登录
登录
注册
找到
15
篇与
相关的结果
2024-03-24
Ansible追加
部署密钥认证免密码登录、双机互信一些服务在使用前要求做密钥认证,管理轻松。手动写批量管理脚本。==注:密钥认证是单向==密钥对 公钥:public key 一般以.pub结尾 私钥:private key角色主机名IP管理机m01192.168.10.50被管理机nfs01192.168.10.51被管理机web01192.168.10.52被管理机backup192.168.10.53常规密钥无密钥前检测#ping ...... #22端口 sshd服务开启或可以访问 [root@m01 ~]# nmap -p 22 nfs01 web01 buckup Starting Nmap 6.40 ( http://nmap.org ) at 2024-03-10 21:03 EDT Nmap scan report for nfs01 (192.168.10.51) Host is up (0.00013s latency). PORT STATE SERVICE 22/tcp open ssh MAC Address: 00:0C:29:53:DD:74 (VMware) Nmap scan report for web01 (192.168.10.52) Host is up (0.00025s latency). PORT STATE SERVICE 22/tcp open ssh MAC Address: 00:0C:29:29:8F:D8 (VMware) Nmap scan report for buckup (192.168.10.53) Host is up (0.00022s latency). PORT STATE SERVICE 22/tcp open ssh MAC Address: 00:0C:29:3A:62:EB (VMware) Nmap done: 3 IP addresses (3 hosts up) scanned in 0.42 seconds创建密钥[root@m01 ~]# ssh-keygen -t rsa Your identification has been saved in /root/.ssh/id_rsa. Your public key has been saved in /root/.ssh/id_rsa.pub. 公钥和私钥 [root@m01 ~]# cd /root/.ssh/ [root@m01 .ssh]# ls id_rsa id_rsa.pub known_hosts #都是加密的分发公钥[root@m01 ~]# ssh-copy-id -i /root/.ssh/id_rsa.pub root@buckup测试ssh root@192.168.10.51公钥分发的位置[root@nfs01 ~]# cd /root/.ssh/ [root@nfs01 .ssh]# ls #位置不变 密钥文件名改变 authorized_keys自动创建与分发密钥集群数量庞大,无法每个单独配置阻碍:1.创建密钥对2.分发公钥的时候:yes/no(yes会保存到 .ssh/know_hosts)3.分发公钥的时候:输入密码sshpass作用sshpass适用于ssh相关的命令提供密码:ssh,scp,ssh-copy-idexpect,用户实现非交互式判断,认证操作 yes/no#在无密钥认证的时候 使用ssh不可加参数也必须交互式输密码 [root@m01 ~]# sshpass -proot ssh nfs01 -p指定密码 ssh是指定命令注意:sshpass,ssh-copy-id第一次连接,如果提示yes/no,则sshpass失效!创建密钥参数[root@m01 ~]# ssh-keygen -f ~/.ssh/id_rsa -P '' -f 参数用于指定私钥位置 -P 参数是密码短语 设置为空 #创建密钥时 就不需要回车分发密钥[root@m01 ~]# sshpass -proot ssh-copy-id -i ~/.ssh/id_rsa.pub buckup #分发公钥时就不需输入密码第一次建立连接yes/no#非建立连接过的主机在ssh,ssh-copy时会提示yes/no #建立连接后的主机信息会记录在/root/.ssh/know_hosts中 #在建立连接时 -oStrictHostKeyChecking=no 临时不检查主机信息(know_hosts) [root@m01 ~]# ssh nfs01 The authenticity of host 'nfs01 (192.168.10.51)' can't be established. ECDSA key fingerprint is SHA256:p6P+DDIogoJ7Q4OMmGs18IftWDwEWR4TEhiJ5SptmZU. ECDSA key fingerprint is MD5:6a:c1:a5:66:a0:f6:38:11:ac:72:a7:ca:8a:fe:87:18. Are you sure you want to continue connecting (yes/no)? [root@m01 ~]# ssh-copy-id -oStrictHostKeyChecking=no nfs01 解决建立连接时yes/no提示 [root@m01 ~]# sshpass -proot ssh-copy-id -oStrictHostKeyChecking=no nfs01 #解决yes/no以及密码提示脚本执行[root@m01 ~]# cat sshkey.sh #!/bin/bash #auther: To9cn #version: v1 #desc: 自动创建密钥对 自动分发公钥 passwd=root ips="192.168.10.51 192.168.10.52 192.168.10.53" #环境判断 是否联网、是否可以使用yum... yum install -y sshpass #创建密钥对 if [ -f ~/.ssh/id_rsa ] then echo "密钥对存在!" sleep 1 else echo "密钥对不存在; 开始创建密钥对..." ssh-keygen -t rsa -f ~/.ssh/id_rsa -P '' &>/dev/null sleep 1 echo "密钥对创建成功!" fi #分发公钥 for ip in $ips do sshpass -p$ ssh-copy-id -oStrictHostKeyChecking=no $ip echo "$ip 成功分发密钥!" sleep 1 done检查脚本测试无密钥的连通性[root@m01 ~]# cat test_ssh.sh #!/bin/bash #auther: To9cn #desc: 批量执行命令 for ip in 192.168.10.51 192.168.10.52 192.168.10.53 do ssh $ip hostname done [root@m01 ~]# ./test_ssh.sh nfs01 web01 buckupAnsible自动化运维:批量管理、批量分发、批量执行与维护...导图:https://www.processon.com/view/link/61addd266376896056c1b1b2任务:熟练脚本部署密钥认证Ansible批量管理结构Ansible主机清单(添加、管理集群)Ansible常用模块Ansible-批量管理-批量部署-批量分发Ansible管理架构Inventory :主机清单---被管理主机的IP列表,分类。ad-hoc模式:==命令行==批量管理(使用模块),临时任务。playbook:剧本模式---把操作写出脚本,可重复运行这个脚本Ansible模块概述:ansible中的模块就类似于Linux中的命令,我们Linux命令管理系统,我们通过ansible模块实现批量管理.ansible中模块一般相当于Linux中的一些命令.yum模块,file模块,user模块.ansible中的模块拥有不同的选项,这些选项一般都是一些单词.有自己格式和要求Ansible模块 modules Ansible中通过各种模块实现批量管理.一般来说这些模块对应着Linux里面的基本操作或服务管理。找出Linux场景操作对应的模块即可.Ansible安装epel源yum -y install epel-release yum -y install vconfig -y yum install -y ansible [root@m01 ~]# ansible --version ansible 2.9.27优化配置修改配置文件关闭Host_key_checking(yes/no)修改配置文件开启日志功能[root@m01 ~]# vim /etc/ansible/ansible.cfg 71行:关闭主机检测 112行:开启日志功能 [root@m01 ~]# egrep -vn '^$|#' /etc/ansible/ansible.cfg 11:[defaults] 72:host_key_checking = False 112:log_path = /var/log/ansible.log 328:[inventory] 341:[privilege_escalation] 347:[paramiko_connection] 371:[ssh_connection] 432:[persistent_connection] 446:[accelerate] 461:[selinux] 470:[colors] 486:[diff]ansible内置参数参数功能-i (inventory)指定主机组inventory-u (remote_user)指定sudo被控制的用户 (需要sudo权限)-b (become)启动特权功能--become-method --become-user切换(sudo)方式和切换的用户--ask-become-pass -K询问密码Ans-Inventory主机清单主机清单格式[分类或组的名字] #服务器集群用途 IP或主机名或域名 #主机名要解析(etc/hosts)ansible管理的主机节点的列表---默认读取/etc/ansible/hosts,一般会把清单放在指定位置。## db-[99:101]-node.example.com [nfs] 192.168.10.51 [web] 192.168.10.52 [buckup] 192.168.10.53没有公钥的主机清单配置(不推荐)[nfs] 192.168.10.51 ansible_user=root ansible_password=123 ansible_port=22测试[root@m01 ~]# ansible all -m ping #-m指定模块 #all可以替换为nfs,web等分组内容,也可写IP单必须在主机组 192.168.10.53 | SUCCESS => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python" }, "changed": false, "ping": "pong" } #获取被管理节点 系统信息 [root@m01 ~]# ansible all -a "cat /etc/os-release" 192.168.10.51 | CHANGED | rc=0 >> NAME="CentOS Linux" VERSION="7 (Core)" ID="centos" ID_LIKE="rhel fedora" VERSION_ID="7" PRETTY_NAME="CentOS Linux 7 (Core)" ANSI_COLOR="0;31" CPE_NAME="cpe:/o:centos:centos:7" HOME_URL="https://www.centos.org/" BUG_REPORT_URL="https://bugs.centos.org/"针对单台指定机器 ==ansible_host==ansible_host: 192.168.10.50不包含在其他任何主机组的机器- hosts: ungrouped'*'的作用- hosts: all == - hosts: '*' #匹配以 .example结尾的主机 - hosts: '*.example' # 有特殊符号必须放在引号内部 #匹配以 192.168.2 为网段的主机 - hosts: '192.168.2.*' #也表示以xxx开头==防止被shell意外扩展==--- - hosts: '!test1.example.com,development'管理多个主机- hosts: name1,name2,name3 #可混合‘*’等表达使用 : 组,IP,‘*’表达条件判断表达(针对主机必须满足多个条件的过滤)- hosts: lab,&nfs # 匹配同时属于这两个组的主机 # !加主机则排除本组的此主机 - hosts: nfs,!192.168.10.52 # 匹配除本主机的nfs组其他机器 # 也可针对组管理 - hosts: all,!nfs #匹配除nfs组的其他所有组 条件表达的位置前后可变换检查主机是否在清单中ansible nfs.example.com -i /etc/ansible/hosts --list-hosts #列出 ansible all -i /etc/ansible/hosts --list-hosts 支持判断 ansible '*.example.com' -i /etc/ansible/hosts --list-hosts 多个判断 ansible '*.example.com','!nfs.example.com' -i /etc/ansible/hosts --list-hosts '172.10*' 'backup,172*,*example*' 含有example,172开头,backup组(此时无&符号,表示或) 'web,&nfs' 同属两组 以Json格式列出清单主机ansible-inventory -i /etc/ansible/hosts --list子组期望对backup,nfs两组,再创建新分组data:[data:children]#创建新分组,包含已有的分组backup,nfs [data:children] nfs backup [root@m01 ~]# ansible data -m ping 192.168.10.51 | SUCCESS => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python" }, "changed": false, "ping": "pong" }Ansible模块模块的本质是替换Linux命令。模块有不同选项(单词),有自己的格式查看ansible全部模块ansible-doc -l #全部模块 ansible-doc -s file #搜索模块、找模块参数模块分类模块命令和脚本模块command模块 默认模块 执行简单命令,不支持特殊符号 shell模块 执行命令 支持特殊符号 script模块 分发脚本并执行文件file 创建目录,文件,软连接 copy 远程分发文件,修改权限,所有者,备份服务systemd服务管理 service 服务管理(了解)软件包yum源 yum_repository yum命令 get_url下载软件系统管理mount模块 挂载 cron模块 定时任务用户管理group模块 管理用户组 user模块 管理用户其他压缩解压(unarchive),rsync模块(synchronize),数据库模块(mysql_db,mysql_user)...调试模块ping检测ansible与其它节点连通性 debug模块 检查、显示 变量 命令和脚本1.command模块是ans默认模块,适用于简单命令,不支持特殊符号[root@m01 ~]# ansible all -m command -a "hostname" #-m 指定模块,-a模块的选项(命令);command也是默认模块 可以不写 # ansible all -a "hostname" 192.168.10.53 | CHANGED | rc=0 >> buckup 192.168.10.52 | CHANGED | rc=0 >> web01 192.168.10.51 | CHANGED | rc=0 >> nfs012.shell模块与command模块相似,但支持特殊符号(==避免因特殊符号和引号导致的问题==)ansible all -m shell -a 'rm -rf /tmp/*' #可用双引号批量获取IP[root@m01 ~]# ip a s ens33 | awk -F'[/ ]+' 'NR==3' 192.168.10.50 [root@m01 ~]# ansible all -m shell -a "ip a s ens33 | awk -F'[/ ]+' 'NR==3'" #“”转义特殊符号,\转义‘’号中的特殊符号 192.168.10.52 | CHANGED | rc=0 >> 192.168.10.52 192.168.10.51 | CHANGED | rc=0 >> 192.168.10.51 192.168.10.53 | CHANGED | rc=0 >> 192.168.10.53shell模块不推荐执行较为复杂的命令,如果需要,可放在脚本中执行3.script模块1.分发脚本(传输脚本),在被管理端执行脚本2.运行脚本注:被控制节点执行完脚本后才有反馈[root@m01 script]# cat xuntest.sh #!/bin/bash #auther: To9cn #desc: 系统巡检脚本 hostname hostname -I ip a s ens33 | awk -F'[/ ]+' 'NR==3' uptime whoami date +%F sleep 3 #模块执行 [root@m01 script]# ansible all -m script -a '/root/script/xuntest.sh' #被管理端ps -ef | grep ansible 可查看临时脚本文件路径 [root@nfs01 ~]# ps -ef | grep ansible root 11774 11749 0 21:58 pts/0 00:00:00 /bin/sh -c /root/.ansible/tmp/ansible-tmp-1710208685.15-15173-53973950998774/xuntest.sh && sleep 0 #执行玩脚本以后文件自动删除4.debug模块执行Ansible在命令行只会显示OK,Changed等,debug模块可自定义==控制台输出内容==[root@m01 playbook]# ansible all -m debug -a "msg='hello word'" #剧本模式 debug: msg: "Test Debug"-v参数[root@m01 test]# ansible -i inventory web --list-hosts -v #显示cfg的配置文件 Using /etc/ansible/ansible.cfg as config file hosts (1): 192.168.10.52文件相关模块1.file模块管理文件、目录、软连接file模块把touch、mkdir、rm、ln等命令结合在一起file模块模块说明==path==目录、文件路径 必写src源文件一般用link(创建软连接) 用于指定源文件==state==状态(模式)state=directory 创建目录state=file(默认) 更新文件,若文件不存在不创建state=link 创建软连接state=touch 创建文件==state==state=absent 删除 (如果是目录递归删除目录) modemode=755 创建并修改权限 mode: 0640owneronwer=rootgroupgroup=rootrecurse创建文件,如果存在,更新文件时间戳forceforce参数:当state=link的时候,可配合此参数强制创建链接文件,当force=yes时,表示强制创建链接文件,不过强制创建链接文件分为两种情况,情况一:当你要创建的链接文件指向的源文件并不存在时,使用此参数,可以先强制创建出链接文件。情况二:当你要创建链接文件的目录中已经存在与链接文件同名的文件时,将force设置为yes,回将同名文件覆盖为链接文件,相当于删除同名文件,创建链接文件。情况三:当你要创建链接文件的目录中已经存在与链接文件同名的文件,并且链接文件指向的源文件也不存在,这时会强制替换同名文件为链接文件被控制节点批量创建删除文件、目录[root@m01 ~]# ansible all -m file -a "path=/opt/test.sh state=touch" #删除 [root@m01 ~]# ansible all -m file -a "path=/opt/test.sh state=absent" [root@m01 ~]# ansible all -m file -a "path=/root/test/abc/ state=directory" #支持创建多级目录 #软连接 ansible all -m file -a "path=/opt/hosts src=/etc/hosts state=link" #path是创建后叫什么放哪 src是源文件 #检测 [root@m01 ~]# ansible all -a 'ls -l /opt/hosts' 192.168.10.53 | CHANGED | rc=0 >> lrwxrwxrwx. 1 root root 10 Mar 11 23:00 /opt/hosts -> /etc/hosts 192.168.10.52 | CHANGED | rc=0 >> lrwxrwxrwx. 1 root root 10 Mar 11 23:00 /opt/hosts -> /etc/hosts 192.168.10.51 | CHANGED | rc=0 >> lrwxrwxrwx. 1 root root 10 Mar 11 23:00 /opt/hosts -> /etc/hosts #owner修改所有者;推荐在创建时指定属主、权限... [root@m01 ~]# ansible all -m file -a "path=/testmdr/ owner=root group=root mode=777 state=directory" #属主和组必须存在才可成功 #控制节点检测 [root@m01 ~]# ansible all -a 'ls -ld /testmdr'2.copy模块批量分发:scp,管理节点发送文件到所有被管理端注:copy传输是单向的copy模块 ==src==source 源文件,管理端的文件(不推荐传目录)==dest==destnation 目标;被管理端的目录文件backupbackup=yes 在覆盖前进行备份(文件存在且不一样会备份)mode修改权限: 0644owner修改为指定所有者group修改为指定用户组content提供一个字符串 可转义特殊符号:"this is contentn" 替代src文件,自行输入内容,避免源文件混乱force默认为yes;强制覆盖受管机文件。手动设no;如果文件不存在,源文件不发生改变 扩展:==fetch==从被管理节点拉取文件到管理节点3.lineinfile修改文件内容:类似sed -i 'sg' , sed 'cai'path 指定文件、create 如果文件不存在是否创建(true/false)regexp 正则 只换正则匹配的内容(匹配多行只修改最后一行)path/dest: 目标文件绝对路径+文件名,必须参数 line: 替换/插入的内容 regexp: 待匹配内容 insertbefore: 匹配行前面插入 insertafter: 匹配行面插入 state: 删除匹配行,需要将值设为absent,默认值present。 backup: 是否在修改文件之前对文件进行备份。 yes/no create: 当要操作的文件并不存在时,是否创建对应的文件。yes/no backrefs:yes/no 1.backrefs为no时,如果没有匹配,则添加一行line。如果匹配了,则把匹配内容替被换为line内容。 2.backrefs为yes时,如果没有匹配,则文件保持不变。如果匹配了,把匹配内容替被换为line内容。4.blockinfile匹配一段文字,插入、更改、删除backup: 是否备份文件 block: 指定要插入标记内的文本:别名叫 "content" create: 如果文件不存在,则创建新文件 group: 文件属组 insertafter: 如果指定,文本将插入到最后一次匹配项的后面 insertbefore: 如果指定,文本讲插入到最后一次匹配项的前面 maker: 假如我们想要在指定的文件中插入一段文本,ansible会自动为这段文本添加2个标记,一个开始标记,一个结束标记; 默认情况下,开始标记为:# BEGIN ANSIBLE MANAGED BLOCK,结束标记为# END ANSIBLE MANAGED BLOCK path: 文件路径 state: 可选present或absent,默认为将指定的文本插入到文件中,如果文件中存在该文本,则会更新对应的段落,如果为absent,则删除对应的段落--- - hosts: all tasks: - name: Add blocktxt to a file blockfile: path: /root/files/ block: | First line is good Second line is cool state: present5.stat模块stat模块用于获取文件或文件组的状态信息。这可以包括文件的大小、权限、最后修改时间等。参数/类型选项/默认值描述checksum_algorithm<br/>string·sha1←<br/>· md5<br/>·sha224<br/>·sha256<br/>·sha384<br/>· sha512确定文件校验和的算法。<br/>如果主机无法使用指定的算法,将抛出错误。<br/>远程主机必须支持指定的散列方法,如果主机符合FIPS-140, md5可能不可用。follow<br/>boolean· no ←<br/>· yes是否遵循符号链接get_attributes<br/>boolean· yes ←<br/>· no如果存在,使用lsattr工具获取文件属性get_checksum<br/>boolean· yes ←<br/>· no是否返回文件的校验和get_mime<br/>boolean· yes ←<br/>· no使用文件魔法并返回关于文件性质的数据。它使用了在大多数Linux/Unix系统上都可以找到的“文件”实用程序。<br/>这将同时添加’ mime_type ‘和’charset’字段,如果可能的话。<br/>在Ansible 2.3中,这个选项从’mime’变为’get_mime’,默认为’Yes’。path<br/>path<br/>required 要获取的事实的文件/对象的完整路径。6.Synchronize模块Synchronize模块成为了实现高效文件同步的重要组件:synchronize模块用于同步两个系统之间的文件或目录。它可以将一个系统(控制主机)上的文件或目录同步到一个或多个远程系统上。compress:开启压缩,默认为开启 archive:是否采用归档模式同步,保证源文件和目标文件属性一致 checksum:是否效验 dirs:以非递归的方式传送目录 links:同步链接文件 recursive:是否递归yes/no rsync_opts:使用rsync的参数 copy_links:同步的时候是否复制链接 delete:删除源中没有但目标存在的文件,使两边内容一样,以推送方为主 src:源目录及文件 dest:目标文件及目录 dest_port:目标接收的端口 rsync_path:服务的路径,指定rsync在远程服务器上执行 rsync_remote_user:设置远程用户名 –exclude=.log:忽略同步以.log结尾的文件,这个可以自定义忽略什么格式的文件,或者.txt等等都可以,但是由于这个是rsync命令的参数,所以必须和rsync_opts一起使用,比如rsync_opts=--exclude=.txt这种模式 mode:同步的模式,rsync同步的方式push、pull,默认是推送push,从本机推送给远程主机,pull表示从远程主机上拿文件--- - hosts: all tasks: - name test synchronize synchronuze: src: file dest: /path/to/filereplace替换多行模块服务管理-systemdsystemd模块相当于Linux systemd命令:开启,关闭,重启服务开机自启服务systemd模块 ==name==指定服务名称==enabled==yes开机自启==state==表示服务开关重启state=started 开启state=stopped 关闭state=reloaded 重读配置文件state=restarted 重启daemon-reloadyes是否从新加载对应的服务管理配置文件自定义配置文件 #开启crond服务(集群)并设置开机自启 [root@m01 ~]# ansible all -m systemd -a "name=crond enabled=yes state=started" #开启,关闭防火墙 [root@m01 ~]# ansible all -m systemd -a "name=firewalld enabled=yes state=started" [root@m01 ~]# ansible all -m systemd -a "name=firewalld enabled=no state=stopped" 扩展:systemd适用于大部分Linux系统;service模块适用于旧的系统软件管理yum模块get_url模块,wget命令yum_repository模块,yum配置模块,可通过copy模块实现。1.yum模块yum模块不只是yum命令,包含==yum,apt==命令yum模块 name指定软件包名字;可以指定==多个==,用 “ , ”分割。stateinstalled 安装(present(默认))removed 删除(也可写为absent)lastest 安装或更新update_cache设置为no加速,表示不更新yum缓存,建议开启 #安装常用软件htop,tree,lrzsz [root@m01 ~]# ansible all -m yum -a "name=htop,tree,lrzsz update_cache=yes state=present" 2.get_url模块相当于wget命令,所有主机有网络才可推荐在管理节点下载好,使用copy仅分发即可get_url下载功能 url指定下载路径,地址dest下载到本地哪个目录validate_certs默认yes,no跳过https(SSL报错) #zabbix-agent地址为:#https://mirrors.aliyun.com/zabbix/zabbix/6.0/rhel/7/x86_64/zabbix-agent-6.0.13-release1.el7.x86_64.rpm 下载zabbix到/app/tools下 #创建目录 [root@m01 ~]# ansible all -m file -a "path=/app/tools state=directory" #控制节点下载zabbix [root@m01 ~]# ansible all -m get_url -a "url='https://mirrors.aliyun.com/zabbix/zabbix/6.0/rhel/7/x86_64/zabbix-agent-6.0.13-release1.el7.x86_64.rpm' dest=/app/tools" #yum安装 [root@m01 ~]# ansible all -m yum -a "name=/app/tools/zabbix-agent-6.0.13-release1.el7.x86_64.rpm state=installed update_cache=no" ==有时wget识别不了https,需要加上 --no-check-certificate 参数==wget --no-check-certificate XXXXXX3.yum_repository模块用处不是很多推荐:未来在单独目录下书写好yum配置文件,copy分发过去即可。yum源模块 yum_repository nameyum源中的名字 [Centos]descriptionyum源中的注释说明 对应的 是name的内容baseurlyum源中 baseurl 下载地址enabled是否启动这个源 yes/nogpgcheck是否启动gpgcheck功能 no(校验官方,许可等)file指定yum源文件 自动添加.repo 默认与模块名字一致 与普通yum文件区别[name]name=centos 默认为源文件的文件名name=centosdescription="" 描述enabled=1enabled=yesgpgcheck=0gpgcheck=no 用户管理user用户管理:useraddgroup用户组管理:groupadd1.user模块user模块 name用户名uid指定uidgroup指定用户组,用于事先创建好了用户组 通过选项指定shell指定命令解释器create_home是否创建家目录(yes/no)statepresent 添加absent 删除password更新密码 #创建www-ans用户uid 2000 [root@m01 ~]# ansible all -m user -a "name=www-ans uid=2000 shell=/sbin/nologin create_home=no state=present" [root@m01 ~]# ansible all -a "grep www-ans /etc/passwd"#带密码 ansible all -m user -a "name=wang password=} state=present" #'wang'是随机加的字符 #sha512加密格式输出加密后的结果 [root@m01 ~]# ansible all -i localhost, -m debug -a "msg=}" localhost | SUCCESS => { "msg": "$6$wang$8N45KDaHJsVGx6VQSjHS8helqldy7geS/zTb739WyuoPNxdW49B55l5SoCxg8rx5hv/O791edTg5k5C3QV/5a0" } #使用加密后的msg作为密码 ansible all -m user -a "name=liu1 password='$6$wang$8N45KDaHJsVGx6VQSjHS8helqldy7geS/zTb739WyuoPNxdW49B55l5SoCxg8rx5hv/O791edTg5k5C3QV/5a0' state=present" #等价于密码1 #shell模块更新密码 [root@m01 ~]# ansible all -m shell -a "echo 1 | passwd --stdin liu" 192.168.10.53 | CHANGED | rc=0 >> Changing password for user liu. passwd: all authentication tokens updated successfully. 关于}解释} 1表示密码,经过管道,传递给password_hash()插件,sha512加密算法,wang是随机字符用于生成加密后的密码。2.group模块group name指定用户组名字gid指定组idstatepresent 添加absent 删除 mount模块实现mount命令进行挂载,且可修改/etc/fstab实现永久挂载。mount fstype指定文件系统;xfs,ext4,iso9660,nfssrc源地址(nfs地址 eg 192.168.10.50/data)path挂载点(把源挂载到哪里)state见下表 mount的state参数可用值 ==absent==卸载并修改fstabunmounted卸载不修改/etc/fstabpresent仅修改/etc/fstab 不挂载==mounted==挂载并修改/etc/fstabremounted从新挂载 定时任务cron用于管理系统的定时任务,替代了crontab -e功能cron模块说明name定时任务名字(必加),对应下面==注释==内容minute分钟 minute="/2"hour小时day日期month月份week周几job指定命令或脚本(定向到空) job="/sbin/ntpdate ntp1.aliyum.com &>/dev/null"statepresent 添加定时任务(默认)absent 删除 #添加定时同步时间任务 */2 * * * * /sbin/ntpdate ntp1.aliyum.com &>/dev/null ansible all -m cron -a 'name="10.sync time wang" minute="*/10" job="/sbin/ntpdate ntp1.aliyum.com &>/dev/null" state=present' #被控制节点查看任务 [root@nfs01 ~]# crontab -l #Ansible: 10.sync time wang */10 * * * * /sbin/ntpdate ntp1.aliyum.com &>/dev/null #删除任务 name + state ansible all -m cron -a 'name="10.sync time wang" state=absent'清理已有的定时任务#使用sed替换 [root@m01 ~]# ansible all -a "sed -i '/ntpdate/d' /var/spool/cron/root" #但注释还在 [root@nfs01 ~]# crontab -l -u root #Ansible: 10.sync time wang其他模块集群批量管理-Ansible-剧本-变量剧本:可以书写部署服务脚本rsync、nfs、sersync变量:类似脚本,在剧本使用剧本playbook 文件;用于长久保存并实现批量管理,维护,部署的文件脚本中存放命令和变量,剧本中存放==模块==剧本yaml格式;yaml格式的文件:空格,冒号剧本和hoc区别 ans剧本ans ad-hoc共同点批量管理,使用模块批量管理,使用模块区别重复调用不方便重复调用应用场景部署服务,多个步骤任务测试模块,临时性任务 [root@m01 playbook]# cat 01.show.yml --- - hosts: all tasks: - name: 01 起床 shell: echo 01 >> /tmp/everyday.log - name: 02 刷牙 shell: echo 02 >> /tmp/everyday.log - name: 03 吃早餐 shell: echo 03 >> /tmp/everyday.log - hosts: [server1,serverb]==剧本hosts指定多个集群 :====- hosts: nfs:web:buckup==192.168.10.51 : ok=4 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 192.168.10.52 : ok=4 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 192.168.10.53 : ok=4 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 #剧本执行命令 ansible-playbook 01_test.yml #检测剧本语法 ansible-playbook 01_test.yml --syntax-check #奶牛优化 [root@m01 playbook]# ansible-playbook 01.show.yml #修改etc/ansible/ansible.cfg 随机图案 cow_selection = random #打开注释 #剧本目录下最好有/ansible/hosts文件 ansible-playbook -i hosts 02_file.yml #-i 指定主机清单注:==同级内容对齐、不同层级隔两个空格、不可用tab键==vi编辑器缩进修改在/etc/vimrc文件添加 set tabstop=2剧本案例1.创建并分发文件1.创建目录 /server/files/2.把 /etc/hosts 文件发送到 /server/files/#创建目录server/files/ ansible all -m file a "path='/server/files/' state=directory" #分发 ansible all -m copy a "src=/etc/hosts dest=/server/files/"剧本模式[root@m01 playbook]# cat 02.file.yml --- - hosts: all tasks: - name: 01 Creat file file: path=/server/files/ state=directory - name: 02 Copy file copy: src=/etc/hosts dest=/server/files/==冒号格式(专业格式);==[root@m01 playbook]# cat 02.file.yml --- - hosts: all tasks: - name: 01 Creat file file: path: /server/files/ state: directory - name: 02 Copy file copy: src: /etc/hosts dest: /server/files/2.安装软件分发安装包、安装软件、启动服务zabbix-agent软件包(下载)安装软件包配置(略)开机自启==步骤--->模块--->剧本== ==测试:分步测试==#下载安装包 wget https://mirrors.aliyun.com/zabbix/zabbix/6.0/rhel/7/x86_64/zabbix-agent-6.0.13-release1.el7.x86_64.rpm #安装软件 yum install -y zabbix-agent-6.0.13-release1.el7.x86_64.rpm #启动 systemctl模块#下载: get_url(url) #安装:yum(installed) #启动:system剧本[root@m01 playbook]# cat 03_install_zabbix.yml --- - hosts: all tasks: - name: 01 ---创建下载目录 file: path: /root/zabbix/ state: directory - name: 03 ---下载安装包 get_url: url: https://mirrors.aliyun.com/zabbix/zabbix/6.0/rhel/7/x86_64/zabbix-agent-6.0.13-release1.el7.x86_64.rpm dest: /root/zabbix/ validate_certs: no - name: 04 ---安装软件 yum: name: /root/zabbix/zabbix-agent-6.0.13-release1.el7.x86_64.rpm state: present - name: 05 ---设置自启 systemd: name: zabbix-agent enabled: yes state: started#检测 [root@m01 playbook]# ansible all -m shell -a "ps -ef | grep zabbix" 192.168.10.51 | CHANGED | rc=0 >> zabbix 14944 1 0 14:05 ? 00:00:00 zabbix_agentd zabbix 14945 14944 0 14:05 ? 00:00:06 zabbix_agentd: collector [idle 1 sec]3.nfs服务day40-9nfs服务端:在backup部署nfs服务,共享/backup-nfs目录,all_squash,nfsnobodynfs客户端:web挂载 /ans-upload目录挂载nfs服务端共享的/backup-nfs(永久挂载)服务端流程:1.部署nfs-utils2.修改配置文件3.创建共享目录,改所有者4.启动服务rpcbind,nfs客户端流程:1.安装nfs-utils2.挂载与永久挂载剧本模式#nfs Client --- - hosts: buckup tasks: - name: 01 Deploy nfs-utils,rpcbind yum: name: nfs-utils,rpcbind state: present - name: 02 Present system file lineinfile: path: /etc/exports line: "/buckup-nfs 192.168.10.0/24(rw,all_squash)" create: true - name: 03-1 Create Together file & Present User user: name: nfsnobody create_home: yes state: present - name: 03-2 Create Together file & Present User file: path: /buckup-nfs owner: nfsnobody group: nfsnobody state: directory - name: 04-1 Start Service(rpcbind,nfs) systemd: name: rpcbind enabled: yes state: started - name: 04-2 Start Service(rpcbind,nfs) systemd: name: nfs enabled: yes state: started #nfs Server - hosts: web tasks: - name: 01 Deploy nfs-utils yum: name: nfs-utils state: present - name: 02 Mount nfs mount: src: 192.168.10.53:/buckup-nfs path: /ans-upload fstype: nfs state: mountedAnsible变量可以定义变量的地方说明在剧本文件中定义比较常用.仅仅限于当前的play使用register变量(注册变量)ip=hostname-I实现脚本中反引号的功能,可以获取命令结果变量文件,根据主机清单分组进行定义变量如果多个剧本,使用相同的变量,大型的剧本rolesinventory主机清单中定义变量未来可以用于批量修改主机使用,其他很少用了facts变量一般用于获取主机基本信息:ip,主机名,系统(centos/ubuntu)如果不需要可以关闭,用于加速剧本的执行 0.在主机组Inventory中的变量针对单个主机组或多个主机组(子组)的变量定义[nfs_server] 192.168.10.51 [web_server] 192.168.10.52 [service:children] nfs_server web_server [web_server:vars] #用于web_server组 user=web [service:vars] #用于子组全部组 user=root1.在playbook定义变量仅在当前play生效,存放路径,用户名,ip...[root@m01 playbook]# cat 05_var_test.yml #var test --- - hosts: all vars: dir: /to9cn/wang/oldboy/a/b/c/ tasks: - name: Create directory file: path: "}" state: directory - name: debug tab debug: msg: "The vars: }:::" #不管多少空格只取变量值#检测 [root@m01 playbook]# ansible all -i hosts -a "tree /to9cn" 192.168.10.53 | CHANGED | rc=0 >> /to9cn └── wang └── oldboy └── a └── b └── c变量引号问题#变量只要是选项的开头 就必须加引号"" '' dir: /to9cn/wang/oldboy/a/b/c/ path: "}" #选项开头加引号 state: directory path: /root/script/} #非选项开头不加引号2.变量文件(共用)a. vars_files(变量文件)可在任意目录下创建此变量文件,可使用相对和绝对路径缺点:每个需要变量文件的剧本都==必须在开始调用变量文件==[root@m01 vars_group]# cat 01_var_test.yml --- - hosts: all vars_files: ./vars.yml # 若不是在同级目录,可直接使用相对目录 tasks: - name: 01 Print vars debug: msg: "vars: } } }"b.group_files(主机组文件)主机组清单变量文件在剧本文件的同级目录下创建group_vars目录,此目录中创建以主机组命名的目录;最后在主机组目录下书写变量文件(vars.yml);==playbook的同级目录下:group_vars/all(web nfs backup)/vars.yml==智能==自动识别,剧本不需引用==且可针对主机组指定变量#结构 [root@m01 vars_group]# ls 01_var_test.yml group_vars vars.yml [root@m01 vars_group]# tree . ├── 01_var_test.yml ├── group_vars │ └── all │ └── vars.yml [root@m01 vars_group]# cat group_vars/all/vars.yml user: wang(group) src: https://grpup_vars dest: /root/group_vars/vas/剧本删除变量文件引用[root@m01 vars_group]# cat 01_var_test.yml --- - hosts: all tasks: - name: 01 Print vars debug: msg: "vars: } } }" ok: [192.168.10.52] => { "msg": "vars: wang(group) https://grpup_vars /root/group_vars/vas/" } ok: [192.168.10.51] => { "msg": "vars: wang(group) https://grpup_vars /root/group_vars/vas/" } ok: [192.168.10.53] => { "msg": "vars: wang(group) https://grpup_vars /root/group_vars/vas/" }c.host_vars(特定主机)[root@m01 hosts_var]# tree -F . ├── 01_hostvar.yml ├── hosts └── host_vars/ └── web01.yml 1 directory, 3 filesd.(一次性)==覆盖已经定义的变量==ansible-plbook main.yaml -e "user=wang"e.变量数组定义与取值user: home: first_name: wang last_name: tao school: first_name: liu last_name: chao "}" "}" user['home']['first_name'] 3.register变量注册变量实现脚本中的 `` 反引号功能 : ip='hostname -I' 期望得到ip通过shell等系统命令结果保存到Register变量中==stdout==全名是standard putput (标准输出)[root@m01 playbook]# cat 06_register.yml --- - hosts: all tasks: - name: 01 Get Server Time shell: date +%F register: result #接收命令获取结果给变量 - name: 02 Out result debug: msg: | "register all: }" # "register.stdout: }" ok: [192.168.10.52] => { "msg": "register.stdout: 2024-03-14" }"msg": "\"register all: {'stderr_lines': [], u'changed': True, u'end': u'2024-03-14 23:17:54.964215', 'failed': False, u'stdout': u'2024-03-14', #标准输出 u'cmd': u'date +%F', u'rc': 0, u'start': u'2024-03-14 23:17:54.960870', u'stderr': u'', u'delta': u'0:00:00.003345', 'stdout_lines': [u'2024-03-14']}\"4.facts变量==ans内置变量==ans内置变量,ans运行剧本的时候会有一个默认的TASK [Gathering Facts]。运行剧本的时候ans会收集每个主机的基本信息,这些信息形成的变量叫做facts变量.==facts变量setup模块获取==---- ansible web -m setup 变量归属与读取 "ansible_swapfree_mb": 2047, #前面只有8个空格的变量可直接使用 #八个空格 "ansible_swaptotal_mb": 2047, "ansible_system": "Linux",大于8个空格:每四个空格为一个归属,找到上级用 “ . ”读取到下级内容 "ansible_effective_user_id": 0, "ansible_ens33": { #八个空格 "active": true, "device": "ens33", "features": { "ipv4": { #上级为ansible_ens33 "address": "192.168.10.52", #上级为ipv4 "broadcast": "192.168.10.255", "netmask": "255.255.255.0", "network": "192.168.10.0"读取IP:==ansible_ens33.ipv4.address==剧本--- - hosts: all tasks: - name: 显示系统的基本信息 debug: msg: | 你的系统是} 你系统的版本是} 你主机名为} ok: [192.168.10.52] => { "msg": "你的系统是CentOS\n你系统的版本是7.5\n你主机名为web01\n" }常见的facts变量ansible_hostname #主机名 ansible_memtotal_mb #内存大小(总计)单位mb ansible_processor_vcpus #cpu数量 ansible_default_ipv4.address #默认的网卡ip eth0 ansible_distribution #系统发行版本名字 Centos Ubuntu Debian... ansible_distribution_version #系统的版本 ansible_date_time.date #时间在剧本中如果不需要用到facts内置变量,可以==关闭此任务提高自动化效率==。在tasks上注明:- hosts: web gather_facts: no tasks: - name: file: ...a.==新版ansible_facts拆解== "ansible_dns": { # 八个空格 "nameservers": [ "192.168.10.200" ] }, #拆解表达 ansible_facts.dns.nameserver ansible_facts['dns']['nameserver']b.关闭事物收集提升性能--- - hosts: web gather_facts: false #关闭后可使用事实,手动收集事实才可使用 tasks: # - name: Open the facts # setup: - name: show facts debug: msg: "}"c.自定义事实自定义事实文件位置:[root@web01 facts.d]# ls server.fact [root@web01 facts.d]# pwd /etc/ansible/facts.d自定义事实包含在 : }[root@web01 redhat_ansible]# cat /etc/ansible/facts.d/server.fact [web] name= wang school= GZEU [nfs] name=liu school=Dahua剧本使用:集群批量管理-流程控制-RolesAnsible流程控制==handler==when==loop==/with_items1.handler触发器修复服务的配置文件后---重启服务配置文件无变化,不重启服务,仅配置变化才重启应用场景:分发配置文件的时候---重启服务(或者做其他)格式: notify: name1 , handlers: -name1 -name2注意:handlers必须放在剧本最后,否则之后的剧本都认做handlers[root@m01 playbook]# cat 08.handler.yml --- - hosts: nfs gather_facts: no tasks: - name: Hand files copy: src: exports dest: /etc/exports backup: yes - name: Restart Service #无论文件如何变化 重启服务都会执行 systemd: name: nfs state: reloaded使用handler与notify[root@m01 playbook]# cat 08.handler.yml --- - hosts: nfs gather_facts: no tasks: - name: Hand files copy: src: /etc/exports dest: /etc/exports backup: yes notify: #如果检测到此任务Changed 匹配handler中的name并执行 - Restart Service - #可添加多个 handlers: #如果对应的任务状态不是Changed 不会执行handler - name: Restart Service systemd: name: nfs state: reloaded2.when判断用于给ans运行的task(模块)设置条件,满足或不满足条件在运行对应的模块.应用建议:when进行判断,一般与变量一起使用.when条件一般与facts变量或reqister变量较多.# 以系统类型为条件判断 分系统安装个需软件 [root@m01 playbook]# cat 09_when.yml - hosts: all tasks: - name: CentOS系统安装sl,cowsay,tree yum: name: sl,cowsay,tree state: present when: ansible_distribution == "CentOS" - name: Ubuntu系统安装cmatrix,lolcat apt: name: cmatrix,lolcat state: present when: ansible_distribution == "Ubuntu" # 若没条件判断,所有节点都会安装两任务的全部软件 ==when常见表达== == != is / is not match eg: is not match("web|backup") #支持正则 条件1 and 条件2 条件1 or 条件2 is (not) defined 变量不存在 memory_available 布尔值为true,1:True和yes也为true not memory_available 布尔值为false,0,False eg: when: ansible_distribution == "Ubuntu" and/or ansible_hostname is match("web|backup") # 增强可读性 when: - ansible_distribution == "Ubuntu" - ansible_hostname is wang or表达: when: > ( ansible_distribution == "Ubuntu" and ansible_hostname is wang) or ( ansible_distribution == "CentOs" ansible_hostname is liu) 3.循环with_items 与 ==loop==场景:批量创建文件、添加用户、启动和重启服务"}"+with_items 与 "}"+loop用法一致重启多个服务(循环单个参数)[root@m01 playbook]# cat 10_loop.yml --- - hosts: buckup gather_facts: no tasks: - name: restart Service(rpcbind,nfs) systemd: name: "}" #item没有s state: restarted with_items: [a,b] #loop: 效果和with_items:一样 loop没有s - rpcbind - nfs - sshd - crond为集群添加用户(循环多个参数: name uid passwd...)[root@m01 playbook]# cat 11_loop_more.yml --- - hosts: nfs gather_facts: no tasks: - name: Add User user: name: "}" uid: "}" state: present loop: - #整数不用加引号 - - # 参数前需要 " - "Ubuntu和Centos的细微差别#CentOS的 /bin/sh 指向bash [root@m01 playbook]# ll /bin/sh lrwxrwxrwx. 1 root root 4 Mar 8 06:32 /bin/sh -> bash #Ubuntu区别 # ll /bin/sh /bin/sh -> dash* #脚本语法部分不一样针对不同的系统优化添加playbook的解释器 user: name: "}" uid: "}" shell: /bin/bash # Ubuntu系统将会更改 解释器 state: present==变量循环遍历==循环遍历时需要去playbook寻找items具体位置,可写在vars变量(在book首部)中或vars变量文件中;方便修改vars: information: - name - school - addr tasks: - name: Check the loop vars service: name: "}}" state: satrted loop: "}"==分组循环==user: name: "}" group: "}" state: present loop: - name: wang group: GZEU #一组变量 不用加 ‘ - ’ - name: liu group: YushanLoop+RegisterAnsible剧本调试:one:剧本单步执行:two:tag标签:three:忽略错误1.单步执行-C --check 模拟运行,不做出改变(变量可能报错,因为没真正运行脚本)--syntax-check 只检查语法,不运行--step 单步运行:y执行这个task,n忽略这个task,c从当前开始自动运行2.tag标签(step改进)tag标签类似于超市物品的分类,只不过tag标签是给ansible中的task进行分类.加上标记;也就是单独对name moudle分类运行剧本的时候运行指定的tag标签或排除某些tag.==想单独运行部分板块或者不想运行部分板块==tags:==内容中不要有空格== [root@m01 playbook]# cat 12_tag.yml --- - hosts: buckup gather_facts: no tasks: - name: 01 Deploy nfs-utils,rpcbind yum: name: nfs-utils,rpcbind state: present tags: 1.install #针对独立name 进行标签 - name: 02 Present system file lineinfile: path: /etc/exports line: "/buckup-nfs 192.168.10.0/24(rw,all_squash)" create: true tags: 2.conf - name: 03-1 Create Together file & Present User user: name: nfsnobody create_home: yes state: present tags: 3.file - name: 03-2 Create Together file & Present User file: path: /buckup-nfs owner: nfsnobody group: nfsnobody state: directory tags: 4.user - name: 04 Start Service(rpcbind,nfs) systemd: name: "}" enabled: yes state: started loop: - rpcbind - nfs tags: 5.service-t 、--tags 运行的标签,如果多个标签则通过","分割--skip-tags 排除指定的tags,如果多个标签则通过","分割--list-tags 列出剧本的全部标签# 列出标签 [root@m01 playbook]# ansible-playbook --list-tags 12_tag.yml playbook: 12_tag.yml play #1 (buckup): buckup TAGS: [] TASK TAGS: [1.install, 2.conf, 3.file, 4.user, 5.service] # 运行tags板块1 [root@m01 playbook]# ansible-playbook -t 1.install 12_tag.yml # 运行板块1和2 [root@m01 playbook]# ansible-playbook -t 1.install,2.conf 12_tag.yml #板块之间无空格 #--skip-tags 除开选择的tags标签 剩余的标签全部执行 [root@m01 playbook]# ansible-playbook --skip-tags 2.conf,3.file,4.user,5.service 12_tag.yml #只执行 1.install3.忽略错误anisble在执行出错的时候终结剧本,不再执行后续程序因重复导致的错误提示(并非真错误,例如目录,用户已经存在) systemd服务名错误也能忽略通过 ignore_errors忽略错误,继续剧本ignore_errors: true true/false yes/no场景:才执行创建文件、目录、用户等操作时可加此参数- hosts: nfs tasks: - name: 01 Creat file file: path: /server/files/ state: directory ignore_errors: true #和tags一样与模块、name对齐Jinja2模板1.基本使用在分发文件时,文件中==需要使用变量==(facts,Clents_info,groups_vars)copy传输文件 文件纹丝不动传递==template会替换掉文件中的变量(.j2) 无需手动修改==文件必须以 .j2 结尾必须使用template模块(传输时替换j2文件中的变量)# 分发主机信息文件 [root@m01 templates]# cat 01_Jinja2_test.j2 ###################### welcome to oldboy elastic linux system 操作需谨慎,删根弹指间. 主机名: } ip地址: } 内存大小: } CPU数量: } 核心总数: } 发行版本: }# 剧本 [root@m01 templates]# cat 02_handj2.yml --- - hosts: nfs tasks: - name: Create (copy templates) file file: path: /root/jinja/ state: directory - name: template Hand J2 file template: src: /root/script/playbook/templates/01_Jinja2_test.j2 dest: /root/jinja/template backup: yes - name: copy Hand J2 file copy: src: /root/script/playbook/templates/01_Jinja2_test.j2 dest: /root/jinja/copy backup: yes #对比两模块 变量是否变化 # copy [root@m01 templates]# ansible nfs -m shell -a "cat /root/jinja/copy" 主机名: } ip地址: } #无法识别变量 # template 主机名: nfs01 ip地址: 192.168.10.512.判断使用判断和循环可存在在 .j2文件中# 条件判断 state Mater state Node 3.循环配置文件server.conf10.0.0.5 10.0.0.6 10.0.0.7 10.0.0.8 10.0.0.9 10.0.0.10 #适合不连续的 10.0.0.} #适合大范围连续的 10.0.0.} 4.过滤器} } 输出对应的文本格式# to_nice_json,to_nice_yaml #过滤相应要求的JSON或TAML格式 } }集群批量管理-Ans-完结篇include文件包含1个ansible剧本内容过多,==涉及到多个play(-host:web)==,可读性变弱,不方便调试.于是人们想出把单个大的剧本拆分为多个,小的剧本.多个小的剧本可以通过include功能合并使用.缺点: 同级目录下存在多个yml文件、变量文件vars以及j2文件,板块较为混乱 不适合大型剧本拆分后的文件只包含tasks后面的部分:==不包含tasks的行==[root@m01 include]# cat 01_nfs_server.yml - name: 01 Deploy nfs-utils,rpcbind yum: [root@m01 include]# cat 02_nfs_client.yml - name: 01 Deploy nfs-utils,rpcbind yum: [root@m01 include]# cat 03_nfs_include.yml --- - hosts: buckup tasks: - include_tasks: 01_nfs_server.yml - hosts: web tasks: - include_tasks: 02_nfs_client.yml #handlersroles概述include将大型剧本模块化,但handlers、变量文件、发送配置文件(.j2)等比较混乱roles规则:这个规范是一套剧本目录结构的要求与标准,让我们书写剧本的时候,把剧本的内容和需要的文件,按照目录要求,分门别类存储。roles的本质就是规定了1套目录结构,用于书写剧本的.roles前提:熟练剧本模块,掌握服务流程;尽量==多使用变量==让剧本灵活性变高。[root@m01 include]# ls 01_nfs_server.yml 02_nfs_client.yml 03_nfs_include.yml # 可能还会设计多个变量、配置文件roles框架如果有自定义变量 ,在同级目录下有: group_vars/all/main.ymltasks/:存放角色的主要任务文件,可以包含多个 YAML 文件,每个文件定义一个任务。 handlers/:存放角色的处理器文件,用于处理由任务触发的事件。 templates/:存放角色使用的模板文件,可以在任务中使用 Jinja2 模板语法进行渲染。 files/:存放角色使用的普通文件,这些文件会被复制到目标主机上。 vars/:存放角色的变量文件,可以定义角色所使用的变量。 defaults/:存放角色的默认变量文件,这些变量的默认值会被其他变量覆盖。 meta/:存放角色的元数据文件,包含角色的描述信息、依赖关系等。 使用角色时,可以通过 import_role 或 include_role 导入和调用角色。nfs案例(S+C)Vault加密重要配置文件、参数文件涉密,需要通过加密保证安全 ==ansible-vault ==ansible-vault ==encrypt== 文件 :加密文件,直接读取是编码ansible-vault ==create== hosts_test 创建加密文件 默认用vi打开 自己添加内容ansible-vault ==edit== hosts_test 编辑加密文件(直接编辑为乱码)ans-hoc或ansible-playbook ==--ask-vault-pass== 即可使用中解密ansible-vault ==decryp==t 文件: 彻底解密(修改文件内容必须彻底解密):可加上==--output==参数 以其他名称另存加密文件;ansible-vault decrypt main.yml --output=main_vaulted.yml ansible-vault ==view== hosts_test 查看加密文件内容 不解密ansible-vault ==rekey== hosts_test 更改加密文件旧密码运行加密的剧本:==--vault-id @prompt==#加密文件 [root@m01 vault]# ansible-vault ansible-vault ansible-vault-2 ansible-vault-2.7 [root@m01 vault]# ansible-vault encrypt hosts New Vault password: Confirm New Vault password: Encryption successful [root@m01 vault]# cat hosts $ANSIBLE_VAULT;1.1;AES256 6638363062643933656664643233356...... #不解密情况下直接使用加密文件:无法识别#添加解密参数后: [root@m01 vault]# ansible --ask-vault-pass -i hosts nfs -m shell -a "ps -ef" Vault password: 192.168.10.51 | CHANGED | rc=0 >> #将加密文件彻底解密 [root@m01 vault]# ansible-vault decrypt hosts Vault password: Decryption successful #解密后才可对文件进行修改,也可直接识别和读取--vault-password-file=vault-pass 以文件形式解密 # echo 'root' > vault-pass # # ansible-playbook 03.debug-Registory.yml --vault-password-file=vault-pass Galaxy别人的Roles:第三方、官方、用户的rolesansible-galaxy collection install#galaxy.ansible.com/search?deprecated=false&keywords=nginx&order_by=-relevance&page=1 #官网roles # 默认下载到家目录 ansible-galaxy collection install nginxinc.nginx_core下载失败可选择下载 ==tarbao==优化常见优化ssh连接速度优化,关闭UseDNS,GSSAPIAuthcation....不要让ansible运行交互式的命令,非要用使用命令的非交互模式.需要使用ans,yum安装软件,可以自建本地yum仓库,然后ans安装.(自建yum源,自己制作的rpm包)#ansible并发默认五台机器 -f FORKS, --forks FORKS specify number of parallel processes to use (default=5) #根据CPU的核心数提高需求给ansible配置缓存,队列。缓存(facts)给主机进行分组操作(web,nfs,backup)关闭gather_facts,如果不用facts变量可以关闭,剧本中:gather_facts:false配置文件:gathering = explicit关闭host,key,check一般使用密码认证的时候需要关闭,如果不关闭 ansible配置文件host_key_checking = False ==第一次ssh时的yes/no====安全==生产环境下一般不是ansible节点root远程集群root,默认会关闭root的远程权限,==ansible使用的时sudo提权的用户====配置sudo提权== ans ALL=(ALL) NOPASSWD: ALL 密码是1,ss端口22配合 vpn,jms一起使用用户--->vpn--->jms--->ansible用户密码、涉密文件、配置(bash,ansible-vault)==ansible---sudo==客户端# sudoers文件提权 [root@nfs01 ~]# tail -1 /etc/sudoers ans_sudo ALL=(ALL) NOPASSWD: ALL # 创建此用户 密码设置为1 [root@nfs01 ~]# useradd ans_sudo useradd: user 'ans_sudo' already exists [root@nfs01 ~]# passwd ans_sudo Changing password for user ans_sudo. New password: BAD PASSWORD: The password is a palindrome Retype new password: passwd: all authentication tokens updated successfully. [ans_sudo@nfs01 root]$ sudo -l User ans_sudo may run the following commands on nfs01: (ALL) NOPASSWD: ALL管理端1.修改/etc/ansible/ansible.cfg文件:添加被管理端上的sudo用户和使用的用户(不指定默认是当前root用户/root) 2.开启sudo功能和命令 指定切换用户3.被管理端root禁止远程登录,密钥认证需要发给sudu用户;[root@m01 ~]# ssh-copy-id ans_sudo@192.168.10.51 ans_sudo@192.168.10.51's password: and check to make sure that only the key(s) you wanted were added.4.如果不使用sudo用户,需要关闭sudo以及sudo指定用户:不一定全部机器有sudo配置以及指定的用户;5.禁用root远程登录禁用root远程前,需要注册好普通用户,配置sudovim /etc/ssh/sshd_config systemctl restart sshdRedHat补充模块补充service模块参数注解statestarted,stopped,restarted,reloaded(重载),enabled,name服务名mapper启动的参数:"service_mapper_name"arguments特定启动参数:arguments: "--specific-arguments"- name: Reload service service: name: httpd state: reloaded - name: Enable service service: name: httpd enabled: yes # 设置服务的启动 mapper 参数: - name: Set service mapper service: name: httpd mapper: "service_mapper_name" # 使用特定的启动参数启动服务: - name: Start service with specific arguments service: name: httpd state: started arguments: "--specific-arguments" ansible testB -m service -a "name=httpd enabled=yes"将testB(server3)中的httpd服务被设置为开机自动启动项firewalld模块参数选项注解icmp_block 在防火墙中添加或者移除的ICMP块。icmp_bolck_inversion 开启/关闭防火墙区域ICMP报文反转功能。==immediate==yes or no,默认no配置==立即生效==interface 在防火墙中添加或移除interfacemasquerade 在在防火墙中开启或关闭masquerade功能offlineyes or no是否在防火墙离线时运行此模块。==permanent==yes or no配置==永久添加==port 在防火墙中添加或移除端口名称或端口范围。端口范围必须为PORT/PROTOCOL或PORT-PORT/PROTOCOL格式rich_rule rich_rule添加或删除到防火墙==service== 在防火墙中添加或移除服务名称该服务必须在==firewall-cmd --get-services==的输出中列出。source 在防火墙中添加或移除某个来源的网络==state==absent or disabled or enabled or present启用或禁用一项设置。对于端口:该端口是否接受(enabled)或拒绝(disabled)连接。状态的(present)和(absent)只能在区域级别操作中使用(即,当除了zone和state没有设置其他参数时)。timeout默认0该规则应在非永久性时生效的时间zone 添加或移除的防火墙区域。注意,可以为每个系统配置默认的区域,可能的值有block, dmz, drop, external, home, internal, public, trusted, work,public- name: Start firewalld service service: name: firewalld state: started - name: Stop firewalld service service: name: firewalld state: stopped - name: Restart firewalld service service: name: firewalld state: restarted #添加移除防火墙规则 - name: Add a new firewall rule firewalld: zone: public service: http permanent: yes immediate: yes state: present - name: Remove a firewall rule firewalld: zone: public service: http permanent: yes immediate: yes state: absent #更改区域 - name: Change zone of an interface firewalld: zone: public interface: eth0 #富规则 - name: Add a rich rule firewalld: zone: public rich_rule: 'rule family="ipv4" source address="192.168.0.0/24" port port=80 protocol=tcp accept' permanent: yes immediate: yes state: present #自定义服务 - name: Add a new custom service firewalld: zone: public service: myservice port: 12345/tcp protocol: tcp permanent: yes immediate: yes state: present - firewalld: service: https permanent: yes state: enabled - firewalld: port: 8081/tcp permanent: yes state: disabled - firewalld: port: 161-162/udp permanent: yes state: enabled - firewalld: zone: dmz service: http permanent: yes state: enabled - firewalld: rich_rule: rule service name="ftp" audit limit value="1/m" accept permanent: yes state: enabled - firewalld: source: 192.0.2.0/24 zone: internal state: enabled - firewalld: zone: trusted interface: eth2 permanent: yes state: enabled - firewalld: masquerade: yes state: enabled permanent: yes zone: dmz - firewalld: zone: custom state: present permanent: yes - firewalld: zone: drop state: present permanent: yes icmp_block_inversion: yes - firewalld: zone: drop state: present permanent: yes icmp_block: echo-request - name: Redirect port 443 to 8443 with Rich Rule firewalld: rich_rule: rule family=ipv4 forward-port port=443 protocol=tcp to-port=8443 zone: public permanent: yes immediate: yes state: enableduri模块file模块: setype参数确保新的或者现有的文件具有==正确的权限和SElinux类型==[root@m01 file-module]# ansible nfs -m shell -a "ls -Z /root/redhat_ansible/file-module/testfile" 192.168.10.51 | CHANGED | rc=0 >> -rw-r-----. user1 group1 unconfined_u:object_r:admin_home_t:s0 /root/redhat_ansible/file-module/testfile[root@m01 file-module]# cat 02.file_samba.yml --- - hosts: nfs tasks: - name: samba set file: path: /root/redhat_ansible/file-module/testfile setype: samba_share_t[root@m01 file-module]# ansible nfs -m shell -a "ls -Z /root/redhat_ansible/file-module/testfile" 192.168.10.51 | CHANGED | rc=0 >> -rw-r-----. user1 group1 unconfined_u:object_r:samba_share_t:s0 /root/redhat_ansible/file-module/testfile系统可能会撤销模板的更改,需要==sefcontext模板更新SELinux策略== - name: samba set is persistently sefcontext: target: /root/redhat_ansible/file-module/testfile setype: samba_share_t state: present滚动更新 serial--- - hosts: web # 假设有五台机器 tasks: serial: 2 # 一次并发2台机器 - name: Latest apache httpd yum: name: httpd state: latest notify: restart httpd handlers: - name: restsrt apache service: httpd state: restarted若不设置serial参数,系统默认最大forks为5,即一次play执行可达五台机器的并发,五台web服务器同时进行更新并重启,web服务必定中断使用serial参数,设定在本次play中,每次并发为2,即前2台机器更新重启前,其余三台处于正常运行状态;服务降级但不会中断。time确定运行时间time ansible-playbook 04.show_facts.yml real 0m2.371s user 0m0.366s sys 0m1.080s==包含和导入==在住playbook中可导入若干其他的playbook;==import_playbook:== 静态- name: import_playbook play1.yml import_playbook: play1.yml - name: import_playbook play2.yml import_playbook: play2.yml # 可与主playbook交替使用可在tasks中导入tasks文件:==import_tasks:== 在play执行最先预处理得到具体任务(开始之前)tasks文件,从-name:(tasks后)开始 针对某个主机组的执行操作[root@m01 import_tasks]# cat tasks_test.yml - name: install apache yum: name: httpd state: present导入到playbook指定位置--- - hosts: all tasks: - name: install server tools import_tasks: tasks_test.yml==include_tasks : 在任务到此处时读取到yml文件才开始处理== 动态
2024年03月24日
21 阅读
0 评论
0 点赞
2024-02-01
Shell总结
Shelllinux内核(kernel),操作计算机硬件资源,告诉CPU干什么、需要多少内存...linux用户操作作用在外层应用程序,内核不能直接识别用户的操作指令,需要借助Shell命令行解释器(解释、调用程序,向内核发起申请),才能让内核完成命令操作查看Linux下的shell的解释器默认bash shellHello Word案例shell脚本一般一.sh为后缀,且第一行必须是 #!/bin/bash 或者 #!/bin/sh 执行脚本 1.sh、bash + 脚本相对或绝对路径2.对文件添加可执行权限X,./脚本文件执行3.对文件添加可执行权限X,用 “.” 或者“source” + 文件相对路径或绝对路径==不会启动子shell====.和./执行的逻辑不一样,.是命令,./是当前目录下执行某文件==变量全局变量:当前的shell和子shell都可以访问局部变量:只对当前shell有作用,其余子shell和父shell都不管用1.常用系统变量$HOME 家目录$PWD 当前目录查看全部全局变量:env 或者printenv==(只是系统的全局变量)==查看具体某一个环境变量:printenv + 变量名set查看系统的全局变量和局部变量,==包括自己定义的==自定义变量(默认定义为字符串)局部变量变量名=变量值,===前后不能有空格==变量值如果有空格,使用双引号myname=“wang tao”全局变量export myname,寓意为导出,子shell即可生效如果在子shell更改,退出子shell后不生效,只在子shell或者子shell的子shell生效查看子shell进程 ps -f,bash启动新子shell==局部变量输出==1.使用“.”或者“source”,在当前shell执行,不启动子shell即可生效2.使用export将局部变量变为全局变量只读变量(不能更改的常量)readonly a=wang变量常量的撤销unset + 变量名,==常量不可uset==变量名规则1.不能以数字开头,==环境变量名建议大写==2.bash中默认变量类型为字符串类型,无法直接数值运算3.变量值有空格,需要用单/双引号创建脚本命令将脚本文件放在/bin/下,输入脚本文件名即可执行(带后缀)特殊变量1.$n$n(n为数字,0表示脚本名称,(1-9)表示第一到第九个参数),十以上的参数需要用,示例#!/bin/sh echo "Hello Word! SH " echo "Hello,$1" echo "Hello $0"执行# ./hello.sh wangtao Hello Word! SH Hello,wangtao Hello ./hello.sh单引号中不会编译特殊符号,会按照源字符输出#!/bin/bash echo '========$0=========' echo script name: $0 echo 1st paramater: $1 echo 2nd parameter: $2 # ./part wang liu ========$0========= script name: ./part 1st paramater: wang 2nd parameter: liu2.$获取当前输入参数的个数,常用于循环(参数个数失败会报错)#!/bin/bash echo '========$0=========' echo script name: $0 echo 1st paramater: $1 echo 2nd parameter: $2 echo parameter number: $# [root@sre_shell ~]# ./part wang liu ========$0========= script name: ./part 1st paramater: wang 2nd parameter: liu parameter number: 23.$*$* :代表命令行中所有的参数,会把所有参数看成一个整体$@:代表命令行所有参数,把每个参数区分对待(数组)echo $* echo $@ # ./part wang liu wang liu wang liu不加"" 两者没有区别[root@sre_shell ~]# cat parameter_for.sh #!/bin/bash echo '$*' for para in "$*" do echo $para done echo '$@' for para in "$@" do echo $para done[root@sre_shell ~]# ./parameter_for.sh a b c e $* a b c e $@ a b c e4.$?返回最后一次执行命令返回状态,如果为0,表示成功执行,如果非0(不同数值表示不同错误),表示不正确运算符赋值默认为字符串,不可直接做运算expr 1 + 1,expr 3 * 9 注意有空格赋值格式[root@sre_shell ~]# a=$((1+9)) [root@sre_shell ~]# echo $a 10 [root@sre_shell ~]# a=$[9*3] [root@sre_shell ~]# echo $a 27 [root@sre_shell ~]# a=$[(2+3)*4] && echo $a 20expr赋值格式[root@sre_shell ~]# a=$(expr 9 \* 2) [root@sre_shell ~]# echo $a 18 [root@sre_shell ~]# a=`expr 9 / 3` [root@sre_shell ~]# echo $a 3加法脚本[root@sre_shell ~]# cat add.sh echo $[$1+$2] [root@sre_shell ~]# ./add.sh 2 3 5条件判断基本语法 test + 条件表达式(==前后面有空格,否则都为0==)[root@sre_shell ~]# test $a = hello [root@sre_shell ~]# echo $? 0 [root@sre_shell ~]# test $a = hell [root@sre_shell ~]# echo $? 1等价于==[ ]也有空格==[root@sre_shell ~]# [ $a = hello ] [root@sre_shell ~]# echo $? 0 [root@sre_shell ~]# [ $a = hell ] [root@sre_shell ~]# echo $? 1 = ,!=是判断字符串是否相等 [ 2 != 2 ] 1 这里比较的是字符串比较-a -o在同一个[ ]中可以用-a参数表示&&,-o表示||[root@sre_shell ~]# echo $a 20 [root@sre_shell ~]# if [ $a -gt 18 ] && [ $a -lt 30 ]; then echo OK; fi OK [root@sre_shell ~]# if [ $a -gt 18 -a $a -lt 30 ]; then echo OK; fi OK [root@sre_shell ~]# if [ $a -gt 30 -o $a -lt 18 ]; then echo OK; fi [root@sre_shell ~]# [] 空值为 1 (假)数值之间的比较参数-eq 等于 -ne 不等于 -lt 小于-le小于等于 -gt大于 -ge大于等于[root@sre_shell ~]# echo $? 0 [root@sre_shell ~]# [ 8 -eq 8 ] [root@sre_shell ~]# echo $? 0 [root@sre_shell ~]# [ 8 -ne 8 ] [root@sre_shell ~]# echo $? 1 [root@sre_shell ~]# [ 8 -lt 8 ] [root@sre_shell ~]# echo $? 1 [root@sre_shell ~]# [ 8 -le 8 ] [root@sre_shell ~]# echo $? 0 [root@sre_shell ~]# [ 8 -gt 8 ] [root@sre_shell ~]# echo $? 1 [root@sre_shell ~]# [ 8 -ge 8 ] [root@sre_shell ~]# echo $? 0判断文件权限-r 有读的权限 -w 有写的权限 -x有执行的权限[root@sre_shell ~]# ls -l part -rwxr-xr-x. 1 root root 148 Mar 4 08:01 part [root@sre_shell ~]# [ -r part ] && [ -w part ] [root@sre_shell ~]# echo $? 0判断文件类型-e 表示文件存在 -f 表示存在且是一个常规文件 -d存在且是目录[root@sre_shell ~]# ls add.sh anaconda-ks.cfg hello.sh part test [root@sre_shell ~]# [ -e part ] [root@sre_shell ~]# echo $? 0 [root@sre_shell ~]# [ -f part ] [root@sre_shell ~]# echo $? 0 [root@sre_shell ~]# [ -d part ] [root@sre_shell ~]# echo $? 1 [root@sre_shell ~]# [ -d test ] [root@sre_shell ~]# echo $? 0==案例(三元)==A&&B||C:A真执行B,否则执行C[root@sre_shell ~]# [ $a -lt 300 ] && echo "$a<300" || echo "$a>300" 200<300 []有字符串为真,空为假 [root@sre_shell ~]# [ ] && echo "ok" || echo "nook" nook流程控制1.if单分支 if [ 条件判断 ];then #常用于命令行 程序 fi 或者 if [ 条件判断 ] #常用于文本脚本 then 程序 fi 例 [root@sre_shell ~]# if [ $a -gt 18 ]; then echo OK; fi OK ==传参防空==[root@sre_shell ~]# cat iftest #!/bin/bash if [ "$1"x = "wang"x ] #字符串拼接原理,保证有一个字母 then echo "hello,$1" fi多分支 if [ 条件判断 ] then 程序 elif [ 条件判断 ] then 程序 else 程序 fi if [ $2 -lt 22 ] then echo "<22" elif [ $2 -lt 25 ] then echo "<25" else echo ">25" fi[ ]中的条件判断两边必须要有空格 ,if elif 后面有空格2.casecase $变量名 in "值1") 如果变量=值1,执行程序1 ;; "值2") 如果变量=值2,执行程序2 ;; *) 都不满足就执行此程序 ;; esac[root@sre_shell ~]# ./case.sh 40 年轻 [root@sre_shell ~]# ./case.sh 60 老了 [root@sre_shell ~]# ./case.sh 30 加油 [root@sre_shell ~]# cat case.sh #!/bin/bash case $1 in "60") # 60)可以不用"" echo "老了" ;; "40") echo "年轻" ;; *) echo "加油" ;; esac循环1.forfor ((初始值;循环控制条件;变量变化)) do 程序 done[root@sre_shell ~]# chmod +x for.sh [root@sre_shell ~]# ./for.sh 5050 [root@sre_shell ~]# cat for.sh #!/bin/bash sum=0 for((i=0;i<=100;i++)) do sum=$[$sum+$i] #内层$只是字符串拼接,外层$[]是按数值运算 done echo $sum传参式[root@sre_shell ~]# cat sum1.sh #!/bin/bash sum=0 for (( i=1;i<=$1;i++)) do sum=$[ $sum + $i ] done echo $sum [root@sre_shell ~]# ./sum1.sh 100 50502.定值for#!/bin/bash for os in linux windows macos do echo $os down [root@sre_shell ~]# ./dfor linux windows macos [root@sre_shell ~]# for os in window linux macos; do echo $os;done window linux macos3.增强型[root@sre_shell ~]# for i in ; do sum=$[$sum+$i]; done; echo $sum 5050[root@sre_shell ~]# ./for.sh 5050 [root@sre_shell ~]# cat for.sh #!/bin/bash sum=0 for i in do sum=$[$sum+$i] #内层$只是字符串拼接,外层$[]是按数值运算 done echo $sum4.while循环while [ 条件判断 ]#循环外的初始值 do 程序 #包含程序结束条件 done[root@sre_shell ~]# cat while.sh #!/bin/bash a=1 while [ $a -le $1 ] do sum2=$[$sum2+$a] a=$[$a+1] done echo $sum2 [root@sre_shell ~]# ./while.sh 100 50505.let(转义别的语法==C==)let+C语言语法#!/bin/bash a=1 while [ $a -le $1 ] do let sum2+=a let a++ done echo $sum2读取控制台read读取控制台从控制台读取用户的输入read (选项) (参数) #有空格 -p 输入前的提示符 -t 指定等待时间(不加表示一直等待) 参数 指定读取值的变量名[root@sre_shell ~]# cat read.sh #!/bin/bash read -t 10 -p "请输入:" name #注意空格 echo "Hello $name" [root@sre_shell ~]# ./read.sh 请输入:wang Hello wangread+条件判断[root@sre_shell ~]# cat read.sh #!/bin/bash read -t 3 -p "请输入:" name if [ $name ] then echo "Hello $name" else echo "no name" fi [root@sre_shell ~]# ./read.sh 请输入:wang Hello wang [root@sre_shell ~]# ./read.sh 请输入:no name函数系统函数轻量化脚本==变量+系统时间戳==[root@sre_shell ~]# cat namedate.sh #!/bin/bash filename="$1"_logtime_$(date +%s) echo $filename [root@sre_shell ~]# ./namedate.sh testname testname_logtime_1709686703 [root@sre_shell ~]# date +%s 1709686712==basename==截取文件路径的文件名称(去掉路径也可去掉后缀)basename /home/test/wang.test wang.test basename /home/test/wang.text .text wang==实际用法:生产带时间戳、拼接等字符串时 不能带上文件路径和后缀==[root@sre_shell ~]# cat srcipt.sh #!/bin/bash echo script_name: $0 [root@sre_shell ~]# ./srcipt.sh script_name: ./srcipt.sh [root@sre_shell ~]# /root/srcipt.sh script_name: /root/srcipt.sh #$0会取到文件路径和后缀 改进 #!/bin/bash echo script_name: $(basename $0 .sh) #用()添加系统命令 [root@sre_shell ~]# ./srcipt.sh script_name: srciptdirname和basename相反,==截取最后一个/之前的路径==不管相对还是绝对路径,当做字符串处理,截取最后/前字符[root@sre_shell ~]# dirname /root/while.sh /root [root@sre_shell ~]# dirname /root/wang/test /root/wang #不管路径或者文件存不存在脚本输出文件绝对路径即使使用相对路径调用脚本也会获取绝对路径[root@sre_shell ~]# cat dirname.sh #!/bin/bash cd $(dirname $0) echo script path: $(pwd) 简化 [root@sre_shell ~]# cat dirname.sh #!/bin/bash echo script path: $(cd $(dirname $0); pwd) #dirname有可能读取是相对路径,使用pwd获取绝对路径 [root@sre_shell ~]# ./dirname.sh script path: /root自定义函数function functionname() { Action; [return int;] } 必须在调用函数前声明函数,shell是逐行运行 函数返回值只能通过$?获取,return返回 如果不加就以最后一条命令运行结果作为返回值,return后跟数值n(0-255)函数定义和调用[root@sre_shell ~]# cat funtionname.sh #!/bin/bash function sum() { s=$[$1+$2] echo "sum="$s } read -p "number1: " a read -p "number2: " b sum $a $b [root@sre_shell ~]# ./funtionname.sh number1: 23 number2: 43 sum=66有返回值[root@sre_shell ~]# cat funtionname.sh #!/bin/bash function sum() { s=$[$1+$2] return $s } read -p "number1: " a read -p "number2: " b sum $a $b echo $? # $?的取值范围是0-255,超出即进入下一次循环 [root@sre_shell ~]# ./funtionname.sh number1: 255 number2: 5 sum=4优化用return后,¥?只能捕获0-255,所以不用$?捕获#!/bin/bash function sum() { s=$[$1+$2] echo $s } read -p "number1: " a read -p "number2: " b sum=$(sum $a $b) #将函数echo的值转换并赋值 echo "sum="$sum echo "sum^2="$[$sum*$sum] #二次计算正则 正则表达式使用单个字符申来描述、匹配一系列符合某个语法规则的字符串。在很多文本编辑器里,正则表达式通常被用来==检索、替换那些符合某个模式的文本==。在Linux中,grep,sed,awk等文本处理工具都支持通过正则表达式进行模式匹配。用来定义一个模糊检索规则常用于模糊检索;以什么开头的IP、什么结尾的文件1.常规匹配[root@kernel_shell archive]# cat /etc/passwd | grep wang wang:x:1000:1000::/home/wang:/bin/bash2.常用特殊字符^ ;匹配一行的开头可以接一个字符和一个字符串[root@kernel_shell archive]# cat /etc/passwd | grep ^w #以w字母开头的 wang:x:1000:1000::/home/wang:/bin/bash wangtao:x:1001:1001::/home/wangtao:/bin/bash$ ;匹配一行的结束h$ 匹配以h结尾的行[root@kernel_shell archive]# cat /etc/passwd | grep h$ root:x:0:0:root:/root:/bin/bash wang:x:1000:1000::/home/wang:/bin/bash wangtao:x:1001:1001::/home/wangtao:/bin/bash如果同时出现^,$,中间匹配的字符必须是和那一行一模一样才会匹配成功[root@kernel_shell archive]# cat /etc/passwd | grep ^wang:x:1000:1000::/home/wang:/bin/bash$ wang:x:1000:1000::/home/wang:/bin/bash [root@kernel_shell archive]# ^,$之间如果没有字符,则是匹配空行[root@kernel_shell archive]# cat /root/archive/kong.sh | grep -n ^$ 1: 2:k 3: 4: [root@kernel_shell archive]# -n 显示空行所在的行号“ . ” 任意一个字符“ . ”匹配任意==一个==字符[root@kernel_shell archive]# cat /etc/passwd | grep r..t #r和t之间只有两个字符的 root:x:0:0:root:/root:/bin/bash operator:x:11:0:operator:/root:/sbin/nologin ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin dockerroot:x:997:994:Docker User:/var/lib/docker:/sbin/nologin“ * ”上个字符0此和多次匹配*前面字符0此和多次[root@kernel_shell archive]# cat /etc/passwd | grep ro*t #匹配到有 rt、rot、root、roooot......等的行.*可以匹配任何行==^$,.*联用==.*可用于限定开头和结尾,不限定中间字符的正则[root@kernel_shell archive]# cat /etc/passwd | grep ^w.*sh$ wang:x:1000:1000::/home/wang:/bin/bash wangtao:x:1001:1001::/home/wangtao:/bin/bash[root@kernel_shell archive]# cat /etc/passwd | grep ^a.*var.*in$ # a任意var任意in的行 adm:x:3:4:adm:/var/adm:/sbin/nologin字符串区间“[]”[ ] 表示匹配某个范围的一个字符[6,8]:匹配6或8[0-9]:匹配0-9的数字[0-9]*:匹配任意长度的数字字符串[a-z]:匹配一个a-z之间的字符[a-z]*:匹配任意长度的字母字符串[a-c,e-f]:匹配a-c或者e-f之间的任意字符[root@kernel_shell ~]# cat /etc/passwd | grep r[a,b]t #可以不加“,” [root@kernel_shell ~]# echo "raaaabbbbabat" | grep r[ab]*t raaaabbbbabat [root@kernel_shell ~]# echo "rabt" | grep r[ab]t 无结果,[ab],[a,b]都只匹配一个字符a,b [root@kernel_shell ~]# cat /etc/passwd | grep r[a-z]*t转义特殊字符无法加入正则,需要借助转义符号 \[root@kernel_shell ~]# cat read.sh | grep '\$' if [ $name ] echo "Hello $name" 匹配的字符串:'/root/\$name'判断合法手机号码[root@kernel_shell ~]# echo 17628274871 | grep ^1[3456789][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9] 17628274871 [root@kernel_shell ~]# echo 12628274871 | grep ^1[3456789][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9] [root@kernel_shell ~]# 脚本[root@kernel_shell ~]# cat phonenumber.sh #!/bin/bash read -p "请输入手机号码:" number number=$[$(echo $number | grep ^1[3456789][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]$)] if [ $number -eq 0 ] then echo "手机号格式错误" else echo "手机号格式正确" fi [root@kernel_shell ~]# ./phonenumber.sh 请输入手机号码:17628274871 手机号格式正确 [root@kernel_shell ~]# ./phonenumber.sh 请输入手机号码:12545698965 手机号格式错误 [root@kernel_shell ~]# ./phonenumber.sh 请输入手机号码:175282448911 手机号格式错误正则优化==-E参数==表示支持扩展正则表达:,?......grep -E ^1[3456789][0-9]$ #出现9次文本处理工具cut负责剪切数据,cut从文件的每一行剪切字节、字符、字段并将这些字节字符字段输出;cut [选项参数] filename ls | cut (捕获剪切)选项参数功能-f列号,提取第几列-d按照指定分隔符分割列,默认制表符“t”-c按字符切割,后加n表示取第几列:-c 1 -d从第一行开始,遇到“”中匹配的字符中断,不包含本字符,作为一列,进入下一行[root@kernel_shell ~]# cat cut.txt name age address wang 20 sichuan liu 24 bazhong zhang 32 guiyang [root@kernel_shell ~]# cut -d " " -f 1 cut.txt 以空格为分割 name wang liu zhang [root@kernel_shell ~]# [root@kernel_shell ~]# cut -d "a" -f 1 cut.txt n w liu 24 b zh [root@kernel_shell ~]# 区间剪切[root@kernel_shell ~]# cut -d " " -f 2,3 cut.txt 表示将每行以“ ”空格隔开,提取第二列和第三列 age 20 32 [root@kernel_shell ~]# cat /etc/passwd | grep bash$ | cut -d ":" -f 1,6,7 root:/root:/bin/bash wang:/home/wang:/bin/bash wangtao:/home/wangtao:/bin/bash-f 7- :7行以后-f -4 :4行之前[root@kernel_shell ~]# echo $PATH | cut -d ":" -f 3- /usr/sbin:/usr/bin:/root/bin截取IP地址==有多少空格就算多少列==[root@kernel_shell ~]# ip a | grep ens33$ | cut -d " " -f 6 192.168.10.144/24 [root@kernel_shell ~]#awk(gawk)grep+cut文本分析工具,把文件逐行读入,以空格为默认分隔符将每行就行切片,切片的部分再进行分析处理;awk [选项参数] '/pattern/ /pattern2/...' filebame pattern: 表示awk在数据中查找的内容,就是匹配模式 action: 在找到匹配内容时所执行的一系列命令-F:指定输入文件分隔符-v:赋值一个用户定义变量搜索passwd 文件以root关键字开头的所有行,并输出该行的第7列。[root@kernel_shell ~]# awk -F : '/^root/' passwd /bin/bash : 表示指定分割字符为 : , 讲符合正则的代码块切片,每个参数代表列号 等价 [root@kernel_shell ~]# cat passwd | grep ^root | cut -d ":" -f 7 /bin/bash搜索passwd 文件以root关键字开头的所有行,并输出该行的第1列和第7列,中间以“,”号分割。[root@kernel_shell ~]# awk -F : '/^root/' passwd root,/bin/bash grep+cut不好实现 [root@kernel_shell ~]# cat passwd | grep ^root | cut -d ":" -f 1","7 root:/bin/bash只显示/etc/passwd的第一列和第七列,以逗号分割,且在所有行前面添加列名user,shell 在最后一行添加"dahaige,/bin/zuishuai"。[root@kernel_shell ~]# awk -F : 'BEGIN END' passwd user, shell wang,/bin/bash wangtao,/bin/bash dahaige,/bin/nihao==BEGIN在所有数据读取前执行,END在所有数据执行之后执行==将passwd文件中的用户id增加数值1并输出[root@kernel_shell ~]# awk -F ":" '' passwd 用户定义参数优化[root@kernel_shell ~]# awk -F ":" -v i=1 '' passwd awk内置变量FILENAME:文件名NR:已读的记录数(行号)NF:浏览记录的域的个数(切割后,列的个数)统计passwd文件名,每行的行号,每行的列数[root@kernel_shell ~]# awk -F ":" '' passwd 文件名:passwd行号:22列数:7 文件名:passwd行号:23列数:7awk输出空行行号[root@kernel_shell ~]# cat awk_kong.txt | awk '/^$/ ' 2 4 5 如果使用grep,默认格式会带“:”且无法更改 [root@kernel_shell ~]# cat awk_kong.txt | grep -n ^$ 2: 4: 5:优化捕获IP[root@kernel_shell ~]# ip a | awk -d '/ens3.$/ ' 192.168.10.144/24综合案例归档文件实际生产中需要对重要数据就行归档备份需求:实现一个每天对指定目录备份的脚本;输入一个目录名称(末尾不带/),将目录下的所有文件按天归档保存,将日期附加在归档文件名上,放在/root/archive下。tar -c表示归档、-z表示压缩,后缀为.tar.gz#!/bin/bash #判断输入参数是否唯一 if [ $# -ne 1 ] then echo "参数个数错误(一个参数作为归档目录名)" exit fi #从参数中获取目录名称 if [ -d $1 ] #判断目录是否存在 then echo else echo "目录不存在" exit fi dirname=$(basename $1) dirpath=$(cd $(dirname $1); pwd) #获取当前日期 date=$(date +%y%m%d) #定义生成的归档文件名称 filename=archive_$_$date.tar.gz dest=/root/archive/$filename #开始归档 echo "开始归档" tar -czf $dest $dirpath/$dirname if [ $? -eq 0 ] then echo "归档成功!" echo "归档文件为:$dest" else echo "出现错误;" echo fi exit [root@kernel_shell archive]# ls archive_archive_240306.tar.gz dayarc.sh定时任务的设定crontab -e -u root * 2 * * * /root/archive/dayarc.sh /root/archive #每天凌晨两点 [root@kernel_shell archive]# crontab -l * 2 * * * /root/archive/dayarc.sh /root/archive发送消息利用linux自带的mesg和write工具,向其他用户发送消息需求:实现向某个用户快速发送消息的脚本,输入用户作为第一个参数,后面接着需要发送的消息。脚本需要检测用户是否登录在系统中,是否打开消息功能,以及发送内容是否为空...#!/bin/bash #检测/passwd/文件是否存在输入的用户 #此模块尚未完善 可去除不影响正常功能 check_user=$(cat/etc/passwd | awk -d ":" -f 1 ) if [ -z check_user ] then echo "未检索到用户$check_user!" echo "脚本退出!" exit else sleep 1 echo "检索到$check_user 用户" # 1查看用户是否登录 login_user=$(who | grep -i -m 1 $1 | awk '') # -i表示过滤忽略大小写 -m表示匹配最大值,只取第一个 if [ -z $login_user ] #-z参数查看字符串是否为空 then echo "$1 不在线!" echo "脚本退出!" exit else sleep 1 echo "$1 检索在线" fi # 2查看用户是否开启mesage is_allowed=$(who -T | grep -i -m 1 $1 | awk '') if [ $is_allowed != "+" ] then echo "$1 没有开启mesage功能!" echo "脚本退出!" exit else sleep 1 echo "$1 mesage状态正常;" fi # 3判断消息内容是否为空 if [ -z $2 ] then echo "消息为空!" echo "脚本退出!" exit else sleep 1 echo "开始发送消息" fi #从参数中获取要发送的消息 whole_msg=$(echo $* | cut -d " " -f 2-) #获取用户登录终端 user_terminal=$(who | grep -i -m 1 $1 | awk '') #写入发送的消息 echo $whole_msg | write $login_user $user_terminal if [ $? != 0 ] then echo "消息发送失败!" else echo "消息发送成功!" fi sleep 2 echo "脚本执行结束!"
2024年02月01日
22 阅读
0 评论
1 点赞
2023-12-02
今天天气和往常不一样
呼吸一下外面的空气挺好的 久违的新鲜感
2023年12月02日
15 阅读
0 评论
0 点赞
2023-11-29
Kubernetes的污点和容忍
一、Taint 和 Toleration介绍节点亲和性,是 pod 的一种属性(偏好或硬性要求),它使 pod 被吸引到一类特定的节点。Taint 则相反,它使节点能够排斥一类特定的pod,Taint 和 toleration 相互配合,可以用来避免 pod 被分配到不合适的节点上。每个节点上都可以应用一个或多个taint ,这表示对于那些不能容忍这些 taint 的 pod,是不会被该节点接受的。如果将 toleration 应用于 pod上,则表示这些 pod 可以(但不要求)被调度到具有匹配 taint 的节点上。二、污点(Taint)2.1、 污点 ( Taint ) 的组成使用 kubectl taint 命令可以给某个Node节点设置污点,Node 被设置上污点之后就和 Pod 之间存在了一种相斥的关系,可以让 Node 拒绝 Pod 的调度执行,甚至将 Node 已经存在的 Pod 驱逐出去。污点的对象是: 节点每个污点的组成: key=value:effect每个污点有一个 key 和 value 作为污点的标签,其中 value 可以为空,effect 描述污点的作用。当前 taint effect 支持如下三个选项:NoSchedule :表示 k8s 将不会将 Pod 调度到具有该污点的 Node 上。PreferNoSchedule :表示 k8s 将尽量避免将 Pod 调度到具有该污点的 Node 上。NoExecute :表示 k8s 将不会将 Pod 调度到具有该污点的 Node 上,同时会将 Node 上已经存在的 Pod 驱逐出去。我们的 Master 节点上本来就已经有了污点,所以我们在创建 Pod 的时候,才不会将 Pod 创建在 Master 节点上。2.2、污点的设置、查看和去除设置污点kubectl taint nodes node1 key1=value1:NoSchedule这里我们打了一个 NoExecute 的标签,这个时候我们可以看到,之前在 node-1 上的 Pod 已经被驱离,因为这是自助式的 Pod ,没有我们的资源管理器进行管理的 Pod ,所以被驱离以后没有在被创建出来。节点说明中,查找 Taints 字段kubectl describe pod pod-name去除污点kubectl taint nodes node1 key1:NoSchedule-三、容忍(Tolerations)设置了污点的 Node 将根据 taint 的 effect:NoSchedule、PreferNoSchedule、NoExecute 和 Pod 之间产生互斥的关系,Pod 将在一定程度上不会被调度到 Node 上。 但我们可以在 Pod 上设置容忍 ( Toleration ) ,意思是设置了容忍的 Pod 将可以容忍污点的存在,可以被调度到存在污点的 Node 上。容忍的对象是: pod比如,我们现在将 node-1 与 node-2 都标记上污点,这个时候我们来创建一个 Pod 看一下:pod.spec.tolerationstolerations: - key: "key1" operator: "Equal" value: "value1" effect: "NoSchedule" tolerationSeconds: 3600 # 其中 key, vaule, effect 要与 Node 上设置的 taint 保持一致 # operator 的值为 Exists 将会忽略 value 值 # tolerationSeconds 用于描述当 Pod 需要被驱逐时可以在 node 上继续保留运行的时间 # 1、当不指定 key 值时,表示容忍所有的污点 key: tolerations: - operator: "Exists" # 2、当不指定 effect 值时,表示容忍所有的污点作用 tolerations: - key: "key" operator: "Exists" # 3、有多个 Master 存在时,防止资源浪费,可以如下设置 kubectl taint nodes Node-Name node-role.kubernetes.io/master=:PreferNoSchedule这个时候我们来设置一下,看下效果:vim tole-pod.yaml apiVersion: v1 kind: Pod metadata: name: pod-1 labels: app: pod-1 spec: containers: - name: pod-1 image: docker.io/busybox command: [ "/bin/sh", "-c", "sleep 600s" ] tolerations: - key: "node" operator: "Equal" value: "zutuaxue" effect: "NoExecute" tolerationSeconds: 30 # 容忍时间,超过该时间后将其驱离
2023年11月29日
18 阅读
0 评论
2 点赞
2023-11-28
Goroutine多种监控
监控goroutine的执行select类似switch case语句,select的功能和Linux的ip的select、poll、epoll相似。==主要作用于多个channel==eg:有两个goroutine都在执行,在主的gotoutine中,当某一个执行完成后需要立马得到反馈var done bool var lock sync.Mutex func g1() { time.Sleep(time.Second) lock.Lock() defer lock.Unlock() done = true } func g2() { time.Sleep(time.Second * 2) lock.Lock() defer lock.Unlock() done = true } func main() { go g1() go g2() for { if done { fmt.Println("done") time.Sleep(time.Millisecond * 10) return } } }a.select完成多个channel的监控var done = make(chan struct) func g1() { time.Sleep(time.Second) done <- struct } func g2() { time.Sleep(time.Second * 2) done <- struct } func main() { go g1() go g2() <-done fmt.Println("done") //只能知道有goroutine down了但是不知道哪一个 }监控多个不同的goroutine,不使用全局channelselect监控多个channel,每个channel返回都知道。==某一个分支就绪就执行该分支,若果两个都就绪,随机执行==func g1(ch chan struct) { time.Sleep(time.Second * 2) ch <- struct } func g2(ch chan struct) { time.Sleep(time.Second * 1) ch <- struct } func main() { g1ch := make(chan struct) g2ch := make(chan struct) go g1(g1ch) go g2(g2ch) select { case <-g1ch: fmt.Println("g1 down") case <-g2ch: fmt.Println("g2 down") } } g2 down //取决于函数sleepb.select default防止阻塞 select { case <-g1ch: fmt.Println("g1 down") case <-g2ch: fmt.Println("g2 down") default: fmt.Println("default") } //其他函数通常没有执行的机会default设置执行时间 select { case <-g1ch: fmt.Println("g1 down") case <-g2ch: fmt.Println("g2 down") default: time.Sleep(time.Second * 5) //只留给case总共五秒钟时间 fmt.Println("default") }c.Timerfunc g1(ch chan struct) { time.Sleep(time.Second * 2) ch <- struct } func g2(ch chan struct) { time.Sleep(time.Second * 1) ch <- struct } func main() { g1ch := make(chan struct) g2ch := make(chan struct) go g1(g1ch) go g2(g2ch) tm := time.NewTimer(5 * time.Second) //default默认退出时间 for { select { case <-g1ch: fmt.Println("g1 down") case <-g2ch: fmt.Println("g2 down") case <-tm.C: fmt.Println("time out") return //如果不return,循环将继续执行,会导致死锁 } } }
2023年11月28日
14 阅读
0 评论
0 点赞
1
2
3