关于GitHub Actions和Terraform {#%E5%85%B3%E4%BA%8Egithub-actions%E5%92%8Cterraform}
GitHub Actions 是 GitHub 提供的一个强大而灵活的自动化工具,能够帮助开发者实现持续集成(CI)和持续交付/部署(CD)流水线。它能够让开发者在代码库的不同阶段(如代码提交、拉取请求、发布等)自动触发构建、测试、部署等任务。借助 GitHub Actions,开发者可以通过自定义的 YAML 文件定义工作流,实现从代码提交到应用发布的全自动化过程。
Terraform是目前最热门的基础设施即代码工具,它能够以脚本的形式定义基础设施配置,这极大地增强了基础设施的可复用性,并且可以更好的同CI/CD流水线集成。
GitHub Actions的优势 {#github-actions%E7%9A%84%E4%BC%98%E5%8A%BF}
深度集成:GitHub Actions 与 GitHub 仓库无缝集成,可以根据事件自动触发工作流,适用于各类开发项目。
灵活性高:支持高度自定义的工作流,开发者可以根据不同的项目需求,灵活地配置不同的任务、条件和依赖
生态系统丰富:GitHub Marketplace 提供了数千个现成的 Actions(如容器部署、测试工具、CI/CD 任务等),开发者可以方便地复用已有组件,减少重复工作。
并行化任务执行:GitHub Actions 可以让多个任务并行运行,提升 CI/CD 的效率,适应大型项目的复杂需求。
可扩展性强: GitHub actions可以与主流云计算平台相结合,实现无缝的云部署。
实践:通过GitHub Actions实现自动化构建docker镜像并部署到Azure Kubernetes上
使用Terraform创建Azure Kubernetes集群和Container Registry镜像存储库 {#%E4%BD%BF%E7%94%A8terraform%E5%88%9B%E5%BB%BAazure-kubernetes%E9%9B%86%E7%BE%A4%E5%92%8Ccontainer-registry%E9%95%9C%E5%83%8F%E5%AD%98%E5%82%A8%E5%BA%93}
编写Shell脚本 {#%E7%BC%96%E5%86%99shell%E8%84%9A%E6%9C%AC}
GitHub Actions会使用Linux环境执行Workflow中的操作,因此将所有涉及到的命令拆分为多个Shell脚本效率更高,也更便于修改。
构建镜像脚本 {#%E6%9E%84%E5%BB%BA%E9%95%9C%E5%83%8F%E8%84%9A%E6%9C%AC}
set -u
: $CONTAINER_REGISTRY
: $VERSION
docker build -t $CONTAINER_REGISTRY/book-catalog:$VERSION --file ./book_catalog/Dockerfile .
docker build -t $CONTAINER_REGISTRY/inventory:$VERSION --file ./inventory_management/Dockerfile .
</code>
</pre>
#### 推送镜像脚本 {#%E6%8E%A8%E9%80%81%E9%95%9C%E5%83%8F%E8%84%9A%E6%9C%AC}
`````````bash
set -u
: "$CONTAINER_REGISTRY"
: "$VERSION"
: "$REGISTRY_UN"
: "$REGISTRY_PW"
echo $REGISTRY_PW \| docker login $CONTAINER_REGISTRY --username $REGISTRY_UN --password-stdin
docker push $CONTAINER_REGISTRY/book-catalog:$VERSION
docker push $CONTAINER_REGISTRY/inventory:$VERSION
</code>
</pre>
#### 部署脚本 {#%E9%83%A8%E7%BD%B2%E8%84%9A%E6%9C%AC}
````````bash
set -u
: "$CONTAINER_REGISTRY"
: "$VERSION"
: "$DB_URL"
envsubst \< ./scripts/kubernetes/configmap.yaml \| kubectl apply -f -
envsubst \< ./scripts/kubernetes/service.yaml \| kubectl apply -f -
envsubst \< ./scripts/kubernetes/deployment.yaml \| kubectl apply -f -
</code>
</pre>
其中 ` envsubst ` 命令能将后面文件中的环境变量占位符替换为当前环境中的实际值。
#### 删除脚本 {#%E5%88%A0%E9%99%A4%E8%84%9A%E6%9C%AC}
```````bash
set -u
: "$CONTAINER_REGISTRY"
: "$VERSION"
: "$DB_URL"
envsubst \< ./scripts/kubernetes/deployment.yaml \| kubectl delete -f -
envsubst \< ./scripts/kubernetes/service.yaml \| kubectl delete -f -
envsubst \< ./scripts/kubernetes/configmap.yaml \| kubectl delete -f -
</code>
</pre>
### 编写GitHub workflow配置 {#%E7%BC%96%E5%86%99github-workflow%E9%85%8D%E7%BD%AE}
#### Apply terraform yaml {#apply-terraform-yaml}
在编写配置之前,需要做一些准备工作
* 创建Azure服务主体
Azure服务主体包含了一些数据,如CLIENT_ID,CLIENT_SECRET和TENANT_ID,这些数据可以用来免交互登录Azure。使用如下命令:
``````bash
az ad sp create-for-rbac --name <服务主体名称> --role Owner --scopes /subscriptions/<你的subscriptions ID> --sdk-auth
</code>
</pre>
该命令执行成功后会生成一个Json文件,保存好该文件
* 为GitHub账户创建Personal access tokens
该字符可以让GitHub Actions执行器访问GitHub仓库中的secrets并设置。
https://github.com/settings/tokens?ref=blog.freelytomorrow.com
* 编写Workflow配置
`````yaml
name: Terraform Apply
# 仅限手动构建,如果使用branches关键字,可以指定当代码被推送到对应分支是触发自动构建
on:
workflow_dispatch:
jobs:
terraform:
name: Terraform apply
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v3
- name: Set up Terraform
uses: hashicorp/setup-terraform@v2
with:
terraform_version: 1.5.6
# 使用之前生成的服务主体数据
- name: Azure Login
run: az login --service-principal -u ${{ secrets.CLIENT_ID }} -p ${{ secrets.CLIENT_SECRET }} --tenant ${{ secrets.TENANT_ID }}
- name: Terraform Init
working-directory: ./scripts/terraform
run: terraform init
# ${{ vars.AZURE_RESOURCE_NAME }}等变量保存在GitHub仓库中的Repository variables列表下,由于这些内容并非机密数据,因此不必设置为secrets
# 这些变量指定的Terraform资源所使用的资源组名,位置,K8s集群和容器注册表名称以及K8s版本
- name: Terraform Apply
working-directory: ./scripts/terraform
run: terraform apply -auto-approve -var "resource_group_name=${{ vars.AZURE_RESOURCE_NAME }}" -var "location=${{ vars.AZURE_RESOURCE_LOCATION }}" -var "app_name=${{ vars.APP_NAME }}" -var "kubernetes_version=${{ vars.AZURE_AKS_VERSION }}"
continue-on-error: true
# 安装后续操作所需的依赖,其中gh为GitHub-Cli,jq用来过滤Json数据
- name: Install dependencies
run: |
sudo apt install gh -y
sudo apt install jq -y
# 这里的Token是先前创建的Personal access tokens
- name: GitHub-Cli login
run: |
echo "${{ secrets.TOKEN }}" | gh auth login --with-token
# 刷新Terraform状态
- name: Refresh terraform state
run: terraform refresh
# 通过gh命令设置Secrets
- name: Set Secrets
run: |
acr_name=$(az acr list | jq -r '.[0].loginServer')
gh secret set CONTAINER_REGISTRY --body "$acr_name"
az acr credential show --name "$acr_name" --query "{username:username, passwords:passwords[0].value}" --output json > credentials.json
gh secret set REGISTRY_UN --body "$(cat credentials.json | jq -r '.username')"
gh secret set REGISTRY_PW --body "$(cat credentials.json | jq -r '.passwords')"
az aks get-credentials --resource-group ${{ vars.AZURE_RESOURCE_NAME }} --name ${{ vars.APP_NAME }}
gh secret set KUBE_CONFIG --body "$(cat ~/.kube/config | base64 -w 0)"
</code>
</pre>
#### Deploy Microservice yaml {#deploy-microservice-yaml}
````yaml
name: Deploy microservice
on:
workflow_dispatch:
将要运行的任务
=======
jobs:
deploy:
runs-on: ubuntu-latest
# 环境变量,这些变量在仓库的secrets中声明和配置
env:
VERSION: ${{ github.sha }}
CONTAINER_REGISTRY: ${{ secrets.CONTAINER_REGISTRY }}
REGISTRY_UN: ${{ secrets.REGISTRY_UN }}
REGISTRY_PW: ${{ secrets.REGISTRY_PW }}
DB_URL: ${{ secrets.DB_URL }}
# 具体的任务步骤
steps:
# actions/checkout:GitHub 官方提供的一个标准 Action,用来将代码库的当前版本拉取到虚拟机或容器中。
- uses: actions/checkout@v3
- name: Build images
run: bash ./scripts/build-image.sh
- name: Push image
run: bash ./scripts/push-image.sh
# tale/kubectl-action:一个第三方 Action,用于在 GitHub Actions 工作流中执行 kubectl 命令,管理 Kubernetes 集群
- uses: tale/kubectl-action@v1
with:
# 经过 base64 编码的 Kubernetes 配置文件
base64-kube-config: ${{ secrets.KUBE_CONFIG }}
# 指定 kubectl 的版本号
kubectl-version: v1.30.3
- name: Deploy
run: bash ./scripts/deploy.sh
</code>
</pre>
#### Delete Microservice yaml {#delete-microservice-yaml}
和Deploy差不多,只不过在关键的地方使用 ` delete.sh ` 脚本触发kubectl delete操作。
```yaml
name: Delete microservice
on:
workflow_dispatch:
jobs:
deploy:
runs-on: ubuntu-latest
env:
VERSION: ${{ github.sha }}
CONTAINER_REGISTRY: ${{ secrets.CONTAINER_REGISTRY }}
REGISTRY_UN: ${{ secrets.REGISTRY_UN }}
REGISTRY_PW: ${{ secrets.REGISTRY_PW }}
DB_URL: ${{ secrets.DB_URL }}
steps:
- uses: actions/checkout@v3
- uses: tale/kubectl-action@v1
with:
base64-kube-config: ${{ secrets.KUBE_CONFIG }}
kubectl-version: v1.30.3
- name: delete
run: ./scripts/delete.sh
</code>
</pre>
### 在仓库的secrets中声明和配置变量 {#%E5%9C%A8%E4%BB%93%E5%BA%93%E7%9A%84secrets%E4%B8%AD%E5%A3%B0%E6%98%8E%E5%92%8C%E9%85%8D%E7%BD%AE%E5%8F%98%E9%87%8F}
需要将azure登录凭据和gh登录凭据存储到secrets中,其他的secrets会通过gh命令在执行Actions自动设置。
### 触发构建 {#%E8%A7%A6%E5%8F%91%E6%9E%84%E5%BB%BA}
在GitHub仓库中点击 ` Actions ` ,在workflow中找到 ` Deploy microservice ` ,然后点击 ` Run workflow ` 就可以触发构建。
当右上角出现对号图标,意味着构建成功。
值得注意的是,GitHub Actions构建成功不一定代表部署成功,比如如果Kubernetes配置文件中存在错误,除非是会导致 ` exit code 1 ` 的语法错误,否则是不会提示错误的。
同理,要想删除部署,只需要点击 ` Delete microservice ` 并运行构建。
```
````
`````
``````
```````
````````
`````````