微服务架构下的开发部署

本文涉及的产品
注册配置 MSE Nacos/ZooKeeper,118元/月
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
云原生网关 MSE Higress,422元/月
简介: 微服务架构是近两年兴起的概念。在此之前,互联网企业在生产环境的分布式系统中处理实际问题时就已经实际使用了微服务架构。例如最初的淘宝系统也是单体式应用,为了应对随着用户量增大而带来的系统处理能力不足的问题,淘宝对其应用系统进行了一系列服务化拆分和改造,淘宝开源的Dubbo框架以及其企业内部用的HSF框架都属于微服务架构的实现成果。

微服务架构是近两年兴起的概念。在此之前,互联网企业在生产环境的分布式系统中处理实际问题时就已经实际使用了微服务架构。例如最初的淘宝系统也是单体式应用,为了应对随着用户量增大而带来的系统处理能力不足的问题,淘宝对其应用系统进行了一系列服务化拆分和改造,淘宝开源的Dubbo框架以及其企业内部用的HSF框架都属于微服务架构的实现成果。

本文将从以下几个方面简要说明微服务架构项目的实践经验:架构选型、开发测试环境下的相关工具支持、人员分工及开发部署流程、相关设计及注意事项。最后,将根据实践经验讨论提高微服架构下的开发和运维效率的切实需求,进一步理清本项目所实现的容器服务管理平台的完善性需求。

项目背景及微服务架构选型

本项目是一个企业级的容器服务管理平台,该平台的功能是基于容器实现的应用运行环境管理,以及应用开发阶段的持续集成和持续发布。简单的理解该平台的核心功能之一就是管理复杂应用的开发和运维环境,提高微服务架构下的开发和运维效率。项目的开发背景如下:

首先,该系统具有典型分布式应用系统特征:

该平台所运行的服务器配置不高,例如华为RH1288这类低配置服务器,允许硬件失败;

系统平台要求可根据实际用户数的规模进行伸缩部署,保证硬件资源的合理利用;

由于系统平台之上需要运行若干企业应用的开发和运行环境,可靠性是非常重要的,不允许单点失效。

其次,本系统功能复杂,从架构的角度需要将系统分成多个层次和若干个子系统。不同的层次、子系统根据具体情况需要采用不同的开发语言,由不同的开发小组完成。

第三,项目组成员由几个城市的异地团队协同开发,统一的开发环境和协同工具是必不可少的。

针对上述项目背景的考虑,本项目选择基于微服务架构进行项目开发。

开发、测试、部署使用到的工具集

“工欲善其事、必先利其器”,借助适合的流程和相关工具集,才能提高微服务架构下的应用开发效率。本项目利用DevOPs流程并选用一套相关工具集实现应用开发管理,提高开发、测试、部署的效率。

代码库:本项目使用分布式代码库Gitlab,它的功能不限于代码仓库,还包括reviews(代码审查), issue tracking(问题跟踪)、wiki等功能,是代码管理和异地团队沟通、协作工具的首选。

Docker镜像仓库、Docker:本项目用容器贯穿整个软件开发流程,以容器作为应用发布的载体,应用的开发环境和测试发版环境都运行在Docker容器中。对于复杂的开发和运维环境管理Docker具有先天的优势,目前国内外的互联网公司有大多数都已经将Docker应用到了他们的开发或者生产环境中了。

K8s:本项目采用Kubernates作为容器调度管理的基础环境,开发环境、测试环境的Docker容器都由K8s负责调度管理。

Jenkins:快速的部署发布离不开老牌持续集成明星Jenkins,本项目通过Jenkins任务构建代码、将应用打包成Docker镜像,最终发布到K8s环境中将容器运行起来。

Shell脚本:编写Shell脚本将项目打分支、发布应用等开发阶段的配置管理工作自动化,降低运维门槛、提高配置管理和运维的效率。

WIKI:Gitlib上的WIKI功能相对简陋,因此项目组选择dokuwiki作为异地团队协作和沟通的工具,团队成员可以将设计文档、知识分享文档、公告信息等信息可以更新到wiki上,便与协同开发。

禅道:为了便于开发计划、开发任务和bug关联起来,本项目使用禅道进行开发任务和bug管理。

人员分工及开发流程

微服务架构应用的开发、部署的复杂度都是远大于单体式应用的,靠运维人员手工的配置管理显然是难于应付了。DevOps主张以自动化任务处理方式实现软件交付及基础设施更新,可以说是微服务架构应用开发和运维的必要条件,本项目采用DevOps的理念的开发流程进行开发。实现部署和运维的自动化需要工具,同时DevOps强调软件开发者与其他IT员工及管理层间的协作与沟通,因此明确的人员分工和开发流程是与工具同样重要的因素。通俗的说,就是有了工具,大家要知道怎么使用工具,并且愿意使用工具才能真正达到提高研发效率的目的。

项目组的主要工作成员无非也是做开发、测试和系统管理三类工作,这里只说明与传统的企业应用开发过程中三类人员所做的工作略有不同的工作内容。

开发人员:

a) 开发者做开发设计,需要将涉及到接口部分设计更新到wiki上,供调用者评审和调用。

b) 开发者除了编写程序逻辑外,还需要注意编写单元测试用例,因为分布式应用联调相对复杂,先做在编写单服务时做好了测试再联调能够提高开发效率。

c) 由于本项目是采用Docker容器作为发布载体的,开发者可能需要修改DockerFile模板里的部分参数,便于部署阶段能将编译后的代码打包到镜像中。相对于传统的开发方式,这是对开发者额外的要求。让所有开发者懂Dockerfile似乎要求也有点高,其实每个子项目中的DockerFile及脚本一般是在搭建项目框架时,主要系统配置管理员编写的好的模板,若开发人员不懂相关技术,也可以跟配置管理员沟通需求,由配置管理员修改相关文件。

测试人员:测试人员的工作没有什么特别,只是需要注意除了每个Sprint阶段的测试外,还需要配合开发人员持续集成的测试;

系统配置管理人员:一般DevOps的开发方式是依赖于云基础平台以及自动化发布工具的,因此相对于传统开发方式,对系统配置管理者的技术要求会比较低。但是,我们的项目开发目的就是构建一个能支撑DevOps流程的平台,其开发本身还不具备相应的平台基础。因此,我们项目最初的系统配置管理工作是由架构师来做的,主要需要做如下这些事:

a) 部署运行项目组开发需要用到公共的服务组件、例如zookeeper注册中心、Docker Registry镜像仓库、数据库等;

b) 为子项目编写在git上打分支的脚本,便于测试发版的时候打分支;

c) 编写各类型应用发布部署成镜像的Dockerfile;

d) 制作或者在网上找到现成的开发所需环境的Docker镜像,并且Push到项目开发使用的私有镜像库中;

e) 编写Shell脚本实现将子项目打包成Docker镜像,并且Push到镜像仓库中。

f) 在Jenkins上配置自动编译或者部署任务,实现持续集成和部署。

本文将对项目的开发、部署联调以及测试发版流程和规范做简要说明,并提供项目各个阶段使用到的部分自动化脚本工具示例。

image

代码分支管理:
image
image

如图所示,在git上创建的每一个项目都需要至少建立develop和master两个分支。开发人员只有权限把代码提交到develop分支上,平时的持续集成和联调都从develop分支上获取代码。 每个Sprint阶段测试发版时,配置管理员从develop分支上创建一个用于测试的release分支。当测试修改bug时,开发人员只把修改后的代码提交到对应的测试Release分支上。当测试版本稳定后,由配置管理员将代码合并到Master分支中。

自动部署和发布:

项目借助于Shell脚本、Dockerfile、K8s配置文件和Jenkins任务实现了自动化的持续集成和部署。配置管理员在项目目录下编写的脚本文件结构如图2所示。

a) 创建分支的shell脚本,示例见附件1;

#!/bin/bash
if [ -z "$1" ]; then
 cat <
         EOF  exit 1  fi DEPLOY_VERSION=$1 RP_FILES=(subproject1/kube-rc.yaml subproject1/pom.xml subproject1/Makefile) if [ -z $(git branch -a | grep -e /${DEPLOY_VERSION}$) ]; then   git branch ${DEPLOY_VERSION}  git checkout ${DEPLOY_VERSION}  else  git checkout ${DEPLOY_VERSION}  git pull  fi  #替换k8s配置文件中环境指向,从开发切换到测试  #替换掉pom.xml文件中的SNAPSHOT为release版本号  #替换掉makefile中发布的镜像Tag的latest为release版本号  for f in ${RP_FILES[@]}; do  sed -i -e "s#api.devproject.com#api.testproject.com#g" \  -e "s#           0.0.1-SNAPSHOT     #           ${DEPLOY_VERSION}-SNAPSHOT     #g" \  -e "s#latest#${DEPLOY_VERSION}#g" $f  done git commit -a -m "Create Branch ${DEPLOY_VERSION}"  git push origin ${DEPLOY_VERSION} 

b) Dockerfile示例文件,将Java dubbo服务发布为镜像为例,示例见附件2:

FROM registry.xcompany.com/java:openjdk-7-jre
MAINTAINER zhangsan
ENV spring.profiles.active="production"
 ENV JAVA_OPTS="-Xmx1024m"
RUN mkdir -p /app 
 COPY target/subproject1.war /app/
 COPY ./startup.sh /app/
 RUN chmod +x /app/startup.sh
 WORKDIR /app
 CMD ["./startup.sh"]
EXPOSE 8080

c) Makefile文件: 包括编译项目、将项目打包成Docker镜像、将镜像Push到镜像仓库、在K8s上创建ReplicationController、在K8s上创建service的命令脚本:

IMAGE_PREFIX = registry.xcompany.com/project1/
COMPONENT = subproject1
ifndef BUILD_TAG
 BUILD_TAG = latest
endif
IMAGE = $(IMAGE_PREFIX)$(COMPONENT):$(BUILD_TAG)
ifndef KUBE_OPS
 KUBE_OPS = --server=https://api.devproject.com --namespace=project1
endif
clean:
 mvn clean
compile: clean
 mvn -U -DskipTests=true -Dmaven.javadoc.skip=true package
#将当前程序打包成Docker镜像
 build: 
 docker build -t $(IMAGE) .
 #将当前镜像Push到镜像仓库
 push: 
 docker push $(IMAGE)
run: 
 docker run --rm -it -e spring.profiles.active=application -p 8080:8080 $(IMAGE)
 #部署RelicationController
 deploy:
 kubectl create -f kube-rc.yaml $(KUBE_OPS)
redeploy:
 kubectl replace -f kube-rc.yaml $(KUBE_OPS)
undeploy:
 kubectl delete -f kube-rc.yaml $(KUBE_OPS)
 #创建service
 deploy-svc:
 kubectl create -f kube-svc.yaml $(KUBE_OPS)
undeploy-svc:
 kubectl delete -f kube-svc.yaml $(KUBE_OPS)

d) K8s部署配置文件,创建ReplicationController、创建service示例见附件4:

#创建ReplicationController
apiVersion: v1
kind: ReplicationController
metadata:
  name: subproject1
spec:
  replicas: 1
  selector:
    name: subproject1
  template:
    metadata:
      labels:
        name: subproject1
    spec:
      containers:
        - name: subproject1
          image: registry.xcompany.com/project1/subproject1:latest
          imagePullPolicy: Always
          env:
            - name: DUBBO_REGISTRY_ADDRESS
              value: "kube://zookeeper:2181"
            - name: DUBBO_REGISTRY_REGISTER
              value: "true"
          ports:
            - containerPort: 8888
#创建Service
apiVersion: v1
kind: Service
metadata: 
  name: subproject1
  labels:
    component: subproject1
spec: 
  ports:
    - port: 8888
      nodePort: 16888
  selector: 
    name: svc-subproject1
  type: NodePor

e) 配置管理员在Jenkins上配置自动或手动触发的任务,在jenkins任务中配置shell脚本,可实现应用的一键部署,示例见附件5。

#!/bin/bash -e
IMAGE=registry.xcompay.com/project1/sub-project1:$IMAGE_VERSION
make compile
if [ $build = "true" ]; then
   echo "docker build -t $IMAGE"
   docker build -t $IMAGE .
   echo "docker push $IMAGE"
   docker push $IMAGE
fi
if [ $undeploy = "true" ]; then
make undeploy
fi
if [ $deploy = "true" ]; then
make deploy
fi
if [ $deploysvc = "true" ]; then
make deploy-svc
fi

具体的过程说如下:

  1. 从Git上拉取代码,编译、发布项目;
  2. 将编译好的程序包,打包成Docker镜像;
  3. 将打包好的Docker镜像Push到镜像仓库;
  4. Jenkins执行Shell脚本命令,从镜像仓库拉取镜像在K8s环境中创建pod和RC,将应用程序及其运行环境所在的容器在K8s平台上运行起来。

测试与发版:

从图中可以看到,项目的开发环境和测试环境是相互隔离的两套环境。

a) 部署在开发环境的应用代码,来自develop分支,对应的Docker镜像Tag用latest,供开发人员调试、以及测试人员随时协助做集成测试;

b) 部署在测是环境的应用代码,来自每到一个Sprint阶段发版测试时配置管理员从develop分支中打出的测试发版分支,分支名对应的版本号不同,相应的Docker镜像的tag也会随是版本号改变。测试环境中部署的应用主要用于测试验证。

部署联调:

项目分为四层:前端UI、WEB层有若干个web应用、Service层包括若干个分布式服务、基础底层。这里简要说明一下各层之间的调试方式:

a) 前端和Web层联调:前端开发人员本地启动一个Nginx,配置nginx.conf文件将localhost代理指向web server的地址,即可在本地调试与动态Web端的交互。

b) WEB层与服务层联调、服务层之间联调、服务层与基础层联调,分为两种方式:

本地调试:部署一个专用的zookeeper注册中心,开发者可以把本机地址注册到注册中心,供相关人员临时调用服务调试。

集成环境调试:提交代码触发Jenkins任务,将服务打包成容器镜像,部署到K8s上在完整的系统运行环境中联合调试。具体的集成环境编排依赖于k8s完成。

微服务的分层和服务交互设计

关于微服架构的利弊以及设计原则有很多著名的文章有介绍,例如MarinFowler的博文《Microservices:a definition of this new architectural term》和来自DZone community社区的《Microservices in Practice: From Architecture to Deployment》在InfoQ等技术网站都有中文翻译,本文就不对概念和设计原则做过多赘述。本小节主要是说明关于项目的逻辑分层结构和服务交互方面的设计。

本项目遵守以下微服务架构的主要基本原则,但是也会根据具体项目情况有所保留。

  1. 单一责任原则(Single Responsibility Principle,SRP)
  2. 保证微服务设计能支持服务的敏捷/独立地开发和部署。

image

架构分层设计

如图2所示,项目的架构是分为四层:静态UI层、动态WEB层、业务服务层、基础业务层。

  1. 静态UI层,直接面向用户的操作展示界面,包括静态UI设计和JS交互代码,主要采用Angulars框架;

ii.动态WEB层是各业务服务的“门面”,根据前端设计的需要调用、组装业务服务层的API,相对来说,这一层变动的频率较高,例如系统需要进行流程优化或者前端UE改造,相应的都要变更这一层。动态WEB层采用Java Spring或者python Django框架实现;

iii.业务服务层,根据业务需求按照功能对基础服务层进行扩展和包装,采用Dubbo分布式服务框架实现,具体版本是当当扩展过的Dubbox,支持REST API,并且对Spring的支持升级到了3.x;

  1. 基础服务层比较稳定,提供一些基础功能,采用Go语言/Ruby/Java/Python等多种语言实现的。

各层之间的交互通信设计

  1. 各层次之间以及同一层次之间的交互主要是按照微服务架构的设计原则,采用轻量式通信机制:REST API、Dubbo API(hessian协议)和异步消息实现的。

ii.但是也有些服务之间的交互是通过共享数据库实现的,这一点是违背微服务架构强调的“独立的服务、独立的数据库”的原则的。本项目每个服务尽可能使用独立的数据表,但是采用了共享的数据库。根据具体业务场景,综合考虑技术成本、以及耦合带来的风险大小等因素,部分不同层次的服务之间的交互是通过数据表实现的。这也是从单体式应用进化到分布式应用的一个折中方案,将来若系统规模扩大,要拆分数据库代价并不会很大。但是不可否认,微服务架构下使用共享的数据库是存在风险的,将来可能因为某些蹩脚的设计使得微服务之间的耦合性变大,导致微服务不再“微”了。

相关实践学习
通过容器镜像仓库与容器服务快速部署spring-hello应用
本教程主要讲述如何将本地Java代码程序上传并在云端以容器化的构建、传输和运行。
Kubernetes极速入门
Kubernetes(K8S)是Google在2014年发布的一个开源项目,用于自动化容器化应用程序的部署、扩展和管理。Kubernetes通常结合docker容器工作,并且整合多个运行着docker容器的主机集群。 本课程从Kubernetes的简介、功能、架构,集群的概念、工具及部署等各个方面进行了详细的讲解及展示,通过对本课程的学习,可以对Kubernetes有一个较为全面的认识,并初步掌握Kubernetes相关的安装部署及使用技巧。本课程由黑马程序员提供。 &nbsp; 相关的阿里云产品:容器服务 ACK 容器服务 Kubernetes 版(简称 ACK)提供高性能可伸缩的容器应用管理能力,支持企业级容器化应用的全生命周期管理。整合阿里云虚拟化、存储、网络和安全能力,打造云端最佳容器化应用运行环境。 了解产品详情:&nbsp;https://www.aliyun.com/product/kubernetes
目录
相关文章
|
3天前
|
缓存 负载均衡 JavaScript
探索微服务架构下的API网关模式
【10月更文挑战第37天】在微服务架构的海洋中,API网关犹如一座灯塔,指引着服务的航向。它不仅是客户端请求的集散地,更是后端微服务的守门人。本文将深入探讨API网关的设计哲学、核心功能以及它在微服务生态中扮演的角色,同时通过实际代码示例,揭示如何实现一个高效、可靠的API网关。
|
6天前
|
设计模式 Java API
微服务架构演变与架构设计深度解析
【11月更文挑战第14天】在当今的IT行业中,微服务架构已经成为构建大型、复杂系统的重要范式。本文将从微服务架构的背景、业务场景、功能点、底层原理、实战、设计模式等多个方面进行深度解析,并结合京东电商的案例,探讨微服务架构在实际应用中的实施与效果。
31 6
|
2天前
|
Dubbo Java 应用服务中间件
服务架构的演进:从单体到微服务的探索之旅
随着企业业务的不断拓展和复杂度的提升,对软件系统架构的要求也日益严苛。传统的架构模式在应对现代业务场景时逐渐暴露出诸多局限性,于是服务架构开启了持续演变之路。从单体架构的简易便捷,到分布式架构的模块化解耦,再到微服务架构的精细化管理,企业对技术的选择变得至关重要,尤其是 Spring Cloud 和 Dubbo 等微服务技术的对比和应用,直接影响着项目的成败。 本篇文章会从服务架构的演进开始分析,探索从单体项目到微服务项目的演变过程。然后也会对目前常见的微服务技术进行对比,找到目前市面上所常用的技术给大家进行讲解。
11 1
服务架构的演进:从单体到微服务的探索之旅
|
1天前
|
Cloud Native 安全 API
云原生架构下的微服务治理策略与实践####
—透过云原生的棱镜,探索微服务架构下的挑战与应对之道 本文旨在探讨云原生环境下,微服务架构所面临的关键挑战及有效的治理策略。随着云计算技术的深入发展,越来越多的企业选择采用云原生架构来构建和部署其应用程序,以期获得更高的灵活性、可扩展性和效率。然而,微服务架构的复杂性也带来了服务发现、负载均衡、故障恢复等一系列治理难题。本文将深入分析这些问题,并提出一套基于云原生技术栈的微服务治理框架,包括服务网格的应用、API网关的集成、以及动态配置管理等关键方面,旨在为企业实现高效、稳定的微服务架构提供参考路径。 ####
13 5
|
3天前
|
监控 API 微服务
后端技术演进:从单体架构到微服务的转变
随着互联网应用的快速增长和用户需求的不断演化,传统单体架构已难以满足现代软件开发的需求。本文深入探讨了后端技术在面对复杂系统挑战时的演进路径,重点分析了从单体架构向微服务架构转变的过程、原因及优势。通过对比分析,揭示了微服务架构如何提高系统的可扩展性、灵活性和维护效率,同时指出了实施微服务时面临的挑战和最佳实践。
17 7
|
2天前
|
Kubernetes 负载均衡 Cloud Native
云原生架构下的微服务治理策略
随着云原生技术的不断成熟,微服务架构已成为现代应用开发的主流选择。本文探讨了在云原生环境下实施微服务治理的策略和方法,重点分析了服务发现、负载均衡、故障恢复和配置管理等关键技术点,以及如何利用Kubernetes等容器编排工具来优化微服务的部署和管理。文章旨在为开发者提供一套实用的微服务治理框架,帮助其在复杂的云环境中构建高效、可靠的分布式系统。
14 5
|
2天前
|
负载均衡 监控 Cloud Native
云原生架构下的微服务治理策略与实践####
在数字化转型浪潮中,企业纷纷拥抱云计算,而云原生架构作为其核心技术支撑,正引领着一场深刻的技术变革。本文聚焦于云原生环境下微服务架构的治理策略与实践,探讨如何通过精细化的服务管理、动态的流量调度、高效的故障恢复机制以及持续的监控优化,构建弹性、可靠且易于维护的分布式系统。我们将深入剖析微服务治理的核心要素,结合具体案例,揭示其在提升系统稳定性、扩展性和敏捷性方面的关键作用,为读者提供一套切实可行的云原生微服务治理指南。 ####
|
5天前
|
消息中间件 供应链 架构师
微服务如何实现低耦合高内聚?架构师都在用的技巧!
本文介绍了微服务的拆分方法,重点讲解了“高内聚”和“低耦合”两个核心设计原则。高内聚强调每个微服务应专注于单一职责,减少代码修改范围,提高系统稳定性。低耦合则通过接口和消息队列实现服务间的解耦,确保各服务独立运作,提升系统的灵活性和可维护性。通过领域建模和事件通知机制,可以有效实现微服务的高效拆分和管理。
23 7
|
1天前
|
Cloud Native 安全 数据安全/隐私保护
云原生架构下的微服务治理与挑战####
随着云计算技术的飞速发展,云原生架构以其高效、灵活、可扩展的特性成为现代企业IT架构的首选。本文聚焦于云原生环境下的微服务治理问题,探讨其在促进业务敏捷性的同时所面临的挑战及应对策略。通过分析微服务拆分、服务间通信、故障隔离与恢复等关键环节,本文旨在为读者提供一个关于如何在云原生环境中有效实施微服务治理的全面视角,助力企业在数字化转型的道路上稳健前行。 ####
|
3天前
|
监控 持续交付 Docker
Docker 容器化部署在微服务架构中的应用有哪些?
Docker 容器化部署在微服务架构中的应用有哪些?