指令很全的K8s学习笔记(二)

本文涉及的产品
.cn 域名,1个 12个月
传统型负载均衡 CLB,每月750个小时 15LCU
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 指令很全的K8s学习笔记(二)

二、资源控制器

Kubernetes 中内建了很多 controller(控制器),这些相当于一个状态机,用来控制 Pod 的具体状态和行为


一、什么是控制器

Kubernetes 中内建了很多 controller(控制器),这些相当于一个状态机,用来控制 Pod 的具体状态和行为


**二、**控制器类型

① ReplicationController 和 ReplicaSet


② Deployment


③ DaemonSet


④ StateFulSet


⑤ Job/CronJob


⑥ Horizontal Pod Autoscaling


**1、**ReplicationController 和 ReplicaSet

ReplicationController(RC)用来确保容器应用的副本数始终保持在用户定义的副本数,即如果有容器异常退出,会自动创建新的 Pod 来替代;而如果异常多出来的容器也会自动回收;在新版本的 Kubernetes 中建议使用 ReplicaSet 来取代 ReplicationController 。ReplicaSet 跟ReplicationController 没有本质的不同,只是名字不一样,并且 ReplicaSet 支持集合式的 selector(标签 );


**2、**Deployment

Deployment 为 Pod 和 ReplicaSet 提供了一个声明式定义 (declarative) 方法,用来替代以前的ReplicationController 来方便的管理应用。典型的应用场景包括;


① 定义 Deployment 来创建 Pod 和 ReplicaSet


② 滚动升级和回滚应用


③ 扩容和缩容


④ 暂停和继续 Deployment


滚动更新:会创建一个新副本的rs1,旧的rs的pod减少一个时,rs1会新加一个,直到全部增减完成

1.png

回滚:同理,需要恢复旧的rs时,会启动rs,再进行增减操作


**3、**DaemonSet

DaemonSet确保全部(或者一些)Node 上运行一个 Pod 的副本。当有 Node 加入集群时,也会为他们新增一个Pod 。当有 Node 从集群移除时,这些 Pod 也会被回收。删除 DaemonSet 将会删除它创建的所有 Pod


使用 DaemonSet 的一些典型用法:


① 运行集群存储 daemon,例如在每个 Node 上运行glusterd、ceph


② 在每个 Node 上运行日志收集 daemon,例如fluentd、logstash


③ 在每个 Node 上运行监控 daemon,例如Prometheus Node Exporter、collectd、Datadog 代理、New Relic 代理,或 Ganglia gmond


Job 负责批处理任务,即仅执行一次的任务,它保证批处理任务的一个或多个 Pod 成功结束


**4、**CronJobCron Job

管理基于时间的 Job,即:


在给定时间点只运行一次

周期性地在给定时间点运行

使用前提条件:当前使用的 Kubernetes 集群,版本 >= 1.8(对 CronJob)。对于先前版本的集群,版本 <1.8,启动 API Server时,通过传递选项–runtime-config=batch/v2alpha1=true可以开启 batch/v2alpha1API


典型的用法如下所示:


在给定的时间点调度 Job 运行


创建周期性运行的 Job,例如:数据库备份、发送邮件


**5、**StatefulSet

StatefulSet 作为 Controller 为 Pod 提供唯一的标识。它可以保证部署和 scale 的顺序


StatefulSet是为了解决有状态服务的问题(对应Deployments和ReplicaSets是为无状态服务而设计),其应用场景包括:


① 稳定的持久化存储,即Pod重新调度后还是能访问到相同的持久化数据,基于PVC来实现


② 稳定的网络标志,即Pod重新调度后其PodName和HostName不变,基于Headless Service(即没有Cluster IP的Service)来实现


③ 有序部署,有序扩展,即Pod是有顺序的,在部署或者扩展的时候要依据定义的顺序依次依次进行(即从0到N-1,在下一个Pod运行之前所有之前的Pod必须都是Running和Ready状态),基于init containers来实现


④ 有序收缩,有序删除(即从N-1到0)


**6、**Horizontal Pod Autoscaling(HPA )

应用的资源使用率通常都有高峰和低谷的时候,如何削峰填谷,提高集群的整体资源利用率,让service中的Pod个数自动调整呢?这就有赖于Horizontal Pod Autoscaling了,顾名思义,使Pod水平自动缩放


三、控制器实例

**1、**RS 与 RC 与 Deployment 关联RC (ReplicationController )

主要的作用就是用来确保容器应用的副本数始终保持在用户定义的副本数。即如果有容器异常退出,会自动创建新的Pod来替代;而如果异常多出来的容器也会自动回收


Kubernetes 官方建议使用 RS(ReplicaSet )替代 RC (ReplicationController )进行部署,RS 跟 RC 没有本质的不同,只是名字不一样,并且 RS 支持集合式的 selector


查看RS完整模板信息:kubectl explain rs


RS创建模板

apiVersion: extensions/v1beta1
kind: ReplicaSet
metadata:
  name: frontend
spec:
  replicas: 3
  selector:
    matchLabels:
      tier: frontend
  template:
    metadata:
      labels:
        tier: frontend
    spec:
      containers:
      - name: myapp
        image: hub.lqz.com/library/nginx:V1
        env:
        - name: GET_HOSTS_FROM
          value: dns
        ports:
        - containerPort: 80

资源控制器所创建的pod,删除后会被新建

kubectl get pod --show-labels 查看标签

2、RS 与 Deployment 的关联

1.png

Deployment 为 Pod 和 ReplicaSet 提供了一个声明式定义(declarative)方法,用来替代以前的ReplicationController 来方便的管理应用。典型的应用场景包括:


① 定义Deployment来创建Pod和ReplicaSet


② 滚动升级和回滚


③ 应用扩容和缩容


④ 暂停和继续Deployment


**3、**部署一个简单的 Nginx 应用(Deployment )

1、创建

kubectl apply -f deployment.yaml --record
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 3
  template:
    metadata:
      labels:
        app: nginx
  spec:
      containers:
      - name: nginx
    image: nginx:1.7.9
    ports:
    - containerPort: 80

kubectl create -f https://kubernetes.io/docs/user-guide/nginx-deployment.yaml --record## --record参数可以记录命令,我们可以很方便的查看每次 revision 的变化

2、扩容

kubectl scale deployment nginx-deployment --replicas 10

3、如果集群支持 horizontal pod autoscaling 的话,还可以为Deployment设置自动扩展

kubectl autoscale deployment nginx-deployment --min=10–max=15–cpu-percent=80

4、更新镜像也比较简单

kubectl set image deployment/nginx-deployment nginx=nginx:1.9.1

5、回滚

kubectl rollout undo deployment/nginx-deployment

6、更新 Deployment

6.1假如我们现在想要让 nginx pod 使用nginx:1.9.1的镜像来代替原来的nginx:1.7.9的镜像

kubectl set image deployment/nginx-deployment nginx=nginx:1.9.1deployment “nginx-deployment” image updated

6.2可以使用edit命令来编辑 Deployment

kubectl edit deployment/nginx-deploymentdeployment “nginx-deployment” edited

6.3查看 rollout 的状态

kubectl rollout status deployment/nginx-deployment

6.4查看历史 RS

1.png

6.5 Deployment 更新策略


Deployment 可以保证在升级时只有一定数量的 Pod 是 down 的。默认的,它会确保至少有比期望的Pod数量少一个是up状态(最多一个不可用)

Deployment 同时也可以确保只创建出超过期望数量的一定数量的 Pod。默认的,它会确保最多比期望的Pod数量多一个的 Pod 是 up 的(最多1个 surge )

未来的 Kuberentes 版本中,将从1-1变成25%-25%

6.6Rollover(多个rollout并行)


假如您创建了一个有5个niginx:1.7.9 replica的 Deployment,但是当还只有3个nginx:1.7.9的 replica 创建出来的时候您就开始更新含有5个nginx:1.9.1 replica 的 Deployment。在这种情况下,Deployment 会立即杀掉已创建的3个nginx:1.7.9的 Pod,并开始创建nginx:1.9.1的 Pod。它不会等到所有的5个nginx:1.7.9的Pod 都创建完成后才开始改变航道


6.7回退 Deployment

kubectl set image deployment/nginx-deployment nginx=nginx:1.91
kubectl rollout status deployments nginx-deployment
kubectl get pods
kubectl rollout history deployment/nginx-deployment
kubectl rollout undo deployment/nginx-deployment
## 可以使用 --revision参数指定某个历史版本
kubectl rollout undo deployment/nginx-deployment --to-revision=2  
## 暂停 deployment 的更新
kubectl rollout pause deployment/nginx-deployment

您可以用kubectl rollout status命令查看 Deployment 是否完成。如果 rollout 成功完成,kubectl rolloutstatus将返回一个0值的 Exit Code


6.8清理 Policy


您可以通过设置.spec.revisonHistoryLimit项来指定 deployment 最多保留多少 revision 历史记录。默认的会保留所有的 revision;如果将该项设置为0,Deployment 就不允许回退了


4、DaemonSet

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: daemon-example
  labels:
    app: daemonSet
spec:
  selector: 
    metchLables:
      name: daemon-example
    template:
      metadatas:
        lables: 
          name: daemon-example
    spec:
      containers:
      - name: daemon-example
        images: 容器镜像:版本

5、Job

Job 负责批处理任务,即仅执行一次的任务,它保证批处理任务的一个或多个 Pod 成功结束

特殊说明

spec.template格式同Pod

RestartPolicy仅支持Never或OnFailure

单个Pod时,默认Pod成功运行后Job即结束

spec.completions 标志Job结束需要成功运行的Pod个数,默认为1

spec.parallelism 标志并行运行的Pod的个数,默认为1

spec.activeDeadlineSeconds 标志失败Pod的重试最大时间,超过这个时间不会继续重试

apiVersion: batch/v1
kind: Job
metadata: 
  name: pi
spec:
  template:
    metadata:
      name: pi
    spec:
      containers:
      - name: pi
        images: per1
        command: ["per1", "-Mbignum=bpi", "-wle", "print bpi(2000)"]
      restartPolicy: Nerver

6、CronJob

CronJob Spec

spec.template格式同Pod

RestartPolicy仅支持Never或OnFailure

单个Pod时,默认Pod成功运行后Job即结束

spec.completions 标志Job结束需要成功运行的Pod个数,默认为1


spec.parallelism 标志并行运行的Pod的个数,默认为1


spec.activeDeadlineSeconds 标志失败Pod的重试最大时间,超过这个时间不会继续重试


CronJob

Cron Job 管理基于时间的 Job,即:

在给定时间点只运行一次

周期性地在给定时间点运行

使用条件:当前使用的 Kubernetes 集群,版本 >= 1.8(对 CronJob)

典型的用法如下所示:

在给定的时间点调度 Job 运行

创建周期性运行的 Job,例如:数据库备份、发送邮件


CronJob Spec

.spec.schedule :调度,必需字段,指定任务运行周期,格式同 Cron

.spec.jobTemplate :Job 模板,必需字段,指定需要运行的任务,格式同 Job

.spec.startingDeadlineSeconds :启动 Job 的期限(秒级别),该字段是可选的。如果因为任何原因而错

过了被调度的时间,那么错过执行时间的 Job 将被认为是失败的。如果没有指定,则没有期限

.spec.concurrencyPolicy :并发策略,该字段也是可选的。它指定了如何处理被 Cron Job 创建的 Job 的

并发执行。只允许指定下面策略中的一种:

Allow (默认):允许并发运行 Job

Forbid :禁止并发运行,如果前一个还没有完成,则直接跳过下一个

Replace :取消当前正在运行的 Job,用一个新的来替换

注意,当前策略只能应用于同一个 Cron Job 创建的 Job。如果存在多个 Cron Job,它们创建的 Job 之间总

是允许并发运行。

spec.suspend :挂起,该字段也是可选的。如果设置为 true ,后续所有执行都会被挂起。它对已经开始

执行的 Job 不起作用。默认值为 false 。


spec.successfulJobsHistoryLimit 和


spec.failedJobsHistoryLimit :历史限制,是可选的字段。它

们指定了可以保留多少完成和失败的 Job。默认情况下,它们分别设置为 3 和 1 。设置限制的值为 0 ,相

关类型的 Job 完成后将不会被保留。

apiVersion: batch/v1beta1
kind: CronJob
metadata: 
  name: hello
spec:
  #每一分钟执行一次
  schedule: "*/1 * * * *"
  jobTemplate: 
    spec:
      template:
        spec:
          containers:
          - name: hello
            images: busybox
            atgs: 
            - /bin/sh
            - -C
            - data; echo Hello from the Kubernetes cluster
          restartPolicy: OnFailure
$ kubectl get cronjob NAME SCHEDULE SUSPEND ACTIVE LAST-SCHEDULE hello */1 * * * * False 0 <none> 
$ kubectl get jobs NAME DESIRED SUCCESSFUL AGE hello-1202039034 1 1 49s 
$ pods=$(kubectl get pods --selector=job-name=hello-1202039034 --output=jsonpath= {.items..metadata.name}) 
$ kubectl logs $pods Mon Aug 29 21:34:09 UTC 2016 Hello from the Kubernetes cluster # 注意,删除 cronjob 的时候不会自动删除 job,这些 job 可以用 kubectl delete job 来删除 
$ kubectl delete cronjob hello cronjob "hello" deleted


四、Service

**一、**Service 的概念

Kubernetes Service定义了这样一种抽象:一个Pod的逻辑分组,一种可以访问它们的策略 —— 通常称为微服务。这一组Pod能够被Service访问到,通常是通过Label Selector

1.png

Service能够提供负载均衡的能力,但是在使用上有以下限制:只提供 4 层负载均衡能力,而没有 7 层功能,但有时我们可能需要更多的匹配规则来转发请求,这点上 4 层负载均衡是不支持的


**二、**Service 的类型

Service 在 K8s 中有以下四种类型ClusterIp:


① 默认类型,自动分配一个仅 Cluster 内部可以访问的虚拟 IP


1.png


② NodePort:在 ClusterIP 基础上为 Service 在每台机器上绑定一个端口,这样就可以通过:NodePort 来访问该服务


1.png


③ LoadBalancer:在 NodePort 的基础上,借助 cloud provider 创建一个外部负载均衡器,并将请求转发到: NodePort


1.png


④ ExternalName:把集群外部的服务引入到集群内部来,在集群内部直接使用。没有任何类型代理被创建,这只有 kubernetes 1.7 或更高版本的 kube-dns 才支持


1.png


svc基础导论


1.png


总结


客户端访问节点时通过iptables实现的,


iptables规则是通过kube-proxy写入的,


apiserver通过监控kube-proxy去进行对服务和端点的监控,


kube-proxy通过pod的标签(lables)去判断这个断点信息是否写入到Endpoints里去。


**三、**VIP 和 Service 代理

在 Kubernetes 集群中,每个 Node 运行一个kube-proxy进程。kube-proxy负责为Service实现了一种VIP(虚拟 IP)的形式,而不是ExternalName的形式。在 Kubernetes v1.0 版本,代理完全在 userspace。在Kubernetes v1.1 版本,新增了 iptables 代理,但并不是默认的运行模式。从 Kubernetes v1.2 起,默认就是iptables 代理。在 Kubernetes v1.8.0-beta.0 中,添加了 ipvs 代理


在 Kubernetes 1.14 版本开始默认使用ipvs 代理


在 Kubernetes v1.0 版本,Service是 “4层”(TCP/UDP over IP)概念。在 Kubernetes v1.1 版本,新增了Ingress API(beta 版),用来表示 “7层”(HTTP)服务


为何不使用 round-robin DNS?

DNS会在很多的客户端里进行缓存,很多服务在访问DNS进行域名解析完成、得到地址后不会对DNS的解析进行清除缓存的操作,所以一旦有他的地址信息后,不管访问几次还是原来的地址信息,导致负载均衡无效。


四、代理模式的分类

1、userspace 代理模式

1.png


2、iptables 代理模式


1.png

3、ipvs 代理模式

这种模式,kube-proxy 会监视 Kubernetes Service对象和Endpoints,调用netlink接口以相应地创建ipvs 规则并定期与 Kubernetes Service对象和Endpoints对象同步 ipvs 规则,以确保 ipvs 状态与期望一致。访问服务时,流量将被重定向到其中一个后端 Pod


与 iptables 类似,ipvs 于 netfilter 的 hook 功能,但使用哈希表作为底层数据结构并在内核空间中工作。这意味着 ipvs 可以更快地重定向流量,并且在同步代理规则时具有更好的性能。此外,ipvs 为负载均衡算法提供了更多选项,例如:


① rr:轮询调度


② lc:最小连接数


③ dh:目标哈希


④ sh:源哈希


⑤ sed:最短期望延迟


⑥ nq:不排队调度


1.png


五、ClusterIP

clusterIP 主要在每个 node 节点使用 iptables,将发向 clusterIP 对应端口的数据,转发到 kube-proxy 中。然后 kube-proxy 自己内部实现有负载均衡的方法,并可以查询到这个 service 下对应 pod 的地址和端口,进而把数据转发给对应的 pod 的地址和端口


1.png


为了实现图上的功能,主要需要以下几个组件的协同工作:


apiserver 用户通过kubectl命令向apiserver发送创建service的命令,apiserver接收到请求后将数据存储到etcd中

kube-proxy kubernetes的每个节点中都有一个叫做kube-porxy的进程,这个进程负责感知service,pod的变化,并将变化的信息写入本地的iptables规则中

iptables 使用NAT等技术将virtualIP的流量转至endpoint中

创建 myapp-deploy.yaml 文件
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-deploy
  namespace: default
spec:
  replicas: 3
  selector:
    matchLabels:
    app: myapp
      release: stabel
  template:
    metadata:
      labels:
        app: myapp
      release: stabel
        env: test
  spec:
      containers:
      - name: myapp
    image: wangyanglinux/myapp:v2
        imagePullPolicy: IfNotPresent
        ports:
    - name: http
        containerPort: 80
创建service
apiVersion: v1
kind: Service
metadata:
  name: myapp
  namespace: default
spec:
  type: ClusterIP
  selector:
    app: myapp
    release: stabel
  ports:
  - name: http
    port: 80
    targetPort: 80

六、Headless Service

有时不需要或不想要负载均衡,以及单独的 Service IP 。遇到这种情况,可以通过指定 ClusterIP(spec.clusterIP) 的值为 “None” 来创建 Headless Service 。这类 Service 并不会分配 Cluster IP, kube-proxy 不会处理它们,而且平台也不会为它们进行负载均衡和路由

[root@k8s-master mainfests]# vim myapp-svc-headless.yaml
apiVersion: v1
kind: Service
metadata:
  name: myapp-headless
  namespace: default
spec:
  selector:
    app: myapp
    clusterIP: "None"
  ports:
  - port: 80
    targetPort: 80
[root@k8s-master mainfests]# dig -t A myapp-headless.default.svc.cluster.local. @10.96.0.10

七、NodePortnodePort

的原理在于在 node 上开了一个端口,将向该端口的流量导入到 kube-proxy,然后由 kube-proxy 进一步到给对应的 pod


类型 命令 描述 基础命令 create 通过文件名或标准输入创建资源 expose 将一个资源公开为一个新的Service run 在集群中运行一个特定的镜像 set 在对象上设置特定的功能 get 显示一个或多个资源 explain 文档参考资料。 edit 使用默认的编辑器编辑一个资源。 delete 通过文件名、标准输入、资源名称或标签选择器来删除资源。 部署命令 rollout 管理资源的发布 rolling-update 对给定的复制控制器滚动更新 scale 扩容或缩容Pod数量,Deployment、ReplicaSet、RC或Job autoscale 创建一个自动选择扩容或缩容并设置Pod数量 集群管理命令 certificate 修改证书资源 cluster-info 显示集群信息 top 显示资源(CPU/Memory/Storage)使用。需要Heapster运行 cordon 标记节点不可调度 uncordon 标记节点可调度 drain 维护期间排除节点 taint

[root@master manifests]# vim myapp-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: myapp
  namespace: default
spec:
  type: NodePort
  selector:
    app: myapp
    release: stabel
  ports:
  - name: http
    port: 80
    targetPort: 80
查看流程
iptables -t nat -nv

八、LoadBalancer(了解  )

loadBalancer 和 nodePort 其实是同一种方式。区别在于 loadBalancer 比 nodePort 多了一步,就是可以调用cloud provider 去创建 LB 来向节点导流(LB收费)


**九、**ExternalName

这种类型的 Service 通过返回 CNAME 和它的值,可以将服务映射到 externalName 字段的内容( 例如:hub.atguigu.com )。ExternalName Service 是 Service 的特例,它没有 selector,也没有定义任何的端口和Endpoint。相反的,对于运行在集群外部的服务,它通过返回该外部服务的别名这种方式来提供服务

kind: Service
apiVersion: v1
metadata:
  name: my-service-1
  namespace: default
spec:
  type: ExternalName
  externalName: hub.atguigu.com

当查询主机 my-service.defalut.svc.cluster.local ( SVC_NAME.NAMESPACE.svc.cluster.local )时,集群的DNS 服务将返回一个值 my.database.example.com 的 CNAME 记录。访问这个服务的工作方式和其他的相同,唯一不同的是重定向发生在 DNS 层,而且不会进行代理或转发


五、ingress

**一、**资料信息

Ingress-Nginx github 地址:https://github.com/kubernetes/ingress-nginx


Ingress-Nginx 官方网站:https://kubernetes.github.io/ingress-nginx/


进入官方下载


**wget **https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/static/mandatory.yaml

1.png

1.png

**二、**部署 Ingress-Nginx

kubectl apply -f mandatory.yaml
kubectl apply -f service-nodeport.yaml

Ingress HTTP 代理访问

deployment、Service、Ingress Yaml 文件

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: nginx-dm
spec:
  replicas: 2
  template:
    metadata:
      labels:
        name: nginx
    spec:
      containers:
      - name: nginx
      image: wangyanglinux/myapp:v1
    imagePullPolicy: IfNotPresent
    ports:
    - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-svc
spec:
  ports:
  - port: 80
    targetPort: 80
    protocol: TCP
  selector:
    name: nginx
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
   name: nginx-test
spec:
  rules:
  - host: www1.atguigu.com
  http:
  paths:
    - path: /
      backend:
    serviceName: nginx-svc
    servicePort: 80

**三、**Ingress HTTPS 代理访问

创建证书,以及 cert 存储方式

openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj"/CN=nginxsvc/O=nginxsvc" kubectl create secret tls tls-secret --key tls.key --cert tls.crt

deployment、Service、Ingress Yaml 文件

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: nginx-test
spec:
  tls:
    - hosts:
      - foo.bar.com
    secretName: tls-secret
  rules:
    - host: foo.bar.com
    http:
    paths:
    - path: /
      backend:
      serviceName: nginx-svc
      servicePort: 80

**四、**Nginx 进行 BasicAuth

yum -y install httpd
htpasswd -c auth foo
kubectl create secret generic basic-auth --from-file=auth

yaml

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: ingress-with-auth
  annotations:
  nginx.ingress.kubernetes.io/auth-type: basic
  nginx.ingress.kubernetes.io/auth-secret: basic-auth
  nginx.ingress.kubernetes.io/auth-realm: 'Authentication Required - foo'
spec:
  rules:
  - host: foo2.bar.com
  http:
      paths:
      - path: /
    backend:
      serviceName: nginx-svc
      servicePort: 80

**五、**Nginx 进行重写

1.png

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: nginx-test
  annotations:
  nginx.ingress.kubernetes.io/rewrite-target: http://foo.bar.com:31795/hostname.html
spec:
  rules:
  - host: foo10.bar.com
    http:
     paths:
     - path: /
       backend:
     serviceName: nginx-svc
       servicePort: 80

六、存储

一、存储之ConfigMap

**1、**描述信息

ConfigMap 功能在 Kubernetes1.2 版本中引入,许多应用程序会从配置文件、命令行参数或环境变量中读取配置信息。ConfigMap API 给我们提供了向容器中注入配置信息的机制,ConfigMap 可以被用来保存单个属性,也可以用来保存整个配置文件或者 JSON 二进制大对象


ConfigMap 的创建存储之ConfigMap


I、使用目录创建

$ ls docs/user-guide/configmap/kubectl/
game.properties
ui.properties
$ cat docs/user-guide/configmap/kubectl/game.properties
enemies=aliens
lives=3
enemies.cheat=true
enemies.cheat.level=noGoodRotten
secret.code.passphrase=UUDDLRLRBABAS
secret.code.allowed=true
secret.code.lives=30
$ cat docs/user-guide/configmap/kubectl/ui.properties
color.good=purple
color.bad=yellow
allow.textmode=true
how.nice.to.look=fairlyNice
$ kubectl create configmap game-config --from-file=docs/user-guide/configmap/kubectl
 game-config :configmap的名称
--from-file:指定一个目录,目录下的所有内容都会被创建出来。以键值对的形式
—from-file指定在目录下的所有文件都会被用在 ConfigMap 里面创建一个键值对,键的名字就是文件名,值就是文件的内容
kubectl get cm 查看configmap文件
kubectl get cm game-config -o yaml   查看详细信息
kubectl describe cm
II、使用文件创建

只要指定为一个文件就可以从单个文件中创建 ConfigMap

$ kubectl create configmap game-config-2 --from-file=docs/user-guide/configmap/kubectl/game.properties
$ kubectlget configmaps game-config-2 -o yaml

–from-file这个参数可以使用多次,你可以使用两次分别指定上个实例中的那两个配置文件,效果就跟指定整个目录是一样的

III、使用字面值创建

使用文字值创建,利用—from-literal参数传递配置信息,该参数可以使用多次,格式如下

$ kubectl create configmap special-config --from-literal=special.how=very --from-literal=special.type=charm
$ kubectlget configmaps special-config -o yaml    #查看
--from-literal=special.how=very  
指定键名为special.how  键值为very
**2、**Pod 中使用 ConfigMap
I、使用 ConfigMap 来替代环境变
apiVersion: v1
kind: ConfigMap
metadata:
  name: special-config
  namespace: default
data:
  special.how: very
  special.type: charm
apiVersion: v1
kind: ConfigMap
metadata:
  name: env-config
  namespace: default
data:
  log_level: INFO
#将两个ConfigMap文件注入到pod环境中
apiVersion: v1
kind: Pod
metadata:
  name: dapi-test-pod
spec:
  containers:
  - name: test-container
    image: hub.atguigu.com/library/myapp:v1
    command: ["/bin/sh","-c","env"]
    env:                           #第一种导入方案
    - name: SPECIAL_LEVEL_KEY
        valueFrom:
      configMapKeyRef:
      name: special-config    #从那个configMap文件导入
            key: special.how       #导入的是那个键的键名,就是将special.how键的键值赋予
    - name: SPECIAL_TYPE_KEY
        valueFrom:
      configMapKeyRef:
            name: special-config
      key: special.type
  envFrom:                   #第二种导入方案
    - configMapRef: 
          name: env-config
  restartPolicy: Never

II、用 ConfigMap 设置命令行参数

apiVersion: v1
kind: ConfigMap
metadata:
  name: special-config
  namespace: default
data:
  special.how: very
  special.type: charm
apiVersion: v1
kind: Pod
metadata:
  name: dapi-test-pod
spec:
  containers:
    - name: test-container
      image: hub.atguigu.com/library/myapp:v1
      command: ["/bin/sh","-c","echo $(SPECIAL_LEVEL_KEY) $(SPECIAL_TYPE_KEY)"]
      env:
    - name: SPECIAL_LEVEL_KEY
      valueFrom:
      configMapKeyRef:
              name: special-config
              key: special.how
    - name: SPECIAL_TYPE_KEY
          valueFrom:
      configMapKeyRef:
        name: special-config
          key: special.type
  restartPolicy: Never

III、通过数据卷插件使用ConfigMap

apiVersion: v1
kind: ConfigMap
metadata:
name: special-config
namespace: default
data:
  special.how: very
  special.type: charm

在数据卷里面使用这个 ConfigMap,有不同的选项。最基本的就是将文件填入数据卷,在这个文件中,键就是文件名,键值就是文件内容

apiVersion: v1
kind: Pod
metadata:
  name: dapi-test-pod
spec:
  containers:
    - name: test-container
      image: hub.atguigu.com/library/myapp:v1
      command: ["/bin/sh","-c","cat /etc/config/special.how"]
      volumeMounts:                      #容器下进行volum挂载
      - name: config-volume                #挂载的名称为config-volume,与下边相呼应
        mountPath: /etc/config
  volumes:
    - name: config-volume      #名称为config-volume
      configMap:              #从configMap导入
        name: special-config     #导入的configMap名称
  restartPolicy: Never
**3、**ConfigMap 的热更新
#创建一个configMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: log-config
  namespace: default
data:
  log_level: INFO
---
#创建Deployment对configMap进行调用,调用的方式是以volum方式进行挂载
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: my-nginx
spec:
  replicas: 1
  template:
    metadata:
      labels:
    run: my-nginx
    spec:
      containers:
      - name: my-nginx
        image: hub.atguigu.com/library/myapp:v1
        ports:
        - containerPort: 80
    volumeMounts:
    - name: config-volume
         mountPath: /etc/config
    volumes:
      - name: config-volume
          configMap:
            name: log-config
#获取信息
$ kubectl exec `kubectl get pods -l run=my-nginx -o=name|cut -d "/" -f2`cat/etc/config/log_level
INFO

修改 ConfigMap

$ kubectl edit configmap log-config

修改log_level的值为DEBUG等待大概 10 秒钟时间,再次查看环境变量的值

$ kubectl exec `kubectl get pods -l run=my-nginx -o=name|cut -d "/" -f2`cat /tmp/log_levelDEBUG

ConfigMap 更新后滚动更新 Pod

更新 ConfigMap 目前并不会触发相关 Pod 的滚动更新,可以通过修改 pod annotations 的方式强制触发滚动更新

$ kubectl patch deployment my-nginx --patch'{"spec": {"template": {"metadata": {"annotations":{"version/config": "20190411" }}}}}'

这个例子里我们在.spec.template.metadata.annotations中添加version/config,每次通过修改version/config来触发滚动更新


!!!更新 ConfigMap 后:使用该 ConfigMap 挂载的 Env 不会同步更新使用该 ConfigMap 挂载的 Volume 中的数据需要一段时间(实测大概10秒)才能同步更新


二、存储之secret

**1、**Secret 存在意义

Secret 解决了密码、token、密钥等敏感数据的配置问题,而不需要把这些敏感数据暴露到镜像或者 Pod Spec中。Secret 可以以 Volume 或者环境变量的方式使用


2、Secret 有三种类型

① Service Account:用来访问 Kubernetes API,由 Kubernetes 自动创建,并且会自动挂载到 Pod 的/run/secrets/kubernetes.io/serviceaccount目录中


② Opaque:base64编码格式的Secret,用来存储密码、密钥等


③ kubernetes.io/dockerconfigjson:用来存储私有 docker registry 的认证信息


**3、**Service Account

Service Account 用来访问 Kubernetes API,由 Kubernetes 自动创建,并且会自动挂载到 Pod的/run/secrets/kubernetes.io/serviceaccount目录中

1.png

**4、**Opaque Secret
**Ⅰ、**创建说明

Opaque 类型的数据是一个 map 类型,要求 value 是 base64 编码格式:

$ echo-n"admin" | base64
YWRtaW4=
$ echo-n"1f2d1e2e67df" | base64
MWYyZDFlMmU2N2Rm
II、使用方式

1)、将 Secret 挂载到 Volume 中

apiVersion: v1
kind: Pod
metadata:
  labels:
    name: seret-test
  name: seret-test
spec:
  volumes:
  - name: secrets
    secret:
      secretName: mysecret
  containers:
  - image: hub.atguigu.com/library/myapp:v1
    name: db
    volumeMounts:
    - name: secrets
      mountPath: ""   #挂载目录
    readOnly: true

2)、将 Secret 导出到环境变量中

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: pod-deployment
spec:
  replicas: 2
  template:
    metadata:
      labels:
        app: pod-deployment
    spec:
      containers:
    - name: pod-1
    image: hub.atguigu.com/library/myapp:v1
    ports:
    - containerPort: 80
    env:
    - name: TEST_USER
      valueFrom:
      secretKeyRef:
        name: mysecret
        key: username
    - name: TEST_PASSWORD
    valueFrom:
      secretKeyRef:
      name: mysecret
      key: password
**5、**kubernetes.io/dockerconfigjson

使用 Kuberctl 创建 docker registry 认证的 secret

$ kubectl create secret docker-registry myregistrykey --docker-server=DOCKER_REGISTRY_SERVER --docker-username=DOCKER_USER --docker-password=DOCKER_PASSWORD --docker-email=DOCKER_EMAILsecret "myregistrykey" created.

在创建 Pod 的时候,通过imagePullSecrets来引用刚创建的 `myregistrykey

apiVersion: v1
kind: Pod
metadata:
  name: foo
spec:
  containers:
    - name: foo
      image: roc/awangyang:v1
  imagePullSecrets:
    - name: myregistrykey

三、存储数据卷Volume

容器磁盘上的文件的生命周期是短暂的,这就使得在容器中运行重要应用时会出现一些问题。首先,当容器崩溃时,kubelet 会重启它,但是容器中的文件将丢失——容器以干净的状态(镜像最初的状态)重新启动。其次,在Pod中同时运行多个容器时,这些容器之间通常需要共享文件。Kubernetes 中的Volume抽象就很好的解决了这些问题


**1、**背景

Kubernetes 中的卷有明确的寿命 —— 与封装它的 Pod 相同。所f以,卷的生命比 Pod 中的所有容器都长,当这个容器重启时数据仍然得以保存。当然,当 Pod 不再存在时,卷也将不复存在。也许更重要的是,Kubernetes支持多种类型的卷,Pod 可以同时使用任意数量的卷


**2、**卷的类型

1.png

**3、**emptyDir

当 Pod 被分配给节点时,首先创建emptyDir卷,并且只要该 Pod 在该节点上运行,该卷就会存在。正如卷的名字所述,它最初是空的。Pod 中的容器可以读取和写入emptyDir卷中的相同文件,尽管该卷可以挂载到每个容器中的相同或不同路径上。当出于任何原因从节点中删除 Pod 时,emptyDir中的数据将被永久删除


emptyDir的用法有:


① 暂存空间,例如用于基于磁盘的合并排序


② 用作长时间计算崩溃恢复时的检查点


③ Web服务器容器提供数据时,保存内容管理器容器提取的文件


apiVersion: v1
kind: Pod
metadata:
  name: test-pd
spec:
  containers:
  - image: k8s.gcr.io/test-webserver
    name: test-container
    volumeMounts:
  - mountPath: /cache
    name: cache-volume
 volumes:
 - name: cache-volume
   emptyDir: {}


4、hostPathhostPath

卷将主机节点的文件系统中的文件或目录挂载到集群中


hostPath的用途如下:


① 运行需要访问 Docker 内部的容器;使用/var/lib/docker的hostPath


② 在容器中运行 cAdvisor;使用/dev/cgroups的hostPath


③ 允许 pod 指定给定的 hostPath 是否应该在 pod 运行之前存在,是否应该创建,以及它应该以什么形式存在


除了所需的path属性之外,用户还可以为hostPath卷指定type


空字符串(默认)用于向后兼容,这意味着在挂载 hostPath 卷之前不会执行任何检查


值 行为

空字符串(默认)用于向后兼容,这意味着在挂载 hostPath 卷之前不会执行任何检查

DirectoryOrCreate 如果在给定的路径上没有任何东西存在,那么将根据需要在那里创建一个空目录,权限设置为0755,与Kubelet具有相同的组和所有权。

Directory 给定的路径下必须存在目录

FileOrCreate 如果在给定的路径上没有任何东西存在,那么会根据需要创建一个空文件,权限设置为0644,与Kubelet具有相同的组和所有权。

File 给定的路径下必须存在文件

Socket 给定的路径下必须存在UNIX套接字

CharDevice 给定的路径下必须存在字符设备

BlockDevice 给定的路径下必须存在块设备

使用这种卷类型是请注意,因为:


① 由于每个节点上的文件都不同,具有相同配置(例如从 podTemplate 创建的)的 pod 在不同节点上的行为可能会有所不同


② 当 Kubernetes 按照计划添加资源感知调度时,将无法考虑hostPath使用的资源


③ 在底层主机上创建的文件或目录只能由 root 写入。您需要在特权容器中以 root 身份运行进程,或修改主机上的文件权限以便写入hostPath卷

apiVersion: v1
kind: Pod
metadata:
  name: test-pd
spec:
  containers:
    - image: k8s.gcr.io/test-webserver
   name: test-container
      volumeMounts:
    - mountPath: /test-pd
     name: test-volume
  volumes:
  - name: test-volume
    hostPath:
# directory location on host
    path: /data
# this field is optional type: Directory
    type: Directory


四、PersistentVolumeClaim (PVC)

PersistentVolume (PV)

是由管理员设置的存储,它是群集的一部分。就像节点是集群中的资源一样,PV 也是集群中的资源。 PV 是 Volume 之类的卷插件,但具有独立于使用 PV 的 Pod 的生命周期。此 API 对象包含存储实现的细节,即 NFS、

iSCSI 或特定于云供应商的存储系统


PersistentVolumeClaim (PVC)

是用户存储的请求。它与 Pod 相似。Pod 消耗节点资源,PVC 消耗 PV 资源。Pod 可以请求特定级别的资源

(CPU 和内存)。声明可以请求特定的大小和访问模式(例如,可以以读/写一次或 只读多次模式挂载)


静态 pv

集群管理员创建一些 PV。它们带有可供群集用户使用的实际存储的细节。它们存在于 Kubernetes API 中,可用

于消费


动态

当管理员创建的静态 PV 都不匹配用户的 PersistentVolumeClaim 时,集群可能会尝试动态地为 PVC 创建卷。此

配置基于 StorageClasses :PVC 必须请求 [存储类],并且管理员必须创建并配置该类才能进行动态创建。声明该

类为 “” 可以有效地禁用其动态配置

要启用基于存储级别的动态存储配置,集群管理员需要启用 API server 上的 DefaultStorageClass [准入控制器]

。例如,通过确保 DefaultStorageClass 位于 API server 组件的 --admission-control 标志,使用逗号分隔的

有序值列表中,可以完成此操作


绑定

master 中的控制环路监视新的 PVC,寻找匹配的 PV(如果可能),并将它们绑定在一起。如果为新的 PVC 动态

调配 PV,则该环路将始终将该 PV 绑定到 PVC。否则,用户总会得到他们所请求的存储,但是容量可能超出要求

的数量。一旦 PV 和 PVC 绑定后, PersistentVolumeClaim 绑定是排他性的,不管它们是如何绑定的。 PVC 跟

PV 绑定是一对一的映射


持久化卷声明的保护

PVC 保护的目的是确保由 pod 正在使用的 PVC 不会从系统中移除,因为如果被移除的话可能会导致数据丢失

当启用PVC 保护 alpha 功能时,如果用户删除了一个 pod 正在使用的 PVC,则该 PVC 不会被立即删除。PVC 的

删除将被推迟,直到 PVC 不再被任何 pod 使用


持久化卷类型

PersistentVolume 类型以插件形式实现。Kubernetes 目前支持以下插件类型:


GCEPersistentDisk AWSElasticBlockStore AzureFile AzureDisk FC (Fibre Channel)


FlexVolume Flocker NFS iSCSI RBD (Ceph Block Device) CephFS


Cinder (OpenStack block storage) Glusterfs VsphereVolume Quobyte Volumes


HostPath VMware Photon Portworx Volumes ScaleIO Volumes StorageOS


持久卷演示代码


apiVersion: v1 
kind: PersistentVolume 
metadata: 
  name: pv0003 
spec: 
  capacity: 
    storage: 5Gi 
  volumeMode: Filesystem 
  accessModes: 
    - ReadWriteOnce 
  persistentVolumeReclaimPolicy: Recycle 
  storageClassName: slow 
  mountOptions: 
    - hard 
    - nfsvers=4.1 
  nfs:
    path: /tmp 
    server: 172.17.0.2


PV 访问模式

PersistentVolume 可以以资源提供者支持的任何方式挂载到主机上。如下表所示,供应商具有不同的功能,每个


PV 的访问模式都将被设置为该卷支持的特定模式。例如,NFS 可以支持多个读/写客户端,但特定的 NFS PV 可能


以只读方式导出到服务器上。每个 PV 都有一套自己的用来描述特定功能的访问模式


**ReadWriteOnce——**该卷可以被单个节点以读/写模式挂载
**ReadOnlyMany——**该卷可以被多个节点以只读模式挂载
**ReadWriteMany——**该卷可以被多个节点以读/写模式挂载


在命令行中,访问模式缩写为:


**RWO - ReadWriteOnce**
**ROX - ReadOnlyMany**
**RWX - ReadWriteMany**


回收策略

Retain(保留)——手动回收


Recycle(回收)——基本擦除( rm **-**rf /thevolume/)


Delete(删除)——关联的存储资产(例如 AWS EBS、GCE PD、Azure Disk 和 OpenStack Cinder 卷)


将被删除


当前,只有 NFS 和 HostPath **支持回收策略。AWS EBS、GCE PD、**Azure Disk 和 Cinder 卷支持删除策略


状态

卷可以处于以下的某种状态:


Available(可用)——一块空闲资源还没有被任何声明绑定


Bound(已绑定)——卷已经被声明绑定


Released(已释放)**——**声明被删除,但是资源还未被集群重新声明Failed(失败)——该卷的自动回收失败


命令行会显示绑定到 PV 的 PVC 的名称


持久化演示说明 - NFS

Ⅰ、安装 NFS 服务器

yum install -y nfs-common nfs-utils rpcbind 
mkdir /nfsdata 
chmod 666 /nfsdata 
chown nfsnobody /nfsdata 
cat /etc/exports 
    /nfsdata *(rw,no_root_squash,no_all_squash,sync) 
systemctl start rpcbind 
systemctl start nfs


Ⅱ、部署 PV

apiVersion: v1 
kind: PersistentVolume 
metadata: 
  name: nfspv1 
spec: 
  capacity: 
    storage: 1Gi 
  accessModes: 
  - ReadWriteOnce 
  persistentVolumeReclaimPolicy: Recycle 
  storageClassName: nfs 
  nfs:
    path: /data/nfs 
    server: 10.66.66.10

Ⅲ、创建服务并使用 PVC

apiVersion: v1 
kind: Service 
metadata: 
  name: nginx 
  labels: 
  app: nginx 
spec: 
  ports: 
  - port: 80 
    name: web 
    clusterIP: None 
    selector: 
      app: nginx
---
apiVersion: apps/v1 
kind: StatefulSet 
metadata: 
  name: web 
spec: 
  selector: 
    matchLabels: 
      app: nginx 
  serviceName: "nginx" 
  replicas: 3 
  template: 
    metadata: 
   labels: 
  app: nginx 
    spec: 
   containers: 
  - name: nginx 
    image: k8s.gcr.io/nginx-slim:0.8 
    ports: 
    - containerPort: 80 
    name: web 
    volumeMounts: 
    - name: www 
    mountPath: /usr/share/nginx/html 
    volumeClaimTemplates: 
    - metadata: 
  name: www 
   spec: 
  accessModes: [ "ReadWriteOnce" ] 
  storageClassName: "nfs" 
  resources: 
    requests: 
    storage: 1Gi

关于 StatefulSet

匹配 Pod name ( 网络标识 ) 的模式为:$(statefulset名称)-$(序号),比如上面的示例:web-0,web-1,

web-2

StatefulSet 为每个 Pod 副本创建了一个 DNS 域名,这个域名的格式为: $(podname).(headless server

name),也就意味着服务间是通过Pod域名来通信而非 Pod IP,因为当Pod所在Node发生故障时, Pod 会

被飘移到其它 Node 上,Pod IP 会发生变化,但是 Pod 域名不会有变化

StatefulSet 使用 Headless 服务来控制 Pod 的域名,这个域名的 FQDN 为:$(service

name).$(namespace).svc.cluster.local,其中,“cluster.local” 指的是集群的域名

根据 volumeClaimTemplates,为每个 Pod 创建一个 pvc,pvc 的命名规则匹配模式:

(volumeClaimTemplates.name)-(pod_name),比如上面的 volumeMounts.name=www, Pod

name=web-[0-2],因此创建出来的 PVC 是 www-web-0、www-web-1、www-web-2

删除 Pod 不会删除其 pvc,手动删除 pvc 将自动释放 pv,


Statefulset的启停顺序:

**有序部署:**部署StatefulSet时,如果有多个Pod副本,它们会被顺序地创建(从0到N-1)并且,在下一个

Pod运行之前所有之前的Pod必须都是Running和Ready状态。

**有序删除:**当Pod被删除时,它们被终止的顺序是从N-1到0。

**有序扩展:**当对Pod执行扩展操作时,与部署一样,它前面的Pod必须都处于Running和Ready状态。


StatefulSet使用场景:

1、稳定的持久化存储,即Pod重新调度后还是能访问到相同的持久化数据,基于 PVC 来实现。

2、稳定的网络标识符,即 Pod 重新调度后其 PodName 和 HostName 不变。

3、有序部署,有序扩展,基于 init containers 来实现。

4、有序收缩。

相关实践学习
通过Ingress进行灰度发布
本场景您将运行一个简单的应用,部署一个新的应用用于新的发布,并通过Ingress能力实现灰度发布。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
相关文章
|
7月前
|
Kubernetes Docker 容器
Kubernetes学习笔记-Part.06 Docker安装
Part.01 Kubernets与docker Part.02 Docker版本 Part.03 Kubernetes原理 Part.04 资源规划 Part.05 基础环境准备 Part.06 Docker安装 Part.07 Harbor搭建 Part.08 K8s环境安装 Part.09 K8s集群构建 Part.10 容器回退
73 1
|
4月前
|
Prometheus Kubernetes 网络协议
k8s学习笔记之CoreDNS
k8s学习笔记之CoreDNS
|
4月前
|
Kubernetes jenkins 持续交付
jenkins学习笔记之二十一:k8s部署jenkins及动态slave
jenkins学习笔记之二十一:k8s部署jenkins及动态slave
|
4月前
|
存储 Kubernetes 数据安全/隐私保护
k8s学习笔记之ConfigMap和Secret
k8s学习笔记之ConfigMap和Secret
|
4月前
|
存储 运维 Kubernetes
k8s学习笔记之StorageClass+NFS
k8s学习笔记之StorageClass+NFS
|
7月前
|
Kubernetes 调度 Docker
Ubantu docker学习笔记(十一)k8s基本操作
Ubantu docker学习笔记(十一)k8s基本操作
|
7月前
|
Kubernetes Docker 容器
Kubernetes学习笔记-Part.08 安装k8s环境
Part.01 Kubernets与docker Part.02 Docker版本 Part.03 Kubernetes原理 Part.04 资源规划 Part.05 基础环境准备 Part.06 Docker安装 Part.07 Harbor搭建 Part.08 K8s环境安装 Part.09 K8s集群构建 Part.10 容器回退
108 2
|
7月前
|
Kubernetes Linux 开发工具
Kubernetes学习笔记-Part.05 基础环境准备
Part.01 Kubernets与docker Part.02 Docker版本 Part.03 Kubernetes原理 Part.04 资源规划 Part.05 基础环境准备 Part.06 Docker安装 Part.07 Harbor搭建 Part.08 K8s环境安装 Part.09 K8s集群构建 Part.10 容器回退
81 1
|
7月前
|
存储 Kubernetes Cloud Native
Kubernetes学习笔记-Part.07 Harbor搭建
Part.01 Kubernets与docker Part.02 Docker版本 Part.03 Kubernetes原理 Part.04 资源规划 Part.05 基础环境准备 Part.06 Docker安装 Part.07 Harbor搭建 Part.08 K8s环境安装 Part.09 K8s集群构建 Part.10 容器回退
104 0
Kubernetes学习笔记-Part.07 Harbor搭建
|
7月前
|
Kubernetes Docker 容器
Kubernetes学习笔记-Part.10 容器回退
Part.01 Kubernets与docker Part.02 Docker版本 Part.03 Kubernetes原理 Part.04 资源规划 Part.05 基础环境准备 Part.06 Docker安装 Part.07 Harbor搭建 Part.08 K8s环境安装 Part.09 K8s集群构建 Part.10 容器回退
111 0