魔鸡马奇克2免安装绿色中文版
175M · 2025-09-17
通过本篇教程,你将学会:
graph TB
subgraph "开发阶段"
A1[源码开发] --> A2[单元测试]
A2 --> A3[集成测试]
A3 --> A4[代码质量检查]
end
subgraph "构建阶段"
B1[Maven 编译] --> B2[注解处理]
B2 --> B3[资源打包]
B3 --> B4[JAR/WAR 生成]
end
subgraph "发布阶段"
C1[版本标签] --> C2[签名验证]
C2 --> C3[仓库上传]
C3 --> C4[文档发布]
end
subgraph "部署阶段"
D1[环境准备] --> D2[应用部署]
D2 --> D3[配置管理]
D3 --> D4[健康检查]
end
A4 --> B1
B4 --> C1
C4 --> D1
style A1 fill:#e8f5e8
style B1 fill:#e3f2fd
style C1 fill:#fff3e0
style D1 fill:#fce4ec
flowchart LR
subgraph "开发环境"
DEV1[本地开发]
DEV2[单元测试]
DEV3[集成测试]
end
subgraph "测试环境"
TEST1[功能测试]
TEST2[性能测试]
TEST3[兼容性测试]
end
subgraph "预生产环境"
STAGE1[预发布验证]
STAGE2[压力测试]
STAGE3[回归测试]
end
subgraph "生产环境"
PROD1[蓝绿部署]
PROD2[滚动更新]
PROD3[监控告警]
end
DEV1 --> TEST1
TEST3 --> STAGE1
STAGE3 --> PROD1
style DEV1 fill:#e8f5e8
style TEST1 fill:#e3f2fd
style STAGE1 fill:#fff3e0
style PROD1 fill:#ffebee
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>io.github.nemoob</groupId>
<artifactId>atlas-mapper-parent</artifactId>
<version>1.0.0</version>
<packaging>pom</packaging>
<name>Atlas Mapper Parent</name>
<description>高性能 Java Bean 映射框架 - 基于编译时代码生成</description>
<url>https://github.com/nemoob/atlas-mapper</url>
<!-- 项目信息 -->
<licenses>
<license>
<name>MIT License</name>
<url>https://opensource.org/licenses/MIT</url>
<distribution>repo</distribution>
</license>
</licenses>
<developers>
<developer>
<id>nemoob</id>
<name>杨杨杨大侠</name>
<email>[email protected]</email>
<organization>Atlas Mapper</organization>
<organizationUrl>https://github.com/nemoob</organizationUrl>
<roles>
<role>architect</role>
<role>developer</role>
</roles>
<timezone>+8</timezone>
</developer>
</developers>
<scm>
<connection>scm:git:git://github.com/nemoob/atlas-mapper.git</connection>
<developerConnection>scm:git:ssh://github.com:nemoob/atlas-mapper.git</developerConnection>
<url>https://github.com/nemoob/atlas-mapper/tree/main</url>
</scm>
<issueManagement>
<system>GitHub</system>
<url>https://github.com/nemoob/atlas-mapper/issues</url>
</issueManagement>
<ciManagement>
<system>GitHub Actions</system>
<url>https://github.com/nemoob/atlas-mapper/actions</url>
</ciManagement>
<!-- 属性配置 -->
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.build.sourceEncoding>
<!-- 依赖版本 -->
<spring.version>5.2.25.RELEASE</spring.version>
<spring-boot.version>2.2.13.RELEASE</spring-boot.version>
<freemarker.version>2.3.32</freemarker.version>
<junit.version>5.8.2</junit.version>
<!-- 插件版本 -->
<maven-compiler-plugin.version>3.8.1</maven-compiler-plugin.version>
<maven-source-plugin.version>3.2.1</maven-source-plugin.version>
<maven-javadoc-plugin.version>3.4.1</maven-javadoc-plugin.version>
<maven-gpg-plugin.version>3.0.1</maven-gpg-plugin.version>
<nexus-staging-maven-plugin.version>1.6.13</nexus-staging-maven-plugin.version>
<jacoco-maven-plugin.version>0.8.8</jacoco-maven-plugin.version>
<maven-surefire-plugin.version>3.0.0-M7</maven-surefire-plugin.version>
<maven-failsafe-plugin.version>3.0.0-M7</maven-failsafe-plugin.version>
<!-- 发布配置 -->
<maven.deploy.skip>false</maven.deploy.skip>
<gpg.skip>false</gpg.skip>
<skipTests>false</skipTests>
</properties>
<!-- 子模块 -->
<modules>
<module>atlas-mapper-core</module>
<module>atlas-mapper-processor</module>
<module>atlas-mapper-spring-boot-starter</module>
<module>atlas-mapper-example</module>
</modules>
<!-- 依赖管理 -->
<dependencyManagement>
<dependencies>
<!-- Spring Framework BOM -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-framework-bom</artifactId>
<version>${spring.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- Spring Boot BOM -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- 内部模块 -->
<dependency>
<groupId>io.github.nemoob</groupId>
<artifactId>atlas-mapper-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.github.nemoob</groupId>
<artifactId>atlas-mapper-processor</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.github.nemoob</groupId>
<artifactId>atlas-mapper-spring-boot-starter</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<!-- 构建配置 -->
<build>
<pluginManagement>
<plugins>
<!-- 编译插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
<encoding>${project.build.sourceEncoding}</encoding>
<showWarnings>true</showWarnings>
<showDeprecation>true</showDeprecation>
</configuration>
</plugin>
<!-- 源码插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>${maven-source-plugin.version}</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- 文档插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>${maven-javadoc-plugin.version}</version>
<configuration>
<encoding>${project.build.sourceEncoding}</encoding>
<charset>${project.build.sourceEncoding}</charset>
<docencoding>${project.build.sourceEncoding}</docencoding>
<doclint>none</doclint>
<quiet>true</quiet>
</configuration>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- 测试插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven-surefire-plugin.version}</version>
<configuration>
<skipTests>${skipTests}</skipTests>
<includes>
<include>**/*Test.java</include>
<include>**/*Tests.java</include>
</includes>
</configuration>
</plugin>
<!-- 集成测试插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>${maven-failsafe-plugin.version}</version>
<configuration>
<skipTests>${skipTests}</skipTests>
<includes>
<include>**/*IT.java</include>
<include>**/*IntegrationTest.java</include>
</includes>
</configuration>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- 代码覆盖率插件 -->
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>${jacoco-maven-plugin.version}</version>
<executions>
<execution>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>report</id>
<phase>test</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<!-- 默认启用的插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<!-- 发布配置 -->
<profiles>
<!-- 发布到中央仓库 -->
<profile>
<id>release</id>
<build>
<plugins>
<!-- GPG 签名插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>${maven-gpg-plugin.version}</version>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
<configuration>
<skip>${gpg.skip}</skip>
</configuration>
</execution>
</executions>
</plugin>
<!-- Nexus 发布插件 -->
<plugin>
<groupId>org.sonatype.plugins</groupId>
<artifactId>nexus-staging-maven-plugin</artifactId>
<version>${nexus-staging-maven-plugin.version}</version>
<extensions>true</extensions>
<configuration>
<serverId>ossrh</serverId>
<nexusUrl>https://s01.oss.sonatype.org/</nexusUrl>
<autoReleaseAfterClose>true</autoReleaseAfterClose>
</configuration>
</plugin>
</plugins>
</build>
</profile>
<!-- 快照版本发布 -->
<profile>
<id>snapshot</id>
<properties>
<gpg.skip>true</gpg.skip>
</properties>
</profile>
<!-- 跳过测试 -->
<profile>
<id>skip-tests</id>
<properties>
<skipTests>true</skipTests>
</properties>
</profile>
</profiles>
<!-- 分发管理 -->
<distributionManagement>
<snapshotRepository>
<id>ossrh</id>
<url>https://s01.oss.sonatype.org/content/repositories/snapshots</url>
</snapshotRepository>
<repository>
<id>ossrh</id>
<url>https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/</url>
</repository>
</distributionManagement>
</project>
#!/bin/bash
# Atlas Mapper 发布脚本
# 作者: 杨杨杨大侠 (MasterY)
# 版本: 1.0.0
set -e
# 颜色定义
RED=' 33[0;31m'
GREEN=' 33[0;32m'
YELLOW=' 33[1;33m'
BLUE=' 33[0;34m'
NC=' 33[0m' # No Color
# 日志函数
log_info() {
echo -e "${BLUE}[INFO]${NC} $1"
}
log_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
log_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# 检查必要的工具
check_prerequisites() {
log_info "检查发布前置条件..."
# 检查 Maven
if ! command -v mvn &> /dev/null; then
log_error "Maven 未安装或不在 PATH 中"
exit 1
fi
# 检查 Git
if ! command -v git &> /dev/null; then
log_error "Git 未安装或不在 PATH 中"
exit 1
fi
# 检查 GPG
if ! command -v gpg &> /dev/null; then
log_warning "GPG 未安装,将跳过签名"
export GPG_SKIP=true
fi
# 检查工作目录是否干净
if [[ -n $(git status --porcelain) ]]; then
log_error "工作目录不干净,请先提交或暂存更改"
git status --short
exit 1
fi
log_success "前置条件检查通过"
}
# 获取版本信息
get_version_info() {
CURRENT_VERSION=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout)
log_info "当前版本: $CURRENT_VERSION"
if [[ $CURRENT_VERSION == *"-SNAPSHOT" ]]; then
RELEASE_VERSION=${CURRENT_VERSION%-SNAPSHOT}
NEXT_VERSION=$(echo $RELEASE_VERSION | awk -F. '{$NF = $NF + 1;} 1' | sed 's/ /./g')-SNAPSHOT
else
RELEASE_VERSION=$CURRENT_VERSION
NEXT_VERSION=$(echo $RELEASE_VERSION | awk -F. '{$NF = $NF + 1;} 1' | sed 's/ /./g')-SNAPSHOT
fi
log_info "发布版本: $RELEASE_VERSION"
log_info "下一个开发版本: $NEXT_VERSION"
}
# 运行测试
run_tests() {
log_info "运行测试套件..."
# 单元测试
log_info "执行单元测试..."
mvn clean test -q
# 集成测试
log_info "执行集成测试..."
mvn verify -q
# 代码覆盖率检查
log_info "生成代码覆盖率报告..."
mvn jacoco:report -q
# 检查覆盖率阈值
COVERAGE=$(grep -o 'Total.*[0-9]+%' target/site/jacoco/index.html | grep -o '[0-9]+%' | head -1 | sed 's/%//')
if [[ $COVERAGE -lt 80 ]]; then
log_warning "代码覆盖率 ($COVERAGE%) 低于推荐阈值 (80%)"
else
log_success "代码覆盖率: $COVERAGE%"
fi
}
# 构建项目
build_project() {
log_info "构建项目..."
# 清理并编译
mvn clean compile -q
# 生成源码和文档
mvn source:jar javadoc:jar -q
# 打包
mvn package -DskipTests -q
log_success "项目构建完成"
}
# 更新版本号
update_version() {
local new_version=$1
log_info "更新版本号到: $new_version"
mvn versions:set -DnewVersion=$new_version -q
mvn versions:commit -q
# 更新 README 中的版本号
if [[ -f README.md ]]; then
sed -i.bak "s/<version>.*</version>/<version>$new_version</version>/g" README.md
rm -f README.md.bak
fi
}
# 创建 Git 标签
create_git_tag() {
local version=$1
local tag_name="v$version"
log_info "创建 Git 标签: $tag_name"
git add .
git commit -m "Release version $version"
git tag -a $tag_name -m "Release version $version"
log_success "Git 标签创建完成"
}
# 发布到仓库
deploy_to_repository() {
local profile=$1
log_info "发布到仓库 (profile: $profile)..."
if [[ $profile == "release" ]]; then
# 发布正式版本
mvn clean deploy -P release -DskipTests -q
else
# 发布快照版本
mvn clean deploy -P snapshot -DskipTests -q
fi
log_success "发布完成"
}
# 推送到远程仓库
push_to_remote() {
log_info "推送到远程仓库..."
git push origin main
git push origin --tags
log_success "推送完成"
}
# 生成发布说明
generate_release_notes() {
local version=$1
local notes_file="RELEASE_NOTES_$version.md"
log_info "生成发布说明: $notes_file"
cat > $notes_file << EOF
# Atlas Mapper $version 发布说明
## 发布日期
$(date '+%Y-%m-%d')
## 版本亮点
- 高性能编译时代码生成
- 完整的 Spring Boot 集成
- 丰富的映射配置选项
- 详细的调试和监控功能
## Maven 依赖
```xml
<dependency>
<groupId>io.github.nemoob</groupId>
<artifactId>atlas-mapper-spring-boot-starter</artifactId>
<version>$version</version>
</dependency>
```
## 升级指南
1. 更新 Maven 依赖版本
2. 检查配置文件兼容性
3. 运行测试确保功能正常
## 已知问题
- 无
## 文档链接
- [用户指南](https://github.com/nemoob/atlas-mapper/blob/main/README.md)
- [API 文档](https://nemoob.github.io/atlas-mapper/)
- [示例项目](https://github.com/nemoob/atlas-mapper/tree/main/atlas-mapper-example)
## 致谢
感谢所有贡献者和用户的支持!
---
**完整更新日志**: https://github.com/nemoob/atlas-mapper/compare/v$(git describe --tags --abbrev=0 HEAD^)...v$version
EOF
log_success "发布说明生成完成: $notes_file"
}
# 清理临时文件
cleanup() {
log_info "清理临时文件..."
# 清理 Maven 临时文件
find . -name "*.versionsBackup" -delete
find . -name "pom.xml.bak" -delete
log_success "清理完成"
}
# 主函数
main() {
log_info "开始 Atlas Mapper 发布流程..."
# 解析命令行参数
RELEASE_TYPE=${1:-"snapshot"}
if [[ $RELEASE_TYPE != "release" && $RELEASE_TYPE != "snapshot" ]]; then
log_error "无效的发布类型: $RELEASE_TYPE (支持: release, snapshot)"
exit 1
fi
# 执行发布流程
check_prerequisites
get_version_info
if [[ $RELEASE_TYPE == "release" ]]; then
# 正式版本发布流程
run_tests
build_project
# 更新到发布版本
update_version $RELEASE_VERSION
create_git_tag $RELEASE_VERSION
deploy_to_repository "release"
# 更新到下一个开发版本
update_version $NEXT_VERSION
git add .
git commit -m "Prepare for next development iteration: $NEXT_VERSION"
push_to_remote
generate_release_notes $RELEASE_VERSION
log_success "正式版本 $RELEASE_VERSION 发布完成!"
log_info "下一个开发版本: $NEXT_VERSION"
else
# 快照版本发布流程
run_tests
build_project
deploy_to_repository "snapshot"
log_success "快照版本 $CURRENT_VERSION 发布完成!"
fi
cleanup
log_success "Atlas Mapper 发布流程完成!"
}
# 错误处理
trap 'log_error "发布过程中发生错误,请检查日志"; cleanup; exit 1' ERR
# 执行主函数
main "$@"
# Atlas Mapper 示例应用 Dockerfile
# 多阶段构建,优化镜像大小
# 构建阶段
FROM maven:3.8.6-openjdk-8-slim AS builder
# 设置工作目录
WORKDIR /app
# 复制 POM 文件(利用 Docker 缓存)
COPY pom.xml .
COPY atlas-mapper-core/pom.xml atlas-mapper-core/
COPY atlas-mapper-processor/pom.xml atlas-mapper-processor/
COPY atlas-mapper-spring-boot-starter/pom.xml atlas-mapper-spring-boot-starter/
COPY atlas-mapper-example/pom.xml atlas-mapper-example/
# 下载依赖(利用 Docker 缓存)
RUN mvn dependency:go-offline -B
# 复制源码
COPY . .
# 构建应用
RUN mvn clean package -DskipTests -B
# 运行阶段
FROM openjdk:8-jre-alpine
# 设置时区
RUN apk add --no-cache tzdata &&
cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime &&
echo "Asia/Shanghai" > /etc/timezone &&
apk del tzdata
# 创建应用用户
RUN addgroup -g 1000 atlas &&
adduser -D -s /bin/sh -u 1000 -G atlas atlas
# 设置工作目录
WORKDIR /app
# 复制应用 JAR
COPY --from=builder /app/atlas-mapper-example/target/atlas-mapper-example-*.jar app.jar
# 创建日志目录
RUN mkdir -p /app/logs &&
chown -R atlas:atlas /app
# 切换到应用用户
USER atlas
# 健康检查
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3
CMD wget --no-verbose --tries=1 --spider http://localhost:8080/actuator/health || exit 1
# 暴露端口
EXPOSE 8080
# JVM 参数优化
ENV JAVA_OPTS="-Xms512m -Xmx1024m -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap"
# 启动应用
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar app.jar"]
# docker-compose.yml
version: '3.8'
services:
# Atlas Mapper 示例应用
atlas-mapper-app:
build:
context: .
dockerfile: Dockerfile
image: atlas-mapper-example:latest
container_name: atlas-mapper-app
ports:
- "8080:8080"
environment:
- SPRING_PROFILES_ACTIVE=docker
- JAVA_OPTS=-Xms512m -Xmx1024m -XX:+UseG1GC
volumes:
- ./logs:/app/logs
- ./config:/app/config
networks:
- atlas-network
depends_on:
- redis
- mysql
restart: unless-stopped
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:8080/actuator/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
# Redis 缓存
redis:
image: redis:6.2-alpine
container_name: atlas-redis
ports:
- "6379:6379"
volumes:
- redis-data:/data
- ./redis/redis.conf:/usr/local/etc/redis/redis.conf
command: redis-server /usr/local/etc/redis/redis.conf
networks:
- atlas-network
restart: unless-stopped
# MySQL 数据库
mysql:
image: mysql:8.0
container_name: atlas-mysql
ports:
- "3306:3306"
environment:
- MYSQL_ROOT_PASSWORD=atlas123
- MYSQL_DATABASE=atlas_mapper
- MYSQL_USER=atlas
- MYSQL_PASSWORD=atlas123
volumes:
- mysql-data:/var/lib/mysql
- ./mysql/init.sql:/docker-entrypoint-initdb.d/init.sql
networks:
- atlas-network
restart: unless-stopped
# Nginx 反向代理
nginx:
image: nginx:1.21-alpine
container_name: atlas-nginx
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf
- ./nginx/ssl:/etc/nginx/ssl
- ./nginx/logs:/var/log/nginx
networks:
- atlas-network
depends_on:
- atlas-mapper-app
restart: unless-stopped
# Prometheus 监控
prometheus:
image: prom/prometheus:latest
container_name: atlas-prometheus
ports:
- "9090:9090"
volumes:
- ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
- prometheus-data:/prometheus
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.path=/prometheus'
- '--web.console.libraries=/etc/prometheus/console_libraries'
- '--web.console.templates=/etc/prometheus/consoles'
networks:
- atlas-network
restart: unless-stopped
# Grafana 可视化
grafana:
image: grafana/grafana:latest
container_name: atlas-grafana
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=atlas123
volumes:
- grafana-data:/var/lib/grafana
- ./grafana/dashboards:/etc/grafana/provisioning/dashboards
- ./grafana/datasources:/etc/grafana/provisioning/datasources
networks:
- atlas-network
depends_on:
- prometheus
restart: unless-stopped
networks:
atlas-network:
driver: bridge
volumes:
redis-data:
mysql-data:
prometheus-data:
grafana-data:
#!/bin/bash
# Docker 构建和部署脚本
set -e
# 颜色定义
RED=' 33[0;31m'
GREEN=' 33[0;32m'
YELLOW=' 33[1;33m'
BLUE=' 33[0;34m'
NC=' 33[0m'
log_info() {
echo -e "${BLUE}[INFO]${NC} $1"
}
log_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
log_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# 构建 Docker 镜像
build_image() {
local version=${1:-"latest"}
log_info "构建 Docker 镜像 (版本: $version)..."
# 构建应用镜像
docker build -t atlas-mapper-example:$version .
# 标记为 latest
if [[ $version != "latest" ]]; then
docker tag atlas-mapper-example:$version atlas-mapper-example:latest
fi
log_success "Docker 镜像构建完成"
}
# 推送到镜像仓库
push_image() {
local registry=${1:-"docker.io"}
local version=${2:-"latest"}
log_info "推送镜像到仓库 ($registry)..."
# 标记镜像
docker tag atlas-mapper-example:$version $registry/nemoob/atlas-mapper-example:$version
# 推送镜像
docker push $registry/nemoob/atlas-mapper-example:$version
if [[ $version != "latest" ]]; then
docker tag atlas-mapper-example:$version $registry/nemoob/atlas-mapper-example:latest
docker push $registry/nemoob/atlas-mapper-example:latest
fi
log_success "镜像推送完成"
}
# 启动服务
start_services() {
log_info "启动 Docker Compose 服务..."
# 创建必要的目录
mkdir -p logs config mysql redis nginx/ssl nginx/logs prometheus grafana/dashboards grafana/datasources
# 启动服务
docker-compose up -d
# 等待服务启动
log_info "等待服务启动..."
sleep 30
# 检查服务状态
check_services_health
log_success "服务启动完成"
}
# 检查服务健康状态
check_services_health() {
log_info "检查服务健康状态..."
local services=("atlas-mapper-app" "redis" "mysql" "nginx")
for service in "${services[@]}"; do
if docker-compose ps $service | grep -q "Up"; then
log_success "$service: 运行正常"
else
log_error "$service: 运行异常"
docker-compose logs $service
fi
done
# 检查应用健康检查
log_info "检查应用健康状态..."
for i in {1..10}; do
if curl -f http://localhost:8080/actuator/health > /dev/null 2>&1; then
log_success "应用健康检查通过"
break
else
log_warning "等待应用启动... ($i/10)"
sleep 10
fi
done
}
# 停止服务
stop_services() {
log_info "停止 Docker Compose 服务..."
docker-compose down
log_success "服务停止完成"
}
# 清理资源
cleanup() {
log_info "清理 Docker 资源..."
# 停止并删除容器
docker-compose down -v
# 删除镜像(可选)
if [[ $1 == "--remove-images" ]]; then
docker rmi atlas-mapper-example:latest || true
fi
# 清理未使用的资源
docker system prune -f
log_success "资源清理完成"
}
# 查看日志
view_logs() {
local service=${1:-"atlas-mapper-app"}
log_info "查看 $service 服务日志..."
docker-compose logs -f $service
}
# 执行数据库迁移
migrate_database() {
log_info "执行数据库迁移..."
# 等待 MySQL 启动
until docker-compose exec mysql mysqladmin ping -h"localhost" --silent; do
log_info "等待 MySQL 启动..."
sleep 2
done
# 执行迁移脚本
docker-compose exec mysql mysql -u atlas -patlas123 atlas_mapper < ./mysql/migration.sql
log_success "数据库迁移完成"
}
# 备份数据
backup_data() {
local backup_dir="./backups/$(date +%Y%m%d_%H%M%S)"
log_info "备份数据到: $backup_dir"
mkdir -p $backup_dir
# 备份 MySQL 数据
docker-compose exec mysql mysqldump -u atlas -patlas123 atlas_mapper > $backup_dir/mysql_backup.sql
# 备份 Redis 数据
docker-compose exec redis redis-cli BGSAVE
docker cp atlas-redis:/data/dump.rdb $backup_dir/redis_backup.rdb
# 备份配置文件
cp -r config $backup_dir/
log_success "数据备份完成: $backup_dir"
}
# 恢复数据
restore_data() {
local backup_dir=$1
if [[ -z $backup_dir || ! -d $backup_dir ]]; then
log_error "请指定有效的备份目录"
exit 1
fi
log_info "从备份恢复数据: $backup_dir"
# 恢复 MySQL 数据
if [[ -f $backup_dir/mysql_backup.sql ]]; then
docker-compose exec -T mysql mysql -u atlas -patlas123 atlas_mapper < $backup_dir/mysql_backup.sql
log_success "MySQL 数据恢复完成"
fi
# 恢复 Redis 数据
if [[ -f $backup_dir/redis_backup.rdb ]]; then
docker-compose stop redis
docker cp $backup_dir/redis_backup.rdb atlas-redis:/data/dump.rdb
docker-compose start redis
log_success "Redis 数据恢复完成"
fi
# 恢复配置文件
if [[ -d $backup_dir/config ]]; then
cp -r $backup_dir/config/* config/
log_success "配置文件恢复完成"
fi
log_success "数据恢复完成"
}
# 性能测试
performance_test() {
log_info "执行性能测试..."
# 检查应用是否运行
if ! curl -f http://localhost:8080/actuator/health > /dev/null 2>&1; then
log_error "应用未运行,请先启动服务"
exit 1
fi
# 使用 Apache Bench 进行压力测试
if command -v ab &> /dev/null; then
log_info "使用 Apache Bench 进行压力测试..."
ab -n 1000 -c 10 http://localhost:8080/api/users/1/dto
else
log_warning "Apache Bench 未安装,跳过性能测试"
fi
# 使用 curl 进行简单测试
log_info "执行功能测试..."
# 测试健康检查
curl -f http://localhost:8080/actuator/health
# 测试映射接口
curl -f http://localhost:8080/api/users/1/dto
log_success "性能测试完成"
}
# 显示帮助信息
show_help() {
cat << EOF
Atlas Mapper Docker 部署脚本
用法: $0 [命令] [参数]
命令:
build [version] 构建 Docker 镜像
push [registry] [version] 推送镜像到仓库
start 启动所有服务
stop 停止所有服务
restart 重启所有服务
status 查看服务状态
logs [service] 查看服务日志
cleanup [--remove-images] 清理资源
migrate 执行数据库迁移
backup 备份数据
restore [backup_dir] 恢复数据
test 执行性能测试
help 显示帮助信息
示例:
$0 build 1.0.0 构建版本 1.0.0 的镜像
$0 push docker.io 1.0.0 推送镜像到 Docker Hub
$0 start 启动所有服务
$0 logs atlas-mapper-app 查看应用日志
$0 backup 备份数据
$0 test 执行性能测试
EOF
}
# 主函数
main() {
local command=${1:-"help"}
case $command in
build)
build_image $2
;;
push)
push_image $2 $3
;;
start)
start_services
;;
stop)
stop_services
;;
restart)
stop_services
start_services
;;
status)
docker-compose ps
;;
logs)
view_logs $2
;;
cleanup)
cleanup $2
;;
migrate)
migrate_database
;;
backup)
backup_data
;;
restore)
restore_data $2
;;
test)
performance_test
;;
help|*)
show_help
;;
esac
}
# 执行主函数
main "$@"
# k8s/namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
name: atlas-mapper
labels:
name: atlas-mapper
---
# k8s/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: atlas-mapper-config
namespace: atlas-mapper
data:
application.yml: |
server:
port: 8080
spring:
profiles:
active: k8s
datasource:
url: jdbc:mysql://mysql-service:3306/atlas_mapper
username: atlas
password: atlas123
redis:
host: redis-service
port: 6379
management:
endpoints:
web:
exposure:
include: health,info,metrics,prometheus
endpoint:
health:
show-details: always
atlas:
mapper:
debug:
enabled: false
optimization:
cache-max-size: 10000
enable-performance-monitoring: true
---
# k8s/secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: atlas-mapper-secret
namespace: atlas-mapper
type: Opaque
data:
mysql-password: YXRsYXMxMjM= # atlas123 base64 encoded
redis-password: ""
---
# k8s/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: atlas-mapper-app
namespace: atlas-mapper
labels:
app: atlas-mapper-app
spec:
replicas: 3
selector:
matchLabels:
app: atlas-mapper-app
template:
metadata:
labels:
app: atlas-mapper-app
spec:
containers:
- name: atlas-mapper-app
image: nemoob/atlas-mapper-example:latest
ports:
- containerPort: 8080
env:
- name: SPRING_PROFILES_ACTIVE
value: "k8s"
- name: JAVA_OPTS
value: "-Xms512m -Xmx1024m -XX:+UseG1GC"
volumeMounts:
- name: config-volume
mountPath: /app/config
- name: logs-volume
mountPath: /app/logs
livenessProbe:
httpGet:
path: /actuator/health
port: 8080
initialDelaySeconds: 60
periodSeconds: 30
timeoutSeconds: 10
failureThreshold: 3
readinessProbe:
httpGet:
path: /actuator/health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
resources:
requests:
memory: "512Mi"
cpu: "250m"
limits:
memory: "1Gi"
cpu: "500m"
volumes:
- name: config-volume
configMap:
name: atlas-mapper-config
- name: logs-volume
emptyDir: {}
---
# k8s/service.yaml
apiVersion: v1
kind: Service
metadata:
name: atlas-mapper-service
namespace: atlas-mapper
labels:
app: atlas-mapper-app
spec:
selector:
app: atlas-mapper-app
ports:
- protocol: TCP
port: 80
targetPort: 8080
type: ClusterIP
---
# k8s/ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: atlas-mapper-ingress
namespace: atlas-mapper
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/rewrite-target: /
nginx.ingress.kubernetes.io/ssl-redirect: "true"
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
tls:
- hosts:
- atlas-mapper.example.com
secretName: atlas-mapper-tls
rules:
- host: atlas-mapper.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: atlas-mapper-service
port:
number: 80
---
# k8s/hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: atlas-mapper-hpa
namespace: atlas-mapper
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: atlas-mapper-app
minReplicas: 3
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
---
# k8s/mysql-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: mysql
namespace: atlas-mapper
spec:
replicas: 1
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql:8.0
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: atlas-mapper-secret
key: mysql-password
- name: MYSQL_DATABASE
value: atlas_mapper
- name: MYSQL_USER
value: atlas
- name: MYSQL_PASSWORD
valueFrom:
secretKeyRef:
name: atlas-mapper-secret
key: mysql-password
ports:
- containerPort: 3306
volumeMounts:
- name: mysql-storage
mountPath: /var/lib/mysql
volumes:
- name: mysql-storage
persistentVolumeClaim:
claimName: mysql-pvc
---
# k8s/mysql-service.yaml
apiVersion: v1
kind: Service
metadata:
name: mysql-service
namespace: atlas-mapper
spec:
selector:
app: mysql
ports:
- protocol: TCP
port: 3306
targetPort: 3306
---
# k8s/mysql-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mysql-pvc
namespace: atlas-mapper
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
---
# k8s/redis-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: redis
namespace: atlas-mapper
spec:
replicas: 1
selector:
matchLabels:
app: redis
template:
metadata:
labels:
app: redis
spec:
containers:
- name: redis
image: redis:6.2-alpine
ports:
- containerPort: 6379
volumeMounts:
- name: redis-storage
mountPath: /data
volumes:
- name: redis-storage
persistentVolumeClaim:
claimName: redis-pvc
---
# k8s/redis-service.yaml
apiVersion: v1
kind: Service
metadata:
name: redis-service
namespace: atlas-mapper
spec:
selector:
app: redis
ports:
- protocol: TCP
port: 6379
targetPort: 6379
---
# k8s/redis-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: redis-pvc
namespace: atlas-mapper
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
#!/bin/bash
# Kubernetes 部署脚本
set -e
# 颜色定义
RED=' 33[0;31m'
GREEN=' 33[0;32m'
YELLOW=' 33[1;33m'
BLUE=' 33[0;34m'
NC=' 33[0m'
log_info() {
echo -e "${BLUE}[INFO]${NC} $1"
}
log_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
log_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# 检查 kubectl 连接
check_kubectl() {
log_info "检查 kubectl 连接..."
if ! command -v kubectl &> /dev/null; then
log_error "kubectl 未安装"
exit 1
fi
if ! kubectl cluster-info &> /dev/null; then
log_error "无法连接到 Kubernetes 集群"
exit 1
fi
log_success "kubectl 连接正常"
}
# 部署应用
deploy() {
log_info "部署 Atlas Mapper 到 Kubernetes..."
# 应用所有配置
kubectl apply -f k8s/
# 等待部署完成
log_info "等待部署完成..."
kubectl wait --for=condition=available --timeout=300s deployment/atlas-mapper-app -n atlas-mapper
kubectl wait --for=condition=available --timeout=300s deployment/mysql -n atlas-mapper
kubectl wait --for=condition=available --timeout=300s deployment/redis -n atlas-mapper
log_success "部署完成"
}
# 检查部署状态
check_status() {
log_info "检查部署状态..."
echo "=== Pods ==="
kubectl get pods -n atlas-mapper
echo -e "n=== Services ==="
kubectl get services -n atlas-mapper
echo -e "n=== Ingress ==="
kubectl get ingress -n atlas-mapper
echo -e "n=== HPA ==="
kubectl get hpa -n atlas-mapper
}
# 查看日志
view_logs() {
local pod_name=$1
if [[ -z $pod_name ]]; then
# 获取第一个应用 Pod
pod_name=$(kubectl get pods -n atlas-mapper -l app=atlas-mapper-app -o jsonpath='{.items[0].metadata.name}')
fi
log_info "查看 Pod 日志: $pod_name"
kubectl logs -f $pod_name -n atlas-mapper
}
# 扩缩容
scale() {
local replicas=${1:-3}
log_info "扩缩容到 $replicas 个副本..."
kubectl scale deployment atlas-mapper-app --replicas=$replicas -n atlas-mapper
# 等待扩缩容完成
kubectl wait --for=condition=available --timeout=300s deployment/atlas-mapper-app -n atlas-mapper
log_success "扩缩容完成"
}
# 滚动更新
rolling_update() {
local image=${1:-"nemoob/atlas-mapper-example:latest"}
log_info "执行滚动更新,镜像: $image"
kubectl set image deployment/atlas-mapper-app atlas-mapper-app=$image -n atlas-mapper
# 等待滚动更新完成
kubectl rollout status deployment/atlas-mapper-app -n atlas-mapper
log_success "滚动更新完成"
}
# 回滚部署
rollback() {
local revision=$1
log_info "回滚部署..."
if [[ -n $revision ]]; then
kubectl rollout undo deployment/atlas-mapper-app --to-revision=$revision -n atlas-mapper
else
kubectl rollout undo deployment/atlas-mapper-app -n atlas-mapper
fi
# 等待回滚完成
kubectl rollout status deployment/atlas-mapper-app -n atlas-mapper
log_success "回滚完成"
}
# 删除部署
delete() {
log_warning "删除 Atlas Mapper 部署..."
read -p "确认删除?(y/N): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
kubectl delete -f k8s/
log_success "删除完成"
else
log_info "取消删除"
fi
}
# 端口转发
port_forward() {
local local_port=${1:-8080}
local remote_port=${2:-80}
# 获取服务名
local service_name="atlas-mapper-service"
log_info "端口转发: localhost:$local_port -> $service_name:$remote_port"
kubectl port-forward service/$service_name $local_port:$remote_port -n atlas-mapper
}
# 执行命令
exec_command() {
local pod_name=$1
shift
local command="$@"
if [[ -z $pod_name ]]; then
# 获取第一个应用 Pod
pod_name=$(kubectl get pods -n atlas-mapper -l app=atlas-mapper-app -o jsonpath='{.items[0].metadata.name}')
fi
log_info "在 Pod $pod_name 中执行命令: $command"
kubectl exec -it $pod_name -n atlas-mapper -- $command
}
# 获取监控指标
get_metrics() {
log_info "获取监控指标..."
# CPU 和内存使用情况
kubectl top pods -n atlas-mapper
# HPA 状态
kubectl get hpa -n atlas-mapper
# 事件
kubectl get events -n atlas-mapper --sort-by='.lastTimestamp'
}
# 健康检查
health_check() {
log_info "执行健康检查..."
# 检查 Pod 状态
local unhealthy_pods=$(kubectl get pods -n atlas-mapper --field-selector=status.phase!=Running -o name)
if [[ -n $unhealthy_pods ]]; then
log_warning "发现不健康的 Pod:"
echo $unhealthy_pods
else
log_success "所有 Pod 运行正常"
fi
# 检查服务端点
kubectl get endpoints -n atlas-mapper
# 检查应用健康状态(通过端口转发)
log_info "检查应用健康状态..."
# 临时端口转发
kubectl port-forward service/atlas-mapper-service 18080:80 -n atlas-mapper &
local pf_pid=$!
sleep 5
if curl -f http://localhost:18080/actuator/health > /dev/null 2>&1; then
log_success "应用健康检查通过"
else
log_error "应用健康检查失败"
fi
# 停止端口转发
kill $pf_pid 2>/dev/null || true
}
# 备份配置
backup_config() {
local backup_dir="./k8s-backups/$(date +%Y%m%d_%H%M%S)"
log_info "备份 Kubernetes 配置到: $backup_dir"
mkdir -p $backup_dir
# 备份所有资源
kubectl get all -n atlas-mapper -o yaml > $backup_dir/all-resources.yaml
kubectl get configmap -n atlas-mapper -o yaml > $backup_dir/configmaps.yaml
kubectl get secret -n atlas-mapper -o yaml > $backup_dir/secrets.yaml
kubectl get pvc -n atlas-mapper -o yaml > $backup_dir/pvcs.yaml
log_success "配置备份完成: $backup_dir"
}
# 显示帮助信息
show_help() {
cat << EOF
Atlas Mapper Kubernetes 部署脚本
用法: $0 [命令] [参数]
命令:
deploy 部署应用到 Kubernetes
status 查看部署状态
logs [pod_name] 查看 Pod 日志
scale [replicas] 扩缩容应用
update [image] 滚动更新应用
rollback [revision] 回滚部署
delete 删除部署
port-forward [local] [remote] 端口转发
exec [pod] [command] 在 Pod 中执行命令
metrics 获取监控指标
health 健康检查
backup 备份配置
help 显示帮助信息
示例:
$0 deploy 部署应用
$0 scale 5 扩容到 5 个副本
$0 update nemoob/atlas-mapper-example:v1.1.0 更新镜像
$0 logs 查看应用日志
$0 port-forward 8080 80 端口转发
$0 health 健康检查
EOF
}
# 主函数
main() {
local command=${1:-"help"}
# 检查 kubectl(除了 help 命令)
if [[ $command != "help" ]]; then
check_kubectl
fi
case $command in
deploy)
deploy
;;
status)
check_status
;;
logs)
view_logs $2
;;
scale)
scale $2
;;
update)
rolling_update $2
;;
rollback)
rollback $2
;;
delete)
delete
;;
port-forward)
port_forward $2 $3
;;
exec)
shift
exec_command "$@"
;;
metrics)
get_metrics
;;
health)
health_check
;;
backup)
backup_config
;;
help|*)
show_help
;;
esac
}
# 执行主函数
main "$@"
# .github/workflows/ci-cd.yml
name: Atlas Mapper CI/CD
on:
push:
branches: [ main, develop ]
tags: [ 'v*' ]
pull_request:
branches: [ main ]
env:
REGISTRY: docker.io
IMAGE_NAME: nemoob/atlas-mapper-example
jobs:
# 代码质量检查
code-quality:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Set up JDK 8
uses: actions/setup-java@v3
with:
java-version: '8'
distribution: 'temurin'
- name: Cache Maven dependencies
uses: actions/cache@v3
with:
path: ~/.m2
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
restore-keys: ${{ runner.os }}-m2
- name: Run code quality checks
run: |
mvn clean compile
mvn checkstyle:check
mvn spotbugs:check
# 单元测试
unit-tests:
runs-on: ubuntu-latest
needs: code-quality
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Set up JDK 8
uses: actions/setup-java@v3
with:
java-version: '8'
distribution: 'temurin'
- name: Cache Maven dependencies
uses: actions/cache@v3
with:
path: ~/.m2
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
restore-keys: ${{ runner.os }}-m2
- name: Run unit tests
run: mvn clean test
- name: Generate test report
uses: dorny/test-reporter@v1
if: success() || failure()
with:
name: Maven Tests
path: '**/target/surefire-reports/*.xml'
reporter: java-junit
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
with:
file: ./target/site/jacoco/jacoco.xml
# 集成测试
integration-tests:
runs-on: ubuntu-latest
needs: unit-tests
services:
mysql:
image: mysql:8.0
env:
MYSQL_ROOT_PASSWORD: atlas123
MYSQL_DATABASE: atlas_mapper_test
MYSQL_USER: atlas
MYSQL_PASSWORD: atlas123
ports:
- 3306:3306
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
redis:
image: redis:6.2-alpine
ports:
- 6379:6379
options: --health-cmd="redis-cli ping" --health-interval=10s --health-timeout=5s --health-retries=3
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Set up JDK 8
uses: actions/setup-java@v3
with:
java-version: '8'
distribution: 'temurin'
- name: Cache Maven dependencies
uses: actions/cache@v3
with:
path: ~/.m2
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
restore-keys: ${{ runner.os }}-m2
- name: Run integration tests
run: mvn clean verify -Dspring.profiles.active=test
env:
MYSQL_URL: jdbc:mysql://localhost:3306/atlas_mapper_test
REDIS_HOST: localhost
# 构建和发布
build-and-publish:
runs-on: ubuntu-latest
needs: [unit-tests, integration-tests]
if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/'))
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Set up JDK 8
uses: actions/setup-java@v3
with:
java-version: '8'
distribution: 'temurin'
- name: Cache Maven dependencies
uses: actions/cache@v3
with:
path: ~/.m2
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
restore-keys: ${{ runner.os }}-m2
- name: Configure Maven settings
uses: s4u/[email protected]
with:
servers: |
[{
"id": "ossrh",
"username": "${{ secrets.OSSRH_USERNAME }}",
"password": "${{ secrets.OSSRH_PASSWORD }}"
}]
- name: Import GPG key
if: startsWith(github.ref, 'refs/tags/')
uses: crazy-max/ghaction-import-gpg@v5
with:
gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
passphrase: ${{ secrets.GPG_PASSPHRASE }}
- name: Build project
run: mvn clean package -DskipTests
- name: Publish snapshot to OSSRH
if: github.ref == 'refs/heads/main'
run: mvn deploy -P snapshot -DskipTests
- name: Publish release to OSSRH
if: startsWith(github.ref, 'refs/tags/')
run: mvn deploy -P release -DskipTests
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Log in to Docker Hub
uses: docker/login-action@v2
with:
registry: ${{ env.REGISTRY }}
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v4
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
- name: Build and push Docker image
uses: docker/build-push-action@v4
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
# 部署到测试环境
deploy-staging:
runs-on: ubuntu-latest
needs: build-and-publish
if: github.ref == 'refs/heads/main'
environment: staging
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Configure kubectl
uses: azure/k8s-set-context@v3
with:
method: kubeconfig
kubeconfig: ${{ secrets.KUBE_CONFIG_STAGING }}
- name: Deploy to staging
run: |
sed -i 's|nemoob/atlas-mapper-example:latest|nemoob/atlas-mapper-example:main|g' k8s/deployment.yaml
kubectl apply -f k8s/ -n atlas-mapper-staging
kubectl rollout status deployment/atlas-mapper-app -n atlas-mapper-staging
- name: Run smoke tests
run: |
kubectl port-forward service/atlas-mapper-service 18080:80 -n atlas-mapper-staging &
sleep 10
curl -f http://localhost:18080/actuator/health
curl -f http://localhost:18080/api/users/1/dto
# 部署到生产环境
deploy-production:
runs-on: ubuntu-latest
needs: build-and-publish
if: startsWith(github.ref, 'refs/tags/')
environment: production
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Configure kubectl
uses: azure/k8s-set-context@v3
with:
method: kubeconfig
kubeconfig: ${{ secrets.KUBE_CONFIG_PRODUCTION }}
- name: Extract version
id: version
run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT
- name: Deploy to production
run: |
sed -i 's|nemoob/atlas-mapper-example:latest|nemoob/atlas-mapper-example:${{ steps.version.outputs.VERSION }}|g' k8s/deployment.yaml
kubectl apply -f k8s/ -n atlas-mapper-production
kubectl rollout status deployment/atlas-mapper-app -n atlas-mapper-production
- name: Run production tests
run: |
kubectl port-forward service/atlas-mapper-service 18080:80 -n atlas-mapper-production &
sleep 10
curl -f http://localhost:18080/actuator/health
# 安全扫描
security-scan:
runs-on: ubuntu-latest
needs: build-and-publish
steps:
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
image-ref: '${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:main'
format: 'sarif'
output: 'trivy-results.sarif'
- name: Upload Trivy scan results to GitHub Security tab
uses: github/codeql-action/upload-sarif@v2
with:
sarif_file: 'trivy-results.sarif'
# 性能测试
performance-test:
runs-on: ubuntu-latest
needs: deploy-staging
if: github.ref == 'refs/heads/main'
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Run performance tests
run: |
# 这里可以集成 JMeter、K6 或其他性能测试工具
echo "Running performance tests..."
# 示例:使用 curl 进行简单的性能测试
for i in {1..100}; do
curl -s http://staging.atlas-mapper.example.com/api/users/1/dto > /dev/null
done
# 通知
notify:
runs-on: ubuntu-latest
needs: [deploy-staging, deploy-production]
if: always()
steps:
- name: Notify Slack
uses: 8398a7/action-slack@v3
with:
status: ${{ job.status }}
channel: '#atlas-mapper'
webhook_url: ${{ secrets.SLACK_WEBHOOK }}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }}
# 1. 本地开发和测试
git clone https://github.com/nemoob/atlas-mapper.git
cd atlas-mapper
mvn clean test
# 2. 构建和打包
./scripts/release.sh snapshot
# 3. Docker 构建和测试
./scripts/docker-deploy.sh build 1.0.0
./scripts/docker-deploy.sh start
./scripts/docker-deploy.sh test
# 4. 推送到镜像仓库
./scripts/docker-deploy.sh push docker.io 1.0.0
# 5. 部署到 Kubernetes
./scripts/k8s-deploy.sh deploy
./scripts/k8s-deploy.sh health
# 6. 监控和维护
./scripts/k8s-deploy.sh metrics
./scripts/k8s-deploy.sh logs
# 1. 准备发布
git checkout main
git pull origin main
# 2. 执行发布
./scripts/release.sh release
# 3. 验证发布
curl -s https://repo1.maven.org/maven2/io/github/nemoob/atlas-mapper-core/1.0.0/
# 4. 部署到生产环境
git tag v1.0.0
git push origin v1.0.0
# GitHub Actions 会自动触发生产部署
# 查看应用状态
kubectl get pods -n atlas-mapper-production
# 查看监控指标
curl http://grafana.atlas-mapper.example.com/d/atlas-mapper
# 查看日志
kubectl logs -f deployment/atlas-mapper-app -n atlas-mapper-production
# 扩容应用
./scripts/k8s-deploy.sh scale 5
# 滚动更新
./scripts/k8s-deploy.sh update nemoob/atlas-mapper-example:1.0.1
A: 检查以下配置:
# 1. 检查 GPG 签名
gpg --list-secret-keys --keyid-format LONG
# 2. 检查 OSSRH 账号
curl -u username:password https://s01.oss.sonatype.org/service/local/staging/profiles
# 3. 检查 POM 配置
mvn help:effective-pom | grep -A 10 distributionManagement
# 4. 手动发布测试
mvn clean deploy -P release -DskipTests
A: 常见问题和解决方案:
# 1. 检查 Dockerfile 语法
docker build --no-cache -t test .
# 2. 检查基础镜像
docker pull openjdk:8-jre-alpine
# 3. 检查构建上下文
echo "target/" >> .dockerignore
echo ".git/" >> .dockerignore
# 4. 多阶段构建优化
# 确保构建阶段和运行阶段分离
A: 故障排查步骤:
# 1. 检查 Pod 状态
kubectl describe pod <pod-name> -n atlas-mapper
# 2. 查看事件
kubectl get events -n atlas-mapper --sort-by='.lastTimestamp'
# 3. 检查资源限制
kubectl top pods -n atlas-mapper
# 4. 检查配置
kubectl get configmap atlas-mapper-config -n atlas-mapper -o yaml
# 5. 检查网络
kubectl exec -it <pod-name> -n atlas-mapper -- nslookup mysql-service
A: 性能优化策略:
# 1. JVM 参数调优
JAVA_OPTS="-Xms1g -Xmx2g -XX:+UseG1GC -XX:MaxGCPauseMillis=200"
# 2. 应用层优化
# - 启用缓存
# - 使用连接池
# - 优化数据库查询
# 3. Kubernetes 资源优化
# - 调整 CPU/内存限制
# - 配置 HPA
# - 使用节点亲和性
# 4. 监控和分析
# - 使用 APM 工具
# - 分析 GC 日志
# - 监控业务指标
通过本章学习,你应该掌握了:
恭喜你完成了 Atlas Mapper 的全部 10 篇教程!你现在已经掌握了:
175M · 2025-09-17
302M · 2025-09-17
318M · 2025-09-17