如何在GitHub Actions中自动执行git pull且不覆盖服务器专属配置文件?
GitHub Actions部署到Digital Ocean Droplet时,保留敏感配置文件不被Git覆盖的最佳实践
问题描述
我正在使用GitHub Actions将应用部署至Digital Ocean Droplet云服务器,当前遇到的核心问题是包含数据库凭证的config.json文件冲突:
- 仓库中的
config.json是占位符值,用于代码同步; - 服务器上的
config.json存储真实敏感凭证,不希望被git pull操作覆盖。
我的GitHub Actions工作流核心代码如下:
name: Deploy to Droplet on: push: branches: - main # 推送至main分支时触发部署 jobs: deploy: runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v3 - name: Install sshpass run: sudo apt-get install sshpass - name: Deploy to Droplet run: | sshpass -p "${{ secrets.SSH_PASSWORD }}" ssh -o StrictHostKeyChecking=no root@208.189.185.180 << 'EOF' cd /root/automation git pull origin main # 重启应用或执行其他必要步骤 # Example: systemctl restart your-app EOF
执行该工作流时,git pull会因仓库与服务器的config.json内容不一致产生冲突,手动解决不现实。我尝试过两种方案但都有弊端:
- 将
config.json加入.gitignore:导致仓库无法通过Git更新该文件的结构; - 使用
git stash保存本地更改:恢复stash时仍可能引发冲突。
请问这类场景下的最佳实践是什么?有没有既能合并仓库更新,又能自动保留服务器专属配置的方法?
解决方案
针对这类敏感配置文件的部署冲突问题,有三种成熟的最佳实践,可根据你的场景选择:
1. 使用Git的assume-unchanged标记忽略本地修改
这是最简单的方案,适合配置文件结构不频繁变更的场景:
- 原理:告诉Git忽略指定文件的本地修改,
git pull时不会尝试覆盖该文件; - 操作步骤:
- 在Droplet服务器上执行一次:
cd /root/automation git update-index --assume-unchanged config.json - 修改GitHub Actions的部署脚本,处理配置结构变更的极端情况:
- name: Deploy to Droplet run: | sshpass -p "${{ secrets.SSH_PASSWORD }}" ssh -o StrictHostKeyChecking=no root@208.189.185.180 << 'EOF' cd /root/automation # 临时取消标记,避免结构变更时的拉取冲突(忽略命令执行失败) git update-index --no-assume-unchanged config.json || true # 拉取代码,若配置文件冲突,优先保留仓库的结构版本 git pull origin main --strategy-option theirs # 重新标记忽略本地修改 git update-index --assume-unchanged config.json # 重启应用 systemctl restart your-app EOF
- 在Droplet服务器上执行一次:
- 注意:如果仓库中
config.json的结构(比如新增配置项)有变更,服务器上的文件会被仓库版本覆盖,之后需要手动补充敏感凭证,或者结合脚本自动合并。
2. 分离配置模板与本地配置
适合需要保留本地自定义配置,且文件结构可能频繁变更的场景:
- 原理:仓库中存储配置模板(占位符),服务器上保留真实配置文件,部署时仅同步模板,不覆盖真实配置;
- 操作步骤:
- 在仓库中将
config.json重命名为config.json.template,提交并推送至Git; - 在Droplet服务器上,将
config.json加入本地.gitignore(或用assume-unchanged标记),避免Git追踪; - 修改部署脚本,拉取代码后用模板更新本地配置(仅新增未存在的配置项):
- name: Deploy to Droplet run: | sshpass -p "${{ secrets.SSH_PASSWORD }}" ssh -o StrictHostKeyChecking=no root@208.189.185.180 << 'EOF' cd /root/automation git pull origin main # 使用jq工具合并模板与本地配置(需先在服务器安装jq:apt install jq) jq -s '.[0] * .[1]' config.json.template config.json > temp.json && mv temp.json config.json # 重启应用 systemctl restart your-app EOF
- 在仓库中将
- 优势:既同步了配置结构的更新,又保留了本地的敏感凭证,无需手动干预。
3. 通过GitHub Secrets动态生成配置文件
适合完全用密钥管理工具托管敏感信息,不希望服务器本地存储配置文件的场景:
- 原理:将敏感配置存储在GitHub Secrets中,部署时在服务器上动态生成
config.json; - 操作步骤:
- 在GitHub仓库的「Settings → Secrets and variables → Actions」中添加敏感字段(如
DB_USER、DB_PASSWORD); - 仓库中可以删除
config.json,或保留一个不含敏感信息的模板; - 修改部署脚本,动态生成配置文件:
- name: Deploy to Droplet run: | sshpass -p "${{ secrets.SSH_PASSWORD }}" ssh -o StrictHostKeyChecking=no root@208.189.185.180 << EOF cd /root/automation git pull origin main # 生成包含敏感信息的config.json cat > config.json << 'EOL' { "db": { "user": "${{ secrets.DB_USER }}", "password": "${{ secrets.DB_PASSWORD }}" }, "api_url": "https://your-production-api.com", "debug": false } EOL # 重启应用 systemctl restart your-app EOF
- 在GitHub仓库的「Settings → Secrets and variables → Actions」中添加敏感字段(如
- 优势:敏感信息完全托管在GitHub Secrets中,服务器上不会残留明文凭证,安全性更高。
内容的提问来源于stack exchange,提问作者krishna vamsi
相关产品推荐
相关产品推荐

