前言
k8s全称kubernetes,是一个开源的容器编排引擎,用来对容器化应用进行自动化部署、 扩缩和管理。该项目托管在 cncf。目前k8s已经成为发展最快、市场占有率最高的容器编排引擎产品,越来越多企业正在拥抱k8s,推动微服务、容器等热门技术的普及和落地。
对于 k8s这项平台级技术,覆盖的技术范围非常广,包括了计算、网络、存储、高可用、监控、日志管理等多个方面。越是门槛高的知识,就越需要搭建一个最小可用系统,先把玩起来,快速了解基本概念、功能和使用场景,建立起对学习对象的感性认识。如果直接上来就学习理论知识和概念,很容易从入门到放弃。
0. 目录
1. k8s基础知识
2. 部署环境
3. centos初始化配置
4. master节点配置
5. worker节点配置
6. 使用k8s部署应用
7. 后记
8. 参考文献
1. k8s基础知识
k8s集群是主从分布式架构,由master node和worker node组成,节点上运行着k8s组件服务。
master 是 cluster 的大脑,主要职责是调度,运行的 k8s 组件有kube-apiserver、kube-scheduler、kube-controller-manager、etcd 和 pod 网络(例如 flannel)。可以同时运行多个 master实现高可用。
api server(kube-apiserver):提供 http/https restful api,实现认证、授权、访问控制、api注册和发现等功能,各种客户端工具(cli 或 ui)以及 k8s 其他组件可以通过它管理 cluster 资源。scheduler(kube-scheduler):负责决定将 pod 放在哪个 node 上运行。scheduler 在调度时会充分考虑 cluster 的拓扑结构、当前各个节点的负载以及应用对高可用、性能、数据亲和性的需求。controller manager(kube-controller-manager):负责管理 cluster 各种资源,保证资源处于预期的状态。controller manager 由多种 controller 组成,包括 replication controller、endpoints controller、namespace controller、serviceaccounts controller 等。不同的 controller 管理不同的资源。例如 replication controller 管理 deployment、statefulset、daemonset 的生命周期,namespace controller 管理 namespace 资源。etcd :负责保存 cluster 的配置信息和各种资源的状态信息。当数据发生变化时,etcd 会快速地通知 k8s相关组件。pod 网络:pod 是 k8s的最小工作单元。每个 pod 包含一个或多个容器。pod 中的容器会作为一个整体被 master 调度到一个 worker上运行。pod 要能够相互通信,cluster 必须部署 pod 网络,flannel 是其中一个可选方案。
worker是 pod 运行的地方,k8s 支持 docker、rkt 等容器 runtime。worker上运行的组件有 kubelet、kube-proxy 和 pod 网络。worker 由 master 管理,负责监控并向master汇报容器的状态,并根据 master 的要求管理容器的生命周期。
kubelet:是 worker的 agent,当 scheduler 确定在某个 worker上运行 pod 后,会将 pod 的具体配置信息(image、volume 等)发送给该节点的 kubelet,kubelet 根据这些信息创建和运行容器,并向 master 报告运行状态。kube-proxy:service 在逻辑上代表了后端的多个 pod,外界通过 service 访问 pod。service 接收到的请求是如何转发到 pod 的呢?这就是 kube-proxy 要完成的工作。每个 worker都会运行 kube-proxy 服务,负责将访问 service 的 tcp/upd 数据流转发到后端的容器。如果有多个副本,kube-proxy 会实现负载均衡。
2. 部署环境
本次实验将搭建一个包含1个master 节点 2个worker 节点的k8s集群环境。
操作系统版本:centos 7.9
k8s版本:1.20.15
docker版本:19.3.5
主机名
ip
k8s-master
10.10.10.128
k8s-worker1
10.10.10.131
k8s-worker2
10.10.10.132
3. centos初始化配置
tips:本次实验准备了3台centos 虚拟机,为了减少重复劳动,可以先初始化配置好一台虚拟机,再克隆出另外两台虚拟机(记得要修改ip)。
(1)更新yum源(非必须)
yum update -y
(2)配置网络
cd /etc/sysconfig/network-scripts/ # 进入网络配置目录vim ifcfg-ens36 # 编辑对应网卡的配置文件,我的环境是ens36# 修改网卡配置文件内容如下所示type=ethernetproxy_method=nonebrowser_only=nobootproto=static # bootproto的值由dhcp改为static,设为静态ipdefroute=yesipv4_failure_fatal=noipv6init=yesipv6_autoconf=yesipv6_defroute=yesipv6_failure_fatal=noipv6_addr_gen_mode=stable-privacyname=ens36device=ens36onboot=yes # onboot的值由no改为yesipaddr=10.10.10.128netmask=255.255.255.0gateway=10.10.10.2 # 设置**,就可以过nat形式上**dns1=10.10.10.2zone=publicprefix=24service network restart # 重启网络服务使新配置生效
(3)修改主机名
hostnamectl set-hostname k8s-master # 修改主机名,重新打开终端即可看到主机名已修改成功# 采取类似方法修改两台worker节点的主机名hostnamectl set-hostname k8s-worker1 # 修改10.10.10.131的主机名hostnamectl set-hostname k8s-worker2 # 修改10.10.10.132的主机名
(4)配置hosts
vim /etc/hosts# 添加以下3行10.10.10.128 k8s-master10.10.10.131 k8s-worker110.10.10.132 k8s-worker2
(5)关闭主机防火墙
systemctl stop firewalld # 关闭防火墙systemctl disable firewalld # 禁用开机自启动
(6)关闭selinux
[root@localhost ~]# getenforce # 查看selinux状态enforcing # selinux未关闭[root@localhost ~]# setenforce 0 # 临时关闭selinux[root@localhost ~]# getenforce # 查看selinux状态permissive # selinux已关闭#永久关闭selinux的方法vim /etc/sysconfig/selinux将selinux=enforcing 替换为selinux=disabled,需重启主机
(7)关闭swap
# 临时关闭swapoff -a # 永久关闭swapvim /etc/fstab注释掉最后一行关于swap的配置
(8)将桥接的ipv4流量传递到iptables的链
touch /etc/sysctl.d/k8s.conf # k8s.conf文件原来不存在,需要新建vim /etc/sysctl.d/k8s.conf# 添加下面4行net.bridge.bridge-nf-call-ip6tables=1net.bridge.bridge-nf-call-iptables=1net.ipv4.ip_forward=1vm.swappiness=0sysctl –system # 加载系统参数,使配置生效
(9)安装docker
rpm -qa | grep docker # 查看是否已安装docker组件yum remove docker docker-common docker-client # 如已安装,则卸载旧版docker相关组件yum install -y yum-utils #安装yum-utils,提供yum-config-manager命令 yum-config-manager –add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo #添加阿里云的yum源,便于快速下载dockeryum list docker-ce –showduplicates | sort -r #查看可获取的docker版本yum install -y docker-ce-19.03.5 docker-ce-cli-19.03.5 containerd.io # 安装指定版本的docker,这里选择19.03.5systemctl enable docker # 设置开机自启动systemctl start docker # 启动docker服务systemctl status docker # 查看docker服务状态
(10)安装k8s
添加阿里云yum源,便于快速下载k8s
cat
下载指定版本的k8s组件
#查看可获取的k8s组件版本yum list kubelet –showduplicates | sort -r# 这里选择安装1.20.15版本的k8s组件yum install -y kubelet-1.20.15 kubeadm-1.20.15 kubectl-1.20.15
启动服务
systemctl enable kubelet # 设置开机自启动systemctl start kubelet # 启动kubelet服务systemctl status kubelet # 查看kubelet服务状态
4. master节点配置
(1)初始化 k8s
执行初始化命令:
kubeadm init \–image-repository registry.aliyuncs.com/google_containers \–kubernetes-version v1.20.15 \–apiserver-advertise-address 10.10.10.128 \–pod-network-cidr=10.244.0.0/16
参数说明:
–image-repository:指定镜像源–kubernetes-version:指定 k8s 版本,要跟上面安装的保持一致–apiserver-advertise-address:指明用 master 的哪个 interface 与 cluster 的其他节点通信。如果 master 有多个 interface,建议明确指定,如果不指定,kubeadm 会自动选择有默认**的 interface。–pod-network-cidr:指定 pod 网络的范围。k8s支持多种网络方案,而且不同网络方案对 –pod-network-cidr 有自己的要求,这里设置为 10.244.0.0/16 是因为将使用 flannel 网络方案,必须设置成这个 cidr。
初始化脚本执行了以下动作:
kubeadm 执行初始化前的检查。生成 token 和证书。生成 kubeconfig 文件,kubelet 需要这个文件与 master 通信。安装 master 组件,会从 goolge 的 registry 下载组件的 docker 镜像,这一步可能会花一些时间,主要取决于网络质量。安装附加组件 kube-proxy 和 kube-dns。k8s master 初始化成功。提示如何配置 kubectl。提示如何安装 pod 网络。提示如何注册其他节点到 cluster。
初始化脚本执行成功的结果:
your kubernetes control-plane has initialized successfully!to start using your cluster, you need to run the following as a regular user: mkdir -p $home/.kube sudo cp -i /etc/kubernetes/admin.conf $home/.kube/config sudo chown $(id -u):$(id -g) $home/.kube/configalternatively, if you are the root user, you can run: export kubeconfig=/etc/kubernetes/admin.confyou should now deploy a pod network to the cluster.run “kubectl apply -f [podnetwork].yaml” with one of the options listed at: https://kubernetes.io/docs/concepts/cluster-administration/addons/then you can join any number of worker nodes by running the following on each as root:kubeadm join 10.10.10.128:6443 –token olw0rl.dx8iq0av6yld4npr \ –discovery-token-ca-cert-hash sha256:9a4a7aa30ea54665d914b86faed89b588fff9937e36d0f28414676c57473702f
(2)配置kubectl
mkdir -p $home/.kubesudo cp -i /etc/kubernetes/admin.conf $home/.kube/configsudo chown $(id -u):$(id -g) $home/.kube/config
(3)安装pod网络
k8s cluster 工作必须安装pod网络,否则pod之间无法通信,k8s支持多种方案,这里选择flannel。
由于https://raw.githubusercontent.com/coreos/flannel/master/documentation/kube-flannel.yml被墙无法访问,所以不能采用以下命令在线安装:kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/documentation/kube-flannel.yml
从网上下载kube-flannel.yml文件:
—apiversion: policy/v1beta1kind: podsecuritypolicymetadata: name: psp.flannel.unprivileged annotations: seccomp.security.alpha.kubernetes.io/allowedprofilenames: docker/default seccomp.security.alpha.kubernetes.io/defaultprofilename: docker/default apparmor.security.beta.kubernetes.io/allowedprofilenames: runtime/default apparmor.security.beta.kubernetes.io/defaultprofilename: runtime/defaultspec: privileged: false volumes: – configmap – secret – emptydir – hostpath allowedhostpaths: – pathprefix: “/etc/cni/net.d” – pathprefix: “/etc/kube-flannel” – pathprefix: “/run/flannel” readonlyrootfilesystem: false # users and groups runasuser: rule: runasany supplementalgroups: rule: runasany fsgroup: rule: runasany # privilege escalation allowprivilegeescalation: false defaultallowprivilegeescalation: false # capabilities allowedcapabilities: [‘net_admin’, ‘net_raw’] defaultaddcapabilities: [] requireddropcapabilities: [] # host namespaces hostpid: false hostipc: false hostnetwork: true hostports: – min: 0 max: 65535 # selinux selinux: # selinux is unused in caasp rule: ‘runasany’—kind: clusterroleapiversion: rbac.authorization.k8s.io/v1metadata: name: flannelrules:- apigroups: [‘extensions’] resources: [‘podsecuritypolicies’] verbs: [‘use’] resourcenames: [‘psp.flannel.unprivileged’]- apigroups: – “” resources: – pods verbs: – get- apigroups: – “” resources: – nodes verbs: – list – watch- apigroups: – “” resources: – nodes/status verbs: – patch—kind: clusterrolebindingapiversion: rbac.authorization.k8s.io/v1metadata: name: flannelroleref: apigroup: rbac.authorization.k8s.io kind: clusterrole name: flannelsubjects:- kind: serviceaccount name: flannel namespace: kube-system—apiversion: v1kind: serviceaccountmetadata: name: flannel namespace: kube-system—kind: configmapapiversion: v1metadata: name: kube-flannel-cfg namespace: kube-system labels: tier: node app: flanneldata: cni-conf.json: | { “name”: “cbr0”, “cniversion”: “0.3.1”, “plugins”: [ { “type”: “flannel”, “delegate”: { “hairpinmode”: true, “isdefaul**ateway”: true } }, { “type”: “portmap”, “capabilities”: { “portmappings”: true } } ] } net-conf.json: | { “network”: “10.244.0.0/16”, “backend”: { “type”: “vxlan” } }—apiversion: apps/v1kind: daemonsetmetadata: name: kube-flannel-ds namespace: kube-system labels: tier: node app: flannelspec: selector: matchlabels: app: flannel template: metadata: labels: tier: node app: flannel spec: affinity: nodeaffinity: requiredduringsche**ngignoredduringexecution: nodeselectorterms: – matchexpressions: – key: kubernetes.io/os operator: in values: – linux hostnetwork: true priorityclassname: system-node-critical tolerations: – operator: exists effect: noschedule serviceaccountname: flannel initcontainers: – name: install-cni-plugin image: rancher/mirrored-flannelcni-flannel-cni-plugin:v1.2 command: – cp args: – -f – /flannel – /opt/cni/bin/flannel volumemounts: – name: cni-plugin mountpath: /opt/cni/bin – name: install-cni image: quay.io/coreos/flannel:v0.15.1 command: – cp args: – -f – /etc/kube-flannel/cni-conf.json – /etc/cni/net.d/10-flannel.conflist volumemounts: – name: cni mountpath: /etc/cni/net.d – name: flannel-cfg mountpath: /etc/kube-flannel/ containers: – name: kube-flannel image: quay.io/coreos/flannel:v0.15.1 command: – /opt/bin/flanneld args: – –ip-masq – –kube-subnet-mgr resources: requests: cpu: “100m” memory: “50mi” limits: cpu: “100m” memory: “50mi” securitycontext: privileged: false capabilities: add: [“net_admin”, “net_raw”] env: – name: pod_name valuefrom: fieldref: fieldpath: metadata.name – name: pod_namespace valuefrom: fieldref: fieldpath: metadata.namespace volumemounts: – name: run mountpath: /run/flannel – name: flannel-cfg mountpath: /etc/kube-flannel/ volumes: – name: run hostpath: path: /run/flannel – name: cni-plugin hostpath: path: /opt/cni/bin – name: cni hostpath: path: /etc/cni/net.d – name: flannel-cfg configmap: name: kube-flannel-cfg
安装flannel
[root@k8s-master ~]# kubectl apply -f kube-flannel.ymlpodsecuritypolicy.policy/psp.flannel.unprivileged createdclusterrole.rbac.authorization.k8s.io/flannel createdclusterrolebinding.rbac.authorization.k8s.io/flannel createdserviceaccount/flannel createdconfigmap/kube-flannel-cfg createddaemonset.apps/kube-flannel-ds created
查看 pod 状态,状态都为running表示安装成功
[root@k8s-master 桌面]# kubectl get pod –all-namespaces -o widenamespace name ready status restarts age ip node nominated node readiness gateskube-system coredns-7f89b7bc75-kqhd6 1/1 running 0 68m 10.244.0.3 k8s-master kube-system coredns-7f89b7bc75-vbqqr 1/1 running 0 68m 10.244.0.2 k8s-master kube-system etcd-k8s-master 1/1 running 0 68m 10.10.10.128 k8s-master kube-system kube-apiserver-k8s-master 1/1 running 0 68m 10.10.10.128 k8s-master kube-system kube-controller-manager-k8s-master 1/1 running 0 68m 10.10.10.128 k8s-master kube-system kube-flannel-ds-wrhqc 1/1 running 0 6m3s 10.10.10.128 k8s-master kube-system kube-proxy-gx9nj 1/1 running 0 68m 10.10.10.128 k8s-master kube-system kube-scheduler-k8s-master 1/1 running 0 68m 10.10.10.128 k8s-master
查看 node,状态已为 ready
[root@k8s-master 桌面]# kubectl get nodesname status roles age versionk8s-master ready control-plane,master 73m v1.20.15
5. worker节点配置
(1)添加 k8s-worker1 和 k8s-worker2
在 k8s-worker1 和 k8s-worker2 上分别执行如下命令,将其注册到 cluster 中:
kubeadm join 10.10.10.128:6443 –token olw0rl.dx8iq0av6yld4npr \ –discovery-token-ca-cert-hash sha256:9a4a7aa30ea54665d914b86faed89b588fff9937e36d0f28414676c57473702f
这里的 –token 和–discovery-token-ca-cert-hash 来自前面 kubeadm init 输出的第 ⑨ 步提示,如果当时没有记录下来可以通过 kubeadm token list 查看。
(2)在k8s-master上查看worker节点情况
查看节点运行情况,ready表明节点加入成功。
[root@k8s-master ~]# kubectl get nodesname status roles age versionk8s-master ready control-plane,master 84m v1.20.15k8s-worker1 ready 6m28s v1.20.15k8s-worker2 ready 6m2s v1.20.15
查看pod运行情况,running表示运行正常。
[root@k8s-master ~]# kubectl get pod –all-namespacesnamespace name ready status restarts agekube-system coredns-7f89b7bc75-kqhd6 1/1 running 1 101mkube-system coredns-7f89b7bc75-vbqqr 1/1 running 1 101mkube-system etcd-k8s-master 1/1 running 1 101mkube-system kube-apiserver-k8s-master 1/1 running 1 101mkube-system kube-controller-manager-k8s-master 1/1 running 1 101mkube-system kube-flannel-ds-9vglr 1/1 running 1 24mkube-system kube-flannel-ds-wrhqc 1/1 running 1 39mkube-system kube-flannel-ds-xz82j 1/1 running 0 2m51skube-system kube-proxy-fmc9v 1/1 running 1 24mkube-system kube-proxy-gx9nj 1/1 running 1 101mkube-system kube-proxy-zrhzt 1/1 running 0 2m51skube-system kube-scheduler-k8s-master 1/1 running 1 101m
(3)删除和重新添加节点
# 删除 k8s-worker2 节点[root@k8s-master ~]# kubectl delete node k8s-worker2 # 重置k8s-worker2 节点[root@k8s-worker2 ~]# kubeadm reset # 将k8s-worker2重新加入集群[root@k8s-worker2 ~]# kubeadm join 10.10.10.128:6443 –token olw0rl.dx8iq0av6yld4npr \ –discovery-token-ca-cert-hash sha256:9a4a7aa30ea54665d914b86faed89b588fff9937e36d0f28414676c57473702f
6. 使用k8s部署应用
至此k8s集群已配置完毕,接下来就来部署一个nginx应用感受一下吧。
(1)k8s 支持两种方式创建资源
方式一:基于命令。
用 kubectl 命令直接创建,在命令行中通过参数指定资源的属性,比如:
kubectl run nginx-deployment –image=nginx:1.23.2 –replicas=2
方式二:基于配置文件。
通过yaml配置文件和 kubectl apply 命令创建,比如:
kubectl apply -f nginx.yml
两种方式比较:
基于命令:简单直观快捷,上手快。适合临时测试或实验。基于配置文件:配置文件描述了 what,即应用最终要达到的状态。配置文件提供了创建资源的模板,能够重复部署。可以像管理代码一样管理部署。适合正式的、跨环境的、规模化部署。要求熟悉配置文件的语法,有一定难度。
(2)采用 deployment 部署应用
k8s通过controller来管理pod的生命周期。为了满足不同业务场景,k8s开发了deployment、replicaset、daemonset、statefulset、job等多种controller。这次采用最常用的deployment,对应的 nginx.yml 内容为:
apiversion: apps/v1kind: deploymentmetadata: name: nginx-deployment labels: app: nginx-deploymentspec: replicas: 3 selector: matchlabels: app: nginx-pod template: metadata: labels: app: nginx-pod spec: containers: – name: nginx image: nginx:1.23.2 imagepullpolicy: ifnotpresent ports: – containerport: 80
参数说明:
apiversion 是当前配置格式的版本。kind 是要创建的资源类型,这里是 deployment。metadata 是该资源的元数据,name 是必需的元数据项。spec 部分是该 deployment 的规格说明。replicas 指明副本数量,默认为 1。template 定义 pod 的模板,这是配置文件的重要部分。metadata 定义 pod 的元数据,至少要定义一个 label。label 的 key 和 value 可以任意指定。spec 描述 pod 的规格,此部分定义 pod 中每一个容器的属性,name 和 image 是必需的。
执行命令,开始部署应用
[root@k8s-master 桌面]# kubectl apply -f nginx.ymldeployment.apps/nginx-deployment created
查看应用部署情况,还在进行中…
[root@k8s-master 桌面]# kubectl get deployment nginx-deploymentname ready up-to-date available agenginx-deployment 0/3 3 0 23s[root@k8s-master 桌面]# kubectl get podsname ready status restarts agenginx-deployment-84f787d66f-jvtwj 0/1 containercreating 0 37snginx-deployment-84f787d66f-sjsqj 0/1 containercreating 0 37snginx-deployment-84f787d66f-x5mjp 0/1 containercreating 0 37s
查看某个pod的部署状态详情
[root@k8s-master 桌面]# kubectl describe pod nginx-deployment-84f787d66f-x5mjp[…省略…]events: type reason age from message —- —— —- —- ——- normal scheduled 2m25s default-scheduler successfully assigned default/nginx-deployment-84f787d66f-jvtwj to k8s-worker1 normal pulling 2m24s kubelet pulling image “nginx:1.23.2” normal pulled 83s kubelet successfully pulled image “nginx:1.23.2” in 1m1.152513339s normal created 82s kubelet created container nginx normal started 82s kubelet started container nginx
已完成部署
[root@k8s-master 桌面]# kubectl get deployment nginx-deployment -o widename ready up-to-date available age containers images selectornginx-deployment 3/3 3 3 13m nginx nginx:1.23.2 app=nginx-pod
已生成3个副本,其中一个跑着worker1节点上,2个跑在worker2节点上。
[root@k8s-master 桌面]# kubectl get pods -o widename ready status restarts age ip node nominated node readiness gatesnginx-deployment-84f787d66f-jvtwj 1/1 running 0 15m 10.244.1.2 k8s-worker1 nginx-deployment-84f787d66f-sjsqj 1/1 running 0 15m 10.244.2.3 k8s-worker2 nginx-deployment-84f787d66f-x5mjp 1/1 running 0 15m 10.244.2.2 k8s-worker2
可以正常访问应用,访问方式是 pod ip port
[root@k8s-master 桌面]# curl http://10.244.2.2:80html { color-scheme: light dark; }body { width: 35em; margin: 0 auto;font-family: tahoma, verdana, arial, sans-serif; }welcome to nginx!if you see this page, the nginx web server is successfully installed andworking. further configuration is required.for online documentation and support please refer tonginx.org.commercial support is available atnginx.com.thank you for using nginx.
至此,k8s集群搭建工作告一段落,有关k8s的其他知识,留待以后再跟大家分享。
7. 后记
虽然网上有很多资料可以参考,但实践的过程还是蛮曲折的,知易行难,所幸在解决了各种奇奇怪怪的报错后最终完成任务。由于还处在入门阶段,这次是基于前人轨迹亦步亦趋走下来的,没有太多自己的思考,比如关闭防火墙、关闭selinux这种事,也不应该是搞安全的人干出来的,但为了poc能够顺利通过,还是在没有深究原因的情况下很“违心”地做了。
目前k8s最新版已到1.25,其中 1.24是个分水岭,k8s从这个版本开始正式弃用了dockershim中转模式,而是直接调用containerd,“没有了中间商赚差价”可以明显提升性能效率,算是重大升级了,有兴趣的读者可以移步《【k8s】kubernetes“弃用docker”是怎么回事?》(链接见参考文献)做进一步了解。不过,在“稳定压倒一切”的指导方针下,估计国内吃螃蟹的企业暂时不会太多,可能是不够痛不差钱亦或是极客精神的缺失吧。
静下心来思考k8s的设计理念,不禁感慨老外确实厉害——简洁高效、举止优雅,“增之一分则太长,减之一分则太短 ;著粉则太白,施朱则太赤”,各个组件分工明确、环环相扣,像一台精密仪器,更像一件艺术品,再贴上免费、开源的标签,再次印证了谷歌是一家有能力、有格局的伟大公司。我在想,假如我们能在文字的遣词造句、对仗排比上省点精力,也许能在技术的精益求精、开拓创新方面更有建树吧。毕竟,文山会海是将军的地狱,金戈铁马才是战士的天堂。
8. 参考文献
1、《每天5分钟玩转 docker 容器技术》,cloudman著,清华大学出版社
2、《每天5分钟玩转 kubernetes》,cloudman著,清华大学出版社
3、《【k8s】kubernetes“弃用docker”是怎么回事?》:
https://www.jianshu.com/p/71ad22345cc5
本文来自投稿,不代表商川网立场,如若转载,请注明出处:http://www.sclgvs.com/zhishi/57091.html
凯发体育手机开户的版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请联系凯发体育手机开户举报,一经查实,本站将立刻删除。