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

标签: k8s 项目 更新 | 发表时间:2021-01-27 00:58 | 作者:MacroZheng
出处:https://juejin.im/backend?sort=monthly_hottest

SpringBoot实战电商项目mall(40k+star)地址: github.com/macrozheng/…

摘要

如果你看了 《Kubernetes太火了!花10分钟玩转它不香么?》一文的话,基本上已经可以玩转K8S了。其实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   AGE
kubernetes-nginx   1/1     1            1           43h
复制代码
  • 获取所有ReplicaSet可使用如下命令:
   kubectl get rs
复制代码
   NAME                          DESIRED   CURRENT   READY   AGE
kubernetes-nginx-78bcc44665   1         1         1       43h
复制代码
  • 对应用进行扩容操作,扩容到4个实例,再查看所有:
   kubectl scale deployments/kubernetes-nginx --replicas=4
复制代码
   [[email protected] root]$ kubectl get deployments
NAME               READY   UP-TO-DATE   AVAILABLE   AGE
kubernetes-nginx   4/4     4            4           43h
复制代码
  • 查看所有Pod,发现已经有4个运行在不同的IP地址上了;
   kubectl get pods -o wide
复制代码
   NAME                                READY   STATUS    RESTARTS   AGE   IP           NODE       NOMINATED NODE   READINESS GATES
kubernetes-nginx-78bcc44665-8fnnn   1/1     Running   2          43h   172.17.0.3   minikube              
kubernetes-nginx-78bcc44665-dvq4t   1/1     Running   0          84s   172.17.0.8   minikube              
kubernetes-nginx-78bcc44665-thzg9   1/1     Running   0          84s   172.17.0.7   minikube              
kubernetes-nginx-78bcc44665-w7xqd   1/1     Running   0          84s   172.17.0.6   minikube              
复制代码
  • 对应用进行缩放操作,缩放到2个实例;
   kubectl scale deployments/kubernetes-nginx --replicas=2
复制代码
   NAME                                READY   STATUS    RESTARTS   AGE   IP           NODE       NOMINATED NODE   READINESS GATES
kubernetes-nginx-78bcc44665-8fnnn   1/1     Running   2          44h   172.17.0.3   minikube              
kubernetes-nginx-78bcc44665-w7xqd   1/1     Running   0          11m   172.17.0.6   minikube              
复制代码

滚动更新

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

  • 目前运行了4个Nginx 1.10版本的实例:
   [[email protected] root]$ kubectl get pods
NAME                                READY   STATUS    RESTARTS   AGE
kubernetes-nginx-78bcc44665-8fnnn   1/1     Running   2          44h
kubernetes-nginx-78bcc44665-jpw2g   1/1     Running   0          5s
kubernetes-nginx-78bcc44665-w7xqd   1/1     Running   0          59m
kubernetes-nginx-78bcc44665-xx8s5   1/1     Running   0          5s
复制代码
  • 可以通过 kubectl describe命令来查看镜像版本号:
   [[email protected] root]$ kubectl describe pods |grep Image
    Image:          nginx:1.10
    Image ID:       docker-pullable://[email protected]:6202beb06ea61f44179e02ca965e8e13b961d12640101fca213efbfd145d7575
复制代码
  • 通过 kubectl set image命令来更新Nginx镜像的版本号为 1.19,此时K8S会执行滚动更新,逐步停止 1.10版本的实例并启动 1.19版本的实例;
   # 命令格式 kubectl set image Deployment的名称 容器名称=容器镜像:镜像版本号
kubectl set image deployments/kubernetes-nginx nginx=nginx:1.19
复制代码
   # 停止1个旧实例并创建2个新实例
NAME                                READY   STATUS              RESTARTS   AGE
kubernetes-nginx-66f67cd758-rbcz5   0/1     ContainerCreating   0          11s
kubernetes-nginx-66f67cd758-s9ck8   0/1     ContainerCreating   0          11s
kubernetes-nginx-78bcc44665-8fnnn   1/1     Running             2          45h
kubernetes-nginx-78bcc44665-jpw2g   0/1     Terminating         0          15m
kubernetes-nginx-78bcc44665-w7xqd   1/1     Running             0          75m
kubernetes-nginx-78bcc44665-xx8s5   1/1     Running             0          15m
# 1个实例已被停止2个新实例仍创建中
NAME                                READY   STATUS              RESTARTS   AGE
kubernetes-nginx-66f67cd758-rbcz5   0/1     ContainerCreating   0          30s
kubernetes-nginx-66f67cd758-s9ck8   0/1     ContainerCreating   0          30s
kubernetes-nginx-78bcc44665-8fnnn   1/1     Running             2          45h
kubernetes-nginx-78bcc44665-w7xqd   1/1     Running             0          75m
kubernetes-nginx-78bcc44665-xx8s5   1/1     Running             0          15m
# 4个新实例均已创建完成
NAME                                READY   STATUS    RESTARTS   AGE
kubernetes-nginx-66f67cd758-jn926   1/1     Running   0          48s
kubernetes-nginx-66f67cd758-rbcz5   1/1     Running   0          3m12s
kubernetes-nginx-66f67cd758-s9ck8   1/1     Running   0          3m12s
kubernetes-nginx-66f67cd758-smr7n   1/1     Running   0          44s
复制代码
  • 此时再使用 kubectl describe命令来查看镜像版本号,发现Nginx已经更新至 1.19版本:
   [[email protected] root]$ kubectl describe pods |grep Image
    Image:          nginx:1.19
    Image ID:       docker-pullable://[email protected]:4cf620a5c81390ee209398ecc18e5fb9dd0f5155cd82adcbae532fec94006fb9
复制代码
  • 如果想回滚到原来的版本的话,直接使用 kubectl rollout undo命令即可。
   kubectl rollout undo deployments/kubernetes-nginx
复制代码

配置管理

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

  • 添加配置文件 nginx-config.yaml用于创建ConfigMap,ConfigMap名称为 nginx-config,配置信息存放在 data节点下:
   apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
  namespace: default
data:
  nginx-env: test
复制代码
  • 应用 nginx-config.yaml文件创建ConfigMap:
   kubectl create -f nginx-config.yaml
复制代码
  • 获取所有ConfigMap:
   kubectl get configmap
复制代码
   NAME               DATA   AGE
kube-root-ca.crt   1      2d22h
nginx-config       1      13s
复制代码
  • 通过 yaml格式查看ConfigMap中的内容:
   kubectl get configmaps nginx-config -o yaml
复制代码
   apiVersion: v1
data:
  nginx-env: test
kind: ConfigMap
metadata:
  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/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  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:/bin
HOSTNAME=nginx-deployment-66fcf997c-xxdsb
NGINX_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 [email protected]:/home/docker/mydata/nginx
复制代码
  • 添加配置文件 nginx-volume-deployment.yaml用于创建Deployment:
   apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-volume-deployment
  labels:
    app: nginx
spec:
  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: v1
kind: Service
metadata:
  name: nginx-service
spec:
  type: NodePort
  selector:
    app: nginx
  ports:
    - name: http
      protocol: TCP
      port: 80
      targetPort: 80
      nodePort: 30080
复制代码
  • 应用配置文件创建Service;
   kubectl apply -f nginx-service.yaml
复制代码
  • 查看下Service服务访问端口;
   [[email protected] nginx]$ kubectl get services
NAME                      TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
kubernetes                ClusterIP   10.96.0.1               443/TCP        6d23h
kubernetes-nginx          NodePort    10.106.227.54           80:30158/TCP   5d22h
nginx-service             NodePort    10.103.72.111           80:30080/TCP   7s
复制代码
  • 通过CURL命令可以访问Nginx首页信息。
   curl $(minikube ip):30080
复制代码

网关路由

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

  • Minikube默认没有启用Ingress插件,需要手动开启;
   minikube addons enable ingress
复制代码
  • 开启Ingress过程中遇到了一个坑,会在验证的时候卡主,其实是Minikube内部无法下载Ingress镜像导致的:
   [[email protected] ~]$ minikube addons enable ingress
* Verifying ingress addon...
复制代码
  • 解决该问题需要手动下载第三方镜像,并标记为需要的镜像,并重新启用Ingress插件;
   # 查找启动有问题的Pod
kubectl get pods -n kube-system
# 查看启动失败原因
kubectl describe ingress-nginx-controller-xxx -n kube-system
# 连接到Minikube
minikube 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   AGE
ingress-nginx-admission-create-krpgk        0/1     Completed   0          46h
ingress-nginx-admission-patch-wnxlk         0/1     Completed   3          46h
ingress-nginx-controller-558664778f-wwgws   1/1     Running     2          46h
复制代码
  • 添加配置文件 nginx-ingress.yaml用于创建Ingress;
   apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: nginx-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
  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   AGE
nginx-ingress      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就更好了。

参考资料

官方文档:https://kubernetes.io/zh/docs/home/

本文 GitHub github.com/macrozheng/… 已经收录,欢迎大家Star!

相关 [k8s 项目 更新] 推荐:

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

- - 掘金后端本月最热
SpringBoot实战电商项目mall(40k+star)地址:. 如果你看了 《Kubernetes太火了. 》一文的话,基本上已经可以玩转K8S了. 其实K8S中还有一些高级特性也很值得学习,比如弹性扩缩应用、滚动更新、配置管理、存储卷、网关路由等. 今天我们就来了解下这些高级特性,希望对大家有所帮助.

更新应用时,如何实现 K8s 零中断滚动更新?

- - DockOne.io
作者 | 子白(阿里云开发工程师)、溪恒(阿里云技术专家). <关注阿里巴巴云原生公众号,回复 排查 即可下载电子书>. 《深入浅出 Kubernetes》一书共汇集 12 篇技术文章,帮助你一次搞懂 6 个核心原理,吃透基础理论,一次学会 6 个典型问题的华丽操作. Kubernetes 集群中,业务通常采用 Deployment + LoadBalancer 类型 Service 的方式对外提供服务,其典型部署架构如图 1 所示.

CentOS7 安装 K8S

- - 企业架构 - ITeye博客
前提:VirtualBox CentOS7. 物理机IP   192.168.18.8. 虚拟机1IP:192.168.18.100(VMaster master). 虚拟机2IP:192.168.18.101(VServer1 node1). 虚拟机3IP:192.168.18.102(VServer2 node2).

k8s docker集群搭建 - CSDN博客

- -
一、Kubernetes系列之介绍篇.     - 一次构建,到处运行. 2.什么是kubernetes.   首先,他是一个全新的基于容器技术的分布式架构领先方案. Kubernetes(k8s)是Google开源的容器集群管理系统(谷歌内部:Borg). 在Docker技术的基础上,为容器化的应用提供部署运行、资源调度、服务发现和动态伸缩等一系列完整功能,提高了大规模容器集群管理的便捷性.

深入掌握K8S Pod - Yabea - 博客园

- -
K8S configmap介绍. Pod是k8s中最小的调度单元,包含了一个“根容器”和其它用户业务容器. 如果你使用过k8s的话,当然会了解pod的基本使用,但是为了更好的应用,你需要深入了解pod的配置、调度、升级和扩缩容等. pod包含一个或多个相对紧密耦合的容器,处于同一个pod中的容器共享同样的存储空间、IP地址和Port端口.

浅谈 k8s ingress controller 选型 - 知乎

- -
大家好,先简单自我介绍下,我叫厉辉,来自腾讯云. 业余时间比较喜欢开源,现在是Apache APISIX PPMC. 今天我来简单给大家介绍下 K8S Ingress 控制器的选型经验,今天我讲的这些内容需要大家对 K8S 有一定的了解,下面是我的分享. 阅读本文需要熟悉以下基本概念:. 集群:是指容器运行所需云资源的集合,包含了若干台云服务器、负载均衡器等云资源.

docker容器部署Spring Boot项目及更新

- - 编程语言 - ITeye博客
Docker这项容器技术已经是十分的火热了,读者要是不了解docker的话可以吧docker先理解为虚拟机. 我们的Springboot最终是要部署在Linux上的,docker作为Linux轻量级的实现. docker也是可以用来部署Springboot应用的. 1.创建Dockerfile . 创建一个文件名为Dockerfile的文件,复制以下内容到文件中.

使用kube-proxy让外部网络访问K8S service的ClusterIP

- - zzm
kubernetes版本大于或者等于1.2时,外部网络(即非K8S集群内的网络)访问cluster IP的办法是:. 修改master的/etc/kubernetes/proxy,把KUBE_PROXY_ARGS=”“改为KUBE_PROXY_ARGS=”–proxy-mode=userspace”.

k8s外网如何访问业务应用之Service 池化pod

- - IT瘾-geek
一、废话:先讲述一个k8s重要概念,我觉得这个概念是整个k8s集群实现微服务的最核心的概念. Service定义了Pod的逻辑集合和访问该集合的策略,是真实服务的抽象. Service提供了一个统一的服务访问入口以及服务代理和发现机制,用户不需要了解后台Pod是如何运行. 只需要将一组跑同一服务的pod池化成一个service,k8s集群会自动给这个service分配整个集群唯一ip和端口号(这个端口号自己在yaml文件中定义),一个service定义了访问pod的方式,就像单个固定的IP地址和与其相对应的DNS名之间的关系.

K8S的SDN容器网络解决方案及其价值

- - SegmentFault 最新的文章
编者按:关于容器网络的解决方案业界已经有较多的讨论,笔者无意继续赘述. K8S及其网络模型体现了鲜明的解耦设计思想,采用SDN技术实现K8S容器网络,并与相应的生态组件形成SDN监管控一体化解决方案,可以更好地提高整个系统的运营水平,更有效地提升企业的核心竞争力. 本文拟抛砖引玉,从K8S的网络实现入手,重点阐述SDN在容器网络中的应用价值.