Config 工程化的灵感是来自于澳洲体育视频项目,他们的 Remote Config 工程化做的非常好,它分为两大类 Config 和 Storage,然后用 CircleCI 来自动化处理 Config 的更新和 Storage 的文件上传,是由运维人员来实现的,具体实现细节不是很清楚,所以这里我们来实现一个基于 Python 的 Config 工程化的案例。
最初方案
经过一番搜索我们得到一个接近的方案,具体可参考 这里,链接里提供了三个文件
1 2 3
| cd.yaml // 主要放在项目根目录下的 ".github/workflows/"下 用于当 git push 时自动发布 config_manage.py // Python 可执行文件 requirement.txt // 根据txt文件里的声明通过 pip 安装依赖
|
下面我们依次对这三个文件进行说明
cd.yaml:
1 2 3 4 5 6 7 8 9
| Build阶段: 1.安装Python,版本是 3.8 2.把requirement.txt文件设置到缓存 3.安装requirement.txt里声明的依赖 发布阶段: 需要Build阶段执行完后再执行 1.安装Python,版本是 3.8 2.安装requirement.txt里声明的依赖 3.把PROJECT_ID和CREDENTIALS设置到环境变量并运行config_manage.py 的publish方法
|
config_manage.py:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| ... def _get_access_token(): // 根据oauth2client库的api和环境变量里的凭证去获取 access token ...
def _get(save=False): // 通过requests库用access token获取Remote Config并写入本地config.json文件 ...
def _listVersions(): // 通过requests库用access token获取Remote Config最近修改的5个版本号 ...
def _rollback(version): // 通过requests库用access token撤回Remote Config到指定版本 ...
def _publish(): // 把本地"remoteconfig.template.json"的内容push到远程 ...
def main(): //通过接受的参数执行相应的方法 ...
|
requirement.txt:
1 2 3
| oauth2client // Google获取授权的python库 requests // 用于进行Api请求 python-dotenv // 用户获取系统变量里的值
|
这个方案并不能解决我们的实际需求,config_manage.py 里的方法相对比较单一,但是给了我们方向,增大了我们方案实现可行性
改造实现
经过我们的改造,工程的目录结构如下:
1 2 3 4 5 6 7 8 9 10 11
| config-example ├── .github │ └── workflows │ └── deploy.yaml // Github Actions 配置文件 ├── remote_config │ └── configs.json // 各种Remote Config的json文件 ├── storage │ └── files // 需要上传到Firebase Storage的文件 ├── remoteconfig.template.json ├── config_manage.py └── requirement.txt
|
对于config_manage.py
文件我们增加一个validation()
方法并改造publish()
以满足我们的需求
config_manage.py:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| ...
def _validation(): 1.调用_get()方法并把ETag缓存起来 2.扫描remote_config目录,把多个json文件合并成符合Remote Config规则的remoteconfig.template.json文件 3.使用requests库调用 validate api 来验证remoteconfig.template.json文件是否符合Remote Config规则 ...
def _publish(): 1.调用_validation()方法检查json文件 2.使用requests库把"remoteconfig.template.json"的内容push到远程 ...
def main(): //通过接受的参数执行相应的方法 ...
|
我们这里也修改了 deploy 的触发条件,改为pull_request
的时候触发,也就是在pull_request
时,会自动发布。
后续优化
由于每次发布 config 都需要 PR,当一个人开发时还是比较繁琐,这里我们 copy 一份config_manage.py
命名为config_manage_local.py
,并把 Firebase 工程的account.json
放到本地,然后在config_manage_local.py
里修改 PROJECT_ID 和 credentials 的读取方式,这样就可以在命令行里直接发布 Remote Config。
最后工程目录结构如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| config-example ├── .github │ └── workflows │ └── deploy.yaml // Github Actions 配置文件 ├── account_key // 把当前目录加入.gitignore,防止上传到Github │ └── account.json ├── remote_config │ └── configs.json // 各种Remote Config的json文件 ├── storage │ └── files // 需要上传到Firebase Storage的文件 ├── remoteconfig.template.json ├── config_manage.py ├── config_manage_local.py └── requirement.txt
|
跟之前项目的 Config 工程相比,我们的工程化更加灵活,Conbine jsons to template 的逻辑还可以根据后期的需求进行调整。
Firebase Storage 的 Deploy
Firebase Sotrage 文件上传就很简单了,只需要在.github/workflows/
定义 yaml 文件,具体如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| name: Upload files to Cloud Storage
on: pull_request: branches: - deploy/uat-storage - deploy/prod-storage
jobs: upload: runs-on: ubuntu-latest
permissions: contents: 'read' id-token: 'write' steps: - id: 'checkout' uses: 'actions/checkout@v3'
- id: 'auth' uses: 'google-github-actions/auth@v1' with: credentials_json: ${{ secrets.CREDENTIALS }}
- id: 'upload-folder' uses: 'google-github-actions/upload-cloud-storage@v1' with: path: './storage' destination: '这里填写你的Bucket' process_gcloudignore: false
|
到这里 Firebase Remote Config 和 Storage 的工程化就完成了,后续会考虑把 storage 里的文件部署到 Amazon S3,应该只需要添加一个 yaml 文件即可。