面试之Docker如何打出最小的镜像

面试的时候被问到:如何才能让 docker 打出的镜像包尽量小? 其实在生产已经尽量使用最小化的镜像包了,只是突然被问到还是有点懵圈;因为印象中自己基本是使用 alphine 做底包,Dockerfile 通常就是 copy 一个可执行的程序进去就完事了,如果不行,再开 shell 进去慢慢添加缺少的库文件。 这里就总结一下,两点: 一、使用尽量小的底包 以 alphine 为主,使用 alphine 底包的时候,需要注意以下: 1、替换 apk 的源 2、更新、更新证书 3、注意 Timezone 的设置 4、注意 glibc 库的兼容问题 二、使用分阶段build 通常类似c、go、rust之类的源代码,都需要经过编译,最后产生可执行文件,那么完整的编译环境其实对最后的镜像来说都是不需要的。 所以利用分阶段build,甩脱编译环境以及中间产物,就可以缩小最后 build 出镜像的大小,使用也很简单。 Dockerfile 文件内容如下: FROM golang:alpine AS build-env WORKDIR /app ADD . /app RUN cd /app && go build -o goapp FROM alpine RUN apk update && \ apk add ca-certificates && \ update-ca-certificates && \ rm -rf /var/cache/apk/* WORKDIR /app COPY --from=build-env /app/goapp /app EXPOSE 8080 ENTRYPOINT ./goapp

2022年04月01日 · 1 分钟 · 80 字 · 八戒

面试之Nginx的epoll的优势

面试时被问到:是否了解 Nginx,它使用的 epoll 模式和其他的相比有什么优势? 直接被问住,实际生产中配过不少的 Nginx,各种 rewrite、regex、正反向代理、php、fast-cgi、限流、证书、jwt、cors;epoll 只大概有印象是下面这行: events { use epoll; worker_connections 1024; } 实在是汗颜啊,所以得仔细研究一下这个 epoll。 首先扔概念 IO多路复用: 多路是指网络连接,复用指的是同一个线程。 IO多路复用是一种同步IO模型,实现一个线程可以监视多个文件描述符; 一旦某个描述符就绪(一般是读就绪或者写就绪),就能够通知应用程序进行相应的读写操作; 没有文件描述符就绪时会阻塞应用程序,交出cpu。 那么IO多路复用的实现方法有三种: select、poll、epoll select、poll、epoll本质上都是同步I/O,用户进程(这里就是Nginx)负责读写(从内核空间拷贝到用户空间),读写过程中,用户进程是阻塞的。 select: 查询 fd_set 中,是否有就绪的 fd,可以设定一个超时时间,当有 fd (File descripter) 就绪或超时返回; fd_set 是一个位集合,大小是在编译内核时的常量,默认大小为 1024 特点: 连接数限制,fd_set 可表示的 fd 数量太小了; 线性扫描:判断 fd 是否就绪,需要遍历一边 fd_set; 数据复制:从内核空间拷贝到用户空间,复制连接就绪状态信息 poll: 解决了连接数限制: poll 中将 select 中的 fd_set 替换成了一个 pollfd 数组 解决 fd 数量过小的问题 数据复制:从内核空间拷贝到用户空间,复制连接就绪状态信息 epoll:event 事件驱动 事件机制:避免线性扫描 为每个 fd,注册一个监听事件 fd 变更为就绪时,将 fd 添加到就绪链表 ...

2022年04月01日 · 1 分钟 · 129 字 · 八戒

Kubernetes下Flannel网络

现在各大公有云的 k8s 网络插件基本用的都是 vxlan,我们也需要对这个进行一下详细了解,以便用于公司的正式生产环境。 一、原理 首先,kubernetes的网络模型: 包含三要素: 所有的容器(container)之间能够在不使用 NAT 的情况下互相通讯 所有的节点(Node)能够在不使用 NAT 的情况下跟所有的容器(container)互相通讯(反之容器访问节点亦然) 容器(container)中的IP地址,在容器内和容器外面看起来是一样的 那来到 flannel,它是一种 Overlay network 覆盖网络,盖在原有的 Node 网络基础上: 上图要仔细分析, K8S 中存在三个+一个网络段: node 网络段,上图是 172.20.32.0/19,这是基础网络段 pod 网络段,100.96.0.0/16,2¹⁶(65536)个IP,这是由 flannel 产生的 overlay network,所有的 pod 都站在一个大广场上,互相可见 svc 网络段,上图未提,我们需要知道,想要把 pod 的 ip 给固定下来,就得使用 svc 来分配固定的域名,这个是由 iptables 来维护的 In-Host docker network网络段,这是每个 Node 主机的单独网络段,flannel给每个 Node 主机划分了一个 100.96.x.0/24 段,然后在 etcd 内进行维护,来避免不同的 Node 主机分配IP冲突。 综述:flannel 为每个 Node 分配一个 subnet,容器(container)从此 subnet 中分配 IP,这些 IP 可以在 Node 间路由,容器间无需 NAT 和 port mapping 就可以跨主机通信。 ...

2022年03月17日 · 3 分钟 · 462 字 · 八戒

ucarp的安装配置

有 V2EX 的坛友问到如何静态编译 keepalived 的问题,实际上 keepalived 确实配置比较麻烦。那还有一个简单易行的 ucarp,生产也可以用这个。 ucarp 跟 keepalived 一样,都是用于高可用的 IP 漂移 但是比 keepalived 配置简单,而且 opnsense 就是用的这个做的高可用,opnsense 是个非常可靠的防火墙软件。 首先有两台虚机,172.18.19.1和172.18.19.2,虚拟ip是172.18.19.3 先配置172.18.19.1 yum install epel-release yum install psmisc yum install ucarp cat<< EOF >> /etc/systemd/system/ucarp.service [Unit] Description=UCARP virtual interface After=network.target [Service] Type=simple ExecStart=/usr/local/bin/ucarp.sh RemainAfterExit=true ExecStop=/usr/bin/killall -SIGTERM ucarp ExecStop=/bin/sleep 10 TimeoutStopSec=30 StandardOutput=journal [Install] WantedBy=multi-user.target EOF 注意,上面我们的systemd是直接调用了ucarp.sh来启动,这样更简单。 三个脚本,注意权限是755 cat<< EOF >> /usr/local/bin/ucarp.sh #!/bin/bash' /usr/sbin/ucarp -i eth0 -B -p nb1Dshiwode -v 001 -a 172.18.19.3 -s 172.18.19.1 --shutdown --preempt -u /usr/local/bin/vip-up.sh -d /usr/local/bin/vip-down.sh EOF cat<< EOF >> /usr/local/bin/vip-up.sh #!/bin/sh /sbin/ip addr add ${2}/24 dev ${1} /sbin/ip neigh flush dev ${1} EOF cat<< EOF >> /usr/local/bin/vip-down.sh #!/bin/sh /sbin/ip addr del ${2}/24 dev ${1} /usr/sbin/arp -d ${2} EOF chmod 755 /usr/local/bin/ucarp.sh /usr/local/bin/vip-up.sh /usr/local/bin/vip-down.sh ok,第一台机器就配置好了 ...

2022年02月25日 · 1 分钟 · 174 字 · 八戒

gost tunnel的使用

用过了好几个 tunnel 工具软件,各有长处。 ghostunnel 是支持自定义 tls 证书加密的,这回用个更厉害的,支持各种代理链条的,gost 项目地址:https://github.com/ginuerzh/gost 里面的概念有点意思,其实就两条,-L 本地监听,-F 链条转发。 注意的就一点,-F 的时候实际是一个中转服务器。这个中转服务器要转发的规则需要在 -L 参数里指定。 那么举个具体的例子: 中转服务器开了一个明文端口 9999,这个端口跑的是 ghostunnel client,加密数据后传到另外一个ghostunnel server服务器,然后数据明文穿出,访问具体的目的网站的端口。 客户端的服务器呢无外网访问权限,需要访问中转服务器 192.168.1.1 的 9999 端口,然后数据通过 ghostunnel 加密穿出到外网。 中转服务器配置如下: # ghostunnel 监听本地环回地址的9999端口,TLS 加密穿越到外网110.114.5.19:9999,然后根据外网 server 里面的配置,到达最终目的地 ip 和 端口 ghostunnel client --listen localhost:9999 --target 110.114.5.19:9999 --keystore client.pem --cacert ca.pem --unsafe-listen # gost 监听本地网卡192.168.1.1的9999端口 gost-linux-amd64-2.11.1 -L=tls://192.168.1.1:9999 客户端配置如下: gost-linux-amd64-2.11.1 -L=tcp://localhost:9999/localhost:9999 -F=tls://192.168.1.1:9999 这样客户端的程序,只要连接 localhost:9999 的 tcp 端口,就可以接力中转服务器穿出去了。 上面的配置非常怪异吧,仔细解释一下: 中转服务器呢有两个地址,localhost的环回地址,以及本地网卡192.168.1.1 localhost:9999 是用 ghostunnel 加密 tcp 流量,tls 穿到外网 110.114.5.19 的 9999 端口,然后外网再转发。 ...

2022年02月24日 · 1 分钟 · 99 字 · 八戒

KVM下宿主机的目录直通到虚机

这个需求也很有点意思,DBA 要求做 MySQL 的卸载从库,数据量会很大,硬盘空间后期需要扩容,但是 cpu 反倒占的不多。 单独 MySQL 是无法限制其 CPU 核使用的,这样的话,最好就是做个虚机来控制 MySQL 总 CPU 核数的使用,然后硬盘扩容的话,比如要拉伸虚机的附加第二块硬盘,如果是 QEMU 格式,会花费很长时间,所以干脆把宿主机的目录直接透传进虚机,之后如果要扩容加硬盘,直接把新的大硬盘 mount 出来再透进去即可,新旧硬盘拷贝数据也比拉伸虚机硬盘快。 CentOS7 下的做法如下: 两个大前提: 一、宿主机的 KVM qemu 系统需要使用新的 rpm 包,需要编译 二、虚机的内核需要升级,mount 命令需要支持 -t p9 的新格式 我们做好准备,就可以开始了 一、编译宿主机的qemu新包 现在已经是2022年了,所以编译的方式也发生变化了,最佳编译方式是干脆启动一个 Docker 虚拟机,来编译出来 rpm 包,也不污染环境。 首先克隆下来项目: git clone https://github.com/AlekseyChudov/qemu-kvm-virtfs.git cd qemu-kvm-virtfs 看一下最后的 build 脚本,有一个地方需要修改: 现在的 CentOS 最新版是 7.9.2009 ,这个版本树里是没有 qemu 的 Source Code 的,需要修改 baseurl,降低到 7.8.2003 才有 Source 的 repo baseurl=https://mirrors.tripadvisor.com/centos-vault/centos/\$releasever/virt/Source/kvm-common/ 改成: baseurl=https://mirrors.tripadvisor.com/centos-vault/centos/7.8.2003/virt/Source/kvm-common/ 改好后 build 脚本如下 ...

2022年02月23日 · 2 分钟 · 276 字 · 八戒

如何用CPU挖Polygon网络的MATIC币

这是个严肃话题,正经挖以太币的话,很多的矿厂都是如果直接挖到以太币地址,那么必须挖到完整一个才允许提现,手续费还特高。 但是如果挖到以太链Polygon的地址的话,就可以 0.005 ETH提币了,如下图所示 但是千万记住,Polygon提出的所谓 0.005 ETH,看下图,只是个ERC-20的Token,实际是wETH Token,必须经过转换才能提到 ETH 去。 从 ERC-20 转换到其它代币呢,需要 MATIC 代币来付账,这玩意也必须得有啊!废话不多说,直接放上挖MATIC教程,我的机器是 CentoOS 首先需要有个完全自主的的 ETH 钱包地址,这个我就不教大家了 一、下载xmrig挖矿软件 下载地址:https://github.com/xmrig/xmrig/releases 我们选择最近的下载就好 二、做好加密通道 我们需要做好一条加密tcp通道 用 ghostunnel, localhost:9012 —> vps:9012 —> rx.unmineable.com:3333 三、用screen后台开挖 screen #./xmrig -o localhost:9999 -a rx -k -u DOGE:MATIC地址.矿工名 ./xmrig -o localhost:9012 -u MATIC:0x64358C7ddC96001697aBbA7ed431BADB6ABAaec5.cpu01 -p x --cpu-no-yield ctrl+a+d 四、查看挖了多少 查看地址:https://unmineable.com/coins/MATIC/address/ 五、兑换 挖到了足够的 MATIC,就可以愉快的兑换了。

2022年02月22日 · 1 分钟 · 55 字 · 八戒

Grafana画出prometheus的图

公司要做阿里的小程序接入,需要通过测试,测试呢需要提供硬盘的监控报告,比如 iops 。 同事从网上找了一下,iops 监控原文如下:监控磁盘的 iops ,利用 linux 的 /proc/diskstats 的第四个字段和第八字段可监控读和写的 iops,第四个记录是记录所有读的次数,第八个字段是记录所有写的次数。通过 zabbix 上的差速率即可监控磁盘的 iops。 文章链接:https://cloud.tencent.com/developer/article/1519113?ivk_sa=1024320u 仔细研究了一下上面的文章,看了它提供了两张监控图,分析一下: 第一张图: 有两个指标,绿色的是硬盘每秒的 io 读次数,红色的是硬盘每秒的 io 写次数。 第二张图: 同样两个指标,绿色的是硬盘每秒的 io 读 Bytes,红色的是硬盘每秒的 io 写 Bytes。 知道了指标具体的含义,这样就好办了。 我们用的是 prometheus 和 node_exporter 首先去看看 node_exporter 暴露的指标,搜一搜 node_disk,会看到如下4个指标: # HELP node_disk_reads_completed_total The total number of reads completed successfully. # TYPE node_disk_reads_completed_total counter node_disk_reads_completed_total{device="sda"} 4.9530358e+07 # HELP node_disk_writes_completed_total The total number of writes completed successfully. # TYPE node_disk_writes_completed_total counter node_disk_writes_completed_total{device="sda"} 1.4449267304e+10 # HELP node_disk_read_bytes_total The total number of bytes read successfully. # TYPE node_disk_read_bytes_total counter node_disk_read_bytes_total{device="sda"} 6.4101677568e+11 # HELP node_disk_written_bytes_total The total number of bytes written successfully. # TYPE node_disk_written_bytes_total counter node_disk_written_bytes_total{device="sda"} 1.15483858333184e+14 可以看出是上面 4 个指标,这四个指标都是 counter 计数器类型的,都是只增不减的。 ...

2022年01月18日 · 1 分钟 · 188 字 · 八戒

Javascript的项目与babel和eslint

最近开始弄hubot,顺带也开始学习 javascript ,首先从单独一个 nodejs 项目开始: nvm 和 node 的安装使用在前面已经说过了: Nodejs多版本的安装与管理 新建一个项目目录,build01 然后在其下建立如下目录结构: mkdir build01 cd build01 mkdir es6 dist mkdir public cd public mkdir es6 dist 解释一下,es6 下放的是服务器端的源代码,dist 下放的是服务器端处理过的源代码。 public/es6 放的是浏览器端的源代码,public/dist 放的是浏览器端处理过的源代码。 一、安装gulp和babel babel 是用来做 js 格式转换的,注意,原有的 babel-preset-es2015 已经不适用了。 npm install --save-dev gulp gulp-babel babel-preset-env@next 生成一个.babelrc 文件,内容就一行 { "presets": ["env"] } 在 es6 目录下,建立一个测试的 test.js 文件,内容如下: 'use strict'; const sentences = [ { subject: 'JavaScript', verb: 'is', object: 'great' }, { subject: 'Elephants', verb: 'are', object: 'large' }, ]; function say({ subject, verb, object }) { console.log(`${subject} ${verb} ${object}`); } for ( let s of sentences) { say(s); } 仔细看,上面这个文件用到了 es6 的语法,对象的解构,of语法。 ...

2022年01月04日 · 3 分钟 · 512 字 · 八戒

hubot集成企业微信+jenkins+ansible

Hubot是一个通用的聊天机器人,能和很多聊天软件集成,比如slack、rockchat、telegram、企业微信、IRC等。 公司用的是企业微信,之前用群机器人和 prometheus 集成,发送各种告警信息,但是群机器人无法接收消息;同时我们想集成进去很多自定义命令,比如发送指令就开始 jenkins build,发送 ansible 指令执行,发送流量图就自动把机房的流量图发过来,这个群机器人就用不成了。所以必须再直接一些,构建一个企业微信的应用。 一、企业微信安装前准备 安装前需要在企业微信中拿到4个信息: WECHATWORK_CORP_ID WECHATWORK_APP_AGENT_ID WECHATWORK_APP_SECRET WECHATWORK_AES_KEY 首先联系企业微信管理员新增一个应用: 在“管理后台-我的企业”中可以获得地一个信息,企业 ID 信息,CORP_ID : 拿拿 在“管理后台-应用管理-点击某具体应用-详情”页中可以获得二、三个信息, APP_AGENT_ID 和 APP_SECRET 第四个 AES_KEY 就比较麻烦了,我们进入这个应用,点击配置的图标: 然后进入,点击启用 API 接收 然后设置一下 url 填写 https://hubot.rendoumi.com/wechatwork/webhook Token 点随机获取 EncodingAESKey 点随机获取,这就是具体的 AESKey 了 然后点击保存,这里必然会失败!没有关系,因为我们还没有装hubot呢。我们把这三个地方先记录下来,随后再来点击保存。 二、Hubot 安装前准备 1、注意上面地址:URL 地址是 https ,然后 hubot 的缺省地址是 http://xxx:8080 ,这样如果前面没有证书卸载的设备,就得搭建一个Nginx(haproxy、traefik)来代理 https 443端口到8080。 2、Hubot 是支持 Coffeescript 和 nodejs 的,从它的 Adapters 网页看 https://hubot.github.com/docs/adapters/development/ 里面都是 coffee 味的单箭头函数,导致不太熟悉的八戒以为在 wechatwork module导出的时候也应该用单箭头函数,结果就悲剧了。 ...

2021年12月22日 · 4 分钟 · 675 字 · 八戒