编辑
2025-08-10
undefined
00
请注意,本文编写于 122 天前,最后修改于 122 天前,其中某些信息可能已经过时。

目录

3、第二阶段续篇
13、Tomcat集群部署
1、介绍
2、Tomcat快速安装
1、安装jdk
2、安装Tomcat
3、配置systemc方式启动
4、配置文件
5、Tomcat Http请求过程
6、Tomcat管理页面
7、Tomcat部署zrlog项目
3、Tomcat集群实战
1、安装Tomcat
2、拷贝代码和文件 ,web1执行
3、web02操作如下
4、挂载到nfs网络文件系统
5、配置负载均衡,Tomcat+Nginx+HTTPS
4、Tomcat+Nginx+Redis会话保持
1、web01配置
2、web02配置
5、部署最新版zrlog
14、阿里云平台
1、云基本介绍
2、ECS产品使用
1、产品架构
2、产品购买
3、ECS挂载磁盘
4、ECS搭建kodcloud
5、ECS快照与镜像
6、通过ECS镜像启动新的实例
7、配置负载均衡
部署完释放资源
3、快速恢复kod业务
1、基于镜像恢复实例
2、部署负载均衡
4、云解析DNS
1、DNS解析过程
2、记录概览
3、配置域名解析
5、配置HTTPS证书
6、四层负载
1、配置四层负载
7、Redis集群
1、高可用概念
2、部署redis实现kod会话保持
3、外网链接Redis
4、Redis规格升级
5、卸载redis会话保持
8、kod接入mysql
1、升级读写分离
9、NAS
1、挂载
2、卸载
10、OSS
1、购买
2、kod介入oss
3、删除oss
11、CDN
1、产品架构
2、加速原理
3、CDN概述
4、部署CDN
12、WAF防火墙
13、弹性伸缩
1、什么是弹性伸缩
2、创建弹性伸缩
3、报错案例
4、缩减弹性伸缩
14、NATA
1、概念
2、设置NAT
3、VPC NAT网关
15、Ansible
1、Ansible安装配置
1、Ansible使用
2、Ansible主机清单
1、Ansible示例
2、知识点小结
3、Ansible-adhoc
1、ping模块
2、yum模块
3、copy模块
4、command模块
5、file模块
6、group模块
7、user模块
8、yum\_repository模块
9、systemd
10、其他模块
4、Ansible-playbook
1、Playboot创建文件
2、Playbook重构backup服务
3、Playbook重构NFS服务
1、安装配置NFS
2、挂载方式
4、Playbook重构Nginx服务
5、Playbook重构PHP服务
6、Playbook重构Lsyncd服务
7、Playbook重构Mariadb服务器
8、Playbook重构wp业务
5、Ansible高级模块
1、cron模块
案例2. 一次创建多个用户
不建议使用此定义方法,因为不规范,主机清单就是主机清单
调用变量
定义变量,了解
调用变量
装B写法
结果全跳过不执行
backup安装 其他跳过
[backup]
2. #!/bin/bash
最底行添加auth-user-pass,注意该配置文件不要有多余空格,否则可能会报错,注意,要把配置文件client.ovpn拖出来再修改
nomodify 禁止修改配置
notrap 禁止trap服务
noquery 禁止时间查询
nopeer 禁止对等体模式
使用的时间同步服务器配置
启用统计记录
Allows members of the users group to shutdown this system
%users localhost=/sbin/shutdown -h now
cdrom as root
%users ALL=/sbin/mount /mnt/cdrom, /sbin/umount /mnt/cdrom
Allows members of the users group to shutdown this system
%users localhost=/sbin/shutdown -h now
jumpserver与网关做免密钥
限制不让人访问81端口如何做?
默认filter表
清空
sample configuration for iptables service
you can edit this manually or use system-config-firewall
please do not ask us to add additional ports/services to this default configuration
清空规则
#172段ping测试,通,因为没对172做限制
先允许后拒绝,可以连接、先拒绝后允许,不可以连接
#net.ipv4.icmpechoignore_all=1 写入到 /etc/sysctl.conf
#sysctl -p
Generated by iptables-save v1.8.5 on Mon May 19 22:18:35 2025
Completed on Mon May 19 22:18:35 2025
Generated by iptables-save v1.8.5 on Mon May 19 22:18:35 2025
Completed on Mon May 19 22:18:35 2025
Generated by iptables-save v1.8.5 on Mon May 19 22:19:41 2025
Completed on Mon May 19 22:19:41 2025
Generated by iptables-save v1.8.5 on Mon May 19 22:19:41 2025
Completed on Mon May 19 22:19:41 2025
当访问我的10.0.0.20的1111那么让你访问172.16.1.7:22
方法1: 使用bash或者sh
方法2: 使用路径的方式
方法3: 使用source或者.
从后往前匹配 %
表示传参的个数 用来控制用户传参个数
1. 取到负载值
2. %.*表示把0.00中.00去掉
[% ]+表示以%+空格为分隔符
#+#g'|bc
测试结果 遇到old3则退出脚本
定义源服务器和目标服务器的IP对应关系
遍历所有源服务器
查看隐藏的代码仓库
查看当前状态
工作区的d.txt添加内容
git diff 比对的工作目录和暂存区的不同
git diff --cached 比对的是暂存区和本地仓库的不同
git log只能看当前版本及之前版本的信息,无法查看所有的
回滚到4cc392a
查看当前工作目录状态
查看当前所在分支
创建testing分支
查看当前所在
切换到testing分支
查看当前所在
创建新的功能c.txt
切换到主分支
因为没同步testing分支,所以没有新文件
将testing中的代码合并到master分支
合并后删除testing分支,因为开发有很多,如果都提交了功能,那么当前分支落后于主分支会提交失败,代码不同步
查看当前分支
创建分支
追加内容
提交到本地仓库
切换testing分支
追加内容
切换主分支
合并testing分支,失败,显示冲突了
查看冲突文件
vim进去手动解决冲突
提交到仓库,解决
给最早的一个hahs值打tag
查看标签
查看tag的详细信息
通过tag版本回滚代码
删除标签
yum仓库更新安装和配置所需的依赖
安装仓库依赖
通过curl到的bash脚本然后交给bash执行
安装gitlab,时间大约40分钟
查看gitlab状态
停止gitlab服务
启动gitlab服务
添加一个远程仓库“origin”,链接地址为:git@10.0.0.201:oldboy/test.git
可以看到仓库的详细信息
删除远程仓库
将本地master分支推送到远程origin仓库
返回gitlab查看,可以看到代码已经同步到gitlab中
将test1仓库clone到本地
克隆的自带远程仓库,并不需要配置
创建代码文件推送到本地仓库
查看git分支
将本地main分支推送到远程origin仓库
将game仓库clone到本地
解压到gama目录
将代码推送到本地仓库,保证工作目录是干净的
推送到远端
查看gitlab页面
如何拉取刚上传的代码克隆到别的服务器
拉取到本地
浏览器测试
开发所用的服务器做与dev用户的免密钥就可以成功拉取所看到的项目代码
添加免密钥
拉取远程代码
直接在master进行修改
2、第90行的魂斗罗改成魂斗斗
3、提交到本地仓库,git commit -am集成了git add .跟git commit -m ""。使用前提是已经提交到仓库了
4、远程推送失败
1.创建新的testing分支
2.把testing分支推送到项目中,此时第90行的魂斗罗已经改成了魂斗斗
普通用户页面可以看到,页面点击创建合并请求
测试合并后的代码是否是魂斗斗
访问,成功修改成魂斗斗
创建并切换到test分支
第90行修改为魂斗斗123
提交到本地仓库
On branch test
注意! 切换到master分支进行提交
返回dev页面会看到“创建合并请求”,点击并填写内容
重新拉取代码测试
安装JDK运行环境
上传软件包并安装
查看本地jdk版本
安装
选择默认版本
再次查看java版本
已经成功启动
修改启动用户为root默认使用jenkins运行。
重新加载配置文件
启动jenkins
启动成功目录可以看到文件
重启jenkins生效
如果是云服务器访问失败,检查一下安全组规则是否放行了8080端口
默认的工作目录,也就是jenkins的家/var/lib/jenkins/workspace
可以看到新创建的文件
因为用的root用户启动,所以可以在别的地方创建文件
实例迁移后遇到项目URL指向旧 IP 的问题,这是典型的配置残留问题。
修改为当前服务器IP
重新加载,问题解决
换成新ip又报错了,原因又两个,1是底层没有做免密钥,要把235这台的公钥放到gitlab中去。2是需要手动把项目拉取到本地一下,输入个“yes”
目录下已经有了
原因是8.138.120.235与8.148.236.36之间没有做免密钥
配置nginx
1.更新看是否有新代码
2.修改代码
3.推送到本地仓库
4.推送到远程gitlab的master分支,因为与管理员做了免密钥
5.jenkins直接执行立即构建,把从git本地仓库的项目推到远程gitlab服务器的代码下载到jenkins本地/var/lib/jenkins/workspace/ganme目录。再scp到47.111.25.47:/code/game/
修改测试
提交到本地仓库
推送到远程服务器master节点
浏览器测试
sonar默认端口为9000
这里有个错误,分配了2g显示Elasticsearch 已经成功启动,但随后被系统终止(exit code 137)。这通常是内存不足导致的内核OOMKiller
介入的结果。调整内存大小为4g启动成功
再次登录,变成中文
第二遍搭的
上传包解压
创建软连接
将客户端写入PATH命令
进入到代码目录
执行代码扫描
返回浏览器查看
运行测试
这里有个问题,sonar集成到jenkins上自动推送,我这只改了sonar内存到4g,放到jenkins里面也得需要至少2g的内存,所以jenkins也得4g
已经自动推送到web服务器
因为是centons,可能版本不兼容,需要python3以上的版本
centos执行
优化py代码
-- coding: utf-8 --
移除 Python 2 特有的代码
reload(sys)
sys.setdefaultencoding('utf-8')
测试,成功
存放上面内容
脚本移动到server/scripts/
修改代码提交到本地仓库
推送到gitlab远程,剩余自动执行
项目代码已经改变
jenkins已经正常执行
已经正常推送
创建标签
推送到远程
测试
修改代码内容
提交到本地仓库
推送到远程
可以看到新创建的v1.1
脚本内容
检测脚本语法
执行完毕后根据tag标签创建了目录并且自动创建了软连接
执行完毕后把软连接指向了新发布的v1.1目录
添加到/etc/profile
访问测试
On branch master
Your branch is ahead of 'origin/master' by 3 commits.
(use "git push" to publish your local commits)
# Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
# modified: pom.xml
modified: src/main/webapp/index.jsp
no changes added to commit (use "git add" and/or "git commit -a")
上传到本地仓库
删除之前的
设置git@8.138.250.63:oldboy/java.git为远程仓库
推送到远程,报错了,原因是这台服务器与gitlab的普通用户做了免密钥导致权限不够,解决办法,删除普通用的的密钥,与管理员做免密钥
删除普通用户免密钥,新增管理员密钥,浏览器测试
进入Jenkins工作目录,已经成功编译了
查看,已经创建软连接
修改代码测试
上传到仓库
上传到本地仓库
返回Jenkins点击立即构建,没问题
编译会去中央仓库下载依赖,下载速度特别慢,因为仓库是国外的
中央仓库缓存位置
进入settings.xml文件修改
回到hellowork目录mvn 测试
上传JDK
上传nexus安装包
启动nexus
查看服务是否启动
浏览器访问
修改maven配置文件
测试,已经去找刚才配置的47.111.25.47地址了
报错,这个错误表明 Jenkins agent 节点的 Java 版本(1.8.0_412)与 Jenkins 控制器发送的 remoting.jar 文件不兼容。
升级版本
返回观察,已经正常
3.打印第二行的内容
4.打印最后一行
5.指定某行进行内容替换
This file controls the state of SELinux on the system.
SELINUX= can take one of these three values:
enforcing - SELinux security policy is enforced.
permissive - SELinux prints warnings instead of enforcing.
disabled - No SELinux policy is loaded.
6.指定删除第三行, 但不会改变文件内容
7.从第三行删除到最后一行
8.删除最后一行
9.删除所有的行
10.匹配指定的行进行删除
11.在第10行上面添加内容
12.将匹配到的行写入到新文件中
13.将 passwd 文件的第二行写入到 newfile 中
14.除了第三行,其他全部删除
15.替换每行出现的第一个 root
16.替换全部root
17.匹配包含有 root 的行进行替换
18.给1-3行添加注释
19.给20行到结尾添加注释
20.删除配置文件中#号开头的注释行, 如果碰到 tab 或空格是无法删除
1.BEGIN 发生在读文件之前
2.BEGIN 在行处理前, 修改字段分隔符
1.匹配root的行,输出1,3列
2.判断大于多少则输出什么内容
1. NR记录输入总的编号(行号)
2.NF保存行的最后一列列号,$NF保存最后一列内容
3.print格式化输出函数
4.匹配最后一列不是bash的列
1.uid为0的列出来
2.uid小于10的全部列出来
3.用户登陆的 shell 等于/bin/bash
4.第一列为#root的列出来
5.如果uid的值大于5555则打印第三列,否则打印第一列
6.查看用户数量分别是多少
7.匹配用户名为 root 或 uid 大于 5000
8.打印当前管理员用户名称
9.统计系统用户数量
修改密码:
解压zabbix源码
需要将schema.sql images.sql data.sql导入zabbix库
检查9000 3306 80端口
编写systemctl运行zabbix
重新加载
停止服务,但是服务并没有停止,因为不是systemctl启动的
pkill杀死所有zabbix的进程
启动进程
访问10.0.0.71
根据报错信息进行修改
重启php服务
测试
进入存放字体的目录
备注修改名称
将windows上传的字体改名
刷新页面检查字体
用zabbix取客户端的登陆用户数流程
Format: UserParameter=<key>,<shell command> 把 shell command命令放到<key>里面
提权,所有普通用户在执行这个命令的时候都拥有root权限,在客户端加权,因为
页面配置
关闭nginx服务
刷新测试
注意!添加“查看值”的时候,上面单位的数量要清空,否则不生效
net.tcp.listen[]是系统自带的监控项,可以监控端口
停止php服务
zabbix页面添加
已成功收到邮件
配置邮件告警信息
上传py脚本
修改weixin.py中的三个参数
安装python2版本
查看公网ip
将脚本移动到固定的目录
修改日志权限
查看日志,无关键内容
手动测试连通性,显示没有文件,查看原因是文件名错误,修改文件名
测试
测试联通性,没问题,遇到个问题,命令行跟界面测试都没能发送过去,但是联通性不行
1.配置七种状态
2.自定义取值
3.重启客户端,先关闭等端口消失再启动,否则会出现客户端能显示监控项。服务端看不到的清空
4.查看自定义值
5.服务端获取客户端自定义值测试zabbix_get
压力测试
这行取消注释
1.修改配置文件
2.配置nginx
3.php状态介绍
4.配置key参数值
5.重启zabbix-agent
创建php模板
页面创建监控项
使用oid的方式
查看日志
重启服务端测试
修改密码:
发现并没有启动,查看后台日志
杀死zabbix进程
重新启动
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
如遇到tomcat端口起不来的情况,先杀死进程再启动
迟迟不生效,服务端获取值测试
发现权限不足,原因是zabbix访问root目录没有权限
服务端可以正常获取

3、第二阶段续篇

13、Tomcat集群部署

1、介绍

bash
Tomcat Tomcat和Nginx类似,都是WEB服务器软件 只不过Tomcat是基于JAVA开发的WEB服务,主要解析JAVA代码 Nginx仅支持静态资源解析,而Tomcat支持解析Java开发的WEB应用,还支持解析静态资源(效率不高) Nginx适合做前端负载均衡,Tomcat适合做后端应用服务处理 通常情况企业会使用Nginx+Tomcat结合,Nginx处理静态资源,Tomcat处理动态资源 JAVA环境JRE和JDK的区别 jre是java的运行环境,包含jvm jdk是java的开发环境,会包含java的运行环境jre 如果说单纯的运行java代码,只需要jre足够,但如果需要提供开发环境以及运行环境则需要JDK

image-20250422151724982

2、Tomcat快速安装

1、安装jdk
bash
1、上传rmp包 2、解压 [root@web01 ~]#rpm -ivh jdk-8u181-linux-x64.rpm 查看是否安装成功 [root@web01 ~]#rpm -qa|grep jdk jdk1.8-1.8.0_181-fcs.x86_64
2、安装Tomcat
bash
1、安装Tomcat(下载 Tomcat、解压、启动 ) Tomcat官网: https://tomcat.apache.org [root@web01 ~]#wget https://dlcdn.apache.org/tomcat/tomcat-9/v9.0.104/bin/apache-tomcat-9.0.104.tar.gz 2、创建Tomcat目录/soft [root@web01 ~]#mkdir /soft 3、解压 [root@web01 ~]#tar xf apache-tomcat-9.0.104.tar.gz -C /soft/ 4、创建软连接 [root@web01 ~]#ln -s /soft/apache-tomcat-9.0.104/ /soft/tomcat 5、启动 [root@web01 ~]# /soft/tomcat/bin/startup.sh Using CATALINA_BASE: /soft/apache Using CATALINA_HOME: /soft/apache Using CATALINA_TMPDIR: /soft/apache/temp Using JRE_HOME: /usr Using CLASSPATH: /soft/apache/bin/bootstrap.jar:/soft/apache/bin/tomcat-juli.jar Using CATALINA_OPTS: Tomcat started. [root@web01 /soft]#netstat -tnulp # 8080 对外提供服务的端口 # 8005 关闭Tomcat端口 Active Internet connections (only servers) tcp6 0 0 127.0.0.1:8005 :::* LISTEN 3171/java tcp6 0 0 :::8080 :::* LISTEN 3171/java 6、停止 [root@web01 ~]# /soft/tomcat/bin/shutdown.sh
3、配置systemc方式启动
bash
#1.查看内容 [root@lb01 ~]# systemctl cat nginx #2.不存在文件则自动创建,并复制进去 [root@lb01 ~]# cat >/usr/lib/systemd/system/tomcat.service<<'EOF' [Unit] Description=Apache Tomcat Server After=network.target remote-fs.target nss-lookup.target [Service] Type=forking ExecStart=/soft/tomcat/bin/startup.sh ExecStop=/soft/tomcat/bin/shutdown.sh ExecRetart=/soft/tomcat/bin/shutdown.sh && sleep2 && /soft/tomcat/bin/startup.sh [Install] WantedBy=multi-user.target EOF #3.查看内容 [root@web01 /soft]#cat /usr/lib/systemd/system/tomcat.service [Unit] Description=Apache Tomcat Server After=network.target remote-fs.target nss-lookup.target [Service] Type=forking ExecStart=/soft/tomcat/bin/startup.sh #启动的命令 ExecStop=/soft/tomcat/bin/shutdown.sh #停止的命令 ExecRetart=/soft/tomcat/bin/shutdown.sh && sleep2 && /soft/tomcat/bin/startup.sh [Install] WantedBy=multi-user.target #4.重新加载 [root@web01 /soft]#systemctl daemon-reload [root@web01 /soft]#systemctl enable tomcat Created symlink /etc/systemd/system/multi-user.target.wants/tomcat.service → /usr/lib/systemd/system/tomcat.service. #5.启动tomcat [root@web01 /soft]#systemctl start tomcat [root@web01 /soft]#netstat -tnulp Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp6 0 0 127.0.0.1:8005 :::* LISTEN 3491/java tcp6 0 0 :::8080 :::* LISTEN 3491/java
4、配置文件
bash
tomcat软件目录结构:/soft/tomcat bin ---主要包含启动和关闭tomcat的脚本(启停java脚本依赖jar包文件) conf ---tomcat配置文件的目录(站点配置:server.xml) lib ---tomcat运行时需要加载的jar包 logs ---tomcat日志存放位置 temp ---tomcat临时存放文件路径 webapps ---tomcat默认站点目录 work ---tomcat运行时产生的缓存文件 配置文件详解-----> /soft/tomcat/conf/server.xml <?xml version="1.0" encoding="UTF-8"?> <Server port="8005" shutdown="SHUTDOWN"> #关闭通过8005端口关闭 <Listener className="org.apache.catalina.startup.VersionLoggerListener" /> <Listener className="org.apache.catalina.core.AprLifecycleListener" /> <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" /> <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" /> <Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" /> <GlobalNamingResources> <Resource name="UserDatabase" auth="Container" type="org.apache.catalina.UserDatabase" description="User database that can be updated and saved" factory="org.apache.catalina.users.MemoryUserDatabaseFactory" pathname="conf/tomcat-users.xml" /> </GlobalNamingResources> <Service name="Catalina"> #主服务 <Connector port="8080" protocol="HTTP/1.1" #连接器,响应外部用户的连接请求。可以有多个sever,也就是多个域名 connectionTimeout="20000" redirectPort="8443" maxParameterCount="1000" /> <Engine name="Catalina" defaultHost="localhost"> #引擎,类似于容器 <Realm className="org.apache.catalina.realm.LockOutRealm"> <Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase"/> </Realm> <Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true"> <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" prefix="localhost_access_log" suffix=".txt" pattern="%h %l %u %t &quot;%r&quot; %s %b" /> </Host> --------------------------------------配置虚拟主机------------------------------------------------------------ <Host name="diy.etiantian.ora" appBase="/code/diy" #域名、代码目录,默认是webapps/ROOT,比nginx多这一级 unpackWARs="true" autoDeploy="true"> #自动解压WAR包,类似于zip,但不需要手动解压 <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" #日志 prefix="diy_access_log" suffix=".txt" #日志名称、后缀 pattern="%h %l %u %t &quot;%r&quot; %s %b" /> #自定义日志格式 --------------------------------------配置虚拟主机----------------------------------------------------------- </Host> </Engine> </Service> </Server> # </Connector>连接器包含着 <Engine引擎,引擎里面包含着<Host,可以包含多个<Host

image-20250422164810973

bash
#1.添加域名 <Host name="diy.etiantian.ora" appBase="/code/diy" unpackWARs="true" autoDeploy="true"> <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" prefix="diy_access_log" suffix=".txt" pattern="%h %l %u %t &quot;%r&quot; %s %b" /> </Host> [root@web01 /soft/tomcat/conf]#mkdir /code/diy [root@web01 /soft/tomcat/conf]#echo tomcat ... > /code/diy/index.html [root@web01 /soft/tomcat/conf]#systemctl restart tomcat #2.如果配置文件有问题起不来端口,比如目录没创建,代码错误 [root@web01 /soft/tomcat/conf]#netstat -tnulp tcp6 0 0 127.0.0.1:8005 :::* LISTEN 3914/java tcp6 0 0 :::8080 :::* LISTEN 3914/java # 日志文件 [root@web01 /soft/tomcat/conf]#cat /soft/tomcat/logs/catalina.out #3.解析host 浏览器访问diy.etiantian.org:8080

image-20250422171730770

bash
#4.访问测试失败,因为没有创建ROOT目录 #5.创建ROOT目录 [root@web01 /soft/tomcat/conf]#mkdir /code/diy/ROOT -p #6.将文件移动到ROOT下 [root@web01 /code/diy]#mv index.html ROOT/ #7.刷新测试

image-20250422171952275

5、Tomcat Http请求过程

image-20250422172525370

bash
首先http或者https请求负载均衡,然后到server层,这里面有connector连接器,通过这个连接器响应我们客户端的连接,再通过service再转发 给引擎,引擎里面有多个host,看外部是哪个域名访问,通过引擎给用户响应host 简述Tomcat一个请求的完整过程? Tomcat 处理一个请求的完整过程如下: 客户端请求:客户端(如浏览器)通过 HTTP 协议向 Tomcat 发送请求。 接收请求:Tomcat 的连接器(Connector)监听特定端口(如 8080),接收客户端的请求。 解析请求:连接器将请求封装成 HttpServletRequest 对象,并交给合适的引擎(Engine)。 匹配虚拟主机(Host):引擎(Engine)根据请求的主机名匹配到相应的 Host。 匹配上下文(Context):Host 进一步根据 URL 的路径部分将请求分发给相应的 Context(即对应的 web 应用)。 匹配过滤器(Filter):Context 根据请求路径匹配一系列的 Filter,按照顺序依次调用这些过滤器。 调用Servlet:过滤器处理完成后,将请求交给具体的 Servlet,由 Servlet 执行业务逻辑。 生成响应:Servlet 处理请求后,将响应数据写入 HttpServletResponse 对象中。 过滤器后处理:响应返回给过滤器链,过滤器可对响应进行后处理。 返回响应:Tomcat 将 HttpServletResponse 返回给连接器,由连接器通过网络将响应发送回客户端。 #tomcat中Context的作用: <Host name="diy.etiantian.com" appBase="/code/diy" unpackWARs="true" autoDeploy="true"> <!--访问diy.etiantian.com:8080/tt这个uri,获取/code/tt中页面资源,不存在该目录会报错 无法启动Tomcat 需要提前创建--> <Context docBase="/code/tt" path="/tt" reloadable="true" /> <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" prefix="diy_access_log" suffix=".log" pattern="%h %l %u %t &quot;%r&quot; %s %b" /> </Host> #context作用:----> 类似于nginx中的alias,如果有人访问diy.etiantian.com:8080/tt,那么直接去/code/tt去获取资源,用context #是不需要ROOT目录的 #Context测试 #1.增加配置文件 [root@web01 /soft/tomcat/conf]#vim server.xml <Host name="diy.etiantian.org" appBase="/code/diy" unpackWARs="true" autoDeploy="true"> <Context docBase="/code/tt" path="/tt" reloadable="true" /> #加了这行启动失败...... <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" prefix="diy_access_log" suffix=".txt" pattern="%h %l %u %t &quot;%r&quot; %s %b" /> </Host> #2.重启,启动失败 [root@web01 /soft/tomcat/conf]#systemctl restart tomcat [root@web01 /soft/tomcat/conf]#netstat -tnulp Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1081/sshd: /usr/sbi tcp 0 0 127.0.0.1:9000 0.0.0.0:* LISTEN 1078/php-fpm: maste tcp6 0 0 :::22 :::* LISTEN 1081/sshd: /usr/sbi #3.查看报错日志,因为文件不存在导致无法读取 [root@web01 /soft/tomcat/conf]#cat ../logs/catalina.out Caused by: java.lang.IllegalArgumentException: The main resource set specified [/code/tt] is not a directory or war file, or is not readable (it does not exist or permissions to access it are missing) #4.根据报错创建目录并写入测试数据 [root@web01 /soft/tomcat/conf]# mkdir /code/tt [root@web01 /soft/tomcat/conf]#echo "tt...." > /code/tt/index.html [root@web01 /soft/tomcat/conf]#cat /code/tt/index.html tt.... #5.启动服务 [root@web01 /soft/tomcat/conf]#systemctl restart tomcat [root@web01 /soft/tomcat/conf]#netstat -tnulp Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1081/sshd: /usr/sbi tcp 0 0 127.0.0.1:9000 0.0.0.0:* LISTEN 1078/php-fpm: maste tcp6 0 0 :::22 :::* LISTEN 1081/sshd: /usr/sbi tcp6 0 0 127.0.0.1:8005 :::* LISTEN 4818/java tcp6 0 0 :::8080 :::* LISTEN 4818/java #6.再次请求测试,diy.etiantian.org:8080/tt,默认访问index.html,如果是1.log那么路径是diy.etiantian.org:8080/tt/1.log

image-20250422191404297

6、Tomcat管理页面
bash
Tomcat自带的管理页面: 管理功能 监控功能 1.所有的管理页面,都将权限赋予给了角色,而角色的名称是固定的:manager-gui admin-gui 2.需要添加一个用户,将用户捆绑至对应的角色,这样用户就可以访问到对应的页面 #编辑tomcat-users.xml文件将tomcat这个用户成为managergui,admin-gui这两个角色,就可以访问页面 [root@web01 /soft/tomcat/conf]#tail -5 tomcat-users.xml --> <role rolename="manager-gui"/> <role rolename="admin-gui"/> <user username="tomcat" password="123456" roles="manager-gui,admin-gui"/> </tomcat-users> 3.由于项目默认允许127.0.0.1访问,所以配置好了角色和用户也无法正常访问: #编辑配置文件 [root@web01 /soft/tomcat/conf]#vim /soft/tomcat/webapps/host-manager/META-INF/context.xml 将 allow="127\.\d+\.\d+\.\d+|::1|0:0:0:0:0:0:0:1" /> 改为 allow="\d+\.\d+\.\d+\.\d+|::1|0:0:0:0:0:0:0:1" /> [root@web01 /soft/tomcat/conf]#vim /soft/tomcat/webapps/manager/META-INF/context.xml 将 allow="127\.\d+\.\d+\.\d+|::1|0:0:0:0:0:0:0:1" /> 改为 allow="\d+\.\d+\.\d+\.\d+|::1|0:0:0:0:0:0:0:1" /> 4. 重启tomcat并访问 [root@web01 /soft/tomcat/conf]#systemctl restart tomcat [root@web01 /soft/tomcat/conf]#netstat -tnulp Active Internet connections (only servers) #浏览器访问测试

image-20250422193114275

bash
#编辑context路径

image-20250422193914875

image-20250422193955401

bash
#添加模拟主机

image-20250422194202666

bash
本地host解析 #浏览器访问测试

image-20250422194317921

7、Tomcat部署zrlog项目
bash
#1.编辑配置文件 [root@web01]#vim /soft/tomcat/conf/server.xml <Host name="zrlog.oldboy.com" appBase="/zrlog" unpackWARs="true" autoDeploy="true"> <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" prefix="zrlog_access_log" suffix=".log" pattern="%h %l %u %t &quot;%r&quot; %s %b" /> </Host> #2.重启 [root@web01 /zrlog]#systemctl restart tomcat [root@web01 /zrlog]#netstat -tnulp Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1081/sshd: /usr/sbi tcp 0 0 127.0.0.1:9000 0.0.0.0:* LISTEN 1078/php-fpm: maste tcp6 0 0 :::22 :::* LISTEN 1081/sshd: /usr/sbi tcp6 0 0 127.0.0.1:8005 :::* LISTEN 5377/java tcp6 0 0 :::8080 :::* LISTEN 5377/java #3.创建目录 [root@web01 /soft/tomcat/conf]#mkdir /zrlog #4.上传war包,自动解压 [root@web01 /zrlog]#ll total 15360 drwxr-x--- 9 root root 126 Apr 22 19:53 zrlog-2.2.1-efbe9f9-release -rw-r--r-- 1 root root 11243048 Apr 21 17:03 zrlog-2.2.1-efbe9f9-release.war #5.但是目录不对,修改名称为ROOT,自动解压,注意要大写 [root@web01 /zrlog]#mv zrlog-2.2.1-efbe9f9-release.war ROOT.war [root@web01 /zrlog]#ll total 15360 drwxr-x--- 9 root root 126 Apr 22 19:55 ROOT -rw-r--r-- 1 root root 11243048 Apr 21 17:03 ROOT.war #6.WINDOWS的hosts解析 10.0.0.7 zrlog.oldboy.com #浏览器访问:zrlog.oldboy.com:8080

image-20250422200002418

bash
#7.数据库创建信息: MariaDB [(none)]> create database zrlog; Query OK, 1 row affected (0.022 sec) MariaDB [(none)]> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | wordpress | | zrlog | +--------------------+ 5 rows in set (0.296 sec) #8.返回浏览器继续操作

image-20250422200338916

3、Tomcat集群实战

image-20250422200944603

bash
1.在web02搭建Tomcat,把数据代码同步过去,默认连接数据库。 2.在web服务器前面加上负载均衡,转发两个接口,并且都以80端口去访问。 3.用户在访问web的时候实际是访问nginx的80端口,但是负载均衡是代理着用户去访问8080端口,与web分别建立连接。 4.找到两台web服务器图片存放的位置,部署nfs挂载到web服务器存放图片的路径
1、安装Tomcat
bash
[root@oldboy ~]#yum install java -y # 默认安装的版本高 先不使用 #先通过上传rpm包的方式安装jdk [root@oldboy ~]#rz -E [root@oldboy ~]#ll total 180016 -rw-r--r-- 1 root root 13867286 Apr 2 02:15 apache-tomcat-10.1.40.tar.gz #如果已经安装了其他的JDK需要先卸载再安装新版本 [root@oldboy ~]#rpm -qa|grep java-11|xargs yum -y remove [root@oldboy ~]#rpm -ivh jdk-8u181-linux-x64.rpm
2、拷贝代码和文件 ,web1执行
bash
[root@web01 /zrlog]#scp -rp /soft 10.0.0.8:/ [root@web01 /zrlog]#scp -rp /zrlog 10.0.0.8:/ [root@web01 /zrlog]#scp /usr/lib/systemd/system/tomcat.service 172.16.1.8:/usr/lib/systemd/system/tomcat.service
3、web02操作如下
bash
#启动tomcat [root@web02 /soft/tomcat]#systemctl start tomcat [root@web02 /soft/tomcat]#systemctl enable tomcat host解析 #浏览器访问测试

image-20250422203954258

bash
#上传图片测试

image-20250422204323303

bash
host解析成10.0.0.7访问图片失败,因为上面的图片存到了8的本地磁盘里

image-20250422204446969

4、挂载到nfs网络文件系统
bash
#编辑配置文件 [root@nfs ~]#cat /etc/exports /data/rw 172.16.1.0/24(rw,sync,all_squash,anonuid=200,anongid=200) /data/ro 172.16.1.0/24(ro,sync,all_squash,anonuid=200,anongid=200) /data/zrlog 172.16.1.0/24(ro,sync,all_squash,anonuid=200,anongid=200) #创建路径 [root@nfs ~]#mkdir /data/zrlog #拷贝图片 [root@web02 /soft/tomcat]#scp -r /zrlog/ROOT/attached/image/ 10.0.0.31:/data/zrlog #授权 [root@nfs /data]#chown -R www.www zrlog/ #重启生效 [root@nfs /data]#systemctl restart nfs #web01挂载 [root@web01 /soft/tomcat]#mount -t nfs 172.16.1.31:/data/zrlog /zrlog/ROOT/attached/ [root@web01 /soft/tomcat]#df -h 172.16.1.31:/data/zrlog 47G 3.8G 44G 9% /zrlog/ROOT/attached #web02挂载 [root@web02 /soft/tomcat]#mount -t nfs 172.16.1.31:/data/zrlog /zrlog/ROOT/attached/ [root@web02 /soft/tomcat]#df -h 172.16.1.31:/data/zrlog 47G 3.8G 44G 9% /zrlog/ROOT/attached #现在7也可以访问图片

image-20250422205628395

5、配置负载均衡,Tomcat+Nginx+HTTPS
bash
#修改配置文件 [root@lb01 /etc/nginx/conf.d]#cat zrlog.conf upstream zrlog { server 172.16.1.7:8080; server 172.16.1.8:8080; } server { listen 80; server_name zrlog.oldboy.com; location / { proxy_pass http://zrlog; include proxy_params; } } # 加证书部署方式 upstream zrlog { # 定义后端服务器组(负载均衡池) server 172.16.1.7:8080; # 后端服务器1 server 172.16.1.8:8080; # 后端服务器2 } server { listen 443 ssl; # 监听HTTPS端口(443) server_name zrlog.oldboy.com; # 域名绑定 ssl_certificate ssl_key/server.crt; # SSL证书路径 ssl_certificate_key ssl_key/server.key; # SSL私钥路径 location / { # 处理所有请求 proxy_pass http://zrlog; # 将请求代理到上游服务器组 include proxy_params; # 包含代理通用参数配置 } } server { listen 80; # 监听HTTP端口(80) server_name zrlog.oldboy.com; # 域名绑定 return 302 https://$server_name$request_uri; # 强制跳转到HTTPS } #1、用户在浏览器输入 http://zrlog.oldboy.com 或直接访问该域名(默认匹配80端口) #2、Nginx返回302重定向,浏览器自动跳转到 https://zrlog.oldboy.com #3、浏览器与Nginx完成TLS握手,验证证书有效性(ssl_certificate 和 ssl_certificate_key)。 #4、监听端口:443,匹配server_name zrlog.oldboy.com 的server块 #5、反向代理到upstream组,加载通用代理参数 #6、Nginx根据默认轮询策略,选择 172.16.1.7:8080 或 172.16.1.8:8080 中的一个后端服务器。 #7、选中的后端服务器(如 172.16.1.7:8080)接收请求,处理业务逻辑 建立加密通道,后续数据传输均加密 [root@lb01 /etc/nginx/conf.d]#nginx -t nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful [root@lb01 /etc/nginx/conf.d]#systemctl restart nginx #浏览器访问测试:zrlog.oldboy.com,配置负载均衡不要加8080

image-20250422210355734

4、Tomcat+Nginx+Redis会话保持

bash
多种会话方式:1.ip_hash 2.mysql 3.redis
1、web01配置
bash
#1.修改配置文件 [root@web01 ~]#vim /soft/tomcat/conf/server.xml <Host name="session.oldboy.com" appBase="/session" unpackWARs="true" autoDeploy="true"> <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" prefix="session_access_log" suffix=".log" pattern="%h %l %u %t &quot;%r&quot; %s %b" /> </Host> #2.创建数据 [root@web01 /soft/tomcat/conf]#mkdir -p /session/ROOT [root@web01 /session/ROOT]#cat index.jsp <body> <% //HttpSession session = request.getSession(true); System.out.println(session.getCreationTime()); out.println("<br> web01 SESSION ID:" + session.getId() + "<br>"); out.println("Session created time is :" + session.getCreationTime() + "<br>"); %> </body> #3.重启 [root@web01 /session/ROOT]#systemctl restart tomcat [root@web01 /session/ROOT]#netstat -tnulp Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1081/sshd: /usr/sbi tcp 0 0 127.0.0.1:9000 0.0.0.0:* LISTEN 1078/php-fpm: maste tcp6 0 0 :::22 :::* LISTEN 1081/sshd: /usr/sbi tcp6 0 0 :::8080 :::* LISTEN 6376/java #4.解析域名 浏览器测试抓取

image-20250422213842004

2、web02配置
bash
#1.修改配置文件 [root@web02 /soft/tomcat]#vim conf/server.xml <Host name="session.oldboy.com" appBase="/session" unpackWARs="true" autoDeploy="true"> <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" prefix="session_access_log" suffix=".log" pattern="%h %l %u %t &quot;%r&quot; %s %b" /> </Host> #2.创建数据 [root@web02 /soft/tomcat]#mkdir /session/ROOT -p [root@web02 /soft/tomcat]#vim /session/ROOT/index.jsp [root@web02 /soft/tomcat]#cat /session/ROOT/index.jsp <body> <% //HttpSession session = request.getSession(true); System.out.println(session.getCreationTime()); out.println("<br> web02 SESSION ID:" + session.getId() + "<br>"); out.println("Session created time is :" + session.getCreationTime() + "<br>"); %> </body> #3.重启 [root@web02 /soft/tomcat]#systemctl restart tomcat [root@web02 /soft/tomcat]#netstat -tnulp

image-20250422214817280

bash
#接入负载均衡 #1.编辑配置文件 [root@lb01 /etc/nginx/conf.d]#cat session.conf upstream session { server 172.16.1.7:8080; server 172.16.1.8:8080; } server { listen 80; server_name session.oldboy.com; location / { proxy_pass http://session; include proxy_params; } } #2.重启 [root@lb01 /etc/nginx/conf.d]#nginx -t nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful [root@lb01 /etc/nginx/conf.d]#systemctl restart nginx #浏览器访问测试,无会话保持:

image-20250422220655016

image-20250422220706708

bash
#接入TomcatClusterRedisSessionManager #1.上传 [root@web01 ~]#ll -rw-r--r-- 1 root root 921429 Apr 21 17:01 tomcat-cluster-redis-session-manager.zip #2.解压zip包 [root@web01 ~]#unzip tomcat-cluster-redis-session-manager.zip #3.拷贝jars到tomcat的/lib目录中 [root@web01 ~]#cp tomcat-cluster-redis-session-manager/lib/* /soft/tomcat/lib/ #4.拷贝conf下的redis.properties文件,到tomcat的conf文件 [root@web01 ~]#cp tomcat-cluster-redis-session-manager/conf/redis-data-cache.properties /soft/tomcat/conf/ #5.将配置文件中连接redis地址修改为如下地址即可 [root@web01 ~]#vim /soft/tomcat/conf/redis-data-cache.properties redis.hosts=172.16.1.51:6379 redis.password=123 #6.添加如下两行至tomcat/conf/context.xml (添加在</Context> 上一行 ) [root@web01 ~]# vim /soft/tomcat/conf/context.xml <Valve className="tomcat.request.session.redis.SessionHandlerValve" /> <Manager className="tomcat.request.session.redis.SessionManager" /> </Context> [root@web01 ~]#rsync -avz /soft/tomcat/ --delete 10.0.0.8:/soft/tomcat #修改完成后重启Tomcat

这里出现个错误Valve打成了value导致400错误

bash
#redis数据库测试 [root@db01 ~]#redis-cli 127.0.0.1:6379> keys * (error) NOAUTH Authentication required. 127.0.0.1:6379> auth 123 OK 127.0.0.1:6379> keys * (empty array) 127.0.0.1:6379> 127.0.0.1:6379> keys * 1) "5BCBABBC154E7CAFF45D246281FB0BAC" 2) "PHPREDIS_SESSION:18um6d4t97odef790b26d6srtm" #浏览器测试,一个seeion值

image-20250423082430735

image-20250423082526117

5、部署最新版zrlog

不需要额外部署tomcatweb服务

bash
#用199服务器来实现 #1.安装数据库 1.安装数据库服务 [root@db01 ~]# yum -y install mariadb-server 2.启动服务 [root@db01 ~]# systemctl start mariadb-server 3.登录 [root@db01 ~]#mysql -uroot -plzy123.com Welcome to the MariaDB monitor. Commands end with ; or \g. Your MariaDB connection id is 8 Server version: 10.3.39-MariaDB MariaDB Server Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. 4.创建数据库 MariaDB [(none)]> create database zrlog_test; Query OK, 1 row affected (0.001 sec) MariaDB [(none)]> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | wordpress | | zrlog | | zrlog_test | +--------------------+ 6 rows in set (0.043 sec)
bash
#2.下载JDK [root@oldboy ~]# wget https://download.oracle.com/java/21/latest/jdk-21_linux-x64_bin.rpm #3.下载源代码 [root@web02 /opt]#wget https://dl.zrlog.com/release/zrlog.zip 解压代码到/opt/zrlog下 [root@oldboy ~]#cd /opt/zrlog/ [root@web02 /opt/zrlog]#ll total 32 drwxr-xr-x 2 root root 53 Apr 10 08:59 bin drwxr-xr-x 2 root root 59 Mar 24 00:51 doc drwxr-xr-x 2 root root 4096 Mar 24 00:51 lib -rw-r--r-- 1 root root 11358 Mar 24 00:51 LICENSE -rw-r--r-- 1 root root 3113 Mar 24 00:51 README.en-us.md -rw-r--r-- 1 root root 4200 Mar 24 00:51 README.md -rw-r--r-- 1 root root 3335 Mar 24 00:51 zrlog-starter.jar #4.启动一定要看jar包的路径 [root@web02 /opt/zrlog]#ll total 32 drwxr-xr-x 2 root root 70 Apr 23 09:16 bin drwxr-xr-x 2 root root 59 Mar 24 00:51 doc drwxr-xr-x 2 root root 4096 Mar 24 00:51 lib -rw-r--r-- 1 root root 11358 Mar 24 00:51 LICENSE -rw-r--r-- 1 root root 3113 Mar 24 00:51 README.en-us.md -rw-r--r-- 1 root root 4200 Mar 24 00:51 README.md -rw-r--r-- 1 root root 3335 Mar 24 00:51 zrlog-starter.jar [root@web02 /opt/zrlog]##sh bin/start.sh # 启动方法1 或者使用 [root@web02 /opt/zrlog]#nohup java -Xmx48m -Dfile.encoding=UTF-8 -jar zrlog-starter.jar & # 启动方法2 [root@oldboy zrlog]# netstat -tnulp Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1089/sshd: /usr/sbi tcp6 0 0 :::8080 :::* LISTEN 1892/java tcp6 0 0 :::22 :::* LISTEN 1089/sshd: /usr/sbi udp 0 0 127.0.0.1:323 0.0.0.0:* 768/chronyd udp6 0 0 ::1:323 :::* 768/chronyd #浏览器访问测试:10.0.0.199:8080

image-20250423165803365

14、阿里云平台

1、云基本介绍

bash
#1.什么是云 云是一种”按需付费的模式“,这种模式提供了(计算、存储、网络等资源),这些资源能够被快速提供。 1.包年包月; 2.按需付费; SIM流量一样; 用多少给多少钱; 云只是一种思想,并不是某种具体的技术; 云需要依托于 虚拟化技术才可以实现; #2.云的分类 公有云:阿里云、腾讯云、亚马逊云。只有使用权,按需付费(技术层面:数据不安全) 私有云:自建机房,自己搭建,所有自行管理,将真实的物理服务器逻辑捆绑成一个虚拟资源池,用户可以根据虚拟资源池按需使用,资源是固定。 私有云; vmware,ESXI5.4(集成了操作系统和虚拟化软件),在公司, 使用多台性能较高的物理主机, 逻辑组成一个庞大资源池;根据业务需要,进行按需创建,使用对应的资源;不对外开放,仅对本公司开放; 好处: 数据安全, 劣势:1.自己维护,自己管理,成本高; 2.无法快速的扩展节点; # 那私有云跟传统机房有啥区别啊,都是自己弄物理设备 私有云: 多台机器逻辑捆绑在一起;组成的资源池; --> 系统平台; 传统机房: 物理机器托管在机房; 在物理机上运行资源; IDC机房: 城市的机房位置。 混合云(主要业务放私有云、当有临时需求的时候使用公有云,使用结束后释放) 按需使用、按需付费、保证业务稳定的同时,也能节省一定的成本。 两类场景: 1.公司正常的业务运行,资源不够, 借助公有云来快速,高效扩展业务; 2.重要的业务,核心的业务,在私托有云平台、官网、OA、等等不是很敏感的信息,托管在公有云; #3为什么要用云 1)海量资源池灵活调配 [像大海一样|无尽头] 2)无处不在的网络访问 [随时随地能访问云资源] 3)随需应变的自助服务 [包年包月-电话卡|按需付费-流量包] 4)保证服务的高可用性 5)能实现快速弹性伸缩 [扩展|伸缩|自愈] #4云有哪些厂商 1) 阿里云 | 腾讯云 | Ucloud | 青云 | [ AWS ] 2) 华为云 | 京东云 | 滴滴云 | #5云上面的产品名词 1)物理服务器 --> 阿里云 2)服务器 --> ECS、快照、镜像,克隆; 3)负载均衡 --> SLB 4) 数据库 --> RDS 5) 存储服务NFS --> NAS、OSS 5) 防火墙 --> 安全组iptables,firewalld、高防IP、WAF 6)远程访问 --> VPN | JumpServer + OpenVPN 7) 消息队列 --> MQ 8) 网络 --> 弹性网卡 NAT

2、ECS产品使用

bash
云服务器(Elastic Compute Service,简称 ECS),是一种简单高效、可弹性伸缩的计算服务。 比如: 当服务器运行负荷不够时,通常的做法是增加服务器,那么增加服务器的流程和步骤如下: 1.购买硬件,拆开服务器、安装硬件设备。 2.部署系统、部署应用、接入集群。 但如果使用云主机,可以实现自动化感知、自动化扩展集群。 #1.ECS地域与可用区说明 https://help.aliyun.com/document_detail/188196.html?spm=a2c4g.11186623.6.556.3e5e53c0ZQ8lpP 地域: 指的是一个城市,比如北京; 可用区: 指的是城市下面的区,北京可用区A和北京可用区B等; 1.相同地域,不同可用区之间的内网是互通的; 2.不同地域,相同可用区,内网不互通; 但是我们可以通过技术手段来实现互联互通; 3.每一个地域,都有一个VPC路由器; 每一个可用区都需要有一个交换机; 所有的交换机都是连接的同一个VPC路由器; #2.ECS云主机配置选型 web节点: 4c x 16Gb DB节点: 4c x 64Gb 4c x 32Gb 12c x 128GB 建议使用:SSD 性能会受到磁盘的限制; 数据迁移 将物理机的服务 --> 云主机 故障案例: 4c x 64GB 物理机 磁盘 SATA = 400Mbps 4c x 64GB 云主机 磁盘 高效盘 100Mbps | SSD 固态盘 = 400Mbps dd | hdparm -t /dev/vda1 #3.ECS中的网络简要说明 EIP: 弹性公网IP SLB: 负载均衡 NAT: 网关设备 VPN: 远程访问服务 VPC: 软件路由器 ( 可以创建交换机, 可以在每个可用区都创建 ) VPC文档:https://help.aliyun.com/document_detail/54095.html?spm=5176.11182174.content.1.4411488295LcKx#title-oil-ncn-266
1、产品架构

image-20250423170720543

bash
# ECS云服务逻辑架构 通过账号登录,从管理员入口进入-->通过地域/可用区购买自己的ECS-->购买成功后通过Workbench/VNC访问服务器,也可以通过远程命令去控制它,也可以通过SSH登录Linux-->费用可以包年包月等等 可以对ECS做数据的存储-->可以做数据备份,也可以把/做一个快照(快照可以回滚云盘)---基于快照创建镜像---基于快照启动实例 可以对ERC做一个弹性网卡,可以绑定公网ip,从任意一个地方可以访问就绑定公网
2、产品购买
bash
1.登录--产品--云服务器ECS--立即购买--自定义购买,选择配置
3、ECS挂载磁盘
bash
#云服务器: 进入实例-->点击块存储-->创建云盘

image-20250423175244596

bash
选好自己的地域,从哪里买ECS选哪里,最后点确认下单

image-20250423175521120

image-20250423175831668

!

bash
创建成功后,点击前往示例云盘列表,可以看到多出来的数据盘

image-20250423175919517

bash
#1.查看磁盘信息,可以看到/dev/vdb [root@aliyun ~]#fdisk -l Disk /dev/vda: 42.9 GB, 42949672960 bytes, 83886080 sectors Units = sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disk label type: dos Disk identifier: 0x000edc45 Device Boot Start End Blocks Id System /dev/vda1 * 2048 83886046 41941999+ 83 Linux Disk /dev/vdb: 21.5 GB, 21474836480 bytes, 41943040 sectors Units = sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes #2.格式化: [root@web01 ~]# mkfs.xfs /dev/vdb meta-data=/dev/vdb isize=512 agcount=4, agsize=3276800 blks = sectsz=512 attr=2, projid32bit=1 = crc=1 finobt=0, sparse=0 data = bsize=4096 blocks=13107200, imaxpct=25 = sunit=0 swidth=0 blks naming =version 2 bsize=4096 ascii-ci=0 ftype=1 log =internal log bsize=4096 blocks=6400, version=2 = sectsz=512 sunit=0 blks, lazy-count=1 realtime =none extsz=4096 blocks=0, rtextents=0 #3.挂载 [root@web01 ~]# mount /dev/vdb /mnt [root@web01 ~]# df -h /dev/vdb 20G 33M 50G 1% /mnt #4.创建测试数据 [root@aliyun ~]#cd /mnt [root@aliyun /mnt]#touch {1..10}.log [root@aliyun /mnt]#ll total 0 -rw-r--r-- 1 root root 0 Apr 23 18:02 10.log -rw-r--r-- 1 root root 0 Apr 23 18:02 1.log -rw-r--r-- 1 root root 0 Apr 23 18:02 2.log -rw-r--r-- 1 root root 0 Apr 23 18:02 3.log -rw-r--r-- 1 root root 0 Apr 23 18:02 4.log -rw-r--r-- 1 root root 0 Apr 23 18:02 5.log -rw-r--r-- 1 root root 0 Apr 23 18:02 6.log -rw-r--r-- 1 root root 0 Apr 23 18:02 7.log -rw-r--r-- 1 root root 0 Apr 23 18:02 8.log -rw-r--r-- 1 root root 0 Apr 23 18:02 9.log 在线扩容: 云盘--> 选择50G的数据盘 在线扩容到100G #5.回到块存储,点击三个点,选择扩容

image-20250423180433475

image-20250423180644302

image-20250423180658124

bash
#6.执行命令扩容文件系统 [root@web01 ~]# xfs_growfs /mnt meta-data=/dev/vdb isize=512 agcount=4, agsize=1310720 blks = sectsz=512 attr=2, projid32bit=1 = crc=1 finobt=0 spinodes=0 data = bsize=4096 blocks=5242880, imaxpct=25 = sunit=0 swidth=0 blks naming =version 2 bsize=4096 ascii-ci=0 ftype=1 log =internal bsize=4096 blocks=2560, version=2 = sectsz=512 sunit=0 blks, lazy-count=1 realtime =none extsz=4096 blocks=0, rtextents=0 data blocks changed from 5242880 to 15728640 #7.查看已经扩容到了60G [root@aliyun /mnt]#df -h /dev/vdb 60G 33M 60G 1% /mnt #8.查看文件还存在 [root@aliyun /mnt]#ll total 0 -rw-r--r-- 1 root root 0 Apr 23 18:02 10.log -rw-r--r-- 1 root root 0 Apr 23 18:02 1.log -rw-r--r-- 1 root root 0 Apr 23 18:02 2.log -rw-r--r-- 1 root root 0 Apr 23 18:02 3.log -rw-r--r-- 1 root root 0 Apr 23 18:02 4.log -rw-r--r-- 1 root root 0 Apr 23 18:02 5.log -rw-r--r-- 1 root root 0 Apr 23 18:02 6.log -rw-r--r-- 1 root root 0 Apr 23 18:02 7.log -rw-r--r-- 1 root root 0 Apr 23 18:02 8.log -rw-r--r-- 1 root root 0 Apr 23 18:02 9.log # 如果已经格式化后再执行会报错 [root@git ~]#mkfs.xfs /dev/vdb mkfs.xfs: /dev/vdb appears to contain an existing filesystem (xfs). mkfs.xfs: Use the -f option to force overwrite. # 通过blkid命令查看,如果已格式化,输出会显示文件系统类型和 UUID [root@git ~]#blkid /dev/vdb /dev/vdb: UUID="b52efd9a-09a1-41aa-96c8-bc6240d57bab" TYPE="xfs" #卸载云盘 [root@aliyun /]#umount /mnt [root@aliyun /]#df -h Filesystem Size Used Avail Use% Mounted on devtmpfs 868M 0 868M 0% /dev tmpfs 879M 0 879M 0% /dev/shm tmpfs 879M 492K 878M 1% /run tmpfs 879M 0 879M 0% /sys/fs/cgroup /dev/vda1 40G 2.7G 35G 8% / tmpfs 176M 0 176M 0% /run/user/0 #点击卸载

image-20250423181133764

bash
#点击释放,释放完成

image-20250423181212459

4、ECS搭建kodcloud
bash
#1.安装Nginx [root@web01 /]#yum -y install nginx #2.配置Nginx [root@web01 /etc/nginx/conf.d]#cat kod.conf server { listen 80; server_name kod.weixinag.info; location / { root /code; index index.php index.html; } location ~ \.php$ { root /code; fastcgi_pass 127.0.0.1:9000; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } } #创建目录并修改权限 [root@web01 ~]#mkdir /code [root@web01 /code]#chown -R nginx.nginx /code #3.启动Nginx [root@web01 /etc/nginx/conf.d]#nginx -t nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful [root@web01 /etc/nginx/conf.d]#systemctl restart nginx [root@web01 /etc/nginx/conf.d]#systemctl enable nginx #4.PHP-FPM 上传安装 [root@web01 ~]#tar xf php71.tar.gz #因为安装包互相有依赖,所以全包安装 [root@web01 ~]#yum -y localinstall *.rpm #5.修改配置文件并启动php [root@web01 /code]#cat -n /etc/php-fpm.d/www.conf 8 user = nginx 10 group = nginx [root@web01 ~]#systemctl start php-fpm.service [root@web01 ~]#systemctl enable php-fpm.service Created symlink from /etc/systemd/system/multi-user.target.wants/php-fpm.service to /usr/lib/systemd/system/php-fpm.service. [root@web01 ~]#netstat -tnulp Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1028/sshd tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN 998/master tcp 0 0 127.0.0.1:9000 0.0.0.0:* LISTEN 1466/php-fpm: maste #6.下载可道云 [root@web01 /code]#wget https://static.kodcloud.com/update/download/kodbox.1.30.zip #7.解压 [root@web01 /code]#unzip kodbox.1.30.zip #浏览器登录,要在安全组--管理规则中放行80端口,要不连接失败

image-20250423194525048

image-20250423194525048

image-20250423194101362

5、ECS快照与镜像
bash
#1.云服务器ECS--实例--选择其中一个实例--块存储--创建快照,基于快照可以回滚文件 #测试,删除root下的所有文件,通过回滚云盘可以把文件回复,基于公司需求可以创建自动快照策略,分周跟小时 ECS快照 3.1)快照基本介绍 3.2)快照使用场景 3.3)快照使用方式 手动创建快照 自动创建快照 Document:https://help.aliyun.com/document_detail/25391.html?spm=a2c4g.11186623.6.823.73175b2cIbssVu 测试: 将web01的代码删除 通过页面无法访问 通过快照恢复再次访问

image-20250423195125829

bash
#2.创建完成后点击快照可以看到,等进度完成100%,点击创建自定义镜像,基于快照创建镜像

image-20250423195340742

image

image

bash
#3.点击左侧的镜像可以看到创建的镜像,基于镜像可以启动实例

image-20250423195605721

6、通过ECS镜像启动新的实例
bash
镜像概述:https://help.aliyun.com/zh/ecs/user-guide/image-overview?spm=a2c4g.11186623.0.i0 其他正常选,镜像选择自己保存的

image-20250423200648038

image-20250423203145351

7、配置负载均衡
bash
购买负载均衡服务器

image-20250423205350066

bash
把web服务器的弹性ip解绑,绑定到负载均衡服务器,解绑后xshell连不上了,只能通过页面去连接

image-20250423205535297

bash
回到负载均衡,绑定EIP

image-20250423205706798

image-20250423205942080

image

image-20250423210245548

image-20250423210315013

bash
这个地方相当于upstream{ server xxxxxx 80; server xxxxxx 80; }

image-20250423210341128

image-20250423210519637

image-20250423210612915

bash
可以看到负载均衡已经转发到后端两台了

image-20250423210716045

bash
#输入负载均衡的公网ip,浏览器测试可以正常访问

image-20250423210932406

bash
#登录页面,查看日志,没问题

image-20250423211129553

image-20250423211229658

image-20250423211229658

bash
面试:阿里云怎么配的负载均衡 先购买传统型负载均衡服务器,然后去配置,选择http或者https,选择端口。然后下一步选择后面两台的web,默认使用轮询的方式
部署完释放资源

3、快速恢复kod业务

1、基于镜像恢复实例

image-20250424125852814

image-20250424130049925

image-20250424130238238

2、部署负载均衡

image-20250424130533714

image-20250424130704112

bash
通过公网ip测试访问没问题

image-20250424130752917

4、云解析DNS

bash
#1、DNS智能解析 1.传统DNS解析,不判断访问者来源,会随机选择其中一个IP地址返回给访问者。而智能DNS解析,会判断访问者的来源,为不同的访问者智能返回不同的IP地址,使访问者在访问网站时获取指定的IP地址,能够减少解析时延,并提升网站访问速度。 传统DNS解析示例 例如域名www.cloud-example.com,有三台服务器,分别是联通IP,移动IP和电信IP,DNS解析配置如下: 将域名指向联通IP地址 (192.x.x.1) 将域名指向移动IP地址 (192.x.x.2) 将域名指向电信IP地址 (192.x.x.3) 实现的解析效果: 传统DNS解析不判断访问者的来源,会将192.x.x.1、192.x.x.2、192.x.x.3三个地址全部返回给访问者的LocalDNS,由访问者的LocalDNS通过随机或者优选的方式将其中一个IP地址返回给访问者,传统DNS解析有可能会造成访问者跨网访问。 2.智能DNS解析示例 例如域名www.cloud-example.com被解析到3个IP地址,分别是联通IP,移动IP和电信IP,DNS解析配置如下: 解析请求来源配置 默认 指向联通IP地址 (192.x.x.1) 解析请求来源配置 中国移动 指向移动IP地址 (192.x.x.2) 解析请求来源配置 中国电信 指向电信IP地址 (192.x.x.3) 实现的解析效果:云解析会判断访问者的来源: 为来源于中国移动运营商的访问者返回192.x.x.2的解析地址; 为来源于中国电信运营商的访问者返回192.x.x.3的解析地址; 为其他来源的访问者返回192.x.x.1的解析地址。
1、DNS解析过程

image-20250424132738751

bash
DNS解析过程 通过域名example.com访问网站的域名解析过程如下。 1、用户在Web浏览器中输入“example.com”, 向本地域名服务器发起查询请求。若本地域名服务器存在缓存的解析数据,则直接将域名example.com对应的IP地址返回给Web浏览器,跳至步骤9。若本地域名服务器没有查到缓存的解析数据,则继续步骤2。 2、本地域名服务器向根域名服务器进行查询。 3、根域名服务器将.com顶级域名服务器的地址,返回给本地域名服务器。 4、本地域名服务器向.com顶级域名服务器发起example.com的查询请求。 5、.com顶级域名服务器将为example.com提供权威解析的权威域名服务器地址,返回给本地域名服务器。 6、本地域名服务器向权威域名服务器发起查询请求。 7、权威域名服务器将域名example.com对应的IP地址,返回给本地域名服务器。 8、本地域名服务器最后把查询的IP地址响应给Web浏览器。 9、Web浏览器通过IP地址访问网站服务器。 10、网站服务器返回网页信息。
2、记录概览

云解析支持的记录类型及其常见应用场景:

记录类型说明及场景
A记录将域名解析到指定的IPv4地址。常用于网站域名解析。
CNAME 记录将一个域名解析到另一个域名。常用于网站解析、CDN域名加速、企业邮箱、全局流量管理接入等。访问这个域名跳转到别的域名
TXT 记录用于对域名进行标识和说明。常用于数字认证证书、SPF 记录(反垃圾邮件)、域名找回等场景。验证来使用
3、配置域名解析

image-20250424135918371

image-20250424135959745

bash
将kodd.weixiang.info解析到SLB公网ip

image

bash
#ping域名测试: C:\Users\z1340>ping weixiang.info 正在 Ping weixiang.info [8.148.226.254] 具有 32 字节的数据: 来自 8.148.226.254 的回复: 字节=32 时间=38ms TTL=87 来自 8.148.226.254 的回复: 字节=32 时间=40ms TTL=87 C:\Users\z1340>ping kod.weixiang.info 正在 Ping kod.weixiang.info [8.148.226.254] 具有 32 字节的数据: 来自 8.148.226.254 的回复: 字节=32 时间=38ms TTL=87 来自 8.148.226.254 的回复: 字节=32 时间=38ms TTL=87 #浏览器访问测试

image

5、配置HTTPS证书

bash
创建证书

image

image-20250424143732117

bash
回到传统型负载均衡

image-20250424144320548

image-20250424144637355

image-20250424144616214

image-20250424144737277

image-20250424144836005

bash
下一步-下一步-提交

image-20250424144923024

bash
#现在配置好了,浏览器正常登录,但是有个问题,现在配置了80、443两个监听端口,分别创建了两种转发方式,没有创建80跳转到443的方式,所以需要删掉80端口,配置80转443的监听方式

image-20250424145647955

image-20250424145818710

image-20250424145910221

bash
#修改web01与web02配置文件,开启https #浏览器测试,正常进入

image

需要修改的配置

bash
# 后端web服务器需要开启fastcgi_param HTTPS on; [root@iZ7xv58a45kz3zmvjl2vajZ ~]#cat /etc/nginx/conf.d/kod.conf server { listen 80; server_name linux.weixiang.info; # server_name,域名 location / { root /code/kid; index index.php index.html; } location ~ \.php$ { root /code/kid; fastcgi_pass 127.0.0.1:9000; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; fastcgi_param HTTPS on; # 这里要开启 } }

image

image

6、四层负载

image

bash
标准架构高可用类型采用主备(master-replica)模式搭建。主节点提供日常服务访问,备节点通常不对外提供服务,仅保障高可用性(HA)。当主节 点发生故障,系统会自动在30秒内切换至备节点,保证业务平稳运行。 web服务器跟后端连接都是lvs四层负载,以ip+端口的方式访问,方便做故障切换,web直接连接数据库的话,数据库有故障只能手动修改配置文件再 切换。存在lvs四层负载,web连接lvs的vip(虚拟ip),vip绑定在后端一台数据库上,所以web访问vip就是访问绑定vip的后端数据库,如果数据库 故障,vip会自动飘移到另一台数据库上,如果数据库之间有会话保持,那么数据也不会少

img

1、配置四层负载

image

image-20250424160136368

bash
#四层转发只能对一个域名

image-20250424160324274

image

image-20250424160418608

bash
xshell连接8.148.226.254的2222端口

image-20250424160506142

bash
TCP的2222端口转发到web01的22端口

image-20250424160816709

image

7、Redis集群

1、高可用概念

标准架构高可用类型采用主备(master-replica)模式搭建。主节点提供日常服务访问,备节点通常不对外提供服务,仅保障高可用性(HA)。当主节点发生故障,系统会自动在30秒内切换至备节点,保证业务平稳运行。

image

bash
标准架构高可用类型的特点如下: 服务可靠:采用双机主备(master-replica)架构,主备节点位于不同物理机。当主节点出现故障,自研的HA系统会自动进行主备切换,保证业务平稳运行。 数据可靠:默认开启数据持久化功能,数据全部落盘。支持数据备份功能,您可以针对备份集回滚实例或者克隆实例,有效地解决数据误操作等问题。同时,在支持容灾的可用区(例如杭州可用区H+I)创建的实例,还具备同城容灾的能力。 兼容性:完全兼容Redis协议,自建的Redis数据库可以平滑迁移Redis标准版。阿里云还提供数据传输工具(DTS)进行增量的Redis迁移,保证业务平稳过渡。 阿里云自研 故障探测切换系统(HA): 云数据库Tair(兼容 Redis)封装HA切换系统,实时探测主节点的异常情况,可以有效解决磁盘IO故障,CPU故障等问题导致的服务异常,及时进行主备切换,从而保证服务高可用。 主备复制机制: 云数据库Tair(兼容 Redis)对主备全量同步中的Fork问题进行了优化,实现了无阻塞,在增量同步中采用增量日志格式进行复制传输。当主备复制中断后,对系统性能及稳定性影响极低,有效地避免了Redis原生主备复制的弊端。
2、部署redis实现kod会话保持
bash
1.购买redis服务器

image-20250424165002601

image-20250424165251717

bash
2.查看购买的redis基础信息,添加白名单,才能链接

image

bash
设置完白名单后返回实例会出现个链接地址

image-20250424165606798

bash
3.ping测试,要用同一网段才能ping通,slb四层转发后连接到的内网地址可以ping通 #ping这个地址会发现自动获得的ip是同一地域下的172.29.93.22 [root@web01 ~]#ping r-7xvjstzmnearjq1tbe.redis.rds.aliyuncs.com PING r-7xvjstzmnearjq1tbe.redis.rds.aliyuncs.com (172.29.93.22) 56(84) bytes of data. 64 bytes from 172.29.93.22 (172.29.93.22): icmp_seq=1 ttl=102 time=0.557 ms 64 bytes from 172.29.93.22 (172.29.93.22): icmp_seq=2 ttl=102 time=0.559 ms 64 bytes from 172.29.93.22 (172.29.93.22): icmp_seq=3 ttl=102 time=0.538 ms 4.修改免密登录,添加数据库信息

image

image-20250424170329461

image

bash
配置完后,页面访问失败,这是因为设置免密登录失败了,重新设置了下,可以正常访问

image

bash
5.因为有两台web服务器,而nginx负载均衡以轮询的方式配置了其中一台,所以只把某一台的配置文件写到了后端数据库 ,所以需要找到哪台配置 了redis的账号信息,复制到另外一台。所以最好的方式是先配置其中一台web的配置文件,然后拷贝到另一台。通过网页填写的方式不知道会写到 哪一台

image-20250424170518664

image-20250424170548953

bash
6.配置另一台web #递归查找r-7xvjstzmnearjq1tbe.redis.rds.aliyuncs.com保存在/code下哪个目录 [root@iZ7xvdbtdxwjcty17oye0dZ /]#grep -r r-7xvjstzmnearjq1tbe.redis.rds.aliyuncs.com /code /code/config/setting_user.php:$config['cache']['redis']['host'] = 'r-7xvjstzmnearjq1tbe.redis.rds.aliyuncs.com'; #查看 [root@iZ7xvdbtdxwjcty17oye0dZ /]#cat /code/config/setting_user.php <?php $config['database'] = array ( 'DB_TYPE' => 'sqlite3', 'DB_NAME' => USER_SYSTEM.'d5IJnDm6atPX.php', 'DB_SQL_LOG' => true, 'DB_FIELDS_CACHE' => true, 'DB_SQL_BUILD_CACHE' => false, ); $config['cache']['sessionType'] = 'file'; $config['cache']['cacheType'] = 'file'; $config['cache']['sessionType'] = 'redis'; $config['cache']['cacheType'] = 'redis'; $config['cache']['redis']['host'] = 'r-7xvjstzmnearjq1tbe.redis.rds.aliyuncs.com'; $config['cache']['redis']['port'] = '6379'; $config['cache']['sessionType'] = 'redis'; $config['cache']['cacheType'] = 'redis'; $config['cache']['redis']['host'] = 'r-7xvjstzmnearjq1tbe.redis.rds.aliyuncs.com'; $config['cache']['redis']['port'] = '6379' #将文件拷贝过去 [root@iZ7xvdbtdxwjcty17oye0dZ /]#scp /code/config/setting_user.php 172.22.233.224:/code/config/ The authenticity of host '172.22.233.224 (172.22.233.224)' can't be established. ECDSA key fingerprint is SHA256:do2XH/bkTOZjHpEX7lxS52FExhRfExyz8Imv3SzNhA8. ECDSA key fingerprint is MD5:84:fb:aa:97:8c:19:65:5d:e7:05:a4:c1:05:33:61:6a. Are you sure you want to continue connecting (yes/no)? yes Warning: Permanently added '172.22.233.224' (ECDSA) to the list of known hosts. root@172.22.233.224's password: setting_user.php #浏览器测试。正常

image-20250424171810308

3、外网链接Redis
bash
#1要开启公网,2添加白名单,3新建用户密码远程连接 1.申请链接公网地址,刷新后可以看到

image-20250424172808628

image-20250424172838608

bash
2.访问测试,随便可以联网的电脑都可以ping通 [root@web02 ~]#ping r-7xvjstzmnearjq1tbepd.redis.rds.aliyuncs.com PING r-7xvjstzmnearjq1tbepd.redis.rds.aliyuncs.com (8.148.168.150) 56(84) bytes of data. 64 bytes from 8.148.168.150 (8.148.168.150): icmp_seq=1 ttl=128 time=67.2 ms 64 bytes from 8.148.168.150 (8.148.168.150): icmp_seq=2 ttl=128 time=35.3 ms 3.登录数据库 [root@db01 ~]#redis-cli -h r-7xvjstzmnearjq1tbepd.redis.rds.aliyuncs.com 4.查看数据库报错,显示服务器关闭了连接,要放行白名单(出网的公网ip,通过curl cip.cc命令),设置用户名密码 # 查看公网ip [root@db01 ~]#curl cip.cc IP : 123.117.19.236 地址 : 中国 北京 北京 运营商 : 联通 数据二 : 中国北京北京 | 联通 数据三 : 中国北京北京市 | 联通 URL : http://www.cip.cc/123.117.19.236

image-20250424173811524

image-20250424174036481

image-20250424174307940

bash
5.可以正常登录数据库 [root@db01 ~]#redis-cli -h r-7xvjstzmnearjq1tbepd.redis.rds.aliyuncs.com -a 'oldboy:oldboy123!' r-7xvz1v70hylxkkk5nnpd.redis.rds.aliyuncs.com:6379> keys * 14298) "c2de1abb7018147446cdc1363d7941ec" 14299) "c4d8d9bfeb404b80fbd72daa8f317c72" 14300) "7ced0dd25a2648efe2b54089daa5b9bf" 14301) "4f47d74bc7730b4f5d0f594e8e51172e" 14302) "b255220aedf062c9d8e2c272e89505c3" 14303) "a3052762f7c8bab344324086702f6063" 14304) "2ae6bcc0b86482de55c2c8e28862f3a1" 14305) "48d1e8773ba74b97d6bdcd73db635437" 14306) "8772d3bd43e1269bd35a95cbe8a0ceca" (1.06s)
4、Redis规格升级

image-20250424174758780

5、卸载redis会话保持
bash
#进入配置文件把redis相关的删除 vim /code/config/setting_user.php #访问已经看不到了

image-20250424175457099

8、kod接入mysql

bash
1.购买一台mysql数据库 2.查看ip地址

image

image

image-20250424181007687

bash
[root@web01 ~]#ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000 link/ether 00:16:3e:03:b1:90 brd ff:ff:ff:ff:ff:ff inet 172.22.233.223/20 brd 172.22.239.255 scope global dynamic eth0 valid_lft 1892145632sec preferred_lft 1892145632sec inet6 fe80::216:3eff:fe03:b190/64 scope link valid_lft forever preferred_lft forever [root@web01 ~]#ping rm-7xvn9qi9495vfku4y.mysql.rds.aliyuncs.com PING rm-7xvn9qi9495vfku4y.mysql.rds.aliyuncs.com (172.22.233.225) 56(84) bytes of data. 64 bytes from 172.22.233.225 (172.22.233.225): icmp_seq=1 ttl=102 time=0.222 ms 64 bytes from 172.22.233.225 (172.22.233.225): icmp_seq=2 ttl=102 time=0.173 ms 3.创建账号密码

image

bash
4.安装mysql客户端 [root@web01 ~]#yum -y install mysql 5.登录 [root@web01 ~]#mysql -h rm-7xvn9qi9495vfku4y.mysql.rds.aliyuncs.com -uoldboy -pSdms2018 Welcome to the MariaDB monitor. Commands end with ; or \g. Your MySQL connection id is 915 Server version: 8.0.36 Source distribution Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. MySQL [(none)]> #添加数据库信息

image-20250424184739383

bash
因为有两台web服务器,而nginx负载均衡以轮询的方式配置了其中一台,所以只把某一台的配置文件写到了后端数据库 ,所以需要找到哪台配置了mysql的账号信息,复制到另外一台。所以最好的方式是先配置其中一台web的配置文件,然后拷贝到另一台。通过网页填写的方式不知道会写到哪一台 #查看哪一台web有mysql配置信息 [root@iZ7xvdbtdxwjcty17oye0eZ ~]#cat /code/config/setting_user.php <?php $config['database'] = array ( 'DB_TYPE' => 'sqlite3', 'DB_NAME' => USER_SYSTEM.'d5IJnDm6atPX.php', 'DB_SQL_LOG' => true, 'DB_FIELDS_CACHE' => true, 'DB_SQL_BUILD_CACHE' => false, ); $config['cache']['sessionType'] = 'file'; $config['cache']['cacheType'] = 'file'; $config['database'] = array ( 'DB_TYPE' => 'mysqli', 'DB_NAME' => 'kodbox', 'DB_HOST' => 'rm-7xvn9qi9495vfku4y.mysql.rds.aliyuncs.com', 'DB_PORT' => 3306, 'DB_USER' => 'oldboy', 'DB_PWD' => 'oldboy123!', 'DB_SQL_LOG' => true, 'DB_FIELDS_CACHE' => true, 'DB_SQL_BUILD_CACHE' => false,); #将配置文件复制到另外一台web #配置好访问测试

image-20250424185623215

bash
#mysql发现数据库已经存在 MySQL [(none)]> show databases; +--------------------+ | Database | +--------------------+ | __recycle_bin__ | | information_schema | | kodbox | | mysql | | performance_schema | | sys | +--------------------+ 6 rows in set (0.01 sec)
1、升级读写分离

image-20250424190236397

image-20250424190351460

image-20250424190726891

image-20250424192210304

bash
修改数据库配置,把内网连接地址放到php文件 [root@web01 ~]#vim /code/config/setting_user.php

9、NAS

1、挂载
bash
购买一台nas服务器

image-20250425142054049

image

image-20250425142216342

image

image-20250425142305105

image-20250425142332652

bash
#查看。已经完成自动挂载 [root@iZ7xv5bq4vfmj0398fehyiZ ~]#df -h Filesystem Size Used Avail Use% Mounted on devtmpfs 485M 0 485M 0% /dev tmpfs 496M 0 496M 0% /dev/shm tmpfs 496M 524K 495M 1% /run tmpfs 496M 0 496M 0% /sys/fs/cgroup /dev/vda1 40G 3.1G 35G 9% / tmpfs 100M 0 100M 0% /run/user/0 2879784bcb8-ydn91.cn-guangzhou.nas.aliyuncs.com:/ 10P 0 10P 0% /mnt #自动添加到自动挂载 [root@iZ7xvir6mu3v4yxtwwtiw6Z /mnt]#cat /etc/fstab # # /etc/fstab # Created by anaconda on Fri Jun 28 04:16:23 2024 # # Accessible filesystems, by reference, are maintained under '/dev/disk' # See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info # UUID=c8b5b2da-5565-4dc1-b002-2a8b07573e22 / ext4 defaults 1 1 2879784bcb8-ydn91.cn-guangzhou.nas.aliyuncs.com:/ /mnt nfs vers=3,nolock,proto=tcp,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2,noresvport,_netdev 0 0 #创建文件 [root@iZ7xv5bq4vfmj0398fehyiZ /mnt]#touch {1..10}.log [root@iZ7xv5bq4vfmj0398fehyiZ /mnt]#ll total 0 -rw-r--r-- 1 root root 0 Apr 25 14:27 10.log -rw-r--r-- 1 root root 0 Apr 25 14:27 1.log -rw-r--r-- 1 root root 0 Apr 25 14:27 2.log -rw-r--r-- 1 root root 0 Apr 25 14:27 3.log -rw-r--r-- 1 root root 0 Apr 25 14:27 4.log -rw-r--r-- 1 root root 0 Apr 25 14:27 5.log -rw-r--r-- 1 root root 0 Apr 25 14:27 6.log -rw-r--r-- 1 root root 0 Apr 25 14:27 7.log -rw-r--r-- 1 root root 0 Apr 25 14:27 8.log -rw-r--r-- 1 root root 0 Apr 25 14:27 9.log

image-20250425143019797

2、卸载

image-20250425143624134

bash
[root@iZ7xv5bq4vfmj0398fehyiZ /]#df -h Filesystem Size Used Avail Use% Mounted on devtmpfs 485M 0 485M 0% /dev tmpfs 496M 0 496M 0% /dev/shm tmpfs 496M 520K 495M 1% /run tmpfs 496M 0 496M 0% /sys/fs/cgroup /dev/vda1 40G 3.1G 35G 9% / tmpfs 100M 0 100M 0% /run/user/0 # 卸载后挂载到别的云服务器,文件照样存在 [root@iZ7xv58a45kz3zmvjl2vajZ ~]#cd /mnt [root@iZ7xv58a45kz3zmvjl2vajZ /mnt]#ll total 0 -rw-r--r-- 1 root root 0 Jun 12 18:53 10.log -rw-r--r-- 1 root root 0 Jun 12 18:53 1.log -rw-r--r-- 1 root root 0 Jun 12 18:53 2.log -rw-r--r-- 1 root root 0 Jun 12 18:53 3.log -rw-r--r-- 1 root root 0 Jun 12 18:53 4.log -rw-r--r-- 1 root root 0 Jun 12 18:53 5.log -rw-r--r-- 1 root root 0 Jun 12 18:53 6.log -rw-r--r-- 1 root root 0 Jun 12 18:53 7.log -rw-r--r-- 1 root root 0 Jun 12 18:53 8.log -rw-r--r-- 1 root root 0 Jun 12 18:53 9.log

10、OSS

bash
OSS对象存储 15.1) 什么是对象存储? 阿里云对象存储OSS(Object Storage Service)是一款海量、安全、低成本、高可靠的云存储服务,可提供99.9999999999%(12个9)的数据持久 性,99.995%的数据可用性。多种存储类型供选择,全面优化存储成本。 OSS具有与平台无关的RESTful API接口,您可以在任何应用、任何时间、任何地点存储和访问任意类型的数据。 15.2) 对象存储使用场景? 15.3) Kodcloud对接OSS存储构建私有网盘 Document:https://help.aliyun.com/product/31815.html?spm=a2c4g.11186623.6.540.152f406cjmJWuA

image-20250425150637095

bash
用户想访问图片,正常访问流程通过负载均衡代理着用户访问到程序框架,然后才能访问到nfs的图片。 如果是oss,用户通过cdn加速可以直接访问,免去了走程序框架
1、购买
bash
1.创建bucket

image

image-20250425151625136

2、kod介入oss
bash
2.创建子账号获取信息 进入bucket-->权限控制-->访问控制RAM-->前往RAM控制台--用户:创建用户

image

bash
用户登录名称:weixiang@1431044874515527.onaliyun.com AccessKey ID:LTAI5tPb7SQjbizHNhYC3AzJ AccessKey Secret:qHqm5jgunyfRAnkmh2nHLCSLdlZYVQ

image

image

bash
给账号添加管理存储的权限: 权限控制-->bucket授权策略-->新增授权,授权子账号拥有完全控制权限 #ping以下看看地域节点通不通 [root@iZ7xv5bq4vfmj0398fehyiZ /]# ping oss-cn-guangzhou-internal.aliyuncs.com PING oss-cn-guangzhou-internal.aliyuncs.com (100.115.33.42) 56(84) bytes of data. 64 bytes from 100.115.33.42 (100.115.33.42): icmp_seq=1 ttl=102 time=0.129 ms 64 bytes from 100.115.33.42 (100.115.33.42): icmp_seq=2 ttl=102 time=0.140 ms

image

image

image

bash
3.根据上面信息对接kod云平台

image

3、删除oss

image-20250425155049018

11、CDN

bash
什么是CDN? 内容分发网络 面试题: cdn加速原理 我们在北京要访问上海的网站,因为跨网络特别远,怎么样提高效率呢,当然要访问离我们最近的服务器,正好昌平有个机房里面有大量的服务器,这个 机房存储着要访问的资源,所以我们访问的内容在这个机房就可以给我们响应了,不需要跨区域再去上海访问,每个地区都有CDN节点,目的就说为了提高 用户访问静态资源的速度
1、产品架构

img

bash
当用户去访问静态资源的时候,会先去访问DNS,DNS拿到CNAME,会进入智能DNS,会进行链路探测,判断你带宽的来源,比如移动,之后会进行一个路 由选择,然后再进行一个策略中心调度,会给用户返回最近的一个CDN节点。如果返回给用户没有目标资源,会向二级缓存请求,如果全没有会去访问源站, 从源站拿到资源后会给所以的CDN节点加载资源,然后再响应给用户
2、加速原理

img

bash
1.当终端用户向www.aliyundoc.com下的指定资源发起请求时,首先向Local DNS(本地DNS)发起请求域名www.aliyundoc.com对应的IP。 2.Local DNS检查缓存中是否有www.aliyundoc.com的IP地址记录。如果有,则直接返回给终端用户;如果没有,则向网站授权DNS请求域名www.aliyundoc.com的解析记录。 3.当网站授权DNS解析www.aliyundoc.com后,返回域名的CNAME www.aliyundoc.com.example.com。 4.Local DNS向阿里云CDN的DNS调度系统请求域名www.aliyundoc.com.example.com的解析记录,阿里云CDN的DNS调度系统将为其分配最佳节点IP地址。 5.Local DNS获取阿里云CDN的DNS调度系统返回的最佳节点IP地址。 6.Local DNS将最佳节点IP地址返回给用户,用户获取到最佳节点IP地址。 7.用户向最佳节点IP地址发起对该资源的访问请求。
3、CDN概述
bash
配置CDN场景 1.简单的验证: 先搭建一个可道云,然后检测是否丛源站获取资源,然后配置加速,在验证是否丛不同的CDN节点获取的资源. 2.分布式缓存:源站提供mp4下载,然后通过不同地域的服务器wget资源,检查是否是从不同地域的边缘节点获取的资源。 3.检测的站点 ( http://tool.chinaz.com/speedtest.aspx | https://tools.ipip.net/ping.php ) #加CDN前

image-20250425163544154

image-20250425163742131

image-20250425163756162

bash
#新上传图片测试,显示公网负载均衡地址

image

4、部署CDN
bash
1.添加域名: CDN-域名管理-添加域名 #此时要用备案的域名 加速域名,业务类型,新增源站信息

image

image

image

bash
2.配置CNAME 将域名解析到CNAME记录值 DNS-解析设置,将记录类型A改为CNAME,记录纸的值从公网ip改为CNAME的值 #测试,ping以下公网ip,正确是返回CDNDE IP地址,只要不是返回自己的公网ip #站点测试tools.ipip.net/ping.php

image

image

image

image

bash
可以看到已经返回cdn的节点了

``·

image

bash
#故障案例 公司开发上传了一张图片,但是客户那边没变,排查问题发现前端加了cdn,根据cdn机制,cdn有就响应,没有就去源站请求 CDN缓存机制: 上传/code目录第二张图片覆盖第一张,用户请求域名会先去请求cdn,cdn会根据名称进行返回,如果查询的名字一样,那cdn就返回第一张图片内容 解决方法: 一、刷新:给后台一个链接,比如kod.linux.com/123.png对这个链接进行刷新,删除所有cdn节点上的资源,重新去请求源站,获取123.png,强制回源 二、预热:提前把资源上传到cdn节点预热,全国各地所有cdn节点就有了,就不用回源 操作方法:CDN-刷新,放置新图片链接-提交,浏览器测试是否更换成新图片 删除CDN后要把记录类型修改成A,记录纸修改为CNAME

image

12、WAF防火墙

bash
https://yunsuo.qianxin.com/ 应用层面防火墙 1.下载 [root@web01 ~]#wget https://download.yunsuo.qianxin.com/v3/yunsuo_agent_64bit.tar.gz && tar xvzf yunsuo_agent_64bit.tar.gz && chmod +x yunsuo_install/install && yunsuo_install/install 2.注册用户

image-20250426083423807

bash
3.默认已经启动 [root@web01 ~]#ps aux|grep yunsuo root 21821 0.1 3.3 1728580 59904 ? Sl 08:30 0:00 ./yunsuo_agent_service -c config.xml -l runlog/run_log.log -e ALL -t ALL -s safe -m daemon root 21892 0.0 0.2 175704 4848 ? Ssl 08:30 0:00 ./yunsuo_agent_guard root 21986 0.0 0.0 112812 976 pts/0 S+ 08:36 0:00 grep --color=auto yunsuo 4.添加服务器到云中心。 [root@web01 ~]#/usr/local/yunsuo_agent/agent_smart_tool.sh -u 1360821977@qq.com -p weixiang123 Bind Server Success. 5.云锁启动/停止/重启/状态 service yunsuo start/stop/restart/status /etc/init.d/yunsuo start/stop/restart/status 6./usr/local/yunsuo_agent/uninstall #下载windows版本云锁 云锁实现的功能: 抗CC攻击:秒级识别恶意流量,保障网站可用性 防篡改:实时监控网页,拦截暗链、黑链、挂马 防御SQL注入、禁用敏感词 展示CPU、内存、磁盘、网络IO等性能指标,支持阈值告警 #面试题 做过安全吗? 我在上家公司主要是维护web服务器这一块,安全这一块虽然不是我具体负责,但我知道我们公司关于安全的业务是怎么做的 1.首先是网络层面的一个控制,前面硬件的话有硬件防火墙,是网络安全方面的一个防护,在硬件防火墙里面开启防cc攻击,防洪水、syn攻击。这些我都配置过 2.系统层面,修改默认SSH,默认端口,禁止默认root登录,使用普通用户提权登录,配置iptables规则放行80跟443端口还有远程连接的端口,阿里云(安全组规则) 3.业务层面安全,因为我上面是web服务器,前面部署开源云锁WAF防火墙,防文件篡改,防用户连接跟请求

13、弹性伸缩

1、什么是弹性伸缩
bash
13.1) 什么是弹性伸缩? 使用弹性伸缩(Auto Scaling),您可以根据业务需求和策略设置伸缩规则,在业务需求增长时自动为您增加ECS实例以保证计算能力,在业务需求下降时自动减少ECS实例以节约成本。弹性伸缩不仅适合业务量不断波动的应用程序,同时也适合业务量稳定的应用程序。 13.2) 弹性伸缩应用场景 某视频公司:春晚或每周五热门节目来临时,负载激增,需及时、自动扩展云计算资源。 某视频直播公司:业务负载变化难以预测,需要阿里云自动根据CPU利用率、应用负载、带宽利用率作为衡量指标进行弹性伸缩。 某游戏公司:每天中午12点及晚上6点到9点间需求增长,需要定时扩容。 某电商:在大促中,临时激增大量云服务器需求,需要在数分钟内实现从创建到可用。 13.3) 弹性伸缩模式 定时模式:您自定义自动伸缩发生的时间和频率,如每天 13:00增加 ECS 实例。 动态模式:基于云监控性能指标(如 CPU 利用率),自动增加或减少 ECS 实例。 健康模式:如 ECS 实例为非 Running 状态,弹性伸缩将自动移出或释放不健康的 ECS 实例。 13.4) ESS弹性伸缩配置实践 配置的流程: 配置好负载均衡-->创建伸缩组-->添加伸缩配置-->添加已有ECS实例-->启用伸缩组 1) 创建伸缩组规则 1.1) 添加ECS实例规则 CPU大于80% 1.2) 减少ECS实例规则 CPU小于30% 2) 弹性伸缩规则会在什么时候添加或减少,根据动作来触发. 定时任务 云上监控 3) 模拟CPU大于百分之80% Document:https://help.aliyun.com/product/25855.html?spm=a2c4g.11186623.6.540.535448595bgK6Y
2、创建弹性伸缩
bash
#1.创建弹性伸缩: 弹性伸缩-伸缩组管理-创建伸缩组 注意点:1.组内实例配置信息来源,选择某个实例当模板来配置伸缩实例 2.添加已有实例,把原先存在的都勾选上 3.关联传统型负载均衡CLB(原SLB),要选中才能把新加入的添加到负载均衡里

image-20250427172635413

bash
#2.配置伸缩规则 弹性伸缩-伸缩组管理-伸缩规则与报警任务-创建伸缩规则 注意点:创建报警任务,根据业务选择不同的报警指标描述,如系统平均负载、内存、cpu使用率等,重复几次后报警 执行操作、实际预热时间

image-20250427173222245

image-20250427173330884

bash
#3.执行测试任务 1.负载均衡配置四层负载,xshell连接两台虚拟机 2.安装ab命令 [root@iZ7xv00d8xv6isvthuiz7aZ ~]#yum -y install httpd 3.两台web都执行压力测试 [root@iZ7xv00d8xv6isvthuiz7bZ ~]#ab -n200000 -c200 http://127.0.0.1/index.php 4.xshell登录另一个窗口,监控负载 [root@iZ7xv00d8xv6isvthuiz7bZ ~]#uptime 17:40:56 up 31 min, 3 users, load average: 19.97, 5.01, 1.71 #测试,已自动扩展两台至四台

image-20250427183528414

3、报错案例
bash
案例:安装过程中出现弹性伸缩-报警任务-系统监控出现数据不足的状态

image.png

bash
如果是上图这样,那么这个问题是因为ECS服务器中没有安装云监控插件, 或者是安装了云监控插件,但是因为网络问题,导致云监控插件没有成功上报数据给云监控平台,导致 云监控平台 获取不到服务器的采集数据,就会显示数据不足,麻烦您点这里https://cloudmonitor.console.aliyun.com/hostMonitor/?AliyunHost=all&KeyWord=name,&currentPage=1&pageSize=10 然后如下图去安装更新下云监控后等10分钟后测试下,谢谢。 https://help.aliyun.com/document_detail/183482.html

image.png

4、缩减弹性伸缩
bash
弹性伸缩-伸缩组管理-伸缩规则与报警任务-创建伸缩规则 注意点:报警指标描述:系统平均负载要选< 执行操作要选减少 #测试

image-20250427184242336

image-20250427184325811

image-20250427184419457

image-20250427185102561

14、NATA

1、概念
bash
14.NAT(运维) 14.1) 内网ECS没有购买公网IP,无法上网 方式一、firewalld实现内部主机共享上网(不推荐) 1.购买一台ECS专门用于共享上网,需要有独立公网IP,主机名称为Manager 2.开启Manager服务器firewalld防火墙,打开masquerade路由转发功能 3.找到需要上网的ECS实例所在的VPC网络,添加一条路由规则,去往0.0.0.0/0 下一跳是Manager 这台ECS实例 方式二、NAT网关实现内网共享上网 (强烈推荐) 1.购买按量付费的NAT网关 2.购买弹性EIP,将EIP捆绑置NAT网关 3.配置NAT网关的SNAT路由条目,进行地址转换,最后测试连通性 注意: NAT网关设备允许多个可用区共用一个NAT网关设备进行上网 Document:https://help.aliyun.com/product/44413.html?spm=a2c4g.11186623.6.540.47462f2aoaZFjK 14.2)解决内网主机无法直连的问题 方式一、跳板机方式 方式二、负载均衡TCP 方式三、NAT网关端口映射( 需要额外在购买一个弹性公网IP地址 )
2、设置NAT
bash
1.阿里云没有内网,上不去网 [root@iZ7xv00d8xv6isvthuiz7bZ ~]#ping www.baidu.com PING www.a.shifen.com (183.2.172.177) 56(84) bytes of data. ^C --- www.a.shifen.com ping statistics --- 3 packets transmitted, 0 received, 100% packet loss, time 1999ms 2.配置NAT网关 NAT网关-创建公网NAT-购买,需要绑定弹性公网ip 注意:访问模式选择稍后设置 公网NAT网关-设置SNAT-创建SNAT条目(会出现VPC粒度、交换机粒度、ESC/弹性网卡粒度、自定义网段粒度)-选择VPC粒度 VPC粒度:所有地域下的都能上网,比如呼和浩特 交换机粒度:在本交换机下面的都可以上网 ESC/弹性网卡粒度:自己选择谁可以上网 自定义网段粒度:只允许哪个网段可以上网

image

image

image-20250427190612647

bash
3.再ping测试可以通 [root@iZ7xv00d8xv6isvthuiz7bZ ~]#ping www.baidu.com PING www.a.shifen.com (183.2.172.177) 56(84) bytes of data. 64 bytes from 183.2.172.177 (183.2.172.177): icmp_seq=1 ttl=50 time=4.78 ms 64 bytes from 183.2.172.177 (183.2.172.177): icmp_seq=2 ttl=50 time=4.71 ms [root@iZ7xv00d8xv6isvthuiz7aZ ~]#curl cip.cc IP : 8.134.171.158 地址 : 中国 广东 广州 运营商 : 阿里云 数据二 : 中国广东深圳 | 阿里云 数据三 : 中国 | 阿里巴巴 URL : http://www.cip.cc/8.134.171.158 创建DNAT管理,不需要通过负载均衡 专有网-公网NAT网关-ngw-7xvnli6ai79ia056oz75r-创建DNAT条目

image

bash
#测试可以连接 [C:\~]$ ssh 8.134.88.105 111 Connecting to 8.134.88.105:111... Connection established. To escape to local shell, press 'Ctrl+Alt+]'. WARNING! The remote SSH server rejected X11 forwarding request. Last failed login: Thu Jun 12 22:02:55 CST 2025 from 219.77.222.7 on ssh:notty There were 8 failed login attempts since the last successful login. Last login: Thu Jun 12 18:52:36 2025 from 123.117.19.236 Welcome to Alibaba Cloud Elastic Compute Service !
3、VPC NAT网关
bash
实现不同地域之间的网络连接 VPC NAT网关(VPC NAT Gateway)是一款企业级的VPC私网网关,提供私网NAT代理(SNAT和DNAT),可支持VPC和线下IDC及VPC之间地址转换 能力,可提供高达100Gbps转发能力以及跨可用区容灾能力。

15、Ansible

image-20250427193300164

image-20250427193423053

1、Ansible安装配置

bash
基本概述: Ansible是一个自动化统一配置管理工具,自动化主要体现在Ansible集成了丰富模块以及功能组件,可以通过一个命令完成一系列操作, 从而减少重复性的工作和维护成本,可以提高工作效率 #1.在python安装源码包 [root@m01 ~]#wget https://www.python.org/ftp/python/3.8.16/Python-3.8.16.tgz #2.解压 [root@m01 ~]#tar xzf Python-3.8.16.tgz #3.进入 [root@m01 ~]#cd Python-3.8.16 #4.编译 [root@m01 ~/Python-3.8.16]#./configure --enable-optimizations [root@m01 ~/Python-3.8.16]#make -j$(nproc) [root@m01 ~/Python-3.8.16]#make altinstall #5.安装Ansible [root@m01 ~/Python-3.8.16]#pip3.8 install ansible [root@m01 ~]#ansible --version ansible [core 2.13.13] #6.配置ansible (不需要启动) [root@m01 ~/Python-3.8.16]#mkdir /etc/ansible [root@m01 ~/Python-3.8.16]#vim /etc/ansible/ansible.cfg [defaults] host_key_checking = False deprecation_warnings = False interpreter_python = /usr/bin/python3 [inventory] #如果不写就按照编译的默认配置 [privilege_escalation] [paramiko_connection] [ssh_connection] [persistent_connection] [accelerate] [selinux] [colors] [diff]
1、Ansible使用
bash
#ansible <host-pattern> [options] --version #ansible版本信息 -v #显示详细信息 -i #主机清单文件路径,默认是在/etc/ansible/host -m #使用模块名称,默认使用command模块 -a #使用的模块参数,模块的具体动作 -k #提示输入ssh密码,而不使用基于ssh的密钥认证 -C #模拟执行测试,但不会真的执行 -T #执行命令的超时

2、Ansible主机清单

bash
#配置方式有两种,一种基于用户名密码的方式管理客户端,一种基于免秘钥的方式管理客户端 方法1.基于用户名密码方式管理客户端 [root@m01 ~]#cat /etc/ansible/hosts 172.16.1.7 ansible_ssh_user=root ansible_ssh_port=22 ansible_ssh_pass='Sdms2018' ✦•············································································································•✦ 分割线 ✦•············································································································•✦方法2.基于免秘钥方式管理客户端(使用此方式管理客户端) #单台配置 #1.配置文件 [root@m01 ~]#cat /etc/ansible/hosts 172.16.1.7 172.16.1.8 #2.创建密钥 [root@m01 ~]#ssh-keygen Generating public/private rsa key pair. Enter file in which to save the key (/root/.ssh/id_rsa): Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /root/.ssh/id_rsa Your public key has been saved in /root/.ssh/id_rsa.pub The key fingerprint is: SHA256:fxMERq7conAFXpHG0SujhmY8GvdjM90lOEiXNokYMuQ root@m01 The keys randomart image is: +---[RSA 3072]----+ | .. ..+*+ | | .o .. o+o.. | | Eo o.o.o... | | . ooOo.. | | ..o.=S=. . | | . Bo+.oo. .. | | * +.. o.oo | | . * . .. . | | . + | +----[SHA256]-----+ #3.钥匙复制到7、8 [root@m01 ~]#ssh-copy-id 172.16.1.7 [root@m01 ~]#ssh-copy-id 172.16.1.8 #4.ping测试 [root@m01 ~]#ansible all -m ping 172.16.1.7 | SUCCESS => { "changed": false, "ping": "pong" } 172.16.1.8 | SUCCESS => { "changed": false, "ping": "pong" } 注意: #如果修改成这种方式,只能写前面的主机名称,写ip报错 [root@m01 ~]#cat /etc/ansible/hosts web01 ansible_ssh_host=172.16.1.7 web02 ansible_ssh_host=172.16.1.8 [root@m01 ~]#ansible web01 -m ping web01 | SUCCESS => { "changed": false, "ping": "pong" } [root@m01 ~]#ansible 172.16.1.7 -m ping [WARNING]: Could not match supplied host pattern, ignoring: 172.16.1.7 [WARNING]: No hosts matched, nothing to do #Ansible主机清单设置组 [root@m01 ~]#ansible web_server -m ping 172.16.1.8 | SUCCESS => { "changed": false, "ping": "pong" } 172.16.1.7 | SUCCESS => { "changed": false, "ping": "pong" } #定义多组,多组汇总整合 [root@m01 ~]#cat /etc/ansible/hosts [db_server] 172.16.1.51 [web_server] 172.16.1.7 172.16.1.8 [root@m01 ~]#ansible db_server -m ping 172.16.1.51 | SUCCESS => { "changed": false, "ping": "pong" } #hehe这个组包含了db_server、web_server,操作hehe就等于操作这两个组 [root@m01 ~]#cat /etc/ansible/hosts [db_server] 172.16.1.51 [web_server] 172.16.1.7 172.16.1.8 [hehe:children] db_server web_server [root@m01 ~]#ansible hehe -m ping 172.16.1.51 | SUCCESS => { "changed": false, "ping": "pong" } 172.16.1.8 | SUCCESS => { "changed": false, "ping": "pong" } 172.16.1.7 | SUCCESS => { "changed": false, "ping": "pong" } [root@m01 ~]#ansible web_server -m ping [root@m01 ~]#cat /etc/ansible/hosts [web_server:vars] ansible_ssh_user=root ansible_ssh_pass='Sdms2018' #使用变量 172.16.1.8 | SUCCESS => { "changed": false, "ping": "pong" }
1、Ansible示例
bash
[root@m01 ~]#ansible-doc yum EXAMPLES: - name: Install the latest version of Apache ansible.builtin.yum: name: httpd 👉 #软件名字 state: latest 👉 #状态,最新版本,很少安装最新版本 - name: Install Apache >= 2.4 ansible.builtin.yum: name: httpd>=2.4 state: present 👉 #状态安装 - name: Remove the Apache package ansible.builtin.yum: name: httpd 👉 #软件名字 state: absent 👉 #状态卸载 EXAMPLES: - name: Copy file with owner and permissions ansible.builtin.copy: src: /srv/myfiles/foo.conf 👉 #原文件 dest: /etc/foo.conf 👉 #目标位置 owner: foo 👉 #属主 group: foo 👉 #属组 mode: '0644' 👉 #权限
2、知识点小结
bash
知识点小结: 1.ansible安装 python3.8安装 创建配置文件(/etc/ansible/ansible.cfg) mkdir /etc/ansible vim /etc/ansible/ansible.cfg 粘贴配置... -----------远程管理客户端方式 2.基于ip+端口+用户名+密码远程验证方式(使用较少) vim /etc/ansible/hosts 172.16.1.7 ansible_ssh_user=root ansible_ssh_pass='oldboy123.com' 3.基于免秘钥方式配置主机清单 1)生产密钥对 2)和客户端做免秘钥 ssh-copy-id 172.16.1.7 3)vim /etc/ansible/hosts web01 ansible_ssh_host=172.16.1.7 ----------------------------- 4.主机清单配置方式 支持单台 172.16.1.7 172.16.1.8 支持组 [web_server] 172.16.1.7 172.16.1.8 [db_server] 172.16.1.51 支持多个组的组合 [lnmp:children] web_server db_server

3、Ansible-adhoc

bash
#Ad-hoc部署backup服务 #1.41拷贝rsyncd.conf到61 [root@backup /]#scp -r /etc/rsyncd.conf 10.0.0.61:/root/ #2.配置 [root@m01 ~/.ssh]#cat /etc/ansible/hosts [backup_server] backup ansible_ssh_host:172.16.1.41 #3.61免密钥到41 [root@m01 ~]#ssh-copy-id 172.16.1.41 #4.执行安装步骤 使用yum模块安装rsync服务 #安装rsync服务 [root@m01 ~]#ansible backup -m yum -a 'name=rsync state=present' -m: #模块,必有 -a: #动作,必有 name=rsync: #软件名字rsync state=present: #state动作,present安装 #5.配置Rsync服务,将61服务器./rsyncd.conf拷贝到/etc/下 [root@m01 ~]#ansible backup -m copy -a 'src=./rsyncd.conf dest=/etc/' #6.根据配置文件创建必要的数据信息

与 Playbook 的对比:

特性Ad-Hoc 命令Playbook
复杂度简单(单条命令)复杂(YAML 文件)
适用场景临时任务、快速验证复杂流程、重复性任务
可复用性不可复用可版本控制、重复使用
功能完整性功能受限(不支持条件/循环等逻辑)支持完整自动化逻辑
执行日志无持久化记录有详细执行记录
1、ping模块
bash
#模块1.ping模块 测试联通性,不指定文件位置会默认。 [root@m01 ~]#ansible web_server -m ping 172.16.1.7 | SUCCESS => { "changed": false, "ping": "pong" } 172.16.1.8 | SUCCESS => { "changed": false, "ping": "pong" } #2.ping模块 测试联通性,-i 指定文件位置 cp /etc/ansible/hosts ./zhang [root@m01 ~]#ansible all -m ping -i zhang/hosts backup | SUCCESS => { "changed": false, "ping": "pong" } 172.16.1.51 | SUCCESS => { "changed": false, "ping": "pong" } 172.16.1.8 | SUCCESS => { "changed": false, "ping": "pong" } 172.16.1.7 | SUCCESS => { "changed": false, "ping": "pong" }
2、yum模块
bash
yum: -m: #模块,必有 -a: #动作,必有 name: lrzsz # 软件名称可以是本地的rpm包 state: present|absent # 安装或者卸载 latest # 安装最新版本 download_only: true # 只下载不安装 download_dir: /opt/ # 只下载不安装存放的位置 #卸载41的lrzsz,黄色表示已经卸载完成 [root@m01 ~]#ansible backup -m yum -a 'name=lrzsz state=absent' backup | CHANGED => { "ansible_facts": { "pkg_mgr": "dnf" }, "changed": true, "msg": "", "rc": 0, "results": [ "Removed: lrzsz-0.12.20-46.ky10.x86_64" ] } #查看41,已经没有了 [root@backup /]#sz -bash: sz: command not found [root@backup /]#rz -bash: rz: command not found #同时卸载web01和web02的wget [root@m01 ~]#ansible web_server -m yum -a "name=wget state=absent" #安装 [root@m01 ~]#ansible web_server -m yum -a "name=wget state=present"
3、copy模块
bash
copy: src: /etc/passwd # 指定源文件的位置 content dest: /root/ owner: www group: www mode: 0600 backup: yes #案例1.将61服务器/etc/passwd拷贝到41服务器/root/下并修改属主属组为www,修改权限为600 [root@m01 ~]#ansible backup -m copy -a 'src=/etc/passwd dest=/root/ owner=www group=www mode=600' 查看 [root@backup ~]#ll -rw------- 1 www www 1927 Apr 27 21:36 passwd #案例2.拷贝hosts到root目录下改名为1.txt [root@m01 ~]#ansible backup_server -m copy -a 'src=/etc/hosts dest=/root/1.txt' backup | CHANGED => { "changed": true, "checksum": "7335999eb54c15c67566186bdfc46f64e0d5a1aa", "dest": "/root/1.txt", "gid": 0, "group": "root", "md5sum": "54fb6627dbaa37721048e4549db3224d", "mode": "0644", "owner": "root", "size": 158, "src": "/root/.ansible/tmp/ansible-tmp-1745817736.6964135-76073-247149860659350/source", "state": "file", "uid": 0 } #案例3.拷贝目录 [root@m01 ~]#ansible backup_server -m copy -a 'src=zhang dest=/root/' backup | CHANGED => { "changed": true, "dest": "/root/", "src": "/root/zhang" } #案例4.目标文件是否备份使用backup参数,如果目标文件存在 #当源文件(src)与目标文件(dest)同名且内容不同时,Ansible会先将原始文件重命名为备份文件,然后再复制新文件,不会覆盖原文件 [root@m01 ~]#ansible backup_server -m copy -a 'src=1 dest=/root backup=yes' backup | CHANGED => { "backup_file": "/root/1.73259.2025-04-28@13:28:16~", 👉 #目录名称 "changed": true, "checksum": "4183845ea9681da0328a776c957ea1ada6e6190c", "dest": "/root/1", "gid": 0, "group": "root", "md5sum": "c5f42eddf777ef2d2b0f7263c094c20f", "mode": "0644", "owner": "root", "size": 8, "src": "/root/.ansible/tmp/ansible-tmp-1745818095.5799327-76209-222995593520644/source", "state": "file", "uid": 0 } #案例5.将100定向到目标主机/root/100.log下,源目录没有也会自动创建,将content的100定向到100.log [root@m01 ~]#ansible backup_server -m copy -a 'content=100 dest=/root/100.log' [root@backup ~]#cat 100.log 100 #案例6.将content后面的字符串定向到目标主机的pass.txt中 权限为600 [root@m01 ~]#ansible backup_server -m copy -a 'content=100 dest=/root/100.log' [root@m01 ~]#ansible backup -m copy -a 'content="rsync_backup:123456" dest=/root/pass.txt mode=0600'
4、command模块
bash
#后面直接加命令,缺乏shell环境,管道等符号不支持,不建议使用 #案例1.创建文件 [root@m01 ~]#ansible backup_server -m command -a 'touch /root/1.log' backup | CHANGED | rc=0 >> [root@backup ~]#ll total 0 -rw-r--r-- 1 root root 0 Apr 28 13:53 1.log #案例2.下载命令 [root@m01 ~]#ansible backup_server -m command -a 'yum -y install lrzsz'
5、file模块
bash
file: path: /root/a.txt 👉 # 路径 state: touch 👉 # 创建文件 directory 👉 # 创建目录 owner: www group: www mode: 0600 recurse: yes 👉 # 递归修改目录及以下所有文件属主属组 #案例1.创建a.txt 属主属组为lp 权限为600 [root@m01 ~]#ansible backup_server -m file -a 'path=/root/a.txt state=touch owner=www group=www mode=600' [root@backup ~]#ll total 0 -rw------- 1 www www 0 Apr 28 14:02 a.txt #案例2.创建oldboy目录 属主属组为root权限给777 [root@m01 ~]#ansible backup_server -m file -a 'path=/root/oldboy state=directory mode=777' drwxrwxrwx 2 root root 6 Apr 28 14:04 oldboy #案例3.递归创建目录 [root@m01 ~]#ansible backup_server -m file -a 'path=/root/1/2/3 state=directory mode=777' [root@backup ~]#tree 1 1 └── 2 └── 3 #案例4.递归修改文件的属主属组 [root@m01 ~]#ansible backup_server -m file -a 'path=/root/1 state=directory owner=www group=www recurse=yes' #案例5.删除文件a.txt [root@m01 ~]#ansible backup_server -m file -a 'path=/root/a.txt state=absent' #案例6.删除目录1,递归删除 [root@m01 ~]#ansible backup_server -m file -a 'path=/root/1 state=absent'
6、group模块
bash
#案例1.创建一个组 gid为666 名称为www [root@m01 ~]#ansible backup -m group -a 'name=www gid=666 state=present' #查看 [root@backup ~]#grep www /etc/group www:x:666:
7、user模块
bash
user: name: www uid: 666 group: www shell: /bin/bash 或者/sbin/nologin state: present 👉 # 创建用户 absent 👉 # 删除用户 remove: yes 👉 # 删除用户所有相关信息 create_home: true 👉 # 创建家目录 默认为true false 👉 # 不创建家目录 创建虚拟用户的时候使用 #案例1.创建一个普通账号hehe uid300 gid300 创建家目录 允许登录 先创建组 [root@m01 ~]#ansible backup_server -m group -a 'name=hehe gid=300 state=present' 再创建用户 [root@m01 ~]#ansible backup_server -m user -a 'name=hehe uid=300 group=300 create_home=true shell=/bin/bash' #案例2.创建一个虚拟账号 oldboy uid 777 gid 777 不创建加 不允许登录 [root@m01 ~]#ansible backup_server -m group -a 'name=oldboy gid=777 state=present' [root@m01 ~]#ansible backup_server -m user -a 'name=oldboy uid=777 group=777 create_home=false shell=/sbin/nologin' #案例3.删除用户oldboy,remove=yes参数的作用是彻底删除用户及其关联的目录和文件 [root@m01 ~]#ansible backup_server -m user -a 'name=oldboy state=absent remove=yes'
8、yum_repository模块
bash
vim /etc/yum/repos.d/nginx.repo [nginx-stable] 👉 # 名称 name=nginx stable repo 👉 # 名称描述 baseurl=http://nginx.org/packages/centos/7/$basearch/ 👉 # 下载的URL地址 通过此链接下载nginx软件 gpgcheck=1 👉 # 检查包的完整性 一般可以关闭 enabled=1 👉 # 1启动此仓库 0关闭此仓库 gpgkey=https://nginx.org/keys/nginx_signing.key 👉 # 检查的md5值 #如果系统时间对不上,gpgcheck开启的话没法检查包的完整性,无法正常下载,这时候可以把gpgcheck改为0 #案例: 部署nginx的仓库 [root@m01 ~]#ansible backup -m yum_repository -a 'name=nginx description="Nginx Repo" baseurl=http://nginx.org/packages/centos/7/$basearch/ gpgcheck=no enabled=yes' #查看: [root@backup ~]#cat /etc/yum.repos.d/nginx.repo [nginx] async = 1 #异步模式,允许并行下载 baseurl = http://nginx.org/packages/centos/7/$basearch/ enabled = 1 gpgcheck = 0 name = Nginx Repo #下载测试,如果安装的是nginx是1.26,说明配置的nginx仓库正确 [root@m01 ~]#ansible backup_server -m yum -a 'name=nginx state=present' [root@backup ~]#nginx -v nginx version: nginx/1.26.1
9、systemd
bash
systemd: name: nginx state: started 👉 # 启动 stopped 👉 # 停止 restarted 👉 # 重启 reloaded 👉 # 重新加载 enable: yes 👉 # 开机自启 no 开机禁止启动 #案例1.启动nginx服务 并加入开机自启 [root@m01 ~]#ansible backup_server -m systemd -a 'name=nginx state=started enabled=yes' #案例2.重启nginx服务 [root@m01 ~]#ansible backup_server -m systemd -a 'name=nginx state=restarted' #案例3.重新加载nginx服务 [root@m01 ~]#ansible backup_server -m systemd -a 'name=nginx state=reloaded'
10、其他模块
bash
setup模块 #获取客户端所有的信息 setup 模块用于收集被管理节点(目标主机)的系统信息(Facts),这些信息以变量的形式存储,供Playbook或Ad-Hoc命令使用。 #案例1.获取IP地址 [root@m01 ~]#ansible backup -m setup -a 'filter=ansible_default_ipv4' #案例2.获取内存信息 [root@m01 ~]#ansible backup -m setup -a 'filter=ansible_memory_mb' #案例3.获取客户主机名称 [root@m01 ~]#ansible all -m setup -a 'filter=ansible_hostname' 或者 [root@m01 ~]#ansible all -m setup -a 'filter=ansible_fqdn'
bash
内容总结: 1.ping模块 ansible web01 -m ping 2.yum模块 yum: name: lrzsz 👉 # 安装软件的名称 state: 动作 present: 安装 absent: 卸载 ansible web01 -m yum -a 'name=lrzsz state=absent' ansible web01 -m yum -a 'name=lrzsz state=present' 3.copy模块 copy: src: /etc/hosts 👉 # ansible上的哪个文件 dest: /root 👉 # 存放客户端的具体路径 owner: lp 👉 # 属主 group: lp 👉 # 属组 mode: 0600 👉 # 文件权限 snible web01 -m copy -a 'src=/etc/hosts dest=/root/ onwer=lp group=lp mode=0600'

4、Ansible-playbook

bash
PlayBook即“剧本”,“兵书”之意,由以下部分组成: play:定义的是主机的角色(主角还是配角,找哪个明星) task:定义的是具体执行的任务(角色的台词和动作) playbook:由一个或多个play(角色)组成,一个play(角色)可以包含多个task(台词,动作,大腕每集拍什么) 简单理解为,使用不同的模块完成一件事情

image

1、Playboot创建文件
bash
1.书写Playboot [root@m01 ~]#cat b.yml - hosts: backup_server tasks: - name : backup touch a.txt 👉 #描述 file : 👉 #使用file模块 path: /root/a.txt 👉 #创建的路径 state: touch 👉 #动作 owner: root 👉 #属主 group: root 👉 #属组 mode: 0600 👉 #权限 - name : install nginx server yum : 👉 #使用yum模块 name: nginx state: present 2.检查语法 [root@m01 ~/ansible]#ansible-playbook --syntax-check b.yml playbook: b.yml 👉 # 这样说明没问题 3.执行ansible root@m01 ~]#ansible-playbook b.yml PLAY [backup] *********************************************************************************************** TASK [Gathering Facts] ************************************************************************************** ok: [backup] 👉 # 默认获取客户端信息 TASK [backup touch a.txt] *********************************************************************************** changed: [backup] TASK [install nginx server] ********************************************************************************* ok: [backup] PLAY RECAP ************************************************************************************************** backup : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 4.查看 [root@backup ~]#ll total 0 -rw-r--r-- 1 root root 0 Apr 28 13:53 1.log -rw------- 1 root root 0 Apr 28 15:53 a.txt
2、Playbook重构backup服务
bash
#1.配置主机清单 [root@m01 ~]#cat /etc/ansible/hosts [backup_server] backup ansible_ssh_host=172.16.1.41 #2.免秘钥,61发给41 [root@m01 ~]#ssh-copy-id 10.0.0.41 #3.写playbook [root@m01 ~/ansible]#vim backup.yml - hosts: backup_server tasks: - name: Install Rsyncd Server 👉 #1.安装rsync yum: name: rsync 🟢服务名 state: present 🟢安装 - name: configure Rsync Server 👉 #2.copy配置文件 copy: src: rsyncd.conf 🟢源文件 dest: /etc/ 🟢目标位置 - name: Create Group www 👉 #3.创建属组 group: name: www 🟢组名 gid: 666 🟢组id - name: Create user www 👉 #4.创建用户 user: name: www 🟢用户名 uid: 666 🟢用户id group: www 🟢组名 shell: /sbin/nologin 🟢解释器 create_home: false 🟢创建家目录 - name: Create pass file 👉 #5.创建密码文件 copy: content: rsync_backup:123 dest: /etc/rsync.passwd mode: 0600 🟢权限 - name: Create /backup 👉 #6.创建目录 file: path: /backup state: directory owner: www group: www - name: Start Rsync Server 👉 #7.开机自启 systemd: name: rsyncd state: started enabled: yes #4.根据内容创建数据 [root@m01 ~]#mkdir ansible [root@m01 ~]#cp rsyncd.conf ansible/ #5.检查语法 [root@m01 ~/ansible]#ansible-playbook --syntax-check backup.yml playbook: backup.yml #6.执行 [root@m01 ~/ansible]#ansible-playbook backup.yml #7.测试 [root@web01 ~]#rsync -avz /root/1.txt rsync_backup@10.0.0.41::backup Password: sending incremental file list 1.txt sent 88 bytes received 43 bytes 87.33 bytes/sec total size is 0 speedup is 0.00
3、Playbook重构NFS服务
1、安装配置NFS
bash
#1.配置主机清单 [root@m01 ~/ansible]#cat /etc/ansible/hosts [nfs_server] nfs ansible_ssh_host=172.16.1.31 #2.免秘钥,61发给31 [root@m01 ~/ansible]#ssh-copy-id 172.16.1.31 #3.写playbook [root@m01 ~/ansible]#cat nfs.yml - hosts: nfs tasks: - name: Install nfs Server 👉 #1.安装nfs服务 yum: name: nfs-utils state: present - name: Configure NFS Server 👉 #2.拷贝配置文件 copy: src: exports dest: /etc/ - name: Crete Group www 👉 #3.创建属组 group: name: www gid: 666 - name: Create user www 👉 #4.创建用户 user: name: www uid: 666 group: www shell: /sbin/nologin create_home: false - name: Create /data/wp 👉 #5.创建路径 file: path: /data/wp state: directory owner: www group: www - name: Start NFS Server 👉 #6.开机自启动 systemd: name: nfs state: started enabled: yes #4.根据内容创建数据 [root@m01 ~/ansible]#cat exports /data/wp 172.16.1.0/24(rw,sync,all_squash,anonuid=666,anongid=666) #5.语法检测 [root@m01 ~/ansible]#ansible-playbook --syntax-check nfs.yml #6.执行playbook [root@m01 ~/ansible]#ansible-playbook nfs.yml PLAY [nfs] *********************************************************************************************************************************************************************** TASK [Gathering Facts] *********************************************************************************************************************************************************** ok: [nfs] TASK [Install nfs Server] ******************************************************************************************************************************************************** ok: [nfs] TASK [Configure NFS Server] ****************************************************************************************************************************************************** ok: [nfs] TASK [Crete Group www] *********************************************************************************************************************************************************** ok: [nfs] TASK [Create user www] *********************************************************************************************************************************************************** changed: [nfs] TASK [Create /data/wp] *********************************************************************************************************************************************************** changed: [nfs] TASK [Start NFS Server] ********************************************************************************************************************************************************** changed: [nfs] PLAY RECAP *********************************************************************************************************************************************************************** nfs : ok=7 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 #7.测试 [root@web01 ~]#showmount -e 172.16.1.31 Export list for 172.16.1.31: /data/wp 172.16.1.0/24
2、挂载方式
bash
#客户端挂载playbook mount: src: 挂载的源 path: 挂在到本地的哪个目录 state: present 👉 # 只写入到开机自动挂载 fstab中 unmounted 👉 # 只卸载nfs 不删除fstab中自动挂载 mounted 👉 # 挂载nfs 并且写入到fstab absent 👉 # 卸载nfs 并且删除fstab中开机自动挂载 #案例1.只写入开机自动挂载fstab present #1.写playbook [root@m01 ~/ansible]#cat m.yml - hosts: web_server tasks: - name: mount nfs /code/wp mount: src: 172.16.1.31:/data/wp 👉 #挂载的源是172.16.1.31:/data/wp path: /mnt 👉 #挂在到本地的/mnt目录 fstype: nfs 👉 #挂载类型 state: present 👉 #只写入到开机自动挂载 fstab中 #2.语法检测 [root@m01 ~/ansible]#ansible-playbook --syntax-check m.yml #3.执行 [root@m01 ~/ansible]#ansible-playbook m.yml #4.查看 [root@web01 ~]#cat /etc/fstab 172.16.1.31:/data/wp /mnt nfs defaults 0 0 ✦•············································································································•✦ 分割线 ✦•············································································································•✦ #案例2.挂载并写入到开机自动挂载fstab mounted #1.写playbook [root@m01 ~/ansible]#cat m.yml - hosts: web_server tasks: - name: mount nfs /code/wp mount: src: 172.16.1.31:/data/wp path: /mnt fstype: nfs state: mounted 👉 #state从present修改为mounted #2.执行 [root@m01 ~/ansible]#ansible-playbook m.yml #3.web端测试 [root@web01 ~]#cat /etc/fstab /dev/sdb2 /data xfs defaults 0 0 172.16.1.31:/data/wp /mnt nfs defaults 0 0 [root@web01 ~]#df -h tmpfs 95M 0 95M 0% /run/user/0 172.16.1.31:/data/wp 47G 3.8G 44G 9% /mnt ✦•············································································································•✦ 分割线 ✦•············································································································•✦#案例3.只卸载不删除fstab中的自动挂载 unmounted #1.写playbook [root@m01 ~/ansible]#cat m.yml - hosts: web_server tasks: - name: mount nfs /code/wp mount: src: 172.16.1.31:/data/wp path: /mnt fstype: nfs state: unmounted #2.执行 [root@m01 ~/ansible]#ansible-playbook m.yml #3.df -h没有 [root@web01 ~]#df -h ✦•············································································································•✦ 分割线 ✦•············································································································•✦#案例4.卸载nfs并且删除开机自动挂载 absent #1.写playbook [root@m01 ~/ansible]#cat m.yml - hosts: web_server tasks: - name: mount nfs /code/wp mount: src: 172.16.1.31:/data/wp path: /mnt fstype: nfs state: absent #2.执行 [root@m01 ~/ansible]#ansible-playbook m.yml
4、Playbook重构Nginx服务
bash
#1.配置主机清单 [root@m01 ~/ansible]#cat /etc/ansible/hosts [nfs_server] nfs ansible_ssh_host=172.16.1.31 [backup_server] backup ansible_ssh_host=172.16.1.41 web02 ansible_ssh_host=172.16.1.8 [db_server] 172.16.1.51 #2.免秘钥 [root@m01 ~]#ssh-copy-id 172.16.1.8 #3.书写playbook,段落同一缩进,ctrl+v进入块模式,选中要缩进的,大写的I,两下空格,ESC [root@m01 ~/ansible]#cat ng.yml - hosts: web02 tasks: - name: Configure Nginx YUM Repo 👉 # 1.安装Nginx源 yum_repository: name: nginx 👉 # 仓库名 description: Nginx YUM repo 👉 # 描述 baseurl: http://nginx.org/packages/centos/7/$basearch/ 👉 # 下载的URL地址 通过此链接下载nginx软件 gpgcheck: no 👉 # 检查包的完整性 no关闭 enabled: yes 👉 # 启动此仓库 - name: Install Nginx Server 👉 # 2.下载nginx yum: name: nginx state: present - name: Configure Nginx Server 👉 # 3.拷贝文件 copy: src: nginx.conf dest: /etc/nginx/ - name: Start Nginx Server 👉 # 4.启动nginx并设置为开机自启 systemd: name: nginx state: started enabled: yes #4.根据内容创建数据 [root@web01 ~]#scp /etc/nginx/nginx.conf 10.0.0.61:/root/ansible/ root@10.0.0.61s password: nginx.conf 100% 694 33.7KB/s 00:00 [root@web01 ~]# #5.语法检测 [root@m01 ~/ansible]#ansible-playbook --syntax-check nfs.yml #6.执行playbook [root@m01 ~/ansible]#ansible-playbook ng.yml #7.检查版本号及是否启动80端口 [root@web02 ~]#nginx -v nginx version: nginx/1.26.1 [root@web02 ~]#netstat -tnulp Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 5803/nginx: maste
5、Playbook重构PHP服务
bash
WEB02测试 #1.配置主机清单 [root@m01 ~/ansible]#cat /etc/ansible/hosts [nfs_server] nfs ansible_ssh_host=172.16.1.31 [backup_server] backup ansible_ssh_host=172.16.1.41 web02 ansible_ssh_host=172.16.1.8 [db_server] 172.16.1.51 #2.免秘钥 [root@m01 ~]#ssh-copy-id 172.16.1.8 #3.书写Playbook [root@m01 ~/ansible]#cat php.yml - hosts: web02 tasks: - name: Install PHP Server 👉 # 1.安装PHP yum: name: - php - php-bcmath - php-cli - php-common - php-devel - php-embedded - php-fpm - php-gd - php-intl - php-mbstring - php-mysqlnd - php-opcache - php-pdo - php-process - php-xml - php-json state: present - name: Configure PHP Server 👉 # 2.拷贝PHP配置文件www.conf到/etc/php-fpm.d/ copy: src: www.conf dest: /etc/php-fpm.d/ - name: Start PHP Server 👉 # 3.启动PHP并设置为开机自启 systemd: name: php-fpm state: started enabled: yes #4.根据内容创建数据 [root@web02 ~]#echo php php-bcmath php-cli php-common php-devel php-embedded php-fpm php-gd php-intl php-mbstring php-mysqlnd php-opcache php-pdo php-process php-xml php-json|xargs -n1|awk '{print"- " $1}' [root@web01 ~]#scp /etc/php-fpm.d/www.conf 10.0.0.61:/root/ansible/ www.conf #5.语法检测 [root@m01 ~/ansible]#ansible-playbook --syntax-check nfs.yml #6.执行playbook [root@m01 ~/ansible]#ansible-playbook php.yml #7.测试php服务是否启动 [root@web02 ~]#netstat -tnulp Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 127.0.0.1:9000 0.0.0.0:* LISTEN 58737/php-fpm: mast
6、Playbook重构Lsyncd服务
bash
WEB02测试 #1.配置主机清单 [root@m01 ~/ansible]#cat /etc/ansible/hosts [nfs_server] nfs ansible_ssh_host=172.16.1.31 [backup_server] backup ansible_ssh_host=172.16.1.41 web02 ansible_ssh_host=172.16.1.8 [db_server] 172.16.1.51 #2.免秘钥 [root@m01 ~]#ssh-copy-id 172.16.1.8 #3.书写Playbook [root@m01 ~/ansible]#cat lsync.yml - hosts: nfs tasks: - name: Install lsync Server 👉 # 1.安装lsync Server yum: name: lsyncd state: present - name: Configure lsync Server 👉 # 2.拷贝配置文化 copy: src: lsyncd.conf dest: /etc/ - name: Creta pass file 👉 # 3.设置密码文件 copy: content: 123 dest: /etc/rsyncd.pwd mode: 600 - name : Start Rsync Server 👉 # 4.开机自启动 systemd: name: rsyncd state: started enabled: yes - hosts : backup tasks: - name: Create /wp 👉 # 5.创建目录 file: path: /wp state: directory owner: www group: www #4.创建数据 #lsyncd.conf [root@m01 ~/ansible]#cat lsyncd.conf settings { logfile = "/var/log/lsyncd/lsyncd.log", statusFile ="/var/log/lsyncd/lsyncd.status", maxProcesses = 2, nodaemon = false, } sync { default.rsync, source = "/data/wp", target = "rsync_backup@10.0.0.41::wp", delete = true, delay = 1, rsync = { binary = "/usr/bin/rsync", password_file = "/etc/rsyncd.pwd", archive = true, compress = true, } } #rsyncd.conf [root@backup /wp]#cat /etc/rsyncd.conf uid = www gid = www port = 873 fake super = yes use chroot = no max connections = 200 timeout = 600 ignore errors read only = false list = false auth users = rsync_backup secrets file = /etc/rsync.passwd log file = /var/log/rsyncd.log ##################################### [backup] comment = welcome to oldboyedu backup! path = /backup [wp] path=/wp #5.语法检测 [root@m01 ~/ansible]#ansible-playbook --syntax-check lsync.yml #6.执行playbook [root@m01 ~/ansible]#ansible-playbook lsync.yml
7、Playbook重构Mariadb服务器
bash
#1.配置主机清单 [root@m01 ~/ansible]#cat /etc/ansible/hosts [nfs_server] nfs ansible_ssh_host=172.16.1.31 [backup_server] backup ansible_ssh_host=172.16.1.41 web02 ansible_ssh_host=172.16.1.8 [db_server] 172.16.1.51 #2.免秘钥 [root@m01 ~]#ssh-copy-id 172.16.1.8 #3.书写playbook [root@m01 ~/ansible]#cat mariadb.yml - hosts: db_server tasks: - name: Install mariadb Server 👉 # 1.安装mariadb yum: name: mariadb-server state: present - name: Start Mariadb Servermariadb 👉 # 2.启动并设置为开机自启动 systemd: name: mariadb state: started enabled: yes - name: Mariadb Password 👉 # 3.设置root command: mysqladmin -u root password 'lzy123.com' become: yes #4.语法检测 [root@m01 ~/ansible]#ansible-playbook --syntax-check mariadb.yml #5.执行playbook [root@m01 ~/ansible]#ansible-playbook mariadb.yml #6.检查服务是否已开启 [root@db01 ~]#systemctl status mariadb.service ● mariadb.service - MariaDB 10.3.39 database server Loaded: loaded (/usr/lib/systemd/system/mariadb.service; enabled; vendor preset: disabled) Active: active (running) since Tue 2025-04-29 07:28:44 CST; 1min 24s ago #检查80端口 [root@db01 ~]#netstat -tnulp Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1078/sshd: /usr/sbi tcp6 0 0 :::22 :::* LISTEN 1078/sshd: /usr/sbi tcp6 0 0 :::3306 :::* LISTEN 5206/mysqld
8、Playbook重构wp业务
bash
#1.配置主机清单 [root@m01 ~/ansible]#cat /etc/ansible/hosts [nfs_server] nfs ansible_ssh_host=172.16.1.31 [backup_server] backup ansible_ssh_host=172.16.1.41 web02 ansible_ssh_host=172.16.1.8 [db_server] 172.16.1.51 #2.免秘钥 [root@m01 ~]#ssh-copy-id 172.16.1.8 #3.书写playbook [root@m01 ~/ansible]#cat wp.yaml - hosts: web02 tasks: - name: Copy wp.conf copy: src: wp.conf dest: /etc/nginx/conf.d/ - name: Create /code/wp file: path: /code/wp state: directory owner: nginx group: nginx mode: 0755 - name: Copy wp.zip copy: src: wordpress-6.7.2-zh_CN.zip dest: /code/wp/ - name: Unzip unarchive: src: /code/wp/wordpress-6.7.2-zh_CN.zip dest: /code/wp/ remote_src: yes # 指定使用目标主机上的文件 owner: nginx # 设置解压后文件属主 group: nginx # 设置解压后文件属组 #4.检查语法 [root@m01 ~/ansible]#ansible-playbook --syntax-check wp.yaml playbook: wp.yaml #5.创建数据 [root@web01 /mnt]#scp /etc/nginx/conf.d/ /etc/nginx/conf.d/admin.conf /etc/nginx/conf.d/m.conf /etc/nginx/conf.d/php-fpm.conf /etc/nginx/conf.d/re.conf /etc/nginx/conf.d/xbw.conf /etc/nginx/conf.d/ceshi.conf /etc/nginx/conf.d/old.conf /etc/nginx/conf.d/r.conf /etc/nginx/conf.d/wp.conf [root@web01 /mnt]#scp /etc/nginx/conf.d/wp.conf 10.0.0.61:/root/ Authorized users only. All activities may be monitored and reported. root@10.0.0.61s password: wp.conf #6.执行playbook #7.host解析

5、Ansible高级模块

1、cron模块
bash
#案例1.创建定时任务每间隔5分钟进行时间同步 [root@m01 ~/ansible]#cat cr.yml - hosts: web02 tasks: - name: ntpdate cron: name: "时间同步" minute: '*/5' job: "ntpdate ntp1.aliyun.com &>/dev/null" state: present [root@web02 ~]#crontab -l #Ansible: 时间同步 */5 * * * * ntpdate ntp1.aliyun.com &>/dev/null #案例2.删除定时任务 [root@m01 ~/ansible]#cat cr.yml - hosts: web02 tasks: - name: ntpdate cron: name: "时间同步" minute: '*/5' job: "ntpdate ntp1.aliyun.com &>/dev/null" state: absent #案例3.配置两个定时任务 [root@m01 ~/ansible]#cat cr.yml - hosts: web02 tasks: - name: ntpdate cron: name: "时间同步" minute: '*/5' job: "ntpdate ntp1.aliyun.com &>/dev/null" state: present - name: print task cron: name: "print oldboy" minute: '*' job: "echo oldboy >> /root/a.txt" state: present #案例4.使用字典循环 [root@m01 ~/ansible]#cat cr.yml - hosts: web02 tasks: - name: ntpdate cron: name: "{{ item.name }}" minute: "{{ item.m }}" job: "{{ item.j }}" state: "{{ item.s }}" loop: - { name: ntpdate,m: '*/5',j: "ntpdate ntp1.aliyun.com &>/dev/null",s: present } - { name: print oldboy,m: '*',j: "echo oldboy >> /root/a.txt",s: present } #执行 [root@m01 ~/ansible]#ansible-playbook cr.yml ‍```bash #案例1.创建定时任务每间隔5分钟进行时间同步 [root@m01 ~/ansible]#cat cr.yml - hosts: web02 tasks: - name: ntpdate cron: name: "时间同步" minute: '*/5' job: "ntpdate ntp1.aliyun.com &>/dev/null" state: present [root@web02 ~]#crontab -l #Ansible: 时间同步 */5 * * * * ntpdate ntp1.aliyun.com &>/dev/null #案例2.删除定时任务 [root@m01 ~/ansible]#cat cr.yml - hosts: web02 tasks: - name: ntpdate cron: name: "时间同步" minute: '*/5' job: "ntpdate ntp1.aliyun.com &>/dev/null" state: absent #案例3.配置两个定时任务 [root@m01 ~/ansible]#cat cr.yml - hosts: web02 tasks: - name: ntpdate cron: name: "时间同步" minute: '*/5' job: "ntpdate ntp1.aliyun.com &>/dev/null" state: present - name: print task cron: name: "print oldboy" minute: '*' job: "echo oldboy >> /root/a.txt" state: present #案例4.使用字典循环 [root@m01 ~/ansible]#cat cr.yml - hosts: web02 tasks: - name: ntpdate cron: name: "{{ item.name }}" minute: "{{ item.m }}" job: "{{ item.j }}" state: "{{ item.s }}" loop: - { name: ntpdate,m: '*/5',j: "ntpdate ntp1.aliyun.com &>/dev/null",s: present } - { name: print oldboy,m: '*',j: "echo oldboy >> /root/a.txt",s: present } #执行 [root@m01 ~/ansible]#ansible-playbook cr.yml ##查看 #Ansible: ntpdate */5 * * * * ntpdate ntp1.aliyun.com &>/dev/null #Ansible: print oldboy * * * * * echo oldboy >> /root/a.txt
2、Ansible-jinja2模版
bash
#Jinja2 是用于动态生成配置文件的核心模板引擎,用 {{ }} 包裹变量,直接渲染值: #1.编写配置文件 [root@m01 ~/ansible]#cat exports.j2 {{ dir }} {{ ip }}(rw,sync,all_squash,anonuid=666,anongid=666) #2.编写playbook [root@m01 ~/ansible]#cat n.yml - hosts: nfs vars: # 定义变量 ip: 172.16.1.0/24 # ip dir: /data/ds # dir tasks: - name: Install NFS Server yum: name: nfs-utils state: present - name: Configure NFS Server template: src: exports.j2 dest: /etc/exports notify: Restart nfs Server - name : Create {{ dir }} file: path: "{{ dir }}" state: directory owner: www group: www - name: Start NFS Server systemd: name: nfs state: started enabled: yes handlers: - name: Restart nfs Server systemd: name: nfs state: restarted #执行 [root@m01 ~/ansible]#ansible-playbook n.yml #nfs查看 [root@nfs ~]#cat /etc/exports /data/ds 172.16.1.0/24(rw,sync,all_squash,anonuid=666,anongid=666)
3、unarchive解压模块
bash
#案例1.将ansible服务器上的all.tar.gz解压到web02 [root@m01 ~/ansible]#tar zcvf ./all.tar.gz /etc/hosts [root@m01 ~/ansible]#tar tf all.tar.gz etc/hosts [root@m01 ~/ansible]#cat un.yml - hosts: web02 tasks: - name: unarchive all.tar.gz to web02 unarchive: src: all.tar.gz dest: /root/ #案例2.解压web02服务器上的all.tar.gz 到web02的/root下 [root@m01 ~/ansible]#cat un.yml - hosts: web02 tasks: - name: unarchive all.tar.gz to web02 unarchive: src: all.tar.gz dest: /root/ remote_src: yes #yes表示远端文件解压到远端 [root@web02 ~]#ll total 4 -rw-r--r-- 1 root root 912 Apr 30 11:26 all.tar.gz drwxr-xr-x 2 root root 20 Apr 30 11:28 etc [root@web02 ~]#ll etc/ total 4 -rw-r--r-- 1 root root 1942 Apr 29 11:43 passwd #案例3.creates判断后面的路径如果存在则不解压,如果路径不存在则解压 [root@m01 ~/ansible]#cat un.yml - hosts: web02 tasks: - name: unarchive all.tar.gz to web02 unarchive: src: all.tar.gz dest: /root/ creates: etc #判断是否存在 #案例4.解压后需要递归修改目录及目录下属主属组 [root@m01 ~/ansible]#cat un.yml - hosts: web02 tasks: - name: unarchive all.tar.gz to web02 unarchive: src: all.tar.gz dest: /root/ owner: www group: www creates: etc

image-20250430114654325

image-20250430115344270

4、Ansible-handlers监控
bash
#案例1.配置文件变化notify触发通知handlers进行重启动作 [root@m01 ~/ansible]#cat had.yml - hosts: web02 tasks: - name: Install Nginx Server yum: name: nginx state: present - name: Configure Nginx Server copy: src: nginx.conf dest: /etc/nginx/nginx.conf notify: Restart Nginx Server #监控这个模块,如果nginx.conf发生变化,那么执行下面的handlers模块 - name: Create www Group group: name: www gid: 666 - name: Create www User user: name: www uid: 666 group: www create_home: false shell: /sbin/nologin - name: Start nginx Server systemd: name: nginx state: started enabled: yes handlers: - name: Restart Nginx Server #上面配置文件修改,那么这里就执行模块 systemd: name: nginx state: restarted #案例2.修改本机nginx.conf的nginx启动用户为www,然后执行 [root@m01 ~/ansible]#ansible-playbook had.yml [root@m01 ~/ansible]#ansible-playbook had.yml PLAY [web02] ********************************************************************************************************************************************************************* TASK [Gathering Facts] *********************************************************************************************************************************************************** ok: [web02] TASK [Install Nginx Server] ****************************************************************************************************************************************************** ok: [web02] TASK [Configure Nginx Server] **************************************************************************************************************************************************** changed: [web02] #执行 TASK [Create www Group] ********************************************************************************************************************************************************** ok: [web02] TASK [Create www User] *********************************************************************************************************************************************************** ok: [web02] TASK [Start nginx Server] ******************************************************************************************************************************************************** ok: [web02] RUNNING HANDLER [Restart Nginx Server] ******************************************************************************************************************************************* changed: [web02] #执行 #测试发现nginx 的启动用户成了www [root@web02 ~]#ps aux|grep nginx nginx 58738 0.0 1.2 235844 12420 ? S Apr29 0:00 php-fpm: pool www nginx 58739 0.0 1.2 235844 12420 ? S Apr29 0:00 php-fpm: pool www nginx 58740 0.0 1.2 235844 12420 ? S Apr29 0:00 php-fpm: pool www nginx 58741 0.0 1.2 235844 12420 ? S Apr29 0:00 php-fpm: pool www nginx 58742 0.0 1.2 235844 12420 ? S Apr29 0:00 php-fpm: pool www root 121286 0.0 0.0 22504 908 ? Ss 13:33 0:00 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf www 121287 0.0 0.4 33920 4244 ? S 13:33 0:00 nginx: worker process root 121335 0.0 0.0 213272 888 pts/0 S+ 13:33 0:00 grep --color=auto nginx #案例3.配置文件变化并且配置文件检查正确、然后notify触发通知handlers进行重启动作, [root@m01 ~/ansible]#cat had.yml - hosts: web02 tasks: - name: Install Nginx Server yum: name: nginx state: present - name: Configure Nginx Server copy: src: nginx.conf dest: /etc/nginx/nginx.conf notify: Restart Nginx Server - name: check nginx configure command: nginx -t #执行命令 register: ng_re #将上面执行的结果赋值给ls_re(自定义)这个变量 ignore_errors: yes #忽略错误继续往下执行 - name: Create www Group group: name: www gid: 666 - name: Create www User user: name: www uid: 666 group: www create_home: false shell: /sbin/nologin - name: Start nginx Server systemd: name: nginx state: started enabled: yes handlers: - name: Restart Nginx Server systemd: name: nginx state: restarted when: ng_re.rc is search "0" #如果ng_re.rc匹配到0,也就是没出错,才会重启nginx
5、Ansible强制执行handlers
bash
[root@m01 ~/ansible]#cat had.yml - hosts: web02 force_handlers: yes # 当notify触发时候,后面的task执行失败,也会强制执行最后的handlers任务 tasks: - name: Install Nginx Server yum: name: nginx state: present - name: Configure Nginx Server copy: src: nginx.conf dest: /etc/nginx/nginx.conf notify: Restart Nginx Server - name: check nginx configure command: nginx -t register: ng_re ignore_errors: yes - name: Create www Group group: name: www gid: 666 tags: - c_u - ab - name: Create www User user: name: www uid: 666 group: wwww # 故意出错 wwww create_home: false shell: /sbin/nologin tags: c_u - name: Start nginx Server systemd: name: nginx state: started enabled: yes handlers: - name: Restart Nginx Server systemd: name: nginx state: restarted when: ng_re.rc is search "0" #了解 [root@m01 ~/ansible]#cat wh.yml - hosts: backup tasks: - name: ls command: ls -l changed_when: false # 执行的结果修改为绿色
6、Ansible-tag标签
bash
#作用: 测试某个或者n个task时使用。只单独运行某一个task。 [root@m01 ~/ansible]#cat had.yml - hosts: web02 tasks: - name: Install Nginx Server yum: name: nginx state: present - name: Configure Nginx Server copy: src: nginx.conf dest: /etc/nginx/nginx.conf notify: Restart Nginx Server - name: check nginx configure command: nginx -t register: ng_re ignore_errors: yes - name: Create www Group group: name: www gid: 666 tags: - c_u - ab - name: Create www User user: name: www uid: 666 group: www create_home: false shell: /sbin/nologin tags: c_u - name: Start nginx Server systemd: name: nginx state: started enabled: yes handlers: - name: Restart Nginx Server systemd: name: nginx state: restarted when: ng_re.rc is search "0" #案例1.调用执行c_u标签 [root@m01 ~/ansible]#ansible-playbook had.yml -t c_u #案例2.调用执行ab标签 [root@m01 ~/ansible]#ansible-playbook had.yml -t ab #案例3.跳过某个标签不执行 使用较少 [root@m01 ~/ansible]#ansible-playbook had.yml --skip-tags c_u #案例4.列出所有的标签tag [root@m01 ~/ansible]#ansible-playbook had.yml --list-tags playbook: had.yml play #1 (web02): web02 TAGS: [] TASK TAGS: [ab, c_u]
7、Ansible-文件调用
bash
#去掉nfs.yml文件里的hosts跟tasks [root@m01 ~/ansible]#cat nfs.yml - name: Install nfs Server yum: name: nfs-utils state: present - name: Configure NFS Server copy: src: exports dest: /etc/ - name: Crete Group www group: name: www gid: 666 - name: Create user www user: name: www uid: 666 group: www shell: /sbin/nologin create_home: false - name: Create /data/wp file: path: /data/wp state: directory owner: www group: www - name: Start NFS Server systemd: name: nfs state: started enabled: yes #去掉backup.yml文件里的hosts跟tasks [root@m01 ~/ansible]#cat backup.yml - name: Install Rsyncd Server yum: name: rsync state: present - name: configure Rsync Server copy: src: rsyncd.conf dest: /etc/ - name: Create Group www group: name: www gid: 666 - name: Create user www user: name: www uid: 666 group: www shell: /sbin/nologin create_home: false - name: Create pass file copy: content: rsync_backup:123 dest: /etc/rsync.passwd mode: 0600 - name: Create /backup file: path: /backup state: directory owner: www group: www - name: Start RSYNC Server systemd: name: rsyncd state: started enabled: yes #3.整合tasks配置文件到all.yml [root@m01 ~/ansible]#cat all.yml - hosts: all tasks: - include_tasks: backup.yml #把backup.yml引用进来 when: ansible_hostname == "backup" #做判断,backup.yml里面的模块只在backup主机运行 - include_tasks: nfs.yml #把nfs.yml引用进来 when: ansible_hostname == "nfs" #做判断,nfs.yml里面的模块只在nfs主机运行
8、循环
bash
#案例1.创建a.txt 1.txt两个文件 [root@m01 ~/ansible]#cat t.yml - hosts: backup tasks: - name: touch a.txt 1.txt file: path: /root/{{ item }} #item是固定的写法 state: touch loop: - a.txt #item先取a.txt - 1.txt #item再取1.txt #案例2.同时在root下创建aa.txt 在/opt创建11.txt [root@m01 ~/ansible]#cat t.yml - hosts: backup tasks: - name: touch a.txt 1.txt file: path: "{{ item }}" state: touch loop: - /root/aa.txt - /opt/11.txt

1、字典循环
bash
#案例3.字典循环 #在/root/aa.txt 属主 www 属组 www 权限600 #在/opt/11.txt 属主 root属组 root 权限777 #注意最后的权限需要加引号 [root@m01 ~/ansible]#cat t.yml - hosts: backup tasks: - name: touch a.txt 1.txt file: path: "{{ item.path }}" #path: /root/aa.txt、path: /opt/11.txt owner: "{{ item.owner }}" group: "{{ item.group }}" mode: "{{ item.mode }}" state: touch loop: - { path: /root/aa.txt,owner: www,group: www,mode: '0600' } - { path: /opt/11.txt,owner: root,group: root,mode: '0777' } #案例1.一次启动多个服务 [root@m01 ~/ansible]#cat sys.yml - hosts: web02 tasks: - name: Start Nginx PHP Server systemd: name: "{{ item }}" state: started enabled: yes loop: - nginx - php-fpm # 案例2. 一次创建多个用户 普通账号: oldboy uid777 gid 777 虚拟账号: www uid 666 gid 666 不创建家 不允许登录 [root@m01 ~/ansible]#cat u.yml - hosts: backup tasks: - name: Create Group group: name: "{{ item.name }}" gid: "{{ item.gid }}" loop: - { name: www,gid: '666' } - { name: oldboy,gid: '777' } - name: Create User user: name: "{{ item.name }}" uid: "{{ item.uid }}" group: "{{ item.group }}" create_home: "{{ item.home }}" shell: "{{ item.shell }}" loop: - { name: www,uid: 666,group: www,home: false,shell: /sbin/nologin } - { name: oldboy,uid: 777,group: oldboy,home: true,shell: /bin/bash } [root@m01 ~/ansible]#ansible-playbook --syntax-check vars.yml #案例3.一次拷贝多个文件,将本机拷贝到41 需求:将rsyncd.conf 拷贝到backup的/opt/目录 属主 属组 root 权限为644 将rsync.passwd拷贝到/tmp/目录 属主属组为root 权限为600 [root@m01 ~/ansible]#cat c.yml - hosts: backup tasks: - name: Copy file to backup copy: src: "{{ item.src }}" dest: "{{ item.dest }}" owner: "{{ item.owner }}" group: "{{ item.group }}" mode: "{{ item.mode }}" loop: - { src: rsyncd.conf,dest: /opt/,owner: root,group: root,mode: '0644' } - { src: rsync.passwd,dest: /tmp/,owner: www,group: www,mode: '0600' }

6、Ansible变量

1、在play中定义变量
bash
#最直观,最常用的。如果定义多个变量和调用多个变量都要换行 #方法1 一个变量对应一个值 [root@m01 ~/ansible]#cat vars.yml - hosts: backup vars: pk: wget # 定义变量将wget赋值给pk tasks: - name: Install wget pk yum: name: "{{ pk }}" # 调用变量使用 "{{}}" state: present #方法2 多个变量对应多个值 [root@m01 ~/ansible]#cat vars.yml - hosts: backup vars: - pk1: wget # 定义变量pk1 - pk2: lrzsz # 定义变量pk2 tasks: - name: Install wget pk yum: name: - "{{ pk1 }}" # 调用pk1 - "{{ pk2 }}" # 调用pk1 state: absent #方法3 1个变量对应多个值 [root@m01 ~/ansible]#cat vars.yml - hosts: backup vars: package: #定义列表 - lrzsz #列表下的值1 - wget #列表下的值2 tasks: - name: Install wget pk yum: name: "{{ package }}" #调用列表 state: present #2.如果变量是路径则不需要引号 [root@m01 ~/ansible]#cat vars.yml - hosts: backup vars: - host: backup - ip: 10.0.0.41 tasks: - name: create dir backup_10.0.0.41 file: path: /root/{{ host }}_{{ ip }} state: directory
2、在vars_file中定义变量
bash
#1.把变量定义在文件中 [root@m01 ~/ansible]#cat var/v1.yml pack1: wget pack2: lrzsz #2.在play中引用变量文件,并调用变量 [root@m01 ~/ansible]#cat vars.yml - hosts: backup vars_files: var/v1.yml # 引用变量的文件 tasks: - name: Create yum: name: - "{{ pack1 }}" - "{{ pack2 }}" state: absent #调用多个vars文件 [root@m01 ~/ansible]#cat v1.yml pack1: wget pack2: lrzsz [root@m01 ~/ansible]#cat v2.yml host: backup ip: 172.16.1.41 [root@m01 ~/ansible]#cat vars.yml - hosts: backup vars_files: - v1.yml - v2.yml tasks: - name: create dir backup_10.0.0.41 yum: name: - "{{ pack1 }}" - "{{ pack2 }}" state: absent - name: create dir backup_172.16.1.41 file: path: /root/{{ host }}_{{ ip }} state: directory
3、调用ansible的内置变量
bash
[root@m01 ~/ansible]#cat vars.yml - hosts: backup tasks: - name: create dir file: path: /root/{{ ansible_hostname }}_{{ ansible_default_ipv4.address }} #内置变量不用定义,直接用 state: directory [root@m01 ~/ansible]#ansible-playbook --syntax-check mariadb.yml
4、在主机清单中定义
bash
# 不建议使用此定义方法,因为不规范,主机清单就是主机清单 [root@m01 ~/ansible]#cat /etc/ansible/hosts web01 ansible_ssh_host=172.16.1.7 web02 ansible_ssh_host=172.16.1.8 [nfs_server] nfs ansible_ssh_host=172.16.1.31 [backup_server] # 1.新增[bk_server]组 backup ansible_ssh_host=172.16.1.41 [backup_server:vars] # 2.给bk_server这个组定义变量,(必须在组定义之后) pa1=wget # 变量 pa2=lrzsz # 变量 # 调用变量 [root@m01 ~/ansible]#cat vars.yml - hosts: backup tasks: - name: Install yum: name: - "{{ pa1 }}" - "{{ pa2 }}" state: present
5、在文件中定义变量
bash
#之前的几种变量定义都不是很好用,比较好用的是在Ansible项目目录下创建两个变量目录: host_vars # 目录固定写法,用于定义单个主机的变量 ├── web01.yml # 对应 web01 主机的变量 └── db01.yml # 对应 db01 主机的变量 group_vars # 目录固定写法,用于定义主机组的变量 ├── all.yml # 所有主机通用变量 ├── web_servers.yml # web_servers 组变量 └── db_servers.yml # db_servers 组变量 #案例1.给WEB01单独定义变量 [root@m01 ~/ansible]#mkdir host_vars # 目录固定写法,不能修改 [root@m01 ~/ansible]#cat host_vars/backup # backup的文件名要在主机清单中定义成组变量 pkpk: wget [root@m01 ~/ansible]#cat vars.yml - hosts: backup #host_vars目录下的backup文件,对应主机清单的backup主机名称 tasks: - name: Install yum: name: - "{{ pkpk }}" #变量值写在host_vars目录下的backup文件里面 state: absent #主机清单 [root@m01 ~/ansible]#cat /etc/ansible/hosts [backup_server] backup ansible_ssh_host=172.16.1.41 #案例2.给组定义变量,因为不是全局,别的组调用这个变量是报错的 [root@m01 ~/ansible]#mkdir group_vars [root@m01 ~/ansible]#cat group_vars/backup_server # 目录固定写法,不能修改 ttt: wget [root@m01 ~/ansible]#cat vars.yml - hosts: backup_server #设置为主机清单组名 tasks: - name: Install yum: name: - "{{ ttt }}" #为wget命令 state: present #安装 #主机清单 [root@m01 ~/ansible]#cat /etc/ansible/hosts [backup_server] backup ansible_ssh_host=172.16.1.41 db ansible_ssh_host=172.16.1.51 #执行,两台全执行 [root@m01 ~/ansible]#ansible-playbook vars.yml PLAY RECAP *********************************************************************************************************************************************************************** backup : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 db : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 #案例3.给all(所有的主机)定义好变量,wget命令在所有模块中都可以调用,前提是hosts要填入主机模块名称 [root@m01 ~/ansible]#cat group_vars/all pkck: wget [root@m01 ~/ansible]#cat vars.yml - hosts: backup tasks: - name: install lrzsz wget yum: name: "{{ pkck }}" state: present
6、变量注册register
bash
当absible的模块运行之后,其实都会返回一些result结果,就像执行脚本,我们有的时候需要脚本给我们一些return返回值,才知道上一步是否 可以成功,但是默认没有返回值,所以,需要把这些返回值存储到变量中,这样就可以调用对应的变量名获取这些result,这种模块的返回值,写入 到变量中的方法称为变量注册 #1.需要ls -l 的返回结果 [root@m01 ~/ansible]#cat vars.yml - hosts: backup tasks: - name: register env command: ls -l /root/ # 执行命令 register: ls_re # 将上面执行的结果赋值给ls_re(自定义)这个变量 - name: print ls_re env debug: msg: "{{ ls_re.stdout_lines }}" # 通过debug模块msg输出ls_re变量中的内容 #执行,这是没加.stdout_lines的执行结果 [root@m01 ~/ansible]#ansible-playbook vars.yml PLAY [backup] ******************************************************************************************************************************************************************** TASK [Gathering Facts] *********************************************************************************************************************************************************** ok: [backup] TASK [register env] ************************************************************************************************************************************************************** changed: [backup] TASK [print ls_re env] *********************************************************************************************************************************************************** ok: [backup] => { "msg": { "changed": true, "cmd": [ "ls", "-l", "/root/" ], "delta": "0:00:00.049672", "end": "2025-04-29 17:54:50.534965", "failed": false, "msg": "", "rc": 0, #msg返回0是正确的 "start": "2025-04-29 17:54:50.485293", "stderr": "", "stderr_lines": [], "stdout": "total 0\ndrwxr-xr-x 2 root root 6 Apr 29 16:16 backup_10.0.0.41", "stdout_lines": [ "total 0", "drwxr-xr-x 2 root root 6 Apr 29 16:16 backup_10.0.0.41" ] } } PLAY RECAP *********************************************************************************************************************************************************************** backup : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 #这是加了.stdout_lines的执行结果 TASK [print ls_re env] *********************************************************************************************************************************************************** ok: [backup] => { "msg": [ "total 0", "drwxr-xr-x 2 root root 6 Apr 29 16:16 backup_10.0.0.41" ] } #2.需要查看nginx -t的返回结果 [root@m01 ~/ansible]#cat vars.yml - hosts: web02 tasks: - name: register env command: nginx -t register: ls_re 没有返回结果 #使用变量注册方式查看nginx检查结果 [root@m01 ~/ansible]#cat vars.yml - hosts: web02 tasks: - name: register env command: nginx -t register: ng_re - name: print ng_re debug: msg: "{{ ng_re.stderr_lines }}" [root@m01 ~/ansible]#ansible-playbook vars.yml PLAY [web02] ************************************************************************************************ TASK [Gathering Facts] ************************************************************************************** ok: [web02] TASK [register env] ***************************************************************************************** changed: [web02] TASK [print ng_re] ****************************************************************************************** ok: [web02] => { "msg": [ "nginx: the configuration file /etc/nginx/nginx.conf syntax is ok", "nginx: configuration file /etc/nginx/nginx.conf test is successful" ] } [root@m01 ~/ansible]#cat vars.yml - hosts: web02 tasks: - name: register env command: nginx -t register: ng_re - name: print ng_re debug: msg: "{{ ng_re.rc }}" TASK [print ng_re] ****************************************************************************************** ok: [web02] => { "msg": "0" } #3.测试nginx报错,忽略错误,继续往下执行 修改nginx.conf配置文件,报错,playbook退出,如果Nginx报错依然希望执行下面的tasks使用忽略模块,不影响下面要执行的内容 [root@m01 ~/ansible]#cat vars.yml - hosts: web02 tasks: - name: register env command: nginx -t register: ng_re ignore_errors: yes # 忽略此task的错误,继续向下执行。要写在这里, - name: print ng_re debug: msg: "{{ ng_re.rc }}" PLAY [web02] ************************************************************************************************ TASK [Gathering Facts] ************************************************************************************** ok: [web02] TASK [register env] ***************************************************************************************** fatal: [web02]: FAILED! => {"changed": true, "cmd": ["nginx", "-t"], "delta": "0:00:00.007733", "end": "2025-04-29 19:07:44.127962", "msg": "non-zero return code", "rc": 1, "start": "2025-04-29 19:07:44.120229", "stderr": "nginx: [emerg] unknown directive \"iiuser\" in /etc/nginx/nginx.conf:2\nnginx: configuration file /etc/nginx/nginx.conf test failed", "stderr_lines": ["nginx: [emerg] unknown directive \"iiuser\" in /etc/nginx/nginx.conf:2", "nginx: configuration file /etc/nginx/nginx.conf test failed"], "stdout": "", "stdout_lines": []} ...ignoring TASK [print ng_re] ****************************************************************************************** ok: [web02] => { "msg": "1" #返回了1,表示有错误,但是忽略了上面错误继续执行下来的 } PLAY RECAP ************************************************************************************************** web02 : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=1
7、层级定义变量
bash
# 定义变量,了解 [root@m01 ~/ansible]# cat var/v1.yml lnmp: pack: pk1: lrzsz # 调用变量 [root@m01 ~/ansible]#cat vars.yml - hosts: web02 vars_files: var/v1.yml tasks: - name: install yum: name: "{{ lnmp.pack.pk1 }}" state: present # 装B写法 [root@m01 ~/ansible]#cat vars.yml - hosts: web02 vars_files: v1.yml tasks: - name: install wget yum: name: "{{ lnmp['pack']['pk1'] }}" state: present #内置变量的高大上写法 [root@m01 ~/ansible]#cat vars.yml - hosts: web02 tasks: - name: Create dir file: path: /root/{{ ansible_default_ipv4['address'] }}.txt state: touch #这个跟上面结果是一样的 [root@m01 ~/ansible]#cat vars.yml - hosts: web02 tasks: - name: Create dir file: path: /root/{{ ansible_default_ipv4.address }}.txt state: touch
8、关闭客户端的内置变量
bash
#facts缓存是在被管理追击上通过Ansible自动采集法相的变量。facts包含每台特定的主机信息,比如被控端的主机名、ip地址、系统版本、cpu数量等 [root@m01 ~]# vim facts.yml - hosts: web_group gather_facts: no #关闭信息采集,内置变量就无法用了,执行过程中TASK [Gathering Facts]将不显示 tasks: ........
9、知识点小结
bash
1.变量定义 play中定义 vars_file定义 主机清单中定义 官方推荐 host_vars group_vars group_vars/all所有主机 2.变量注册 很多命令通过ansible执行没有结果 ls -l nginx -t register 变量注册 debug模块输出变量内容 3.when判断 when: 条件表达式 ansible_host == "backup" ansible_host is match ansible_host is search or 或者 and 并且 4.使用when重构服务 5.循环loop "{{ item }}" 6.字典循环 "{{ item. }}"

7、Aansible-when判断

bash
#案例1.如果客户端主机名称是backup则安装wget,否则不安装 [root@m01 ~/ansible]#cat /etc/ansible/hosts web01 ansible_ssh_host=172.16.1.7 web02 ansible_ssh_host=172.16.1.8 [nfs_server] nfs ansible_ssh_host=172.16.1.31 [backup_server] backup ansible_ssh_host=172.16.1.41 db ansible_ssh_host=172.16.1.51 [backup_server:vars] pa1=wget pa2=lrzsz #写playbook [root@m01 ~/ansible]#cat vars.yml - hosts: all tasks: - name: Create dir yum: name: wget state: present when: ansible_hostname == 'backup' # 判断主机名称是backup的安装wget #语法检测 [root@m01 ~/ansible]#ansible-playbook --syntax-check vars.yml playbook: vars.yml #执行结果 [root@m01 ~/ansible]#ansible-playbook vars.yml PLAY [all] ********************************************************************* TASK [Gathering Facts] ********************************************************* ok: [web02] ok: [nfs] ok: [web01] ok: [backup] ok: [db] TASK [Create dir] ************************************************************** skipping: [web01] skipping: [nfs] skipping: [web02] skipping: [db] changed: [backup] #案例2.IP地址是10.0.0.41的安装lrzsz命令 [root@m01 ~/ansible]#cat vars.yml - hosts: all tasks: - name: Install lrzsz pack yum: name: lrzsz state: present when: ansible_default_ipv4.address == "10.0.0.41" [root@m01 ~/ansible]#cat /etc/ansible/hosts web01 ansible_ssh_host=172.16.1.7 web02 ansible_ssh_host=172.16.1.8 #案例3.使用匹配的机制判断 [root@m01 ~/ansible]#cat vars.yml - hosts: all tasks: - name: Install lrzsz pack yum: name: lrzsz state: present when: ansible_hostname is match "web" #案例4.使用search查找 [root@m01 ~/ansible]#cat vars.yml - hosts: all tasks: - name: Install lrzsz pack yum: name: lrzsz state: present when: ansible_hostname is search "web"
特性is matchis search
匹配范围必须从字符串开头匹配可在字符串任意位置匹配
等价正则隐式添加 ^无隐式锚点
性能稍快(匹配失败时更快退出)稍慢(需扫描整个字符串)
适用场景验证字符串格式(如 IP 地址)查找子字符串(如日志关键词)
bash
#案例5.Nginx的语法检测 [root@m01 ~/ansible]#cat vars.yml - hosts: web02 tasks: - name: Nginx Config Check command: nginx -t register: ngx_re ignore_errors: yes #有问题就忽悠继续往下 - name: Print Ngx_re debug: msg: "{{ ngx_re.stderr_lines }}" - name: Restart Nginx Server systemd: name: nginx state: restarted when: ngx_re.stderr_lines is search "syntax is ok" #没问题重启 #案例6.使用rc结果判断 [root@m01 ~/ansible]#cat vars.yml - hosts: web02 tasks: - name: Nginx Config Check command: nginx -t register: ngx_re ignore_errors: yes - name: Print Ngx_re debug: msg: "{{ ngx_re.rc }}" - name: Restart Nginx Server systemd: name: nginx state: restarted when: ngx_re.rc is match "0"
1、Ansible的并且关系
bash
#案例1.要求主机名称为backup并且IP地址是10.0.0.41安装lrzsz [root@m01 ~/ansible]#cat va.yml - hosts: all tasks: - name: Install lrzsz yum: name: lrzsz state: present when: (ansible_hostname == "backup") and (ansible_default_ipv4.address == "10.0.0.31") ### 结果全跳过不执行 [root@m01 ~/ansible]#cat va.yml - hosts: all tasks: - name: Install lrzsz yum: name: lrzsz state: present when: (ansible_hostname == "backup") and (ansible_default_ipv4.address == "10.0.0.41") ## backup安装 其他跳过 #并且的列表的书写方式 [root@m01 ~/ansible]#cat va.yml - hosts: all tasks: - name: Install lrzsz yum: name: lrzsz state: absent when: - ansible_hostname == "backup" - ansible_default_ipv4.address == "10.0.0.41" #案例2.在nfs或者backup服务器上安装lrzsz [root@m01 ~/ansible]#cat va.yml - hosts: all tasks: - name: Install lrzsz yum: name: lrzsz state: present when: (ansible_hostname == "backup") or (ansible_default_ipv4.address == "10.0.0.31") #案例3.操作系统为kylin并且主机名称为backup安装network—srcipts [root@m01 ~/ansible]#cat va.yml - hosts: all tasks: - name: Install network-scripts yum: name: network-scripts state: present when: - ansible_hostname == "backup" - ansible_distribution == "Kylin Linux Advanced Server"
2、使用when判断重构rsync
bash
#1.恢复快照 #2.免秘钥 [root@m01 ~/ansible]#ssh-copy-id 172.16.1.41 #3、书写playbook [root@m01 ~/ansible]#cat rsync.yml - hosts: all vars: - Rs_user: www - Rs_dir: /backup tasks: - name: Install Rsyncd Server yum: name: rsync state: present - name: Configure Rsync Server copy: src: rsyncd.conf dest: /etc/ when: ansible_hostname == "backup" - name: Create Group {{ Rs_user }} group: name: "{{ Rs_user }}" gid: 666 - name: Create User {{ Rs_user }} user: name: "{{ Rs_user }}" uid: 666 group: "{{ Rs_user }}" create_home: false shell: /sbin/nologin - name: Create pass file copy: content: rsync_backup:123 dest: /etc/rsync.passwd mode: 0600 when: ansible_hostname == "backup" - name: Create {{ Rs_dir }} file: path: "{{ Rs_dir }}" state: directory owner: "{{ Rs_user }}" group: "{{ Rs_user }}" when: ansible_hostname == "backup" - name: Start Rsync Server systemd: name: rsyncd state: started enabled: yes when: ansible_hostname == "backup" [root@m01 ~/ansible]#ansible-playbook --syntax-check vars.yml

8、Ansible面试题

bash
Ansible 你用来干啥? 批量管理:管理数百台服务器的系统配置(时区、SSH策略、防火墙、软件源等) 批量部署:实现Java应用从代码提交到生产的全流程自动化。 批量变更配置文件 重要。 批量收集数据信息 ansible部署流程: 1、安装ansible 2、配置主机清单,把要管理的主机ip添加到/etc/ansible/hosts文件里面 3、底层配置免密要,发送给客户端 4、书写playbook 5、根据playbook内容准备对应的数据 6、执行playbook,想看详细信息可以加-v Ansible你都用过哪些模块 template systemd register handlers when loop file user yum copy 开放性问题如何解答。 1.说一说你对运维的理解: 我觉得运维就像一个隐形守护者,他首先保障了系统的稳定运行,比如开发了一个app,可以确保你顺利登陆,没有卡顿,闪退,黑屏等问题。 我认为运维的本质是保障业务连续性、提升系统效率和降低运营风险的技术保障体系,是连接开发与业务的桥梁 2.在公司遇到不会的问题怎么解决 3.你对加班怎么看 4.你平时喜欢做什么 5.你了解安全吗

16、Ansible实现自动化部署

1、基础环境优化

bash
1、配置免密钥 2、安装epel仓库 3、安装nginx仓库 4、创建www用户 5、时间同步 6、关闭防火墙 7、文件最大描述符 8、修改默认SSH端口 禁止root登录 使用普通用户登录 9、安装常用软件 #1、创建playbook代码总目录roles [root@m01 ~]#mkdir roles #2、创建基础环境优化目录basic/tasks [root@m01 ~/roles/basic]#tree . └── tasks └── main.yml #3、创建免密钥目录 [root@m01 ~/roles/miyao/tasks]#pwd /root/roles/miyao/tasks #4、配置免密钥主机清单的参数 [root@m01 ~/roles]#cat /etc/ansible/hosts [db_server] db01 ansible_ssh_host=172.16.1.51 ansible_ssh_pass=Sdms2018 #远程服务器的登录密码 [web_server] web01 ansible_ssh_host=172.16.1.7 ansible_ssh_pass=Sdms2018 web02 ansible_ssh_host=172.16.1.8 ansible_ssh_pass=Sdms2018 [nfs_server] nfs ansible_ssh_host=172.16.1.31 ansible_ssh_pass=Sdms2018 [backup_server] backup ansible_ssh_host=172.16.1.41 ansible_ssh_pass=Sdms2018 #5、书写免密钥playbook [root@m01 ~/roles/miyao/tasks]#cat main.yml - name: ssh_keys authorized_key: user: root key: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}" state: present #6、书写基础环境优化playbook [root@m01 ~/roles/basic/tasks]#cat main.yml - name: 安装epel仓库 yum_repository: name: epel description: EPEL YUM repo baseurl: http://mirrors.aliyun.com/epel/7/$basearch gpgcheck: no enabled: yes - name: 安装nginx仓库 yum_repository: name: nginx description: Nginx YUM repo baseurl: http://nginx.org/packages/centos/7/$basearch/ gpgcheck: no enabled: yes - name: 创建属组 group: name: www gid: 666 - name: 创建用户 user: name: www group: www uid: 666 create_home: false shell: /sbin/nologin - name: 时间同步 cron: name: ntpdate minute: "*/5" job: /usr/sbin/ntpdate ntp1.aliyun.com &>/dev/null #添加ntpdate的绝对路径,因为普通用户的定时任务没有这个路径 state: present - name: 关闭防火墙 systemd: name: firewalld state: stopped enabled: no - name: 安装软件 yum: name: "{{ item }}" state: present loop: - vim - tree - ntpdate - lrzsz - wget - unzip - network-scripts - python3-mysqlclient #安装这个命令防止后面mariadb缺少而报错 #7、编写执行文件 [root@m01 ~/roles]#cat site.yml - hosts: all # 清单所有主机 gather_facts: no # 禁用事实收集(不获取系统信息) roles: - role: miyao # 应用名为 miyao 的角色(无条件,所有主机执行) - role: basic # 应用名为 basic 的角色(有条件,仅特定主机执行) when: inventory_hostname == "backup" # 条件:当主机在清单中的名称为 backup 时执行 #8、语法验证 [root@m01 ~/roles]#ansible-playbook --syntax-check site.yml playbook: site.yml #9、执行playbook [root@m01 ~/roles]#ansible-playbook site.yml PLAY [all] *********************************************************************************************************************************************************************** TASK [miyao : ssh_keys] ********************************************************************************************************************************************************** ok: [backup] ok: [db01] ok: [web01] ok: [web02] ok: [nfs] TASK [basic : 安装epel仓库] ****************************************************************************************************************************************************** skipping: [db01] skipping: [web01] skipping: [web02] skipping: [nfs] changed: [backup] TASK [basic : 安装nginx仓库] ***************************************************************************************************************************************************** skipping: [db01] skipping: [web01] skipping: [web02] skipping: [nfs] changed: [backup] TASK [basic : 创建属组] ********************************************************************************************************************************************************** skipping: [db01] skipping: [web01] skipping: [web02] skipping: [nfs] changed: [backup]

2、Ansible重构rsync

bash
#1、重建rsync [root@m01 ~/roles]#ansible-galaxy init rsync - Role rsync was created successfully #2、删除不必要的目录及文件 [root@m01 ~/roles/rsync]#ll total 0 drwxr-xr-x 2 root root 6 May 6 19:12 files drwxr-xr-x 2 root root 22 May 6 19:11 handlers drwxr-xr-x 2 root root 22 May 6 19:11 tasks drwxr-xr-x 2 root root 6 May 6 19:11 templates drwxr-xr-x 2 root root 22 May 6 19:11 vars #3、书写rsync的playbook [root@m01 ~/roles/rsync/tasks]#ll total 4 -rw-r--r-- 1 root root 554 May 6 20:07 main.yml [root@m01 ~/roles/rsync/tasks]#cat main.yml - name: 安装Rsync yum: name: rsync state: present - name: 拷贝配置文件 template: #字典循环 src: "{{ item.src }}" dest: "{{ item.dest }}" mode: "{{ item.mode }}" loop: - { src: rsyncd.conf.j2,dest: /etc/rsyncd.conf,mode: '0644' } - { src: rsync.passwd,dest: /etc/,mode: '0600' } notify: Restart Rsync Server #监控这个模块,如果配置文件发生变化,那么执行handler模块 - name: 创建目录 file: path: "{{ r_dir }}" state: directory owner: "{{ r_u }}" group: "{{ r_u }}" - name: 启动服务 systemd: name: rsyncd state: started enabled: yes #4、根据playbook创建handlers [root@m01 ~/roles/rsync/handlers]#cat main.yml - name: Restart Rsync Server #跟notify名字一样 systemd: #如果发生变化,那么就重启 name: rsyncd state: restarted #5、创建变量文件 [root@m01 ~/roles/rsync/vars]#cat main.yml r_u: www r_dir: /data #6、准备配置文件 [root@m01 ~/roles/rsync/templates]#cat rsyncd.conf.j2 uid = {{ r_u }} #以变量形式存放 gid = {{ r_u }} #以变量形式存放 port = 873 fake super = yes use chroot = no max connections = 200 timeout = 600 ignore errors read only = false list = false auth users = rsync_backup secrets file = /etc/rsync.passwd log file = /var/log/rsyncd.log ##################################### [backup] comment = welcome to oldboyedu backup! path = {{ r_dir }} #以变量形式存放 [wp] path=/wp #7、密码文件 [root@m01 ~/roles/rsync/templates]#cat rsync.passwd rsync_backup:123456 #8、编写执行文件 [root@m01 ~/roles]#cat site.yml - hosts: all gather_facts: no roles: - role: miyao - role: basic when: inventory_hostname == "web02" - role: rsync when: inventory_hostname == "backup" #9、语法检验 [root@m01 ~/roles]#ansible-playbook --syntax-check site.yml playbook: site.yml #10、执行playbook [root@m01 ~/roles]#ansible-playbook site.yml #11、web01测试rsync [root@web01 ~]#rsync -avz /etc/hosts rsync_backup@10.0.0.41::backup Password: sending incremental file list hosts sent 172 bytes received 43 bytes 86.00 bytes/sec total size is 188 speedup is 0.87

3、Ansible重构NFS

BASH
#1、创建目录 [root@m01 ~/roles/nfs]#ls ../rsync|xargs mkdir #2、书写nfs的playbook [root@m01 ~/roles/nfs/tasks]#cat main.yml - name: 安装NFS yum: name: nfs-utils state: present - name: 拷贝配置文件 template: src: exports.j2 dest: /etc/exports notify: Restart nfs server - name: 创建wp目录 file: path: "{{ dir1 }}" state: directory owner: www group: www recurse: yes - name: 创建zh目录 file: path: "{{ dir2 }}" state: directory owner: www group: www recurse: yes - name: 创建zrlog目录 file: path: "{{ dir3 }}" state: directory owner: www group: www recurse: yes - name: 启动NFS服务 systemd: name: nfs state: started enabled: yes #3、根据playbook创建handlers [root@m01 ~/roles/nfs/handlers]#cat main.yml - name: Restart nfs server systemd: name: nfs state: restarted #4、创建变量文件 [root@m01 ~/roles/nfs/vars]#cat main.yml dir1: /data/wp dir2: /data/zh dir3: /data/zrlog ip: 172.16.1.0/24 #5、准备配置文件 [root@m01 ~/roles/nfs/templates]#cat exports.j2 {{ dir1 }} {{ ip }}(rw,sync,all_squash,anonuid=666,anongid=666) {{ dir2 }} {{ ip }}(rw,sync,all_squash,anonuid=666,anongid=666) {{ dir3 }} {{ ip }}(rw,sync,all_squash,anonuid=666,anongid=666) #6、编写执行文件 [root@m01 ~/roles]#cat site.yml - hosts: all gather_facts: no roles: - role: miyao - role: basic when: inventory_hostname == "web02" - role: rsync when: inventory_hostname == "backup" - role: nfs when: inventory_hostname == "nfs" #7、语法检验 [root@m01 ~/roles]#ansible-playbook --syntax-check site.yml playbook: site.yml #8、执行playbook [root@m01 ~/roles]#ansible-playbook site.yml #9、测试 [root@web01 ~]#showmount -e 172.16.1.31 Export list for 172.16.1.31: /data/zrlog 172.16.1.0/24 /data/zh 172.16.1.0/24 /data/wp 172.16.1.0/24

4、Ansible重构Nginx、Php

bash
#1、创建目录 [root@m01 ~/roles/nfs]#ls ../rsync|xargs mkdir #2、书写playbbook [root@m01 ~/roles/nginx/tasks]#cat main.yml - name: 安装Nginx、PHP yum: name: - nginx - php - php-bcmath - php-cli - php-common - php-devel - php-embedded - php-fpm - php-gd - php-intl - php-mbstring - php-mysqlnd - php-opcache - php-pdo - php-process - php-xml - php-json state: present - name: 拷贝配置nginx文件 template: src: nginx.conf dest: /etc/nginx/nginx.conf notify: Restart nginx server #监控nginx.conf - name: 拷贝配置php文件 copy: src: "{{ item.src }}" dest: "{{ item.dest }}" loop: - { src: www.conf,dest: /etc/php-fpm.d/www.conf } - { src: php.ini,dest: /etc/ } notify: Restart php server #监控php配置文件 - name: 启动nginx、php systemd: name: "{{ item.name }}" state: "{{ item.state }}" enabled: "{{ item.en }}" loop: - { name: nginx,state: started,en: yes } - { name: php-fpm,state: started,en: yes } #3、根据playbook创建handlers [root@m01 ~/roles/nginx/handlers]#cat main.yml - name: Restart nginx server systemd: name: nginx state: restarted - name: Restart php server systemd: name: php-fpm state: restarted #4、创建变量文件 [root@m01 ~/roles/nginx/vars]#cat main.yml u_r: www #5、准备配置文件 [root@m01 ~/roles/nginx/templates]#cat nginx.conf user {{ u_r }}; #这里写变量 worker_processes auto; worker_cpu_affinity auto; ... [root@m01 ~/roles/nginx/files]#cat www.conf ... user = www #这里写变量一直报错,改成用户名 ; RPM: Keep a group allowed to write in log dir. group = www .... #6、编写执行文件 [root@m01 ~/roles]#cat site.yml - hosts: all gather_facts: no roles: - role: miyao - role: basic when: inventory_hostname == "web02" - role: rsync when: inventory_hostname == "backup" - role: nfs when: inventory_hostname == "nfs" - role: nginx when: inventory_hostname == "web02" #7、语法检验 [root@m01 ~/roles]#ansible-playbook --syntax-check site.yml playbook: site.yml #8、执行playbook [root@m01 ~/roles]#ansible-playbook site.yml #9、测试存在80、9000端口 [root@web02 ~]#netstat -tnulp Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 127.0.0.1:9000 0.0.0.0:* LISTEN 62609/php-fpm: mast tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 62610/nginx: master tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1068/sshd: /usr/sbi tcp6 0 0 :::22 :::* LISTEN 1068/sshd: /usr/sbi udp 0 0 127.0.0.1:323 0.0.0.0:* 738/chronyd udp6 0 0 ::1:323 :::* 738/chronyd

5、Ansible重构mariadb

bash
#1、创建目录 [root@m01 ~/roles/mariadb]#ls ../nfs|xargs mkdir [root@m01 ~/roles/mariadb]#ll total 0 drwxr-xr-x 2 root root 6 May 7 05:52 files drwxr-xr-x 2 root root 6 May 7 05:52 handlers drwxr-xr-x 2 root root 6 May 7 05:52 tasks drwxr-xr-x 2 root root 6 May 7 05:52 templates drwxr-xr-x 2 root root 6 May 7 05:52 vars #2、将51数据库的数据导出 [root@db01 ~]#mysqldump -uroot -plzy123.com -A > all.sql [root@db01 ~]#ll total 3388 -rw-r--r-- 1 root root 0 Mar 31 11:55 1 -rw-r--r-- 1 root root 3353016 May 7 05:50 all.sql #3、将导出的数据库拷贝到m01 [root@db01 ~]#scp all.sql 10.0.0.61:/root/roles/mariadb/files all.sql #4、书写mariadb的playbook [root@m01 ~/roles/mariadb/tasks]#cat main.yml - name: 安装数据库 yum: name: mariadb-server state: present - name: 启动服务 systemd: name: mariadb state: started enabled: yes - name: 拷贝sql文件 copy: src: all.sql dest: /root/ - name: 导入sql文件 mysql_db: name: all target: /root/all.sql state: import login_user: root - name: 重启mysql systemd: name: mariadb state: restarted #5、准备sql文件 [root@m01 ~/roles/mariadb/files]#ll total 3276 -rw-r--r-- 1 root root 3353016 May 7 05:57 all.sql #6、编写执行文件 [root@m01 ~/roles]#cat site.yml - hosts: all gather_facts: no roles: - role: miyao - role: basic when: inventory_hostname == "web02" - role: rsync when: inventory_hostname == "backup" - role: nfs when: inventory_hostname == "nfs" - role: nginx when: inventory_hostname == "web02" - role: mariadb when: inventory_hostname == "db01" #7、语法检验 [root@m01 ~/roles]#ansible-playbook --syntax-check site.yml playbook: site.yml #8、执行 [root@m01 ~/roles]#ansible-playbook site.yml #9、测试 [root@db01 ~]#netstat -tnulp Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1078/sshd: /usr/sbi tcp6 0 0 :::22 :::* LISTEN 1078/sshd: /usr/sbi tcp6 0 0 :::3306 :::* LISTEN 11443/mysqld udp 0 0 127.0.0.1:323 0.0.0.0:* 744/chronyd udp6 0 0 ::1:323 :::* 744/chronyd

6、Ansible重构wp业务

bash
#1、创建wp目录 [root@m01 ~/roles/wp]#ls ../rsync|xargs mkdir [root@m01 ~/roles/wp]#ll total 0 drwxr-xr-x 2 root root 6 May 7 06:22 files drwxr-xr-x 2 root root 6 May 7 06:22 handlers drwxr-xr-x 2 root root 6 May 7 06:22 tasks drwxr-xr-x 2 root root 6 May 7 06:22 templates drwxr-xr-x 2 root root 6 May 7 06:22 vars #2、书写nfs共享目录的playbook [root@m01 ~/roles/nfs_server/tasks]#cat main.yml - name: 创建基础目录 file: #字典循环,创建wp、zh、zrlog三个业务的日志 path: "{{ item.path }}" state: "{{ item.state }}" owner: "{{ item.owner }}" group: "{{ item.group }}" loop: - { path: /code/wp, state: directory, owner: www, group: www } - { path: /code/zh, state: directory, owner: www, group: www } - { path: /code/zrlog, state: directory, owner: www, group: www } - name: 把共享wp图片拷贝到nfs copy: src: 2025/ dest: /data/wp owner: www group: www #3、根据共享目录的playbook准备数据 #拷贝wp目录 [root@web01 ~]#scp -r /code/wp/wp-content/uploads/* 10.0.0.61:/root/roles/nfs_server [root@m01 ~/roles/nfs_server]#tree . ├── files │   └── 2025 │   └── 05 │   ├── image-20250409152029527-768x381.png │   └── image-20250409152029527.png └── tasks └── main.yml #4、书写wp业务的playbook [root@m01 ~/roles/wp/tasks]#cat main.yml - name: 删除默认配置文件 #不删除会读取到里面的配置 file: path: /etc/nging/conf.d/default.conf state: absent - name: 拷贝wp配置文件到web copy: src: wordpress.conf dest: /etc/nginx/conf.d notify: Restart Nginx Server - name: 拷贝代码目录到web解压 unarchive: src: wp.tar.gz dest: / owner: www group: www creates: /code/wp #存在就不解压 #5、创建挂载目录 [root@m01 ~/roles/mount/tasks]#pwd /root/roles/mount/tasks #6、挂载,这个要在放在执行文件的最后, [root@m01 ~/roles/mount/tasks]#cat main.yml - name: 挂载 NFS 共享目录 mount: src: "{{ item.src }}" path: "{{ item.path }}" fstype: "{{ item.fs }}" state: "{{ item.state }}" loop: - { src: 172.16.1.31:/data/wp, path: /code/wp/wp-content/uploads, fs: nfs, state: mounted } - { src: 172.16.1.31:/data/zh, path: /code/zh/uploads/answer, fs: nfs, state: mounted } - { src: 172.16.1.31:/data/zrlog, path: /zrlog/ROOT/attached/thumbnail, fs: nfs, state: mounted } #7、根据wp业务的playbook创建数据 #创建handlers文件 [root@m01 ~/roles/wp/handlers]#cat main.yml - name: Restart Nginx Server systemd: name: nginx state: restarted #拷贝wp代码的目录 [root@web01 /code/wp]#scp wp.tar.gz 10.0.0.61:/root/roles/wp/files Authorized users only. All activities may be monitored and reported. root@10.0.0.61s password: wp.tar.gz #拷贝wp配置文件 [root@web01 /etc/nginx/conf.d]#scp wordpress.conf 10.0.0.61:/root/roles/wp/files Authorized users only. All activities may be monitored and reported. root@10.0.0.61s password: wordpress.conf #8、语法检查 [root@m01 ~/roles]#ansible-playbook --syntax-check site.yml playbook: site.yml #9、执行playbook [root@m01 ~/roles]#ansible-playbook site.yml #注意,到这里会报错,因为密码发生改变了,卡在这过不去就忽略 TASK [mariadb : 导入sql文件] ******************************************************************* skipping: [web01] skipping: [web02] skipping: [nfs] skipping: [backup] fatal: [db01]: FAILED! => {"changed": false, "msg": "unable to find /root/.my.cnf. Exception message: (1045, \"Access denied for user 'root'@'localhost' (using password: NO)\")"} #10、检查是否挂载成功 [root@web02 ~]#df -h Filesystem Size Used Avail Use% Mounted on devtmpfs 459M 0 459M 0% /dev tmpfs 475M 0 475M 0% /dev/shm tmpfs 475M 19M 456M 4% /run tmpfs 475M 0 475M 0% /sys/fs/cgroup /dev/mapper/klas-root 47G 4.0G 43G 9% / /dev/sda1 1014M 169M 846M 17% /boot tmpfs 95M 0 95M 0% /run/user/0 172.16.1.31:/data/wp 47G 3.8G 44G 9% /code/wp/wp-content/uploads 172.16.1.31:/data/zh 47G 3.8G 44G 9% /code/zh/uploads/answer 172.16.1.31:/data/zrlog 47G 3.8G 44G 9% /zrlog/ROOT/attached/thumbnail [root@web02 ~]#cat /etc/fstab 172.16.1.31:/data/wp /code/wp/wp-content/uploads nfs defaults 0 0 172.16.1.31:/data/zh /code/zh/uploads/answer nfs defaults 0 0 172.16.1.31:/data/zrlog /zrlog/ROOT/attached/thumbnail nfs defaults 0 0 #11、host解析 #12、浏览器测试是否可以正常访问

image

7、Ansible重构zh业务

bash
#1、创建目录 [root@m01 ~/roles]#mkdir zh [root@m01 ~/roles/zh]#ls ../rsync|xargs mkdir [root@m01 ~/roles/zh]#ll total 0 drwxr-xr-x 2 root root 6 May 7 08:39 files drwxr-xr-x 2 root root 6 May 7 08:39 handlers drwxr-xr-x 2 root root 6 May 7 08:39 tasks drwxr-xr-x 2 root root 6 May 7 08:39 templates drwxr-xr-x 2 root root 6 May 7 08:39 vars #2、书写nfs共享目录的playbook [root@m01 ~/roles/zh/tasks]#cat main.yml - name: 拷贝zh配置文件到web copy: src: zh.conf dest: /etc/nginx/conf.d notify: Restart Nginx Server #监控zh.conf配置文件 - name: 拷贝zh代码目录到web解压 unarchive: src: zh.tar.gz dest: / owner: www group: www creates: /code/zh/index.php #3、根据playbook创建handler数据 [root@m01 ~/roles/zh/handlers]#cat main.yml - name: Restart Nginx Server systemd: name: nginx state: restarted #4、拷贝web01的zh代码目录到ansible [root@web01 ~]#scp zh.tar.gz 10.0.0.61:/root/roles/zh/files Authorized users only. All activities may be monitored and reported. root@10.0.0.61s password: zh.tar.gz 100% 45MB 23.6MB/s 00:01 #5、拷贝zh配置文件到ansible [root@web01 /etc/nginx/conf.d]#scp zh.conf 10.0.0.61:/root/roles/zh/files Authorized users only. All activities may be monitored and reported. root@10.0.0.61s password: zh.conf 100% 358 129.6KB/s 00:00 #6、拷贝wp目录到nfs_server [root@web01 ~]#scp -r /code/zh/uploads/answer/* 10.0.0.61:/root/roles/nfs_server/files d80c938a2586f6a1cd48686e478229 100% 347KB 17.1MB/s 00:00 #7、语法检查 [root@m01 ~/roles]#ansible-playbook --syntax-check site.yml playbook: site.yml #8、执行playbook [root@m01 ~/roles]#ansible-playbook site.yml #9、host解析 #10、测试

image

8、Ansible重构Tomcat

bash
#1、创建tomcat目录 [root@m01 ~/roles/tomcat]#ll total 0 drwxr-xr-x 2 root root 95 May 7 21:10 files drwxr-xr-x 2 root root 22 May 7 20:38 handlers drwxr-xr-x 2 root root 22 May 7 23:30 tasks drwxr-xr-x 2 root root 6 May 7 15:30 templates drwxr-xr-x 2 root root 6 May 7 15:30 vars #2、书写Tomcat的playbook [root@m01 ~/roles/tomcat/tasks]#cat main.yml - name: 拷贝tomcat文件 copy: src: "{{ item.src }}" dest: "{{ item.dest }}" loop: - { src: jdk-8u181-linux-x64.rpm,dest: /root/ } - { src: tomcat.service,dest: /usr/lib/systemd/system/ } - name: 检查 JDK 是否已安装 ansible.builtin.command: cmd: rpm -q jdk-8u181-linux-x64 register: jdk_installed # 注册变量 ignore_errors: yes # 忽略错误 changed_when: false - name: 安装JDK shell: "rpm -ivh jdk-8u181-linux-x64.rpm" when: jdk_installed.rc != 0 # 调用注册变量 become: yes ignore_errors: yes - name: 创建目录 file: path: "{{ item.path }}" state: "{{ item.state }}" loop: - { path: /soft,state: directory } - name: 解压Tomcat安装包 unarchive: src: apache-tomcat-9.0.104.tar.gz dest: /soft/ creates: /soft/tomcat/bin #如果存在就不解压 - name: 创建tomcat软连接 file: src: /soft/apache-tomcat-9.0.104 dest: /soft/tomcat state: link force: yes - name: 启动tomcat systemd: name: tomcat state: started enabled: yes #3、根据playbook准备数据 [root@m01 ~/roles/tomcat/files]#ll total 178532 -rw-r--r-- 1 root root 12787166 May 7 15:34 apache-tomcat-9.0.104.tar.gz -rw-r--r-- 1 root root 170023183 Aug 14 2018 jdk-8u181-linux-x64.rpm -rw-r--r-- 1 root root 315 May 7 20:32 tomcat.service #4、语法检查 [root@m01 ~/roles]#ansible-playbook --syntax-check site.yml #5、执行playbook [root@m01 ~/roles]#ansible-playbook site.yml

9、Ansible重构zrlog

bash
#1、创建zrlog目录 [root@m01 ~/roles/zrlog]#ll total 0 drwxr-xr-x 3 root root 96 May 7 23:14 files drwxr-xr-x 2 root root 22 May 7 22:17 handlers drwxr-xr-x 2 root root 22 May 7 23:11 tasks drwxr-xr-x 2 root root 6 May 7 20:53 templates drwxr-xr-x 2 root root 6 May 7 20:53 vars #2、书写zrlog的playbook [root@m01 ~/roles/zrlog/tasks]#cat main.yml - name: 拷贝配置文件 copy: src: server.xml dest: /soft/tomcat/conf/ notify: Restart Tomcat Server - name: 解压缩 unarchive: src: zrlog.tar.gz dest: / creates: /zrlog/ROOT - name: 重启tomcat systemd: name: tomcat state: restarted #3、根据playbook配置handler [root@m01 ~/roles/zrlog/handlers]#cat main.yml - name: Restart Tomcat Server systemd: name: tomcat state: restarted #4、准备数据 [root@m01 ~/roles/zrlog/files]#ll total 16416 -rw------- 1 root root 1997 May 7 18:38 server.xml drwxr-xr-x 3 root root 18 May 7 23:14 zrlog -rw-r--r-- 1 root root 16802342 May 7 22:05 zrlog.tar.gz #5、语法检测 [root@m01 ~/roles]#ansible-playbook --syntax-check site.yml #6、执行playbook [root@m01 ~/roles]#ansible-playbook site.yml #7、host解析 #8、浏览器测试

image

10、Ansible重构phpmyadmin

bash
#1、创建phpmysql代码目录 [root@m01 ~/roles/phpmyadmin]#ls ../zrlog/|xargs mkdir [root@m01 ~/roles/phpmyadmin]#ll total 0 drwxr-xr-x 2 root root 6 May 8 08:20 files drwxr-xr-x 2 root root 6 May 8 08:20 handlers drwxr-xr-x 2 root root 6 May 8 08:20 tasks drwxr-xr-x 2 root root 6 May 8 08:20 templates drwxr-xr-x 2 root root 6 May 8 08:20 vars #2、打包代码文件上传到Ansible [root@web01 ~]#scp phpmyadmin.tar.gz 10.0.0.61:/root/roles/phpmyadmin/files #3、书写playbook [root@m01 ~/roles/phpmyadmin]#cat tasks/main.yml - name: 拷贝phpMyadmin到web解压 unarchive: src: phpmyadmin.tar.gz dest: / # 因为压缩包包含了/code/admin路径,所以只写/ owner: www group: www creates: /code/admin # 如果存在/code/admin就不解压 - name: 拷贝配置到web copy: src: admin.conf # 代码配置文件 dest: /etc/nginx/conf.d notify: Restart nginx # 监控配置文件,如果内容发生修改就触发handler - name: 增加权限 shell: "chown www.www /var/lib/php/session/" # 放在权限不够写不进去而报错 - name: 重启nginx systemd: name: nginx state: restarted #4、根据playbook准备数据 [root@m01 ~/roles/phpmyadmin/files]#ll total 26448 -rw-r--r-- 1 root root 364 May 8 08:33 admin.conf #nginx配置文件,来自web01 -rw-r--r-- 1 root root 27076722 May 8 08:29 phpmyadmin.tar.gz #代码文件,来自web01打包 #5、编写handler信息 [root@m01 ~/roles/phpmyadmin/handlers]#cat main.yml - name: Restart nginx # 对应上面notify systemd: name: nginx state: restarted #6、语法检测 [root@m01 ~/roles]#ansible-playbook --syntax-check site.yml #7、执行playbook [root@m01 ~/roles]#ansible-playbook site.yml #8、host解析 10.0.0.8 admin.oldboy.com #9、浏览器单台测试

image

1、加入web03
2、加入负载均衡

bash
#1、创建负载均衡目录 [root@m01 ~/roles/lb]#ls ../tomcat/|xargs mkdir [root@m01 ~/roles/lb]#ll total 0 drwxr-xr-x 2 root root 6 May 8 09:13 files drwxr-xr-x 2 root root 6 May 8 09:13 handlers drwxr-xr-x 2 root root 6 May 8 09:13 tasks drwxr-xr-x 2 root root 6 May 8 09:13 templates drwxr-xr-x 2 root root 6 May 8 09:13 vars #2、书写playbook [root@m01 ~/roles/lb]#cat tasks/main.yml - name: copy: src: admin.conf dest: /etc/nginx/conf.d/ notify: Restart nginx #3、根据playbook书写handler信息 [root@m01 ~/roles/lb/handlers]#cat main.yml - name: Restart nginx systemd: name: nginx state: restarted #4、拷贝配置文件,来自lb01 [root@m01 ~/roles/lb/files]#cat admin.conf upstream ad{ server 172.16.1.9; #7修改成9 server 172.16.1.8; } server { listen 80; server_name admin.oldboy.com; location / { proxy_pass http://ad; include proxy_params; } } #5、新增主机清单内容 [lb_server] lb01 ansible_ssh_host=172.16.1.6 ansible_ssh_pass=Sdms2018 #6、ping测试 [root@m01 ~/roles/lb/files]#ansible lb01 -m ping lb01 | SUCCESS => { "changed": false, "ping": "pong" } #7、host解析 10.0.0.6 admin.oldboy.com #8、浏览器测试,因为没有后端

image

3、部署redis
bash
#1、创建目录 [root@m01 ~/roles/redis]#ll total 0 drwxr-xr-x 2 root root 50 May 8 10:15 files drwxr-xr-x 2 root root 22 May 8 10:33 handlers drwxr-xr-x 2 root root 22 May 8 10:32 tasks drwxr-xr-x 2 root root 6 May 7 15:03 templates drwxr-xr-x 2 root root 6 May 7 15:03 vars #2、书写playbook [root@m01 ~/roles/redis/tasks]#cat main.yml - name: 安装redis yum: name: redis state: present - name: 拷贝redis配置文件 copy: src: redis.conf dest: /etc/ notify: Restart redis - name: 启动redis systemd: name: redis state: started enabled: yes #3、根据playbook创建hangler [root@m01 ~/roles/redis]#cat handlers/main.yml - name: Restart redis systemd: name: redis state: restarted #4、准备数据 [root@m01 ~/roles/redis]#ll files/ total 536 -rw-r----- 1 root root 107546 May 8 10:03 redis.conf
4、编译redis
bash
#1、创建编译目录 [root@m01 ~/roles/byredis]#ll total 0 drwxr-xr-x 2 root root 32 May 8 12:50 files drwxr-xr-x 2 root root 22 May 8 13:24 handlers drwxr-xr-x 2 root root 22 May 8 13:20 tasks #2、书写playbook [root@m01 ~/roles/byredis]#cat tasks/main.yml - name: phpredis-6.2.0.zip unarchive: src: phpredis-6.2.0.zip dest: /root/ creates: /root/phpredis-6.2.0 #如果此文件已存在,任务将自动跳过,避免重复执行。 - name: 编译安装 shell: | cd phpredis-6.2.0/ && # phpize && ./configure && make && make install args: # 通过 args 声明模块参数 chdir: /root/ # 所有命令在 /root/ 目录下执行 creates: /usr/lib64/php/modules/redis.so # 如果此文件已存在,任务将自动跳过,避免重复执行。 notify: Restart php # 任务成功后触发名为 Restart php 的 Handler,用于重启 PHP 服务 become: yes #3、根据ansible编写handler [root@m01 ~/roles/byredis]#cat handlers/main.yml - name: Restart php systemd: name: php-fpm.service state: restarted #4、准备编译包 [root@m01 ~/roles/byredis]#ll files/ total 428 -rw-r--r-- 1 root root 435613 Apr 14 17:50 phpredis-6.2.0.zip #5、完善主机清单 [root@m01 ~/roles]#cat /etc/ansible/hosts [db_server] db01 ansible_ssh_host=172.16.1.51 ansible_ssh_pass=Sdms2018 [web_server] web01 ansible_ssh_host=172.16.1.7 ansible_ssh_pass=Sdms2018 web02 ansible_ssh_host=172.16.1.8 ansible_ssh_pass=Sdms2018 web03 ansible_ssh_host=172.16.1.9 ansible_ssh_pass=Sdms2018 [nfs_server] nfs ansible_ssh_host=172.16.1.31 ansible_ssh_pass=Sdms2018 [lb_server] lb02 ansible_ssh_host=172.16.1.6 ansible_ssh_pass=Sdms2018 [backup_server] backup ansible_ssh_host=172.16.1.41 ansible_ssh_pass=Sdms2018 [backup_server:vars] pa1=wget pa2=lrzsz [hehe:children] nfs_server backup_server #6、完善执行文件 [root@m01 ~/roles]#cat site.yml - hosts: all gather_facts: no roles: - role: miyao - role: nginx when: (inventory_hostname == "web03") or (inventory_hostname == "web02") - role: lb when: inventory_hostname == "lb02" - role: redis when: inventory_hostname == "db01" - role: byredis when: (inventory_hostname == "web03") or (inventory_hostname == "web02") - role: mount when: inventory_hostname == "web02" #7、语法检测 [root@m01 ~/roles]#ansible-playbook --syntax-check site.yml #8、执行playbook [root@m01 ~/roles]#ansible-playbook site.yml #浏览器测试

image

4、错误
bash
在编写phpmysqladmin会话保持的时候出现下面的错误,一刷新到登录界面,再一刷新成了错误界面,经过长时间的排错,发现是php-frp没重启导 致的,应该是监控的配置文件没修改,所以不会触发重启,而后面又手动编译过,所以手动重启了下可以访问了

c76915a6eb206e925ae7d00e51e81a6

30aa2837d81c99a8907d975c131c5e8

11、Ansible重构lsync

bash
#1、创建目录 [root@m01 ~/roles/lsync]#ll total 0 drwxr-xr-x 2 root root 43 May 8 15:15 files drwxr-xr-x 2 root root 22 May 8 14:49 handlers drwxr-xr-x 2 root root 22 May 8 15:38 tasks drwxr-xr-x 2 root root 6 May 8 14:35 templates drwxr-xr-x 2 root root 6 May 8 14:35 vars #2、书写playbook [root@m01 ~/roles/lsync]#cat tasks/main.yml - name: 安装lsync yum: name: lsyncd state: present - name: 拷贝配置文件 copy: src: lsyncd.conf dest: /etc/ notify: Restart lsyncd - name: 拷贝密码文件 copy: src: rsyncd.pwd dest: /etc/ mode: 600 - name: 启动lsync systemd: name: lsyncd state: started #3、准备数据 [root@m01 ~/roles/lsync]#ll files/ total 8 -rw-r--r-- 1 root root 686 May 8 15:15 lsyncd.conf -rw-r--r-- 1 root root 7 May 8 14:45 rsyncd.pwd #4、backup服务器创建存放数据的目录 - name: 创建目录 file: path: /wp state: director owner: "{{ r_u }}" group: "{{ r_u }}" #5、根据playbook创建handler [root@m01 ~/roles/lsync/handlers]#cat main.yml - name: Restart lsyncd systemd: name: lsyncd state: restarted #6、测试,已经实时推送过来了 [root@backup /wp]#ll total 0 drwxr-xr-x 2 www www 6 May 8 14:52 backup drwxr-xr-x 4 www www 28 May 7 09:45 wp drwxr-xr-x 4 www www 38 May 7 14:58 zh drwxr-xr-x 2 www www 6 May 6 21:39 zrlog #7、晚上执行文件 [root@m01 ~/roles]#cat site.yml - hosts: all gather_facts: no roles: - role: miyao - role: lsync when: inventory_hostname == "nfs"

12、keepalived

bash
#1、创建两个keepalived目录,因为要用lb01、lb02 drwxr-xr-x 7 root root 77 May 8 15:55 keepalived01 drwxr-xr-x 7 root root 77 May 8 16:11 keepalived02 [root@m01 ~/roles/keepalived01]#ll total 0 drwxr-xr-x 2 root root 29 May 8 15:59 files drwxr-xr-x 2 root root 22 May 8 16:46 handlers drwxr-xr-x 2 root root 22 May 8 16:47 tasks drwxr-xr-x 2 root root 22 May 8 16:01 templates drwxr-xr-x 2 root root 6 May 8 15:55 vars #2、书写keepalived01的playbook [root@m01 ~/roles/keepalived01/tasks]#cat main.yml - name: 安装keepalived yum: name: keepalived state: present - name: 拷贝配置文件 copy: src: keepalived.conf dest: /etc/keepalived/ notify: Restart keepalived - name: 启动keepalived systemd: name: keepalived state: started enabled: yes #3、配置抢占模式,01是主 [root@m01 ~/roles/keepalived01/files]#cat keepalived.conf global_defs { router_id lb01 } vrrp_script check_web { script "/root/chek.sh" interval 3 } vrrp_instance VI_1 { state MASTER interface ens33 virtual_router_id 50 priority 150 advert_int 1 authentication { auth_type PASS auth_pass 1111 } virtual_ipaddress { 10.0.0.3 } track_script { check_web } } #4、监控notify [root@m01 ~/roles/keepalived01/handlers]#cat main.yml - name: Restart keepalived systemd: name: keepalived state: restarted #5、书写keepalived02的playbook [root@m01 ~/roles/keepalived02]#cat tasks/main.yml - name: 安装keepalived yum: name: keepalived state: present - name: 拷贝配置文件 copy: src: keepalived.conf dest: /etc/keepalived/ notify: Restart keepalived - name: 启动keepalived systemd: name: keepalived state: started enabled: yes #6、配置抢占模式,02是从 [root@m01 ~/roles/keepalived02]#cat files/keepalived.conf global_defs { router_id lb02 } vrrp_instance VI_1 { state BACKUP interface ens33 virtual_router_id 50 priority 100 advert_int 1 authentication { auth_type PASS auth_pass 1111 } virtual_ipaddress { 10.0.0.3 } } #7、监控notify [root@m01 ~/roles/keepalived02]#cat handlers/main.yml - name: Restart keepalived systemd: name: keepalived state: restarted #8、语法检测,成功 #9、测试vip在哪 [root@lb01 /etc/nginx/conf.d]#ip a |grep 10.0.0.3 inet 10.0.0.3/32 scope global ens33 #停掉lb01 [root@lb01 /etc/nginx/conf.d]#systemctl stop keepalived.service #vip飘逸到lb02 [root@lb02 /etc/nginx]#ip a |grep 10.0.0.3 inet 10.0.0.3/32 scope global ens33 #开启lb01,抢占过来 [root@lb01 /etc/nginx/conf.d]#ip a |grep 10.0.0.3 inet 10.0.0.3/32 scope global ens33 #lb01开启防火墙产生脑裂 [root@lb01 /etc/nginx/conf.d]#systemctl start firewalld [root@lb01 /etc/nginx/conf.d]#ip a |grep 10.0.0.3 inet 10.0.0.3/32 scope global ens33 #lb02开启防火墙产生脑裂 [root@lb02 /etc/nginx]#systemctl start firewalld [root@lb02 /etc/nginx]#ip a |grep 10.0.0.3 inet 10.0.0.3/32 scope global ens33

13、Https

bash
#1、书写playbook [root@m01 ~/roles/lb]#cat tasks/main.yml - name: 拷贝文件 copy: src: admin.conf dest: /etc/nginx/conf.d/ notify: Restart nginx - name: 解压钥匙 unarchive: src: ssl.tar.gz dest: /etc/nginx/ creates: /etc/nginx/ssl_key notify: Restart nginx #2、加入证书 [root@m01 ~/roles/lb/files]#cat admin.conf upstream ad { server 172.16.1.9; server 172.16.1.8; } server { listen 443 ssl; server_name www.weixiang.info; ssl_certificate ssl_key/server.crt; ssl_certificate_key ssl_key/server.key; location / { proxy_pass http://ad; include proxy_params; fastcgi_param HTTPS on; } } server { listen 80; server_name www.weixiang.info; return 302 https://$server_name$request_uri; } #3、拷贝钥匙 [root@m01 ~/roles/lb/files]#tar -tf ssl.tar.gz ssl_key/ ssl_key/server.key ssl_key/-sha256 ssl_key/server.crt ssl_key/18172849_www.weixiang.info_nginx.zip

27868cd80357c4f0b784fcbb45292038

17、述职

3f11a6db203633bfbcd5b34bb7796939

bash
一、DNS解析流程 1.用户在浏览器输入域名www.baidu.com,会先查询浏览器缓存,如果有就返回IP与百度服务器建立连接,没有则查询本地的HOSTS文件 2.如果HOSTS文件有就返回IP与百度服务器建立连接,如果没有继续查询本地的DNS 3.本地DNS一般是我们自己配置的比如223.5.5.5查询本地DNS是否有对应的IP,如果是223.5.5.5,那么就去查询阿里云的dns,看是否有对应关系 如果有返回给浏览器 如果没有则查询根服务器 ----------1-3过程称为递归查询,一层一层去查询--------------- 4.根服务器不存储域名解析,会给LDNS返回顶级域.com的服务器IP地址 5.LDNS重新请求.com顶级域服务器 .com不存在域名解析,会返回权威域名服务器的IP地址给LDNS 6.LDNS重新请求baidu.com权威域名服务器,权威域服务器就是我们自己配置的A记录解析,将A记录对应的IP地址返回给LDNS 7.LDNS拿到后自己缓存一份 返回给浏览器一份 8.浏览器和拿到的百度服务器IP地址建立连接 ---------这个过程称为迭代查询,有去有回,至此到这里DNS解析完毕 二、解析完毕后获取到百度服务器的ip和下面的负载均衡也就是vip10.0.0.3建立tcp三次握手 第一次握手:客户端向服务器端发送报文,内容是想建立连接SYN=1,并且客户端向服务器发送数据包编号seq=x(用x表示第一个数据包) 第二次握手:服务器端收到后会响应客户端表示已经收到ACK=1,并且发出建立连接请求SYN=1,并且我给你发送我的第一个数据包seq=y,并且还会 确认要给发我下一个数据包了Ack=x+1 第三次握手:客户端响应服务器端你的数据我收到了ACK=1,并且我给你发送第二个数据包了seq=x+1,并且你下次应该给我发第二个数据包了Ack=y+1 ---------建立三次握手后发送http/https请求页面内容 三、http请求 请求页面内容,包括请求头部,请求行,请求空行,请求内容主题。请求头部的话有请求主机名是什么,请求类型,请求是否压缩,请求长连接, 请求编码,请求语言,请求缓存。f12调试工具可以看到具体内容 请求后进行响应。响应服务器版本,响应主机,响应是否压缩,响应长连接,响应缓存等等。 里面包括请求方法get,post,put、delete 四、https加密流程 如果客户端通过浏览器hppt请求后的网站部署了https证书,,服务器端接收到请求并返回证书,证书里包含公钥,浏览器会去CA机构验证这 个证书的是否合法有效,如果不合法会给个警告提示,你访问的网站不安全,如果合法有效,浏览器这边把会生成一个随机数,比如用R来表示,通 过服务端返回的公钥对R进行加密,加密之后传给服务端。服务端用自己的私钥解自己的公钥,解开后获取到客户端传过来的R,然后用R再进行加密, 将加密后的内容传给自己的客户端,最后浏览器用自己的随机数进行解密。 五、负载均衡调度算法 然后到负载均衡,我们是以proxy_pass+upstream实现负载均衡,并且负载均衡默认以轮询的方式进行请求的下发,除了rr轮询,还有weight、 ip_hash、url_hash、最小连接数(least_conn),再给大家说一下4层跟7层的区别,4层是在传输层,7层是在应用层,4层是ip+端口,7层是域名, 4层可以解决7层端口不够用的情况。真正实现4层负载的是LVS中的dr模式 六、我们配置了两台负载均衡服务器,加入了keepalived,两台完全相同的业务系统,当有一台宕机了,另外一台服务器就能快速的接管,如果硬件或者 网络问题产生的脑裂,这样可以在备用服务器写一个监控脚本,当两边都有vip,杀死当前服务器 七、tcp握手之后就是进入请求数据阶段,如果是请求动态数据就是到nginx,nginx将动态数据发给php-frm,php-frm用自己的工作进程warrap去解析, 如果可以解析就返回给nginx,nginx给负载均衡,最后给浏览器,解析不了,tcp与数据库连接,数据库返回给php子进程,php再给nginx,最后再返回 给浏览器。如果请求静态资源,那么直接请求本地磁盘,如果通过nfs网络文件系统挂载的,那么会请求nfs磁盘。 八、nginx优化 1、CPU亲和、worker进程数默认和CPU核心数量相同 2、调整每个worker进程的最大连接数,默认是的1024 调整25532 3、开启tcp长连接,以及长连接超时时间keepalived 4、开启文件传输压缩gzip 5、开启静态文件expires缓存 6、隐藏nginx版本号 7、配置防盗链、以及跨域访问 8、优雅显示nginx错误页面 #定向到别的页面 9、文件的高效读取sendfile、nopush 10、文件的传输实时性、nodealy 11、nginx加密传输https优化 12、防DDOS、cc攻击,限制单IP并发连接,以及http请求 连接限制和请求限制。 九、四次挥手 主动方要求关闭连接,FIN就是我想跟你断开连接 被动方收到了,说你稍等一下,我看看我还有没有数据要传给你或者你给我的数据我看看有没有接受完ACK。 确认完毕被动方给主动方发送断开连接请求FIN 然后主动方发送ACK确认,四次挥手断开

18、搭建VPN

一、安装配置证书软件
bash
链接地址1:https://developer.aliyun.com/article/1303828 链接地址2:https://developer.aliyun.com/article/1303829?spm=a2c6h.24874632.expert-profile.54.62691134T5YvVK 1. [root@Web01 ~]# yum -y install easy-rsa 2. [root@Web01 ~]# mkdir /opt/easy-rsa 3. [root@Web01 easy-rsa]# rpm -ql easy-rsa #查看已安装的RPM包中名为 easy-rsa 的文件列表 4. [root@Web01 easy-rsa]# cp -a /usr/share/easy-rsa/3.0.8/* . 5. [root@Web01 easy-rsa]# cp -a /usr/share/doc/easy-rsa-3.0.8/vars.example ./vars 6. [root@Web01 easy-rsa]# > vars 7. [root@Web01 easy-rsa]# cat vars 8. if [ -z "$EASYRSA_CALLER" ]; then 9. echo "You appear to be sourcing an Easy-RSA 10. 'vars' file." >&2 11. echo "This is no longer necessary and is 12. disallowed. See the section called" >&2 13. echo "'How to use this file' near the top 14. comments for more details." >&2 15. return 1 16. fi 17. set_var EASYRSA_DN "cn_only" 18. set_var EASYRSA_REQ_COUNTRY "CN" 19. set_var EASYRSA_REQ_PROVINCE "Beijing" 20. set_var EASYRSA_REQ_CITY "Shanghai" 21. set_var EASYRSA_REQ_ORG "koten" 22. set_var EASYRSA_REQ_EMAIL "888888@qq.comm" 23. set_var EASYRSA_NS_SUPPORT "yes"
二、创建证书
bash
1. [root@Web01 easy-rsa]# ./easyrsa init-pki #1、初始化,在当前目录创建PKI目录,用于存储整数 2. [root@Web01 easy-rsa]# ./easyrsa build-ca #2、创建根证书,会提示设置密码,用于ca对之后生成的server和client证书签名时使用,其他提示内容直接回车即可 3. Enter New CA Key Passphrase: #注意密码不能太短,我这边设置的是123456 4. Re-Enter New CA Key Passphrase: 5. [root@Web01 easy-rsa]# ./easyrsa gen-req server nopass #3、创建server端证书和私钥文件,nopass表示不加密私钥文件,提示内容直接回车即可 6. [root@Web01 easy-rsa]# ./easyrsa sign server server #4、给server端证书签名,提示内容需要输入yes和创建ca根证书时候的密码 7. [root@Web01 easy-rsa]# ./easyrsa gen-dh #5、创建Diffie-Hellman文件,密钥交换时的Diffie-Hellman算法 8. [root@Web01 easy-rsa]# ./easyrsa gen-req client nopass #6、创建client端的证书和私钥文件,nopass表示不加密私钥文件,提示内容直接回车即可 9. [root@Web01 easy-rsa]# ./easyrsa sign client client #7、给client端证书前面,提示内容输入yes和创建ca根证书时候的密码 10. [root@Web01 easy-rsa]# tree #检查是否有ca根证书、客户端服务端证书、客户端服务端私钥 11. . 12. ├── easyrsa #管理命令 13. ├── openssl-easyrsa.cnf 14. ├── pki 15. │ ├── ca.crt #ca根证书,服务端与客户端都需要用 16. │ ├── certs_by_serial 17. │ │ ├── 633C217979C7B5F1D0A9ECA971006F96.pem 18. │ │ └── 857F9B2E3F6C3D35934672212343B42D.pem 19. │ ├── dh.pem #认证算法 服务端 20. │ ├── index.txt 21. │ ├── index.txt.attr 22. │ ├── index.txt.attr.old 23. │ ├── index.txt.old 24. │ ├── issued 25. │ │ ├── client.crt #客户端证书 26. │ │ └── server.crt #服务端证书 27. │ ├── openssl-easyrsa.cnf 28. │ ├── private 29. │ │ ├── ca.key 30. │ │ ├── client.key #客户端私钥 31. │ │ └── server.key #服务端私钥 32. ......
三、安装openvpn并写入服务端配置文件
bash
1. [root@Web01 easy-rsa]# yum -y install openvpn 2. [root@Web01 easy-rsa]# cat /etc/openvpn/server.conf 3. port 1194 #端口 4. proto udp #协议 5. dev tun #采用路由隧道模式 6. ca /opt/easy-rsa/pki/ca.crt #ca证书的位置 7. cert /opt/easy-rsa/pki/issued/server.crt #服务端公钥的位置 8. key /opt/easy-rsa/pki/private/server.key #服务端私钥的位置 9. dh /opt/easy-rsa/pki/dh.pem #证书校验算法 10. server 10.8.0.0 255.255.255.0 #给客户端分配的地址池 11. push "route 172.16.1.0 255.255.255.0" #允许客户端访问的内网网段 12. ifconfig-pool-persist ipp.txt #地址池记录文件位置,未来让openvpn客户端固定ip地址使用的 13. keepalive 10 120 #存活时间,10秒ping一次,120秒如果未收到响应则视为短线 14. max-clients 100 #最多允许100个客户端连接 15. status openvpn-status.log #日志位置,记录openvpn状态 16. log /var/log/openvpn.log #openvpn日志记录位置 17. verb 3 #openvpn版本 18. client-to-client #允许客户端与客户端之间通信 19. persist-key #通过keepalive检测超时后,重新启动VPN,不重新读取 20. persist-tun #检测超时后,重新启动VPN,一直保持tun是linkup的,否则网络会先linkdown然后再linkup 21. duplicate-cn #客户端密钥(证书和私钥)是否可以重复 22. comp-lzo #启动lzo数据压缩格式
四、启动并检查端口
bash
1. [root@Web01 easy-rsa]# systemctl start openvpn@server 2. [root@Web01 easy-rsa]# systemctl enable openvpn@server 3. Created symlink from /etc/systemd/system/multi-user.target.wants/openvpn@server.service to /usr/lib/systemd/system/openvpn@.service. 4. [root@Web01 easy-rsa]# ip a s tun0 #查看网段 5. 4: tun0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN group default qlen 100 6. link/none 7. inet 10.8.0.1 peer 10.8.0.2/32 scope global tun0 8. valid_lft forever preferred_lft forever 9. inet6 fe80::b1:7ea6:1178:8a1a/64 scope link flags 800 10. valid_lft forever preferred_lft forever 11. [root@Web01 easy-rsa]# ss -lntup|grep 1194 #检查端口 12. udp UNCONN 0 0 *:1194 *:* users:(("openvpn",pid=47104,fd=6)) 13. [root@Web01 easy-rsa]# ps -ef|grep openvpn #检查pid 14. root 47104 1 0 10:59 ? 00:00:00 /usr/sbin/openvpn --cd /etc/openvpn/ --config server.conf 15. root 47202 40565 0 11:01 pts/0 00:00:00 grep --color=auto openvpn
五、OpenVPN客户端搭建部署(windows端)
一、安装OpenVPN软件

image

二、将ca根证书、client.key、client.crt放入config目录
bash
1. [root@Web01 easy-rsa]# sz pki/ca.crt 2. [root@Web01 easy-rsa]# sz pki/private/client.key 3. [root@Web01 easy-rsa]# sz pki/issued/client.crt 再创建client.ovpn,写入如下内容 1. client 2. dev tun 3. proto udp 4. remote 10.0.0.7 1194 #注意此处更改为openvpn服务端代码 5. resolv-retry infinite 6. nobind 7. ca ca.crt 8. cert client.crt 9. key client.key 10. verb 3 11. persist-key 12. comp-lzo

image

目录最终状态

image

三、直连其他内网服务器

首先确保我们的openvpn服务端开启了内核转发

1. [root@Web01 ~]# echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf #确保openvpn开启了ip转发 2. [root@Web01~]# sysctl -p 3. net.ipv4.ip_forward = 1

尝试ping其他内网服务器,会显示请求超时,需要在添加其他内网服务器添加网关后,才可以ping通,才可以直连。

1. [c:\~]$ ping 172.16.1.8 #1、无法ping通其他内网服务器,也就是无法直连 2. 3. 正在 Ping 172.16.1.8 具有 32 字节的数据: 4. 请求超时。 5. ...... 6. 7. [root@Web02 ~]# yum -y install tcpdump #2、安装tcpdump尝试监控流量 8. [root@Web02 ~]# tcpdump -i eth1 -nn not icmp #3、windows端再次ping,虽然ping显示请求超时,但是tcp监控有流量进入,说明只能接收,不能返回 9. 12:47:58.759367 IP 10.8.0.10 > 172.16.1.8: ICMP echo request, id 1, seq 514, length 40 10. 12:48:03.290454 IP 10.8.0.10 > 172.16.1.8: ICMP echo request, id 1, seq 515, length 40 11. ...... 12. [root@Web02 ~]# route add -net 10.8.0.0 netmask 255.255.255.0 gw 172.16.1.7 #4、添加路由,临时生效,可以加入/etc/rc.local实现永久生效 13. 14. [c:\~]$ ping 172.16.1.8 #5、本地成功ping通 15. 16. 正在 Ping 172.16.1.8 具有 32 字节的数据: 17. 来自 172.16.1.8 的回复: 字节=32 时间=1ms TTL=63 18. 来自 172.16.1.8 的回复: 字节=32 时间=2ms TTL=63 19. ...... 20. [c:\~]$ ssh 172.16.1.8 #6、直连也没有问题 21. 22. Connecting to 172.16.1.8:22... 23. Connection established. 24. To escape to local shell, press Ctrl+Alt+]. 25. 26. Last login: Sun May 21 12:47:51 2023 from 10.0.0.1 27. [root@Web02 ~]#
六、Openvpn密码认证
1、服务端配置

bash
1、修改服务端配置文件为支持密码认证 1. [root@Web01 ~]# cat /etc/openvpn/server.conf #添加配置文件 2. ...... 3. script-security 3 #允许使用自定义脚本 4. auth-user-pass-verify /etc/openvpn/check.sh via-env #指定认证脚本 5. username-as-common-name #用户密码登陆方式验证 2、编写脚本文件 1. [root@Web01 ~]# cat /etc/openvpn/check.sh # 2. #!/bin/bash 3. PASSFILE="/etc/openvpn/openvpnfile" #密码文件 用户名 密码明文 4. LOG_FILE="/var/log/openvpn-password.log" #用户登录情况的日志 5. TIME_STAMP=`date "+%Y-%m-%d %T"` 6. if [ ! -r "${PASSFILE}" ]; then 7. echo "${TIME_STAMP}: Could not open password file \"${PASSFILE}\" for reading." >> ${LOG_FILE} 8. exit 1 9. fi 10. CORRECT_PASSWORD=`awk '!/^;/&&!/^#/&&$1=="'${username}'"{print $2;exit}' ${PASSFILE}` 11. if [ "${CORRECT_PASSWORD}" = "" ]; then 12. echo "${TIME_STAMP}: User does not exist: username=\"${username}\",password=\"${password}\"." >> ${LOG_FILE} 13. exit 1 14. fi 15. if [ "${password}" = "${CORRECT_PASSWORD}" ]; then 16. echo "${TIME_STAMP}: Successful authentication: username=\"${username}\"." >> ${LOG_FILE} 17. exit 0 18. fi 19. echo "${TIME_STAMP}: Incorrect password: username=\"${username}\", password=\"${password}\"." >> ${LOG_FILE} 20. exit 1 3、给脚本执行权限 [root@Web01 ~]# chmod +x /etc/openvpn/check.sh 4、创建用户密码,空格为分割符 1. [root@Web01 ~]# cat /etc/openvpn/openvpnfile 2. koten 1 5、重启服务端 [root@Web01 ~]# systemctl restart openvpn@serve
2、windows客户端配置

image

bash
# 最底行添加auth-user-pass,注意该配置文件不要有多余空格,否则可能会报错,注意,要把配置文件client.ovpn拖出来再修改 1. client 2. dev tun 3. proto udp 4. remote 10.0.0.7 1194 5. resolv-retry infinite 6. nobind 7. ca ca.crt 8. cert client.crt 9. key client.key 10. verb 3 11. persist-key 12. comp-lzo 13. auth-user-pass

image

image

bash
[C:\~]$ ping 172.16.1.7 正在 Ping 172.16.1.7 具有 32 字节的数据: 来自 172.16.1.7 的回复: 字节=32 时间=2ms TTL=64 来自 172.16.1.7 的回复: 字节=32 时间=1ms TTL=64 172.16.1.7 的 Ping 统计信息: 数据包: 已发送 = 2,已接收 = 2,丢失 = 0 (0% 丢失), 往返行程的估计时间(以毫秒为单位): 最短 = 1ms,最长 = 2ms,平均 = 1ms

19、本地搭建时间服务器

bash
服务器端: #1、下载ntp [root@data ~]#yum install -y ntp #2、配置文件 [root@data ~]#vim /etc/ntp.conf -----------------------------------------------------------------------------------------------配置 driftfile /var/lib/ntp/drift # 时钟漂移记录文件 #访问控制配置 # nomodify 禁止修改配置 # notrap 禁止trap服务 # noquery 禁止时间查询 # nopeer 禁止对等体模式 #kod 启用Kiss-o'-Death(DoS防护) restrict default kod nomodify notrap nopeer noquery restrict -6 default kod nomodify notrap nopeer noquery restrict source limited kod nomodify notrap noquery restrict 127.0.0.1 #允许本地访问 restrict ::1 restrict 172.16.1.0 mask 255.255.255.0 nomodify notrap # 允许内网客户端 # 使用的时间同步服务器配置 server 0.cn.pool.ntp.org iburst server 1.cn.pool.ntp.org iburst server 2.cn.pool.ntp.org iburst server 3.cn.pool.ntp.org iburst tos maxclock 5 disable monitor logfile /var/log/ntp.log # 日志文件路径 # 启用统计记录 statistics loopstats peerstats clockstats filegen loopstats file loopstats type day enable filegen peerstats file peerstats type day enable filegen clockstats file clockstats type day enable -----------------------------------------------------------------------------------------------配置 #3、重启ntp服务器 [root@data ~]#systemctl restart ntpd #4、验证同步状态 [root@data ~]#ntpq -p remote refid st t when poll reach delay offset jitter ============================================================================== 119.28.183.184 100.122.36.196 2 u 1 64 1 54.875 -4.765 0.748 stratum2-1.ntp. 130.173.91.58 2 u 1 64 1 112.340 +5.506 0.457 *ntp5.flashdance 194.58.202.20 2 u 1 64 1 194.903 -18.280 0.479 ntp8.flashdance 194.58.202.20 2 u - 64 1 212.404 -9.170 10.896 #5、客户端测试,修改时间为20221011 [root@m01 ~/roles]#date -s 20221011 Tue Oct 11 00:00:00 CST 2022 #6、同步服务器端时间 [root@m01 ~/roles]#ntpdate 172.16.1.100 13 May 10:10:46 ntpdate[10352]: step time server 172.16.1.100 offset +81684636.920378 sec #7、查看时间 [root@m01 ~/roles]#date Tue May 13 10:10:48 CST 2025

20、搭建jumpserver

1、跳板机功能介绍
bash
官方网站:https://jumpserver.org/ 1、管理局域网的服务器 2、资产管理(所有服务器的信息,IP、系统、磁盘、内存) 3、资产授权(运维、开发、测试)权限管理 4、限制危险命令,不能执行rm命令 5、日志审计、命令审计、视频审计,监控用户所有行为 6、登录限制,用户名,密码,多因子方式认证(动态密码验证方式)

image-20250515084359989

2、安装部署jumpserver跳板机
bash
1.操作系统 CentOS、Kylin、ubuntu [root@j01 ~/jumpserver-ce-v4.9.0-x86_64]#cat /etc/os-release NAME="Kylin Linux Advanced Server" VERSION="V10 (Lance)" ID="kylin" VERSION_ID="V10" PRETTY_NAME="Kylin Linux Advanced Server V10 (Lance)" ANSI_COLOR="0;31" 2.准备jumpserver软件包 https://community.fit2cloud.com/#/products/jumpserver/downloads 3.已经下载成功的,上传jumpserver压缩包 [root@j01 ~]#ll total 1202020 -rw-r--r-- 1 root root 1230865983 May 8 18:15 jumpserver-ce-v4.9.0-x86_64.tar.gz 4.安装jumpserver [root@jumpserver /opt/jumpserver-ce-v4.9.0-x86_64]#./jmsctl.sh install 5.安装完成后启动jumpserver [root@j01 ~/jumpserver-ce-v4.9.0-x86_64]#./jmsctl.sh start [+] Running 8/0 ✔ Container jms_lion Running 0.0s ✔ Container jms_chen Running 0.0s ✔ Container jms_web Running 0.0s ✔ Container jms_redis Running 0.0s ✔ Container jms_postgresql Running 0.0s ✔ Container jms_core Running 0.0s ✔ Container jms_celery Running 0.0s ✔ Container jms_koko Running 6.查看端口号 [root@j01 ~/jumpserver-ce-v4.9.0-x86_64]#netstat -tnulp Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 1649/docker-proxy tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1097/sshd: /usr/sbi tcp 0 0 0.0.0.0:2222 0.0.0.0:* LISTEN 1730/docker-proxy tcp6 0 0 :::80 :::* LISTEN 1655/docker-proxy tcp6 0 0 :::22 :::* LISTEN 1097/sshd: /usr/sbi tcp6 0 0 :::2222 :::* LISTEN 1756/docker-proxy udp 0 0 127.0.0.1:323 0.0.0.0:* 764/chronyd udp6 0 0 ::1:323 :::* 764/chronyd 7.浏览器访问,用户名密码默认admin/ChangeMe

QQ_1747291107854

3、Jumpserver的三类用户

bash
1、特权账号: 1.资产管理(可以看到后端所有主机的信息,172.16.1.7 1核 1G 50G) 2.收集客户端配置 3.批量创建普通账号(linux系统账号) 4.批量执行命令 2、系统账号: 1.例如goudan(linux系统账号) 3、jumpserver登录用户(可以多因子认证,动态密码登录) 1.使用个人姓名登录jumoserver #1、jumpserver底层调用的是Ansible,Ansible里面有个files模块,可以自动获取客户端的配置信息,所以jumpserve要用特权账号和后端做免密钥才能进行管理 #2、使用系统账号(goudan)登录后端服务器,比如goudan授权给运维、gousheng授权给开发

image-20250515093054137

bash
创建组: 用户组--创建--填完提交

QQ_1747292890456

bash
创建用户: 用户列表--创建--添加名称、用户名、邮箱、用户组、设置密码

QQ_1747293138610

4、添加资产
1、添加root特权账号
bash
1.生成密钥对 [root@j01 ~]#ssh-keygen Generating public/private rsa key pair. Enter file in which to save the key (/root/.ssh/id_rsa): Created directory '/root/.ssh'. Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /root/.ssh/id_rsa Your public key has been saved in /root/.ssh/id_rsa.pub The key fingerprint is: SHA256:8Qvm3l3/ltm4EeeThsSqOPxism6ifn23oMwTWtaJfng root@j01 The keys randomart image is: +---[RSA 3072]----+ | | | | | . | | o . | | o S . o. .| | = = . .o .+.| | * +.. .. .o==| | +oB.Eoo.. .o=+| |.oo +*O.*+o . .o+| +----[SHA256]-----+ 2.和后端资产做免秘钥 [root@j01 ~]#ssh-copy-id 10.0.0.8 [root@j01 ~]#ssh-copy-id 10.0.0.9 [root@j01 ~]#ssh-copy-id 10.0.0.51 3.添加资产 先添加资产树

QQ_1747294472799

bash
资产列表--创建资产--添加名称、IP主机、平台、节点--选择模板添加 模板添加--创建--添加名称、用户名、SSH密钥、私钥([root@j01 ~]#cat .ssh/id_rsa可以看到)

QQ_1747294589490

QQ_1747294795655

QQ_1747294973721

image

image

QQ_1747295756258

2、添加linux后端资产的管理用户-运维
bash
账号模板--创建--名称、用户名(系统用户名称)、SSH密钥跟随机生成(做了免密要,防止远程登录的时候需要密码)、自动推送

QQ_1747296290248

3、添加linux后端资产的管理用户-开发

QQ_1747296208132

5、资产授权
bash
资产授权--创建--名称、用户组、节点、指定账号、根据模板选中
1、授权weixiang用户登录后端所有资产

image

bash
模板添加完后会在账号列表中显示相关的账号信息

image

bash
登录weixiang用户可以看到已授权的资产

QQ_1747296536735

bash
登陆测试,正常链接,已创建goudan普通用户登录

QQ_1747296688531

2、授权zhangjia用户只登录数据库资产

添加用户

7e1a9778-8d7a-4d63-ac61-afa762b2006f

QQ_1747297136408

bash
模板添加完后会在账号列表中显示相关的账号信息

image

bash
登录zhangjia用户可以看到已授权的资产

image

bash
登陆测试,正常链接,已创建gousheng普通用户登录

image

6、管理后端资产服务器两种方法
bash
一种是通过页面远程登录 一种是通过xshell远程登录 [C:\~]$ ssh weixiang@10.0.0.20 2222 #密码是jumpserver登录用户的密码,jump远程端口2222 Connecting to 10.0.0.20:2222... Connection established. To escape to local shell, press 'Ctrl+Alt+]'. Welcome to JumpServer SSH Server WARNING! The remote SSH server rejected X11 forwarding request. 维祥, JumpServer 1) Enter part IP, Hostname, Comment to to search login if unique. 2) Enter / + IP, Hostname, Comment to to search, such as: /192.168. 3) Enter p to display the assets you have permission. 4) Enter g to display the node that you have permission. 5) Enter h to display the hosts that you have permission. 6) Enter d to display the databases that you have permission. 7) Enter k to display the kubernetes that you have permission. 8) Enter r to refresh your assets and nodes. 9) Enter s to language switch. 10) Enter ? to print help. 11) Enter q to exit. Opt> p #p打印,查看自己可以看到的资产 ID | NAME | ADDRESS | PLATFORM | ORGANIZATION | COMMENT -----+-------+-------------+-----------------------------------------------+---------------------------------------------------+----------------------------------------------- 1 | db01 | 172.16.1.51 | Linux | DEFAULT | 2 | web02 | 172.16.1.8 | Linux | DEFAULT | 3 | web03 | 172.16.1.9 | Linux | DEFAULT | Page: 1, Count: 33, Total Page: 1, Total Count: 3 Enter ID number directly login, multiple search use // + field, such as: //16 Page up: b Page down: n Search: [Host]> 1 #输入1进入到db资源里面 Connecting to goudan(后端资产的系统运维用户)(goudan)@172.16.1.51 0.2 Authorized users only. All activities may be monitored and reported. Activate the web console with: systemctl enable --now cockpit.socket Last login: Thu May 15 16:07:27 2025 from 172.16.1.20 [goudan@db01 ~]#exit ID | NAME | ADDRESS | PLATFORM | ORGANIZATION | COMMENT -----+-------+-------------+-----------------------------------------------+---------------------------------------------------+----------------------------------------------- 1 | db01 | 172.16.1.51 | Linux | DEFAULT | 2 | web02 | 172.16.1.8 | Linux | DEFAULT | 3 | web03 | 172.16.1.9 | Linux | DEFAULT | Page: 1, Count: 33, Total Page: 1, Total Count: 3 Enter ID number directly login, multiple search use // + field, such as: //16 Page up: b Page down: n Search: [Host]> web02 #进入到web02资产 Connecting to goudan(后端资产的系统运维用户)(goudan)@172.16.1.8 0.2 Authorized users only. All activities may be monitored and reported. Activate the web console with: systemctl enable --now cockpit.socket Last login: Thu May 15 16:50:27 2025 from 172.16.1.20 [goudan@web02 ~]#
设置db01的登陆脚本
bash
连接: 名称:登录web01脚本 协议:SSH 主机:10.0.0.20 端口号:2222 用户身份验证: 用户名:weixiang 密码:654321 登录脚本: Expect:Opt> Send:p Expect:[Host] Send:db01

image

image

image

7、审计功能
bash
切换审计台--会话记录--再现会话--监控,可对用户进行监控

QQ_1747301043655

QQ_1747301160613

bash
会话命令里面可以看到用户相关操作所使用的命令

QQ_1747301203313

8、用户提权
bash
一、goudan后端系统运维用户提权su #1.查看用户权限 [root@db01 ~]#visudo ## Read drop-in files from /etc/sudoers.d (the # here does not mean a comment) #includedir /etc/sudoers.d goudan ALL=(ALL) NOPASSWD: /bin/whoami gousheng ALL=(ALL) NOPASSWD: /bin/whoami #2.账号列表--选中要提权的账号--推送--添加信息 注意:这里要提前做好规划,账号模板--编辑--帐号推送参数--设置,提前修改为对应的权限

QQ_1747301874186

image

bash
#3.可以看到goudan用户已经有了/bin/su权限 ## Allows members of the users group to shutdown this system # %users localhost=/sbin/shutdown -h now ## Read drop-in files from /etc/sudoers.d (the # here does not mean a comment) #includedir /etc/sudoers.d goudan ALL=(ALL) NOPASSWD: /bin/whoami,/bin/su #已经授权 gousheng ALL=(ALL) NOPASSWD: /bin/whoami #4.切换用户,成功 [goudan@db01 ~]#sudo su - Last login: Thu May 15 17:37:05 CST 2025 from 172.16.1.20 on pts/1 [root@db01 ~]# 二、gousheng后端系统开发用户提权cat

image

bash
#查看权限 [root@db01 ~]#visudo ## cdrom as root # %users ALL=/sbin/mount /mnt/cdrom, /sbin/umount /mnt/cdrom ## Allows members of the users group to shutdown this system # %users localhost=/sbin/shutdown -h now ## Read drop-in files from /etc/sudoers.d (the # here does not mean a comment) #includedir /etc/sudoers.d goudan ALL=(ALL) NOPASSWD: /bin/whoami,/bin/su gousheng ALL=(ALL) NOPASSWD: /bin/whoami,/bin/cat #已经授权 #sudo查看文件内容 [gousheng@db01 ~]#sudo cat /var/log/messages
9、数据库授权
bash
资产列表--创建--添加名称、地址、平台、节点--模板添加

QQ_1747303120974

bash
从上面的模板添加--名称、用户名、指定密码(lzy123.com)、不用选择自动推送(库里有这个用户)

image

bash
回到资产授权--授权给开发组--添加刚才创建的数据库应用模板、指定账号

QQ_1747303648819

bash
登录zhangjia开发组用户,登录终端,直接登录数据库终端

QQ_1747303729974

QQ_1747303819494

10.禁止使用危险命令

bash
命令过滤--命令组--创建--名称、内容

QQ_1747306344499

bash
命令过滤--创建--名称、账号(所有账号)、命令组(限制)、动作(拒绝)

QQ_1747306463135

bash
#测试,通过跳板机登录,被禁止使用,如果xshell直接连接51服务器rm可以正常执行命令 [root@db01 ~]#rm 1.log Command rm is forbidden [root@db01 ~]#reboot Command `reboot` is forbidden
11、jumpserver的网域功能
bash
jumpserver管理不同的局域网,需要用到网域 如果管理云服务器,需要用到公网ip,从10.0.0.81到阿里云11.22.33.44(公网ip做免密钥)再到阿里云后端继续做免密钥 JumpServer的网域功能主要用于解决混合云、跨网络隔离区域或无法直连的内网资产访问问题,通过网关服务器实现流量转发(JumpServer → 网域网关 → 目标资产)。

image

bash
购买两个不同网段的ip,地域为呼和浩特

QQ_1747308800129

bash
购买弹性公网IP并绑定,否则没法连接,弹性公网IP地域是呼和浩特

image

bash
xshell连接

image

bash
网域列表--创建--名称--提交,添加网域

QQ_1747309374643

bash
创建网域列表--网关列表

QQ_1747309458617

QQ_1747309650608

bash
# jumpserver与网关做免密钥 [root@j01 ~]#ssh-copy-id 39.104.22.137 /usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_rsa.pub" The authenticity of host '39.104.22.137 (39.104.22.137)' can't be established. ECDSA key fingerprint is SHA256:j8X8/NusNkgJIUadeBTEXWpmqfL2KhnDGqM5y5FRIjg. Are you sure you want to continue connecting (yes/no/[fingerprint])? /usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed The authenticity of host '39.104.22.137 (39.104.22.137)' can't be established. ECDSA key fingerprint is SHA256:j8X8/NusNkgJIUadeBTEXWpmqfL2KhnDGqM5y5FRIjg. Are you sure you want to continue connecting (yes/no/[fingerprint])? yes /usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys root@39.104.22.137s password: Number of key(s) added: 1 Now try logging into the machine, with: "ssh '39.104.22.137'" and check to make sure that only the key(s) you wanted were added. #ssh测试,没问题,可以跳转 [root@j01 ~]#ssh 39.104.22.137 Last failed login: Thu May 15 20:48:44 CST 2025 from 221.218.208.164 on ssh:notty There were 15 failed login attempts since the last successful login. Last login: Thu May 15 20:07:44 2025 from 221.218.208.164 Welcome to Alibaba Cloud Elastic Compute Service ! [root@wy ~]# #创建资产

QQ_1747311523793

bash
#添加资产需要创建阿里云的特权账号 #网域需要生成密钥对和后端的资产做免秘钥 [root@wy ~]# ssh-keygen #做免秘钥 [root@wy .ssh]# ssh 172.27.43.118 #网关分发到后端 [root@wy .ssh]# ssh-copy-id 172.27.43.118 把免密钥添加到私钥里面阿里云的

QQ_1747311322140

bash
授权阿里云资产给运维组

QQ_1747313723361

1747314232608

bash
创建新的账号模板

QQ_1747314422472

bash
添加账号模板

QQ_1747314520527

bash
#查询id [root@ali01 ~]# id ali uid=1000(ali) gid=1000(ali) groups=1000(ali) #命令行测试 [C:\~]$ ssh weixiang@10.0.0.20 2222 #密码654321 Connecting to 10.0.0.20:2222... Connection established. To escape to local shell, press 'Ctrl+Alt+]'. Welcome to JumpServer SSH Server WARNING! The remote SSH server rejected X11 forwarding request. 维祥, JumpServer 1) Enter part IP, Hostname, Comment to to search login if unique. 2) Enter / + IP, Hostname, Comment to to search, such as: /192.168. 3) Enter p to display the assets you have permission. 4) Enter g to display the node that you have permission. 5) Enter h to display the hosts that you have permission. 6) Enter d to display the databases that you have permission. 7) Enter k to display the kubernetes that you have permission. 8) Enter r to refresh your assets and nodes. 9) Enter s to language switch. 10) Enter ? to print help. 11) Enter q to exit. Opt> p ID | NAME | ADDRESS | PLATFORM | ORGANIZATION | COMMENT -----+------------------+---------------+-------------------------------------------+----------------------------------------------+------------------------------------------- 1 | db01 | 172.16.1.51 | Linux | DEFAULT | 2 | db01-172.16.1.51 | 172.16.1.51 | MariaDB | DEFAULT | 3 | web02 | 172.16.1.8 | Linux | DEFAULT | 4 | web03 | 172.16.1.9 | Linux | DEFAULT | 5 | 阿里云-ali01 | 172.27.43.118 | Linux | DEFAULT | 6 | 阿里云-网关 | 39.104.22.137 | Gateway | DEFAULT | Page: 1, Count: 33, Total Page: 1, Total Count: 6 Enter ID number directly login, multiple search use // + field, such as: //16 Page up: b Page down: n Search: [Host]> 5 Connecting to aili系统账号(ali)@172.27.43.118 0.5 Last login: Thu May 15 21:08:56 2025 from 172.27.43.119 Welcome to Alibaba Cloud Elastic Compute Service ! [ali@ali01 ~]$ id ali uid=1000(ali) gid=1000(ali) groups=1000(ali) [ali@ali01 ~]$
12、多因子认证
bash
开启多因子认证

QQ_1747312349948

1c70afa091c0e884378aef6a1d5ab0d

21、iptables

bash
硬件: 整个企业入口 三层路由: H3C 华为 Cisco(思科) 特点:贵、速度快 深信服 Juniper 软件: 开源软件 网站内部 封ip 封ip iptables 写入到Linux内核中 以后服务docker firewalld C7 云防火墙 阿里云:安全组(只能限制端口)

1、iptables四表五链
bash
面试题: 4表5链 4表: filter表、nat表、raw表、mangle表 5链: INPUT、OUTPUT、FORWARD、PREROUTING、POSTROUTING filter表: 实现数据安全,阻止一些非法的流量入侵,包括协议ip端口 nat表: 实现网络地址转换,数据转发,可以实现路由器的功能,把这张表作为一个路由器来使用 raw表: 不常用 mangle表: 支持头部信息的改写,一般不会用 INPUT链: 功能:处理目标地址是本机的入站数据包(例如访问本地服务的请求)。 应用场景:防火墙规则过滤进入本机的流量(如允许/拒绝SSH连接或HTTP请求)。 OUTPUT链: 功能:处理从本机生成并发出的出站数据包(例如浏览器访问外部网站)。 应用场景:控制本机程序对外通信的权限(如禁止某个应用联网)。 FORWARD链: 功能:处理经过本机转发的数据包(例如路由器或网关转发流量到其他设备)。 应用场景:配置网络转发规则(如允许内网设备通过本机访问外网)。 PREROUTING链: 功能:在路由决策前处理所有进入本机的数据包(无论目标是本机还是其他设备)。 应用场景:修改目标地址(DNAT),常用于端口转发或负载均衡。 POSTROUTING链: 功能:在路由决策后处理所有离开本机的数据包(包括转发和本机生成的流量)。 应用场景:修改源地址(SNAT),例如将内网IP转换为公网IP以访问互联网。 # 限制不让人访问81端口如何做? iptables -I INPUT -p tcp --dport 81 -j DROP

image

bash
当作老男孩框架,学员进入老男孩(网络层)进行学习,NetFilter把学员全部截获,分为不同班级进行学习(不同的表表示不同的功能)

image

2、每个表说明

1) filter表
  • 防火墙: 屏蔽或准许 端口 ip
filter表强调:主要和主机自身相关,真正负责主机防火墙功能的(过滤流入流出主机的数据包) filter表示iptables默认使用的表,这个表定义了三个链(chains) 企业工作场景:主机防火墙
INPUT负责过滤所有目标地址是本机地址的数据包 通俗来说:就是过滤进入主机的数据包
FORWARD负责转发流经主机的数据包。起转发的作用,和NAT关系很大,后面会详细介绍 LVS NAT模式,net.ipv4.ip_forward=0
OUTPUT处理所有源地址是本机地址的数据包 通俗的讲:就是处理从主机发出去的数据包
2) nat表
  • 实现nat功能

    • 实现共享上网(既有内网又有外网的主机,使用nat表实现路由器的功能,其他服务器网关指向iptables这台)
    • 端口映射和ip映射
NAT负责网络地址转换的,即来源与目的IP地址和port的转换。 应用:和主机本身无关,一般用于局域网共享上网或者特殊的端口转换服务相关。 工作场景: 1. 用于企业路由(zebra)或网关(iptables),共享上网(POSTROUTING) 2. 做内部外部IP地址一对一映射(dmz),硬件防火墙映射IP到内部服务器,ftp服务(PREROUTING) 3. WEB,单个端口的映射,直接映射80端口(PREROUTING) 这个表定义了3个链,nat功能相当于网络的acl控制。和网络交换机acl类似。
OUTPUT和主机放出去的数据包有关,改变主机发出数据包的目的地址。
PREROUTING在数据包到达防火墙时,进行路由判断之前执行的规则,作用是改变数据包的目的地址、目的端口等
就是收信时,根据规则重写收件人的地址。
例如:把公网IP:xxx.xxx.xxx.xxx映射到局域网的xx.xx.xx.xx服务器上。
如果是web服务,可以报80转换为局域网的服务器9000端口上
10.0.0.61 8080(目标端口) ----nat---à 10.0.0.7 22
POSTROUTING在数据包离开防火墙时进行路由判断之后执行的规则,作用改变数据包的源地址,源端口等。
写好发件人的地址,要让家人回信时能够有地址可回。
例如。默认笔记本和虚拟机都是局域网地址,在出网的时候被路由器将源地址改为了公网地址。
生产应用:局域网共享上网

57557cf1258bdf2519caf41e1a3a4dbd

bash
想要访问10.0.0.78:2222,iptables使用nat表的PREROUTING链,可以实现目标地址的改写,如果有人访问我10.0.0.78:2222,则把访问的目标 改写为172.16.1.51:22,属于DNAT,类似于nginx的4层转发 可以管理后端的方法: SSH免密钥 OPENvpn Jumpserver NAT功能(云服务器SNAT、DNAT)

538979f91582c32b34df575789429636

bash
上面PREROUTING目标地址的改写相当于DNAT,除了DNAT还有SNAT源地址的改写,如果172.16.1.51想上网,经过SNAT访问外网的百度,网关需要配置 成172.16.1.78。用iptables的POSTROUTING链将172.16.1.51改写成10.0.0.78,属于SNAT

image

3、环境准备及命令

bash
#停止防火墙 [root@m01 ~]# systemctl stop firewalld [root@m01 ~]# systemctl disable firewalld [root@oldboy-m01 ~]# uname -r 3.10.0-862.el7.x86_64 #下载iptables [root@oldboy-m01 ~]# yum install -y iptables-services [root@m01 ~]# rpm -ql iptables /etc/sysconfig/ip6tables /etc/sysconfig/iptables #防火墙的配置文件 /usr/lib/systemd/system/ip6tables.service /usr/lib/systemd/system/iptables.service #防火墙服务配置文件(命令) #防火墙相关模块 加载到内核中 modprobe ip_tables modprobe iptable_filter modprobe iptable_nat modprobe ip_conntrack modprobe ip_conntrack_ftp modprobe ip_nat_ftp modprobe ipt_state #永久 cat >>/etc/rc.local<<EOF modprobe ip_tables modprobe iptable_filter modprobe iptable_nat modprobe ip_conntrack modprobe ip_conntrack_ftp modprobe ip_nat_ftp modprobe ipt_state EOF [root@m01 ~]# lsmod |egrep 'filter|nat|ipt' nf_nat_ftp 12770 0 nf_conntrack_ftp 18638 1 nf_nat_ftp iptable_nat 12875 0 nf_nat_ipv4 14115 1 iptable_nat nf_nat 26787 2 nf_nat_ftp,nf_nat_ipv4 nf_conntrack 133053 6 nf_nat_ftp,nf_nat,xt_state,nf_nat_ipv4,nf_conntrack_ftp,nf_conntrack_ipv4 iptable_filter 12810 0 ip_tables 27126 2 iptable_filter,iptable_nat libcrc32c 12644 3 xfs,nf_nat,nf_conntrack [root@m01 ~]# systemctl start iptables.service [root@m01 ~]# systemctl enable iptables.service Created symlink from /etc/systemd/system/basic.target.wants/iptables.service to /usr/lib/systemd/system/iptables.service. [root@m01 ~]# iptables -nL # 默认filter表 Chain INPUT (policy ACCEPT) # INPUT链,表示进来的,默认的规则是允许所有人可以访问我,具体看下面规则 #动作 #端口/协议 #源地址,拒绝谁 #目标地址,拒绝谁访问我ip target prot opt source destination ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED # TCP三次握手四次挥手11种状态集 ACCEPT icmp -- 0.0.0.0/0 0.0.0.0/0 #允许ping协议 ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 state NEW tcp dpt:22 #允许任意ip的网段访问我任意网段,放行22端口 REJECT all -- 0.0.0.0/0 0.0.0.0/0 reject-with icmp-host-prohibited # 除了上面其他都被丢弃 # 规则从上往下执行,最后在默认 Chain FORWARD (policy ACCEPT) # FORWARD链,默认的规则是允许所有人可以访问我,具体看下面规则 target prot opt source destination REJECT all -- 0.0.0.0/0 0.0.0.0/0 reject-with icmp-host-prohibited Chain OUTPUT (policy ACCEPT) # OUTPUT链,表示出去的,默认的规则是允许所有人可以访问我,具体看下面规则 target prot opt source destination

4e67e000e4b44408bffff37ae539a0f2_image-20200212105352301

4、iptables命令参数

参数含义
-L显示表中的所有规则
-n不要把端口 或ip反向解析为 名字
-t指定表 不指定默认是filter表
-Aappend 追加 加入准许类规则 使用-A
-Ddelete 删除 -D INPUT 1
-Iinsert 拒绝类规则放在所有规则最上面 拒绝类 -I
--line-numbers显示行号
参数含义
-p协议 protocal tcp/udp/icmp/all
--dport目标端口 dest destination 指定端口 加上协议 -p tcp
--sport源端口 source 源
-s--source 源ip
-d--destination 目标ip
-m指定模块 multiport
-iinput 输入的时候 从哪个网卡进来
-oouput 输出的时候 从哪个网卡出去
参数含义
-j满足条件后的动作 : DROP/ACCEPT/REJECT
DROP REJECT拒绝
DROP把数据丢掉 不会返回信息给用户
REJECT 拒绝 返回拒绝信息
参数含义
-F flush清除所有规则,不会处理默认的规则
-X删除用户自定义的链
-Z链的计数器清零(数据包计数器与数据包字节计数器)

5、配置filter表规则

  • 正式配置之前 先备份, 清空规则
bash
[root@m01 ~]# iptables -F # 清空 [root@m01 ~]# iptables -X [root@m01 ~]# iptables -Z [root@m01 ~]# iptables -nL Chain INPUT (policy ACCEPT) target prot opt source destination Chain FORWARD (policy ACCEPT) target prot opt source destination Chain OUTPUT (policy ACCEPT) target prot opt source destination #重启会恢复规则,因为规则默认写在了配置文件里 [root@j01 /etc/yum.repos.d]#systemctl restart iptables [root@j01 /etc/yum.repos.d]#iptables -nL Chain INPUT (policy ACCEPT) target prot opt source destination ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED ACCEPT icmp -- 0.0.0.0/0 0.0.0.0/0 ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 state NEW tcp dpt:22 REJECT all -- 0.0.0.0/0 0.0.0.0/0 reject-with icmp-host-prohibited Chain FORWARD (policy ACCEPT) target prot opt source destination REJECT all -- 0.0.0.0/0 0.0.0.0/0 reject-with icmp-host-prohibited Chain OUTPUT (policy ACCEPT) target prot opt source destination #查看配置文件 [root@j01 /etc/yum.repos.d]#cat /etc/sysconfig/iptables # sample configuration for iptables service # you can edit this manually or use system-config-firewall # please do not ask us to add additional ports/services to this default configuration *filter :INPUT ACCEPT [0:0] :FORWARD ACCEPT [0:0] :OUTPUT ACCEPT [0:0] -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT -A INPUT -p icmp -j ACCEPT -A INPUT -i lo -j ACCEPT -A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT -A INPUT -j REJECT --reject-with icmp-host-prohibited -A FORWARD -j REJECT --reject-with icmp-host-prohibited COMMIT #当开启上面的规则后只允许22端口,那么80端口将被禁止,浏览器测试

image

image

bash
# 清空规则 [root@j01 /etc/yum.repos.d]#iptables -F [root@j01 /etc/yum.repos.d]#iptables -nL Chain INPUT (policy ACCEPT) target prot opt source destination Chain FORWARD (policy ACCEPT) target prot opt source destination Chain OUTPUT (policy ACCEPT) target prot opt source destination #访问测试

image

1、禁止访问端口
bash
#1、禁止访问22端口 [root@j01 /etc/yum.repos.d]#iptables -I INPUT -p tcp --dport 22 -j DROP -I INPUT:在INPUT链里面插入 -p tcp:协议是TCP --dport 22:访问我的22端口 -j DROP:动作是拒绝 [root@j01 /etc/yum.repos.d]#iptables -D INPUT -p tcp --dport 22 -j DROP 创建规则后被踢出xshell连接,登录vmware把规则删掉 #删除规则 查看序号 [root@m01 ~]# iptables -nL --line Chain INPUT (policy ACCEPT) num target prot opt source destination 1 DROP tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:80 根据序号删除规则 [root@m01 ~]# iptables -D INPUT 1 第二种删除方式: [root@j01 ~]#iptables -D INPUT -p tcp --dport 22 -j DROP #2、禁止80端口 [root@j01 ~]#iptables -I INPUT -p TCP --dport 80 -j DROP 访问测试

image

bash
#2、删除禁止80端口规则 [root@j01 ~]#iptables -D INPUT -p TCP --dport 80 -j DROP [root@j01 ~]#iptables -nL Chain INPUT (policy ACCEPT) target prot opt source destination Chain FORWARD (policy ACCEPT) target prot opt source destination Chain OUTPUT (policy ACCEPT) target prot opt source destination 访问测试

image

2、封ip 屏蔽某个ip
bash
#封掉10.0.0.7的ip,所有,包括连接,ping [root@j01 ~]#iptables -I INPUT -s 10.0.0.7 -j DROP [root@j01 ~]#iptables -nL Chain INPUT (policy ACCEPT) target prot opt source destination DROP all -- 10.0.0.7 0.0.0.0/0 Chain FORWARD (policy ACCEPT) target prot opt source destination Chain OUTPUT (policy ACCEPT) target prot opt source destination #7段ping、ssh测试,不通 [root@web01 ~]#ping 10.0.0.20 PING 10.0.0.20 (10.0.0.20) 56(84) bytes of data. ^C --- 10.0.0.20 ping statistics --- 3 packets transmitted, 0 received, 100% packet loss, time 2085ms [root@web01 ~]#ssh 10.0.0.20 ssh: connect to host 10.0.0.20 port 22: Connection timed out [root@web01 ~]# #172段ping测试,通,因为没对172做限制 [root@web01 ~]#ping 172.16.1.20 PING 172.16.1.20 (172.16.1.20) 56(84) bytes of data. 64 bytes from 172.16.1.20: icmp_seq=1 ttl=64 time=22.7 ms 64 bytes from 172.16.1.20: icmp_seq=2 ttl=64 time=27.9 ms ^C #web02因为没做禁止,所有可以ping通 [root@web02 ~]#ping 10.0.0.20 PING 10.0.0.20 (10.0.0.20) 56(84) bytes of data. 64 bytes from 10.0.0.20: icmp_seq=1 ttl=64 time=0.506 ms 64 bytes from 10.0.0.20: icmp_seq=2 ttl=64 time=0.432 ms #删除规则 [root@j01 ~]#iptables -D INPUT -s 10.0.0.7 -j DROP [root@j01 ~]#iptables -nL Chain INPUT (policy ACCEPT) target prot opt source destination Chain FORWARD (policy ACCEPT) target prot opt source destination Chain OUTPUT (policy ACCEPT) target prot opt source destination 案例:封禁访问超过5000的ip做封禁 #1、用web02做压力测试访问web01 [root@web02 ~]#ab -n2000 -c20 http://10.0.0.7/index.html #2、统计 [root@web01 ~]#cat /var/log/nginx/access.log|awk '{print $1}'|sort|uniq -c|awk '$1>5000' 6000 10.0.0.8 #3、封禁 [root@j01 ~]#iptables -I INPUT -s 10.0.0.8 -j DROP
3、禁止网段连入
bash
#1、禁止172.16.1.0/24,默认在上面 [root@j01 ~]#iptables -I INPUT -s 172.16.1.0/24 -j DROP [root@j01 ~]#iptables -nL Chain INPUT (policy ACCEPT) target prot opt source destination DROP all -- 172.16.1.0/24 0.0.0.0/0 #先执行这个 DROP all -- 10.0.0.8 0.0.0.0/0 #再执行这个,上下有逻辑关系,如果上面禁止这个ip,下面允许了也连不上 Chain FORWARD (policy ACCEPT) target prot opt source destination Chain OUTPUT (policy ACCEPT) target prot opt source destination #如果想把规则写到下面,那就是追加,-A是追加 [root@j01 ~]#iptables -A INPUT -s 172.16.1.0/24 -j DROP [root@j01 ~]#iptables -nL Chain INPUT (policy ACCEPT) target prot opt source destination DROP all -- 10.0.0.8 0.0.0.0/0 DROP all -- 172.16.1.0/24 0.0.0.0/0 Chain FORWARD (policy ACCEPT) target prot opt source destination Chain OUTPUT (policy ACCEPT) target prot opt source destination #测试,不通 [root@web01 ~]#ping 172.16.1.20 PING 172.16.1.20 (172.16.1.20) 56(84) bytes of data. ^C --- 172.16.1.20 ping statistics --- 2 packets transmitted, 0 received, 100% packet loss, time 1021ms #2、禁止172.16.1.0的22端口 [root@j01 ~]#iptables -I INPUT -s 172.16.1.0/24 -p tcp --dport 22 -j DROP [root@j01 ~]#iptables -nL Chain INPUT (policy ACCEPT) target prot opt source destination DROP tcp -- 172.16.1.0/24 0.0.0.0/0 tcp dpt:22 DROP all -- 10.0.0.8 0.0.0.0/0 Chain FORWARD (policy ACCEPT) target prot opt source destination Chain OUTPUT (policy ACCEPT) target prot opt source destination #测试,ping是通的,ssh连接不上 [root@web01 ~]#ping 172.16.1.20 PING 172.16.1.20 (172.16.1.20) 56(84) bytes of data. 64 bytes from 172.16.1.20: icmp_seq=1 ttl=64 time=0.430 ms 64 bytes from 172.16.1.20: icmp_seq=2 ttl=64 time=0.513 ms ^C --- 172.16.1.20 ping statistics --- 2 packets transmitted, 2 received, 0% packet loss, time 1011ms rtt min/avg/max/mdev = 0.430/0.471/0.513/0.041 ms [root@web01 ~]#ssh 172.16.1.20 #curl80端口 [root@web01 ~]#curl 172.16.1.20 <!DOCTYPE html><html><head><meta charset=utf-8><meta content="IE=edge,chrome=1" http-equiv=X-UA-Compatible><meta content=0 http-equiv=Expires><meta content=no-cache http-equiv=Pragma><meta content=no-cache http-equiv=Cache-control><meta content=no-cache http-equiv=Cache><meta content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no" name=viewport><title></title><link href=/ui/theme/element-ui.css rel=stylesheet><style>#loading { position: fixed; top: 0; #curl头部信息 [root@web01 ~]#curl -I 172.16.1.20 HTTP/1.1 200 OK Server: nginx Date: Mon, 19 May 2025 13:06:07 GMT Content-Type: text/html Content-Length: 22650 Connection: keep-alive Vary: Accept-Encoding Last-Modified: Thu, 17 Apr 2025 12:30:12 GMT Vary: Accept-Encoding ETag: "6800f454-587a" Accept-Ranges: bytes # 先允许后拒绝,可以连接、先拒绝后允许,不可以连接 规则执行机制解析: Chain INPUT (policy DROP) # 默认策略为DROP(丢弃所有) 1. ACCEPT all -- 10.0.0.0/24 0.0.0.0/0 # 规则1:允许10.0.0.0/24 2. DROP all -- 10.0.0.0/24 0.0.0.0/0 # 规则2:拒绝10.0.0.0/24 关键原理:"首次匹配"原则 当来自 10.0.0.5 的数据包进入INPUT链: 首先匹配规则1:源IP在 10.0.0.0/24 范围内 → 匹配成功 执行动作:ACCEPT(接受) 规则处理立即终止!不再检查后续规则 规则2永远不会被执行: 因为规则1已经接受了该流量 iptables 的规则处理是"短路逻辑",匹配成功后立即停止
4、只允许指定网段连入

实现阿里云白名单功能 :默认是拒绝 开放端口 网段

allow 10.0.0.0/24;

deny all;

bash
#方法1: 利用!进行排除 #只准许 10.0.0.0/24 访问 言外之意 除了 10.0.0.0/24 都拒绝 iptables -I INPUT ! -s 10.0.0.0/24 -j DROP #!只允许10.0.0.0/24段 [root@web01 ~]#iptables -I INPUT ! -s 10.0.0.0/24 -j DROP [root@web01 ~]#iptables -nL Chain INPUT (policy ACCEPT) target prot opt source destination DROP all -- !10.0.0.0/24 0.0.0.0/0 Chain FORWARD (policy ACCEPT) target prot opt source destination Chain OUTPUT (policy ACCEPT) target prot opt source destination #10段可以ping通,172段不通 [root@web01 ~]#ping 10.0.0.20 PING 10.0.0.20 (10.0.0.20) 56(84) bytes of data. 64 bytes from 10.0.0.20: icmp_seq=1 ttl=64 time=0.365 ms 64 bytes from 10.0.0.20: icmp_seq=2 ttl=64 time=0.417 ms ^C --- 10.0.0.20 ping statistics --- 2 packets transmitted, 2 received, 0% packet loss, time 1061ms rtt min/avg/max/mdev = 0.365/0.391/0.417/0.026 ms [root@web01 ~]#ping 172.16.1.20 PING 172.16.1.20 (172.16.1.20) 56(84) bytes of data. ^C --- 172.16.1.20 ping statistics --- 4 packets transmitted, 0 received, 100% packet loss, time 3055ms #方法2: 修改链默认规则 ,先添加准许规则再修改为拒绝!!要不容易连接不上。 #添加10.0.0.0/24允许规则 [root@j01 ~]#iptables -I INPUT -s 10.0.0.0/24 -j ACCEPT #修改默认规则为拒绝 [root@j01 ~]#iptables -P INPUT DROP #默认变成拒绝 [root@j01 ~]#iptables -nL Chain INPUT (policy DROP) target prot opt source destination ACCEPT all -- 10.0.0.0/24 0.0.0.0/0 Chain FORWARD (policy ACCEPT) target prot opt source destination Chain OUTPUT (policy ACCEPT) target prot opt source destination #测试完成后 修改回去 ​ iptables -P INPUT ACCEPT
5、指定多个端口
bash
#-m multiport多端口,禁止80跟443端口 [root@m01 ~]# iptables -I INPUT -p tcp -m multiport --dport 80,443 -j DROP [root@j01 ~]#iptables -nL Chain INPUT (policy ACCEPT) target prot opt source destination DROP tcp -- 0.0.0.0/0 0.0.0.0/0 multiport dports 80,443 Chain FORWARD (policy ACCEPT) target prot opt source destination Chain OUTPUT (policy ACCEPT) target prot opt source destination #测试

image

bash
#取反,除了80跟443,其他都禁掉 [root@m01 ~]# iptables -I INPUT -p tcp -m multiport !--dport 80,443 -j DROP #如果是 连续的端口 可以不加上-m multiport 1:1024 [root@m01 ~]# iptables -I INPUT -p tcp --dport 1:1024 -j DROP
6、匹配ICMP类型
bash
通过防火墙规则 控制是否可以ping #限制10.0.0.7的ping,icmp --icmp-type 8固定写法 [root@j01 ~]#iptables -I INPUT -s 10.0.0.7 -p icmp --icmp-type 8 -j DROP [root@j01 ~]#iptables -nL Chain INPUT (policy ACCEPT) target prot opt source destination DROP icmp -- 10.0.0.7 0.0.0.0/0 icmptype 8 DROP tcp -- 0.0.0.0/0 0.0.0.0/0 multiport dports 80,443 Chain FORWARD (policy ACCEPT) target prot opt source destination Chain OUTPUT (policy ACCEPT) target prot opt source destination [root@j01 ~]# #ping测试,不通 [root@web01 ~]#ping 10.0.0.20 PING 10.0.0.20 (10.0.0.20) 56(84) bytes of data. #通过内核参数 控制 禁止被ping [root@m01 ~]# cat /etc/sysctl.conf #/proc/sys/net/ipv4/icmp_echo_ignore_all net.ipv4.icmp_echo_ignore_all = 1 [root@m01 ~]# sysctl -p net.ipv4.icmp_echo_ignore_all = 1 [root@oldboy-m01 ~]# echo 1 >/proc/sys/net/ipv4/icmp_echo_ignore_all [root@oldboy-m01 ~]# #net.ipv4.icmp_echo_ignore_all=1 写入到 /etc/sysctl.conf [root@oldboy-m01 ~]# #sysctl -p #测试。ping不通 [root@web02 ~]#ping 10.0.0.20 PING 10.0.0.20 (10.0.0.20) 56(84) bytes of data. ^C --- 10.0.0.20 ping statistics --- 2 packets transmitted, 0 received, 100% packet loss, time 1016ms [root@web02 ~]#ping 172.16.1.20 PING 172.16.1.20 (172.16.1.20) 56(84) bytes of data. #改为0 [root@oldboy-m01 ~]# echo 0 >/proc/sys/net/ipv4/icmp_echo_ignore_all #测试。通 [root@web02 ~]#ping 172.16.1.20 PING 172.16.1.20 (172.16.1.20) 56(84) bytes of data. 64 bytes from 172.16.1.20: icmp_seq=51 ttl=64 time=0.680 ms 64 bytes from 172.16.1.20: icmp_seq=52 ttl=64 time=0.481 ms 64 bytes from 172.16.1.20: icmp_seq=53 ttl=64 time=0.610 ms
7、防火墙规则的保存与恢复
  • iptables-save 默认输出到屏幕
  • iptables-restore 加上文件
  • 写入到/etc/sysconfig/iptables
bash
[root@j01 ~]#iptables-save # Generated by iptables-save v1.8.5 on Mon May 19 22:18:35 2025 *nat :PREROUTING ACCEPT [102:5481] :INPUT ACCEPT [1:52] :OUTPUT ACCEPT [0:0] :POSTROUTING ACCEPT [0:0] COMMIT # Completed on Mon May 19 22:18:35 2025 # Generated by iptables-save v1.8.5 on Mon May 19 22:18:35 2025 *filter :INPUT ACCEPT [228:18175] :FORWARD ACCEPT [0:0] :OUTPUT ACCEPT [146:13472] -A INPUT -p tcp -m multiport --dports 80,443 -j DROP COMMIT # Completed on Mon May 19 22:18:35 2025 #关闭防火墙后将不显示规则 [root@j01 ~]#systemctl stop iptables.service [root@j01 ~]#iptables-save # Generated by iptables-save v1.8.5 on Mon May 19 22:19:41 2025 *nat :PREROUTING ACCEPT [0:0] :INPUT ACCEPT [0:0] :OUTPUT ACCEPT [0:0] :POSTROUTING ACCEPT [0:0] COMMIT # Completed on Mon May 19 22:19:41 2025 # Generated by iptables-save v1.8.5 on Mon May 19 22:19:41 2025 *filter :INPUT ACCEPT [6:428] :FORWARD ACCEPT [0:0] :OUTPUT ACCEPT [4:528] COMMIT # Completed on Mon May 19 22:19:41 2025 #1、添加放行规则 [root@j01 ~]#iptables -A INPUT -m multiport -p tcp --dport 443,80,22 -j ACCEPT # -A 追加 [root@j01 ~]#iptables -A INPUT -s 10.0.0.0/24 -j ACCEPT [root@j01 ~]#iptables -A INPUT -s 172.16.1.0/24 -j ACCEPT [root@j01 ~]#iptables -A INPUT -i lo -j ACCEPT #lo是自己本机的127.0.0.1 [root@j01 ~]#iptables -nL Chain INPUT (policy ACCEPT) target prot opt source destination ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 multiport dports 443,80,22 ACCEPT all -- 10.0.0.0/24 0.0.0.0/0 ACCEPT all -- 172.16.1.0/24 0.0.0.0/0 ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 Chain FORWARD (policy ACCEPT) target prot opt source destination Chain OUTPUT (policy ACCEPT) target prot opt source destination #2、将默认放行规则改为拒绝 [root@j01 ~]#iptables -P INPUT DROP #3、将规则保存到文件中,企业必须备份!!! [root@j01 ~]#iptables-save >/etc/sysconfig/iptables #4、如果不小心把规则给删掉,恢复方法有两种 [root@oldboy-m01 ~]# systemctl restart iptables.service [root@oldboy-m01 ~]# iptables-restore </etc/sysconfig/iptables

6、nat

  • 共享上网

  • 端口转发/端口映射

  • ip映射

    bash
    [root@m01 ~]# iptables -P INPUT ACCEPT [root@m01 ~]# iptables -P FORWARD ACCEPT [root@m01 ~]# iptables -nL Chain INPUT (policy ACCEPT) target prot opt source destination DROP icmp -- 0.0.0.0/0 0.0.0.0/0 icmptype 8 ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:22 ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 multiport dports 443,80 ACCEPT all -- 10.0.0.0/24 0.0.0.0/0 ACCEPT all -- 172.16.1.0/24 0.0.0.0/0 ​ Chain FORWARD (policy ACCEPT) target prot opt source destination ​ Chain OUTPUT (policy ACCEPT) target prot opt source destination ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 [root@m01 ~]# iptables -F [root@m01 ~]# iptables -nL Chain INPUT (policy ACCEPT) target prot opt source destination ​ Chain FORWARD (policy ACCEPT) target prot opt source destination ​ Chain OUTPUT (policy ACCEPT) target prot opt source destination

image

实现共享上网

03c9b403a5335bebfabb99203b8ae4d5_E88081E794B7E5ADA9E69599E882B2-iptables-E585B1E4BAABE4B88AE7BD91

1. 防火墙配置
bash
#当有172.16.1.0网段出网的时候,则把它改为10.0.0.20 [root@j01 ~]#iptables -t nat -A POSTROUTING -s 172.16.1.0/24 -j SNAT --to-source 10.0.0.20 -t nat:指定nat表 -A POSTROUTING:使用POSTROUTING链 -s 172.16.1.0/24:指定源 -j SNAT:动作源地址转换 --to-source 10.0.0.20:改为10.0.0.20 [root@j01 ~]#iptables -t nat -nL Chain PREROUTING (policy ACCEPT) target prot opt source destination Chain INPUT (policy ACCEPT) target prot opt source destination Chain OUTPUT (policy ACCEPT) target prot opt source destination Chain POSTROUTING (policy ACCEPT) target prot opt source destination SNAT all -- 172.16.1.0/24 0.0.0.0/0 to:10.0.0.20 #开启内核转发,实现路由功能 [root@j01 ~]# echo 'net.ipv4.ip_forward = 1' >> /etc/sysctl.conf [root@j01 ~]# sysctl -p net.ipv4.icmp_echo_ignore_all = 0 net.ipv4.ip_forward = 1 #注意事项: 公网ip不固定: iptables -t nat -A POSTROUTING -s 172.16.1.0/24 -j MASQUERADE
2、web配置
bash
两种配置: #第一种 #1、把外网的网卡down掉 [root@web02 ~]#ifdown ens33 #2、通过ssh连接172 [root@web01 ~]#ssh 172.16.1.8 #3、指定网卡为172.16.1.20 [root@web02 ~]#vim /etc/sysconfig/network-scripts/ifcfg-ens36 TYPE=Ethernet BOOTPROTO=none NAME=ens36 DEVICE=ens36 ONBOOT=yes PREFIX=24 IPADDR=172.16.1.8 GATEWAY=172.16.1.20 DNS1=223.5.5.5 #4、重启36网卡 [root@web02 ~]#ifdown ens36 && ifup ens36 #5、查看网关 [root@web02 ~]#route -n Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface 0.0.0.0 172.16.1.20 0.0.0.0 UG 100 0 0 ens36 172.16.1.0 0.0.0.0 255.255.255.0 U 100 0 0 ens36 #6、ping百度测试 [root@web01 ~]#ping www.baidu.com PING www.a.shifen.com (110.242.70.57) 56(84) bytes of data. 64 bytes from 110.242.70.57 (110.242.70.57): icmp_seq=1 ttl=127 time=10.9 ms 64 bytes from 110.242.70.57 (110.242.70.57): icmp_seq=2 ttl=127 time=12.0 ms 64 bytes from 110.242.70.57 (110.242.70.57): icmp_seq=3 ttl=127 time=12.0 ms 第二种方式,待补充 #删掉网关 [root@web02 ~]#ip route del 0/0 via 10.0.0.2 [root@web02 ~]#route -n Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface 0.0.0.0 10.0.0.2 0.0.0.0 UG 101 0 0 ens36 10.0.0.0 0.0.0.0 255.255.255.0 U 100 0 0 ens33 10.0.0.2 0.0.0.0 255.255.255.255 UH 101 0 0 ens36 172.16.1.0 0.0.0.0 255.255.255.0 U 101 0 0 ens36 [root@web02 ~]#ip route del 0/0 via 10.0.0.2 [root@web02 ~]#route -n Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface 10.0.0.0 0.0.0.0 255.255.255.0 U 100 0 0 ens33 10.0.0.2 0.0.0.0 255.255.255.255 UH 101 0 0 ens36 172.16.1.0 0.0.0.0 255.255.255.0 U 101 0 0 ens36 #添加20服务器的网关,默认是上不去网的 [root@web02 ~]#ip route add 0/0 via 172.16.1.20 [root@web02 ~]#route -n Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface 0.0.0.0 172.16.1.20 0.0.0.0 UG 0 0 0 ens36 10.0.0.0 0.0.0.0 255.255.255.0 U 100 0 0 ens33 10.0.0.2 0.0.0.0 255.255.255.255 UH 101 0 0 ens36 172.16.1.0 0.0.0.0 255.255.255.0 U 101 0 0 ens36 [root@web02 ~]#ping www.baidu.com

iptables实现目标地址映射

1a4f4f796dbf06a80a80a36268e539b8_E88081E794B7E5ADA9E69599E882B2-iptables-E7ABAFE58FA3E8BDACE58F91

image

bash
# 当访问我的10.0.0.20的1111那么让你访问172.16.1.7:22 [root@j01 ~]#iptables -t nat -A PREROUTING -d 10.0.0.20 -p tcp --dport 1111 -j DNAT --to-destination 172.16.1.7:22 [root@j01 ~]#iptables -nL -t nat Chain PREROUTING (policy ACCEPT) target prot opt source destination DNAT tcp -- 0.0.0.0/0 10.0.0.20 tcp dpt:2222 to:172.16.1.8:22 Chain INPUT (policy ACCEPT) target prot opt source destination Chain OUTPUT (policy ACCEPT) target prot opt source destination Chain POSTROUTING (policy ACCEPT) target prot opt source destination #连接测试,可以正常连接 [C:\~]$ ssh 10.0.0.20 1111 Connecting to 10.0.0.20:1111... Connection established. To escape to local shell, press 'Ctrl+Alt+]'. Authorized users only. All activities may be monitored and reported. WARNING! The remote SSH server rejected X11 forwarding request. Activate the web console with: systemctl enable --now cockpit.socket Last login: Tue May 20 07:52:41 2025 from 172.16.1.8 [root@web01 ~]#ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000 link/ether 00:0c:29:02:88:28 brd ff:ff:ff:ff:ff:ff 3: ens36: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000 link/ether 00:0c:29:02:88:32 brd ff:ff:ff:ff:ff:ff inet 172.16.1.7/24 brd 172.16.1.255 scope global noprefixroute ens36 valid_lft forever preferred_lft forever inet6 fe80::20c:29ff:fe02:8832/64 scope link valid_lft forever preferred_lft forever [root@web01 ~]#

7、总结

bash
练习题: 【面试题】老男孩教育防火墙企业面试题iptalbes https://www.jianshu.com/p/19422676b854 5、请写出查看iptables当前所有规则的命令。 iptables-save iptables -nL iptables -nL -t nat 6、禁止来自10.0.0.188 ip地址访问80端口的请求 iptables -I INPUT -s 10.0.0.188 -p tcp --dport 80 -j DROP 7、如何使在命令行执行的iptables规则永久生效? iptables-save ​ /etc/sysconfig/iptables 8、实现把访问10.0.0.3:80的请求转到172.16.1.17:80 iptables -t nat -A PREROUTING -d 10.0.0.3 -p tcp --dport 80 -j DNAT --to-destination 172.16.xxxx:80 9、实现172.16.1.0/24段所有主机通过124.32.54.26外网IP共享上网。 iptables -t nat -A POSTROUTING -s 172.16.1.0/24 -j SNAT --to-source 123.32.54.26 ​ iptables -t nat -A POSTROUTING -s 172.16.1.0/24 -j SNAT MASQUERADE 10.案例 iptalbes 实现防止syn ddos 和ping攻击 -A FORWARD -p tcp --syn -m limit --limit 1/s --limit-burst 5 -j ACCEPT -A FORWARD -p tcp --tcp-flags SYN,ACK,FIN,RST RST -m limit --limit 1/s -j ACCEPT -A FORWARD -p icmp --icmp-type echo-request -m limit --limit 1/s -j ACCEPT 说明:第一行:每秒中最多允许5个新连接。第二行:防止各种端口扫描。第三行:Ping洪水攻击(Ping of Death),可以根据需要调整或关闭 防火墙 笔试题 www.jianshu.com/p/2180face8381

22、shell

1、shell基础篇

1、shell编程大纲
bash
1.Shell的作用 2.什么是Shell 3.了解编程语言 4.如何学习shell 5.学习shell必会的基础知识 6.第一个shell脚本 7.执行shell的方式、执行脚本方式的区别 8.变量定义方式、变量调用 9.变量子串知识(笔试题) 10.数值运算 11.数值比对 12.字符串比对、正则比对 13.判断if判断 14.for循环 while循环 15.循环控制语句 break continue exit return 16.函数定义、调用 17.数组定义、调用 其中以上技术内容穿插了很多的技术案例。 云计算运维人员必会的技术之一。
2、Shell的作用
bash
用shell来干嘛? 1.安装操作系统、kickstart cobbler自动化安装操作系统 2.操作系统优化、安装常用命令、时间同步、优化防火墙、修改默认的YUM源、加大文件描述符、Selinux、修改默认SSH端口、禁用root登录改用普通账号,使用shell脚本 3.安装服务,使用脚本部署安装 4.优化服务,代码变更,使用shell脚本辅助发版 5.监控硬件、操作系统、服务存活、服务运行状态、业务,zabbix+shell取值监控 6.日志切割,shell脚本实现 7.数据统计、分析,通过shell实现 8.编写启动、停止脚本(tomct) 不被systemctl所管理的项目,python 9.辅助程序(业务)健康运行 开发程序问题(程序死了、程序退出了、内存干满了、磁盘干满了、CPU干满了) 甚至有些企业为了赶进度、拿到需求写完需求不在管了,直接扔给测试部门、运维部门直接运行。 10.写数据项目、游戏项目。 云计算 DBA 运维安全 运维开发
3、什么是Shell
bash
Shell是命令解释器、用来解释用户输入的命令给内核,由内核驱动硬件处理数据,完成后由内核将结果返回给shell。 Shell由很多种类的解释器。Linux系统默认的解释器为bash ‌Bash (Bourne Again Shell)‌ ‌特点‌:最流行的Linux默认Shell,兼容Bourne Shell语法,支持命令历史、自动补全等交互功能。 ‌应用场景‌:系统管理、脚本编写及日常命令行操作。 ‌Zsh (Z Shell)‌ ‌特点‌:集成了Bash和Ksh的特性,提供更强大的自动补全、主题/插件支持(如Oh My Zsh框架)。 ‌应用场景‌:开发者偏好,追求个性化与效率。 ‌Ksh (Korn Shell)‌ ‌特点‌:结合Bourne Shell与C Shell优点,性能优越,支持高级脚本特性。 ‌应用场景‌:企业级复杂脚本开发。 ‌Csh/Tcsh (C Shell)‌ ‌特点‌:语法类似C语言,提供交互式功能(如命令历史),但已被Bash取代。 ‌应用场景‌:习惯C语法的用户或遗留系统维护。 ‌Fish (Friendly Interactive Shell)‌ ‌特点‌:新手友好,自带语法高亮、自动建议等现代功能。 ‌应用场景‌:注重用户体验的命令行初学者。 ‌Sh (Bourne Shell)‌ ‌特点‌:最早的Unix Shell,简洁高效,适合基础脚本。 ‌应用场景‌:系统启动脚本或兼容性要求高的环境。 什么是Shell脚本? 将多条可执行命令写入到文本中,成为shell脚本.此文本包含了变量、判断、循环、函数、属组...
4、了解各种编程语言
5、如何学习Shell
bash
1.基础牢固,变量、数值比对、字符串比对。 2.看的懂脚本,可以看着写出来然后再自己写(熟练) 3.熟练后可以根据脚本自己进行修改、扩展、完善 4.切忌拿来即用,需求->百度->每行的含义吸收。
6、学习Shell脚本必会的基础知
bash
1.Shell基础命令 包括sed awk grep 2.vim编辑器、快捷键 3.xshell
7、书写Shell脚本的规范
bash
1.Shell脚本开头必须有解释器 #!/bin/bash或者 #!/bin/sh 2.Shell脚本必须以.sh结尾 [root@shell ~/Shell/day01]#ll total 4 -rw-r--r-- 1 root root 13 May 20 10:07 test.sh 3.Shell脚本有作者和脚本的作用注释 [root@shell ~/Shell/day01]#cat test.sh #!/bin/bash #version v1.1 #作者: oldboy #时间: 20281010 #作用: 日志切割 4.脚本中注释尽量不使用中文。 5.脚本中的符号必须是英文 '' "" {} [] [[]] `` $ <> ‘’ “” {} 【】【【】】·· ¥ 《》 6.脚本中成对的符号一次性写完
8、第一个脚本
bash
[root@shell ~/Shell/day01]#cat test.sh #!/bin/bash # 指定解释器 #version v1.1 # 脚本的说明 #作者: oldboy #时间: 20281010 #作用: ceshi echo "Hello World!!" # 将字符串输出到屏幕上
9、运行Shell脚本方式
bash
# 方法1: 使用bash或者sh [root@shell ~/Shell/day01]#sh test.sh Hello World!! [root@shell ~/Shell/day01]#bash test.sh Hello World!! # 方法2: 使用路径的方式 必须给文件增加x执行权限。 绝对路径: [root@shell ~/Shell/day01]#/root/Shell/day01/test.sh -bash: /root/Shell/day01/test.sh: Permission denied [root@shell ~/Shell/day01]#chmod +x test.sh [root@shell ~/Shell/day01]#ll test.sh -rwxr-xr-x 1 root root 97 May 20 10:17 test.sh [root@shell ~/Shell/day01]#/root/Shell/day01/test.sh Hello World!! 相对路径: [root@shell ~/Shell/day01]#./test.sh Hello World!! # 方法3: 使用source或者. [root@shell ~/Shell/day01]#source test.sh Hello World!! [root@shell ~/Shell/day01]#. test.sh Hello World!! 其他执行方式: [root@shell ~/Shell/day01]#bash < test.sh Hello World!! 将屏幕上的命令作为命令运行 [root@shell ~/Shell/day01]#echo pwd pwd [root@shell ~/Shell/day01]#echo pwd|bash /root/Shell/day01 [root@shell ~/Shell/day01]#cat test.sh #!/bin/bash #version v1.1 #作者: oldboy #时间: 20281010 #作用: ceshi echo "Hello World!!" [root@shell ~/Shell/day01]#cat test.sh |bash Hello World!! Shell脚本执行方式的区别: bash和路径执行方式方式、运行方式都是相同的。 都是在子shell中执行 source和.执行方式和上面的执行方式不同 都是在父shell中执行 父shell: 登录操作系统后看到的就是父shell 子shell: 使用bash或路径运行的脚本都是子shell中运行的 在父shell中直接输入bash回车,会进入到子shell中,理解为生了个孩子。 子shell默认继承了父shell的变量 父shell不能继承子shell的变量 小结: 脚本的执行方式: 方法1. bash或者sh 方法2. 路径方式 绝对路径和相对路径 方法3. source或者.方式 bash和路径的方式执行都是在子shell中运行 source和.就是脚本中的内容拿到父shell中运行
10、脚本的变量
bash
什么是变量? 变量由一个固定的值表示一堆不固定的值。 name=oldboy x=1 y=x+1 变量的分类: 系统中已经存在环境变量、让我们正常使用操作系统而提前定义好的。 [root@shell ~/Shell/day01]#env SHELL=/bin/bash HISTCONTROL=ignoredups HISTSIZE=1000 HOSTNAME=shell PWD=/root/Shell/day01 LOGNAME=root XDG_SESSION_TYPE=tty MOTD_SHOWN=pam HOME=/root 环境变量(全局变量) # 类似国法 对所有的shell全都生效 环境变量(Environment Variable): 通过 export name=oldboy 定义的变量会成为环境变量,可被子进程继承。 普通变量(局部变量) # 类似家规 只对当前的shell生效 自己定义的变量(常用的变量) 局部变量(Local Variable): 通过 name=oldboy 定义的变量默认是局部变量,仅对当前 Shell 进程有效。 变量按照生命周期分类: 临时变量: 在命令行临时定义的、退出xshell失效 永久变量: 写在/etc/profile 文本中
11、变量的定义
bash
一.变量名称的定义 1)变量名称由数字下划线字母组合而成、不能由数字开头 2)等号两端不允许有空格 3)见名知意 4)大写、小写、大驼峰、小驼峰 选择自己喜欢的一种即可。 [root@shell ~]#NAME=oldboy [root@shell ~]#name=oldboy [root@shell ~]#Name_Age=oldboy [root@shell ~]#name_Age=oldboy 二.变量值的定义 1)数字的定义、必须是连续的,如果不连续需要加引号 [root@shell ~]#age=123 [root@shell ~]#echo $age 123 [root@shell ~]#age='123 423423' [root@shell ~]#echo $age 123 423423 2)字符串的定义、连续的字符串 [root@shell ~]#name=oldboy fwefw -bash: fwefw: command not found [root@shell ~]#name='oldboy fwefw' [root@shell ~]#echo $name oldboy fwefw 应用场景: 字符串定义路径 [root@shell ~]#dir=/etc/sysconfig/network-scripts [root@shell ~]#echo $dir /etc/sysconfig/network-scripts [root@shell ~]#cd $dir [root@shell /etc/sysconfig/network-scripts]# [root@shell ~]#viens33=/etc/sysconfig/network-scripts/ifcfg-ens33 [root@shell ~]#vim $viens33 [root@shell ~]#Test='echo hehe' [root@shell ~]#echo $Test echo hehe [root@j01 ~]#$Test # 直接执行$变量名时,变量的值echo hehe会被解析为命令 hehe 3)命令的定义 #如果变量的值用单引号双引号不加引号都是字符串 #如果用反引号则是先执行反引号中的内容,将结果赋值给变量 [root@shell ~]#Test=`echo hehe` [root@shell ~]#echo $Test hehe [root@j01 ~]#test=`echo 456` [root@j01 ~]#$test # 直接执行$变量名时,变量的值会在反引号里面先计算成456,然后会被解析为命令 -bash: 456: command not found [root@shell ~]#Test=$(echo hehe) [root@shell ~]#echo $Test hehe 重复赋值 [root@shell ~]#Test=$(echo oldboy) # 跟反引号的作用是一样的 [root@shell ~]#echo $Test oldboy 案例1.执行变量相当于执行变量中的命令 [root@shell ~]#Test=`echo hehe` # 执行的结果赋值给Test [root@shell ~]#Test='echo hehe' # 将echo hehe字符串赋值给Test [root@shell ~]#echo $Test echo hehe [root@shell ~]#$Test hehe 案例2.执行变量相当于执行变量中的命令 [root@shell ~]#Time=`date +%F-%H-%M-%S` [root@shell ~]#echo $Time 2025-05-20-11-14-40 [root@shell ~]#echo $Time 2025-05-20-11-14-40 [root@shell ~]#echo $Time 2025-05-20-11-14-40 [root@shell ~]#Time='date +%F-%H-%M-%S' [root@shell ~]#echo $Time date +%F-%H-%M-%S [root@shell ~]#date +%F-%H-%M-%S 2025-05-20-11-17-17 [root@shell ~]#$Time 2025-05-20-11-17-20 [root@shell ~]#$Time 2025-05-20-11-17-28 [root@shell ~]#$Time 2025-05-20-11-17-29 #案例.变量赋值变量 [root@shell ~]#name=oldboy [root@shell ~]#Test=$name_test [root@shell ~]#echo $Test [root@shell ~]#Test=${name}_test [root@shell ~]#echo $Test oldboy_test 案例2.变量赋值变量的PATH应用 [root@shell ~]##需求/opt/bin/mvn 写入到PATH变量中 [root@shell ~]#echo $PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/root/bin [root@shell ~]#PATH='/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/root/bin:/opt/bin/' [root@shell ~]#PATH="$PATH:/opt/bin/" 定义变量方式: export name=oldboy和 name=oldboy的区别 加export针对当前连接的窗口中所有的bash都生效 不加export只针对当前的shell生效 让所有的窗口所有的bash都生效 写入/etc/profile,因为每次重启系统或者每次重新xshell连接系统都会执行/etc/profile [root@shell ~]#tail -1 /etc/profile export name=oldboy 变量相关的配置文件: 一个一个运行 /etc/profile #执行顺序,1 .bash_profile #执行顺序,4 .bashrc #执行顺序,3 /etc/bashrc #执行顺序,2 echo $name
12、变量的子串
bash
1.统计字符串的长度 方法1: [root@shell ~]#echo oldboy oldboy [root@shell ~]#echo oldboy|wc -L 6 [root@shell ~]#cat 1.txt a bc oldboy 123 [root@shell ~]#cat 1.txt|wc -L #显示最长的 6 方法2: [root@shell ~]#echo oldboy|awk '{print length}' 6 方法3: [root@shell ~]#expr length "oldboy" 6 方法4: [root@shell ~]#name=oldboy [root@shell ~]#echo ${#name} 6 2.输出小于3长度的字符串 [root@shell ~]#echo I am lizhenya I am 18 I am lizhenya I am 18 [root@shell ~]#cat for.sh for i in I am lizhenya I am 18 # 1.遍历in后面的列表中的每个字符,依次赋值给变量i do echo $i # 2.打印变量i的值 done [root@shell ~]#sh for.sh I am lizhenya I am 18 ------------- [root@shell ~]#cat for.sh for i in I am lizhenya I am 18 do echo ${#i} # 输出每个字符的长度是多少 done [root@shell ~]#sh for.sh 1 2 8 1 2 2 -------------- for i in I am lizhenya I am 18 do [ ${#i} -lt 3 ] && echo $i i=I [ 1 -lt 3 ] && echo $i I I=am [ 2 -lt 3 ] && echo $i am I=lizhenya [ 8 -lt 3 ] &&不会执行 done --------------------------- [root@shell ~]#cat for.sh for i in I am lizhenya I am 18 do [ ${#i} -lt 3 ] && echo $i # ${#i}:获取变量 i 的字符长度 # -lt 3:检查长度是否小于3(-lt 是 "less than" 的缩写)。 done # 如果条件成立(长度 < 3),执行 && 后的 echo $i [root@shell ~]#sh for.sh I am I am 18 -------------------------------- 扩展: awk可以统计小于3的 2.变量子串之删除 [root@shell ~]##只取出old 其他省略 [root@shell ~]#echo oldboy|awk -Fb '{print $1}' old [root@shell ~]#echo oldboy|awk -Fboy '{print $1}' old [root@shell ~]#echo oldboy|awk -Fb '{print $2}' oy [root@shell ~]#echo ${url/w/} ww.baidu.com [root@shell ~]#echo ${url/ww/} w.baidu.com [root@shell ~]#echo ${url/www./} baidu.com #使用正则方式匹配删除 www.baidu.com [root@shell ~]#echo ${url/*./} #删除最后一个.前面的 com [root@shell ~]#echo ${url/.*/} #删除第一个.前面的 www 案例1.获取磁盘使用百分比、做字符串比对去掉百分号。 [root@j01 ~]#df -h Filesystem Size Used Avail Use% Mounted on devtmpfs 1.1G 0 1.1G 0% /dev tmpfs 1.1G 0 1.1G 0% /dev/shm tmpfs 1.1G 23M 1.1G 3% /run tmpfs 1.1G 0 1.1G 0% /sys/fs/cgroup /dev/mapper/klas-root 47G 11G 37G 23% / /dev/sda1 1014M 169M 846M 17% /boot tmpfs 211M 0 211M 0% /run/user/0 #方法一 [root@j01 ~]#df -h|awk '/\/$/{print $(NF-1)}'|awk -F% '{print $1}' 23 #方法二 [root@shell ~]#Disk_use=`df -h|awk '/\/$/{print $(NF-1)}'` [root@shell ~]#echo ${Disk_use%\%} # 字符串末尾删除百分号 % 9
写法作用示例(输入23%​ → 输出)
${Disk_use%\%}删除末尾的 %23
${Disk_use%%*%}贪婪匹配,删除最后一个 %​ 之后的所有内容23
${Disk_use//%/}删除所有 %23
echo ${Disk_use%?}删除最后一个字符(无论是什么)23
bash
#变量子串的替换 [root@shell ~]#echo $url www.baidu.com [root@shell ~]#echo ${url/w/A} Aww.baidu.com [root@shell ~]#echo ${url//w/A} AAA.baidu.com [root@shell ~]#echo ${url/www/test} test.baidu.com 子串知识点小结: 1.子串长度统计 echo ${#name} oldboy=aaaaaaaaaa expr length "$oldboy" echo oldboy|awk '{print length}' echo oldboy|wc -L 2.子串删除 从前往后匹配 # 贪婪匹配 ## 从后往前匹配 % 贪婪匹配 %% 3.子串替换 echo ${url/w/W} # 替换单个 echo ${url//w/W}# 贪婪匹配
bash
知识点小结: 1.shell执行方式 方法1: bash sh 方法2: 绝对路径 相对路径 方法3: source . 2.变量的定义 变量名称的定义 变量值的定义 1)数字定义 2)字符串定义、或者路径 dir=/etc/sysconfig/ code_dir=/www/html/wp 变量的拼接 主机名称_IP_时间 固定写法: [root@shell ~/Shell/day01]#cat env.sh #!/bin/bash code_dir=`hostname`_`hostname -I|awk '{print $1}'`_`date +%F` mkdir $code_dir tar zcf $code_dir/all.tar.gz /etc/hosts /etc/passwd find $code_dir/ -mtime +7|xargs rm -rf [root@shell ~/Shell/day01]#ll shell_10.0.0.5_2025-05-20/ total 4 -rw-r--r-- 1 root root 984 May 20 16:08 all.tar.gz 灵活拼接: [root@shell ~/Shell/day01]#cat env.sh #!/bin/bash HOST=`hostname` IP=`hostname -I|awk '{print $1}'` Time=`date +%F` code_dir=${HOST}_${IP}_$Time mkdir -p $code_dir tar zcf $code_dir/${Time}_all.tar.gz /etc/hosts /etc/passwd &>/dev/null find $code_dir/ -mtime +7|xargs rm -rf 3)命令定义 Time=`date +%F` Time=$(date +%F) 案例1.写一个脚本把每行的执行命令记录下来,并且按当前的运行时间记录 [root@shell ~/Shell/day01]#cat nginx.sh #!/bin/bash #配置nginx仓库 Time='date +%F-%H-%M-%S' echo "`$Time` 配置nginx仓库...." >> nginx.log sleep 1 echo "`$Time` yum -y isntall nginx...." >> nginx.log sleep 2 echo "`$Time` configure nginx...." >> nginx.log sleep 1 echo "`$Time` start nginx...." >> nginx.log 案例2.统计字符串长度小于3的(记忆for循环的) [root@shell ~]#echo I am lizhenya I am 18|xargs -n1 I am lizhenya I am 18 [root@shell ~]#echo I am lizhenya I am 18|xargs -n1|awk '{print length}' 1 2 8 1 2 2 扩展: [root@shell ~]#echo I am lizhenya I am 18|xargs -n1|awk '{if(length<3)print}' # 长度小于3就打印 I am I am 18 灵活拼接: [root@shell ~/Shell/day01]#cat env.sh #!/bin/bash HOST=`hostname` IP=`hostname -I|awk '{print $1}'` Time=`date +%F` code_dir=${HOST}_${IP}_$Time mkdir -p $code_dir tar zcf $code_dir/${Time}_all.tar.gz /etc/hosts /etc/passwd &>/dev/null find $code_dir/ -mtime +7|xargs rm -rf 3)命令定义 Time=`date +%F` Time=$(date +%F) 案例1.写一个脚本把每行的执行命令记录下来,并且按当前的运行时间记录 [root@shell ~/Shell/day01]#cat nginx.sh #!/bin/bash #配置nginx仓库 Time='date +%F-%H-%M-%S' echo "`$Time` 配置nginx仓库...." >> nginx.log sleep 1 echo "`$Time` yum -y isntall nginx...." >> nginx.log sleep 2 echo "`$Time` configure nginx...." >> nginx.log sleep 1 echo "`$Time` start nginx...." >> nginx.log 案例2.统计字符串长度小于3的(记忆for循环的) [root@shell ~]#echo I am lizhenya I am 18|xargs -n1 I am lizhenya I am 18 [root@shell ~]#echo I am lizhenya I am 18|xargs -n1|awk '{print length}' 1 2 8 1 2 2 扩展: [root@shell ~]#echo I am lizhenya I am 18|xargs -n1|awk '{if(length<3)print}' I am I am 18 xargs -n1: # 将输入按空格分割,并强制每行输出一个单词 length: # Awk内置函数,返回当前行的字符数 if(length<3): # 仅当长度小于3时执行 print

image

2、shell晋级

1、特殊位置变量
bash
$0 # 表示脚本的名称 给用户提示使用方法的时候使用。 使用场景1: [root@shell ~/Shell/day02]#cat test.sh #!/bin/bash echo hehe echo "Usage: $0 [start|stop|restart|status]" 使用场景2: [root@web01 ~]#cat test.sh #!/bin/bash echo "脚本名称:$0" [root@web01 ~]#sh test.sh 脚本名称:test.sh [root@web01 ~]#sh /root/test.sh 脚本名称:/root/test.sh $n # 表示脚本的传参 n为数字 $1表示脚本的第一个参数 $2为第二个参数 $# # 表示传参的个数 用来控制用户传参个数 [root@shell ~/Shell/day02]#cat a.sh #!/bin/bash [ $# -ne 2 ] && echo "请输入两个参数" && exit #传参的个数不等于2,则执行后续命令 echo name=$1 echo age=$2 $? # 表示上一条命令的执行结果,0为成功,非0失败 [root@shell ~/Shell/day02]#cat b.sh #!/bin/bash echo aa re=$? #把echo aa的返回结果赋值给re c /tmp &>/dev/null #故意输错 [ $re -eq 0 ] && echo ok #eq等于0则打印ok [root@web01 ~/count_bash]#sh b.sh aa ok ------------了解------------ $@ # 表示脚本传参的所有参数,在脚本中直接使用和$*相同,在循环体中加双引号不同 $* # 表示脚本传参的所有参数,在脚本中直接使用和$@相同,在循环体中加双引号不同 [root@shell ~/Shell/day02]#cat test.sh #!/bin/bash echo $1 $2 echo $@ echo $* [root@shell ~/Shell/day02]#sh test.sh a b a b a b a b [root@shell ~/Shell/day02]#sh test.sh a b c d a b a b c d a b c d [root@shell ~/Shell/day02]#sh test.sh {1..10} 1 2 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 [root@shell ~/Shell/day02]#sh test.sh {a..z} a b a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z [root@shell ~/Shell/day02]#set -- "I am" old BOY [root@shell ~/Shell/day02]#echo $* I am old BOY [root@shell ~/Shell/day02]#echo $@ I am old BOY [root@shell ~/Shell/day02]#set -- "I am" old BOY [root@shell ~/Shell/day02]#echo $* I am old BOY [root@shell ~/Shell/day02]#echo $@ I am old BOY [root@shell ~/Shell/day02]#echo "$*" I am old BOY [root@shell ~/Shell/day02]#echo "$@" I am old BOY [root@shell ~/Shell/day02]#for i in $*;do echo $i;done I am old BOY [root@shell ~/Shell/day02]#for i in $@;do echo $i;done I am old BOY [root@shell ~/Shell/day02]#for i in "$*";do echo $i;done I am old BOY [root@shell ~/Shell/day02]#for i in "$@";do echo $i;done I am old BOY -------------------------- $$ # 表示脚本的PID号 系统启动脚本将PID写入到文件中,在相同脚本名称中使用功能不同。 [root@shell ~/Shell/day02]#cat test.sh #!/bin/bash echo tomcat...... echo $$ > /tmp/tomcat.pid sleep 500 $! # 表示上一个在后台运行脚本的PID号 脚本排查问题的时候提高效率 [root@shell ~/Shell/day02]#sh test.sh & [root@web01 ~/count_bash]#echo $! 62014 [root@shell ~/Shell/day02]#kill -9 $! $_ # 获取任何命令的最后一个参数 [root@shell ~/Shell/day02]#echo 1 2 3 4 5 a b c 1 2 3 4 5 a b c [root@shell ~/Shell/day02]#echo $_ c 位置参数小结: $0 $n 脚本传参参数 $1 $2 $# 脚本传参的个数 $? 上一条命令的执行结果 ---了解 $! $$ $@ $* $_ ---

2、脚本传参
bash
#方法1: 直接传参 #参数与参数之间必须有空格 #echo后面单引号或者双引号都为字符串、如果反引号则先执行里面的命令!!! [root@shell ~/Shell/day02]#cat test.sh #!/bin/bash echo $1 [root@shell ~/Shell/day02]#sh test.sh oldboy oldboy [root@shell ~/Shell/day02]#cat test.sh #!/bin/bash echo $1 $2 [root@shell ~/Shell/day02]#sh test.sh a b a b [root@shell ~/Shell/day02]#cat test.sh #!/bin/bash echo $2 $1 [root@shell ~/Shell/day02]#sh test.sh a b b a [root@shell ~/Shell/day02]#cat test.sh #!/bin/bash echo "name=$1" #echo后面有反引号是执行后面命令,引号当作字符串输出 echo "age=$2" [root@shell ~/Shell/day02]#sh test.sh oldboy 18 name=oldboy age=18 #方法2: 赋值传参 [root@shell ~/Shell/day02]#cat test.sh #!/bin/bash name=$1 age=$2 echo "name=$name" echo "age=$age" [root@shell ~/Shell/day02]#sh test.sh oldboy 123 name=oldboy age=123 #方法3: read方式(交互式传参) [root@shell ~/Shell/day02]#cat test.sh #!/bin/bash read -p "请输入你的姓名和年龄: " name age echo $name echo $age [root@shell ~/Shell/day02]#cat test.sh #!/bin/bash read -p "请输入你的姓名: " name # name是变量名 read -p "请输入你的年龄: " age echo name=$name echo age=$age [root@shell ~/Shell/day02]#sh test.sh 请输入你的姓名: test 请输入你的年龄: 1 name=test age=1 [root@shell ~/Shell/day02]#cat test.sh #!/bin/bash read -s -p "请输入你的银行卡密码: " pass echo echo 你的银行密码是: $pass [root@shell ~/Shell/day02]#sh test.sh 请输入你的银行卡密码: # 输入密码的时候不显示 你的银行密码是: 123 案例: 使用三种传参方式实现 1.修改主机名称 #1. [root@xxx ~/count_bash]#cat host.sh #!/bin/bash hostnamectl set-hostname $1 #2. [root@web01 ~/count_bash]#cat host.sh #!/bin/bash host=$1 hostnamectl set-hostname $host #3. [root@shell ~/Shell/day02]#cat host.sh #!/bin/bash read -p "请输入新的主机名称: " host hostnamectl set-hostname $host bash # 执行bash命令,启动一个新的子Shell进程。新的子Shell会读取更新后的主机名,终端提示符立即显示新主机名 [root@shell ~/Shell/day02]#sh host.sh 请输入新的主机名称: test [root@test day02]# 2.修改IP地址(作业) [root@web01 ~/count_bash]#cat ip.sh #!/bin/bash read -p "请输入新的ip:" ip host=`hostname -I|awk '{print $1}'` sed -i "s#$host#$ip#g" /etc/sysconfig/network-scripts/ifcfg-ens33 #用双引号,解析变量 systemctl restart network 3.修改DNS(作业) [root@web01 ~/count_bash]#cat dns.sh #!/bin/bash read -p "请输入新的DNSip:" dns re=`awk 'NR==2{print $2}' /etc/resolv.conf` sed -i "s#$re#$dns#g" /etc/resolv.conf cat /etc/resolv.conf
3、数值运算
bash
expr # 只支持整数运算、不支持小数 $[] # 只支持整数运算、不支持小数运算 $(()) # 只支持整数运算、不支持小数运算 效率最高! let # 通过变量的方式做运算 只支持整数运算 bc # 支持整数和小数 awk python 1.expr 只支持整数运算、不支持小数 [root@shell ~]#expr 1 + 1 2 [root@shell ~]#expr 10 + 1 11 [root@shell ~]#expr 10 - 1 9 [root@shell ~]#expr 10 \* 100 1000 [root@shell ~]# [root@shell ~]#expr 1000 / 100 10 2.$[] # 只支持整数运算、不支持小数运算 [root@shell ~]#echo $[10+10] 20 [root@shell ~]#echo $[10-10] 0 [root@shell ~]#echo $[10*10] 100 [root@shell ~]#echo $[10/10] 1 #取余 [root@shell ~]#expr $[10%2] 0 [root@shell ~]#expr $[10%3] 1 3.$(()) # 只支持整数运算、不支持小数运算 效率最高! [root@shell ~]#echo $((100+100)) 200 [root@shell ~]#echo $((100-100)) 0 [root@shell ~]#echo $((100*100)) 10000 [root@shell ~]#echo $((100/100)) 1 [root@shell ~]#echo $((100%10)) 0 [root@shell ~]# [root@shell ~]#echo $((100%3)) 1 4.let # 通过变量的方式做运算 只支持整数运算 [root@shell ~]#let i++ [root@shell ~]#echo $i 1 [root@shell ~]#let i=i+1 [root@shell ~]#echo $i 2 [root@shell ~]#let a=a+1 [root@shell ~]#echo $a 1 [root@shell ~]##let a++ ====== a=a+1 应用场景: [root@shell ~]#cat for.sh for i in I am lizhenya I am 18 do let a++ done echo 当前脚本循环了 $a 次 [root@shell ~]#sh for.sh 当前脚本循环了 6 次 脚本2:错误统计循环次数 bash #!/bin/bash for i in uyix nmnmbnbn ijj ii 2881 xx s # 列表中共7个元素 do let i++ # 操作循环变量i,每次循环i自增1 done echo 当前脚本循环了$i次 执行过程 循环变量 i 的行为: 在每次循环迭代时,i 被赋值为列表中的元素(如 uyix、nmnmbnbn 等)。 let i++ 试图将 i 视为数值进行自增,但列表中元素 均为非数字字符串(如 uyix),Bash会将其当作 0 处理。 每次执行 let i++ 后,i 的值变为 1,但下一次循环时,i 会被重新赋值为列表中的下一个元素,覆盖之前的值。 最后一次迭代后的 i 值: 循环结束后,i 的值为最后一次迭代时的结果: 列表最后一个元素是 s,执行 let i++ 后,i 被当作0处理,自增后变为 1。 因此,$i 的最终值为 1,输出: 当前脚本循环了1次 #取消变量 [root@shell ~]#unset i [root@shell ~]#unset a [root@shell ~]#unset name i++和++i的区别: #a++先赋值后运算 #++b先运算后赋值 [root@web01 ~]#let ++c [root@web01 ~]#let d=++c [root@web01 ~]#echo $d 2 [root@web01 ~]#let a++ [root@web01 ~]#let b=a++ [root@web01 ~]#echo $b 1 5.bc 支持整数和小数 [root@shell ~]#echo 10+100|bc 110 [root@shell ~]#echo 10000-100|bc 9900 [root@shell ~]#echo 10000*100|bc 1000000 [root@shell ~]#echo 10000/100|bc 100 [root@shell ~]#echo 10000/100.5|bc 99 [root@shell ~]#echo 10000/3|bc 3333 [root@shell ~]#echo 10.5+2.3|bc 12.8 [root@shell ~]#echo 10.5+2.38582342|bc 12.88582342 6.awk [root@shell ~]#awk 'BEGIN{print 10+10}' 20 [root@shell ~]#awk 'BEGIN{print 10-10}' 0 [root@shell ~]#awk 'BEGIN{print 10*10}' 100 [root@shell ~]#awk 'BEGIN{print 10/10}' 1 [root@shell ~]#awk 'BEGIN{print 10^10}' 10000000000 [root@shell ~]#awk 'BEGIN{print 10%10}' 0 [root@shell ~]#awk 'BEGIN{print 10.5*44.233423}' 464.451 [root@shell ~]#awk 'BEGIN{print 1000/3}' 333.333 7.python 案例.使用三种传参方式做一个加减乘除的计算器。 [root@shell ~]#cat count.sh #!/bin/bash #控制用户传参的个数 [ $# -ne 2 ] && echo "必须传入两个参数" && exit #判断用户传入必须为数字的整数 expr $1 + $2 &>/dev/null [ $? -ne 0 ] && echo "必须为整数、小数都不行" && exit echo $1+$2=$[$1+$2] # $1+$2表示输入的两个字符串、$[]表示运算 echo $1-$2=$[$1-$2] echo $1*$2=$[$1*$2] echo $1/$2=$[$1/$2] #判断用户传入年龄必须为整数 [root@shell ~/Shell/day02]#cat age.sh #!/bin/bash read -p "请输入你的姓名: " name read -p "请输入你的年龄: " age expr $age + 10 &>/dev/null [ $? -ne 0 ] && echo "必须输入整数" && exit echo name=$name echo age=$age
4、数值比较
bash
语法结构: test 10 -eq 10 # 语法1 使用较少 [ 10 -eq 10 ] # 语法2 常用 比较符号: -eq # 等于 -ne # 不等于 -gt # 大于 -ge # 大于或等于 -lt # 小于 -le # 小于等于 [root@shell ~]#test 10 -eq 10 [root@shell ~]#echo $? 0 [root@shell ~]#[ 10 -eq 10 ] && echo 成立 || echo 不成立 成立 [root@shell ~]#[ 20 -eq 10 ] && echo 成立 || echo 不成立 不成立 [root@shell ~]#[ 20 -gt 10 ] && echo 成立 || echo 不成立 成立 [root@shell ~]#[ 5 -lt 10 ] && echo 成立 || echo 不成立 成立 [root@shell ~]#[ 5 -ne 10 ] && echo 成立 || echo 不成立 成立 案例1.判断磁盘使用率,如果超过80%则发送邮件告警。 1)取出磁盘使用率 [root@shell ~]#df -h|awk '/\/$/{print $(NF-1)}' 9% 2)比较判断 3)发送邮件告警 [root@shell ~]#cat disk.sh #!/bin/bash #1.取出当前磁盘的使用率 Use=`df -h|awk '/\/$/{print $(NF-1)}'` 或者这样写 Use=`df -h|awk '/\/$/{print $(NF-1)}'|awk -F% '{print $1}'` #2.判断磁盘使用率大于80%则发送邮件告警 [ ${Use%\%} -gt 80 ] && echo "send mail...." || echo "磁盘使用率正常: $Use" 或者这样写 [root@web01 ~/count_bash]#[ $Use -gt 80 ] && echo "磁盘报警" || echo "磁盘使用率正常:$Use" [root@shell ~]#sh disk.sh 磁盘使用率正常: 9% 案例2.内存使用率告警、达到了70%以上告警 [root@shell ~]#free|awk 'NR==2{print $3/$2*100}' 23.6509 另一种方法 [root@web01 ~/count_bash]#Fr=`free|awk 'NR==2{print $3/$2*100}'|awk -F. '{print $1}'` [root@web01 ~/count_bash]#[ $Fr -gt 70 ] && echo "内存报警" || echo "内存率使用正常:$Fr" [ ${fr%.*} -gt 70 ] && echo "内存报警" || echo "内存率使用正常:$fr" 内存率使用正常:21 案例3.负载高告警 1分钟的平均值达到了2以上 [root@shell ~]#uptime 11:32:33 up 9 days, 4:38, 3 users, load average: 0.00, 0.00, 0.00 # 1. 取到负载值 [root@web01 ~/count_bash]#up=`uptime|awk -F": " '{print $2}'|awk -F, '{print $1}'` # 2. %.*表示把0.00中.00去掉 [root@web01 ~]#[ ${up%.*} -gt 2 ] && echo "负载报警" || echo "负载正常: "$up 负载正常: 0.50 [root@web01 ~]#ab -n200000 -c 1700 http://127.0.0.1/ 案例4.使用传参输入两个整数比较两个数的大小 扩展diff命令 [root@shell ~]#diff 1.txt 2.txt 1c1 < 1 --- > 2 [root@shell ~]#cat diff.sh #!/bin/bash read -p "请输入两个整数: " num1 num2 [ $num1 -gt $num2 ] && echo "$num1 > $num2" [ $num1 -lt $num2 ] && echo "$num1 < $num2" [ $num1 -eq $num2 ] && echo "$num1 = $num2" [root@shell ~]#sh diff.sh 请输入两个整数: 10 20 10 < 20 [root@shell ~]#sh diff.sh 请输入两个整数: 50 10 50 > 10 [root@shell ~]#sh diff.sh 请输入两个整数: 100 100 100 = 100
5、文件判断
bash
语法格式: test -f /etc/hosts # 方法1 不常用 [ -f /etc/hosts ] # 方法2 常用 判断符号: -f # 文件存在并且为普通文件即成立 -d # 目录存在即成立 -e # 只要存在即成立 -x # 文件可执行即成立 -w # 文件可写即成立 -r # 文件可读即成立 [root@shell ~]#[ -f /etc/hosts ] && echo 成立 || echo 不成立 成立 [root@shell ~]#[ -d /etc/hosts ] && echo 成立 || echo 不成立 不成立 [root@shell ~]#[ -d /etc/ ] && echo 成立 || echo 不成立 成立 [root@shell ~]#[ -e /etc/ ] && echo 成立 || echo 不成立 成立 [root@shell ~]#[ -e /etc/hosts ] && echo 成立 || echo 不成立 成立 [root@shell ~]#[ -r /etc/hosts ] && echo 成立 || echo 不成立 成立 [root@shell ~]#[ -w /etc/hosts ] && echo 成立 || echo 不成立 成立 [root@shell ~]#[ -x /etc/hosts ] && echo 成立 || echo 不成立 不成立 [root@shell ~]#ll /etc/hosts -rw-r--r-- 1 root root 183 Apr 15 11:46 /etc/hosts 案例1.判断文件是否存在、存在则执行 [root@shell ~]#cat test.sh #!/bin/bash [ -f /etc/profile ] && . /etc/profile echo $name [root@shell ~]#sh test.sh oldgirl 案例2.判断目录是否存在 [root@shell ~]#cat test.sh #!/bin/bash [ -d /code ] || mkdir /code cd /etc/ tar zcf /code/test.tar.gz hosts passwd
6、字符串比对
bash
语法结构: [ test = test ] # 等于即成立 name=oldboy [ $name != root ] # 不等于即成立 [root@shell ~]#[ root = root ] && echo 成立 || echo 不成立 成立 [root@shell ~]#[ root != root ] && echo 成立 || echo 不成立 不成立 [root@shell ~]#[ oldboy != root ] && echo 成立 || echo 不成立 成立 [root@shell ~]#echo $USER root [root@shell ~]#[ $USER != root ] && echo 成立 || echo 不成立 不成立 [root@shell ~]#[ $USER = root ] && echo 成立 || echo 不成立 成立 [root@shell ~]#[ $USER = $name ] && echo 成立 || echo 不成立 -bash: [: root: unary operator expected 不成立 #注意必须有字符串 [root@shell ~]#[ $USER = ] && echo 成立 || echo 不成立 -bash: [: root: unary operator expected 不成立 [root@shell ~]#name=oldboy [root@shell ~]#[ $USER = $name ] && echo 成立 || echo 不成立 不成立 #数字可以看为字符串,但是字符串不能看做数字做比对。 [root@shell ~]#[ 10 = 10 ] && echo 成立 || echo 不成立 成立 [root@shell ~]#[ oldboy = 10 ] && echo 成立 || echo 不成立 不成立 [root@shell ~]#[ oldboy -eq 10 ] -bash: [: oldboy: integer expression expected 参数1: -z 变量字符串长度为0即成立 [root@shell ~]#name=oldboy [root@shell ~]#[ -z $name ] && echo 成立 || echo 不成立 不成立 参数2: -n 变量字符串长度不为0即成立 [root@shell ~]#[ -n $name ] && echo 成立 || echo 不成立 成立 案例.判断用户名字传参不能为空 [root@shell ~/Shell/day02]#cat age.sh #!/bin/bash read -p "请输入你的姓名: " name [ -z $name ] && echo 必须输入姓名 && exit read -p "请输入你的年龄: " age expr $age + 10 &>/dev/null [ $? -ne 0 ] && echo "必须输入整数" && exit echo name=$name echo age=$age
7、正则比对
bash
语法结构: [[ user =~ ^u ]] 注意: 使用正则需要[[]]、比较判断使用[] [root@shell ~]#[[ root =~ root ]] && echo 成立 || echo 不成立 成立 [root@shell ~]#[[ root =~ r ]] && echo 成立 || echo 不成立 成立 [root@shell ~]#[[ root =~ o ]] && echo 成立 || echo 不成立 成立 [root@shell ~]#[[ root =~ ^r ]] && echo 成立 || echo 不成立 成立 [root@shell ~]#[[ root =~ t$ ]] && echo 成立 || echo 不成立 成立 [root@shell ~]#[[ root =~ a$ ]] && echo 成立 || echo 不成立 不成立 [root@shell ~]#[[ root =~ ^o ]] && echo 成立 || echo 不成立 不成立 [root@shell ~]#[[ oldboy =~ [abc] ]] && echo 成立 || echo 不成立 # 匹配到a-z中的b就成立 成立 [root@shell ~]#[[ oldboy =~ [a-z] ]] && echo 成立 || echo 不成立 成立 [root@web01 ~/count_bash]#[[ oldboy =~ [a-z]$ ]] && echo 成立 || echo 不成立 # $ 表示匹配字符串的结尾 成立 [root@shell ~]#[[ old2boy =~ ^[a-z]$ ]] && echo 成立 || echo 不成立 # 整个字符串必须严格是单个小写字母 不成立 [root@shell ~]#[[ oldboy =~ ^[a-z]$ ]] && echo 成立 || echo 不成立 # 只匹配单一一个字符 不成立 [root@shell ~]#[[ o =~ ^[a-z]$ ]] && echo 成立 || echo 不成立 # 匹配单一一个字符 成立 [root@shell ~]#[[ oldboy =~ ^[a-z]+$ ]] && echo 成立 || echo 不成立 # 匹配连续的字符 成立 [root@shell ~]#[[ old2boy =~ ^[a-z]+$ ]] && echo 成立 || echo 不成立 不成立 [root@shell ~]#[[ old-boy =~ ^[a-z]+$ ]] && echo 成立 || echo 不成立 不成立 应用案例: [root@shell ~/Shell/day02]#cat age.sh #!/bin/bash read -p "请输入你的姓名: " name [ -z $name ] && echo 必须输入姓名 && exit if [[ $name =~ ^[a-z]+$ ]];then # 输入连续的字符串 read -p "请输入你的年龄: " age expr $age + 10 &>/dev/null [ $? -ne 0 ] && echo "必须输入整数" && exit echo name=$name echo age=$age else echo "你必须输入字符串" exit fi ------------------------------- [root@shell ~/Shell/day02]#cat age.sh #!/bin/bash read -p "请输入你的姓名: " name [ -z $name ] && echo 必须输入姓名 && exit [[ ! $name =~ ^[a-z]+$ ]] && echo "必须输入字符串" && exit read -p "请输入你的年龄: " age expr $age + 10 &>/dev/null [ $? -ne 0 ] && echo "必须输入整数" && exit echo name=$name echo age=$age ---------------------------------
8、表达式中支持命令
bash
# [% ]+表示以%+空格为分隔符 [root@shell ~]#[ `df -h|awk -F "[% ]+" '/\/$/{print $(NF-1)}'` -gt 80 ] && echo 成立 || echo 不成立 不成立 [root@shell ~]#[ `df -h|awk -F "[% ]+" '/\/$/{print $(NF-1)}'` -eq 9 ] && echo 成立 || echo 不成立 成立 判断表达式中[] 支持并且和或者 -a 并且 -o 或者 [root@shell ~]#[ 10 -eq 10 -a 100 -gt 50 ] && echo 成立 || echo 不成立 成立 [root@shell ~]#[ 10 -eq 10 -a 100 -lt 50 ] && echo 成立 || echo 不成立 不成立 [root@shell ~]#[ 10 -eq 10 -o 100 -lt 50 ] && echo 成立 || echo 不成立 成立 #注意 在[[]] 中使用 &&并且 和 ||或者 [root@shell ~]#[[ user =~ ^u && test =~ t$ ]] && echo 成立 || echo 不成立 成立 [root@shell ~]#[[ user =~ ^u && test =~ a$ ]] && echo 成立 || echo 不成立 不成立 [root@shell ~]#[[ user =~ ^u || test =~ a$ ]] && echo 成立 || echo 不成立 成立 作业: awk sed grep 取值 sh os.sh在屏幕上输出以下结果 当前的操作系统外网IP是: 221.218.208.164 当前操作系统的ens33IP: 10.0.0.5 当前操作系统版本是: KYLINv10 SP3 当前操作系统主机名称: shell 当前操作系统登录用户: root 当前操作系统内存百分比: 22.2% 当前操作系统磁盘使用率: 9% 当前操作系统使用平台是: vmware [root@web01 ~/count_bash]#cat os.sh #!/bin/bash cip=`curl -s ip.sb` eip=`hostname -I|awk '{print $1}'` hostn=`hostname` fre=`free -h|awk 'NR==2{print $3/$2*100}'` cipan=`df -h|awk '/\/$/{print $(NF-1)}'` vm=`hostnamectl|awk -F":" 'NR==6{print $2}'` echo 当前的操作系统外网IP是: $cip echo 当前操作系统的ens33IP: $eip echo 当前操作系统版本是: KYLINv10 SP3 echo 当前操作系统主机名称: $hostn echo 当前操作系统登录用户: $USER echo 当前操作系统内存百分比: $fre echo 当前操作系统磁盘使用率: $cipan echo 当前操作系统使用平台是: $vm 面试题:10-15K 1.zabbix服务优化 2.日志文件 取TOP10 3.安全也是你负责啊? 4.编译安装的nginx、找出和nginx相关的文件怎么找? 如何找找某个文件被哪个进程所占用? lsof 1)lsof 2)find 5.proc文件 内存的映射 6.静态路由 动态路由 VLAN TCP三次握手! 7.你老家是哪的 我们可是在杭州! 我给你介绍我们公司的业务!!

3、循环

1、while循环
bash
语法结构: while [] # 中括号里面就是条件表达式 条件表达式成立则执行do后面的动作,如果不成立则不执行。 do 命令集合 done 面试题: 写一个死循环脚本 [root@shell ~]#cat while.sh #!/bin/bash while [ 10 -eq 10 ] # 如果条件表达式成立则打印呵呵 do echo hehe sleep 1 # 睡眠1秒继续循环 done [root@shell ~]#cat while.sh #!/bin/bash while true do echo hehe sleep 1 done [root@shell ~]#cat while.sh #!/bin/bash while [ -f /etc/hosts ] do echo hehe sleep 1 done 条件表达式不成立则退出循环脚本 [root@shell ~]#cat while.sh #!/bin/bash i=1 while [ $i -le 10 ] do echo hehe sleep 1 let i++ done 循环套循环 [root@shell ~]# [root@shell ~]#cat while.sh #!/bin/bash while true do echo hehe sleep 1 while true do echo oldboy sleep 1 done done 跳出循环体 [root@shell ~]#cat while.sh #!/bin/bash while true # 1 do # 1 echo hehe # 1 sleep 1 # 1 while true do echo oldboy sleep 1 break done # 1 done [root@shell ~]#cat while.sh #!/bin/bash while true do echo hehe sleep 1 while true do echo oldboy sleep 1 break 2 done done echo done.......... [root@shell ~]#sh while.sh hehe oldboy done..........
2、if判断
bash
语法结构1: 1个条件、1个结果 [ 10 -eq 10 ] && echo Ok if [ 条件表达式 ];then 命令的集合 fi if [ 条件表示成立 ] then 命令的集合 fi ---------------- if [ 你有钱 ];then 我就嫁给你 fi 语法结构2: 1个条件、2个结果 [ 10 -eq 10 ] && echo Ok || echo error if [ 条件表达式 ];then 命令 else 命令 fi if [ 你有钱 ];then 我就嫁给你 else 我就嫁给别人 fi 语法结构3: 多个条件多个结果 if [ 条件表达式 ];then 动作 elif [ 条件表达式 ];then 动作 elif [ 条件表达式 ];then 动作 else 动作 fi if [ 你有钱 ];then 我就嫁给你 elif [ 你长的帅 ];then 先处朋友 elif [ 活好 ];then 运维学的好 潜力股 先处对象 else 你是个好人,咱俩不合适! fi 案例1.传参判断两个整数的大小 [root@shell ~]#cat if.sh #!/bin/bash if [ $1 -gt $2 ];then #如果$1>$2,则打印$1>$2 echo "$1>$2" elif [ $1 -lt $2 ];then #如果$1<$2,则打印$1<$2 echo "$1<$2" else echo "$1=$2" fi [root@shell ~]#sh if.sh 20 30 20<30 [root@shell ~]#sh if.sh 20 20 20=20 [root@shell ~]#sh if.sh 100 10 100>10 [root@shell ~]#cat if.sh #!/bin/bash #判断传参和个数 expr $1 + $2 &>/dev/null re=$? if [ $# -ne 2 ];then echo "必须输入两个参数" exit elif [ $re -ne 0 ];then echo "必须输入的整数" exit fi #比大小 if [ $1 -gt $2 ];then echo "$1>$2" elif [ $1 -lt $2 ];then echo "$1<$2" else echo "$1=$2" fi 案例2.猜数字 1)系统随机生成1-100之间一个数字号码 RANDOM 0-32767之间随机生成一个数字 [root@shell ~]#echo $((RANDOM)) 5288 [root@shell ~]#echo $((RANDOM%99+1)) 61 2)让用户猜这个数字 3)如果用户输入的大了 给提示大了、小了则提示小了 4)如果正确则提示中奖退出脚本 5)总共猜了几次 [root@shell ~]#cat ran.sh #!/bin/bash ran=`echo $((RANDOM%99+1))` i=0 while true # true相当于中括号,中括号里面就是条件表达式 条件表达式成立则执行do后面的动作,如果不成立则不执行。 do let i++ read -p "请输入你要猜的数字: " num if [ $num -gt $ran ];then echo "你猜大了" elif [ $num -lt $ran ];then echo "你猜小了" else echo "恭喜你中奖了金额: 100000000000000000¥" break fi done echo "总共猜了$i次" 案例2.1级菜单案例 1)安装各种服务的脚本 2)NGINX TOMCAT REDIS 3)显示菜单 4)用户根据安装需求选择菜单进行安装 [root@shell ~]#cat menu.sh #!/bin/bash echo "1.Redis" echo "2.Tomcat" echo "3.Nginx" read -p "请选择你要安装服务的编号: " num if [ $num -eq 1 ];then echo "Instll Redis....." elif [ $num -eq 2 ];then echo "Instll Tomcat....." elif [ $num -eq 3 ];then echo "Instll Nginx....." else echo "Usage: $0 [1|2|3]" exit fi --------------------完善脚本 [root@shell ~]#cat menu.sh #!/bin/bash echo -e "\t\t\t\t\t\033[1;34m1.Redis\033[0m" echo -e "\t\t\t\t\t\033[1;34m2.Tomcat\033[0m" echo -e "\t\t\t\t\t\033[1;34m3.Nginx\033[0m" echo -e "\t\t\t\t\t\033[1;34m4.all_server\033[0m" echo -e "\t\t\t\t\t\033[1;34m5.退出脚本\033[0m" while true do read -p "请选择你要安装服务的编号: " num if [ $num -eq 1 ];then echo "Instll Redis....." elif [ $num -eq 2 ];then echo "Instll Tomcat....." elif [ $num -eq 3 ];then echo "Instll Nginx....." elif [ $num -eq 4 ];then echo "yum -y install redis tomcat nginx........." elif [ $num -eq 5 ];then exit else echo "Usage: $0 [1|2|3]" exit fi done --------------------------------- [root@shell ~]#cat menu.sh #!/bin/bash echo -e "\t\t\t\t\t\033[1;34m1.Redis\033[0m" echo -e "\t\t\t\t\t\033[1;34m2.Tomcat\033[0m" echo -e "\t\t\t\t\t\033[1;34m3.Nginx\033[0m" echo -e "\t\t\t\t\t\033[1;34m4.all_server\033[0m" echo -e "\t\t\t\t\t\033[1;34m5.退出脚本\033[0m" #判断网络 ping -c1 -W1 www.baidu.com &>/dev/null if [ $? -ne 0 ];then echo "你的网络不通,尝试重启..." systemctl restart network ping -c1 -W1 www.baidu.com &>/dev/null [ $? -ne 0 ] && echo "请手动排查网络问题" fi #部署仓库 cat >/etc/yum.repos.d/nginx.repo<<EOF [nginx-stable] name=nginx stable repo baseurl=http://nginx.org/packages/centos/7/$basearch/ gpgcheck=0 enabled=1 gpgkey=https://nginx.org/keys/nginx_signing.key EOF while true do read -p "请选择你要安装服务的编号: " num if [ $num -eq 1 ];then echo "Instll Redis....." elif [ $num -eq 2 ];then echo "Instll Tomcat....." elif [ $num -eq 3 ];then echo "Instll Nginx....." elif [ $num -eq 4 ];then echo "yum -y install redis tomcat nginx........." elif [ $num -eq 5 ];then exit else echo "Usage: $0 [1|2|3]" exit fi done ------------------------------------ 案例3.二级菜单 1)Nginx Redis Tomcat 2)nginx1.18 nginx 1.26 Redis1.1 Redis1.2 [root@shell ~]#cat m.sh #!/bin/bash echo -e "\t\t\t\t\t\033[1;34m1.Redis\033[0m" echo -e "\t\t\t\t\t\033[1;34m2.Nginx\033[0m" read -p "请输入你安装软件的编号: " num if [ $num -eq 1 ];then echo -e "\t\t\t\t\t\033[1;35m1.Redis1.1\033[0m" echo -e "\t\t\t\t\t\033[1;35m2.Redis1.2\033[0m" elif [ $num -eq 2 ];then echo -e "\t\t\t\t\t\033[1;35m1.Nginx1.18\033[0m" echo -e "\t\t\t\t\t\033[1;35m2.Nginx1.26\033[0m" fi -------------------------------------- 完善二级菜单 [root@shell ~]#cat m.sh #!/bin/bash while true do echo -e "\t\t\t\t\t\033[1;34m1.Redis\033[0m" echo -e "\t\t\t\t\t\033[1;34m2.Nginx\033[0m" read -p "请输入你安装软件的编号: " num if [ $num -eq 1 ];then while true do echo -e "\t\t\t\t\t\033[1;35m1.Redis1.1\033[0m" echo -e "\t\t\t\t\t\033[1;35m2.Redis1.2\033[0m" echo -e "\t\t\t\t\t\033[1;35m3.返回上一级菜单\033[0m" read -p "请输入你安装版本的编号: " num1 if [ $num1 -eq 1 ];then echo "yum -y install Rredis1.1............" elif [ $num1 -eq 2 ];then echo "yum -y install Rredis1.2............" elif [ $num1 -eq 3 ];then break fi done elif [ $num -eq 2 ];then echo -e "\t\t\t\t\t\033[1;35m1.Nginx1.18\033[0m" echo -e "\t\t\t\t\t\033[1;35m2.Nginx1.26\033[0m" fi done 案例4.批量创建用户 1)传参传入前缀 old 2)传参传入个数 10 3)判断用户是否存在 4)给每个用户随机创建一个8位的密码 [root@shell ~]#echo $((RANDOM))|md5sum|cut -c1-8 d3dd930e [root@shell ~]#date +%N|md5sum|cut -c1-8 3ff00f2a #yum -y install expect [root@shell ~]#mkpasswd Ob8Dkgc6! [root@shell ~]#mkpasswd AZ$ef5go0 [root@shell ~]#cat user.sh #!/bin/bash read -p "请输入用户的前缀: " pre read -p "请输入创建用户的个数: " num for i in `seq $num` # 把i放在输入的个数里面以序列的方式循环 do echo $pre$i done [root@shell ~]#sh user.sh 请输入用户的前缀: old 请输入创建用户的个数: 5 old1 old2 old3 old4 old5 -----------------------框架 [root@shell ~]#cat user.sh #!/bin/bash read -p "请输入用户的前缀: " pre read -p "请输入创建用户的个数: " num for i in `seq $num` do echo $pre$i done read -p "删除或者创建以上用户[y创建|d删除] " re for a in `seq $num` do user=$pre$a if [ $re = y ];then id $user &>/dev/null if [ $? -ne 0 ];then useradd $user [ $? -eq 0 ] && echo "$user 创建成功" else echo "$user 用户存在" fi elif [ $re = d ];then id $user &>/dev/null if [ $? -eq 0 ];then userdel -r $user [ $? -eq 0 ] && echo "$user 删除成功" else echo "$user 不存在" fi fi done
3、for循环
bash
语法结构: for i in 取值列表 # i为变量 a也可以 b也可以 hehe也可以 取值列表: 数字 字符串 序列 命令 do 执行的命令集合 done 案例1.循环数字 [root@shell ~]#cat f.sh #!/bin/bash for i in 1 2 5 10 do echo $i done [root@shell ~]#sh f.sh 1 2 5 10 案例2.循环字符串 [root@shell ~]#cat f.sh #!/bin/bash for i in a b c d do echo $i done [root@shell ~]#sh f.sh a b c d [root@shell ~]#cat f.sh #!/bin/bash for i in a b c d do echo hehe done [root@shell ~]#sh f.sh hehe hehe hehe hehe [root@shell ~]#cat f.sh #!/bin/bash for i in a b c d # 循环4次,i依次取值为a、b、c、d do let a++ done echo "循环了 $a 次" # 输出变量a的值 [root@shell ~]#sh f.sh 循环了 4 次 ---------------------------- [root@shell ~]#cat f.sh #!/bin/bash for i in a b c d # 循环4次,i依次取值为a、b、c、d do let i++ done echo "循环了 $i 次" # 输出最后一次循环后的i值 案例3.数字和字符串拼接 [root@shell ~]#cat for.sh for i in 1 2 3 do echo oldboy$i done [root@shell ~]#sh for.sh oldboy1 oldboy2 oldboy3 变量的赋值 [root@shell ~]#cat for.sh for i in 1 2 3 do user=oldboy$i id $user &>/dev/null [ $? -ne 0 ] && useradd $user done 案例4.支持命令 [root@shell ~]#cat for.sh for i in `ls` do echo $i done [root@shell ~]#cat for.sh for i in `seq 5` do echo $i done [root@shell ~]#sh for.sh 1 2 3 4 5 [root@shell ~]#cat for.sh for i in {1..5} do echo $i done [root@shell ~]#sh for.sh 1 2 3 4 5 案例5.笔试题批量ping一个网段10.0.0.0/24的IP地址、ping通输出在线。 [root@shell ~]#cat ping.sh #!/bin/bash for i in {1..254} do IP=10.0.0.$i echo $IP done [root@shell ~]#sh ping.sh 10.0.0.1 10.0.0.2 10.0.0.3 ....... --------------------------------------------- [root@shell ~]#cat ping.sh #!/bin/bash for i in {1..254} # 取值范围 do { IP=10.0.0.$i # 变量IP存在10.0.0.1..254的值 ping -c1 -W1 $IP &>/dev/null # ping这个$ip [ $? -eq 0 ] && echo "$IP在线....." # 如果上面通,打印ip在线 } & done wait echo done............... ---------------------------------- 案例6.笔试题从1加到100 [root@shell ~]#cat f.sh #!/bin/bash for i in {1..100} do sum=$[$sum+$i] # done echo $sum [root@shell ~]#sh f.sh 5050 执行流程: #!/bin/bash for i in {1..100} do sum=$[$sum+$i] i=1 sum=$[0+1] sum=1 i=2 sum=$[1+2] sum=3 i=3 sum=$[3+3] sum=6 ... done echo $sum 案例7.反向破解MD5值对应的数字 作业 57cb6d79 88547d63 1c81d357 5dc5d335 53f0b30 867d054 支持命令行写法 [root@shell ~]#for i in a b c;do echo $i;done a b c [root@shell ~]#for i in {1..5};do useradd oldboy$i;done [root@shell ~]#tail -5 /etc/passwd oldboy1:x:1006:1006::/home/oldboy1:/bin/bash oldboy2:x:1007:1007::/home/oldboy2:/bin/bash oldboy3:x:1008:1008::/home/oldboy3:/bin/bash oldboy4:x:1009:1009::/home/oldboy4:/bin/bash oldboy5:x:1010:1010::/home/oldboy5:/bin/bash 批量删除5个用户 [root@shell ~]#for i in {1..5};do userdel -r oldboy$i;done 案例8.文件中存在用户名称需要批量创建或者删除 [root@shell ~]#cat user.txt zhangsan lisi laowang [root@shell ~]#cat u.sh for i in `cat user.txt` do useradd $i done 命令行写法: [root@shell ~]#for i in `cat user.txt`;do echo $i;done zhangsan lisi laowang [root@shell ~]#for i in `cat user.txt`;do useradd $i;done [root@shell ~]#tail -3 /etc/passwd zhangsan:x:1011:1011::/home/zhangsan:/bin/bash lisi:x:1012:1012::/home/lisi:/bin/bash laowang:x:1013:1013::/home/laowang:/bin/bash 案例9.抓阄 全班同学抓阄每个同学抓1次,生成一个数字1-100 出现过的数字不能再出现 yayi 77 mingg 66 xingming 11 continue 忽略剩余代码重新执行。 #扩展错误3次、找回密码 输入你的邮箱 [root@shell ~]#cat pa.sh #!/bin/bash echo "欢迎光临oldboy银行!" i=0 while true do let i++ if [ $i -eq 4 ];then echo "密码错误超过3次罚站120秒" sleep 5 unset i fi read -s -p "请输入银行卡的密码: " pass echo -e "\n" if [ $pass = 12345 ];then break else echo "密码错误,请重新输入" continue # 回到循环体的开头 fi done echo "欢迎老王你目前的账号余额是0.00元" echo "1.取钱" echo "2.存钱"

4、循环进阶

1、while循环
bash
while [条件表达式] 数值比较 文件判断 字符串比对 正则 do 命令集合 done 死循环脚本: while true do echo hehe done while 从1加到100 [root@test ~]#cat c.sh #!/bin/bash i=0 # i的初始值为0 while [ $i -le 100 ] # i值小于100 do sum=$[sum+i] # sum=[0+0] let i++ # i=i+1,继续循环 done echo $sum [root@test ~]#sh c.sh 5050 [root@test ~]#echo {1..100}|sed 's# #+#g'|bc 5050 [root@test ~]#seq -s + 100|bc 5050 读取文件: 默认以空格为分割符号 for i in `cat /etc/hosts` do echo done [root@test ~]#cat /etc/hosts 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 127.0.0.1 s.oldboy.com [root@test ~]#for i in `cat /etc/hosts`;do echo $i;done 127.0.0.1 localhost localhost.localdomain localhost4 while读取文件: 按照行进行取值 [root@test ~]#cat while.sh #!/bin/bash while read line # line为变量 类似for循环的i变量 line叫其他任意自定义变量 do echo $line # 以行的格式读取 done< /etc/hosts [root@test ~]#sh while.sh 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 127.0.0.1 s.oldboy.com 案例.文件中存放着用户名密码使用循环来自动创建 [root@test ~]#cat 1.txt aa aa123.com bb bb123.com cc cc123.com [root@test ~]#cat while.sh #!/bin/bash while read line do echo $line done< 1.txt [root@test ~]#cat while.sh #!/bin/bash while read line do user=`echo $line|awk '{print $1}'` # 取文件的第一列,用户列 pass=`echo $line|awk '{print $2}'` # 取文件的第二列,密码列 useradd $user echo $pass|passwd --stdin $user done< 1.txt [root@test ~]# 作业: 写一个随机数脚本、每次随机输出一个同学的名称到屏幕。 break # 跳出循环 continue # 结束本次剩余代码、从头继续执行。 exit # 退出整个脚本 案例1.测试exit 1)提前创建old3用户 [root@test ~]#useradd old3 2)在执行以下脚本测试 [root@test ~]#cat test.sh #!/bin/bash for i in `seq 5` do user=old$i:: id $user &>/dev/null if [ $? -eq 0 ];then exit # 退出整个脚本 else useradd $user [ $? -eq 0 ] && echo $user 创建成功 fi done echo done.............. [root@test ~]#sh test.sh old1 创建成功 old2 创建成功 # 测试结果 遇到old3则退出脚本 案例2.break 跳出循环 [root@test ~]#userdel -r old1 [root@test ~]#userdel -r old2 [root@test ~]#cat test.sh #!/bin/bash for i in `seq 5` do user=old$i id $user &>/dev/null if [ $? -eq 0 ];then break # 跳出循环 else useradd $user [ $? -eq 0 ] && echo $user 创建成功 fi done echo done.............. #测试结果 [root@test ~]#sh test.sh old1 创建成功 old2 创建成功 done.............. 案例3.测试continue 结束本次循环、继续下一次循环 [root@test ~]#userdel -r old1 [root@test ~]#userdel -r old2 [root@test ~]#cat test.sh #!/bin/bash for i in `seq 5` do user=old$i id $user &>/dev/null if [ $? -eq 0 ];then continue # 结束本次循环、进入下一次循环 else useradd $user [ $? -eq 0 ] && echo $user 创建成功 fi done echo done.............. #测试结果 [root@test ~]#sh test.sh old1 创建成功 old2 创建成功 old4 创建成功 old5 创建成功 done..............
2、case语句
bash
语法结构: case 变量 in 匹配序列1) 命令集合 ;; 匹配序列2) 命令集合 ;; 匹配序列3) 命令集合 ;; *) 命令集合(给用户提示) esac 案例1.语法 [root@test ~]#cat case.sh #!/bin/bash case $1 in shell) # 如果匹配到这个,就输出下面的shell echo shell...... ;; mysql) # 如果匹配到这个,就输出下面的mysql echo mysql......... ;; docker) # 如果匹配到这个,就输出下面的docker echo docker...... ;; *) echo "[Usage: $0 shell|mysql|docker ]" esac [root@test ~]#sh case.sh [Usage: case.sh shell|mysql|docker ] [root@test ~]#sh case.sh shell shell...... [root@test ~]#sh case.sh mysql mysql......... [root@test ~]#sh case.sh docker docker...... 补充: if判断或者 [ -f /etc/hosts -a -d /etc ] [ 10 -eq 10 -o 20 -gt 30 ] [root@test ~]#cat if.sh #!/bin/bash read -p "请输入用户的前缀: " pre read -p "请输入创建用户个数: " num for i in `seq $num` do echo $pre$i done [root@test ~]#sh if.sh 请输入用户的前缀: ol 请输入创建用户个数: 5 ol1 ol2 ol3 ol4 ol5 [root@test ~]#cat if.sh #!/bin/bash read -p "请输入用户的前缀: " pre read -p "请输入创建用户个数: " num1 for i in `seq $num1` do echo $pre$i done read -p "请输入创建[y|Y|yes]或者删除[d|D]以上用户: " num if [ $num = y -o $num = Y -o $num = yes ];then echo "创建用户....." elif [ $num = d -o $num = D ];then echo "删除用户....." fi 案例.使用菜单查看系统的信息 [root@test ~]#cat m.sh #!/bin/bash echo -e "\t\t\t\t\t\033[1;34m1|f.查看内存\033[0m" echo -e "\t\t\t\t\t\033[1;34m2|d.查看磁盘\033[0m" echo -e "\t\t\t\t\t\033[1;34m3|u.查看负载\033[0m" while true do read -p "请输入你要查看系统的编号: " num if [ $num = 1 -o $num = f ];then free -h elif [ $num = 2 -o $num = d ];then df -h elif [ $num = 3 -o $num = u ];then uptime fi done case案例: [root@test ~]#cat m.sh #!/bin/bash echo -e "\t\t\t\t\t\033[1;34m1|f.查看内存\033[0m" echo -e "\t\t\t\t\t\033[1;34m2|d.查看磁盘\033[0m" echo -e "\t\t\t\t\t\033[1;34m3|u.查看负载\033[0m" while true do read -p "请输入你要查看系统的编号: " num case $num in 1|f) free -h ;; 2|d) df -h ;; 3|u) uptime ;; *) echo "Usage $0 [1|f|2|3|u]" esac done [root@test ~]#cat te.sh #!/bin/bash fun(){ echo "1 redis" echo "2 shell" } fun fun fun fun 使用函数调用菜单 [root@test ~]#cat m.sh #!/bin/bash menu(){ echo -e "\t\t\t\t\t\033[1;34m1|f.查看内存\033[0m" echo -e "\t\t\t\t\t\033[1;34m2|d.查看磁盘\033[0m" echo -e "\t\t\t\t\t\033[1;34m3|u.查看负载\033[0m" } menu while true do read -p "请输入你要查看系统的编号[4|h帮助]: " num case $num in 1|f) free -h ;; 2|d) df -h ;; 3|u) uptime ;; 4|h) clear menu ;; *) echo "Usage $0 [1|f|2|3|u]" esac done 案例.Nginx case启动脚本 Nginx启动方式 方法1 systemctl start nginx 方法2 [root@test ~]#which nginx /usr/sbin/nginx [root@test ~]#/usr/sbin/nginx [root@test ~]#/usr/sbin/nginx -s stop # 停止 [root@test ~]#/usr/sbin/nginx -s reload # 重新加载 [root@test ~]#/usr/sbin/nginx -s stop && sleep 1 && /usr/sbin/nginx [root@test ~]#cat nginx.sh #!/bin/bash case $1 in start) /usr/sbin/nginx ;; stop) /usr/sbin/nginx -s stop ;; reload) /usr/sbin/nginx -s reload ;; restart) /usr/sbin/nginx -s stop && sleep 1 && /usr/sbin/nginx ;; status) Nginx_port=`netstat -tnulp|grep nginx|grep 80|awk '{print $4}'` echo "当前Nginx监听端口: $Nginx_port" ;; *) echo "Usage: $0 [start|stop|reload|restart|status]" esac -------------完善返回结果----------------- [root@test ~]#cat nginx.sh #!/bin/bash case $1 in start) /usr/sbin/nginx if [ $? -eq 0 ];then echo "Nginx $1 成功" else echo "Nginx $1 失败" fi ;; stop) /usr/sbin/nginx -s stop if [ $? -eq 0 ];then echo "Nginx $1 成功" else echo "Nginx $1 失败" fi ;; reload) /usr/sbin/nginx -s reload if [ $? -eq 0 ];then echo "Nginx $1 成功" else echo "Nginx $1 失败" fi ;; restart) /usr/sbin/nginx -s stop && sleep 1 && /usr/sbin/nginx if [ $? -eq 0 ];then echo "Nginx $1 成功" else echo "Nginx $1 失败" fi ;; status) Nginx_port=`netstat -tnulp|grep nginx|grep 80|awk '{print $4}'` echo "当前Nginx监听端口: $Nginx_port" ;; *) echo "Usage: $0 [start|stop|reload|restart|status]" esac ------------------------------- 使用函数调用判断 [root@test ~]#cat nginx.sh #!/bin/bash env1=$1 Te(){ # 重复的写到函数里 if [ $? -eq 0 ];then echo "Nginx $env1 成功" else echo "Nginx $env1 失败" fi } case $1 in start) /usr/sbin/nginx Te # 调用函数 ;; stop) /usr/sbin/nginx -s stop Te ;; reload) /usr/sbin/nginx -s reload Te ;; restart) /usr/sbin/nginx -s stop && sleep 1 && /usr/sbin/nginx Te ;; status) Nginx_port=`netstat -tnulp|grep nginx|grep 80|awk '{print $4}'` echo "当前Nginx监听端口: $Nginx_port" ;; *) echo "Usage: $0 [start|stop|reload|restart|status]" esac 企业py脚本启动方式: [root@test ~]#cat s.sh #!/bin/bash nohup python3.7 test.py --redis-ip=172.16.1.51 --redis-port=6379 xxx & 停止脚本 cat stop.sh [root@test ~]#kill -9 `ps axu|grep test.py|awk '{print $2}'` 案例.跳板机脚本 [root@test ~]#ssh-keygen 和客户端做免秘钥 [root@test ~]#ssh-copy-id 172.16.1.51 [root@test ~]#ssh-copy-id 172.16.1.7 [root@test ~]#ssh-copy-id 172.16.1.8 [root@test ~]#cat jumpserver.sh #!/bin/bash WEB01=172.16.1.7 WEB02=172.16.1.8 DB01=172.16.1.51 echo -e "\t\t\t\t\t\033[1;34m1.$WEB01\033[0m" echo -e "\t\t\t\t\t\033[1;34m2.$WEB02\033[0m" echo -e "\t\t\t\t\t\033[1;34m3.$DB01\033[0m" trap "" INT TSTP HUP while true do read -p "请输入要连接服务器的编号: " num case $num in 1) ssh $WEB01 # 提前做好免秘钥 ;; 2) ssh $WEB02 ;; 3) ssh $DB01 ;; woshiyunwei) exit ;; *) echo "Usage: $0 [1|2|3]" esac done ----------------------完善jumpserver [root@test ~]#cat jumpserver.sh #!/bin/bash WEB01=172.16.1.7 WEB02=172.16.1.8 DB01=172.16.1.51 role(){ echo -e "\t\t\t\t\t\033[1;34m1.运维\033[0m" echo -e "\t\t\t\t\t\033[1;34m2.开发\033[0m" } ops(){ echo -e "\t\t\t\t\t\033[1;34m1.$WEB01\033[0m" echo -e "\t\t\t\t\t\033[1;34m2.$WEB02\033[0m" echo -e "\t\t\t\t\t\033[1;34m3.$DB01\033[0m" echo -e "\t\t\t\t\t\033[1;34m4.返回上一级\033[0m" } dev(){ echo -e "\t\t\t\t\t\033[1;34m1.$WEB01\033[0m" } #trap "" INT TSTP HUP while true do role read -p "请输入你的角色: " num if [ $num -eq 1 ];then # 1 #判断运维密码--- i=0 while true do let i++ [ $i -eq 4 ] && echo "已错了3次,请想一想在输入" && sleep 10 && unset i read -s -p "欢迎LNB的运维、请输入密码: " pass echo "" if [ $pass = 123456 ];then break else echo "密码错误请重新输入" continue fi done #--------------- ops # 1 while true do read -p "请输入要连接服务器的编号[h菜单]: " num1 case $num1 in 1) ssh $WEB01 ;; 2) ssh $WEB02 ;; h) clear ops ;; 4) break ;; esac done elif [ $num -eq 2 ];then # 1 dev # 1 fi # 1 done # 1
3、作业讲解
bash
1.修改IP地址(作业) [root@test ~]#cat i.sh #!/bin/bash en_36=/etc/sysconfig/network-scripts/ifcfg-ens36 S_IP=`sed -n "/^IP/p" $en_36|awk -F. '{print $NF}'` read -p "请输入新的IP地址: " ip sed -i "s#172.16.1.$S_IP#172.16.1.$ip#g" $en_36 #重启生效 systemctl restart network 2.反向破解MD5值对应的数字 作业 0-32767之间一个随机数字的MD5值前8和7位 57cb6d79 88547d63 1c81d357 5dc5d335 53f0b30 867d054 [root@test ~]#cat md.sh #!/bin/bash for i in `seq 32767` do ran=`echo $i|md5sum|cut -c1-8` if [[ $ran =~ 57cb6d79 || $ran =~ 88547d63 || $ran =~ 1c81d357 || $ran =~ 5dc5d335 || $ran =~ 53f0b30 || $ran =~ 867d054 ]];then echo -e "$i\t$ran" fi done 3.写一个抓阄脚本、每次随机输出一个同学的名称到屏幕。 不能退出脚本、所有的同学输入完毕后退出 sh z.sh zs 78 qq 44 cc 88 最后按照数字的逆序排序 [root@test ~]#cat ran.sh #!/bin/bash > ran.txt while true do read -p "请输入你的姓名[q退出]: " name if [ $name = q ];then #如果输入的姓名等于q则跳出循环 break fi while true do ran=`echo $((RANDOM%99+1))` # 生成随机数 if [ `grep -w $ran ran.txt|wc -l` -eq 1 ];then # 如果生成的随机数$ran在文件里有,则重新循环 continue else break # 如果生成的随机数在在文件里没有,就跳出当前循环 fi done echo -e "$name\t$ran"|tee -a ran.txt # 把名字跟随机数打印出来并写到ran.txt文件里面 done sort -rnk2 ran.txt 其他项目: 中午吃啥? 1.16元快餐 2.面条 3.盖饭 4.水饺 5.汉堡 6.烤肉拌饭 7.凉皮肉夹馍 点餐系统: 1.菜单 2.价格 3.会员-->文件 卡号 密码 4.密码错误? 按摩系统 双色球: 颜色 机选5注 1-33个数字随机出6个红球 1-16个数字随机出1个篮球 函数 数组

5、最后一天

1、函数
bash
特点: 1.函数类似变量 先定义在调用 2.函数完成特定功能的代码块 3.可以重复复用 1)函数的定义 2)函数的传参 3)函数的变量 4)函数的返回值 函数的定义 [root@test ~]#cat fun.sh fun1(){ echo "第一种定义方式" } function fun2 { echo "第二种定义方式" } function fun3(){ echo "第三种定义方式" } fun1 fun2 fun3 #执行 [root@xxxx ~/count_bash]#sh fun.sh 第一种方式 第二种定义方式 第三种定义方式 #调用不成功,因为是子shell,没法在父shell中用 [root@xxxx ~/count_bash]#fun1 -bash: fun1: command not found #加载引用一下 [root@xxxx ~/count_bash]#source fun.sh 第一种方式 第二种定义方式 第三种定义方式 #调用 [root@xxxx ~/count_bash]#fun1 第一种方式 [root@xxxx ~/count_bash]#fun2 第二种定义方式 [root@xxxx ~/count_bash]#fun3 第三种定义方式 #想在别的脚本中引用定义的变量 [root@xxxx ~/count_bash]#cat test.sh [ -f /root/count_bash/fun.sh ] && . /root/count_bash/fun. fun1 [root@xxxx ~/count_bash]#sh test.sh 第一种方式 第二种定义方式 第三种定义方式 第一种方式 # 默认输出,再调用fun1 系统自带的函数库 /etc/init.d/functions #先引用函数库 [ -f /etc/init.d/functions ] && . /etc/init.d/functions env1=$1 Te(){ if [ $? -eq 0 ];then action "Nginx $env1" true # 使用action函数 else action "Nginx $env1" false fi [root@xxxx ~/count_bash]#sh nginx.sh stop Nginx stop [ OK ] 2)函数的传参、不能直接接收shell脚本的传参 方式1: [root@test ~]#cat fun.sh fun1(){ if [ -f $1 ];then echo "$1 存在" else echo "$1 不存在" fi } fun1 /etc/hosts #fun1后面第一个参数就是函数体里面的$1 [root@test ~]#cat fun.sh fun1(){ if [ -f $2 ];then echo "$2 存在" else echo "$2 不存在" fi } fun1 /etc/hosts /etc/passwd #fun1后面第二个参数就是函数体里面的$2 [root@test ~]#sh fun.sh /etc/passwd 存在 [root@test ~]#cat fun.sh fun1(){ if [ -f $1 ];then # 然后函数体这里接收到fun1 /etc/passwd echo "$1 存在" else echo "$1 不存在" fi } fun1 $1 # 下面输入的/etc/passwd先被这里接收到 [root@test ~]#sh fun.sh /etc/passwd /etc/passwd存在 [root@test ~]#cat fun.sh fun1(){ if [ -f $2 ];then # 这里的$2是fun1后面第二个参数,也就是$1 echo "$2 存在" else echo "$2 不存在" fi } fun1 $2 $1 [root@test ~]#sh fun.sh /etc/hosts /etc/passwd /etc/hosts 存在 方式2 [root@test ~]#cat fun.sh #!/bin/bash FILE=$1 #变量先接收 fun1(){ if [ -f $FILE ];then echo "$FILE 存在" else echo "$FILE 不存在" fi } fun1 [root@test ~]#sh fun.sh /etc/hosts /etc/hosts 存在 [root@test ~]#sh fun.sh /etc/hostssssssssss /etc/hostssssssssss 不存在 #nginx去掉env1=$1 #!/bin/bash [ -f /etc/init.d/functions ] && . /etc/init.d/functions te(){ if [ $? -eq 0 ];then action "Nginx $1" true else action "Nginx $1" false fi } case $1 in start) /usr/sbin/nginx te $1 ;; 3)函数的变量 [root@test ~]#cat fun.sh #!/bin/bash fun1(){ name=oldboy echo $name } fun1 echo $name [root@test ~]#sh fun.sh oldboy oldboy [root@test ~]#cat fun.sh #!/bin/bash fun1(){ local name=oldboy # local只在函数中生效 echo $name } fun1 echo $name # 输出结果为空,调用不到函数里面的变量 [root@test ~]#sh fun.sh oldboy 4)函数的返回值 错误的返回值写法 [root@test ~]# [root@test ~]#cat fun.sh #!/bin/bash fun1(){ if [ -f $1 ];then return 50 else return 100 fi } fun1 $1 [ $? -eq 50 ] && echo "文件存在" [ $? -eq 100 ] && echo "文件不存在" # 上面判断$1存在的返回值接受不到,只能接受到上一条的返回值 错误的写法 [root@test ~]#cat fun.sh #!/bin/bash fun1(){ if [ -f $1 ];then return 50 else return 100 fi } fun1 $1 if [ $? -eq 50 ];then echo "$1 存在" elif [ $? -eq 100 ];then echo "$1 存在" fi 正确的写法: #返回值在0-255之间 [root@test ~]#cat fun.sh #!/bin/bash fun1(){ if [ -f $1 ];then return 50 else return 100 fi } fun1 $1 re=$? if [ $re -eq 50 ];then echo "$1 存在" elif [ $re -eq 100 ];then echo "$1 不存在" fi [root@test ~]#sh fun.sh /etc/hosts /etc/hosts 存在 [root@test ~]#sh fun.sh /etc/hostssssssssss /etc/hostssssssssss 不存在 函数的语法格式: yum(){ xxx } install(){ xxx } configure(){ xxxx } start(){ xxxx } xf(){ xxxx } cp(){ xxxxx } main(){ yum install configure start xf cp } mian
2、数组
bash
语法格式: array[索引|下标]=值 两种格式: 普通数组 只能用数字作为索引 关联数组 使用数字或者字符串作为索引 特点: 一个变量对应一个值 name=oldboy 类似 一个箱子装一个苹果 一个数组对应多个值 name=(zs ls lw) 类似 一个箱子装多个水果 数组定义: 使用索引方式定义: [root@test ~]#array[1]=shell [root@test ~]#array[2]=mysql [root@test ~]#array[3]=docker 查看对应索引的值: [root@test ~]#echo ${array[1]} shell [root@test ~]#echo ${array[2]} mysql [root@test ~]#echo ${array[3]} docker 查看数组中的索引值: [root@test ~]#echo ${array[*]} shell mysql docker 查看数组的索引 [root@test ~]#echo ${!array[*]} 1 2 3 定义方式2: 取消变量或者数组的定义 [root@test ~]#unset array [root@test ~]#echo ${array[*]} [root@test ~]#array=(shell mysql docker) [root@test ~]#echo ${array[*]} shell mysql docker [root@test ~]#echo ${!array[*]} 0 1 2 定义方式3: 支持命令 [root@test ~]#array=(`ls`) [root@test ~]#echo ${array[*]} 1.sh 1.txt 2.txt 5 a.sh blue.txt case.sh count.sh c.sh diff.sh disk.sh eluosi.sh for.sh f.sh fun.sh if.sh i.sh jumpserver.sh md.sh menu.sh m.sh nginx.sh os.sh os.sh.0 pa.sh ping.sh ran.sh ran.txt red.txt Shell sq.sh s.sh te.sh test.sh t.sh user.sh user.txt u.sh while.sh z.sh [root@test ~]#echo ${!array[*]} 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 定义方式: 混合定义 #注意不加[]为值,[]中为索引 [root@test ~]#array=(5=A B 10=C test) [root@test ~]#echo ${array[*]} 5=A B 10=C test [root@test ~]##array=([5]=A B 10=C test) [root@test ~]#unset array [root@test ~]#array=([5]=A B [10]=C test) [root@test ~]#echo ${array[*]} A B C test [root@test ~]#echo ${!array[*]} 5 6 10 11 案例.批量ping不连续的IP地址,如果通则输出在线 www.baidu.com www.weibo.com 10.0.0.2 10.0.0.7 www.oldboyedu.com [root@test ~]#ip=(www.baidu.com www.sina.com www.weibo.com 10.0.0.2) [root@test ~]#echo ${ip[*]} www.baidu.com www.sina.com www.weibo.com 10.0.0.2 [root@test ~]#for i in ${ip[*]};do echo $i;done www.baidu.com www.sina.com www.weibo.com 10.0.0.2 [root@test ~]#cat p.sh #!/bin/bash #定义数组 ip=(www.baidu.com www.sinaaaa.com www.weibo.com 10.0.0.222) #遍历数组 for i in ${ip[*]} do ping -c1 -W1 $i &>/dev/null [ $? -eq 0 ] && echo "$i 在线..." || echo "$i 不在线..." done [root@test ~]#sh p.sh www.baidu.com 在线... www.sinaaaa.com 不在线... www.weibo.com 在线... 10.0.0.222 不在线... #使用索引的方式遍历述职 [root@test ~]#cat p.sh #!/bin/bash ip=(www.baidu.com www.sinaaaa.com www.weibo.com 10.0.0.222) for i in ${!ip[*]} do ping -c1 -W1 ${ip[$i]} &>/dev/null [ $? -eq 0 ] && echo "${ip[$i]} 通的.." || echo "${ip[$i]} 不通的.." done [root@test ~]#sh p.sh www.baidu.com 通的.. www.sinaaaa.com 不通的.. www.weibo.com 通的.. 10.0.0.222 不通的.. 关联数组: 定义方式和普通数组相同、使用字符串作为索引(要先声明,数字不用声明) [root@test ~]#declare -A array #shell中先声明为关联数组 [root@test ~]#array[index1]=shell [root@test ~]#array[index2]=mysql [root@test ~]#array[index3]=docker [root@test ~]#echo ${!array[*]} index1 index3 index2 [root@test ~]#echo ${array[*]} shell docker mysql [root@test ~]#echo ${array[index1]} shell [root@test ~]#echo ${array[index3]} docker 案例1.统计单词出现的次数 [root@test ~]#cat a.txt shell test mysql shell shell docker test [root@test ~]#cat array.sh #!/bin/bash declare -A array for i in `cat a.txt` # shell mysql shell do let array[$i]++ # let array[mysql]++ let mysql++ let i++,如果是mysql次数+1,这里是记录次数 done for i in ${!array[*]} # ${array[*]}是放的上面的累加值,!取反取到索引 do echo $i 出现了 ${array[$i]}done declare -A array for i in `cat a.txt` 女人 男人 女人 女人 男人 人妖 do let array[$i]++ let array[女人]++ array[女人]=1 let array[$i]++ let array[男人]++ array[男人]=1 let array[$i]++ let array[女人]++ array[女人]=1 [女人]=2 let array[$i]++ let array[女人]++ array[女人]=1 [女人]=3 let array[$i]++ let array[男人]++ array[男人]=1 [男人]=2 let array[$i]++ let array[人妖]++ array[人妖]=1 [人妖]=1 done for i in ${!array[*]} do echo $i 出现了 ${array[$i]}done for i in ${!array[*]} *放的数字。!取反取到女人 男人 人妖 do echo 女人 出现了 ${array[女人]}echo 男人 出现了 ${array[男人]}echo 人妖 出现了 ${array[人妖]}done 统计passwd中最后一列解释器的次数 [root@test ~]#cat bash.sh #!/bin/bash declare -A array while read line do let array[`echo $line|awk -F: '{print $NF}'`]++ done</etc/passwd for i in ${!array[*]} do echo $i 出现了 ${array[$i]}done [root@test ~]#sh bash.sh /bin/bash 出现了 9 次 /bin/sync 出现了 1 次 /sbin/halt 出现了 1 次 /sbin/nologin 出现了 32 次 /sbin/shutdown 出现了 1 次
3、面试题笔试题
bash
面试题: 1.会写Shell吗 2.你都用shell写过什么脚本? 1)系统优化脚本 2)服务安装脚本(安装服务软件 版本不同 使用菜单方式选择安装) 3)系统巡检脚本 cpu 负载 磁盘 内存 网络带宽 4)日志切割脚本、预防单个文件过大 5)定时任务+脚本 数据统计 分析日志取TOP10 业务(python程序的 爬虫) 6)zabbix的自定义取值 7)程序的启停脚本 case $1 in 8)辅助程序的运行脚本 磁盘打满了 内存占满了 或者程序跑着跑着就没了 9)数据库备份脚本 全量 增量 分库分表备份 ... 3.写一个死循环脚本 4.$0 $n $# $?的含义 企业案例:需求是很多老服务器的数据 一对一的拷贝到 新服务器对应的目录下 比如 10.0.0.10下/code/目录下内容 拷贝到 10.0.0.200/code下 10.0.0.203/code目录下拷贝到 10.0.0.7/code目录下 依次类推 [root@docker01 ~]# cat test.sh #!/bin/bash # 定义源服务器和目标服务器的IP对应关系 declare -A server_map=( ["10.0.0.10"]="10.0.0.200" ["10.0.0.203"]="10.0.0.7" ) # 遍历所有源服务器 for src_ip in "${!server_map[@]}"; do 10.0.0.10 10.0.0.203 dst_ip=${server_map[$src_ip]} dst_ip=${server_map[$src_ip]} 10.0.0.10=10.0.0.200 echo "开始从 $src_ip:/search/odin/daemon/ 复制到 $dst_ip:/search/odin/daemon/" # 使用rsync进行同步 scp -rp -o StrictHostKeyChecking=no root@$src_ip:/search/odin/daemon/* root@$dst_ip:/search/odin/daemon/ if [ $? -eq 0 ];then echo "$src_ip$dst_ip 同步成功" else echo "$src_ip$dst_ip 同步失败" fi done echo "所有同步任务完成"

23、持续集成

1、Devops

bash
服务器 虚拟机 纯干净的系统 IP 主机名 配置 10.0.0.200 Gitlab 2核4G 50G硬盘 10.0.0.201 Jenkins 1核2G 50G硬盘 10.0.0.202 Nexus 1核2G 50G硬盘 10.0.0.203 Sonar 1核2G 50G硬盘 10.0.0.7 Web 1核1G 50G硬盘
1、Devops能干嘛
bash
提高产品质量 1 自动化测试 2 持续集成 3 代码质量管理工具 4 程序员鼓励师
2、Devops如何实现
bash
既然这么好?为什么有些公司没有 设计架构规划‐代码的存储‐构建‐测试、预生产、部署、监控

2、Git版本控制系统

1、版本控制系统简介
bash
vcs `version control system` 版本控制系统是一种记录一个或若干个文件内容变化,以便将来查阅特定版本内容情况的系统 记录文件的所有历史变化 随时可恢复到任何一个历史状态 多人协作开发 #类似于虚拟机的快照
2、常见版本管理工具
bash
1.SVN 2.git 页面版的代码仓库 1.github 全球使用最多的代码仓库 2.gitlab 全球使用最多的私有代码仓库 3.gitee 码云 中国使用最多的代码仓库

image

image

3、git使用
1、配置当前代码仓库的使用角色的信息
bash
git环境Kylin v10 SP3 [root@oldboy:~]#git --version git version 2.27.0 [root@xxxx ~/count_bash]#git config --global user.name "lizhenya" [root@xxxx ~/count_bash]#git config --global user.email "lizhenya@mail.com" [root@xxxx ~/count_bash]#git config --global color.ui true [root@oldboy:~]#git config --list user.name=lizhenya user.email=lizhenya@mail.com color.ui=true #实际写入到.gitconfig文件 [root@xxxx ~]#cat .gitconfig [user] email = lizhenya@mail.com name = lizhenya [color] ui = true
2、初始化仓库
bash
#创建代码目录 [root@git ~]#mkdir git_data [root@git ~]#cd git_data/ #git初始化命令,初始化后生成隐藏代码仓库.git [root@git ~/git_data]#git init Initialized empty Git repository in /root/git_data/.git/ [root@git ~/git_data]#ll -a total 0 drwxr-xr-x 3 root root 18 May 28 21:42 . dr-xr-x--- 5 root root 207 May 28 21:41 .. drwxr-xr-x 7 root root 119 May 28 21:42 .git # 查看隐藏的代码仓库 [root@git ~/git_data]#ll .git/ total 12 drwxr-xr-x 2 root root 6 May 28 21:42 branches # 分支 -rw-r--r-- 1 root root 92 May 28 21:42 config # 配置文件 -rw-r--r-- 1 root root 73 May 28 21:42 description # 描述 -rw-r--r-- 1 root root 23 May 28 21:42 HEAD # 头部 drwxr-xr-x 2 root root 332 May 28 21:42 hooks # 勾子 drwxr-xr-x 2 root root 21 May 28 21:42 info drwxr-xr-x 4 root root 30 May 28 21:42 objects # 项目 代码放此目录但是不是明文的HASH drwxr-xr-x 4 root root 31 May 28 21:42 refs drwxr-xr-x 4 root root 31 Sep 27 09:23 index # 暂存区文件,只有代码提交到暂存区才有
3、git区域名称

image

bash
工作目录: 进入git_data目录 当前的位置称为工作目录 类似车间工人 暂存区域: 临时存放代码的问题 类似质检车间 有问题可以返回,没有问题可以保存到仓库,类似于反悔的区域 本地仓库: 存储代码的位置类似工厂仓库 开发在工作目录写代码--->提交到暂存区域---->提交到本地仓库--->代码才真正的被管理。每次走当前这个流程相当于虚拟机做了一个快照的动作
4、git常用命令
bash
#增 将文件保存到本地仓库的流程 1.创建文件 [root@git ~/git_data]#touch a.txt # 查看当前状态 [root@git ~/git_data]#git status On branch master # 当前位于主干 No commits yet # 没有可提交的操作 Untracked files: # 未跟踪的文件 (use "git add <file>..." to include in what will be committed) a.txt # 文件是红色 nothing added to commit but untracked files present (use "git add" to track) 2.工作区提交到暂存区 [root@git ~/git_data]#git add a.txt [root@git ~/git_data]#git status On branch master No commits yet Changes to be committed: (use "git rm --cached <file>..." to unstage) new file: a.txt # 文件被提交到暂存区,变成了绿色 #多出了一个index文件 [root@git ~/git_data]#ll .git total 16 drwxr-xr-x 2 root root 6 May 28 21:42 branches -rw-r--r-- 1 root root 92 May 28 21:42 config -rw-r--r-- 1 root root 73 May 28 21:42 description -rw-r--r-- 1 root root 23 May 28 21:42 HEAD drwxr-xr-x 2 root root 332 May 28 21:42 hooks -rw-r--r-- 1 root root 104 May 28 21:54 index drwxr-xr-x 2 root root 21 May 28 21:42 info drwxr-xr-x 5 root root 40 May 28 21:54 objects drwxr-xr-x 4 root root 31 May 28 21:42 refs 3.将暂存区的内容提交到本地仓库,类似快照 注意: 只要执行一次commit 就相当于做了一个快照 [root@git ~/git_data]#git commit -m "newfile a.txt" [master (root-commit) 1150b18] newfile a.txt 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 a.txt #提交完之后要成为下面的状态,干净的工作目录 [root@git ~/git_data]#git status On branch master nothing to commit, working tree clean #又创建新的文件,相当于第二次快照里面有a.txt跟b.txt [root@git ~/git_data]#touch b.txt [root@git ~/git_data]#git status On branch master Untracked files: (use "git add <file>..." to include in what will be committed) b.txt nothing added to commit but untracked files present (use "git add" to track) [root@git ~/git_data]#git add b.txt [root@git ~/git_data]#git status On branch master Changes to be committed: (use "git restore --staged <file>..." to unstage) new file: b.txt [root@git ~/git_data]#git commit -m "newfile ab.txt" [master 2ce0877] newfile ab.txt 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 b.txt [root@git ~/git_data]#ll total 0 -rw-r--r-- 1 root root 0 May 28 21:52 a.txt -rw-r--r-- 1 root root 0 May 28 22:02 b.txt #删 git删除文件使用 git rm -f 1. 删除 [root@git ~/git_data]#git rm -f b.txt rm 'b.txt' [root@git ~/git_data]#git status On branch master Changes not staged for commit: (use "git add/rm <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) deleted: b.txt no changes added to commit (use "git add" and/or "git commit -a") 2.把操作提交到暂存区 [root@git ~/git_data]#git add b.txt [root@git ~/git_data]#git status On branch master Changes to be committed: (use "git restore --staged <file>..." to unstage) deleted: b.txt 3.将暂存区的内容提交到本地仓库,快照 [root@git ~/git_data]#git commit -m "newfile" [master 3ca1df7] newfile 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 a.txt #如果不小心误删除了工作目录的文件可以恢复git恢复工作目录的文件 [root@oldboy:git_data]#rm -f a.txt [root@oldboy:git_data]#git restore a.txt [root@oldboy:git_data]#ll total 0 -rw-r--r-- 1 root root 0 Sep 27 09:55 a.txt # 改 git修改文件 [root@oldboy:git_data]#echo aaaa >> b.txt [root@oldboy:git_data]#git add . [root@oldboy:git_data]#git commit -m "modifiled b.txt >>aaaa" [master 21ed94f] modifiled b.t xt >>aaaa 1 file changed, 1 insertion(+) 查看历史提交日志 git log --oneline git log commit 28736231685dd9f4dfb9e793615f933b2dd674dd (HEAD -> master) Author: lizhenya <lizhenya@mail.com> Date: Wed May 28 22:33:44 2025 +0800 modifiled d.txt commit 48078b4b712e387eb0c227076f78e3d19f7f71ec Author: lizhenya <lizhenya@mail.com> Date: Wed May 28 22:32:08 2025 +0800 delete c.txt

2ec6f31b062376e5d946761d1264386b

bash
# 工作区的d.txt添加内容 [root@git ~/git_data]#echo dddddddd >> d.txt [root@git ~/git_data]#ll total 4 -rw-r--r-- 1 root root 13 May 28 22:44 d.txt #比较工作区跟暂存区的区别 [root@git ~/git_data]#git diff d.txt diff --git a/d.txt b/d.txt index 1d60b70..02eda96 100644 --- a/d.txt +++ b/d.txt @@ -1 +1,2 @@ ddd +dddddddd # 多的内容 #提交到暂存区,内容一样 [root@git ~/git_data]#git add . [root@git ~/git_data]#git diff #比较暂存区和本地仓库的区别 #因为没提交,所以一样 [root@git ~/git_data]#git diff --cached d.txt #提交后,内容不一样 [root@git ~/git_data]#git diff --cached d.txt diff --git a/d.txt b/d.txt index 1d60b70..02eda96 100644 --- a/d.txt +++ b/d.txt @@ -1 +1,2 @@ ddd +dddddddd #提交到本地仓库,一样 [root@git ~/git_data]#git commit -m "v1.5" [master da5d4f0] v1.5 1 file changed, 1 insertion(+) [root@git ~/git_data]#git diff --cached d.txt # git diff 比对的工作目录和暂存区的不同 # git diff --cached 比对的是暂存区和本地仓库的不同 版本回滚 # git log只能看当前版本及之前版本的信息,无法查看所有的 [root@oldboy ~/git_data]#git log --oneline 2cfee95 (HEAD -> master) delfile 4cc392a newfile b.txt 8984112 newfile a.txt # 回滚到4cc392a [root@oldboy ~/git_data]#git reset --hard 4cc392a HEAD is now at 4cc392a newfile b.txt [root@oldboy ~/git_data]#ll total 0 -rw-r--r-- 1 root root 0 May 28 23:18 a.txt -rw-r--r-- 1 root root 0 May 28 23:14 b.txt [root@oldboy ~/git_data]#git log --oneline 4cc392a (HEAD -> master) newfile b.txt 8984112 newfile a.txt #reflog 查看所有的历史提交 [root@oldboy ~/git_data]#git reflog 4cc392a (HEAD -> master) HEAD@{0}: reset: moving to 4cc392a 2cfee95 HEAD@{1}: commit: delfile 4cc392a (HEAD -> master) HEAD@{2}: commit: newfile b.txt 8984112 HEAD@{3}: commit (initial): newfile a.txt
5、git分支

514e79f62c067db7d2a2e6c0931f2ff3

bash
拉取复制主分支代码到子分支进行测试、开发,之后进行合并 # 查看当前工作目录状态 [root@oldboy ~/git_data]#git status On branch master nothing to commit, working tree clean # 查看当前所在分支 [root@oldboy ~/git_data]#git branch * master # 创建testing分支 [root@oldboy ~/git_data]#git branch testing # 查看当前所在 [root@oldboy ~/git_data]#git branch * master testing # 切换到testing分支 [root@oldboy ~/git_data]#git checkout testing Switched to branch 'testing' # 查看当前所在 [root@oldboy ~/git_data]#git branch master * testing # 创建新的功能c.txt [root@oldboy ~/git_data]#touch c.txt [root@oldboy ~/git_data]#git add c.txt [root@oldboy ~/git_data]#git commit -m "new files c.txt" [testing 70bc6a9] new files c.txt 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 c.txt [root@oldboy ~/git_data]#git status On branch testing nothing to commit, working tree clean [root@oldboy ~/git_data]#ll total 0 -rw-r--r-- 1 root root 0 May 28 23:18 a.txt -rw-r--r-- 1 root root 0 May 28 23:14 b.txt -rw-r--r-- 1 root root 0 May 28 23:42 c.txt # 切换到主分支 [root@oldboy ~/git_data]#git checkout master Switched to branch 'master' [root@oldboy ~/git_data]#git branch * master testing [root@oldboy ~/git_data]#git status On branch master nothing to commit, working tree clean # 因为没同步testing分支,所以没有新文件 [root@oldboy ~/git_data]#ll total 0 -rw-r--r-- 1 root root 0 May 28 23:18 a.txt -rw-r--r-- 1 root root 0 May 28 23:14 b.txt # 将testing中的代码合并到master分支 [root@oldboy ~/git_data]#git merge testing Updating 4cc392a..70bc6a9 Fast-forward c.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 c.txt [root@oldboy ~/git_data]#ll total 0 -rw-r--r-- 1 root root 0 May 28 23:18 a.txt -rw-r--r-- 1 root root 0 May 28 23:14 b.txt -rw-r--r-- 1 root root 0 May 28 23:47 c.txt # 合并后删除testing分支,因为开发有很多,如果都提交了功能,那么当前分支落后于主分支会提交失败,代码不同步 [root@oldboy ~/git_data]#git branch * master testing [root@oldboy ~/git_data]#git branch -d testing Deleted branch testing (was 70bc6a9). [root@oldboy ~/git_data]#git branch * master
6、分支冲突
bash
1.主分支新增内容 # 查看当前分支 [root@oldboy ~/git_data]#git branch * master # 创建分支 [root@oldboy ~/git_data]#git branch testing [root@oldboy ~/git_data]#git branch * master testing [root@oldboy ~/git_data]#ll total 0 -rw-r--r-- 1 root root 0 May 28 23:18 a.txt -rw-r--r-- 1 root root 0 May 28 23:14 b.txt -rw-r--r-- 1 root root 0 May 28 23:47 c.txt # 追加内容 [root@oldboy ~/git_data]#echo "111" > a.txt [root@oldboy ~/git_data]#cat a.txt 111 [root@oldboy ~/git_data]#git add a.txt # 提交到本地仓库 [root@oldboy ~/git_data]#git commit -m "modifle a.txt 111" [master 627f9be] modifle a.txt 111 1 file changed, 1 insertion(+) [root@oldboy ~/git_data]#ll total 4 -rw-r--r-- 1 root root 4 May 29 08:43 a.txt -rw-r--r-- 1 root root 0 May 28 23:14 b.txt -rw-r--r-- 1 root root 0 May 28 23:47 c.txt [root@oldboy ~/git_data]#git status On branch master nothing to commit, working tree clean 2.testing分支增加内容 # 切换testing分支 [root@oldboy ~/git_data]#git checkout testing Switched to branch 'testing' [root@oldboy ~/git_data]#git branch master * testing # 追加内容 [root@oldboy ~/git_data]#echo "222" > a.txt [root@oldboy ~/git_data]#cat a.txt 222 [root@oldboy ~/git_data]#git add a.txt [root@oldboy ~/git_data]#git commit -m "modifl a.txt 222" [testing 2faee16] modifl a.txt 222 1 file changed, 1 insertion(+) [root@oldboy ~/git_data]#ll total 4 -rw-r--r-- 1 root root 4 May 29 08:47 a.txt -rw-r--r-- 1 root root 0 May 28 23:14 b.txt -rw-r--r-- 1 root root 0 May 28 23:47 c.txt [root@oldboy ~/git_data]#git status On branch testing nothing to commit, working tree clean 3.切换主分支合并 # 切换主分支 [root@oldboy ~/git_data]#git checkout master Switched to branch 'master' [root@oldboy ~/git_data]#git branch * master testing [root@oldboy ~/git_data]#cat a.txt 111 # 合并testing分支,失败,显示冲突了 [root@oldboy ~/git_data]#git merge testing Auto-merging a.txt CONFLICT (content): Merge conflict in a.txt Automatic merge failed; fix conflicts and then commit the result. # 查看冲突文件 [root@oldboy ~/git_data]#cat a.txt > HEAD 111 ======= 222 < testing # vim进去手动解决冲突 [root@oldboy ~/git_data]#cat a.txt 111 222 # 提交到仓库,解决 [root@oldboy ~/git_data]#git add . [root@oldboy ~/git_data]#git commit -m "merge testing" [master 7284362] merge testing [root@oldboy ~/git_data]#git status On branch master nothing to commit, working tree clean [root@oldboy ~/git_data]#ll total 4 -rw-r--r-- 1 root root 8 May 29 08:52 a.txt -rw-r--r-- 1 root root 0 May 28 23:14 b.txt -rw-r--r-- 1 root root 0 May 28 23:47 c.txt [root@oldboy ~/git_data]#cat a.txt 111 222
7、git标签
bash
标签也是指向了一次commit提交,是一个里程碑式的标签,回滚打标签直接加标签号,不需要加唯一字符串不好记 标签即为版本号 [root@oldboy ~/git_data]#git log --oneline 7284362 (HEAD -> master) merge testing 2faee16 modifl a.txt 222 627f9be modifle a.txt 111 70bc6a9 new files c.txt 4cc392a newfile b.txt 8984112 newfile a.txt # 给最早的一个hahs值打tag [root@oldboy ~/git_data]#git tag -a v1.0 8984112 -m "v1.0稳定版" [root@oldboy ~/git_data]#git tag -a v1.1 7284362 -m "v1.0最新版" # 查看标签 [root@oldboy ~/git_data]#git tag v1.0 v1.1 # 查看tag的详细信息 [root@oldboy ~/git_data]#git show v1.0 tag v1.0 Tagger: lizhenya <lizhenya@mail.com> Date: Thu May 29 09:06:07 2025 +0800 v1.0稳定版 commit 89841125cfbf9d55e1cd2886fd8f188f93dcb87a (tag: v1.0) Author: lizhenya <lizhenya@mail.com> Date: Wed May 28 23:14:27 2025 +0800 newfile a.txt diff --git a/a.txt b/a.txt new file mode 100644 index 0000000..e69de29 # 通过tag版本回滚代码 [root@oldboy ~/git_data]#git reset --hard v1.0 HEAD is now at 8984112 newfile a.txt [root@oldboy ~/git_data]#ll total 0 -rw-r--r-- 1 root root 0 May 29 09:09 a.txt # 删除标签 [root@oldboy ~/git_data]#git tag -d v1.0 Deleted tag 'v1.0' (was 866c266) [root@oldboy ~/git_data]#git tag -d v1.1 Deleted tag 'v1.1' (was 7157754) [root@oldboy ~/git_data]#git tag

3、gitlab

bash
github #是公共平台 类似阿里云平台。开发经常使用、将自己开发的代码上传到github平台供其他人员使用。 码云 # 国内代码共享平台。 GitLab: 是一个用于仓库管理系统的开源项目。使用Git作为代码管理工具,并在此基础上搭建起来的web服务。可通过Web界面进行访问公开的或者私人项目。它拥有与 Github类似的功能,能够浏览源代码,管理缺陷和注释。可以管理团队对仓库的访问,它非常易于浏览提交过的版本并提供一个文件历史库。团队成员可以利用内置的简单聊 天程序(Wall)进行交流。它还提供一个代码片段收集功能可以轻松实现代码复用。 常用的网站: 官网:https://about.gitlab.com/ 中文网站: https://gitlab.cn/ 国内镜像: https://mirrors.tuna.tsinghua.edu.cn/gitlab‐ce/yum/
1、ubt安装gitlab
bash
安装环境: 1、 ubuntu22.04 2、 8G内存 3、 安装包:gitlab-ce_16.5.2-ce.0_amd64 4、 禁用防火墙,关闭selinux # yum仓库更新安装和配置所需的依赖 sudo apt-get update # 安装仓库依赖 sudo apt-get install -y curl openssh-server ca-certificates tzdata perl # 通过curl到的bash脚本然后交给bash执行 curl -L get.gitlab.cn | bash # 安装gitlab,时间大约40分钟 root@oldboy:~# EXTERNAL_URL="http://8.138.250.63" apt-get install -y gitlab-jh root@ubuntu:~# gitlab-ctl status # 查看gitlab状态 root@ubuntu:~# gitlab-ctl stop # 停止gitlab服务 root@ubuntu:~# gitlab-ctl start # 启动gitlab服务 安装完成后访问8.138.250.63 默认用户: root 临时密码位置:cat /etc/gitlab/initial_root_password

image修改语言为中文

image

image修改密码

image

2、创建新的项目

cd226c4193df0ee6b126df25f7d0b5bb

bash
开发创建本地仓库git_data 1.通过vim编辑、2.通过git add .提交到暂存区、3.通过git commit -m "xxx"提交到仓库、4.将本地仓库的代码推送到远程仓库 创建项目的三种方式: #1、已经存在的代码 1、gitlab创建game仓库 2、本地仓库中配置gitlab的game仓库为远程仓库 3、将本地仓库的游戏代码推送到远程gitlab的ganme仓库 #2、代码不存在,开发从头写 1、首先从gitlab创建test仓库 2、直接将test仓库clone到本地 3、本地可以看到test目录,并且远程仓库是gitlab的test仓库 4、直接在test目录写代码,提交到本地仓库,推送到远程仓库 #3、第三方代码 1、第三方的代码连接 2、将代码的连接导入到gitlab的仓库中即可
1、第一种方式

创建群组

image

添加项目为远程仓库,用组的身份创建

image

bash
1.添加远程仓库 [root@git ~/git_data]#git remote # 添加一个远程仓库“origin”,链接地址为:git@10.0.0.201:oldboy/test.git [root@git ~/git_data]#git remote add origin git@10.0.0.201:oldboy/test.git [root@git ~/git_data]#git remote origin # 可以看到仓库的详细信息 [root@git ~/git_data]#git remote -v origin git@10.0.0.201:oldboy/test.git (fetch) # 拉取 origin git@10.0.0.201:oldboy/test.git (push) # 推送 # 删除远程仓库 [root@git ~/git_data]#git remote remove origin 2.做免密钥 #在推送之前需要先做免密钥,将kylin200的公钥放到ubuntu201 gitlab页面 [root@git ~]#ssh-keygen Generating public/private rsa key pair. Enter file in which to save the key (/root/.ssh/id_rsa): Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in yes Your public key has been saved in yes.pub The key fingerprint is: SHA256:CRfxHSl8YYkQVjO3EdAridsDKwCQ73FaWN6Ene/6fjQ root@git The keys randomart image is: +---[RSA 3072]----+ |.o o .**=+B= | |. . o +. o+*=+ | | . = o.....+o. | | + = .o+.o . | | . = . .S= . | | o . + E | | o . o | | . . | | oo. | +----[SHA256]-----+ [root@git ~]#cat .ssh/id_rsa.pub ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDPhKgLVj/iYrnEq4nVj4trux+ZWR+eJttAX6wlmRK4+9Ie9fWYyJ1NqXUu/eAK1ExbPlG4/O7 vwZIpF+wc8gq28trR6vwCp+CyDbU1JoTjjWjyanU8O7JqyGyCVJpfo/BSPPeVpqVCQXaEeaK+0pAnOIhvfgNmtez1Kgn7k4AkdzEkO4K92DlNE+ K8DKznEOyZkY9xDzzmCD2NEGRyJPom2s/A8PG4ADRcD2ieIo7QyhpYofFfqeG6d4Y9YuxAW6kZqqVUhSyml5TlZEmjG2RzXfQYJlgjtbdZ815qA TCaXFSgkvq7qo1Vc6WLcPF0pQzOgDSEBU8Oi/8rMYiw54yLIZEnQ3VYnNCh6q9EsjpBpiusgCBRHqApVh6ZwOQ7OuCpw67/lxvLSzKQPeTME4Lo ugIJqLnBkrgbqHvYEE/HtG9rp0R2fSVFVEh4CK0MP+GgtEXy70107DhePqsq5QvppFb+bMwZEpA30ZOCqhvUNmJkc11RGTJhu4eyfHAdMj0= root@git

image

bash
3.将本地仓库的代码推送到远程gitlab的test仓库 # 将本地master分支推送到远程origin仓库 [root@git ~/git_data]#git push -u origin master The authenticity of host 10.0.0.201 (10.0.0.201)' can't be established. ECDSA key fingerprint is SHA256:ws3CQoYswByBQMVJKbuDH0vtlKBq2qSQXVAoWW0CulA. Are you sure you want to continue connecting (yes/no/[fingerprint])? yes Warning: Permanently added '10.0.0.201' (ECDSA) to the list of known hosts. Enumerating objects: 3, done. Counting objects: 100% (3/3), done. Writing objects: 100% (3/3), 206 bytes | 206.00 KiB/s, done. Total 3 (delta 0), reused 0 (delta 0), pack-reused 0 To 10.0.0.201:oldboy/test.git * [new branch] master -> master Branch 'master' set up to track remote branch 'master' from 'origin'. # 返回gitlab查看,可以看到代码已经同步到gitlab中

image

删除项目

bash
设置-通用-往下拉找到高级-删除项目

image

2、第二种创建方式

image

image

bash
# 将test1仓库clone到本地 [root@git ~]#git clone git@10.0.0.201:oldboy/test1.git Cloning into 'test1'... remote: Enumerating objects: 3, done. remote: Counting objects: 100% (3/3), done. remote: Compressing objects: 100% (2/2), done. remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0 (from 0) Receiving objects: 100% (3/3), done. [root@git ~]#ll total 8 drwxr-xr-x 3 root root 31 May 29 11:30 git_data drwxr-xr-x 3 root root 35 May 29 12:20 test1 [root@git ~/test1]#ll total 8 -rw-r--r-- 1 root root 6103 May 29 12:20 README.md # 克隆的自带远程仓库,并不需要配置 [root@git ~/test1]#git remote origin [root@git ~/test1]#git remote -v origin git@10.0.0.201:oldboy/test1.git (fetch) origin git@10.0.0.201:oldboy/test1.git (push) # 创建代码文件推送到本地仓库 [root@git ~/test1]#touch 1.txt [root@git ~/test1]#git add 1.txt [root@git ~/test1]#git commit -m "1.txt" [main 7b81125] 1.txt 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 1.txt [root@git ~/test1]#ll total 8 -rw-r--r-- 1 root root 0 May 29 12:23 1.txt -rw-r--r-- 1 root root 6103 May 29 12:20 README.md # 查看git分支 [root@git ~/test1]#git branch * main # 将本地main分支推送到远程origin仓库 [root@git ~/test1]#git push -u origin main Enumerating objects: 4, done. Counting objects: 100% (4/4), done. Compressing objects: 100% (2/2), done. Writing objects: 100% (3/3), 263 bytes | 263.00 KiB/s, done. Total 3 (delta 0), reused 0 (delta 0), pack-reused 0 To 10.0.0.201:oldboy/test1.git 2c3fcdf..7b81125 main -> main Branch 'main' set up to track remote branch 'main' from 'origin'. #gitlab页面查看

image

3、第三种创建方式

image

image

bash
# 将game仓库clone到本地 [root@git ~]#git clone git@10.0.0.201:oldboy/game.git Cloning into 'game'... warning: You appear to have cloned an empty repository. [root@git ~]#ll total 7728 drwxr-xr-x 3 root root 18 May 29 12:49 game # 解压到gama目录 [root@git ~/game]#unzip '小霸王_FC怀旧游戏机-HTML源码_(1).zip' -d game [root@git ~/game]#ll total 48 -rw-r--r-- 1 root root 28032 May 24 2021 bgm.mp3 drwxr-xr-x 2 root root 23 May 24 2021 css drwxr-xr-x 2 root root 23 May 24 2021 images -rw-r--r-- 1 root root 8956 May 24 2021 index.html drwxr-xr-x 2 root root 213 May 24 2021 js drwxr-xr-x 2 root root 4096 May 24 2021 roms -rw-r--r-- 1 root root 811 May 24 2021 shuoming.html # 将代码推送到本地仓库,保证工作目录是干净的 [root@git ~/game]#git status On branch master No commits yet Untracked files: (use "git add <file>..." to include in what will be committed) bgm.mp3 css/ images/ index.html js/ roms/ shuoming.html nothing added to commit but untracked files present (use "git add" to track) [root@git ~/game]#git add . [root@git ~/game]#git commit -m "xbw" # 推送到远端 [root@git ~/game]#git push -u origin master Enumerating objects: 98, done. Counting objects: 100% (98/98), done. Compressing objects: 100% (96/96), done. Writing objects: 100% (98/98), 7.35 MiB | 5.75 MiB/s, done. Total 98 (delta 3), reused 0 (delta 0), pack-reused 0 To 10.0.0.201:oldboy/game.git * [new branch] master -> master Branch 'master' set up to track remote branch 'master' from 'origin'. # 查看gitlab页面

image

bash
# 如何拉取刚上传的代码克隆到别的服务器 做免密钥,将kylin07的公钥放到ubuntu201 gitlab页面 [root@xxxx ~]#cat .ssh/id_rsa.pub ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCwiPpshps3lfDel6wjszSRkNp6w29JYywvhHhXmu5vP8bOT61cJ4ZXXrwqtX0CvAuyzRVIfHP fM8V/UTfadrct0fL6TC2PSxj/EvtfK0pQi3I+dCd1vAQFJCWI2ux/ooGnhCE0VQVn+Dolw3Pbf4MjifStE8TBxSMZ0CZrnak967J6ouh1rGDWF ks0qwS2/qSKlcrAMVTVa9MPfsz6cJ+j7SOU+3Zgizv5BU0Yc9FXDozzDN42fpGwzVg8Q1JvrTej2grTB8K2Y46VBSuS4gR/4JtFIpiVbxqSR4u L86NLTfxKJPGSK23X7ud33A0x1BQWzxX6tEQQYlEShKT+vRPMwJ8a0HKuvUfpP8la/dC0kk8nJl8UGhF7u1OmDi1YXsSvI84khrUR1lqwZCK 1rN5xrvdrYYQtNndFm69N7PvF3qgZ7XzDurWzGkjnkfSmsQNWSg9uFnrdANvH8H0//MN2UThZqeOVI0f/YOBvprACVgPE0UZum+Hw5soN8bGy 0F8= root@web01

image

bash
# 拉取到本地 [root@xxxx /code/xy]#git clone git@10.0.0.201:oldboy/game.git Cloning into game'... The authenticity of host '10.0.0.201 (10.0.0.201)' can't be established. ECDSA key fingerprint is SHA256:ws3CQoYswByBQMVJKbuDH0vtlKBq2qSQXVAoWW0CulA. Are you sure you want to continue connecting (yes/no/[fingerprint])? yes Warning: Permanently added '10.0.0.201' (ECDSA) to the list of known hosts. remote: Enumerating objects: 98, done. remote: Counting objects: 100% (98/98), done. remote: Compressing objects: 100% (96/96), done. remote: Total 98 (delta 3), reused 0 (delta 0), pack-reused 0 (from 0) Receiving objects: 100% (98/98), 7.53 MiB | 5.88 MiB/s, done. Resolving deltas: 100% (3/3), done. [root@xxxx /code/xy]#ll total 48 -rw-r--r-- 1 root root 28032 May 29 13:06 bgm.mp3 drwxr-xr-x 2 root root 23 May 29 13:06 css drwxr-xr-x 3 root root 18 May 29 13:07 game drwxr-xr-x 2 root root 23 May 29 13:06 images -rw-r--r-- 1 root root 8956 May 29 13:06 index.html drwxr-xr-x 2 root root 213 May 29 13:06 js drwxr-xr-x 2 root root 4096 May 29 13:06 roms -rw-r--r-- 1 root root 811 May 29 13:06 shuoming.html # 浏览器测试

image

3、创建普通用户

仪表盘-新建用户-填入用户名

image

image

bash
创建完新用户dev,另开窗口无痕登录dev用户 切回管理员用户 群组-进入oldboy小组-管理权限-邀请成员,选中dev用户,角色选择开发者

image

可以看到新添加的成员

image

回到dev用户,可以看到项目

image

bash
# 开发所用的服务器做与dev用户的免密钥就可以成功拉取所看到的项目代码 [root@web01 ~]# ssh-keygen Generating public/private rsa key pair. Enter file in which to save the key (/root/.ssh/id_rsa): Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /root/.ssh/id_rsa. Your public key has been saved in /root/.ssh/id_rsa.pub. The key fingerprint is: SHA256:XRP4KKGBL7fNGhQoMW0t7n3FSwKet2Iy7uYyUHeQffc root@web01 The keys randomart image is: +---[RSA 2048]----+ | oo * .. | | ..O * o o . | | + = B + +o | | . + O +.=.E. | | . o * =S*.. | |. + * = . | | . . + = | | o o . | | *o | +----[SHA256]-----+ [root@web01 ~]# cat .ssh/id_rsa.pub ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC4+CZ9F5zi2HbPCS/npKfo4KOsk0ko3K356/h79fU78K9hnBJdmnFsrTgd6YsXrwL0Kr4r79S16+gUrq0hGCN/dDO6AL0jGIfunitoQ5TBxdzfy1PufvO/xQhe5AR6qI3iM+qUntSLFOsw7WuTJReK0/LxNxaDhoY2aPLZbN5W0SWZdUH2iKpzkkg43z6rEyDoBIFzGjCNFct6x6Dx++rlMaoOuOD/DHF6tiuQiC18M6LkXRObdmXpAwXWmtsOTkfPxtNy79XXnBTMc31WL3vS3zvPhopefwHi86BDf7ODntGf++n7X6WCJejghPhcbHqNURX3sMnDgYwYn2G2qkJ7 root@web01 # 添加免密钥

image

bash
# 拉取远程代码 [root@web01 code]# git clone git@8.138.120.235:oldboy/game.git Cloning into 'game'... remote: Enumerating objects: 98, done. remote: Counting objects: 100% (98/98), done. remote: Compressing objects: 100% (96/96), done. remote: Total 98 (delta 3), reused 0 (delta 0), pack-reused 0 (from 0) Receiving objects: 100% (98/98), 7.53 MiB | 691.00 KiB/s, done. Resolving deltas: 100% (3/3), done. 什么时候用git clone? 本地没有代码的情况下 什么时候用git pull? 别的开发上传代码了或者在你上传之前不确定别人有没有上传,拉取一下试一下,更新下

4、模拟开发写完功能提交代码
bash
1. 错误流程 # 直接在master进行修改 #1、创建开发者名称信息 [root@web01 game]# git config --global user.name "dev" [root@web01 game]# git config --global user.email "dev@mail.com" [root@web01 game]# git config --global color.ui true [root@web01 game]# cat /root/.gitconfig [user] name = dev email = dev@mail.com [color] ui = true # 2、第90行的魂斗罗改成魂斗斗 ['魂斗斗', 'roms/Contra1(U)30.nes'], # 3、提交到本地仓库,git commit -am集成了git add .跟git commit -m ""。使用前提是已经提交到仓库了 [root@web01 game]# git commit -am "魂斗斗" [master 8dd2d66] 魂斗斗 1 file changed, 2 insertions(+), 2 deletions(-) # 4、远程推送失败 [root@web01 game]# git push -u origin master Counting objects: 5, done. Delta compression using up to 2 threads. Compressing objects: 100% (3/3), done. Writing objects: 100% (3/3), 290 bytes | 0 bytes/s, done. Total 3 (delta 2), reused 0 (delta 0) # 你无法推送至受保护的分支,开发者无权限 remote: GitLab: You are not allowed to push code to protected branches on this project.To git@8.138.120.235:oldboy/game.git ! [remote rejected] master -> master (pre-receive hook declined) error: failed to push some refs to 'git@8.138.120.235:oldboy/game.git'

546e7344ddc516585f22ac82a5af74f5

bash
2.正确流程 # 1.创建新的testing分支 [root@web01 game]# git branch * master [root@web01 game]# git branch testing [root@web01 game]# git branch * master testing # 2.把testing分支推送到项目中,此时第90行的魂斗罗已经改成了魂斗斗 [root@web01 game]# git push -u origin testing Counting objects: 5, done. Delta compression using up to 2 threads. Compressing objects: 100% (3/3), done. Writing objects: 100% (3/3), 290 bytes | 0 bytes/s, done. Total 3 (delta 2), reused 0 (delta 0) remote: remote: To create a merge request for testing, visit: remote: http://8.138.120.235/oldboy/game/-/merge_requests/new?merge_request%5Bsource_branch%5D=testing remote: To git@8.138.120.235:oldboy/game.git * [new branch] testing -> testing Branch testing set up to track remote branch testing from origin. # 普通用户页面可以看到,页面点击创建合并请求

image

image

bash
回到管理员页面 进入ganme项目可以看到“合并请求” 因为合并的时候删除了源分支,所以合并完成回到项目的时候,testing分支已经被删除了

image

bash
# 测试合并后的代码是否是魂斗斗 #下载新的代码 [root@web01 code]# git clone git@8.138.120.235:oldboy/game.git Cloning into 'game'... remote: Enumerating objects: 102, done. remote: Counting objects: 100% (102/102), done. remote: Compressing objects: 100% (100/100), done. remote: Total 102 (delta 5), reused 0 (delta 0), pack-reused 0 (from 0) Receiving objects: 100% (102/102), 7.54 MiB | 686.00 KiB/s, done. Resolving deltas: 100% (5/5), done. [root@web01 code]# ll total 4 drwxr-xr-x 7 root root 4096 May 29 20:46 game # 访问,成功修改成魂斗斗

image

bash
开发提交代码的第二种方式 # 创建并切换到test分支 [root@web01 game]# git checkout -b test Switched to a new branch 'test' [root@web01 game]# git branch master * test # 第90行修改为魂斗斗123 [root@web01 game]# vim index.html ['魂斗斗123', 'roms/Contra1(U)30.nes'], # 提交到本地仓库 [root@web01 game]# git add . [root@web01 game]# git commit -m "魂斗斗123" [test 0464fcf] 魂斗斗123 1 file changed, 1 insertion(+), 1 deletion(-) [root@web01 game]# git status # On branch test nothing to commit, working directory clean # 注意! 切换到master分支进行提交 [root@web01 game]# git checkout master Switched to branch 'master' [root@web01 game]# git push -u origin test Counting objects: 5, done. Delta compression using up to 2 threads. Compressing objects: 100% (3/3), done. Writing objects: 100% (3/3), 289 bytes | 0 bytes/s, done. Total 3 (delta 2), reused 0 (delta 0) remote: remote: To create a merge request for test, visit: remote: http://8.138.120.235/oldboy/game/-/merge_requests/new?merge_request%5Bsource_branch%5D=test remote: To git@8.138.120.235:oldboy/game.git * [new branch] test -> test Branch test set up to track remote branch test from origin. # 返回dev页面会看到“创建合并请求”,点击并填写内容

image

bash
返回管理员页面看到了新的合并请求

image

bash
# 重新拉取代码测试 [root@web01 code]# git clone git@8.138.120.235:oldboy/game.git

image

4、Jenkins

bash
官网 jenkins.io Jenkins是一个开源软件项目,是基于Java开发的一种持续集成工具,用于监控持续重复的工作,旨在提供一个开放易用的软件平台,使软件的持续集成变成可能。
1、安装jenkins
bash
Kylin系统 10.0.0.202 1核2G内存 # 安装JDK运行环境 [root@jenkins:~]#yum -y install java # 上传软件包并安装 [root@jenkins:~]#rpm -ivh jenkins-2.405-1.1.noarch.rpm ------------------------------------------------------------------------------------------------------- #这里有个问题,centos默认安装完java环境后启动jenkins报错,原因是java版本太低 [root@jenkins ~]# systemctl start jenkins Job for jenkins.service failed because the control process exited with error code. See "systemctl status jenkins.service" and "journalctl -xe" for details. [root@jenkins ~]# java -version openjdk version "1.8.0_412" OpenJDK Runtime Environment (build 1.8.0_412-b08) OpenJDK 64-Bit Server VM (build 25.412-b08, mixed mode) # 查看本地jdk版本 [root@jenkins ~]# yum search java | grep openjdk java-1.8.0-openjdk-src.x86_64 : OpenJDK 8 Source Bundle java-11-openjdk.i686 : OpenJDK Runtime Environment 11 java-11-openjdk.x86_64 : OpenJDK 11 Runtime Environment # 安装 [root@jenkins ~]# yum -y install java-11-openjdk # 选择默认版本 [root@jenkins ~]# alternatives --config java There are 3 programs which provide 'java'. Selection Command ----------------------------------------------- *+ 1 java-1.8.0-openjdk.x86_64 (/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.412.b08-1.el7_9.x86_64/jre/bin/java) 2 /usr/java/jdk1.8.0_181-amd64/jre/bin/java 3 java-11-openjdk.x86_64 (/usr/lib/jvm/java-11-openjdk-11.0.23.0.9-2.el7_9.x86_64/bin/java) Enter to keep the current selection[+], or type selection number: 3 #选择3 # 再次查看java版本 [root@jenkins ~]# java -version openjdk version "11.0.23" 2024-04-16 LTS OpenJDK Runtime Environment (Red_Hat-11.0.23.0.9-2.el7_9) (build 11.0.23+9-LTS) OpenJDK 64-Bit Server VM (Red_Hat-11.0.23.0.9-2.el7_9) (build 11.0.23+9-LTS, mixed mode, sharing) # 已经成功启动 [root@jenkins ~]# systemctl status jenkins ● jenkins.service - Jenkins Continuous Integration Server Loaded: loaded (/usr/lib/systemd/system/jenkins.service; disabled; vendor preset: disabled) Active: activating (start) since Thu 2025-05-29 22:58:02 CST; 51s ago Main PID: 15831 (java) ------------------------------------------------------------------------------------------------------- # 修改启动用户为root默认使用jenkins运行。 [root@jenkins:~]#grep root /usr/lib/systemd/system/jenkins.service User=root Group=root # 重新加载配置文件 [root@jenkins:~]#systemctl daemon-reload # 启动jenkins [root@jenkins:~]#systemctl start jenkins # 启动成功目录可以看到文件 [root@jenkins ~]# ll /var/lib/jenkins/ total 56 drwxr-xr-x 3 root root 4096 May 29 22:56 %C -rw-r--r-- 1 root root 1658 May 29 23:02 config.xml -rw-r--r-- 1 root root 156 May 29 23:01 hudson.model.UpdateCenter.xml -rw-r--r-- 1 root root 171 May 29 22:56 jenkins.telemetry.Correlator.xml drwxr-xr-x 2 root root 4096 May 29 22:56 jobs -rw-r--r-- 1 root root 907 May 29 23:01 nodeMonitors.xml drwxr-xr-x 2 root root 4096 May 29 22:56 nodes drwxr-xr-x 2 root root 4096 May 29 22:56 plugins -rw-r--r-- 1 root root 129 May 29 23:01 queue.xml.bak -rw-r--r-- 1 root root 64 May 29 22:56 secret.key -rw-r--r-- 1 root root 0 May 29 22:56 secret.key.not-so-secret drwx------ 2 root root 4096 May 29 22:56 secrets drwxr-xr-x 2 root root 4096 May 29 23:04 updates drwxr-xr-x 2 root root 4096 May 29 22:56 userContent drwxr-xr-x 3 root root 4096 May 29 22:56 users #配置jenkins的插件 将jenkins_plu.tar.gz压缩包上传到/var/lib/jenkins/plugins解压 [root@jenkins:plugins]#tar xf jenkins_plu.tar.gz # 重启jenkins生效 [root@jenkins:~]#systemctl restart jenkins 打开浏览器通过页面安装步骤 http://47.111.25.47:8080/ # 如果是云服务器访问失败,检查一下安全组规则是否放行了8080端口

image

页面安装

image

image

image

修改密码登录

image

image

image

bash
创建测试任务

image

保存创建完成之后点立即构建

image

构建完成后

image

image

bash
# 默认的工作目录,也就是jenkins的家/var/lib/jenkins/workspace [root@jenkins workspace]# ll total 4 drwxr-xr-x 2 root root 4096 May 30 09:20 测试任务 [root@jenkins workspace]# pwd /var/lib/jenkins/workspace 配置-touch 1.log

image

image

bash
# 可以看到新创建的文件 [root@jenkins 测试任务]# ll total 0 -rw-r--r-- 1 root root 0 May 30 09:25 1.log [root@jenkins 测试任务]# pwd /var/lib/jenkins/workspace/测试任务 # 因为用的root用户启动,所以可以在别的地方创建文件 [root@jenkins ~]# ll total 257260 -rw-r--r-- 1 root root 0 May 30 09:28 1.log
2、jenkins拉取gitlab代码到web服务器

创建game项目

image

丢弃旧的构建。保留5天,个数5个

image

image

bash
这里有个问题,为什么8.138.250.63是gitlab服务器,而这里显示8.138.120.235呢,原因是之前使用阿里云 http://8.138.120.235/构建了 gitlab之后保存了镜像,然后服务器释放了,没多久又买了一台服务器http://8.138.250.63/用的是之前8.138.120.235服务器的镜像创建的实例, 现在问题是8.138.250.63服务器可以正常登录gitlab,但是之前创建的项目ip是8.138.120.235导致git没法用 # 实例迁移后遇到项目URL指向旧 IP 的问题,这是典型的配置残留问题。 步骤 1:修改 GitLab 外部 URL 登录新服务器: ssh root@8.138.250.63 编辑 GitLab 主配置文件: vim /etc/gitlab/gitlab.rb # 修改为当前服务器IP external_url 'http://8.138.250.63' # 重新加载,问题解决 root@gitlab:~# gitlab-ctl reconfigure root@gitlab:~# gitlab-ctl restart # 换成新ip又报错了,原因又两个,1是底层没有做免密钥,要把235这台的公钥放到gitlab中去。2是需要手动把项目拉取到本地一下,输入个“yes”

image

bash
[root@jenkins tmp]# git clone git@8.138.250.63:oldboy/game.git Cloning into 'game... The authenticity of host '8.138.250.63 (8.138.250.63)' can't be established. ECDSA key fingerprint is SHA256:W+umSUAQfaudsq8eZE4Qm7tN/RZJcoH+iptU5YgWmkI. ECDSA key fingerprint is MD5:fd:b9:d1:ff:3d:10:5e:1f:5f:c7:49:52:0f:cc:df:a0. Are you sure you want to continue connecting (yes/no)? yes # 输入yes

image

保存后点击立即构建

image

bash
# 目录下已经有了 [root@jenkins ganme]# pwd /var/lib/jenkins/workspace/ganme [root@jenkins ganme]# ll total 60 -rw-r--r-- 1 root root 28032 May 30 10:29 bgm.mp3 drwxr-xr-x 2 root root 4096 May 30 10:29 css drwxr-xr-x 2 root root 4096 May 30 10:29 images -rw-r--r-- 1 root root 8956 May 30 10:29 index.html drwxr-xr-x 2 root root 4096 May 30 10:29 js drwxr-xr-x 2 root root 4096 May 30 10:29 roms -rw-r--r-- 1 root root 811 May 30 10:29 shuoming.html

推送到web服务器

image

bash
保存完-立即构建-失败了 # 原因是8.138.120.235与8.148.236.36之间没有做免密钥 [root@jenkins ganme]# ssh-copy-id 8.148.236.36

image

成功执行

image

bash
# 配置nginx [root@git /code/game]#cat /etc/nginx/conf.d/kod.conf server { listen 80 default; server_name _; location / { root /code/game; index index.html index.htm; } } [root@git /code/game]#nginx -t nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful [root@git /code/game]#systemctl restart nginx
3、jenkins配置webhook自动触发
bash
# 1.更新看是否有新代码 [root@git ~/game]#git pull remote: Enumerating objects: 8, done. remote: Counting objects: 100% (5/5), done. remote: Compressing objects: 100% (5/5), done. remote: Total 8 (delta 0), reused 5 (delta 0), pack-reused 3 (from 1) Unpacking objects: 100% (8/8), done. From 8.138.250.63:oldboy/game 099f5e1..d1a547a master -> origin/master Updating 099f5e1..d1a547a Fast-forward index.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) # 2.修改代码 ['混蛋罗', 'roms/Contra1(U)30.nes'], # 3.推送到本地仓库 [root@git ~/game]#git add . [root@git ~/game]#git commit -m "混蛋" [master 4683391] 混蛋 1 file changed, 2 insertions(+), 2 deletions(-) # 4.推送到远程gitlab的master分支,因为与管理员做了免密钥 [root@git ~/game]#git push -u origin master Counting objects: 5, done. Delta compression using up to 2 threads. Compressing objects: 100% (3/3), done. Writing objects: 100% (3/3), 299 bytes | 0 bytes/s, done. Total 3 (delta 2), reused 0 (delta 0) To git@8.138.250.63:oldboy/game.git 528394c..4683391 master -> master Branch master set up to track remote branch master from origin. # 5.jenkins直接执行立即构建,把从git本地仓库的项目推到远程gitlab服务器的代码下载到jenkins本地/var/lib/jenkins/workspace/ganme目录。再scp到47.111.25.47:/code/game/

image

刷新浏览器测试

image

配置自动触发

bash
如果master代码一变更就自动触发项目,自动去gitlab拉取代码然后推送到服务端

image

image

bash
jenkins在自己的game项目中生成钥匙token给gitlab,gitlab在自己game项目中配置钥匙,当gitlab的master一变,gitlab拿着钥匙来 触发jenkins的game项目

允许网络请求

image

配置钩子

image

image

bash
# 修改测试 ['混蛋罗123', 'roms/Contra1(U)30.nes'], # 提交到本地仓库 [root@git ~/game]#git add . [root@git ~/game]#git commit -m "混蛋罗123" [master 9854c6b] 混蛋罗123 1 file changed, 1 insertion(+), 1 deletion(-) # 推送到远程服务器master节点 [root@git ~/game]#git push -u origin master Counting objects: 5, done. Delta compression using up to 2 threads. Compressing objects: 100% (3/3), done. Writing objects: 100% (3/3), 300 bytes | 0 bytes/s, done. Total 3 (delta 2), reused 0 (delta 0) To git@8.138.250.63:oldboy/game.git 4683391..9854c6b master -> master Branch master set up to track remote branch master from origin. # 浏览器测试

image

5、SonarQube代码扫描

bash
jenkins将代码拉取到jenkins本地,先将代码推送到sonar服务器上代码扫描检测,检测漏洞 逻辑 坏味道。
1、安装
bash
1.安装java [root@SonarQube ~]# yum -y install java 2.安装mysql [root@SonarQube ~]# wget dev.mysql.com/get/mysql-community-release-el6-5.noarch.rpm [root@SonarQube ~]# rpm -ivh mysql-community-release-el6-5.noarch.rpm [root@SonarQube ~]# yum -y install mariadb-server 启动mysql [root@SonarQube ~]# service mysqld start 创建mysql密码 [root@SonarQube ~]# mysqladmin -uroot password lizhenya123 创建数据库 [root@SonarQube ~]# mysql -uroot -plizhenya123 -e "CREATE DATABASE sonar DEFAULT CHARACTER SET utf8;" 查看数据库 [root@SonarQube ~]# mysql -uroot -plizhenya123 -e "show databases;" Warning: Using a password on the command line interface can be insecure. +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | sonar | +--------------------+ 3.安装sonarqube 上传软件包 解压 [root@SonarQube ~]# unzip sonarqube-7.0.zip -d /usr/local/ 创建软连接 [root@SonarQube ~]# ln -s /usr/local/sonarqube-7.0/ /usr/local/sonarqube 修改连接数据库信息 [root@SonarQube ~]# cd /usr/local/sonarqube/conf/ [root@sonarqube:conf]#vim sonar.properties 修改配置文件的16 17和26行 16 sonar.jdbc.username=root 17 sonar.jdbc.password=lizhenya123 18 19 #----- Embedded Database (default) 20 # H2 embedded database server listening port, defaults to 9092 21 #sonar.embeddedDatabase.port=9092 22 23 #----- MySQL 5.6 or greater 24 # Only InnoDB storage engine is supported (not myISAM). 25 # Only the bundled driver is supported. It can not be changed. 26 sonar.jdbc.url=jdbc:mysql://localhost:3306/sonar?useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true &useConfigs=maxPerformance&useSSL=false 4.创建普通用户sonar sonarqube服务必须由普通用户运行。 [root@SonarQube conf]# useradd sonar [root@SonarQube conf]# chown -R sonar.sonar /usr/local/sonarqube-7.0/ 5.使用sonar用户运行服务 [root@SonarQube conf]# su - sonar -c "/usr/local/sonarqube/bin/linux-x86-64/sonar.sh start" Starting SonarQube... Started SonarQube. # sonar默认端口为9000 [root@SonarQube ~]# netstat -tnulp Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1094/sshd tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN 1052/master tcp 0 0 127.0.0.1:32000 0.0.0.0:* LISTEN 2060/java tcp 0 0 0.0.0.0:111 0.0.0.0:* LISTEN 549/rpcbind tcp6 0 0 :::22 :::* LISTEN 1094/sshd tcp6 0 0 ::1:25 :::* LISTEN 1052/master tcp6 0 0 :::9000 :::* LISTEN 2163/java tcp6 0 0 127.0.0.1:9001 :::* LISTEN 2082/java tcp6 0 0 :::3306 :::* LISTEN 1377/mysqld tcp6 0 0 :::111 :::* LISTEN 549/rpcbind udp 0 0 0.0.0.0:68 0.0.0.0:* 800/dhclient # 这里有个错误,分配了2g显示Elasticsearch 已经成功启动,但随后被系统终止(exit code 137)。这通常是内存不足导致的内核OOMKiller # 介入的结果。调整内存大小为4g启动成功 6.安装插件 进入目录 [root@SonarQube ~]# cd /usr/local/sonarqube/extensions/ [root@SonarQube extensions]# cd plugins/ 删除默认 [root@SonarQube plugins]# rm -rf * 上传插件 解压插件 [root@sonarqube:plugins]#tar xf sonar_plugins.tar.gz [root@sonarqube:plugins]#mv plugins/* . 重启sonarqube服务 [root@SonarQube plugins]# su - sonar -c "/usr/local/sonarqube/bin/linux-x86-64/sonar.sh restart" Stopping SonarQube... Waiting for SonarQube to exit... Stopped SonarQube. Starting SonarQube... Started SonarQube. # 再次登录,变成中文

image

image

2、sonar创建项目

image

bash
sonar-scanner \ -Dsonar.projectKey=html \ -Dsonar.sources=. \ -Dsonar.host.url=http://8.138.206.142:9000 \ -Dsonar.login=3ab430110acf50b8df9caa51a11d1da7ac822865 # 第二遍搭的 sonar-scanner \ -Dsonar.projectKey=html \ -Dsonar.sources=. \ -Dsonar.host.url=http://47.111.25.47:9000 \ -Dsonar.login=a6e032b1a51e9842c44ed9e0f535728d4babb469
3、客户端执行代码扫描上传到sonar服务器
bash
需要在jenkins安装sonar客户端,因为需要把代码拉取到jenkins,在jenkins调取sonar客户端推送到sonar服务器进行代码质量检测
bash
安装客户端: # 上传包解压 [root@jenkins ~]# unzip sonar-scanner-cli-4.2.0.1873-linux.zip -d /usr/local [root@jenkins ~]# cd /usr/local/ # 创建软连接 [root@jenkins local]# ln -s sonar-scanner-4.2.0.1873-linux/ sonar [root@jenkins bin]# pwd /usr/local/sonar/bin [root@jenkins bin]# ll total 8 -rwxr-xr-x 1 root root 1771 Oct 1 2019 sonar-scanner -rwxr-xr-x 1 root root 610 Oct 1 2019 sonar-scanner-debug # 将客户端写入PATH命令 [root@jenkins ~]# tail -1 /etc/profile export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/root/bin:/usr/local/sonar/bin" [root@jenkins local]# source /etc/profile [root@jenkins local]# echo $PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/root/bin:/usr/local/sonar/bin # 进入到代码目录 [root@jenkins ~]# cd /var/lib/jenkins/workspace/ganme/ [root@jenkins ganme]# ll total 60 -rw-r--r-- 1 root root 28032 May 30 10:29 bgm.mp3 drwxr-xr-x 2 root root 4096 May 30 10:29 css drwxr-xr-x 2 root root 4096 May 30 10:29 images -rw-r--r-- 1 root root 8960 May 30 11:53 index.html drwxr-xr-x 2 root root 4096 May 30 10:29 js drwxr-xr-x 2 root root 4096 May 30 10:29 roms -rw-r--r-- 1 root root 811 May 30 10:29 shuoming.html # 执行代码扫描 [root@jenkins ganme]# sonar-scanner \ > -Dsonar.projectKey=html \ > -Dsonar.sources=. \ > -Dsonar.host.url=http://8.138.206.142:9000 \ > -Dsonar.login=3ab430110acf50b8df9caa51a11d1da7ac822865 INFO: Scanner configuration file: /usr/local/sonar-scanner-4.2.0.1873-linux/conf/sonar-scanner.properties INFO: Project root configuration file: NONE INFO: SonarQube Scanner 4.2.0.1873 INFO: Java 11.0.3 AdoptOpenJDK (64-bit) INFO: Linux 3.10.0-1160.119.1.el7.x86_64 amd64 INFO: User cache: /root/.sonar/cache INFO: SonarQube server 7.0.0 INFO: Default locale: "en_US", source code encoding: "UTF-8" (analysis is platform dependent) 。。。 INFO: More about the report processing at http://8.138.206.142:9000/api/ce/task?id=AZcf6pW7utqRfyAaOpgN INFO: Task total time: 16.693 s INFO: ------------------------------------------------------------------------ INFO: EXECUTION SUCCESS INFO: ------------------------------------------------------------------------ INFO: Total time: 1:56.651s INFO: Final Memory: 14M/150M INFO: ------------------------------------------------------------------------ # 返回浏览器查看

image

4、sonar集成到jenkins上自动推送

image

image

image

image

bash
保存后,找到系统管理-系统配置,往下拉再找到SonarQube servers

image

image

服务器端配置好了

image

image

image

bash
snoar.projectName=${JOB_NAME} sonar.projectKey=html sonar.sources=. sonar.projectName=${JOB_NAME} # 项目在sonarqube上的显示名称 sonar.projectKey=html # 项目的唯一表示,不能重复 sonar.sources=. # 扫描那个项目的源码 # 运行测试 # 这里有个问题,sonar集成到jenkins上自动推送,我这只改了sonar内存到4g,放到jenkins里面也得需要至少2g的内存,所以jenkins也得4g

image

image

跑一遍流程

bash
1.修改代码 [root@git ~/game]#vim index.html ['魂斗罗', 'roms/Contra1(U)30.nes'], 2.提交到仓库 [root@git ~/game]#git commit -am "魂斗罗" [master 87c0642] 魂斗罗 1 file changed, 1 insertion(+), 1 deletion(-) 3.推送到远程 [root@git ~/game]#git push -u origin master Counting objects: 5, done. Delta compression using up to 2 threads. Compressing objects: 100% (3/3), done. Writing objects: 100% (3/3), 304 bytes | 0 bytes/s, done. Total 3 (delta 2), reused 0 (delta 0) To git@8.138.250.63:oldboy/game.git 9854c6b..87c0642 master -> master Branch master set up to track remote branch master from origin. # 已经自动推送到web服务器

image

image

6、token丢失或者创建新项目

image

image

5、代码发布测试流程

2f946be4e527c5ec94cb309b6d0aaf81

6、配置企业微信

bash
1.由于jenkins没有官网的插件来完成此功能,所以我们只能用网络上一些开源的插件(线下班不需要以下步骤,已集合在plugins) github下载代码 https://github.com/daniel-beck/changelogenvironment-plugin 解压到某个目录-》进入目录执行以下操作 cd 到 changelog-environment-plugin-master下,执行mvn verify 时间较长,会在changelog-environment-pluginmaster/target/下有个changelogenvironment.hpi文件,上传到jenkins即可使用 2.配置jenkins jenkins进入到项目中->构建环境多了Add Changelog Information to Environment-> 点击选择 Entry Format中添加 %3$s(at %4$s via %1$s),参数分别为ChangeLog内容,时间,提交人。 Date Format中添加 yyyy‐MM‐dd HH:mm:ss 就是时间格式。

image

bash
1.注册企业微信 https://mp.weixin.qq.com/ 2.上传py脚本 [root@jenkins:~]#ll total 4 -rw-r--r-- 1 root root 2008 Sep 28 14:59 jenkins_notify.py 3.修改信息 [root@jenkins ~]# vim jenkins_notify.py 34 "touser" : "ZhangWeiXiang", 63 Corpid = "wwc2749ba833b4e897" 64 Secret = "XUc23DnuGn-YcAzpa4T9_7yQc43IzgZL96XqtM5-9Ao"

609dd5f429e35ffb5dda7921fa1fee7image

bash
4.# 命令行测试,kylin可以 [root@jenkins:~]#yum -y install python2 [root@jenkins:~]#yum -y install python2-pip

image

image

image

image

可以正常访问

image

bash
# 因为是centons,可能版本不兼容,需要python3以上的版本 [root@sonar ~]# pip2.7 install requests Collecting requests Downloading http://mirrors.cloud.aliyuncs.com/pypi/packages/63/70/2bf7780ad2d390a8d301ad0b550f1581eadbd9a20f896afe06353c2a2913/requests-2.32.3.tar.gz (131kB) 100% |████████████████████████████████| 133kB 16.8MB/s Complete output from command python setup.py egg_info: ========================== Unsupported Python version ========================== This version of Requests requires at least Python 3.8, but you're trying to install it on Python 2.7. To resolve this, consider upgrading to a supported Python version. If you cant upgrade your Python version, you'll need to pin to an older version of Requests (<2.32.0). ---------------------------------------- Command "python setup.py egg_info" failed with error code 1 in /tmp/pip-build-sJ1R7V/requests/ You are using pip version 8.1.2, however version 25.1.1 is available. You should consider upgrading via the 'pip install --upgrade pip' command. [root@sonar ~]# python --version Python 2.7.5
bash
# centos执行 [root@jenkins ~]# pip3 install requests [root@jenkins scripts]# python3 jen.py test /etc/hosts game # 优化py代码 [root@sonar opt]# cat jen.py #!/usr/bin/env python3 # -*- coding: utf-8 -*- import requests import sys import json import urllib3 urllib3.disable_warnings() # 移除 Python 2 特有的代码 # reload(sys) # sys.setdefaultencoding('utf-8') def GetToken(Corpid, Secret): Url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken" Data = { "corpid": Corpid, "corpsecret": Secret } r = requests.get(url=Url, params=Data, verify=False) Token = r.json()['access_token'] return Token def SendMessage(Token, Subject, Content, ProName): Url = "https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=%s" % Token data = { "touser": "ZhangWeiXiang", "msgtype": "text", "agentid": 1000002, # 企业微信AgentId "text": { "content": "[项目名称] : " + ProName + '\n' + "[项目地址] : " + Subject + '\n' + Content + '\n' }, "safe": 0 } r = requests.post(url=Url, data=json.dumps(data), verify=False) return r.text def action_from_file(filename): try: str1 = '[变更日志] : ' with open(filename, 'r', encoding='utf-8') as f: for i in f.readlines(): str1 += i # 修复缩进问题,使用空格代替制表符 if len(str1) == 17: str1 += " 无变更" return str1 except Exception as e: # 使用 Python 3 的 print 函数 print(f'[ERROR] {e}') str1 += str(e) return str1 if __name__ == '__main__': Corpid = "wwc2749ba833b4e897" Secret = "XUc23DnuGn-YcAzpa4T9_7yQc43IzgZL96XqtM5-9Ao" Subject = sys.argv[1] Content = action_from_file(sys.argv[2]) ProName = sys.argv[3] Token = GetToken(Corpid, Secret) Status = SendMessage(Token, Subject, Content, ProName) print(Status) # 测试,成功

1aeba295042ff0da1883132d6334379

1、企业微信集成到jenkins

点击增加构建后操作步骤

image

输入打印的信息内容

image

bash
# 存放上面内容 echo "==========Start Notify==============" echo ${SCM_CHANGELOG} > /tmp/${JOB_NAME}_change.log python3 /server/scripts/jen.py ${BUILD_URL} /tmp/${JOB_NAME}_change.log ${JOB_NAME} rm -fv /tmp/${JOB_NAME}_change.log # 脚本移动到server/scripts/ [root@sonar opt]# mkdir -p /server/scripts/ [root@sonar opt]# mv jen.py /server/scripts/ [root@sonar opt]# ll /server/scripts/ total 4 -rw-r--r-- 1 root root 1840 Jun 2 15:54 jen.py
2、测试流程
bash
# 修改代码提交到本地仓库 [root@git ~/game]#vim index.html [root@git ~/game]#git add . [root@git ~/game]#git commit -m "魂斗罗v1.1" [master 70912ac] 魂斗罗v1.1 1 file changed, 1 insertion(+), 1 deletion(-) # 推送到gitlab远程,剩余自动执行 [root@git ~/game]#git push -u origin master Counting objects: 5, done. Delta compression using up to 2 threads. Compressing objects: 100% (3/3), done. Writing objects: 100% (3/3), 302 bytes | 0 bytes/s, done. Total 3 (delta 2), reused 0 (delta 0) To git@8.138.250.63:oldboy/game.git 9b2583b..70912ac master -> master Branch master set up to track remote branch master from origin. # 项目代码已经改变

image

bash
#时间已经更改为最新的

image

bash
# jenkins已经正常执行

image

bash
# 已经正常推送

d4ea5f88b1d9e202b14d031a509b7f2

7、代码线上业务发布流程

66d9e250677092d0a4fc6ef47ff78888

1、Jenkins参数构建配置

项目配置

image

image

image

image

bash
# 创建标签 [root@git ~/game]#git tag -a v1.0 -m "v1.0" [root@git ~/game]#git tag v1.0 [root@git ~/game]#git show v1.0 tag v1.0 Tagger: lizhenya <lizhenya@mail.com> Date: Fri May 30 17:55:09 2025 +0800 v1.0 commit 87c06422dc2b78f94addb49d543e44740606e3a4 Author: lizhenya <lizhenya@mail.com> Date: Fri May 30 15:38:28 2025 +0800 魂斗罗 diff --git a/index.html b/index.html index 46cd32f..267e4a8 100644 --- a/index.html +++ b/index.html @@ -87,7 +87,7 @@ nes = new JSNES({ 'ui': $('#emulator').JSNESUI({ "经典": [ - ['混蛋罗123', 'roms/Contra1(U)30.nes'], + ['魂斗罗', 'roms/Contra1(U)30.nes'], ['超级玛丽', 'roms/(W) Super Mario Bros. [!].nes'], ['坦克', 'roms/(Ch) Missile Tank.nes'], ['双截龙', 'roms/Double Dragon1.nes'], # 推送到远程 [root@git ~/game]# git push -u origin v1.0 Counting objects: 1, done. Writing objects: 100% (1/1), 151 bytes | 0 bytes/s, done. Total 1 (delta 0), reused 0 (delta 0) To git@8.138.250.63:oldboy/game.git * [new tag] v1.0 -> v1.0

image

Jenkins获取gitlab标签

image

image

image

image

bash
# 测试 # 修改代码内容 ['魂斗罗1.1', 'roms/Contra1(U)30.nes'], # 提交到本地仓库 [root@git ~/game]#git commit -am "v1.1" [master bcf41c1] v1.1 1 file changed, 1 insertion(+), 1 deletion(-) [root@git ~/game]#git tag -a v1.1 -m "v1.1" # 推送到远程 [root@git ~/game]#git push -u origin v1.1 Counting objects: 6, done. Delta compression using up to 2 threads. Compressing objects: 100% (4/4), done. Writing objects: 100% (4/4), 401 bytes | 0 bytes/s, done. Total 4 (delta 2), reused 0 (delta 0) To git@8.138.250.63:oldboy/game.git * [new tag] v1.1 -> v1.1 # 可以看到新创建的v1.1

image

bash
可以看到推送成功了

image

2、实现秒级回滚

bash
# 脚本内容 [root@jenkins ~]# cat deploy.sh #!/bin/bash code_tar(){ tar zcvf /opt/web.tar.gz ./* } code_cp(){ scp /opt/web.tar.gz 47.111.25.47:/code/ } code_un(){ ssh 47.111.25.47 "mkdir -p /code/web_code_$git_version" ssh 47.111.25.47 "cd /code;tar xf web.tar.gz -C web_code_$git_version && rm -rf web.tar.gz" } code_ln(){ ssh 47.111.25.47 "rm -rf /code/game && ln -s /code/web_code_$git_version /code/game" } main(){ code_tar code_cp code_un code_ln } if [ $deploy_env = "deploy" ];then main elif [ $deploy_env = "rollback" ];then code_ln fi # 检测脚本语法 [root@jenkins ~]# bash -n /root/deploy.sh

image

执行v1.0版本

image

bash
# 执行完毕后根据tag标签创建了目录并且自动创建了软连接 [root@web02 code]# ll total 4 lrwxrwxrwx 1 root root 19 May 30 19:02 game -> /code/web_code_v1.0 drwxr-xr-x 6 root root 4096 May 30 19:02 web_code_v1.0 #浏览器可以正常访问

构建v1.1版本

bash
# 执行完毕后把软连接指向了新发布的v1.1目录 [root@web02 code]# ll total 8 lrwxrwxrwx 1 root root 19 May 30 19:14 game -> /code/web_code_v1.1 drwxr-xr-x 6 root root 4096 May 30 19:02 web_code_v1.0 drwxr-xr-x 6 root root 4096 May 30 19:14 web_code_v1.1

image

bash
避免重复构建 当重复执行构建后会生成多个相同版本的文件,利用jenkins变量值解决重复性构建问题 jenkins变量 1. GIT_COMMIT 当前版本提交产生的哈希唯一值 2. GIT_PREVIOUS_SUCCESSFUL_COMMIT 已经提交过的版本的哈希唯一值 使用以上两个值做比较,如果已提交则退出,如果没有提交过则继续执行构建,更改脚本做判断 [root@jenkins ~]# cat deploy.sh #!/bin/bash code_tar(){ tar zcvf /opt/web.tar.gz ./* } code_cp(){ scp /opt/web.tar.gz 47.111.25.47:/code/ } code_un(){ ssh 47.111.25.47 "mkdir -p /code/web_code_$git_version" ssh 47.111.25.47 "cd /code;tar xf web.tar.gz -C web_code_$git_version && rm -rf web.tar.gz" } code_ln(){ ssh 47.111.25.47 "rm -rf /code/game && ln -s /code/web_code_$git_version /code/game" } main(){ code_tar code_cp code_un code_ln } if [ $deploy_env = "deploy" ];then if [ "$GIT_COMMIT" == "$GIT_PREVIOUS_SUCCESSFUL_COMMIT" ];then echo "构建失败该 $git_version 版本号已部署" exit else main fi elif [ $deploy_env = "rollback" ];then code_ln fi

8、java项目发布流程

1、Maven介绍
bash
Maven是一个项目管理和综合工具。Maven提供给开发人员构建一个完整的生命周期框架。 开发团队可以自动完成该项目的基础设施建设,Maven使用标准的目录结构和默认构建生命周期。 Apache的开源项目主要服务于JAVA平台的构建、依赖管理、项目管理。 Project Object Model,项目对象模型。通过xml格式保存的pom.xml文件。该文件用于管理:源代码、配置文件、开发者的信息和角色、问题追踪系统、组织信息、项目 授权、项目的url、项目的依赖关系等等。该文件是由开发维护,我们运维人员可以不用去关心。
2、Maven安装
bash
1、下载Maven 3安装包 官网:http://maven.apache.org/download.cgi 清华镜像:https://mirrors.tuna.tsinghua.edu.cn/apache/maven/ 2、上传java代码 3、安装Maven [root@jenkins ~]# tar -xf apache-maven-3.3.9-bin.tar.gz -C /usr/local [root@jenkins ~]# cd /usr/local [root@jenkins local]# ln -s apache-maven-3.3.9/ maven 4、加入到PATH变量 [root@jenkins maven]# cd bin/ [root@jenkins bin]# pwd /usr/local/maven/bin [root@jenkins bin]# PATH="$PATH:/usr/local/maven/bin" # 添加到/etc/profile [root@jenkins bin]# echo $PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/root/bin:/usr/local/sonar/bin:/root/bin:/usr/local/maven/bin 5、打包项目 [root@jenkins:~]#cd hello-world-war/ [root@jenkins:hello-world-war]#mvn package ... [INFO] Packaging webapp [INFO] Assembling webapp [hello-world-war] in [/root/hello-world-war/target/hello-world-war-1.0.0] [INFO] Processing war project [INFO] Copying webapp resources [/root/hello-world-war/src/main/webapp] [INFO] Building war: /root/hello-world-war/target/hello-world-war-1.0.0.war [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 04:03 min [INFO] Finished at: 2025-05-31T08:07:51+08:00 [INFO] Final Memory: 15M/154M [INFO] ------------------------------------------------------------------------ [root@jenkins hello-world-war]# ll total 20 drwxr-xr-x 2 root root 4096 May 23 2014 dist -rw-r--r-- 1 root root 931 May 14 2024 pom.xml -rw-r--r-- 1 root root 213 May 23 2014 README.md drwxr-xr-x 3 root root 4096 May 23 2014 src drwxr-xr-x 4 root root 4096 May 31 08:07 target # 多出一个target目录 [root@jenkins hello-world-war]# ll target/ total 12 drwxr-xr-x 4 root root 4096 May 31 08:07 hello-world-war-1.0.0 -rw-r--r-- 1 root root 1934 May 31 08:07 hello-world-war-1.0.0.war # 这个就是我们想要的 drwxr-xr-x 2 root root 4096 May 31 08:07 maven-archiver 6.web02部署tomcat [root@web02 ~]# yum -y install java [root@web02 ~]# wget https://dlcdn.apache.org/tomcat/tomcat-9/v9.0.105/bin/apache-tomcat-9.0.105.tar.gz [root@web02 ~]# tar xf apache-tomcat-9.0.105.tar.gz [root@web02 ~]# ll total 12700 drwxr-xr-x 9 root root 4096 May 31 08:20 apache-tomcat-9.0.105 -rw-r--r-- 1 root root 13000541 May 31 08:18 apache-tomcat-9.0.105.tar.gz [root@web02 ~]# mv apache-tomcat-9.0.105 /usr/local/tomcat [root@web02 ~]# /usr/local/tomcat/bin/startup.sh Using CATALINA_BASE: /usr/local/tomcat Using CATALINA_HOME: /usr/local/tomcat Using CATALINA_TMPDIR: /usr/local/tomcat/temp Using JRE_HOME: /usr Using CLASSPATH: /usr/local/tomcat/bin/bootstrap.jar:/usr/local/tomcat/bin/tomcat-juli.jar Using CATALINA_OPTS: Tomcat started. 7.web清空之前的 [root@web02 tomcat]# cd webapps//ROOT/ [root@web02 ROOT]# ll total 168 -rw-r----- 1 root root 27235 May 8 02:36 asf-logo-wide.svg -rw-r----- 1 root root 713 May 8 02:36 bg-button.png -rw-r----- 1 root root 1918 May 8 02:36 bg-middle.png -rw-r----- 1 root root 1401 May 8 02:36 bg-nav.png -rw-r----- 1 root root 3103 May 8 02:36 bg-upper.png -rw-r----- 1 root root 21630 May 8 02:36 favicon.ico -rw-r----- 1 root root 12234 May 8 02:36 index.jsp -rw-r----- 1 root root 6902 May 8 02:36 RELEASE-NOTES.txt -rw-r----- 1 root root 5584 May 8 02:36 tomcat.css -rw-r----- 1 root root 67795 May 8 02:36 tomcat.svg drwxr-x--- 2 root root 4096 May 31 08:20 WEB-INF [root@web02 ROOT]# pwd /usr/local/tomcat/webapps/ROOT [root@web02 ROOT]# rm -rf * 8.拷贝war包到web [root@jenkins hello-world-war]# scp target/hello-world-war-1.0.0.war 47.111.25.47:/usr/local/tomcat/webapps/ROOT hello-world-war-1.0.0.war 9.回web解压 [root@web02 ROOT]# unzip hello-world-war-1.0.0.war Archive: hello-world-war-1.0.0.war inflating: META-INF/MANIFEST.MF creating: WEB-INF/ creating: WEB-INF/classes/ inflating: WEB-INF/web.xml inflating: index.jsp inflating: META-INF/maven/com.efsavage/hello-world-war/pom.xml inflating: META-INF/maven/com.efsavage/hello-world-war/pom.properties [root@web02 ROOT]# ll total 16 -rw-r--r-- 1 root root 1934 May 31 08:23 hello-world-war-1.0.0.war -rw-r--r-- 1 root root 210 Oct 15 2019 index.jsp drwxr-xr-x 3 root root 4096 May 31 08:24 META-INF drwxr-xr-x 3 root root 4096 May 31 08:07 WEB-INF 重启生效 [root@web02 ROOT]# /usr/local/tomcat/bin/shutdown.sh [root@web02 ROOT]# /usr/local/tomcat/bin/startup.sh # 访问测试

image

3、集成到Jenkins
bash
1. 清理生成的target包 [root@jenkins hello-world-war]# mvn clean 2. gitlab新建项目组

image

bash
3. 上传到远程 [root@jenkins hello-world-war]# git status # On branch master # Your branch is ahead of 'origin/master' by 3 commits. # (use "git push" to publish your local commits) # # Changes not staged for commit: # (use "git add <file>..." to update what will be committed) # (use "git checkout -- <file>..." to discard changes in working directory) # # modified: pom.xml # modified: src/main/webapp/index.jsp # no changes added to commit (use "git add" and/or "git commit -a") # 上传到本地仓库 [root@jenkins hello-world-war]# git add . [root@jenkins hello-world-war]# git commit -m "xx" [master 86168c9] xx 2 files changed, 3 insertions(+), 3 deletions(-) # 删除之前的 [root@jenkins hello-world-war]# git remote origin [root@jenkins hello-world-war]# git remote remove origin [root@jenkins hello-world-war]# git remote # 设置git@8.138.250.63:oldboy/java.git为远程仓库 [root@jenkins hello-world-war]# git remote add origin git@8.138.250.63:oldboy/java.git [root@jenkins hello-world-war]# git remote -v origin git@8.138.250.63:oldboy/java.git (fetch) origin git@8.138.250.63:oldboy/java.git (push) # 推送到远程,报错了,原因是这台服务器与gitlab的普通用户做了免密钥导致权限不够,解决办法,删除普通用的的密钥,与管理员做免密钥 [root@jenkins hello-world-war]# git push -u origin master Counting objects: 44, done. Delta compression using up to 2 threads. Compressing objects: 100% (29/29), done. Writing objects: 100% (44/44), 4.89 KiB | 0 bytes/s, done. Total 44 (delta 11), reused 0 (delta 0) remote: GitLab: remote: A default branch (e.g. main) does not yet exist for oldboy/java remote: Ask a project Owner or Maintainer to create a default branch: remote: remote: http://8.138.250.63/oldboy/java/-/project_members remote: To git@8.138.250.63:oldboy/java.git ! [remote rejected] master -> master (pre-receive hook declined) error: failed to push some refs to 'git@8.138.250.63:oldboy/java.git' # 删除普通用户免密钥,新增管理员密钥,浏览器测试

image

新建Jenkins项目

image

image

image

image

image

bash
# 进入Jenkins工作目录,已经成功编译了 [root@jenkins hello-world-war]# cd /var/lib/jenkins/workspace/ [root@jenkins workspace]# ll total 16 drwxr-xr-x 7 root root 4096 May 30 19:19 deploy drwxr-xr-x 8 root root 4096 May 30 15:38 ganme drwxr-xr-x 6 root root 4096 May 31 09:28 java drwxr-xr-x 2 root root 4096 May 30 09:25 测试任务 [root@jenkins workspace]# ll java/ total 20 drwxr-xr-x 2 root root 4096 May 31 09:26 dist -rw-r--r-- 1 root root 931 May 31 09:26 pom.xml -rw-r--r-- 1 root root 213 May 31 09:26 README.md drwxr-xr-x 3 root root 4096 May 31 09:26 src drwxr-xr-x 4 root root 4096 May 31 09:28 target # gitlab是没有这个目录的

image

image

bash
# 查看,已经创建软连接 [root@web02 webapps]# ll total 28 drwxr-x--- 16 root root 4096 May 31 08:20 docs drwxr-x--- 7 root root 4096 May 31 08:20 examples drwxr-x--- 4 root root 4096 May 31 09:52 hello-world-war-1.0.0 -rw-r--r-- 1 root root 1933 May 31 09:52 hello-world-war-1.0.0.war drwxr-x--- 6 root root 4096 May 31 08:20 host-manager drwxr-xr-x 4 root root 4096 May 31 09:52 java_5 drwxr-x--- 6 root root 4096 May 31 08:20 manager lrwxrwxrwx 1 root root 6 May 31 09:52 ROOT -> java_5 # 修改代码测试 [root@jenkins hello-world-war]# vim src/main/webapp/index.jsp v1.0改为v1.1 # 上传到仓库 [root@jenkins hello-world-war]# git commit -am "v1.1" [master c0eb105] v1.1 1 file changed, 1 insertion(+), 1 deletion(-) # 上传到本地仓库 [root@jenkins hello-world-war]# git push -u origin master Counting objects: 11, done. Delta compression using up to 2 threads. Compressing objects: 100% (4/4), done. Writing objects: 100% (6/6), 432 bytes | 0 bytes/s, done. Total 6 (delta 2), reused 0 (delta 0) To git@8.138.250.63:oldboy/java.git 86168c9..c0eb105 master -> master Branch master set up to track remote branch master from origin. # 返回Jenkins点击立即构建,没问题

image

image

4、修改默认的中央仓库
bash
# 编译会去中央仓库下载依赖,下载速度特别慢,因为仓库是国外的 [root@jenkins hello-world-war]# mvn package # 中央仓库缓存位置 [root@jenkins ~]# cd .m2/ [root@jenkins .m2]# ll total 4 drwxr-xr-x 11 root root 4096 May 31 08:07 repository [root@jenkins .m2]# ll repository/ total 36 drwxr-xr-x 3 root root 4096 May 31 08:05 backport-util-concurrent drwxr-xr-x 3 root root 4096 May 31 08:04 classworlds drwxr-xr-x 3 root root 4096 May 31 08:05 com drwxr-xr-x 3 root root 4096 May 31 08:04 commons-cli drwxr-xr-x 3 root root 4096 May 31 08:07 commons-io drwxr-xr-x 3 root root 4096 May 31 08:05 commons-logging drwxr-xr-x 3 root root 4096 May 31 08:04 junit drwxr-xr-x 3 root root 4096 May 31 08:05 log4j drwxr-xr-x 8 root root 4096 May 31 08:07 org # 进入settings.xml文件修改 [root@jenkins conf]# pwd /usr/local/maven/conf [root@jenkins conf]# vim settings.xml 159 <mirror> 160 <id>nexus-aliyun</id> 161 <mirrorOf>*</mirrorOf> 162 <name>Nexus aliyun</name> 163 <url>http://maven.aliyun.com/nexus/content/groups/public</url> 164 </mirror> 165 </mirrors> # 这行不用粘贴 # 回到hellowork目录mvn 测试 [root@jenkins hello-world-war]# cd hello-world-war/ [root@jenkins hello-world-war]# mvn clean [INFO] Scanning for projects... [INFO] [INFO] ------------------------------------------------------------------------ [INFO] Building Hello World Web Application Repository 1.0.0 [INFO] ------------------------------------------------------------------------ Downloading: http://maven.aliyun.com/nexus/content/groups/public/org/apache/maven/plugins/maven-clean-plugin/2.5/maven-clean-plugin-2.5.pom 注意:如果公司部分java代码 不需要配置nexus私服,只需要将maven配置文件仓库指向阿里云仓库 如果公司是重java项目,则需要搭建私有的仓库nexus
5、配置nexus私服

df29d04d11b7737daddb6b73852a8160

bash
类似代理的作用,编译去找nexus私服,nexus去找阿里云的仓库,找到自己缓存一份,给java一份
bash
部署私服 xenus 下载https://www.sonatype.com/download‐oss‐sonatype 配置仓库两个选项 1、项目下的pom.xml配置、只生效当前的项目 2、在maven配置全局所有项目生效 # 上传JDK [root@nexus:~]#rpm -ivh jdk-8u181-linuxx64.rpm # 上传nexus安装包 -rw-r--r-- 1 root root 122904706 Sep 27 17:19 nexus-3.13.0-01-unix.tar.gz #解压代码 [root@nexus:~]#tar xf nexus-3.13.0-01-unix.tar.gz #移动到/usr/local/nexus [root@nexus:~]#mv nexus-3.13.0-01 /usr/local/nexus # 启动nexus [root@nexus:~]#/usr/local/nexus/bin/nexus start # 查看服务是否启动 [root@web02 ~]# netstat -tnulp Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 0.0.0.0:8081 0.0.0.0:* LISTEN 1366/java # 浏览器访问 47.111.25.47:8081 admin admin123

image

浏览器配置nexus

image

image

image

image

bash
# 修改maven配置文件 [root@jenkins conf]# cd /usr/local/maven/conf [root@jenkins conf]# vim settings.xml 156 <mirrors> 157 <mirror> 158 <id>nexus</id> 159 <mirrorOf>*</mirrorOf> 160 <url>http://47.111.25.47:8081/repository/maven-public/</url> # 修改为对应的ip 161 </mirror> 。。。 262 <profile> 263 <id>nexus</id> 264 <repositories> 265 <repository> 266 <id>central</id> 267 <url>http://47.111.25.47:8081/repository/maven-public/</url> # 修改为对应的ip 268 <releases><enabled>true</enabled></releases> 269 <snapshots><enabled>true</enabled></snapshots> 270 </repository> 271 </repositories> 272 <pluginRepositories> 273 <pluginRepository> 274 <id>central</id> 275 <url>http://47.111.25.47:8081/repository/maven-public/</url> # 修改为对应的ip 276 <releases><enabled>true</enabled></releases> 277 <snapshots><enabled>true</enabled></snapshots> 278 </pluginRepository> 279 </pluginRepositories> 280 </profile> 281 </profiles> # 测试,已经去找刚才配置的47.111.25.47地址了 [root@jenkins hello-world-war]# mvn clean [INFO] Scanning for projects... [INFO] [INFO] ------------------------------------------------------------------------ [INFO] Building Hello World Web Application Repository 1.0.0 [INFO] ------------------------------------------------------------------------ Downloading: http://47.111.25.47:8081/repository/maven-public/org/apache/maven/plugins/maven-clean-plugin/2.5/maven-clean-plugin-2.5.pom Downloaded: http://47.111.25.47:8081/repository/maven-public/org/apache/maven/plugins/maven-clean-plugin/2.5/maven-clean-plugin-2.5.pom (0 B at 0.0 KB/sec) Downloading: http://47.111.25.47:8

image

9、Jenkins Pipeline项目

1.CI/CD持续集成/持续部署
bash
持续集成(Continuous integration)是一种软件开发实践,即团队开发成员经常集成它们的工作,通过每个成员每天至少集成一次,也就意味着每天 可能会发生多次集成。每次集成都通过自动化的构建(包括编译,发布,自动化测试)来验证,从而尽早地发现集成错误。 比如(你家装修厨房,其中一项是铺地砖,边角地砖要切割大小。如果一次全切割完再铺上去,发现尺寸有误的话浪费和返工时间就大了,不如切一块铺 一块。这就是持续集成。) 持续部署(continuous deployment)是通过自动化的构建、测试和部署循环来快速交付高质量的产品。某种程度上代表了一个开发团队工程化的程度, 毕竟快速运转的互联网公司人力成本会高于机器,投资机器优化开发流程化相对也提高了人的效率。 比如(装修厨房有很多部分,每个部分都有检测手段,如地砖铺完了要测试漏水与否,线路铺完了要通电测试电路通顺,水管装好了也要测试冷水热水。 如果全部装完了再测,出现问题可能会互相影响,比如电路不行可能要把地砖给挖开……。那么每完成一部分就测试,这是持续部署。) 持续交付 Continuous Delivery:频繁地将软件的新版本,交付给质量团队或者用户,以供评审尽早发现生产环境中存在的问题;如果评审通过,代码 就进入生产阶段比如(全部装修完了,你去验收,发现地砖颜色不合意,水池太小,灶台位置不对,返工吗?所以不如没完成一部分,你就去用一下试用验 收,这就是持续交付。) 敏捷思想中提出的这三个观点,还强调一件事:通过技术手段自动化这三个工作。加快交付速度。
2.pipeline介绍
bash
1.什么是pipeline Jenkins 2.0的精髓是Pipeline as Code,是帮助Jenkins实现CI到CD转变的重要角色。什么是Pipeline,简单来说,就是一套运行于Jenkins 上的工作流框架,将原本独立运行于单个或者多个节点的任务连接起来,实现单个任务难以完成的复杂发布流程。Pipeline的实现方式是一套Groovy DSL, 任何发布流程都可以表述为一段Groovy脚本,并且Jenkins支持从代码库直接读取脚本,从而实现了Pipeline as Code的理念。 2.Pipeline 概念 Pipeline 是一个用户定义的 CD 流水线模式。Pipeline 代码定义了通常包含构建、测试和发布步骤的完整的构建过程。 Node node 是一个机器,它是 Jenkins 环境的一部分,并且能够执行 Pipeline。同时,node 代码块也是脚本式Pipeline 语法的关键特性。 Stage Stage 块定义了在整个 Pipeline 中执行的概念上不同的任务子集(例如“构建”,“测试”和“部署”阶段),许多插件使用它来可视化或呈现 Jenkins 管道状态/进度。Step一项任务。从根本上讲,一个步骤告诉 Jenkins 在特定时间点(或过程中的“步骤”)要做什么。例如,使用sh step:sh 'make' 可以执行 make 这个 shell 命令。 1. Pipeline(流水线)🍜 想象你点了一碗牛肉面,从下单到上桌的完整流程: 下单 → 煮面 → 加料 → 上桌 这就是一个典型的"流水线"。 在 Jenkins 中: Pipeline 就是把软件从代码变成产品的完整自动化流程,包含构建→测试→部署等环节,就像面条从面粉变成美食的过程。 2. Node(节点)🔧 好比厨房里的工作台: 主厨工作台(Jenkins 服务器) 配菜工作台(其他服务器) 在 Jenkins 中: Node 就是执行任务的机器,可以是 Jenkins 服务器本身,也可以是连接的其他电脑/服务器。 3. Stage(阶段)📦 把煮面过程拆解: 准备阶段:洗菜、切肉 烹饪阶段:煮面、熬汤 装盘阶段:摆盘、加料 在 Jenkins 中: Stage 就是把复杂流程分成几个逻辑阶段,比如: 编译代码阶段 测试阶段 部署阶段 4. Step(步骤)🔍 煮面时的具体动作: 烧水(烧水 500ml) 下面(下面条 200g) 计时(等待 3分钟) 在 Jenkins 中: Step 就是最小操作单元,比如: 拉取代码:git 'https://...' 运行测试:sh 'mvn test' 发送通知:slackSend '完成啦!' 举个完整的栗子 🌰 groovy // 整个流水线在厨房工作台(node)进行 node('厨房') { // 阶段1:准备食材 stage('备菜') { step('洗菜') { 水龙头.打开() } step('切肉') { 刀.切(牛肉, 薄片) } } // 阶段2:烹饪 stage('煮面') { step('烧水') { 锅.加水(500ml).加热() } step('下面') { 锅.加(面条).煮(3min) } } // 阶段3:上菜 stage('装盘') { step('摆盘') { 碗.放(面条).加(牛肉) } step('送餐') { 服务员.送到(桌号) } } } 关键优势 💡 可视化流程:像看外卖进度图一样清晰 [备菜] ✅ → [煮面] ✅ → [装盘] 🟡 版本控制:菜谱(Pipeline脚本)存在Git里,随时回滚 灵活复用:同一套流程可以做: 牛肉面套餐(生产环境部署) 素面套餐(测试环境部署) 实际 Jenkins 示例 🔧 groovy node('linux-server') { // 阶段1:准备代码 stage('拉代码') { git 'https://github.com/myapp.git' } // 阶段2:打包 stage('打包') { sh 'mvn clean package' } // 阶段3:部署 stage('上线') { sh 'scp target/app.war user@prod:/opt/tomcat' } } 总结 🚀 概念 生活比喻 Jenkins 作用 Pipeline 牛肉面制作流程 完整的 CI/CD 流程 Node 厨房工作台 执行任务的服务器 Stage 准备/煮/上菜 流程的逻辑阶段 Step 洗菜/切肉/烧水 具体的操作命令 简单说:Pipeline 就是用代码描述你的软件生产流水线,Jenkins 就是这条自动化流水线的总控台!
3、新建流水线项目

image

image

image

10、Jenkins部署分布式

bash
如果项目需要定期集成,同时每次集成都需要较长时间。如果都运行在master服务器上,会消耗过多资源,导致其他项目搁置无法集成,这时就需要在 建立多台设备,并配置作为slave机器来为master提供负载服务。

84f7078a760be43e93fde7e5f5ef8013

bash
配置的Jenkins从节点可以工作: 1、能执行git命令,拉取gitlab代码,所以要把公钥放到gitlab打通 2、执行sonar客户端的命令 3、推送到web要和web做免密钥 4、调用python脚本的权限进行通知的推送
1、部署分布式服务器
bash
1.找一台或者目前已有的服务器配置为slave端 2.在je02上安装java jdk git和soanr客户端 yum -y install java # centos 注意版本 yum -y install git # kylin不用安装 2.jenkins服务器操作 注意带版本号做软链接 [root@jenkins hello-world-war]# ssh-copy-id 8.138.242.118 [root@jenkins hello-world-war]# scp -r /usr/local/sonar 8.138.242.118:/usr/local/ [root@jenkins hello-world-war]# scp -r /usr/local/maven/ 8.138.242.118:/usr/local 3.与web服务器做免密钥 [root@jen02 /]# ssh-copy-id 47.111.25.47 4.将所有用到的shell脚本拷贝到je02 [root@jenkins ~]# scp deploy.sh 8.138.242.118:/root 5.jenkins服务端添加从节点je02 PS: 把je02的公钥上传至gitlab 拥有下载代码的权限 点击系统管理->节点管理->新建节点 [root@lb02:~]#ssh-keygen [root@lb02:~]#cat .ssh/id_rsa.pub

image

拉取代码测试

image

系统管理->节点管理->新建节点

image

image

image

image

image

bash
# 报错,这个错误表明 Jenkins agent 节点的 Java 版本(1.8.0_412)与 Jenkins 控制器发送的 remoting.jar 文件不兼容。 Error: A JNI error has occurred, please check your installation and try again Exception in thread "main" java.lang.UnsupportedClassVersionError: hudson/remoting/Launcher has been compiled by a more recent version of the Java Runtime (class file version 55.0), this version of the Java Runtime only recognizes class file versions up to 52.0 at java.lang.ClassLoader.defineClass1(Native Method) at java.lang.ClassLoader.defineClass(ClassLoader.java:756) at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142) at java.net.URLClassLoader.defineClass(URLClassLoader.java:473) at java.net.URLClassLoader.access$100(URLClassLoader.java:74) at java.net.URLClassLoader$1.run(URLClassLoader.java:369) at java.net.URLClassLoader$1.run(URLClassLoader.java:363) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:362) at java.lang.ClassLoader.loadClass(ClassLoader.java:418) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:352) at java.lang.ClassLoader.loadClass(ClassLoader.java:351) at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:621) Agent JVM has terminated. Exit code=1 [05/31/25 14:08:43] Launch failed - cleaning up connection [05/31/25 14:08:43] [SSH] Connection closed. # 升级版本 [root@jen02 /]# yum -y install java-11-openjdk [root@jen02 /]# alternatives --config java There are 2 programs which provide 'java'. Selection Command ----------------------------------------------- *+ 1 java-1.8.0-openjdk.x86_64 (/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.412.b08-1.el7_9.x86_64/jre/bin/java) 2 java-11-openjdk.x86_64 (/usr/lib/jvm/java-11-openjdk-11.0.23.0.9-2.el7_9.x86_64/bin/java) Enter to keep the current selection[+], or type selection number: 2 [root@jen02 /]# java -version openjdk version "11.0.23" 2024-04-16 LTS OpenJDK Runtime Environment (Red_Hat-11.0.23.0.9-2.el7_9) (build 11.0.23+9-LTS) OpenJDK 64-Bit Server VM (Red_Hat-11.0.23.0.9-2.el7_9) (build 11.0.23+9-LTS, mixed mode, sharing) # 返回观察,已经正常

image

执行测试

image

image

image

11、代码发布流程

1、直接发布
bash
使用拷贝或者直接使用FTP方式进行发布代码,早期使用此种发布方式 优点: 成本较低,发布速度快,简单粗暴 缺点: 出现问题直接影响用户,回退代码较慢 适用场景: 1.开发测试场景 2.不影响用户的业务 3.初创型公司,流量较少,可以选择流量低谷期发布代码

2、金丝雀发布
bash
1.金丝雀发布一般先发 1 台,或者一个小比例,例如 2% 的服务器,主要做流量验证用,也称为金丝雀 (Canary) 测试(国内常称灰度测试)。 以前旷工开矿下矿洞前,先会放一只金丝雀进去探是否有有毒气体,看金丝雀能否活下来,金丝雀发布由此得名。简单的金丝雀测试一般通过手工测试 验证,复杂的金丝雀测试需要比较完善的监控基础设施配合,通过监控指标反馈,观察金丝雀的健康状况,作为后续发布或回退的依据。 2.如果金丝测试通过,则把剩余的 V1 版本全部升级为 V2 版本。如果金丝雀测试失败,则直接回退金丝雀,发布失败 优点: 用户体验影响小,出现问题只对少数用户有影响 缺点: 自动化程度不够,发布期间可能引发服务的中断 适用场合: 1.对新代码缺乏自信,在判断测试过程中的项目 2.用户体验要求较高的网站业务 3.缺乏足够自动化发布的公司
3、滚动式发布
bash
1. 滚动式发布一般先发 1 台,或者一个小比例,如 2% 服务器,主要做流量验证用,类似金丝雀 (Canary) 测试。 2. 滚动式发布需要比较复杂的发布工具和智能 LB,支持平滑的版本替换和流量拉入拉出。 3. 每次发布时,先将老版本 V1 流量从 LB 上摘除,然后清除老版本,发新版本 V2,再将 LB 流量接入新版本。这样 可以尽量保证用户体验不受影响。 4. 一次滚动式发布一般由若干个发布批次组成,每批的数量一般是可以配置的(可以通过发布模板定义)。例如第一 批 1 台(金丝雀),第二批 10%,第三批 50%,第四批 100%。每个批次之间留观察间隔,通过手工验证或监控 反馈确保没有问题再发下一批次,所以总体上滚动式发布过程是比较缓慢的 (其中金丝雀的时间一般会比后续批次 更长,比如金丝雀 10 分钟,后续间隔 2 分钟)。 5. 回退是发布的逆过程,将新版本流量从 LB 上摘除,清除新版本,发老版本,再将 LB 流量接入老版本。和发布过程 一样,回退过程一般也比较慢的。 6. 滚动式发布国外术语通常叫 Rolling Update Deployment。 优点: 用户体验影响小 缺点: 发布和回滚时间比较缓慢,发布工具比较复杂,负载需要平滑的流量摘除和拉入能力 使用场景: 1.用户体验不能中断的业务 2.有一定复杂发布工具的研发能力
4、面试
bash
1、代码上线流程是什么? 代码上线这边的话,我给上家公司部署了gitlab、jenkins、sonarqube、maven编译等等,之前公司用的是svn,然后我去了之后领导让我部署 一套CI\CD的流程,我当时一边看视频和资料,一边给公司搭建起来这样的一套CI\CD的项目,然后我们上线的流程的话是我给公司部署了几套测试流程, 还有几套我们线上的发布流程,然后底层代码的话我们用的是python还有我们的java也有,上线流程是开发写代码,写完代码之后他们提交到自己的一 个分支,然后没有问题之后发起一个合并,合并到我们的测试分支,比如发布到我们的一个testing分支上,那我们通过在jenkins上设置的一个自动触 发,然后回触发jenkins的一个项目,这个测试项目回拉取gitlab中的testing分支,拉取完成之后会发布到sonarqube上进行一个代码质量检测, 然后有问题的话,开发他们自己去看就可以了,然后再往下的话就是发布到sonarqube之后我们会把代码推送到我的一个测试环境或者是类生产环境上, 然后进行一个测试看结果,如果是查看的日志或者是我们人工进行测试,如果没有问题的话,然后对当前的testing分支进行一个打标签,我们给它打上一个 tag标签,然后我们利用tag标签进行一个参数化的线上发布,然后参数化构建的话就是我们里程碑式的一个标签,如果说没有问题的话我们打一个v1.1 这样的一个版本,然后我们通过jenkins去拉取这个对应的这个稳定版本,拉取到稳定版本之后我们是直接底层利用ansible或者是shell的方式进行 批量部署到我们的线上服务器,那当然部署之前的话,我们都是已经经过金丝雀一个测试了的,然后没有问题之后我们才是批量发布到我们的线上服务器, 如果是有问题的话,我在jenkins上给它做了一个秒级回滚,底层的话是通过软连接的方式,然后再链接到我之前的这样一个版本,那如果是java项目的 话,然后jenkins里面就给它集成了一个maven这样的一个插件,然后通过maven进行一个编译,我们拿到一个jar包或者是war包,然后发布到我们的 tomcat下面,然后进行一个运行,然后最后的话,还给公司部署了pipeline流水线,就我们前面的项目稳定了话,没有问题的话,然后我会给它写成一 个pipeline流水线,然后pipeline它使用看板的方式,它可以更直观的看到我们的一个发布速度,发布的流程,发布步骤,然后能够快速定位我们发 布过程中出现的一些问题,然后里面可以使用一些循环,判断。来判断我们下一步发布的一个流程,到底是发布还是回滚等等,这是我之前在上家公司做 的一个代码上线的流程。 2、jenkins用过啥插件 代码管理:Git 构建触发:

24、三剑客进阶

1、sed 选项参数

bash
-e 允许多项编辑 -n 取消默认的输出 -i 直接修改对应文件 -r 支持扩展元字符

2、sed`内置命令参数

bash
a 在当前行后添加一行或多行 c 在当前行进行替换修改 d 在当前行进行删除操作 i 在当前行之前插入文本 p 打印匹配的行或指定行 n 读入下一输入行,从下一条命令进行处理 ! 对所选行以外的所有行应用命令 h 把模式空间里的内容重定向到暂存缓冲区 H 把模式空间里的内容追加到暂存缓冲区 g 取出暂存缓冲区的内容,将其复制到模式空间,覆盖该处原有内容 G 取出暂存缓冲区的内容,将其复制到模式空间,追加在原有内容后面 #1.先删除行,然后管道给后面的 sed 进行替换 [root@web01 ~]#sed '1,9d' 1.txt|sed 's#home#oldboy#g' [root@web01 ~]#sed -e '1,9d' -e 's#home#oldboy#g' 1.txt #2.打印匹配halt的行 [root@web01 ~]#sed '/halt/p' 1.txt #未使用 -n 选项:sed 默认会打印每一行(无论是否匹配)。 root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin:/sbin/nologin daemon:x:2:2:daemon:/sbin:/sbin/nologin adm:x:3:4:adm:/var/adm:/sbin/nologin lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin sync:x:5:0:sync:/sbin:/bin/sync shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown halt:x:7:0:halt:/sbin:/sbin/halt #/halt/p 的作用:匹配包含 halt 的行时,额外打印一次该行。 halt:x:7:0:halt:/sbin:/sbin/halt mail:x:8:12:mail:/var/spool/mail:/sbin/nologin operator:x:11:0:operator:/root:/sbin/nologin [root@web01 ~]#sed -n '/halt/p' 1.txt halt:x:7:0:halt:/sbin:/sbin/halt # 3.打印第二行的内容 [root@Shell ~]# sed -n '2p' 1.txt bin:x:1:1:bin:/bin:/sbin/nologin # 4.打印最后一行 [root@Shell ~]# sed -n '$p' passwd # 5.指定某行进行内容替换 [root@web01 ~]#sed '7c SELINUX=disable111' /etc/selinux/config # This file controls the state of SELinux on the system. # SELINUX= can take one of these three values: # enforcing - SELinux security policy is enforced. # permissive - SELinux prints warnings instead of enforcing. # disabled - No SELinux policy is loaded. SELINUX=disable111 # 6.指定删除第三行, 但不会改变文件内容 [root@web01 ~]# sed '3d' passwd # 7.从第三行删除到最后一行 [root@web01 ~]#sed '3,$d' 1.txt root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin:/sbin/nologin # 8.删除最后一行 [root@web01 ~]#sed '$d' 1.txt # 9.删除所有的行 [root@web01 ~]#sed '1,$d' 1.txt # 10.匹配指定的行进行删除 [root@web01 ~]#sed '/mail/d' 1.txt # 11.在第10行上面添加内容 [root@web01 ~]#sed -i '10i listen 80;' 1.txt # 12.将匹配到的行写入到新文件中 [root@web01 ~]#sed -n '/listen/w newfile' 1.txt [root@web01 ~]#cat newfile listen 80; # 13.将 passwd 文件的第二行写入到 newfile 中 [root@web01 ~]#sed -n '2w newfile' 1.txt [root@web01 ~]#cat newfile bin:x:1:1:bin:/bin:/sbin/nologin # 14.除了第三行,其他全部删除 [root@web01 ~]#sed -r '3!d' 1.txt # -r扩展正则 daemon:x:2:2:daemon:/sbin:/sbin/nologin # 15.替换每行出现的第一个 root [root@web01 ~]#sed 's#root#adm#' 1.txt # 16.替换全部root [root@web01 ~]#sed 's#root#adm#g' 1.txt # 17.匹配包含有 root 的行进行替换 [root@web01 ~]#sed -r 's/root/alice/g' 1.txt # 18.给1-3行添加注释 [root@web01 ~]#sed '1,3s/^/#/' 1.txt # 19.给20行到结尾添加注释 [root@web01 ~]#sed '20,$s/^/#/' /etc/nginx/nginx.conf # 20.删除配置文件中#号开头的注释行, 如果碰到 tab 或空格是无法删除 [root@web01 ~]#sed '/^#/d' 1.txt

3、awk 选项 options

bash
选项 options: -F 定义输入字段分隔符,默认的分隔符, 空格或 tab 键 命令 command 行处理前 行处理 行处理后 BEGIN{} {} END{} # 1.BEGIN 发生在读文件之前 [root@web01 ~]#awk 'BEGIN{print 1/2}' 0.5 # 2.BEGIN 在行处理前, 修改字段分隔符 [root@web01 ~]#awk 'BEGIN{FS=":";OFS="---"} {print $1,$2}' 1.txt FS=":" 设置输入字段分隔符为冒号 : OFS="---" 设置输出字段分隔符为三个连字符 --- [root@web01 ~]#awk 'BEGIN{print 1/2} {print "ok"} END {print "Game Over"}' /etc/hosts 0.5 ok ok Game Over ------------------------ 1. 执行 BEGIN 块 2. 逐行读取文件 对每一行:执行主代码块,也就是每读取一行,就执行一次 {print "ok"} 3. 执行 END 块(如果有) ------------------------

4、awk命令格式

bash
# 1.匹配root的行,输出1,3列 [root@web01 ~]#awk -F ':' '/root/ {print $1,$3}' /etc/passwd root 0 operator 11 # 2.判断大于多少则输出什么内容 [root@web01 ~]#df|awk '/\/$/ {if ($2>5000) print $1}' [root@web01 ~]#ps -auxf|head|awk '{if ($2>5)print $1,$2}'

5、Awk 内部变量

bash
# 1. NR记录输入总的编号(行号) [root@Shell ~]# awk '{print NR,$0}' /etc/passwd [root@Shell ~]# awk 'NR<=3' /etc/passwd # 2.NF保存行的最后一列列号,$NF保存最后一列内容 [root@web01 ~]#awk -F ":" '{print NF,$NF}' 1.txt 7 /bin/bash 7 /sbin/nologin 7 /sbin/nologin 7 /sbin/nologin 7 /sbin/nologin 7 /bin/sync 7 /sbin/shutdown 7 /sbin/halt 7 /sbin/nologin 1 listen 80; 7 /sbin/nologin # 3.print格式化输出函数 [root@Shell ~]# awk -F: '{print "用户是:" $1 "\t 用户 uid: " $3 "\t 用户 gid:" $4}' /etc/passwd printf 函数 [root@Shell ~]# awk -F: '{printf "%-15s %-10s %-15s\n", $1, $2, $3}' /etc/passwd %s 字符类型 %d 数值类型 占 15 字符 - 表示左对齐,默认是右对齐 printf 默认不会在行尾自动换行,加\n # 4.匹配最后一列不是bash的列 [root@web01 ~]#awk '$NF !~ /bash$/' 1.txt #bin:x:1:1:bin:/bin:/sbin/nologin #daemon:x:2:2:daemon:/sbin:/sbin/nologin

6、awk比较表达式

bash
# 1.uid为0的列出来 [root@Shell ~]# awk -F ":" '$3==0' /etc/passwd uid 小于 10 的全部列出来 # 2.uid小于10的全部列出来 [root@Shell ~]# awk -F: '$3 < 10' /etc/passwd # 3.用户登陆的 shell 等于/bin/bash [root@web01 ~]#awk -F: '$7=="/bin/bash"' 1.txt #root:x:0:0:root:/root:/bin/bash [root@web01 ~]#awk -F: '$NF=="/bin/bash"' 1.txt #root:x:0:0:root:/root:/bin/bash # 4.第一列为#root的列出来 [root@web01 ~]#awk -F: '$1=="#root"' 1.txt #root:x:0:0:root:/root:/bin/bash # 5.如果uid的值大于5555则打印第三列,否则打印第一列 [root@web01 ~]#awk -F: '{if($3>5555){print $3} else {print $1}}' 1.txt #root #bin #daemon adm # 6.查看用户数量分别是多少 [root@web01 ~]#awk -F: '{if($3==0){a++} else if($3>0&&$3<1000){b++} else{c++}}END{print "管理员数量: "a "\n虚拟用户的数量: "b "\n普通用户的数量是: "c}' 1.txt 管理员数量: 1 虚拟用户的数量: 9 普通用户的数量是: 1 # 7.匹配用户名为 root 或 uid 大于 5000 [root@web01 ~]#awk -F: '$1=="root"||$3>5000' /etc/passwd root:x:0:0:root:/root:/bin/bash nobody:x:65534:65534:Kernel Overflow User:/:/sbin/nologin # 8.打印当前管理员用户名称 [root@Shell ~]# awk -F: '{ if($3==0){print $1 "is adminisitrator"} }' /etc/passwd # 9.统计系统用户数量 [root@Shell ~]# awk -F: '{ if($3>0 && $3<1000){i++}} END {print i}' /etc/passwd

25、zabbix

1、zabbix监控的重要性

bash
1.什么是监控 对我们的操作系统进行不间断的监控 2.为什么要监控 软件生命周期中非常重要的一个环节 能够做到事前告警,事后我们还可以根据监控内容排查问题 3.如何去监控监控什么内容: • 监控硬件 磁盘 df -h 内存 free 磁盘IO 负载 CPU 网络 • 软件服务 端口 进程 状态 • 业务层面 业务数据进行数据 自定义监控 订单量 注册用户 充值用户 日志中 数据库中体现 • 业务之间接口调用监控 curl 4.监控有哪些工具 • zabbix 硬件 服务状态 自定义监控 • Nagions 网络产品 交换机 路由器 • Cacti 流量 • OPen-Falcon 小米公司 • prometheus kubernetes docker • 监控宝等

2、zabbix平台架构

bash
基于LNMP平台 Linux Nginx MySQL PHP zabbix端口 zabbix服务端: 10051 zabbix_proxy: 10051 java_gateway: 10052 zabbix_agent: 10050

3、安装部署mysql

bash
1.下载mysql8.0版本 [root@zabbix ~]#ll total 975892 -rw-r--r-- 1 root root 999311360 Sep 23 2024 mysql-8.0.36-1.el8.x86_64.rpm-bundle.tar 2.解压数据库 [root@zabbix ~]#tar -xf mysql-8.0.36-1.el8.x86_64.rpm-bundle.tar 3.rpm安装 [root@zabbix ~]#rpm -ivh mysql-community-common-8.0.36-1.el8.x86_64.rpm [root@zabbix ~]#rpm -ivh mysql-community-client-plugins-8.0.36-1.el8.x86_64.rpm [root@zabbix ~]#rpm -ivh mysql-community-libs-8.0.36-1.el8.x86_64.rpm [root@zabbix ~]#rpm -ivh mysql-community-client-8.0.36-1.el8.x86_64.rpm [root@zabbix ~]#rpm -ivh mysql-community-icu-data-files-8.0.36-1.el8.x86_64.rpm [root@zabbix ~]#rpm -ivh mysql-community-devel-8.0.36-1.el8.x86_64.rpm [root@zabbix ~]#rpm -ivh mysql-community-server-8.0.36-1.el8.x86_64.rpm 4.启动数据库 [root@zabbix ~]#systemctl start mysqld [root@zabbix ~]#netstat -tnulp Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1122/sshd: /usr/sbi tcp6 0 0 :::22 :::* LISTEN 1122/sshd: /usr/sbi tcp6 0 0 :::33060 :::* LISTEN 2909/mysqld tcp6 0 0 :::3306 :::* LISTEN 2909/mysqld udp 0 0 127.0.0.1:323 0.0.0.0:* 797/chronyd udp6 0 0 ::1:323 :::* 797/chronyd 5.进入数据库修改密码 查看随机生成的密码 [root@zabbix ~]#cat /var/log/mysqld.log |grep root@local 2025-06-04T08:02:08.392446Z 6 [Note] [MY-010454] [Server] A temporary password is generated for root@localhost: wl/.Rlrm!4kk # 修改密码: [root@zabbix ~]#mysql -uroot -p Enter password: wl/.Rlrm!4kk # 输入mysqld.log里的密码 mysql> alter user root@localhost identified by 'Oldboy123.com' 6.创建zabbix库 mysql> create database zabbix character set utf8 collate utf8_bin; 7.创建用户 mysql> create user 'zabbix'@'%' identified by 'Oldboy123.com'; 设置密码 mysql> ALTER USER 'zabbix'@'%' IDENTIFIED WITH mysql_native_password BY 'Oldboy123.com'; mysql> grant all privileges on zabbix.* to 'zabbix'@'%'; 清理mysql安装包 [root@zabbix ~]#rm -rf * 8.下载zabbix的源码包,将sql数据导入到zabbix库中 [root@zabbix ~]#ll total 21616 -rw-r--r-- 1 root root 22132982 Jun 4 10:08 zabbix-5.0.47.tar.gz # 解压zabbix源码 [root@zabbix ~]#tar -xf zabbix-5.0.47.tar.gz 9.进入源码目录 [root@zabbix ~/zabbix-5.0.47/database/mysql]#pwd /root/zabbix-5.0.47/database/mysql [root@zabbix ~/zabbix-5.0.47/database/mysql]#ll total 17008 -rw-r--r-- 1 oldboy1 oldboy1 15252182 May 20 15:10 data.sql -rw-r--r-- 1 oldboy1 oldboy1 282 May 20 15:10 double.sql -rw-r--r-- 1 oldboy1 oldboy1 1978341 May 19 19:09 images.sql -rw-r--r-- 1 oldboy1 oldboy1 482 May 20 15:10 Makefile.am -rw-r--r-- 1 oldboy1 oldboy1 15936 May 20 15:10 Makefile.in -rw-r--r-- 1 oldboy1 oldboy1 156294 May 20 15:10 schema.sql # 需要将schema.sql images.sql data.sql导入zabbix库 [root@zabbix ~/zabbix-5.0.47/database/mysql]#mysql -uzabbix -p'Oldboy123.com' zabbix < schema.sql mysql: [Warning] Using a password on the command line interface can be insecure. [root@zabbix ~/zabbix-5.0.47/database/mysql]#mysql -uzabbix -p'Oldboy123.com' zabbix < images.sql mysql: [Warning] Using a password on the command line interface can be insecure. [root@zabbix ~/zabbix-5.0.47/database/mysql]#mysql -uzabbix -p'Oldboy123.com' zabbix < data.sql mysql: [Warning] Using a password on the command line interface can be insecure.

4、安装部署php服务

bash
1.安装php服务 [root@zabbix ~/zabbix-5.0.47/database/mysql]#yum -y install php php-bcmath php-cli php-common php-devel php-embedded php-fpm php-gd php-intl php-mbstring php-mysqlnd php-opcache php-pdo php-process php-xml php-json php-ldap 2.修改监听方式为端口 [root@zabbix ~/zabbix-5.0.47/database/mysql]#vim /etc/php-fpm.d/www.conf 39 listen = 127.0.0.1:9000 3.启动加入开机自启 [root@zabbix ~/zabbix-5.0.47/database/mysql]#systemctl start php-fpm.service [root@zabbix ~/zabbix-5.0.47/database/mysql]#systemctl enable php-fpm.service

5、安装部署Nginx服务

bash
1.配置Nginx仓库 [root@zabbix ~/zabbix-5.0.47/database/mysql]#cat /etc/yum.repos.d/nginx.repo [nginx-stable] name=nginx stable repo baseurl=http://nginx.org/packages/centos/7/$basearch/ gpgcheck=0 enabled=1 gpgkey=https://nginx.org/keys/nginx_signing.key 2.安装nginx [root@zabbix ~/zabbix-5.0.47/database/mysql]#yum -y install nginx 3.配置Nginx服务 [root@zabbix ~/zabbix-5.0.47/database/mysql]#cat /etc/nginx/conf.d/default.conf server { listen 80; server_name _; root /code; index index.php index.html; location ~ \.php$ { fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } } [root@zabbix ~/zabbix-5.0.47/database/mysql]#nginx -t 4.启动nginx并开机自启 [root@zabbix ~/zabbix-5.0.47/database/mysql]#systemctl start nginx [root@zabbix ~/zabbix-5.0.47/database/mysql]#systemctl enable nginx # 检查9000 3306 80端口 [root@zabbix ~/zabbix-5.0.47/database/mysql]#netstat -tnulp Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1122/sshd: /usr/sbi tcp 0 0 127.0.0.1:9000 0.0.0.0:* LISTEN 3904/php-fpm: maste tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 4296/nginx: master tcp6 0 0 :::22 :::* LISTEN 1122/sshd: /usr/sbi tcp6 0 0 :::33060 :::* LISTEN 2909/mysqld tcp6 0 0 :::3306 :::* LISTEN 2909/mysqld udp 0 0 127.0.0.1:323 0.0.0.0:* 797/chronyd udp6 0 0 ::1:323 :::* 797/chronyd 5.将代码文件拷贝到/code目录 [root@zabbix ~/zabbix-5.0.47/database/mysql]#mkdir /code [root@zabbix ~/zabbix-5.0.47/database/mysql]#cd /code 6.拷贝源码中的前端页面代码到/code目录 [root@zabbix /code]#cp -r /root/zabbix-5.0.47/ui/* . 7.修改目录权限为apache [root@zabbix /code]#chown -R apache.apache /code 8.统一用户php和nginx都使用apache运行 #修改nginx启动用户为apache [root@zabbix /code]#vim /etc/nginx/nginx.conf [root@zabbix /code]#systemctl restart nginx

6、编译zabbix

bash
1.进入源码目录 [root@zabbix ~]#cd zabbix-5.0.47/ [root@zabbix ~/zabbix-5.0.47]#ll 2.安装依赖包 [root@zabbix ~/zabbix-5.0.47]#yum -y install libxml2 libxml2-devel net-snmp-devel curl-devel libevent-devel 3.配置zabbix [root@zabbix ~/zabbix-5.0.47]#./configure --enable-server --enable-agent --with-mysql --enable-ipv6 --with-net-snmp --with-libcurl --with-libxml2 4.编译 [root@zabbix ~/zabbix-5.0.47]#make 5.安装 [root@zabbix ~/zabbix-5.0.47]#make install 6.完成后检查 在命令行输入zabbix tab键 检查 [root@zabbix:~]#zabbix_ zabbix_agentd zabbix_get zabbix_js zabbix_sender zabbix_server 7.配置zabbix连接数据库信息 [root@zabbix ~/zabbix-5.0.47]#grep -n ^DB /usr/local/etc/zabbix_server.conf 94:DBName=zabbix 110:DBUser=zabbix 118:DBPassword=Oldboy123.com 8.创建启动虚拟用户zabbix [root@zabbix ~/zabbix-5.0.47]#groupadd -g666 zabbix [root@zabbix ~/zabbix-5.0.47]#useradd -u666 -g666 -M -s /sbin/nologin zabbix [root@zabbix ~/zabbix-5.0.47]#id 666 uid=666(zabbix) gid=666(zabbix) groups=666(zabbix) 9.启动 zabbix_server # 启动服务端 zabbix_agentd # 启动客户端 # 编写systemctl运行zabbix [root@zabbix ~/zabbix-5.0.47]#cat /usr/lib/systemd/system/zabbix.service [Unit] Description=Zabbix server After=network.target [Service] Type=forking ExecStart=/usr/local/sbin/zabbix_server ExecStop=/usr/local/sbin/zabbix_server stop User=zabbix Group=zabbix [Install] WantedBy=multi-user.target # 重新加载 [root@zabbix ~/zabbix-5.0.47]#systemctl daemon-reload # 停止服务,但是服务并没有停止,因为不是systemctl启动的 [root@zabbix ~/zabbix-5.0.47]#systemctl stop zabbix [root@zabbix ~/zabbix-5.0.47]#netstat -tnulp Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1122/sshd: /usr/sbi tcp 0 0 0.0.0.0:10051 0.0.0.0:* LISTEN 17631/zabbix_server # pkill杀死所有zabbix的进程 [root@zabbix ~/zabbix-5.0.47]#pkill zabbix_server # 启动进程 [root@zabbix ~/zabbix-5.0.47]#systemctl start zabbix [root@zabbix ~/zabbix-5.0.47]#systemctl enable zabbix [root@zabbix ~/zabbix-5.0.47]#netstat -tnulp Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1122/sshd: /usr/sbi tcp 0 0 0.0.0.0:10051 0.0.0.0:* LISTEN 17802/zabbix_server # 访问10.0.0.71

7、界面安装部署

image

bash
# 根据报错信息进行修改 [root@zabbix ~/zabbix-5.0.47]#egrep -n "post_max_size|max_execution_time|max_input_time|timezone" /etc/php.ini|grep -v ';' 383:max_execution_time = 300 393:max_input_time = 300 672:post_max_size = 16M 902:date.timezone =Asia/ShangHai 测试PHP [root@zabbix ~/zabbix-5.0.47]#php-fpm -t [04-Jun-2025 17:07:50] NOTICE: configuration file /etc/php-fpm.conf test is successful # 重启php服务 [root@zabbix ~/zabbix-5.0.47]#systemctl restart php-fpm.service # 测试

image

image

image

1、zabbix界面配置
1、修改语言为中文

image

2、修改默认的字体

image

bash
# 进入存放字体的目录 [root@zabbix ~/zabbix-5.0.47]#cd /code/assets/fonts/ [root@zabbix /code/assets/fonts]#ll total 740 -rw-r--r-- 1 apache apache 756072 Jun 4 16:32 DejaVuSans.ttf 将windows的字体上传到当前目录修改名称 C:\Windows\fonts\目录下 # 备注修改名称 [root@zabbix /code/assets/fonts]#mv DejaVuSans.ttf DejaVuSans.ttf.bak # 将windows上传的字体改名 [root@zabbix /code/assets/fonts]#mv SIMKAI.TTF DejaVuSans.ttf. # 刷新页面检查字体

image

2、监控zabbix服务器本身
bash
1.安装客户端zabbix-agent 默认已经编译安装 2.启动客户端 [root@zabbix:~]#zabbix_agentd

image

image

3、监控客户端
bash
1.准备客户端10.0.0.7 2.安装zabbix-agent客户端 Kylin系统直接安装(其他操作 部署YUM仓库) [root@zabbix /code/assets/fonts]#ll /etc/yum.repos.d/ epel.repo kylin_x86_64.repo nginx.repo [root@web01 /tmp]#yum -y install zabbix-agent 3.配置zabbix客户端配置文件指向服务端172.16.1.71 [root@web01 /tmp]#grep -n ^Server /etc/zabbix_agentd.conf 115:Server=172.16.1.71 #被动模式 外部Server(172.16.1.71)可拉取Agent数据 161:ServerActive=127.0.0.1 #主动模式 Agent会向本机(127.0.0.1)推送数据(需确保本机运行Zabbix Server) 4.启动zabbix客户端10050端口 [root@web01 /tmp]#systemctl start zabbix-agent.service [root@web01 /tmp]#systemctl enable zabbix-agent.service Created symlink /etc/systemd/system/multi-user.target.wants/zabbix-agent.service → /usr/lib/systemd/system/zabbix-agent.service. [root@web01 /tmp]#netstat -tnulp Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1066/sshd: /usr/sbi tcp 0 0 0.0.0.0:10050 0.0.0.0:* LISTEN 2116/zabbix_agentd 5.zabbix页面配置添加监控的主机

image

image

image

image

image

添加后观察主机是否变绿色

image

8、日志位置

bash
服务端日志: /tmp/zabbix_server.log 客户端yum安装: /var/log/zabbix/zabbix_agentd.log

9 、zabbix自定义监控

bash
zabbix监控流程: 创建添加主机(里面定义了监控项,比如内存呢,CPU,负载),写入数据库,间隔一段时间后去客户端取值,取到值后写入数据库并在页面上展示
1、自定义监控流程
bash
# 用zabbix取客户端的登陆用户数流程 1、客户端取到这个值 # awk '{print$(NF-6)}' 2、把取到这个值的shell命令添加到配置文件的key值里面 # /etc/zabbix_agentd.conf 3、重启客户端 4、客户端及服务端测试能否查看 # zabbix_agentd -p zabbix_get -s 172.16.1.7 -k user_login 5、页面创建应用集 6、创建监控项,填写自定义的key值,创建的应用集 7、观察变化
bash
1.取值 [root@web01 /tmp]#uptime |awk '{print$(NF-6)}' 1 2.配置到客户端的配置文件中zabbix-agent.conf [root@web01 /tmp]#grep user_login /etc/zabbix_agentd.conf # Format: UserParameter=<key>,<shell command> 把 shell command命令放到<key>里面 UserParameter=user_login,uptime |awk '{print$(NF-6)}' #把 uptime |awk '{print$(NF-6)}'的值放到user_login里面 # 这个user_login是key值需要创建 3.重启服务 [root@web01 /tmp]#systemctl restart zabbix-agent.service 4.查看自定义key值 [root@web01 /tmp]#zabbix_agentd -p user_login [t|1] #5.在zabbix服务端命令行使用zabbix_get取值测试,这里能取到值可以往页面上添加 [root@zabbix /code/assets/fonts]#zabbix_get -s 172.16.1.7 -k user_login 1 6.将自定义的key添加到zabbix页面进行监控

image

image

image

image

image

image

image

bash
#自定义取值可以使用include方式将自定key单独存放.conf的配置文件中 1.修改客户端的配置文件 [root@web01 /tmp]#sed -n '314p' /etc/zabbix_agentd.conf Include=/etc/zabbix_agentd.conf.d/*.conf 2.创建存放conf的路径 [root@web01 /tmp]#mkdir /etc/zabbix_agentd.conf.d/ 3.创建新的文件自定义key [root@web01 /tmp]#cd /etc/zabbix_agentd.conf.d [root@web01 /etc/zabbix_agentd.conf.d]#cat os.conf UserParameter=user_login,uptime |awk '{print$(NF-6)}'
2、自定义监控端口是否存在
bash
客户端配置: 1.添加key值 [root@web01 /etc/zabbix_agentd.conf.d]#cat os.conf UserParameter=user_login,uptime |awk '{print$(NF-6)}' UserParameter=ng_port,netstat -tnulp|grep nginx|grep 80|wc -l 2.重启客户端zabbix [root@web01 /etc/zabbix_agentd.conf.d]#systemctl restart zabbix-agent.service 3.客户端查看定义的key值 [root@web01 /etc/zabbix_agentd.conf.d]#zabbix_agentd -p|grep ng_port ng_port [t|1] #4.服务端查看失败,因为netstat命令zabbix无法执行,需要提权 [root@zabbix /code/assets/fonts]#zabbix_get -s 172.16.1.7 -k ng_port (Not all processes could be identified, non-owned process info will not be shown, you would have to be root to see it all.) 0 # 提权,所有普通用户在执行这个命令的时候都拥有root权限,在客户端加权,因为 [root@web01 /etc/zabbix_agentd.conf.d]#chmod u+s /usr/bin/netstat #继续执行,成功获取到值 [root@zabbix /code/assets/fonts]#zabbix_get -s 172.16.1.7 -k ng_port 1 # 页面配置

image

image

image

image

image

bash
# 关闭nginx服务 [root@web01 /etc/zabbix_agentd.conf.d]# systemctl stop nginx # 刷新测试

image

3、自定义映射值

image

image

image

image

image

bash
# 注意!添加“查看值”的时候,上面单位的数量要清空,否则不生效

image

image

4、使用系统自带的监控项监控端口
bash
[root@zabbix /code/assets/fonts]#zabbix_get -s 172.16.1.7 -k net.tcp.listen[9000] 1 [root@zabbix /code/assets/fonts]#zabbix_get -s 172.16.1.7 -k net.tcp.listen[22] 1 # net.tcp.listen[]是系统自带的监控项,可以监控端口

image

image

image

image

bash
# 停止php服务 [root@web01 /etc/zabbix_agentd.conf.d]#systemctl stop php-fpm.service

image

5、自定义监控内存使用率
bash
1.设置key参数值 [root@web01 /etc/zabbix_agentd.conf.d]#cat os.conf UserParameter=user_login,uptime |awk '{print$(NF-6)}' UserParameter=ng_port,netstat -tnulp|grep nginx|grep 80|wc -l UserParameter=free_use,free|awk 'NR==2{print$3/$2*100}' 2.重启客户端 [root@web01 /etc/zabbix_agentd.conf.d]#systemctl restart zabbix-agent 3.服务端测试取值 [root@zabbix /code/assets/fonts]#zabbix_get -s 172.16.1.7 -k free_use 24.2305 # zabbix页面添加

添加监控项

image

image

image

10、设置触发器

1、设置登录数报警

image

创建触发器

image

image

image

image

image

image

2、设置报警声音

image

3、设置内存超过20%告警(实际工作中80%)

image

已经产生报警

image

image

image

image

11、配置邮件告警

bash
默认标题: 故障: {EVENT.NAME} 消息内容: 报警主机: {HOST.NAME1} 报警服务: {ITEM.NAME} 报警key1: {ITEM.KEY1}: {ITEM.VALUE1} 报警key2: {ITEM.KEY2}: {ITEM.VALUE2} 严重级别: {TRIGGER.SEVERITY} 恢复操作 默认标题: 恢复: {EVENT.NAME} 消息内容: 恢复主机: {HOST.NAME1} 恢复服务: {ITEM.NAME} 恢复key1: {ITEM.KEY1}: {ITEM.VALUE1} 恢复key2: {ITEM.KEY2}: {ITEM.VALUE2}
1、配置告警媒介

image

image

image

image

设置发送方

image

​​

bash
QTajTY4PwVH34zCh

设置接收方

image

image

image

image

配置接收人

image

image

测试发送

image

2、配置消息模板

image

image

bash
# 已成功收到邮件

image

bash
# 配置邮件告警信息 1、配置主机,设置相关监控项 2、根据监控项设置触发器 3、设置邮箱163邮箱-把IMAP/SMTP服务跟POP3/SMTP服务开启,保存授权码 4、设置发送方,创建媒介类型,添加163邮箱信息,添加配置模板,添加完测试是否能正常发送邮件 5、配置动作,设置发送用户,发送目的 6、配置接收人,选择用户群组及用户

12、配置远程执行命令+邮箱

设置监控项

image

设置触发器

image

image

bash
配置sudo提权: [root@web01 ~]#chmod u+w /etc/sudoers [root@web01:~]#grep zabbix /etc/sudoers zabbix ALL=(ALL) NOPASSWD: ALL 客户端开启远程执行命令功能: [root@web01 ~]#vim /etc/zabbix_agentd.conf [root@web01 ~]#grep -n ^EnableRemoteCommand /etc/zabbix_agentd.conf 91:EnableRemoteCommands=1 [root@web01 ~]#systemctl restart zabbix-agent.service [root@web01 ~]#netstat -tnulp

设置触发动作

image

image

image

image

故意把nginx配置文件改错,测试

image

image

配置文件改回来,手动启动,显示正常

image

bash
企业微信后面界面: https://work.weixin.qq.com/wework_admin/loginpage_wx?from=myhome

13、配置企业微信告警

1、注册企业微信
2、下载weixin python告警脚本
bash
# 上传py脚本 [root@zabbix:~]#ll -rw-r--r-- 1 root root 1364 Sep 24 15:09 weixin.python # 修改weixin.py中的三个参数 [root@zabbix:~]#vim weixin.python ... corpid='wwc2749ba833b4e897' appsecret='XUc23DnuGn-YcAzpa4T9_7yQc43IzgZL96XqtM5-9Ao' agentid=1000002 ... # 安装python2版本 [root@zabbix ~]#yum -y install python2 安装python2-pip # 用来安装python依赖 [root@zabbix ~]#yum -y install python2-pip 安装运行python脚本的依赖 [root@zabbix ~]#pip2.7 install requests
3、在企业平台创建的zabbix应用中管理接口

​​

bash
# 查看公网ip [root@web01 ~]#curl cip.cc IP : 123.117.19.236 地址 : 中国 北京 北京 运营商 : 联通 数据二 : 中国北京北京 | 联通 数据三 : 中国北京北京市 | 联通 URL : http://www.cip.cc/123.117.19.236

image

bash
测试脚本: [root@zabbix:~]#python2.7 weixin.python "ZhaoJunJie" "下雨了" "回家开车"
4、集成到zabbix页面中
bash
# 将脚本移动到固定的目录 [root@zabbix:~]#mv weixin.python /usr/local/share/zabbix/alertscripts/ [root@zabbix:~]#ll /usr/local/share/zabbix/alertscripts/ total 4 -rw-r--r-- 1 root root 1352 Jun 5 16:02 weixin.python [root@zabbix ~]#chmod +x /usr/local/share/zabbix/alertscripts/weixin.python [root@zabbix ~]#ll /usr/local/share/zabbix/alertscripts/weixin.python -rwxr-xr-x 1 root root 1352 Jun 5 16:02 /usr/local/share/zabbix/alertscripts/weixin.python # 修改日志权限 [root@zabbix ~]#chown zabbix.zabbix /tmp/weixin.log [root@zabbix ~]#ll /tmp/weixin.log -rw-r--r-- 1 zabbix zabbix 898 Jun 5 16:05 /tmp/weixin.log
1、创建媒介类型

image

bash
{ALERT.SENDTO} #发给谁 {ALERT.SUBJECT} #报警标题 {ALERT.MESSAGE} #报警内容

image

image

2、配置接收方

image

3、配置收件人

image

bash
测试,推送失败。显示No message defined for media type. # 查看日志,无关键内容 [root@zabbix ~]#cat /tmp/weixin.log Thu, 05 Jun 2025 16:04:55, connectionpool.py, DEBUG, Starting new HTTPS connection (1): qyapi.weixin.qq.com:443 Thu, 05 Jun 2025 16:05:00, connectionpool.py, DEBUG, https://qyapi.weixin.qq.com:443 "GET /cgi-bin/gettoken?corpid=wwc2749ba833b4e897&corpsecret=XUc23DnuGn-YcAzpa4T9_7yQc43IzgZL96XqtM5-9Ao HTTP/1.1" 200 277 Thu, 05 Jun 2025 16:05:00, connectionpool.py, DEBUG, Starting new HTTPS connection (1): qyapi.weixin.qq.com:443 Thu, 05 Jun 2025 16:05:05, connectionpool.py, DEBUG, https://qyapi.weixin.qq.com:443 "POST /cgi-bin/message/send?access_token=6EzcKE7W8dDy4avVkeYhnggXsRI3IUrSn7VS6aowim1mf_EVtDar3TwjpLb40dx99V7uzWXBSJBMTxjdNI-hyEntawVzxrQR-gGbJ-_St0nWDwqeQjyJQObpeqEopUe7MRKkfPvb6Tvw-YW0SNdNtfCAfvGzuOCBAvtru1it15K7ZQdd_9bRBm6KrqFL8LITZE_5AgQaZPSGfjqwQM9yPw HTTP/1.1" 200 145 Thu, 05 Jun 2025 16:05:05, weixin.py, INFO, sendto:ZhangWeiXiang;;subject:回家;;message:回家 打老鼠

image

bash
# 手动测试连通性,显示没有文件,查看原因是文件名错误,修改文件名 [root@zabbix /usr/local/share/zabbix/alertscripts]#mv weixin.py weixin.python # 测试

image

bash
# 测试联通性,没问题,遇到个问题,命令行跟界面测试都没能发送过去,但是联通性不行 方法,管理--用户--报警媒介,把用户名更新一下 管理--媒介--消息模板,更新一下

1b4c3817ece834260af1033afd49a27

14、配置图形

bash
配置--主机--图形--创建图表
1、内存使用率

image

image

image

2、用户登录数

image

3、监控指标放到一张图

image

image

4、聚合图形

15、自定义模板

1、nginx七种状态
bash
# 1.配置七种状态 [root@web01 ~]#cat /etc/nginx/conf.d/xbw.conf server { listen 80 default; server_name _; location / { root /code/xy; index index.html index.htm; } location /nginx_status{ stub_status; } } [root@web01 ~]#nginx -t nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful [root@web01 ~]#systemctl restart nginx [root@web01 ~]#curl 10.0.0.7/nginx_status Active connections: 1 server accepts handled requests 1 1 1 Reading: 0 Writing: 1 Waiting: 0 [root@web01 ~]# # 2.自定义取值 [root@web01 /etc/zabbix_agentd.conf.d]#cat nginx.conf UserParameter=nginx_ac,curl -s 10.0.0.7/nginx_status|awk 'NR==1{print $NF}' UserParameter=nginx_ap,curl -s 10.0.0.7/nginx_status|awk 'NR==3{print $1}' UserParameter=nginx_ha,curl -s 10.0.0.7/nginx_status|awk 'NR==3{print $2}' UserParameter=nginx_re,curl -s 10.0.0.7/nginx_status|awk 'NR==3{print $3}' # 3.重启客户端,先关闭等端口消失再启动,否则会出现客户端能显示监控项。服务端看不到的清空 [root@web01 /etc/zabbix_agentd.conf.d]#pkill zabbix_agentd # 4.查看自定义值 [root@web01 /etc/zabbix_agentd.conf.d]#zabbix_agentd -p|grep ng ng_port [t|1] nginx_ac [t|1] nginx_ap [t|9] nginx_ha [t|10] nginx_re [t|10] # 5.服务端获取客户端自定义值测试zabbix_get [root@zabbix /usr/local/share/zabbix/alertscripts]#zabbix_get -s 172.16.1.7 -k nginx_ac 1 [root@zabbix /usr/local/share/zabbix/alertscripts]#zabbix_get -s 172.16.1.7 -k nginx_ap 13 [root@zabbix /usr/local/share/zabbix/alertscripts]#zabbix_get -s 172.16.1.7 -k nginx_ha 14 [root@zabbix /usr/local/share/zabbix/alertscripts]#zabbix_get -s 172.16.1.7 -k nginx_re 14

创建模板

bash
创建nginx的七种状态的模板,那么这个模板再其他web服务器可以直接拿来调用,直接监控七种状态

image

image

image

创建应用集

image

创建监控项

image

克隆监控项

image

image

image

新增触发器

image

新建图形

image

创建聚合图形

image

2、关联七种状态,让模板生效生效

image

image

image

bash
# 压力测试 [root@web01 /etc/zabbix_agentd.conf.d]#ab -c20 -n2000 http://10.0.0.7/index.html

image

image

3、web02关联nginx模版
bash
1.安装zabbix客户端 [root@web02 ~]#yum -y install zabbix-agent 2.配置文件指向服务端 [root@web02 ~]#grep 172.16.1.71 /etc/zabbix_agentd.conf Server=172.16.1.71 # 这行取消注释 313 Include=/etc/zabbix_agentd.conf.d/*.conf 3.重启生效 [root@web02 /etc/zabbix_agentd.conf.d]#systemctl restart zabbix-agent.service 4.创建文件目录 [root@web02 ~]#mkdir -p /etc/zabbix_agentd.conf.d [root@web02 /etc/zabbix_agentd.conf.d]#cat nginx.conf UserParameter=nginx_ac,curl -s 10.0.0.8/nginx_status|awk 'NR==1{print $NF}' UserParameter=nginx_ap,curl -s 10.0.0.8/nginx_status|awk 'NR==3{print $1}' UserParameter=nginx_ha,curl -s 10.0.0.8/nginx_status|awk 'NR==3{print $2}' UserParameter=nginx_re,curl -s 10.0.0.8/nginx_status|awk 'NR==3{print $3}' 5.配置nginx状态 [root@web02 ~]#cat /etc/nginx/conf.d/xbw.conf server { listen 80 default; server_name _; location / { root /code/xy; index index.html index.htm; } location /nginx_status{ stub_status; } } 6.重启配置 [root@web02 ~]#systemctl restart nginx 7.测试联通性 [root@web02 ~]#curl 10.0.0.8/nginx_status Active connections: 1 server accepts handled requests 1 1 1 Reading: 0 Writing: 1 Waiting: 0

客户端配置

image

image

测试

image

4、监控PHP状态信息
bash
# 1.修改配置文件 [root@web01 /etc/zabbix_agentd.conf.d]#sed -n '240p' /etc/php-fpm.d/www.conf pm.status_path = /status [root@web01 /etc/zabbix_agentd.conf.d]#php-fpm -t [05-Jun-2025 20:47:19] NOTICE: configuration file /etc/php-fpm.conf test is successful # 2.配置nginx [root@web01 /etc/nginx/conf.d]#cat xbw.conf server { listen 80 default; server_name _; location / { root /code/xy; index index.html index.htm; } location /nginx_status{ stub_status; } location /status{ fastcgi_pass 127.0.0.1:9000; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } } [root@web01 /etc/nginx/conf.d]#systemctl restart nginx [root@web01 /etc/nginx/conf.d]#systemctl restart php-fpm.service # 3.php状态介绍 [root@web01 /etc/nginx/conf.d]#curl 127.0.0.1/status pool: www # pool的名称 process manager: dynamic # 进程管理方式,现在大多数为dynamic,不要使用static start time: 05/Jun/2025:20:55:45 +0800 # php-fpm上次启动的时间 start since: 2 # php-fpm已经运行了多少秒 accepted conn: 1 # pool接受到的请求数 listen queue: 0 # 处于等待状态的连接数,自动增加 max listen queue: 0 # 从php-fpm启动到现在处于等待链接的最大数量 listen queue len: 128 # 处于等待连接队列的套接字大小 idle processes: 4 # 处于空闲状态的进程数 active processes: 1 # 处于活动状态的进程数 total processes: 5 # 进程总数 max active processes: 1 # 从php-fpm启动到现在最多有几个进程处于活动状态、php-fpm自启动以来达到的最高并发进程数,记录历史峰值,只增不减 max children reached: 0 # 当pm试图启动更多的children进程时,却达到了进程数的限制,达到一次记录一次,如果不为0,需要增加php-fpm pool进程最大数 slow requests: 0 # 当启动php-fpm slow-log功能时,如果出现php-fpm慢请求这个计数器会增加,一般不当的mysql查询会触发这个值 # 4.配置key参数值 [root@web01 /etc/zabbix_agentd.conf.d]#cat php.conf UserParameter=php_idle,curl -s 127.0.0.1/status |awk '/^idle/{print$NF}' # 处于空闲状态的进程数 UserParameter=php_ac,curl -s 127.0.0.1/status |awk '/^active/{print$NF}' # 处于活动状态的进程数 UserParameter=php_max,curl -s 127.0.0.1/status |awk 'NR==12{print$NF}' # 从php-fpm启动到。。。 UserParameter=php_chil,curl -s 127.0.0.1/status |awk 'NR==13{print$NF}' # 当启动php-fpm slow-l。。。 # 5.重启zabbix-agent [root@web01 /etc/zabbix_agentd.conf.d]#systemctl restart zabbix-agent.service #6.服务端测试 [root@zabbix /usr/local/share/zabbix/alertscripts]#zabbix_get -s 172.16.1.7 -k php_idle 4 [root@zabbix /usr/local/share/zabbix/alertscripts]#zabbix_get -s 172.16.1.7 -k php_ac 1 [root@zabbix /usr/local/share/zabbix/alertscripts]#zabbix_get -s 172.16.1.7 -k php_max 1 [root@zabbix /usr/local/share/zabbix/alertscripts]#zabbix_get -s 172.16.1.7 -k php_chil 0 # 创建php模板

image

image

image

克隆监控项

image

image

添加触发器

image

添加图形

image

关联到WEB01

image

查看图形

image

16、使用脚本方式自定义监控项

bash
1.使用case脚本传参的方式获取七种状态 [root@web01 /etc/zabbix_agentd.conf.d]#cat nginx.sh #!/bin/sh case $1 in active) curl -s 127.0.0.1/nginx_status|awk 'NR==1{print $NF}' ;; accepts) curl -s 127.0.0.1/nginx_status|awk 'NR==3{print $1}' ;; handled) curl -s 127.0.0.1/nginx_status|awk 'NR==3{print $2}' ;; requests) curl -s 127.0.0.1/nginx_status|awk 'NR==3{print $3}' ;; *) echo "Usage: $0 [active|accepts|handled|requests]" esac 2.给脚本执行权限 [root@web01 /etc/zabbix_agentd.conf.d]#chmod +x /etc/zabbix_agentd.conf.d/nginx.sh [root@web01 /etc/zabbix_agentd.conf.d]#ll /etc/zabbix_agentd.conf.d/nginx.sh -rwxr-xr-x 1 root root 525 Jun 5 22:48 /etc/zabbix_agentd.conf.d/nginx.sh 3.测试 [root@web01 /etc/zabbix_agentd.conf.d]#curl -s 127.0.0.1/nginx_status Active connections: 1 server accepts handled requests 5957 5957 5993 Reading: 0 Writing: 1 Waiting: 0 [root@web01 /etc/zabbix_agentd.conf.d]#sh nginx.sh active 1 [root@web01 /etc/zabbix_agentd.conf.d]#sh nginx.sh accepts 6028 4.修改配置文件 [root@web01 /etc/zabbix_agentd.conf.d]#cat nginx.conf UserParameter=nginx.[*],/etc/zabbix_agentd.conf.d/nginx.sh $1 5.重启生效 [root@web01 /etc/zabbix_agentd.conf.d]#systemctl restart zabbix-agent.service 6.服务端测试 [root@zabbix /usr/local/share/zabbix/alertscripts]#zabbix_get -s 172.16.1.7 -k nginx.[active] 1 # 页面创建监控项

image

image

17、zabbix通过SNMP监控网络设备

bash
监控linux操作系统使用Agent客户端方式,里面的键值有tcp、udp。添加主机接口中能看到 客户端启动snmp服务,设置团体名称public。然后在主机点击snmp协议 SNMP简单网络管理协议(SNMP-SimpleNetwork ManagementProtocol) SNMP的经常使用版本有三个:SNMPv1、SNMPv2、SNMPv3(SNMPv3是具备安全性的通讯协议) SNMP被普遍应用在NMS网络管理系统中(Network ManagementSystem)。知名的NMS包括BMC的Patrol、CA的Unicenter、SunMangegement控制 台、IBM的TivoliNetview、以及全球著名的HPOpenview。NMS的目标是提供一个监控和管理全部开启SNMP功能的设备的单一入口。 SNMP协议经过UDP端口161和162进行通讯。 161端口:SNMPMessage 162端口:SNMPTrapMeaasge SNMP管理模型中有三个基本组成部分:管理站(Manager),被管代理(Agent)和管理信息库(MIB)。 被管代理(Agent)指的是用于跟踪监测被管理设备状态的特殊软件或硬件,每个代理都拥有自己本地的MIB。 被管代理(Agent)翻译来自管理站(Manager)的请求,验证操作的可执行性,通过直接与相应的功能实体(如网络设备)通信来执行信息处理任务, 同时向管理站返回响应信息。 网络设备硬件信息表示方式两种: OID表述方法 数字表示 .1.3.6.1.2.1.25.2.2.0 #获取内存大小 MIB表示方法 字符串表示hrMemorySize #获取内存大小 OID和MIB大全 https://www.cnblogs.com/cqx6388/p/17235747.html 1.客户端安装snmp [root@web01 /etc/zabbix_agentd.conf.d]#yum -y install net-snmp 2.修改配置 [root@web01 /etc/zabbix_agentd.conf.d]#sed -n '41p;55p;116p' /etc/snmp/snmpd.conf com2sec notConfigUser default public # 去掉注释 view systemview included .1. group notConfigGroup v2c notConfigUser # 去掉注释 3.启动snmp端口161 [root@web01 /etc/zabbix_agentd.conf.d]#systemctl start snmpd [root@web01 /etc/zabbix_agentd.conf.d]#netstat -tnulp Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 127.0.0.1:199 0.0.0.0:* LISTEN 241668/snmpd tcp 0 0 127.0.0.1:9000 0.0.0.0:* LISTEN 134267/php-fpm: mas tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 133580/nginx: maste tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1066/sshd: /usr/sbi tcp 0 0 0.0.0.0:10050 0.0.0.0:* LISTEN 236430/zabbix_agent tcp6 0 0 :::22 :::* LISTEN 1066/sshd: /usr/sbi tcp6 0 0 :::10050 :::* LISTEN 236430/zabbix_agent udp 0 0 0.0.0.0:161 0.0.0.0:* 241668/snmpd 4.服务端安装snmp命令 [root@zabbix /usr/local/share/zabbix/alertscripts]#yum -y install net-snmp-utils [root@zabbix /usr/local/share/zabbix/alertscripts]#snmpwalk -v2c -c public 10.0.0.7 SysName SNMPv2-MIB::sysName.0 = STRING: web01 -v 指定SNMP版本 2c 指定SNMP版本为V2 -c 指定团体名称 SysName 主机名 # 使用oid的方式 [root@zabbix /usr/local/share/zabbix/alertscripts]#snmpwalk -v2c -c public 10.0.0.7 .1.3.6.1.2.1.25.2.2.0 HOST-RESOURCES-MIB::hrMemorySize.0 = INTEGER: 970908 KBytes 5.测试通过后,页面使用snmp协议监控

image

image

image

18、zabbix自动化监控

1、自动发现

​​

bash
1.zabbix自动发现 zabbix服务端通过扫描地址段的方式自动发现存活的服务器,发现服务器后进行动作处理,添加主机、关联模板、关联报警等 缺点1: 扫描速度慢 server压力较大 缺点2: 所有扫描到的客户端只能使用统一模板,比如web和数据库使用模板是不同的还需要手动进行配置

配置自动发现

image

image

配置动作

image

image

image

image

image

image

bash
# 查看日志 [root@zabbix ~]#cat /tmp/zabbix_server.log 17967:20250606:143005.152 At least one of '/usr/sbin/fping', '/usr/sbin/fping6' must exist. Both are missing in the system. 17960:20250606:150002.070 enabling Zabbix agent checks on host "172.16.1.7": host became available 17956:20250606:150009.077 enabling Zabbix agent checks on host "172.16.1.8": host became available # 重启服务端测试

image

image

2、自动注册
bash
客户端主动将自身信息上传给服务端用来减少服务端的压力 根据需求调整自动还是被动模式 zabbix服务端:默认主动模式--我主动去抓取客户端的数据--10s 被动模式:等着客户端主动将数据提交给服务端 例如:当服务器超过300-500+台以上,当网络较复杂的情况,当服务器配置一般的情况。修改模版监控项为主动上报模式。 [root@web01 ~]#vim /etc/zabbix_agentd.conf 161 ServerActive=172.16.1.71 # 修改为服务器端的ip,主动上报 172 Hostname=web01 # 修改为自己的主机名 [root@web01 ~]#systemctl restart zabbix-agent.service

关闭自动发现

image

image

bash
重启客户端生效 [root@web02 ~]#systemctl restart zabbix-agent.service

image

bash
区分是否主动上报

image

image

bash
修改服务端为被动式

image

imageimage

image

bash
在自动注册动作里面,ansible如何一键修改配置文件,把配置文件拿到ansible本地,把Active设置成172.16.1.71(zabbix服务端),把 Hostname设置为变量,取自己的主机名,这样自动注册动作根据自己主机名进行模板关联

0ad02af46b923261debf39bd0db88be

19、zabbix proxy代理

image

image

bash
Zabbix Proxy是Zabbix监控系统中的一个重要组件,主要作用如下: 1:分布式监控,作为Zabbix Server的代理,在远程位置收集监控数据,减轻Zabbix Server的负载 2:数据缓冲,在无法连接到Zabbix Server时临时存储监控数据,连接恢复后自动将数据发送到主服务器 3:降低网络流量,在本地预处理数据,减少向主服务器传输的数据量 4:简化管理,允许集中管理多个远程位置的监控配置 5:主要功能是数据采集、缓冲和转发 与Zabbix Server的区别: 1、Proxy不处理告警、不执行事件关联、不直接向用户提供数据,这些功能仍由主服务器完成。 2、Proxy是Zabbix实现可扩展性和分布式监控的关键组件。
1、安装数据库
bash
1.下载mysql8.0版本 [root@zabbix ~]#ll total 975892 -rw-r--r-- 1 root root 999311360 Sep 23 2024 mysql-8.0.36-1.el8.x86_64.rpm-bundle.tar 2.解压数据库 [root@zabbix ~]#tar -xf mysql-8.0.36-1.el8.x86_64.rpm-bundle.tar 3.rpm安装 [root@zabbix ~]#rpm -ivh mysql-community-common-8.0.36-1.el8.x86_64.rpm [root@zabbix ~]#rpm -ivh mysql-community-client-plugins-8.0.36-1.el8.x86_64.rpm [root@zabbix ~]#rpm -ivh mysql-community-libs-8.0.36-1.el8.x86_64.rpm [root@zabbix ~]#rpm -ivh mysql-community-client-8.0.36-1.el8.x86_64.rpm [root@zabbix ~]#rpm -ivh mysql-community-icu-data-files-8.0.36-1.el8.x86_64.rpm [root@zabbix ~]#rpm -ivh mysql-community-devel-8.0.36-1.el8.x86_64.rpm [root@zabbix ~]#rpm -ivh mysql-community-server-8.0.36-1.el8.x86_64.rpm 4.启动数据库 [root@zabbix ~]#systemctl start mysqld [root@zabbix ~]#netstat -tnulp Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1122/sshd: /usr/sbi tcp6 0 0 :::22 :::* LISTEN 1122/sshd: /usr/sbi tcp6 0 0 :::33060 :::* LISTEN 2909/mysqld tcp6 0 0 :::3306 :::* LISTEN 2909/mysqld udp 0 0 127.0.0.1:323 0.0.0.0:* 797/chronyd udp6 0 0 ::1:323 :::* 797/chronyd 5.进入数据库修改密码 查看随机生成的密码 [root@zabbix ~]#cat /var/log/mysqld.log |grep root@local 2025-06-04T08:02:08.392446Z 6 [Note] [MY-010454] [Server] A temporary password is generated for root@localhost: wl/.Rlrm!4kk # 修改密码: [root@zabbix ~]#mysql -uroot -p Enter password: wl/.Rlrm!4kk # 输入mysqld.log里的密码 mysql> alter user root@localhost identified by 'Oldboy123.com' 6.创建zabbix库 mysql> create database zabbix character set utf8 collate utf8_bin; 7.创建用户 mysql> create user 'zabbix'@'localhost' identified by 'Oldboy123.com'; 设置密码 mysql> ALTER USER 'zabbix'@'localhost' IDENTIFIED WITH mysql_native_password BY 'Oldboy123.com'; mysql> grant all privileges on zabbix.* to 'zabbix'@'localhost'; 8.复制zabbix包 [root@zabbix ~]#scp zabbix-5.0.47 10.0.0.5:/root [root@lb01 ~/zabbix-5.0.47/database/mysql]#tar -xf zabbix-5.0.47.tar.gz [root@lb01 ~/zabbix-5.0.47/database/mysql]#mysql -uzabbix -pOldboy123.com zabbix<schema.sql 9.安装编译依赖 [root@lb01 ~/zabbix-5.0.47]#./configure --prefix=/usr/ --enable-proxy --with-net-snmp --with-mysql [root@lb01 ~/zabbix-5.0.47]#make && make install 10.修改proxy配置文件连接数据库信息 [root@lb01 ~/zabbix-5.0.47]#grep ^DB /usr/etc/zabbix_proxy.conf DBName=zabbix DBUser=zabbix DBPassword=Oldboy123.com [root@lb01 ~/zabbix-5.0.47]#egrep "10.0.0.81|sh_proxy" /usr/etc/zabbix_proxy.conf Server=10.0.0.71 Hostname=sh_proxy 11.启动zabbix proxy [root@lb01 ~/zabbix-5.0.47]#useradd zabbix [root@lb01 ~/zabbix-5.0.47]#zabbix_proxy [root@lb01 ~/zabbix-5.0.47]#netstat -tnulp
2、修改web指定到代理服务器lb01
bash
1.更改web01局域网配置 [root@web01 ~]#grep Server /etc/zabbix_agentd.conf Server=172.16.1.5 # 通过proxy方式上传 ServerActive=172.16.1.5 [root@web01 ~]#systemctl restart zabbix-agent.service [root@web01 ~]#netstat -tnulp 2.更改web02局域网配置 [root@web02 ~]#grep Server /etc/zabbix_agentd.conf Server=172.16.1.5 # 通过proxy方式上传 ServerActive=172.16.1.5 [root@web02 ~]#systemctl restart zabbix-agent.service [root@web02 ~]#netstat -tnulp
3、页面设置

image

image

image

添加web01主机

image

image

添加web02主机

image

image

image

bash
# 发现并没有启动,查看后台日志 [root@zabbix ~/zabbix-5.0.47]#tail /tmp/zabbix_server.log 60137:20250606:194213.001 cannot parse proxy data from active proxy at "10.0.0.5": proxy "sh_proxy" not found 60137:20250606:194214.003 cannot parse proxy data from active proxy at "10.0.0.5": proxy "sh_proxy" not found 60137:20250606:194215.005 cannot parse proxy data from active proxy at "10.0.0.5": proxy "sh_proxy" not found 60137:20250606:194216.007 cannot parse proxy data from active proxy at "10.0.0.5": proxy "sh_proxy" not found 60137:20250606:194217.009 cannot parse proxy data from active proxy at "10.0.0.5": proxy "sh_proxy" not found 60137:20250606:194218.010 cannot parse proxy data from active proxy at "10.0.0.5": proxy "sh_proxy" not found 60137:20250606:194219.013 cannot parse proxy data from active proxy at "10.0.0.5": proxy "sh_proxy" not found 60137:20250606:194220.015 cannot parse proxy data from active proxy at "10.0.0.5": proxy "sh_proxy" not found 60118:20250606:194955.225 executing housekeeper 60118:20250606:195001.332 housekeeper [deleted 0 hist/trends, 24461 items/triggers, 0 events, 0 problems, 0 sessions, 0 alarms, 0 audit, 0 records in 6.105992 sec, idle for 1 hour(s)] # 杀死zabbix进程 [root@lb01 ~/zabbix-5.0.47]#pkill zabbix_proxy [root@lb01 ~/zabbix-5.0.47]#ps auxf|grep zabbix root 16450 0.0 0.0 213140 896 pts/0 S+ 19:59 0:00 \_ grep --color=auto zabbix # 重新启动 [root@lb01 ~/zabbix-5.0.47]#zabbix_proxy

image

20、监控java程序

bash
zabbix通过zabbix-java-gateway实现对java进行监控 监控java使用jmx协议 服务端: 10.0.0.71 zabbix-java-gateway: 10.0.0.5 tomcat: 10.0.0.7
1、web01部署tomcat
bash
1.安装jdk 上传jdk 安装jdk [root@web01 ~]#rpm -ivh jdk-8u181-linux-x64.rpm 2.上传tomcat [root@web01 ~]#ll -rw-r--r-- 1 root root 12787166 May 4 20:33 apache-tomcat-9.0.104.tar.gz 3.解压 [root@web01 ~]#tar xf apache-tomcat-9.0.104.tar.gz [root@web01 ~]#mv apache-tomcat-9.0.104 /usr/local/tomcat 4.配置tomcat开启jmx协议 [root@web01 ~]#head -10 /usr/local/tomcat/bin/catalina.sh #!/bin/sh CATALINA_OPTS="$CATALINA_OPTS\ -Dcom.sun.management.jmxremote\ -Djava.rmi.server.hostname=10.0.0.7\ -Dcom.sun.management.jmxremote.port=12345\ -Dcom.sun.management.jmxremote.ssl=false\ -Dcom.sun.management.jmxremote.authenticate=false" # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with 5.启动tomcat [root@web01 ~]#/usr/local/tomcat/bin/startup.sh Using CATALINA_BASE: /usr/local/tomcat Using CATALINA_HOME: /usr/local/tomcat Using CATALINA_TMPDIR: /usr/local/tomcat/temp Using JRE_HOME: /usr Using CLASSPATH: /usr/local/tomcat/bin/bootstrap.jar:/usr/local/tomcat/bin/tomcat-juli.jar Using CATALINA_OPTS: -Dcom.sun.management.jmxremote -Djava.rmi.server.hostname=10.0.0.7 -Dcom.sun.management.jmxremote.port=12345 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false Tomcat started. [root@web01 ~]#netstat -tnulp # 如遇到tomcat端口起不来的情况,先杀死进程再启动
2、服务端配置java网关
bash
1.下载安装java gateway [root@lb01 ~/zabbix-5.0.47]#rpm -Uvh https://repo.zabbix.com/zabbix/5.0/rhel/7/x86_64/zabbix-release-5.0-1.el7.noarch.rpm [root@lb01 ~/zabbix-5.0.47]#yum -y install zabbix-java-gateway 2.启动 [root@lb01 ~/zabbix-5.0.47]#systemctl start zabbix-java-gateway.service [root@lb01 ~/zabbix-5.0.47]#netstat -tnulp #10052端口 tcp6 0 0 :::10052 :::* LISTEN 17352/java 3.服务端配置java网关 [root@zabbix ~/zabbix-5.0.47]#vim /usr/local/etc/zabbix_server.conf 291 JavaGateway=10.0.0.5 299 JavaGatewayPort=10052 307 StartJavaPollers=2 [root@zabbix ~/zabbix-5.0.47]#systemctl restart zabbix.service
3、页面配置

image

image

image

21、监控文件被篡改

bash
#1.创建文件 [root@web01 ~]#echo aaa >a.txt [root@web01 ~]#cat a.txt aaa #2.地址修改为71 [root@web01 ~]#grep 172.16.1.81 /etc/zabbix_agentd.conf Server=172.16.1.71 ServerActive=172.16.1.71 #3.重启 [root@web01 ~]# systemctl restart zabbix-agent.service 创建主机

image

bash
# 迟迟不生效,服务端获取值测试 [root@zabbix ~/zabbix-5.0.47]# zabbix_get -s 172.16.1.7 -k php_idle 5 # 发现权限不足,原因是zabbix访问root目录没有权限 [root@zabbix ~/zabbix-5.0.47]# zabbix_get -s 172.16.1.7 -k vfs.file.cksum[/root/a.txt] ZBX_NOTSUPPORTED: Cannot open file: [13] Permission denied 提权再移动 [root@web01 ~]#chown zabbix.zabbix /tmp/a.txt [root@web01 ~]#mv a.txt /tmp # 服务端可以正常获取 [root@zabbix ~/zabbix-5.0.47]# zabbix_get -s 172.16.1.7 -k vfs.file.cksum[/tmp/a.txt] 563241142

创建监控项

image

查看最新数据

image

创建触发器

image

bash
修改a.txt测试 [root@web01 /tmp]#echo lll > a.txt

image

22、zabbix优化

bash
1.高并发需要对MySQL进行拆分 2.zabbix-agent被动上传修改为主动上报模式 3.地区较多情况尽量或者网络复杂情况使用proxy代理模式 4.系统自带监控项优化 5.进程优化,自带的zabbix_server 6.缓存优化 面试题:zabbix监控过哪些内容 1.监控主机硬件信息内存CPU、负载磁盘IO 2.监控系统重要的配置文件、代码文件防黑客篡改 3.监控服务是否正常(通过取端口号或者进程号) 4.监控服务,软件业务的状态信息(nginx状态信息数据库的状态信息增删改查订单量慢查询) 5.监控业务调用接口 curl状态返回 6.业务数据监控日志监控。日志状态码客户端IP地址

image

image

本文作者:张龙龙

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!