当前位置:首页 > 技术 > 正文内容

自动化部署:使用 GitHub Actions 将应用推送到 AWS EC2 完整指南

访客 技术 2

如果你曾经推送代码到 GitHub 后立即打开终端 SSH 到服务器重启应用,那么本指南将为你解决这个问题。

手动部署在第一次时还好。但当你一天内多次推送时,它就变成了开发中最繁琐的部分。本文将展示如何完全自动化整个流程:推送代码 → 构建 Docker 镜像 → 自动部署到 AWS EC2。

无需手动步骤。无需 SSH。只需推送即可上线。

项目目标

完成本指南后,你将拥有一个能够执行以下操作的流水线:

  • 每次推送到 main 分支时自动触发
  • 构建应用程序的 Docker 镜像
  • 推送至 Amazon ECR(私有 Docker 注册表)
  • SSH 连接 EC2 实例并替换运行中的容器
  • 清理旧镜像以节省磁盘空间

前置条件

开始之前,请确保具备以下条件:

  • AWS 账户(免费套餐即可)
  • GitHub 账户
  • 正在运行的 EC2 实例(Amazon Linux 2023 或 Ubuntu 22.04)
  • Docker 基础知识

第一步 — 配置 EC2 实例

SSH 连接到 EC2 并安装 Docker 和 AWS CLI。创建名为 initialize.sh 的文件:

#!/bin/bash

# 安装 Docker
sudo yum update -y
sudo yum install -y docker
sudo systemctl enable docker
sudo systemctl start docker
sudo usermod -aG docker ec2-user

# 安装 AWS CLI
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
sudo yum install -y unzip
unzip -q awscliv2.zip
sudo ./aws/install --update

执行脚本:

chmod +x initialize.sh
./initialize.sh

⚠️ 完成后退出并重新 SSH 登录 — 这是应用 Docker 权限组所必需的。

第二步 — 创建 ECR 存储库

Amazon ECR 是你的私有 Docker 注册表。从本地计算机创建一个:

aws ecr create-repository \
  --repository-name web-application \
  --region us-east-1

记下输出中的 repositoryUri。格式如下:

987654321.dkr.ecr.us-east-1.amazonaws.com/web-application

第三步 — 为 GitHub Actions 创建 IAM 用户

GitHub Actions 需要 AWS 凭据才能将镜像推送到 ECR。创建具有最小权限的专用用户。

  1. 进入 AWS 控制台 → IAM → 用户 → 创建用户
  2. 命名为 ci-cd-deployment
  3. 创建自定义策略并粘贴以下 JSON:
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["ecr:GetAuthorizationToken"],
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "ecr:BatchCheckLayerAvailability",
        "ecr:PutImage",
        "ecr:InitiateLayerUpload",
        "ecr:UploadLayerPart",
        "ecr:CompleteLayerUpload",
        "ecr:GetDownloadUrlForLayer",
        "ecr:BatchGetImage"
      ],
      "Resource": "arn:aws:ecr:*:*:repository/*"
    }
  ]
}
  1. 创建 访问密钥 并保存凭据。

第四步 — 添加 GitHub 密钥

进入 GitHub 仓库 → 设置 → 机密和变量 → Actions → 添加以下内容:

机密名称
AWS_ACCESS_KEY_ID 第三步获取的值
AWS_SECRET_ACCESS_KEY 第三步获取的值
SERVER_HOST EC2 公共 IP 地址
SERVER_SSH_PRIVATE_KEY .pem 密钥文件的完整内容

第五步 — 流水线配置文件

在仓库中创建 .github/workflows/deployment.yml

name: 构建并部署到 AWS EC2

on:
  push:
    branches:
      - main

env:
  AWS_REGION: us-east-1
  ECR_REPOSITORY: web-application
  SERVER_USERNAME: ec2-user
  APPLICATION_PORT: 3000

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: 检出代码
        uses: actions/checkout@v4

      - name: 配置 AWS 凭据
        uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ${{ env.AWS_REGION }}

      - name: 登录 Amazon ECR
        id: authenticate-ecr
        uses: aws-actions/amazon-ecr-login@v2

      - name: 构建、标记并推送镜像到 ECR
        id: build-container
        env:
          REGISTRY_ENDPOINT: ${{ steps.authenticate-ecr.outputs.registry }}
          TAG_VERSION: ${{ github.sha }}
        run: |
          docker build -t $REGISTRY_ENDPOINT/$ECR_REPOSITORY:$TAG_VERSION .
          docker push $REGISTRY_ENDPOINT/$ECR_REPOSITORY:$TAG_VERSION
          echo "container_image=$REGISTRY_ENDPOINT/$ECR_REPOSITORY:$TAG_VERSION" >> $GITHUB_OUTPUT

      - name: 部署到 EC2
        uses: appleboy/ssh-action@v1.0.3
        with:
          host: ${{ secrets.SERVER_HOST }}
          username: ${{ env.SERVER_USERNAME }}
          key: ${{ secrets.SERVER_SSH_PRIVATE_KEY }}
          script: |
            aws ecr get-login-password --region ${{ env.AWS_REGION }} | \
              docker login --username AWS --password-stdin \
              ${{ steps.authenticate-ecr.outputs.registry }}
            docker pull ${{ steps.build-container.outputs.container_image }}
            docker stop web-service || true
            docker rm web-service || true
            docker run -d \
              --name web-service \
              --restart unless-stopped \
              -p 80:${{ env.APPLICATION_PORT }} \
              ${{ steps.build-container.outputs.container_image }}
            docker system prune -f

第六步 — 推送并观察运行

git add .
git commit -m "添加 ci/cd 流水线"
git push origin main

前往 GitHub → Actions 标签页。观察其运行。绿色对勾表示应用已上线。✅

在浏览器中打开 EC2 公共 IP 确认。

常见错误及解决方案

ECR 登录失败 通常是 GitHub 机密中的凭据错误。仔细检查访问密钥 ID 和密钥。

SSH 连接被拒绝 EC2 安全组中未开放端口 22。为 SSH 添加入站规则。

浏览器无法加载应用 安全组未开放端口 80。或容器崩溃 — 在 EC2 上运行 docker logs web-service 查看原因。

EC2 上 Docker 权限被拒绝 未在运行 initialize.sh 后退出。退出并重新 SSH 登录。

平台错误 在 docker build 命令中添加 --platform linux/amd64。常见于 Apple M1/M2 Mac。

后续考虑

一旦此流水线运行正常,可考虑添加:

  • 部署成功/失败的通知(Slack 或邮件)
  • 部署后调用 /health 端点的健康检查步骤
  • 如果健康检查失败,使用前一镜像标签的回滚逻辑
  • 不同分支的独立流水线(如预发布和生产环境)

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Mac 安装 Node.js 指南

方法一:通过官网安装包(最简单,适合初学者)如果你只是想快速安装并开始使用,这是最直接的方法。访问 Node.js 官网。页面会显示两个版本:LTS (Recommended For Most Users):长期支持版,最稳定。建议选这个。Current:最新特性版,包含最新功能但可能不够稳定。下载 .pkg 安装包并运行。按照安装向导点击“下一步”即可完成。方法二:使用 Homebrew 安装(...

Dom\HTML_NO_DEFAULT_NS 的副作用:自动加闭合标签

在使用Dom\HTMLDocument时,Dom\HTML_NO_DEFAULT_NS 将禁止在解析过程中设置元素的命名空间, 此设置是为了与DOMDocument向后兼容而存在的。当使用它时,已知的一个副作用就是:自动加闭合标签例如 </img> 为什么会这样?当你使用:Dom\HTML_NO_DEFAULT_NS文档会变成 无命名空间模式,此时内部更接近 XML...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。