前端的第一次CI/CD经验:Jenkins+Docker

0 阅读4分钟

使用 Jenkins + Docker 在服务器上部署前端项目(指南)

本文档介绍如何在 Linux 服务器上安装 Docker 与 Jenkins,并使用 Jenkins Pipeline 自动构建镜像、替换环境变量并运行前端容器。文中示例与仓库内 Jenkinsfile 思路一致(注意不要把私密 token 直接写入仓库)。

目标

  • 在服务器上安装 Docker
  • 在服务器上安装并配置 Jenkins(或以容器方式运行 Jenkins)
  • 在 Jenkins 中创建参数化 Pipeline,拉取代码、构建镜像并运行容器

先决条件

  • 一台 Linux 服务器(本文以 Ubuntu/Debian 为主,另有 CentOS/RHEL 命令注记)
  • 有 sudo 权限的用户

使用 WSL 在本地快速验证(替代服务器)

如果你没有或不想使用远程服务器,WSL(Windows Subsystem for Linux)是在本地快速验证 Jenkins + Docker 部署流程的可行方案。作为没接触过后端的前端,只能以这种方式来试错了,以下为快速流程与注意事项:

  1. 安装 WSL(Windows 10/11):
# 在 PowerShell(管理员)中运行:
wsl --install -d ubuntu
# 安装完成后重启并打开 Ubuntu 终端,直接搜索Ubuntu,如下图

image.png

image.png 以上我们就已经拥有了一个简单的本地服务器.


  1. 在 WSL 内安装 Docker:

如果选择在 WSL 内直接安装 Docker Engine,请参考官方文档并确保 systemd/docker 服务可用(某些 WSL 发行版需额外配置)。


1. 在服务器上安装 Docker(Ubuntu 示例)

# 更新并安装依赖
sudo apt update
sudo apt install -y ca-certificates curl gnupg lsb-release

# 添加 Docker 官方 GPG 并设置仓库
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo \"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable\" \
  | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin

# 将当前用户加入 docker 组(重登录后生效)
sudo usermod -aG docker $USER

CentOS/RHEL 可参考 Docker 官方文档,基本步骤为添加 yum 源并安装 docker-ce

验证 Docker:

docker version
docker run --rm hello-world

其他命令:
# 开机自启动并立即启动
sudo systemctl enable --now docker

# 手动启动/停止/查询
sudo systemctl start  docker
sudo systemctl stop   docker
sudo systemctl status docker

image.png

特别要注意docker拉取镜像默认走的官方源,而国内经常访问不过去,只能找一些加速源,本人AI查了也没找到一个可用的源,最后朋友发了一个可用的,这里也贴出如何配置这个镜像源:

#编辑镜像源的config
nano /etc/docker/daemon.json
#查看当前文件内容
cat /etc/docker/daemon.json

image.png

使用docker拉取镜像:

#拉取官方源
docker pull node:18-alpine
#拉取指定镜像源
docker pull registry.example.com/library/node:18

2. 安装 Jenkins

方法 A:使用系统包(Ubuntu/Debian)

这里不多说,直接参考jenkins官方文档: www.jenkins.io/doc/book/in…

要注意jdk版本要对应jenkins版本,否则后续启动就会出错,本人在这里踩坑了,最后直接对照官方文档去做就一次性过

# 开机自启动并立即启动
sudo systemctl enable --now jenkins

# 手动启动/停止/查询
sudo systemctl start  jenkins
sudo systemctl stop   jenkins
sudo systemctl status jenkins

image.png

当你按照官方文档进行安装和启动后就可以打开一个jenkins的登录地址,安装指导初始化账号和密码,下图本人设置好了:

image.png

image.png

image.png

3. Jenkins 初始配置与插件

  • 打开 http://localhost:8080,按页面提示完成解锁和初始管理员用户创建。
  • 推荐安装插件:Git, Pipeline, GitHub, Credentials, Docker Pipeline, SSH Agent, Blue Ocean(可选)

Credentials 中添加:

  • Git 访问的凭据(推荐使用 Personal Access Token 或 SSH Key),示例 IDgithub-key-id。在 Pipeline 的 git 步骤中通过 credentialsId 使用它。

4. 在 Jenkins 中创建参数化 Pipeline 作业

在新建 Job 时选择 Pipeline,勾选 This project is parameterized,添加参数:

  • BranchToBuild(String)默认 mainmaster
  • SUBMENU_BGCOLOR(String)如果需要在构建时替换 env.js 中的值

在 Pipeline 脚本中可以直接使用 pipeline 或使用仓库中的 Jenkinsfile(推荐把 Jenkinsfile 放在代码仓库里)。本人直接使用了pipeline,我的script如下:

pipeline {
    agent any
    environment {
        DOCKER_IMAGE = 'my-vite-app'
        DOCKER_TAG = 'latest'
    }
    stages {

        stage('Delete Workspace') {
            steps {
                cleanWs()
            }
        }
        stage('Checkout') {

            steps {
                echo 'Current Branch: '
                echo "${params.BranchToBuild}"
                #用凭据而非在 URL 中写 token
                git branch: params.BranchToBuild, credentialsId: 'github-token-id', url: 'https://example.com/vite-demo-test.git'
            }
        }
        stage('Stop Old Container') {
            steps {
                sh 'docker stop ${DOCKER_IMAGE} || true'
                sh 'docker rm ${DOCKER_IMAGE} || true'
                sh 'docker rmi ${DOCKER_IMAGE}:${DOCKER_TAG} || true'
            }
        }
        stage('Replace env variable') {
            steps {
               echo 'Current SUBMENU_BGCOLOR: '
               echo "${params.SUBMENU_BGCOLOR}"               
               sh '''
               #!/bin/bash
               sed -i "s/'\\\$SUBMENU_BGCOLOR'/'${SUBMENU_BGCOLOR}'/g" public/env.js
               '''
            }
        }
        stage('Docker Build') {
            steps {
                sh "docker build -t ${DOCKER_IMAGE}:${DOCKER_TAG} ."
            }
        }
        stage('Run New Container') {
            steps {
                sh "docker run -d --name ${DOCKER_IMAGE} -p 80:9080 ${DOCKER_IMAGE}:${DOCKER_TAG}"
            }
        }
    }
}

注意以上script里有两个value:params.BranchToBuildparams.SUBMENU_BGCOLOR,这两个参数是jenkins配置参数,第一个配置的是拉取的git分支,第二个是前端页面的背景颜色,那是如何config的?如下图,其中背景颜色是通过sh脚本改了前端项目下env.js的参数值,这样就依据不同的场配置不同的参数,当然这种适合小型项目.

image.png

image.png

image.png

image.png

说明:把 https://your.git.server/your/repo.git 替换为你的仓库地址,并在 Jenkins 的凭据中添加对应的 credentialsId(例如 github-key-id)。切勿将 Personal Access Token 直接写入 Jenkinsfile 或仓库。


6. 容器化部署与替换环境变量

  • 上述 Pipeline 在构建前通过 sed 替换 public/env.js 中的占位符;如果使用其它方式管理运行时配置(例如 nginx 入口替换、运行时读取环境变量或使用配置文件),可按需调整。
  • 如果希望端口从 9080 转到 80(宿主机 80),示例中 docker run -p 80:9080 会将容器 9080 映射到宿主 80。 从我的script见到有docker build,而这里也需要把Dockerfile文件写好放进前端项目的更目录下,以及都是部署在nginx服务器上,因此也要放nginx config进前端项目里,我的dockerfile如下:
# Stage 1: Build the React application
FROM node:18-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm install --force
COPY . .
RUN npm run build

# Stage 2: Serve the static files with Nginx
FROM nginx:alpine
COPY --from=build /app/build /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 9080

nginx config:

server {
    listen 9080;
    server_name localhost;
    client_max_body_size 11M;

    location /svc/ {
        rewrite ^/svc/(.*)$ /$1 break;
        proxy_pass http://xxxxx:8080/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        proxy_connect_timeout 1000;
        proxy_read_timeout 1000;
        proxy_send_timeout 1000;
        proxy_cache_valid any 0;
    }
    location = /index.html {
        root /usr/share/nginx/html;
        expires off;
        add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0";
    }
    location / {
        root /usr/share/nginx/html;
        index index.html index.htm;
        try_files $uri $uri/ /index.html;
    }

    error_log /var/log/nginx/error.log debug;
    error_page 500 502 503 504 /50x.html;
    location = /50x.html {
        root /usr/share/nginx/html;
    }
}

而docker的知识就不在这说明了,自行AI吧。

注意:若宿主机上已有服务占用 80 端口,需先停止或选择其它端口。 注意本人在dockerfile构建了多阶段的内容,第二阶段已经把nginx服务build进镜像了,因此服务器上不需要再安装nginx,而jenkins脚本里用到了docker来做集成和部署,因此服务器需要先安装好docker服务,jenkins不会自行安装


7 常见问题排查

  • 如果 Jenkins 无法拉取代码:检查 credentialsId 是否正确、凭据是否有权限、Webhook/网络是否通畅。
  • 如果 docker build 报错:在 Jenkins 节点上手动运行 docker build 验证环境,一般是 Docker 权限或上下文问题。
  • sed 替换无效:确认 public/env.js 中的占位符格式,与 sed 的匹配模式一致并注意转义。

8 安全建议

  • 永远使用 Jenkins 的 Credentials 管理凭据,避免在 Jenkinsfile 或仓库中写明明文 token。
  • 生产环境建议在私有网络或使用 VPN 访问 Jenkins,限制访问来源并开启 HTTPS。