电商项目DevOps一体化运维实战

一、大厂都在做的DevOps,CI\CD都是什么?

​ 谈到DevOps,只要你有实际项目的开发经验,那么对这个词一定不会陌生。各大互联网厂商都在不断推出自己的DevOps实践落地的理论、规则、产品。我们这个电商项目也不例外。代码最终需要经过DevOps的一系列操作才能部署到服务器上真实运行。那到底什么是DevOps呢?

1、开发与运维割裂的问题

​ 当开发人员基于本地开发环境完成了代码开发后,最终是需要部署到生产的服务器上执行的。在传统的运维体系下,开发和运维通常都是割裂的。很多大型项目中,开发人员不允许接触生产环境的服务器,服务器只能由运维团队进行操作。这样可以极大的提高服务器的安全性。尤其对于像我们的电商这样面向互联网的项目,不经保护的开放服务,就是给黑客提供攻击的靶子。

​ 因此,在现代化的大型软件项目中,对于开发人员的要求也更为全面。虽然开发人员不要求像专业的运维人员一样,掌握服务器的各种安全策略、参数调优等。但是对于基础的运行环境运维操作也必须要了解,这样才能指导运维人员进行业务环境部署,也就是开发运维一体化。虽然现在有很多工具能够帮助开发人员减少一些复杂的操作,但是开发人员还是需要更多的接触运维的工作。

​ 但是这种运维方式,同时也给项目开发过程中带来了很多困难。

​ 一方面,开发人员只能向运维人员描述具体的部署方式。但是由于开发人员无法接触到生产服务器,所以文字描述的方式往往很难保证操作的准确性。经常会出现开发人员在开发环境运行得很好的迭代包,升级到生产环境上之后无法保证升级的效果。对于现在流行的基于敏捷开发的大型项目来说,很多需求需要以代码分支的方式进行并行开发,然后再合并部署,这其中更是非常容易出现错误,造成生产环境不稳定。

​ 另一方面,当项目在线上运行出现故障时,开发人员也很难第一时间接触到错误日志。如果线上出现问题,开发人员往往需要找运维部门协同,才能获取到生产环境的服务日志。这会极大的延缓错误排查的及时性。

2、DevOps与CI\CD

​ 以上那些问题的核心,其核心就是在传统运维体系下,开发和运维之间是有天然的壁垒和鸿沟的。而DevOps则是试图打破这些壁垒鸿沟的一种方法论。DevOps是Development(开发)和Operation(运维)两个单词的组合,他是一种重视软件开发人员和运维技术人员之间沟通合作的文化、运动或者惯例。通过自动化软件交互和架构变更的流程,使得构建、测试、发布软件时能够更加快捷、频繁和可靠。

​ 总而言之,DevOps是一个标准,一种方法论或者说是一个目标,并不指一个特定的规则或者一系列特殊的工具。那要如何落地DevOps呢?通常,这就需要CI\CD出马了。

​ CI\CD中的CI指的是持续集成Continuous Integeration,他是开发人员的自动化过程。成功的CI意味着人员同的新代码变更会定期构建、测试并合并到共享存储库(比如Git或者SVN)。而CD指的是持续交付Continuous Delivery和持续部署Continuous Deployment。成功的CD意味着运维人员可以从共享存储库中持续获取到最新的产品副本,并确保最新的产品副本可以正确更新到服务器上。

​ 关于如何达成CI\CD,各大互联网厂商提供了大量的方法论以及工具。下面就以电商项目为例,基于最为典型的GitLab和Jenkins搭建一套简单的自动部署环境。

二、使用GitLab+Jenkins搭建CI\CD执行环境

​ 关于GitLab和Jenkins的安装过程,这里只简单介绍一下关键步骤。如果对安装有问题的同学,可以自行到网上搜索一下安装教程,网上的资料非常多。

1、GitLab安装

​ GitLab是企业中最为常用的私有代码仓库解决方案。你可以把他理解为一个企业自己搭建的GitHub或者Gitee(程序员交友平台,不会没用过把?)。企业通常会通过GitLab搭建自己的代码仓库,开发人员的应用代码都通过GitLab进行协同开发。

​ GitLab是一个开源项目,分为免费的ce社区版和收费的ee企业版。这里介绍ce社区版的安装过程。

​ 首先要检查服务器配置。GitLab需要部署非常多的后台服务,通常建议单机内存不要低于4G。如果配置太低的话,会出现很多奇怪的问题。Linux服务器需要提前安装几个服务 yum install -y curl policycoreutils-python openssh-server 。如果已经安装了,这一步可以省略。

​ 然后获取GitLab安装包。社区版的GitLab下载地址https://packages.gitlab.com/gitlab/gitlab-ce。电商项目中采用的Linux服务器,就可以选择下载gitlab-ce-15.1.0-ce.0.el7.x86_64.rpm。

​ 接下来就可以安装GitLab了。 执行rpm -Uvh gitlab-ce-15.1.0-ce.0.el7.x86_64.rpm 开始安装。

​ 安装完成后,第一次运行GitLab前,需要执行一次配置初始化操作。 gitlab-ctl reconfig。 这个过程耗时比较长。

​ 接下来就可以使用gitlab-ctl指令来操作gitlab服务了。

  • gitlab-ctl reconfigure 重新配置gitlab。

  • gitlab-ctl start 启动gitlab

  • gitlab-ctl stop 停止gitlab

  • gitlab-ctl restart 重启gitlab

  • gitlab-ctl status 查看gitlab服务状态

  • gitlab-ctl tail 查看gitlab服务日志。

    ​服务启动完成后,就可以访问gitlab服务了。默认的服务端口就是80端口。默认的用户名和密码是root/123456(通常建议登录后立即修改默认密码)。

如果需要修改访问的地址和端口,可以修改/etc/gitlab/gitlab.rb配置文件,修改其中的external_url属性即可。

复制代码
## GitLab URL
##! URL on which GitLab will be reachable.
##! For more details on configuring external_url see:
##! https://docs.gitlab.com/omnibus/settings/configuration.html#configuring-the-external-url-for-gitlab
##!
##! Note: During installation/upgrades, the value of the environment variable
##! EXTERNAL_URL will be used to populate/replace this value.
##! On AWS EC2 instances, we also attempt to fetch the public hostname/IP
##! address from AWS. For more details, see:
##! https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instancedata-data-retrieval.html
external_url 'http://192.168.65.78'

​ 接下来就可以登录进入GitLab,维护基础权限信息,并将项目代码上传到Git仓库当中。这些基础的操作跟GitHub或者Gitee基本上是一样的。

2、Jenkins安装

​ Jenkins是企业最常用的一个自动化部署软件。下载地址为Download and deploy 。建议下载LTS(长期支持)版本的war包部署。下载获取jenkins.war文件。

​ 首先,需要安装JDK。 Jenkins运行需要JDK环境支持,目前Jenkins建议使用JDK11版本。

​ 然后,就可以直接启动Jenkins。 启动指令 java -jar Jenkins.war。 当然,你也可以使用后台执行的方式。 nohup java -jar jenkins.war & 。这种方式不会占用当前命令行窗口,日志输出到nohup.out下。

在启动时,也可以指定端口。 java -jar Jenkins.war --httpPort=8080 。 端口默认就是8080端口。

​ 在第一次启动的过程中,Jenkins会在日志文件中打印默认的admin用户密码。这个需要留意一下。

复制代码
*************************************************************

Jenkins initial setup is required. An admin user has been created and a password generated.
Please use the following password to proceed to installation:

e3c2de8a2084429ea733ef30512a0523

This may also be found at: /root/.jenkins/secrets/initialAdminPassword

*************************************************************

​ 启动完成后,就可以访问Jenkins的前台管理页面http://192.168.65.200:8080/。第一次访问时,前端页面会会引导进行一些初始化工作。例如,需要输入admin用户的默认密码,这个密码就在启动日志当中。

后续还会引导设定admin用户的用户名。

​ 然后会引导安装一些插件。这一步比较自由。你可以按照默认方式安装,也可以选择一些你认识的常用插件安装。关键插件漏了没有关系,后续也可以再安装插件。

​ 引导步骤安装完成后,就可以进入Jenkins的首页了。

​ 接下来需要安装几个核心的插件。选择 Manage Jenkins-> Manage Plugins,进入插件管理页面。

​ 在这里需要安装几个核心的插件。包括Git 、Git client、NodeJS Plugin、Maven integration plugin。如果你希望Jenkins能够更多的显示中文,还可以安装 Localization:Chinese(Simplified)插件。下载完成后有些插件需要重启才能生效。Jenkins重启的方式是直接在浏览器上访问restart接口。

​ 重启完成后,还需要配置几个基础的组件。进入Mange Jenkins->Global ToolConfiguration页面。在这里需要对Maven、Git和NodeJS组件进行配置。你可以选择按照页面提示,自动下载安装对应的组件。 当前电商环境中是直接另外去安装对应的组件。

​ 例如对于git,只要服务器能够支持git指令接口。如果没有安装的话,可以使用yum -install git 安装git客户端。

复制代码
[root@192-168-65-200 ~]# git --version
git version 1.8.3.1

​ 而Maven和NodeJS插件,可以去官网上下载对应的压缩包,解压后,将bin子目录配置到环境变量当中。跟安装JDK的方式差不多。同样只要服务器能够直接支持mvn指令和node指令即可。

复制代码
[root@192-168-65-200 ~]# mvn -versin
Apache Maven 3.6.3 (cecedd343002696d0abb50b32b541b8a6ba2883f)
Maven home: /app/maven/apache-maven-3.6.3
Java version: 11.0.10, vendor: Oracle Corporation, runtime: /app/jdk/jdk-11.0.10
Default locale: zh_CN, platform encoding: UTF-8
OS name: "linux", version: "3.10.0-1160.el7.x86_64", arch: "amd64", family: "unix"
[root@192-168-65-200 bin]# node -v
v14.15.0

​ 到这里基础环境就算搭建完成了。

3、基于GitLab+Jenkins快速实现CI\CD

​ 接下来需要在Jenkins中配置一个构建任务。下面就以电商项目的后端工程为例,演示配置过程。另外电商项目的两个前端工程也可以以类似的方式进行配置。

1、创建一个maven项目

​ 在Jenkins首页选择新建Item,然后选择构建一个maven项目

2、配置项目构建及部署过程

​ 接下来在Jenkins中配置项目的配置项还是挺多的,这里只列出几个关键的配置。其他部分可以自行调整。

​ 首先需要在源码管理部分配置对应的git仓库地址。

构建触发器部分,可以选择配置Poll SCM选项。这个选项可以定时扫描Git代码仓库。当发现Git仓库代码有变化,即有代码提交时,就会触发一次构建任务。当前电商项目采用手动控制发布的方式,就没有选择配置了。

这里面Poll SCM是一个比较常用的配置。通过这个配置,可以让jenkins定期去检查代码库。如果发现代码库有更新,则自动触发当前任务,完成项目的构建以及部署。当前电商项目编译任务太重,提交也不太频繁,所以就选择不配置该属性。

构建环境部分建议选择一下JDK版本,因为电商项目采用的是JDK8版本进行开发。

接下来的Build部分,就可以选择需要执行的编译脚本。

这一步相当于指定使用 mvn package -Dmaven.test.skip=true指令对后端项目进行重新打包构建。

如果是前端项目,就需要用Nodejs的npm run build指令来构建。

​ 构建完成之后,就会在后端项目的各个模块的target目录下生成可执行的包。这时,可以选择用Jenkins将这些Jar包分发到远程服务器上,并直接运行。

前端项目也可以用同样的方式传递到远端服务器上。远端指令只需要执行 nginx -s reload 更新一下即可。

​ 这样就完成了一个基础项目的配置过程。接下来,保存之后,就可以选择Jenkins首页对应项目右侧的三角指令发起一次构建了。构建过程中如果有问题,可以查看构建日志,进行排查。

这里完成的是一个最简单的Maven项目构建。实际上,在企业中,还会构建更复杂的任务。

例如集成Docker,进行虚拟化部署。

添加Blue Ocean插件做一些代码质量检测,邮件通知等复杂的步骤。甚至使用Pepeline构建更为复杂的任务流水。

或者搭建SonarQube服务,并通过jenkins集成。这样就可以使用SonarQube服务来进行代码质量检测。

三、电商后端项目打包及部署方式

​ 从刚才的部署过程中可以看到,基于Jenkins的CI\CD配置方式就是执行Maven对项目进行编译,然后将Jar包传到远端服务器上执行。这个过程跟我们手动进行任务部署是差不多的,只不过Jenkins将这些过程自动完成了。

​ 但是这里其实有一个小问题。当前电商项目在编译时,是在pom.xml中采用SpringBoot的Maven插件将整个项目打成了一个可执行的Jar包。 这样打出来的Jar包可以直接使用Java -jar指令执行。

复制代码
<build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.3.2.RELEASE</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
                <!-- 解决运行包不能被其他包依赖的问题 -->
                <configuration>
                    <classifier>exec</classifier>
                </configuration>
            </plugin>
        </plugins>
</build>

​ 但是,这种方式也有一个很大的问题,就是Jar包太大了。这么大的Jar包,编译会很耗时,并且在网络中传输是非常麻烦的。所以,对于一些大型项目,通常不会采用这种一体化的fat Jar的方式。而会选择将依赖单独打成小的Jar包。这样后续每次更新只需要更新调整过的少量Jar包即可。那有哪些Maven打包方式可以帮助我们打出小的jar包呢?

​ 其实Maven提供了很多的打包插件。例如将上面的plugin部分替换为maven-dependency-plugin,就可以将项目打成小包。

复制代码
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-dependency-plugin</artifactId>
    <!-- <version>2.10</version> -->
    <executions>
        <execution>
            <id>copy-dependencies</id>
            <phase>package</phase>
            <goals>
                <goal>copy-dependencies</goal>
            </goals>
            <configuration>
                <outputDirectory>export</outputDirectory> <!-- 将依赖包放入export文件夹 -->
                <excludeTransitive>false</excludeTransitive>
                <stripVersion>true</stripVersion>
            </configuration>
        </execution>
    </executions>
</plugin>

​ 通过这种方式,就可以将所有依赖的jar包都放到export文件夹中,target目录下的jar包只包含当前项目的源码,文件大小就会小很多。

​ 将export目录下的所有jar包和target下的当前项目jar包上传到服务器的同一个目录当中,就可以直接运行了。这种方式就跟很多开源框架的运行方式相似了。至于要如何运行呢?当然就不能用java -jar指令简单执行了,需要通过java -cp指令指定依赖包和主启动类执行。至于如何使用这个指令,你之前学过的很多开源组件都可以提供帮助了。比如shardingproxy、RocketMQ等,都有这样的脚本。

​ 这里也给出一个简单的Linux执行脚本示例,供你参考。

复制代码
more runapp.sh 

#!/bin/sh
#执行jar包
RUN_LIBS=""
#依赖jar包 自行制定目录
SUPPORT_LIBS=""
RUN_LIB_PATH="/app/lib"
SUPPORT_LIB_PATH="/app/support"
#加载程序包
for i in ${RUN_LIB_PATH}/* ; do
   RUN_LIBS=${RUN_LIBS}:$i
done
#加载依赖包
for i in ${SUPPORT_LIB_PATH}/* ; do
   SUPPORT_LIBS=${SUPPORT_LIBS}:$i
done
#整合classpath
CLASSPATH=${RUN_LIBS}:${SUPPORT_LIBS}
export CLASSPATH
#调用java指令执行。-D输入参数 java中可以用 System.getProperties读取。同时指定执行入口类 SpringBootApplication  这是一个典型的Springboot的执行方式。
java  -Xdebug  -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,address=27899,suspend=n -cp $CLASSPATH  -Dspring.profiles.active=prod com.tuling.TulingmallCartApplication -D
user.timezone=GMT+08 1>tulingmall-admin.out 2>tulingmall-admin.err &
echo Start App Success!

实际上这样定制脚本对于提高运行效率是非常重要的,你学了很多次的JVM调优就体现在脚本定制的过程中。在脚本最后的java指令中,可以添加哪些优化参数?

另外,这种部署方式,你可以自己尝试用jenkins配置自动部署吗?

​ 实际上,Maven还提供了非常多插件。比如对于很多复杂的项目,可能需要将不同的模块输出到多个不同的jar包当中,而不是所有代码全都输出一个jar包。下面就是使用maven-jar-plugin插件的一个可行的示例,将不同模块的代码分别整合到myapp.jar和myapp2.jar中。有兴趣你可以自己尝试下。

复制代码
<plugin> 
  <groupId>org.apache.maven.plugins</groupId>  
  <artifactId>maven-jar-plugin</artifactId>  
  <version>3.0.2</version>  
  <configuration>  <!-- manifest配置信息 主要是可以配置主执行类。有主执行类,可以用java-jar直接执行。没有的话就需要指定执行类 -->
    <archive> 
      <manifest> 
        <addClasspath>true</addClasspath>  
        <classpathPrefix>support/</classpathPrefix>  
        <mainClass>com.myapp.MyAppApplication</mainClass> 
<!-- 可以按上面的方式自己配置,也可以指定MF文件打包。 -->
        <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
      </manifest> 
    </archive>  
  </configuration>
  <executions> 
    <execution> 
      <id>myapp1-jar</id>  
      <phase>package</phase>  
      <goals> 
        <goal>jar</goal> 
      </goals>  
      <configuration> 
        <classifier>myapp</classifier>  
        <includes> 
          <include>com/myapp/**</include>  
          <include>mybatis/**</include>  
          <include>templates/**</include>  
          <include>*.properties</include>  
          <include>dubbo.xml</include> 
        </includes> 
      </configuration> 
    </execution>  
    <execution> 
      <id>myapp2-jar</id>  
      <phase>package</phase>  
      <goals> 
        <goal>jar</goal> 
      </goals>  
      <configuration> 
        <classifier>myapp2</classifier>  
        <includes> 
          <include>com/myapp2/crawler/*</include>  
          <include>com/myapp2/crawler/*</include>  
          <include>com/myapp2/utils/**</include>  
          <include>log4j.properties</include> 
        </includes> 
      </configuration> 
    </execution>  
  </executions> 
</plugin>

​ 如果你对Maven感兴趣,可以去Maven官网上看看Maven目前官方提供的插件。 https://maven.apache.org/plugins/index.html。 这上面能找到非常多有趣的插件,并且都有详细的说明。比如changelog插件,可以打印出Maven仓库中最近的提交记录。checkstyle和pmd插件可以对代码进行静态检查。javadoc插件可以打印出项目文档,你还可以用pdf插件,打印出pdf版本的项目文档。或者使用antrun插件去执行一些ant脚本(老程序员应该对ant很熟悉)。 很多精彩等你发现。

相关推荐
乘云数字DATABUFF16 小时前
5分钟部署开源APM Databuff:OpenTelemetry全链路追踪入门实战
运维·后端
荣--3 天前
一键部署不是为了省时间 —— 它是把"买来的 PaaS"变成"自己的平台"的拐点
运维·zabbix·工程化·一键部署·平台化·边界设计
江华森3 天前
动手实战学 Docker — 从零到集群编排完全指南
运维
Avan_菜菜3 天前
FRP 内网穿透完整实战:从 HTTP 映射到 HTTPS 自签代理
运维·nginx·https
SelectDB4 天前
Litefuse 开源并推出单进程轻量模式,25 秒就能跑起来的 Agent 可观测与评估平台
运维·后端·自动化运维
XIAOHEZIcode6 天前
Linux系统鼠标偏移常见原因以及修复方案
linux·运维·游戏
用户0328472220706 天前
如何搭建本地yum源(上)
运维
大树889 天前
金刚石散热越强,管路越先见顶
大数据·运维·服务器·人工智能·ai
摇滚侠9 天前
Linux CentOS7 rpm 安装 MySQL 5.7
linux·运维·mysql
霸道流氓气质9 天前
领域驱动设计(DDD)在 Spring Boot 微服务中的实践指南
运维·spring boot·微服务