查看: 247|回复: 0

微服务架构Docker,K8S,KVM,Hypervisor和微服务有什么区别联系吗?

[复制链接]
  • TA的每日心情
    奋斗
    2022-7-25 00:26
  • 签到天数: 1 天

    [LV.1]初来乍到

    5万

    主题

    5万

    帖子

    16万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    167923
    发表于 2024-1-6 18:47:11 | 显示全部楼层 |阅读模式
    7 x/ L' s7 j8 p" i3 m0 q

    DDD的挑战

    + I7 w1 _: l( x; ]# ?* [

    首先,领域驱动设计需要一定的学习成本,而且学习曲线陡峭,在团队中如果不能接受新的设计理念,那么实施起来一定困难重重。

    7 E& {$ q" ?# E, @* Y2 T5 ~

    其次,领域驱动设计需要领域专家持续不断地参与项目,而领域专家多来自客户方,客户方能配合和参与项目团队的设计与讨论的领域专家并不多。最后,领域驱动设计与传统的系统设计思路大不相同,项目团队在适应新的思维方式的同时,还需要考虑许多设计活动,如需要投入时间和精力在沟通与建立统一语言等事情上。

    % C" f3 Q. u9 b' A1 ^

    不过,尽管DDD会面临诸多挑战,仍然建议学习和尝试这一设计方法,领域驱动设计可以使开发人员表达出更加丰富的业务需求,将软件转换为更加富有业务价值的功能,一旦我们采用了DDD的设计并成功应用后,就会习惯并再也离不开它。

    + x0 p0 i( Z$ L

    Docker和K8s

    O: l% g0 [- \& h

    ◎ 虚拟化技术

    8 H" [1 k+ ]/ P, G. ]& O

    ◎ Docker容器化

    3 n3 E6 Z+ F. l- @8 d

    ◎ 学习使用Docker

    & C' W9 ~1 ~$ D3 I: g# q

    ◎ 容器编排

    . f: X' ]5 M3 C4 R

    ◎ 云商的支持

    ! j4 H- c N* M% |. d7 R$ A

    提到微服务,首先想到的是服务小、职责小,如果是一个庞大复杂的系统,我们必然会建立很多的微服务,而且服务都可以水平扩展。在一些大型的互联网企业,服务的数量可能是成百上千的,如何去部署和管理这些服务成了一个难题,一旦发布新的版本,又该如何去更新?所以,Docker容器化、K8s容器编排等技术逐渐登上了舞台。

    ( H" w& D: K7 O5 \0 T) O+ I

    下面介绍微服务架构下部署和维护服务的方式。

    9 z1 v/ \% @0 y P- M D

    虚拟化技术

    6 X2 v* K5 Z2 t8 H/ m8 P" m0 g

    在以往的软件项目中,我们会使用虚拟化的技术来实现服务的部署和发布。虚拟化(Virtualization)是一种资源管理技术,将计算机的各种实体资源,如CPU、网络、内存及硬盘空间等,予以抽象、转换后呈现出来并可供分割、组合为一个或多个计算机配置环境,使用户可以通过比原本的组态更好的方式来应用这些资源。这些资源的新虚拟部分不受现有资源的架设方式、地域或物理组态所限制。一般所指的虚拟化资源包括计算能力和资料存储,虚拟技术按抽象层次可以分为5个层次:硬件抽象层次、指令集架构抽象层次、操作系统抽象层次、库抽象层次、应用抽象层次。

    : z; u& k5 m% W. v2 D, K
    ) }: z. j2 t& M' Z9 Q4 M( x

    抽象程度由硬件到应用逐渐递增,通常我们将计算机硬件虚拟分割成一个或多个虚拟机(Virtual Machine,VM),然后将服务和页面都部署在各个虚拟机上,并提供多用户对大型计算机的同时交互、访问,可以算作硬件抽象层次,通过纵向地扩展虚拟机的配置,或者横向地扩展虚拟机的个数,更加容易增加系统的负载量。

    8 e" M8 X9 @! q5 [6 ~8 f' C" e, _

    但传统的虚拟化技术正在遭受到重大挑战,随着微服务的兴起,在笨重的虚拟机上部署应用无法满足我们的需求。笔者曾有一个微服务项目,这是一个庞大且运营了很多年的产品,要完整地运行一个项目需要上百个不同的服务。一般需要20~30个虚拟机,每次新部署一套产品上线,需要花费大量的人力进行虚拟机配置、网络调试、基础环境搭建。例如,数据库的安装部署、服务配置和部署、系统测试等工作,加上虚拟机的调试和启动速度不够理想,每次完整地部署这套产品,哪怕只是测试环境,都需要两周,如果换一个不熟悉系统的人,完成一次新产品的部署工作几乎不可能。

    $ }' m9 ]$ Y) M/ g6 o
    ( {) _1 O4 X+ D. E: ]: O

    如今网络信息化技术飞速发展,市场对企业响应速度的要求也越来越高,很多时候一旦慢人一步,很可能带来无法挽回的失败。那么,有没有一项技术可以替代虚拟机技术,加快响应速度,让应用更加便捷、快速部署呢?

    + h- Z% Y5 z% F/ Y

    容器化技术诞生了,Docker是当前最流行的一款容器技术,从原理上,Docker并没有采用与虚拟机一样的虚拟化技术,并不会对硬件进行虚拟化。它是直接基于Linux的内核,对文件系统、网络、进程等进行封装和隔离,由硬件虚拟化上升到了操作系统抽象层次的虚拟化技术,所以Docker更加轻量、快速、便捷。

    / g) M8 R/ n$ ~6 H. C6 `* B

    Docker容器化

    3 d- q4 U6 A$ a+ ~/ C0 O# v+ n

    在软件技术与架构飞速发展时,业界逐渐认识到虚拟机技术既浪费资源,又无法满足业务上的需求,因此容器化技术诞生了,并迅速流行起来。什么是容器化?它与传统的虚拟化相比有什么优势呢?

    3 u. {. S6 T o* {2 p u

    Docker的概念

    ; R n5 N, |: r

    Docker是目前最流行的容器化的软件和平台,可以在如macOS、Windows和Linux等环境中运行,借用官网上的一句话,Docker容器化解锁你的开发和运维的潜力。Docker可以将软件打包成标准化单元:容器,用于开发、迁移和部署。Docker通过创建简单的工具和通用打包方法,将容器内的所有应用程序依赖关系捆绑在一起,并使容器化应用程序能够在任何基础架构上一致地运行,为开发人员和运营团队解决依赖性问题,减少了“我的电脑是好的呀”声音出现。

    6 H$ ~$ n& {& w7 e2 ]. X8 E& e9 @. W- M
    & {7 ?1 V8 B4 h0 [

    那么,Docker是如何做到的?由前面章节我们知道,Docker是一款容器技术,是存在着系统抽象层次的虚拟化技术。我们可以把Docker的容器想象成一个集装箱,在项目中拥有多个不同的服务或应用程序,技术栈(如开发语言、框架、数据库等)都不相同,但可以将这些服务或应用程序打包到集装箱中,每个集装箱都用相同的方式运行、存储和运输。例如,在没有使用容器时,要运行或部署一个Java Web的应用程序,首先需要安装JDK,然后安装Web服务器,如Tomcat,接着安装数据库,最后需要将Java程序打包,部署到Tomcat中运行起来,这是相当烦琐且容易出错的过程。

    ! ?7 D. R) C( Z$ |6 k
    * C& {0 X' f% o4 I7 }; V

    在不同环境中,JDK的版本、Tomcat的版本及数据库的配置等都可能导致程序的运行结果出现差异,当问题发生时,我们很难快速定位是环境问题还是程序问题,这也是为什么程序员都喜欢说“我的电脑是好的呀”。毕竟程序运的环境往往比较复杂,需要很多依赖配置,而程序员的本地环境和程序正式的运的环境差异较大。而Docker可以将这些繁琐的步骤自动化,我们将JDK、Tomcat,甚至是数据库都打包在一起运行,无论是什么环境,我们只需将打包的集装箱进行迁移即可,每个环境运行的程序都完全相同,从而屏蔽复杂的操作和环境的差异。

    8 O& }& A; Z8 A3 t& ~- _) v) q

    每个集装箱都提供统一的接口给外部调用者使用,不用的程序都标准化管理起来,并且屏蔽了差异化,为开发和运维提供便利。例如,有的程序需要启动Tomcat,或者启动MySQL,或者启动Nginx,那么作为运维人员,要根据不同的技术或工具编写不同的操作脚本,运行startup,或者运行start,不同的程序指令层出不穷,这在大规模环境部署时非常痛苦,需要反复修改脚本文件,但我们需要的操作都有规律,如启动、停止、重启和日志等,Docker就提供一系列的操作接口,运维人员只需操作集装箱即可,不需要关注集装箱内部的运行细节。

    1 l9 N: q$ t& o3 E: F& ~$ I
    H3 Q$ T1 j6 _% D

    最后,集装箱还有隔离的特性,每个集装箱都相互独立,集装箱内部的运行互不影响。例如,我们可以在一个容器内使用JDK1.8,同时在另一个容器内使用JDK1.7,两个容器相互独立,这也更加契合微服务的思想。

    5 |6 p0 n# u. ^, N

    Docker提供社区版和企业版两个版本,社区版永久免费,并且内核与企业版完全相同,企业版将容器技术扩展到容器平台,提供企业级容器平台,提供安全和治理等企业级更高级的功能实现。社区版目前完全可以运用于生产环境,不过在大规模的场景下还需要一些(如Kubernetes等)容器编排系统来配合使用。

    ! f7 c7 ^/ { E# \

    容器的概念

    1 y" J8 A; }4 A5 p7 J# y1 X7 ?

    在介绍Docker时可以看出,容器是Docker的核心技术,那么什么是容器?容器是一个标准的软件单元,它将代码及其所有依赖关系打包,以便应用程序从一个计算环境快速可靠地运行到另一个计算环境。Docker通过容器镜像(Docker Image)将包含运行应用程序所需的一切:代码、运行时、系统工具、系统库和设置,构建成一个轻量级、可独立执行的软件包,而容器镜像在运行时成为容器,无论基础架构如何,容器化软件都将始终运行在相同的配置环境中,容器将软件与其环境隔离开来,并确保它可以统一工作。容器和虚拟机具有类似的资源隔离和分配优势,但功能不同,因为容器是虚拟化操作系统而不是硬件,并且容器更便携、高效。容器的运行依赖于容器runtime,containerd是一个行业标准的容器runtime,利用了runc,创建时强调简单性、健壮性和便携性。而containerd也是Docker Engine的核心容器运行时。

    ! x) L# R1 }: u+ ?& a: ]2 }' g/ n

    图8.1所示为Docker Engine的结构,Docker Engine主要包括Server、REST API和Client 3个部分。Server是一种长时间运行的程序,称为Docker守护进程;REST API则可以用来与守护进程通信并指示它做什么接口;Client是一个命令行接口(CLI)的客户端,CLI使用Docker REST API通过脚本或直接CLI命令控制Docker守护进程或与之交互,Docker对象包括图像(Image)、容器(Container)、网络(Network)和volumes。在Docker Engine上运行的Docker容器拥有以下3个特性。

    / W* U. u4 l' b; k" E7 A
    / n. g! b2 ]7 N9 i! M# `6 p

    (1)标准:Docker为容器创建了行业标准,因此它们可以随处携带。

    ' }3 u: R$ l; _/ s

    (2)轻量级:容器共享机器的操作系统内核,因此不需要每个应用程序的操作系统,从而提高服务器效率并降低服务器和许可成本。

    + X8 m/ J7 S2 I* W

    (3)安全:应用程序在容器中更安全,Docker提供业界最强大的默认隔离功能。

    1 x( l% j+ Y3 |( Y/ m

    Docker使用客户端-服务器架构。Docker客户端与Docker服务器(守护进程)进行通信,服务器负责构建、运行和分发Docker容器。Docker客户端和服务器可以在同一系统上运行,也可以将Docker客户端连接到远程Docker服务器。Docker客户端和服务器使用REST API,并通过UNIX Socket或网络接口进行通信。同时,Docker还提供了镜像仓库的机制,方便我们将构建好的镜像存储在镜像仓库中,快速地进行传输和部署,如图8.2所示。

    / `7 S& F/ ?2 k( x! C
    6 j) k: r% E7 j# J6 n

    学习使用Docker

    : Q7 L5 O% y3 E2 M

    使用容器可以更快地构建和部署新应用程序,Docker容器将软件及其依赖关系整合到一个标准化的软件开发单元中,包括运行所需的一切:代码、运行时、系统工具和库。这可以保证应用程序始终运行在相同的环境下,并使协作变得像共享容器映像一样简单。

    , R3 n/ w" s* ^" O9 V; c+ A' l' y

    下面为大家介绍Docker具体的使用方法。

    + }& o9 y! N0 t' e! y

    Docker的安装方法

    5 x. F0 `& m8 ~6 S$ H

    Docker的安装十分简单,且对各平台都很友好。在macOS和Windows中都有相应的安装包,可以一键安装。Docker有社区版和企业版两个版本,下面以社区版为例来介绍Docker具体的使用方式。

    / [! H, v2 o/ f" J; `' R. E, x7 c

    首先,需要下载Docker的安装文件,可以在Docker Hub上找到各自平台的安装包 。以 macOS 为 例,双击下载的安装文件 :

    % x0 h2 p* G9 b, F2 H

    Docker.dmg ( Windows 版 本 的 文 件 名 为 Docker for Windows Installer.exe ) , 然 后 在 出 现 的 窗 口 中 将 Docker.app 拖入Applications文件夹即可,如图8.3所示。

    / e8 W7 v) v) g* y
    * C9 p9 }2 w8 I2 V T5 I( N) h3 A9 d

    安装好后可以通过双击Docker.app来启动Docker。默认随系统一起启动,然后在快速访问工具栏中看见Docker的图标,单击Docker的图标可以打开快捷菜单,如图8.4所示。

    + `8 f2 [0 b% J `) P' E) @+ o
    , F% V# z% w1 n t3 D) l9 A3 ^

    图 8.4 中 第一行会显示 Docker 的状态, “Docker Desktopisrunning”表示Docker目前正在运行,打开命令行工具输入如下指令。

    0 m& Z9 S) S' A1 U- k

    docker -v

    + J) ?% d- W5 I' t0 X4 D

    如果安装成功,就会得到如下结果。

    ' s; A* T# g& B+ F! S. `" `7 c5 N

    Docker version 18.09.0, build 4d60db4

    3 F% Y- B1 I$ \

    如果想要查看Docker完整的版本信息,可以输入以下指令。

    9 Y3 }! z2 }+ F5 h& e4 v% O# u9 P

    docker version

    1 v3 H/ b+ t& y3 {- ? A7 q0 j

    可以得到具体的Docker的Client和Server的详细信息,结果如下。

    / @* D ]5 L+ U3 ~7 x1 u/ C9 [
    3 P/ R+ M/ c% k4 j7 K

    详细的安装教程可以在Docker的官网上找到。

    ' U, q, T! w' t8 d$ ^

    构建Docker镜像

    ; B6 d: K6 _6 M: S5 f

    如果说容器是Docker的核心,镜像就是核心的基础,正如之前所提到的,镜像在Docker Engine上运行时成为容器,无论基础架构如何,容器化软件都将始终运行在相同的环境中,容器将软件与其环境隔离开来,并确保它可以统一的工作,镜像是根文件系统更改的有序集合,它通常包含堆叠在彼此顶部的分层文件系统的并集,没有状态,而且永远不会改变。

    + P6 C4 ^- A5 [6 m( w; T1 p

    如何使用Docker镜像?一般在项目中,我们会搭建私有的Docker镜像仓库,或者使用云厂商提供的镜像仓库来存储项目中构建的镜像。当然,Docker也提供了公共的镜像仓库,可以把镜像仓库理解为我们在使用Gradle或Maven时的repository,这里使用Docker默认公网的镜像仓库来体验一下Docker镜像的用法。

    ( {1 k1 \$ A8 b' \* q' y1 u5 c

    Docker官方提供了一个简单的镜像来让我们体验,镜像名为hello-world,打开命令行工具,输入如下指令,从镜像仓库拉取hello-world的镜像。

    " L6 B- z9 E2 v

    docker pull hello-world

    & ^) N+ v( b2 k) H" g6 W

    可以看到如下运行结果。

    9 r6 t! {# k0 |
    * F5 C- Y5 k9 y1 t; ^( r

    通过运行的输出结果可以看出,这里下载了一个新的镜像helloworld:latest,Docker的镜像有tag的概念,tag就好比镜像的版本号,通过指定具体的tag来下载相应版本。例如,我们想要指定下载镜像a的v1.0.0版本,输入“docker pull a:v1.0.0”。这里拉取的hello-world并没有指定具体 的tag,Docker使用默认 的“tag:latest”的镜像进行下载。下载完成后,我们可以通过如下指令查询已经下载的镜像。

    ( R, k7 J A' `' V

    docker images

    9 K* {' D6 `! K7 W q

    显示结果如下。

    * s: A9 d" `2 \6 j
    ; Y, c# |6 j$ \% H5 U j2 O5 E8 {

    下载完成后,我们可以通过docker run来运行镜像,指令如下。

    # U' h1 C# ?& ]

    docker run hello-world

    2 v* ^* f) F" c) v( x7 ~/ [

    如果显示结果如下,说明已经成功运行了一个Docker镜像。

    & w. N J2 [0 U3 F6 S2 ]% y
    " w( t- F: h1 n# I1 w1 a

    当然,镜像也可以删除,指令如下。

    4 {3 P/ @$ ^5 v1 z

    docker rmi hello-world

    ; ?9 s" P/ b7 ^( K/ V3 }2 `: W

    得到结果如下。

    & l+ v; d9 x* M+ u

    Error response from daemon: conflict: unable to remove repository reference "hello-world"(must force)- container f8064c37e60d is using its referenced image fce289c99cb9

    7 p; `; n* Q; t1 E. N) W1 m+ x

    以上代码说明镜像有引用它的容器存在,还不能删除,并且告诉了我们容器的ID,所以可以先删除容器,指令如下。

    ( ]1 F/ V) L: S1 t2 G m/ S7 r( p& i

    docker rm f8064e37e60d

    ) p8 A D7 Y! ^

    成功删除容器后,再执行删除镜像的指令,得到结果如下。

    0 D1 _0 P) y' e- S6 S+ z3 \0 R3 ^
    9 i- S0 ?4 F5 D) K4 m# r/ v! v" C! k8 b3 y

    说明镜像已经成功被删除,那么一个镜像又是如何产生的?

    . O% \6 U; K( ]4 `7 F

    Docker通过从Dockerfile的方式来定义所有命令,在构建镜像时从文本文件(Dockerfile)中读取指令来自动构建镜像Dockerfile遵循特定的格式和指令集,每层都代表一个Dockerfile指令,这些层是堆叠的,每层都是前一层变化的增量,且会按顺序构建给定镜像。下面是一个Dockerfile的例子。

    8 V j/ ?3 J/ W' z; x, w
    2 _8 E, {+ l9 U

    这里解释得比较模糊,下面以一个真实的项目为例来构建并运行一个镜像。例如,一个Spring Boot的工程项目,我们快速创建一个Spring Boot的Web,然后添加一个hello world的接口,代码如下。

    2 z7 J9 c+ b* V" S
    1 v" p! }9 c# {2 t3 m# e

    由上述代码可知,这里提供了一个接口,URL是“/hello”,然后返回“World”的字符串,如果我们使用的是Gradle,编译之后在项目根目录的build/libs文件夹下产生一个jar包,即项目本身的最终产物,包名为

    docker-test-webapp-0.0.1-SNAPSHOT.jar,然后通过Java指令运行这个jar包,指令如下。# B+ a6 j+ z) X 1 i1 q* E5 P2 k

    java -jar build/libs/docker-test-webapp-0.0.1-SNAPSHOT.jar

    - W" G+ P: ]" ` U

    我们可以将指令写在一个Shell文件中,在项目根目录创建名为run.sh的文件,并添加启动指令,这里稍作修改,让指令可以估计指定名称的关键字自动寻找jar包,内容如下。

    2 h! V; _( [( o7 x
    ; _! F1 P6 q; E. _ c+ i

    需要给run.sh配置权限,指令如下。

    & Z) L( d7 ^' u) }* O. t! }" ~

    chmod 755 run.sh

    , t6 Q. h" x- ~ Z g

    接下来就可以编写Dockerfile文件,首先来分析一下,我们的目的很简单,就是要将项目构建成镜像并运行,传统的方式会使用shell脚本来运行编译好的jar包,运行jar包需要在Java环境下执行,也就是jre或jdk;其次需要shell脚本来运行jar包,所以镜像中还应该包含shell脚本和jar包两个文件;最后需要在容器运行时执行shell脚本,接下来在项目的根目录下新建一个名为Dockerfile的文件,并添加如下内容。

    6 F% k- l! W. a# b
    * W3 K. f" D- s5 `/ g$ K* u) h6 M

    指令的意思很明显,首先FROM来构建基础镜像,也就是以openjdk的镜像作为基础镜像,这样就有了jdk的运行环境,然后在COPY,复制我们的jar包和shell脚本到指定的目录,这里是/app目录,最后通过CMD指令,即在容器运行时运行shell脚本run.sh。

    ) _: i. R3 l- |' k* n* N$ v) k

    构建之前还需要运行Gradle的编译指令生成jar包,指令如下。

    7 L( t5 b+ V& w5 i) ]

    -./gradlew clean build

    3 C4 C1 V5 h. C

    下面来试一下,运行如下指令来构建镜像。

    + l$ X1 P7 U2 b1 F0 ^

    docker build -t docker-test-webapp:001 .

    2 v1 _2 N4 S; t) R B' ^

    “.”表示从当前目录读取Dockerfile文件来构建镜像,设置镜像的名称为docker-test webapp,tag是001,如果得到结果如下就说明构建成功了。

    ' e! B+ D' ?- S
    ; Z Z5 O' D7 S9 o; C; B8 g8 \

    通过输出可以清楚地看出这里按照顺序执行了4步操作,与我们定义在Dockerfile中的一致,然后通过之前提过的docker image指令来查看本地镜像,结果如下。

    # _& p4 B* _. Z& {- k% r$ k
    8 j( j5 U4 q, W

    可以看到,在本地的镜像仓库中,已经存在了一个名为dockertest-webapp且tag为001的镜像,当然,在构建镜像之前不要忘记执行“./gradlew clean build”来构建好jar包,不然在构建镜像时会报错“找不到文件”。

    9 h g+ M; ^* D; I! ^

    这里只是列举了一些常用的指令来帮助大家理解Docker镜像的用法,详细的Dockerfile的指令还有很多。例如,通过ENV来设置环境变量,通过EXPOSE来设置容器在运行时侦听指定的网络端口,通过ADD指令复制文件、目录或远程文件,并将它们添加到镜像的文件系统中。此外,还有ENTRYPOINT、VOLUME和USER等指令,具体用法由于篇幅关系不再列举,可以在Docker的官网上找到详细的介绍。

    3 s9 u# m3 s+ u5 ^+ @: x+ l

    本文给大家讲解的内容是DDD的挑战;

    下篇文章给大家讲解的是运行Docker容器觉得文章不错的朋友可以转发此文关注小编;感谢大家的支持!, E6 m+ p0 H" Q8 c* |3 D% ~) U7 { 8 b( a# g% H! l9 K; d: X * N8 n4 ~' y# o" O. T5 O! a
    回复

    使用道具 举报

    懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    客服QQ/微信
    921439866 周一至周日:09:00 - 21:00
    致力打造互联网创业第一品牌,学习网上创业赚钱,首选泓嘉网络创业,值得信赖! 泓嘉网络科技 版权所有!

    本站内容均转载于互联网,并不代表泓嘉网立场! 拒绝任何人以任何形式在本站发表与中华人民共和国法律相抵触的言论!。

    信息产业部备案号 豫ICP备2022016396号-1

    QQ|免责声明|广告服务|小黑屋|泓嘉网创 ( 豫ICP备2022016396号-1 )|网站地图

    GMT+8, 2026-4-17 10:47 , Processed in 2.283952 second(s), 25 queries .

    快速回复 返回顶部 返回列表