Files
life-echo/.github/workflows/README.md

326 lines
9.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# GitHub Actions CI/CD 工作流配置说明
## 工作流列表
| 工作流 | 说明 | 文档 |
|--------|------|------|
| Docker Build and Deploy | API 镜像构建与部署 | 见下文 |
| Android Release Build | Android APK 构建与发布 | 见下文 |
| App Expo Deploy | app-expo Web 构建与发布 | [docs/app-expo-deploy.md](../../docs/app-expo-deploy.md) |
---
## 概述
本工作流实现了自动化的 Docker 镜像构建和部署流程:
1. **构建阶段**:当代码推送到指定分支时,自动构建 Docker 镜像
2. **推送阶段**将构建好的镜像推送到阿里云容器镜像服务ACR
3. **部署阶段**:通过 SSH 连接到远程服务器,拉取最新镜像并重建容器
## 工作流触发条件
- 推送到 `main``master``develop` 分支
- 仅当 `api/` 目录或 `.github/workflows/` 目录有变更时触发
- 支持手动触发workflow_dispatch
## 配置步骤
### 1. 配置 GitHub Secrets
在 GitHub 仓库设置中添加以下 Secrets
#### 必需配置
- **SSH_PRIVATE_KEY**: SSH 私钥,用于连接到远程服务器
```bash
# 生成 SSH 密钥对(如果还没有)
ssh-keygen -t ed25519 -C "github-actions"
# 将私钥添加到 GitHub Secrets
cat ~/.ssh/id_ed25519 # 复制内容到 SSH_PRIVATE_KEY
# 将公钥添加到远程服务器的 ~/.ssh/authorized_keys
cat ~/.ssh/id_ed25519.pub | ssh user@your-server "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"
```
- **SSH_USER**: SSH 用户名(例如:`root`、`ubuntu`、`deploy`
- **SSH_HOST**: 远程服务器 IP 地址或域名(例如:`192.168.1.100`、`example.com`
#### 阿里云容器镜像服务配置(必需)
- **ALIYUN_CR_USERNAME**: 阿里云容器镜像服务用户名(例如:`zaikunxu`
- **ALIYUN_CR_PASSWORD**: 阿里云容器镜像服务密码
#### 可选配置
- **SSH_PORT**: SSH 端口(默认:`22`
- **DEPLOY_PATH**: 远程服务器上的部署目录(默认:`/opt/life-echo`
### 2. 容器镜像仓库配置
本工作流使用**阿里云容器镜像服务ACR**作为镜像仓库。
#### 镜像地址
- 镜像仓库地址:`crpi-u2903xccyzd6nqnc.cn-shanghai.personal.cr.aliyuncs.com`
- 命名空间:`huaga`
- 镜像名称:`lifecho-api`
- 完整镜像路径:`crpi-u2903xccyzd6nqnc.cn-shanghai.personal.cr.aliyuncs.com/huaga/lifecho-api:latest`
#### 配置说明
工作流已配置为使用阿里云容器镜像服务,无需修改工作流文件。只需在 GitHub Secrets 中配置:
- `ALIYUN_CR_USERNAME`: 阿里云容器镜像服务用户名
- `ALIYUN_CR_PASSWORD`: 阿里云容器镜像服务密码
#### 在远程服务器上配置 Docker 登录
确保远程服务器可以拉取私有镜像,需要在远程服务器上执行:
```bash
docker login crpi-u2903xccyzd6nqnc.cn-shanghai.personal.cr.aliyuncs.com \
--username=zaikunxu \
--password=57ucV,g4LF2cqm8
```
或者将登录信息添加到工作流的部署步骤中(已自动配置)。
### 3. 远程服务器准备
确保远程服务器已安装:
- Docker
- Docker Compose
```bash
# 安装 DockerUbuntu/Debian
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
# 安装 Docker Compose
sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
```
### 4. 首次部署准备
在远程服务器上创建部署目录:
```bash
mkdir -p /opt/life-echo/api
```
确保 SSH 用户可以访问该目录并执行 Docker 命令。
## 工作流执行流程
### 构建阶段build-and-push
1. 检出代码
2. 设置 Docker Buildx
3. 登录到容器镜像仓库
4. 提取元数据(标签、标签)
5. 构建并推送 Docker 镜像
### 部署阶段deploy
1. 设置 SSH 连接
2. 登录到容器镜像仓库(在远程服务器上)
3. 拉取最新镜像
4. 停止现有容器
5. 更新 docker-compose.yml 中的镜像标签
6. 启动新容器
7. 清理旧镜像
8. 验证部署状态
## 镜像标签规则
- `main`/`master` 分支 → `latest`
- 其他分支 → 使用分支名作为标签
- 同时会生成基于 commit SHA 的标签
## 故障排查
### 1. SSH 连接失败
- 检查 `SSH_PRIVATE_KEY` 是否正确配置
- 确认远程服务器的 SSH 服务正在运行
- 验证 SSH 公钥已添加到远程服务器的 `~/.ssh/authorized_keys`
### 2. Docker 登录失败
- 检查 `ALIYUN_CR_USERNAME` 和 `ALIYUN_CR_PASSWORD` 是否正确配置
- 确认阿里云容器镜像服务的账号密码是否正确
- 检查远程服务器是否可以访问阿里云容器镜像服务
### 3. 镜像拉取失败
- 确认远程服务器可以访问容器镜像仓库
- 检查镜像标签是否正确
- 验证网络连接
### 4. 容器启动失败
- 检查 docker-compose.yml 文件是否正确
- 查看容器日志:`docker-compose logs`
- 确认环境变量配置正确
## 手动触发
可以通过 GitHub Actions 界面手动触发工作流:
1. 进入仓库的 Actions 标签页
2. 选择 "Docker Build and Deploy" 工作流
3. 点击 "Run workflow" 按钮
## 自定义配置
### 修改触发分支
编辑 `.github/workflows/docker-build-deploy.yml`
```yaml
on:
push:
branches:
- your-branch-name
```
### 修改镜像名称
编辑工作流文件中的 `IMAGE_NAME` 和 `REGISTRY_NAMESPACE` 环境变量:
```yaml
env:
IMAGE_NAME: your-image-name
REGISTRY_NAMESPACE: your-namespace
```
### 修改部署路径
在 GitHub Secrets 中设置 `DEPLOY_PATH`,或直接修改工作流文件中的默认值。
## 注意事项
1. **安全性**:确保 SSH 私钥和密码等敏感信息只存储在 GitHub Secrets 中,不要提交到代码仓库
2. **权限**:确保 SSH 用户在远程服务器上有执行 Docker 命令的权限
3. **备份**:部署前会自动备份 docker-compose.yml 文件(`.bak` 后缀)
4. **回滚**:如果部署失败,可以使用备份文件恢复
## 相关文件
- 工作流文件:`.github/workflows/docker-build-deploy.yml`
- Dockerfile`api/Dockerfile`
- Docker Compose`api/docker-compose.yml`
---
# Android Release 工作流
## 概述
自动构建生产环境签名 APK 并发布到 GitHub Releases
1. **构建阶段**:编译 Release APK使用生产签名配置
2. **发布阶段**:创建 GitHub Release将 APK 作为附件上传
## 工作流触发条件
- **Tag 推送**:推送 `v*` 格式的标签时自动触发(如 `v1.0.0`、`v1.2.3-beta`
- **手动触发**:通过 GitHub Actions 界面手动触发,可选指定版本号
## 配置步骤
### 1. 配置 GitHub Secrets
在 GitHub 仓库设置中添加以下 Secrets
| Secret | 说明 | 示例 |
|--------|------|------|
| `ANDROID_KEYSTORE_BASE64` | keystore 文件的 Base64 编码 | 见下方生成方法 |
| `ANDROID_KEY_ALIAS` | 密钥别名 | `suiyueshishu` |
| `ANDROID_KEY_PASSWORD` | 密钥密码 | |
| `ANDROID_STORE_PASSWORD` | keystore 密码 | |
#### 生成 ANDROID_KEYSTORE_BASE64
```bash
# 在本地项目 app-android 目录下执行
base64 -i release-keystore.jks | pbcopy # macOS结果已复制到剪贴板
# Linux
base64 -w 0 release-keystore.jks
```
将输出内容粘贴到 GitHub Secrets 的 `ANDROID_KEYSTORE_BASE64` 中。
### 2. 版本号管理
- **Tag 触发**:从 tag 名自动提取版本号(如 `v1.0.0` → `versionName = "1.0.0"`
- **手动触发**:使用输入的 `version_name`,或使用 `build.gradle.kts` 中的默认值
- **versionCode**:自动使用 `GITHUB_RUN_NUMBER` 递增
### 3. 发布流程
#### 方式一:通过 Tag 自动发布
```bash
# 打标签并推送
git tag v1.0.0
git push origin v1.0.0
# 或者一步完成
git tag v1.0.0 && git push origin v1.0.0
```
工作流将自动:
1. 构建签名 Release APK
2. 上传 APK 为 GitHub Artifact
3. 创建 GitHub Release附带 APK 和自动生成的更新日志)
#### 方式二:手动触发
1. 进入仓库的 Actions 标签页
2. 选择 "Android Release Build" 工作流
3. 点击 "Run workflow" 按钮
4. (可选)填写版本号
5. 点击 "Run workflow"
手动触发时仅构建 APK 并上传为 Artifact不会创建 GitHub Release。
## 工作流执行流程
1. 检出代码(完整历史)
2. 确定版本号Tag / 手动输入 / build.gradle.kts 默认值)
3. 设置 JDK 17 + Gradle 缓存
4. 解码签名 keystore + 生成 keystore.properties
5. 覆盖 build.gradle.kts 中的版本号
6. 执行 `./gradlew assembleRelease`
7. 上传 APK 为 Artifact保留 30 天)
8. Tag 触发时)生成 Release Notes 并创建 GitHub Release
## APK 命名规则
APK 文件命名格式:`岁月时书_v{版本号}_release.apk`
示例:`岁月时书_v1.0.0_release.apk`
## 故障排查
### 1. 签名失败
- 检查 `ANDROID_KEYSTORE_BASE64` 是否正确生成(不能有换行或空格)
- 确认 `ANDROID_KEY_ALIAS`、`ANDROID_KEY_PASSWORD`、`ANDROID_STORE_PASSWORD` 与 keystore 匹配
### 2. 构建失败
- 检查 Actions 日志中的 Gradle 错误输出
- 确认本地 `./gradlew assembleRelease` 可以成功
### 3. Release 创建失败
- 确认工作流有 `contents: write` 权限
- 检查 Tag 名称是否以 `v` 开头