写点什么

自从上了 K8S,项目更新都不带停机的!

发布于: 2021 年 01 月 26 日

其实 K8S 中还有一些高级特性也很值得学习,比如弹性扩缩应用、滚动更新、配置管理、存储卷、网关路由等。今天我们就来了解下这些高级特性,希望对大家有所帮助!

核心概念

首先我们先来了解一些核心概念,了解这些核心概念对使用 K8S 的高级特性很有帮助。

ReplicaSet

ReplicaSet 确保任何时间都有指定数量的 Pod 副本在运行。通常用来保证给定数量的、完全相同的 Pod 的可用性。建议使用 Deployment 来管理 ReplicaSet,而不是直接使用 ReplicaSet。

ConfigMap

ConfigMap 是一种 API 对象,用来将非机密性的数据保存到键值对中。使用时,Pod 可以将其用作环境变量、命令行参数或者存储卷中的配置文件。使用 ConfigMap 可以将你的配置数据和应用程序代码分开。

Volume

Volume 指的是存储卷,包含可被 Pod 中容器访问的数据目录。容器中的文件在磁盘上是临时存放的,当容器崩溃时文件会丢失,同时无法在多个 Pod 中共享文件,通过使用存储卷可以解决这两个问题。

常用的存储卷有如下几种:

  • configMap:configMap 卷提供了向 Pod 注入配置数据的方法。ConfigMap 对象中存储的数据可以被 configMap 类型的卷引用,然后被 Pod 中运行的容器化应用使用。

  • emptyDir:emptyDir 卷可用于存储缓存数据。当 Pod 分派到某个 Node 上时,emptyDir 卷会被创建,并且 Pod 在该节点上运行期间,卷一直存在。当 Pod 被从节点上删除时 emptyDir 卷中的数据也会被永久删除。

  • hostPath:hostPath 卷能将主机节点文件系统上的文件或目录挂载到你的 Pod 中。在 Minikube 中的主机指的是 Minikube 所在虚拟机。

  • local:local 卷所代表的是某个被挂载的本地存储设备,例如磁盘、分区或者目录。local 卷只能用作静态创建的持久卷,尚不支持动态配置。

  • nfs:nfs 卷能将 NFS(网络文件系统)挂载到你的 Pod 中。

  • persistentVolumeClaim:persistentVolumeClaim 卷用来将持久卷(PersistentVolume)挂载到 Pod 中。持久卷(PV)是集群中的一块存储,可以由管理员事先供应,或者使用存储类(Storage Class)来动态供应,持久卷是集群资源类似于节点。

Ingress

Ingress 类似于 K8S 中的网关服务,是对集群中服务的外部访问进行管理的 API 对象,典型的访问方式是 HTTP。Ingress 可以提供负载均衡、SSL 终结和基于名称的虚拟托管。


高级特性

扩缩应用

当流量增加时,我们需要扩容应用程序满足用户需求。当流量减少时,需要缩放应用以减少服务器开销。在 K8S 中扩缩是通过改变 Deployment 中的副本数量来实现的。

  • 获取所有 Deployment 可使用如下命令:

kubectl get deployments
复制代码


点击并拖拽以移动


NAME               READY   UP-TO-DATE   AVAILABLE   AGEkubernetes-nginx   1/1     1            1           43h
复制代码


点击并拖拽以移动
  • 获取所有 ReplicaSet 可使用如下命令:

kubectl get rs
复制代码


点击并拖拽以移动


NAME                          DESIRED   CURRENT   READY   AGEkubernetes-nginx-78bcc44665   1         1         1       43h
复制代码


点击并拖拽以移动
  • 对应用进行扩容操作,扩容到 4 个实例,再查看所有:

kubectl scale deployments/kubernetes-nginx --replicas=4
复制代码


点击并拖拽以移动


[macro@linux-local root]$ kubectl get deploymentsNAME               READY   UP-TO-DATE   AVAILABLE   AGEkubernetes-nginx   4/4     4            4           43h
复制代码


点击并拖拽以移动
  • 查看所有 Pod,发现已经有 4 个运行在不同的 IP 地址上了;

kubectl get pods -o wide
复制代码


点击并拖拽以移动


NAME                                READY   STATUS    RESTARTS   AGE   IP           NODE       NOMINATED NODE   READINESS GATESkubernetes-nginx-78bcc44665-8fnnn   1/1     Running   2          43h   172.17.0.3   minikube   <none>           <none>kubernetes-nginx-78bcc44665-dvq4t   1/1     Running   0          84s   172.17.0.8   minikube   <none>           <none>kubernetes-nginx-78bcc44665-thzg9   1/1     Running   0          84s   172.17.0.7   minikube   <none>           <none>kubernetes-nginx-78bcc44665-w7xqd   1/1     Running   0          84s   172.17.0.6   minikube   <none>           <none>
复制代码


点击并拖拽以移动
  • 对应用进行缩放操作,缩放到 2 个实例;

kubectl scale deployments/kubernetes-nginx --replicas=2
复制代码


点击并拖拽以移动


NAME                                READY   STATUS    RESTARTS   AGE   IP           NODE       NOMINATED NODE   READINESS GATESkubernetes-nginx-78bcc44665-8fnnn   1/1     Running   2          44h   172.17.0.3   minikube   <none>           <none>kubernetes-nginx-78bcc44665-w7xqd   1/1     Running   0          11m   172.17.0.6   minikube   <none>           <none>
复制代码


点击并拖拽以移动

滚动更新

滚动更新允许通过使用新的实例逐步更新 Pod 实例,零停机进行 Deployment 更新。K8S 不仅可以实现滚动更新,还可以支持回滚操作。

  • 目前运行了 4 个 Nginx 1.10 版本的实例:

[macro@linux-local root]$ kubectl get podsNAME                                READY   STATUS    RESTARTS   AGEkubernetes-nginx-78bcc44665-8fnnn   1/1     Running   2          44hkubernetes-nginx-78bcc44665-jpw2g   1/1     Running   0          5skubernetes-nginx-78bcc44665-w7xqd   1/1     Running   0          59mkubernetes-nginx-78bcc44665-xx8s5   1/1     Running   0          5s
复制代码


点击并拖拽以移动
  • 可以通过 kubectl describe 命令来查看镜像版本号:

[macro@linux-local root]$ kubectl describe pods |grep Image    Image:          nginx:1.10    Image ID:       docker-pullable://nginx@sha256:6202beb06ea61f44179e02ca965e8e13b961d12640101fca213efbfd145d7575
复制代码


点击并拖拽以移动
  • kubectl set image 1.19 1.10 1.19

# 命令格式 kubectl set image Deployment的名称 容器名称=容器镜像:镜像版本号kubectl set image deployments/kubernetes-nginx nginx=nginx:1.19
复制代码


点击并拖拽以移动


# 停止1个旧实例并创建2个新实例NAME                                READY   STATUS              RESTARTS   AGEkubernetes-nginx-66f67cd758-rbcz5   0/1     ContainerCreating   0          11skubernetes-nginx-66f67cd758-s9ck8   0/1     ContainerCreating   0          11skubernetes-nginx-78bcc44665-8fnnn   1/1     Running             2          45hkubernetes-nginx-78bcc44665-jpw2g   0/1     Terminating         0          15mkubernetes-nginx-78bcc44665-w7xqd   1/1     Running             0          75mkubernetes-nginx-78bcc44665-xx8s5   1/1     Running             0          15m# 1个实例已被停止2个新实例仍创建中NAME                                READY   STATUS              RESTARTS   AGEkubernetes-nginx-66f67cd758-rbcz5   0/1     ContainerCreating   0          30skubernetes-nginx-66f67cd758-s9ck8   0/1     ContainerCreating   0          30skubernetes-nginx-78bcc44665-8fnnn   1/1     Running             2          45hkubernetes-nginx-78bcc44665-w7xqd   1/1     Running             0          75mkubernetes-nginx-78bcc44665-xx8s5   1/1     Running             0          15m# 4个新实例均已创建完成NAME                                READY   STATUS    RESTARTS   AGEkubernetes-nginx-66f67cd758-jn926   1/1     Running   0          48skubernetes-nginx-66f67cd758-rbcz5   1/1     Running   0          3m12skubernetes-nginx-66f67cd758-s9ck8   1/1     Running   0          3m12skubernetes-nginx-66f67cd758-smr7n   1/1     Running   0          44s
复制代码


点击并拖拽以移动
  • 此时再使用 kubectl describe 命令来查看镜像版本号,发现 Nginx 已经更新至 1.19 版本:

[macro@linux-local root]$ kubectl describe pods |grep Image    Image:          nginx:1.19    Image ID:       docker-pullable://nginx@sha256:4cf620a5c81390ee209398ecc18e5fb9dd0f5155cd82adcbae532fec94006fb9
复制代码


点击并拖拽以移动
  • 如果想回滚到原来的版本的话,直接使用 kubectl rollout undo 命令即可。

kubectl rollout undo deployments/kubernetes-nginx
复制代码


配置管理

ConfigMap 允许你将配置文件与镜像文件分离,以使容器化的应用程序具有可移植性。接下来我们演示下如何将 ConfigMap 的的属性注入到 Pod 的环境变量中去。

  • nginx-config.yaml nginx-config data

apiVersion: v1kind: ConfigMapmetadata:  name: nginx-config  namespace: defaultdata:  nginx-env: test
复制代码


点击并拖拽以移动
  • 应用 nginx-config.yaml 文件创建 ConfigMap:

kubectl create -f nginx-config.yaml
复制代码


点击并拖拽以移动
  • 获取所有 ConfigMap:

kubectl get configmap
复制代码


点击并拖拽以移动


NAME               DATA   AGEkube-root-ca.crt   1      2d22hnginx-config       1      13s
复制代码


点击并拖拽以移动
  • 通过 yaml 格式查看 ConfigMap 中的内容:

kubectl get configmaps nginx-config -o yaml
复制代码


点击并拖拽以移动


apiVersion: v1data:  nginx-env: testkind: ConfigMapmetadata:  creationTimestamp: "2021-01-08T01:49:44Z"  managedFields:  - apiVersion: v1    fieldsType: FieldsV1    fieldsV1:      f:data:        .: {}        f:nginx-env: {}    manager: kubectl-create    operation: Update    time: "2021-01-08T01:49:44Z"  name: nginx-config  namespace: default  resourceVersion: "61322"  uid: a477567f-2aff-4a04-9a49-f19220baf0d3
复制代码


点击并拖拽以移动
  • 添加配置文件 nginx-deployment.yaml 用于创建 Deployment,部署一个 Nginx 服务,在 Nginx 的环境变量中引用 ConfigMap 中的属性:

apiVersion: apps/v1kind: Deploymentmetadata:  name: nginx-deployment  labels:    app: nginxspec:  replicas: 1  selector:    matchLabels:      app: nginx  template:    metadata:      labels:        app: nginx    spec:      containers:        - name: nginx          image: nginx:1.10          ports:            - containerPort: 80          env:            - name: NGINX_ENV # 在Nginx中设置环境变量              valueFrom:                configMapKeyRef:                  name: nginx-config # 设置ConfigMap的名称                  key: nginx-env # 需要取值的键      
复制代码


点击并拖拽以移动
  • 应用配置文件文件创建 Deployment:

kubectl apply -f nginx-deployment.yaml
复制代码


点击并拖拽以移动
  • 创建成功后查看 Pod 中的环境变量,发现 NGINX_ENV 变量已经被注入了;

kubectl exec deployments/nginx-deployment -- env
复制代码


点击并拖拽以移动


PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/binHOSTNAME=nginx-deployment-66fcf997c-xxdsbNGINX_ENV=test
复制代码


点击并拖拽以移动

存储卷使用

通过存储卷,我们可以把外部数据挂载到容器中去,供容器中的应用访问,这样就算容器崩溃了,数据依然可以存在。

  • 记得之前我们使用 Docker 部署 Nginx 的时候,将 Nginx 的 html、logs、conf 目录从外部挂载到了容器中;

docker run -p 80:80 --name nginx \-v /mydata/nginx/html:/usr/share/nginx/html \-v /mydata/nginx/logs:/var/log/nginx  \-v /mydata/nginx/conf:/etc/nginx \-d nginx:1.10
复制代码


点击并拖拽以移动
  • Minikube 可以认为是一台虚拟机,我们可以用 Minikube 的 ssh 命令来访问它;

minikube ssh
复制代码


点击并拖拽以移动
  • Minikube 中默认有一个 docker 用户,我们先重置下它的密码;

sudo passwd docker
复制代码


点击并拖拽以移动
  • 在 Minikube 中创建 mydata 目录;

midir /home/docker/mydata
复制代码


点击并拖拽以移动
  • 我们需要把 Nginx 的数据目录复制到 Minikube 中去,才能实现目录的挂载,注意 docker 用户只能修改 /home/docker 目录中的文件,我们通过 scp 命令来复制文件;

scp -r /home/macro/mydata/nginx docker@192.168.49.2:/home/docker/mydata/nginx
复制代码


点击并拖拽以移动
  • 添加配置文件 nginx-volume-deployment.yaml 用于创建 Deployment:

apiVersion: apps/v1kind: Deploymentmetadata:  name: nginx-volume-deployment  labels:    app: nginxspec:  replicas: 1  selector:    matchLabels:      app: nginx  template:    metadata:      labels:        app: nginx    spec:      containers:        - name: nginx          image: nginx:1.10          ports:            - containerPort: 80          volumeMounts:            - mountPath: /usr/share/nginx/html              name: html-volume            - mountPath: /var/log/nginx              name: logs-volume            - mountPath: /etc/nginx              name: conf-volume      volumes:        - name: html-volume          hostPath:            path: /home/docker/mydata/nginx/html            type: Directory        - name: logs-volume          hostPath:            path: /home/docker/mydata/nginx/logs            type: Directory        - name: conf-volume          hostPath:            path: /home/docker/mydata/nginx/conf            type: Directory
复制代码


点击并拖拽以移动
  • 应用配置文件创建 Deployment;

kubectl apply -f nginx-volume-deployment.yaml
复制代码


点击并拖拽以移动
  • 添加配置文件 nginx-service.yaml 用于创建 Service;

apiVersion: v1kind: Servicemetadata:  name: nginx-servicespec:  type: NodePort  selector:    app: nginx  ports:    - name: http      protocol: TCP      port: 80      targetPort: 80      nodePort: 30080
复制代码


点击并拖拽以移动
  • 应用配置文件创建 Service;

kubectl apply -f nginx-service.yaml
复制代码


点击并拖拽以移动
  • 查看下 Service 服务访问端口;

[macro@linux-local nginx]$ kubectl get servicesNAME                      TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGEkubernetes                ClusterIP   10.96.0.1       <none>        443/TCP        6d23hkubernetes-nginx          NodePort    10.106.227.54   <none>        80:30158/TCP   5d22hnginx-service             NodePort    10.103.72.111   <none>        80:30080/TCP   7s
复制代码


点击并拖拽以移动
  • 通过 CURL 命令可以访问 Nginx 首页信息。

curl $(minikube ip):30080
复制代码


点击并拖拽以移动

网关路由

Ingress 可以作为 K8S 的网关来使用,能提供服务路由和负载均衡等功能。

  • Minikube 默认没有启用 Ingress 插件,需要手动开启;

minikube addons enable ingress
复制代码


点击并拖拽以移动
  • 开启 Ingress 过程中遇到了一个坑,会在验证的时候卡主,其实是 Minikube 内部无法下载 Ingress 镜像导致的:

[macro@linux-local ~]$ minikube addons enable ingress* Verifying ingress addon...
复制代码


点击并拖拽以移动
  • 解决该问题需要手动下载第三方镜像,并标记为需要的镜像,并重新启用 Ingress 插件;

# 查找启动有问题的Podkubectl get pods -n kube-system# 查看启动失败原因kubectl describe ingress-nginx-controller-xxx -n kube-system# 连接到Minikubeminikube ssh# 原来需要下载的镜像(已经无法下载)docker pull us.gcr.io/k8s-artifacts-prod/ingress-nginx/controller:v0.40.2# 下载第三方替代镜像(直接去DockerHub官网搜索即可)docker pull pollyduan/ingress-nginx-controller:v0.40.2# 修改镜像名称docker tag pollyduan/ingress-nginx-controller:v0.40.2 us.gcr.io/k8s-artifacts-prod/ingress-nginx/controller:v0.40.2 
复制代码


点击并拖拽以移动
  • 重启插件后检查下 Ingress 是否在运行;

kubectl get pods -n kube-system
复制代码


点击并拖拽以移动


NAME                                        READY   STATUS      RESTARTS   AGEingress-nginx-admission-create-krpgk        0/1     Completed   0          46hingress-nginx-admission-patch-wnxlk         0/1     Completed   3          46hingress-nginx-controller-558664778f-wwgws   1/1     Running     2          46h
复制代码


点击并拖拽以移动
  • 添加配置文件 nginx-ingress.yaml 用于创建 Ingress;

apiVersion: networking.k8s.io/v1kind: Ingressmetadata:  name: nginx-ingress  annotations:    nginx.ingress.kubernetes.io/rewrite-target: /$1spec:  rules:    - host: nginx-volume.com      http:        paths:          - path: /            pathType: Prefix            backend:              service:                name: nginx-service                port:                  number: 80
复制代码


点击并拖拽以移动
  • 应用配置文件创建 Ingress;

kubectl apply -f nginx-ingress.yaml
复制代码


点击并拖拽以移动
  • 查看所有 Ingress,此时我们已经可以通过 nginx-volume.com 来访问 Pod 中运行的 Nginx 服务了;

kubectl get ingress
复制代码


点击并拖拽以移动


NAME            CLASS    HOSTS              ADDRESS        PORTS   AGEnginx-ingress   <none>   nginx-volume.com   192.168.49.2   80      6s
复制代码


点击并拖拽以移动
  • 需要修改下 host 文件,注意切换到 root 账号后修改:

# 切换到root用户su -# 修改host文件vi /etc/hosts# 添加如下记录192.168.49.2 nginx-volume.com
复制代码


点击并拖拽以移动
  • 最后通过 CURL 命令可以访问 Nginx 首页信息。

curl nginx-volume.com
复制代码


点击并拖拽以移动

总结

通过 K8S 扩展和管理容器化应用确实十分方便,通过几个命令我们就可以实现零停机更新,出了故障也不怕,一个命令实现回滚。但是大量的命令行操作总显得枯燥无味,要是有个可视化工具可以直接管理 K8S 就更好了。

推荐阅读

程序员年薪百万的飞马计划你听说过吗?

为什么阿里巴巴的程序员成长速度这么快,看完他们的内部资料我懂了

从事开发一年的程序员能拿到多少钱?

字节跳动总结的设计模式 PDF 火了,完整版开放下载

刷Github时发现了一本阿里大神的算法笔记!标星70.5K

程序员50W年薪的知识体系与成长路线。

关于【暴力递归算法】你所不知道的思路

开辟鸿蒙,谁做系统,聊聊华为微内核

 

看完三件事❤️

如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我三个小忙:

点赞,转发,有你们的 『点赞和评论』,才是我创造的动力。

关注公众号 『 Java 斗帝 』,不定期分享原创知识。

同时可以期待后续文章 ing🚀

用户头像

还未添加个人签名 2020.09.07 加入

还未添加个人简介

评论

发布
暂无评论
自从上了K8S,项目更新都不带停机的!