CentOS7的救援模式和紧急模式

说到 CentOS7 的紧急模式与救援模式,网上可以搜到漫天飞的帖子,说一下区别 RESCUE 救援模式: 救援模式启动的系统没有挂载硬盘,可以将硬盘 mount 出然后拷出数据。 EMERGENCY 紧急模式: 紧急模式启动的系统是一个最小的环境。根目录档案系统将会被挂载为仅能读取,而且将不会做任何的设定。 当然进入的方法也很简单,进入系统的时候按 e 修改 grub 菜单参数,就可以进入不同的模式 本文讨论的重点不是怎么进去,而是那两句命令,在紧急状态下反正我是记不住的 systemd.unit=rescue.target systemd.unit=emergency.target 都没有之前的 single 简单,也完全记不住,既然记不住,那就干脆做到菜单里好了,这才是本文的重点。 现在都是使用 grub2 了,而不是 grub,这很重要。grub2的配置文件是 /boot/grub2/grub.cfg。 修改 grub2 有两个工具,grub2-mkconfig 和 grubby,不要同时使用这两个工具修改,会覆盖的 grub2-mkconfig 会去搜索 /boot 目录下的内核文件,有多少个内核就会生成多少个启动项。那么如果是同一个内核,想修改不同的启动参数,做多个启动项就完蛋,他不能自动生成单内核的多个启动项 grubby 很灵活,可以根据当前 grub2 的配置,生成一个内核,多个不同启动参数的多个启动项。 那么我们要加进去两个只是启动参数不同,内核其实一样的启动项,用 grubby 就好了 grubby --add-kernel=\$(ls -1cat /boot/vmlinuz*|grep rescue) --title="RESCUE BOOT" --initrd=\$(ls -1cat /boot/initramfs*|grep rescue) --args="systemd.unit=rescue.target" --copy-default grubby --add-kernel=\$(ls -1cat /boot/vmlinuz*|grep rescue) --title="EMERGENCY BOOT" --initrd=\$(ls -1cat /boot/initramfs*|grep rescue) --args="systemd.unit=emergency.target" --copy-default 切忌我们之后不能运行 ...

2021年11月19日 · 1 分钟 · 86 字 · 八戒

linux下web pacproxy的用法

说实在话,这个场景非常怪异,客户在 linux 下要动态根据 url 选择代理: 看图,中间的是前端代理,地址是 192.168.1.1:8080,然后客户设置使用这个代理 export http_proxy=http://192.168.1.1:8080 export https_proxy=http://192.168.1.1:8080 然后对应后端有三个代理,两个 http 代理,一个 socks 代理 http 192.168.2.1:3128 socks 192.168.2.2:1080 http 192.168.2.3:3128 我们要根据客户的请求 URL 来决定具体要使用后端的哪个代理 这个如果在浏览器上设置非常容易,设置 PAC 即可。但是偏偏客户端不是浏览器,而是一个程序,那么麻烦就来了。怎么设置呢? 步骤很简单: 一、安装 pacproxy 网址:https://github.com/williambailey/pacproxy wget https://github.com/williambailey/pacproxy/releases/download/v.2.0.4/pacproxy_2.0.4_linux_amd64.tar.gz tar zxvf pacproxy_2.0.4_linux_amd64.tar.gz 拷出来 pacproxy 备用 二、生成配置文件 最主要的就是 PAC 文件的生成 我们给个例子: cat << EOF >> pac function FindProxyForURL(url, host) { if (host == "www.baidu.com") { return "PROXY 192.168.2.1:3128"; } else if (host == "www.sina.com.cn") { return "SOCKS 192.168.2.2:1080"; } else if (host == "www.sohu.com") { return "SOCKS 192.168.2.3:1080"; } else { return "DIRECT"; } } EOF 其实 PAC 文件的内容就是一段 javascript,用来返回代理的地址 ...

2021年11月16日 · 1 分钟 · 117 字 · 八戒

Tomcat server.xml配置详细解释

Tomcat 是一个 HTTP server。同时,它也是一个 serverlet 容器,可以执行 java 的 Servlet,也可以把 JavaServer Pages(JSP)和 JavaServerFaces(JSF)编译成 Java Servlet。它的模型图如下: 给个生产环境 server.xml 的例子: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 <?xml version='1.0' encoding='utf-8'?> <Server port="-1" shutdown="SHUTDOWN"> <Listener className="org.apache.catalina.startup.VersionLoggerListener" /> <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" /> <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" /> <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" /> <Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" /> <GlobalNamingResources> <Resource name="UserDatabase" auth="Container" type="org.apache.catalina.UserDatabase" description="User database that can be updated and saved" factory="org.apache.catalina.users.MemoryUserDatabaseFactory" pathname="conf/tomcat-users.xml" /> </GlobalNamingResources> <Service name="Catalina"> <Connector port="8080" server="www.rendoumi.com" protocol="org.apache.coyote.http11.Http11NioProtocol" maxHttpHeaderSize="8192" acceptCount="500" maxThreads="1000" minSpareThreads="200" enableLookups="false" redirectPort="8443" connectionTimeout="20000" relaxedQueryChars="[]|{}@!$*()+'.,;^\`&quot;&lt;&gt;" disableUploadTimeout="true" allowTrace="false" URIEncoding="UTF-8" useBodyEncodingForURI="true" /> <Engine name="Catalina" defaultHost="localhost"> <Realm className="org.apache.catalina.realm.LockOutRealm"> <Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase"/> </Realm> <Host name="localhost" appBase="webapps" unpackWARs="false" autoDeploy="false"> <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" prefix="access_log." suffix=".txt" fileDateFormat="yyyy-MM-dd" pattern="%a|%A|%T|%{X-Forwarded-For}i|%l|%u|%t|%r|%s|%b|%{Referer}i|%{User-Agent}i " resolveHosts="false"/> <Context path="" docBase="/export/servers/tomcat/webapps/web" /> </Host> </Engine> </Service> </Server> 分解开来一部分一部分的看: ...

2021年11月15日 · 3 分钟 · 444 字 · 八戒

GlusterFS文件系统的优化

公司用了6年的GlusterFS终于到了要调整卷参数的地步了。 小文件已经多到要影响 IO 的地步了。 首先说一下结论,GlusterFS 安装完成后,基本不需要调整任何参数。生产系统千万不可盲目! 然后我们这是有特殊情况,所以调优步骤如下(以卷名为 esign-vol 为例): #必须关掉NFS gluster volume set esign-vol nfs.disable on #必须保留10%的空间,避免塞爆卷空间 gluster volume set esign-vol cluster.min-free-disk 10% #本机有256G的内存,所以设置25G的读缓存 gluster volume set esign-vol performance.cache-size 25GB #读缓存中,单个文件的缓存,最大文件size是128MB,大于128MB的单个文件不缓存 gluster volume set esign-vol performance.cache-max-file-size 128MB #设置每个客户端都允许多线程,缺省是2,多个小文件增加为4 gluster volume set esign-vol client.event-threads 4 #设置服务器端对特定的卷允许多线程,缺省是1,多个小文件增加为4 gluster volume set esign-vol server.event-threads 4 #分割线,以下参数不要调整,除非明确知道后果 #设置 io 线程数量,这个值缺省是16,已经很大了,足够用 gluster volume set esign-vol performance.io-thread-count 16 #设置写缓冲区,这个值缺省是1M,弄大了如果停电什么的,会丢数据 gluster volume set esign-vol performance.write-behind-window-size: 1M 以上就可以了。还有个参数 global-threading ,缺省是 off,不要设置为 on,有使用条件的,弄错了反而会导致性能降低。

2021年11月15日 · 1 分钟 · 73 字 · 八戒

Python的协程详细解释

在实际中遇到这样一个问题,公司软件发布上线自动化。 说简单点,就是需要去登录一个上线的内部网站,然后爬下所有的上线数据。 然后根据爬下来的数据整理好,可以一起上线的,就并发多线程,其实就是去传参数点击一个链接等返回。 不能并发的就单线程点链接。 那这个事情必须更有效率,单线程的没问题,用 python 的 request 就可以实现了。 我们仔细研究一下协程,先讲一下历史: 使用Python的人往往纠结在多线程、多进程,哪个效率更高?到底用哪个好呢? 其实 Python 的多进程和多线程,相对于别家的协程和异步处理机制,都不行,线程之间切换耗费 CPU 和寄存器,OS 的调度不可控,多进程之间通讯也不便。性能根本不行。 后来呢 Python 改进了语法,出现了 yiled from 充当协程调度,有人就根据这个特性开发了第三方的协程框架,Tornado,Gevent等。 官方也不能坐视不理啊,任凭别人出风头,于是 Python 之父深入简出3年,苦心钻研自家的协程,async/await 和 asyncio 库,并放到 Python3.5 后成为官方原生的协程。 对于 http请求、读写文件、读写数据库这种高延时的 IO 操作,协程是个大杀器,优点非常多;它可以在预料到一个阻塞将发生时,挂起当前协程,跑去执行其它协程,同时把事件注册到循环中,实现了多协程并发,其实这玩意是跟 Nodejs 的回调学的。 看下图,详细解释下,左边我们有100个网页请求,并发100个协程请求(其实也是1个1个发),当需要等待长时间回应回应时,挂起当前协程,并注册一个回调函数到事件循环(Event Loop)中,执行下一个协程,当有协程事件完成再通过回调函数唤醒挂起的协程,然后返回结果。 这个跟 nodejs 的回调函数基本一样,我们必须注意主进程和协程的关系,如果我在一个主进程中,触发协程函数,有100个协程,那么必须等待100个协程都结束后,才能回到正常的那个主进程中。当然,主进程也可能也是一个协程。 那么协程的基本用法 async f(n) 声明一个函数是协程的 await f(n) 挂起当前协程,把控制权交回 event loop,并且执行f(n)和注册之后的f(n)回调。 举个例子:如果在 g() 这个函数中执行了 await f(),那么g()函数会被挂起,并等待 f() 函数有结果结束,然后返回 g() 继续执行。 async def get(url): async with aiohttp.ClientSession() as session: async with session.get(url) as response: return await response.text() 最后一行 await 是挂起命令,挂起当前函数 get() ,并执行 response.text() 和注册回调,等待 response.text() 执行完成后重新激活当前函數get()继续执行,返回。 ...

2021年11月12日 · 2 分钟 · 402 字 · 八戒

kubernetes使用filebeat multiline自定义收集日志

我们介绍了如何在 kubernetes 环境中使用 filebeat sidecar 方式收集日志 使用的是 filebeat 的 moudle 模块,但凡是常用的软件,基本都有对应的模块可用,所以我们首先应该使用模块来收集日志。 那对于一些我们自己写的 Go 软件呢,或者根本不是标准的,那该怎么办呢? 那就自定义 filebeat.inputs,网上的 filebeat 例子,其实大多都是这样的 很简单,给个例子 [beat-logstash-some-name-832-2015.11.28] IndexNotFoundException[no such index] at org.elasticsearch.cluster.metadata.(IndexNameExpressionResolver.java:566) at org.elasticsearch.cluster.metadata.(IndexNameExpressionResolver.java:133) at org.elasticsearch.cluster.metadata.(IndexNameExpressionResolver.java:77) at org.elasticsearch.action.admin..checkBlock(TransportDeleteIndexAction.java:75) 看如上日志,如果不用模式匹配的话,那么会送5条记录到 ES, Kibana 看起来就十分割裂了。 所以要用正则把底下的4行和上面的第1行合在一起,合并成一条就记录推送到 ES 去 仔细观察,开头一行是以 [ 开始的,所以正则就是 ‘^\[’,我们要匹配的是底下的4行,必须反转一下模式。 multiline 的 negate 属性,这个是指定是否反转匹配到的内容,这里如果是 true 的话,反转,那就是选择不以 [ 开头的行。 netgate 属性的缺省值是 false multiline 的 match 属性,after 指追加到上一条事件(向上合并),before 指合并到下一条(向下合并) 于是,我们就可以写出以下的匹配模式,这样就把匹配到条目追加到上一条,合并在一起了: filebeat.inputs: - type: log enabled: true paths: - /Users/liuxg/data/multiline/multiline.log multiline.type: pattern multiline.pattern: '^\[' multiline.negate: true multiline.match: after output.elasticsearch: hosts: ["localhost:9200"] index: "multiline" 再给个例子,java 的 stack 调用,日志格式如下: ...

2021年11月11日 · 2 分钟 · 231 字 · 八戒

生产环境kubernetes使用持久化卷GlusterFS

在生产环境使用 Kubernetes ,绕不过去的一个问题就是持久化卷。 如果是使用阿里 ACK 托管平台的话,可以用 OSS 来持久化卷,如果是自搭的 kubernetes,那么存储就需要仔细考虑了。 ceph比较复杂,容易出故障。nfs 也不可用,毛病多多。minio倒是可以。 这种情况下使用双副本的 GlusterFS 就是不错的选择。 生产环境就不能随意了,最好不要使用 Heketi,因为凡是要持久化的东西,都是比较重要的东西,最好都有 yaml 记录。 GlusterFS 的搭建就不说了。说说实际使用过程: 一、装GFS,生产新卷 安装就不说了,我们的GFS有两个节点,172.19.20.18 和 172.19.20.36,我们强制建立一个两副本的卷: kuaijian-vol gluster volume create kuaijian-vol replica 2 transport tcp 172.19.20.18:/glusterfs/kuaijian-vol 172.19.20.36:/glusterfs/kuaijian-vol force 二、为k8s产生GFS的endingpoint和service cat << EOF >> ep-svc.yaml --- apiVersion: v1 kind: Service metadata: name: gfs-cluster_svc spec: ports: - port: 1 --- apiVersion: v1 kind: Endpoints metadata: name: gfs-cluster_svc subsets: - addresses: - ip: 172.19.20.18 ports: - port: 1 - addresses: - ip: 172.19.20.36 ports: - port: 1 EOF kubectl apply -f ep-svc.yaml 这里要提一个概念,通常情况下 service 是通过 selector 标签来选择对应的 pod 来增加 endingpoint 的。如下: ...

2021年11月10日 · 2 分钟 · 272 字 · 八戒

kubernetes生产环境使用filebeat sidecar收集日志

在生产环境中,ES 通常是不会在 k8s 集群中存在的,一般 MySQL 和 Elasticsearch 都是独立在 k8s 之外。 那么无论哪种 pod,要甩日志到 ES,最轻量的方案肯定是用 filebeat 甩过去了。 当然,如果是阿里的 ACK,logtail 和 logstore 配搭已经非常不错了,根本用不到 filebeat 和 ES。 可但是,我们不想为阿里 sls、logstore 出钱买单,就只能用 filebeat + ES 了 说一下 filebeat 的 sidecar 边车(僚机)用法: 如上图所示,简单说就是起一个 filebeat 的 logging-agent 边车(僚机),边车和主应用之间共享某个文件夹(mountPath),达到收集主应用日志并发送到 ES,而不用动 app-container 分毫。 我们以部署一个 Tomcat 应用为例来说明: 一、打造 filebeat 边车镜像 首先准备 Dockerfile FROM alpine:3.12 ARG VERSION=7.15.1 COPY docker-entrypoint.sh / RUN set -x \ && cd /tmp \ && wget https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-${VERSION}-linux-x86_64.tar.gz \ && tar xzvf filebeat-${VERSION}-linux-x86_64.tar.gz \ && mv filebeat-${VERSION}-linux-x86_64 /opt \ && rm /tmp/* \ && chmod +x /docker-entrypoint.sh ENV PATH $PATH:/opt/filebeat-${VERSION}-linux-x86_64 WORKDIR /opt/filebeat-${VERSION}-linux-x86_64 ENTRYPOINT ["/docker-entrypoint.sh"] 我们以 alphine:3.12 为底版,然后下载 filebeat 7.15.1的二进制包并释放到 /opt 下,最后指定入口文件 /docker-entrypoint.sh ...

2021年11月10日 · 2 分钟 · 369 字 · 八戒

haproxy一个端口跑多个服务

我们选择 haproxy 1.8 版本以上的,编译安装到路径 /export/servers/haproxy make TARGET=linux2628 PREFIX=/export/servers/haproxy USE_GETADDRINFO=1 USE_ZLIB=1 USE_REGPARM=1 USE_OPENSSL=1 \ USE_SYSTEMD=1 USE_PCRE=1 USE_PCRE_JIT=1 USE_NS=1 make install PREFIX=/export/servers/haproxy 编辑 haproxy.conf 配置文件: global maxconn 5120 chroot /export/servers/haproxy daemon quiet nbproc 2 pidfile /tmp/haproxy.pid defaults timeout connect 5s timeout client 50s timeout server 20s listen http bind :80 timeout client 1h tcp-request inspect-delay 2s acl is_http req_proto_http tcp-request content accept if is_http server server-http :8080 use_backend ssh if !is_http backend ssh mode tcp timeout server 1h server server-ssh :22 解释一下:我们在 8080 端口开了 http 服务,在 22 端口开了 ssh 服务,80端口由 haproxy 做代理转发,首先判断客户端请求是否是 http 请求,如果是就转发到 8080 端口,如果不是,就转发到 22 端口,这样就实现了 80 端口同时跑 http 和 ssh 两个服务。 ...

2021年11月10日 · 1 分钟 · 102 字 · 八戒

sslh的一个端口同时跑多个服务

Ucloud的机器在两会期间干脆端口全灭,firewall设置进来的端口全关闭!!!!!! 还好有个Global ssh的服务,可以 ssh ubuntu@111.129.37.89.ipssh.net 登录上去,注意,直接ssh ubuntu@111.129.37.89是不通的。 那我们就搭建一个SSLH服务,可以把ssh和openvpn以及ssl服务统统塞到一个端口22里 动手吧 1、修改openssh的端口 从22端口改成2222,千万别重启,22这会先得归ssh用 2、安装sslh sudo apt install sslh vi /etc/default/sslh 找到Run=no 改成Run=yes 然后到下面,按需配置(不跑443的话可以不配) DAEMON_OPTS="--user sslh --listen 0.0.0.0:22 --ssh 127.0.0.1:2222 --ssl 127.0.0.1:443 --openvpn 127.0.0.1:1194 --pidfile /var/run/sslh/sslh.pid --timeout 5" 3、配置sslh并且重启服务器 sudo systemctl enable sslh sudo reboot 就搞定了

2021年11月10日 · 1 分钟 · 43 字 · 八戒