秋月无边
IP:
0关注数
0粉丝数
0获得的赞
工作年
编辑资料
链接我:

创作·50

全部
问答
动态
项目
学习
专栏
秋月无边

12. 网络性能优化的几个思路(下)将顺着 TCP/IP 网络模型,继续向下,看看如何从传输层、网络

上一篇在优化网络的性能时,可以结合 Linux 系统的网络协议栈和网络收发流程,然后从应用程序、套接字、传输层、网络层再到链路层等每个层次,进行逐层优化。主要学习了应用程序和套接字的优化思路,比如:在应用程序中,主要优化 I/O 模型、工作模型以及应用层的网络协议;在套接字层中,主要优化套接字的缓冲区大小。这篇文章将顺着 TCP/IP 网络模型,继续向下,看看如何从传输层、网络层以及链路层中,优化 Linux 网络性能。网络性能优化传输层传输层最重要的是 TCP 和 UDP 协议,所以这儿的优化,其实主要就是对这两种协议的优化。我们首先来看TCP协议的优化。TCP 提供了面向连接的可靠传输服务。要优化 TCP,我们首先要掌握 TCP 协议的基本原理,比如流量控制、慢启动、拥塞避免、延迟确认以及状态流图(如下图所示)等。img掌握这些原理后,就可以在不破坏 TCP 正常工作的基础上,对它进行优化。下面,分几类情况详细说明。第一类,在请求数比较大的场景下,可能会看到大量处于 TIME_WAIT 状态的连接,它们会占用大量内存和端口资源。这时,我们可以优化与 TIME_WAIT 状态相关的内核选项,比如采取下面几种措施。增大处于 TIME_WAIT 状态的连接数量 net.ipv4.tcp_max_tw_buckets ,并增大连接跟踪表的大小 net.netfilter.nf_conntrack_max。减小 net.ipv4.tcp_fin_timeout 和 net.netfilter.nf_conntrack_tcp_timeout_time_wait ,让系统尽快释放它们所占用的资源。开启端口复用 net.ipv4.tcp_tw_reuse。这样,被 TIME_WAIT 状态占用的端口,还能用到新建的连接中。增大本地端口的范围 net.ipv4.ip_local_port_range 。这样就可以支持更多连接,提高整体的并发能力。增加最大文件描述符的数量。你可以使用 fs.nr_open 和 fs.file-max ,分别增大进程和系统的最大文件描述符数;或在应用程序的 systemd 配置文件中,配置 LimitNOFILE ,设置应用程序的最大文件描述符数。第二类,为了缓解 SYN FLOOD 等,利用 TCP 协议特点进行攻击而引发的性能问题,你可以考虑优化与 SYN 状态相关的内核选项,比如采取下面几种措施。增大 TCP 半连接的最大数量 net.ipv4.tcp_max_syn_backlog ,或者开启 TCP SYN Cookies net.ipv4.tcp_syncookies ,来绕开半连接数量限制的问题(注意,这两个选项不可同时使用)。减少 SYN_RECV 状态的连接重传 SYN+ACK 包的次数 net.ipv4.tcp_synack_retries。第三类,在长连接的场景中,通常使用 Keepalive 来检测 TCP 连接的状态,以便对端连接断开后,可以自动回收。但是,系统默认的 Keepalive 探测间隔和重试次数,一般都无法满足应用程序的性能要求。所以,这时候需要优化与 Keepalive 相关的内核选项,比如:缩短最后一次数据包到 Keepalive 探测包的间隔时间 net.ipv4.tcp_keepalive_time;缩短发送 Keepalive 探测包的间隔时间 net.ipv4.tcp_keepalive_intvl;减少Keepalive 探测失败后,一直到通知应用程序前的重试次数 net.ipv4.tcp_keepalive_probes。整理成表格如下:(数值仅供参考,具体配置还要结合你的实际场景来调整):img优化 TCP 性能时,还要注意,如果同时使用不同优化方法,可能会产生冲突。比如,服务器端开启 Nagle 算法,而客户端开启延迟确认机制,就很容易导致网络延迟增大。另外,在使用 NAT 的服务器上,如果开启 net.ipv4.tcp_tw_recycle ,就很容易导致各种连接失败。实际上,由于坑太多,这个选项在内核的 4.1 版本中已经删除了。说完TCP,我们再来看 UDP 的优化。UDP 提供了面向数据报的网络协议,它不需要网络连接,也不提供可靠性保障。所以,UDP 优化,相对于 TCP 来说,要简单得多。常见的几种优化方案如下跟上篇套接字部分提到的一样,增大套接字缓冲区大小以及 UDP 缓冲区范围;跟前面 TCP 部分提到的一样,增大本地端口号的范围;根据 MTU 大小,调整 UDP 数据包的大小,减少或者避免分片的发生。网络层接下来,我们再来看网络层的优化。网络层,负责网络包的封装、寻址和路由,包括 IP、ICMP 等常见协议。在网络层,最主要的优化,其实就是对路由、 IP 分片以及 ICMP 等进行调优。第一种,从路由和转发的角度出发,你可以调整下面的内核选项。在需要转发的服务器中,比如用作 NAT 网关的服务器或者使用 Docker 容器时,开启 IP 转发,即设置 net.ipv4.ip_forward = 1。调整数据包的生存周期 TTL,比如设置 net.ipv4.ip_default_ttl = 64。注意,增大该值会降低系统性能。开启数据包的反向地址校验,比如设置 net.ipv4.conf.eth0.rp_filter = 1。这样可以防止 IP 欺骗,并减少伪造 IP 带来的 DDoS 问题。第二种,从分片的角度出发,最主要的是调整 MTU(Maximum Transmission Unit)的大小。通常,MTU 的大小应该根据以太网的标准来设置。以太网标准规定,一个网络帧最大为 1518B,那么去掉以太网头部的 18B 后,剩余的 1500 就是以太网 MTU 的大小。在使用 VXLAN、GRE 等叠加网络技术时,要注意,网络叠加会使原来的网络包变大,导致 MTU 也需要调整。比如,就以 VXLAN 为例,它在原来报文的基础上,增加了 14B 的以太网头部、 8B 的 VXLAN 头部、8B 的 UDP 头部以及 20B 的 IP 头部。换句话说,每个包比原来增大了 50B。所以,我们就需要把交换机、路由器等的 MTU,增大到 1550, 或者把 VXLAN 封包前(比如虚拟化环境中的虚拟网卡)的 MTU 减小为 1450。另外,现在很多网络设备都支持巨帧,如果是这种环境,还可以把 MTU 调大为 9000,以提高网络吞吐量。第三种,从 ICMP 的角度出发,为了避免 ICMP 主机探测、ICMP Flood 等各种网络问题,可以通过内核选项,来限制 ICMP 的行为。比如,禁止 ICMP 协议,即设置 net.ipv4.icmp_echo_ignore_all = 1。这样,外部主机就无法通过 ICMP 来探测主机。或者,禁止广播 ICMP,即设置 net.ipv4.icmp_echo_ignore_broadcasts = 1。链路层网络层的下面是链路层,所以最后,我们再来看链路层的优化方法。链路层负责网络包在物理网络中的传输,比如 MAC 寻址、错误侦测以及通过网卡传输网络帧等。自然,链路层的优化,也是围绕这些基本功能进行的。接下来,我们从不同的几个方面分别来看。由于网卡收包后调用的中断处理程序(特别是软中断),需要消耗大量的 CPU。所以,将这些中断处理程序调度到不同的 CPU 上执行,就可以显著提高网络吞吐量。这通常可以采用下面两种方法。为网卡硬中断配置 CPU 亲和性(smp_affinity),或者开启 irqbalance 服务。开启 RPS(Receive Packet Steering)和 RFS(Receive Flow Steering),将应用程序和软中断的处理,调度到相同CPU 上,这样就可以增加 CPU 缓存命中率,减少网络延迟。另外,现在的网卡都有很丰富的功能,原来在内核中通过软件处理的功能,可以卸载到网卡中,通过硬件来执行。TSO(TCP Segmentation Offload)和 UFO(UDP Fragmentation Offload):在 TCP/UDP 协议中直接发送大包;而TCP 包的分段(按照 MSS 分段)和 UDP 的分片(按照 MTU 分片)功能,由网卡来完成 。GSO(Generic Segmentation Offload):在网卡不支持 TSO/UFO 时,将 TCP/UDP 包的分段,延迟到进入网卡前再执行。这样,不仅可以减少 CPU 的消耗,还可以在发生丢包时只重传分段后的包。LRO(Large Receive Offload):在接收 TCP 分段包时,由网卡将其组装合并后,再交给上层网络处理。不过要注意,在需要 IP 转发的情况下,不能开启 LRO,因为如果多个包的头部信息不一致,LRO 合并会导致网络包的校验错误。GRO(Generic Receive Offload):GRO 修复了 LRO 的缺陷,并且更为通用,同时支持 TCP 和 UDP。RSS(Receive Side Scaling):也称为多队列接收,它基于硬件的多个接收队列,来分配网络接收进程,这样可以让多个 CPU 来处理接收到的网络包。VXLAN 卸载:也就是让网卡来完成 VXLAN 的组包功能。最后,对于网络接口本身,也有很多方法,可以优化网络的吞吐量。开启网络接口的多队列功能(todo)。这样,每个队列就可以用不同的中断号,调度到不同 CPU 上执行,从而提升网络的吞吐量。增大网络接口的缓冲区大小,以及队列长度等,提升网络传输的吞吐量(注意,这可能导致延迟增大)。使用 Traffic Control 工具,为不同网络流量配置 QoS。对于吞吐量要求高的场景,可以用两种方式来优化。第一种,使用 DPDK 技术,跳过内核协议栈,直接由用户态进程用轮询的方式,来处理网络请求。同时,再结合大页、CPU 绑定、内存对齐、流水线并发等多种机制,优化网络包的处理效率。第二种,使用内核自带的 XDP 技术,在网络包进入内核协议栈前,就对其进行处理,这样也可以实现很好的性能。小结通过这两篇文章,我们梳理了常见的 Linux 网络性能优化方法。在优化网络的性能时,我们可以结合 Linux 系统的网络协议栈和网络收发流程,从应用程序、套接字、传输层、网络层再到链路层等,对每个层次进行逐层优化。实际上,我们分析和定位网络瓶颈,也是基于这些网络层进行的。而定位出网络性能瓶颈后,我们就可以根据瓶颈所在的协议层,进行优化。具体而言:在应用程序中,主要是优化 I/O 模型、工作模型以及应用层的网络协议;在套接字层中,主要是优化套接字的缓冲区大小;在传输层中,主要是优化 TCP 和 UDP 协议;在网络层中,主要是优化路由、转发、分片以及 ICMP 协议;最后,在链路层中,主要是优化网络包的收发、网络功能卸载以及网卡选项。工作模型以及应用层的网络协议;在套接字层中,主要是优化套接字的缓冲区大小;在传输层中,主要是优化 TCP 和 UDP 协议;在网络层中,主要是优化路由、转发、分片以及 ICMP 协议;最后,在链路层中,主要是优化网络包的收发、网络功能卸载以及网卡选项。如果这些方法依然不能满足要求,那就可以考虑,使用 DPDK 等用户态方式,绕过内核协议栈;或者,使用 XDP,在网络包进入内核协议栈前进行处理。
0
0
0
浏览量2013
秋月无边

5.DNS基本介绍与性能排查问题

IP 地址是 TCP/IP 协议中,用来确定通信双方的一个重要标识。每个 IP 地址又包括了主机号和网络号两部分。相同网络号的主机组成一个子网;不同子网再通过路由器连接,组成一个庞大的网络。然而,IP 地址虽然方便了机器的通信,却给访问这些服务的人们,带来了很重的记忆负担。我相信,没几个人能记得住 GitHub 所在的 IP 地址,因为这串字符,对人脑来说并没有什么含义,不符合我们的记忆逻辑。不过,这并不妨碍我们经常使用这个服务。为什么呢?当然是因为还有更简单、方便的方式。我们可以通过域名 github.com 访问,而不是必须依靠具体的 IP 地址,这其实正是域名系统 DNS 的由来。DNS(Domain Name System),即域名系统,是互联网中最基础的一项服务,主要提供域名和 IP 地址之间映射关系的查询服务。DNS 不仅方便了人们访问不同的互联网服务,更为很多应用提供了,动态服务发现和全局负载均衡(Global Server Load Balance,GSLB)的机制。这样,DNS 就可以选择离用户最近的 IP 来提供服务。即使后端服务的 IP 地址发生变化,用户依然可以用相同域名来访问。DNS显然是我们工作中基础而重要的一个环节。那么,DNS 出现问题时,又该如何分析和排查呢?域名与 DNS 解析域名我们本身都比较熟悉,由一串用点分割开的字符组成,被用作互联网中的某一台或某一组计算机的名称,目的就是为了方便识别,互联网中提供各种服务的主机位置。要注意,域名是全球唯一的,需要通过专门的域名注册商才可以申请注册。为了组织全球互联网中的众多计算机,域名同样用点来分开,形成一个分层的结构。而每个被点分割开的字符串,就构成了域名中的一个层级,并且位置越靠后,层级越高。我们以极客时间的网站 time.geekbang.org 为例,来理解域名的含义。这个字符串中,最后面的 org 是顶级域名,中间的 geekbang 是二级域名,而最左边的 time 则是三级域名。如下图所示,注意点(.)是所有域名的根,也就是说所有域名都以点作为后缀,也可以理解为,在域名解析的过程中,所有域名都以点结束。通过理解这几个概念,可以看出,域名主要是为了方便让人记住,而IP 地址是机器间的通信的真正机制。把域名转换为 IP 地址的服务,就是域名解析服务(DNS),而对应的服务器就是域名服务器,网络协议则是 DNS 协议。这里注意,DNS 协议在 TCP/IP 栈中属于应用层,不过实际传输还是基于 UDP 或者 TCP 协议(UDP 居多) ,并且域名服务器一般监听在端口 53 上。既然域名以分层的结构进行管理,相对应的,域名解析其实也是用递归的方式(从顶级开始,以此类推),发送给每个层级的域名服务器,直到得到解析结果。递归查询的过程并不需要亲自操作,由DNS 服务器完成,用户只需要预先配置一个可用的 DNS 服务器就可以了。通常来说,每级DNS 服务器,都会有最近解析记录的缓存。当缓存命中时,直接用缓存中的记录应答就可以了。如果缓存过期或者不存在,才需要用刚刚提到的递归方式查询。所以,系统管理员在配置 Linux 系统的网络时,除了需要配置 IP 地址,还需要给它配置 DNS 服务器,这样它才可以通过域名来访问外部服务。比如,我的系统配置的就是 114.114.114.114 这个域名服务器。可以执行下面的命令,来查询你的系统配置:$ cat /etc/resolv.conf nameserver 114.114.114.114另外,DNS 服务通过资源记录的方式,来管理所有数据,它支持 A、CNAME、MX、NS、PTR 等多种类型的记录。比如:A 记录,用来把域名转换成 IP 地址;CNAME 记录,用来创建别名;而 NS 记录,则表示该域名对应的域名服务器地址。当我们访问某个网址时,就需要通过 DNS 的 A 记录,查询该域名对应的 IP 地址,然后再通过该 IP 来访问 Web 服务。比如,以极客时间的网站 time.geekbang.org 为例,执行下面的 nslookup 命令,就可以查询到这个域名的 A 记录,可以看到,它的 IP 地址是 39.106.233.176:$ nslookup time.geekbang.org # 域名服务器及端口信息 Server: 114.114.114.114 Address: 114.114.114.114#53 # 非权威查询结果 Non-authoritative answer: Name: time.geekbang.org Address: 39.106.233.17这里要注意,由于 114.114.114.114 并不是直接管理 time.geekbang.org 的域名服务器,所以查询结果是非权威的。使用上面的命令,你只能得到 114.114.114.114 查询的结果。前面还提到了,如果没有命中缓存,DNS 查询实际上是一个递归过程,那有没有方法可以知道整个递归查询的执行呢?其实除了 nslookup,另外一个常用的 DNS 解析工具 dig ,就提供了 trace 功能,可以展示递归查询的整个过程。例如可以执行下面的命令,得到查询结果:# +trace表示开启跟踪查询 # +nodnssec表示禁止DNS安全扩展 $ dig +trace +nodnssec time.geekbang.org ; <<>> DiG 9.11.3-1ubuntu1.3-Ubuntu <<>> +trace +nodnssec time.geekbang.org ;; global options: +cmd . 322086 IN NS m.root-servers.net. . 322086 IN NS a.root-servers.net. . 322086 IN NS i.root-servers.net. . 322086 IN NS d.root-servers.net. . 322086 IN NS g.root-servers.net. . 322086 IN NS l.root-servers.net. . 322086 IN NS c.root-servers.net. . 322086 IN NS b.root-servers.net. . 322086 IN NS h.root-servers.net. . 322086 IN NS e.root-servers.net. . 322086 IN NS k.root-servers.net. . 322086 IN NS j.root-servers.net. . 322086 IN NS f.root-servers.net. ;; Received 239 bytes from 114.114.114.114#53(114.114.114.114) in 1340 ms org. 172800 IN NS a0.org.afilias-nst.info. org. 172800 IN NS a2.org.afilias-nst.info. org. 172800 IN NS b0.org.afilias-nst.org. org. 172800 IN NS b2.org.afilias-nst.org. org. 172800 IN NS c0.org.afilias-nst.info. org. 172800 IN NS d0.org.afilias-nst.org. ;; Received 448 bytes from 198.97.190.53#53(h.root-servers.net) in 708 ms geekbang.org. 86400 IN NS dns9.hichina.com. geekbang.org. 86400 IN NS dns10.hichina.com. ;; Received 96 bytes from 199.19.54.1#53(b0.org.afilias-nst.org) in 1833 ms time.geekbang.org. 600 IN A 39.106.233.176 ;; Received 62 bytes from 140.205.41.16#53(dns10.hichina.com) in 4 msdig trace 的输出,主要包括四部分。第一部分,是从 114.114.114.114 查到的一些根域名服务器(.)的 NS 记录。第二部分,是从 NS 记录结果中选一个(h.root-servers.net),并查询顶级域名 org. 的 NS 记录。第三部分,是从 org. 的 NS 记录中选择一个(b0.org.afilias-nst.org),并查询二级域名 geekbang.org. 的 NS 服务器。最后一部分,就是从 geekbang.org. 的 NS 服务器(dns10.hichina.com)查询最终主机 time.geekbang.org. 的 A 记录。这个输出里展示的各级域名的 NS 记录,其实就是各级域名服务器的地址,流程图如下:不仅仅是发布到互联网的服务需要域名,很多时候,我们也希望能对局域网内部的主机进行域名解析(即内网域名,大多数情况下为主机名)。Linux 也支持这种行为。所以,可以把主机名和 IP 地址的映射关系,写入本机的 /etc/hosts 文件中。这样,指定的主机名就可以在本地直接找到目标 IP。比如,你可以执行下面的命令来操作:$ cat /etc/hosts 127.0.0.1 localhost localhost.localdomain ::1 localhost6 localhost6.localdomain6 192.168.0.100 domain.com或者,你还可以在内网中,搭建自定义的 DNS 服务器,专门用来解析内网中的域名。而内网 DNS 服务器,一般还会设置一个或多个上游 DNS 服务器,用来解析外网的域名。清楚域名与 DNS 解析的基本原理后,接下来,一起来看几个案例,实战分析 DNS 解析出现问题时,该如何定位。案例准备本次案例还是基于 Ubuntu 18.04,同样适用于其他的 Linux 系统。我使用的案例环境如下所示:机器配置:2 CPU,8GB 内存。预先安装 docker 等工具,如 apt install docker.io。先打开一个终端,SSH 登录到 Ubuntu 机器中,然后执行下面的命令,拉取案例中使用的 Docker 镜像:$ docker pull feisky/dnsutils Using default tag: latest ... Status: Downloaded newer image for feisky/dnsutils:latest然后,运行下面的命令,查看主机当前配置的 DNS 服务器:$ cat /etc/resolv.conf nameserver 114.114.114.114可以看到,这台主机配置的 DNS 服务器是 114.114.114.114。到这里,准备工作就完成了。接下来,正式进入操作环节。案例分析案例1: DNS解析失败首先,执行下面的命令,进入今天的第一个案例。将看到下面这个输出:# 进入案例环境的SHELL终端中 $ docker run -it --rm -v $(mktemp):/etc/resolv.conf feisky/dnsutils bash root@7e9ed6ed4974:/#注意:下面的代码段中, /# 开头的命令都表示在容器内部运行的命令。接着,继续在容器终端中,执行 DNS 查询命令,还是查询 time.geekbang.org 的 IP 地址:/# nslookup time.geekbang.org ;; connection timed out; no servers could be reached可以发现,这个命令阻塞很久后,还是失败了,报了 connection timed out 和 no servers could be reached 错误。看到这里,估计你的第一反应就是网络不通了,到底是不是这样呢?我们用 ping 工具检查试试。执行下面的命令,就可以测试本地到 114.114.114.114 的连通性:/# ping -c3 114.114.114.114 PING 114.114.114.114 (114.114.114.114): 56 data bytes 64 bytes from 114.114.114.114: icmp_seq=0 ttl=56 time=31.116 ms 64 bytes from 114.114.114.114: icmp_seq=1 ttl=60 time=31.245 ms 64 bytes from 114.114.114.114: icmp_seq=2 ttl=68 time=31.128 ms --- 114.114.114.114 ping statistics --- 3 packets transmitted, 3 packets received, 0% packet loss round-trip min/avg/max/stddev = 31.116/31.163/31.245/0.058 ms这个输出中,可以看到网络是通的。那要怎么知道nslookup 命令失败的原因呢?这里其实有很多方法,最简单的一种,就是开启 nslookup 的调试输出,查看查询过程中的详细步骤,排查其中是否有异常。比如,我们可以继续在容器终端中,执行下面的命令:/# nslookup -debug time.geekbang.org ;; Connection to 127.0.0.1#53(127.0.0.1) for time.geekbang.org failed: connection refused. ;; Connection to ::1#53(::1) for time.geekbang.org failed: address not available.从这次的输出可以看到,nslookup 连接环回地址(127.0.0.1 和 ::1)的 53 端口失败。这里就有问题了,为什么会去连接环回地址,而不是我们的先前看到的 114.114.114.114 呢?因为容器中没有配置 DNS 服务器。那我们就执行下面的命令确认一下:/# cat /etc/resolv.conf果然,这个命令没有任何输出,说明容器里的确没有配置 DNS 服务器。到这一步,很自然的,我们就知道了解决方法。在 /etc/resolv.conf 文件中,配置上 DNS 服务器就可以了。执行下面的命令,在配置好 DNS 服务器后,重新执行 nslookup 命令。这次可以正常解析了:/# echo "nameserver 114.114.114.114" > /etc/resolv.conf /# nslookup time.geekbang.org Server: 114.114.114.114 Address: 114.114.114.114#53 Non-authoritative answer: Name: time.geekbang.org Address: 39.106.233.176到这里,第一个案例就轻松解决了。最后,在终端中执行 exit 命令退出容器,Docker 就会自动清理刚才运行的容器。案例2: DNS解析不稳定接下来,再来看第二个案例。执行下面的命令,启动一个新的容器,并进入它的终端中:$ docker run -it --rm --cap-add=NET_ADMIN --dns 8.8.8.8 feisky/dnsutils bash root@0cd3ee0c8ecb:/#然后,跟上一个案例一样,还是运行 nslookup 命令,解析 time.geekbang.org 的 IP 地址。不过,这次要加一个 time 命令,输出解析所用时间。如果一切正常,会看到如下输出:/# time nslookup time.geekbang.org Server: 8.8.8.8 Address: 8.8.8.8#53 Non-authoritative answer: Name: time.geekbang.org Address: 39.106.233.176 real 0m10.349s user 0m0.004s sys 0m0.0可以看到,这次解析非常慢,居然用了 10 秒。如果你多次运行上面的 nslookup 命令,可能偶尔还会碰到下面这种错误:/# time nslookup time.geekbang.org ;; connection timed out; no servers could be reached real 0m15.011s user 0m0.006s sys 0m0.006s换句话说,跟上一个案例类似,也会出现解析失败的情况。综合来看,现在 DNS 解析的结果不但比较慢,而且还会发生超时失败的情况。这是为什么呢?碰到这种问题该怎么处理呢?根据前面的讲解,我们知道,DNS 解析,说白了就是客户端与服务器交互的过程,并且这个过程还使用了 UDP 协议。那么,对于整个流程来说,解析结果不稳定,就有很多种可能的情况了。比方说:DNS 服务器本身有问题,响应慢并且不稳定;或者是,客户端到 DNS 服务器的网络延迟比较大;再或者,DNS 请求或者响应包,在某些情况下被链路中的网络设备弄丢了。根据上面 nslookup 的输出,你可以看到,现在客户端连接的DNS 是 8.8.8.8,这是 Google 提供的 DNS 服务。对 Google 我们还是比较放心的,DNS 服务器出问题的概率应该比较小。基本排除了DNS服务器的问题,那是不是第二种可能,本机到 DNS 服务器的延迟比较大呢?前面讲过,ping 可以用来测试服务器的延迟。比如,你可以运行下面的命令:/# ping -c3 8.8.8.8 PING 8.8.8.8 (8.8.8.8): 56 data bytes 64 bytes from 8.8.8.8: icmp_seq=0 ttl=31 time=137.637 ms 64 bytes from 8.8.8.8: icmp_seq=1 ttl=31 time=144.743 ms 64 bytes from 8.8.8.8: icmp_seq=2 ttl=31 time=138.576 ms --- 8.8.8.8 ping statistics --- 3 packets transmitted, 3 packets received, 0% packet loss round-trip min/avg/max/stddev = 137.637/140.319/144.743/3.152 ms从ping 的输出可以看到,这里的延迟已经达到了 140ms,这也就可以解释,为什么解析这么慢了。实际上,如果多次运行上面的 ping 测试,还会看到偶尔出现的丢包现象。$ ping -c3 8.8.8.8 PING 8.8.8.8 (8.8.8.8): 56 data bytes 64 bytes from 8.8.8.8: icmp_seq=0 ttl=30 time=134.032 ms 64 bytes from 8.8.8.8: icmp_seq=1 ttl=30 time=431.458 ms --- 8.8.8.8 ping statistics --- 3 packets transmitted, 2 packets received, 33% packet loss round-trip min/avg/max/stddev = 134.032/282.745/431.458/148.713 ms这也进一步解释了,为什么 nslookup 偶尔会失败,正是网络链路中的丢包导致的。碰到这种问题该怎么办呢?显然,既然延迟太大,那就换一个延迟更小的 DNS 服务器,比如电信提供的 114.114.114.114。配置之前,我们可以先用 ping 测试看看,它的延迟是不是真的比 8.8.8.8 好。执行下面的命令,你就可以看到,它的延迟只有 31ms:/# ping -c3 114.114.114.114 PING 114.114.114.114 (114.114.114.114): 56 data bytes 64 bytes from 114.114.114.114: icmp_seq=0 ttl=67 time=31.130 ms 64 bytes from 114.114.114.114: icmp_seq=1 ttl=56 time=31.302 ms 64 bytes from 114.114.114.114: icmp_seq=2 ttl=56 time=31.250 ms --- 114.114.114.114 ping statistics --- 3 packets transmitted, 3 packets received, 0% packet loss round-trip min/avg/max/stddev = 31.130/31.227/31.302/0.072 ms这个结果表明,延迟的确小了很多。继续执行下面的命令,更换 DNS 服务器,然后,再次执行 nslookup 解析命令:/# echo nameserver 114.114.114.114 > /etc/resolv.conf /# time nslookup time.geekbang.org Server: 114.114.114.114 Address: 114.114.114.114#53 Non-authoritative answer: Name: time.geekbang.org Address: 39.106.233.176 real 0m0.064s user 0m0.007s sys 0m0.006s可以发现,现在只需要 64ms 就可以完成解析,比刚才的 10s 要好很多。到这里,问题看似就解决了。不过,如果你多次运行 nslookup 命令,估计就不是每次都有好结果了。/# time nslookup time.geekbang.org Server: 114.114.114.114 Address: 114.114.114.114#53 Non-authoritative answer: Name: time.geekbang.org Address: 39.106.233.176 real 0m1.045s user 0m0.007s sys 0m0.004s1s 的 DNS 解析时间还是太长了,对很多应用来说也是不可接受的。那么,该怎么解决这个问题呢?那就是使用 DNS 缓存。这样,只有第一次查询时需要去 DNS 服务器请求,以后的查询,只要 DNS 记录不过期,使用缓存中的记录就可以了。不过要注意,我们使用的主流 Linux 发行版,除了最新版本的 Ubuntu (如 18.04 或者更新版本)外,其他版本并没有自动配置 DNS 缓存。所以,想要为系统开启 DNS 缓存,就需要你做额外的配置。比如,最简单的方法,就是使用 dnsmasq。dnsmasq 是最常用的 DNS 缓存服务之一,还经常作为 DHCP 服务来使用。它的安装和配置都比较简单,性能也可以满足绝大多数应用程序对 DNS 缓存的需求。我们继续在刚才的容器终端中,执行下面的命令,就可以启动 dnsmasq:/# /etc/init.d/dnsmasq start * Starting DNS forwarder and DHCP server dnsmasq [ OK ]然后,修改 /etc/resolv.conf,将 DNS 服务器改为 dnsmasq 的监听地址,这儿是 127.0.0.1。接着,重新执行多次 nslookup 命令:/# echo nameserver 127.0.0.1 > /etc/resolv.conf /# time nslookup time.geekbang.org Server: 127.0.0.1 Address: 127.0.0.1#53 Non-authoritative answer: Name: time.geekbang.org Address: 39.106.233.176 real 0m0.492s user 0m0.007s sys 0m0.006s /# time nslookup time.geekbang.org Server: 127.0.0.1 Address: 127.0.0.1#53 Non-authoritative answer: Name: time.geekbang.org Address: 39.106.233.176 real 0m0.011s user 0m0.008s sys 0m0.003snslookup time.geekbang.orgServer: 127.0.0.1Address: 127.0.0.1#53Non-authoritative answer:Name: time.geekbang.orgAddress: 39.106.233.176real 0m0.492suser 0m0.007ssys 0m0.006s/# time nslookup time.geekbang.orgServer: 127.0.0.1Address: 127.0.0.1#53Non-authoritative answer:Name: time.geekbang.orgAddress: 39.106.233.176real 0m0.011suser 0m0.008ssys 0m0.003s现在我们可以看到,只有第一次的解析很慢,需要 0.5s,以后的每次解析都很快,只需要 11ms。
0
0
0
浏览量2011
秋月无边

11. 网络性能优化的几个思路(上)应用层的各种 I/O 模型,冗长的网络协议栈和众多的内核选项,抑

应用层的各种 I/O 模型,冗长的网络协议栈和众多的内核选项,抑或是各种复杂的网络环境,都提高了网络的复杂性。不过,只要掌握了 Linux 网络的基本原理和常见网络协议的工作流程,再结合各个网络层的性能指标来分析,你会发现,定位网络瓶颈并不难。找到网络性能瓶颈后,下一步要做的就是优化了,也就是如何降低网络延迟,并提高网络的吞吐量。接下面我们通过两篇文章分析优化网络性能问题的思路和一些注意事项。确定优化目标我们观察到的网络性能指标,要达到多少才合适呢?实际上,虽然网络性能优化的整体目标,是降低网络延迟(如 RTT)和提高吞吐量(如 BPS 和 PPS),但具体到不同应用中,每个指标的优化标准可能会不同,优先级顺序也大相径庭。就拿上一节提到的 NAT 网关来说,由于其直接影响整个数据中心的网络出入性能,所以 NAT 网关通常需要达到或接近线性转发,也就是说, PPS 是最主要的性能目标。再如,对于数据库、缓存等系统,快速完成网络收发,即低延迟,是主要的性能目标。而对于我们经常访问的 Web 服务来说,则需要同时兼顾吞吐量和延迟。所以,为了更客观合理地评估优化效果,我们首先应该明确优化的标准,即要对系统和应用程序进行基准测试,得到网络协议栈各层的基准性能。img基于上图,在进行基准测试时,我们就可以按照协议栈的每一层来测试。由于底层是其上方各层的基础,底层性能也就决定了高层性能。所以我们要清楚,底层性能指标,其实就是对应高层的极限性能。我们从下到上来理解这一点。首先是网络接口层和网络层,它们主要负责网络包的封装、寻址、路由,以及发送和接收。每秒可处理的网络包数 PPS,就是它们最重要的性能指标(特别是在小包的情况下)。可以用内核自带的发包工具 pktgen ,来测试 PPS 的性能。再向上到传输层的 TCP 和 UDP,它们主要负责网络传输。对它们而言,吞吐量(BPS)、连接数以及延迟,就是最重要的性能指标。我们可以用 iperf 或 netperf ,来测试传输层的性能。不过要注意,网络包的大小,会直接影响这些指标的值。所以,通常,需要测试一系列不同大小网络包的性能。最后,再往上到了应用层,最需要关注的是吞吐量(BPS)、每秒请求数以及延迟等指标。可以用 wrk、ab 等工具,来测试应用程序的性能。不过,这里要注意的是,测试场景要尽量模拟生产环境,这样的测试才更有价值。比如,可以到生产环境中,录制实际的请求情况,再到测试中回放。总之,根据这些基准指标,再结合已经观察到的性能瓶颈,我们就可以明确性能优化的目标。网络性能工具imgimg网络性能优化总的来说,先要获得网络基准测试报告,然后通过相关性能工具,定位出网络性能瓶颈。再接下来的优化工作,就是水到渠成的事情了。Linux 系统的网络协议栈和网络收发流程如下:img接下来,我们就可以从应用程序、套接字、传输层、网络层以及链路层等几个角度,分别来看网络性能优化的基本思路。应用程序应用程序,通常通过套接字接口进行网络操作。由于网络收发通常比较耗时,所以应用程序的优化,主要就是对网络 I/O 和进程自身的工作模型的优化。从网络 I/O 的角度来说,主要有下面两种优化思路。第一种是最常用的 I/O 多路复用技术 epoll,主要用来取代 select 和 poll。这其实是解决 C10K 问题的关键,也是目前很多网络应用默认使用的机制。第二种是使用异步 I/O(Asynchronous I/O,AIO)。AIO 允许应用程序同时发起很多 I/O 操作,而不用等待这些操作完成。等到 I/O完成后,系统会用事件通知的方式,告诉应用程序结果。不过,AIO 的使用比较复杂,你需要小心处理很多边缘情况。而从进程的工作模型来说,也有两种不同的模型用来优化。第一种,主进程+多个 worker 子进程。其中,主进程负责管理网络连接,而子进程负责实际的业务处理。这也是最常用的一种模型。第二种,监听到相同端口的多进程模型。在这种模型下,所有进程都会监听相同接口,并且开启 SO_REUSEPORT 选项,由内核负责,把请求负载均衡到这些监听进程中去。除了网络 I/O 和进程的工作模型外,应用层的网络协议优化,也是至关重要的一点。常见的几种优化方法如下:使用长连接取代短连接,可以显著降低 TCP 建立连接的成本。在每秒请求次数较多时,这样做的效果非常明显。使用内存等方式,来缓存不常变化的数据,可以降低网络 I/O 次数,同时加快应用程序的响应速度。使用 Protocol Buffer 等序列化的方式,压缩网络 I/O 的数据量,可以提高应用程序的吞吐。使用 DNS 缓存、预取、HTTPDNS 等方式,减少 DNS 解析的延迟,也可以提升网络 I/O 的整体速度。套接字套接字可以屏蔽掉 Linux 内核中不同协议的差异,为应用程序提供统一的访问接口。每个套接字,都有一个读写缓冲区。读缓冲区,缓存了远端发过来的数据。如果读缓冲区已满,就不能再接收新的数据。写缓冲区,缓存了要发出去的数据。如果写缓冲区已满,应用程序的写操作就会被阻塞。所以,为了提高网络的吞吐量,你通常需要调整这些缓冲区的大小。比如:增大每个套接字的缓冲区大小 net.core.optmem_max;增大套接字接收缓冲区大小 net.core.rmem_max 和发送缓冲区大小 net.core.wmem_max;增大 TCP 接收缓冲区大小 net.ipv4.tcp_rmem 和发送缓冲区大小 net.ipv4.tcp_wmem。套接字的内核选项如下:img有几点需要注意。tcp_rmem 和 tcp_wmem 的三个数值分别是 min,default,max,系统会根据这些设置,自动调整TCP接收/发送缓冲区的大小。udp_mem 的三个数值分别是 min,pressure,max,系统会根据这些设置,自动调整UDP发送缓冲区的大小。表格中的数值只提供参考价值,具体应该设置多少,还需要根据实际的网络状况来确定。比如,发送缓冲区大小,理想数值是吞吐量*延迟,这样才可以达到最大网络利用率。除此之外,套接字接口还提供了一些配置选项,用来修改网络连接的行为:为 TCP 连接设置 TCP_NODELAY 后,就可以禁用 Nagle 算法;为 TCP 连接开启 TCP_CORK 后,可以让小包聚合成大包后再发送(注意会阻塞小包的发送);使用 SO_SNDBUF 和 SO_RCVBUF ,可以分别调整套接字发送缓冲区和接收缓冲区的大小。小结在优化网络性能时,可以结合 Linux 系统的网络协议栈和网络收发流程,然后从应用程序、套接字、传输层、网络层再到链路层等,进行逐层优化。定位出性能瓶颈后,就可以根据瓶颈所在的协议层进行优化。这篇文章主要讲解了应用程序和套接字的优化思路:在应用程序中,主要优化 I/O 模型、工作模型以及应用层的网络协议;在套接字层中,主要优化套接字的缓冲区大小。络层再到链路层等,进行逐层优化。定位出性能瓶颈后,就可以根据瓶颈所在的协议层进行优化。这篇文章主要讲解了应用程序和套接字的优化思路:在应用程序中,主要优化 I/O 模型、工作模型以及应用层的网络协议;在套接字层中,主要优化套接字的缓冲区大小。
0
0
0
浏览量2010
秋月无边

2.性能指标Linux网络根据TCP/IP模型,构建其网络协议栈。TCP/IP 模型由应用层、传输层

上一篇学习了 Linux 网络的基础原理。Linux 网络根据 TCP/IP 模型,构建其网络协议栈。TCP/IP 模型由应用层、传输层、网络层、网络接口层等四层组成,这也是 Linux 网络栈最核心的构成部分。应用程序通过套接字接口发送数据包时,先要在网络协议栈中从上到下逐层处理,然后才最终送到网卡发送出去;而接收数据包时,也要先经过网络栈从下到上的逐层处理,最后送到应用程序。了解Linux 网络的基本原理和收发流程后,如何去观察网络的性能情况。具体而言,哪些指标可以用来衡量 Linux 的网络性能呢?性能指标实际上,我们通常用带宽、吞吐量、延时、PPS(Packet Per Second)等指标衡量网络的性能。带宽,表示链路的最大传输速率,单位通常为 b/s (比特/秒)。吞吐量,表示单位时间内成功传输的数据量,单位通常为 b/s(比特/秒)或者 B/s(字节/秒)。吞吐量受带宽限制,而吞吐量/带宽,也就是该网络的使用率。延时,表示从网络请求发出后,一直到收到远端响应,所需要的时间延迟。在不同场景中,这一指标可能会有不同含义。比如,它可以表示,建立连接需要的时间(比如 TCP 握手延时),或一个数据包往返所需的时间(比如 RTT)。PPS,是 Packet Per Second(包/秒)的缩写,表示以网络包为单位的传输速率。PPS 通常用来评估网络的转发能力,比如硬件交换机,通常可以达到线性转发(即 PPS 可以达到或者接近理论最大值)。而基于 Linux 服务器的转发,则容易受网络包大小的影响。除了这些指标, 网络的可用性(网络能否正常通信)、 并发连接数(TCP连接数量)、 丢包率(丢包百分比)、 重传率(重新传输的网络包比例)等也是常用的性能指标。接下来,打开一个终端,SSH登录到服务器上,然后一起来探索这些性能指标。网络配置分析网络问题的第一步,通常是查看网络接口的配置和状态。可以使用 ifconfig 或者 ip 命令,来查看网络的配置。更推荐使用 ip 工具,因为它提供了更丰富的功能和更易用的接口。ifconfig 和 ip 分别属于软件包 net-tools 和 iproute2,iproute2 是 net-tools 的下一代。通常情况下它们会在发行版中默认安装。但如果你找不到 ifconfig 或者 ip 命令,可以安装这两个软件包。以网络接口 eth0 为例,你可以运行下面的两个命令,查看它的配置和状态:$ ifconfig eth0 eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 10.240.0.30 netmask 255.240.0.0 broadcast 10.255.255.255 inet6 fe80::20d:3aff:fe07:cf2a prefixlen 64 scopeid 0x20<link> ether 78:0d:3a:07:cf:3a txqueuelen 1000 (Ethernet) RX packets 40809142 bytes 9542369803 (9.5 GB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 32637401 bytes 4815573306 (4.8 GB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 $ ip -s addr show dev eth0 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000 link/ether 78:0d:3a:07:cf:3a brd ff:ff:ff:ff:ff:ff inet 10.240.0.30/12 brd 10.255.255.255 scope global eth0 valid_lft forever preferred_lft forever inet6 fe80::20d:3aff:fe07:cf2a/64 scope link valid_lft forever preferred_lft forever RX: bytes packets errors dropped overrun mcast 9542432350 40809397 0 0 0 193 TX: bytes packets errors dropped carrier collsns 4815625265 32637658 0 0 0 0 可以看到,ifconfig 和 ip 命令输出的指标基本相同,只是显示格式略微不同。比如,它们都包括了网络接口的状态标志、MTU 大小、IP、子网、MAC 地址以及网络包收发的统计信息。这些具体指标的含义,在文档中都有详细的说明,不过,这里有几个跟网络性能密切相关的指标,需要特别关注一下。第一,网络接口的状态标志。ifconfig 输出中的 RUNNING ,或 ip 输出中的 LOWER_UP ,都表示物理网络是连通的,即网卡已经连接到了交换机或者路由器中。如果你看不到它们,通常表示网线被拔掉了。第二,MTU 的大小。MTU 默认大小是 1500,根据网络架构的不同(比如是否使用了 VXLAN 等叠加网络),你可能需要调大或者调小 MTU 的数值。第三,网络接口的 IP 地址、子网以及 MAC 地址。这些都是保障网络功能正常工作所必需的,你需要确保配置正确。第四,网络收发的字节数、包数、错误数以及丢包情况,特别是 TX 和 RX 部分的 errors、dropped、overruns、carrier 以及 collisions 等指标不为 0 时,通常表示出现了网络 I/O 问题。其中:errors 表示发生错误的数据包数,比如校验错误、帧同步错误等;dropped 表示丢弃的数据包数,即数据包已经收到了 Ring Buffer,但因为内存不足等原因丢包;overruns 表示超限数据包数,即网络 I/O 速度过快,导致 Ring Buffer 中的数据包来不及处理(队列满)而导致的丢包;carrier 表示发生 carrirer 错误的数据包数,比如双工模式不匹配、物理电缆出现问题等;collisions 表示碰撞数据包数。套接字信息ifconfig 和 ip 只显示了网络接口收发数据包的统计信息,但在实际的性能问题中,网络协议栈中的统计信息,我们也必须关注。可以用 netstat 或者 ss 来查看套接字、网络栈、网络接口以及路由表的信息。更推荐使用 ss 来查询网络的连接信息,因为它比 netstat 提供了更好的性能(速度更快)。比如,执行下面的命令,查询套接字信息:# head -n 3 表示只显示前面3行 # -l 表示只显示监听套接字 # -n 表示显示数字地址和端口(而不是名字) # -p 表示显示进程信息 $ netstat -nlp | head -n 3 Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 127.0.0.53:53 0.0.0.0:* LISTEN 840/systemd-resolve # -l 表示只显示监听套接字 # -t 表示只显示 TCP 套接字 # -n 表示显示数字地址和端口(而不是名字) # -p 表示显示进程信息 $ ss -ltnp | head -n 3 State Recv-Q Send-Q Local Address:Port Peer Address:Port LISTEN 0 128 127.0.0.53%lo:53 0.0.0.0:* users:(("systemd-resolve",pid=840,fd=13)) LISTEN 0 128 0.0.0.0:22 0.0.0.0:* users:(("sshd",pid=1459,fd=3))netstat 和 ss 的输出也是类似的,都展示了套接字的状态、接收队列、发送队列、本地地址、远端地址、进程 PID 和进程名称等。其中,接收队列(Recv-Q)和发送队列(Send-Q)需要你特别关注,它们通常应该是 0。当你发现它们不是 0 时,说明有网络包的堆积发生。当然还要注意,在不同套接字状态下,它们的含义不同。当套接字处于连接状态(Established)时,Recv-Q 表示套接字缓冲还没有被应用程序取走的字节数(即接收队列长度)。而 Send-Q 表示还没有被远端主机确认的字节数(即发送队列长度)。当套接字处于监听状态(Listening)时,Recv-Q 表示全连接队列的长度。而 Send-Q 表示全连接队列的最大长度。所谓全连接,是指服务器收到了客户端的 ACK,完成了 TCP 三次握手,然后就会把这个连接挪到全连接队列中。这些全连接中的套接字,还需要被 accept() 系统调用取走,服务器才可以开始真正处理客户端的请求。与全连接队列相对应的,还有一个半连接队列。所谓半连接是指还没有完成 TCP 三次握手的连接,连接只进行了一半。服务器收到了客户端的 SYN 包后,就会把这个连接放到半连接队列中,然后再向客户端发送 SYN+ACK 包。协议栈统计信息类似的,使用 netstat 或 ss ,也可以查看协议栈的信息:$ netstat -s ... Tcp: 3244906 active connection openings 23143 passive connection openings 115732 failed connection attempts 2964 connection resets received 1 connections established 13025010 segments received 17606946 segments sent out 44438 segments retransmitted 42 bad segments received 5315 resets sent InCsumErrors: 42 ... $ ss -s Total: 186 (kernel 1446) TCP: 4 (estab 1, closed 0, orphaned 0, synrecv 0, timewait 0/0), ports 0 Transport Total IP IPv6 * 1446 - - RAW 2 1 1 UDP 2 2 0 TCP 4 3 1这些协议栈的统计信息都很直观。ss 只显示已经连接、关闭、孤儿套接字等简要统计,而netstat 则提供的是更详细的网络协议栈信息。比如,上面 netstat 的输出示例,就展示了 TCP 协议的主动连接、被动连接、失败重试、发送和接收的分段数量等各种信息。网络吞吐和 PPS接下来再来看看如何查看系统当前的网络吞吐量和 PPS。推荐使用 sar,它同时支持排查 CPU、内存和 I/O 。给 sar 增加 -n 参数就可以查看网络的统计信息,比如网络接口(DEV)、网络接口错误(EDEV)、TCP、UDP、ICMP 等等。执行下面的命令,你就可以得到网络接口统计信息:# 数字1表示每隔1秒输出一组数据 $ sar -n DEV 1 Linux 4.15.0-1035 (ubuntu) 01/06/19 _x86_64_ (2 CPU) 13:21:40 IFACE rxpck/s txpck/s rxkB/s txkB/s rxcmp/s txcmp/s rxmcst/s %ifutil 13:21:41 eth0 18.00 20.00 5.79 4.25 0.00 0.00 0.00 0.00 13:21:41 docker0 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 13:21:41 lo 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00这儿输出的指标比较多,我来简单解释下它们的含义。rxpck/s 和 txpck/s 分别是接收和发送的 PPS,单位为包/秒。rxkB/s 和 txkB/s 分别是接收和发送的吞吐量,单位是KB/秒。rxcmp/s 和 txcmp/s 分别是接收和发送的压缩数据包数,单位是包/秒。%ifutil 是网络接口的使用率,即半双工模式下为 (rxkB/s+txkB/s)/Bandwidth,而全双工模式下为 max(rxkB/s, txkB/s)/Bandwidth。其中,Bandwidth 可以用 ethtool 来查询,它的单位通常是 Gb/s 或者 Mb/s,不过注意这里小写字母 b ,表示比特而不是字节。我们通常提到的千兆网卡、万兆网卡等,单位也都是比特。如下为千兆网卡:$ ethtool eth0 | grep Speed Speed: 1000Mb/s连通性和延时最后,通常使用 ping ,来测试远程主机的连通性和延时,而这基于 ICMP 协议。比如,执行下面的命令,就可以测试本机到 114.114.114.114 这个 IP 地址的连通性和延时:# -c3表示发送三次ICMP包后停止$ ping -c3 114.114.114.114 PING 114.114.114.114 (114.114.114.114) 56(84) bytes of data. 64 bytes from 114.114.114.114: icmp_seq=1 ttl=54 time=244 ms 64 bytes from 114.114.114.114: icmp_seq=2 ttl=47 time=244 ms 64 bytes from 114.114.114.114: icmp_seq=3 ttl=67 time=244 ms --- 114.114.114.114 ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 2001ms rtt min/avg/max/mdev = 244.023/244.070/244.105/0.034 msping 的输出,可以分为两部分。第一部分,是每个 ICMP 请求的信息,包括 ICMP 序列号(icmp_seq)、TTL(生存时间,或者跳数)以及往返延时。第二部分,则是三次 ICMP 请求的汇总。比如上面的示例显示,发送了 3 个网络包,并且接收到 3 个响应,没有丢包发生,这说明测试主机到 114.114.114.114 是连通的;平均往返延时(RTT)是 244ms,也就是从发送 ICMP 开始,到接收到 114.114.114.114 回复的确认,总共经历 244ms。小结我们通常使用带宽、吞吐量、延时等指标,来衡量网络的性能;相应的,可以用 ifconfig、netstat、ss、sar、ping 等工具,来查看这些网络的性能指标。
0
0
0
浏览量2099
秋月无边

3.C10K 和 C1000K 回顾 Linux 网络基于 TCP/IP 模型,构建了其网络协议栈,

C10K 和 C1000K 回顾前面内容,学习了 Linux 网络的基础原理以及性能观测方法。Linux 网络基于 TCP/IP 模型,构建了其网络协议栈,把繁杂的网络功能划分为应用层、传输层、网络层、网络接口层四个不同的层次,既解决了网络环境中设备异构的问题,也解耦了网络协议的复杂性。基于 TCP/IP 模型,我们还梳理了 Linux 网络收发流程和相应的性能指标。在应用程序通过套接字接口发送或者接收网络包时,这些网络包都要经过协议栈的逐层处理。我们通常用带宽、吞吐、延迟、PPS 等来衡量网络性能。主要来回顾下经典的 C10K 和 C1000K 问题,以更好理解 Linux 网络的工作原理,并进一步分析,如何做到单机支持 C10M。注意,C10K 和 C1000K 的首字母 C 是 Client 的缩写。C10K 就是单机同时处理 1 万个请求(并发连接1万)的问题,而 C1000K 也就是单机支持处理 100 万个请求(并发连接100万)的问题。C10KC10K 问题 最早由 Dan Kegel 在 1999年提出。那时的服务器还只是 32 位系统,运行着 Linux 2.2 版本(后来又升级到了 2.4 和 2.6,而 2.6 才支持 x86_64),只配置了很少的内存(2GB)和千兆网卡。怎么在这样的系统中支持并发 1 万的请求呢?从资源上来说,对2GB 内存和千兆网卡的服务器来说,同时处理 10000 个请求,只要每个请求处理占用不到 200KB(2GB/10000)的内存和 100Kbit (1000Mbit/10000)的网络带宽就可以。所以,物理资源是足够的,接下来自然是软件的问题,特别是网络的 I/O 模型问题。在 C10K 以前,Linux 中网络处理都用同步阻塞的方式,也就是每个请求都分配一个进程或者线程。请求数只有 100 个时,这种方式自然没问题,但增加到 10000 个请求时,10000 个进程或线程的调度、上下文切换乃至它们占用的内存,都会成为瓶颈。既然每个请求分配一个线程的方式不合适,那么,为了支持 10000 个并发请求,这里就有两个问题需要我们解决。第一,怎样在一个线程内处理多个请求,也就是要在一个线程内响应多个网络 I/O。以前的同步阻塞方式下,一个线程只能处理一个请求,到这里不再适用,是不是可以用非阻塞 I/O 或者异步 I/O 来处理多个网络请求呢?第二,怎么更节省资源地处理客户请求,也就是要用更少的线程来服务这些请求。是不是可以继续用原来的 100 个或者更少的线程,来服务现在的 10000 个请求呢?I/O 模型优化异步、非阻塞 I/O 的解决思路,你应该听说过,其实就是我们在网络编程中经常用到的 I/O 多路复用(I/O Multiplexing)。I/O 多路复用是什么意思呢?别急,详细了解前,我先来讲两种 I/O 事件通知的方式:水平触发和边缘触发,它们常用在套接字接口的文件描述符中。水平触发( LT):只要文件描述符可以非阻塞地执行 I/O ,就会触发通知。也就是说,应用程序可以随时检查文件描述符的状态,然后再根据状态,进行 I/O 操作。边缘触发(ET):只有在文件描述符的状态发生改变(也就是 I/O 请求达到)时,才发送一次通知。这时候,应用程序需要尽可能多地执行 I/O,直到无法继续读写,才可以停止。如果 I/O 没执行完,或者因为某种原因没来得及处理,那么这次通知也就丢失了。应用场景:select/poll是LT模式,epoll默认使用的也是水平触发模式(LT)。 目前业界对于ET的最佳实践大概就是Nginx了,单线程redis也是使用的LTLT:文件描述符准备就绪时(FD关联的读缓冲区不为空,可读。写缓冲区还没满,可写),触发通知。ET:当FD关联的缓冲区发生变化时(例如:读缓冲区由空变为非空,有新数据达到,可读。写缓冲区满变有空间了,有数据被发送走,可写),触发通知,仅此一次接下来,再回过头来看 I/O 多路复用的方法。第一种,使用非阻塞 I/O 和水平触发通知,比如使用 select 或者 poll。根据刚才水平触发的原理,select 和 poll 需要从文件描述符列表中,找出哪些可以执行 I/O ,然后进行真正的网络 I/O 读写。由于 I/O 是非阻塞的,一个线程中就可以同时监控一批套接字的文件描述符,这样就达到了单线程处理多请求的目的。所以,这种方式的最大优点,是对应用程序比较友好,它的 API 非常简单。但是,应用软件使用 select 和 poll 时,需要对这些文件描述符列表进行轮询,这样,请求数多的时候就会比较耗时。并且,select 和 poll 还有一些其他的限制。select 使用固定长度的位相量,表示文件描述符的集合,因此会有最大描述符数量的限制。比如,在 32 位系统中,默认限制是 1024。并且,在 select 内部,检查套接字状态是用轮询的方法,处理耗时跟描述符数量是 O(N) 的关系。而 poll 改进了 select 的表示方法,换成了一个没有固定长度的数组,这样就没有了最大描述符数量的限制(当然还会受到系统文件描述符限制)。但应用程序在使用 poll 时,同样需要对文件描述符列表进行轮询,这样,处理耗时跟描述符数量就是 O(N) 的关系。除此之外,应用程序每次调用 select 和 poll 时,还需要把文件描述符的集合,从用户空间传入内核空间,由内核修改后,再传出到用户空间中。这一来一回的内核空间与用户空间切换,也增加了处理成本。有没有什么更好的方式来处理呢?答案自然是肯定的。第二种,使用非阻塞 I/O 和边缘触发通知,比如 epoll。既然 select 和 poll 有那么多的问题,就需要继续对其进行优化,而 epoll 就很好地解决了这些问题。epoll 使用红黑树,在内核中管理文件描述符的集合,这样,就不需要应用程序在每次操作时都传入、传出这个集合。epoll 使用事件驱动的机制,只关注有 I/O 事件发生的文件描述符,不需要轮询扫描整个集合。不过要注意,epoll 是在 Linux 2.6 中才新增的功能(2.4 虽然也有,但功能不完善)。由于边缘触发只在文件描述符可读或可写事件发生时才通知,那么应用程序就需要尽可能多地执行 I/O,并要处理更多的异常事件。第三种,使用异步 I/O(Asynchronous I/O,简称为 AIO)。在前面文件系统原理的内容中,我曾介绍过异步I/O 与同步 I/O 的区别。异步I/O 允许应用程序同时发起很多 I/O 操作,而不用等待这些操作完成。而在 I/O完成后,系统会用事件通知(比如信号或者回调函数)的方式,告诉应用程序。这时,应用程序才会去查询 I/O 操作的结果。异步 I/O 也是到了 Linux 2.6 才支持的功能,并且在很长时间里都处于不完善的状态,比如 glibc 提供的异步 I/O 库,就一直被社区诟病。同时,由于异步 I/O 跟我们的直观逻辑不太一样,想要使用的话,一定要小心设计,其使用难度比较高。工作模型优化了解了 I/O 模型后,请求处理的优化就比较直观了。使用 I/O 多路复用后,就可以在一个进程或线程中处理多个请求,其中,又有下面两种不同的工作模型。第一种,主进程+多个 worker 子进程,这也是最常用的一种模型。这种方法的一个通用工作模式就是:主进程执行 bind() + listen() 后,创建多个子进程;然后,在每个子进程中,都通过 accept() 或 epoll_wait() ,来处理相同的套接字。比如,最常用的反向代理服务器 Nginx 就是这么工作的。它也是由主进程和多个 worker 进程组成。主进程主要用来初始化套接字,并管理子进程的生命周期;而 worker 进程,则负责实际的请求处理。关系如下。​这里要注意,accept() 和 epoll_wait() 调用,还存在一个惊群的问题。换句话说,当网络 I/O 事件发生时,多个进程被同时唤醒,但实际上只有一个进程来响应这个事件,其他被唤醒的进程都会重新休眠。其中,accept() 的惊群问题,已经在 Linux 2.6 中解决了;而 epoll 的问题,到了 Linux 4.5 ,才通过 EPOLLEXCLUSIVE 解决。为了避免惊群问题, Nginx 在每个 worker 进程中,都增加一个了全局锁(accept_mutex)。这些 worker 进程需要首先竞争到锁,只有竞争到锁的进程,才会加入到 epoll 中,这样就确保只有一个 worker 子进程被唤醒。进程的管理、调度、上下文切换的成本非常高。那为什么使用多进程模式的 Nginx ,却具有非常好的性能呢?这里最主要的一个原因就是,这些 worker 进程,实际上并不需要经常创建和销毁,而是在没任务时休眠,有任务时唤醒。只有在 worker 由于某些异常退出时,主进程才需要创建新的进程来代替它。当然,也可以用线程代替进程:主线程负责套接字初始化和子线程状态的管理,而子线程则负责实际的请求处理。由于线程的调度和切换成本比较低,实际上可以进一步把 epoll_wait() 都放到主线程中,保证每次事件都只唤醒主线程,而子线程只需要负责后续的请求处理。第二种,监听到相同端口的多进程模型。在这种方式下,所有的进程都监听相同的接口,并且开启 SO_REUSEPORT 选项,由内核负责将请求负载均衡到这些监听进程中去。这一过程如下图所示。由于内核确保了只有一个进程被唤醒,就不会出现惊群问题了。比如,Nginx 在 1.9.1 中就已经支持了这种模式。要注意想要使用SO_REUSEPORT选项,需要用 Linux 3.9 以上的版本才可以。C1000K基于 I/O 多路复用和请求处理的优化,C10K 问题很容易就可以解决。不过,随着摩尔定律带来的服务器性能提升,以及互联网的普及,新兴服务会对性能提出更高的要求。很快,原来的 C10K 已经不能满足需求,所以又有了 C100K 和 C1000K,也就是并发从原来的 1 万增加到10 万、乃至 100 万。从 1 万到 10 万,其实还是基于 C10K 的这些理论,epoll 配合线程池,再加上 CPU、内存和网络接口的性能和容量提升。大部分情况下,C100K 很自然就可以达到。那么,再进一步,C1000K 是不是也可以很容易就实现呢?这其实没有那么简单了。首先从物理资源使用上来说,100 万个请求需要大量的系统资源。比如,假设每个请求需要 16KB 内存的话,那么总共就需要大约 15 GB 内存。而从带宽上来说,假设只有 20% 活跃连接,即使每个连接只需要 1KB/s 的吞吐量,总共也需要 1.6 Gb/s 的吞吐量。千兆网卡显然满足不了这么大的吞吐量,所以还需要配置万兆网卡,或者基于多网卡 Bonding 承载更大的吞吐量。其次,从软件资源上来说,大量的连接也会占用大量的软件资源,比如文件描述符的数量、连接状态的跟踪(CONNTRACK)、网络协议栈的缓存大小(比如套接字读写缓存、TCP 读写缓存)等等。最后,大量请求带来的中断处理,也会带来非常高的处理成本。这样,就需要多队列网卡、中断负载均衡、CPU 绑定、RPS/RFS(软中断负载均衡到多个 CPU 核上),以及将网络包的处理卸载(Offload)到网络设备(如 TSO/GSO、LRO/GRO、VXLAN OFFLOAD)等各种硬件和软件的优化。C1000K 的解决方法,本质上还是构建在 epoll 的非阻塞 I/O 模型上。只不过,除了 I/O 模型之外,还需要从应用程序到 Linux 内核、再到 CPU、内存和网络等各个层次的深度优化,特别是需要借助硬件,来卸载那些原来通过软件处理的大量功能。C10M显然,人们对于性能的要求是无止境的。再进一步,有没有可能在单机中,同时处理 1000 万的请求呢?这也就是 C10M 问题。实际上,在 C1000K 问题中,各种软件、硬件的优化很可能都已经做到头了。特别是当升级完硬件(比如足够多的内存、带宽足够大的网卡、更多的网络功能卸载等)后,可能会发现,无论怎么优化应用程序和内核中的各种网络参数,想实现 1000 万请求的并发,都是极其困难的。究其根本,还是 Linux 内核协议栈做了太多太繁重的工作。从网卡中断带来的硬中断处理程序开始,到软中断中的各层网络协议处理,最后再到应用程序,这个路径实在是太长了,就会导致网络包的处理优化,到了一定程度后,就无法更进一步了。要解决这个问题,最重要就是跳过内核协议栈的冗长路径,把网络包直接送到要处理的应用程序那里去。这里有两种常见的机制,DPDK 和 XDP。第一种机制,DPDK,是用户态网络的标准。它跳过内核协议栈,直接由用户态进程通过轮询的方式,来处理网络接收。说起轮询,你肯定会下意识认为它是低效的象征,但是进一步反问下自己,它的低效主要体现在哪里呢?是查询时间明显多于实际工作时间的情况下吧!那么,换个角度来想,如果每时每刻都有新的网络包需要处理,轮询的优势就很明显了。比如:在 PPS 非常高的场景中,查询时间比实际工作时间少了很多,绝大部分时间都在处理网络包;而跳过内核协议栈后,就省去了繁杂的硬中断、软中断再到 Linux 网络协议栈逐层处理的过程,应用程序可以针对应用的实际场景,有针对性地优化网络包的处理逻辑,而不需要关注所有的细节。此外,DPDK 还通过大页、CPU 绑定、内存对齐、流水线并发等多种机制,优化网络包的处理效率。前提需要能支持 DPDK 的网卡配合使用。第二种机制,XDP(eXpress Data Path),则是 Linux 内核提供的一种高性能网络数据路径。它允许网络包,在进入内核协议栈之前,就进行处理,也可以带来更高的性能。XDP 底层跟我们之前用到的 bcc-tools 一样,都是基于 Linux 内核的 eBPF 机制实现的。XDP 的原理如下图所示:XDP 对内核的要求比较高,需要的是 Linux 4.8 以上版本,并且它也不提供缓存队列。基于 XDP 的应用程序通常是专用的网络应用,常见的有 IDS(入侵检测系统)、DDoS 防御、 cilium 容器网络插件等。小结这篇文章回顾了经典的 C10K 问题,并进一步延伸到了C1000K 和 C10M 问题。C10K 问题的根源,一方面在于系统有限的资源;另一方面,也是更重要的因素,是同步阻塞的 I/O 模型以及轮询的套接字接口,限制了网络事件的处理效率。Linux 2.6 中引入的 epoll ,完美解决了 C10K 的问题,现在的高性能网络方案都基于 epoll。从 C10K 到 C100K ,可能只需要增加系统的物理资源就可以满足;但从 C100K 到 C1000K ,就不仅仅是增加物理资源就能解决的问题了。这时,就需要多方面的优化工作了,从硬件的中断处理和网络功能卸载、到网络协议栈的文件描述符数量、连接状态跟踪、缓存队列等内核的优化,再到应用程序的工作模型优化,都是考虑的重点。再进一步,要实现 C10M ,就不只是增加物理资源,或者优化内核和应用程序可以解决的问题了。这时候,就需要用 XDP 的方式,在内核协议栈之前处理网络包;或者用 DPDK 直接跳过网络协议栈,在用户空间通过轮询的方式直接处理网络包。当然了,实际上,在大多数场景中,我们并不需要单机并发 1000 万的请求。通过调整系统架构,把这些请求分发到多台服务器中来处理,通常是更简单和更容易扩展的方案。10k并发:epoll+线程池;100K:增加物理资源;1000k:更高的系统优化(软件的功能交给专业硬件);10mk: dpdx xdp;
0
0
0
浏览量2022
秋月无边

7.怎么缓解DDoS攻击带来的性能下降问题

DDoS简介DDoS 的前身是 DoS(Denail of Service),即拒绝服务攻击,指利用大量的合理请求,来占用过多的目标资源,从而使目标服务无法响应正常请求。DDoS(Distributed Denial of Service) 则是在 DoS 的基础上,采用了分布式架构,利用多台主机同时攻击目标主机。这样,即使目标服务部署了网络防御设备,面对大量网络请求时,还是无力应对。比如,目前已知的最大流量攻击,正是去年 Github 遭受的 DDoS 攻击,其峰值流量已经达到了 1.35Tbps,PPS 更是超过了 1.2 亿(126.9 million)。从攻击的原理上来看,DDoS 可以分为下面几种类型。第一种,耗尽带宽。无论是服务器还是路由器、交换机等网络设备,带宽都有固定的上限。带宽耗尽后,就会发生网络拥堵,从而无法传输其他正常的网络报文。第二种,耗尽操作系统的资源。网络服务的正常运行,都需要一定的系统资源,像是CPU、内存等物理资源,以及连接表等软件资源。一旦资源耗尽,系统就不能处理其他正常的网络连接。第三种,消耗应用程序的运行资源。应用程序的运行,通常还需要跟其他的资源或系统交互。如果应用程序一直忙于处理无效请求,也会导致正常请求的处理变慢,甚至得不到响应。比如,构造大量不同的域名来攻击 DNS 服务器,就会导致 DNS 服务器不停执行迭代查询,并更新缓存。这会极大地消耗 DNS 服务器的资源,使 DNS 的响应变慢。无论是哪一种类型的 DDoS,危害都是巨大的。那么,如何可以发现系统遭受了 DDoS 攻击,又该如何应对这种攻击呢?接下来,通过一个案例,一起来看看这些问题。案例准备下面的案例仍然基于 Ubuntu 18.04,同样适用于其他的 Linux 系统。环境如下:机器配置:2 CPU,8GB 内存。预先安装 docker、sar 、hping3、tcpdump、curl 等工具,比如 apt-get install docker.io hping3 tcpdump curl。hping3 可以构造 TCP/IP 协议数据包,对系统进行安全审计、防火墙测试、DoS 攻击测试等。本次案例用到三台虚拟机,关系图如下:可以看到,其中一台虚拟机运行 Nginx ,用来模拟待分析的 Web 服务器;而另外两台作为 Web 服务器的客户端,其中一台用作 DoS 攻击,而另一台则是正常的客户端。使用多台虚拟机的目的,自然还是为了相互隔离,避免“交叉感染”。由于案例只使用了一台机器作为攻击源,所以这里的攻击,实际上还是传统的 DoS ,而非 DDoS。接下来,我们打开三个终端,分别 SSH 登录到三台机器上(下面的步骤,都假设终端编号与图示VM 编号一致),并安装上面提到的这些工具。同以前的案例一样,下面的所有命令,都默认以 root 用户运行。如果你是用普通用户身份登陆系统,请运行 sudo su root 命令切换到 root 用户。接下来,我们就进入到案例操作环节。案例分析首先,在终端一中,执行下面的命令运行启动一个最基本的 Nginx 应用:# 运行Nginx服务并对外开放80端口 # --network=host表示使用主机网络(这是为了方便后面排查问题) $ docker run -itd --name=nginx --network=host nginx然后,在终端二和终端三中,使用 curl 访问 Nginx 监听的端口,确认 Nginx 正常启动。假设 192.168.0.30 是 Nginx 所在虚拟机的 IP 地址,那么运行 curl 命令后,会出现如下数据:# -w表示只输出HTTP状态码及总时间,-o表示将响应重定向到/dev/null $ curl -s -w 'Http code: %{http_code}\nTotal time:%{time_total}s\n' -o /dev/null http://192.168.0.30/ ... Http code: 200 Total time:0.002s从这里可以看到,正常情况下,访问 Nginx 只需要 2ms(0.002s)。接着,在终端二中,运行 hping3 命令,来模拟 DoS 攻击:# -S参数表示设置TCP协议的SYN(同步序列号),-p表示目的端口为80 # -i u10表示每隔10微秒发送一个网络帧 $ hping3 -S -p 80 -i u10 192.168.0.30现在,再回到终端一,你就会发现,现在不管执行什么命令,都慢了很多。不过,在实践时要注意:如果你的现象不那么明显,那么请尝试把参数里面的 u10 调小(比如调成 u1),或者加上–flood选项;如果你的终端一完全没有响应了,那么请适当调大 u10(比如调成 u30),否则后面就不能通过 SSH 操作 VM1。然后,到终端三中,执行下面的命令,模拟正常客户端的连接:# --connect-timeout表示连接超时时间 $ curl -w 'Http code: %{http_code}\nTotal time:%{time_total}s\n' -o /dev/null --connect-timeout 10 http://192.168.0.30 ... Http code: 000 Total time:10.001s curl: (28) Connection timed out after 10000 milliseconds可以发现,在终端三中,正常客户端的连接超时了,并没有收到 Nginx 服务的响应。这是发生了什么问题呢?再回到终端一中,检查网络状况。这里使用 sar命令,它既可以观察 PPS(每秒收发的报文数),还可以观察 BPS(每秒收发的字节数)。回到终端一中,执行下面的命令:$ sar -n DEV 1 08:55:49 IFACE rxpck/s txpck/s rxkB/s txkB/s rxcmp/s txcmp/s rxmcst/s %ifutil 08:55:50 docker0 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 08:55:50 eth0 22274.00 629.00 1174.64 37.78 0.00 0.00 0.00 0.02 08:55:50 lo 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00关于 sar 输出中的各列含义,可以点击 这里 查看,或者执行 man sar 查询手册。从这次 sar 的输出中,你可以看到,网络接收的 PPS 已经达到了 20000 多,但是 BPS 却只有 1174 kB,这样每个包的大小就只有 54B(1174*1024/22274=54)。这明显就是个小包了,不过具体是个什么样的包呢?那我们就用 tcpdump 抓包看看吧。在终端一中,执行下面的 tcpdump 命令:# -i eth0 只抓取eth0网卡,-n不解析协议名和主机名 # tcp port 80表示只抓取tcp协议并且端口号为80的网络帧 $ tcpdump -i eth0 -n tcp port 80 09:15:48.287047 IP 192.168.0.2.27095 > 192.168.0.30: Flags [S], seq 1288268370, win 512, length 0 09:15:48.287050 IP 192.168.0.2.27131 > 192.168.0.30: Flags [S], seq 2084255254, win 512, length 0 09:15:48.287052 IP 192.168.0.2.27116 > 192.168.0.30: Flags [S], seq 677393791, win 512, length 0 09:15:48.287055 IP 192.168.0.2.27141 > 192.168.0.30: Flags [S], seq 1276451587, win 512, length 0 09:15:48.287068 IP 192.168.0.2.27154 > 192.168.0.30: Flags [S], seq 1851495339, win 512, length 0这个输出中,Flags [S] 表示这是一个 SYN 包。大量的 SYN 包表明,这是一个 SYN Flood 攻击。通过 Wireshark 来观察,可以更直观地看到 SYN Flood 的过程:实际上,SYN Flood 正是互联网中最经典的 DDoS 攻击方式。从上面这个图,你也可以看到它的原理:即客户端构造大量的 SYN 包,请求建立 TCP 连接;而服务器收到包后,会向源 IP 发送 SYN+ACK 报文,并等待三次握手的最后一次ACK报文,直到超时。这种等待状态的 TCP 连接,通常也称为 半开连接。由于连接表的大小有限,大量的半开连接就会导致连接表迅速占满,从而无法建立新的 TCP 连接。参考下面这张 TCP 状态图,此时,服务器端的 TCP 连接,会处于 SYN_RECEIVED 状态:这其实提示了我们,查看 TCP 半开连接的方法,关键在于 SYN_RECEIVED 状态的连接。我们可以使用 netstat ,来查看所有连接的状态,不过要注意,SYN_REVEIVED 的状态,通常被缩写为 SYN_RECV。继续在终端一中,执行下面的 netstat 命令:# -n表示不解析名字,-p表示显示连接所属进程 $ netstat -n -p | grep SYN_REC tcp 0 0 192.168.0.30:80 192.168.0.2:12503 SYN_RECV - tcp 0 0 192.168.0.30:80 192.168.0.2:13502 SYN_RECV - tcp 0 0 192.168.0.30:80 192.168.0.2:15256 SYN_RECV - tcp 0 0 192.168.0.30:80 192.168.0.2:18117 SYN_RECV -从结果中,可以发现大量 SYN_RECV 状态的连接,并且源IP地址为 192.168.0.2。进一步,我们还可以通过 wc 工具,来统计所有 SYN_RECV 状态的连接数:$ netstat -n -p | grep SYN_REC | wc -l 193找出源 IP 后,要解决 SYN 攻击的问题,只要丢掉相关的包就可以。这时,iptables 可以帮你完成这个任务。在终端一中,执行下面的 iptables 命令:$ iptables -I INPUT -s 192.168.0.2 -p tcp -j REJECT然后回到终端三中,再次执行 curl 命令,查看正常用户访问 Nginx 的情况:$ curl -w 'Http code: %{http_code}\nTotal time:%{time_total}s\n' -o /dev/null --connect-timeout 10 http://192.168.0.30 Http code: 200 Total time:1.572171s现在,正常用户也可以访问 Nginx 了,只是响应比较慢,从原来的 2ms 变成了现在的 1.5s。不过,一般来说,SYN Flood 攻击中的源 IP 并不是固定的。比如,可以在 hping3 命令中,加入 –rand-source 选项,来随机化源 IP。这时,刚才的方法就不适用了。幸好,我们还有很多其他方法,实现类似的目标。比如,可以用以下两种方法,来限制 syn 包的速率:# 限制syn并发数为每秒1次 $ iptables -A INPUT -p tcp --syn -m limit --limit 1/s -j ACCEPT # 限制单个IP在60秒新建立的连接数为10 $ iptables -I INPUT -p tcp --dport 80 --syn -m recent --name SYN_FLOOD --update --seconds 60 --hitcount 10 -j REJECT到这里,我们已经初步限制了 SYN Flood 攻击。不过这还不够,因为我们的案例还只是单个的攻击源。如果是多台机器同时发送 SYN Flood,这种方法可能就直接无效了。因为很可能无法 SSH 登录(SSH 也是基于 TCP 的)到机器上去,更别提执行上述所有的排查命令。所以,这还需要事先对系统做一些 TCP 优化。比如,SYN Flood 会导致 SYN_RECV 状态的连接急剧增大。在上面的 netstat 命令中,你也可以看到 190 多个处于半开状态的连接。不过,半开状态的连接数是有限制的,执行下面的命令,就可以看到,默认的半连接容量只有 256:$ sysctl net.ipv4.tcp_max_syn_backlog net.ipv4.tcp_max_syn_backlog = 256换句话说, SYN 包数再稍微增大一些,就不能 SSH 登录机器了。 所以,还应该增大半连接的容量,可以用下面的命令,将其增大为 1024:$ sysctl -w net.ipv4.tcp_max_syn_backlog=1024 net.ipv4.tcp_max_syn_backlog = 1024另外,连接每个 SYN_RECV 时,如果失败的话,内核还会自动重试,并且默认的重试次数是5次。可以执行下面的命令,将其减小为 1 次:$ sysctl -w net.ipv4.tcp_synack_retries=1 net.ipv4.tcp_synack_retries = 1除此之外,TCP SYN Cookies 也是一种专门防御 SYN Flood 攻击的方法。SYN Cookies 基于连接信息(包括源地址、源端口、目的地址、目的端口等)以及一个加密种子(如系统启动时间),计算出一个哈希值(SHA1),这个哈希值称为 cookie。然后,这个 cookie 就被用作序列号,来应答 SYN+ACK 包,并释放连接状态。当客户端发送完三次握手的最后一次 ACK 后,服务器就会再次计算这个哈希值,确认是上次返回的 SYN+ACK 的返回包,才会进入 TCP 的连接状态。因而,开启 SYN Cookies 后,就不需要维护半开连接状态了,进而也就没有了半连接数的限制。注意,开启 TCP syncookies 后,内核选项 net.ipv4.tcp_max_syn_backlog 也就无效了。可以通过下面的命令,开启 TCP SYN Cookies:$ sysctl -w net.ipv4.tcp_syncookies=1 net.ipv4.tcp_syncookies = 1注意,上述 sysctl 命令修改的配置都是临时的,重启后这些配置就会丢失。所以,为了保证配置持久化,还应该把这些配置,写入 /etc/sysctl.conf 文件中。比如:$ cat /etc/sysctl.conf net.ipv4.tcp_syncookies = 1 net.ipv4.tcp_synack_retries = 1 net.ipv4.tcp_max_syn_backlog = 1024不过要注意,写入 /etc/sysctl.conf 的配置,需要执行 sysctl -p 命令后,才会动态生效。DDoS到底该怎么防御为什么不是解决 DDoS ,而只是缓解呢?而且案例中的方法,也只是让 Nginx 服务访问不再超时,但访问延迟还是比一开始时的 2ms 大得多。实际上,当 DDoS 报文到达服务器后,Linux 提供的机制只能缓解,而无法彻底解决。即使像是 SYN Flood 这样的小包攻击,其巨大的 PPS ,也会导致 Linux 内核消耗大量资源,进而导致其他网络报文的处理缓慢。虽然可以调整内核参数,缓解 DDoS 带来的性能问题,却也会像案例这样,无法彻底解决它。Linux 内核中冗长的协议栈,在 PPS 很大时,就是一个巨大的负担。可以基于 XDP 或者 DPDK,构建 DDoS 方案,在内核网络协议栈前,或者跳过内核协议栈,来识别并丢弃 DDoS 报文,避免DDoS 对系统其他资源的消耗。不过,对于流量型的 DDoS 来说,当服务器的带宽被耗尽后,在服务器内部处理就无能为力了。这时,只能在服务器外部的网络设备中,设法识别并阻断流量(当然前提是网络设备要能扛住流量攻击)。比如,购置专业的入侵检测和防御设备,配置流量清洗设备阻断恶意流量等。既然 DDoS 这么难防御,这是不是说明, Linux 服务器内部压根儿就不关注这一点,而是全部交给专业的网络设备来处理呢?当然不是,因为 DDoS 并不一定是因为大流量或者大 PPS,有时候,慢速的请求也会带来巨大的性能下降(这种情况称为慢速 DDoS)。比如,很多针对应用程序的攻击,都会伪装成正常用户来请求资源。这种情况下,请求流量可能本身并不大,但响应流量却可能很大,并且应用程序内部也很可能要耗费大量资源处理。这时,就需要应用程序考虑识别,并尽早拒绝掉这些恶意流量,比如合理利用缓存、增加 WAF(Web Application Firewall)、使用 CDN 等等。小结DDoS 利用大量的伪造请求,使目标服务耗费大量资源,来处理这些无效请求,进而无法正常响应正常的用户请求。由于 DDoS 的分布式、大流量、难追踪等特点,目前还没有方法可以完全防御 DDoS 带来的问题,只能设法缓解这个影响。比如,可以购买专业的流量清洗设备和网络防火墙,在网络入口处阻断恶意流量,只保留正常流量进入数据中心的服务器中。就需要应用程序考虑识别,并尽早拒绝掉这些恶意流量,比如合理利用缓存、增加 WAF(Web Application Firewall)、使用 CDN 等等。在 Linux 服务器中,可以通过内核调优、DPDK、XDP 等多种方法,来增大服务器的抗攻击能力,降低 DDoS 对正常服务的影响。而在应用程序中,可以利用各级缓存、 WAF、CDN 等方式,缓解 DDoS 对应用程序的影响。
0
0
0
浏览量2010
秋月无边

4. 怎么评估linux系统的网络性能?

性能指标回顾在评估网络性能前,先来回顾一下衡量网络性能的指标有哪些。首先, 带宽,表示链路的最大传输速率,单位是 b/s(比特/秒)。在你为服务器选购网卡时,带宽就是最核心的参考指标。常用的带宽有 1000M、10G、40G、100G 等。第二, 吞吐量,表示没有丢包时的最大数据传输速率,单位通常为 b/s (比特/秒)或者 B/s(字节/秒)。吞吐量受带宽的限制,吞吐量/带宽也就是该网络链路的使用率。第三, 延时,表示从网络请求发出后,一直到收到远端响应,所需要的时间延迟。这个指标在不同场景中可能会有不同的含义。它可以表示建立连接需要的时间(比如 TCP 握手延时),或者一个数据包往返所需时间(比如 RTT)。最后, PPS,是 Packet Per Second(包/秒)的缩写,表示以网络包为单位的传输速率。PPS 通常用来评估网络的转发能力,而基于 Linux 服务器的转发,很容易受到网络包大小的影响(交换机通常不会受到太大影响,即交换机可以线性转发)。这四个指标中,带宽跟物理网卡配置是直接关联的。一般来说,网卡确定后,带宽也就确定了(当然,实际带宽会受限于整个网络链路中最小的那个模块)。另外,你可能在很多地方听说过“网络带宽测试”,这里测试的实际上不是带宽,而是网络吞吐量。Linux 服务器的网络吞吐量一般会比带宽小,而对交换机等专门的网络设备来说,吞吐量一般会接近带宽。最后的 PPS,则是以网络包为单位的网络传输速率,通常用在需要大量转发的场景中。而对 TCP 或者 Web 服务来说,更多会用并发连接数和每秒请求数(QPS,Query per Second)等指标,它们更能反应实际应用程序的性能。网络基准测试如何通过性能测试来确定这些指标的基准值。Linux 网络基于 TCP/IP 协议栈,而不同协议层的行为显然不同。那么,测试之前,应该弄清楚,要评估的网络性能,究竟属于协议栈的哪一层?换句话说,你的应用程序基于协议栈的哪一层呢?根据前面学过的 TCP/IP 协议栈的原理,这个问题应该不难回答。比如:基于 HTTP 或者 HTTPS 的 Web 应用程序,显然属于应用层,需要我们测试 HTTP/HTTPS 的性能;而对大多数游戏服务器来说,为了支持更大的同时在线人数,通常会基于 TCP 或 UDP ,与客户端进行交互,这时就需要测试 TCP/UDP 的性能;还有一些场景,是把 Linux 作为一个软交换机或者路由器来用的。这种情况下,你更关注网络包的处理能力(即 PPS),重点关注网络层的转发性能。接下来,从下往上,了解不同协议层的网络性能测试方法。不过要注意,低层协议是其上的各层网络协议的基础。自然,低层协议的性能,也就决定了高层的网络性能。注意,以下所有的测试方法,都需要两台 Linux 虚拟机。其中一台,可以当作待测试的目标机器;而另一台,则可以当作正在运行网络服务的客户端,用来运行测试工具。各协议层的性能测试转发性能首先来看,网络接口层和网络层,它们主要负责网络包的封装、寻址、路由以及发送和接收。在这两个网络协议层中,每秒可处理的网络包数 PPS,就是最重要的性能指标。特别是 64B 小包的处理能力,值得我们特别关注(小包更能体现pps的性能)。那么,如何来测试网络包的处理能力呢?Linux 内核自带的高性能网络测试工具 pktgen。pktgen 支持丰富的自定义选项,方便你根据实际需要构造所需网络包,从而更准确地测试出目标服务器的性能。不过,在 Linux 系统中,并不能直接找到 pktgen 命令。因为 pktgen 作为一个内核线程来运行,需要你加载 pktgen 内核模块后,再通过 /proc 文件系统来交互。下面就是 pktgen 启动的两个内核线程和 /proc 文件系统的交互文件:$ modprobe pktgen $ ps -ef | grep pktgen | grep -v grep root 26384 2 0 06:17 ? 00:00:00 [kpktgend_0] root 26385 2 0 06:17 ? 00:00:00 [kpktgend_1] $ ls /proc/net/pktgen/ kpktgend_0 kpktgend_1 pgctrlpktgen 在每个 CPU 上启动一个内核线程,并可以通过 /proc/net/pktgen 下面的同名文件,跟这些线程交互;而 pgctrl 则主要用来控制这次测试的开启和停止。如果 modprobe 命令执行失败,说明你的内核没有配置 CONFIG_NET_PKTGEN 选项。这就需要你配置 pktgen 内核模块(即 CONFIG_NET_PKTGEN=m)后,重新编译内核,才可以使用。在使用 pktgen 测试网络性能时,需要先给每个内核线程 kpktgend_X 以及测试网卡,配置 pktgen 选项,然后再通过 pgctrl 启动测试。以发包测试为例,假设发包机器使用的网卡是 eth0,而目标机器的 IP 地址为 192.168.0.30,MAC 地址为 11:11:11:11:11:11。接下来,就是一个发包测试的示例。# 定义一个工具函数,方便后面配置各种测试选项 function pgset() { local result echo $1 > $PGDEV result=`cat $PGDEV | fgrep "Result: OK:"` if [ "$result" = "" ]; then cat $PGDEV | fgrep Result: fi } # 为0号线程绑定eth0网卡 PGDEV=/proc/net/pktgen/kpktgend_0 pgset "rem_device_all" # 清空网卡绑定 pgset "add_device eth0" # 添加eth0网卡 # 配置eth0网卡的测试选项 PGDEV=/proc/net/pktgen/eth0 pgset "count 1000000" # 总发包数量 pgset "delay 5000" # 不同包之间的发送延迟(单位纳秒) pgset "clone_skb 0" # SKB包复制 pgset "pkt_size 64" # 网络包大小 pgset "dst 192.168.0.30" # 目的IP pgset "dst_mac 11:11:11:11:11:11" # 目的MAC # 启动测试 PGDEV=/proc/net/pktgen/pgctrl pgset "start"稍等一会儿,测试完成后,结果可以从 /proc 文件系统中获取。通过下面代码段中的内容,我们可以查看刚才的测试报告:$ cat /proc/net/pktgen/eth0 Params: count 1000000 min_pkt_size: 64 max_pkt_size: 64 frags: 0 delay: 0 clone_skb: 0 ifname: eth0 flows: 0 flowlen: 0 ... Current: pkts-sofar: 1000000 errors: 0 started: 1534853256071us stopped: 1534861576098us idle: 70673us ... Result: OK: 8320027(c8249354+d70673) usec, 1000000 (64byte,0frags) 120191pps 61Mb/sec (61537792bps) errors: 0测试报告主要分为三个部分:第一部分的 Params 是测试选项;第二部分的 Current 是测试进度,其中, packts so far(pkts-sofar)表示已经发送了 100 万个包,也就表明测试已完成。第三部分的 Result 是测试结果,包含测试所用时间、网络包数量和分片、PPS、吞吐量以及错误数。根据上面的结果,PPS 为 12 万,吞吐量为 61 Mb/s,没有发生错误。那么,12 万的 PPS 好不好呢?作为对比,你可以计算一下千兆交换机的 PPS。交换机可以达到线速(满负载时,无差错转发),它的 PPS 就是 1000Mbit 除以以太网帧的大小,即 1000Mbps/((64+20)*8bit) = 1.5 Mpps(其中,20B 为以太网帧前导和帧间距的大小)。即使是千兆交换机的 PPS,也可以达到 150 万 PPS,比测试得到的 12 万大多了。所以,看到这个数值你并不用担心,现在的多核服务器和万兆网卡已经很普遍了,稍做优化就可以达到数百万的 PPS。而且,如果用了 DPDK 或 XDP ,还能达到千万数量级。TCP/UDP 性能iperf 和 netperf 都是最常用的网络性能测试工具,测试 TCP 和 UDP 的吞吐量。它们都以客户端和服务器通信的方式,测试一段时间内的平均吞吐量。接下来,以 iperf 为例,看一下 TCP 性能的测试方法。目前,iperf 的最新版本为 iperf3,可以运行下面的命令来安装:# Ubuntu apt-get install iperf3 # CentOS yum install iperf3然后,在目标机器上启动 iperf 服务端:# -s表示启动服务端,-i表示汇报间隔,-p表示监听端口 $ iperf3 -s -i 1 -p 10000接着,在另一台机器上运行 iperf 客户端,运行测试:# -c表示启动客户端,192.168.0.30为目标服务器的IP # -b表示目标带宽(单位是bits/s) # -t表示测试时间 # -P表示并发数,-p表示目标服务器监听端口 $ iperf3 -c 192.168.0.30 -b 1G -t 15 -P 2 -p 10000稍等一会儿(15秒)测试结束后,回到目标服务器,查看 iperf 的报告:[ ID] Interval Transfer Bandwidth ... [SUM] 0.00-15.04 sec 0.00 Bytes 0.00 bits/sec sender [SUM] 0.00-15.04 sec 1.51 GBytes 860 Mbits/sec receiver最后的 SUM 行就是测试的汇总结果,包括测试时间、数据传输量以及带宽等。按照发送和接收,这一部分又分为了 sender 和 receiver 两行。从测试结果你可以看到,这台机器 TCP 接收的带宽(吞吐量)为 860 Mb/s, 跟目标的 1Gb/s 相比,还是有些差距的。HTTP 性能从传输层再往上,到了应用层。有的应用程序,会直接基于 TCP 或 UDP 构建服务。当然,也有大量的应用,基于应用层的协议来构建服务,HTTP 就是最常用的一个应用层协议。比如,常用的 Apache、Nginx 等各种 Web 服务,都是基于 HTTP。要测试 HTTP 的性能,也有大量的工具可以使用,比如 ab、webbench 等,都是常用的 HTTP 压力测试工具。其中,ab 是 Apache 自带的 HTTP 压测工具,主要测试 HTTP 服务的每秒请求数、请求延迟、吞吐量以及请求延迟的分布情况等。运行下面的命令,你就可以安装 ab 工具:# Ubuntu $ apt-get install -y apache2-utils # CentOS $ yum install -y httpd-tools接下来,在目标机器上,使用 Docker 启动一个 Nginx 服务,然后用 ab 来测试它的性能。首先,在目标机器上运行下面的命令:$ docker run -p 80:80 -itd nginx而在另一台机器上,运行 ab 命令,测试 Nginx 的性能:# -c表示并发请求数为1000,-n表示总的请求数为10000 $ ab -c 1000 -n 10000 http://192.168.0.30/ ... Server Software: nginx/1.15.8 Server Hostname: 192.168.0.30 Server Port: 80 ... Requests per second: 1078.54 [#/sec] (mean) Time per request: 927.183 [ms] (mean) Time per request: 0.927 [ms] (mean, across all concurrent requests) Transfer rate: 890.00 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 0 27 152.1 1 1038 Processing: 9 207 843.0 22 9242 Waiting: 8 207 843.0 22 9242 Total: 15 233 857.7 23 9268 Percentage of the requests served within a certain time (ms) 50% 23 66% 24 75% 24 80% 26 90% 274 95% 1195 98% 2335 99% 4663 100% 9268 (longest request) 可以看到,ab 的测试结果分为三个部分,分别是请求汇总、连接时间汇总还有请求延迟汇总。以上面的结果为例,我们具体来看。在请求汇总部分,可以看到:Requests per second 为 1074;每个请求的延迟(Time per request)分为两行,第一行的 927 ms 表示平均延迟,包括了线程运行的调度时间和网络请求响应时间,而下一行的 0.927ms ,则表示实际请求的响应时间;Transfer rate 表示吞吐量(BPS)为 890 KB/s。连接时间汇总部分,则是分别展示了建立连接、请求、等待以及汇总等的各类时间,包括最小、最大、平均以及中值处理时间。最后的请求延迟汇总部分,则给出了不同时间段内处理请求的百分比,比如, 90% 的请求,都可以在 274ms 内完成。应用负载性能当用 iperf 或者 ab 等测试工具,得到 TCP、HTTP 等的性能数据后,这些数据是否就能表示应用程序的实际性能呢?答案应该是否定的。比如,你的应用程序基于 HTTP 协议,为最终用户提供一个 Web 服务。这时,使用 ab 工具,可以得到某个页面的访问性能,但这个结果跟用户的实际请求,很可能不一致。因为用户请求往往会附带着各种各种的负载(payload),而这些负载会影响 Web 应用程序内部的处理逻辑,从而影响最终性能。那么,为了得到应用程序的实际性能,就要求性能工具本身可以模拟用户的请求负载,而iperf、ab 这类工具就无能为力了。幸运的是,我们还可以用 wrk、TCPCopy、Jmeter 或者 LoadRunner 等实现这个目标。以 wrk 为例,它是一个 HTTP 性能测试工具,内置了 LuaJIT,方便你根据实际需求,生成所需的请求负载,或者自定义响应的处理方法。wrk 工具本身不提供 yum 或 apt 的安装方法,需要通过源码编译来安装。比如,可以运行下面的命令,来编译和安装 wrk:$ https://github.com/wg/wrk $ cd wrk $ apt-get install build-essential -y $ make $ sudo cp wrk /usr/local/bin/wrk 的命令行参数比较简单。比如,我们可以用 wrk ,来重新测一下前面已经启动的 Nginx 的性能。# -c表示并发连接数1000,-t表示线程数为2 $ wrk -c 1000 -t 2 http://192.168.0.30/ Running 10s test @ http://192.168.0.30/ 2 threads and 1000 connections Thread Stats Avg Stdev Max +/- Stdev Latency 65.83ms 174.06ms 1.99s 95.85% Req/Sec 4.87k 628.73 6.78k 69.00% 96954 requests in 10.06s, 78.59MB read Socket errors: connect 0, read 0, write 0, timeout 179 Requests/sec: 9641.31 Transfer/sec: 7.82MB这里使用 2 个线程、并发 1000 连接,重新测试了 Nginx 的性能。你可以看到,每秒请求数为 9641,吞吐量为 7.82MB,平均延迟为 65ms,比前面 ab 的测试结果要好很多。这也说明,性能工具本身的性能,对性能测试也是至关重要的。不合适的性能工具,并不能准确测出应用程序的最佳性能。当然,wrk 最大的优势,是其内置的 LuaJIT,可以用来实现复杂场景的性能测试。wrk 在调用 Lua 脚本时,可以将 HTTP 请求分为三个阶段,即 setup、running、done,如下图所示:​ 比如,你可以在 setup 阶段,为请求设置认证参数(来自于 wrk 官方 示例):-- example script that demonstrates response handling and -- retrieving an authentication token to set on all future -- requests token = nil path = "/authenticate" request = function() return wrk.format("GET", path) end response = function(status, headers, body) if not token and status == 200 then token = headers["X-Token"] path = "/resource" wrk.headers["X-Token"] = token end end而在执行测试时,通过 -s 选项,执行脚本的路径:$ wrk -c 1000 -t 2 -s auth.lua http://192.168.0.30/wrk 需要你用 Lua 脚本,来构造请求负载。这对于大部分场景来说,可能已经足够了 。不过,它的缺点也正是,所有东西都需要代码来构造,并且工具本身不提供 GUI 环境。像 Jmeter 或者 LoadRunner(商业产品),则针对复杂场景提供了脚本录制、回放、GUI 等更丰富的功能,使用起来也更加方便。小结性能评估是优化网络性能的前提,只有在你发现网络性能瓶颈时,才需要进行网络性能优化。根据 TCP/IP 协议栈的原理,不同协议层关注的性能重点不完全一样,也就对应不同的性能测试方法。比如,在应用层,你可以使用 wrk、Jmeter 等模拟用户的负载,测试应用程序的每秒请求数、处理延迟、错误数等;而在传输层,则可以使用 iperf 等工具,测试 TCP 的吞吐情况;再向下,你还可以用 Linux 内核自带的 pktgen ,测试服务器的 PPS。由于低层协议是高层协议的基础。所以,一般情况下,我们需要从上到下,对每个协议层进行性能测试,然后根据性能测试的结果,结合 Linux 网络协议栈的原理,找出导致性能瓶颈的根源,进而优化网络性能。
0
0
0
浏览量2022
秋月无边

9. 如何优化 NAT 性能?(上)NAT 技术可以重写 IP 数据包的源 IP 或者目的 IP,被

上一篇文章介绍了在发现网络延迟增大的情况后,可以先从路由、网络包的收发、网络包的处理,再到应用程序等,从各个层级分析网络延迟,等到找出网络延迟的来源层级后,再深入定位瓶颈所在。这一篇文章我们来介绍另一个可能导致网络延迟的因素,即网络地址转换(Network Address Translation),缩写为 NAT。接下来,我们先来学习 NAT 的工作原理,并弄清楚如何优化 NAT 带来的潜在性能问题。NAT原理NAT 技术可以重写 IP 数据包的源 IP 或者目的 IP,被普遍地用来解决公网 IP 地址短缺的问题。它的主要原理就是,网络中的多台主机,通过共享同一个公网 IP 地址,来访问外网资源。同时,由于 NAT 屏蔽了内网网络,自然也就为局域网中的机器提供了安全隔离。既可以在支持网络地址转换的路由器(称为 NAT 网关)中配置 NAT,也可以在 Linux 服务器中配置 NAT。如果采用第二种方式,Linux 服务器实际上充当的是“软”路由器的角色。NAT 的主要目的,是实现地址转换。根据实现方式的不同,NAT 可以分为三类:静态 NAT,即内网 IP 与公网 IP 是一对一的永久映射关系;动态 NAT,即内网 IP 从公网 IP 池中,动态选择一个进行映射;网络地址端口转换 NAPT(Network Address and Port Translation),即把内网 IP 映射到公网 IP 的不同端口上,让多个内网 IP 可以共享同一个公网 IP 地址。NAPT 是目前最流行的 NAT 类型,我们在 Linux 中配置的 NAT 也是这种类型。而根据转换方式的不同,我们又可以把 NAPT 分为三类。第一类是源地址转换SNAT,即目的地址不变,只替换源 IP 或源端口。SNAT 主要用于,多个内网 IP 共享同一个公网 IP ,来访问外网资源的场景。第二类是目的地址转换DNAT,即源 IP 保持不变,只替换目的 IP 或者目的端口。DNAT 主要通过公网 IP 的不同端口号,来访问内网的多种服务,同时会隐藏后端服务器的真实 IP 地址。第三类是双向地址转换,即 同时使用 SNAT 和 DNAT。当接收到网络包时,执行 DNAT,把目的 IP 转换为内网 IP;而在发送网络包时,执行 SNAT,把源 IP 替换为外部 IP。双向地址转换,其实就是外网 IP 与内网 IP 的一对一映射关系,所以常用在虚拟化环境中,为虚拟机分配浮动的公网 IP 地址。下面演示一下这个过程:本地服务器的内网 IP 地址为 192.168.0.2;NAT 网关中的公网 IP 地址为 100.100.100.100;要访问的目的服务器 baidu.com 的地址为 123.125.115.110。那么 SNAT 和 DNAT 的过程,就如下图所示:img从图中,你可以发现:当服务器访问 baidu.com 时,NAT 网关会把源地址,从服务器的内网 IP 192.168.0.2 替换成公网 IP 地址 100.100.100.100,然后才发送给 baidu.com;当 baidu.com 发回响应包时,NAT 网关又会把目的地址,从公网 IP 地址 100.100.100.100 替换成服务器内网 IP 192.168.0.2,然后再发送给内网中的服务器。了解了 NAT 的原理后,我们再来看看,如何在 Linux 中实现 NAT 的功能。iptables与NATLinux 内核提供的 Netfilter 框架,允许对网络数据包进行修改(比如 NAT)和过滤(比如防火墙)。在这个基础上,iptables、ip6tables、ebtables 等工具,又提供了更易用的命令行接口,以便系统管理员配置和管理 NAT、防火墙的规则。其中,iptables 就是最常用的一种配置工具。要掌握 iptables 的原理和使用方法,最核心的就是弄清楚,网络数据包通过 Netfilter 时的工作流向,流程图如下:img(图片来自 Wikipedia)在这张图中,绿色背景的方框,表示表(table),用来管理链。Linux 支持 4 种表,包括 filter(用于过滤)、nat(用于NAT)、mangle(用于修改分组数据) 和 raw(用于原始数据包)等。跟 table 一起的白色背景方框,则表示链(chain),用来管理具体的 iptables 规则。每个表中可以包含多条链,比如:filter 表中,内置 INPUT、OUTPUT 和 FORWARD 链;nat 表中,内置PREROUTING、POSTROUTING、OUTPUT 等。当然,你也可以根据需要,创建你自己的链。灰色的 conntrack,表示连接跟踪模块。它通过内核中的连接跟踪表(也就是哈希表),记录网络连接的状态,是 iptables 状态过滤(-m state)和 NAT 的实现基础。iptables 的所有规则,就会放到这些表和链中,并按照图中顺序和规则的优先级顺序来执行。要实现 NAT 功能,主要是在 nat 表进行操作。而 nat 表内置了三个链:PREROUTING,用于路由判断前所执行的规则,比如,对接收到的数据包进行 DNAT。POSTROUTING,用于路由判断后所执行的规则,比如,对发送或转发的数据包进行 SNAT 或 MASQUERADE。OUTPUT,类似于 PREROUTING,但只处理从本机发送出去的包。熟悉 iptables 中的表和链后,相应的 NAT 规则就比较简单了。下面以 NAPT 的三个分类为例,来具体解读一下。SNATSNAT 需要在 nat 表的 POSTROUTING 链中配置。我们常用两种方式来配置它。第一种方法,是为一个子网统一配置 SNAT,并由 Linux 选择默认的出口 IP。这实际上就是经常说的 MASQUERADE(地址伪装,灵活分配ip):$ iptables -t nat -A POSTROUTING -s 192.168.0.0/16 -j MASQUERADE DNS第二种方法,是为具体的 IP 地址配置 SNAT,并指定转换后的源地址:$ iptables -t nat -A POSTROUTING -s 192.168.0.2 -j SNAT --to-source 100.100.100.100 DNSDNATDNAT 需要在 nat 表的 PREROUTING 或者 OUTPUT 链中配置,其中, PREROUTING 链更常用一些(因为它还可以用于转发的包)。$ iptables -t nat -A PREROUTING -d 100.100.100.100 -j DNAT --to-destination 192.168.0.2 DNS双向地址转换双向地址转换,就是同时添加 SNAT 和 DNAT 规则,为公网 IP 和内网 IP 实现一对一的映射关系,即:$ iptables -t nat -A POSTROUTING -s 192.168.0.2 -j SNAT --to-source 100.100.100.100 $ iptables -t nat -A PREROUTING -d 100.100.100.100 -j DNAT --to-destination 192.168.0.2 DNS在使用 iptables 配置 NAT 规则时,Linux 需要转发来自其他 IP 的网络包,所以你千万不要忘记开启 Linux 的 IP 转发功能。可以执行下面的命令,查看这一功能是否开启。如果输出的结果是 1,就表示已经开启了 IP 转发:$ sysctl net.ipv4.ip_forward net.ipv4.ip_forward = 1 STYLUS如果还没开启,可以执行下面的命令,手动开启:$ sysctl -w net.ipv4.ip_forward=1 net.ipv4.ip_forward = 1 STYLUS为了避免重启后配置丢失,不要忘记将配置写入 /etc/sysctl.conf 文件中:$ cat /etc/sysctl.conf | grep ip_forward net.ipv4.ip_forward=1 GRADLE小结这篇文章分析了 Linux 网络地址转换 NAT 的原理。NAT 技术能够重写 IP 数据包的源 IP 或目的 IP,所以普遍用来解决公网 IP 地址短缺的问题。它可以让网络中的多台主机,通过共享同一个公网 IP 地址,来访问外网资源。同时,由于 NAT 屏蔽了内网网络,也为局域网中机器起到安全隔离的作用。Linux 中的NAT ,基于内核的连接跟踪模块实现。所以,它维护每个连接状态的同时,也会带来很高的性能成本。具体 NAT 性能问题的分析方法,我们将在下节课继续学习。思考。MASQUERADE 是最常用的一种 SNAT 规则,常用来为多个内网 IP 地址提供共享的出口 IP。假设现在有一台 Linux 服务器,使用了 MASQUERADE 的方式,为内网的所有 IP 提供出口访问功能。那么,当多个内网 IP 地址的端口号相同时,MASQUERADE 还可以正常工作吗?如果内网 IP 地址数量或请求数比较多,这种方式有没有什么隐患呢?问题1:Linux的NAT时给予内核的连接跟踪模块实现,保留了源IP、源端口、目的IP、目的端口之间的关系,多个内网IP地址的端口相同,但是IP不同,再nf_conntrack中对应不同的记录,所以MASQUERADE可以正常工作。口号相同时,MASQUERADE 还可以正常工作吗?如果内网 IP 地址数量或请求数比较多,这种方式有没有什么隐患呢?
0
0
0
浏览量2016
秋月无边

10.如何优化NAT性能(下)

Linux 中的NAT ,基于内核的连接跟踪模块实现。所以,它维护每个连接状态的同时,也对网络性能有一定影响。那么,碰到 NAT 性能问题时,我们又该怎么办呢?接下来,通过一个案例,学习 NAT 性能问题的分析思路。案例准备下面的案例仍然基于 Ubuntu 18.04,同样适用于其他的 Linux 系统。案例环境如下:机器配置:2 CPU,8GB 内存。预先安装 docker、tcpdump、curl、ab、SystemTap 等工具,比如# Ubuntu $ apt-get install -y docker.io tcpdump curl apache2-utils # CentOS $ curl -fsSL https://get.docker.com | sh $ yum install -y tcpdump curl httpd-tools POWERSHELL这里简单介绍一下 SystemTap 。SystemTap 是 Linux 的一种动态追踪框架,它把用户提供的脚本,转换为内核模块来执行,用来监测和跟踪内核的行为。安装步骤如下:# Ubuntu apt-get install -y systemtap-runtime systemtap # Configure ddebs source echo "deb http://ddebs.ubuntu.com $(lsb_release -cs) main restricted universe multiverse deb http://ddebs.ubuntu.com $(lsb_release -cs)-updates main restricted universe multiverse deb http://ddebs.ubuntu.com $(lsb_release -cs)-proposed main restricted universe multiverse" | \ sudo tee -a /etc/apt/sources.list.d/ddebs.list # Install dbgsym apt-key adv --keyserver keyserver.ubuntu.com --recv-keys F2EDC64DC5AEE1F6B9C621F0C8CAB6595FDFF622 apt-get update apt install ubuntu-dbgsym-keyring stap-prep apt-get install linux-image-`uname -r`-dbgsym # CentOS yum install systemtap kernel-devel yum-utils kernel stab-prep VIM本次案例基于 Nginx,并且会用 ab 作为它的客户端,进行压力测试。案例中总共用到两台虚拟机,关系图如下。img接下来,打开两个终端,分别 SSH 登录到两台机器上(以下步骤,假设终端编号与图示VM 编号一致),并安装上面提到的这些工具。注意,curl 和 ab 只需要在客户端 VM(即 VM2)中安装。案例分析为了对比 NAT 带来的性能问题,我们首先运行一个不用 NAT 的 Nginx 服务,并用 ab 测试它的性能。在终端一中,执行下面的命令,启动 Nginx,注意选项 –network=host ,表示容器使用 Host 网络模式,即不使用 NAT:$ docker run --name nginx-hostnet --privileged --network=host -itd feisky/nginx:80 ROUTEROS然后到终端二中,执行 curl 命令,确认 Nginx 正常启动:$ curl http://192.168.0.30/ ... <p><em>Thank you for using nginx.</em></p> </body> </html> XML继续在终端二中,执行 ab 命令,对 Nginx 进行压力测试。不过在测试前要注意,Linux 默认允许打开的文件描述数比较小,比如在我的机器中,这个值只有 1024:# open files $ ulimit -n 1024 SHELL所以,执行 ab 前,先要把这个选项调大,比如调成 65536:# 临时增大当前会话的最大文件描述符数 $ ulimit -n 65536 SHELL接下来,再去执行 ab 命令,进行压力测试:# -c表示并发请求数为5000,-n表示总的请求数为10万 # -r表示套接字接收错误时仍然继续执行,-s表示设置每个请求的超时时间为2s $ ab -c 5000 -n 100000 -r -s 2 http://192.168.0.30/ ... Requests per second: 6576.21 [#/sec] (mean) Time per request: 760.317 [ms] (mean) Time per request: 0.152 [ms] (mean, across all concurrent requests) Transfer rate: 5390.19 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 0 177 714.3 9 7338 Processing: 0 27 39.8 19 961 Waiting: 0 23 39.5 16 951 Total: 1 204 716.3 28 7349 ... TAP可以看出:每秒请求数(Requests per second)为 6576;每个请求的平均延迟(Time per request)为 760ms;建立连接的平均延迟(Connect)为 177ms。记住这几个数值,这将是接下来案例的基准指标。接着,回到终端一,停止这个未使用NAT的Nginx应用:$ docker rm -f nginx-hostnet POWERSHELL再执行下面的命令,启动今天的案例应用。案例应用监听在 8080 端口,并且使用了 DNAT ,来实现 Host 的 8080 端口,到容器的 8080 端口的映射关系:$ docker run --name nginx --privileged -p 8080:8080 -itd feisky/nginx:nat STYLUSNginx 启动后,执行 iptables 命令,确认 DNAT 规则已经创建:$ iptables -nL -t nat Chain PREROUTING (policy ACCEPT) target prot opt source destination DOCKER all -- 0.0.0.0/0 0.0.0.0/0 ADDRTYPE match dst-type LOCAL ... Chain DOCKER (2 references) target prot opt source destination RETURN all -- 0.0.0.0/0 0.0.0.0/0 DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:8080 to:172.17.0.2:8080 VIM可以看到,在 PREROUTING 链中,目的为本地的请求,会转到 DOCKER 链;而在 DOCKER 链中,目的端口为 8080 的 tcp 请求,会被 DNAT 到 172.17.0.2 的 8080 端口。其中,172.17.0.2 就是 Nginx 容器的 IP 地址。接下来,切换到终端二中,执行 curl 命令,确认 Nginx 已经正常启动:$ curl http://192.168.0.30:8080/ ... <p><em>Thank you for using nginx.</em></p> </body> </html> XML然后,再次执行上述的 ab 命令,不过这次注意,要把请求的端口号换成 8080:# -c表示并发请求数为5000,-n表示总的请求数为10万 # -r表示套接字接收错误时仍然继续执行,-s表示设置每个请求的超时时间为2s $ ab -c 5000 -n 100000 -r -s 2 http://192.168.0.30:8080/ ... apr_pollset_poll: The timeout specified has expired (70007) Total of 5602 requests completed TAP果然,刚才正常运行的 ab ,现在失败了,还报了连接超时的错误。运行 ab 时的-s 参数,设置了每个请求的超时时间为 2s,而从输出可以看到,这次只完成了 5602 个请求。既然是为了得到 ab 的测试结果,把超时时间延长,延长到 30s。延迟增大意味着要等更长时间,为了快点得到结果,我们可以同时把总测试次数,也减少到 10000:$ ab -c 5000 -n 10000 -r -s 30 http://192.168.0.30:8080/ ... Requests per second: 76.47 [#/sec] (mean) Time per request: 65380.868 [ms] (mean) Time per request: 13.076 [ms] (mean, across all concurrent requests) Transfer rate: 44.79 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 0 1300 5578.0 1 65184 Processing: 0 37916 59283.2 1 130682 Waiting: 0 2 8.7 1 414 Total: 1 39216 58711.6 1021 130682 ... YAML再重新看看 ab 的输出,这次的结果显示:每秒请求数(Requests per second)为 76;每个请求的延迟(Time per request)为 65s;建立连接的延迟(Connect)为 1300ms。显然,每个指标都比前面差了很多。回忆一下Netfilter 中,网络包的流向以及 NAT 的原理,会发现,要保证 NAT 正常工作,就至少需要两个步骤:第一,利用 Netfilter 中的钩子函数(Hook),修改源地址或者目的地址。第二,利用连接跟踪模块 conntrack ,关联同一个连接的请求和响应。是不是这两个地方出现了问题呢?我们用前面提到的动态追踪工具 SystemTap 来试试。由于今天案例是在压测场景下,并发请求数大大降低,并且我们清楚知道 NAT 是罪魁祸首。所以,我们有理由怀疑,内核中发生了丢包现象。我们可以回到终端一中,创建一个 dropwatch.stp 的脚本文件,并写入下面的内容:#! /usr/bin/env stap ############################################################ # Dropwatch.stp # Author: Neil Horman <nhorman@redhat.com> # An example script to mimic the behavior of the dropwatch utility # http://fedorahosted.org/dropwatch ############################################################ # Array to hold the list of drop points we find global locations # Note when we turn the monitor on and off probe begin { printf("Monitoring for dropped packets\n") } probe end { printf("Stopping dropped packet monitor\n") } # increment a drop counter for every location we drop at probe kernel.trace("kfree_skb") { locations[$location] <<< 1 } # Every 5 seconds report our drop locations probe timer.sec(5) { printf("\n") foreach (l in locations-) { printf("%d packets dropped at %s\n", @count(locations[l]), symname(l)) } delete locations } CLEAN这个脚本,跟踪内核函数 kfree_skb() 的调用,并统计丢包的位置。文件保存好后,执行下面的 stap 命令,就可以运行丢包跟踪脚本。这里的stap,是 SystemTap 的命令行工具:$ stap --all-modules dropwatch.stp Monitoring for dropped packets GAMS当你看到 probe begin 输出的 “Monitoring for dropped packets” 时,表明 SystemTap 已经将脚本编译为内核模块,并启动运行了。接着,我们切换到终端二中,再次执行 ab 命令:$ ab -c 5000 -n 10000 -r -s 30 http://192.168.0.30:8080/ TAP然后,再次回到终端一中,观察 stap 命令的输出:10031 packets dropped at nf_hook_slow 676 packets dropped at tcp_v4_rcv 7284 packets dropped at nf_hook_slow 268 packets dropped at tcp_v4_rcv BASIC会发现,大量丢包都发生在 nf_hook_slow 位置。这是在 Netfilter Hook 的钩子函数中,出现丢包问题了。但是不是 NAT,还不能确定。接下来,我们还得再跟踪 nf_hook_slow 的执行过程,这一步可以通过 perf 来完成。我们切换到终端二中,再次执行 ab 命令:$ ab -c 5000 -n 10000 -r -s 30 http://192.168.0.30:8080/ TAP然后,再次切换回终端一,执行 perf record 和 perf report 命令# 记录一会(比如30s)后按Ctrl+C结束 $ perf record -a -g -- sleep 30 # 输出报告 $ perf report -g graph,0 POWERSHELL在 perf report 界面中,输入查找命令 / 然后,在弹出的对话框中,输入 nf_hook_slow;最后再展开调用栈,就可以得到下面这个调用图:img从这个图我们可以看到,nf_hook_slow 调用最多的有三个地方,分别是 ipv4_conntrack_in、br_nf_pre_routing 以及 iptable_nat_ipv4_in。换言之,nf_hook_slow 主要在执行三个动作。第一,接收网络包时,在连接跟踪表中查找连接,并为新的连接分配跟踪对象(Bucket)。第二,在 Linux 网桥中转发包。这是因为案例 Nginx 是一个 Docker 容器,而容器的网络通过网桥来实现;第三,接收网络包时,执行 DNAT,即把 8080 端口收到的包转发给容器。到这里,我们其实就找到了性能下降的三个来源。这三个来源,都是 Linux 的内核机制,所以接下来的优化,自然也是要从内核入手。Linux 内核为用户提供了大量的可配置选项,这些选项可以通过 proc 文件系统,或者 sys 文件系统,来查看和修改。除此之外,还可以用 sysctl 这个命令行工具,来查看和修改内核配置。比如,我们今天的主题是 DNAT,而 DNAT 的基础是 conntrack,所以我们可以先看看,内核提供了哪些 conntrack 的配置选项。我们在终端一中,继续执行下面的命令:$ sysctl -a | grep conntrack net.netfilter.nf_conntrack_count = 180 net.netfilter.nf_conntrack_max = 1000 net.netfilter.nf_conntrack_buckets = 65536 net.netfilter.nf_conntrack_tcp_timeout_syn_recv = 60 net.netfilter.nf_conntrack_tcp_timeout_syn_sent = 120 net.netfilter.nf_conntrack_tcp_timeout_time_wait = 120 ... DOS这里最重要的三个指标:net.netfilter.nf_conntrack_count,表示当前连接跟踪数;net.netfilter.nf_conntrack_max,表示最大连接跟踪数;net.netfilter.nf_conntrack_buckets,表示连接跟踪表的大小。所以,这个输出告诉我们,当前连接跟踪数是 180,最大连接跟踪数是 1000,连接跟踪表的大小,则是 65536。回想一下前面的 ab 命令,并发请求数是 5000,而请求数是 100000。显然,跟踪表设置成,只记录 1000 个连接,是远远不够的。实际上,内核在工作异常时,会把异常信息记录到日志中。比如前面的 ab 测试,内核已经在日志中报出了 “nf_conntrack: table full” 的错误。执行 dmesg 命令,可以看到:$ dmesg | tail [104235.156774] nf_conntrack: nf_conntrack: table full, dropping packet [104243.800401] net_ratelimit: 3939 callbacks suppressed [104243.800401] nf_conntrack: nf_conntrack: table full, dropping packet [104262.962157] nf_conntrack: nf_conntrack: table full, dropping packet GAMS其中,net_ratelimit 表示有大量的日志被压缩掉了,这是内核预防日志攻击的一种措施。而当你看到 “nf_conntrack: table full” 的错误时,就表明 nf_conntrack_max 太小了。那是不是,直接把连接跟踪表调大就可以了呢?调节前,得先明白,连接跟踪表,实际上是内存中的一个哈希表。如果连接跟踪数过大,也会耗费大量内存。其实,我们上面看到的 nf_conntrack_buckets,就是哈希表的大小。哈希表中的每一项,都是一个链表(称为 Bucket),而链表长度,就等于 nf_conntrack_max 除以 nf_conntrack_buckets。比如,我们可以估算一下,上述配置的连接跟踪表占用的内存大小:# 连接跟踪对象大小为376,链表项大小为16 nf_conntrack_max*连接跟踪对象大小+nf_conntrack_buckets*链表项大小 = 1000*376+65536*16 B = 1.4 MB EXCEL接下来,我们将 nf_conntrack_max 改大一些,比如改成 131072(即nf_conntrack_buckets的2倍):$ sysctl -w net.netfilter.nf_conntrack_max=131072 $ sysctl -w net.netfilter.nf_conntrack_buckets=65536 ROUTEROS然后再切换到终端二中,重新执行 ab 命令。注意,这次我们把超时时间也改回原来的 2s:$ ab -c 5000 -n 100000 -r -s 2 http://192.168.0.30:8080/ ... Requests per second: 6315.99 [#/sec] (mean) Time per request: 791.641 [ms] (mean) Time per request: 0.158 [ms] (mean, across all concurrent requests) Transfer rate: 4985.15 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 0 355 793.7 29 7352 Processing: 8 311 855.9 51 14481 Waiting: 0 292 851.5 36 14481 Total: 15 666 1216.3 148 14645 TAP可以看到:每秒请求数(Requests per second)为 6315(不用NAT时为6576);每个请求的延迟(Time per request)为 791ms(不用NAT时为760ms);建立连接的延迟(Connect)为 355ms(不用NAT时为177ms)。这个结果,已经比刚才的测试好了很多,也很接近最初不用 NAT 时的基准结果了。不过,你可能还是很好奇,连接跟踪表里,到底都包含了哪些东西?这里的东西,又是怎么刷新的呢?实际上,你可以用 conntrack 命令行工具,来查看连接跟踪表的内容。比如:# -L表示列表,-o表示以扩展格式显示 $ conntrack -L -o extended | head ipv4 2 tcp 6 7 TIME_WAIT src=192.168.0.2 dst=192.168.0.96 sport=51744 dport=8080 src=172.17.0.2 dst=192.168.0.2 sport=8080 dport=51744 [ASSURED] mark=0 use=1 ipv4 2 tcp 6 6 TIME_WAIT src=192.168.0.2 dst=192.168.0.96 sport=51524 dport=8080 src=172.17.0.2 dst=192.168.0.2 sport=8080 dport=51524 [ASSURED] mark=0 use=1 ROUTEROS从这里你可以发现,连接跟踪表里的对象,包括了协议、连接状态、源IP、源端口、目的IP、目的端口、跟踪状态等。由于这个格式是固定的,所以我们可以用 awk、sort 等工具,对其进行统计分析。比如,我们还是以 ab 为例。在终端二启动 ab 命令后,再回到终端一中,执行下面的命令:# 统计总的连接跟踪数 $ conntrack -L -o extended | wc -l 14289 # 统计TCP协议各个状态的连接跟踪数 $ conntrack -L -o extended | awk '/^.*tcp.*$/ {sum[$6]++} END {for(i in sum) print i, sum[i]}' SYN_RECV 4 CLOSE_WAIT 9 ESTABLISHED 2877 FIN_WAIT 3 SYN_SENT 2113 TIME_WAIT 9283 # 统计各个源IP的连接跟踪数 $ conntrack -L -o extended | awk '{print $7}' | cut -d "=" -f 2 | sort | uniq -c | sort -nr | head -n 10 14116 192.168.0.2 172 192.168.0.96 SHELL这里统计了总连接跟踪数,TCP协议各个状态的连接跟踪数,以及各个源IP的连接跟踪数。你可以看到,大部分 TCP 的连接跟踪,都处于 TIME_WAIT 状态,并且它们大都来自于 192.168.0.2 这个 IP 地址(也就是运行 ab 命令的 VM2)。这些处于 TIME_WAIT 的连接跟踪记录,会在超时后清理,而默认的超时时间是 120s,你可以执行下面的命令来查看:$ sysctl net.netfilter.nf_conntrack_tcp_timeout_time_wait net.netfilter.nf_conntrack_tcp_timeout_time_wait = 120 STYLUS所以,如果你的连接数非常大,确实也应该考虑,适当减小超时时间。除了上面这些常见配置,conntrack 还包含了其他很多配置选项,可以参考 nf_conntrack 的 文档 来配置。小结由于 NAT 基于 Linux 内核的连接跟踪机制来实现。所以,在分析 NAT 性能问题时,我们可以先从 conntrack 角度来分析,比如用 systemtap、perf 等,分析内核中 conntrack 的行文;然后,通过调整 netfilter 内核选项的参数,来进行优化。其实,Linux 这种通过连接跟踪机制实现的 NAT,也常被称为有状态的 NAT,而维护状态,也带来了很高的性能成本。sysctl net.netfilter.nf_conntrack_tcp_timeout_time_waitnet.netfilter.nf_conntrack_tcp_timeout_time_wait = 120STYLUS 所以,如果你的连接数非常大,确实也应该考虑,适当减小超时时间。 除了上面这些常见配置,conntrack 还包含了其他很多配置选项,可以参考 nf_conntrack 的 [文档](https://www.kernel.org/doc/Documentation/networking/nf_conntrack-sysctl.txt) 来配置。 ## 小结 由于 NAT 基于 Linux 内核的连接跟踪机制来实现。所以,在分析 NAT 性能问题时,我们可以先从 conntrack 角度来分析,比如用 systemtap、perf 等,分析内核中 conntrack 的行文;然后,通过调整 netfilter 内核选项的参数,来进行优化。 其实,Linux 这种通过连接跟踪机制实现的 NAT,也常被称为有状态的 NAT,而维护状态,也带来了很高的性能成本。 所以,除了调整内核行为外,在不需要状态跟踪的场景下(比如只需要按预定的IP和端口进行映射,而不需要动态映射),我们也可以使用无状态的
0
0
0
浏览量2015
秋月无边

6. 怎么使用 tcpdump 和 Wireshark 分析网络流量?

之前的文章我们介绍了ping,作为最常用的测试服务延迟的工具。很多情况下,ping 可以帮我们定位出延迟问题,不过有时候遇到网络问题,我们可以抓取ping 命令执行时收发的网络包,然后分析这些网络包,进而找出问题根源。tcpdump 和 Wireshark 就是最常用的网络抓包和分析工具,更是分析网络性能必不可少的利器。tcpdump 仅支持命令行格式使用,常用在服务器中抓取和分析网络包。Wireshark 除了可以抓包外,还提供了强大的图形界面和汇总分析工具,在分析复杂的网络情景时,尤为简单和实用。因而,在实际分析网络性能时,先用 tcpdump 抓包,后用 Wireshark 分析,也是一种常用的方法。让我们通过这篇文章,了解怎么使用 tcpdump 和 Wireshark ,来分析网络的性能问题。案例准备本次案例还是基于 Ubuntu 18.04,同样适用于其他的 Linux 系统。案例环境如下:机器配置:2 CPU,8GB 内存。预先安装 tcpdump、Wireshark 等工具,如:# Ubuntu apt-get install tcpdump wireshark # CentOS yum install -y tcpdump wireshark再探 ping前面讲过,ping 是一种最常用的网络工具,常用来探测网络主机之间的连通性以及延迟。不过,虽然 ping 比较简单,但有时候你会发现,ping 工具本身也可能出现异常,比如运行缓慢,但实际网络延迟却并不大的情况。接下来,打开一个终端,SSH 登录到案例机器中,执行下面的命令,来测试案例机器与极客时间官网的连通性和延迟。如果一切正常,会看到如下输出:# ping 3 次(默认每次发送间隔1秒) # 假设DNS服务器还是上一期配置的114.114.114.114 $ ping -c3 geektime.org PING geektime.org (35.190.27.188) 56(84) bytes of data. 64 bytes from 35.190.27.188 (35.190.27.188): icmp_seq=1 ttl=43 time=36.8 ms 64 bytes from 35.190.27.188 (35.190.27.188): icmp_seq=2 ttl=43 time=31.1 ms 64 bytes from 35.190.27.188 (35.190.27.188): icmp_seq=3 ttl=43 time=31.2 ms --- geektime.org ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 11049ms rtt min/avg/max/mdev = 31.146/33.074/36.809/2.649 ms假如你运行时发现 ping 很快就结束了,那就执行下面的命令,再重试一下。# 禁止接收从DNS服务器发送过来并包含googleusercontent的包 $ iptables -I INPUT -p udp --sport 53 -m string --string googleusercontent --algo bm -j DROP根据 ping 的输出,可以发现,geektime.org 解析后的 IP 地址是 35.190.27.188,而后三次 ping 请求都得到了响应,延迟(RTT)都是 30ms 多一点。但汇总的地方,就有点儿意思了。3次发送,收到3次响应,没有丢包,但三次发送和接受的总时间居然超过了 11s(11049ms),这就有些不可思议了吧。这是 DNS 解析缓慢的问题吗?再回去看 ping 的输出,三次 ping 请求中,用的都是 IP 地址,说明 ping 只需要在最开始运行时,解析一次得到 IP,后面就可以只用 IP了。我们再用 nslookup 试试。在终端中执行下面的 nslookup 命令,注意,这次我们同样加了 time 命令,输出 nslookup 的执行时间:$ time nslookup geektime.org Server: 114.114.114.114 Address: 114.114.114.114#53 Non-authoritative answer: Name: geektime.org Address: 35.190.27.188 real 0m0.044s user 0m0.006s sys 0m0.003s可以看到,域名解析还是很快的,只需要 44ms,显然比 11s 短了很多。到这里,再往后该怎么分析呢?这时候就可以用 tcpdump 抓包,查看 ping 在收发哪些网络包。再打开另一个终端(终端二),SSH 登录案例机器后,执行下面的命令:$ tcpdump -nn udp port 53 or host 35.190.27.188知道了 geekbang.org 的 IP 地址是35.190.27.188,也知道 ping 命令会执行 DNS 查询。所以,上面这条命令,就是基于这个规则进行过滤。具体解释一下这条命令。-nn ,表示不解析抓包中的域名(即不反向解析)、协议以及端口号。udp port 53 ,表示只显示 UDP协议的端口号(包括源端口和目的端口)为53的包。host 35.190.27.188 ,表示只显示 IP 地址(包括源地址和目的地址)为35.190.27.188的包。这两个过滤条件中间的“ or ”,表示或的关系,也就是说,只要满足上面两个条件中的任一个,就可以展示出来。接下来,回到终端一,执行相同的 ping 命令:$ ping -c3 geektime.org ... --- geektime.org ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 11095ms rtt min/avg/max/mdev = 81.473/81.572/81.757/0.130 ms命令结束后,再回到终端二中,查看 tcpdump 的输出:tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes 14:02:31.100564 IP 172.16.3.4.56669 > 114.114.114.114.53: 36909+ A? geektime.org. (30) 14:02:31.507699 IP 114.114.114.114.53 > 172.16.3.4.56669: 36909 1/0/0 A 35.190.27.188 (46) 14:02:31.508164 IP 172.16.3.4 > 35.190.27.188: ICMP echo request, id 4356, seq 1, length 64 14:02:31.539667 IP 35.190.27.188 > 172.16.3.4: ICMP echo reply, id 4356, seq 1, length 64 14:02:31.539995 IP 172.16.3.4.60254 > 114.114.114.114.53: 49932+ PTR? 188.27.190.35.in-addr.arpa. (44) 14:02:36.545104 IP 172.16.3.4.60254 > 114.114.114.114.53: 49932+ PTR? 188.27.190.35.in-addr.arpa. (44) 14:02:41.551284 IP 172.16.3.4 > 35.190.27.188: ICMP echo request, id 4356, seq 2, length 64 14:02:41.582363 IP 35.190.27.188 > 172.16.3.4: ICMP echo reply, id 4356, seq 2, length 64 14:02:42.552506 IP 172.16.3.4 > 35.190.27.188: ICMP echo request, id 4356, seq 3, length 64 14:02:42.583646 IP 35.190.27.188 > 172.16.3.4: ICMP echo reply, id 4356, seq 3, length 64这次输出中,前两行,表示 tcpdump 的选项以及接口的基本信息;从第三行开始,就是抓取到的网络包的输出。这些输出的格式,都是 时间戳 协议 源地址.源端口 > 目的地址.目的端口 网络包详细信息(这是最基本的格式,可以通过选项增加其他字段)。网络包的详细信息,本身根据协议的不同而不同。所以,要理解这些网络包的详细含义,就要对常用网络协议的基本格式以及交互原理,有基本的了解。比如,第一条表示,从本地 IP 发送到 114.114.114.114 的 A 记录查询请求,它的报文格式记录在 RFC1035 中,可以点击 这里 查看。在这个 tcpdump 的输出中,36909+ 表示查询标识值,它也会出现在响应中,加号表示启用递归查询。A? 表示查询 A 记录。geektime.org. 表示待查询的域名。30 表示报文长度。接下来的一条,则是从 114.114.114.114 发送回来的 DNS 响应——域名 geektime.org. 的 A 记录值为 35.190.27.188。第三条和第四条,是 ICMP echo request 和 ICMP echo reply,响应包的时间戳 14:02:31.539667,减去请求包的时间戳 14:02:31.508164 ,就可以得到,这次 ICMP 所用时间为 30ms。这看起来并没有问题。但随后的两条反向地址解析 PTR 请求,只看到请求包,却没有应答包。仔细观察它们的时间,会发现,这两条记录都是发出后 5s 才出现下一个网络包,两条 PTR 记录就消耗了 10s。再往下看,最后的四个包,则是两次正常的 ICMP 请求和响应,根据时间戳计算其延迟,也是 30ms。到这里,也就找到了 ping 缓慢的根源,正是两次 PTR 请求没有得到响应而超时导致的。PTR 反向地址解析的目的,是从 IP 地址反查出域名,但事实上,并非所有IP 地址都会定义 PTR 记录,所以 PTR 查询很可能会失败。所以,在你使用 ping 时,如果发现结果中的延迟并不大,而 ping 命令本身却很慢,不要慌,有可能是背后的 PTR 在搞鬼。知道问题后,解决起来就比较简单了,只要禁止 PTR 就可以。还是老路子,执行 man ping 命令,查询使用手册,就可以找出相应的方法,即加上 -n 选项禁止名称解析。比如,我们可以在终端中执行如下命令:$ ping -n -c3 geektime.org PING geektime.org (35.190.27.188) 56(84) bytes of data. 64 bytes from 35.190.27.188: icmp_seq=1 ttl=43 time=33.5 ms 64 bytes from 35.190.27.188: icmp_seq=2 ttl=43 time=39.0 ms 64 bytes from 35.190.27.188: icmp_seq=3 ttl=43 time=32.8 ms --- geektime.org ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 2002ms rtt min/avg/max/mdev = 32.879/35.160/39.030/2.755 ms可以发现,现在只需要 2s 就可以结束,比刚才的 11s 可是快多了。到这里, 我们就通过 tcpdump ,解决了一个最常见的 ping 工作缓慢的问题。案例最后,如果你在开始时,执行了 iptables 命令,那也不要忘了删掉它:$ iptables -D INPUT -p udp --sport 53 -m string --string googleusercontent --algo bm -j DROP不过,明明我们的案例跟 Google 没啥关系,为什么要根据 googleusercontent ,这个毫不相关的字符串来过滤包呢?实际上,如果换一个 DNS 服务器,就可以用 PTR 反查到 35.190.27.188 所对应的域名: $ nslookup -type=PTR 35.190.27.188 8.8.8.8 Server: 8.8.8.8 Address: 8.8.8.8#53 Non-authoritative answer: 188.27.190.35.in-addr.arpa name = 188.27.190.35.bc.googleusercontent.com. Authoritative answers can be found from:虽然查到了 PTR 记录,但结果并非 geekbang.org,而是 188.27.190.35.bc.googleusercontent.com。其实,这也是为什么,案例开始时将包含 googleusercontent 的丢弃后,ping 就慢了。因为 iptables ,实际上是把 PTR 响应给丢了,所以会导致 PTR 请求超时。tcpdump 可以说是网络性能分析最有效的利器。一起看看 tcpdump 的更多使用方法。tcpdumptcpdump 作为常用的一个网络分析工具。它基于 libpcap ,利用内核中的 AF_PACKET 套接字,抓取网络接口中传输的网络包;并提供了强大的过滤规则,帮你从大量的网络包中,挑出最想关注的信息。tcpdump 展示了每个网络包的详细细节,这就要求,在使用前,必须要对网络协议有基本了解。而要了解网络协议的详细设计和实现细节, RFC 当然是最权威的资料。不过,RFC 的内容,对初学者来说可能并不友好。如果对网络协议还不太了解,可以先学习《TCP/IP详解》,特别是第一卷的 TCP/IP 协议族。这是每个程序员都要掌握的核心基础知识。再回到 tcpdump工具本身,它的基本使用方法,还是比较简单的,也就是 tcpdump [选项] [过滤表达式]。当然,选项和表达式的外面都加了中括号,表明它们都是可选的。常用选项如下:比如刚刚用过的是 udp port 53 or host 35.190.27.188 ,表示抓取 DNS 协议的请求和响应包,以及源地址或目的地址为 35.190.27.188 的包。常见过滤表达式如下:输出格式如下:时间戳 协议 源地址.源端口 > 目的地址.目的端口 网络包详细信息其中,网络包的详细信息取决于协议,不同协议展示的格式也不同。详细使用方法可查询 tcpdump 的 man 手册(执行 man tcpdump 也可以得到)。tcpdump 虽然功能强大,可是输出格式却并不直观。特别是,当系统中网络包数比较多(比如PPS 超过几千)的时候,你想从 tcpdump 抓取的网络包中分析问题,实在不容易。对比之下,Wireshark 则通过图形界面,以及一系列的汇总分析工具,提供了更友好的使用界面,让你可以用更快的速度,摆平网络性能问题。接下来,详细来看看它。WiresharkWireshark 作为常用的一个网络分析工具,它最大的好处就是提供了跨平台的图形界面。跟 tcpdump 类似,Wireshark 也提供了强大的过滤规则表达式,同时,还内置了一系列的汇总分析工具。比如,拿刚刚的 ping 案例来说,可以执行下面的命令,把抓取的网络包保存到 ping.pcap 文件中:$ tcpdump -nn udp port 53 or host 35.190.27.188 -w ping.pcap接着,把它拷贝到安装有 Wireshark 的机器中,比如用 scp 把它拷贝到本地来:$ scp host-ip/path/ping.pcap .然后,再用 Wireshark 打开它。打开后,你就可以看到下面这个界面:从 Wireshark 的界面里,可以发现,它不仅以更规整的格式,展示了各个网络包的头部信息;还用了不同颜色,展示 DNS 和 ICMP 这两种不同的协议。也可以一眼看出,中间的两条 PTR 查询并没有响应包。接着,在网络包列表中选择某一个网络包后,在其下方的网络包详情中,还可以看到,这个包在协议栈各层的详细信息。比如,以编号为 5 的 PTR 包为例:可以看到,IP 层(Internet Protocol)的源地址和目的地址、传输层的 UDP 协议(User Datagram Protocol)、应用层的 DNS 协议(Domain Name System)的概要信息。继续点击每层左边的箭头,就可以看到该层协议头的所有信息。比如点击 DNS 后,就可以看到 Transaction ID、Flags、Queries 等 DNS 协议各个字段的数值以及含义。当然,Wireshark 的功能远不止如此。接下来看一个 HTTP 的例子,并理解 TCP 三次握手和四次挥手的工作原理。这个案例我们将要访问的是 http://example.com/ 。进入终端一,执行下面的命令,首先查出 example.com 的 IP。然后,执行 tcpdump 命令,过滤得到的 IP 地址,并将结果保存到 web.pcap 中。$ dig +short example.com 93.184.216.34 $ tcpdump -nn host 93.184.216.34 -w web.pcap实际上,你可以在 host 表达式中,直接使用域名,即 tcpdump -nn host example.com -w web.pcap。接下来,切换到终端二,执行下面的 curl 命令,访问 http://example.com:$ curl http://example.com最后,再回到终端一,按下 Ctrl+C 停止 tcpdump,并把得到的 web.pcap 拷贝出来。使用 Wireshark 打开 web.pcap 后,你就可以在 Wireshark 中,看到如下的界面:由于 HTTP 基于 TCP ,所以你最先看到的三个包,分别是 TCP 三次握手的包。接下来,中间的才是 HTTP 请求和响应包,而最后的三个包,则是 TCP 连接断开时的“三次挥手”包。从菜单栏中,点击 Statistics -> Flow Graph,然后,在弹出的界面中的 Flow type 选择 TCP Flows,你可以更清晰的看到,整个过程中 TCP 流的执行过程:这其实跟各种教程上讲到的,TCP 三次握手和四次挥手很类似,作为对比, 通常看到的 TCP 三次握手和四次挥手的流程如下:不过,对比这两张图,这里抓到的包跟上面的四次挥手,并不完全一样,实际挥手过程只有三个包,而不是四个。其实,之所以有三个包,是因为服务器端收到客户端的 FIN 后,服务器端同时也要关闭连接,这样就可以把 ACK 和 FIN 合并到一起发送,节省了一个包,变成了“三次挥手”。而通常情况下,服务器端收到客户端的 FIN 后,很可能还没发送完数据,所以就会先回复客户端一个 ACK 包。稍等一会儿,完成所有数据包的发送后,才会发送 FIN 包。这也就是四次挥手了。抓包后, Wireshark 中就会显示下面这个界面(原始网络包来自 Wireshark TCP 4-times close 示例,可以点击 [这里](https://wiki.wireshark.org/TCP 4-times close) 下载):当然,Wireshark 的使用方法绝不只有这些,更多的使用方法,同样可以参考 官方文档 以及 WIKI。小结这篇文章讲解了 tcpdump 和 Wireshark 的使用方法,并通过几个案例,学会了如何运用这两个工具来分析网络的收发过程,并找出潜在的性能问题。当针对相同的网络服务,使用 IP 地址快而换成域名却慢很多时,就要想到,有可能是 DNS 在捣鬼。DNS 的解析,不仅包括从域名解析出 IP 地址的 A 记录请求,还包括性能工具帮你,“聪明”地从 IP 地址反查域名的 PTR 请求。实际上, 根据 IP 地址反查域名、根据端口号反查协议名称,是很多网络工具默认的行为,而这往往会导致性能工具的工作缓慢。所以,通常,网络性能工具都会提供一个选项(比如 -n 或者 -nn),来禁止名称解析。这篇文章讲解了 tcpdump 和 Wireshark 的使用方法,并通过几个案例,学会了如何运用这两个工具来分析网络的收发过程,并找出潜在的性能问题。当针对相同的网络服务,使用 IP 地址快而换成域名却慢很多时,就要想到,有可能是 DNS 在捣鬼。DNS 的解析,不仅包括从域名解析出 IP 地址的 A 记录请求,还包括性能工具帮你,“聪明”地从 IP 地址反查域名的 PTR 请求。实际上, 根据 IP 地址反查域名、根据端口号反查协议名称,是很多网络工具默认的行为,而这往往会导致性能工具的工作缓慢。所以,通常,网络性能工具都会提供一个选项(比如 -n 或者 -nn),来禁止名称解析。在工作中,当你碰到网络性能问题时,不要忘记tcpdump 和 Wireshark 这两个大杀器。可以用它们抓取实际传输的网络包,再排查是否有潜在的性能问题。
0
0
0
浏览量2033
秋月无边

8.如何排查网络请求延迟变大

网络延迟提到 网络延迟 时,你可能轻松想起它的含义——网络数据传输所用的时间。不过要注意,这个时间可能是单向的,指从源地址发送到目的地址的单程时间;也可能是双向的,即从源地址发送到目的地址,然后又从目的地址发回响应,这个往返全程所用的时间。通常,我们更常用的是双向的往返通信延迟,比如 ping 测试的结果,就是往返延时 RTT(Round-Trip Time)。除了网络延迟外,另一个常用的指标是 应用程序延迟,它是指,从应用程序接收到请求,再到发回响应,全程所用的时间。通常,应用程序延迟也指的是往返延迟,是网络数据传输时间加上数据处理时间的和。ping 基于 ICMP 协议,它通过计算 ICMP 回显响应报文与 ICMP 回显请求报文的时间差,来获得往返延时。这个过程并不需要特殊认证,常被很多网络攻击利用,比如端口扫描工具 nmap、组包工具 hping3 等等。所以,为了避免这些问题,很多网络服务会把 ICMP 禁止掉,这也就导致我们无法用 ping ,来测试网络服务的可用性和往返延时。这时,可以用 traceroute 或 hping3 的 TCP 和 UDP 模式,来获取网络延迟。比如,以 baidu.com 为例,可以执行下面的 hping3 命令,测试机器到百度搜索服务器的网络延迟:# -c表示发送3次请求,-S表示设置TCP SYN,-p表示端口号为80$ hping3 -c 3 -S -p 80 baidu.com HPING baidu.com (eth0 123.125.115.110): S set, 40 headers + 0 data bytes len=46 ip=123.125.115.110 ttl=51 id=47908 sport=80 flags=SA seq=0 win=8192 rtt=20.9 ms len=46 ip=123.125.115.110 ttl=51 id=6788 sport=80 flags=SA seq=1 win=8192 rtt=20.9 ms len=46 ip=123.125.115.110 ttl=51 id=37699 sport=80 flags=SA seq=2 win=8192 rtt=20.9 ms --- baidu.com hping statistic --- 3 packets transmitted, 3 packets received, 0% packet loss round-trip min/avg/max = 20.9/20.9/20.9 ms从 hping3 的结果中,可以看到,往返延迟 RTT 为 20.9ms。用 traceroute ,也可以得到类似结果:# --tcp表示使用TCP协议,-p表示端口号,-n表示不对结果中的IP地址执行反向域名解析 $ traceroute --tcp -p 80 -n baidu.com traceroute to baidu.com (123.125.115.110), 30 hops max, 60 byte packets 1 * * * 2 * * * 3 * * * 4 * * * 5 * * * 6 * * * 7 * * * 8 * * * 9 * * * 10 * * * 11 * * * 12 * * * 13 * * * 14 123.125.115.110 20.684 ms * 20.798 mstraceroute 会在路由的每一跳发送三个包,并在收到响应后,输出往返延时。如果无响应或者响应超时(默认5s),就会输出一个星号。知道了基于 TCP 测试网络服务延迟的方法后,接下来,我们就通过一个案例,来学习网络延迟升高时的分析思路。案例准备下面的案例仍然基于 Ubuntu 18.04,同样适用于其他的 Linux 系统。环境如下:机器配置:2 CPU,8GB 内存。预先安装 docker、hping3、tcpdump、curl、wrk、Wireshark 等工具,比如 apt-get install docker.io hping3 tcpdump curl。由于Wireshark 需要图形界面,如果你的虚拟机没有图形界面,就可以把 Wireshark 安装到其他的机器中(比如 Windows 笔记本)。本次案例用到两台虚拟机,关系如下:接下来,打开两个终端,分别 SSH 登录到两台机器上(以下步骤,假设终端编号与图示VM 编号一致),并安装上面提到的这些工具。案例分析为了对比得出延迟增大的影响,首先在终端一中,执行下面的命令,运行官方 Nginx,它会在 80 端口监听:$ docker run --network=host --name=good -itd nginx fb4ed7cb9177d10e270f8320a7fb64717eac3451114c9fab3c50e02be2e88ba2继续在终端一中,执行下面的命令,运行案例应用,它会监听 8080 端口:$ docker 1114c9fab3c50e02be2e88ba2继续在终端一中,执行下面的命令,运行案例应用,它会监听 8080 端口:$ docker
0
0
0
浏览量2013
秋月无边

1.网络模型Linux网络是怎么工作的呢?

网络模型说到网络,你肯定经常提起七层负载均衡、四层负载均衡,或者三层设备、二层设备等等。那么,这里说的二层、三层、四层、七层又都是什么意思呢?实际上,这些层都来自国际标准化组织制定的 开放式系统互联通信参考模型(Open System Interconnection Reference Model),简称为 OSI 网络模型。为了解决网络互联中异构设备的兼容性问题,并解耦复杂的网络包处理流程,OSI 模型把网络互联的框架分为应用层、表示层、会话层、传输层、网络层、数据链路层以及物理层等七层,每个层负责不同的功能。其中,应用层,负责为应用程序提供统一的接口。表示层,负责把数据转换成兼容接收系统的格式。会话层,负责维护计算机之间的通信连接。传输层,负责为数据加上传输表头,形成数据包。网络层,负责数据的路由和转发。数据链路层,负责MAC寻址、错误侦测和改错。物理层,负责在物理网络中传输数据帧。但是 OSI 模型还是太复杂了,也没能提供一个可实现的方法。所以,在 Linux 中,我们实际上使用的是另一个更实用的四层模型,即 TCP/IP 网络模型。TCP/IP 模型,把网络互联的框架分为应用层、传输层、网络层、网络接口层等四层,其中,应用层,负责向用户提供一组应用程序,比如 HTTP、FTP、DNS 等。传输层,负责端到端的通信,比如 TCP、UDP 等。网络层,负责网络包的封装、寻址和路由,比如 IP、ICMP 等。网络接口层,负责网络包在物理网络中的传输,比如 MAC 寻址、错误侦测以及通过网卡传输网络帧等。TCP/IP 与 OSI 模型的关系如下所示:当然了,虽说 Linux 实际按照 TCP/IP 模型,实现了网络协议栈,但在平时的学习交流中,我们习惯上还是用 OSI 七层模型来描述。比如,说到七层和四层负载均衡,对应的分别是 OSI 模型中的应用层和传输层(而它们对应到 TCP/IP 模型中,实际上是四层和三层)。TCP/IP 模型包括了大量的网络协议,这些协议的原理以及核心基础知识。可以通过**《TCP/IP 详解》**的卷一和卷二进行学习。Linux网络栈有了 TCP/IP 模型后,在进行网络传输时,数据包就会按照协议栈,对上一层发来的数据进行逐层处理;然后封装上该层的协议头,再发送给下一层。当然,网络包在每一层的处理逻辑,都取决于各层采用的网络协议。比如在应用层,一个提供 REST API 的应用,可以使用 HTTP 协议,把它需要传输的 JSON 数据封装到 HTTP 协议中,然后向下传递给 TCP 层。而封装做的事情就很简单了,只是在原来的负载前后,增加固定格式的元数据,原始的负载数据并不会被修改。比如,以通过 TCP 协议通信的网络包为例,通过下面这张图,可以看到应用程序数据在每个层的封装格式。其中:传输层在应用程序数据前面增加了 TCP 头;网络层在 TCP 数据包前增加了 IP 头;而网络接口层,又在 IP 数据包前后分别增加了帧头和帧尾。这些新增的头部和尾部,都按照特定的协议格式填充,想了解具体格式,可以查看协议的文档。这些新增的头部和尾部,增加了网络包的大小,但我们都知道,物理链路中并不能传输任意大小的数据包。网络接口配置的最大传输单元(MTU),就规定了最大的 IP 包大小。在我们最常用的以太网中,MTU 默认值是 1500(这也是 Linux 的默认值)。一旦网络包超过 MTU 的大小,就会在网络层分片,以保证分片后的 IP 包不大于MTU 值。显然,MTU 越大,需要的分包也就越少,自然,网络吞吐能力就越好。理解了 TCP/IP 网络模型和网络包的封装原理后,Linux 内核中的网络栈,其实也类似于 TCP/IP 的四层结构。如下图所示,就是 Linux 通用 IP 网络栈的示意图:我们从上到下来看这个网络栈,可以发现,最上层的应用程序,需要通过系统调用,来跟套接字接口进行交互;套接字的下面,就是前面提到的传输层、网络层和网络接口层;最底层,则是网卡驱动程序以及物理网卡设备。网卡作为发送和接收网络包的基本设备。在系统启动过程中,网卡通过内核中的网卡驱动程序注册到系统中。而在网络收发过程中,内核通过中断跟网卡进行交互。再结合前面提到的 Linux 网络栈,可以看出,网络包的处理非常复杂。所以,网卡硬中断只处理最核心的网卡数据读取或发送,而协议栈中的大部分逻辑,都会放到软中断中处理。Linux网络收发流程了解了 Linux 网络栈后,我们再来看看, Linux 到底是怎么收发网络包的。注意,以下内容都以物理网卡为例。事实上,Linux 还支持众多的虚拟网络设备,而它们的网络收发流程会有一些差别。网络包的接收流程我们先来看网络包的接收流程。当一个网络帧到达网卡后,网卡会通过 DMA 方式,把这个网络包放到收包队列中;然后通过硬中断,告诉中断处理程序已经收到了网络包。接着,网卡中断处理程序会为网络帧分配内核数据结构(sk_buff),并将其拷贝到 sk_buff 缓冲区中;然后再通过软中断,通知内核收到了新的网络帧。接下来,内核协议栈从缓冲区中取出网络帧,并通过网络协议栈,从下到上逐层处理这个网络帧。比如,在链路层检查报文的合法性,找出上层协议的类型(比如 IPv4 还是 IPv6),再去掉帧头、帧尾,然后交给网络层。网络层取出 IP 头,判断网络包下一步的走向,比如是交给上层处理还是转发。当网络层确认这个包是要发送到本机后,就会取出上层协议的类型(比如 TCP 还是 UDP),去掉 IP 头,再交给传输层处理。传输层取出 TCP 头或者 UDP 头后,根据 <源 IP、源端口、目的 IP、目的端口> 四元组作为标识,找出对应的 Socket,并把数据拷贝到 Socket 的接收缓存中。最后,应用程序就可以使用 Socket 接口,读取到新接收到的数据了。流程图如下所示,这张图的左半部分表示接收流程,而图中的粉色箭头则表示网络包的处理路径。网络包的发送流程了解网络包的接收流程后,就很容易理解网络包的发送流程。网络包的发送流程就是上图的右半部分,很容易发现,网络包的发送方向,正好跟接收方向相反。首先,应用程序调用 Socket API(比如 sendmsg)发送网络包。由于这是一个系统调用,所以会陷入到内核态的套接字层中。套接字层会把数据包放到 Socket 发送缓冲区中。接下来,网络协议栈从 Socket 发送缓冲区中,取出数据包;再按照 TCP/IP 栈,从上到下逐层处理。比如,传输层和网络层,分别为其增加 TCP 头和 IP 头,执行路由查找确认下一跳的 IP,并按照 MTU 大小进行分片。分片后的网络包,再送到网络接口层,进行物理地址寻址,以找到下一跳的 MAC 地址。然后添加帧头和帧尾,放到发包队列中。这一切完成后,会有软中断通知驱动程序:发包队列中有新的网络帧需要发送。最后,驱动程序通过 DMA ,从发包队列中读出网络帧,并通过物理网卡把它发送出去。小结这篇文章梳理了 Linux 网络的工作原理。多台服务器通过网卡、交换机、路由器等网络设备连接到一起,构成了相互连接的网络。由于网络设备的异构性和网络协议的复杂性,国际标准化组织定义了一个七层的 OSI 网络模型,但是这个模型过于复杂,实际工作中的事实标准,是更为实用的 TCP/IP 模型。TCP/IP 模型,把网络互联的框架,分为应用层、传输层、网络层、网络接口层等四层,这也是 Linux 网络栈最核心的构成部分。应用程序通过套接字接口发送数据包,先要在网络协议栈中从上到下进行逐层处理,最终再送到网卡发送出去。而接收时,同样先经过网络栈从下到上的逐层处理,最终才会送到应用程序。
0
0
0
浏览量2195
秋月无边

计算机基础——Linux网络模型详解

深入了解学习Linux网络的工作原理和性能指标
0
0
0
浏览量2698
秋月无边

让Ansible使用jinja2模版部署自定义文件就这么简单

1. Jinja2 模板概述官网地址(中文网站)http://docs.jinkan.org/docs/jinja2/Jinja2 是一个现代的,设计者友好的,仿照 Django 模板的 Python 模板语言。 它速度快,被广泛使用,并且提供了可选的沙箱模板执行环境保证安全。2. Ansible Jinja2模板背景介绍目前Nginx的配置文件在所有的服务器上都是相同的,但我希望能根据每一台服务器的性能去定制服务的启动进程。同时定制每一台Nginx服务的响应头,以便于当某台服务出现问题时能快速定位到具体的服务器。要做这样的定制势必会导致一个问题,Nginx 在每台物理服务器上的配置文件都不一样,这样的配置文件如何管理呢?再使用copy 模块去做管理显然已经不合适。此时使用Ansible 提供的另一个模板(template) 功能,它可以帮助我们完美的解决问题。3. Ansible 如何使用 jinja2 模板Ansible 使用 jinja2 模板,也就是 template 模板。该模块和 copy 模块一样,都是将文件复制到目标机器,但是区别在于 template 模块可以获取要复制文件中的变量的值,而 copy 则是原封不动的把文件内容复制过去。实际运用,比如:针对不同的主机定义不同的变量,template 会在将文件分发前读取变量到 jinja2 模板,之后再然后分发到不同的被管理主机上。4. Jinja2 常用语法Jinja2是基于Python书写的模板引擎。功能比较类似于PHP的smarty模板。1)要想在配置文件中使用jinja2,playbook中的tasks 必须使用template模块2)模板配置文件里面使用变量,比如 {{ PORT }} 或使用 {{ facts 变量 }}5. 基本语法jinja2 文件以 .j2 为后缀, 也可以不写后缀。jinja2 中存在 三种定界符注释: {# 注释内容 #}变量引用: {{ var }}逻辑表达: {% %}注释{# … #}:要把模板中一行或多行注释掉,默认的注释语法。赋值为变量赋值,优先级高于 playbook 中的优先级。{% set username = 'zhang' %} {% set navigation = [('index.html', 'Index'), ('about.html', 'About')] %}变量{{ … }}:把表达式的结果打印到模板上。你可以使用点( . )来访问变量的属性,作为替代,也可以使用所谓的“下标”语 法( [] )。如下示例:{{ foo.bar }} {{ foo['bar'] }}示例:{{ a_variable }}、{{ foo.bar }}、{{ foo[‘bar’] }}花括号不是变量的一部分,而是打印语句的重要一部分。6. 条件判断Jinja 中的 if 语句可比 Python 中的 if 语句。在最简单的形式中,你可以测试一个变量是否未定义,为空或 false:简单形式:{% if 条件表达式 %} …… {% endif %}多分支形式:{% if 条件表达式 %} …… {% elif 条件表达式 %} …… {% else %} …… {% endif %}例如:{# 如果定义了 idc 变量, 则输出 #} {% if idc is defined %} {{ idc }} {% elif %} 没有定义 {% endif %}7. 循环语句for 循环语句{% for user in users %} {{ user }} #user 变量将遍历 users {% endfor %}{% for myhost in groups['myhosts'] %} #列出 myhosts 组中所有主机 {{ myhosts }} {% endfor %}{# 列举出 dbservers 这个 group 中的所有主机 #} {% for host in groups['dbservers'] %} {{ host }} {% endfor %}8. 空白控制默认配置中,模板引擎不会对空白做进一步修改,所以每个空白(空格、制表符、换行符 等等)都会原封不动返回。此外,你也可以手动剥离模板中的空白。当你在块(比如一个 for 标签、一段注释或变量表达式)的开始或结束放置一个减号( - ),可以移除块前或块后的空白。如下:{% for item in range(1,9) -%} {{ item }} {%- endfor %}输出的所有元素前后不会有任何空白,输出会是:1234567899. 过滤器(这个东西嘛,在Ansible高级运用当中会经常使用和涉及。所以呢,在我们现阶段,只做了解已经足够。)变量可以通过 过滤器 修改。过滤器与变量用管道符号( | )分割,并且也可以用圆括号传递可选参数。多个过滤器可以链式调用,前一个过滤器的输出会被作为后一个过滤器的输入。例如 {{ name|striptags|title }} 会移除 name 中的所有 HTML 标签并且改写 为标题样式的大小写格式。过滤器接受带圆括号的参数,如同函数调用。这个例子会 把一个列表用逗号连接起来: {{ list|join(’, ') }}变量过滤器:把输出结果改写为指定格式{{ output | to_json }} #以 json 格式输出 {{ output | to_yaml }} #以 yaml 格式输出 {{ output | from_json }} #对 json 格式字符串进行解析 {{ output | from_yaml }} #对 yaml 格式字符串进行解析内置过滤器清单http://docs.jinkan.org/docs/jinja2/templates.html#builtin-filtersansible 自带过滤器https://docs.ansible.com/ansible/latest/user_guide/playbooks_filters.html?highlight=filter练习创建目录并创建配置文件和主机清单[student@servera ]$ mkdir template [student@servera ]$ cd template [student@servera template]$ cat ansible.cfg [defaults] inventory = hosts [privilege_escalation] become=True become_method=sudo become_user=root become_ask_pass=False [student@servera template]$ cat hosts servera按要求编写jinja2模版[student@servera template]$ cat motd.j2 This is the system {{ ansible_hostname }}. You cat ask {{ system_owner }} for access.按要求编写剧本[student@servera template]$ cat motd.yml --- - name: config motd hosts: servera vars: system_owner: "金鱼哥" tasks: - name: template template: src: motd.j2 dest: /etc/motd owner: root group: root mode: 0644执行剧本[student@servera template]$ ansible-playbook motd.yml PLAY [config motd] ********************************************************************** TASK [Gathering Facts] ****************************************************************** ok: [servera] TASK [template] ************************************************************************* changed: [servera] PLAY RECAP *88888************************************************************************ servera : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0[root@servera ~]# ssh root@servera Last login: Mon Nov 8 14:30:47 2021 from 192.168.159.1 This is the system servera. You cat ask 金鱼哥 for access.总结介绍Jinja2模板。Jinja2 常用语法和基本语法的展示。相关控制:条件判断、循环语句、过滤器。
0
0
0
浏览量2003
秋月无边

七、重定向及管道

7.1 标准输入和输出程序:指令+数据读入数据:Input输出数据:Output打开的文件都有一个fd: file descriptor (文件描述符)文件描述符定义文件描述符:是内核为了高效管理已被打开的文件所创建的索引,用于指向被打开的文件,所有执行I/O操作的系统调用都通过文件描述符;文件描述符是一个简单的非负整数,用以标明每一个被进程所打开的文件,程序刚刚启动的时候,第一个打开的文件是0,第二个是1,依此类推。也可以理解为是一个文件的身份ID。用户通过操作系统处理信息的过程中,使用的交互设备文件(键盘,鼠标,显示器)Linux给程序提供三种 I/O 设备标准输入(STDIN) -0 默认接受来自终端窗口的输入标准输出(STDOUT)-1 默认输出到终端窗口标准错误(STDERR) -2 默认输出到终端窗口范例:文件描述符[root@servera ~]# ll /dev/std* lrwxrwxrwx. 1 root root 15 Mar 25 19:21 /dev/stderr -> /proc/self/fd/2 lrwxrwxrwx. 1 root root 15 Mar 25 19:21 /dev/stdin -> /proc/self/fd/0 lrwxrwxrwx. 1 root root 15 Mar 25 19:21 /dev/stdout -> /proc/self/fd/17.2 I/O重定向 redirectI/O重定向:将默认的输入,输出或错误对应的设备改变,指向新的目标7.2.1 标准输出和错误重新定向STDOUT和STDERR可以被重定向到指定文件,而非默认的当前终端格式:命令 操作符号 文件名支持的操作符号包括:1> 或 > 把STDOUT重定向到文件 2> 把STDERR重定向到文件 &> 把标准输出和错误都重定向 >& 把标准输出和错误都重定向,即和上面功能一样,建议使用上面方式以上如果文件已存在,文件内容会被覆盖set -C 禁止将内容覆盖已有文件,但可追加, 利用 >| 仍可强制覆盖 set +C 允许覆盖,默认范例:[root@servera ~]# ls ~ > /tmp/ls [root@servera ~]# cat /tmp/ls anaconda-ks.cfg Desktop Documents Downloads initial-setup-ks.cfg Music passwd Pictures Public set Templates Videos [root@servera ~]# ls xxx > /tmp/error ls: cannot access 'xxx': No such file or directory [root@servera ~]# cat /tmp/error [root@servera ~]# ls xxx 2> /tmp/error [root@servera ~]# cat /tmp/error ls: cannot access 'xxx': No such file or directory [root@servera ~]# ls ~ xxx &> all [root@servera ~]# cat all ls: cannot access 'xxx': No such file or directory /root: all anaconda-ks.cfg Desktop Documents Downloads initial-setup-ks.cfg Music passwd Pictures Public set Templates Videos追加>> 可以在原有内容基础上,追加内容把输出和错误重新定向追加到文件>> 追加标准输出重定向至文件2>> 追加标准错误重定向至文件范例:[root@servera ~]# ls /opt xxx &>> all [root@servera ~]# cat all ls: cannot access 'xxx': No such file or directory /root: all anaconda-ks.cfg Desktop Documents Downloads initial-setup-ks.cfg Music passwd Pictures Public set Templates Videos ls: cannot access 'xxx': No such file or directory /opt: test 7.2.2 标准输入重定向从文件中导入STDIN,代替当前终端的输入设备,使用 < 来重定向标准输入某些命令能够接受从文件中导入的STDIN如bc命令范例:[root@servera ~]# echo 2^3 > bc.log [root@servera ~]# cat bc.log 2^3 [root@servera ~]# bc < bc.log 87.2.3 把多行重定向使用 “<<终止词” 命令从键盘把多行重导向给STDIN,直到终止词位置之前的所有文本都发送给STDIN,有时被称为就地文本(here documents)其中终止词可以是任何一个或多个符号,比如:!,@,$,EOF(End Of File)等,其中EOF比较常用范例:[root@servera ~]# cat > test << EOF > 1 > 2 > 3 > EOF [root@servera ~]# cat test 1 2 3 [root@servera ~]# cat >> test << EOF > 4 > 5 > 6 > EOF [root@servera ~]# cat test 1 2 3 4 5 6小结把上面的描述做个总结,如下:在工作中,使用得最多的形式:两个特别的操作1>&2 把标准输出重定向到标准错误2>&1 把标准错误重定向到标准输出工作中启动脚本的运用截取工作中 JAVA 程序的启动脚本片段:start() { cd ${SOFTHOME} nohup java -server -Xms512m -Xmx1g -XX:+UseG1GC -verbose:gc -Xloggc:${GCLOG} -XX:+PrintGCDateStamps -XX:+PrintGCDetails -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=100M -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=${DUMPPATH} -jar ${SERVICE} --spring.config.location=${CONFIGFILE} >> ${NOHUP} 2>&1 & }将输出定义到指定的变量 ${NOHUP} 中。7.3 管道7.3.1 管道管道(使用符号“|”表示)用来连接多个命令格式:命令1 | 命令2 | 命令3 | …功能说明:将命令1的STDOUT发送给命令2的STDIN,命令2的STDOUT发送到命令3的STDIN所有命令会在当前shell进程的子shell进程中执行组合多种工具的功能[root@servera ~]# echo 2^3 | bc 8 ifconfig | grep ens160 -A 1 | tail -n 1 | tr -s " " | cut -d" " -f3注意:1、管道命令只处理前一个命令正确输出,不处理错误输出2、管道右边的命令,必须能够接收标准输入的数据流命令才行3、管道符可以把两条命令连起来,它可以链接多个命令使用7.3.2 tee利用 tee 命令可以重定向到多个目标,经常配合管道符一起使用格式命令1 | tee [-a ] 文件名 | 命令2 ......以上可以把命令1的STDOUT保存在文件中,做为命令2的输入选项:-a, --append 内容追加到给定的文件而非覆盖 --help  在线帮助即 tee指令会从标准输入设备读取数据,将其内容输出到标准输出设备,同时保存成文件功能:保存不同阶段的输出复杂管道的故障排除同时查看和记录输出[root@servera ~]# echo 2+3 | tee -a bc.log | bc 5 [root@servera ~]# cat << EOF | tee test1 > 2 > 3 > 4 > 5 > EOF 2 3 4 5 [root@servera ~]# cat test1 2 3 4 5
0
0
0
浏览量2004
秋月无边

Ansible:Ansible临时命令这招功夫就应该要这样耍

简介Ad-Hoc 指的临时意思,就像在命令行写的shell命令就是临时命令,在文件中写的shell命令就是脚本 。Ad-Hoc 就是在命令行直接执行的内容,主要用于临时命令使用场景。(说这么多废话,就是在命令行上运行需要的命令嘛,扎马步都解释这么多。)语法ansible host-pattern -m module [-a ‘module arguments’] [-i inventory]指令 匹配规则的主机清单 -m 模块名 选项host-pattern是inventory中定义的主机或主机组,可以使用 “.” 或 “*” 或 “:” 等特殊字符的匹配型字符串,host-pattern是必须项,不可忽略。常用选项--version 显示版本 -a 模块参数(如果有) -m module 指定模块,默认为command -v 详细过程 –vv -vvv更详细 --list-hosts 显示主机列表,可简写--list -C, --check 检查,并不执行 -T, --timeout=TIMEOUT 执行命令的超时时间,默认10s -u, --user=REMOTE_USER 执行远程执行的用户 -U, SUDO_USER, --sudo-user 指定sodu用户 -b, --become 代替旧版的sudo 切换 --become-method 提权的方法 -k, --ask-pass 提示连接密码,默认Key验证 -K,--ask-become-pass 提示使用sudo密码 2. 招式:模块这个存放各种招式的地方,难道是传说中的藏经阁?位置Ansible模块存放位置:/usr/lib/python2.7/site-packages/ansible/modules # 在系统默认的python目录(不同python版本位置有所不同。)官网模块描述信息https://docs.ansible.com/ansible/latest/user_guide/modules.htmlhttps://docs.ansible.com/ansible/2.9/user_guide/modules_intro.html官网模块分类信息https://docs.ansible.com/ansible/latest/modules/modules_by_category.html # 最新版本https://docs.ansible.com/ansible/2.9/modules/modules_by_category.html#modules-by-category # 2.9版本帮助ansible-doc -l 查看列表ansible-doc modulename 查看模块帮助文件怎么说好呢,还是要善用帮助,多help一下去理解,总有好处。3. 基础招式:ansible的简单使用示范环境:[student@servera ~]$ cat hosts servera serverb [webs] servera serverb1.测试主机连通性ansible -i hosts webs -m ping servera | SUCCESS => { "changed": false, "ping": "pong" } serverb | SUCCESS => { "changed": false, "ping": "pong" } ansible webs -m ping [WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all' [WARNING]: Could not match supplied host pattern, ignoring: webs -i inventory 主机清单文件,不加此选项,默认是在/etc/ansible/hosts,(说白了,会匹配配置文件。)-m 指定模块注意在使用Ansible之前,请在目标主机上保存fingerprint指纹,否则会出现Please add this host’s fingerprint to your known_hosts的错误使用ssh 用户@目标主机连接一下,输入yes,保存下指纹即可(别和我说这个都不会?你真不会?马上踢出山,之后让你回去尝试一下,不就是首次ssh过去时那段OOXX的提示嘛。)2.执行uptime命令,查看返回结果[student@servera ~]$ ansible -i hosts webs -m command -a "uptime" servera | CHANGED | rc=0 >> 00:11:00 up 4:42, 1 user, load average: 0.00, 0.01, 0.05 serverb | CHANGED | rc=0 >> 00:11:00 up 14 min, 1 user, load average: 0.00, 0.01, 0.05 command是执行命令模块-a 是模块的参数可以把主机写在选项的最后面,增加可读性3.查看内核版本号[student@servera ~]$ ansible -i hosts -m command -a "uname -r" webs serverb | CHANGED | rc=0 >> 4.18.0-80.el8.x86_64 servera | CHANGED | rc=0 >> 4.18.0-80.el8.x86_64 4.增加一个用户[student@servera ~]$ ansible -i hosts -m command -a "useradd test" webs servera | FAILED | rc=1 >> useradd: Permission denied. useradd: cannot lock /etc/passwd; try again later.non-zero return code serverb | FAILED | rc=1 >> useradd: Permission denied. useradd: cannot lock /etc/passwd; try again later.non-zero return code [student@servera ~]$ ansible -i hosts -m command -a "whoami" webs serverb | CHANGED | rc=0 >> student servera | CHANGED | rc=0 >> student [student@servera ~]$ ansible -i hosts -m command -a "whoami" webs -u root servera | CHANGED | rc=0 >> root serverb | CHANGED | rc=0 >> root [student@servera ~]$ ansible -i hosts -m command -a "useradd test" webs -u root servera | CHANGED | rc=0 >> serverb | CHANGED | rc=0 >> 5. 注意事项主控端若不设置被控端用户(–user REMOTE_USER),则被管控时,默认被控端会使用主控端当前的用户(演示使用的是student用户)来进行相关的任务操作,因此,若被控端没有主控端当前用户的时候(例如,serverb没有student用户),就会报错。总结,要对使用用户进行合理规划并设置好对应的权限。(总觉被人忽悠,基础招式,我早会了,快上大招吧。)4. 各种真经:ansible的常用模块2015年底270多个模块,2016年达到540个,2018年01月12日有1378个模块,2018年07月15日1852个模块,2019年05月25日(ansible 2.7.10)时2080个模块,2020年03月02日有3387个模块,虽然模块众多,但最常用的模块也就2,30个而已,针对特定业务只用10几个模块。示范环境:[root@servera ~]# cat hosts servera serverb [test] servera serverb ping功能:尝试连接到主机,验证并返回pong成功。对于Windows目标,请改用win_ping模块。不使用icmp协议,使用ssh协议。例子:# ansible servera -m ping -i hosts servera | SUCCESS => { "changed": false, "ping": "pong" > 返回pong表明成功通讯 } command功能:在远程节点上执行命令变量 和操作符号 “<”, “>”, “|”, “;” and “&” 不能正常工作。如果需要使用,请使用shell模块。Ansible默认不指定模块时,将使用此模块。shell功能:在远程节点上执行命令。与command模块使用一致,但是,变量 和操作符号 “<”, “>”, “|”, “;” and “&” 能正常工作。下面2个例子对比能清晰的表示出不同的地方:[root@servera ~]# ansible servera -m command -a 'echo $RANDOM' -i hosts servera | CHANGED | rc=0 >> $RANDOM [root@servera ~]# ansible servera -m shell -a 'echo $RANDOM' -i hosts servera | CHANGED | rc=0 >> 7483 定义在 ~/.bashrc 或 ~/.bash_profile 中的环境变量shell模块由于没有加载,所以无法识别;如果需要使用自定义的环境变量,就需要在最开始,执行加载自定义脚本的语句。# ansible servera -m shell -a "df -h | awk '{print $5}'" -i hosts # “$”不能正常工作 servera | CHANGED | rc=0 >> Filesystem Size Used Avail Use% Mounted on /dev/vda1 40G 1.2G 39G 3% / devtmpfs 475M 0 475M 0% /dev tmpfs 496M 0 496M 0% /dev/shm tmpfs 496M 13M 483M 3% /run tmpfs 496M 0 496M 0% /sys/fs/cgroup tmpfs 100M 0 100M 0% /run/user/0 复杂命令,即使使用shell也可能会失败。解决办法:写到脚本时,copy到远程,执行,再把需要的结果拉回执行命令的机器。# ansible servera -m shell -a "df -hT|sed '1d'|head -1" -i hosts # "|"能正常工作 servera | CHANGED | rc=0 >> /dev/vda1 xfs 40G 1.2G 39G 3% / script功能:把脚本复制到远程节点后,在远程节点本地运行脚本。给定的脚本将通过远程节点上的shell环境进行处理。这个模块在远程系统上不需要python,就像原始脚本一样。以上面不能正常工作(df -h | awk ‘{print $5}’)的例子来测试:# cat test.sh #!/bin/bash USE=`df -h | awk '{print $5}'` echo $USE # ansible servera -m script -a "/root/test.sh" -i hosts servera | CHANGED => { "changed": true, "rc": 0, "stderr": "Shared connection to servera closed.\r\n", "stderr_lines": [ "Shared connection to servera closed." ], "stdout": "Use% 3% 0% 0% 3% 0% 0%\r\n", "stdout_lines": [ "Use% 3% 0% 0% 3% 0% 0%" ] } copy功能:复制文件或目录到远程节点。默认会覆盖目标文件backup: 在覆盖之前将原文件备份,备份文件包含时间信息。有两个选项:yes|nocontent: 用于替代"src",可以直接设定指定文件的内容,相当于echo 重定向内容到文件dest: 必选项。要将源文件复制到的远程主机的绝对路径,如果源文件是一个目录,那么该路径也必须是个目录directory_mode: 递归的设定目录的权限,默认为系统默认权限force: 如果目标主机包含该文件,但内容不同,如果设置为yes,则强制覆盖,如果为no,则只有当目标主机的目标位置不存在该文件时,才复制。默认为yessrc: 要复制到远程主机的文件在本地的地址,可以是绝对路径,也可以是相对路径。如果路径是一个目录,它将递归复制。在这种情况下,如果路径使用 “/” 来结尾,则只复制目录里的内容,如果没有使用 “/” 来结尾,则包含目录在内的整个内容全部复制,类似于rsync# ansible -i hosts servera -m copy -a 'src=/root/test.sh dest=/root backup=yes' servera | CHANGED => { "changed": true, "checksum": "cc0d01995c45d2dbaa45bc4035d45f02ef71b473", "dest": "/root/test.sh", "gid": 0, "group": "root", "md5sum": "5b63433c46dc57d4d730361c5390fc6d", "mode": "0644", "owner": "root", "secontext": "system_u:object_r:admin_home_t:s0", "size": 53, "src": "/root/.ansible/tmp/ansible-tmp-1599190670.37-70286513836843/source", "state": "file", "uid": 0 } # ansible -i hosts servera -m command -a 'ls' servera | CHANGED | rc=0 >> anaconda-ks.cfg original-ks.cfg test.sh 复制目录时,斜线不要写# ansible -i hosts servera -m copy -a 'src=/root/abc dest=/root' servera | CHANGED => { "changed": true, "checksum": "4e1243bd22c66e76c2ba9eddc1f91394e57f9f83", "dest": "/root/abc/test.txt", "gid": 0, "group": "root", "md5sum": "d8e8fca2dc0f896fd7cb4cb0031ba249", "mode": "0644", "owner": "root", "secontext": "system_u:object_r:admin_home_t:s0", "size": 5, "src": "/root/.ansible/tmp/ansible-tmp-1599190972.15-137237299762028/source", "state": "file", "uid": 0 } 根据内容生成文件,相当于echo abc123 > /root/123.txt# ansible -i hosts servera -m copy -a 'content="abc123" dest=/root/123.txt' servera | CHANGED => { "changed": true, "checksum": "6367c48dd193d56ea7b0baad25b19455e529f5ee", "dest": "/root/123.txt", "gid": 0, "group": "root", "md5sum": "e99a18c428cb38d5f260853678922e03", "mode": "0644", "owner": "root", "secontext": "system_u:object_r:admin_home_t:s0", "size": 6, "src": "/root/.ansible/tmp/ansible-tmp-1599191087.61-13911557669155/source", "state": "file", "uid": 0 } # ansible -i hosts servera -m command -a 'cat /root/123.txt' servera | CHANGED | rc=0 >> abc123 file功能: 设置远程节点的文件的文件属性force: 需要在两种情况下强制创建软链接,一种是源文件不存在但之后会建立的情况下;另一种是目标软链接已存在,需要先取消之前的软链,然后创建新的软链,有两个选项:yes|nogroup: 定义文件/目录的属组mode: 定义文件/目录的权限owner: 定义文件/目录的属主path: 必选项,定义文件/目录的路径recurse: 递归的设置文件的属性,只对目录有效src: 要被链接的源文件的路径,只应用于state=link的情况dest: 被链接到的路径,只应用于state=link的情况state: 操作方法directory:如果目录不存在,创建目录file:即使文件不存在,也不会被创建link:创建软链接hard:创建硬链接touch:如果文件不存在,则会创建一个新的文件,如果文件或目录已存在,则更新其最后修改时间absent:删除目录、文件或者取消链接文件。相当于rm -rf创建空文件,类似于touchansible -i hosts servera -m file -a 'path=/root/filemodule.txt state=touch mode=0666 owner=ftp' servera | CHANGED => { "changed": true, "dest": "/root/filemodule.txt", "gid": 0, "group": "root", "mode": "0666", "owner": "ftp", "secontext": "unconfined_u:object_r:admin_home_t:s0", "size": 0, "state": "file", "uid": 14 } 创建空目录, 类似于mkdir -pansible -i hosts servera -m file -a 'path=/root/filemodules state=directory mode=0666 owner=ftp' servera | CHANGED => { "changed": true, "gid": 0, "group": "root", "mode": "0666", "owner": "ftp", "path": "/root/filemodules", "secontext": "unconfined_u:object_r:admin_home_t:s0", "size": 6, "state": "directory", "uid": 14 }创建软链接 ansible -i hosts servera -m file -a 'path=/root/link.txt state=link src=filemodule.txt' servera | CHANGED => { "changed": true, "dest": "/root/link.txt", "gid": 0, "group": "root", "mode": "0777", "owner": "root", "secontext": "unconfined_u:object_r:admin_home_t:s0", "size": 14, "src": "filemodule.txt", "state": "link", "uid": 0 } cron功能:管理计划任务backup: 对远程主机上的原任务计划内容修改之前做备份cron_file: 如果指定该选项,则用该文件替换远程主机上的cron.d目录下的用户的任务计划day: 日(1-31,,/2,……)hour: 小时(0-23,,/2,……)minute: 分钟(0-59,,/2,……)month: 月(1-12,,/2,……)weekday: 周(0-7,*,……)job: 要执行的任务,依赖于state=presentname: 该任务的描述special_time: 指定什么时候执行,参数:reboot,yearly,annually,monthly,weekly,daily,hourlystate: 确认该任务计划是创建还是删除user: 以哪个用户的身份执行创建计划任务# ansible -i hosts servera -m cron -a 'name="test cron job" minute=*/10 job="/usr/bin/wall hello world"' servera | CHANGED => { "changed": true, "envs": [], "jobs": [ "test cron job" ] } # ansible -i hosts servera -a 'crontab -l' servera | CHANGED | rc=0 >> #Ansible: test cron job */10 * * * * /usr/bin/wall hello world 禁用某个计划任务正确的写法:必须完整的写完,包括name等属性# ansible -i hosts servera -m cron -a 'disabled=yes name="test cron job" minute=*/10 job="/usr/bin/wall hello world"' servera | CHANGED => { "changed": true, "envs": [], "jobs": [ "test cron job" ] } # ansible -i hosts servera -m cron -a 'disabled=yes name="test cron job" job="/usr/bin/wall hello world"' servera | CHANGED => { "changed": true, "envs": [], "jobs": [ "test cron job" ] } # ansible -i hosts servera -a 'crontab -l' servera | CHANGED | rc=0 >> #Ansible: test cron job #* * * * * /usr/bin/wall hello world 删除计划任务# ansible -i hosts servera -m cron -a 'state=absent name="test cron job"' servera | CHANGED => { "changed": true, "envs": [], "jobs": [] } # ansible -i hosts servera -a 'crontab -l' servera | CHANGED | rc=0 >> yum功能:使用yum包管理器来管理软件包config_file: yum的配置文件disable_gpg_check: 关闭gpg_checkdisablerepo: 不启用某个源enablerepo: 启用某个源name: 要进行操作的软件包的名字,也可以传递一个url或者一个本地的rpm包的路径state: Whether to install (‘present’ or ‘installed’, ‘latest’), or remove (‘absent’ or ‘removed’) a package.​ (可选值: present, installed, latest, absent, removed) [Default: present]# ansible -i hosts servera -m yum -a 'name=tree state=latest' servera | CHANGED => { "ansible_facts": { "pkg_mgr": "yum" }, "changed": true, "msg": "", "rc": 0, "results": [ "Loaded plugins: langpacks, search-disabled-repos\nResolving Dependencies\n--> Running transaction check\n---> Package tree.x86_64 0:1.6.0-10.el7 will be installed\n--> Finished Dependency Resolution\n\nDependencies Resolved\n\n================================================================================\n Package Arch Version Repository Size\n================================================================================\nInstalling:\n tree x86_64 1.6.0-10.el7 rhel--server-dvd 46 k\n\nTransaction Summary\n================================================================================\nInstall 1 Package\n\nTotal download size: 46 k\nInstalled size: 87 k\nDownloading packages:\nRunning transaction check\nRunning transaction test\nTransaction test succeeded\nRunning transaction\n Installing : tree-1.6.0-10.el7.x86_64 1/1 \n Verifying : tree-1.6.0-10.el7.x86_64 1/1 \n\nInstalled:\n tree.x86_64 0:1.6.0-10.el7 \n\nComplete!\n" ] } # ansible -i hosts servera -a 'rpm -q tree' servera | CHANGED | rc=0 >> tree-1.6.0-10.el7.x86_64 service功能:配置管理服务arguments: 给命令行提供一些选项 。可以使用别名 argsenabled: 是否开机启动 yes|noname:必选项,服务名称pattern: 定义一个模式,如果通过status指令来查看服务的状态时,没有响应,就会通过ps指令在进程中根据该模式进行查找,如果匹配到,则认为该服务依然在运行runlevel: 运行级别sleep:如果执行了restarted,在则stop和start之间沉睡几秒钟state:对当前服务执行启动,停止、重启、重新加载等操作(started,stopped,restarted,reloaded)# ansible -i hosts servera -m yum -a 'name=httpd state=latest' # ansible -i hosts servera -m service -a 'name=httpd state=started' > 一次只能操作一个服务 servera | CHANGED => { "changed": true, "name": "httpd", "state": "started", "status": { "ActiveEnterTimestampMonotonic": "0", "ActiveExitTimestampMonotonic": "0", "ActiveState": "inactive", ............ user功能:管理用户账号很多选项,与useradd这类系统命令差不多name: 用户名,可以使用别名user范例:创建用户# ansible -i hosts servera -m user -a 'name=hunk shell=/sbin/nologin system=yes comment="name is hunk"' servera | CHANGED => { "changed": true, "comment": "name is hunk", "create_home": true, "group": 993, "home": "/home/hunk", "name": "hunk", "shell": "/sbin/nologin", "state": "present", "system": true, "uid": 996 } 删除用户# ansible -i hosts servera -m user -a 'name=hunk state=absent' servera | CHANGED => { "changed": true, "force": false, "name": "hunk", "remove": false, "state": "absent" }修改用户指定信息# ansible -i hosts servera -m user -a 'name=hunk state=present comment=" hunk is my"'remove:删除用户时一并删除用户家目录,需要与state=absent一起使用# ansible -i hosts servera -m user -a 'name=hunk state=absent remove=yes' servera | CHANGED => { "changed": true, "force": false, "name": "hunk", "remove": true, "state": "absent", "stderr": "userdel: hunk mail spool (/var/spool/mail/hunk) not found\n", "stderr_lines": [ "userdel: hunk mail spool (/var/spool/mail/hunk) not found" ] } state: 操作方法。(present , absent)groups: 添加辅助组group: 指定用户的主组以下这个例子注意看,group和groups所代表的含义不同。 - name: add user user: name={{ username }} group=ftp groups={{ groupname }} group功能:添加组或删除组group模块请求的是groupadd, groupdel, groupmod 三个指令用法都是差不多的。gid: 组idname: 组名称state: Present创建Absent删除system: yes|no 是否为系统组# ansible -i hosts servera -m group -a "name=abc state=present gid=1111" servera | CHANGED => { "changed": true, "gid": 1111, "name": "abc", "state": "present", "system": false } # ansible -i hosts servera -m group -a "name=abc state=absent" servera | CHANGED => { "changed": true, "name": "abc", "state": "absent" } 总结遇到不知道如何使用的模块,先 ansible-doc 一下,里面有各种使用选项的说明,同时留意下面的example,这些都是辅助你日后使用的好习惯。多练习,多记忆,多发现。RHCE认证作为基础认证的升级,需要大家在RHCSA的基础上再进行学习,因此,涉及的基础内容需要大家好好进行学习并巩固。有良好的基础才能更上一层楼。好好加油,可以噶。
0
0
0
浏览量2007
秋月无边

十一、监控和管理Linux进程

11.1 什么是进程Process: 运行中的程序的一个副本,是被载入内存的一个指令集合,是资源分配的单位进程ID(Process ID,PID)号码被用来标记各个进程UID、GID、和SELinux语境决定对文件系统的存取和访问权限通常从执行进程的用户来继承存在生命周期进程创建:init:第一个进程,从 rhel7 以后为systemd进程:都由其父进程创建,fork(),父子关系,CoW:Copy On Write(写实复制)进程是通过执行一个静态程序而触发的。静态的程序触发成一个动态的程序。11.1.1 从windows的角度去看待进程打开任务管理器,观察状态打开运行C:\Windows\system32\cmd.exe点击箭头扩展,然后运行一个命令,观察观察进程对资源的使用因此,进程是动态的进程数量的统计11.1.2 从linux的角度去看待进程通过top命令,可以获得动态的类任务管理器页面进程是通过运行一个静态的可执行文件,从而生成的一个动态的进程范例:#第一个终端执行 [root@servera ~]# dd if=/dev/zero of=/dev/null #第二个终端执行 [root@servera ~]# ps aux | grep "dd if" root 6463 98.8 0.0 7324 820 pts/1 R+ 14:55 1:52 dd if=/dev/zero of=/dev/null root 6489 0.0 0.0 12108 1088 pts/2 R+ 14:57 0:00 grep --color=auto dd if进程的拥有者进程在读取或者写入文件的时候,是采用这个拥有者的身份读取和写入的。所以针对需要读取和写入的这个拥有者必须要有权限。   。通常情况下,进程的拥有者为执行者。   。比如一些服务,通常进程的拥有者会在配置文件中指定为该服务的系统用户   。GUID的二进制文件:/usr/bin/passwd进程的资源占用量    。%cpu    。%mem11.2 进程状态进程的基本状态创建状态:进程在创建时需要申请一个空白PCB(process control block进程控制块),向其中填写控制和管理进程的信息,完成资源分配。如果创建工作无法完成,比如资源无法满足,就无法被调度运行,把此时进程所处状态称为创建状态就绪状态:进程已准备好,已分配到所需资源,只要分配到CPU就能够立即运行执行状态:进程处于就绪状态被调度后,进程进入执行状态阻塞状态:正在执行的进程由于某些事件(I/O请求,申请缓存区失败)而暂时无法运行,进程受到阻塞。在满足请求时进入就绪状态等待系统调用终止状态:进程结束,或出现错误,或被系统终止,进入终止状态。无法再执行进程更多的状态:运行态R:running睡眠态S\D:分为两种,可中断:interruptable,不可中断:uninterruptable停止态T:stopped,暂停于内存,但不会被调度,除非手动启动僵死态Z:zombie,僵尸态,结束进程,父进程结束前,子进程不关闭,杀死父进程可以关闭僵死态   的子进程范例:僵尸态[root@servera ~]# bash [root@servera ~]# echo $BASHPID 3988 [root@servera ~]# dd if=/dev/zero of=/dev/null #再开一个终端,停止父进程bash,杀死dd进程,使其进入僵死态 [root@servera ~]# kill -19 3988 [root@servera ~]# kill -9 4018 #方法1:恢复父进程 [root@servera ~]# kill -18 3988 #方法2:杀死父进程 [root@servera ~]# kill -9 398811.3 进程管理和性能相关工具11.3.1 进程树 pstreepstree 可以用来显示进程的父子关系,以树形结构显示来自于psmisc包格式:pstree [OPTION] [ PID | USER ]常用选项:-p 显示PID -T 不显示线程thread,默认显示线程 -u 显示用户切换 -H pid 高亮指定进程及其前辈进程范例:[root@servera ~]# pstree 1 systemd─┬─ModemManager───2*[{ModemManager}] ├─NetworkManager───2*[{NetworkManager}] ├─VGAuthService ├─accounts-daemon───2*[{accounts-daemon}] ├─alsactl ├─atd ├─auditd─┬─sedispatch │ └─2*[{auditd}] ├─avahi-daemon───avahi-daemon ├─bluetoothd ├─chronyd ├─colord───2*[{colord}] [root@servera ~]# pstree user1 bash───ping [root@servera ~]# pstree | grep httpd |-httpd-+-httpd | |-2*[httpd---64*[{httpd}]] | `-httpd---80*[{httpd}] [root@servera ~]# pstree -u | grep httpd |-httpd-+-httpd(apache) | |-2*[httpd(apache)---64*[{httpd}]] | `-httpd(apache)---80*[{httpd}] [root@servera ~]# pstree -p systemd(1)─┬─ModemManager(1002)─┬─{ModemManager}(1041) │ └─{ModemManager}(1054) ├─NetworkManager(1172)─┬─{NetworkManager}(1177) │ └─{NetworkManager}(1178) ├─VGAuthService(996) ├─accounts-daemon(1097)─┬─{accounts-daemon}(1102) │ └─{accounts-daemon}(1108) 范例:高亮显示前辈进程[root@servera ~]# pstree -pH 420711.3.2 进程信息 psps 即process state,可以进程当前状态的快照,默认显示当前终端中的进程,Linux系统各进程的相关信息均保存在/proc/PID目录下的各文件中ps格式ps [OPTION]...支持三种选项:UNIX选项 如: -A -eBSD选项 如: aGNU选项 如: --help常用选项:a 选项包括所有终端中的进程 x 选项包括不链接终端的进程 u 选项显示进程所有者的信息 f 选项显示进程树,相当于 --forest k|--sort 属性 对属性排序,属性前加 - 表示倒序 o 属性… 选项显示定制的信息 pid、cmd、%cpu、%mem L 显示支持的属性列表 -C cmdlist 指定命令,多个命令用,分隔 -L 显示线程 -e 显示所有进程,相当于-A -f 显示完整格式程序信息 -F 显示更完整格式的进程信息 -H 以进程层级格式显示进程相关信息 -u userlist 指定有效的用户ID或名称 -U userlist 指定真正的用户ID或名称 -g gid或groupname 指定有效的gid或组名称 -G gid或groupname 指定真正的gid或组名称 -p pid 显示指pid的进程 --ppid pid 显示属于pid的子进程 -t ttylist 指定tty,相当于 t -M 显示SELinux信息,相当于Zps 输出属性C : ps -ef 显示列 C 表示cpu利用率 VSZ: Virtual memory SiZe,虚拟内存集,线性内存 RSS: ReSident Size, 常驻内存集 STAT:进程状态 R:running S: interruptable sleeping D: uninterruptable sleeping T: stopped Z: zombie +: 前台进程 l: 多线程进程 L:内存分页并带锁 N:低优先级进程 <: 高优先级进程 s: session leader,会话(子进程)发起者 I:Idle kernel thread,新内核新特性(空闲线程) ni: nice值 pri: priority 优先级 rtprio: 实时优先级 psr: processor CPU编号常用组合:aux -ef -eFH -eo pid,tid,class,rtprio,ni,pri,psr,pcpu,stat,comm axo stat,euid,ruid,tty,tpgid,sess,pgrp,ppid,pid,pcpu,comm范例:查看进程详细信息[root@servera ~]# ps -ef UID PID PPID C STIME TTY TIME CMD root 1 0 0 15:17 ? 00:00:02 /usr/lib/systemd/systemd --switched-root --system --deserialize 18 root 2 0 0 15:17 ? 00:00:00 [kthreadd] root 3 2 0 15:17 ? 00:00:00 [rcu_gp] root 4 2 0 15:17 ? 00:00:00 [rcu_par_gp] root 6 2 0 15:17 ? 00:00:00 [kworker/0:0H-kblockd] [root@servera ~]# ps aux USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 1 0.0 0.7 180140 14504 ? Ss 15:17 0:02 /usr/lib/systemd/systemd --switched-root --system --deserialize 18 root 2 0.0 0.0 0 0 ? S 15:17 0:00 [kthreadd] root 3 0.0 0.0 0 0 ? I< 15:17 0:00 [rcu_gp] root 4 0.0 0.0 0 0 ? I< 15:17 0:00 [rcu_par_gp] root 6 0.0 0.0 0 0 ? I< 15:17 0:00 [kworker/0:0H-kblockd] root 8 0.0 0.0 0 0 ? I< 15:17 0:00 [mm_percpu_wq] root 9 0.0 0.0 0 0 ? S 15:17 0:00 [ksoftirqd/0] 范例:#查看进程的父子关系 [root@servera ~]# ps auxf USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 2 0.0 0.0 0 0 ? S 15:17 0:00 [kthreadd] root 3 0.0 0.0 0 0 ? I< 15:17 0:00 \_ [rcu_gp] root 4 0.0 0.0 0 0 ? I< 15:17 0:00 \_ [rcu_par_gp] root 6 0.0 0.0 0 0 ? I< 15:17 0:00 \_ [kworker/0:0H-kblockd] root 8 0.0 0.0 0 0 ? I< 15:17 0:00 \_ [mm_percpu_wq] root 9 0.0 0.0 0 0 ? S 15:17 0:00 \_ [ksoftirqd/0] root 10 0.0 0.0 0 0 ? I 15:17 0:00 \_ [rcu_sched] root 11 0.0 0.0 0 0 ? S 15:17 0:00 \_ [migration/0] root 12 0.0 0.0 0 0 ? S 15:17 0:00 \_ [watchdog/0] #查看进程的特定属性 [root@servera ~]# ps axo pid,cmd,%mem,%cpu PID CMD %MEM %CPU 1 /usr/lib/systemd/systemd -- 0.7 0.0 2 [kthreadd] 0.0 0.0 3 [rcu_gp] 0.0 0.0 4 [rcu_par_gp] 0.0 0.0 6 [kworker/0:0H-kblockd] 0.0 0.0 范例:针对属性排序,rhel6 以下版本不支持#按CPU利用率倒序排序 [root@servera ~]# ps axo pid,cmd,%cpu,%mem k -%cpu PID CMD %CPU %MEM 4568 dd if=/dev/zero of=/dev/nul 88.3 0.0 1 /usr/lib/systemd/systemd -- 0.0 0.7 2 [kthreadd] 0.0 0.0 3 [rcu_gp] 0.0 0.0 4 [rcu_par_gp] 0.0 0.0 6 [kworker/0:0H-kblockd] 0.0 0.0 #按内存倒序排序 [root@servera ~]# ps axo pid,cmd,%cpu,%mem --sort -%mem PID CMD %CPU %MEM 1860 /usr/bin/gnome-shell 0.0 8.3 1900 /usr/bin/Xwayland :1024 -ro 0.0 3.2 1929 /usr/libexec/ibus-x11 --kil 0.0 3.1 1365 /usr/sbin/libvirtd 0.0 2.3 1073 /usr/libexec/platform-pytho 0.0 2.2 1070 /usr/libexec/sssd/sssd_nss 0.0 2.0 1187 /usr/libexec/platform-pytho 0.0 1.7 1975 /usr/libexec/gsd-xsettings 0.0 1.5 1983 /usr/libexec/gsd-color 0.0 1.411.3.3 查看进程信息prtstat可以显示进程信息,来自于psmisc包格式:prtstat [options] PID ...选项:-r raw 格式显示范例:[root@servera ~]# prtstat 1407 Process: httpd State: S (sleeping) CPU#: 0 TTY: 0:0 Threads: 1 Process, Group and Session IDs Process ID: 1407 Parent ID: 1 Group ID: 1407 Session ID: 1407 T Group ID: -1 Page Faults This Process (minor major): 1689 54 Child Processes (minor major): 0 0 CPU Times This Process (user system guest blkio): 0.01 0.09 0.00 0.07 Child processes (user system guest): 0.00 0.00 0.00 Memory Vsize: 288 MB RSS: 11 MB RSS Limit: 18446744073709 MB Code Start: 0x55b6fa9bb000 Code Stop: 0x55b6faa40f60 Stack Start: 0x7fffc2b468a0 Stack Pointer (ESP): 0 Inst Pointer (EIP): 0 Scheduling Policy: normal Nice: 0 RT Priority: 0 (non RT) [root@servera ~]# prtstat -r 1407 pid: 1407 comm: httpd state: S ppid: 1 pgrp: 1407 session: 1407 tty_nr: 0 tpgid: -1 flags: 400100 minflt: 1689 cminflt: 0 majflt: 54 cmajflt: 0 utime: 1 stime: 9 cutime: 0 cstime: 0 priority: 20 nice: 0 num_threads: 1 itrealvalue: 0 starttime: 1054 vsize: 288198656 rss: 2884 rsslim: 18446744073709551615 startcode: 94244376915968 endcode: 94244377464672 startstack: 140736459991200 kstkesp: 0 kstkeip: 0 wchan: 1 nswap: 0 cnswap: 1 exit_signal: 17 processor: 1 rt_priority: 0 policy: 0 delayaccr_blkio_ticks: 7 guest_time: 0 cguest_time: 011.3.4 搜索进程按条件搜索进程ps 选项 | grep ‘pattern’ 灵活 pgrep 按预定义的模式 /sbin/pidof 按确切的程序名称查看pid11.3.4.1 pgrep命令格式pgrep [options] pattern常用选项-u uid: effective user,生效者 -U uid: real user,真正发起运行命令者 -t terminal: 与指定终端相关的进程 -l: 显示进程名 -a: 显示完整格式的进程名 -P pid: 显示指定进程的子进程范例:[root@servera ~]# pgrep -u user1 2593 2623 2657 [root@servera ~]# pgrep -lu user1 2593 bash 2623 bash 2657 ping #错误写法,切记用户选项在后 [root@servera ~]# pgrep -ul user1 pgrep: invalid user name: l [root@servera ~]# pgrep -au user1 2593 -bash 2623 bash [root@servera ~]# pgrep -aP 2623 2695 ping baidu.com [root@servera ~]# pgrep -at pts/1 2563 -bash 2592 su - user1 2593 -bash 2623 bash 2695 ping baidu.com11.3.4.2 pidof命令格式pidof [options] [program [...]]常用选项:-x 按脚本名称查找pid范例:[root@servera ~]# pidof httpd 1928 1927 1926 1924 1407 [root@servera ~]# vim ping.sh [root@servera ~]# chmod a+x ping.sh [root@servera ~]# ./ping.sh [root@servera ~]# pidof -x ping.sh 307611.3.5 负载查询 uptime/proc/uptime 包括两个值,单位 s系统启动时长空闲进程的总时长(按总的CPU核数计算)uptime 和 w 显示以下内容当前时间系统已启动的时间当前上线人数系统平均负载(1、5、15分钟的平均负载,一般不会超过1,超过5时建议警报)系统平均负载: 指在特定时间间隔内运行队列中的平均进程数,通常每个CPU内核的当前活动进程数不大于3,那么系统的性能良好。如果每个CPU内核的任务数大于5,那么此主机的性能有严重问题11.3.6 查看进程实时状态 toptop 提供动态的实时进程状态有许多内置命令帮助:h 或 ? ,按 q 或esc 退出帮助排序: P:以占据的CPU百分比,%CPU M:占据内存百分比,%MEM T:累积占据CPU时长,TIME+ 首部信息(风格)显示: uptime信息:l命令 tasks及cpu信息:t命令 cpu分别显示:1 (数字) memory信息:m命令 退出命令:q 修改刷新时间间隔:s 终止指定进程:k 保存文件:Wtop命令栏位信息简介us:用户空间 sy:内核空间 ni:调整nice时间 id:空闲 wa:等待IO时间 hi:硬中断 si:软中断(模式切换) st:虚拟机偷走的时间top选项:-d # 指定刷新时间间隔,默认为3秒 -b 全部显示所有进程 -n # 刷新多少次后退出示例:top -d 5 -n 511.3.7 RHEL8 新特性 cockpitCockpit 是rhel 8 取入的新特性,是一个基于 Web 界面的应用,它提供了对系统的图形化管理监控系统活动(CPU、内存、磁盘 IO 和网络流量)查看系统日志条目查看磁盘分区的容量查看网络活动(发送和接收)查看用户帐户检查系统服务的状态提取已安装应用的信息查看和安装可用更新(如果以 root 身份登录)并在需要时重新启动系统打开并使用终端窗口范例:安装 cockpit[root@servera ~]# dnf -y install cockpit [root@servera ~]# systemctl enable --now cockpit.socket [root@servera ~]# ss -altun(查看9090端口是否启用)打开浏览器,访问以下地址:https://rhel8主机:909011.3.8 信号发送 killkill:内部命令,可用来向进程发送控制信号,以实现对进程管理,每个信号对应一个数字,信号名称以SIG开头(可省略),不区分大小写显示当前系统可用信号:kill -l trap -l查看帮助:man 7 signal常用信号:1) SIGHUP 无须关闭进程而让其重读配置文件 2) SIGINT 中止正在运行的进程;相当于Ctrl+c 3) SIGQUIT 相当于ctrl+\ 9) SIGKILL 强制杀死正在运行的进程 15) SIGTERM 终止正在运行的进程,默认信号 18) SIGCONT 继续运行 19) SIGSTOP 后台休眠指定信号的方法 :信号的数字标识:1, 2, 9信号完整名称:SIGHUP,sighup信号的简写名称:HUP,hup向进程发送信号:按PID:kill [-s sigspec | -n signum | -sigspec] pid | jobspec ... or kill -l [sigspec]范例kill -1 pid … kill -n 9 pid kill -s SIGINT pid按名称:killall 来自于psmisc包killall可以直接使用信号控制进程,不需要查阅pid等信息killall [-SIGNAL] comm…pkill=killall范例:[root@servera ~]# kill httpd -bash: kill: httpd: arguments must be process or job IDs [root@servera ~]# killall httpd [root@servera ~]# killall httpd httpd: no process found 特殊信号:0信号范例:利用 0 信号实现进程的健康性检查[root@servera ~]# killall -0 ping [root@servera ~]# killall ping [root@servera ~]# killall -0 ping ping: no process found #此方式有局限性,即使进程处于停止或僵尸状态,此方式仍然认为是进程是健康的11.3.9 作业管理Linux的作业控制前台作业:通过终端启动,且启动后一直占据终端后台作业:可通过终端启动,但启动后即转入后台运行(释放终端)让作业运行于后台运行中的作业: Ctrl+z尚未启动的作业: COMMAND &后台作业虽然被送往后台运行,但其依然与终端相关;退出终端,将关闭后台作业。如果希望送往后台后,剥离与终端的关系:nohup COMMAND &>/dev/null &查看当前终端所有作业:jobs作业控制:fg [[%]JOB_NUM]:把指定的后台作业调回前台 bg [[%]JOB_NUM]:让送往后台的作业在后台继续运行 kill [%JOB_NUM]: 终止指定的作业
0
0
0
浏览量2006
秋月无边

运维初哥不要紧,手把手教你运用文件查找、打包和传输文件

📜16.1 文件查找在文件系统上查找符合条件的文件文件查找:locate, find非实时查找(数据库查找):locate实时查找:find📑16.1.1 locatelocate 查询系统上预建的文件索引数据库 /var/lib/mlocate/mlocate.db索引的构建是在系统较为空闲时自动进行(周期性任务),执行updatedb可以更新数据库索引构建过程需要遍历整个根文件系统,很消耗资源来自于mlocate包工作特点:查找速度快模糊查找非实时查找搜索的是文件的全路径,不仅仅是文件名可能只搜索用户具备读取和执行权限的目录格式:locate [OPTION]... [PATTERN]...常用选项-i 不区分大小写的搜索 -n N 只列举前N个匹配项目 -r 使用基本正则表达式范例: locatedb创建数据库[root@servera]# locate conf locate: can not stat () `/var/lib/mlocate/mlocate.db': No such file or directory [root@servera]# updatedb [root@servera]# ll /var/lib/mlocate/mlocate.db -rw-r-----. 1 root slocate 3090337 Apr 7 16:13 /var/lib/mlocate/mlocate.db [root@servera]# locate -n 3 conf /boot/config-4.18.0-193.el8.x86_64 /boot/grub2/i386-pc/configfile.mod /boot/loader/entries/b6d16ca3e4814c4c92e10837fb500b0a-0-rescue.conf范例:#搜索名称或路径中包含“conf”的文件 locate conf #使用Regex来搜索以“.conf”结尾的文件 locate -r '\.conf$'📑16.1.2 findfind 是实时查找工具,通过遍历指定路径完成文件查找工作特点:查找速度略慢精确查找实时查找查找条件丰富可能只搜索用户具备读取和执行权限的目录格式:find [OPTION]... [查找路径] [查找条件] [处理动作]查找路径:指定具体目标路径;默认为当前目录查找条件:指定的查找标准,可以文件名、大小、类型、权限等标准进行;默认为找出指定路径下的所有文件处理动作:对符合条件的文件做操作,默认输出至屏幕范例:[root@servera ~]# find .. ./.bash_logout ./.bash_profile ./.cshrc ./.tcshrc ./anaconda-ks.cfg ./.cache ./.cache/dconf ./.cache/dconf/user ./.cache/libgweather ./.cache/evolution ./.cache/evolution/addressbook ./.cache/evolution/addressbook/trash ./.cache/evolution/calendar ./.cache/evolution/calendar/trash ./.cache/evolution/mail ./.cache/evolution/mail/trash ./.cache/evolution/memos ...🔖16.1.2.1 指定搜索目录层级-maxdepth level 最大搜索目录深度,指定目录下的文件为第1级 -mindepth level 最小搜索目录深度范例:find /etc -maxdepth 2 -mindepth 2范例:[root@servera ~]# mkdir /data/test/test1/test2 -p [root@servera ~]# touch /data/test/f{1..2}.txt [root@servera ~]# touch /data/test/test1/test2/f{3..4}.txt [root@servera data]# tree /data/test/ /data/test/ ├── f1.txt ├── f2.txt └── test1 └── test2 ├── f3.txt └── f4.txt 2 directories, 4 files [root@servera data]# find /data -maxdepth 2 -mindepth 1 /data/test /data/test/f1.txt /data/test/f2.txt /data/test/test1 🔖16.1.2.2 对每个目录先处理目录内的文件,再处理目录本身-depth / -d范例:[root@servera data]# find /data/test /data/test /data/test/f1.txt /data/test/f2.txt /data/test/test1 /data/test/test1/test2 /data/test/test1/test2/f3.txt /data/test/test1/test2/f4.txt [root@servera data]# find /data/test -depth /data/test/f1.txt /data/test/f2.txt /data/test/test1/test2/f3.txt /data/test/test1/test2/f4.txt /data/test/test1/test2 /data/test/test1 /data/test 🔖16.1.2.3 根据文件名和inode查找-name "文件名称":支持使用glob,如:*, ?, [], [^],通配符要加双引号引起来 -iname "文件名称":不区分字母大小写 -inum n 按inode号查找 -samefile name 相同inode号的文件 -links n 链接数为n的文件 -regex “PATTERN”:以PATTERN匹配整个文件路径,而非文件名称范例:find -name snow.png find -iname snow.png find / -name ".txt" find /var -name "log*" [root@servera data]# find -regex ".*\.txt$" ./test/f1.txt ./test/f2.txt ./test/test1/test2/f3.txt ./test/test1/test2/f4.txt🔖16.1.2.4 根据属主、属组查找-user USERNAME:查找属主为指定用户(UID)的文件 -group GRPNAME: 查找属组为指定组(GID)的文件 -uid UserID:查找属主为指定的UID号的文件 -gid GroupID:查找属组为指定的GID号的文件 -nouser:查找没有属主的文件 -nogroup:查找没有属组的文件🔖16.1.2.5 根据文件类型查找-type TYPE TYPE可以是以下形式: f: 普通文件 d: 目录文件 l: 符号链接文件 s:套接字文件 b: 块设备文件 c: 字符设备文件 p: 管道文件范例:[root@servera data]# find -type f ./test/f1.txt ./test/f2.txt ./test/test1/test2/f3.txt ./test/test1/test2/f4.txt ./test/f1 [root@servera data]# find -type d . ./test ./test/test1 ./test/test1/test2 [root@servera data]# find -type d -ls 67299970 0 drwxr-xr-x 3 root root 18 Apr 7 16:26 . 101802332 0 drwxr-xrwt 3 root root 57 Apr 7 16:35 ./test 34379336 0 drwxr--r-- 3 root root 19 Apr 7 16:28 ./test/test1 68403853 0 dr-xr--r-- 2 root root 34 Apr 7 16:28 ./test/test1/test2 🔖16.1.2.6 空文件或目录-empty范例:find /data -type f -empty🔖16.1.2.7 组合条件与:-a ,默认多个条件是与关系 或:-o 非:-not ! 范例:[root@servera data]# find /home -user user1 -a -type d /home/user1 /home/user1/.mozilla /home/user1/.mozilla/extensions /home/user1/.mozilla/plugins /home/user1/.cache /home/user1/.ssh [root@servera data]# find /data/ -type f /data/test/f1.txt /data/test/f2.txt /data/test/test1/test2/f3.txt /data/test/test1/test2/f4.txt /data/test/f1 [root@servera data]# find /data/ -type f -o -type d /data/ /data/test /data/test/f1.txt /data/test/f2.txt /data/test/test1 /data/test/test1/test2 /data/test/test1/test2/f3.txt /data/test/test1/test2/f4.txt /data/test/f1德·摩根定律:(非 A) 或 (非 B) = 非(A 且 B)(非 A) 且 (非 B) = 非(A 或 B)示例:!A -a !B = !(A -o B)!A -o !B = !(A -a B)范例:[root@servera data]# find ! \( -type f -a -type d \) ----> -type f -o -tpye d . ./test ./test/f1.txt ./test/f2.txt ./test/test1 ./test/test1/test2 ./test/test1/test2/f3.txt ./test/test1/test2/f4.txt ./test/f1 [root@servera data]# find -type f -a -type d [root@servera data]# find /home \( -user student -a -type d \) /home/student /home/student/.mozilla /home/student/.mozilla/extensions /home/student/.mozilla/plugins /home/student/.config /home/student/.config/pulse /home/student/.cache /home/student/student /home/student/test /home/student/.vim [root@servera data]# find /home ! \( -user student -a -type d \) /home /home/student/.bash_logout /home/student/.bash_profile /home/student/.bashrc /home/student/.config/pulse/b6d16ca3e4814c4c92e10837fb500b0a-device-volumes.tdb /home/student/.config/pulse/b6d16ca3e4814c4c92e10837fb500b0a-stream-volumes.tdb🔖16.1.2.8 排除目录范例:#查找/etc/下,除/etc/sane.d目录的其它所有.conf后缀的文件 find /etc -path '/etc/sane.d' -a -prune -o -name "*.conf"🔖16.1.2.9 根据文件大小来查找-size [+|-]#UNIT 常用单位:k, M, G,c(byte),注意大小写敏感 #UNIT: (#-1, #] 如:6k 表示(5k,6k] -#UNIT:[0,#-1] 如:-6k 表示[0,5k] +#UNIT:(#,∞) 如:+6k 表示(6k,∞)范例:find / -size 10G find / -size -10G find / -size +10G🔖16.1.2.10 根据时间戳#以“天”为单位 -atime [+|-]# -mtime -ctime #: [#,#+1) -#: [0,#) +#: [#+1,∞] -mtime 10 -mtime -10 -mtime +10 #以“分钟”为单位 -amin -mmin -cmin🔖16.1.2.11 根据权限查找-perm [/|-]MODE MODE: 精确权限匹配 /MODE:任何一类(u,g,o)对象的权限中只要能一位匹配即可,或关系,+ 从Rhel 7开始淘汰 -MODE:每一类对象都必须同时拥有指定权限,与关系 0 表示不关注说明:find -perm 755 会匹配权限模式恰好是755的文件只要当任意人有写权限时,find -perm /222就会匹配只有当每个人都有写权限时,find -perm -222才会匹配只有当其它人(other)有写权限时,find -perm -002才会匹配🔖16.1.2.12 处理动作-print:默认的处理动作,显示至屏幕 -ls:类似于对查找到的文件执行"ls -dils"命令格式输出 -fls file:查找到的所有文件的长格式信息保存至指定文件中,相当于 -ls > file -delete:删除查找到的文件,慎用! -ok COMMAND {} \; 对查找到的每个文件执行由COMMAND指定的命令,对于每个文件执行命令之前,都会 交互式要求用户确认 -exec COMMAND {} \; 对查找到的每个文件执行由COMMAND指定的命令 {}: 用于引用查找到的文件名称自身范例:#备份配置文件,添加.orig这个扩展名 find -name *.conf -exec cp {} {}.orig \; #提示删除存在时间超过3天以上的joe的临时文件 find /tmp -ctime +3 -user joe -ok rm {} \; #在主目录中寻找可被其它用户写入的文件 find ~ -perm -002 -exec chmod o-w {} \; #查找/data下的权限为644,后缀为sh的普通文件,增加执行权限 find /data –type f -perm 644 -name "*.sh" –exec chmod 755 {} \;📜16.2 压缩和解压缩gzip gunzip bzip2 bunzip2 xz unxz zip unzip 压缩比:xz > bzip2 > gz📑16.2.1 gzip和gunzip格式:gzip [OPTION]... FILE ...常用选项:-k keep, 保留原文件,RHEL 8 新特性 -d 解压缩,相当于gunzip -c 结果输出至标准输出,保留原文件不改变 -# 指定压缩比,#取值为1-9,值越大压缩比越大范例:#解压缩 gunzip file.gz #不显式解压缩的前提下查看文本文件内容 zcat file.gz范例gzip -c messages >messages.gz gzip -c -d messages.gz > messages zcat messages.gz > messages cat messages | gzip > m.gz📑16.2.2 bzip2和bunzip2来自于 bzip2 包格式:bzip2 [OPTION]... FILE ...常用选项-k keep, 保留原文件 -d 解压缩 -c 结果输出至标准输出,保留原文件不改变 -# 1-9,压缩比,默认为6范例:bunzip2 file.bz2 解压缩 bzcat file.bz2 不显式解压缩的前提下查看文本文件内容📑16.2.3 xz和unxz来自于 xz 包格式xz [OPTION]... FILE ...常用选项-k keep, 保留原文件 -d 解压缩 -c 结果输出至标准输出,保留原文件不改变 -# 压缩比,取值1-9,默认为9范例:unxz file.xz 解压缩 xzcat file.xz 不显式解压缩的前提下查看文本文件内容📑16.2.4 zip和unzipzip 可以实现打包目录和多个文件成一个文件并压缩,但可能会丢失文件属性信息,如:所有者和组信息,一般建议使用 tar 代替来自于zip 和 unzip 包范例:#打包并压缩 zip -r /backup/sysconfig.zip /etc/sysconfig/ #不包括目录本身,只打包目录内的文件和子目录 cd /etc/sysconfig; zip -r /root/sysconfig.zip * #默认解压缩至当前目录 unzip /backup/sysconfig.zip #解压缩至指定目录,如果指定目录不存在,会在其父目录(必须事先存在)下自动生成 unzip /backup/sysconfig.zip -d /tmp/config cat /var/log/messages | zip messages - #-p 表示管道 unzip -p message.zip > message范例: 非交互式加密和解密[root@servera test]#zip -P 123456 test.zip * adding: ca.crt (deflated 25%) adding: client.ovpn (deflated 27%) adding: dh.pem (deflated 19%) adding: ta.key (deflated 40%) [root@servera test]#mv test.zip /opt [root@servera test]#cd /opt [root@servera opt]#unzip -P 123456 test.zip Archive: test.zip [test.zip] ca.crt password: inflating: ca.crt inflating: client.ovpn inflating: dh.pem inflating: ta.key📜16.3 打包和解包tartar 即 Tape ARchive 磁带归档,可以对目录和多个文件打包一个文件,并且可以压缩,保留文件属性不丢失,常用于备份功能,推荐使用格式tar [OPTION]...选项:-c #创建打包文件 -p #保留权限 -x #解包 -r #追加文件 -t #列表列出 -f #使用文档文件(1) 创建归档,保留权限tar -cpvf /PATH/FILE.tar FILE...(2) 追加文件至归档: 注:不支持对压缩文件追加tar -rf /PATH/FILE.tar FILE...(3) 查看归档文件中的文件列表tar -t -f /PATH/FILE.tar(4) 展开归档tar xf /PATH/FILE.tar tar xf /PATH/FILE.tar -C /PATH/(5) 结合压缩工具实现:归档并压缩-z 相当于gzip压缩工具-j 相当于bzip2压缩工具-J 相当于xz压缩工具范例:[root@servera test]# tar jcvf etc.tar.bz2 /etc/ [root@servera test]# tar Jcvf etc.tar.xz /etc/ [root@servera test]# tar zcvf etc.tar.gz /etc/ [root@servera test]# ll total 31260 -r--r--r--. 1 root root 5498569 Apr 7 21:15 etc.tar.bz2 -r--r--r--. 1 root root 7150891 Apr 7 21:15 etc.tar.gz -r--r--r--. 1 root root 4741700 Apr 7 21:16 etc.tar.xz📜16.4 文件传输📑16.4.1 scp命令scp [options] SRC... DEST/两种方式:scp [options] [user@]host:/sourcefile /destpath scp [options] /sourcefile [user@]host:/destpath常用选项:-C 压缩数据流 -r 递归复制 -p 保持原文件的属性信息 -q 静默模式 -P PORT 指明remote host的监听的端口📑16.4.2 rsync 命令rsync工具可以基于ssh和rsync协议实现高效率的远程系统之间复制文件,使用安全的shell连接做为传输方式,比scp更快,基于增量数据同步,即只复制两方不同的文件,此工具来自于rsync包注意:通信两端主机都需要安装 rsync软件rsync -av /etc server1:/tmp #复制目录和目录下文件 rsync -av /etc/ server1:/tmp #只复制目录下文件常用选项:-n 模拟复制过程 -v 显示详细过程 -r 递归复制目录树 -p 保留权限 -t 保留修改时间戳 -g 保留组信息 -o 保留所有者信息 -l 将软链接文件本身进行复制(默认) -L 将软链接文件指向的文件复制 -u 如果接收者的文件比发送者的文件较新,将忽略同步 -z 压缩,节约网络带宽 -a 存档,相当于-rlptgoD,但不保留ACL(-A)和SELinux属性(-X) --delete 源数据删除,目标数据也自动同步删除范例:[root@servera ~]#rsync -auv --delete /data/test 10.0.0.7:/data📑16.4.3 sftp交互式文件传输工具,用法和传统的ftp工具相似,利用ssh服务实现安全的文件上传和下载使用ls cd mkdir rmdir pwd get put等指令,可用?或help获取帮助信息sftp [user@]host sftp> help
0
0
0
浏览量2004
秋月无边

十、文件权限管理

10.1 文件所有者和属组属性操作10.1.1 设置文件的所有者chownchown 命令可以修改文件的属主,也可以修改文件属组格式:chown [OPTION]... [OWNER]:[GROUP] FILE... chown [OPTION]... --reference=RFILE FILE...用法说明:OWNER #只修改所有者 OWNER:GROUP #同时修改所有者和属组 :GROUP #只修改属组,冒号也可用 . 替换 --reference=RFILE #参考指定的的属性,来修改 -R #递归,此选项慎用,非常危险!范例:[root@servera ~]# chown student.student f3 [root@servera ~]# ll f3 -rw-r--r--. 1 student student 0 Mar 27 15:35 f3 [root@servera ~]# ll f4 -rw-r--r--. 1 root root 0 Mar 27 15:35 f4 [root@servera ~]# chown --reference=f4 f3 [root@servera ~]# ll f3 -rw-r--r--. 1 root root 0 Mar 27 15:35 f3 [root@servera ~]# chown student:student f3 [root@servera ~]# ll f3 -rw-r--r--. 1 student student 0 Mar 27 15:35 f3 [root@servera test]# pwd /root/test [root@servera test]# ll total 4 -rw-r--r--. 1 root root 0 Mar 27 16:37 a -rw-r--r--. 1 root root 2716 Mar 27 16:40 pass drwxr-xr-x. 2 root root 31 Mar 27 16:36 test2 [root@servera test]# chown -R student.student ~/test [root@servera test]# ll -d drwxr-xr-x. 3 student student 40 Mar 27 16:47 . [root@servera test]# ll total 4 -rw-r--r--. 1 student student 0 Mar 27 16:37 a -rw-r--r--. 1 student student 2716 Mar 27 16:40 pass drwxr-xr-x. 2 student student 31 Mar 27 16:36 test2 [root@servera test]# cd test2/ [root@servera test2]# ll total 0 -rw-r--r--. 1 student student 0 Mar 27 16:05 a10.1.2 设置文件的属组信息chgrpchgrp 命令可以只修改文件的属组格式chgrp [OPTION]... GROUP FILE... chgrp [OPTION]... --reference=RFILE FILE...-R 递归范例:[root@servera test]# chgrp student . [root@servera test]# ll -d drwxr-xr-x. 3 root student 40 Mar 27 16:47 .10.2 文件权限10.2.1 文件权限说明文件的权限主要针对三类对象进行定义owner 拥有者, u group 属组, g other 其他, o注意:用户的最终权限,是从左向右进行顺序匹配,即,所有者,所属组,其他人,一旦匹配权限立即生效,不再向右查看其权限每个文件针对每类访问者都定义了三种常用权限r Readable w Writable x eXcutable对文件的权限:r 可使用文件查看类工具,比如:cat,可以获取其内容 w 可修改其内容 x 可以把此文件提请内核启动为一个进程,即可以执行(运行)此文件(此文件的内容必须是可执行)对目录的权限:r 可以使用ls查看此目录中文件列表 w 可在此目录中创建文件,也可删除此目录中的文件,而和此被删除的文件的权限无关 x 可以cd进入此目录,可以使用ls -l查看此目录中文件元数据(须配合r权限),属于目录的可访问的最 小权限 X 只给目录x权限,不给无执行权限的文件x权限数学法的权限二进制数字--- 000 0 --x 001 1 -w- 010 2 -wx 011 3 r-- 100 4 r-x 101 5 rw- 110 6 rwx 111 7例如:rw-r----- 640 rwxr-xr-x 75510.2.2 修改文件权限chmod格式chmod [OPTION]... MODE[,MODE]... FILE... chmod [OPTION]... OCTAL-MODE FILE... #参考RFILE文件的权限,将FILE的修改为同RFILE chmod [OPTION]... --reference=RFILE FILE...说明:修改指定一类用户的所有权限 u= g= o= ug= a= u=,g= 修改指定一类用户某个或某个权限 u+ u- g+ g- o+ o- a+ a- + - -R: 递归修改权限范例: 设置 X 权限[root@servera test2]# chmod a+x -R . [root@servera test2]# ll total 0 -rwxr-xr-x. 1 root root 0 Mar 27 16:05 a lrwxrwxrwx. 1 root root 10 Mar 27 16:36 test.lnk -> /root/test [root@servera test2]# ll -d drwxr-xr-x. 2 root root 31 Mar 27 16:36 . [root@servera test]# chmod -R a+X . [root@servera test]# ll total 4 -rw-r--r--. 1 root root 0 Mar 27 16:37 a -rw-r--r--. 1 root root 2716 Mar 27 16:40 pass drwxr-xr-x. 2 root root 31 Mar 27 16:36 test2r=4 w=2 x=110.2.3 新建文件和目录的默认权限umask 的值可以用来保留在创建文件权限实现方式:新建文件的默认权限: 666-umask,如果所得结果某位存在执行(奇数)权限,则将其权限+1,偶数不 变新建目录的默认权限: 777-umask非特权用户umask默认是 002root的umask 默认是 022查看umaskumask #模式方式显示 umask –S #输出可被调用 umask –p修改umaskumask #范例:umask 002 umask u=rw,g=r,o=持久保存umask全局设置: /etc/porfile用户设置:~/.bashrc思考题:当usmak=233的时候,创建文件的权限是多少?创建目录的权限是多少?常用范例:#临时设置umask创建文件或目录后自动恢复为原来的umask [root@centos8 ~]#umask 0022 [root@centos8 ~]#( umask 666; touch /data/f1.txt ) [root@centos8 ~]#umask 0022 [root@centos8 ~]#ll /data/f1.txt ---------- 1 root root 0 Mar 27 14:55 /data/f1.txt10.2.4 Linux文件系统上的特殊权限前面介绍了三种常见的权限:r, w, x 还有三种特殊权限:SUID, SGID, Sticky10.2.4.1 特殊权限SUID前提:进程有属主和属组;文件有属主和属组任何一个可执行程序文件能不能启动为进程,取决发起者对程序文件是否拥有执行权限启动为进程之后,其进程的属主为发起者,进程的属组为发起者所属的组进程访问文件时的权限,取决于进程的发起者(a) 进程的发起者,同文件的属主:则应用文件属主权限(b) 进程的发起者,属于文件属组;则应用文件属组权限© 应用文件“其它”权限二进制的可执行文件上SUID权限功能:chmod u+s FILE... chmod 6xxx FILE chmod u-s FILE...范例:[root@servera test]# ll /usr/bin/passwd -rwsr-xr-x. 1 root root 33544 Dec 14 2019 /usr/bin/passwd说白了就是其他用户以root用户身份运行命令10.2.4.2 特殊权限SGID二进制的可执行文件上SGID权限功能:任何一个可执行程序文件能不能启动为进程:取决发起者对程序文件是否拥有执行权限启动为进程之后,其进程的属组为原程序文件的属组SGID权限设定:chmod g+s FILE... chmod 2xxx FILE chmod g-s FILE...目录上的SGID权限功能:默认情况下,用户创建文件时,其属组为此用户所属的主组,一旦某目录被设定了SGID,则对此目录有写权限的用户在此目录中创建的文件所属的组为此目录的属组,通常用于创建一个协作目录SGID权限设定:chmod g+s FILE... chmod 2xxx FILE chmod g-s FILE...10.2.4.3 特殊权限 Sticky 位具有写权限的目录通常用户可以删除该目录中的任何文件,无论该文件的权限或拥有权在目录设置Sticky 位,只有文件的所有者或root可以删除该文件sticky 设置在文件上无意义Sticky权限设定:chmod o+t DIR... chmod 1xxx DIR chmod o-t DIR...数字位:GUID=6SGID=2sticky=1权限位映射SUID: user,占据属主的执行权限位s:属主拥有x权限S:属主没有x权限SGID: group,占据属组的执行权限位s: group拥有x权限S:group没有x权限Sticky: other,占据other的执行权限位t:other拥有x权限T:other没有x权限10.2.5 设定文件特殊属性设置文件的特殊属性,可以访问 root 用户误操作删除或修改文件不能删除,改名,更改chattr +i只能追加内容,不能删除,改名chattr +a显示特定属性lsattr10.2.6 访问控制列表10.2.6.1 ACL权限功能ACL:Access Control List,实现灵活的权限管理除了文件的所有者,所属组和其它人,可以对更多的用户设置权限rhel7 默认创建的xfs和ext4文件系统具有ACL功能rhel7 之前版本,默认手工创建的ext4文件系统无ACL功能,需手动增加tune2fs -o acl /dev/sdb1 mount -o acl /dev/sdb1 /mnt/testACL生效顺序:所有者,自定义用户,所属组|自定义组,其他人10.2.6.2 ACL相关命令setfacl 可以设置ACL权限getfacl 可查看设置的ACL权限范例:[root@servera cur]# setfacl -m u:hao:rw test [root@servera cur]# getfacl test # file: test # owner: root # group: root user::r-- user:hao:rw- group::r-- mask::rw- other::r--范例:getfacl file |directory setfacl -m u:hao:rwx file|directory setfacl -m g:admins:rw file| directory setfacl -x u:hao file |directory #清除所有ACL权限 setfacl -b file1–set 选项会把原有的ACL项都删除,用新的替代,需要注意的是一定要包含UGO的设置,不能象-m一样只是添加ACL就可以范例:setfacl --set u::rw,u:hao:rw,g::r,o::- file110.2.6.3 mask 权限mask只影响除所有者和other的之外的人和组的最大权限mask需要与用户的权限进行逻辑与运算后,才能变成有限的权限(Effective Permission)用户或组的设置必须存在于mask权限设定范围内才会生效范例:setfacl -m mask::rx file范例:[root@centos8 data]#ll f1.txt -rw-rw-r--+ 1 root root 728 Dec 18 14:51 f1.txt [root@centos8 data]#chmod g=r f1.txt [root@centos8 data]#ll f1.txt -rw-r--r--+ 1 root root 728 Dec 18 14:51 f1.txt [root@centos8 data]#getfacl f1.txt # file: f1.txt # owner: root # group: root user::rw user:hao:--- group::r-- group:admins:-w- #effective:--- mask::r-- other::r-- [root@centos8 data]#setfacl -m mask::rw f1.txt [root@centos8 data]#getfacl f1.txt # file: f1.txt # owner: root # group: root user::rw user:hao:--- group::r-- group:admins:-w mask::rw other::r-- [root@centos8 data]#setfacl -m u:hao:rwx f1.txt [root@centos8 data]#getfacl f1.txt # file: f1.txt # owner: root # group: root user::rwuser: hao:rwx group::r-- group:admins:-w mask::rwx other::r-- [root@centos8 data]#setfacl -m mask::rw f1.txt [root@centos8 data]#getfacl f1.txt # file: f1.txt # owner: root # group: root user::rw user::hao:rwx #effective:rw group::r-- group:admins:-w mask::rw other::r--10.3 普通用户权限提升10.3.1 sudo 介绍sudo 即superuser do,允许系统管理员让普通用户执行一些或者全部的root命令的一个工具,如halt,reboot,su等等。这样不仅减少了root用户的登录 和管理时间,同样也提高了安全性。在最早之前,一般用户管理系统的方式是利用su切换为超级用户。但是使用su的缺点之一在于必须要先告知超级用户的密码。sudo于1980年前后推出,sudo使一般用户不需要知道超级用户的密码即可获得权限。首先超级用户将普通用户的名字、可以执行的特定命令、按照哪种用户或用户组的身份执行等信息,登记在特殊的文件中(通常是/etc/sudoers),即完成对该用户的授权(此时该用户称为“sudoer”);在一般用户需要取得特殊权限时,其可在命令前加上“sudo”,此时sudo将会询问该用户自己的密码(以确认终端机前的是该用户本人),回答后系统即会将该命令的进程以超级用户的权限运行。之后的一段时间内(默认为5分钟,可在/etc/sudoers自定义),使用sudo不需要再次输入密码。由于不需要超级用户的密码,部分Unix系统甚至利用sudo使一般用户取代超级用户作为管理帐号,例如Ubuntu、Mac OS X等。sudo特性:sudo能够授权指定用户在指定主机上运行某些命令。如果未授权用户尝试使用 sudo,会提示联系管理员sudo提供了丰富的日志,详细地记录了每个用户干了什么。它能够将日志传到中心主机或者日志服务器sudo使用时间戳文件来执行类似的“检票”系统。当用户调用sudo并且输入它的密码时,用户获得了一张存活期为5分钟的票sudo的配置文件是sudoers文件,它允许系统管理员集中的管理用户的使用权限和使用的主机。它所存放的位置默认是在/etc/sudoers,属性必须为044010.3.2 sudo 组成包:sudo配置文件:/etc/sudo.conf授权规则配置文件:/etc/sudoers/etc/sudoers.d安全编辑授权规则文件和语法检查工具/usr/sbin/visudo范例:#检查语法 visudo -c10.3.3 visudovisudo实际为编辑/etc/sudoers文件专用工具,有语法检测功能范例:#创建用户别名 # User_Alias ADMINS = jsmith, mikem User_Alias TEST = student, hao #添加用户并指定获权命令 ## Allow root to run any commands anywhere ## 允许root用户执行任意路径下的任意命令 root ALL=(ALL) ALL hao ALL=(ALL) /usr/sbin/fdisk NOPASSWD:/usr/sbin/ ## Allows members of the 'sys' group to run networking, software, ## service management apps and more. ## 允许sys中户组中的用户使用NETWORKING等所有别名中配置的命令 # %sys ALL = NETWORKING, SOFTWARE, SERVICES, STORAGE, DELEGATING, PROCESSES, LOCATE, DRIVERS #添加组和别名指定获权命令(别名不需要加%) %student ALL=(ALL) /usr/sbin/fdisk TEST ALL=(ALL) NOPASSWD:/usr/sbin/parted
0
0
0
浏览量2003
秋月无边

六、在Linux中获取帮助

📜6.1 查看命令的帮助📑6.1.1 内部命令帮助help COMMANDman bash范例:[root@servera ~]# type history history is a shell builtin [root@servera ~]# help history history: history [-c] [-d offset] [n] or history -anrw [filename] or history -ps arg [arg...] Display or manipulate the history list. Display the history list with line numbers, prefixing each modified entry with a `*'. An argument of N lists only the last N entries. Options: -c clear the history list by deleting all of the entries -d offset delete the history entry at position OFFSET. -a append history lines from this session to the history file -n read all history lines not already read from the history file and append them to the history list -r read the history file and append the contents to the history list -w write the current history to the history file -p perform history expansion on each ARG and display the result without storing it in the history list -s append the ARGs to the history list as a single entry If FILENAME is given, it is used as the history file. Otherwise, if HISTFILE has a value, that is used, else ~/.bash_history. If the HISTTIMEFORMAT variable is set and not null, its value is used as a format string for strftime(3) to print the time stamp associated with each displayed history entry. No time stamps are printed otherwise. Exit Status: Returns success unless an invalid option is given or an error occurs.📑6.1.2 外部命令和软件帮助COMMAND --help 或 COMMAND -h使用 man 手册(manual): man COMMAND信息页:info COMMAND程序自身的帮助文档:README、INSTALL、ChangeLog程序官方文档相关网站 CSDN搜索引擎 百度,谷歌📜6.2 --help 或 -h 选项显示用法总结和参数列表,大多数命令使用,但并非所有的范例:[root@servera ~]# date --help Usage: date [OPTION]... [+FORMAT] or: date [-u|--utc|--universal] [MMDDhhmm[[CC]YY][.ss]] Display the current time in the given FORMAT, or set the system date. Mandatory arguments to long options are mandatory for short options too. -d, --date=STRING display time described by STRING, not 'now' [root@servera ~]# cal -h Usage: cal [options] [[[day] month] year] cal [options] <timestamp|monthname> Display a calendar, or some part of it. Without any arguments, display the current month.📜6.3 man命令man 提供命令帮助的文件,手册页存放在/usr/share/man几乎每个命令都有man的“页面”中文man需安装包man-pagesman-pages-zh-CNman章节man 页面分组为不同的“章节”,统称为Linux手册,man 1 man1:用户命令2:系统调用3:C库调用4:设备文件及特殊文件5:配置文件格式6:游戏7:杂项8:管理类的命令9:Linux 内核API查看man手册man [章节] keywordman page 导航阅读man page标题Name 主题名称。通常是命令或文件名。非常简短的描述。SYNOPSIS 命令语法的概要DESCRIPTION 提供对主题的基本理解的深度描述OPTIONS 命令执行选项说明EXAMPLES 有关如何使用命令、功能或文件的示例。FLIES 与 man page 相关的文件和目录的列表BUGS 软件中的已知错误man 常用选项mandb 更新whatis数据库列出所有帮助man -a keyword搜索man手册#列出所有匹配的页面,使用 whatis 数据库 man -k keyword相当于 whatisman -f keyword打印man帮助文件的路径man -w [章节] keyword📜6.4 infoman常用于命令参考 ,GNU工具 info 适合通用文档参考没有参数,列出所有的页面info 页面的结构就像一个网站每一页分为“节点”链接节点之前info 命令格式info [命令]导航info页方向键,PgUp,PgDn 导航U 返回父链接D 返回首页
0
0
0
浏览量496
秋月无边

Linux基础:软件包管理

📜18.1 软件包和包管理器介绍📑18.1.1 软件包介绍开源软件最初只提供了.tar.gz的打包的源码文件,用户必须自已编译每个想在GNU/Linux上运行的软件。用户急需系统能提供一种更加便利的方法来管理这些软件,当Debian诞生时,这样一个管理工具dpkg也就应运而生,可用来管理deb后缀的"包"文件。从而著名的“package”概念第一次出现在GNU/Linux系统中,稍后Red Hat才开发自己的rpm包管理系统范例:利用 cpio工具查看包文件列表rpm2cpio 包文件|cpio –itv 预览包内文件 rpm2cpio 包文件|cpio –id “*.conf” 释放包内文件📑18.1.2 软件包管理器介绍软件包管理器功能:将编译好的应用程序的各组成文件打包一个或几个程序包文件,利用包管理器可以方便快捷地实现程序包的安装、卸载、查询、升级和校验等管理操作主流的软件包管理器:redhat:rpm文件, rpm 包管理器,rpm:Redhat Package Manager,RPM Package Managerrpm包命名方式:name-VERSION-release.arch.rpm常见的arch:x86: i386, i486, i586, i686x86_64: x64, x86_64, amd64跟平台无关:noarch📑18.1.3 分类和拆包软件包为了管理和使用的便利,会将一个大的软件分类,放在不同的子包中。包的分类Application-VERSION-ARCH.rpm: 主包Application-devel-VERSION-ARCH.rpm 开发子包Application-utils-VERSION-ARHC.rpm 其它子包Application-libs-VERSION-ARHC.rpm 其它子包📑18.1.4 包的依赖软件包之间可能存在依赖关系,甚至循环依赖,即:A包依赖B包,B包依赖C包,C包依赖A包安装软件包时,会因为缺少依赖的包,而导致安装包失败。解决依赖包管理工具:yum:rpm包管理器的前端工具dnf:Fedora 18+ rpm包管理器前端管理工具,RHEL 8 版代替 yum📑18.1.5 软件包管理器相关文件1.包文件组成 (每个包独有)包内的文件元数据,如:包的名称,版本,依赖性,描述等可能会有包安装或卸载时运行的脚本2.数据库(公共):/var/lib/rpm程序包名称及版本依赖关系包安装后生成的各文件路径及校验码信息📜18.2 包管理器 rpmRHEL系统上使用rpm命令管理程序包功能:安装、卸载、升级、查询、校验、数据库维护📑18.2.1 安装格式:rpm {-i|--install} [install-options] PACKAGE_FILE…选项:-v: verbose -h: 以#显示程序包管理执行进度 -i:安装常用组合:rpm -ivh PACKAGE_FILE ...rpm包安装[install-options]--test: 测试安装,但不真正执行安装,即dry run模式 --nodeps:忽略依赖关系 --replacepkgs | replacefiles --nosignature: 不检查来源合法性 --nodigest:不检查包完整性 --noscripts:不执行程序包脚本 %pre: 安装前脚本 --nopre %post: 安装后脚本 --nopost %preun: 卸载前脚本 --nopreun %postun: 卸载后脚本 --nopostun📑18.2.2 升级和降级rpm包升级rpm {-U|--upgrade} [install-options] PACKAGE_FILE... rpm {-F|--freshen} [install-options] PACKAGE_FILE...对应选项:upgrade:安装有旧版程序包,则“升级”,如果不存在旧版程序包,则“安装” freshen:安装有旧版程序包,则“升级”, 如果不存在旧版程序包,则不执行升级操作 --oldpackage:降级 --force: 强制安装常用组合:rpm -Uvh PACKAGE_FILE ... rpm -Fvh PACKAGE_FILE ...升级注意项:(1) 不要对内核做升级操作;Linux支持多内核版本并存,因此直接安装新版本内核(2) 如果原程序包的配置文件安装后曾被修改,升级时,新版本提供的同一个配置文件不会直接覆盖老版本的配置文件,而把新版本文件重命名(FILENAME.rpmnew)后保留📑18.2.3 包查询rpm {-q|--query} [select-options] [query-options] 1 [select-options] -a:所有包 -f:查看指定的文件由哪个程序包安装生成 -p rpmfile:针对尚未安装的程序包文件做查询操作 [query-options] --changelog:查询rpm包的changelog -c:查询程序的配置文件 -d:查询程序的文档 -i:information -l:查看指定的程序包安装后生成的所有文件 --scripts:程序包自带的脚本 #和CAPABILITY相关 --whatprovides CAPABILITY:查询指定的CAPABILITY由哪个包所提供 --whatrequires CAPABILITY:查询指定的CAPABILITY被哪个包所依赖 --provides:列出指定程序包所提供的CAPABILITY -R:查询指定的程序包所依赖的CAPABILITY常用查询用法:-qa -q PACKAGE -qi PACKAGE -qc PACKAGE -ql PACKAGE -qd PACKAGE -q --scripts PACKAGE -qf FILE -qpi PACKAGE_FILE -qpl PACKAGE_FILE, ...📑18.2.4 包卸载格式:rpm {-e|--erase} [--allmatches] [--nodeps] [--noscripts] [--notriggers] [--test] PACKAGE_NAME ...注意:当包卸载时,对应的配置文件不会删除, 以FILENAME.rpmsave形式保留📑18.2.5 包校验在安装包时,系统也会检查包的来源是否是合法的检查包的完整性和签名rpm -K|--checksig rpmfile在检查包的来源和完整性前,必须导入所需要公钥rpm --import RPM-GPG-KEY-redhat-release rpm --import RPM-GPG-KEY-redhat-beta范例:校验包文件[root@servera sr0]# rpm -K ./BaseOS/Packages/samba-4.11.2-13.el8.x86_64.rpm ./BaseOS/Packages/samba-4.11.2-13.el8.x86_64.rpm: digests signatures OK📜18.3 dnf注意:8的系统已经不提供仓库支持,如果使用8的话,可参考阿里的设置方式。阿里CentOS源:https://developer.aliyun.com/mirror/centos阿里EPEL源:https://developer.aliyun.com/mirror/epelRHEL8使用dnf解决rpm的包依赖关系YUM: Yellowdog Update Modifier,rpm的前端程序,可解决软件包相关依赖性,可在多个库之间定位软件包,up2date的替代工具,RHEL 8 用dnf 代替了yum ,不过保留了和 yum的兼容性,配置也是通用的📑18.3.1 yum/dnf工作原理yum/dnf 是基于C/S 模式yum 服务器存放rpm包和相关包的元数据库yum 客户端访问yum服务器进行安装或查询等yum 实现过程先在yum服务器上创建 yum repository(仓库),在仓库中事先存储了众多rpm包,以及包的相关的元数据文件(放置于特定目录repodata下),当yum客户端利用yum/dnf工具进行安装包时,会自动下载repodata中的元数据,查询元数据是否存在相关的包及依赖关系,自动从仓库中找到相关包下载并安装。yum服务器的仓库可以多种形式存在:file:// 本地路径http://https://ftp://注意:yum仓库指向的路径一定必须是reported目录所在目录📑18.3.2 yum仓库配置yum客户端配置文件/etc/yum.conf #为所有仓库提供公共配置 /etc/yum.repos.d/*.repo: #为每个仓库的提供配置文件帮助参考: man 5 yum.conf相关变量:yum的repo配置文件中可用的变量: $releasever: 当前OS的发行版的主版本号,如:8,7,6 $arch: CPU架构,如:aarch64, i586, i686,x86_64等 $basearch:系统基础平台;i386, x86_64 $contentdir:表示目录,比如:centos-8,centos-7 $YUM0-$YUM9:自定义变量范例:http://server/rhel/$releasever/$basearch/ http://server/rhel/7/x86_64 http://server/rhel/6/i386repo仓库配置文件指向的定义:[repositoryID] name=Some name for this repository baseurl=url://path/to/repository/ enabled={1|0} gpgcheck={1|0} gpgkey=URL enablegroups={1|0} failovermethod={roundrobin|priority} roundrobin:意为随机挑选,默认值 priority:按顺序访问 cost= 默认为1000baseurl指向的路径阿里云提供了写好的CentOS和ubuntu的仓库文件下载链接http://mirrors.aliyun.com/repo/CentOS系统的yum源#阿里云 https://mirrors.aliyun.com/centos/$releasever/os/x86_64/ #华为云 https://mirrors.huaweicloud.com/ #清华大学 https://mirrors.tuna.tsinghua.edu.cn/centos/$releasever/AppStream/os/x86_64/EPEL的yum源#阿里云 https://mirrors.aliyun.com/epel/$releasever/x86_64 #Fedora-EPEL:Extra Packages for Enterprise Linux yum install https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm范例:为RHEL 8 配置 yum 的系统和EPEL源仓库[root@centos8 ~]#cat /etc/yum.repos.d/base.repo [BaseOS] name=BaseOS baseurl=file:///mnt/cd/BaseOS gpgcheck=1 gpgkey=/etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial [AppStream] name=AppStream baseurl=file:///misc/cd/AppStream gpgcheck=0 [epel] name=EPEL baseurl=http://mirrors.aliyun.com/epel/$releasever/Everything/$basearch gpgcheck=0 enabled=1 [httpAppstream] name=aliyun Appstream baseurl=https://mirrors.aliyun.com/centos/$releasever/AppStream/$basearch/os gpgcheck=0📑18.3.3 yum/dnf命令yum命令的用法:yum [options] [command] [package ...]yum的命令行选项:-y #自动回答为“yes” -q #静默模式 --nogpgcheck #禁止进行gpg check --enablerepo=repoidglob #临时启用此处指定的repo,支持通配符,如:”*“ --disablerepo=repoidglob #临时禁用此处指定的repo,和上面语句同时使用,放在后面的生效18.3.3.1 显示仓库列表yum repolist [all|enabled|disabled]18.3.3.2 显示程序包yum list yum list [all | glob_exp1] [glob_exp2] [...] yum list {available|installed|updates} [glob_exp1] [...] yum group list18.3.3.3 安装程序包yum install package1 [package2] [...] yum group install "package group" yum reinstall package1 [package2] [...] #重新安装18.3.3.4 卸载程序包yum remove | erase package1 [package2] [...]18.3.3.5 升级和降级yum update [package1] [package2] [...] yum downgrade package1 [package2] [...] (降级)18.3.3.6 仓库缓存清除目录/var/cache/yum/缓存yum clean [ packages | metadata | expire-cache | rpmdb | plugins | all ]构建缓存:yum makecache18.3.3.7 启用模块流和安装模块(8的新特性)模块模块是一组属于一个整体的、协调一致的RPM软件包。通常,这是围绕软件应用或编程语言的特定版本进行组织的。典型的模块可以包含应用的软件包、应用特定依赖库的软件包、应用文档的软件包,以及帮助器实用程序的软件包。模块流每个模块可以具有一个或多个模块流,其包含不同版本的内容。每个流独立接收更新。模块流可以视为应用流物理存储库中的虚拟存储库。对于每个模块,只能启用其中一个流并提供它的软件包。查看模块流yum module list安装模块流yum module install 18.3.3.8 查看yum事务历史yum 执行安装卸载命令会记录到相关日志中日志文件:#RHEL 8 版本日志 /var/log/dnf.rpm.log /var/log/dnf.log日志命令yum history [info|list|packages-list|packages-info|summary|addoninfo| redo|undo|rollback|new|sync|stats]
0
0
0
浏览量2003
秋月无边

Ansible处理任务失败要这样来学才牢固

Ansible处理任务失败要这样来学才牢固1. 管理play中任务错误Ansible评估任务的返回代码,从而确定任务是成功还是失败。通常而言,当任务失败时,Ansible将立即在该主机上中止play的其余部分并且跳过所有后续任务,但有些时候,可能希望即使在任务失败时也继续执行play。2. 忽略任务失败默认情况下,任务失败时play会中止。不过,可以通过忽略失败的任务来覆盖此行为。可以在任务中使用ignore_errors关键字来实现此目的。[student@servera example]$ vim ignore_errors.yml --- - name: test hosts: servera remote_user: root gather_facts: no tasks: - name: install httpd yum: name: packages # 没有这个包 state: present ignore_errors: yes # 可选{yes、no} - name: show some massage debug: msg: "hello word"[student@servera example]$ ansible-playbook ignore_errors.yml PLAY [test] **************************************************************************** TASK [install httpd] ******************************************************************* fatal: [servera]: FAILED! => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": false, "msg": "No package matching 'packages' found available, installed or updated", "rc": 126, "results": ["No package matching 'packages' found available, installed or updated"]} ...ignoring TASK [show some massage] *************************************************************** ok: [servera] => { "msg": "hello word" } PLAY RECAP ***************************************************************************** servera: ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=1观察执行可发现跳过了报告错误的任务。3. 任务失败也强制执行处理程序(handlers)通常任务失败,playbook 会终止,那么收到 play 中之前任务通知的处理程序将不会运行,如果要运行,需要在剧本中使用关键字:force_handlers:yes[student@servera example]$ cat force_handlers.yml --- - name: test hosts: servera remote_user: root force_handlers: yes # 强制执行handlers tasks: - name: show the msg debug: msg: "test the force_handlers" notify: - xxx changed_when: yes - name: error task command: ls /abc handlers: - name: xxx debug: msg: "the task is failed,but also print the msg."[student@servera example]$ ansible-playbook force_handlers.yml PLAY [test] **************************************************************************** TASK [Gathering Facts] ***************************************************************** ok: [servera] TASK [show the msg] ******************************************************************** changed: [servera] => { "msg": "test the force_handlers" } TASK [error task] ********************************************************************** fatal: [servera]: FAILED! => {"changed": true, "cmd": ["ls", "/abc"], "delta": "0:00:00.007170", "end": "2021-12-16 12:20:06.136278", "msg": "non-zero return code", "rc": 2, "start": "2021-12-16 12:20:06.129108", "stderr": "ls: cannot access /abc: No such file or directory", "stderr_lines": ["ls: cannot access /abc: No such file or directory"], "stdout": "", "stdout_lines": []} RUNNING HANDLER [xxx] ****************************************************************** ok: [servera] => { "msg": "the task is failed,but also print the msg." } PLAY RECAP ***************************************************************************** servera : ok=3 changed=1 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0因为处理程序会在任务报告changed结果时获得通知,而在任务报告ok或failed结果时不会获得通知。除了可在剧本中指定强制执行外,还可以在命令行中使用 –force-handlers 选项参数,例如上述例子中,在后面加上对应的选项即可:ansible-playbook force_handlers.yml --force-handlers还可在配置文件中添加对应配置:force_handlers = True4. 指定任务失败的条件方法一: 使用failed_when关键字在任务中使用failed_when关键字来指定表示任务已失败的条件;通常与命令模块搭配使用,这些模块可能成功执行了某一命令,但命令的输出可能指示了失败# cat test.sh #!/bin/bash cat /root # 这句肯定会出错 echo "hello word"# 注意:在playbook中执行脚本会以最后一个命令作为错误判断标准,中间错误命令不会影响整体的出错,同样也不会因为中间出错而报错# cat playbook.yaml --- - name: test conditions hosts: servera remote_user: root tasks: - name: test script: test.sh register: result failed_when: "'Is a directory' in result['stdout']" # 加上报错的条件 [student@servera ~]$ ansible-playbook -i hosts playbook.yml PLAY [test conditions] ****************************************************************** TASK [Gathering Facts] ****************************************************************** ok: [servera] TASK [test] ***************************************************************************** fatal: [servera]: FAILED! => {"changed": true, "failed_when_result": true, "rc": 0, "stderr": "Shared connection to servera closed.\r\n", "stderr_lines": ["Shared connection to servera closed."], "stdout": "cat: /root: Is a directory\r\nhello word\r\n", "stdout_lines": ["cat: /root: Is a directory", "hello word"]} to retry, use: --limit @/home/student/playbook.retry PLAY RECAP ****************************************************************************** servera : ok=1 changed=0 unreachable=0 failed=1 方法二:使用fail模块进行报错条件fail模块也可用于强制任务失败(主要是将杂乱的提示信息通过自己设置提示方式,达到简单、明了的目的)--- - name: test conditions hosts: servera remote_user: root tasks: - name: test script: test.sh register: result - name: fail modules fail: msg: "There have a failed" when: "'Is a directory' in result['stdout']"[student@servera ~]$ ansible-playbook -i hosts playbook.yml PLAY [test conditions] **************************************************************** TASK [Gathering Facts] **************************************************************** ok: [servera] TASK [test] *************************************************************************** changed: [servera] TASK [fail modules] ******************************************************************* fatal: [servera]: FAILED! => {"changed": false, "msg": "There have a failed"} to retry, use: --limit @/home/student/playbook.retry PLAY RECAP **************************************************************************** servera : ok=2 changed=1 unreachable=0 failed=15. 指定任务何时报告“changed”结果当任务对托管主机进行了更改时,会报告 changed 状态并通知处理程序。如果任务不需要进行更改,则会报告ok并且不通知处理程序。changed_when关键字可用于控制任务在何时报告它已进行了更改。演示一:--- - name: test conditions hosts: servera tasks: - name: test shell: echo "hello word" changed_when: false #可选{true、false}True,无论是否成功执行,报告返回结果都为changed。如果为False,在task没有错误的情况下,始终返回ok。演示二:--- - name: test conditions hosts: servera tasks: - name: test command: echo "hello word" register: result changed_when: "'hello word' in result.stdout" # changed_when: "'hello word' not in result.stdout"# 因为在result[‘stdout’]中有hello word ,所以被认定为是true,所以就显示changed;如果是不在,即为false,就会显示OK。6. Ansible块(block)和错误处理在playbook中,块是对任务进行逻辑分组的子句,可用于控制任务的执行方式。也可结合rescue和always语句来处理错误。如果块中的任何任务失败,则执行其rescue块中的任务来进行恢复。在block子句中的任务以及rescue子句中的任务(如果出现故障才运行)运行之后,always子句中的任务才运行。block:定义要运行的主要任务rescue:定义要在block子句中定义的任务失败时运行的任务always:定义始终都独立运行的任务,不论block和rescue子句中定义的任务是成功还是失败[student@servera example]$ cat block.yml --- - name: test block hosts: servera vars: file_name: test tasks: - name: test block block: - name: block1 command: ls /tmp - name: block2 command: "ls /tmp/{{ file_name }}" # 若文件不存在,执行rescue rescue: - name: "touch the {{ file_name }}" # 创建此文件 file: name: "/tmp/{{ file_name }}" state: touch always: # 无论block成功与否,都执行always - name: print command: echo "\(@^0^@)/" register: result - debug: msg: "{{ result.stdout }}"block中的when条件也会应用到其rescue和always子句(若存在)[student@servera example]$ ansible-playbook block.yml PLAY [test block] ********************************************************************* TASK [Gathering Facts] **************************************************************** ok: [servera] TASK [block1] ************************************************************************** changed: [servera] TASK [block2] ************************************************************************** fatal: [servera]: FAILED! => {"changed": true, "cmd": ["ls", "/tmp/test"], "delta": "0:00:00.008167", "end": "2021-12-16 14:48:40.867397", "msg": "non-zero return code", "rc": 2, "start": "2021-12-16 14:48:40.859230", "stderr": "ls: cannot access /tmp/test: No such file or directory", "stderr_lines": ["ls: cannot access /tmp/test: No such file or directory"], "stdout": "", "stdout_lines": []} TASK [touch the test] ****************************************************************** changed: [servera] TASK [print] *************************************************************************** changed: [servera] TASK [debug] *************************************************************************** ok: [servera] => { "msg": "\\(@^0^@)/" } PLAY RECAP ***************************************************************************** servera: ok=5 changed=3 unreachable=0 failed=0 skipped=0 rescued=1 ignored=0总结介绍如何忽略任务失败而继续进行任务。使用相关设置让任务失败也强制执行处理程序。可指定任务失败的条件。可指定任务何时报告“changed”结果。介绍了如何使用块(block)来进行错误处理。
0
0
0
浏览量677
秋月无边

一、运维概述与操作系统概述

1、运维概述1.1 运维岗位收入情况(职友集)来先看运维岗位的收入情况,金鱼哥是广州人,在大广州游荡,所以以广州的数据看做一下参考:1.2 运维岗位的定义什么是运维?​ 在技术人员(写代码的)之间,一致对运维有一个开玩笑的认知:运维就是修电脑的、装网线的、背锅的岗位。​ IT运维管理是指为了保障企业IT系统及网络的可用性、安全性、稳定性,保障业务的连续性,通过专业技术手段,对计算机网络、应用系统、电信网络、软硬件环境及运维服务流程等进行的综合管理。​ 随着企业数字化转型升级进程加快,企业IT系统架构越来越复杂,软件更新迭代越来越快。企业信息化建设使得大量业务和数据需要依靠信息系统来完成,稳定可用的IT系统是企业业务发展的基础条件,IT运维管理随之成为企业信息化建设的重要环节。​ 近年来,因为IT系统突然出现故障导致业务瘫痪甚至造成巨额损失的现象频出不穷。而大型数据中心由于对系统、数据的高度依赖,IT风险更大,对IT运维管理的重视也就更高。运维领域经常看到的技术及概念1)云计算架构云计算 = 公有云(阿里云、百度云、华为云) + 私有云(OpenStack) + 混合云​ 云服务器是由云服务厂商提供的性能卓越、稳定可靠、弹性扩展的IaaS(Infrastructure as a Service)级别云计算服务。云服务器免去了采购IT硬件的前期准备,让企业像使用水、电、天然气等公共资源一样便捷、高效地使用服务器,实现计算资源的即开即用和弹性伸缩。2) DevOps运维开发工程师​ DevOps(Development和Operations的组合词),它是一组过程、方法与系统的统称,主要用于促进开发和运营保障团队之间的协作与沟通,从而提高应用程序和服务的交付响应速度。 大概6:4 = 6运维:4开发(Python/Go)​ DevOps把原本独立的开发和运营工作融合到一起,运营团队时刻了解开发人员的进展,并与他们形成互动,共同监控IT业务进展。在运维方面,DevOps可以打通从需求到结果运行的所有环节,以提高业务价值为目标3) AIOps​ 2016年,Gartner提出利用AI技术的新一代IT运维,即AIOps(智能运维),可以解决未来企业可能遭遇的因IT故障而导致的业务中断,AIOps是ITOM的升级和进步,它结合了大数据和机器算法、机器学习技术,通过海量信息的搜集和处理,发现、预测、解决故障,进一步推动了IT运维自动化,减少了人力成本。4)CI/CD​ CI/CD 是一种通过在应用开发阶段引入自动化来频繁向客户交付应用的方法。CI/CD 的核心概念是持续集成、持续交付和持续部署。作为一个面向开发和运营团队的解决方案,CI/CD 主要针对在集成新代码时所引发的问题5)Docker容器化技术​ Docker 是一个开源的应用容器引擎,通常包括客户端、守护进程、镜像、容器,让开发者可以打包他们的应用以及依赖包到一个可移植的镜像中,再发布出去。类似于一个集装箱,可以把货物规整的摆放起来。1.3 运维的诞生​ 从最早的网管开始,九十年代初期,互联网欠发达的时候,还少有服务器的概念,电脑价格昂贵,大多数人并不具备在家上网的条件,网吧应运而生。早期计算机没有硬盘=>软驱=>软盘,1万多块钱 = 8-10万网吧的电脑、猫等设备需要进行日常维护,于是“网管”岗位应运而生,这就是早期运维的雏形。1.4 90年代初网吧图1.5 运维行业背景① 从行业角度来看,随着中国互联网的高速发展(BAT)、网站规模越来越来大、架构越来越复杂,对专职网站运维工程师、网站架构师的要求会越来越急迫,特别是对有经验的优秀运维人才需求量大,而且是越老越值钱。② 从个人角度,运维工程师技术含量及要求会越来越高,同时也是对公司应用、架构最了解最熟悉的人,越来越得到重视。③ 运维工作的相关经验将会变得非常重要,而且也将成为个人的核心竞争力,优秀的运维工程师具备很好的各层面问题的解决能力及方案提供、全局思考的能力等。④ 由于运维岗位所接触的知识面非常广阔,更容易培养或发挥出个人某些方面的特长或爱好,如内核、网络、开发、数据库等方面,可以做得非常深入精通、成为这方面的专家。⑤ 当前国内外对运维人才的需求非常迫切,运维工程师的薪资也水涨船高,与研发、测试等技术部门持平,甚至超出。2、企业运行模式2.1 产品线铁三角 = 产品 + 研发 + 运维(其实还有测试)流程走向:产品设计 → 项目研发 → 项目测试 → 项目上线 → 系统运维研发 = 前端(HTML+CSS+JavaScript) + 后端(Java/Python/Go)运维:产品上线、后期的运行与维护工作都属于运维工程师范畴2.2 部门与部门职责产品部门(PM、UI、UE,3-5 个):设计产品的需求,确定需要做的项目的功能和细节问题研发部门(5-7 个):根据产品部门/测试部门提供的项目模块需求进行编程测试部门(2 个左右即可):对于研发部门提供的代码进行运行测试,检查是否存在bug和一些需要改善的体验运维部门(3-4 个):负责项目环境部署、上线、架构的搭建等等2.3 上线与生产成熟企业中的系统环境:开发环境: 根据系统要求,设计和搭建系统环境测试环境:搭建系统环境,实现自动化发布准生产环境:搭建系统环境,沟通第三方厂商,自动化发布,监控生产环境:搭建系统环境,沟通第三方厂商,自动化发布,监控,发起持续改进上线:发布项目的过程,包含准生产上线,生产上线等。内测/公测 → 开服生产:正式提供对外服务的环境,叫生产环境,需要运维重点关注。在项目的从无到有的过程中,可以将其分为两个阶段:研发/测试阶段、生产运行阶段。运维工作贯穿了开发,测试,生产的各个阶段,是其中重要的一环。2.4 几个重要概念① 服务器就是给用户提供服务的机器(电脑)。服务器可以分为四大类:塔式服务器、机式服务器、刀片服务器、柜式服务器。问题一:普通台式机/笔记本能否充当服务器来使用?标准的回答:如果从提供服务的实现角度来考虑的话的确是可以,但是如果要想稳定、高效的提供服务,则在这个角度考虑家用电脑和笔记就无法取代服务器地位。家用台式机/笔记本从系统角度来看,一般都会使用Windows 系统(易用),并不适合作为服务器来使用。家用台式机/笔记本硬件和专门的服务器相比标准不统一。 问题二:服务器有哪些特性? 高性能特性 + 标准化统一特性。 ② IP地址形式ipv4(常见)、ipv6(不考虑)。Ipv4 形式:x.x.x.x,x 有取值范围(第1 位x取值1-223,从第二位开始0-255)。由于资源有限为了保证全球这么多台电脑都可以使用,ip 可以分为公网/外网ip 和私网/内网ip 地址。0.0.0.0,表示任意地方,anywhere…③ 域名就是在浏览器地址栏中输入的那一串字母和数字的组合,例如:www.baidu.com,这个就是域名,域名主要是方便用户记忆。问:www.baidu.com 这个域名是几级的域名?二级域名,看域名的级别只要看有几个".",日常所说的注册域名指的是注册顶级域名(一级)】额外购买:中国万网(已经被阿里云收购),域名属于有限资源,先买先得(按年付费)④ 公网www(万维网),全世界都可以互相访问的网。⑤ 局域网局域网/内网/私网:在某个单元内部(家庭/教室/公司)能够进行互相访问的网络,红色警戒游戏对战平台。2.5 服务器的重要结构组成家用电脑组成: CPU、主板、内存条、显卡、硬盘、电源、风扇、网卡、显示器、机箱、键盘鼠标等等。1)CPUCPU是电脑的大脑,如下图所示:CPU发展史:32 位CPU:最大的内存寻址地址2^32,大约4G的大小。CPU很傻,只认识0和132位的CPU,其支持的内存最大值 = 2的32次方 ≈ 3.80G,大约4G的大小64位的CPU,其支持的内存最大值 = 2的64次方聊聊2的32次方怎么算? 1T = 1024GB 1GB = 1024MB 1MB = 1024KB 1KB = 1024B 2^32B = 2^32 /1024/1024 /1024 = 4GBCPU i3、i5、i7、i9、志强系列(移动工作站或者企业级服务器),现在买计算机,看CPU还要看几代的。i5,十代U2)内存内存也是电脑必需组件之一。计算机是一个商铺:CPU相当于人,内存相当于仓库。商品必须上架才能显示。3)风扇4)电源5)硬盘硬盘的作用:存储数据。硬盘可以分为机械硬盘、固态硬盘。机械硬盘与固态硬盘的区别?① 速度:固态硬盘更快,不受转速影响② 安全性:机械硬盘的安全性较高,即使损坏了,也有80%以上的恢复概率企业级固态硬盘(安全性也有所提高)扩展:固态硬盘(价格千差万别,因为使用的芯片不一样)QLC(很差) < TLC(一般) < MLC(最好),芯片不同有何影响一方面是速度不一样,另外一方面安全性和寿命不同6)主板主要的作用:自身包含了一些集成电路,负责各个不同的功能和数据通信。主板上有很多空的插槽,插槽的作用在于扩展外部的硬件设备。3、操作系统概述3.1 计算机发展史第一台计算机是1946 年2 月14 日诞生日,第一台名称ENIAC。体积一间屋子的大小,重量高达28t。第一代:1946 – 1958 => 12 年 (电子管)第二代:1958 – 1964 => 6 年 (晶体管)第三代:1964 – 1970 => 6 年 (集成电路)第四代:1970 – 至今 (大规模集成电路)3.2 计算机组成CPU、内存、风扇、硬盘、显示器、主板、电源、声卡、网卡、显卡、鼠标、键盘等3.3 计算机资源(重点)计算机资源分为2 部分:硬件资源、软件资源硬件:一般硬件是指计算机的物理组成,由真实(看得见,摸得着)的设备组成的软件:软件一般是指应用程序,应用程序程序是由开发人员去按照编程语言的特定的规则去编写的程序。除了上述的应用程序之外,操作系统也属于软件资源的范畴,它属特殊的软件。问题:为什么在打开一个应用程序之后(吃鸡游戏),当玩家在敲击键盘和移动鼠标的时候里 面人物会有对应的行为表现呢?答:用户敲击键盘/移动鼠标(硬件操作) → 硬件的驱动(软件资源) → 操作系统(软件) → 硬件支持(cpu) → 操作系统(软件) → 驱动(显卡驱动) → 显示在屏幕上(硬件)所以由此可知,操作系统是软件资源与硬件资源之间的桥梁。3.4 操作系统常见操作系统有:Windows、MacOS、Unix/Linux。 类UNIXWindows:其是微软公司研发的收费操作系统(闭源)。Windows 系统体系分为两类:用户操作系统、Server 操作系统。用户操作系统:win 95、win 98、win NT、win Me、win xp、vista、win7、win8、win10。MacOS:其是由苹果公司开发的一款收费(变相收费,买电脑送系统)操作系统。该系统从终端角度来看分为:watch OS、IOS、MacOS。其表现突出的地方:底层优化实现的很好、安全性要更加高点(闭源)。Linux:Linux 是目前全球使用量最多的服务器操作系统(开源)。其体系很强大,其分支有很多(数不胜数),其目前主要的分支有:RedHat(红帽)、CentOS、Debian、乌班图(ubuntu)等等。其在世界范围最大的使用分支是安卓。闭源:不开放源代码,用户是没有办法看到软件的底层实现(闭源≠收费)。开源:表示开放源代码(开源≠免费)。开源 Open Source软件和源代码提供给所有人,自由分发软件和源代码,free 自由,不是免费的意思能够修改和创建衍生作品软件分类:商业:收费,源码也不公开共享:免费使用,但源码不公开自由:源代码公开开源协议世界上的开源许可证,大概有上百种3.5 为什么需要Linux操作系统问题:windows 既然可以使用傻瓜式的方式进行操作,例如使用ctrl+c 表示复制,ctrl+v 表示粘贴等,为什么还需要使用/学习Linux 系统? ① 性能问题,Windows 服务器操作系统不如Linux 高;② 稳定性问题:底层架构:Linux 更加稳定,其开机时间可以达到好几年不关机;开源:因为开源,人人都可以看到源代码,就可以为其提供自己的补丁,补丁可以提高稳定性和安全性;③ 安全性问题:Linux 操作系统,相对于Windows 操作系统要更加安全;④ 远程管理方面:Windows 不及Linux 操作高效。⑤ 服务器价格昂贵的,需要对资源进行充分利用,充分把计算机资源用到项目上(访问并发、性能),而不是把资源浪费在图形化界面或者方便程度上;3.4 Linux分支(Linux衍生版:Linux厂商基于Linux内核)分支:Linux 分支有很多,现在比较有名的redhat、ubuntu、debian、centos(Community Enterprise Operating System)、suse 等等。redhat红帽(redhat企业版、centos社区版)、ubuntu(乌班图)、debian、suse中国Linux系统:红旗(Redflag)、麒麟、深度OS(推荐,和Windows基本一致)
0
0
0
浏览量1626
秋月无边

四、访问命令行

4.1 执行命令4.1.1 执行命令过程输入命令后回车,提请shell程序找到键入命令所对应的可执行程序或代码,并由其分析后提交给内核分配资源将其运行起来4.1.2 shell中可执行的两类命令内部命令:由shell自带的,而且通过某命令形式提供ll /bin/bash外部命令:在文件系统路径下有对应的可执行程序文件ll /usr/bin/who区别指定的命令是内部或外部命令type COMMAND范例:查看是否存在对应内部和外部命令[root@centos8 ~]# type -a echo echo is a shell builtin echo is /usr/bin/echo内部命令相关help 内部命令列表外部命令的读取方式外部命令是从磁盘中读取,那么系统在执行外部命令的时候是通过$PATH变量找到命令,而不是全局搜索,那样的效率就会太慢[23:44:33 root@servera ~]#echo $PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/binHash缓存表系统初始hash表为空,当外部命令执行时,默认会从PATH路径下寻找该命令,找到后会将这条命令的路径记录到hash表中,当再次使用该命令时,shell解释器首先会查看hash表,存在将执行之,如果不存在,将会去PATH路径下寻找,利用hash缓存表可大大提高命令的调用速率[23:44:31 root@servera ~]# hash hits command 1 /usr/bin/hostnamectl 1 /usr/bin/hostname 1 /usr/bin/who4.1.3 命令别名对于经常执行的较长的命令,可以将其定义成较短的别名,以方便执行显示当前shell进程所有可用的命令别名alias定义别名NAME,其实相当于执行命令VALUEalias NAME='VALUE'范例:[root@centos8 ~]# alias free='free -h'"撤消别名:unaliasunalias [-a] name [name ...] unalias -a #取消所有别名注意:在命令行中定义的别名,仅对当前shell进程有效如果想永久有效,要定义在配置文件中仅对当前用户:~/.bashrc对所有用户有效:/etc/bashrc[root@centos8 ~]# echo "alias free='free -h'" >> .bashrc如果别名同原命令同名,如果要执行原命令,可使用\ALIASNAME “ALIASNAME” ‘ALIASNAME’ command ALIASNAME /path/commmand #只适用于外部命令4.1.4 命令格式COMMAND [选项] [参数]选项:用于启用或关闭命令的某个或某些功能短选项:UNIX 风格选项,-c 例如:-l, -h长选项:GNU风格选项,–word 例如:–all, --humanBSD风格选项: 一个字母,例如:a,使用相对较少参数:命令的作用对象,比如:文件名,用户名等范例:[root@centos8 ~]# ls -a [root@centos8 ~]# ls --all [root@centos8 ~]# free -h [root@centos8 ~]# free --human [root@centos8 ~]# ps a4.1.5 控制执行多个命令;:当第一条命令执行完成后(不管是否执行成功),执行第二条命令,此为顺序执行||:只有当第一条命令执行失败的时候,才会去执行第二条命令&&:只有当你第一条命令执行成功的时候,才会去执行第二条命令范例:[root@servera ~]# cd /tmp;mkdir test1;ls [root@servera tmp]# cd /tmp;cat xxx || mkdir test2;ls cat: xxx: No such file or directory [root@servera tmp]# cd /tmp;cat xxx && mkdir test3;ls cat: xxx: No such file or directory [root@servera tmp]# cd /tmp && mkdir test3;ls注意:多个选项以及多参数和命令之间使用空白字符分隔取消和结束命令执行:Ctrl+c多个命令放在一行,每个命令之间可以用 “;” 符号分开一个命令可以用\分成多行4.1.6 命令行扩展:`` 和 $()把一个命令的输出打印给另一个命令的参数$(COMMAND) 或 `COMMAND` #COMMAND必须是一个有标出信息的命令范例:比较 “ ” ,‘ ’, ``三者区别[root@centos8 ~]# echo "echo $HOSTNAME" echo centos8.localdomain [root@centos8 ~]# echo 'echo $HOSTNAME' echo $HOSTNAME [root@centos8 ~]# echo `echo $HOSTNAME` centos8.localdomain #结论: # 单引号:六亲不认,变量和命令都不识别,都当成了普通的字符串 # 反向单引号:变量和命令都识别,并且会将反向单引号的内容当成命令进行执行后,再交给调用反向单引号的命令继续 # 双引号:不能识别命令,可以识别变量4.2 tab键补全tab 键可以实现命令及路径等补全,提高输入效率,避免出错4.2.1 命令补全最小化安装默认没有子命令补全,需要安装bash-completion注意:用户给定的字符串只有一条惟一对应的命令,直接补全,否则,再次Tab会给出列表范例:[root@centos8 ~]# nmcli connection #按2TAB add delete edit help load monitor show clone down export import modify reload up4.2.2 路径补全把用户给出的字符串当做路径开头,并在其指定上级目录下搜索以指定的字符串开头的文件名如果惟一:则直接补全否则:再次Tab给出列表4.3 命令行历史当执行命令后,系统默认会在内存记录执行过的命令当用户正常退出时,会将内存的命令历史存放对应历史文件中,默认是~/.bash_history登录shell时,会读取命令历史文件中记录下的命令加载到内存中登录进shell后新执行的命令只会记录在内存的缓存区中;这些命令会用户正常退出时“追加”至命令历史文件中利用命令历史。可以用它来重复执行命令,提高输入效率命令:historyhistory [-c] [-d offset] [n] history -anrw [filename] history -ps arg [arg...]-c: 清空命令历史-d offset: 删除历史中指定的第offset个命令n: 显示最近的n条历史-a: 追加本次会话新执行的命令历史列表至历史文件-r: 读历史文件附加到历史列表-w: 保存历史列表到指定的历史文件-n: 读历史文件中未读过的行到历史列表-p: 展开历史参数成多行,但不存在历史列表中-s: 展开历史参数成一行,附加在历史列表后4.3.1 调用命令行历史#重复前一个命令方法 重复前一个命令使用上方向键,并回车执行 按 !! 并回车执行 !n 执行history命令输出对应序号n的命令history:默认记录1000条记录4.4 bash的快捷键课本介绍:扩展:Ctrl + l 清屏,相当于clear命令Ctrl + o 执行当前命令,并重新显示本命令Ctrl + s 阻止屏幕输出,锁定Ctrl + q 允许屏幕输出,解锁Ctrl + c 终止命令Ctrl + z 挂起命令Ctrl + a 光标移到命令行首,相当于HomeCtrl + e 光标移到命令行尾,相当于EndCtrl + f 光标向右移动一个字符Ctrl + b 光标向左移动一个字符Ctrl + xx 光标在命令行首和光标之间移动Alt + f 光标向右移动一个单词尾Alt + b 光标向左移动一个单词首Ctrl + u 从光标处删除至命令行首Ctrl + k 从光标处删除至命令行尾Alt + r 删除当前整行Ctrl + w 从光标处向左删除至单词首Alt + d 从光标处向右删除至单词尾Alt + Backspace 删除左边单词Ctrl + d 删除光标处的一个字符Ctrl + h 删除光标前的一个字符Ctrl + y 将删除的字符粘贴至光标后Alt + c 从光标处开始向右更改为首字母大写的单词Alt + u 从光标处开始,将右边一个单词更改为大写Alt + l 从光标处开始,将右边一个单词更改为小写Ctrl + t 交换光标处和之前的字符位置Alt + t 交换光标处和之前的单词位置Alt + # 提示输入指定字符后,重复显示该字符#次注意:Alt组合快捷键经常和其它软件冲突范例:xshell中启动 alt 键
0
0
0
浏览量2004
秋月无边

三、Linux框架

3.1 用户类型root:root 用户一个特殊的管理帐户也被称为超级用户root已接近完整的系统控制对系统损害几乎有无限的能力除非必要,不要登录为 root普通( 非特权 )用户权限有限造成损害的能力比较有限3.2 终端Terminal介绍3.2.1 终端文本终端:tty伪终端:pts远程终端工具(按操作系统划分):Windows:CMD(Windows 10 1909及更新版本)/ powershell   xshell/SecureCRT/Putty/MobaXterm/…Mac OS: Terminal(因为它是unix系统)Linux: Terminal3.2.2 查看当前终端设备tty命令可以查看当前所在终端范例:[root@centos8 ~]#tty /dev/pts/0查看目前有谁在使用终端whoami:查看当前终端的登陆者[root@localhost ~]# whoami rootwho am i:查看当前登陆的终端、登陆者以及登陆时间等信息[root@localhost ~]# who am i root pts/1 2021-03-24 22:33 (192.168.137.2) w:查看所有终端的终端名、登陆者、登陆时间以及正在做什么事情等信息[root@localhost ~]# w 22:34:00 up 2:08, 3 users, load average: 0.00, 0.00, 0.00 USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT root tty2 tty2 18:43 3:50m 30.26s 0.13s /usr/libexec/track root tty3 - 19:12 2:24m 0.12s 0.12s -bash root pts/1 192.168.137.2 22:33 0.00s 0.05s 0.01s w3.2.3 终端切换默认情况下,系统是以图形化界面启动查看当前默认使用启动模式:[root@servera ~]#systemctl get-default graphical.target切换终端:Ctrl+alt+(fn)+[F1-F6]永久切换默认登陆模式:范例:[root@servera ~]# systemctl set-default multi-user.target文本界面:multi-user.target图形化界面:graphical.target3.3 交互式接口交互式接口:启动终端后,在终端设备附加一个交互式应用程序3.3.1 交互式接口类型GUI 图形化界面CLI shell程序3.3.2 什么是shell由于Shell本身是个程序,所以它可以被任何用户自己开发的各种Shell所代替3.3.3 bash shellGNU Bourne-Again Shell(bash)是GNU计划中重要的工具软件之一,目前也是 Linux标准的shell,与sh兼容显示当前使用的shell[root@localhost ~]# echo $SHELL /bin/bash显示当前系统使用的所有shell[root@localhost ~]# cat /etc/shells /bin/sh /bin/bash /usr/bin/sh /usr/bin/bash3.4 设置主机名hostname NAME范例:最左边的是主机名,后面的是域名[23:23:56 root@servera ~]#hostnamectl set-hostname servera.lab.example.com [23:24:12 root@servera ~]#hostname servera.lab.example.com注意:主机名不支持使用下划线,但支持横线3.5 命令提示符命令提示符: prompt范例:[root@localhost ~]# #是管理员$是普通用户显示提示符格式[root@localhost ~]# echo $PS1 [\u@\h \W]\$修改提示符格式范例[root@localhost ~]# PS1="[\t \u@\h \W]\\$" [22:49:47 root@localhost ~]#永久修改:echo 'PS1="[\t \u@\h \W]\\$"' >> /etc/profile.d/env.sh提示符格式说明:\d :代表日期,格式为weekday month date,例如:Wed Dec 12\H :完整的主机名称。例如:hostname是domain.linux\\h :仅取主机的第一个名字,如上例,则为debian,.linux则被省略\t :显示时间为24小时格式,如:HH:MM:SS\T :显示时间为12小时格式\A :显示时间为24小时格式:HH:MM\u :当前用户的账号名称 如:root\v :BASH的版本信息 如:3.2\w :完整的工作目录名称。家目录会以 ~代替 如显示/etc/default/\W :利用basename取得工作目录名称,所以只会列出最后一个目录 如上例则只显示default
0
0
0
浏览量1581
秋月无边

九、管理本地用户和组

9.1 Linux 安全模型9.1.1 用户Linux中每个用户是通过User Id (UID)来唯一标识的管理员:root, 0普通用户:1-60000 自动分配     。系统用户:1-499 (rhel 6以前), 1-999 (rhel 7以后)        对守护进程获取资源进行权限分配      。 登录用户:500+ (rhel6 以前), 1000+(rhel7以后)          给用户进行交互式登录使用9.1.2 用户组Linux中可以将一个或多个用户加入用户组中,用户组是通过Group ID(GID) 来唯一标识的。管理员组:root, 0普通组:      。系统组:1-499(rhel 6以前), 1-999(rhel7以后), 对守护进程获取资源进行权限分配     。  普通组:500+(rhel 6以前), 1000+(rhel7以后), 给用户使用9.1.3 用户和组的关系用户的主要组(primary group):用户必须属于一个且只有一个主组,默认创建用户时会自动创建和用户名同名的组,做为用户的主要组,由于此组中只有一个用户,又称为私有组用户的附加组(supplementary group): 一个用户可以属于零个或多个辅助组,附属组范例:[root@servera ~]# id mysql uid=27(mysql) gid=27(mysql) groups=27(mysql) [root@servera ~]# id studentLinux安全上下文Context:运行中的程序,即进程 (process),以进程发起者的身份运行,进程所能够访问资源的权限取决于进程的运行者的身份比如:分别以root 和普通用户的身份运行/bin/cat /etc/shadow ,得到的结果是不同的,资源能否能被访问,是由运行者的身份决定,非程序本身范例:[student@servera ~]$ cat /etc/shadow cat: /etc/shadow: Permission denied [root@servera ~]# cat /etc/shadow root:$6$dV.Vb.MYhHB82gJz$FnOeixf0W.UgV.Vd4xx8yWuJT.fSJbGTXpdpQ0K9BwWzI5hWeG4lWQYisFNz.LReR5rcz6QFg9sc9SBZxYXhP0::0:99999:7::: bin:*:18199:0:99999:7::: daemon:*:18199:0:99999:7::: adm:*:18199:0:99999:7:::9.2 用户和组的配置文件9.2.1 用户和组的主要配置文件/etc/passwd:用户及其属性信息(名称、UID、主组ID等)/etc/shadow:用户密码及其相关属性/etc/group:组及其属性信息/etc/gshadow:组密码及其相关属性9.2.2 passwd文件格式student:x:1000:1000:student:/home/student:/bin/bashlogin name:登录用名(student)passwd:密码 (x)UID:用户身份编号 (1000)GID:登录默认所在组编号 (1000)GECOS:用户全名或注释home directory:用户主目录 (/home/student)shell:用户默认使用shell (/bin/bash)9.2.3 shadow文件格式student:$6$4NaBMjQ...::0:99999:7:::登录用名用户密码:一般用sha512加密从1970年1月1日起到密码最近一次被更改的时间密码再过几天可以被变更(0表示随时可被变更)密码再过几天必须被变更(99999表示永不过期)密码过期前几天系统提醒用户(默认为一周)密码过期几天后帐号会被锁定从1970年1月1日算起,多少天后帐号失效字段保留更改密码加密算法:authconfig --passalgo=sha256 --update密码的安全策略足够长使用数字、大写字母、小写字母及特殊字符中至少3种使用随机密码定期更换,不要使用最近曾经使用过的密码范例:生成随机密码[root@servera ~]# openssl rand -base64 9 JcEFSIbX3xGl生成随机密码:https://suijimimashengcheng.51240.com/9.2.4 group文件格式student:x:1000: mail:x:12:postfix群组名称:就是群组名称群组密码:通常不需要设定,密码是被记录在 /etc/gshadowGID:就是群组的 ID以当前组为附加组的用户列表(分隔符为逗号)9.2.5 gshdow文件格式student:!::群组名称:就是群的名称群组密码:组管理员列表:组管理员的列表,更改组密码和成员以当前组为附加组的用户列表:多个用户间用逗号分隔9.2.6 文件操作vipw和vigr pwck和grpck9.3 用户和组管理命令用户管理命令useradd 创建用户 usermod 修改用户属性 userdel 删除用户组帐号维护命令groupadd 创建组 groupmod 修改属性 groupdel 删除组9.3.1 用户创建useradd 命令可以创建新的Linux用户格式:useradd [options] LOGIN常见选项:-u UID -e 设定用户什么时候失效 -o 配合-u 选项,不检查UID的唯一性 -g GID 指明用户所属基本组,可为组名,也可以GID -c "COMMENT“ 用户的注释信息 -d HOME_DIR 以指定的路径(不存在)为家目录 -s SHELL 指明用户的默认shell程序,可用列表在/etc/shells文件中 -G GROUP1[,GROUP2,...] 为用户指明附加组,组须事先存在 -N 不创建私用组做主组,使用users组做主组 -r 创建系统用户 rhel 6之前: ID<500,rhel 7以后: ID<1000 -m 创建家目录,用于系统用户 -M 不创建家目录,用于非系统用户范例:useradd -r -u 48 -g apache -s /sbin/nologin -d /var/www -c "Apache" apache9.3.2 用户属性修改usermod 命令可以修改用户属性格式:usermod [OPTION] login常见选项:-u UID: 新UID -g GID: 新主组 -G GROUP1[,GROUP2,...[,GROUPN]]]:新附加组,原来的附加组将会被覆盖;若保留原有,则要同时使 用-a选项 -s SHELL:新的默认SHELL -c 'COMMENT':新的注释信息 -d HOME: 新家目录不会自动创建;若要创建新家目录并移动原家数据,同时使用-m选项 -l login_name: 新的名字 -L: lock指定用户,在/etc/shadow 密码栏的增加 ! -U: unlock指定用户,将 /etc/shadow 密码栏的 ! 拿掉 -e YYYY-MM-DD: 指明用户账号过期日期 -f INACTIVE: 设定非活动期限,即宽限期9.3.3 删除用户userdel 可删除Linux 用户格式:userdel [OPTION]... Login常见选项:-f, --force 强制 -r, --remove 删除用户家目录和邮箱9.3.4 查看用户相关的ID信息id 命令可以查看用户的UID,GID等信息id [OPTION]... [USER]常见选项:-u: 显示UID -g: 显示GID -G: 显示用户所属的组的ID -n: 显示名称,需配合ugG使用9.3.5 切换用户或以其他用户身份执行命令su: 即 switch user,命令可以切换用户身份,并且以指定用户的身份执行命令格式:su [options...] [-] [user [args...]]常见选项:-l --login su -l UserName 相当于 su - UserName -c, --command <command> pass a single command to the shell with -c切换用户的方式:su UserName:非登录式切换,即不会读取目标用户的配置文件,不改变当前工作目录,即不完全切换su - UserName:登录式切换,会读取目标用户的配置文件,切换至自已的家目录,即完全切换说明:root su至其他用户无须密码;非root用户切换时需要密码注意:su 切换新用户后,使用 exit 退回至旧的用户,而不要再用 su 切换至旧用户,否则会生成很多的bash子进程,环境可能会混乱。换个身份执行命令:su [-] UserName -c 'COMMAND'范例:[root@servera hao]# su - hao -c "touch hao.txt" [root@servera hao]# ll ~hao total 0 -rw-rw-r--. 1 hao hao 0 Mar 26 22:07 hao.txt9.3.6 设置密码格式:passwd [OPTIONS] UserName常用选项:-d:删除指定用户密码 -l:锁定指定用户 -u:解锁指定用户 -e:强制用户下次登录修改密码 -f:强制操作 -n mindays:指定最短使用期限 -x maxdays:最大使用期限 -w warndays:提前多少天开始警告 -i inactivedays:非活动期限 --stdin:从标准输入接收用户密码,Ubuntu无此选项范例:非交互式修改用户密码[root@servera ~]# echo 'redhat' | passwd --stdin redhat Changing password for user redhat. passwd: all authentication tokens updated successfully.9.3.7 修改用户密码策略chage 可以修改用户密码策略格式:chage [OPTION]... LOGIN常见选项:-d LAST_DAY #更改密码的时间 -m --mindays MIN_DAYS -M --maxdays MAX_DAYS -W --warndays WARN_DAYS -I --inactive INACTIVE #密码过期后的宽限期 -E --expiredate EXPIRE_DATE #用户的有效期 -l 显示密码策略范例:[root@servera ~]# chage -m 3 -M 30 -W 14 -I 7 -E 2021-03-27 hao [root@servera ~]# chage -l hao Last password change : password must be changed Password expires : password must be changed Password inactive : password must be changed Account expires : Mar 27, 2021 Minimum number of days between password change : 3 Maximum number of days between password change : 30 Number of days of warning before password expires : 14范例:用户下次登录需要更改密码[root@servera ~]# chage -d 0 hao9.3.8 创建组groupadd实现创建组格式groupadd [OPTION]... group_name常见选项:-g GID 指明GID号;[GID_MIN, GID_MAX] -r 创建系统组,CentOS 6之前: ID<500,CentOS 7以后: ID<1000范例:groupadd -g 48 -r apachegroupmod 组属性修改格式:groupmod [OPTION]... group常见选项:-n group_name: 新名字-g GID: 新的GID9.3.9 组删除groupdel 可以删除组格式groupdel [options] GROUP常见选项:-f, --force 强制删除,即使是用户的主组也强制删除组9.3.10 更改和查看组成员groupmems 可以管理附加组的成员关系格式groupmems [options] [action]常见选项:-g, --group groupname #更改为指定组 (只有root) -a, --add username #指定用户加入组 -d, --delete username #从组中删除用户 -p, --purge #从组中清除所有成员 -l, --list #显示组成员列表范例:[root@servera ~]# id student uid=1000(student) gid=1000(student) groups=1000(student) [root@servera ~]# groupmems -l -g admins [root@servera ~]# groupmems -a student -g admins [root@servera ~]# groupmems -l -g admins student [root@servera ~]# id student uid=1000(student) gid=1000(student) groups=1000(student),1001(admins) [root@servera ~]# groupmems -a student -g mysql [root@servera ~]# id student uid=1000(student) gid=1000(student) groups=1000(student),27(mysql),1001(admins)groups 可查看用户组关系格式:#查看用户所属组列表 groups [OPTION].[USERNAME]...
0
0
0
浏览量265
秋月无边

这样动手玩Ansible多条件判断真爽

多条件判断一个when语句可用于评估多个条件。使用and和or关键字组合条件,并使用括号分组条件。[student@servera ~]$ ansible -i hosts servera -m setup | grep bios_version "ansible_bios_version": "0.5.1", [student@servera ~]$ cat test.yml --- - name: when test hosts: servera remote_user: root tasks: - name: httpd installed yum: name: httpd state: present when: ansible_facts['architecture'] == 'x86_64' and ansible_facts['bios_version'] == '0.5.1' 这里的条件语句表示:当受管主机ansible_facts下的ansible_architecture等于“x86_64”和ansible_bios_version等于“0.5.1”,这两个条件同时满足时,才会执行安装httpd的服务执行测试:[student@servera ~]$ ansible-playbook -i hosts test.yml PLAY [when test] ************************************************************************ TASK [Gathering Facts] ****************************************************************** ok: [servera] TASK [httpd installed] ****************************************************************** changed: [servera] PLAY RECAP ****************************************************************************** servera : ok=2 changed=1 unreachable=0 failed=0 # 测试执行成功如果有一个条件不符合:[student@servera ~]$ cat test.yml --- - name: when test hosts: servera remote_user: root tasks: - name: httpd installed yum: name: httpd state: present when: ansible_facts['architecture'] == 'x86_64' and ansible_facts['bios_version'] == '0.5.2' # 这里将bios_version改为"0.5.2" 执行测试:[student@servera ~]$ ansible-playbook -i hosts test.yml PLAY [when test] *********************************************************************** TASK [Gathering Facts] ***************************************************************** ok: [servera] TASK [httpd installed] ***************************************************************** skipping: [servera] PLAY RECAP ***************************************************************************** servera : ok=1 changed=0 unreachable=0 failed=0 你会发现显示skipping,跳过这任务的执行。上述playbook的另一种写法:when关键字还支持使用列表来描述条件列表。向when关键字提供列表时,将使用and运算组合所有条件。--- - name: when test hosts: servera remote_user: root tasks: - name: httpd installed yum: name: httpd state: present when: - ansible_facts['architecture'] == 'x86_64' - ansible_facts['bios_version'] == '0.5.1' 这种格式提高了可读性,而可读性是良好编写Ansible Playbook的关键目标。通过使用括号分组条件,可以表达更复杂的条件语句。--- - name: when test hosts: servera remote_user: root tasks: - name: httpd installed yum: name: httpd state: present when: > ansible_facts['architecture'] == 'x86_64' or ansible_facts['bios_version'] == '0.5.1' 这种写法的条件语句只需要满足多个条件中的一个就满足了条件,就能执行安装任务。(还记得when后的 > 符号吗?是代表后面的字符窜是同一行,还有 | 符号也是。基础的东西很重要,要谨记。)将上述的几种方法配合使用:--- - name: when test hosts: servera remote_user: root tasks: - name: httpd installed yum: name: httpd state: present when: > ( ansible_facts['architecture'] == "x86_64" and ansible_facts['bios_version'] == "6.00" ) or ( ansible_facts['bios_version'] == "5.00" and ansible_facts['architecture'] == "x86_32" ) 括号内的条件必须两个同时满足,而括号外的两个条件整体两个满足一个即可满足条件语句要求。循环语句和多条件判断语句还可以与循环语句作为组合使用。--- - name: when test hosts: servera remote_user: root tasks: - name: httpd installed yum: name: httpd state: present loop: "{{ ansible_facts['mounts'] }}" when: - item.mount == '/' - item.size_available > 88420000 这里需要满足item.mount和item.size_available > 88420000这两个条件才能触发安装httpd的任务。也许你会问,为什么要写成循环,因为ansible_facts[‘mounts’].mount 有2个值,所以要使用循环,我们可使用setup模块进行观察。[student@servera ~]$ ansible localhost -m setup -a 'filter=*mounts*' localhost | SUCCESS => { "ansible_facts": { "ansible_mounts": [ { "block_available": 21105, "block_size": 4096, "block_total": 50345, "block_used": 29240, "device": "/dev/sda1", "fstype": "xfs", "inode_available": 102074, "inode_total": 102400, "inode_used": 326, "mount": "/boot", "options": "rw,relatime,attr2,inode64,noquota", "size_available": 86446080, "size_total": 206213120, "uuid": "80184c5c-3a00-41c6-a458-f4db8148072e" }, { "block_available": 4306130, "block_size": 4096, "block_total": 4925952, "block_used": 619822, "device": "/dev/mapper/system-root", "fstype": "xfs", "inode_available": 9774997, "inode_total": 9857024, "inode_used": 82027, "mount": "/", "options": "rw,relatime,attr2,inode64,noquota", "size_available": 17637908480, "size_total": 20176699392, "uuid": "2bdd417e-828b-4e8d-9578-db4bf5b42ee7" } ] }, "changed": false } 组合使用注册变量和条件判断语句我们还可以通过使用注册变量上的输出来作为条件上的判断。(啥?如果忘记了如何判断注册变量输出的值,可参考关于注册变量的那一章节,其实,我们直接运用debug模块就可知道了。)- name: when test hosts: servera remote_user: root tasks: - name: httpd status command: /usr/bin/systemctl is-active httpd #查看httpd服务状态 ignore_errors: yes #忽略报错,报错后直接跳过不终止任务 register: result #将以上任务的结果注册为变量 - name: httpd restarted service: name: httpd state: restarted when: result.rc == 3 #如果注册变量的返回值为3则执行重启httpd的任务 上述是编写任务先将httpd服务查看作为注册变量,然后将这注册变量值中的 rc 值作为条件判断,如果返回值为3,则重启服务。(因为systemctl is-active httpd命令如果服务没启动,返回值为3,还记得echo $? 吗)[student@servera ~]$ ansible-playbook -i hosts test.yml PLAY [when test] *********************************************************************** TASK [Gathering Facts] ****************************************************************** ok: [servera] TASK [httpd status] ********************************************************************* fatal: [servera]: FAILED! => {"changed": true, "cmd": ["/usr/bin/systemctl", "is-active", "httpd"], "delta": "0:00:00.004768", "end": "2020-09-08 16:44:17.090311", "msg": "non-zero return code", "rc": 3, "start": "2020-09-08 16:44:17.085543", "stderr": "", "stderr_lines": [], "stdout": "unknown", "stdout_lines": ["unknown"]} ...ignoring TASK [httpd restarted] ****************************************************************** changed: [servera] PLAY RECAP ***************************************************************************** servera : ok=3 changed=2 unreachable=0 failed=0 总结使用 and 和 or 进行多条件判断的编写。可使用括号进行多条件的组合编写。循环语句可与多条件判断组合使用,注册变量和条件判断语句也可组合使用。注意when语句的语法编写。
0
0
0
浏览量2004
秋月无边

快捷玩Ansible循环任务

1. 招式简介—利用循环迭代任务在Ansible编写剧本的时候,我们往往遇到许多重复性的操作,比如安装各种软件包,在某个目录操作各种文件等等。通过利用循环,我们无需编写多个使用同一模块的任务。例如,他们不必编写五个任务来确保存在五个用户,而是只需编写一个任务来对含有五个用户的列表迭代,从而确保它们都存在。Ansible支持使用loop关键字对一组项目迭代任务。可以配置循环以利用列表中的各个项目、列表中各个文件的内容、生成的数字序列或更为复杂的结构来重复任务。2. 基础演练—编写简单循环循环可对一组项目进行迭代任务。使用loop关键字添加到任务中,将应对其迭代任务的项目列表取为值。循环变量item保存每个迭代过程中使用的值。可以理解为loop和item就是一配对。举个例子:不用循环的写法:--- - hosts: localhost tasks: - name: mkdir /home/student/abc shell: mkdir /home/student/abc - name: mkdir /home/student/cde shell: mkdir /home/student/cde使用简单的循环:# cat test.yml --- - hosts: localhost tasks: - name: mkdir /home/student/ file shell: "mkdir /home/student/{{ item }}" loop: - abc - cde明显使用一次shell模块,而不用使用二次就可以达到最终的需求。(突然感觉气血通畅,爽!)还有另一种写法:(这种偏门点的招式,还是看看就好)--- - hosts: localhost vars: dir_name: - abc - cde tasks: - name: mkdir /home/student/ file shell: "mkdir /home/student/{{ item }}" loop: "{{ dir_name }}"3. 招式外放—循环散列或字典列表loop列表可不以简单的值作为调用,而是使用散列或字典,这较为复杂一点的写法。在以下示例中,列表中的每个项实际上是散列或字典。示例中的每个散列或字典具有两个键,即name和groups,当前item循环变量中每个键的值可以分别通过item.name和item.groups变量来检索。--- - hosts: localhost tasks: - name: user loop test user: name: "{{ item.name }}" state: present group: "{{ item.group }}" loop: - name: chap group: chap - name: rebel group: rebel(还记得上文所说的loop和item配对吗?item.name其实就是loop.name,人家是比翼双飞,水影鸳鸾 >.<)较早样式的循环关键字在Ansible2.5之前,大多数playbook使用不同的循环语法。提供了多个循环关键字,前缀为with_,后面跟Ansible查找插件的名称。这种循环语法在现有playbook中很常见,但在将来的某个时候可能会被弃用。(看来招式还是需要定期更新才行,不过在人家还没有过时前,还是得先见招拆招。)较早样式的Ansible循环with_****items循环playbook演示:--- - hosts: localhost vars: data: - abc - cde - efg tasks: - name: with_item test debug: msg: "{{ item }}" with_items: "{{ data }}"4. 一剑定江山—将Register变量与Loop一起使用register关键字也可以用来捕获循环任务的输出。以下代码片段显示了循环任务中register变量的结构:register和loop配合使用[student@servera example]$ cat loop-register.yml --- - hosts: localhost tasks: - name: register and loop shell: "echo test {{ item }}" loop: - abc - cde register: results - name: print result debug: var: results[student@servera example]$ ansible-playbook loop-register.yml PLAY [loop-register] ******************************************************************* TASK [Gathering Facts] ***************************************************************** ok: [localhost] TASK [register and loop] *************************************************************** changed: [localhost] => (item=abc) changed: [localhost] => (item=def) TASK [print result] ******************************************************************** ok: [localhost] => { "results": { "changed": true, "msg": "All items completed", "results": [ { "ansible_loop_var": "item", "changed": true, "cmd": "echo test abc", "delta": "0:00:00.007471", "end": "2021-12-09 23:47:00.084344", "failed": false, "invocation": { "module_args": { "_raw_params": "echo test abc", "_uses_shell": true, "argv": null, "chdir": null, "creates": null, "executable": null, "removes": null, "stdin": null, "stdin_add_newline": true, "strip_empty_ends": true, "warn": true } }, "item": "abc", "rc": 0, "start": "2021-12-09 23:47:00.076873", "stderr": "", "stderr_lines": [], "stdout": "test abc", "stdout_lines": [ "test abc" ] }, { "ansible_loop_var": "item", "changed": true, "cmd": "echo test def", "delta": "0:00:00.007672", "end": "2021-12-09 23:47:00.259170", "failed": false, "invocation": { "module_args": { "_raw_params": "echo test def", "_uses_shell": true, "argv": null, "chdir": null, "creates": null, "executable": null, "removes": null, "stdin": null, "stdin_add_newline": true, "strip_empty_ends": true, "warn": true } }, "item": "def", "rc": 0, "start": "2021-12-09 23:47:00.251498", "stderr": "", "stderr_lines": [], "stdout": "test def", "stdout_lines": [ "test def" ] } ] } } PLAY RECAP ***************************************************************************** localhost : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0更进一步的运用:[student@servera example]$ cat loop-register.yml --- - name: loop-register hosts: localhost tasks: - name: register and loop shell: "echo test {{ item }}" loop: - abc - cde register: results - name: print results debug: msg: "Send out the message: {{ item.stdout }}" loop: "{{ results['results'] }}" # 此为运用散列或字典列表的形式,将results这注册变量所输出项中取results项中的值。 # loop: "{{ results.results }}" # 还记得这个一样的写法吗~~不记得可参考https://blog.csdn.net/qq_41765918/article/details/121796046 章节中,新旧语法对比。[student@servera example]$ ansible-playbook loop-register.yml PLAY [loop-register] ******************************************************************* TASK [Gathering Facts] ***************************************************************** ok: [localhost] TASK [register and loop] *************************************************************** changed: [localhost] => (item=abc) changed: [localhost] => (item=def) TASK [print results] ******************************************************************* ok: [localhost] => (item={u'stderr_lines': [], u'ansible_loop_var': u'item', u'end': u'2021-12-09 23:41:27.978177', u'stderr': u'', u'stdout': u'test abc', u'changed': True, u'failed': False, u'delta': u'0:00:00.007256', u'cmd': u'echo test abc', u'item': u'abc', u'rc': 0, u'invocation': {u'module_args': {u'warn': True, u'executable': None, u'_uses_shell': True, u'strip_empty_ends': True, u'_raw_params': u'echo test abc', u'removes': None, u'argv': None, u'creates': None, u'chdir': None, u'stdin_add_newline': True, u'stdin': None}}, u'stdout_lines': [u'test abc'], u'start': u'2021-12-09 23:41:27.970921'}) => { "msg": "Send out the message: test abc" } ok: [localhost] => (item={u'stderr_lines': [], u'ansible_loop_var': u'item', u'end': u'2021-12-09 23:41:28.148281', u'stderr': u'', u'stdout': u'test def', u'changed': True, u'failed': False, u'delta': u'0:00:00.007047', u'cmd': u'echo test def', u'item': u'def', u'rc': 0, u'invocation': {u'module_args': {u'warn': True, u'executable': None, u'_uses_shell': True, u'strip_empty_ends': True, u'_raw_params': u'echo test def', u'removes': None, u'argv': None, u'creates': None, u'chdir': None, u'stdin_add_newline': True, u'stdin': None}}, u'stdout_lines': [u'test def'], u'start': u'2021-12-09 23:41:28.141234'}) => { "msg": "Send out the message: test def" } PLAY RECAP ***************************************************************************** localhost: ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0总结理解Ansible循环任务的使用场景。运用loop与item编写循环任务。理解循环任务与注册变量的搭配。
0
0
0
浏览量1795
秋月无边

十二、服务管理

12.1 systemd12.1.1 systemd 特性systemd:从 rhel 7 版本之后开始用 systemd 实现init进程,系统启动和服务器守护进程管理器,负责在系统启动或运行时,激活系统资源,服务器进程和其它进程Systemd新特性系统引导时实现服务并行启动按需启动守护进程自动化的服务依赖关系管理同时采用socket式与D-Bus总线式激活服务socket与服务程序分离向后兼容sysv init脚本使用systemctl 命令管理,systemctl命令固定不变,不可扩展,非由systemd启动的服务,systemctl无法与之通信和控制系统状态快照systemd核心概念:unit(单元)unit表示不同类型的systemd对象,通过配置文件进行标识和配置;文件中主要包含了系统服务、监听socket、保存的系统快照以及其它与init相关的信息Unit类型:#查看unit类型 [root@servera ~]# systemctl -t help Available unit types: service socket target device mount automount swap timer path slice scopeservice unit: 文件扩展名为.service, 用于定义系统服务Socket unit: .socket, 定义进程间通信用的socket文件,也可在系统启动时,延迟启动服务,实现按需启动Target unit: 文件扩展名为.target,用于模拟实现运行级别 init 0-6Device unit: .device, 用于定义内核识别的设备Mount unit: .mount, 定义文件系统挂载点Snapshot unit: .snapshot, 管理系统快照Swap unit: .swap, 用于标识swap设备Automount unit: .automount,文件系统的自动挂载点Path unit: .path,用于定义文件系统中的一个文件或目录使用,常用于当文件系统变化时,延迟激活服务,如:spool 目录unit的配置文件/usr/lib/systemd/system:每个服务最主要的启动脚本设置,类似于之前的/etc/init.d/ /run/systemd/system:系统执行过程中所产生的服务脚本,比上面目录优先运行 /etc/systemd/system:管理员建立的执行脚本,类似于/etc/rcN.d/Sxx的功能,比上面目录优先运行12.2 systemctl管理工具12.2.1 systemctl管理系统服务service unit命令:systemctl COMMAND name.service #启动:相当于service name start systemctl start name.service #停止:相当于service name stop systemctl stop name.service #重启:相当于service name restart systemctl restart name.service #查看状态:相当于service name status systemctl status name.service #禁止自动和手动启动: systemctl mask name.service #取消禁止 systemctl unmask name.service #查看某服务当前激活与否的状态: systemctl is-active name.service #查看所有已经激活的服务: systemctl list-units --type|-t service #查看所有服务: systemctl list-units --type service --all|-a #设定某服务开机自启,相当于chkconfig name on systemctl enable name.service #设定某服务开机禁止启动:相当于chkconfig name off systemctl disable name.service #查看所有服务的开机自启状态,相当于chkconfig --list systemctl list-unit-files --type service #用来列出该服务在哪些运行级别下启用和禁用:chkconfig –list name ls /etc/systemd/system/*.wants/name.service #查看服务是否开机自启: systemctl is-enabled name.service #列出失败的服务 systemctl --failed --type=service #开机并立即启动或停止 systemctl enable --now httpd systemctl disable --now httpd #查看服务的依赖关系: systemctl list-dependencies name.service #杀掉进程: systemctl kill unitname 服务状态#显示状态 systemctl list-unit-files --type service --allloaded Unit配置文件已处理active(running) 一次或多次持续处理的运行active(exited) 成功完成一次性的配置active(waiting) 运行中,等待一个事件inactive 不运行enabled 开机启动disabled 开机不启动static 开机不启动,但可被另一个启用的服务激活indirect 重定向到别处范例:systemctl 命令示例#显示所有单元状态 systemctl 或 systemctl list-units #只显示服务单元的状态 systemctl --type=service #显示sshd服务单元 systemctl –l status sshd.service #验证sshd服务当前是否活动 systemctl is-active sshd #启动,停止和重启sshd服务 systemctl start sshd.service systemctl stop sshd.service systemctl restart sshd.service #重新加载配置 systemctl reload sshd.service #列出活动状态的所有服务单元 systemctl list-units --type=service #列出所有服务单元 systemctl list-units --type=service --all #查看服务单元的启用和禁用状态 systemctl list-unit-files --type=service #列出依赖的单元 systemctl list-dependencies sshd #验证sshd服务是否开机启动 systemctl is-enabled sshd #禁用network,使之不能自动启动,但手动可以 systemctl disable network #启用network systemctl enable network #禁用network,使之不能手动或自动启动 systemctl mask network #启用network systemctl unmask network 12.2.2 service unit文件格式/etc/systemd/system:系统管理员和用户使用/usr/lib/systemd/system:发行版打包者使用帮助参考:systemd.directives(7),systemd.unit(5),systemd.service(5), systemd.socket(5),systemd.target(5),systemd.exec(5)unit 格式说明:以 “#” 开头的行后面的内容会被认为是注释相关布尔值,1、yes、on、true 都是开启,0、no、off、false 都是关闭时间单位默认是秒,所以要用毫秒(ms)分钟(m)等须显式说明service unit file文件通常由三部分组成:[Unit]:定义与Unit类型无关的通用选项;用于提供unit的描述信息、unit行为及依赖关系等[Service]:与特定类型相关的专用选项;此处为Service类型[Install]:定义由“systemctl enable”以及"systemctl disable“命令在实现服务启用或禁用时用到的一些选项Unit段的常用选项:Description:描述信息After:定义unit的启动次序,表示当前unit应该晚于哪些unit启动,其功能与Before相反Requires:依赖到的其它units,强依赖,被依赖的units无法激活时,当前unit也无法激活Wants:依赖到的其它units,弱依赖Conflicts:定义units间的冲突关系Service段的常用选项:Type:定义影响ExecStart及相关参数的功能的unit进程启动类型    。 simple:默认值,这个daemon主要由ExecStart接的指令串来启动,启动后常驻于内存中     。forking:由ExecStart启动的程序透过spawns延伸出其他子程序来作为此daemon的主要服务。原          生父程序在启动结束后就会终止        。 oneshot:与simple类似,不过这个程序在工作完毕后就结束了,不会常驻在内存中    。  dbus:与simple类似,但这个daemon必须要在取得一个D-Bus的名称后,才会继续运作.因         此通常也要同时设定BusNname= 才行    。   notify:在启动完成后会发送一个通知消息。还需要配合 NotifyAccess 来让 Systemd 接收消         息      。idle:与simple类似,要执行这个daemon必须要所有的工作都顺利执行完毕后才会执行。这          类的daemon通常是开机到最后才执行即可的服务EnvironmentFile:环境配置文件ExecStart:指明启动unit要运行命令或脚本的绝对路径ExecStartPre: ExecStart前运行ExecStartPost: ExecStart后运行ExecStop:指明停止unit要运行的命令或脚本Restart:当设定Restart=1 时,则当次daemon服务意外终止后,会再次自动启动此服务PrivateTmp:设定为yes时,会在生成/tmp/systemd-private-UUID-NAME.service-XXXXX/tmp/目录Install段的常用选项:Alias:别名,可使用systemctl command Alias.serviceRequiredBy:被哪些units所依赖,强依赖WantedBy:被哪些units所依赖,弱依赖Also:安装本服务的时候还要安装别的相关服务注意:对于新创建的unit文件,或者修改了的unit文件,要通知systemd重载此配置文件,而后可以选择重启systemctl daemon-reload12.2.3 systemctl管理运行级别target units:相当于Rhel 6之前的runlevel ,unit配置文件:.targetls /usr/lib/systemd/system/*.target systemctl list-unit-files --type target --all和运行级别对应关系init0 ==> runlevel0.target, poweroff.target 1 ==> runlevel1.target, rescue.target 2 ==> runlevel2.target, multi-user.target 3 ==> runlevel3.target, multi-user.target 4 ==> runlevel4.target, multi-user.target 5 ==> runlevel5.target, graphical.target 6 ==> runlevel6.target, reboot.target查看依赖性:systemctl list-dependencies graphical.target级别切换:相当于 init Nsystemctl isolate name.target进入默认targetsystemctl default范例:#切换至字符模式,相当于init 3 systemctl isolate multi-user.target
0
0
0
浏览量2002
秋月无边

二、Linux系统安装

2.1 Linux系统安装方式目前安装操作系统方式有2 种:真机安装、虚拟机安装。真机安装:使用真实的电脑进行安装,像安装windows 操作系统一样,真机安装的结果就是替换掉当前的windows 操作系统;(缺点:对系统进行格式化,重新安装)虚拟机安装:通过一些特定的手段,来进行模拟安装,并不会影响当前计算机的真实操作系统;如果是学习或者测试使用,强烈建议使用虚拟机安装方式。2.2 虚拟机概念什么是虚拟机?虚拟机,有些时候想模拟出一个真实的电脑环境,碍于使用真机安装代价太大,因此而诞生的一款可以模拟操作系统运行的软件。虚拟机目前有2 个比较有名的产品:vmware 出品的vmware workstation、oracle 出品的virtual Box。2.3 系统环境需求建议(宿主机)cup:Intel I5 三代以上(台式机可以放宽到I3)/ AMD R3以上内存:8GB(最低要求),推荐16GB硬盘:不作要求,推荐使用SSD作为系统盘(虚拟机)系统:windows 7/8/10 Mac 0S虚拟化底层:VMWare Worktation Pro 15.5以上2.4 RHEL8的安装和初始化配置2.4.1 如何安装RHEL 8安装前准备在VMWare Workstation Pro中创建虚拟机先决条件: 自己的物理机的CPU虚拟化功能要开启Intel的cpu:Virtualization Technology (VT-x)AMD的cpu: SVM Mode#通常情况下,默认CPU虚拟化功能没有开启虚拟机硬件要求:CPU:1 CPU , 2Cores(开启虚拟化)内存:2GB硬盘:100GB(20GB也可以)网络:NAT或仅主机模式(初学建议使用NAT)安装RHEL 8设置磁盘空间分配策略配置网络1.先是默认DHCP,因此我们不动它,直接Done设定时区指定安装包组0基础学习,可以安装图形去了解一下,但还是强烈建议使用最小化系统进行操作。可安装一些工具包。设置root密码以及创建普通用户(可以不建)安装完成允许协议登陆界面2.4.2 强调:CentOS和RHEL的区别a. RHEL:Red Hat Enterprise Linux(企业级的Linux系统)b. CentOS:Community Enterprise Operating System(也是红帽的产品,社区版本)c. 两者区别(1)企业版本RHEL:如果你购买了订阅,可以得到技术支持!但是CentOS没有此服务;400(2)CentOS作为一个社区版本,有些新的特性(不稳定)也是在社区版本优先进行发布,但在RHEL中,它不包含这些。(3)关于漏洞(BUG)修复RHEL的企业级用户:400电话,也是最先响应的;BUG一定会在红帽社区中进行公布,一般会较长一段时间后,BUG的修复才会被公布出来。(4)关于命令及操作:两者在同期的版本的情况下相同。(5)支持周期:RHEL为最近的3个大版本(现在是RHEL6/7/8),CentOS通常只有18个月。
0
0
0
浏览量132
秋月无边

使用Ansible常用文件模块,我的工作效率上来了,业余生活也丰富了

1. 描述文件模块Files模块库包含的模块允许用户完成与Linux文件管理相关的大多数任务,如创建、复制、编辑和修改文件的权限和其他属性。下表提供了常用文件管理模块的列表:常用的文件模块(已介绍的可参照笔记此前的模块参数说明)2. 使用file模块确保受管主机上存在文件使用file模块处理受管主机上的文件。其工作方式与touch命令类似,如果不存在则创建一个空文件,如果存在,则更新其修改时间。# cat playbook.yml --- - hosts: all gather_facts: no tasks: - name: look the file is exit file: path: /root/file mode: 0755 state: touch3. 在受管主机上删除文件从受管主机中删除文件的基本示例是使用file模块和state: absent参数# cat playbook.yml --- - hosts: all gather_facts: no tasks: - name: look the file is exit file: path: /root/file state: absent4. 在受管主机上复制和编辑文件使用fetch模块将受管主机上的文件索取到控制节点上进行检索功能:从远程节点获取文件(只能是文件)到本地目录。默认会以主机清单中的主机名为目录存放获取到的文件# cat playbook.yml --- - hosts: all gather_facts: no tasks: - name: test fetch: src: /root/file dest: files[root@servera ~]# ansible-playbook -i hosts playbook.yml PLAY [all] ***************************************************************************** TASK [test] **************************************************************************** changed: [servera] PLAY RECAP ***************************************************************************** servera : ok=1 changed=1 unreachable=0 failed=0 [root@servera ~]# ll files/servera/root/file # fetch模块会自动生成以受管主机域名的目录 -rw-r--r--. 1 root root 4 Sep 9 08:49 files/servera/root/file5. 使用lineinfile模块,确保文件中主机单个文件中存在特定的单行文本(扩展来讲)功能:替换一个文件中特定的行,或者使用一个反引用的正则表达式替换一个现有的行。常用参数**path:**必须参数,指定要操作的文件。line : 使用此参数指定文本内容。**regexp:**使用正则表达式匹配对应的行,当替换文本时,如果有多行文本都能被匹配,则只有最后面被匹配到的那行文本才会被替换,当删除文本时,如果有多行文本都能被匹配,这么这些行都会被删除。state: 当想要删除对应的文本时,需要将state参数的值设置为absent,absent为缺席之意,表示删除,state的默认值为present。**backrefs :**默认情况下,当根据正则替换文本时,即使regexp参数中的正则存在分组,在line参数中也不能对正则中的分组进行引用,除非将backrefs参数的值设置为yes。backrefs=yes表示开启后向引用,这样,line参数中就能对regexp参数中的分组进行后向引用了,这样说不太容易明白,可以参考后面的示例命令理解。backrefs=yes除了能够开启后向引用功能,还有另一个作用,默认情况下,当使用正则表达式替换对应行时,如果正则没有匹配到任何的行,那么line对应的内容会被插入到文本的末尾,不过,如果使用了backrefs=yes,情况就不一样了,当使用正则表达式替换对应行时,同时设置了backrefs=yes,那么当正则没有匹配到任何的行时,则不会对文件进行任何操作,相当于保持原文件不变。(为no时,如果没有匹配,则添加一行line。如果匹配了,则把匹配内容替被换为line内容。​ 为yes时,如果没有匹配,则文件保持不变。如果匹配了,把匹配内容替被换为line内容。)**insertafter : 配合state=present。**借助insertafter参数可以将文本插入到“指定的行”之后,insertafter参数的值可以设置为EOF或者正则表达式,EOF为End Of File之意,表示插入到文档的末尾,默认情况下insertafter的值为EOF,如果将insertafter的值设置为正则表达式,表示将文本插入到匹配到正则的行之后,如果正则没有匹配到任何行,则插入到文件末尾,当使用backrefs参数时,此参数会被忽略。**insertbefore :配合state=present。**借助insertbefore参数可以将文本插入到“指定的行”之前,insertbefore参数的值可以设置为BOF或者正则表达式,BOF为Begin Of File之意,表示插入到文档的开头,如果将insertbefore的值设置为正则表达式,表示将文本插入到匹配到正则的行之前,如果正则没有匹配到任何行,则插入到文件末尾,当使用backrefs参数时,此参数会被忽略。**backup :**是否在修改文件之前对文件进行备份。**create :**当要操作的文件并不存在时,是否创建对应的文件。**valiate:**在保存sudoers文件前,验证语法,如果有错,执行时,会报出来,重新编辑playbook1.正则匹配,更改某个关键参数值 - name: seline modify enforcing lineinfile: dest: /etc/selinux/config regexp: '^SELINUX=' line: 'SELINUX=enforcing'2.在匹配的内容前或后增加一行# cat http.conf #Listen 12.34.56.78:80 #Listen 80 #Portinsertbefore匹配内容在前面添加 - name: httpd.conf modify 8080 lineinfile: dest: /opt/playbook/test/http.conf regexp: '^Listen' insertbefore: '^#Port' line: 'Listen 8080'# cat http.conf #Listen 12.34.56.78:80 #Listen 80 Listen 8080 #Portinsertafter匹配内容在后面添加 - name: httpd.conf modify 8080 lineinfile: dest: /opt/playbook/test/http.conf regexp: '^Listen' insertafter: '^#Port' line: 'Listen 8080'# cat http.conf #Listen 12.34.56.78:80 #Listen 80 #Port Listen 80803.修改文件内容和权限# cat hosts 127.0.0.1 localhost.localdomain localhost ::1 localhost6.localdomain6 localhost6 192.168.1.2 foo.lab.net foo # ls -l hosts -rwxrwxr-x 1 root test 111 Sep 9 18:07 hosts# 执行剧本: - name: modify hosts lineinfile: dest: /opt/playbook/test/hosts regexp: '^127\.0\.0\.1' line: '127.0.0.1 localhosts' owner: root group: root mode: 0644# cat hosts 127.0.0.1 localhosts 192.168.1.2 foo.lab.net foo # ls -l hosts -rwxrwxr-x 1 root root 111 Sep 9 18:10 hosts4.删除某一行内容# cat hosts 127.0.0.1 localhosts 192.168.1.2 foo.lab.net foo# absent剧本 - name: delete 192.168.1.1 lineinfile: dest: /opt/playbook/test/hosts state: absent regexp: '^192\.'[root@master test]# cat hosts 127.0.0.1 localhosts5.文件存在就添加一行# cat hosts 127.0.0.1 localhosts# 剧本 - name: add a line lineinfile: dest: /opt/playbook/test/hosts line: '192.168.1.2 foo.lab.net foo'6.使用valiate参数在保存sudoers文件前,验证语法,如果有错,执行时,会报出来,重新编辑playbook - name: test validate lineinfile: dest: /etc/sudoers state: present regexp: '^%ADMIN ALL=' line: '%ADMIN ALL=(ALL)' validate: '/usr/sbin/visudo -cf %s'7. 使用backrefs参数 - name: set the zabbix UnsafeUserParameters up lineinfile: path: /etc/zabbix/zabbix_agentd.conf regexp: '^# UnsafeUserParameters=0' line: 'UnsafeUserParameters=1' backrefs: yesbackrefs默认为no,如果没有匹配,则添加一行line,但这样操作会造成配置文件的问题,所以设置成yes,匹配才进行替换内容,没匹配就不改变。6. 使用blockinfile模块将所列出的文件块添加到受管主机现有文件中# cat playbook.yaml --- - hosts: all gather_facts: no tasks: - name: test blockinfile: path: /root/file block: | this is one line this is two line tjis is three line state: present# cat file This is test file # BEGIN ANSIBLE MANAGED BLOCK this is one line this is two line tjis is three line # END ANSIBLE MANAGED BLOCK注意:state:{present、absent}:present表示在现有文件中,如果存在,则报OK;如果不存在,则添加该文件块;absent表示如果存在该文件块,则删除该文件块;如果不存在,则报OK 。7. 使用sefcontext模块更新selinux策略sefcontext模块更新SELinux策略中目标的默认上下文,但不更改现有文件的上下文# 在7中,需要明确控制节点和受管主机上安装这两个模块:libselinux-python和policycoreutils-python# ls -Z /var/www/html/file unconfined_u:object_r:admin_home_t:s0 /var/www/html/file# cat playbook.yaml --- - hosts: all gather_facts: no tasks: - name: test sefcontext: path: /var/www/html/file setype: httpd_sys_content_t state: present# ansible-playbook playbook.yaml PLAY [all] ****************************************************************************** TASK [test] ***************************************************************************** changed: [client.example.com] PLAY RECAP ****************************************************************************** client.example.com : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 # ll -Z file -rw-r--r--. 1 root root unconfined_u:object_r:httpd_sys_content_t:s0 0 Sep 8 17:38 file8. 检索受管主机上的文件状态stat模块检索文件的事实,类似于Linux中的stat命令;参数提供检索文件属性、确定文件检验和等功能。stat模块返回一个包含文件状态数据的值的散列字典,允许用户使用单独的变量引用各条信息。演示实例:注册stat模块的结果,然后显示它检查的文件的MD5检验和# cat playbook.yaml --- - hosts: all gather_facts: no tasks: - name: test stat: path: /root/file checksum_algorithm: md5 register: result - debug: msg: "{{ result['stat']['checksum'] }}" # msg: "{{ result.stat.checksum }}"[root@servera ~]# ansible-playbook -i hosts playbook.yml PLAY [all] ****************************************************************************** TASK [test] ***************************************************************************** ok: [servera] TASK [debug] **************************************************************************** ok: [servera] => { "msg": "ba1f2511fc30423bdbb183fe33f3dd0f" } PLAY RECAP ****************************************************************************** servera : ok=2 changed=0 unreachable=0 failed=09. 同步控制节点和受管主机之间的文件synchronize模块是一个围绕rsync工具的打包程序,它简化了playbook中的常见文件管理任务rsync工具必须同时安装在本机和远程主机上默认情况下,在使用synchronize模块时,“本地主机”是同步任务所源自的主机(通常是控制节点),而“目标主机”是synchronize连接到的主机演示实例:明确控制节点和受管主机上安装rsync工具:yum install -y rsync# cat playbook.yaml --- - hosts: all gather_facts: no tasks: - name: test synchronize: src: abc/test dest: /root/file[root@servera ~]# ansible-playbook -i hosts playbook.yml PLAY [all] ****************************************************************************** TASK [test] ***************************************************************************** changed: [servera] PLAY RECAP ****************************************************************************** servera : ok=1 changed=1 unreachable=0 failed=0 [root@servera ~]# ansible -i hosts all -a 'cat /root/file' servera | CHANGED | rc=0 >> test rysnc总结介绍常用文件模块的使用:file、lineinfile、blockinfile、sefcontext、stat、synchronize。
0
0
0
浏览量2003
秋月无边

集群架构出现问题,差点损失一个亿,原来是时间同步服务没做好

📜14.1 时间同步服务多主机协作工作时,各个主机的时间同步很重要,时间不一致会造成很多重要应用的故障,如:加密协议,日志,集群等, 利用NTP(Network Time Protocol) 协议使网络中的各个计算机时间达到同步。目前NTP协议属于运维基础架构中必备的基本服务之一时间同步软件实现:ntpchronyntp:将系统时钟和世界协调时UTC同步,精度在局域网内可达0.1ms,在互联网上绝大多数的地方精度可以达到1-50mschrony:实现NTP协议的自由软件。可使系统时钟与NTP服务器,参考时钟(例如GPS接收器)以及使用手表和键盘的手动输入进行同步。还可以作为NTPv4(RFC 5905)服务器和对等体运行,为网络中的计算机提供时间服务。设计用于在各种条件下良好运行,包括间歇性和高度拥挤的网络连接,温度变化(计算机时钟对温度敏感),以及不能连续运行或在虚拟机上运行的系统。通过Internet同步的两台机器之间的典型精度在几毫秒之内,在LAN上,精度通常为几十微秒。利用硬件时间戳或硬件参考时钟,可实现亚微秒的精度。📜14.2 chrony📑14.2.1 chrony介绍chrony 的优势:更快的同步只需要数分钟而非数小时时间,从而最大程度减少了时间和频率误差,对于并非全天24 小时运行的虚拟计算机而言非常有用能够更好地响应时钟频率的快速变化,对于具备不稳定时钟的虚拟机或导致时钟频率发生变化的节能技术而言非常有用在初始同步后,它不会停止时钟,以防对需要系统时间保持单调的应用程序造成影响在应对临时非对称延迟时(例如,在大规模下载造成链接饱和时)提供了更好的稳定性无需对服务器进行定期轮询,因此具备间歇性网络连接的系统仍然可以快速同步时钟📑14.2.2 chrony 文件组成包:chrony两个主要程序:chronyd和chronycchronyd:后台运行的守护进程,用于调整内核中运行的系统时钟和时钟服务器同步。它确定计算机增减时间的比率,并对此进行补偿chronyc:命令行用户工具,用于监控性能并进行多样化的配置。它可以在chronyd实例控制的计算机上工作,也可在一台不同的远程计算机上工作📑14.2.3 配置文件chrony.confserver - 可用于时钟服务器,iburst 选项当服务器可达时,发送一个八个数据包而不是通常的一个数据 包。 包间隔通常为2秒,可加快初始同步速度 driftfile - 根据实际时间计算出计算机增减时间的比率,将它记录到一个文件中,会在重启后为系统时钟 作出补偿 rtcsync - 启用内核模式,系统时间每11分钟会拷贝到实时时钟(RTC) allow / deny - 指定一台主机、子网,或者网络以允许或拒绝访问本服务器 cmdallow / cmddeny - 可以指定哪台主机可以通过chronyd使用控制命令 bindcmdaddress - 允许chronyd监听哪个接口来接收由chronyc执行的命令 makestep - 通常chronyd将根据需求通过减慢或加速时钟,使得系统逐步纠正所有时间偏差。在某些特定 情况下,系统时钟可能会漂移过快,导致该调整过程消耗很长的时间来纠正系统时钟。该指令强制chronyd在 调整期大于某个阀值时调整系统时钟 local stratum 10 - 即使server指令中时间服务器不可用,也允许将本地时间作为标准时间授时给其 它客户端📑14.2.4 ntp客户端命令chronyc 可以运行在交互式和非交互式两种方式,支持以下子命令help 命令可以查看更多chronyc的交互命令 accheck 检查是否对特定主机可访问当前服务器 activity 显示有多少NTP源在线/离线 sources [-v] 显示当前时间源的同步信息 sourcestats [-v]显示当前时间源的同步统计信息 add server 手动添加一台新的NTP服务器 clients 报告已访问本服务器的客户端列表 delete 手动移除NTP服务器或对等服务器 settime 手动设置守护进程时间 tracking 显示系统时间信息📑14.2.5 公共NTP服务pool.ntp.org:项目是一个提供可靠易用的NTP服务的虚拟集群cn.pool.ntp.org,0-3.cn.pool.ntp.org阿里云公共NTP服务器Unix/linux类:ntp.aliyun.com,ntp1-7.aliyun.comwindows类: time.pool.aliyun.com腾讯公共NTPtime1-5.cloud.tencent.com大学ntp服务s1a.time.edu.cn 北京邮电大学s1b.time.edu.cn 清华大学s1c.time.edu.cn 北京大学国家授时中心服务器:cn.pool.ntp.org📜14.3 时间工具timedatectl 时间和时区管理#查看日期时间、时区及NTP状态:timedatectl #查看时区列表: timedatectl list-timezones #修改时区: timedatectl set-timezone Asia/Shanghai #修改日期时间: timedatectl set-time "2017-01-23 10:30:00" #开启NTP: timedatectl set-ntp true/false
0
0
0
浏览量2002
秋月无边

不懂日志管理的小金被辞退了,懂事的你快来学

📜15.1 系统日志管理📑15.1.1 系统日志介绍将系统和应用发生的事件记录至日志中,以助于排错和分析使用:日志记录的内容包括:历史事件:时间,地点,人物,事件日志级别:事件的关键性程度,Log level📑15.1.2 系统日志的来源在RHRL系统中:日志是通过syslog协议来进行记录的。其中记录的服务有两个:systemd-journald.service 把服务有关,开机引导有关的事件,以二进制文件的形式保存在内存,如果系统被重启以后就会被清空rsyslog.service主要工作,就是把systemd-journald.service的二进制内容转换成文本文档。保存在/var/log的各个文件当中📜15.2 rsyslog系统日志服务rsyslog是RHEL 6 以后版本的系统管理服务.它提供了高性能,出色的安全性和模块化设计。 尽管rsyslog最初是常规的syslogd,但已发展成为一种瑞士军刀式的记录工具,能够接受来自各种来源的输入,并将其转换,然后输出到不同的目的地。当应用有限的处理时,RSYSLOG每秒可以将超过一百万的消息传递到本地目的地。 即使在远程的目的地和更精细的处理中,性能通常也被认为是“惊人的”。官方网站:https://www.rsyslog.com/rsyslog 特性:多线程UDP, TCP, SSL, TLS, RELPMySQL, PGSQL, Oracle实现日志存储强大的过滤器,可实现过滤记录日志信息中任意部分自定义输出格式适用于企业级中继链📑15.2.1 ELKELK:由Elasticsearch, Logstash, Kibana三个软件组成非关系型分布式数据库基于apache软件基金会jakarta项目组的项目luceneElasticsearch是个开源分布式搜索引擎,可以处理大规模日志数据,比如:Nginx、Tomcat、系统日志等功能Logstash对日志进行收集、分析,过滤,并将其存储供以后使用Kibana 可以提供的日志分析友好的 Web 界面📑15.2.2 rsyslog 管理15.2.2.1 系统日志术语facility:设施,从功能或程序上对日志进行归类auth, authpriv, cron, daemon,ftp,kern, lpr, mail, news, security(auth), user, uucp, syslog #自定义的分类 local0-local7Priority 优先级别,从低到高排序debug, info, notice, warn(warning), err(error), crit(critical), alert, emerg(panic)   参看帮助: man 3 syslog,man logger    详情介绍proc/sys/kernel/printk文件定义了4个数字, 查看日志级别:cat /proc/sys/kernel/printk 4 4 1 7①控制台日志级别:优先级高于该值的消息将被打印至控制台。②缺省的消息日志级别:将用该值来打印没有优先级的消息。③最低的控制台日志级别:控制台日志级别可能被设置的最小值。④缺省的控制台:控制台日志级别的缺省值。15.2.2.2 rsyslog配置文件**/etc/rsyslog.conf配置文件格式:**由三部分组成MODULES:相关模块配置GLOBAL DIRECTIVES:全局配置RULES:日志记录相关的规则配置RULES配置格式:facility.priority; facility.priority… targetfacility格式:* #所有的facility facility1,facility2,facility3,... #指定的facility列表priority格式:*: 所有级别 none:没有级别,即不记录 PRIORITY:指定级别(含)以上的所有级别 =PRIORITY:仅记录指定级别的日志信息target格式:文件路径:通常在/var/log/,文件路径前的-表示异步写入 用户:将日志事件通知给指定的用户,* 表示登录的所有用户 日志服务器:@host,把日志送往至指定的远程UDP日志服务器 @@host 将日志发送到远程TCP日志服务器 管道: | COMMAND,转发给其它命令处理通常的日志文件的格式:日志文件有很多,如: /var/log/messages,cron,secure等,基本格式都是类似的。格式如下事件产生的日期时间 主机 进程(pid):事件内容范例:日志文件格式[root@servera log]# tail messages -n 5 Apr 7 10:56:14 servera systemd-tmpfiles[2185]: [/usr/lib/tmpfiles.d/subscription-manager.conf:1] Line references path below legacy directory /var/run/, updating /var/run/rhsm → /run/rhsm; please update the tmpfiles.d/ drop-in file accordingly. Apr 7 10:56:14 servera systemd[1]: Started Cleanup of Temporary Directories. Apr 7 11:09:02 servera rhsmd[2324]: In order for Subscription Manager to provide your system with updates, your system must be registered with the Customer Portal. Please enter your Red Hat login to ensure your system is up-to-date. Apr 7 11:10:03 servera systemd[1]: Started Session 3 of user root. Apr 7 11:10:03 servera systemd-logind[1082]: New session 3 of user root. [root@servera log]# tail secure -n 5 Apr 7 10:41:34 servera systemd[1993]: pam_unix(systemd-user:session): session opened for user root by (uid=0) Apr 7 10:41:34 servera login[1691]: pam_unix(login:session): session opened for user root by LOGIN(uid=0) Apr 7 10:41:34 servera login[1691]: ROOT LOGIN ON tty1 Apr 7 11:10:03 servera sshd[2337]: Accepted password for root from 192.168.137.2 port 60051 ssh2 Apr 7 11:10:03 servera sshd[2337]: pam_unix(sshd:session): session opened for user root by (uid=0)范例:将ssh服务的日志记录至自定义的local的日志设备#修改sshd服务的配置 Vim /etc/ssh/sshd_config SyslogFacility local2 Service sshd reload #修改rsyslog的配置 Vim /etc/rsyslog.conf Local2.* /var/log/sshd.log Systemctl restart rsyslog #测试 Ssh登录后,查看/var/log/sshd.log有记录 #logger测试 logger -p local2.info "hello sshd" tail /var/log/sshd.log有记录15.2.2.3 启用网络日志服务启用网络日志服务功能,可以将多个远程主机的日志,发送到集中的日志服务器,方便统一管理。范例:RHEL 8 启用网络日志功能[root@servera ~]#vim /etc/rsyslog.conf ## MODULES #### ...省略... # Provides UDP syslog reception # for parameters see http://www.rsyslog.com/doc/imudp.html module(load="imudp") # needs to be done just once input(type="imudp" port="514") # Provides TCP syslog reception # for parameters see http://www.rsyslog.com/doc/imtcp.html module(load="imtcp") # needs to be done just once input(type="imtcp" port="514")15.2.2.4 常见日志文件/var/log/secure:系统安全日志,文本格式,应周期性分析 /var/log/btmp:当前系统上,用户的失败尝试登录相关的日志信息,二进制格式,lastb命令进行 查看 /var/log/wtmp:当前系统上,用户正常登录系统的相关日志信息,二进制格式,last命令可以查 看 /var/log/lastlog:每一个用户最近一次的登录信息,二进制格式,lastlog命令可以查看 /var/log/boot.log 系统服务启动的相关信息,文本格式 /var/log/messages :系统中大部分的信息 /var/log/anaconda : anaconda的日志(安装系统)📜15.3 日志管理工具 journalctlRHEL 7 以后版,利用Systemd 统一管理所有 Unit 的启动日志。带来的好处就是,可以只用journalctl一个命令,查看所有日志(内核日志和应用日志)。日志的配置文件:/etc/systemd/journald.confjournalctl命令格式journalctl [OPTIONS...] [MATCHES...]选项说明:--no-full, --full, -l 如果字段内容超长则以省略号(...)截断以适应列宽。 默认显示完整的字段内容(超长的部分换行显示或者被分页工具截断)。 老旧的 -l/--full 选项 仅用于撤销已有的 --no-full 选项,除此之外没有其他用处。 -a, --all 完整显示所有字段内容, 即使其中包含不可打印字符或者字段内容超长。 -f, --follow 只显示最新的日志项,并且不断显示新生成的日志项。 此选项隐含了 -n 选项。 -e, --pager-end 在分页工具内立即跳转到日志的尾部。 此选项隐含了 -n1000 以确保分页工具不必缓存太多的日志行。 不过这个隐含的行数可以被明确设置的 -n 选项覆盖。 注意,此选项仅可用于 less(1) 分页器。 -n, --lines= 限制显示最新的日志行数。 --pager-end 与 --follow 隐含了此选项。 此选项的参数:若为正整数则表示最大行数; 若为 "all" 则表示不限制行数; 若不设参数则表示默认值10行。 --no-tail 显示所有日志行, 也就是用于撤销已有的 --lines= 选项(即使与 -f 连用)。 -r, --reverse 反转日志行的输出顺序, 也就是最先显示最新的日志。 -o, --output= 控制日志的输出格式。 可以使用如下选项: short 这是默认值, 其输出格式与传统的 syslog[1] 文件的格式相似, 每条日志一行。 short-iso 与 short 类似,只是将时间戳字段以 ISO 8601 格式显示。 short-precise 与 short 类似,只是将时间戳字段的秒数精确到微秒级别。 short-monotonic 与 short 类似,只是将时间戳字段的零值从内核启动时开始计算。 short-unix 与 short 类似,只是将时间戳字段显示为从"UNIX时间原点"(1970-1-1 00:00:00 UTC)以来的秒数。 精确到微秒级别。 verbose 以结构化的格式显示每条日志的所有字段。 export 将日志序列化为二进制字节流(大部分依然是文本) 以适用于备份与网络传输(详见 Journal Export Format[2] 文档)。 json 将日志项按照JSON数据结构格式化, 每条日志一行(详见 Journal JSON Format[3] 文档)。 json-pretty 将日志项按照JSON数据结构格式化, 但是每个字段一行, 以便于人类阅读。 json-sse 将日志项按照JSON数据结构格式化,每条日志一行,但是用大括号包围, 以适应 Server-Sent Events[4] 的要求。 cat 仅显示日志的实际内容, 而不显示与此日志相关的任何元数据(包括时间戳)。2 --utc 以世界统一时间(UTC)表示时间 --no-hostname 不显示来源于本机的日志消息的主机名字段。 此选项仅对 short 系列输出格式(见上文)有效。 -x, --catalog 在日志的输出中增加一些解释性的短文本, 以帮助进一步说明日志的含义、问题的解决方案、支持论坛、 开发文档、以及其他任何内容。 并非所有日志都有这些额外的帮助文本, 详见 Message Catalog Developer Documentation[5] 文档。 注意,如果要将日志输出用于bug报告, 请不要使用此选项。 -q, --quiet 当以普通用户身份运行时, 不显示任何警告信息与提示信息。 例如:"-- Logs begin at ...", "-- Reboot --" -m, --merge 混合显示包括远程日志在内的所有可见日志。 -b [ID][±offset], --boot=[ID][±offset] 显示特定于某次启动的日志, 这相当于添加了一个 "_BOOT_ID=" 匹配条件。 如果参数为空(也就是 ID 与 ±offset 都未指定), 则表示仅显示本次启动的日志。 如果省略了 ID , 那么当 ±offset 是正数的时候, 将从日志头开始正向查找, 否则(也就是为负数或零)将从日志尾开始反响查找。 举例来说, "-b 1"表示按时间顺序排列最早的那次启动, "-b 2"则表示在时间上第二早的那次启动; "-b -0"表示最后一次启动, "-b -1"表示在时间上第二近的那次启动, 以此类推。 如果 ±offset 也省略了, 那么相当于"-b -0", 除非本次启动不是最后一次启动(例如用 --directory 指定了另外一台主机上的日志目录)。 如果指定了32字符的 ID , 那么表示以此 ID 所代表的那次启动为基准 计算偏移量(±offset), 计算方法同上。 换句话说, 省略 ID 表示以本次启动为基准 计算偏移量(±offset)。 --list-boots 列出每次启动的 序号(也就是相对于本次启动的偏移量)、32字符的ID、 第一条日志的时间戳、最后一条日志的时间戳。 -k, --dmesg 仅显示内核日志。隐含了 -b 选项以及 "_TRANSPORT=kernel" 匹配项。 -t, --identifier=SYSLOG_IDENTIFIER 仅显示 syslog[1] 识别符为 SYSLOG_IDENTIFIER 的日志项。 可以多次使用该选项以指定多个识别符。 -u,--unit=UNIT|PATTERN 仅显示属于特定单元的日志。 也就是单元名称正好等于 UNIT 或者符合 PATTERN 模式的单元。 这相当于添加了一个 "_SYSTEMD_UNIT=UNIT" 匹配项(对于 UNIT 来说), 或一组匹配项(对于 PATTERN 来说)。 可以多次使用此选项以添加多个并列的匹配条件(相当于用"OR"逻辑连接)。 --user-unit= 仅显示属于特定用户会话单元的日志。 相当于同时添加了 "_SYSTEMD_USER_UNIT=" 与 "_UID=" 两个匹配条件。 可以多次使用此选项以添加多个并列的匹配条件(相当于用"OR"逻辑连接)。 -p, --priority= 根据日志等级(包括等级范围)过滤输出结果。 日志等级数字与其名称之间的对应关系如下 (参见 syslog(3)): "emerg" (0), "alert" (1), "crit" (2), "err" (3), "warning" (4), "notice" (5), "info" (6), "debug" (7) 。 若设为一个单独的数字或日志等级名称, 则表示仅显示小于或等于此等级的日志 (也就是重要程度等于或高于此等级的日志)。 若使用 FROM..TO.. 设置一个范围, 则表示仅显示指定的等级范围内(含两端)的日志。 此选项相当于添加了 "PRIORITY=" 匹配条件。 -c, --cursor= 从指定的游标(cursor)开始显示日志。 [提示]每条日志都有一个"__CURSOR"字段,类似于该条日志的指纹。 --after-cursor= 从指定的游标(cursor)之后开始显示日志。 如果使用了 --show-cursor 选项, 则也会显示游标本身。 --show-cursor 在最后一条日志之后显示游标, 类似下面这样,以"--"开头: -- cursor: s=0639... 游标的具体格式是私有的(也就是没有公开的规范), 并且会变化。 -S, --since=, -U, --until= 显示晚于指定时间(--since=)的日志、显示早于指定时间(--until=)的日志。 参数的格式类似 "2012-10-30 18:17:16" 这样。 如果省略了"时:分:秒"部分, 则相当于设为 "00:00:00" 。 如果仅省略了"秒"的部分则相当于设为 ":00" 。 如果省略了"年-月-日"部分, 则相当于设为当前日期。 除了"年-月-日 时:分:秒"格式, 参数还可以进行如下设置: (1)设为 "yesterday", "today", "tomorrow" 以表示那一天的零点(00:00:00)。 (2)设为 "now" 以表示当前时间。 (3)可以在"年-月-日 时:分:秒"前加上 "-"(前移) 或 "+"(后移) 前缀以表示相对于当前时间的偏移。 关于时间与日期的详细规范, 参见systemd.time(7) -F, --field= 显示所有日志中某个字段的所有可能值。 [译者注]类似于SQL语句:"SELECT DISTINCT 某字段 FROM 全部日志" -N, --fields 输出所有日志字段的名称 --system, --user 仅显示系统服务与内核的日志(--system)、 仅显示当前用户的日志(--user)。 如果两个选项都未指定,则显示当前用户的所有可见日志。 -M, --machine= 显示来自于正在运行的、特定名称的本地容器的日志。 参数必须是一个本地容器的名称。 -D DIR, --directory=DIR 仅显示来自于特定目录中的日志, 而不是默认的运行时和系统日志目录中的日志。 --file=GLOB GLOB 是一个可以包含"?"与"*"的文件路径匹配模式。 表示仅显示来自与指定的 GLOB 模式匹配的文件中的日志, 而不是默认的运行时和系统日志目录中的日志。 可以多次使用此选项以指定多个匹配模式(多个模式之间用"OR"逻辑连接)。 --root=ROOT 在对日志进行操作时, 将 ROOT 视为系统的根目录。 例如 --update-catalog 将会创建 ROOT/var/lib/systemd/catalog/database --new-id128 此选项并不用于显示日志内容, 而是用于重新生成一个标识日志分类的 128-bit ID 。 此选项的目的在于 帮助开发者生成易于辨别的日志消息, 以方便调试。 --header 此选项并不用于显示日志内容, 而是用于显示日志文件内部的头信息(类似于元数据)。 --disk-usage 此选项并不用于显示日志内容, 而是用于显示所有日志文件(归档文件与活动文件)的磁盘占用总量。 --vacuum-size=, --vacuum-time=, --vacuum-files= 这些选项并不用于显示日志内容, 而是用于清理日志归档文件(并不清理活动的日志文件), 以释放磁盘空间。 --vacuum-size= 可用于限制归档文件的最大磁盘使用量 (可以使用 "K", "M", "G", "T" 后缀); --vacuum-time= 可用于清除指定时间之前的归档 (可以使用 "s", "m", "h", "days", "weeks", "months", "years" 后缀); --vacuum-files= 可用于限制日志归档文件的最大数量。 注意,--vacuum-size= 对 --disk-usage 的输出仅有间接效果, 因为 --disk-usage 输出的是归档日志与活动日志的总量。 同样,--vacuum-files= 也未必一定会减少日志文件的总数, 因为它同样仅作用于归档文件而不会删除活动的日志文件。 此三个选项可以同时使用,以同时从三个维度去限制归档文件。 若将某选项设为零,则表示取消此选项的限制。 --list-catalog [128-bit-ID...] 简要列出日志分类信息, 其中包括对分类信息的简要描述。 如果明确指定了分类ID(128-bit-ID), 那么仅显示指定的分类。 --dump-catalog [128-bit-ID...] 详细列出日志分类信息 (格式与 .catalog 文件相同)。 如果明确指定了分类ID(128-bit-ID), 那么仅显示指定的分类。 --update-catalog 更新日志分类索引二进制文件。 每当安装、删除、更新了分类文件,都需要执行一次此动作。 --setup-keys 此选项并不用于显示日志内容, 而是用于生成一个新的FSS(Forward Secure Sealing)密钥对。 此密钥对包含一个"sealing key"与一个"verification key"。 "sealing key"保存在本地日志目录中, 而"verification key"则必须保存在其他地方。 详见 journald.conf(5) 中的 Seal= 选项。 --force 与 --setup-keys 连用, 表示即使已经配置了FSS(Forward Secure Sealing)密钥对, 也要强制重新生成。 --interval= 与 --setup-keys 连用,指定"sealing key"的变化间隔。 较短的时间间隔会导致占用更多的CPU资源, 但是能够减少未检测的日志变化时间。 默认值是 15min --verify 检查日志文件的内在一致性。 如果日志文件在生成时开启了FSS特性, 并且使用 --verify-key= 指定了FSS的"verification key", 那么,同时还将验证日志文件的真实性。 --verify-key= 与 --verify 选项连用, 指定FSS的"verification key" --sync 要求日志守护进程将所有未写入磁盘的日志数据刷写到磁盘上, 并且一直阻塞到刷写操作实际完成之后才返回。 因此该命令可以保证当它返回的时候, 所有在调用此命令的时间点之前的日志, 已经全部安全的刷写到了磁盘中。 --flush 要求日志守护进程 将 /run/log/journal 中的日志数据 刷写到 /var/log/journal 中 (如果持久存储设备当前可用的话)。 此操作会一直阻塞到操作完成之后才会返回, 因此可以确保在该命令返回时, 数据转移确实已经完成。 注意,此命令仅执行一个单独的、一次性的转移动作, 若没有数据需要转移, 则此命令什么也不做, 并且也会返回一个表示操作已正确完成的返回值。 --rotate 要求日志守护进程滚动日志文件。 此命令会一直阻塞到滚动完成之后才会返回。 -h, --help 显示简短的帮助信息并退出。 --version 显示简短的版本信息并退出。 --no-pager 不将程序的输出内容管道(pipe)给分页程序范例:journalctl用法#查看所有日志(默认情况下 ,只保存本次启动的日志) journalctl #查看内核日志(不显示应用日志) journalctl -k #查看系统本次启动的日志 journalctl -b journalctl -b -0 #查看上一次启动的日志(需更改设置) journalctl -b -1 #查看指定时间的日志 journalctl --since="2017-10-30 18:10:30" journalctl --since "20 min ago" journalctl --since yesterday journalctl --since "2017-01-10" --until "2017-01-11 03:00" journalctl --since 09:00 --until "1 hour ago" #显示尾部的最新10行日志 journalctl -n #显示尾部指定行数的日志 journalctl -n 20 #实时滚动显示最新日志 journalctl -f #查看指定服务的日志 journalctl /usr/lib/systemd/systemd #查看指定进程的日志 journalctl _PID=1 #查看某个路径的脚本的日志 journalctl /usr/bin/bash #查看指定用户的日志 journalctl _UID=33 --since today #查看某个 Unit 的日志 journalctl -u nginx.service journalctl -u nginx.service --since today #实时滚动显示某个 Unit 的最新日志 journalctl -u nginx.service -f #合并显示多个 Unit 的日志 journalctl -u nginx.service -u php-fpm.service --since today #查看指定优先级(及其以上级别)的日志,共有8级 0: emerg 1: alert 2: crit 3: err 4: warning 5: notice 6: info 7: debug journalctl -p err -b #日志默认分页输出,--no-pager 改为正常的标准输出 journalctl --no-pager #日志管理journalctl #以 JSON 格式(单行)输出 journalctl -b -u nginx.service -o json #以 JSON 格式(多行)输出,可读性更好 journalctl -b -u nginx.serviceqq -o json-pretty #显示日志占据的硬盘空间 journalctl --disk-usage #指定日志文件占据的最大空间 journalctl --vacuum-size=1G #指定日志文件保存多久 journalctl --vacuum-time=1years📜15.4 logrotate日志转储📑15.4.1 logrotate 介绍logrotate 程序是一个日志文件管理工具。用来把旧的日志文件删除,并创建新的日志文件,称为日志转储或滚动。可以根据日志文件的大小,也可以根据其天数来转储,这个过程一般通过 cron 程序来执行📑15.4.2 logrotate 配置软件包:logrotate相关文件计划任务:/etc/cron.daily/logrotate程序文件:/usr/sbin/logrotate配置文件: /etc/logrotate.conf日志文件:/var/lib/logrotate/logrotate.status配置文件主要参数如下:范例:对指定日志手动执行日志转储#针对不同的日志创建转储配置文件 [root@centos8 ~]#cat /etc/logrotate.d/test1 /var/log/test1.log { daily rotate 5 compress delaycompress missingok size 1M notifempty create 644 root root postrotate echo `date +%F_%T` >> /data/test1.log endscript } [root@centos8 ~]#cat /etc/logrotate.d/test2 /var/log/test2.log { daily rotate 5 compress delaycompress missingok size 1M notifempty create 644 root root postrotate echo `date +%F_%T` >> /data/test2.log endscript } #针对一个测试日志,手动执行日志转储 [root@centos8 ~]#logrotate /etc/logrotate.d/test1 [root@centos8 ~]#ll /var/log/test* -rw-r--r-- 1 root root 0 Dec 14 16:38 /var/log/test1.log -rw-r--r-- 1 root root 2097152 Dec 14 16:35 /var/log/test1.log.1 -rw-r--r-- 1 root root 2097152 Dec 14 16:36 /var/log/test2.log #对所有日志进行手动转储 [root@centos8 ~]#logrotate /etc/logrotate.conf [root@centos8 ~]#ll /var/log/test* -rw-r--r-- 1 root root 0 Nov 12 14:00 /var/log/test1.log -rw-r--r-- 1 root root 2097152 Nov 12 13:59 /var/log/test1.log.1 -rw-r--r-- 1 root root 0 Nov 12 14:01 /var/log/test2.log -rw-r--r-- 1 root root 2097152 Nov 12 13:59 /var/log/test2.log-20191112 [root@centos8 ~]#ls /data test1.log test2.log [root@centos8 ~]#cat /data/test1.log
0
0
0
浏览量2003
秋月无边

运维经理:如果连CentOS网络配置都不会,就收包袱走人吧

📜17.1 基本网络配置将Linux主机接入到网络,需要配置网络相关设置一般包括如下内容:主机名IP/netmask路由:默认网关DNS服务器主DNS服务器次DNS服务器第三个DNS服务器📜17.2 RHEL6 之前版本网卡名称接口命名方式:RHEL 6以太网:eth[0,1,2,…]ppp:ppp[0,1,2,…]网络接口识别并命名相关的udev配置文件:/etc/udev/rules.d/70-persistent-net.rules查看网卡:dmesg |grep –i ethethtool -i eth0卸载网卡驱动:modprobe -r e1000rmmod e1000装载网卡驱动:modprobe e1000📜17.3 网络配置命令📑17.3.1 ip命令来自于iproute包17.3.1.1 配置Linux网络属性ip [ OPTIONS ] OBJECT { COMMAND | help }ip命令说明:OBJECT := { link | addr | route } ip link - network device configuration set dev IFACE,可设置属性:up and down:激活或禁用指定接口,相当于 ifup/ifdown show [dev IFACE] [up]::指定接口 ,up 仅显示处于激活状态的接口ip地址管理ip addr { add | del } IFADDR dev STRING [label LABEL] [scope {global|link|host}] [broadcast ADDRESS] [label LABEL]:添加地址时指明网卡别名 [scope {global|link|host}]:指明作用域,global: 全局可用.link: 仅链接可用,host: 本机可 用 [broadcast ADDRESS]:指明广播地址 ip address show ip addr flush范例:#禁用网卡 ip link set eth1 down #网卡改名 ip link set eth1 name haonet #启用网卡 ip link set haonet up #网卡别名 ip addr add 172.16.100.100/16 dev eth0 label eth0:0 ip addr del 172.16.100.100/16 dev eth0 label eth0:0 #清除网络地址 ip addr flush dev eth0📑17.3.2 网络配置文件17.3.2.1 网络基本配置文件IP、MASK、GW、DNS相关的配置文件:/etc/sysconfig/network-scripts/ifcfg-IFACE说明参考:/usr/share/doc/initscripts/sysconfig.txt常用配置17.3.2.2 本地主机名数据库和IP地址的映射优先于使用DNS前检查getent hosts 查看/etc/hosts 内容/etc/hosts📑17.3.3 RHEL 7 以上版网络配置RHEL 6之前,网络接口使用连续号码命名:eth0、eth1等,当增加或删除网卡时,名称可能会发生变化,RHEL 7以上版使用基于硬件,设备拓扑和设置类型命名。RHEL 8 中已弃用network.service,采用NetworkManager(NM)为网卡启用命令。RHEL 8 仍可以安装network.service作为网卡服务,只是默认没有安装,具体方法为: dnf install networkscripts,不过官方已明确在下一个大版本中,将彻底放弃network.service,不建议继续使用network.service管理网络。此章节内容还可参考金鱼哥另外2篇博文,可结合一起学习:RH358服务管理和自动化–配置网络接口RH358配置链路聚合–配置网络组TeamRH358配置链路聚合–管理网络组17.3.3.1 网卡命名机制systemd对网络设备的命名方式1.如果Firmware或BIOS为主板上集成的设备提供的索引信息可用,且可预测则根据此索引进行命名,如:eno12.如果Firmware或BIOS为PCI-E扩展槽所提供的索引信息可用,且可预测,则根据此索引进行命名,如:ens13.如果硬件接口的物理位置信息可用,则根据此信息命名,如:enp2s04.如果用户显式启动,也可根据MAC地址进行命名,如:enx2387a1dc565.上述均不可用时,则使用传统命名机制修改网卡命名规则:vim /etc/sysconfig/grub GRUB_CMDLINE_LINUX="resume=/dev/mapper/rhel-swap rd.lvm.lv=rhel/root rd.lvm.lv=rhel/swap rhgb quiet net.ifnames=0 biosdevname=0" #增加net.ifnames=0 biosdevname=0 grub2-mkconfig -o /boot/grub2/grub.conf root vim /etc/sysconfig/network-scripts/ifcfg-xxx NAME=eth0 DEVICE=eth0基于BIOS支持启用biosdevname软件内置网卡:em1,em2 pci卡:pYpX Y:slot ,X:port网卡组成格式en: Ethernet 有线局域网 wl: wlan 无线局域网 ww: wwan无线广域网 o<index>: 集成设备的设备索引号 s<slot>: 扩展槽的索引号 x<MAC>: 基于MAC地址的命名 p<bus>s<slot>: enp2s117.3.3.2 网络配置工具 nmcli命令行工具:nmcli依赖于NetworkManager服务,此服务是管理和监控网络设置的守护进程nmcli命令nmcli命令相关术语设备即网络接口连接是对网络接口的配置,一个网络接口可有多个连接配置,但同时只有一个连接配置生效格式:nmcli [ OPTIONS ] OBJECT { COMMAND | help } device - show and manage network interfaces nmcli device help connection - start, stop, and manage network connections nmcli connection help修改IP地址等属性:nmcli connection modify IFACE [+|-]setting.property value setting.property: ipv4.addresses ipv4.gateway ipv4.dns1 ipv4.method manual | auto修改配置文件执行生效:nmcli con reload nmcli con up con-name范例:#查看帮助 nmcli con add help #使用nmcli配置网络 nmcli con show #显示所有活动连接 nmcli con show --active #显示网络连接配置 nmcli con show "System eth0“ #显示设备状态 nmcli dev status #显示网络接口属性 nmcli dev show eth0 #创建新连接default,IP自动通过dhcp获取 nmcli con add con-name default type Ethernet ifname eth017.3.3.3 网络组 Network Teaming网络组:是将多个网卡聚合在一起方法,从而实现冗错和提高吞吐量网络组不同于旧版中bonding技术,提供更好的性能和扩展性网络组由内核驱动和teamd守护进程实现网络组特点启动网络组接口不会自动启动网络组中的port接口启动网络组接口中的port接口总会自动启动网络组接口禁用网络组接口会自动禁用网络组中的port接口没有port接口的网络组接口可以启动静态IP连接启用DHCP连接时,没有port接口的网络组会等待port接口的加入例子文件:/usr/share/doc/teamd/example_configs/... 1 #创建网络组接口 nmcli con add type team con-name CNAME ifname INAME [config JSON] CNAME 连接名 INAME 接口名 JSON 指定runner方式,格式:'{"runner": {"name": "METHOD"}}' METHOD 可以是broadcast, roundrobin, activebackup, loadbalance, lacp #创建port接口 nmcli con add type team-slave con-name CNAME ifname INAME master TEAM CNAME 连接名,连接名若不指定,默认为team-slave-IFACE INAME 网络接口名 TEAM 网络组接口名 #断开和启动 nmcli dev dis INAME nmcli con up CNAME INAME 设备名 CNAME 网络组接口名或port接口 网络组示例nmcli con add type team con-name myteam0 ifname team0 config '{"runner":{"name": "loadbalance"}}' nmcli con add con-name team0-eth1 type team-slave ifname eth1 master team0 nmcli con add con-name team0-eth2 type team-slave ifname eth2 master team0 nmcli con up myteam0 nmcli con up team0-eth1 nmcli con up team0-eth2 teamdctl team0 state
0
0
0
浏览量1624
秋月无边

厉害了,有人这样对Ansible Playbook做简介

1. 什么是playbook中文名:剧本,它是一个自动化处理脚本。 Playbook采用YAML语言编写。2. playbook演示以下做个简单的操作演示,编写好主机清单后再进行剧本的编写。[student@servera ~]$ cat hosts servera [student@servera ~]$ cat webserver.yml --- - name: play to setup web server hosts: servera remote_user: root become: yes become_method: sudo tasks: - name: latest httpd version install yum: name: httpd state: latest [student@servera ~]$ ansible-playbook -i hosts webserver.yml PLAY [play to setup web server] ********************************************************* TASK [Gathering Facts] ****************************************************************** ok: [servera] TASK [latest httpd version install]****************************************************** changed: [servera] PLAY RECAP ****************************************************************************** servera : ok=2 changed=1 unreachable=0 failed=0 3. Playbook工作流程playbook 剧本是由一个或多个"play"组成的列表play的主要功能在于将预定义的一组主机,装扮成事先通过ansible中的task定义好的角色。Task实际是调用ansible的一个module,将多个play组织在一个playbook中,即可以让它们联合起来,按事先编排的机制执行预定义的动作。Playbook 文件是采用YAML语言编写的(就正如图片小人书,剧本都是由我们根据特定需求编写好的“脚本”,此“脚本”运用各种模块通过作用于特定的主机清单而达到需求。)4. YAML语法简介这里只涉及到playbook相关的语法(更多请参考官网http://www.yaml.org)。语法非常严格,请仔细仔细再仔细。在单一档案中,可用连续三个连字号(---)区分多个档案。另外,还有选择性的连续三个点号( ... )用来表示档案结尾 次行开始正常写Playbook的内容,一般建议写明该Playbook的功能 • 使用#号注释代码 • 缩进必须是统一的,不能空格和tab混用,一般缩进2个空格(可以改造tab为缩进) • 缩进的级别也必须是一致的,同样的缩进代表同样的级别,程序判别配置的级别是通过缩进结合换行来实现的 • YAML文件内容和Linux系统大小写判断方式保持一致,是区别大小写的,key/value的值均需大小写敏感 • key/value的值可以写在同一行,也可换行写。同一行使用 , 逗号分隔 • value可是个字符串,也可是另一个列表 • 一个完整的代码块功能需最少元素需包括 name和task • 一个name只能包括一个task • 使用 | 和 > 来分隔多行,实际上这只是一行。 include_newlines: | exactly as you see will appear these three lines of poetry ignore_newlines: > this is really a single line of text despite appearances • Yaml中不允许在双引号中出现转义符号,所以都是以单引号来避免转义符错误 • YAML文件扩展名通常为yml或yaml 很多刚学习的同学,往往运行报错就挂在语法上,后续可通过不断的练习来理解。(语法基础真的很重要,别 说了你又不听,听了你又不懂,懂了你又不做,做了你又做错,错了你又不认,认了你又不改,改了你又不服。)List:列表其所有元素均使用"-"打头- web - dns -空格web # 书写格式Dictionary:字典(键值对)通常由多个key与value构成多行写法: name: hunk blog: "xxxxx" name:空格hunk > 这个冒号后面必须是一个空格 同一行写法: 需要使用{ } {name: hunk, blog: "xxxxxx"} > 逗号后建议使用留一个空格 布尔值的表示法: yes/no true/false create_key: yes needs_agent: no knows_oop: True likes_emacs: TRUE uses_cvs: false 5. Playbook核心元素name可选配置项,可有助于记录playbook的运行说明。hostshosts 行的内容是一个或多个组或主机的 patterns,以逗号为分隔符。通常是/etc/ansible/hosts定义的主机列表remote_user 就是远程执行任务的账户名:--- - hosts: web,dns remote_user: roottasks任务集 tasks: - name: install httpd yum: name: httpd - name: start httpd service: name=httpd state=started 6. 改造vi中tab键功能为了能更加轻松的编辑playbook,可设置在vi编辑yaml文件时,按下tab键会进行一个双空格缩进。在 $HOME/.vimrc 添加以下内容autocmd FileType yaml setlocal ai ts=2 sw=2 et 参数解释:set ai # 自动缩进 set ts=2 # tabstop,表示按一个tab之后,显示出来的相当于几个空格,默认的是8个。 set sw=2 # shiftwidth,表示每一级缩进的长度 set et # expandtab,将tab转成空格,缩进用空格来表示(别问我为什么要改写,因为当你见到别人噼里啪啦地敲完键盘写好playbook时,你可能还在默念按了多少个空格。>.<)7. playbook书写风格以下书写例子中,就是shorthand格式,比较旧的书写方法:- name: copy new yum config to host copy: src=/etc/yum.repos.d/ dest=/etc/yum.repos.d/ 普遍的yaml格式书写:- name: copy new yum config to host copy: src: /etc/yum.repos.d/ dest: /etc/yum.repos.d/基本都是使用新的写法,便于阅读和排错。8. playbook执行检测语法:ansible-playbook --syntax-check webserver.yml模拟执行:ansible-playbook -C webserver.yml真实执行:ansible-playbook webserver.yml执行的详细程度: -v :显示任务结果。 -vv :任务结果和任务配置都会显示 -vvv :包含关于与受管主机连接的信息 -vvvv:增加了连接插件相关的额外详细程度选项,包括受管主机上用于执行脚本的用户,以及所执行的脚本 9. 练习演示----如何编写playbook设置tab键缩进[student@servera ~]$ cat .vimrc autocmd FileType yaml setlocal ai ts=2 sw=2 et查看配置文件和主机清单[student@servera ~]$ mkdir playbook [student@servera playbook]$ cat ansible.cfg [defaults] inventory=inventory remote_user=student [privilege_escalation] become=True become_method=sudo become_user=root become_ask_pass=False [student@servera playbook]$ cat inventory [web] serverc serverd 编写所需要的剧本[student@servera playbook]$ cat site.yml --- - name: Install and start Aapche HTTPD hosts: web tasks: - name: httpd package is present yum: name: httpd state: present - name: correct index.html is present copy: content: "This is a test page.\n" dest: /var/www/html/index.html - name: httpd is started service: name: httpd state: started enabled: true 语法检查[student@servera playbook]$ ansible-playbook --syntax-check site.yml playbook: site.yml运行剧本前进行语法检查是一个良好习惯。执行剧本[student@servera playbook]$ ansible-playbook site.yml PLAY [Install and start Aapche HTTPD] *************************************************** TASK [Gathering Facts] ****************************************************************** ok: [serverc] ok: [serverd] TASK [httpd package is present] ********************************************************* changed: [serverd] changed: [serverc] TASK [correct index.html is present] **************************************************** changed: [serverc] changed: [serverd] TASK [httpd is started] ***************************************************************** changed: [serverc] changed: [serverd] PLAY RECAP ****************************************************************************** serverc : ok=4 changed=3 unreachable=0 failed=0 serverd : ok=4 changed=3 unreachable=0 failed=0 幂等性[student@servera playbook]$ ansible-playbook site.yml …………此为Ansible重要特性之一,用练习演示更容易进行理解。结果访问检查[student@servera playbook]$ curl serverc This is a test page. [student@servera playbook]$ curl serverd This is a test page. 10. playbook提权可以写在剧本中,与hosts,tasks同级- hosts: all become: true become_method: sudo become_user: root tasks: - debug: msg: "Test" 当然,不在剧本上编写,在配置文件上编写也可以,如果两个地方都进行编写,在剧本中的优先级会比配置文件上的高,例如:配置文件上启动提权become: yes,但剧本上配置了become: no,最终生效为剧本上的配置。11. 善于模块文档ansible-doc -l 查看列表ansible-doc modulename 查看模块帮助文件12. 练习演示----执行多个playbook查看配置文件和主机清单[student@servera ~]$ mkdir playbook-multi [student@servera ~]$ cd playbook-multi/ [student@servera playbook-multi]$ cat ansible.cfg [defaults] inventory=inventory remote_user=student [privilege_escalation] become=False become_method=sudo become_user=root become_ask_pass=False [student@servera playbook-multi]$ cat inventory servera 编写所需要的剧本[student@servera playbook-multi]$ cat web.yml --- - name: Enable web services hosts: servera become: yes tasks: - name: latest version of httpd and firewalld installed yum: name: - httpd - firewalld state: latest - name: test html page is installed copy: content: "Hello World!\n" dest: /var/www/html/index.html - name: firewalld enabled and running service: name: firewalld enabled: true state: started - name: firewalld permits http service firewalld: service: http permanent: true state: enabled immediate: yes - name: httpd enabled and running service: name: httpd enabled: true state: started - name: Test web server hosts: localhost become: no tasks: - name: connect to web server uri: url: http://servera return_content: yes status_code: 200 语法检查[student@servera playbook-multi]$ ansible-playbook --syntax-check web.yml playbook: web.yml使用-v执行剧本[student@servera playbook-multi]$ ansible-playbook web.yml -v PLAY [Enable web services] ************************************************************** TASK [Gathering Facts] ****************************************************************** ok: [servera] TASK [latest version of httpd and firewalld installed] ****************************************** ok: [servera] => {"changed": false, "msg": "", "rc": 0, "results": ["All packages providing httpd are up to date", "All packages providing firewalld are up to date", ""]} ………… TASK [connect to web server] ************************************************************ ok: [localhost] => {"accept_ranges": "bytes", "changed": false, "connection": "close", "content": "Hello World!\n", "content_length": "37", "content_type": "text/html; charset=UTF-8", "cookies": {}, "cookies_string": "", "date": "Fri, 04 Sep 2020 12:54:49 GMT", "etag": "\"25-5ae7c5e78c9df\"", "last_modified": "Fri, 04 Sep 2020 12:54:27 GMT", "msg": "OK (37 bytes)", "redirected": false, "server": "Apache/2.4.6 (Red Hat Enterprise Linux)", "status": 200, "url": "http://servera"} PLAY RECAP ********************************************************************************** localhost : ok=2 changed=0 unreachable=0 failed=0 servera : ok=6 changed=0 unreachable=0 failed=0 总结yaml语法非常严格,仔细编写。改造tab键以提高编写剧本的效率。语法检查是一个良好习惯。善用模块文档查看参数说明与例子。通过练习与实验了解幂等性。可使用 -v 参数查看详细输出进行排错。RHCE认证作为基础认证的升级,需要大家在RHCSA的基础上再进行学习,因此,涉及的基础内容需要大家好好进行学习并巩固。有良好的基础才能更上一层楼。好好加油,可以噶。
0
0
0
浏览量2003
秋月无边

部署ansible--构建ansible主机清单

1. 查看ansible里的安装文件# rpm -ql ansible|less /etc/ansible/ansible.cfg # 默认ansible的默认配置文件位置 /etc/ansible/hosts # 默认inventory主机清单位置 /etc/ansible/roles # 默认inventory角色位置 /usr/bin/ansible # ansible命令的文件 /usr/lib/python3.6/site-packages/ansible # 提供Python模块 /usr/share/man/man1/ # 帮助文档2. 简介inventory是一个被管理主机的一个清单文件。inventory里可以有单个主机,也可以有多个主机加起来的主机组。inventory有静态和动态两种清单。静态主机清单可以通过文本文件来定义。动态主机清单可以根据需要而使用外部信息提供的脚本或其他程序来生成。先进行静态主机清单的学习(重要),动态主机清单后续再进行简述。3. 静态inventory单个主机可以是ip地址,也可以是域名$ cat inventory servera > FQDN 192.168.1.100 > IP地址 192.168.100.11:2222 > 非标准SSH端口主机组格式[组名] 主机1 主机2 主机3 ...示例$ cat inventory localhost [web-server] servera serverb [balancer] serverc [data-server] serverd列出主机all:代表所有主机$ ansible -i inventory --list-hosts all hosts (5): localhost serverc servera serverb serverdungrouped:未分组主机$ ansible -i inventory --list-hosts ungrouped hosts (1): localhost嵌套组格式[组名:children] # children是关键字,固定语法,必须填写。 组名1 组名2示例同一个(主机/组)可以出现在多个组中$ cat inventory localhost [web-server] servera serverb [balancer] serverc [data-server] serverd [webs:children] web-server data-server [bakend:children] balancer webs列出主机$ ansible -i inventory --list-hosts webs hosts (3): servera serverb serverd $ ansible -i inventory --list-hosts bakend hosts (4): serverc servera serverb serverd范围简化表达式格式[start:end]示例192.168.1.1:100 代表192.168.1.1-192.168.1.100 192.168.10:20.1:254 代表192.168.10.1-192.168.20.254 server01:20.domain.com 代表01,02,03…20 a:c.domain.com 代表a,b,c $ cat inventory 192.168.1.[1:100] 192.168.[10:20].[1:254] [server] server[01:20].domain.com [mydomain] [a:c].domain.com列出主机$ ansible -i inventory --list-hosts '192.168.12.25*' hosts (6): 192.168.12.25 192.168.12.250 192.168.12.251 192.168.12.252 192.168.12.253 192.168.12.254 $ ansible -i inventory --list-hosts server12.domain.com hosts (1): server12.domain.com $ ansible -i inventory --list-hosts mydomain hosts (3): a.domain.com b.domain.com c.domain.com模糊匹配通配符在Ansible表示0个或多个任意字符,主要应用于一些模糊规则匹配。匹配匹配所有主机,all或*号功能相同。如检测所有主机存活情况。ansible all --list-hosts ansible '*' --list-hosts ansible '172.25.0.*' --list-hosts ansible 'server*' --list-hosts逻辑或匹配如我们希望同时对多台主机或多个组同时执行,相互之间用 **:(冒号)**或者 ,逗号 分隔即可。ansible 'servera,prod' --list-host ansible 'ba*,prod' --list-host逻辑与(&)匹配逻辑与都匹配到的才执行。ansible 'ser*,&prod' --list-hosts逻辑非匹配逻辑非用感叹号(!)表示,主要针对多重条件的匹配规则,使用方式如下:ansible 'web*,!prod' --list-hosts 多条件组合ansible 'server*,&prod,!ba' --list-host正则匹配Ansible同样完整支持正则匹配功能,~开始表示正则匹配。ansible '~server(a|b)' --list-host使用正则检测 www.example.com、new.example.com、blog.example.com的存活。ansible “~(www|new|blog).example.(com|org)” --list-hosts
0
0
0
浏览量2006
秋月无边

八、创建查看和编辑文本文件

8.1 文本编辑工具VIM练习工具:vimtutor最小化系统默认是不安装的,yum -y install vim8.1.1 使用vim初步8.1.1.1 vim命令格式vim [OPTION]... FILE...常用选项+# #打开文件后,让光标处于第#行的行首,+默认行尾 +/PATTERN #让光标处于第一个被PATTERN匹配到的行行首 -b file #二进制方式打开文件 -d file #比较多个文件,相当于vimdiff -m file #只读打开文件 -e file #直接进入ex模式,相当于执行ex file -y file #Easy mode (like "evim",modeless),直接可以操作文件,ctrl+o:wq|q!保存和不保存退出说明:如果该文件存在,文件被打开并显示内容如果该文件不存在,当编辑后第一次存盘时创建它8.1.1.2 三种主要模式和切换vim是一个模式编辑器,击键行为是依赖于vim的“模式”三种常见模式:命令或者普通(Normal)模式:默认模式,可以实现移动光标,剪切/粘贴文本插入(Insert)或编辑模式:用于修改文本扩展命令(extended command)或命令(末)行模式:保存,退出等模式转换命令模式 --> 插入模式i #insert, 在光标所在处输入 I #在当前光标所在行的行首输入 a #append, 在光标所在处后面输入 A #在当前光标所在行的行尾输入 o #在当前光标所在行的下方打开一个新行 O #在当前光标所在行的上方打开一个新行插入模式—ESC—> 命令模式命令模式— : —> 扩展命令模式扩展命令模式—ESC,enter—> 命令模式8.1.2 命令模式命令模式,又称为Normal模式,功能强大,只是此模式输入指令并在屏幕上显示,所以需要记忆大量的快捷键才能更好的使用8.1.2.1 退出VIMZZ 保存退出 ZQ 不保存退出8.1.2.2 光标跳转字符间跳转:h:左 l:右 j:下 k:上 同时支持方向键 #COMMAND:跳转由#指定的个数的字符 #如:5l单词间跳转:w:下一个单词的词首 e:当前或下一单词的词尾 b:当前或前一个单词的词首 #COMMAND: 由#指定一次跳转的单词数当前页跳转:H:页首 M:页中间行 L:页底 zt:将光标所在当前行移到屏幕顶端 zz:将光标所在当前行移到屏幕中间 zb:将光标所在当前行移到屏幕低端行首行尾跳转:^ 跳转至行首的第一个非空白字符 0 跳转至行首 $ 跳转至行尾行间移动:#G 跳转至由第#行,相当于在扩展命令模式下 :# G 最后一行 1G,gg 第一行命令模式翻屏操作:ctrl+f 向文件尾部翻一屏 ctrl+b 向文件首部翻一屏 ctrl+d 向文件尾部翻半屏 ctrl+u 向文件首部翻半屏8.1.2.3 字符编辑x 删除光标处的字符 #x 删除光标处起始的#个字符 xp 交换光标所在处的字符及其后面字符的位置 ~ 转换大小写 J 删除当前行后的换行符8.1.2.4 替换命令(replace)r 只替换光标所在处的一个字符 R 切换成REPLACE模式(在末行出现-- REPLACE --提示),按ESC回到命令模式8.1.2.5 删除命令(delete)d:删除命令,可结合光标跳转字符,实现范围删除 d$ 删除到行尾 d^ 删除到非空行首 d0 删除到行首 dw de db #COMMAND dd 剪切光标所在的行 #dd 多行删除 D 从当前光标位置一直删除到行尾,等同于d$8.1.2.6 复制命令(yank)y:复制,行为相似于d命令 y$ y0 y^ ye yw yb #COMMAND yy #y Y8.1.2.7 粘贴命令(paste)p 缓冲区存的如果为整行,则粘贴当前光标所在行的下方;否则,则粘贴至当前光标所在处的后面 P 缓冲区存的如果为整行,则粘贴当前光标所在行的上方;否则,则粘贴至当前光标所在处的前面8.1.2.8 改变命令(change)c: 删除后切换成插入模式 c$ c^ c0 cb ce cw #COMMAND cc 删除当前行并输入新内容,相当于S #cc C 删除当前光标到行尾,并切换成插入模式,相当于c$8.1.2.9 查找/PATTERN:从当前光标所在处向文件尾部查找 ?PATTERN:从当前光标所在处向文件首部查找 n: 与命令同方向 N:与命令反方向8.1.2.10 撤销修改u 撤销最近的更改,相当于windows中ctrl+z #u 撤销之前#次更改 U 撤销光标落在这行后所有此行的更改 . 重复前一个操作 #. 重复前一个操作#次8.1.2.11 高级用法<start position><command><end positin>常见Command:y复制、d删除、gU变大写、gu变小写范例:0y$ 命令 0 -> 先到行头 y -> 从这里开始拷贝 $ -> 拷贝到本行最后一个字符范例:粘贴“root”100次100iroot [ESC]高级用法di" 光标在" "之间,则删除" "之间的内容 yi( 光标在()之间,则复制()之间的内容 vi[ 光标在[]之间,则选中[]之间的内容 dtx 删除字符直到遇见光标之后的第一个X字符 ytx 复制字符直到遇见光标之后的第一个X字符8.1.3 扩展命令模式按 冒号 “:” 可以进入Ex模式,创建一个命令提示符 : 处于底部的屏幕左侧8.1.3.1 扩展命令模式基本命令w #写(存)磁盘文件 wq #写入并退出 x #写去并退出 X #加密 q #退出 q! #不存盘退出,即使更改都将丢失 r filename #读文件内容到当前文件中 w filename #将当前文件内容写入另一个新文件 !command #执行命令 r!command #读入命令的输入8.1.3.2 地址定界格式:start_pos,end_pos CMD地址定界格式# #具体第#行,例如2表示第二行 #,# #从左侧#表示起始行,到右侧#表示结尾行 #,+# #从左侧#表示起始行,加上右侧#表示行数,范例:2,+3 表示2到5行 . #当前行 $ #最后一行 .,$-1 #当前行到倒数第二行 % #全文,相当于1,$ /pattern/ #从当前行向下查找,直到匹配pattern的第一行,即:正则表达式 /part1/,/part2/ #从第一次被part1模式匹配到的行开始,一直到第一次被part2匹配到的行结束 #,/pat/ #从指定行开始,一直找到第一个匹配pattern的行结束 /pat/,$ #向下找到第一个匹配pattern的行到整个文件的结尾的所有行地址定界后跟一个编辑命令d #删除/剪切 y #复制 w file #将范围内的行另存至指定文件中 r flle #将指定位置插入指定文件中的所有内容查找并替换格式:s/要查找的内容/替换为的内容/修饰符说明:要查找的内容:可使用基末正则表达式模式 替换为的内容:不能使用模式,但可以使用\1, \2, ...等向后引用符号: 还可以使用“&”引用前面查找时查找到的内容修饰符:i #忽略大小写 g #全局替换,默认情况下,每一行只替换第一次出现 gc #全局替换,每次替换前询问查找替换中的分隔符/可替换为其他字符,如:#,@s@zhangsan@lisi@g s#zhangsan#lisi@g8.1.3.3 定制vim的工作特性扩展命令模式的配置只是对当前vim进程有效,可将配置存放在文件中持久保存配置文件:/etc/vimrc #全局 ~/.vimrc #个人以下示例临时启用,永久启用写在以上配置文件中行号显示:set number,简写set nu 取消显示:set nonumber,简写set nonu略字符的大小写启用:set ignorecase,简写 set ic 禁用:set noic自动缩进启用:set autoindent,简写 set ai 禁用:set noai复制保留格式启用:set paste 禁用:set nopaste显示tab和换行符^|和$显示启用:set list 禁用:set nolist高亮搜索启用:set hlsearch 简写:set hls 禁用:set nohlsearch 简写:nohl #配置文件写简写无效语法高亮启用:syntax on 简写:syn on 禁用:syntax off 简写:syn off文件格式启用windows格式:set fileformat=dos 启用unix格式:set fileformat=unix 简写 set ff=dos|unixTab用空格代替启用:set expandtab 默认为8个空格代替Tab 禁用:noexpandtab 简写:set etTab用指定空格的个数代替启用:set tabstop=# 指定#个空格代替tab 简写:set ts=#设置光标所在行的标示线启用:set cursorline 简写 set cul 禁用:set nocursorline帮助set帮助:help option-list :set or :set all8.1.4 可视化模式在末行有"–VISUAL–"指示,表示在可视化模式允许选择的文本块v 面向字符,在末行会显示:--VISUAL-- V 面向整行,在末行会显示:--VISUAL LINE-- crtl+v 面向块(也称为列模式),在末行会显示--VISUAL BLOCK--可视化键可用于与移动键结合使用w ) } 剪头等突出显示的文字可被删除,复制,变更,过滤,搜索,替换等范例:在文件行首插入#输入ctrl+v 进入可视化模式 输入G 跳到最后一行,选中每一行的第一个字符 输入I 切换至插入模式 输入# 按ESC键8.1.5 多文件模式vim FILE1 FILE2 FILE3... :next 下一个 :prev 前一个 :first 第一个 :last 最后一个 :wall 保存所有 :qall 不保存退出所有 :wqall 保存退出所有8.1.6 多窗口模式8.1.6.1 多文件分割vim -o|-O FILE1 FILE2 ... -o 水平或上下分割 -O 垂直或左右分割(vim only) 在窗口间切换:ctrl+w,Arrow8.1.6.2 单文件窗口分割ctrl+w,s 水平分割,上下分屏 ctrl+w,v 垂直分割,左右分屏 ctrl+w,q 取消相邻窗口 ctrl+w,o 取消所有窗口 :wqall 保存退出所有8.2 文本常见处理工具8.2.1 文件内容查看命令8.2.1.1 查看文本文件内容catcat可以查看文本内容格式:cat [OPTION]...[FILE]...常见选项-E 显示行结束符$ -A 显示所有控制符 -n 对显示出的每一行进行编号 -b 非空行编号 -s 压缩连续的空行为一行nl显示行号,相当于cat -btac逆向显示文本内容[root@localhost tmp]# cat 1.txt 1 2 3 4 5 [root@localhost tmp]# tac 1.txt 5 4 3 2 1rev将同一行的内容逆向显示[root@localhost tmp]# cat 2.txt 1 2 3 4 5 a b c [root@localhost tmp]# rev 2.txt 5 4 3 2 1 c b a8.2.2 分页查看文件内容8.2.2.1 more可以实现分页查看文件,可以配合管道实现输出信息的分页格式more [OPTION] FILE选项-d:显示翻页及退出提示8.2.2.2 lessless也可以实现分页查看文件或STDIN输出,less命令是man命令使用的分页器查看时有用的命令包括:/文本 向下搜索 文本 ?文本 向上搜索 n/N 跳到下一个 或 上一个匹配8.3 显示文本前或后行内容8.3.1 head可以显示文件或标准输入的前面行格式:head [OPTION]... [FILE]...选项:-c # 指定获取前#个字节 -n # 指定获取前#行 -# 同上8.3.2 tailtail和head相反,查看文件或标准输入的倒数行格式:tail [OPTION]... [FILE]...-c # 指定获取后#个字节 -n # 指定获取后#行 -# 同上 -f 跟踪显示文件fd新追的内容,常用日志监控,相当于 --follow=descriptor,当文件删除再新建同文件,将无法继续跟踪文件 -F 跟踪文件名,相当于--follow=name --retry,当文件删除再新建同名文件,将可以继续跟踪文件
0
0
0
浏览量820
秋月无边

终于有人透露Ansible配置文件的奥秘了

第一层 配置文件优先级Ansible配置文件ansible.cfg,可以存在于多个位置,他们的被读取的顺序如下:ANSIBLE_CONFIG # (环境变量) ansible.cfg # (当前目录) .ansible.cfg # (用户家目录) /etc/ansible/ansible.cfg # (默认配置文件)最先匹配的配置文件就会生效,而且可以一个一个单独设置。别说人家有四个配置文件就说人奇葩啊,是方便你打通奇经八脉,运用在江湖的。第二层 配置选项查看ansible.cfg的配置项[student@servera ~]$ grep "^\[" /etc/ansible/ansible.cfg [defaults] # 默认常用配置 [inventory] # 主机清单插件 [privilege_escalation] # 用于提权 [paramiko_connection] # python paramiko模块的连接设置(默认使用SSH) [ssh_connection] # SSH连接设置 [persistent_connection] # 长连接设置 [accelerate] # 加速模式的配置 [selinux] # selinux设置 [colors] # 输出结果颜色的设置 [diff] # 输出不同的设置第三层 常用配置选项解读虽然ansible.cfg配置文件一堆配置选项参数,但常用的,真就那么几个,别说我没告诉你。[defaults] #inventory = /etc/ansible/hosts # 主机清单文件的位置 #library = /usr/share/my_modules/ # 库文件存放目录 #remote_tmp = ~/.ansible/tmp # 临时py命令文件存放在远程主机目录 #local_tmp = ~/.ansible/tmp # 本机的临时命令执行目录 #forks = 5 # 默认并发数 #sudo_user = root # 默认sudo 用户 #ask_sudo_pass = True # 是否需要sudo密码 #ask_pass = True # 连接时是否需要密码 #remote_port = 22 # 远程主机的默认端口,生产中这个端口应该会不同 #log_path = /var/log/ansible.log # 日志路径 #roles_path = /etc/ansible/roles # roles 存放路径 #host_key_checking = False # 首次连接是否检查对应服务器的host_key,建议取消注释。 #remote_user # 指定使用ansible用户。 [privilege_escalation]: become=True # 是否提权 become_method=sudo # 提权方式 become_user=root # 提权的用户 become_ask_pass=False # 提权是否需要密码第四层 官网配置参考网址全部招式,怎么记得住啊?去藏经阁找找:https://docs.ansible.com/ansible/latest/reference_appendices/config.html第五层 提权注意事项根据配置项可知,若要提权成功,则需要设置好对应的sudo权限才可以使用sudo,至于提权是否需要密码,就需要设置好对应的命令是否需要(实验为了方便演示,直接使用NOPASSWD: ALL,但在实际生产环境中,除了管理员外,不应该让用户拥有如此高的权限。)。去炼器阁拿装备高阶武器与防具还是必备。实验拓扑介绍实验使用4台虚拟机,分别命名为 servera、serverb、serverc、serverd。其中,servera 为主控端,serverb、serverc、serverd为被控端。为了方便演示与测试,4台机器的selinux已关闭。演示环境使用CentOS 7 系统。为了方便以主机名做为访问互联,编辑  文件添加对应机器的ip地址映射,演示环境设置如下所示:[root@servera ~]# cat /etc/hosts # 4台机器都编辑同样的映射配置 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 192.168.159.111 servera 192.168.159.112 serverb 192.168.159.113 serverc 192.168.159.114 serverd编写配置文件[student@servera ~]$ mkdir /home/student/manage # 建议不同项目创建不同项目的文件夹,并编写不同的配置文件以方便项目管理。 [student@servera ~]$ cd !$ cd /home/student/manage [student@servera manage]$ vim ansible.cfg [defaults] inventory = ./inventory编写主机清单[student@servera manage]$ vim inventory [myself] localhost [intranetweb] servera [everyone:children] myself intranetweb验证主机清单[student@servera manage]$ ansible myself --list-hosts hosts (1): localhost [student@servera manage]$ ansible intranetweb --list-hosts hosts (1): servera [student@servera manage]$ ansible everyone --list-hosts hosts (2): localhost servera设置提权需要提供密码[student@servera manage]$ vim ansible.cfg [defaults] inventory = ./inventory [privilege_escalation] become = true become_method = sudo become_user = root become_ask_pass=true验证[student@servera manage]$ ansible intranetweb --list-hosts SUDO password: student hosts (1): servera总结RHCE认证作为基础认证的升级,需要大家在RHCSA的基础上再进行学习,因此,涉及的基础内容需要大家好好进行学习并巩固。有良好的基础才能更上一层楼。
0
0
0
浏览量71
秋月无边

十三、配置和保护SSH服务

📜13.1 ssh 服务介绍ssh: secure shell, protocol, 22/tcp, 安全的远程登录,实现加密通信,代替传统的 telnet 协议具体的软件实现:OpenSSH:ssh协议的开源实现,rhel、centos 默认安装dropbear:另一个ssh协议的开源项目的实现SSH 协议版本:v1:基于CRC-32做MAC,不安全;man-in-middlev2:双方主机协议选择安全的MAC方式,基于DH算法做密钥交换,基于RSA或DSA实现身份认证📑13.1.1 公钥交换原理客户端发起链接请求服务端返回自己的公钥,以及一个会话ID(这一步客户端得到服务端公钥)客户端生成密钥对客户端用自己的公钥异或会话ID,计算出一个值Res,并用服务端的公钥加密客户端发送加密后的值到服务端,服务端用私钥解密,得到Res服务端用解密后的值Res异或会话ID,计算出客户端的公钥(这一步服务端得到客户端公钥)最终:双方各自持有三个秘钥,分别为自己的一对公、私钥,以及对方的公钥,之后的所有通讯都会被加密📑13.1.2 ssh加密通讯原理📜13.2 openssh 服务OpenSSH是SSH (Secure SHell) 协议的免费开源实现,一般在各种Linux版本中会默认安装,基于C/S结构Openssh软件相关包:opensshopenssh-clientsopenssh-server服务器:/usr/sbin/sshdUnit 文件:/usr/lib/systemd/system/sshd.service客户端:Linux Client: ssh, scp, sftp,sloginWindows Client:xshell, MobaXterm,putty, securecrt, sshsecureshellclient📑13.2.1 客户端 ssh 命令ssh命令是ssh客户端,允许实现对远程系统经验证地加密安全访问当用户远程连接ssh服务器时,会复制ssh服务器/etc/ssh/ssh_host*key.pub文件中的公钥到客户机的~/.ssh/know_hosts中。下次连接时,会自动匹配相应私钥,不能匹配,将拒绝连接格式:ssh [user@]host [COMMAND] ssh [-l user] host [COMMAND]常见选项-p port:远程服务器监听的端口 -b 指定连接的源IP -v 调试模式 -C 压缩方式 -X 支持x11转发 -t 强制伪tty分配,如:ssh -t remoteserver1 ssh -t remoteserver2 ssh remoteserver3 -o option 如:-o StrictHostKeyChecking=no -i <file> 指定私钥文件路径,实现基于key验证,默认使用文件: ~/.ssh/id_dsa, ~/.ssh/id_ecdsa, ~/.ssh/id_ed25519,~/.ssh/id_rsa等范例:远程执行命令[root@servera .ssh]# ssh 192.168.137.129 ls -l root@192.168.137.129's password: total 4 -rw-------. 1 root root 1624 Apr 2 13:51 anaconda-ks.cfg📑13.2.2 ssh 登录验证🔖ssh登录验证方式介绍ssh服务登录的常用验证方式用户/口令基于密钥基于用户和口令登录验证客户端发起ssh请求,服务器会把自己的公钥发送给用户用户会根据服务器发来的公钥对密码进行加密加密后的信息回传给服务器,服务器用自己的私钥解密,如果密码正确,则用户登录成功基于密钥的登录方式首先在客户端生成一对密钥(ssh-keygen)并将客户端的公钥ssh-copy-id 拷贝到服务端当客户端再次发送一个连接请求,包括ip、用户名服务端得到客户端的请求后,会到authorized_keys中查找,如果有响应的IP和用户,就会随机生成一个字符串服务端将使用客户端拷贝过来的公钥进行加密,然后发送给客户端得到服务端发来的消息后,客户端会使用私钥进行解密,然后将解密后的字符串发送给服务端服务端接受到客户端发来的字符串后,跟之前的字符串进行对比,如果一致,就允许免密码登录🔖实现基于密钥的登录方式在客户端生成密钥对ssh-keygen -t rsa [-P 'password'] [-f “~/.ssh/id_rsa"]把公钥文件传输至远程服务器对应用户的家目录ssh-copy-id [-i [identity_file]] [user@]host重设私钥口令:ssh-keygen -p📑13.2.3 ssh服务器配置服务器端:sshd服务器端的配置文件: /etc/ssh/sshd_config服务器端的配置文件帮助:man 5 sshd_config常用参数:Port #更改端口先关selinux,setenforce 0 ListenAddress ip LoginGraceTime 2m PermitRootLogin yes #默认ubuntu不允许root远程ssh登录 StrictModes yes #检查.ssh/文件的所有者,权限等 MaxAuthTries 6 MaxSessions 10 #同一个连接最大会话 PubkeyAuthentication yes #基于key验证 PermitEmptyPasswords no #空密码连接 PasswordAuthentication yes #基于用户名和密码连接 GatewayPorts no ClientAliveInterval 10 #单位:秒 ClientAliveCountMax 3 #默认3 UseDNS yes #提高速度可改为no GSSAPIAuthentication yes #提高速度可改为no MaxStartups #未认证连接最大值,默认值10 Banner /path/file #以下可以限制可登录用户的办法: AllowUsers user1 user2 user3 DenyUsers AllowGroups DenyGroups范例:设置ssh 空闲60s 自动注销Vim /etc/ssh/sshd_config ClientAliveInterval 60 ClientAliveCountMax 0 Service sshd restart #注意:新开一个连接才有效范例:解决ssh登录缓慢的问题vim /etc/ssh/sshd_config UseDNS no GSSAPIAuthentication no systemctl restart sshd范例:启用/禁用root 远程ssh登录#修改sshd服务配置文件 vim /etc/ssh/sshd_config #PermitRootLogin prohibit-password 注释掉此行 PermitRootLogin yes/no 修改为下面形式(yes启用/no禁用) systemctl restart sshdssh服务的最佳实践建议使用非默认端口 禁止使用protocol version 1 限制可登录用户 设定空闲会话超时时长 利用防火墙设置ssh访问策略 仅监听特定的IP地址 基于口令认证时,使用强密码策略,比如:tr -dc A-Za-z0-9_ < /dev/urandom | head -c 12|xargs 使用基于密钥的认证 禁止使用空密码 禁止root用户直接登录 限制ssh的访问频度和并发在线数 经常分析日志
0
0
0
浏览量1276
秋月无边

玩转Ansible条件任务而不踩坑

前言对于一些比较复杂的内容,例如在shell当中,我们会使用各种条件判断来进行,在Ansible当中也是,Ansible可使用conditionals,在符合特定条件时执行任务或play。例如,可以利用一个条件在Ansible安装或配置服务前确定受管主机上的可用内存。我们可以利用条件来区分不同的受管主机,并根据它们所符合的条件来分配功能角色。Playbook变量、注册的变量和Ansible事实都可通过条件来进行测试。可以使用比较字符串、数字数据和布尔值的运算符。以下场景说明了在Ansible中使用条件的情况:可以在变量中定义硬限制(如min_memory)并将它与受管主机上的可用内存进行比较。Ansible可以捕获并评估命令的输出,以确定某一任务在执行进一步操作前是否已经完成。例如,如果某一程序失败,则将跳过批处理。可以利用Ansible事实来确定受管主机网络配置,并决定要发送的模板文件(如,网络绑定或中继)。可以评估CPU的数量,来确定如何正确调节某一Web服务器。将注册的变量与预定义的变量进行比较,以确定服务是否已更改。例如,测试服务配置文件的MD5检验以和查看服务是否已更改。1. 条件任务语法when语句用于有条件地运行任务。它取要测试的条件为真。如果条件满足,则运行任务。如果条件不满足,则跳过任务。简单的条件语句案例:这个条件语句的意思是当my_server生效时才安装httpd;如果设置成False那么my_server并不生效--- - name: when test hosts: servera remote_user: root vars: my_server: False tasks: - name: "{{ my_server }} is installed" yum: name: httpd state: latest when: my_server 测试可执行性:[student@servera ~]$ ansible-playbook test.yml PLAY [when test] *********************************************************************************** TASK [Gathering Facts]******************************************************** ******************** ok: [servera] TASK [False is installed] ************************************************************************** skipping: [servera] PLAY RECAP *************************************************************************************** servera : ok=1 changed=0 unreachable=0 failed=0# 测试执行时直接跳过了。这里跳过的原因是因为要安装httpd服务的条件是my_server变量必须存在,而将my_server设置成False后,**my_server变量不生效就不满足when的条件,**所以即使这个playbook语法有问题也可以执行,但其中包含的任务是不能被执行的所以直接跳过了。如果将False改为True:[student@workstation ~]$ ansible-playbook -i hosts test.yml --- - name: when test hosts: servera remote_user: root vars: my_server: True tasks: - name: "{{ my_server }} is installed" yum: name: httpd state: latest when: my_server 执行测试PLAY [when test] ************************************************************************ TASK [Gathering Facts] ****************************************************************** ok: [servera] TASK [True is installed] **************************************************************** changed: [servera] PLAY RECAP ****************************************************************************** servera : ok=2 changed=1 unreachable=0 failed=0 # 此时的状态变成了changed而不是skipped当状态变为changed证明任务状态已经发生改变,httpd服务已经符合了安装条件另一种写法(defined):--- - name: when test hosts: servera remote_user: root tasks: - name: "ensure {{ my_server }} is installed" yum: name: "{{ my_server }}" state: latest when: my_server is defined 需要注意的是,这里的my_server变量依旧是没有被定义的[student@servera ~]$ ansible-playbook test.yml PLAY [when test] *********************************************************************************** TASK [Gathering Facts] **************************************************************************** ok: [servera] TASK [ensure {{ my_server }} is installed] ******************************************************* skipping: [servera] PLAY RECAP ************************************************************************************** servera : ok=1 changed=0 unreachable=0 failed=0 # 所以在执行测试时也跳过了任务如果定义my_server而不赋值:[student@servera ~]$ cat test.yml --- - name: when test hosts: servera remote_user: root vars: my_server: tasks: - name: "ensure {{ my_server }} is installed" yum: name: "{{ my_server }}" state: latest when: my_server is defined # 这里的条件是如果变量my_server被定义则执行安装的任务执行测试:[student@servera ~]$ ansible-playbook test.yml PLAY [when test] ************************************************************************ TASK [Gathering Facts] ****************************************************************** ok: [servera] TASK [ensure is installed] ************************************************************* fatal: [servera]: FAILED! => {"changed": false, "module_stderr": "Shared connection to servera closed.\r\n", "module_stdout": "Traceback (most recent call last):\r\n File \"/root/.ansible/tmp/ansible-tmp-1599491486.79-25931710335605/AnsiballZ_yum.py\", line 113, in <module>\r\n _ansiballz_main()\r\n File \"/root/.ansible/tmp/ansible-tmp-1599491486.79-25931710335605/AnsiballZ_yum.py\", line 105, in _ansiballz_main\r\n invoke_module(zipped_mod, temp_path, ANSIBALLZ_PARAMS)\r\n File \"/root/.ansible/tmp/ansible-tmp-1599491486.79-25931710335605/AnsiballZ_yum.py\", line 48, in invoke_module\r\n imp.load_module('__main__', mod, module, MOD_DESC)\r\n File \"/tmp/ansible_yum_payload_FaoojI/__main__.py\", line 1532, in <module>\r\n File \"/tmp/ansible_yum_payload_FaoojI/__main__.py\", line 1527, in main\r\n File \"/tmp/ansible_yum_payload_FaoojI/__main__.py\", line 374, in __init__\r\n File \"/tmp/ansible_yum_payload_FaoojI/ansible_yum_payload.zip/ansible/module_utils/yumdnf.py\", line 79, in __init__\r\nTypeError: 'NoneType' object is not iterable\r\n", "msg": "MODULE FAILURE\nSee stdout/stderr for the exact error", "rc": 1} to retry, use: --limit @/home/student/test.retry PLAY RECAP ****************************************************************************** servera : ok=1 changed=0 unreachable=0 failed=1 # 在执行测试时会这样报错如果定义的变量,却不给变量赋值。那么这个playbook是不能成功执行的,因为yum模块当中name是不能定义为空的。如果我们给变量赋值:--- - name: when test hosts: servera remote_user: root vars: my_server: httpd tasks: - name: "ensure {{ my_server }} is installed" yum: name: "{{ my_server }}" state: latest when: my_server is defined # 这里指定my_server为httpd测试执行:[student@servera ~]$ ansible-playbook test.yml PLAY [when test] ************************************************************************ TASK [Gathering Facts] ****************************************************************** ok: [servera] TASK [ensure httpd is installed] ******************************************************** changed: [servera] PLAY RECAP ****************************************************************************** servera : ok=2 changed=1 unreachable=0 failed=0 # 执行测试成功如果这样编写playbook:--- - name: when test hosts: servera remote_user: root vars: my_server: tasks: - name: "ensure httpd is installed" yum: name: httpd state: latest when: my_server is defined 这里的条件是如果my_server变量为被定义则执行安装httpd的任务。在条件语句中只要满足when的条件就执行任务。然后也添加了vars,这样就相当于定义了my_server,只不过此时my_server的值为空,此时仍可以安装httpd服务即使my_server的值为空,因为空值也是有定义。[student@servera ~]$ ansible-playbook -i hosts test.yml PLAY [when test] ****************************************************************************** TASK [Gathering Facts] ************************************************************************* ok: [servera] TASK [ensure httpd is installed] *************************************************************** changed: [servera] PLAY RECAP *********************************************************************************** servera : ok=2 changed=1 unreachable=0 failed=0 2. 由此可以得知,when的条件语句有两种写法:将变量作为条件任务的触发器,使用True/False控制条件的触发。在playbook中定义变量并直接作为需要实施的任务,通过控制变量是否被定义(my_server is defined/my_server is not defined)来控制条件的触发。下表显示了在处理条件时可使用的一些运算:3. 示例条件语法比较难理解应该是最后的那个语法,可参考以下剧本的演示来进行理解。ansible_distribution in supported_distros类型的例子:--- - name: when test hosts: servera remote_user: root vars: opreate_system: - x86_64 - x86_32 tasks: - name: httpd installed yum: name: httpd state: present when: ansible_facts['architecture'] in opreate_system 这里的条件语句意思是,如果ansible_facts中的ansible_architecture的值能在opreate_system变量中找到符合的值,则安装httpd服务,opreate_system是自己指定的变量测试执行:[student@servera ~]$ ansible-playbook -i hosts test.yml PLAY [when test] ************************************************************************ TASK [Gathering Facts] ****************************************************************** ok: [servera] TASK [httpd installed] ****************************************************************** changed: [servera] PLAY RECAP ****************************************************************************** servera : ok=2 changed=1 unreachable=0 failed=0 注意when语句的缩进。由于when语句不是模块变量,它必须通过缩进到任务的最高级别,放置在模块的外面。任务是YAML散列/字典,when语句只是任务中的又一个键,就如任务的名称以及它所使用的模块一样。通常的惯例是将可能存在的任何when关键字放在任务名称和模块(及模块参数)的后面。总结在一些复杂的调用,需要使用到条件任务来执行剧本任务。条件任务需要判断条件为真才执行。熟悉条件判断的各种语法。注意when语句的语法编写。
0
0
0
浏览量1091
秋月无边

五、从命令行管理文件

5.1 文件系统目录结构文件和目录被组织成一个单根倒置树结构文件系统从根目录下开始,用“/”表示根文件系统(rootfs):root filesystem标准Linux文件系统(如:ext4),文件名称大小写敏感,例如:MAIL, Mail, mail, mAiL以 . 开头的文件为隐藏文件路径分隔的 /文件名最长255个字节包括路径在内文件名称最长4095个字节蓝色–>目录 绿色–>可执行文件 红色–>压缩文件 浅蓝色–>链接文件 灰色–>其他文件除了斜杠和NULL,所有字符都有效.但使用特殊字符的目录名和文件不推荐使用,有些字符需要用引号来引用每个文件都有两类相关数据:元数据:metadata,即属性, 数据:data,即文件内容Linux的文件系统分层结构:FHS Filesystem Hierarchy Standard/boot:引导文件存放目录,内核文件(vmlinuz)、引导加载器(bootloader, grub)都存放于此目录/bin:所有用户使用的基本命令;不能关联至独立分区,OS启动即会用到的程序/sbin:管理类的基本命令;不能关联至独立分区,OS启动即会用到的程序/lib:启动时程序依赖的基本共享库文件以及内核模块文件(/lib/modules)/lib64:专用于x86_64系统上的辅助共享库文件存放位置/etc:配置文件目录/home/USERNAME:普通用户家目录/root:管理员的家目录/media:便携式移动设备挂载点/mnt:临时文件系统挂载点/dev:设备文件及特殊文件存储位置 b: block device,随机访问 c: character device,线性访问/opt:第三方应用程序的安装位置/srv:系统上运行的服务用到的数据/tmp:临时文件存储位置/usr: universal shared, read-only data bin: 保证系统拥有完整功能而提供的应用程序 sbin: lib:32位使用 lib64:只存在64位系统 include: C程序的头文件(header files) share:结构化独立的数据,例如doc, man等 local:第三方应用程序的安装位置 bin, sbin, lib, lib64, etc, share/var: variable data files cache: 应用程序缓存数据目录 lib: 应用程序状态信息数据 local:专用于为/usr/local下的应用程序存储可变数据 lock: 锁文件 log: 日志目录及文件 opt: 专用于为/opt下的应用程序存储可变数据 run: 运行中的进程相关数据,通常用于存储进程pid文件 spool: 应用程序数据池 tmp: 保存系统两次重启之间产生的临时数据/proc: 用于输出内核与进程信息相关的虚拟文件系统/sys:用于输出当前系统上硬件设备相关信息虚拟文件系统/selinux: security enhanced Linux,selinux相关的安全策略等信息的存储位置范例:[root@servera ~]# ls /bin /sbin /lib /lib64 -ld lrwxrwxrwx. 1 root root 7 Aug 12 2018 /bin -> usr/bin lrwxrwxrwx. 1 root root 7 Aug 12 2018 /lib -> usr/lib lrwxrwxrwx. 1 root root 9 Aug 12 2018 /lib64 -> usr/lib64 lrwxrwxrwx. 1 root root 8 Aug 12 2018 /sbin -> usr/sbin [root@centos6 ~]#ls /bin /sbin /lib /lib64 -ld dr-xr-xr-x. 2 root root 4096 Mar 20 09:14 /bin dr-xr-xr-x. 11 root root 4096 Dec 12 2018 /lib dr-xr-xr-x. 9 root root 12288 Mar 20 09:13 /lib64 dr-xr-xr-x. 2 root root 12288 Mar 20 09:14 /sbin5.2 Linux下的文件类型- 普通文件d 目录文件l 符号链接文件linkb 块设备blockc 字符设备characterp 管道文件pipes 套接字文件socket范例:[root@servera ~]# ls -l /run5.3 文件操作命令5.3.1 显示当前工作目录每个shell和系统进程都有一个当前的工作目录 CWD:current work directory显示当前shell CWD的绝对路径pwd命令: printing working directory范例:[root@servera ~]# ll /bin lrwxrwxrwx. 1 root root 7 Aug 12 2018 /bin -> usr/bin [root@servera ~]# cd /bin/ [root@servera bin]# pwd /bin [root@servera bin]# pwd -P /usr/bin5.3.2 绝对和相对路径绝对路径以正斜杠/ 即根目录开始完整的文件的位置路径可用于任何想指定一个文件名的时候[root@servera tmp]# cat /etc/sysconfig/network-scripts/ifcfg-ens160相对路径不以斜线开始一般情况下,是指相对于当前工作目录的路径,特殊场景下,是相对于某目录的位置可以作为一个简短的形式指定一个文件名~当前用户的家目录- 上一个工作目录~student 该用户的家目录. 代表当前路径… 上一级目录[root@servera test2]# pwd /tmp/test/test2 [root@servera test2]# cd ../../ [root@servera tmp]#基名:basename,只取文件名而不要路径目录名:dirname,只取路径,不要文件名范例:[root@centos8 bin]#basename /etc/sysconfig/network network [root@centos8 bin]#dirname /etc/sysconfig/network /etc/sysconfig [root@centos8 ~]#dirname /etc/sysconfig/network-scripts/ifcfg-eth0 /etc/sysconfig/network-scripts [root@centos8 ~]#basename /etc/sysconfig/network-scripts/ifcfg-eth0 ifcfg-eth05.3.3 更改目录命令 cd : change directory 改变目录可以使用绝对或相对路径切换至父目录: cd …切换至当前用户主目录: cd切换至上一个的工作目录: cd -范例:[root@centos8 ~]#cd /etc/sysconfig[root@centos8 sysconfig]#pwd/etc/sysconfig[root@centos8 sysconfig]#cd ../../data[root@centos8 data]#pwd/data[root@centos8 data]#cd /bin[root@centos8 bin]#pwd/bin[root@centos8 bin]#cd -P /bin[root@centos8 bin]#pwd/usr/bin5.3.4 列出目录内容ls 命令可以列出当前目录的内容或指定目录用法:ls [options] [files_or_dirs]常见选项:-a 包含隐藏文件-h 以人类易读的方式显示free -h-l 显示额外的信息-R 目录递归-ld 目录和符号链接信息-1 文件分行显示-S 按从大到小排序-t 按mtime排序-u 配合-t选项,显示并按atime从新到旧排序-U 按目录存放顺序显示-X 按文件后缀排序5.3.5 文件通配符模式文件通配符可以用来匹配符合条件的多个文件,方便批量管理文件通配符采有特定的符号,表示特定的含义,此特符号称为元 meta 字符常见的通配符如下:* 匹配零个或多个字符,但不匹配 "." 开头的文件,即隐藏文件? 匹配任何单个字符~ 当前用户家目录~mage 用户mage家目录~+和. 当前工作目录~- 前一个工作目录[0-9] 匹配数字范围[a-z] 字母[A-Z] 字母[hao] 匹配列表中的任何的一个字符[^hao] 匹配列表中的所有字符以外的字符别外还有在Linux系统中预定义的字符类:man 7 glob[:digit:]:任意数字,相当于0-9[:lower:]:任意小写字母,表示 a-z[:upper:]: 任意大写字母,表示 A-Z[:alpha:]: 任意大小写字母[:alnum:]:任意数字或字母[:blank:]:水平空白字符[:space:]:水平或垂直空白字符[:punct:]:标点符号[:print:]:可打印字符[:cntrl:]:控制(非打印)字符[:graph:]:图形字符[:xdigit:]:十六进制字符范例: [ ] 和 { }[root@servera tmp]# ll f{1..5} ls: cannot access 'f1': No such file or directory ls: cannot access 'f2': No such file or directory -rw-r--r--. 1 root root 0 Mar 25 15:48 f3 -rw-r--r--. 1 root root 0 Mar 25 15:48 f4 -rw-r--r--. 1 root root 0 Mar 25 15:48 f5 [root@servera tmp]# ll f[1-5] -rw-r--r--. 1 root root 0 Mar 25 15:48 f3 -rw-r--r--. 1 root root 0 Mar 25 15:48 f4 -rw-r--r--. 1 root root 0 Mar 25 15:48 f5 [root@servera tmp]# ll f[a-c] -rw-r--r--. 1 root root 0 Mar 25 15:51 fa -rw-r--r--. 1 root root 0 Mar 25 15:51 fA -rw-r--r--. 1 root root 0 Mar 25 15:51 fb -rw-r--r--. 1 root root 0 Mar 25 15:51 fB -rw-r--r--. 1 root root 0 Mar 25 15:51 fc [root@servera tmp]# ll f{a..c} -rw-r--r--. 1 root root 0 Mar 25 15:51 fa -rw-r--r--. 1 root root 0 Mar 25 15:51 fb -rw-r--r--. 1 root root 0 Mar 25 15:51 fc5.3.6 查看文件状态 stat文件相关信息:metadata, data每个文件有三个时间戳:access time 访问时间,atime,读取文件内容modify time 修改时间,mtime,改变文件内容(数据)change time 改变时间,ctime,元数据发生改变5.3.7 复制文件和目录利用 cp(copy)命令可以实现文件或目录的复制格式:cp [OPTION]... SOURCE... DIRECTORY-a 归档,相当于-dR --preserv=all,常用于备份功能-r, -R 递归复制目录及内部的所有内容范例:[root@servera tmp]# cp /etc/passwd . [root@servera tmp]# ls passwd [root@servera tmp]# cp -a /etc/ . [root@servera tmp]# ls etc5.3.8 移动以及重命名文件mv (move)命令可以实现文件或目录的移动和改名同一分区移动数据,速度很快:数据位置没有变化不同分区移动数据,速度相对慢:数据位置发生了变化格式:mv [OPTION]... SOURCE... DIRECTORY常用选项:-i 交互式-f 强制-b 目标存在,覆盖前先备份后面跟的是源文件和目标路径,意思是要把文件移动到哪个目录下面,如果目标路径不存在那就是重命名范例:[root@servera tmp]# ls passwd [root@servera tmp]# mkdir ./test [root@servera tmp]# mv passwd ./test/;ls /tmp /tmp/test /tmp: test /tmp/test: passwd [root@servera tmp]# mv test/passwd ./pass;ls /tmp/ /tmp/test/ /tmp/: pass test /tmp/test/:5.3.9 删除文件使用 rm (remove)命令可以删除文件注意:此命令非常危险,慎重使用,建议使用mv 代替 rm格式:rm [OPTION]... FILE...常用选项:-i 交互式-f 强制删除-r 递归范例:[root@servera tmp]# ls pass test [root@servera tmp]# rm pass rm: remove regular file 'pass'? y [root@servera tmp]# ls test [root@servera tmp]# ls passwd test [root@servera tmp]# rm -f passwd [root@servera tmp]# ls test [root@servera tmp]# rm -f test/ rm: cannot remove 'test/': Is a directory [root@servera tmp]# rm -rf test/ [root@servera tmp]# ls [root@servera tmp]# 5.3.10 目录操作5.3.10.1 显示目录树 tree常见选项:-d:只显示目录 -L level:指定显示的层级数目5.3.10.2 创建目录mkdir常见选项:-p:存在于不报错,且可自动创建所需的各目录-v:显示详细信息-m MODE:创建目录时直接指定权限5.3.10.3 删除空目录rmdir常见选项:-p 递归删除空父目录-v 显示详细信息注意:rmdir只能删除空目录,如果想删除非空目录,可以使用rm -r 命令,递归删除目录树5.4 文件元数据和节点表结构inode表结构:每个文件的属性信息,比如:文件的大小,时间,类型等,称为文件的元数据(meta data)。这此元数据是存放在node(index node)表中。node 表中有很多条记录组成,第一条记录对应的存放了一个文件的元数据信息第一个node表记录对应的保存了以下信息:inode number 节点号文件类型权限UIDGID链接数(指向这个文件名路径名称个数)该文件的大小和不同的时间戳指向磁盘上文件的数据块指针有关文件的其他数据5.4.1 文件访问原理cp和inodecp 命令:分配一个空闲的inode号,在inode表中生成新条目在目录中创建一个目录项,将名称与inode编号关联拷贝数据生成新的文件rm和inoderm 命令:链接数递减,从而释放的inode号可以被重用把数据块放在空闲列表中删除目录项数据实际上不会马上被删除,但当另一个文件使用数据块时将被覆盖mv和inode如果mv命令的目标和源在相同的文件系统,作为mv 命令​用新的文件名创建对应新的目录项删除旧目录条目对应的旧的文件名不影响inode表(除时间戳)或磁盘上的数据位置:没有数据被移动!如果目标和源在一个不同的文件系统, mv相当于cp和rm5.4.2 硬(hard)链接硬链接本质上就给一个文件起一个新的名称,实质是同一个文件硬链接特性创建硬链接会在对应的目录中增加额外的记录项以引用文件对应于同一文件系统上一个物理文件每个目录引用相同的inode号创建时链接数递增删除文件时:rm命令递减计数的链接,文件要存在,至少有一个链接数,当链接数为零时,该文件被删除不能跨越驱动器或分区不支持对目录创建硬链接格式:ln filename [linkname]范例:[root@servera tmp]# ll total 4 -rw-r--r--. 1 root root 2723 Mar 25 17:12 passwd [root@servera tmp]# ln passwd passwd1 [root@servera tmp]# ll total 8 -rw-r--r--. 2 root root 2723 Mar 25 17:12 passwd -rw-r--r--. 2 root root 2723 Mar 25 17:12 passwd15.4.3 符号 ( symbolic ) 或 软 (soft)链接一个符号链接指向另一个文件,就像 windows 中快捷方式,软链接文件和原文件本质上不是同一个文件软链接特点一个符号链接的内容是它引用文件的名称可以对目录创建软链接可以跨分区的文件实现指向的是另一个文件的路径;其大小为指向的路径字符串的长度;不增加或减少目标文件inode的引用计数在创建软链接时, 如果源文件使用相对路径,是相对于软链接文件的路径,而非相对于当前工作目录,但是软链接的路径如果是相对路径,则是相对于当前工作目录格式:ln -s filename [linkname]范例:#绝对路径 ln -s /data/dir /data/dirlink #相对路径 cd /data ln -s ../data/dir /root/dirlink rm -rf /data/dirlink #删除软链接本身,不会删除源目录内容 rm -rf /data/dirlink/ #删除源目录的文件,不会删除链接文件 #查看链接文件指向的原文件 readlink /data/dirlink5.4.4 硬链接与软链接区别总结1.本质硬链接:本质是同一个文件起了多个名字软链接:本质不是同一个文件2.跨设备硬链接:不支持软链接:支持3.inode硬链接:相同软链接:不同4.链接数硬链接:创建新的硬链接,链接数会增加,删除硬链接,链接数减少软链接:创建或删除,链接数不会变化5.文件夹硬链接:不支持软链接:支持6.相对路径硬链接:原始文件相对路径是相对于当前工作目录软链接:原始文件的相对路径是相对于链接文件的相对路径7.删除源文件硬链接:只是链接数减一,但链接文件的访问不受影响软链接:链接文件将无法访问8.文件类型硬链接:和源文件相同软链接:链接文件和源文件无关
0
0
0
浏览量864
秋月无边

弄个linux系统计划任务让你感受一下删库跑路

20.1 一次性任务at工具由包 at 提供依赖与atd服务,需要启动才能实现at任务at队列存放在/var/spool/at目录中执行任务时PATH变量的值和当前定义任务的用户身份一致at 命令:at [option] TIME常用选项:-V 显示版本信息 -t time 时间格式 [[CC]YY]MMDDhhmm[.ss] -l 列出指定队列中等待运行的作业;相当于atq -d N 删除指定的N号作业;相当于atrm -c N 查看具体作业N号任务 -f file 指定的文件中读取任务 -m 当任务被完成之后,将给用户发送邮件,即使没有标准输出注意:作业执行命令的结果中的标准输出和错误以执行任务的用户身份发邮件通知给 root默认RHEL 8 最小化安装没有安装邮件服务,需要自行安装范例:[root@servera ~]# yum -y install postfix [root@servera ~]# systemctl enable --now postfix.service [root@servera ~]# yum -y install mailxTIME:定义出什么时候进行 at 这项任务的时间HH:MM [YYYY-mm-dd] noon, midnight, teatime(4pm) tomorrow now+#{minutes,hours,days, OR weeks}范例:at 时间格式HH:MM 在今日的 HH:MM 进行,若该时刻已过,则明天此时执行任务 02:00 HH:MM YYYY-MM-DD 规定在某年某月的某一天的特殊时刻进行该项任务 02:00 2016-09-20 HH:MM[am|pm] [Month] [Date] 06pm March 17 17:20 tomorrow HH:MM[am|pm] + number [minutes|hours|days|weeks], 在某个时间点再加几个时间后才进行该 项任务 now + 5 min 02pm + 3 daysat 任务执行方式:交互式输入重定向at -f file/etc/at.{allow,deny} 控制用户是否能执行at任务白名单:/etc/at.allow 默认不存在,只有该文件中的用户才能执行at命令黑名单:/etc/at.deny 默认存在,拒绝该文件中用户执行at命令,而没有在at.deny 文件中的使用者则可执行如果两个文件都不存在,只有 root 可以执行 at 命令范例:rhel中 at任务的存放路径[root@serverb at]# cd /var/spool/at/spool/at20.2 周期性计划任务 cron周期性任务计划cron相关的程序包:cronie:主程序包,提供crond守护进程及相关辅助工具crontabs:包含CentOS提供系统维护任务cronie-anacron:cronie的补充程序,用于监控cronie任务执行状况,如:cronie中的任务在过去该运行的时间点未能正常运行,则anacron会随后启动一次此任务cron 依赖于crond服务,确保crond守护处于运行状态:#rhel 7 以后的版本: systemctl status crondcron任务分为:系统cron任务:系统维护作业,/etc/crontab 主配置文件, /etc/cron.d/ 子配置文件用户cron任务:保存在 /var/spool/cron/USERNAME,利用 crontab 命令管理计划任务日志:/var/log/cron20.2.1 系统cron计划任务/etc/crontab 格式说明,详情参见 man 5 crontab注释行以 # 开头[root@servera ~]#cat /etc/crontab 计划任务时间表示法: 范例: crond任务相关文件: SHELL=/bin/bash #默认的SHELL类型 PATH=/sbin:/bin:/usr/sbin:/usr/bin #默认的PATH变量值,可修改为其它路径 MAILTO=root #默认标准输出和错误发邮件给root,可以指向其它用户 # For details see man 4 crontabs # Example of job definition: # .---------------- minute (0 - 59) # | .------------- hour (0 - 23) # | | .---------- day of month (1 - 31) # | | | .------- month (1 - 12) OR jan,feb,mar,apr ... # | | | | .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat # | | | | | # * * * * * user-name command to be executed计划任务时间表示法:(1) 特定值 给定时间点有效取值范围内的值 (2) * 给定时间点上有效取值范围内的所有值 表示“每...” (3) 离散取值 #,#,# (4) 连续取值 #-# (5) 在指定时间范围上,定义步长 /#: #即为步长 (6) 特定关健字 @yearly 0 0 1 1 * @annually 0 0 1 1 * @monthly 0 0 1 * * @weekly 0 0 * * 0 @daily 0 0 * * * @hourly 0 * * * * @reboot Run once after reboot范例:#晚上9点10分运行echo命令 10 21 * * * root /bin/echo "Howdy!" #每3小时echo和wall命令 0 */3 * * * root /bin/echo “howdy”; wall “welcome to servera!”crond任务相关文件:/etc/crontab 配置文件 /etc/cron.d/ 配置文件 /etc/cron.hourly/ 脚本 /etc/cron.daily/ 脚本 /etc/cron.weekly/ 脚本 /etc/cron.monthly/ 脚本注意:这些路径,往往最容易被忽略,就让“病毒”有了可乘之机。所以排查记得查上述的路径文件。20.2.2 用户计划任务crontab命令:每个用户都有专用的cron任务文件:/var/spool/cron/USERNAME默认标准输出和错误会被发邮件给对应的用户,如:user创建的任务就发送至user的邮箱root能够修改其它用户的作业用户的cron 中默认 PATH=/usr/bin:/bin,如果使用其它路径,在任务文件的第一行加PATH=/path或者加入到计划任务执行的脚本中crontab命令格式:crontab [-u user] [-l | -r | -e] [-i]常用选项:-l 列出所有任务 -e 编辑任务 -r 移除所有任务 -i 同-r一同使用,以交互式模式移除指定任务 -u user 仅root可运行,指定用户管理cron任务控制用户执行计划任务:/etc/cron.{allow,deny}范例:每个月日期和星期几字段的关系[root@servera ~]#man 5 crontab Note: The day of a command's execution can be specified in the following two fields — 'day of month', and 'day of week'. If both fields are restricted (i.e., do not contain the "*" character), the command will be run when either field matches the current time. For example, "30 4 1,15 * 5" would cause a command to be run at 4:30 am on the 1st and 15th of each month, plus every Friday.范例:修改默认的cron的文本编辑工具[root@servera ~]# export EDITOR=vim [root@servera ~]# vim /etc/profile.d/env.sh export EDITOR=vim范例:PATH变量#方法1,在计划任务配置中指定PATH [root@servera ~]#crontab -l PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin * * * * * useradd hehe;echo $PATH #方法2,在脚本中指定PATH变量 [root@servera ~]#crontab -l * * * * * /data/test.sh [root@servera ~]#cat /data/test.sh #!/bin/bash PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin useradd hehe echo $PATH注意:运行结果的标准输出和错误以邮件通知给相关用户(1) COMMAND > /dev/null(2) COMMAND &> /dev/nullcron任务中不建议使用%,它有特殊用途,它表示换行的特殊意义,且第一个%后的所有字符串会被将成当作命令的标准输入如果在命令中要使用%,则需要用 \ 转义注意:将%放置于单引号中是不支持的范例:30 2 * * * /bin/cp -a /etc/ /data/etc`date +\%F_\%T` 30 2 * * * /bin/cp -a /etc/ /data/etc`date +‘%F_%T’` 有问题11月每天的6-12点之间每隔2小时执行/app/bin/test.sh[root@centos8 ~]#crontab -l 0 6-12/2 * 11 * /app/bin/test.sh
0
0
0
浏览量2009
秋月无边

Ansible Facts要这样玩才让人心服

📜1. 前言描述在Ansible执行时,默认总有一个任务会先运行,那就是Gathering Fact:TASK [Gathering Facts] **************************************** ok: [192.168.xxx.xxx]从输出内容来看,这是执行了一个名为Gathering Facts的TASK,但其实我们并没有在命令中或者剧本中定义这个任务,这个是Ansible设计的初衷,默认情况自动执行。📜2. Ansible Facts简介Ansible Facts(事实)是Ansible在受管主机上自动检测到的变量。而Facts组件是Ansible用于采集被管理机器设备信息的一个功能,采集的机器设备信息主要包含IP地址,操作系统,以太网设备,mac 地址,时间/日期相关数据,硬件信息等。那么,采集这些信息有什么用呢?有的时候我们需要根据远程主机的信息作为执行条件操作,例如,根据远程服务器使用的操作系统版本,可以安装不同版本的软件包;或者也可以显示与每台远程计算机相关的一些信息,例如每台设备上有多少RAM可用。所以在一些业务场景中, Ansible Facts对我们使用是很有帮助的,直接调用以大大提高了工作效率。📜3. Ansible facts示例可以使用setup模块获取被管理机器的所有facts信息,可以使用filter来查看指定的信息。setup模块获取的整个facts信息被包装在一个JSON格式的数据结构中,ansible_facts是最外层的值。我们可以通过以下Ansible Ad-Hoc命令查看facts信息:[root@servera ~]# ansible localhost -m setup localhost | SUCCESS => { "ansible_facts": { "ansible_all_ipv4_addresses": [ "192.168.159.111" ], "ansible_all_ipv6_addresses": [ "fe80::2a9:fbb5:c93:84f8" ], "ansible_apparmor": { "status": "disabled" }, "ansible_architecture": "x86_64", "ansible_bios_date": "07/29/2019", "ansible_bios_version": "6.00", "ansible_cmdline": { ............📜4. 过滤Facts变量收集到的事实太多而不方便查找的时候,我们可以进行过滤刷选想要的信息:ansible localhost -m setup -a 'filter=ansible_fqdn'📜5. 新旧语法对比前面也提及到,Ansible Facts是Ansible在受管主机上自动检测到的变量,所以当需要调用这些变量的值,就涉及到如何书写的问题,在2.5版本前,是以下表旧的形式来进行调用,虽然官方建议使用新的形式进行编写,但其实两种形式写法都可以(官方未提及是否颓弃旧的写法)。如果变量的值为散列/字典,则可使用两种语法来检索该值。从上表中举两个例子:ansible_facts['default_ipv4']['address'] 可以写成 ansible_facts.default_ipv4.address ansible_facts['dns']['nameservers'] 可以写成 ansible_facts.dns.nameservers📜6. 关闭Facts收集收集托管主机上的 Facts 比较耗费时间,所以可以在不需要的时候关闭 setup 模块。关闭facts收集以后,playbook启动的时间会变快- hosts: dev gather_facts: no tasks: - debug: msg: "closeed facts"📜7. 魔法变量有些特殊变量,名为:魔法变量(magic variables)官网地址:https://docs.ansible.com/ansible/latest/user_guide/playbooks_vars_facts.html#information-about-ansible-magic-variables常见魔法变量:hostvars包含受管主机的变量,可以用于获取某台受管主机的变量的值。如果有一台web服务器的配置文件中需要指定db服务器的ip地址,我们假定这台db服务器的hostname为 db.example.com ,ip地址绑定在eth0网卡上,我们可以通过如下方法在web服务器上调用db服务器的ip地址:{{ hostvars['db.example.com'].ansible_eth0.ipv4.address }}group_names列出当前受管主机所属的所有组 (用于标识当前正在执行task的目标主机位于的组) 。groups列出清单中的所有组和主机。inventory_hostname列出inventory主机清单文件中的主机名称。其余魔法变量:一眼看上去,完全不明所以,还是通过练习来辅助理解才行:[student@servera example]$ cat hosts servera serverb serverc serverd [dev] serverb [test] serverc [pro] serverd [student@servera example]$ cat ansible.cfg [defaults] inventory = hosts[student@servera example]$ cat magic.yml --- - name: magic vars hosts: serverc gather_facts: no tasks: - name: show magic fact inventory_hostname debug: var: inventory_hostname # 调用魔法变量inventory_hostname,演示主机清单文件中的主机名称。 - name: show magic fact groups debug: # var: groups.test var: groups.dev # 调用魔法变量groups,此处还为散列字典,对应清单中所属的主机组。 - name: show magic fact group_names debug: var: group_names # 调用魔法变量group_names,列出当前受管主机所属的所有组 。 - name: show magic fact hostvars debug: var: hostvars.serverb.ansible_forks # 调用魔法变量hostvars,也为散列字典,需要编写对应主机的相关变量信息。[student@servera example]$ ansible-playbook magic.yml PLAY [magic vars] *********************************************************************** TASK [show magic fact inventory_hostname] *********************************************** ok: [serverc] => { "inventory_hostname": "serverc" } TASK [show magic fact groups] *********************************************************** ok: [serverc] => { "groups.dev": [ "serverb" ] } TASK [show magic fact group_names] ****************************************************** ok: [serverc] => { "group_names": [ "test" ] } TASK [show magic fact hostvars] ********************************************************* ok: [serverc] => { "hostvars.serverb.ansible_forks": "5" } PLAY RECAP ***************************************************************************************** serverc : ok=4 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0通过上面输出应该比较清晰的了解到魔法变量究竟是怎样的,在日后的使用中,若忘记,也可以直接编写debug模块来进行测试输出。有时候学习需要运用各种方式来辅助自己。💡总结理解Ansible Facts的概念和使用场景。常运用filter选项进行Facts输出的刷选。新旧语法的对比与运用。不需要收集事实时,进行关闭。特殊变量:魔法变量。理解和运用常用的魔法变量。RHCE认证作为基础认证的升级,需要大家在RHCSA的基础上再进行学习,因此,涉及的基础内容需要大家好好进行学习并巩固。有良好的基础才能更上一层楼。好好加油,可以噶🤪。
0
0
0
浏览量1311
秋月无边

实施Ansible处理程序让任务运行更丝滑

本章节则介绍毕竟特别的东西:处理程序。为了运行任务更“丝滑”来达到需求。1. Ansible处理程序Ansible模块设计为具有幂等性。这表示,在正确编写的playbook中,playbook及其任务可以运行多次而不会改变受管主机,除非需要进行更改使受管主机进入所需的状态。但有时候,在任务确实更改系统时,可能需要运行进一步的任务。例如,更改服务配置文件时可能要求重新加载该服务以便使其更改的配置生效。处理程序是响应由其他任务触发的通知的任务。仅当任务在受管主机上更改了某些内容时,任务才通知其处理程序。每个处理程序具有全局唯一的名称,在playbook中任务块的末尾触发。如果没有任务通过名称通知处理程序,处理程序就不会运行。如果一个或多个任务通知处理程序,处理程序就会在play中的所有其他任务完成后运行一次。因为处理程序就是任务,所以可以在处理程序中使用他们将用于任何其他任务的模块。通常而言,处理程序被用于重新引导主机和重启服务。处理程序可视为非活动任务,只有在使用notify语句显式调用时才会被触发。在下列代码片段中,只有配置文件更新并且通知了该任务,restart apache处理程序才会重启Apache服务器:--- - name: handlers hosts: servera remote_user: root tasks: - name: httpd installed yum: name: httpd state: present - name: provides configure template: src: files/httpd.conf dest: /etc/httpd/conf/httpd.conf notify: # notify语句指出该任务需要触发一个处理程序 - restarted apache # 要运行的处理程序的名称(这里写的必须与下面handlers中- name:选项后的要一样) - name: start service service: name: httpd state: started handlers: # handlers关键字表示处理程序任务列表的开头 - name: restarted apache # 被任务调用的处理程序的名称 service: # 用于该处理程序的模块 name: httpd state: restarted 注意:handlers的缩进应该与tasks对齐. 演示明确主机清单与配置文件(实验一直使用,怕你们忘记,回顾一下。)[student@servera example]$ cat hosts servera serverb serverc serverd [dev] serverb [test] serverc [pro] serverd [student@servera example]$ cat ansible.cfg [defaults] inventory = hosts [privilege_escalation] become=True become_method=sudo become_user=root become_ask_pass=False 编写有处理程序的剧本[student@servera example]$ cat handler.yml --- - name: handlers hosts: servera tasks: - name: install httpd yum: name: httpd state: latest changed_when: yes notify: - abc - name: provides html copy: content: " test a page.\n" dest: /var/www/html/index.html notify: - xxx - name: start service service: name: httpd state: started handlers: - name: xxx service: name: httpd state: restarted - name: abc debug: msg: test 执行剧本以观察输出[student@servera example]$ ansible-playbook handler.yml PLAY [handlers] ************************************************************************ TASK [Gathering Facts] ***************************************************************** ok: [servera] TASK [install httpd] ******************************************************************* changed: [servera] TASK [provides html] ******************************************************************* changed: [servera] TASK [start service] ******************************************************************* ok: [servera] RUNNING HANDLER [xxx] ****************************************************************** changed: [servera] RUNNING HANDLER [abc] ****************************************************************** ok: [servera] => { "msg": "test" } PLAY RECAP ***************************************************************************** servera: ok=6 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 从上可知,就算abc处理程序先被notify,但处理程序还是按handlers部分指定的顺序运行。等所有的任务执行完,最后才执行处理程序。3. 处理程序重要事项1.处理程序始终按照play的handlers部分指定的顺序运行,它们不按在任务中由notify语句列出的顺序运行,或按任务通知它们的顺序运行2.处理程序通常在相关play中的所有其他任务完成后运行,playbook的tasks部分中某一任务调用的处理程序,将等到tasks下的所有任务都已处理后才会运行3.处理程序名称存在于各play命名空间中,如果两个处理程序被错误地给予相同的名称,则仅会运行第一个4.即使有多个任务通知处理程序,该处理程序依然仅运行一次,如果没有任务通知处理程序,它就不会运行5.如果包含notify语句的任务没有报告changed结果(例如,软件包已安装并且任务报告ok),则处理程序不会获得通知,处理程序将被跳过,直到有其他任务通知它。只有相关任务报告了changed状态,Ansible才会通知处理程序重要:处理程序用于在任务对受管主机进行更改时执行额外操作,它们不应用作正常任务的替代总结使用 and 和 or 进行多条件判断的编写。可使用括号进行多条件的组合编写。循环语句可与多条件判断组合使用,注册变量和条件判断语句也可组合使用。注意when语句的语法编写。
0
0
0
浏览量1970
秋月无边

介绍Ansible

第一章 介绍Ansible1.1 一切皆自动化“运维的未来是,让研发人员能够借助工具、自动化和流程,并且让他们能够在运维干预极少的情况下部署和运营服务,从而实现自助服务。每个角色都应该努力使工作实现自动化。”——《运维的未来》1.2 前言公司的服务器越来越多, 维护一些简单的事情都会变得很繁琐。用shell脚本来管理少量服务器效率还行, 服务器多了之后, shell脚本无法实现高效率运维。这种情况下,我们需要引入自动化运维工具, 对多台服务器实现高效运维。场景:假设我要去1000台服务上做一个操作(如nginx服务器修改配置文件里的某一个参数), 下面两种方法缺点明显:1.传统的方法, 手工去装:ssh到每台服务器上去手动操作。缺点:效率太低。容器出错。2.写个shell脚本来做。缺点:   管理的机器平台不一致,脚本可能不具备通用性。    传密码麻烦(在非免密登录的环境下, 需要expect来传密码)    效率较低,循环1000次也需要一个一个的完成,如果用&符放到后台执行,则会产生1000个进程。如果出了错误,需要自己手工去收集信息然后解决,脚本更新了以后又要重新下载一遍去执行,不方便而且效率低。有没有一种工具,能把任务批量给主机去执行,然后还能收集执行过程中的具体信息?1.3 常见的开源自动化运维工具比较1.ansible基于python语言,Agentless,中小型应用环境。简单快捷,被管理端不需要启服务。直接走ssh协议,需要验证所以机器多的话速度会较慢。2.puppet基于ruby语言,功能强大,成熟稳定,配置复杂、重型,适合于大型架构。3.saltstack基于python语言,一般需部署agent,执行效率更高;相对简单,大并发能力比ansible要好, 需要维护被管理端的服务。如果服务断开,连接就会出问题。4.Fabric:python,agentless。5.Chef:ruby,国内应用少。同类自动化工具GitHub关注程度(2016-07-10)ansible集合了众多运维工具(puppet、cfengine、chef、func、fabric)的优点,实现了批量系统配置、批量程序部署、批量运行命令等功能。1.4 自动化运维应用场景文件传输应用部署配置管理任务流编排自动化运维: 将日常IT运维中大量的重复性工作,小到简单的日常检查、配置变更和软件安装,大到整个变更流程的组织调度,由过去的手工执行转为自动化操作,从而减少乃至消除运维中的延迟,实现“零延时”的IT运维。1.5 Ansible发展史作者:Michael DeHaan,也是Cobbler 与 Func 的开发者。ansible 的名称来自科幻小说《安德的游戏》中跨越时空的即时通信工具,使用它可以在相距数光年的距离,远程实时控制前线的舰队战斗。2012-03-09,发布0.0.1版,2015-10-17,Red Hat 宣布1.5亿美元收购。官网: https://www.ansible.com/官方文档: https://docs.ansible.com/1.6 Ansible 是什么Ansible 简单的说是一个配置管理系统(configuration management system)。你只需要可以使用 ssh 访问你的服务器或设备就行。它也不同于其他工具,因为它使用推送的方式,而不是像 puppet 等 那样使用拉取安装agent的方式。你可以将代码部署到任意数量的服务器上!1.7 Ansible特性模块化:调用特定的模块,完成特定任务有Paramiko,PyYAML,Jinja2(模板语言)三个关键模块支持自定义模块基于Python语言实现部署简单,基于python和SSH(默认已安装),agentless安全,基于OpenSSH支持playbook编排任务幂等性:一个任务执行1遍和执行n遍效果一样,不因重复执行带来意外情况无需代理不依赖PKI(无需ssl)可使用任何编程语言写模块YAML格式,编排任务,支持丰富的数据结构较强大的多层解决方案1.8 Ansible架构Ansible主要组成部分功能说明PLAYBOOKS: 任务剧本(任务集),编排定义Ansible任务集的配置文件,由Ansible顺序依次执行,通常是JSON格式的YML文件。INVENTORY: Ansible管理主机的清单/etc/anaible/hosts 。MODULES: Ansible执行命令的功能模块,多数为内置的核心模块,也可自定义,ansible-doc –l 可查看模块PLUGINS: 模块功能的补充,如连接类型插件、循环插件、变量插件、过滤插件等,该功能不常用。API: 供第三方程序调用的应用程序编程接口。ANSIBLE: 组合INVENTORY、 API、 MODULES、PLUGINS的绿框,可以理解为是ansible命令工具,其为核心执行工具。1.9 安装Ansible现时最新的版本为 4,但若是红帽系列使用者,建议使用 2.9的版本。实验过程此操作在 RHEL 或 CentOS上执行。yum安装ansible需要配置好 epel源 或 可用的 Ansible Engine仓库。# yum install epel-release 可配置国内EPEL源安装ansible# yum -y install ansible确保安装成功并查看版本# ansible --version ansible 2.9.23 config file = /etc/ansible/ansible.cfg configured module search path = [u'/root/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules'] ansible python module location = /usr/lib/python2.7/site-packages/ansible executable location = /usr/bin/ansible python version = 2.7.5 (default, Aug 7 2019, 00:51:29) [GCC 4.8.5 20150623 (Red Hat 4.8.5-39)]注意事项执行ansible的主机一般称为主控端,中控,masteransible2.9主控端Python版本需要2.7或3.5以上ansible2.9被控端Python版本需要2.6或3.5以上被控端Python版本小于2.4需要安装python-simplejson被控端如开启SELinux需要安装libselinux-pythonwindows不能做为主控端官网地址:https://docs.ansible.com/ansible/2.9/installation_guide/intro_installation.html#installing-ansible-on-rhel-centos-or-fedora可查看不同版本的情况和python版本的最低要求,也可查看各平台上的安装方法
0
0
0
浏览量2005
秋月无边

不管鸡肋与否还是要学习linux系统原生的调优模板

📜19.1 调优系统基于多种用例工作负载来调整各种设备设置,以此优化系统系统能。tuned守护进程会利用反映特定工作负载要求的调优配置文件,以静态和动态两种方式应用调优调整。📜19.2 Tuned静态调优tuned守护进程会在服务启动时或选择新的调优配置文件时应用系统设置。静态调优会对配置文件中由tuned在运行时应用的预定义kernel参数进行配置。对于静态调优而言,内核参数是针对整体性能预期而设置的,不会随着活跃度的变化而进行调整动态调优对于动态调优而言,tuned守护进程会监视系统活动,并根据运行时行为的变化来调整设置。从所选调优配置文件中声明的初始设置开始,动态调优会不断进行调优调整以适应当前工作负载🔖19.2.1 安装并启用TUNED默认情况下,RHEL 8 的最小化安装中包含并启用了tuned软件包。要手动安装并启用该软件包。范例[root@servera ~]# yum -y install tuned [root@servera ~]# systemctl enable --now tuned Created symlink /etc/systemd/system/multi-user.target.wants/tuned.service → /usr/lib/systemd/system/tuned.service.🔖19.2.2 从命令行管理配置文件查看调优级配置文件:tuned-adm list范例:[root@servera ~]# tuned-adm list Available profiles: - accelerator-performance - Throughput performance based tuning with disabled higher latency STOP states - balanced - General non-specialized tuned profile - desktop - Optimize for the desktop use-case - hpc-compute - Optimize for HPC compute workloads - intel-sst - Configure for Intel Speed Select Base Frequency - latency-performance - Optimize for deterministic performance at the cost of increased power consumption - network-latency - Optimize for deterministic performance at the cost of increased power consumption, focused on low latency network performance - network-throughput - Optimize for streaming network throughput, generally only necessary on older CPUs or 40G+ networks - powersave - Optimize for low power consumption - throughput-performance - Broadly applicable tuning that provides excellent performance across a variety of common server workloads - virtual-guest - Optimize for running inside a virtual guest - virtual-host - Optimize for running KVM guests Current active profile: virtual-guest查看当前系统正在活动的调优配置文件tuned-adm active范例:[root@servera ~]# tuned-adm active Current active profile: virtual-guest让系统推荐最优配置tuned-adm recommend范例:[root@servera ~]# tuned-adm recommend virtual-guest更改配置文件:可以将活动的配置文件切换为更符合系统当前调优要求的其他配置文件[root@servera ~]# tuned-adm profile balanced [root@servera ~]# tuned-adm active Current active profile: balanced关闭调优活动tuned-adm off📜19.3 影响进程调度🔖19.3.1 进程优先级RHEL 优先级🔖19.3.2 设置和调整进程优先级进程优先级调整静态优先级:100-139进程默认启动时的nice值为0,优先级为120只有根用户才能降低nice值(提高优先性)nice命令以指定的优先级来启动进程nice [OPTION] [COMMAND [ARG]...] -n, --adjustment=N add integer N to the niceness (default 10)renice命令可以调整正在执行中的进程的优先级renice [-n] priority pid...查看:ps axo pid,comm,ni范例:[root@servera ~]#nice -n -10 ping 127.0.0.1 [root@servera ~]#ps axo pid,cmd,nice |grep ping 2118 ping 127.0.0.1 -10 2120 grep --color=auto ping 0 [root@servera ~]# [root@servera ~]#renice -n -20 2118 2106 (process ID) old priority -10, new priority -20 [root@servera ~]#ps axo pid,cmd,nice |grep ping 2118 ping 127.0.0.1 -20 2200 grep --color=auto ping 0top调整优先级可进入监控后输入r指定进程进行renice处理
0
0
0
浏览量2004
秋月无边

这样讲解Ansible(ansible-vault)的加密与解密真6

Ansible是很火的一个自动化部署工具,在ansible控制节点内,存放着当前环境服务的所有服务的配置信息,其中自然也包括一些敏感的信息,例如明文密码、IP地址等等。从安全角度来讲,这些敏感数据的文件不应该以明文的形式存在。Ansible官方已经考虑到了这种情况,当我们的playbook中含有不能明文展示的文本时,ansible通过命令行「ansible-vault」给你目标文件/字符串进行加密。在执行playbook时,通过指定相应参数来给目标文件解密,从而实现ansible vault的功能。ansible可以加密任何部署相关的文件数据,例如:主机/组变量等所有的变量文件tasks、hanlders等所有的playbook文件命令行导入的文件(eg : -e @file.yaml ,-e @file.json)copy,template的模块里src参数所使用的文件,甚至是二进制文件。playbook里用到的某个字符串参数也可以加密(Ansible>=2.3)那究竟应该如何操作呢?先来看看命令上的常规操作:1. 创建加密文件ansible-vault create foo.yml 执行该命令后,交互式输入两次相同的密码,则创建加密文件成功2. 使用密码文件创建ansible-vault create --vault-password-file=vault-pass secret.yml3. 给现有文件加密ansible-vault encrypt foo.yml bar.yml baz.yml4. 编辑加密文件对加密过的文件进行编辑也是我们常遇到的,命令为:ansible-vault edit foo.yml # 这个命令会将该文件解密,并放到一个临时文件,编辑完后再保存到原文件。5. 查看加密文件有时我们不是想编辑文件,而是简单查看下文件内容,命令为:ansible-vault view foo.yml bar.yml baz.yml # 从示例中我们可以看出,一行命令可以查看多个加密文件。 6. 更改密码给加密文件更改密码,命令为:ansible-vault rekey foo.yml bar.yml baz.yml # 先交互式输入旧的密码,然后再交互式输入两次新密码,即更改密码成功。7. 取消加密(解密)取消加密的命令为:ansible-vault decrypt foo.yml bar.yml baz.yml # 交互式输入密码,即取消加密成功。8. playbook与ansible vaultansible执行playbook时,可以通过交互式或指定密码文件的方式来解密文件。交互式执行playbook时在终端以交互式的形式输入密码,示例:ansible-playbook --ask-vault-pass site.yaml指定密码文件另外一种使用方式,是将密码放在某个文件内,执行playbook时,通过指定该密码文件进行解密。可以使用「–vault-password-flie」参数:ansible-playbook --vault-password-file=password site.yaml从ansible2.4版本开始,官方不再推荐使用”–vault-password-file”选项,官方开始推荐使用”–vault-id”选项代替”–vault-password-file”选项指定密码文件,也就是说,如下两条命令的效果是一样的。(推荐使用,不代表不能使用。_)ansible-vault decrypt --vault-id passwordfile site.yaml ansible-vault decrypt --vault-password-file passwordfile site.yaml官网地址:https://docs.ansible.com/ansible/2.9/user_guide/vault.html9. 练习演示命令选项[student@servera example]$ ansible-vault -h usage: ansible-vault [-h] [--version] [-v] {create,decrypt,edit,view,encrypt,encrypt_string,rekey} ... encryption/decryption utility for Ansible data files positional arguments: {create,decrypt,edit,view,encrypt,encrypt_string,rekey} create Create new vault encrypted file decrypt Decrypt vault encrypted file edit Edit vault encrypted file view View vault encrypted file encrypt Encrypt YAML file encrypt_string Encrypt a string rekey Re-key a vault encrypted file optional arguments: --version show program's version number, config file location, configured module search path, module location, executable location and exit -h, --help show this help message and exit -v, --verbose verbose mode (-vvv for more, -vvvv to enable connection debugging) See 'ansible-vault <command> --help' for more information on a specific command. 创建加密文件[student@servera ~]$ mkdir example # 创建演示目录 [student@servera ~]$ cd example [student@servera example]$ ansible-vault create vault.yml # 创建加密文件 New Vault password: 123 # 输入密码 Confirm New Vault password: 123 # 确认密码 --- - name: ansible vault hosts: localhost tasks: - name: debug debug: msg: "test the ansible-vault." 查看加密文件[student@servera example]$ cat vault.yml # 直接查看加密剧本演示为ansible-vault进行了加密 $ANSIBLE_VAULT;1.1;AES256 62646137346235623766383531663462663662653261643933613639343133613630616239386437 3364356562656531636561643336336136653266643632350a306235653336666236336535643230 63303331383435323065663562653331373636633761633437383737303538336365326133363637 3663633061383434640a353738333230633432366337383535613363356537383731613966616365 37343430653035656663353832303465333531623738643235643163663763363737346362376437 61636135623737353939653436376535666337653364326433613064643734346638333133303462 30356365313835396566666563396162653336633066653663376132383961396166353766316236 61633833356633613635343465306534656339373732333535633931303034323439323762393234 35313930396534356338333139643033636661666564316564376664653135343130343637383634 3661336535303461353065356335613561366533663534636566 [student@servera example]$ ansible-vault view vault.yml # 查看加密文件 Vault password: 123 --- - name: ansible vault hosts: localhost tasks: - name: debug debug: msg: "test the ansible-vault." 编辑加密文件[student@servera example]$ ansible-vault edit vault.yml Vault password: 123 --- - name: ansible vault hosts: localhost tasks: # 修改name做演示。 - name: debug msg debug: msg: "test the ansible-vault." 更改密码[student@servera example]$ ansible-vault rekey vault.yml # 修改密码需要输入现有密码 Vault password: 123 New Vault password: 321 Confirm New Vault password: 321 Rekey successful 取消加密(解密)[student@servera example]$ ansible-vault decrypt vault.yml # 取消加密(解密) Vault password: 321 Decryption successful [student@servera example]$ cat vault.yml # 查看文件 --- - name: ansible vault hosts: localhost tasks: - name: debug msg debug: msg: "test the ansible-vault." 加密现有文件[student@servera example]$ ansible-vault encrypt vault.yml # 加密现有文件 New Vault password: 123 Confirm New Vault password: 123 Encryption successful [student@servera example]$ ansible-vault view vault.yml # 查看加密文件 Vault password: 123 --- - name: ansible vault hosts: localhost tasks: - name: debug msg debug: msg: "test the ansible-vault." 运行ansible vault加密的剧本交互式运行[student@servera example]$ ansible-playbook vault.yml # 直接运行会提示错误 ERROR! Attempting to decrypt but no vault secrets found [student@servera example]$ ansible-playbook --ask-vault-pass vault.yml # 交互式运行 Vault password: 123 PLAY [ansible vault] ******************************************************************* TASK [Gathering Facts] ***************************************************************** ok: [localhost] TASK [debug msg] *********************************************************************** ok: [localhost] => { "msg": "test the ansible-vault." } PLAY RECAP ***************************************************************************** localhost: ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 指定密码文件[student@servera example]$ vim passwordfile # 编写存放密码的文件 123 [student@servera example]$ ansible-playbook --vault-password-file=passwordfile vault.yml # 可不写等于号的,即 --vault-password-file passwordfile PLAY [ansible vault] ******************************************************************* TASK [Gathering Facts] ***************************************************************** ok: [localhost] TASK [debug msg] *********************************************************************** ok: [localhost] => { "msg": "test the ansible-vault." } PLAY RECAP ***************************************************************************** localhost: ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 [student@servera example]$ ansible-playbook --vault-id=passwordfile vault.yml # 可不写等于号的,即 --vault-id passwordfile PLAY [ansible vault] ******************************************************************* TASK [Gathering Facts] ***************************************************************** ok: [localhost] TASK [debug msg] *********************************************************************** ok: [localhost] => { "msg": "test the ansible-vault." } PLAY RECAP ***************************************************************************** localhost: ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 总结ansible-vault用于加密达到安全性需求。熟悉命令常用选项和参数。可用交互式或者指定文件的形式进行剧本运行。RHCE认证作为基础认证的升级,需要大家在RHCSA的基础上再进行学习,因此,涉及的基础内容需要大家好好进行学习并巩固。有良好的基础才能更上一层楼。好好加油,可以噶。
0
0
0
浏览量2007
秋月无边

面试官问:你能介绍一下Ansible变量吗?之后你噼里啪啦讲得太详细让面试官惊呆了

前文再续,书接上一回,上一回讲到对 Ansible Playbook进行简介,今回介绍Ansible究竟如何定义变量的。就正如shell当中的变量,占据着很重要的地位,如果不理解,首先肯定看不懂别人写的剧本,其次更不能编写对应的剧本。📜1. ansible变量简介ansilbe支持利用变量来存储值,并在ansible项目的所有文件中重复使用这些值。这可以简化项目的创建和维护,并减少错误的数量。通过变量,可以轻松地在ansible项目中管理给定环境的动态值。例如,变量可能包括下面这些值:要创建的用户要安装的软件包要重新启动的服务要删除的文件要从互联网检索的存档📜2. 变量命名变量的命名应该符如下规范:变量名仅能由字母、数字和下划线组成,且只能以字母开头。ansible内置的关键字不能作为变量名。例如:host_port、HOST_PORT、var5是符合命名规范的**,foo-port、 foo port、foo.port 、12**都不符合命名规范。变量的定义通常是YAML形式,在inventory host文件中也可以使用INI形式。ansible变量不仅可以支持简单的key=value格式,而且也支持更复杂数据结构,例如字典类型等。📜3. 命令行变量我们可以在执行playbook的命令行指定变量,需要注意的是,**命令行指定的变量在所有其他变量中优先级是最高的。**也就是说如果命令行指定的变量和其他地方指定的变量有冲突时,那么ansible最终会采用命令行定义的变量。-e,–extra-vars:此参数表示从命令行传入变量-e “key=value”:直接传递变量的格式-e “@vars.yml”:传递变量文件的格式命令行指定变量示例如下:ansible-playbook web.yml –extra-vars “version=1.23.45 other_variable=foo” # 这样指定会覆盖剧本或者其余地方有定义该名称的变量。📜4. 作用于playbook的变量📑vars语句定义全局变量我们可以在playbook中使用「vars」语句定义变量,该变量作用于整个play。例如:--- # inventory/playbooks/test.yaml - hosts: node1 vars: http_port: 80上面示例中中**「http_port」**是一个作用于整个play的变量,对这个play里的tasks、roles、import、include等等(这些现在不知道没关系,后面会教你如何去装-逼)之下定义的task均生效。📑引用变量文件除了将变量写在playbook中,我们也可以将变量放在一个单独的YAML文件中,通过**「vars_files」**语句来导入。「vars_files」变量只能作用于play全局,不能在某个task中单独被引用。「vars_files」参数可以使用系统绝对路径或playbook文件的相对路径。📑用例子辅助理解:📑vars定义变量与引用(引用方式是两个大括号)# cat test.yml --- - hosts: web vars: - my_name: abc # 前面的-也可以不加,但习惯加上可统一书写。 - phone: 123456 tasks: - name: add content copy: content: "{{ my_name }}" dest: /data/a.txt📑vars_files 定义变量与引用# cat variables my_name: abc http_port: 80# 案例一 # cat test.yml --- - hosts: web vars_files: - variables tasks: - name: add content copy: content: "{{ http_port }}" dest: /data/b.txt # 案例二 # cat test.yml --- - hosts: web vars_files: - variables tasks: - name: add content template: src: /root/b.txt dest: /root/c.txt # cat b.txt {{ my_name }} {{ http_port }} # cat c.txt abc 80"var_files"关键字引入了对应的变量文件,然后使用了文件中定义的变量。当然也可以引用多个变量文件,每个被引入的文件都需要以“-”开头。“var”关键字和“var_files”关键字可以同时使用,如下:var: - conf90: /etc/nginx/conf.d/90.conf vars_files: - /testdir/ansible/nginx_vars.yml来自官网的说明:(https://docs.ansible.com/ansible/latest/user_guide/playbooks_variables.html#defining-variables-in-a-playbook)YAML syntax requires that if you start a value with {{ foo }} you quote the whole line, since it wants to be sure you aren’t trying to start a YAML dictionary. This is covered on the YAML Syntax documentation.#This won’t work: - hosts: app_servers vars: app_path: {{ base_path }}/22 #Do it like this and you’ll be fine: - hosts: app_servers vars: app_path: "{{ base_path }}/22"所以遇到这样的情景时候,记得写成这样,否则语法检查户报错。📜5. 主机清单定义主机和主机组变量我们可以在主机清单中定义所需要的主机变量(作用于单主机)和主机组变量(作用于整个主机组)。📑主机变量:主机的后边设置key=value的格式注:inventory_hostname是ansible自带的变量,代表组中的每个主机在配置文件中定义主机变量# cat /etc/ansible/hosts [webservers] servera key=101 serverb key=111[root@servera ~]# ansible all -m shell -a 'echo "{{ key }}"' servera | CHANGED | rc=0 >> 101 serverb | CHANGED | rc=0 >> 111📑主机组变量在配置文件中定义主机组变量# cat /etc/ansible/hosts [webservers] servera serverb [webservers:vars] ansiber_version=2.7 key=nginx[root@servera ~]# ansible all -m shell -a 'echo "{{ key }}"' servera | CHANGED | rc=0 >> nginx serverb | CHANGED | rc=0 >> nginx [root@servera ~]# ansible all -m shell -a 'echo "{{ ansiber_version }}"' servera | CHANGED | rc=0 >> 2.7 serverb | CHANGED | rc=0 >> 2.7📜6. 文件定义主机以及主机组变量除了在主机清单中定义变量外,我们还可以在特定的目录下定义:主机变量目录:host_vars(注:需要在此目录下为每个主机创建一个文件,在此文件中定义变量)组变量目录:group_vars(注:需要在此目录下创建一个以主机组名命名的文件,在此文件中定义变量)注:以上两个目录均不存在,需要自己手动创建;mkdir /etc/ansible/{host_vars,group_vars}注:当需要为所有主机或者所有主机组创建一样的变量时,在host_vars和group_vars目录下,创建all文件并写入变量即可~在配置文件中定义主机组# cat /etc/ansible/hosts [webservers] servera serverb 在host_vars目录下创建以主机名为名字的文件,并在此文件中配置变量,变量格式为: key: value# mkdir host_vars # vim host_vars/servera # vim host_vars/serverb # head host_vars/* ==> host_vars/servera <== key: 101 ==> host_vars/serverb <== key: 111[root@servera ~]# ansible all -m shell -a 'echo "{{ key }}"' servera | CHANGED | rc=0 >> 101 serverb | CHANGED | rc=0 >> 111在group_vars目录创建以主机组为名字的文件,并在此文件中配置变量,变量格式为:key: value# mkdir group_vars # vim group_vars/webservers # head group_vars/* name: nginx[root@servera ~]# ansible all -m shell -a 'echo "{{ name }}"' servera | CHANGED | rc=0 >> nginx serverb | CHANGED | rc=0 >> nginx📜7. 注册变量这是一个比较特别的变量,不过一定要学会,否则以后很难混江湖。(说白了就是想去装嘛,懂的。)register方法能够将一个task的执行结果注册为一个变量。书写格式要与模块名称对齐,该变量作用于整个playbook。通常register变量和when语句联合使用,以达到满足某些条件才运行task的目的。# cat hosts localhost # cat test.yml --- - hosts: all gather_facts: no tasks: - name: display register vars shell: hostname register: info - name: dispaly info debug: msg: "{{info}}"# ansible-playbook test.yml -i hosts PLAY [localhost] ************************************************************************ TASK [display register vars] ************************************************************ changed: [localhost] TASK [dispaly info] ********************************************************************* ok: [localhost] => { "msg": { "changed": true, "cmd": "hostname", "delta": "0:00:00.007093", "end": "2020-09-06 01:25:25.393600", "failed": false, "rc": 0, "start": "2020-09-06 01:25:25.386507", "stderr": "", "stderr_lines": [], "stdout": "workstation.lab.example.com", "stdout_lines": [ "workstation.lab.example.com" ] } } PLAY RECAP ****************************************************************************** localhost : ok=2 changed=1 unreachable=0 failed=0后续的章节学习中会有更多注册变量的演示,也可自行定义去玩耍进行理解。📜8. 练习演示📑查看配置文件和主机清单[student@servera ~]$ mkdir variables [student@servera ~]$ cd variables/ [student@servera variables]$ cat ansible.cfg [defaults] inventory=inventory remote_user=student [privilege_escalation] become=False become_method=sudo become_user=root become_ask_pass=False [student@servera variables]$ cat inventory [webserver] servera📑编写所需要的剧本[student@servera variables]$ cat web.yml - name: Deploy and start apache httpd service hosts: webserver vars: web_pkg: httpd firewall_pkg: firewalld web_service: httpd firewall_service: firewalld rule: http tasks: - name: required packages are installed and up to date yum: name: - "{{ web_pkg }}" - "{{ firewall_pkg }}" state: latest - name: The {{ firewall_service }} service is started and enabled service: name: "{{ firewall_service }}" enabled: true state: started - name: The {{ web_service }} service is started and enabled service: name: "{{ web_service }}" enabled: true state: started - name: web content is in place copy: content: "Example web content for vars./n" dest: /var/www/html/index.html - name: The firewall port for {{ rule }} is open firewalld: service: "{{ rule }}" permanent: true immediate: true state: enabled - name: Test web server hosts: localhost become: no tasks: - name: connect to web server uri: url: http://servera return_content: yes status_code: 200📑语法检查[student@servera variables]$ ansible-playbook --syntax-check web.yml playbook: web.yml📑执行剧本[student@workstation variables]$ ansible-playbook web.yml PLAY [Deploy and start apache httpd service] ******************************************** TASK [Gathering Facts] ****************************************************************** ok: [servera] TASK [required packages are installed and up to date] *********************************** changed: [servera] TASK [The firewalld service is started and enabled] ************************************* ok: [servera] TASK [The httpd service is started and enabled] ***************************************** ok: [servera] TASK [web content is in place] ********************************************************** changed: [servera] TASK [The firewall port for http is open] *********************************************** ok: [servera] PLAY [Verify the Apache service] ******************************************************** TASK [Gathering Facts] ****************************************************************** ok: [localhost] TASK [Ensure the webserver is reachable] ************************************************ ok: [localhost] PLAY RECAP ****************************************************************************** localhost : ok=2 changed=0 unreachable=0 failed=0 servera : ok=6 changed=2 unreachable=0 failed=0💡总结变量定义有他的规范,需要谨记。变量的调用有其优先级,需要合理编写;命令行中的调用优先级最高。变量可在主机清单和文件中定义。注册变量会在后续的条件控制里经常出现,需要学会运用。后续还有魔法变量让你去装-逼。RHCE认证作为基础认证的升级,需要大家在RHCSA的基础上再进行学习,因此,涉及的基础内容需要大家好好进行学习并巩固。有良好的基础才能更上一层楼。好好加油,可以噶🤪。
0
0
0
浏览量2004
秋月无边

戏说 RHCE 认证

准备Red Hat Certified Engineer(RHCE)认证考试。涵盖了RHCE考试的各项重要主题,通过模拟考试题目和实际操作练习,将全面准备并提高在Red Hat Enterprise Linux系统上的高级管理技能
0
0
0
浏览量2079
秋月无边

戏说 RHCSA 认证

为准备Red Hat Certified System Administrator(RHCSA)认证考试。涵盖了RHCSA考试的各个主要主题,包括系统管理、文件操作、用户和组管理、服务配置等。通过模拟考试题目和实际操作练习,将全面准备并提高在Red Hat Enterprise Linux系统上的管理技能
0
0
0
浏览量2082

履历