云计算百科
云计算领域专业知识百科平台

[前端][cicd]使用github-action工具部署docker容器(实现一键推送部署到服务器)

前提:云服务器、docker 账号、GitHub 账号

CI/CD 主要有三种实现方式:

  • 直接命令行部署:通过脚本直接部署到服务器
  • 服务器工具部署:使用阿里云等服务器提供的部署工具
  • GitHub Actions 自动化部署:基于代码提交自动触发部署

1. 命令行直接部署

项目结构

在这里插入图片描述

  • env 文件: 存放服务器端口、账号等配置信息
  • deploy 脚本: 编写主要部署逻辑
  • docker 文件: Docker 容器配置
  • nginx 配置: Web 服务器配置文件

部署脚本示例

Docker Compose 配置文件

docker-compose.yml

version: "3"
services:
mainpage:
image: nginx:stablealpine
container_name: mainpagenginx
restart: always
ports:
"80:80"
volumes:
# Nginx 配置
./nginx.conf:/etc/nginx/conf.d/default.conf:ro
# 0MainPage 构建产物
/root/project/0MainPage/dist:/usr/share/nginx/html:ro

Nginx 配置文件

nginx.conf

server {
listen 80;
server_name localhost;

# MIME 类型配置
include /etc/nginx/mime.types;
default_type application/octet-stream;

# 安全头配置
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;

# 开启 gzip 压缩
gzip on;
gzip_min_length 1k;
gzip_comp_level 6;
gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png application/json;
gzip_vary on;
gzip_disable "MSIE [1-6]\\.";

# 静态资源缓存配置 – JS文件
location ~* \\.js$ {
root /usr/share/nginx/html;
add_header Content-Type "application/javascript; charset=utf-8";
expires 1y;
add_header Cache-Control "public, immutable";
access_log off;
}

# 静态资源缓存配置 – CSS文件
location ~* \\.css$ {
root /usr/share/nginx/html;
add_header Content-Type "text/css; charset=utf-8";
expires 1y;
add_header Cache-Control "public, immutable";
access_log off;
}

# 静态资源缓存配置 – 图片和字体文件
location ~* \\.(png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
root /usr/share/nginx/html;
expires 1y;
add_header Cache-Control "public, immutable";
access_log off;
}

# HTML文件不缓存
location ~* \\.html$ {
root /usr/share/nginx/html;
add_header Cache-Control "no-cache, no-store, must-revalidate";
add_header Pragma "no-cache";
add_header Expires "0";
}

# 0MainPage – 主页项目(根路径)
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}

error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}

PowerShell 部署脚本

deploy.ps1

# Deploy script for 0MainPage project
Write-Host "[Deploy] Starting 0MainPage deployment process…" ForegroundColor Green

# Load environment variables from .env file

$envFile = Join-Path $PSScriptRoot ".env-0mainpage"
if (Test-Path $envFile) {
Write-Host "[Config] Loading environment variables from .env file…" ForegroundColor Yellow
Get-Content $envFile | ForEach-Object {
if ($_.Trim() -match "^([^#][^=]+)=(.*)$") {
$name = $matches[1].Trim()
$value = $matches[2].Trim()
[Environment]::SetEnvironmentVariable($name, $value, "Process")
}
}
} else {
Write-Host "[Warning] .env file not found, using default values" ForegroundColor Yellow
}

# Server configuration from environment variables

$serverHost = if ($env:SERVER_HOST) { $env:SERVER_HOST } else { "" }
$serverUser = if ($env:SERVER_USER) { $env:SERVER_USER } else { "" }
$serverPassword = $env:SERVER_PASSWORD
$serverPath = if ($env:SERVER_0MAINPAGE_PATH) { $env:SERVER_0MAINPAGE_PATH } else { "/root/project/0MainPage/dist" }
$serverConfigPath = if ($env:SERVER_CONFIG_PATH) { $env:SERVER_CONFIG_PATH } else { "/root/project/CD/0MainPage" }
$projectPath = if ($env:LOCAL_0MAINPAGE_PATH) { $env:LOCAL_0MAINPAGE_PATH } else { "C:\\Users\\what\\Desktop\\my-project\\0MainPage" }

if (-not $serverPassword) {
Write-Host "[Error] SERVER_PASSWORD not found in environment variables" ForegroundColor Red
exit 1
}

Write-Host "[Config] Server: $serverHost" ForegroundColor Yellow
Write-Host "[Config] Target: 0MainPage (Port 80)" ForegroundColor Yellow
Write-Host "[Config] Project Path: $projectPath" ForegroundColor Yellow

# Check and navigate to 0MainPage

if (!(Test-Path $projectPath)) {
Write-Host "[Error] 0MainPage directory not found at: $projectPath" ForegroundColor Red
exit 1
}

$currentPath = Get-Location
Set-Location $projectPath
Write-Host "[Info] Changed to project directory: $projectPath" ForegroundColor Yellow

try { # 1. Install dependencies if needed
if (!(Test-Path "node_modules")) {
Write-Host "[Step1] Installing dependencies…" ForegroundColor Cyan
npm install
if ($LASTEXITCODE -ne 0) {
throw "Dependencies installation failed with exit code $LASTEXITCODE"
}
}

# 2. Build project
Write-Host "[Step2] Building 0MainPage project…" ForegroundColor Cyan
npm run build
if ($LASTEXITCODE -ne 0) {
throw "Build command failed with exit code $LASTEXITCODE"
}

if (!(Test-Path "dist")) {
Write-Host "[Error] Build failed, dist directory not found" ForegroundColor Red
exit 1
}

# 3. Create server directory if not exists
Write-Host "[Step3] Preparing server directory…" ForegroundColor Cyan
$plinkExists = Get-Command plink ErrorAction SilentlyContinue
if ($plinkExists) {
try {
$plinkCommand = "echo y | plink -pw '$serverPassword' ${serverUser}@${serverHost} 'mkdir -p ${serverPath} && mkdir -p ${serverConfigPath}'"
Write-Host "[Execute] Creating directories on server…" ForegroundColor Gray
Invoke-Expression $plinkCommand
} catch {
Write-Host "[Warning] Directory creation failed: $_" ForegroundColor Yellow
}
}

# 4. Upload dist to server
Write-Host "[Step4] Uploading 0MainPage dist to server…" ForegroundColor Cyan
$pscpExists = Get-Command pscp ErrorAction SilentlyContinue
if ($pscpExists) {
try {
$pscpCommand = "echo y | pscp -pw '$serverPassword' -r dist/* ${serverUser}@${serverHost}:${serverPath}/"
Write-Host "[Execute] Uploading files…" ForegroundColor Gray
Invoke-Expression $pscpCommand
} catch {
throw "File transfer failed: $_"
}
}

# 5. Upload config files
Write-Host "[Step5] Uploading 0MainPage config files…" ForegroundColor Cyan
$configPath = $PSScriptRoot
if (Test-Path $configPath) {
if ($pscpExists) {
$pscpConfigCommand = "pscp -pw '$serverPassword' ${configPath}/docker-compose.yml ${configPath}/nginx.conf ${serverUser}@${serverHost}:${serverConfigPath}/"
Write-Host "[Execute] Uploading config files…" ForegroundColor Gray
Invoke-Expression $pscpConfigCommand
}
}

# 6. Stop existing container
Write-Host "[Step6] Stopping existing 0MainPage container…" ForegroundColor Cyan
try {
if ($plinkExists) {
$plinkCommand = "plink -batch -pw '$serverPassword' ${serverUser}@${serverHost} 'cd ${serverConfigPath} && docker stop mainpage-nginx || true && docker rm mainpage-nginx || true'"
Write-Host "[Execute] Stopping existing container…" ForegroundColor Gray
Invoke-Expression $plinkCommand
}
} catch {
Write-Host "[Info] No existing container to stop" ForegroundColor Yellow
}

# 7. Start 0MainPage container
Write-Host "[Step7] Starting 0MainPage container…" ForegroundColor Cyan
try {
if ($plinkExists) {
$plinkCommand = "plink -batch -pw '$serverPassword' ${serverUser}@${serverHost} 'cd ${serverConfigPath} && docker compose up -d'"
Write-Host "[Execute] Starting container…" ForegroundColor Gray
Invoke-Expression $plinkCommand
}
} catch {
Write-Host "[Error] Container start failed: $_" ForegroundColor Red
throw
}

# 8. Verify deployment
Write-Host "[Step8] Verifying 0MainPage deployment…" ForegroundColor Cyan
try {
if ($plinkExists) {
$plinkVerifyCommand = "plink -batch -pw '$serverPassword' ${serverUser}@${serverHost} 'docker ps | grep mainpage-nginx'"
Write-Host "[Execute] Verifying container…" ForegroundColor Gray
Invoke-Expression $plinkVerifyCommand
}
} catch {
Write-Host "[Warning] Verification failed: $_" ForegroundColor Yellow
}

Write-Host "[Done] 0MainPage deployment successful!" ForegroundColor Green
Write-Host "[Access] http://$serverHost" ForegroundColor Yellow

} catch {
Write-Host "[Error] Deployment failed: $\\_" ForegroundColor Red
exit 1
} finally {
Set-Location $currentPath
}

2. 服务器工具部署

使用阿里云、腾讯云等云服务商提供的部署工具,具体配置根据服务商文档进行设置。

3. GitHub Actions 自动化部署(推荐)

提供两种部署模式:

  • 主分支自动部署:提交代码到主分支时自动触发部署
  • 标签部署:根据 Git Tag 来触发部署

Dockerfile 配置

# 构建阶段
FROM node:20-alpine as build-stage

WORKDIR /app

# 复制 package 文件
COPY package*.json ./
COPY pnpm-lock.yaml ./

# 安装 pnpm 并安装依赖
RUN npm install -g pnpm
RUN pnpm install

# 复制源代码(排除 node_modules)
COPY src ./src
COPY public ./public
COPY index.html ./
COPY vite.config.ts ./
COPY tsconfig.json ./
COPY tsconfig.app.json ./
COPY tsconfig.node.json ./

# 构建应用
RUN pnpm run build

# 生产阶段
FROM nginx:stable-alpine as production-stage

# 复制自定义 nginx 配置
COPY nginx.conf /etc/nginx/conf.d/default.conf

# 复制构建产物
COPY –from=build-stage /app/dist /usr/share/nginx/html

# 暴露端口
EXPOSE 80

CMD ["nginx", "-g", "daemon off;"]

GitHub Actions 配置文件

name: Publish Image

on:
push:
branches: ["master"]
paths-ignore:
".gitignore"
"README.md"
".vscode/**"
pull_request:
branches: ["master"]

jobs:
build:
runs-on: ubuntulatest
steps:
uses: actions/checkout@v4

uses: docker/loginaction@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

uses: actions/setupnode@v4
with:
node-version: "20"

uses: actions/cache@v4
id: cache
with:
path: node_modules
key: ${{ runner.os }}node${{ hashFiles('packagelock.json') }}
restore-keys: |
${{ runner.os }}-node-

name: Install dependencies
if: steps.cache.outputs.cachehit != 'true'
run: npm install

name: Build
run: npm run build

name: Build and push Docker image
run: |
docker build . –file Dockerfile –tag ghcr.io/${{ github.repository_owner }}/0mainpage:latest
docker push ghcr.io/${{ github.repository_owner }}/0mainpage:latest

name: Deploy to server
uses: appleboy/sshaction@v1.0.0
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
password: ${{ secrets.SERVER_PASSWORD }}
port: ${{ secrets.SERVER_PORT || '22' }}
timeout: 30s
command_timeout: 10m
debug: true
script: |
docker stop mainpage-nginx || true
docker rm mainpage-nginx || true
docker login -u ${{ github.actor }} -p ${{ secrets.GITHUB_TOKEN }} https://ghcr.io
docker pull ghcr.io/${{ github.repository_owner }}/0mainpage:latest
docker run -dp 80:80 –restart=always –name mainpage-nginx ghcr.io/${{ github.repository_owner }}/0mainpage:latest

GitHub 仓库配置

需要在 GitHub 仓库的 Settings > Secrets and variables > Actions 中配置以下环境变量:

  • SERVER_HOST: 服务器地址
  • SERVER_USER: 服务器用户名
  • SERVER_PASSWORD: 服务器密码
  • SERVER_PORT: SSH 端口(默认 22)

在这里插入图片描述

赞(0)
未经允许不得转载:网硕互联帮助中心 » [前端][cicd]使用github-action工具部署docker容器(实现一键推送部署到服务器)
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!