从开发到生产:利用Jenkins和Docker部署Next.js项目的完整指南

813 阅读7分钟

CI/CD 是持续集成(Continuous Integration)和持续交付 / 部署(Continuous Delivery/Deployment)的简称。

持续集成(Continuous Integration)

  • 定义:持续集成是一种软件开发实践,要求开发团队成员经常集中他们的代码。每次集成都通过自动化构建(包括编译、测试等)来验证,尽早发现集成错误。

  • 工作流程:

    • 代码提交:开发人员频繁的将代码更改提交到版本控制系统(如Git)中。
    • 自动化构建:提交触发构建服务器(如Jenkins、GitLab CI等)执行构建操作,包括编译代码、运行单元测试、代码检查等。例如,对于一个 Java 项目,构建过程会编译所有的.java 文件为.class 文件,并运行 JUnit 等单元测试框架编写的测试用例。
    • 快速反馈:如果构建失败或者测试不通过,团队成员会立即收到通知,以便及时修复问题。这有助于保持代码库的健康,减少后期集成问题的复杂性。

持续交付(Continuous Delivery)

  • 定义: 持续交付是在持续集成的基础上,确保软件可以随时发布到生产环境。它强调的是软件在整个生命周期内都保持可部署的状态。

  • 工作流程:

    • 在持续集成基础上: 在完成代码构建和测试后,持续交付会进一步确保软件通过了更全面的测试,包括集成测试、系统测试等。例如,对于一个web应用,会进行不同模块之间的集成测试,确保每个功能模块协同工作正常。
    • 部署准备: 软件的配置管理更加完善,确保在不同环境(开发、测试、生产等)中的配置正确。同时,会准备好部署脚本,以便能够自动化地将软件部部署到目标环境。
    • 手动发布决策: 虽然软件已经准备好发布,但发布过程可能仍然需要人工干预来决定合适的时间点,不过整个发布流程已经高度自动化和标准化。

持续部署(Continuous Deployment)

  • 定义:持续部署是持续交付的延伸,是指软件在通过所有的测试和质量检查后,自动部署到生产环境,无需人工干预。

  • 工作流程:

    • 全自动化流程:从代码提交、构建、测试到部署到生产环境,全部是自动化的。例如,在一个采用持续部署的云原生应用开发中,新的代码更改一旦通过了一系列的自动化测试和验证,就会自动地部署到生产环境中的容器集群中。
    • 快速迭代:允许企业更快地向用户提供新功能和修复问题,快速响应市场变化。

如果是一般的项目,一般CI / CD是集成在一起, 当我们Jenkins检测到github的变化,我们就会开始build,build完成后,启动镜像,完成部署。

CI/CD 极大地提高了软件开发的效率和质量,缩短了开发周期,降低了软件开发过程中的风险,并且能够更快地响应客户需求和市场变化。

CI/CD 的主要优势

  • 减少人为错误
  • 快速交付
  • 提高开发效率
  • 降低风险
  • 持续获得反馈

常用的 CI/CD 工具包括:

  • Jenkins
  • GitLab CI
  • GitHub Actions
  • Travis CI
  • Circle CI

安装Jenkins

服务器使用的阿里云,操作系统是Ubuntu 22.04。首先需要配置镜像源列表,否则可能会下载失败。

1. 配置镜像源

  • 查看Ubuntu版本使用lsb_release -a命令。

  • 常用的Ubuntu版本代号如下:

    • Ubuntu 22.04:jammy
    • Ubuntu 20.04:focal
    • Ubuntu 18.04:bionic
    • Ubuntu 16.04:xenial
  • 常见源:

    • 阿里云
    deb http://mirrors.aliyun.com/ubuntu/ focal main restricted universe multiverse
    deb http://mirrors.aliyun.com/ubuntu/ focal-security main restricted universe multiverse
    deb http://mirrors.aliyun.com/ubuntu/ focal-updates main restricted universe multiverse
    deb http://mirrors.aliyun.com/ubuntu/ focal-backports main restricted universe multiverse
    
    # deb-src http://mirrors.aliyun.com/ubuntu/ focal main restricted universe multiverse
    # deb-src http://mirrors.aliyun.com/ubuntu/ focal-security main restricted universe multiverse
    # deb-src http://mirrors.aliyun.com/ubuntu/ focal-updates main restricted universe multiverse
    # deb-src http://mirrors.aliyun.com/ubuntu/ focal-backports main restricted universe multiverse
    
    ## Pre-released source, not recommended.
    # deb http://mirrors.aliyun.com/ubuntu/ focal-proposed main restricted universe multiverse
    # deb-src http://mirrors.aliyun.com/ubuntu/ focal-proposed main restricted universe multiverse
    
    • 清华源
    deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal main restricted universe multiverse
    deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-updates main restricted universe multiverse
    deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-backports main restricted universe multiverse
    deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-security main restricted universe multiverse
    
    # deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal main restricted universe multiverse
    # deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-updates main restricted universe multiverse
    # deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-backports main restricted universe multiverse
    # deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-security main restricted universe multiverse
    
    ## Pre-released source, not recommended.
    # deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-proposed main restricted universe multiverse
    # deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-proposed main restricted universe multiverse
    

    将上述源中的focal替换为你对应版本的代号即可。

  • 备份原始的软件源文件,以防添加新镜像后出现问题。

 cd /etc/apt
 sudo cp sources.list sources.list.bak
  • 编辑软件源文件

    sudo vim sources.list
    
  • 更新软件源列表

    sudo apt-get update
    

2. 安装相关软件

  • 安装openjdk

    sudo apt-get install openjdk-17-jdk
    
  • 检查java版本

    java - version
    
  • 添加 Jenkins 存储库

    echo deb http://pkg.jenkins.io/debian binary/ | sudo tee /etc/apt/sources.list.d/jenkins.list
    
  • 添加Jenkins公钥

    curl -fsSL https://pkg.jenkins.io/debian/jenkins.io.key | gpg --dearmor -o /etc/apt/trusted.gpg.d/jenkins.gpg
    
  • 更新软件包列表

    sudo apt update
    
  • 安装Jenkins

    sudo apt install jenkins -y
    

3. 启动Jenkins

  • 安装完成后,启动Jenkins服务并设置为开机自启:

    sudo systemctl start jenkins
    sudo systemctl enable jenkins
    
  • 检查Jenkins状态

    sudo systemctl status jenkins
    

Snipaste_2024-10-28_16-03-38.png

  • 访问Jenkins

    http://your_server_ip:8080
    
  • 解锁Jenkins

    首次访问时,需要输入解锁密钥。可以通过以下命令找到密钥:

    sudo cat /var/lib/jenkins/secrets/initialAdminPassword
    

Snipaste_2024-10-28_16-02-42.png

  • 安装插件,因为是第一次安装不熟悉,所以选择推荐安装。

Jenkins集成GitHub

  • 新建Item,输入项目名称后,勾选Freestyle project,点击ok创建应用。
  • 配置Github仓库地址,Github账户私钥,以及分支匹配规则。

Snipaste_2024-10-28_16-18-29.png

  • 配置Github仓库地址,选择SSH。

  • Github账户公钥私钥设置。

    • 生成SSH密钥对

      使用以下命令生成新的SSH密钥对。请根据提示选择文件路径(默认情况下,密钥将保存在~/.ssh/id_rsa),并设置可选的密码短语以增加安全性。

      ssh-keygen -t rsa -b 4096 -C "your_email@example.com"
      
    • Enter键,或自己配置路径和密码。

    • 添加SSH公钥到SSH代理

      # 启动SSH代理
      eval "$(ssh-agent -s)"# 添加私钥
      ssh-add ~/.ssh/id_rsa
      
    • 复制SSH公钥

      cat ~/.ssh/id_rsa.pub
      
    • 在GitHub上添加SSH公钥

    • 测试连接

      ssh -T git@github.com
      

      出现下述消息代表成功:

      Hi username! You've successfully authenticated, but GitHub does not provide shell access.

  • 点击Credentials的Add按钮,将私钥添加进去。打开后选择Kind为SSH,id和description,username自行填写。最后添加Private Key,Private Key就是我们生成的私钥。

Snipaste_2024-10-28_16-47-01.png

部署Nextjs项目进行测试

  • 编写project build流程

    继续在project configure界面中配置build steps, 主要是build镜像,然后再启动当前容器。

    docker -v
    node -v
    npm -v
    //构建一个标签为jenkins-test的Docker镜像,. 表示Dockerfile在当前目录下
    docker build -t jenkins-test .
    docker stop jenkins-test || true
    docker rm jenkins-test || true
    //创建并运行一个新的Docker容器,-d 表示以分离模式(后台)运行容器
    //-p 3005:80 将容器的80端口映射到宿主机的3005端口
    //jenkins-test:latest 指定要运行的镜像
    docker run -d --name jenkins-test -p 3005:80 jenkins-test:latest
    
  • 更换docker镜像源为国内可用镜像源

    sudo vim  /etc/docker/daemon.json
    

    再该文件中添加

    {
      "registry-mirrors": ["https://docker.rainbond.cc","https://hub.xdark.top"]
    }
    

    重新加载json配置文件:

    sudo systemctl daemon-reload
    

    重启docker服务:

    sudo systemctl restart docker
    

    检查更换的镜像源是否生效:

    docker info
    

    如果在输出的日志中registry-mirrors: 下看到你配置的镜像源,就代表成功了。

  • 然后在项目中编写nginx.conf和Dockerfile、.dockerignore

    //nginx/nginx.conf
    events {
        worker_connections 1024;
    }
    
    http {
        include mime.types;
        default_type application/octet-stream;
    
        sendfile on;
        keepalive_timeout 65;
    
        server {
        //指定Nginx监听80端口(HTTP)
            listen 80;
            server_name _;
    
            location / {
        //指定文档根目录为/usr/share/nginx/html,即Nginx将从这个目录提供静态文件。
                root /usr/share/nginx/html;
                index index.html index.htm;
            }
    
            error_page 500 502 503 504 /50x.html;
            location = /50x.html {
                root /usr/share/nginx/html;
            }
        }
    }
    
    
    //Dockerfile
    FROM node:18-alpine AS builder
    
    WORKDIR /app
    COPY package*.json ./
    RUN npm install
    
    COPY . .
    
    RUN npm run build
    # 检查输出目录内容
    RUN ls -al /app/out 
    
    FROM nginx:stable-alpine
    
    COPY --from=builder /app/out /usr/share/nginx/html
    COPY --from=builder /app/nginx/nginx.conf /etc/nginx/nginx.conf
    # 暴露 Nginx 的默认端口
    EXPOSE 80
    
    # 启动 Nginx
    CMD ["nginx", "-g", "daemon off;"]
    
    //.dockerignore
    Dockerfile.dockerignore;
    node_modules;
    npm - debug.log;
    README.md.next.git;
    
    • 可以先在本地使用Docker打包试试,没有问题提交代码,在Jenkins点击构建,然后访问http://[ip地址]:3005,云服务器记得编辑安全组,放行3005端口。