当前位置: 首页 > ds >正文

JAVA 项目工程化实践

项目概述

公司前后端开发人员各两名。后端采用 Java 开发,主要使用 springboot + dubbo 技术栈;前端使用 vue 技术栈。项目使用前后端分离开发的方式。

技术栈

  • 后端:Spring Boot + Dubbo
  • 前端:Vue
  • 部署工具
    • 前端:SFTP
    • 后端:Docker Swarm + Portainer
  • CI/CD:云端构建(使用 Dockerfile-Maven 插件)

项目架构与部署

架构设计

  • 前后端分离:前端为 Vue 开发的静态页面,后端提供接口服务。
  • 统一入口:使用 Nginx 作为服务的统一入口,基于 URL 路径分发请求到前端或后端。

前端静态页面直接放在 nginx html 目录;后端接口服务使用 docker 容器运行。使用多台阿里云 ECS 搭建 docker swarm 集群。

部署方式

  • 前端部署
    • 静态页面直接放置在 Nginx 的 HTML 目录中。
    • 使用 SFTP 进行文件传输。
  • 后端部署
    • 使用 Docker 容器运行。
    • 多台阿里云 ECS 搭建 Docker Swarm 集群。没有采用 Kubernetes,因为当前项目规模较小,Docker Swarm 更简单易用。

环境管理

项目环境

  • 测试环境:用于内部测试和开发联调。
  • 正式环境:线上用户实际使用的生产环境。

Git 分支管理策略

  • 主分支
    • dev:对应测试环境,不能直接提交代码,只能从其他分支合并。
    • release:对应正式环境,不能直接提交代码,只能从其他分支合并。
  • 功能分支
    • feature/*:新需求开发分支。每个独立功能需求对应一个 feature 分支,基于最新的 release 创建。
      • 开发完成后先合并到 dev 用于前端联调。
      • 测试验证通过后合并到 release 上线。
  • 修复分支
    • fix/*:线上 Bug 修复分支。基于最新的 release 创建。
      • 修复完成后先合并到 dev 提交测试验证。
      • 验证通过后再合并到 release 上线。
  • 分支生命周期
    • fixfeature 分支在上线后即可删除。

项目构建方式

没有采用 Jenkins 或本地构建方案,而是选择云端构建 ,使用 dockerfile-maven-plugin 插件,在 Maven 打包时自动构建 Docker 镜像并推送到远程仓库。

关键配置 (Maven pom.xml)

<properties><dockerfile.plugin.version>1.4.13</dockerfile.plugin.version><dockerfile.skip>true</dockerfile.skip><dockerfile.timestamp.skip>true</dockerfile.timestamp.skip><docker.images.tag>latest</docker.images.tag><docker.repository.prefix>registry-vpc.cn-shenzhen.aliyuncs.com/test</docker.repository.prefix><maven.build.timestamp.format>yyyyMMddHHmmss</maven.build.timestamp.format>
</properties><build><pluginManagement><plugins><!--为了统一管理各个maven模块的Dockerfile,这里通过maven-resources-plugin的copy-resources在maven的compile阶段将Dockerfile文件复制到target目录中。这里的resource配置的顺序是copy当前模块中的Dockerfile文件,再copy父级模块中的Dockerfile,因为copy-resources目标的overwrite属性默认为false,所以会优先使用当前模块的Dockerfile。--><plugin><artifactId>maven-resources-plugin</artifactId><executions><execution><id>copy-dockerfile</id><phase>compile</phase><goals><goal>copy-resources</goal></goals><configuration><outputDirectory>${basedir}/target/</outputDirectory><resources><resource><directory>./</directory><includes><include>Dockerfile</include></includes></resource><resource><directory>../</directory><includes><include>Dockerfile</include></includes></resource></resources></configuration></execution></executions></plugin><plugin><groupId>com.spotify</groupId><artifactId>dockerfile-maven-plugin</artifactId><version>${dockerfile.plugin.version}</version><executions><!-- 在build阶段创建image、tag、push --><execution><id>build-tag-push</id><phase>package</phase><goals><goal>build</goal><goal>tag</goal><goal>push</goal></goals><configuration><tag>${docker.images.tag}</tag></configuration></execution><!-- tag 一个以时间为版本号并push --><execution><id>tag-push-latest</id><phase>package</phase><goals><goal>tag</goal><goal>push</goal></goals><configuration><tag>${maven.build.timestamp}</tag><skip>${dockerfile.timestamp.skip}</skip></configuration></execution></executions><configuration><skip>${dockerfile.skip}</skip><repository>${docker.repository.prefix}/${project.build.finalName}</repository><contextDirectory>${basedir}/target</contextDirectory><verbose>true</verbose><!-- 注意在本地.m2/settings.xml中设置Registries账号和密码 --><useMavenSettingsForAuth>true</useMavenSettingsForAuth><buildArgs><ARTIFACT_NAME>${project.build.finalName}</ARTIFACT_NAME></buildArgs></configuration></plugin></plugins></pluginManagement>
</build>

项目构建脚本

#!/bin/bash
# 开头加上set -e,这句语句告诉bash如果任何语句的执行结果不是true则应该退出
set -e
# 项目名称
projectName="接口服务"
# git仓库地址
gitUrl="git@gitee.com:xxx/xxx.git"
# git 分肢
branch="dev"
# 本地工作空间路径
workspace="/home/build-xx"
# maven 参数
mvnParam=""echo "开始构建【${projectName}】"
starttime=`date +'%Y-%m-%d %H:%M:%S'`# 工作目录是否存在
if [ ! -d "$workspace" ]; thenecho "创建工作目录: $workspace"mkdir $workspaceecho "开始拉取代码...."git clone ${gitUrl} $workspace
fi# 进入工作空间
cd $workspace# 读入环境
read -p  "请选择环境(dev,prod),默认[dev],回车跳过: " env
if [ -z "$env" ] || [ ${env} == "dev" ]; thenbranch='dev'
elif [ ${env} == "prod" ]; thenbranch="release"mvnParam="-Ddocker.images.tag=release -Ddockerfile.timestamp.skip=false"
elseecho "无效的环境,只支持dev,prod"exit 1
fimm="git checkout $branch"
echo "切换分支: $mm"
eval $mm# 拉取分支
mm="GIT_TRACE=2  GIT_CURL_VERBOSE=2 git pull origin $branch"
echo "将远程分支merge到当前分支: $mm"
eval $mm# 读入构建的maven模块
read -p  "请输入需要构建的maven模块,默认全部构建,多个模块可以使用\",\"隔开;直接回车跳过:" modules
if [ -n "$modules" ]; thenmodules="-pl ${modules} -am"
fimm="mvn clean package ${mvnParam} -Dmaven.test.skip=true -Ddockerfile.skip=false ${modules}"
echo $mm
eval $mmendtime=`date +'%Y-%m-%d %H:%M:%S'`
start_seconds=$(date --date="$starttime" +%s);
end_seconds=$(date --date="$endtime" +%s);
echo "本次运行时间: "$((end_seconds-start_seconds))"s"

镜像标签规则

  • 测试环境:Docker 镜像的 tag 为 latest
  • 正式环境:Docker 镜像的 tag 为 release,同时以构建时间(yyyyMMddHHmmss)指定另一个 tag。

云端构建环境

直接在 docker swarm 中部署一个容器,容器需要包括的工具有:git、jdk、maven、docker-ce-cli。

Dockerfile

FROM centos:7
MAINTAINER "xx@126.com"
ENV TZ=Asia/Shanghai
WORKDIR /home
COPY ./jdk-17_linux-x64_bin.rpm jdk-17_linux-x64_bin.rpm
RUN rpm -ivh jdk-17_linux-x64_bin.rpm && rm jdk-17_linux-x64_bin.rpm
RUN curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo \&& curl -o /etc/yum.repos.d/docker-ce.repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo \&& yum makecache \&& yum install java-1.8.0-openjdk* git maven docker-ce-cli -y \&& yum install -y glibc-common kde-l10n-Chinese fonts-chinese \&& yum clean packages \&& cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \&& localedef -c -f UTF-8 -i zh_CN zh_CN.UTF-8&& echo "Asia/Shanghai" > /etc/timezone
# 设置默认语言环境
ENV LANG zh_CN.UTF-8
ENV LANGUAGE zh_CN.UTF-8
ENV LC_ALL zh_CN.UTF-8
ENTRYPOINT ["/sbin/init"]

构建命令

docker build -t registry-vpc.cn-shenzhen.aliyuncs.com/xx/java-server-build:release .

应用部署

构建环境部署(Docker Compose)

version: "3.7"
services:build:image: registry-vpc.cn-shenzhen.aliyuncs.com/xx/java-server-build:releaseworking_dir: /home/bin/volumes:- /var/run/docker.sock:/var/run/docker.sock # 将宿主机上的 Docker 套接字(socket)文件挂载到容器中- /java-server-build/.m2:/root/.m2/ # maven settings.xml 和 repository 目录- /java-server-build/.ssh:/root/.ssh/ # git 拉取代码的密钥信息- /java-server-build/bin:/home/bin/ # 项目构建脚本deploy:mode: replicatedreplicas: 1resources:limits:cpus: '2'memory: 4greservations:cpus: '0.5'memory: 200M

应用服务部署(Docker Compose)

version: "3.7"
networks:xx-net: external: true
services:        biz:image: registry-vpc.cn-shenzhen.aliyuncs.com/xx/api-server:latestcontainer_name: api-servernetworks:- xx-netdeploy:replicas: 1update_config:parallelism: 1delay: 5sorder: start-firstresources:limits:cpus: '1'memory: 1greservations:cpus: '0.25'memory: 700Mrestart_policy:condition: on-failuredelay: 5smax_attempts: 2window: 90sdepends_on:- redishealthcheck:test: ["CMD", "curl", "-f", "http://localhost:8080/actuator/health"]interval: 30stimeout: 2sretries: 3start_period: 60senvironment:- SPRING_PROFILES_ACTIVE=docker-dev

网关(nginx)部署(Docker Compose)

version: "3.7"
networks:xx-net:external: true
services:nginx:image: nginx:1.19.2ports:- target: 80published: 80protocol: tcpmode: host- target: 443published: 443protocol: tcpmode: hostrestart: alwayscontainer_name: nginxlogging: options: max-size: "2g" networks:- xx-netdeploy:resources:limits:cpus: '1'memory: 2greservations:cpus: '0.5'memory: 50Mmode: globalvolumes:- /nginx/nginx.conf:/etc/nginx/nginx.conf:ro- /nginx/uc/conf.d:/etc/nginx/conf.d:ro- /nginx/html:/etc/nginx/html:roenvironment:TZ : 'Asia/Shanghai'
http://www.xdnf.cn/news/15480.html

相关文章:

  • fatal: active `post-checkout` hook found during `git clone`
  • v-for中key值的作用:为什么我总被要求加这个‘没用的‘属性?
  • 大小为 K 且平均值大于等于阈值的子数组数目
  • “找到一个或多个多重定义的符号“(LNK2005 或 LNK1169)
  • 006_测试评估与安全实践
  • 深入理解 LangChain:AI 应用开发的全新范式
  • 面试150 填充每个节点的下一个右侧节点指针Ⅱ
  • 第一个Flink 程序 WordCount,词频统计(批处理)
  • ReAct论文解读(1)—什么是ReAct?
  • AI大模型计数能力的深度剖析:从理论缺陷到技术改进
  • Java行为型模式---观察者模式
  • macOS - Chrome 关闭自动更新
  • c语言初阶 结构体
  • 基于Flink的实时开发平台-Dinky
  • v-show和v-if的区别
  • 【C++】auto关键字 C++入门(5)
  • 数据结构(8)——二叉树(2)
  • HarmonyOS 获取设备位置信息开发指导
  • 每天一个前端小知识 Day 30 - 前端文件处理与浏览器存储机制实践
  • Rust 模块系统:控制作用域与私有性
  • 《[系统底层攻坚] 张冬〈大话存储终极版〉精读计划启动——存储架构原理深度拆解之旅》-系统性学习笔记(适合小白与IT工作人员)
  • 从零开始跑通3DGS教程:(五)3DGS训练
  • React强大且灵活hooks库——ahooks入门实践之常用场景hook
  • 实现“micro 关键字搜索全覆盖商品”并通过 API 接口提供实时数据(一个方法)
  • 【LeetCode数据结构】单链表的应用——反转链表问题、链表的中间节点问题详解
  • DVWA靶场通关笔记-XSS DOM(High级别)
  • Dubbo跨越分布式事务的最终一致性陷阱
  • 一文讲懂填充与步幅
  • AI进化论12:大语言模型的爆发——GPT系列“出圈”,AI飞入寻常百姓家
  • jenkins使用Jenkinsfile部署springboot+docker项目