一、Docker
1.1 Docker简介
Docker是一个用于构建运行传送应用程序的平台,即把一个个运用程序打包成集装箱并传输到任何需要的地方。
有了Docker,就可以把运用程序与它运行时需要的各种依赖包和第三方软件库、应用程序与环境变量、配置文件和启动命令打包在一起,以便在任何环境种都可以正确的运行。
例如,我们开发一个现在流行的前后端分离的项目,你需要在本地安装nodejs环境、npm依赖、java运行环境、安装各种第三方依赖、安装mysql数据库、配置环境变量和启动脚本,若是项目再大一些还需要安装Redis缓存,安装配置,并启动这些服务运行。而且若要部署到测试环境和生产环境,这些操作还需要再做一次,十分耗时耗力。有了Docker,可以将这些组件打包成一个个集装箱,只要在开发环境运行成功了,在其他环境中就可以运行成功。
1.2 Docker与传统虚拟机的区别
虚拟机将一个物理服务器虚拟成多个逻辑服务器,每个逻辑服务器都有自己的操作系统、CPU、内存、硬盘和网络接口等,它们之间完全隔离,可以独立运行。缺点是每台虚拟机就需要占用资源,而实际情况下,每台逻辑服务器只需要一个主要对外提供服务的应用程序就可以,并不需要一个操作系统所提供的所用功能。
注意:
Docker和容器不是一个东西,Docker是容器的一种实现,是一种容器化的解决方案和平台,而容器是一种虚拟化技术,和虚拟机类似,也是一个独立的环境,可以在这个环境中运行运用程序。和虚拟机不同的是,它不需要在容器中运行一个完整的操作系统,而是使用宿主机的操作系统,启动速度非常快。同时,因为需要的资源更少,所以可以在一台物理服务器上运行更多的容器,这样就可以更加充分地利用服务器的资源,减少资源地闲置和浪费。
1.3 Docker的基本原理和概念
1.3.1 镜像、容器、仓库、逻辑卷
镜像是一个只读的模板,它可以用来创建容器。
容器是Docker的运行实例,它提供了一个独立的、可移植的环境,可以在这个环境中运行运用程序。
镜像和容器的关系就是java中的类和实例的关系,可以创建一个或多个镜像的容器。
仓库是用来集中存储和管理Docker镜像的地方,最流行和最常用的仓库是Dockerhub,可以将自己的镜像上传至仓库,也可以从仓库中下载镜像。
逻辑卷用来将容器运行时的数据存储到磁盘上(持久化)。
1.3.2 docker daemon
docker daemon是docker 服务端的进程,用来处理客户端发来的各种请求。
1.4 容器化
容器化就是将运用程序打包成容器,然后在容器中运行运用程序的过程。这个过程简单来说可以分成三个步骤,
(1)创建一个Dockerfile(一个文本文件,包含了构建应用程序执行的所有命令):告诉Docker构建应用程序镜像所需要的步骤和配置;
一般情况下会在项目的根目录下创建一个Dockerfile文件,Docker会根据这个文件构建一个镜像,我们就可以使用这个镜像来创建容器,然后在容器中运行运用程序。
镜像是按照层次结构来构建的,每一层都是基于上一层的。所以需要构建一个基础镜像,然后在这个镜像的基础上添加我们的应用程序。“FROM node:18-alpine”使用node的镜像,这个镜像基于alpine(linux一个版本)构建的,18是镜像的版本。
(2)使用Dockerfile来构建镜像;
(3)使用镜像创建和运行容器。
1.5 实战
1.5.1 编写运用程序
通常我们执行这个运用程序需要安装操作系统、安装nodejs环境及复制应用程序、依赖包及配置文件。而有了docker后可以将这些步骤写在dockerfile中,让docker来执行这些步骤。
1.5.2 编写Dockerfile文件
1.5.3 构建镜像(hello-docker为镜像名)
1.5.4 用docker images命令查看生成的镜像
1.5.5 运行镜像
1.5.6 传输镜像
若想在其它环境中运行该运用程序,只需要把镜像文件复制(或者通过仓库上传下载)过去,在执行docker run命令即可。
1.6 docker compose
docker compose的作用是管理多个容器之间的关系。上图中的5个应用程序封装成docker容器,可以使用docker compose来连接它们是指成为一个完整的项目。
二、Kubernetes(发音:枯ber内踢丝)
Kubernetes的主要功能
容器编排:Kubernetes可以自动管理容器的部署、扩展和收缩,以满足应用程序的需求。它可以根据容器的资源需求和拓扑结构自动创建和管理容器集群。
服务发现和负载均衡:Kubernetes提供了服务发现和负载均衡功能,可以将多个容器组合成一个服务,并通过内置的负载均衡器将请求分发到容器。
自动部署和回滚:Kubernetes可以自动部署容器镜像,并在出现问题时进行回滚。它支持滚动更新,可以逐步更新容器,以减少停机时间。
资源管理:Kubernetes可以自动管理容器所需的资源,例如CPU和内存。它可以根据容器的需求动态分配资源,以确保容器具有足够的资源来运行。
自动扩展和收缩:Kubernetes可以根据应用程序的负载自动扩展和收缩容器集群。它可以自动创建新的容器实例以处理增加的负载,并在负载下降时自动删除容器实例以节省资源。
自我修复:Kubernetes具有自我修复功能,可以自动检测和修复容器集群中的问题,例如容器故障或资源不足。
存储管理:Kubernetes可以自动管理存储,例如基于容器的存储卷和有状态应用程序的数据存储。
安全:Kubernetes提供了一系列安全功能,例如访问控制、加密和身份验证,以保护容器化应用程序的安全性。
日志和监控:Kubernetes提供了内置的日志和监控功能,可以收集和分析容器的日志,并提供应用程序的监控指标。
插件化:Kubernetes是一个可扩展的平台,支持通过插件扩展功能。开发人员可以编写自己的Kubernetes插件来满足特定的需求。
2.1 kubernetes简介
当容器数据数量成百上千甚至数以万计时,使用脚本来管理容器就会十分困难。Kubernetes可以帮助管理容器化的应用程序和服务。它提供了容器编排的功能,可以通过一些配置文件(YAML)来定义应用程序的部署方式,让容器的创建、维护和管理变得更加简单和高效。
高可用是指程序可以在长时间内持续正常地运行,并不会因为某一个组件或者服务的故障而导致整个系统不可用这样的情况;
还提供了很多高可用的特性,比如自动重启、自动重建、自我修复等,可以帮助提高集群的可用性。
可扩展性是指系统可以根据负载的变化来动态地扩展或者缩减系统的资源,从而提高系统的性能和资源的利用率。比如双十一期间,各大电商平台和互联网企业的访问量都会暴增,比较好的一个解决方案就是根据负载的变化来动态地扩展或者缩减系统的资源,比如缩减一些不太重要的服务或者测试环境,然后再增加一些关键的服务资源,这样就可以保证系统平稳地度过流量高峰时段,提高用户的体验。
2.2 Kubernetes的组件
到目前为止,kubernetes中的核心对象已经不下几十种了,但大多数时间我们其实只要使用其中几个最为核心的资源对象即可。下面一个例子通过架构升级和组件演进的过程来一步步引入kubernetes中的各种资源对象。
首先从一个最简单的节点Node开始,一个Node是指一台服务器或者虚拟机,在这个节点上可以运行一个或多个pod(pod是kubernetes的最小调度单元,是一个或者多个应用容器的组合,它创建了容器的运行环境,在这个环境中容器可以共享一些资源,比如网络、存储以及一些运行时的配置等)。假设我们的系统包括一个应用程序和一个数据库,就可以将应用程序和数据库分别放到两个不同的pod中,一般情况下,建议一个pod中只运行一个容器(可以更好地实现应用程序的解耦和扩展)。每一个pod会被分配一个ip地址(在pod创建时自动分配),ip地址是在集群内部的ip地址(在集群外部无法访问),pod之间可以通过这个ip地址来进行通信。pod不是一个稳定的实体,非常容易被创建和销毁,一个pod出现故障时,kubernetes会自动销毁这个pod,并创建一个新的pod来替换它,这个时候pod的ip地址会发生变化,再使用原来的ip地址进行访问就会出现问题,这样产生的问题由名为service的资源对象(简称SVC)来解决。
service可以将一组pod封装成一个服务,这个服务可以通过一个统一的入口来访问。例如可以将应用程序和数据库的pod分别封装成两个service,这样应用程序就可以通过service的ip地址来访问数据库,这样当pod发生故障,即使它的ip地址发生了变化,但是service的ip地址是不会发生变化的,service会自动将请求转发到其它健康的pod上,这样就解决了pod的ip地址不稳定的问题。
服务也分为内部服务和外部服务。内部服务是不想暴露给外部或者没有必要暴露给外部的服务,比如MySQL数据库、缓存、消息队列等,这些服务只需要在集群内部访问就可以了。相对应的,有一些服务比如后端api接口和一些给前端用户使用的前端界面等,这种类型的服务为外部服务。外部服务有几种常见的类型,其中一种类型就是NodePort,它会在节点上开放一个端口,然后将这个端口映射到service的ip地址和端口上,这样就可以通过节点的ip地址来访问service。开发和测试环境中使用NodePort没有问题,但是生产环境中是使用域名来访问服务的,这时需要用到另一个资源对象Ingress。
Ingress是用来管理从集群外部访问集群内部服务的入口和方式的,可以通过Ingress来配置不同的转发规则,从而根据不同的规则来访问集群内部不同的service,以及service对应的后端pod。还可以通过Ingress来配置域名,这样可以将原本使用ip地址和端口号的方式转换成使用域名的方式来访问service了,另外ingress也可以配置一些其它的功能,比如负载均衡、SSL证书等等。
Kubernetes提供一个名为ConfigMap的组件,它可以将一些配置信息(如应用程序访问数据库的ip地址、用户名和密码)封装其它,然后就可以在应用程序中读取和使用了,将配置信息和应用程序的镜像内容分离开来,这样就可以保证容器化应用程序的可移植性。当数据库的端口或者登录信息发生变化时,也只需要修改ConfigMap对象中的配置信息,然后重新加载pod,不需要重新编译和运行应用程序,这样就实现了应用程序和数据库的解耦。ConfigMap中的配置信息是明文的,存储一些敏感信息具有风险。为了解决这个问题,使用secret组件,它可以一些敏感信息封装起来,然后就可以在应用程序中读取和使用了,这些敏感信息不是明文存储的,但是也只是做了一层base64编码而已,kubernetes还需要结合一些其他的安全机制比如网络安全、访问控制和身份认证等等。
Volumns组件可以将一些持久化存储的资源挂载到集群的本地磁盘上,或者挂载到集群外部的远程存储上,这样容器被销毁或存储,容器中的数据也不会消失。
kubernetes采用多节点的方式,即将所有东西复制一份放到其它节点中,这样当一个节点出现问题时,service自动将请求转发到另一个节点上来继续提供服务。deploy组件即完成这个任务,它可以管理应用程序的副本数量和简化应用程序的部署和更新操作,并且还具有副本控制、滚动更新(定义和管理应用程序的更新策略)。
StatefulSet(简称sts)用来解决多个数据库程序间的数据一致性问题,与deploy类似(deploy用来部署无状态应用程序,StatefulSet用来部署有状态应用程序),也提供了定义和管理应用程序副本数量和动态扩缩容等等功能。
2.3 kubernetes架构
kubernetes是典型的master-worker架构。
每一个Worker Node上会包含三个组件,分别为kubelet、kube-proxy和container-runtime。
container-runtime(容器运行时)可理解为一个运行容器的软件,负责拉去容器镜像、创建容器、启动或者停止容器等。所有的应用程序都需要使用容器运行时来运行。所以每个工作节点上都必须要安装容器运行时。容器运行时包括docker的docker-engine,初次之外,可以使用其它喜欢的容器运行时,如contained、CRI-0、Mirantis Container Run。
kubelet负责管理和维护每一个节点上的pod,并确保它们按照预期运行。
kube-proxy负责为Pod对象提供网络代理和负载均衡服务,通常情况下Node集群包括多个节点,这些节点之间通过service来进行通信,这就需要负载均衡器来接收请求,并将请求发送到不同的节点上来完成负债均衡的问题,kube-proxy就完成这个功能,它在每个node上启动一个网络代理,使发往service的流量以一种高效的方式路由到正确的后端pod中。
Master Node上的组件与Worker Node完全不同,包括API server、Scheduler调度器、Controller Manager和etcd。
2.4 minikube搭建环境
minikube是一个轻量级的kubernetes实现,可在本地计算机上创建虚拟机,并部署仅包含一个节点的简单集群。