September 13, 2021
利用 docker buildx 构建多平台镜像
"\u003ch1 id=\"什么是-docker-buildx\"\u003e什么是 docker buildx\u003c/h1\u003e\n\u003cp\u003eDocker Buildx是一个CLI插件,它扩展了Docker命令,完全支持Moby BuildKit builder toolkit提供的功能。它提供了与docker build相同的用户体验,并提供了许多新功能,如创建作用域生成器实例和针对多个节点并发构建。\u003c/p\u003e\n\u003cp\u003eDocker Buildx包含在Docker 19.03中,并与以下Docker Desktop版本捆绑在一起。请注意,必须启用“实验特性”选项才能使用Docker Buildx。\u003c/p\u003e\n\u003cp\u003eDocker Desktop Enterprise version 2.1.0\nDocker Desktop Edge version 2.0.4.0 or higher\u003c/p\u003e\n\u003ch1 id=\"用法\"\u003e用法\u003c/h1\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003eUsage: docker buildx [OPTIONS] COMMAND\n\nExtended build capabilities with BuildKit\n\nOptions:\n --builder string Override the configured builder instance …\u003c/code\u003e\u003c/pre\u003e"
August 16, 2021
k8s安装负载均衡器:Metallb
"\u003cp\u003e在使用kubenetes的过程中,如何将服务开放到集群外部访问是一个重要的问题。当使用云平台(阿里云、腾讯云、AWS等)的容器服务时,我们可以通过配置 service 为 \u003cstrong\u003eLoadBalancer\u003c/strong\u003e 模式来绑定云平台的负载均衡器,从而实现外网的访问。但是,如果对于自建的 kubernetes裸机集群,这个问题则要麻烦的多。\u003c/p\u003e\n\u003cp\u003e祼机集群不支持负载均衡的方式,可用的不外乎NodePort、HostNetwork、ExternalIPs等方式来实现外部访问。但这些方式并不完美,他们或多或少都存在的一些缺点,这使得裸机集群成为Kubernetes生态系统中的二等公民。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/metallb/metallb\"\u003eMetalLB\u003c/a\u003e 旨在通过提供与标准网络设备集成的Network LB实施来解决这个痛点,从而使裸机群集上的外部服务也尽可能“正常运行”,减少运维上的管理成本。它是一种纯软件的解决方案,参考 \u003ca href=\"https://kubernetes.github.io/ingress-nginx/deploy/baremetal/\"\u003ehttps://kubernetes.github.io/ingress-nginx/deploy/baremetal/\u003c/a\u003e。\u003c/p\u003e\n\u003cp\u003e从 v0.13.0 版本开始,官方对解决方案进行了部分调整,操作步骤简洁一些,建议使用最新版本, …\u003c/p\u003e"
August 7, 2021
服务网格Istio之服务入口 ServiceEntry
"\u003cp\u003e使用服务入口(Service Entry) 来添加一个服务入口到 Istio 内部维护的服务注册中心。添加了服务入口后,Envoy 代理可以向服务发送流量,就好像它是网格内部的服务一样,可参考 \u003ca href=\"https://istio.io/latest/zh/docs/concepts/traffic-management/#service-entries\"\u003ehttps://istio.io/latest/zh/docs/concepts/traffic-management/#service-entries\u003c/a\u003e。\u003c/p\u003e\n\u003cp\u003e简单的理解就是允许内网向外网服务发送流量请求,但你可能会说正常情况下在pod里也是可以访问外网的,这两者有什么区别呢?\u003c/p\u003e\n\u003cp\u003e确实默认情况下,Istio 配置 Envoy 代理可以将请求传递给外部服务。但是无法使用 Istio 的特性来控制没有在网格中注册的目标流量。这也正是 ServiceEntry 真正发挥的作用,通过配置服务入口允许您管理运行在网格外的服务的流量。\u003c/p\u003e\n\u003cp\u003e此外,可以配置虚拟服务和目标规则,以更精细的方式控制到服务条目的流量,就像为网格中的其他任何服务配置流量一样。\u003c/p\u003e\n\u003cp\u003e为了更好的理解这一块的内容,我们先看一下普通POD发送请求的流程图\u003cimg src=\"https://blogstatic.haohtml.com/uploads/2021/08/d2b5ca33bd970f64a6301fa75ae2eb22.png\" alt=\"\"\u003e普通 Pod 请求\u003c/p\u003e\n\u003ch1 id=\"创建-serviceentry-资源\"\u003e创建 ServiceEntry 资源\u003c/h1\u003e\n\u003cp\u003e举例来说:\u003c/p\u003e\n\u003cp\u003esvc-entry.yaml …\u003c/p\u003e"
July 31, 2021
在linux下安装Kubernetes
"\u003cp\u003e环境 ubuntu18.04 64位\u003c/p\u003e\n\u003cp\u003eKubernetes v1.21.3\u003c/p\u003e\n\u003cp\u003e这里需要注意,本教程安装的k8s版本号 \u003ccode\u003e\u0026lt;- v1.24.0\u003c/code\u003e,主要是因为从v1.24.0以后移除了 \u003ccode\u003eDockershim\u003c/code\u003e,无法继续使用 \u003ccode\u003eDocker Engine\u003c/code\u003e,后续将默认采用 \u003ca href=\"https://containerd.io/\"\u003econtainerd\u003c/a\u003e ,它是一个从 CNCF 毕业的项目。如果仍想使用原来 \u003ccode\u003eDocker Engine\u003c/code\u003e 的方式可以安装 \u003ca href=\"https://github.com/Mirantis/cri-dockerd\"\u003ecri-dockerd\u003c/a\u003e ,它是 Dockershim 的替代品。\u003c/p\u003e\n\u003cp\u003e如果你想将现在 Docker Engine 的容器更换为 \u003ccode\u003econtainerd\u003c/code\u003e,可以参考官方迁移教程 \u003ca href=\"https://kubernetes.io/zh-cn/docs/tasks/administer-cluster/migrating-from-dockershim/change-runtime-containerd/\"\u003e将节点上的容器运行时从 Docker Engine 改为 containerd\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e为了解决国内访问一些国外网站慢的问题,本文使用了国内阿里云的镜像。\u003c/p\u003e\n\u003ch1 id=\"更换apt包源\"\u003e更换apt包源\u003c/h1\u003e\n\u003cp\u003e这里使用aliyun镜像 , 为了安全起见,建议备份原来系统默认的 /etc/apt/sources.list 文件\u003c/p\u003e\n\u003cp\u003e编辑文件 /etc/apt/sources.list,将默认网址 或 替换为\u003c/p\u003e\n\u003cp\u003e更新缓存\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$ sudo apt-get clean all\n$ sudo …\u003c/code\u003e\u003c/pre\u003e"
June 27, 2021
SPIFFE 学习参考资料
"\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/spiffe/spiffe/blob/main/standards/SPIFFE_Workload_API.md\"\u003eThe SPIFFE Workload API\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"https://www.scriptjc.com/article/1097\"\u003eEnvoy spiffe spire\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"https://blog.csdn.net/dnc8371/article/details/106701159\"\u003e简而言之SPIFFE\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"https://cloud.tencent.com/developer/article/1549231\"\u003eSPIFFE信任域\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"https://segmentfault.com/a/1190000018432444\"\u003e使用SPIRE(自动)提供TLS证书给Envoy以进行更强大的身份验证\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"https://segmentfault.com/a/1190000017881797\"\u003e谁使用SPIFFE?\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"https://blog.envoyproxy.io/securing-the-service-mesh-with-spire-0-3-abb45cd79810\"\u003eSecuring the Service Mesh with SPIRE 0.3\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e"
May 23, 2021
Golang中的runtime.LockOSThread 和 runtime.UnlockOSThread
"\u003cp\u003e在runtime中有 \u003ccode\u003e[runtime.LockOSThread](https://github.com/golang/go/blob/go1.16.3/src/runtime/proc.go#L4248-L4278)\u003c/code\u003e 和 \u003ccode\u003e[runtime.UnlockOSThread](https://github.com/golang/go/blob/go1.16.3/src/runtime/proc.go#L4302-L4323)\u003c/code\u003e 两个函数,这两个函数有什么作用呢?我们看一下标准库中对它们的解释。\u003c/p\u003e\n\u003ch2 id=\"runtimelockosthread\"\u003eruntime.LockOSThread\u003c/h2\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e// LockOSThread wires the calling goroutine to its current operating system thread.\n// The calling goroutine will always execute in that thread,\n// and no other goroutine will execute in it,\n// until the calling goroutine has made …\u003c/code\u003e\u003c/pre\u003e"
May 21, 2021
认识无锁队列
"\u003cp\u003e\u003ccode\u003e无锁队列\u003c/code\u003e是 \u003ccode\u003elock-free\u003c/code\u003e 中最基本的数据结构,一般应用在需要一款高性能队列的场景下。\u003c/p\u003e\n\u003cp\u003e对于多线程用户来说,无锁队列的入队和出队操作是线程安全的,不用再加锁控制\u003c/p\u003e\n\u003ch1 id=\"什么是无锁队列\"\u003e什么是无锁队列\u003c/h1\u003e\n\u003cp\u003e队列每个开发者都知道,那么什么又是无锁队列呢?字面理解起来就是一个无锁状态的队列,\u003ccode\u003e多个线程(消费者)\u003c/code\u003e同时操作数据的时候不需要加锁,因为加/解锁都是一个很消耗资源的动作。\u003c/p\u003e\n\u003ch1 id=\"实现原理\"\u003e实现原理\u003c/h1\u003e\n\u003cp\u003e我们先看一下无锁队列的底层实现数据结构。\u003c/p\u003e\n\u003ch2 id=\"数据结构\"\u003e数据结构\u003c/h2\u003e\n\u003cp\u003e无锁队列底层的数据结构实现方式主要有两种:\u003ccode\u003e数组\u003c/code\u003e 和 \u003ccode\u003e链接\u003c/code\u003e。\u003c/p\u003e\n\u003ch3 id=\"数组\"\u003e数组\u003c/h3\u003e\n\u003cp\u003e在首次初始化时,需要申请\u003ccode\u003e一块连接\u003c/code\u003e的\u003ccode\u003e大\u003c/code\u003e的内存。读写数据直接从数据的指定位置操作即可,时间复杂度为O(1)。\u003c/p\u003e\n\u003cp\u003e缺点:数组长度有限,一旦数组索引位置写满,则无法继续写入,即队列有上限。\u003c/p\u003e\n\u003ch3 id=\"链表\"\u003e链表\u003c/h3\u003e\n\u003cp\u003e不用像数组一样,刚开始就申请一块连接的大的内存空间。只有在每次写时数据的时候,申请这个数据节点大小的内存即可,这样就可以实现无限的写入,没有长度限制问题。\u003c/p\u003e\n\u003cp\u003e缺点:每次写数据都要申请内存,在写的场景,最差的情况是多少个数据就申请多少次内存,而每次申请都是一个消耗资源的动作。\u003c/p\u003e\n\u003cp\u003e可以看到无锁底层的实现的不同各有优势。多数据情况下,我们都采 …\u003c/p\u003e"
May 10, 2021
Runtime: goroutine的暂停和恢复源码剖析
"\u003cp\u003e上一节《 \u003ca href=\"https://blog.haohtml.com/archives/27003\"\u003eGC 对根对象扫描实现的源码分析\u003c/a\u003e》中,我们提到过在GC的时候,在对一些goroutine 栈进行扫描时,会在其扫描前触发 G 的暂停(\u003ccode\u003e[suspendG](https://github.com/golang/go/blob/go1.16.2/src/runtime/preempt.go#L76-L254)\u003c/code\u003e)和恢复(\u003ccode\u003e[resumeG](https://github.com/golang/go/blob/go1.16.2/src/runtime/preempt.go#L256-L280)\u003c/code\u003e)。\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e// markroot scans the i\u0026#39;th root.\n//\n// Preemption must be disabled (because this uses a gcWork).\n//\n// nowritebarrier is only advisory here.\n//\n//go:nowritebarrier\nfunc markroot(gcw *gcWork, i uint32) {\n\tbaseFlushCache := uint32(fixedRootCount) …\u003c/code\u003e\u003c/pre\u003e"
May 7, 2021
goroutine栈的申请与释放
"\u003cp\u003e对于提高对 stack 的使用效率,避免重复从heap中分配与释放,对其使用了 \u003ccode\u003epool\u003c/code\u003e 的概念,\u003ccode\u003eruntime\u003c/code\u003e 里为共提供了两个pool, 分别为 \u003ccode\u003estackpool\u003c/code\u003e ,另一个为 \u003ccode\u003estackLarge\u003c/code\u003e。\u003cimg src=\"https://blogstatic.haohtml.com/uploads/2022/05/b33bde90901d27dd591e65c12e007fa2.png\" alt=\"\"\u003estack pool\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003estackpool\u003c/code\u003e: 16b~32k 对应通用的大小的stack。获取时通过调用 \u003ccode\u003estackpoolalloc()\u003c/code\u003e, 释放时调用 \u003ccode\u003estackpoolfree()\u003c/code\u003e。\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003estackLarge\u003c/code\u003e:对应 \u0026gt; 32K 的 stack\u003c/p\u003e\n\u003cp\u003e在程序全局调度器 \u003ca href=\"https://github.com/golang/go/blob/go1.16.3/src/runtime/proc.go#L634\"\u003e初始化\u003c/a\u003e 时会通过调用 \u003ccode\u003estackinit()\u003c/code\u003e 实现对 \u003ccode\u003estack\u003c/code\u003e 初始化。\u003c/p\u003e\n\u003cp\u003e当我们执行一个 \u003ccode\u003ego func()\u003c/code\u003e 语句的时候,\u003ccode\u003eruntime\u003c/code\u003e 会通过调用 \u003ccode\u003enewproc()\u003c/code\u003e 函数来创建G。而内部真正创建G的函数为 \u003ccode\u003e[newproc1()](https://github.com/golang/go/blob/go1.16.3/src/runtime/proc.go#L3990-L4098)\u003c/code\u003e,在没有G可以复用的情况下,会通过 \u003ccode\u003enewg = malg(_StackMin)\u003c/code\u003e 语句创建一个\u003cstrong\u003e包含stack\u003c/strong\u003e的G。\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e// Allocate a …\u003c/code\u003e\u003c/pre\u003e"
May 7, 2021
Golang的GPM 模型在网络编程中存在的问题
"\u003ch2 id=\"现状\"\u003e现状\u003c/h2\u003e\n\u003cp\u003e目前在网络编程中,golang采用的是一种 \u003ccode\u003egoroutine-per-connection\u003c/code\u003e 的模式,即为每一个连接都分配一个goroutine,一个连接就是一个goroutine,多个连接之间没有关系。\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003epackage main\n\nimport (\n\t\u0026#34;fmt\u0026#34;\n\t\u0026#34;io/ioutil\u0026#34;\n\t\u0026#34;net\u0026#34;\n\t\u0026#34;time\u0026#34;\n)\n\n//模拟server端\nfunc main() {\n\ttcpServer, _ := net.ResolveTCPAddr(\u0026#34;tcp4\u0026#34;, \u0026#34;:8080\u0026#34;)\n\tlistener, _ := net.ListenTCP(\u0026#34;tcp\u0026#34;, tcpServer)\n\n\tfor {\n\t\t//当有新客户端请求时拿到与客户端的连接\n\t\tconn, err := listener.Accept()\n\t\tif err != nil {\n\t\t\tfmt.Println(err)\n\t\t\tcontinue\n\t\t}\n\n\t\t// …\u003c/code\u003e\u003c/pre\u003e"
May 1, 2021
Linux 内核select、poll 和 eventpoll 的实现
"\u003cp\u003eLinux 内核仓库 \u003ca href=\"https://github.com/torvalds/linux\"\u003ehttps://github.com/torvalds/linux\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eLinux 内核文档: \u003ca href=\"https://www.kernel.org/doc/html/latest/index.html\"\u003ehttps://www.kernel.org/doc/html/latest/index.html\u003c/a\u003e( \u003ca href=\"https://www.kernel.org/doc/html/latest/translations/zh_CN/index.html\"\u003e中文\u003c/a\u003e)\u003c/p\u003e\n\u003cp\u003e开发工具参考: \u003ca href=\"https://www.kernel.org/doc/html/latest/dev-tools/index.html\"\u003ehttps://www.kernel.org/doc/html/latest/dev-tools/index.html\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e也可以使用 VSCode + 插件C/C++ GNU Global\u003c/p\u003e\n\u003cp\u003e通过前面三个博客可以得知 \u003ca href=\"https://blog.csdn.net/weixin_38537730/article/details/104097648\"\u003e\u003cstrong\u003eselect\u003c/strong\u003e\u003c/a\u003e,** \u003ca href=\"https://blog.csdn.net/weixin_38537730/article/details/104099183\"\u003epoll\u003c/a\u003e\u003cstrong\u003e,\u003c/strong\u003e \u003ca href=\"https://blog.csdn.net/weixin_38537730/article/details/104093556\"\u003eeventpoll\u003c/a\u003e** 的详细实现,现在来总结对比下它们之间的不同:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\u003cstrong\u003eselect 流程图\u003c/strong\u003e\n\u003cimg src=\"https://blogstatic.haohtml.com/uploads/2021/05/cf1f47a3a2058cac1ffe1376a5825bb8.jpg\" alt=\"93c50bd46eded3432584b819b8c1e7cd\"\u003e\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003epoll 流程图\u003c/strong\u003e\n\u003cimg src=\"https://blogstatic.haohtml.com/uploads/2021/05/05795514077440f88ef0622e88fc6eb1.jpg\" alt=\"118c7aba5835cf06e006a1834dbe9f40\"\u003e\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eeventpoll 流程图\u003c/strong\u003e\n\u003cimg src=\"https://blogstatic.haohtml.com/uploads/2021/05/f859094931597fe7298edb417c48c96b.png\" alt=\"2a937b08de0c8ed6c32b45ae19399a01\"\u003e\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e优缺点总结\u003c/strong\u003e\n\u0026lt;1\u0026gt; \u003cstrong\u003e监控文件最大数不同\u003c/strong\u003e:select和poll都是以数组形式传入药监控的文件句柄,而这个数组是有大小限制的1024个左右(不是很清楚).而epoll则是每add一个文件句柄会new一个新epi出来,挂载在ep的红黑树中,监控的文件个数没有明确限制(可能会受限于系统最大打开文件句柄数)从这点上看,epoll是优于select和poll. …\u003c/li\u003e\u003c/ol\u003e"
April 30, 2021
缓存池 bytebufferpool 库实现原理
"\u003cp\u003e上一节 \u003ca href=\"https://blog.haohtml.com/archives/24697\"\u003e《Runtime: Golang 之 sync.Pool 源码分析》\u003c/a\u003e 我们介绍了sync.Pool 的源码分析,本节介绍一个 \u003ca href=\"https://github.com/valyala/fasthttp\"\u003e\u003ccode\u003efasthttp\u003c/code\u003e\u003c/a\u003e 中引用的一缓存池库 \u003ccode\u003e[bytebufferpool](https://github.com/valyala/bytebufferpool)\u003c/code\u003e,这两个库是同一个开发者。对于这个缓存池库与同类型的几个库的对比,可以参考 \u003ca href=\"https://omgnull.github.io/go-benchmark/buffer/\"\u003ehttps://omgnull.github.io/go-benchmark/buffer/\u003c/a\u003e。\u003c/p\u003e\n\u003cp\u003e建议大家了解一下\u003ccode\u003e[fasthttp](https://github.com/valyala/fasthttp)\u003c/code\u003e 这个库,性能要比直接使用内置的 \u003ccode\u003enet/http\u003c/code\u003e 高出很多,其主要原因是大量的用到了缓存池 \u003ccode\u003esync.Pool\u003c/code\u003e 进行性能提升。\u003c/p\u003e\n\u003ch2 id=\"用法\"\u003e用法\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-go\" data-lang=\"go\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e// https://github.com/valyala/bytebufferpool/blob/18533face0/bytebuffer_example_test.go\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003epackage\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ebytebufferpool_test\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e (\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;fmt\u0026#34; …\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e"
April 29, 2021
初识kubernetes 组件
"\u003cp\u003e对于一个刚刚接触 kubernetes(k8s)的新手来说,想好更好的学习它,首先就要对它有一个大概的认知,所以本文我们先以全局观来介绍一个 kubernetes。\u003c/p\u003e\n\u003ch2 id=\"kubernetes-架构-8ee9f2fa987eccb490cfaa91c6484f67kubernetes-架构图\"\u003ekubernetes 架构 \u003cimg src=\"https://blogstatic.haohtml.com/uploads/2021/04/56aec9997240192091adad3e14358736-52.png\" alt=\"8ee9f2fa987eccb490cfaa91c6484f67\"\u003ekubernetes 架构图\u003c/h2\u003e\n\u003cp\u003ekubernets 整体可以分为两大部分,分别为 \u003ccode\u003eMaster\u003c/code\u003e 和 \u003ccode\u003eNode\u003c/code\u003e ,我们一般称其为节点,这两种角色分别对应着控制节点和计算节点,根据我们的经验可以清楚的知道 Master 是控制节点。\u003c/p\u003e\n\u003ch2 id=\"master-节点\"\u003eMaster 节点\u003c/h2\u003e\n\u003cp\u003e控制节点 \u003ccode\u003eMaster\u003c/code\u003e 节点由三部分组成,分别为 \u003ccode\u003eController Manager\u003c/code\u003e 、 \u003ccode\u003eAPI Server\u003c/code\u003e 和 \u003ccode\u003eScheduler\u003c/code\u003e ,它们相互紧密协作,每个部分负责不同的工作职责。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003econtroller-manager\u003c/code\u003e 全称为 kube-controler-manager 组件,主要用来负责容器编排。如一个容器(实际上是 pod,pod 是最基本的调度单元。一般一个 pod 里会部署一个容器服务)服务可以指定副本数量,如果实际运行的副本数据与期望的不一致,则会自动再启动几个容器副本,最终实现期望的数量。这个组件,就是一系列控制器的集合。我们可以 …\u003c/li\u003e\u003c/ul\u003e"
April 26, 2021
docker如何利用cgroup对容器资源进行限制
"\u003cp\u003e在容器里有两个非常重要的概念,一个是 \u003ccode\u003enamespace\u003c/code\u003e 用来实现对容器里所有进程进行隔离;另一个就是 \u003ccode\u003ecgroup\u003c/code\u003e,用来对容器进程内使用资源进行限制。那 \u003ccode\u003ecgroup\u003c/code\u003e 又是如何实现对资源进行限制的呢,今天我们来了解一下它的实现原理。\u003c/p\u003e\n\u003ch2 id=\"什么是cgroup\"\u003e什么是cgroup\u003c/h2\u003e\n\u003cp\u003e\u003ccode\u003ecgroup\u003c/code\u003e 是 \u003ccode\u003eControl Groups\u003c/code\u003e 的缩写,是 Linux 内核提供的一种可以限制、记录、隔离 进程组 所使用的物理资源(如 cpu、memory、磁盘IO等等) 的机制,被 \u003ccode\u003eLXC\u003c/code\u003e、\u003ccode\u003edocker\u003c/code\u003e 等很多项目用于实现进程资源控制。cgroup 是将任意进程进行分组化管理的 Linux 内核功能。\n\u003ccode\u003ecgroup\u003c/code\u003e 本身是提供将进程进行分组化管理的功能和接口的基础结构,I/O 或内存的分配控制等具体的资源管理功能是通过这个功能来实现的。 一定要切记,这里的限制单元为 \u003ccode\u003e进程组\u003c/code\u003e,而不是进程。\u003c/p\u003e\n\u003ch2 id=\"子系统\"\u003e子系统\u003c/h2\u003e\n\u003cp\u003e上面提到的具体的资源管理功能统称为 cgroup \u003ccode\u003e子系统\u003c/code\u003e,所有子系统列表可以通过 \u003ccode\u003ecat /proc/cgroups\u003c/code\u003e 命令查看,主要有以下几大子系统:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e# cat /proc/cgroups\n#subsys_name\thierarchy …\u003c/code\u003e\u003c/pre\u003e"
April 12, 2021
Golang 内存组件之mspan、mcache、mcentral 和 mheap 数据结构
"\u003cp\u003eGolang中的内存组件关系如下图所示\u003cimg src=\"https://blogstatic.haohtml.com/uploads/2021/04/5a666325bb7cfea6f5182e0ee7c528cf.jpg\" alt=\"components of memory allocation\"\u003egolang 内存分配组件\u003c/p\u003e\n\u003cp\u003e在学习golang 内存时,经常会涉及几个重要的数据结构,如果不熟悉它们的情况下,理解起来就显得格外的吃力,所以本篇主要对相关的几个内存组件做下数据结构的介绍。\u003c/p\u003e\n\u003cp\u003e在 Golang 中,\u003ccode\u003emcache\u003c/code\u003e、\u003ccode\u003emspan\u003c/code\u003e、\u003ccode\u003emcentral\u003c/code\u003e 和 \u003ccode\u003emheap\u003c/code\u003e 是内存管理的四大组件,\u003ccode\u003emcache\u003c/code\u003e 管理线程在本地缓存的 \u003ccode\u003emspan\u003c/code\u003e,而 \u003ccode\u003emcentral\u003c/code\u003e 管理着全局的 \u003ccode\u003emspan\u003c/code\u003e 为所有 \u003ccode\u003emcache\u003c/code\u003e 提供所有线程。\u003c/p\u003e\n\u003cp\u003e根据分配对象的大小,内部会使用不同的内存分配机制,详细参考函数 \u003ca href=\"https://github.com/golang/go/blob/go1.16.2/src/runtime/malloc.go#L902-L1171\"\u003emallocgo()\u003c/a\u003e ,所于内存分配与回收,参考文件介绍 \u003ca href=\"https://github.com/golang/go/blob/go1.16.2/src/runtime/malloc.go#L5\"\u003emalloc.go\u003c/a\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003e\u0026lt;16KB\u003c/code\u003e 会使用微小对象内存分配器从 \u003ccode\u003eP\u003c/code\u003e 中的 \u003ccode\u003emcache\u003c/code\u003e 分配,主要使用 \u003ccode\u003emcache.tinyXXX\u003c/code\u003e 这类的字段\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003e16-32KB\u003c/code\u003e 从 \u003ccode\u003eP\u003c/code\u003e 中的 \u003ccode\u003emcache\u003c/code\u003e 中分配\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003e\u0026gt;32KB\u003c/code\u003e 直接从 \u003ccode\u003emheap\u003c/code\u003e 中分配\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e对于golang中的内存申请流程,大家应该都非常熟悉了,这里不再进行详细描述。\u003cimg src=\"https://blogstatic.haohtml.com/uploads/2021/04/1bb7fe2168b7ac2e24afadf698dc6ee6.png\" alt=\"\"\u003eGolang 内存组件关系\u003c/p\u003e\n\u003ch1 id=\"mcache\"\u003emcache\u003c/h1\u003e\n\u003cp\u003e在GPM关系中,会在每个 \u003ccode\u003eP …\u003c/code\u003e\u003c/p\u003e"