Ansible之等待服务状态变成成功

ansible的脚本中我们可能会要启动某项服务并等待,直到服务启动起来,然后再进行下一步 这个非常重要,我们举例来实验一下: - hosts: localhost vars: local__service: ssh tasks: - block: - name: "Stop {{ local__service }} service" systemd: service: "{{ local__service }}" state: stopped - name: "Populate ansible_facts.services variable" ansible.builtin.service_facts: - name: "{{ local__service }} state will be stopped as expected" assert: that: ansible_facts.services[local__service].state == 'stopped' - name: "Start {{ local__service }} service" systemd: service: "{{ local__service }}" state: started - name: "Registered {{ local__service }} state will still be stopped as it was not refreshed" assert: that: ansible_facts.services[local__service].state == 'stopped' - name: "Refresh ansible_facts.services variable" ansible.builtin.service_facts: - name: "{{ local__service }} state will be running as expected" assert: that: ansible_facts.services[local__service].state == 'running' 上面的 playbook 一共有7步: ...

2022年7月29日

LVM系统的Restore

在生产系统中使用LVM务必要注意lvm metadata的备份,曾经在京东的时候发生过虚机用了lvm的磁盘系统,然后虚机文件qcow2突然坏掉了,想尽了办法也无法恢复,这给我们拉响了警钟啊,使用lvm的时候务必要备份分区信息,否则坏的时候就欲哭无泪了。 缺省在 /etc/lvm/backup/ 目录下是最新的备份,同样历史版本都在 /etc/lvm/archive/ 目录下。 一、先备份 在开始恢复之前,一定先做个备份 cp -pr /etc/lvm /etc/lvm_bkp 然后去看看archive下的备份信息 ls -l /etc/lvm/archive/vg_storage_00* -rw-------. 1 root root 13722 Oct 28 23:45 /etc/lvm/archive/vg_storage_00419-1760023262.vg -rw-------. 1 root root 14571 Oct 28 23:52 /etc/lvm/archive/vg_storage_00420-94024216.vg ... -rw-------. 1 root root 14749 Nov 23 15:11 /etc/lvm/archive/vg_storage_00676-394223172.vg -rw-------. 1 root root 14733 Nov 23 15:29 /etc/lvm/archive/vg_storage_00677-187019982.vg # 二、最坏的情形恢复pv 警告:这一步只能在VG无法正常运行的时候再运行!!! 先说最坏的情形,LVM的建立路径是 pv —> vg —> lv,假设连 pv(物理卷都没了) 我们选择最近的备份,/etc/lvm/archive/vg_storage_00677-187019982.vg less /etc/lvm/archive/vg_storage_00677-187019982.vg ... physical_volumes { pv0 { id = "BgR0KJ-JClh-T2gS-k6yK-9RGn-B8Ls-LYPQP0" ... 从里面拿到 pv 的 id ,重建 pv pvcreate --uuid "BgR0KJ-JClh-T2gS-k6yK-9RGn-B8Ls-LYPQP0" \ --restorefile /etc/lvm/archive/vg_storage_00677-187019982.vg 三、恢复VG 如果 vg 是正常的,那么就不用做第二步了,直接从备份中恢复即可,先查看一下 ...

2022年7月28日

dmesg -T 无时间戳的解决方法

现在版本的 dmesg -T 都是带时间戳的。 但是老的机器,很有可能是没有 -T 这个参数的,直接 dmesg 是这样的: 这个时间戳是天书啊,这还算好的,好歹有。还有更差的,连戳子都没有: 戳子都没有的,需要做以下步骤来加上,机器重启后必须再执行一遍: echo 1 > /sys/module/printk/parameters/printk_time 同时写个脚本,/usr/local/bin/dmesgt.sh #!/bin/bash # Translate dmesg timestamps to human readable format # desired date format date_format="%a %b %d %T %Y" # uptime in seconds uptime=$(cut -d " " -f 1 /proc/uptime) # run only if timestamps are enabled if [ "Y" = "$(cat /sys/module/printk/parameters/time)" ]; then dmesg | sed "s/^\[[ ]*\?\([0-9.]*\)\] \(.*\)/\\1 \\2/" | while read timestamp message; do printf "[%s] %s\n" "$(date --date "now - $uptime seconds + $timestamp seconds" +"${date_format}")" "$message" done else echo "Timestamps are disabled (/sys/module/printk/parameters/time)" fi 这样就可以了,最后我们测试一下: ...

2022年7月25日

一次mongodb cpu很high的解决方法

接到同事的通知,说mongodb的cpu很高,下不去,看有什么办法。 看了一下图,cpu都99.4%了,确实很高: 登上机器,首先去看mongod的log,都试如下的查询,都很慢: copy出一条来,备用 2022-07-17T21:30:42.556+0800 I COMMAND [conn196670] command beyou.behaviorAnalysis command: find { find: "behaviorAnalysis", filter: { behavior: { $regex: ".*互动操作.*", $options: "i" }, log: { $regex: ".*\Q观看:《罗马的房子》,\E.*", $options: "i" }, userId: 7345, _class: { $in: [ "com.linkyee.api.domain.po.BehaviorAnalysis" ] } }, $db: "beyou" } planSummary: IXSCAN { _class: 1, behavior: 1, log: 1, userId: 1 } keysExamined:111564 docsExamined:2 cursorExhausted:1 numYields:890 nreturned:2 reslen:571 locks:{ Global: { acquireCount: { r: 891 } }, Database: { acquireCount: { r: 891 } }, Collection: { acquireCount: { r: 891 } } } storage:{} protocol:op_msg 2268ms 发现确实很慢啊,op_msg 居然要2268ms,但是mongodb的数据目录总共才6G多,不客观啊。 ...

2022年7月21日

Infrastructure as Code中packer的使用

先普及一下概念,Infrastructure as Code,也就是从代码开始定义整个网络环境、虚机、各种资源等等。 简单说就是在云上用代码来管理一切,无论是vpc、subnetwork、lb、snat、sg、ec2…… 非常符合我的胃口,因为就连架构图,都是用 graphviz 来画的。 那么 Infrastructure as Code (IAC) 可以分为以下五个部分: Ad hoc scripts Configuration Management tools Orchestration tools Provisioning tools Server Templating tools 一、Ad hoc scripts 就是用软件对目的主机进行 point to point 操作,用shell或者ansible都可以。推荐ansible。 在 infosys 面试被一个印度老外问到这问题,因为平时根本不用ansible 的 ad hoc 点对点模式,结果被当场问住。现在才知道这玩意是什么。当然,用 ansible 的话不建议用这个,因为 playbook 是可追溯的。 二、Configuration Management tools 配置管理,这里当然推荐 ansible,每一步的操作都可以有 inventory 和 playbook 可以追溯。 三、Orchestration tools 协同工具,k8s和kvm 四、Provisioning tools 生产工具,当然是terraform,另外,阿里云是支持plumi的,华为腾讯不支持。 五、Server Templating tools 模板工具,这里就是 Packer,其实我们公司现在的模板工具,是八戒从openstack学的,改动Cloud-init的东西。 Packer更标准一下,是进化版的东西,它既可以打kvm镜像,也可以打Docker镜像。 下面我们就看看怎么使用吧,这里先说kvm,因为kvm的比较难,docker的八戒现在还是用Dockerfile,有空了再研究packer: 安装就不多说了,就一个执行文件,下载下来就行,不用装。 Packer的核心是三个部分 builders provisioners post-processors 我们先建立一个空目录,名字随便,就叫 test-image ...

2022年7月17日

Cisco设备自动执行和备份的脚本

在日常工作中我们经常要对 Cisco 的网络设备的配置进行备份,或者和 suricata 联动的时候要执行操作。 方法其实很简单,调用 python 的相应模块即可。 准备工作如下: 首选需要在/export/servers/python363装好 python 3.6, pip install netmiko 其次,在路由器上可以配置en的密码 然后依次执行备份就可以了。 #!/export/servers/python363/bin/python3.6 from netmiko import Netmiko import time tw_bgp = { "device_type": "cisco_ios", "host": "tw-bgp", "ip": "192.168.1.10", "username": "noc", "use_keys": True, "secret" : "xxxxxxxx", "key_file": "/root/.ssh/id_jump_rsa_new", } tw_r1_e1 = { "device_type": "cisco_ios", "host": "tw-r1-e1", "ip": "192.168.1.11", "username": "noc", "use_keys": True, "key_file": "/root/.ssh/id_jump_rsa_new", } tw_r1_e2 = { "device_type": "cisco_ios", "host": "tw-r1-e2", "ip": "192.168.1.12", "username": "noc", "use_keys": True, "key_file": "/root/.ssh/id_jump_rsa_new", } tw_r2_e1 = { "device_type": "cisco_ios", "host": "tw-r2-e1", "ip": "192.168.1.13", "username": "noc", "use_keys": True, "key_file": "/root/.ssh/id_jump_rsa_new", } tw_r2_e2 = { "device_type": "cisco_ios", "host": "tw-r2-e2", "ip": "192.168.1.14", "username": "noc", "use_keys": True, "key_file": "/root/.ssh/id_jump_rsa_new", } devices=[tw_bgp, tw_r1_e1, tw_r1_e2, tw_r2_e1, tw_r2_e2] for dev in devices: name = dev["ip"] connection = Netmiko(**dev) connection.enable() out = connection.send_command("show running-config") calender = time.strftime("%Y%m%d") file_name = '{}-{}.txt'.format(dev["host"],calender) file = open(file_name ,"w") file.write(out) file.close() connection.disconnect() print("BACKUP for %s done" %dev["host"])

2022年7月17日

用户态的NFS Server

NFS Server 很常用,但是坑也是巨大的。之前在京东运维 Hadoop 集群的时候碰到过脑裂,原因就是 NFS 引起的。 关键 NFS 是内核态的,一旦崩溃,那么客户端的所有命令,ls、df、du等等,统统无反应,结果是很悲剧的。 下面要推荐一下 nfs-ganesha ,它是用户态的nfs-server,支持v3和v4,而nfs缺省是内核态的v3。 强烈推荐大家用这个,而不是用内核态的,并且 nfs-ganesha 还是支持 glusterFS 的。 yum install -y centos-release-nfs-ganesha30.noarch vi /etc/ganesha/ganesha.conf %include /etc/ganesha/exports/gv0.conf vi /etc/ganesha/exports/gv0.conf EXPORT{ Export_Id = 1 ; # Export ID unique to each export Path = "/mnt/upload"; Pseudo = /upload; FSAL { name = VFS; } Access_type = RW; # Access permissions Squash = No_root_squash; # To enable/disable root squashing Disable_ACL = TRUE; # To enable/disable ACL Protocols = "4" ; # NFS protocols supported Transports = "UDP","TCP" ; # Transport protocols supported SecType = "sys"; # Security flavors supported } #启动 systemctl restart nfs-ganesha #手动mount的方法 mount -t nfs -o soft,intr,rsize=8192,wsize=8192,timeo=900,proto=tcp,vers=4 192.168.31.2:/upload /mnt/nfs-upload #自动mount的方法 cat /etc/fstab 192.168.31.2:/upload /mnt/nfs-upload nfs rw,vers=4,addr=192.168.31.2,clientaddr=192.168.31.8 0 0 注意id对齐问题可能要用到rpcidmapd ...

2022年7月6日

JavaScript 到底是如何执行的呢 -- JS的作原理

JavaScript 到底是如何工作的? 一、工作原理 JavaScript到底是: 同步还是异步? 单线程还是多线程? JavaScript 中的一切都发生在 Execution Context (执行上下文)中 您可以假设这个执行上下文 是一个大盒子或一个容器,在其中执行整个 JavaScript 代码。 这个大盒子里有两个组件: Memory(内存组件):这是所有变量和函数存储为键值对的地方。这个**“内存组件”也称为变量环境**。因此,它是一种环境,其中所有这些变量和函数都存储为键值对。 Code(代码组件):这是代码逐行执行的地方。这个“代码组件”也称为执行线程。所以,这个执行线程是一个单线程,整个代码一次只执行一行。 结论:JavaScript 是一种同步单线程语言。 单线程 意味着 JavaScript 一次只能执行一个命令。 同步单线程 意味着 JavaScript 一次只能以特定顺序每次执行一个命令。这意味着它只能在当前行完成执行后转到下一行。这就是同步单线程的意思。 很惊诧吧,实际 javascripts 有单线程 event loop 大循环来完成很多不可思议的事情。 二、实际工作过程分析 JavaScript 代码是如何执行的? 当你运行 JavaScript 代码时会发生什么? 会创建一个Execution Context(执行上下文)。 让我们使用实际的代码来举个例子: var n = 2; function square(num) { var ans = num * num; return ans; } var square2 = square(n); var square4 = square(4); 执行上述代码时,会创建 一个执行上下文 ...

2022年6月21日

Javascripts中if的优化

Javascripts 中的 if … else 用起来倒是很方便,但是看起来就不舒服了 if (true) { } if (true) { } if (true) { if (true) { if (true) { } } else { } } else { } 上面看起来很闹心吧,下面讲讲优化: 一、三元优化 if (ture) else可以用三元操作符来优化它: // Bad 😥 if (true) { console.log("Congratutions!") } else { console.warn("Oops, something went wrong!") } // Great 🥰 true ? console.log("Congratutions") : console.warn("Oops, something went wrong!") 二、与优化 true的情况下才执行可以用与来进行优化: if (true) { alert(1) } // is equals to: true && alert(1) 三、提前返回 如果有多个判断,按照复杂程度,从上到下,提前返回。 ...

2022年6月15日

Shell进阶技巧

Shell脚本的进阶技巧: 一、String 类的技巧 String类当作数组来使用,注意范围的下标,0:4,4最后要被踢掉,实际是0-3,共4个字符: string="Bash is great!" echo ${string:8} # great! echo ${string:0:4} # Bash echo ${string:8:-1} # great (-1: upto 1st element from right) 数组的长度: string="Bash is great!"; len=${#string} echo "len = $len" 字符串的替换: string="Bash is great!!" echo ${string/Bash/GNU Bash} # GNU Bash is great!! echo ${string//!/.} # Bash is great.. 大小写替换: string="Bash" echo ${string^^} # BASH echo ${string,,} # bash 按index存取数组中字符在shell中不可用,但是可以用function变相实现: function charAt() { string=$1 i=$2 echo ${string:i:1} } echo $(charAt "Hello" 2) # l echo $(charAt "Hello" 1) # e 二、数组和字典 定义一个数组并且遍历它: ...

2022年6月9日