拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

用Kind在Docker中快速搭建三节点K8s集群实战

用Kind在Docker中快速搭建三节点K8s集群实战

如果你和我一样,经常要在本地开发机上折腾K8s,一定体会过“装个集群比写代码还累”的滋味。以前我用kubeadm搭三节点集群,得先准备三台虚拟机,处理系统初始化、容器运行时、证书、网络插件,一套流程下来耐心基本耗尽。后来我把本地多节点K8s环境换成了Kind(Kubernetes in Docker),体验完全不一样:它用Docker容器当作节点,一条命令就能拉起一个多节点集群。今天这篇就把我用Kind搭建三节点K8s集群的完整过程记录下来,从原理、配置文件、实操命令到常见故障排查都会讲到。适合想在本机快速拥有一个多节点环境的开发者,也适合准备CKA考试的人用来刷题练手。

1. 为什么用Kind搭三节点集群,而不是Minikube或Kubeadm

1.1 Kind的核心思想:把容器当节点用

Kind的全称是Kubernetes in Docker,思路非常直接:每个K8s节点不是一个虚拟机,而是一个Docker容器。容器内部运行着systemd,作为操作系统1号进程,管理着kubelet、containerd、kube-proxy等组件。对外看它是一个容器,对内看它就是一个完整的Linux节点,还带一套完整的K8s运行时。

这个设计初看有点反直觉,但你只要想想Docker的本质就明白了:Docker容器只是把进程放到隔离的运行环境里,Kind再进一步,把完整的系统服务放进去,让kubelet把这个容器识别为一个K8s节点。节点的IP就是容器IP,节点的“磁盘”就是容器可写层。优点是极轻量,三节点集群的全部开销也就几个容器进程。我在16G内存的Mac上跑1个控制面加2个Worker,空闲时整体占用大概2到3G内存,CPU几乎没有压力,比三台虚拟机的开销小了一个数量级。

Kind这个设计还有一个隐性好处:可重复性极高。节点镜像一旦固定,集群里每个节点的系统环境完全一致,在A机器上创建的集群,和B机器上几乎一模一样。这对排查问题、构建CI测试环境太重要了。我用它跑过很多次一次性环境,用完就删,整个过程没有任何残留,下个需求来了再花两分钟重建一套。

顺便说一句,Kind并不是玩具。它是Kubernetes社区维护的项目,SIG Testing在用,很多开源项目的CI流水线都用Kind做集成测试。因为它轻量、可靠、能模拟真实多节点调度,本地开发联调和CI快速验证这两个场景里的存在感非常高。

1.2 三节点拓扑:1个控制面加2个Worker

开篇说了,目标是三节点集群。K8s集群里节点分成两类:控制面节点(Control Plane)运行kube-apiserver、kube-controller-manager、kube-scheduler、etcd这些大脑组件;Worker节点承载实际业务Pod,运行kubelet和kube-proxy。生产环境通常用3个或5个控制面节点实现高可用,但那是为了抵抗单点故障。

本地开发阶段,我强烈建议用1个控制面加2个Worker。原因有三个。第一,资源开销小。控制面组件相当吃内存,etcd、apiserver都是重量级进程,1个就够把核心API跑稳。第二,能练到调度和故障转移。2个Worker可以观察Pod如何被调度器分配到不同节点,也能模拟节点故障后Pod的迁移。第三,控制面高可用相关的实验对大多数人用不上,等需要练kubeadm HA时,再准备3台机器也不迟。Kind并非不支持多控制面,你完全可以在配置文件里列3个control-plane角色,但单机模拟多控制面很容易把电脑搞卡,我一般不会这么干。

还要注意一个小细节:控制面节点默认带有污点(Taint),普通业务Pod不会调度上去。所以在1控制面加2Worker的布局下,部署应用时,Pod只会出现在两个Worker节点上。这个行为既符合生产语义,又能让你直观看到多节点调度的效果。

1.3 对比:Minikube、k3d、kubeadm、Kind怎么选

很多初学者喜欢问,为什么不用Minikube?这要看你需要什么。Minikube默认是单节点,虽然新版本也支持多节点,但它的核心定位是“本地单机体验”,适合只想跑个K8s看看到底长什么样的人。K3d和Kind思路类似,但底层用的是K3s发行版,资源占用更低,适合轻量场景。而kubeadm是正统安装方式,灵活性最高,但前置条件也最多,你需要自己准备多台机器或虚拟机。

这几类方案我整理成表格方便对比:

方案节点形态多节点启动速度CI友好最典型的场景
Minikube单VM/容器较弱中一般单机初体验
k3dK3s容器节点支持快高轻量验证
kubeadm真实节点支持慢低生产标准化安装
KindK8s容器节点支持快高本地多节点联调

选择Kind的核心理由我归纳成四点:一是多节点调度是真实的,不是模拟器;二是创建和销毁速度以分钟计,比虚拟机强太多;三是镜像可以直接load进节点,不用在本地起Registry;四是官方维护,配置语法稳定,社区案例多。缺点也很明显,所有节点共享宿主机内核,不能测涉及内核参数的实验;每个节点都是Docker容器,对某些特殊网络场景的支持没有真实主机灵活。用之前想清楚这些边界就行。

2. 环境准备与三节点配置文件

2.1 安装Kind和kubectl

动手之前,先把工具准备齐。Kind本身是一个命令行工具,安装方式很简单。Linux/macOS可以用Homebrew,执行brew install kind。不支持Homebrew的服务器环境,直接去Kind官方Releases页面下载对应平台的二进制文件,例如Linux amd64:

curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.24.0/kind-linux-amd64 chmod +x ./kind sudo mv ./kind /usr/local/bin/kind

装完验证一下:

kind version

能输出版本号就说明装好了。

接着装kubectl。它是操作K8s集群的客户端工具,Kind创建集群时会自动生成kubeconfig文件,但不会替你安装kubectl。kubectl安装同样可以用包管理工具或直接下载:

curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" chmod +x kubectl sudo mv kubectl /usr/local/bin/kubectl

装完验证:kubectl version --client。

Kind只负责创建节点容器,真正让容器跑起来的是Docker。所以本机必须有一个能用的Docker环境。Windows上建议用Docker Desktop并启用WSL2后端;macOS同样用Docker Desktop;Linux直接装Docker Engine即可。检查方式很简单:

docker version docker ps

确保Docker daemon在运行,并且当前用户有权限访问。执行docker ps如果报权限错误,在Linux上通常需要把用户加入docker组,命令是sudo usermod -aG docker $USER,改完重新登录一次。这个小坑我踩过几次,有时候刚装完Docker,用户还在旧会话里,权限不会立刻生效,报错会误导你怀疑网络或镜像问题。

这里要注意:kubectl、Kind、Docker的版本差距不能太大。Kind通常支持当前及最近几个K8s版本,Docker版本太老会影响容器特性支持。我现在的习惯是把三者都保持在较新的稳定版本,能少很多奇怪的兼容性问题。

2.2 三节点配置文件逐行拆解

Kind支持命令行直接创建单节点集群,但三节点集群必须通过配置文件定义。创建一份kind-config.yaml,内容如下:

kind: Cluster apiVersion: kind.x-k8s.io/v1alpha4 name: demo nodes: - role: control-plane - role: worker - role: worker

逐行解释一下。kind和apiVersion是Kind配置文件的固定声明,apiVersion: kind.x-k8s.io/v1alpha4表明这是Kind自己的资源定义,不是K8s资源。name是集群名字,不写会用默认的kind。nodes列表声明节点角色,每个元素对应一个Docker容器。第一行role: control-plane会被Kind自动命名成demo-control-plane,后面两个worker容器会自动叫demo-worker和demo-worker2。这个命名规律在查日志时非常有用。

如果你想把控制面做成高可用形态,可以在nodes下面加两个role: control-plane,但我不建议在本地这么干。控制面组件集群模式会带来额外的选举资源开销,对一台开发机来说负担不小。三节点场景里,1个控制面加2个Worker已经能覆盖绝大多数验证需求。

如果本机的6443端口被占用,可以在配置文件里显式指定apiserver的宿主机映射端口:

kind: Cluster apiVersion: kind.x-k8s.io/v1alpha4 name: demo networking: apiServerPort: 16443 nodes: - role: control-plane - role: worker - role: worker

networking块下除了apiServerPort,还能设置podSubnet、serviceSubnet等网络参数。比如你想把Pod网段规划成10.200.0.0/16,就在这里配置。这些参数对应着kubeadm初始化时传给控制面的--pod-network-cidr,Kind会把它们翻译成kubeadm配置。本地联调一般不需要动这些,但如果你在练Calico等网络插件,就需要手动指定网段,避免和默认网段冲突。

2.3 节点镜像与拉取加速:真的会卡在这一步

节点镜像拉不动,是我见过最多的入门问题。Kind在创建集群时,需要从ghcr.io拉取kindest/node镜像。这个操作在部分网络环境下会非常慢,甚至超时。Kind并不直接复用本机Docker的镜像源配置,节点容器内部由containerd负责拉镜像,而containerd默认没有配置镜像源加速,所以你得在Kind配置里告诉它去哪拉。

常见做法是在配置文件里增加containerdConfigPatches:

containerdConfigPatches: - |- [plugins."io.containerd.grpc.v1.cri".registry.mirrors] [plugins."io.containerd.grpc.v1.cri".registry.mirrors."registry.k8s.io"] endpoint = ["https://registry.k8s.io"] [plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"] endpoint = ["https://你自己申请的加速地址"]

这个配置的含义是:当节点内containerd尝试从某些registry拉取镜像时,先尝试走mirror端点。registry.k8s.io对应K8s官方镜像仓库,docker.io对应Docker Hub。如果你没有可用的加速地址,至少可以检查一下Kind节点的日志,确认是不是拉取超时导致的初始化失败。

另一个更稳的绕过策略是提前把镜像准备好。Kind允许你从本机Docker直接导入镜像到节点里,命令是kind load docker-image,我们后面会专门讲这个用法。这里先说结论:搭建三节点集群的前几分钟时间,主要花在节点镜像拉取和kubeadm初始化上,别急着怀疑配置错误,先看日志,再对症处理。

3. 实操全流程:从创建集群到验证调度

3.1 创建集群并看懂启动输出

配置文件准备好之后,执行创建命令:

kind create cluster --config kind-config.yaml

配置文件里已经写了name: demo,所以创建的集群叫demo。创建过程会输出一排提示:创建控制面容器、等待kubeadm初始化、安装CNI插件等。完整执行时间通常在两到五分钟,取决于镜像是否已缓存到本地。我见过有人一看到输出卡住就慌了,其实主要是在等容器里的kubelet把控制面组件全部拉起来。

创建完提示kubeconfig saved之后,先看节点状态:

kubectl get nodes

正常情况下你会看到类似这样的输出:

NAME STATUS ROLES AGE VERSION demo-control-plane Ready control-plane 3m v1.30.0 demo-worker Ready <none> 2m v1.30.0 demo-worker2 Ready <none> 2m v1.30.0

三个节点都是Ready,三节点集群就算建成了。注意这里ROLES列的差异:control-plane节点标记了角色,worker节点的ROLES是<none>,这是kubeadm初始化的正常表现。别试图去改这个字段,它只影响展示输出。

还有一个很实用的操作:查看节点对应的容器:

docker ps

你会看到三个容器,名字分别对应上面的三个节点。容器里的进程就是完整的K8s节点运行环境。这种“容器里的节点”让排查问题时思路清晰很多:节点出了问题,可以直接进容器操纵它,而不是连到一台遥远的虚拟机。

3.2 集群健康检查三板斧

节点Ready不代表一切正常,我习惯再做三组检查。第一组是查看核心组件状态:

kubectl get pods -n kube-system -o wide

这里会看到coredns、etcd、kube-apiserver、kube-controller-manager、kube-scheduler等Pod。Kind还会默认安装一个简单的CNI网络插件kindnetd,常见输出里能看到它。如果这些Pod全部Running,控制面基本没问题。

第二组是检查服务发现和DNS:

kubectl cluster-info

它输出集群控制面地址和CoreDNS地址。输出里如果出现control-plane is healthy,说明API Server可达。其实真正的健康检查我更喜欢直接请求:

kubectl get --raw=/healthz

返回ok就是正常。

第三组是检查节点详细信息和事件:

kubectl describe nodes kubectl get events --all-namespaces --sort-by=.lastTimestamp

describe nodes可以看到节点的内部IP、kubelet版本、容器运行时版本、内存/CPU分配情况。Events里能看到是否有镜像拉取失败、探针失败的事件。做完这三组检查,集群对我来说才算真正“健康”。

3.3 底层发生的事:kubeadm init与Join的自动化过程

Kind的创建看起来是一条命令,内部实际上是标准的K8s引导流程。控制面容器启动后,Kind会往容器里注入kubeadm配置,执行kubeadm init,启动etcd和apiserver。等控制面Ready后,它再用kubeadm token创建加入凭据,在worker容器里执行kubeadm join,最后把三个节点纳入同一个集群。这个流程里如果某个环节失败,Kind会看到明确的错误。

理解这个过程能帮你定位许多问题。比如控制面一直不Ready,多半是apiserver容器起不来或者etcd异常;worker加入失败,多半是token过期、网络隔离、容器运行时版本不匹配。排查时不要只盯着kind create的输出,直接进节点容器看kubelet日志往往更有效:

docker exec -it demo-control-plane journalctl -u kubelet --no-pager | tail -100

很多人搜过“the api server is not healthy after 4m0.00747357s”这类报错,本质就是kubeadm init在等待apiserver健康时超时。Kind里不算常见,但一旦遇到,第一反应应该是看apiserver容器日志,而不是盲目重试:

docker exec -it demo-control-plane crictl ps -a docker exec -it demo-control-plane crictl logs <apiserver容器ID> --tail=50

apiserver起不来的原因里,端口冲突、证书文件权限错误、内存不足是前三名。日志里通常能直接看到线索。

3.4 部署多副本应用,验证三节点的调度效果

集群空跑没意思,我习惯马上部署一个简单应用,验证调度。先创建一个nginx Deployment,副本数设为3:

kubectl create deployment nginx --image=nginx --replicas=3 kubectl get pods -o wide

输出里你会看到三个Pod分布在两个worker节点上,可能是2个在demo-worker、1个在demo-worker2。这就是调度器在做的事情:根据节点的资源余量、污点、亲和性、标签等条件分配Pod。控制面节点因为默认有污点,所以普通Pod不会上去。

然后再直观验证一下多副本的调度行为:

kubectl scale deployment nginx --replicas=5

等几十秒后重新执行kubectl get pods -o wide,你会看到Pod数量变多,调度器会把新Pod尽可能均匀分布到两个Worker节点。如果某个Worker的资源被占满,调度器会拒绝把Pod放过去,并产生FailedScheduling事件。通过kubectl describe pod能看到详细的调度过程和失败原因。

这里补一个经验技巧:验证集群时,别用只有一个副本的应用,那样看不出调度行为。至少跑两三个副本,再用-o wide观察IP和节点分布,整个集群的调度情况一目了然。

4. 常见问题与排查技巧实录

4.1 节点一直NotReady,先看这四类原因

三节点集群建好后最让人头疼的不是创建失败,而是节点NotReady。排查顺序我通常是:容器是否活着、kubelet日志、cgroup驱动、网络插件。

先确认Docker容器状态:

docker ps -a | grep demo

如果某个节点容器被退出或者反复重启,问题基本在容器本身。接着看kubelet日志:

docker exec -it demo-worker journalctl -u kubelet --no-pager | tail -100

日志里能看到kubelet连不上apiserver,或者容器运行时接口调用失败。常见原因之一是cgroup驱动不一致,kubelet和containerd一个用systemd一个用cgroupfs,节点就会一直NotReady。Kind节点镜像默认是systemd环境,这个坑不太常见,但如果你用旧版节点镜像,就需要注意。更好的处理方式是升级Kind和节点镜像,而不是手动改驱动。

还有一个容易被忽略的原因:宿主机资源不足。开三节点集群后,如果Docker Desktop默认内存只有2G,很容易出现节点内存压力,kubelet反复OOM。这时候节点NotReady、Pod Evicted都算正常。先看宿主机资源监控,内存余量不够就调整Docker Desktop的资源配置,或者减少Worker节点数量。

4.2 镜像拉不动:来自节点内部containerd的困惑

你在宿主机上明明能拉nginx镜像,但集群里的Pod就是ImagePullBackOff。这是因为K8s集群内Pod的镜像拉取是由节点上的containerd执行的,和宿主机Docker完全无关。Kind节点内部有一个独立的containerd,它访问公网镜像源时可能非常慢,或者根本没有外网访问能力。

遇到ImagePullBackOff时,先看事件:

kubectl describe pod <pod-name> | grep -A5 Events

如果是网络超时、连接被拒之类的错误,解决方案有三种。第一种是给节点内的containerd配置registry mirror,也就是配置文件里的containerdConfigPatches;第二种是提前在宿主机上拉好镜像,再用kind load docker-image导入;第三种是换用可访问的镜像地址,把image字段改成加速前缀。实际联调中,第二种最稳定,因为它完全不依赖集群节点的外网能力。第三种要注意,本地实验没有问题,但不要把这个习惯带到生产环境的镜像供应链里。

我看到很多教程只让新手清镜像、重启Docker,其实没有解决根本问题。把镜像load进Kind节点,一次导入,三个节点都能用,这比反复拉镜像优雅得多。

注意:K8s节点内部的镜像拉取由节点上的containerd执行,和宿主机Docker无关,别用“宿主机能拉镜像”来判断“集群内也能拉”。

4.3 端口冲突和初始化超时

创建集群时报port is already allocated,说明本机的6443或其它端口被占用了。用ss -lntp | grep 6443看看是谁占的,杀掉或者改Kind配置里的apiServerPort都可以。Kind对端口冲突的错误信息写得比较清晰,按照提示改就行。

如果初始化一直卡在等待API Server健康,不要迷信“重来一次”能解决。我处理这种问题的方法是把创建过程调成verbose模式:

kind create cluster --config kind-config.yaml -v 6

输出里会包含大量日志,能定位具体是镜像拉取、证书生成还是组件启动。如果看到apiserver容器反复退出,大概率是内存或证书问题。内存问题调整宿主机资源;证书问题删除重建集群比进去修证书快得多。

还有一个很细的坑:Windows的WSL2环境里,Docker Desktop和WSL2之间的文件路径、kubeconfig权限偶尔会有异常。Kind生成kubeconfig后会放在~/.kube/config,如果你发现kubectl连接不上,先检查这个文件是否存在、权限是否为600,以及集群IP是否匹配。多数情况下不是Kind的问题,而是本机环境设置问题。

4.4 集群删除与重来:Kind最大的底气

本地集群实验失败时,我的习惯是“宁删勿修”。删掉重来:

kind delete cluster --name demo

这个命令会停止并移除demo集群对应的所有容器,同时清理相关网络。再重新创建,又是一个全新的三节点集群。整个生命周期里,宿主机上不会残留一堆僵尸容器。这就是Kind作为本地开发工具最爽的一点,你可以反复试错,试完一键销毁。

如果只是想临时停掉集群,可以用docker stop停掉节点容器,但我不推荐把它当作集群管理的常规方式。因为控制面和worker节点容器停止后,集群状态会变得很奇怪,恢复时可能出现证书缓存不一致。真的想暂停开发机省电,直接把机器睡眠就行。

5. 进阶玩法:让三节点集群更贴近真实环境

5.1 本地镜像导入与离线验证

本地服务的镜像通常只在你电脑上存在,没有推到Registry,那么K8s集群怎么拉?答案是用kind load docker-image:

kind load docker-image my-app:v1.0 --name demo

这条命令会把本机Docker镜像保存成tar,再导入到集群里每一个节点的containerd镜像存储。它的妙处在于:你不需要搭Registry,也不需要把镜像推到公网,镜像在三个节点上都能被kubelet找到。之后创建Deployment时直接写image: my-app:v1.0即可。

这个能力对本地联调极其重要。我在开发时就是先docker build出镜像,然后kind load,再改代码、再build、再load,循环很快。注意load后的镜像是新镜像,旧Pod不会自动滚动更新,你需要主动执行kubectl rollout restart deployment。这个细节我踩过一次:改了代码,load了新镜像,但Pod还停在旧镜像上,排了半天才想起来没重启。

5.2 通过NodePort访问集群内服务

三节点集群建好后,怎么从宿主机访问Deployment?如果用ClusterIP,只能在集群内部访问;要外部访问,最贴近直觉的方式是NodePort。创建Service时指定type: NodePort,例如:

kubectl expose deployment nginx --type=NodePort --port=80 --target-port=80 --name=nginx-svc kubectl get svc nginx-svc

你会看到一个30000多端的NodePort。但在Kind环境里,直接从宿主机访问<nodeIP>:<nodePort>通常不行,因为节点是Docker容器,它们的IP是Docker内网IP,宿主机虽然能到达,但习惯上用localhost访问更顺手。

所以Kind里更常用的做法是配置节点端口映射。创建集群时在配置文件的节点下加extraPortMappings:

nodes: - role: control-plane extraPortMappings: - containerPort: 30080 hostPort: 8080 protocol: TCP

这样宿主机访问localhost:8080就会映射到control-plane容器的30080端口,而NodePort服务监听在30080,流量就进来了。这相当于给集群加了一个“端口打通”入口。

5.3 externalIPs在Kind里值不值得用

很多人会搜externalIPs,我也顺手说一下。Service的externalIPs字段可以让集群外的客户端通过指定IP访问服务,但要求该IP能路由到节点。Kind节点的IP是Docker网络里的IP,只能在宿主机这一层访问,换个机器、换个网络环境就不通了。所以在这种本地实验环境里,花太多精力配externalIPs意义不大。

如果真要实验,可以这样写Service:

apiVersion: v1 kind: Service metadata: name: nginx-svc spec: selector: app: nginx ports: - port: 80 targetPort: 80 protocol: TCP externalIPs: - 172.18.0.2

这个IP要填你Kind网络的网关或某个节点IP,宿主机可能通,也可能不通,取决于你的Docker网络配置。但我的建议是:本地联调别用externalIPs,用port-forward或NodePort更符合Kind的部署形态。externalIPs的真实价值在裸金属机房,那里的IP可以被路由到集群节点,才能在Service上挂外部IP。

5.4 做一次故障切换实验

三节点集群还有一个很有价值的玩法:模拟节点故障,观察调度系统如何自愈。日常在真实集群里做这种实验可能影响线上业务,但在Kind里随便玩。做法很简单:

docker stop demo-worker

等一两分钟,执行kubectl get nodes,你会看到demo-worker状态变成NotReady。如果Deployment有多个副本,并且有Pod原本在demo-worker上,kube-controller-manager会等一段时间后把那个Pod重新调度到其他Ready节点。

这就是K8s集群的故障转移能力。看kubectl get pods -o wide的输出,原本在demo-worker上的Pod会消失,新Pod出现在demo-worker2上。实验结束恢复:

docker start demo-worker

等节点重新Ready后,调度器不会把Pod自动迁回来,这很正常,K8s不会因为节点回来就强制搬家。这个实验强烈建议亲手做一遍,比看十遍文档都直观。

5.5 在CI流水线里跑三节点Kind集群

Kind是个二进制工具,启动快、可重复、资源占用可控,这些特性让它成了CI环境里非常受欢迎的K8s测试方案。你可以直接在GitHub Actions这类平台上执行:

kind create cluster --config kind-config.yaml kubectl apply -f ./deploy/ kubectl wait --for=condition=Ready pod --all -n demo --timeout=300s kubectl run smoke-test --image=busybox --restart=Never --rm -it -- wget -qO- http://nginx-svc

CI里的好处是每跑一次都从干净环境开始,不会受到本地缓存污染。需要注意的只有两点:一是CI机器的资源,三节点Kind集群在跑测试时至少需要4GB内存;二是并行job的端口冲突,建议在每个job里用随机集群名,比如kind create cluster --name ci-${{ github.run_id }},测试完再删除。用脚本把“创建-验证-删除”包起来,所有的集成测试都能在同一套K8s逻辑下执行。

我现在已经不太能接受“回归没有多节点环境的日子”了。Kind上手之后你会觉得它又轻又稳,但真正让我推荐它的原因不是轻,而是它给了开发者一种“随手就能造一套系统级环境”的底气。你可以在里面随便破坏、随便试验,任何决定都不用担心影响生产。最后分享一个我自己的小习惯:把kind配置文件、部署YAML和常用脚本全部收进一个Git仓库,任何一台装了Docker的新机器上,clone下来就能一键复现同一套三节点环境。开发机可以经常换,但环境复现能力基本不丢。

返回列表