自动化部署的艺术:用 GitHub Action 部署 Python 编写的 Chalice 应用到 AWS Lambda

缘起

大家好,我是老杨。在这篇文章中,我将带大家深入了解如何利用 GitHub Action 自动化部署 Chalice 应用到 AWS Lambda。这不仅是一个技术实践,也是对 CI/CD 流程优化的一次探索。

在现代软件开发中,快速迭代和持续部署是提高开发效率的关键。Chalice 是一个用于部署 Python 应用到 AWS Lambda 的框架,而 GitHub Action 提供了一个强大的自动化平台。结合这两者,我们可以创建一个无缝的部署流程。

Chalice 简介

Chalice 是一个 Python 框架,它使得在 AWS Lambda 和 API Gateway 上部署无服务器应用变得简单。它允许开发者使用熟悉的 Python 语法来定义 Lambda 函数和 RESTful API,同时提供了丰富的配置选项来满足不同的部署需求。

GitHub Action 工作流详解

让我们来看一下这个工作流的核心内容。以下是一个简化的工作流文件示例,它展示了如何配置和执行部署任务。

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
name: Deploy xxxxx-indexer manually using Chalice
run-name: Deploy xxxxx-indexer ${{ inputs.branch }}->${{ inputs.environment }} by @${{ github.actor }}

on:
workflow_dispatch:
inputs:
branch:
description: 'Branch to deploy'
required: true
default: 'v1.1'
environment:
description: 'Deployment environment'
required: true
default: 'dev'
type: choice
options:
- prod
- dev

env:
env_vars: '{"prod": "1111", "dev": "2222"}'
project_directory: 'xxxx-indexer'

jobs:
deploy-job:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4
with:
token: ${{ secrets.TOKEN_CICD }}
ref: ${{ github.event.inputs.branch }}
sparse-checkout: ${{ env.project_directory }}
sparse-checkout-cone-mode: false

- name: Delete configuration files for chalice
run: |
[[ -e ${{ env.project_directory }}/.chalice ]] && \
rm -rf ${{ env.project_directory }}/.chalice

- name: Checkout configuration files for CI/CD
uses: actions/checkout@v4
with:
repository: xxxx-xxxx/CICD
token: ${{ secrets.TOKEN_CICD }}
ref: main
sparse-checkout: chalice/${{ env.project_directory }}
sparse-checkout-cone-mode: false
path: config-chalice

- name: Make a symbolic(soft) link
run: |
ln -srv \
config-chalice/chalice/${{ env.project_directory }}/.chalice \
${{ env.project_directory }}/
echo "after checkout CI/CD:"
ls -lRa ${{ env.project_directory }}

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.9'

- uses: actions/cache@v4
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
restore-keys: |
${{ runner.os }}-pip-

- name: Install dependencies
run: |
cd ${{ env.project_directory }}
pip install -r requirements.txt
pip install chalice

- name: Prepare the .chalice/config.json
run: |
cd ${{ env.project_directory }}
sed -e "s:___GH-REF___:${{ github.event.inputs.branch }}:g" \
-e "s/___GH-COMMIT-ID___/$(git log -1 --format='%H')/g" \
-e "s/___DBPASSWORD___/${{ secrets[format('DB_PWD_{0}', fromJson(env.env_vars)[github.event.inputs.environment])] }}/g" \
-e "s:___GH-REPOSITORY___:${{ github.repository }}:g" \
-e "s:___GH-DIRECTORY___:${{ env.project_directory }}:g" \
-i .chalice/config.json
echo "the content of file .chalice/config.json:"
cat .chalice/config.json

- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-region: ${{ vars[format('AWS_REGION_{0}', fromJson(env.env_vars)[github.event.inputs.environment])] }}
aws-access-key-id: ${{ secrets[format('AWS_ACCESS_KEY_ID_{0}', fromJson(env.env_vars)[github.event.inputs.environment])] }}
aws-secret-access-key: ${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', fromJson(env.env_vars)[github.event.inputs.environment])] }}

- name: Deploy Chalice
id: deploy-step
run: |
cd ${{ env.project_directory }}
chalice deploy --stage ${{ github.event.inputs.environment }}

- name: Check for files changed
id: git_status
run: |
cd config-chalice/chalice/${{ env.project_directory }}/.chalice
git status -s
file_changed=$(if git status -s | grep -q "deployed/${{ github.event.inputs.environment }}.json"; then echo 'true'; else echo 'false'; fi)
echo "changed=${file_changed}" >> $GITHUB_OUTPUT

- name: Commit and push changes
if: ${{ steps.git_status.outputs.changed == 'true' }}
run: |
cd config-chalice/chalice/${{ env.project_directory }}/.chalice
git config --local user.email "[email protected]"
git config --local user.name "contact-xxx"
git config --local pull.rebase false
git add deployed/${{ github.event.inputs.environment }}.json
git commit -m "Update deployed files at $(date)"
git pull
git push

在这个工作流中,我们定义了两个输入参数:branchenvironment。这允许我们在启动工作流时指定要部署的分支和环境。我们还设置了环境变量,这些变量在部署过程中会被用来配置应用。

接下来,工作流会检出指定分支的代码,删除现有的 Chalice 配置文件,并从 CI/CD 仓库中检出新的配置。然后,我们设置 Python 环境,安装依赖,准备配置文件,并配置 AWS 凭证。最后,我们执行 Chalice 部署命令,将应用部署到 AWS Lambda。

GitHub Action 缓存功能

在我们的工作流中,actions/cache 用于缓存 Python 的 pip 依赖。这可以显著提高后续部署的效率,因为依赖项不需要每次都重新下载。缓存的键是基于操作系统和依赖文件的哈希值,这确保了缓存的一致性和可恢复性。

CI/CD 仓库中的 JSON 文件推送

在部署完成后,Chalice 生成的 JSON 文件包含了部署的详细信息。将这个文件推送回 CI/CD 仓库有助于我们跟踪部署历史,管理配置,并在必要时进行回滚。这是一种确保部署过程透明和可审计的重要实践。

结语

通过这个详细的 GitHub Action 工作流,我们实现了 Chalice 应用的自动化部署。这个过程不仅简化了部署步骤,还提高了部署的可靠性。我希望这篇文章能够帮助你更好地理解如何利用 GitHub Action 来优化你的 CI/CD 流程。

如果你有任何问题,或者想要了解更多关于这个话题的信息,欢迎留言讨论。别忘了点赞和分享哦!