K8S学习笔记(3)-从私有仓库拉取镜像

版权声明 本站原创文章 由 萌叔 发表 转载请注明 萌叔 | http://vearne.cc 1. 前言 警告:本文仅用于萌叔自己总结之用,对其它人而言可能毫无营养,没有阅读价值。 在k8s中要使用自己搭建的私有仓库,还需要一些额外的配置。 萌叔使用的harbor搭建的私有仓库 goharbor/harbor, 假定地址为 https://docker-harbor.vearne.cc 2. 配置过程 要能够成功拉去image,需要解决2个问题 2.1 TLS证书验证 由于我们的私有仓库,使用的自签名的证书,所以需要能够通过TLS的握手阶段对证书。 如果证书认证失败,你可能收到如下错误 [root@xx ~]# docker pull docker-harbor.vearne.cc/ut/helloworld:0.2.6 Error response from daemon: Get https://docker-harbor.vearne.cc/ut/helloworld:0.2.6: x509: certificate signed by unknown authority 一种做法是直接添加CA根证书到操作系统获得信任。但是萌叔尝试后,发现无效。 这里验证有效的做法是,使用dockerd的--insecure-registry参数 2.1.1 修改dockerd的配置文件 默认路径为/etc/docker/daemon.json { "insecure-registries" : ["docker-harbor.vearne.cc"] } 2.1.2 重启dockerd systemctl restart docker 2.2 登录 要想在宿主机拉取镜像,可以用 docker login docker-harbor.vearne.cc 在k8s集群中拉取镜像可以使用 kubectl create secret docker-registry regcred \ --docker-server=<你的镜像仓库服务器> \ --docker-username=<你的用户名> \ --docker-password=<你的密码> \ --docker-email=<你的邮箱地址> 创建一个密钥,用于拉取镜像 检查 Secret regcred kubectl get secret regcred --output="jsonpath={.data.\.dockerconfigjson}" | base64 --decode 输出和下面类似: ...

October 20, 2020 · 1 min

k8s学习笔记(2)-删除namespace失败处理

版权声明 本站原创文章 由 萌叔 发表 转载请注明 萌叔 | http://vearne.cc 1. 前言 警告:本文仅用于萌叔自己总结之用,对其它人而言可能毫无营养,没有阅读价值。 删除namespace出现下面的情况 ╰─$ kubectl get ns NAME STATUS AGE default Active 5d3h ingress-nginx Active 4d22h istio-system Active 4d3h kube-node-lease Active 5d3h kube-public Active 5d3h kube-system Active 5d3h kubernetes-dashboard Active 39m ns-helloworld Terminating 3h56m 2.解决方法 2.1 导出namespace配置 kubectl get namespace ns-helloworld -o json > tmp.json namespace无法删除是因为namespace相关联的资源无法释放。 2.2 清空spec中的内容 2.3 触发 kubectl proxy curl -k -H "Content-Type: application/json" -X PUT --data-binary @tmp.json http://127.0.0.1:8001/api/v1/namespaces/ns-helloworld/finalize 参考资料 kubernetes无法删除namespace 提示 Terminating 请我喝瓶饮料

October 19, 2020 · 1 min

利用docker实现Golang程序的交叉编译

版权声明 本站原创文章 由 萌叔 发表 转载请注明 萌叔 | http://vearne.cc 1. 前言 萌叔有有一个开源项目vearne/passwordbox,用于密码的管理。笔者想法是在Mac上build出多个平台下的bin文件,这样用户,可以无需自己编译,直接使用编译好的bin文件。 可是 vearne/passwordbox 内部依赖了 mattn/go-sqlite3。这个库编译时,依赖操作系统上的共享库,无法直接进行交叉编译。 2. 解决 前段时间,萌叔在阅读buger/goreplay源码时,偶然发现它有一个思路是利用docker来实现Golang交叉编译。于是笔者借鉴了它的思路,修改了passwordbox Makefile。 现在在Mac上执行 make docker-img # 只需要执行一次,生成基础镜像即可 make release 就可以同时生成Mac和linux下的bin文件 pwbox-v0.0.10-darwin-amd64.tar.gz pwbox-v0.0.10-linux-amd64.tar.gz 完整代码见Makefile 2.1 build一个基础镜像用于linux环境的编译 docker-img: docker build --rm -t $(CONTAINER) -f Dockerfile.dev . Dockerfile.dev FROM golang:1.14 RUN apt-get update && apt-get install vim-common -y WORKDIR /go/src/github.com/vearne/passwordbox/ ADD . /go/src/github.com/vearne/passwordbox/ RUN go get golang:1.14 实际是基于Ubuntu的一个镜像(Linux) 2.2 借助Docker实现跨平台编译 release-linux: docker run -v `pwd`:$(SOURCE_PATH) -t -e GOOS=linux -e GOARCH=amd64 -i $(CONTAINER) go build $(LDFLAGS) -o pwbox tar -zcvf pwbox-$(VERSION)-linux-amd64.tar.gz ./pwbox rm pwbox -v pwd:$(SOURCE_PATH) 是为了把项目的代码直接挂载到docker中,这样就无需每次拷贝代码到docker中 ...

August 3, 2020 · 1 min

istio学习笔记(2)-envoy

版权声明 本站原创文章 由 萌叔 发表 转载请注明 萌叔 | http://vearne.cc 1. 前言 本文存在的目的,是为了通过图例的方式更好的整理envoy存在的意义 2. 图示 namespace配置了自动注入(istio-injection:enabled)之后,每个POD都会自动生成1个Sidecar容器 istio-proxy(运行sidecar代理,实现方式为Envoy或MOSN 图示展示服务网格中的请求的情况 2.1 请求网格内部的服务 downstream和upstream是网格内的2个服务的容器 downstream调用upstream 对这种场景,请求穿过需要穿过2个envoy,1个是调用方POD中的envoy, 1个是被调用方POD中的envoy 2.2 请求网格外部的服务 External Service是网格外部的1个服务 对于这种场景,只穿过一次envoy 3. 支持的服务治理功能 请求分发, 按不同版本,以特定权重分发 负载均衡 URL重写 故障注入,包含增加延迟,或者直接拒绝 服务熔断,比如针对5XX执行熔断操作 限频 重试 超时控制 状态统计 QPS/流量/URL/延迟等 这部分信息最后会由prometheus统一收集,最终展现在Grafana和Kiali中 envoy实际是将原来应用中的拦截器以及网关实现的部分功能做了抽取和抽象,使得应用开发人员能够转注于业务逻辑开发。 后记(重要) istio默认不记录日志。如果需要记录请求日志,需要在ConfigMap istio中,增加 accessLogFile: /dev/stdout accessLogEncoding: JSON # 可选值为 JSON或TEXT 另外envoy不支持HTTP1.0,如果发出的请求是HTTP1.0,会收到HTTP Status Code 426,要求升级协议。 参考资料 1.Sidecar 注入及透明流量劫持 2.Istio流量分析 打赏我

July 7, 2020 · 1 min

istio学习笔记(1)-配置Gateway

版权声明 本站原创文章 由 萌叔 发表 转载请注明 萌叔 | http://vearne.cc 1. 前言 萌叔试图通过Gateway把服务暴露在服务网格外部,下面是笔者的一些总结。 2. 体系结构 很重要 gateway-controller <-> ingress-controller (实际的pod) istio-ingressgateway <-> nginx-ingress-controller (一种实现) gateway <-> ingress (配置) gateway-controller的一个实现是 istio-ingressgateway ingress-controller的一个实现是 nginx-ingress-controller nginx-ingress-controller相当于openresty, 配置ingress以后会生成对应nginx的配置文件。同样配置gateway之后, 会生成envoy对应的配置文件。 3. 配置 3.1 istio-ingressgateway 当安装了istio以后,服务中会有一个istio-ingressgateway 默认情况下, istio-ingressgateway对应的容器并没有暴露在服务网格之外。需要修改配置。 修改istio-ingressgateway的 Deployment 也可以直接修改helm的 deployment.yaml "dnsPolicy": "ClusterFirstWithHostNet" # 修改(确保能够正确访问pilot) "hostNetwork": true # 添加 (将pod以host网络模式暴露在服务网格外部) “ClusterFirstWithHostNet“: For Pods running with hostNetwork, you should explicitly set its DNS policy “ClusterFirstWithHostNet”. 3.2 gateway 以对kiali的配置为例 1) 创建namespace kubectl create namespace myistio 2)配置gateway 文件 kiali-gateway.yaml ...

December 5, 2019 · 2 min

玩转consul(3)--大规模部署的性能开销定量分析

版权声明 本站原创文章 由 萌叔 发表 转载请注明 萌叔 | http://vearne.cc 1. 引言 今天有朋友问萌叔,consul能否在大规模生产环境下进行应用。场景是总计大约10w+台机器,分为3 ~ 4个机房,单个机房最多3w万+机器。这个问题大的,可把萌叔吓了跳,部门里面consul集群的规模也就是1k+, 还分好几个机房。 不过他的问题确实也让我十分好奇,consul是否有能力支撑这么规模,我决定针对每个可能性能瓶颈进行定量分析 2. 分析 在进行分析前,我们来看看可能遇到瓶颈有哪些? 下图是consul在多DC情况下的体系架构图 2.1 明确一些概念 consul agent分2种模式server模式和client模式。在每个机房consul server(以下简称为server)会部署3 ~ 5台, 其余的consul节点都是consul client(以下简称为server)。 server的数量不宜过多,否则选主的速度会变慢 数据(包括kv数据,service信息,node信息)都是分机房存储的,由所在机房的server负责。如果需要请求其它机房的数据,则server会将请求转发到对应的机房。 比如dc1的某个应用app1想要获取dc2中key “hello"对应的值 过程如下 app1 --> client --> server(dc1) --> server(dc2) 如果读者仔细观察会发现,consul中,很多api都是可以加上dc参数的 consul kv get hello -datacenter dc2 每个dc的所有server构成一个raft集群,client不参与选主。注意上图的leader和follower标识。 单个机房内部consul节点之间有gossip(端口8301) 机房与机房之间 server节点之间有gossip(端口8302) 2.2 可能的瓶颈 2.2.1 client对server的RPC请求 client使用server的TCP/8300端口发起RPC请求, 管理service、kv都要通过这个端口,它们之间是长连接。 1个机房如果有3w+机器,则client和server至少要建立3w+长连接。 不过萌叔观察了一下,3w+长连接是相对均匀的分布在多个server上的,也就是说如果你有6台consul server, 那么每个server最多处理5k个长连接。还是可以接收的。 对于server的处理能力我简单压测了一下。大约是15k qps Intel(R) Xeon(R) CPU E5-2650 v3 @ 2.30GHz 4核CPU 8G内存 ...

October 25, 2019 · 2 min

玩转Prometheus(4)--发现异常节点

版权声明 本站原创文章 由 萌叔 发表 转载请注明 萌叔 | http://vearne.cc 1. 前言 一个服务常常运行几十或者上百个实例上。通过使用docker容器或者有意的为之,我们会控制实例运行的环境完全一致。因为docker容器所处或者虚拟机是与其他容器或者虚拟机共存的(同一个物理机)。又或者因为物理机的硬件设备的潜在故障,某些实例会表现出异常的行为。(也有可能是程序本身的原因) 如何找到异常节点就变得十分重要。 2. 分析&展示报警 这种节点往往会表现出以下的特点 请求超时 请求错误多 2.1 监控图表 在监控图表上,以非200请求举例,我们可以使用topk列出失败请求最多的实例 topk(3, sum(rate(http_requests_total{project="fake-service", run_mode="product", status!~"200|201|204"}[5m])) by (instance)) 列出HTTP状态码非200的最多的3个实例 图1 从图1我们看出蓝色曲线的实例,非200的HTTP请求数量显著的高于其他实例 2.2 配置报警 参考资料2推荐这样去发现异常实例,如果 某个实例指标的值 > 所有实例指标的平均值 + 2 * 所有实例指标的标准差 那么可能有异常实例存在 DSL floor(max(sum(rate(http_requests_total{project="sdk-api", run_mode="product", status!~"200|201|204"}[5m])) by (instance))) > avg(sum(rate(http_requests_total{project="sdk-api", run_mode="product", status!~"200|201|204"}[5m])) by (instance)) + 2 * stddev(sum(rate(http_requests_total{project="sdk-api", run_mode="product", status!~"200|201|204"}[5m])) by (instance)) 后记 前几天线上就发生了一起这样的故障。找到异常节点,并重启后,故障恢复,报警解出。 参考资料 标准差 Practical Anomaly Detection

April 9, 2019 · 1 min

玩转consul(1)--watch机制探究

版权声明 本站原创文章 由 萌叔 发表 转载请注明 萌叔 | http://vearne.cc 1. 前言 consul 经常被用于服务的注册和发现,本文将带你对watch做更深入的探究 2. consul对外暴露了4种通讯接口 2.1 RPC 主要用于内部通讯Gossip/日志分发/选主等 2.2 HTTP API 服务发现/健康检查/KV存储等几乎所有功能 默认端口为8500 2.3 Consul Commands (CLI) consul命令行工具可以与consul agent进行连接,提供一部分consul的功能。 实时上Consul CLI 默认就是调用的HTTP API来与consul集群进行通讯。 可以通过配置CONSUL_HTTP_ADDR 修改Consul CLI连接的目标地址 export CONSUL_HTTP_ADDR=http://127.0.0.1:8500 详见参考资料3 2.4 DNS 仅用于服务查询 3. 服务注册&发现 3.1 服务注册 服务注册可以通过 服务注册接口 /agent/service/register 很容易做到 3.2 服务发现 3.2.1 DNS方式 $ dig @127.0.0.1 -p 8600 web.service.consul ;; QUESTION SECTION: ;web.service.consul. IN A ;; ANSWER SECTION: web.service.consul. 0 IN A 127.0.0.1 我们可以通过cosul提供的DNS接口来获取当前的service “web” 对应的可用节点(详细用法见参考资料4) DNS方式要求使用方主动进行DNS解析,是主动请求的过程。它对线上服务节点的变化,反应是延迟的。 ...

January 10, 2019 · 2 min

玩转Prometheus(1)--第1个例子

版权声明 本站原创文章 由 萌叔 发表 转载请注明 萌叔 | http://vearne.cc 前言 在工作的这几年里,接触不少监控系统, Nagios、Cacti、Zabbix、Open-falcon, 今年开始在新公司使用Prometheus, 网上有文章把Prometheus 称为新一代的监控系统,我一直很好奇,它的新体现在哪儿,相比与传统的监控系统,它有什么优势。 在经过一段时间的使用以后,我觉得我有了一些体会,下面我们通过1个例子来感受一下。 Prometheus的体系架构图 应用场景 从目前各个公司的实践情况来看,Prometheus主要用于应用服务的监控,尤其是基于docker的应用服务;而像主机的运行情况(cpu使用率、内存使用率),网络设备的监控等,依然由传统的监控系统来做。 1. 模拟的应用服务 假定我们有一个web服务叫fake_service fake_server.go package main import ( "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" "gopkg.in/gin-gonic/gin.v1" "strconv" "strings" "time" ) var ( //HTTPReqDuration metric:http_request_duration_seconds HTTPReqDuration *prometheus.HistogramVec //HTTPReqTotal metric:http_request_total HTTPReqTotal *prometheus.CounterVec ) func init() { // 监控接口请求耗时 // HistogramVec 是一组Histogram HTTPReqDuration = prometheus.NewHistogramVec(prometheus.HistogramOpts{ Name: "http_request_duration_seconds", Help: "The HTTP request latencies in seconds.", Buckets: nil, }, []string{"method", "path"}) // 这里的"method"、"path" 都是label // 监控接口请求次数 // HistogramVec 是一组Histogram HTTPReqTotal = prometheus.NewCounterVec(prometheus.CounterOpts{ Name: "http_requests_total", Help: "Total number of HTTP requests made.", }, []string{"method", "path", "status"}) // 这里的"method"、"path"、"status" 都是label prometheus.MustRegister( HTTPReqDuration, HTTPReqTotal, ) } // /api/epgInfo/1371648200 -> /api/epgInfo func parsePath(path string) string { itemList := strings.Split(path, "/") if len(path) >= 4 { return strings.Join(itemList[0:3], "/") } return path } //Metric metric middleware func Metric() gin.HandlerFunc { return func(c *gin.Context) { tBegin := time.Now() c.Next() duration := float64(time.Since(tBegin)) / float64(time.Second) path := parsePath(c.Request.URL.Path) // 请求数加1 HTTPReqTotal.With(prometheus.Labels{ "method": c.Request.Method, "path": path, "status": strconv.Itoa(c.Writer.Status()), }).Inc() // 记录本次请求处理时间 HTTPReqDuration.With(prometheus.Labels{ "method": c.Request.Method, "path": path, }).Observe(duration) } } func DealAPI1(c *gin.Context) { time.Sleep(time.Microsecond * 10) c.Writer.Write([]byte("/api/api1")) } func DealAPI2(c *gin.Context) { time.Sleep(time.Microsecond * 20) c.Writer.Write([]byte("/api/api2")) } func main() { router := gin.Default() g := router.Group("/api") g.Use(Metric()) g.GET("api1", DealAPI1) g.GET("api2", DealAPI2) // 暴露给Prometheus router.GET("/metrics", gin.WrapH(promhttp.Handler())) router.Run(":28181") } 使用fake_client.go模拟真实用户的请求 完整代码 用法: ...

January 3, 2019 · 2 min

packetbeat 初探

版权声明 本站原创文章 由 萌叔 发表 转载请注明 萌叔 | http://vearne.cc 1. 前言 packetbeat是elastic公司开发的网络抓包、嗅探以及分析工具。 和tcpdump一样,它的底层依赖libpcap。但它比tcpdump、tcpcopy功能强大的多。 它能够直接解析以下的网络协议 ICMP (v4 and v6) DHCP (v4) DNS HTTP AMQP 0.9.1 Cassandra Mysql PostgreSQL Redis Thrift-RPC MongoDB Memcache TLS 将网络包转换成JSON字符串,然后导出到以下output File Console Elasticsearch Logstash Kafka Redis 简单描述过程 event -> filter1 -> filter2 … -> output 让我非常吃惊的是它能够捕获MySQL、Redis等的二进制通讯协议,能够从捕获的记录中,清晰的看到每一条SQL查询语句,以及每一条Redis命令 2. 我们能拿它做什么? 据笔者的了解。 以前做线上的流量复制和重放,大致有这么几种方法 (1) 使用tcpcopy (2) 在服务中引起流量复制模块 (3) 服务打印特殊格式的日志 供后期解析,并做重放 (1)是二进制数据流,人无法阅读,(2)、(3)对服务有入侵,不够友好。 JSON格式的数据,对程序优化,对人来说阅读的障碍也不大。个人认为是个不错的选择 有了这些捕获的数据,我们可以用来做 线上排障 服务功能测试/压力测试 对请求(HTTP请求,MySQL、Redis请求等)进行统计分析,为服务优化提供必要的数据支持。 3. 安装&配置&使用 3.1 安装 见参考资料4 ...

December 17, 2018 · 2 min