虚拟机上实现最简 CI/CD

手把手在 CentOS 7 虚拟机上实现最简 CI/CD(无 Docker / 无云服务)

本文通过纯本地环境(CentOS 7 + Git + Apache)演示 CI/CD 核心流程,帮助初学者理解持续集成与持续部署的本质。


📚 目录(点击跳转)


为什么要在本地实现 CI/CD?

  • 理解 CI/CD 的底层原理
  • 不依赖 GitHub/GitLab/Jenkins 等外部平台
  • 适合学习、实验和内网开发环境

完整流程图:

开发者本地

│ git add / commit / push

Bare 仓库:/opt/git/myapp.git ← 模拟 GitHub

│ 触发 post-receive 钩子

CI/CD 脚本执行

├─ 1. 临时目录检出最新代码(/tmp/...)

├─ 2. 运行测试(如检查 index.html 是否存在)← CI

└─ 3. 同步文件到 /var/www/html/myapp/ ← CD

Apache Web 服务 ← 用户访问的"生产环境"
[↑ 回到顶部](#↑ 回到顶部)


一、实验环境准备

  • 操作系统:CentOS 7 虚拟机
  • 所需软件:git、python3(可选)、httpd(Apache)
  • 网络要求:仅本地回环,无需外网

[↑ 回到顶部](#↑ 回到顶部)


二、创建本地"远程" Git 仓库

  • 使用 git init --bare 模拟远程仓库

  • 仓库路径示例:/opt/git/myapp.git

    #清理旧环境(确保干净起点)
    rm -rf ~/myapp-dev /opt/git/myapp.git /var/www/html/myapp /tmp/myapp-deploy-*
    systemctl restart httpd
    #创建"内部 GitHub"(bare 仓库)
    mkdir -p /opt/git/myapp.git
    cd /opt/git/myapp.git
    git init --bare
    #配置 Git 用户(避免提交报错)
    #这里可以不是真实的用户名和邮箱,只是为了区分git用户避免混杂
    git config --global user.name "ci-cd"
    git config --global user.email "ci-cd@example.com"

[↑ 回到顶部](#↑ 回到顶部)


三、开发者工作目录初始化

  • 克隆 bare 仓库到本地开发目录

  • 创建简单应用(如 index.html

  • 首次提交并推送至"远程"

    #创建开发目录并首次提交
    cd ~
    git clone /opt/git/myapp.git myapp-dev
    cd myapp-dev

    echo '

    CI/CD Works!

    ' > index.html
    git checkout -b main # 显式创建 main 分支
    git add .
    git commit -m "Initial commit"
    git push origin main # 首次推送

安装 rsync(用于同步文件)---这个得安装好

yum install -y rsync
[↑ 回到顶部](#↑ 回到顶部)


四、核心:配置 Git Hook 实现自动化(CI/CD 关键)

  • 编写 post-receive 钩子脚本
  • 实现两个阶段:
    • CI(持续集成):代码检出 + 基础校验(如文件存在性)
    • CD(持续部署):自动同步到 Web 目录

post-receive 钩子脚本

复制代码
cat > /opt/git/myapp.git/hooks/post-receive << 'EOF'
#!/bin/bash
# 启用严格模式:任何命令失败立即退出
set -e

# 部署目标目录(Apache 会从此处提供网页)
DEPLOY_DIR="/var/www/html/myapp"

# 临时工作目录(每次部署都新建,避免残留)
TMP_DIR="/tmp/myapp-deploy-$$"  # $$ 是当前进程 ID,保证唯一

# ================================
#  第一步:获取 Git 推送的新提交 ID
# ================================
# Git 在 post-receive 中会通过标准输入(stdin)传入一行:
#   <old-commit-id> <new-commit-id> <ref-name>
# 例如:000... dcc19ac refs/heads/main
read oldrev newrev refname

# 如果是删除分支(newrev 全 0),直接退出
if [ "$newrev" = "0000000000000000000000000000000000000000" ]; then
    exit 0
fi

# ================================
#  第二步:清理并准备临时目录
# ================================
rm -rf "$TMP_DIR"
mkdir -p "$TMP_DIR"

# ================================
#  第三步:从 bare 仓库提取新代码(关键!)
# ================================
# 使用 git archive + newrev 提取指定提交的内容
# 输出是 tar 流,直接 pipe 给 tar 解压到 TMP_DIR
git --git-dir=/opt/git/myapp.git archive "$newrev" | tar -x -C "$TMP_DIR"

# ================================
#  第四步:CI ------ 检查关键文件是否存在
# ================================
if [ ! -f "$TMP_DIR/index.html" ]; then
    echo " CI FAILED: index.html not found!"
    exit 1  # 部署中断
fi
echo " CI PASSED: index.html is present."

# ================================
#  第五步:CD ------ 部署到 Web 目录
# ================================
mkdir -p "$DEPLOY_DIR"
# 同步 TMP_DIR/ 下所有内容到 DEPLOY_DIR/
# 注意结尾的 "/":表示同步内容,而不是嵌套目录
rsync -a --delete "$TMP_DIR/" "$DEPLOY_DIR/"

# 设置 Apache 可读权限(CentOS 默认用户是 apache)
chown -R apache:apache "$DEPLOY_DIR"
chmod -R 755 "$DEPLOY_DIR"

# 成功提示
echo " Deployed to http://localhost/myapp/"
EOF

添加执行权限(必须!)

chmod +x /opt/git/myapp.git/hooks/post-receive

[↑ 回到顶部](#↑ 回到顶部)


五、配置 Apache 支持部署访问

  • 设置 Web 根目录权限

  • 确保 Apache 可读取部署路径

  • 访问测试:http://localhost/myapp/

    #测试部署
    cd ~/myapp-dev
    echo '

    Auto Deploy Success! v2

    ' > index.html
    git add .
    git commit -m "Test auto deploy"
    git push origin main
    ##你应该看到输出:
    remote: CI PASSED: index.html is present.
    remote: Deployed to http://localhost/myapp/

    验证:
    cat /var/www/html/myapp/index.html

    输出:

    Auto Deploy Success! v2

浏览器访问:http://虚拟机IP/myapp/

[↑ 回到顶部](#↑ 回到顶部)


六、完整流程测试

  • 修改代码 → git add/commit/push
  • 观察钩子自动执行输出
  • 验证网页内容是否自动更新

为了完成本地提交--》自动部署 --》网页更新,同时需要展示当前时间,但在html文件中,$(date)只是一个普通的字符串,它是bash的命令语法,所以需要在部署之前将当前时间替换上去(对post-receive脚本进行修改),具体修改如下

复制代码
cat > /opt/git/myapp.git/hooks/post-receive << 'EOF'
#!/bin/bash
set -e

DEPLOY_DIR="/var/www/html/myapp"
TMP_DIR="/tmp/myapp-deploy-$$"

read oldrev newrev refname

if [ "$newrev" = "0000000000000000000000000000000000000000" ]; then
    exit 0
fi

rm -rf "$TMP_DIR"
mkdir -p "$TMP_DIR"

# 提取新提交的内容
git --git-dir=/opt/git/myapp.git archive "$newrev" | tar -x -C "$TMP_DIR"

# 检查 index.html 是否存在
if [ ! -f "$TMP_DIR/index.html" ]; then
    echo "CI FAILED: index.html not found!"
    exit 1
fi

echo "CI PASSED: index.html is present."

#关键:在部署前替换 $(date) 为真实时间
current_time=$(date '+%Y-%m-%d %H:%M:%S')
sed -i "s/\$(date)/$current_time/" "$TMP_DIR/index.html"

# 部署到 Web 目录
mkdir -p "$DEPLOY_DIR"
rsync -a --delete "$TMP_DIR/" "$DEPLOY_DIR/"
chown -R apache:apache "$DEPLOY_DIR"
chmod -R 755 "$DEPLOY_DIR"

echo "Deployed to http://localhost/myapp/"
EOF

chmod +x /opt/git/myapp.git/hooks/post-receive

然后进行如下操作:

复制代码
测试
cd ~/myapp-dev
echo '<h1> CI/CD FULL TEST PASSED! $(date)</h1>' > index.html
git add .
git commit -m "Test dynamic date"
git push origin main


http://192.168.126.50/myapp/

[↑ 回到顶部](#↑ 回到顶部)


七、总结:我们实现了什么?

步骤 对应 CI/CD 概念
git push 代码提交触发
post-receive 自动化流水线
文件校验 持续集成(CI)
同步到 Web 目录 持续部署(CD)
  • 无需 Docker、无需云服务、100% 本地闭环
  • 真正理解"提交即部署"的背后机制

[↑ 回到顶部](#↑ 回到顶部)


八、后续可扩展方向(进阶)

  • 加入单元测试脚本(如 Python unittest)
  • 部署动态应用(如 Flask + systemd)
  • 使用 rsync 或 scp 实现多节点部署
  • 添加邮件/日志通知机制

[↑ 回到顶部](#↑ 回到顶部)


提示:本文所有操作均在 CentOS 7 虚拟机中完成,适合零基础读者动手实践。

如果你觉得有帮助,欢迎点赞、收藏、评论交流!

相关推荐
宋均浩1 天前
# Docker 镜像瘦身实战:从 1.2G 到 80MB 的五个优化步骤
ci/cd·docker
宋均浩6 天前
# GitHub Actions 实战:从零搭建 CI/CD 流水线的 5 个核心配置
ci/cd
lunzi_08268 天前
【开源治理】05-把流程翻译成门禁:开源治理嵌入 DevOps 流水线实战
供应链管理·devops·开源治理
程序员老赵8 天前
服务器没有桌面?Docker 跑个 Chrome,浏览器就能远程用
docker·容器·devops
宋均浩8 天前
# pytest 的 5 个 fixture 骚操作,我用了 3 年才学会
devops
睡不醒男孩0308238 天前
云原生运维实战:高并发架构下的云原生可观测性、韧性降级与自动化干预体系
数据库·kubernetes·高并发·prometheus·devops·sre·缓存调优
爱学习的程序媛8 天前
DevOps 深度解析:从文化理念到落地实践
运维·devops
霸道流氓气质8 天前
GitLab CI/CD 完全指南
linux·ci/cd·gitlab
sbjdhjd8 天前
从零搭建企业级 CI/CD(下):Jenkins+GitLab+Harbor 全链路实战指南
git·servlet·ci/cd·云原生·云计算·gitlab·jenkins
糖果店的幽灵8 天前
软件测试接口测试从入门到精通:接口测试CI_CD集成
软件测试·ci/cd·接口测试