基于 GitHub Workflow和 Docker 构建 NextJS

最近由于某个偶然的事件,突然对Docker、Github自动化部署产生了浓厚的兴趣,开始研究Docker部署Nextjs应用!

NextJS 是 vercel 创建的 JavaScript 框架。它允许你使用 React 构建无服务器 API、服务器端渲染和静态 Web 应用程序。 Vercel 提供与 GitHub、GitLab 和 BitHub 的开箱即用 CI/CD 集成。

但有时,我们希望将 NextJS 应用程序托管在 vercel 之外的其他平台上,例如 AWS、 Azure。

在本博客中,我们将了解如何使用 GitHub Workflow 和 Docker 构建 NextJS 应用程序。

设置 NextJS 应用程序

NextJS 建议使用 create-next-app ,它会自动为你设置所有内容。要创建项目,请运行:

npx create-next-app
# or
yarn create next-app

安装完成后,按照说明启动开发服务器。尝试编辑 pages/index.js 并在浏览器上查看结果。

设置 Dockerfile

我们将把 NextJS 应用程序打包到 Docker 镜像中。使用 Docker 的原因是当我们想要运行 NextJS 服务器时,我们不需要安装任何额外的软件包,如 nodejs、pm2 等。

Docker 会将所有内容捆绑在一起,并为我们提供可以在任何地方运行的镜像。以下是我的 NextJS 应用程序的示例 Dockerfile。

FROM node:lts-alpine

ENV NODE_ENV production
ENV NPM_CONFIG_LOGLEVEL warn

RUN mkdir /home/node/app/ && chown -R node:node /home/node/app

WORKDIR /home/node/app

COPY package.json package.json
COPY package-lock.json package-lock.json

USER node

RUN npm install --production

COPY --chown=node:node .next .next
COPY --chown=node:node public public

EXPOSE 3000

CMD npm start

现在,让我们逐步看看上面的 Dockerfile 中发生了什么。

  • 我们使用 node:lts-alpine 作为基础镜像。
  • 将环境变量设置为 production 。
  • 设置一个 app 文件夹,并以 node 用户作为所有者。
  • 将 package.json 和 package-lock.json 复制到映像中。
  • 运行 npm install production 仅安装生产依赖项。
  • 将 .next 和 public 文件夹复制到容器中。这是非常有趣的一步。为什么我们要复制文件夹而不是使用 next build 命令构建应用程序?我们将在下面详细讨论这一点。
  • 暴露端口 3000,以便我们的应用程序可以从容器中访问。
  • 最后,运行 npm start 命令来启动我们的 NextJS 应用服务器。

我们可以看到,我们没有对 Dockerfile 进行任何更改。它很容易理解并且简单明了。有趣的部分是我们将 .next 和 public 文件夹复制到容器中,而不是在容器内构建。

这是详细的解释:

  • 在NextJS应用程序中,我们可能需要使用NEXT_PUBLIC环境变量。构建时过程需要 NEXT_PUBLIC 变量。 (例如 Firebase Web 客户端)
  • 如果我们使用 Firebase Web 客户端,那么我们需要提供一些必需的变量,例如 firebase api_key、app_id、auth_domain。
  • 在本地开发应用程序时,我们将这些变量写入 .env 或 .env.local 文件中。但我们不、不应该也不得将此文件推送到 git 等 VCS 系统上。
  • 因此,当我们在本地构建应用程序时,它将使用 .env 中的这些变量,并且过程会顺利完成。但是,当我们使用 RUN next build 命令在 Docker 中构建应用程序时,构建命令将失败,因为我们没有在 docker 映像中提供这些变量。
  • 如果我们想在 docker 构建过程中构建 NextJS 应用程序,我们需要在 docker build 命令中使用 --build-args 来传递构建时变量。有两种方法可以做到这一点。
    1. 我们使用 ci 秘密变量并将它们传递到 docker build 命令中
    2. 我们创建一个 .env 文件,使用 base64 对其进行编码,将其作为 ci 秘密变量传递,在 docker 文件内使用 base64 对其进行解码,然后构建 docker 映像。
  • 如果我们的公共变量列表将来增长,这将变得非常难以传递和维护。
  • 因此,为了不使构建过程复杂化,我们将使用 ci job 在 docker 映像之外构建应用程序,然后将 .next 、 public 文件夹复制到 docker 映像中。
  • 要在 ci 中传递环境变量,有两种方法。
    1. 将环境变量作为秘密传递
    2. 传递 .env 文件的base64编码,在ci进程中对其进行解码,将文件写入我们项目文件夹的根目录,与本地开发相同并构建我们的应用程序。

GtiHub Workflow

Workflow是由一个或多个作业组成的可配置自动化流程。我们将使用 YAML 文件配置工作流程。你可以在这里。

下面是工作流程文件,我们将使用相同的。将此文件保存在 PROJECT_ROOT_FOLDER/.github/workflows/main.yml ,以便 GitHub 可以读取 yaml 文件并相应地设置操作。

name: Build & Publish

on:
  push:
    branches:
      - "**"             # all branches
      - "!dependabot/**"      # exclude dependbot branches
  workflow_dispatch:      # Manually run the workflow

jobs:
  next-build:
    if: ${{ github.event_name == 'workflow_dispatch' }}       # Run only if triggered manually
    runs-on: ubuntu-latest
    container: node:lts          # Use node LTS container version, same as Dockerfile base image
    steps:
      - name: Checkout
        uses: actions/checkout@v2       # Checkout the code
      - run: npm ci            #install dependencies
      - run: npm run build
        env:
          NEXT_PUBLIC_FIREBASE_API_KEY: ${{secrets.NEXT_PUBLIC_FIREBASE_API_KEY}}
          NEXT_PUBLIC_FIREBASE_APP_ID: ${{secrets.NEXT_PUBLIC_FIREBASE_APP_ID}}
          NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN: ${{secrets.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN}}
          NEXT_PUBLIC_FIREBASE_PROJECT_ID: ${{secrets.NEXT_PUBLIC_FIREBASE_PROJECT_ID}}
          NEXT_PUBLIC_SENTRY_DSN: ${{secrets.NEXT_PUBLIC_SENTRY_DSN}}
      - name: Upload Next build          # Upload the artifact
        uses: actions/upload-artifact@v2
        with:
          name: build
          path: |
            .next
            public
          retention-days: 7         # artifact retention duration, can be upto 30 days
  docker-push:
    needs: next-build        # Job depends on next-build(above) job
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v2
      - name: Download next build       # Download the above uploaded artifact
        uses: actions/download-artifact@v2
        with:
          name: build
      - name: Login to GitHub Container Registry
        uses: docker/login-action@v1
        with:
          registry: ghcr.io
          username: ${{ github.repository_owner }}
          password: ${{ secrets.CR_PAT }}
      - name: Build and Push Docker Images
        run: |
          export CURRENT_BRANCH=${GITHUB_REF#refs/heads/}
          export TAG=$([[ $CURRENT_BRANCH == "main" ]] && echo "latest" || echo $CURRENT_BRANCH)
          export GITHUB_REF_IMAGE=ghcr.io/$GITHUB_REPOSITORY:$GITHUB_SHA
          export GITHUB_BRANCH_IMAGE=ghcr.io/$GITHUB_REPOSITORY:$TAG
          docker build -t $GCR_IMAGE -t $GITHUB_REF_IMAGE -t $GITHUB_BRANCH_IMAGE .
          echo "Pushing Image to GitHub Container Registry"
          docker push $GITHUB_REF_IMAGE
          docker push $GITHUB_BRANCH_IMAGE

现在,让我们讨论一下 yaml 文件中发生了什么。

  • 我们需要传递要触发工作流程的事件的条件。在我们的例子中,我们希望它出现在推送事件上。它也可以像 [push, pull_request] 一样多个。你可以在这里。
  • 我们可以定义分支,我们希望这个工作流运行来观看。 !意味着要排除这些分支。
  • workflow_dispatch 手动运行构建过程。如果我们不写这个,我们的工作流程将在每次推送到存储库的任何分支时运行。你可以在这里。
  • 我们将构建过程分为 2 个作业。
    1. 下一个构建:
      • 在此步骤中,我们使用 node:lts 作为基础镜像,这必须与 Dockerfile 基础镜像相同
      • 我们保留这份作业手册,因为我们不希望每次推送代码时都运行该作业。所以我们在步骤中添加 if: ${{ github.event_name == ‘workflow_dispatch’ }} 条件。
      • 在 env 部分中,我们从机密中导出环境变量。所以我们需要在GitHub项目的secret中添加这些变量。请在此处阅读有关如何操作的更多信息。
      • 在下一步中,操作将检查代码,运行 npm ci 以安装依赖项,并运行 npm run build 使用导出的环境变量构建 NextJS 应用程序。
      • 最后,在成功构建后,CI 作业将使用 actions/upload-artifact@v2 操作将我们的构建文件夹作为工件上传到 GitHub 上,保留时间为 7 天,以便 ci 作业可以在 docker-build 作业中下载相同的文件夹并用它来构建图像。在构建文件夹中,我们包括 .next 和 public 文件夹。 .next 文件夹是由构建过程生成的,我们使用公共文件夹来存放 svgs、图像等资源。因此我们也希望保留该文件夹。
    1. docker-push:构建我们的 docker 镜像
      • 该作业依赖于 needs:next-build ,这意味着我们只有在成功 next-build 作业后才会看到该作业。如果我们不写这个,那么我们的两个作业将并行,并且该作业将失败,因为它将无法下载 build 工件。 next build 将上传工件,然后,ci 作业,我们将能够访问它。所以我们需要这样写,它将创建一个顺序作业,而不是并行作业。
      • CI 作业将检查代码,使用 actions/download-artifact@v2 下载构建工件文件夹并将其解压缩。
      • 我们希望将 docker 镜像托管在 GitHub 包上,为此,我们将使用 docker/login-action@v1 操作使用用户名和密码登录 GitHub 容器注册表服务器。我们还需要在存储库机密中传递 CR_PAT ,与 NEXT_PUBLIC 变量相同。我们还可以在此处添加其他注册表,例如 GCR、AWS ECR 等。
      • 接下来,ci 作业将获取 CURRENT_BRANCH 并相应地标记我们的 docker 构建。在这里,我们创建 2 个标签,一个是分支名称,如 dev 、 qa 、 uat 、 main ,另一个是 commit沙。
      • 之后,该作业将开始构建我们的 docker 镜像,并在成功构建后将其推送到 GitHub 包。在这里,我们也可以将其推送到其他注册表,例如 GCR、AWS ECR 等。
      • 最后,这个作业就会退出,我们的工作流程就成功通过了。

要运行作业,我们必须导航到存储库操作,你将在左侧边栏上看到带有 Build & Push 的工作流程。单击该链接,你将看到如下屏幕。n

有了这个,我们将能够构建和打包我们的 NextJS 应用程序。你将在屏幕截图下方看到操作屏幕。

帮助链接:

https://dev.to/thakkaryash94/build-nextjs-application-using-github-workflow-and-docker-3foj

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/480046.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

opencv自定义间隔帧获取视频转存为图片的GUI界面实现

该程序功能只将mp4转为jpg 希望得到您的指导 非常感谢您观看我的博客,我的博客是为了记录我的学习过程同时保留我的某些可重复利用代码以方便下次使用。如果您对我的博客有任何建议还请您不吝指出,非常感谢您对我的指导。 背景 在实现opencv逐帧获取…

酷开科技以内容技术服务和数字营销服务为核心,自主研发酷开系统

家庭场景的需求,才是大屏电视的目的。屏幕越大得到的画幕越大,消费者也就看的越清楚,从而获得更好的观看体验,尤其是家里有老人孩子的,为了得到更好的视觉效果,使得消费者对于大屏的需求也在增加。酷开系统…

python的O2O生鲜食品订购flask-django-nodejs-php

用户只能通过一些类似软件进行查看生鲜超市,这样的管理方式仍然是比较机械传统的,本文通过对市面上常见的线上管理系统与现实生活中结合问题的讨论,从一个微信小程序的O2O生鲜食品订购角度进行需求分析,提供一些新的思路&#xff…

【Canvas与艺术】绘制暗绿色汽车速度仪表盘

【原型】 【成果】 【代码】 <!DOCTYPE html> <html lang"utf-8"> <meta http-equiv"Content-Type" content"text/html; charsetutf-8"/> <head><title>暗绿色汽车速度仪表盘</title><style type"t…

从0到1实现RPC | 03 重载方法和参数类型转换

一、存在的问题 1.重载方法在当前的实现中还不支持&#xff0c;调用了会报错。 2.类型转换也还存在问题。 假设定义的接口如下&#xff0c;参数是float类型。 在Provider端接受到的是一个Double类型&#xff0c;这是因为web应用接收的请求后处理的类型。 在反射调用的时候就会…

大数据主要组件HDFS Iceberg Hadoop spark介绍

HDFSIceberghadoopspark HDFS 面向PB级数据存储的分布式文件系统&#xff0c;可以存储任意类型与格式的数据文件&#xff0c;包括结构化的数据以及非结构化的数据。HDFS将导入的大数据文件切割成小数据块&#xff0c;均匀分布到服务器集群中的各个节点&#xff0c;并且每个数据…

综合知识篇18-系统可靠性设计考点(2024年软考高级系统架构设计师冲刺知识点总结系列文章)

专栏系列文章: 2024高级系统架构设计师备考资料(高频考点&真题&经验)https://blog.csdn.net/seeker1994/category_12593400.html案例分析篇00-【历年案例分析真题考点汇总】与【专栏文章案例分析高频考点目录】(2024年软考高级系统架构设计师冲刺知识点总结-案例…

puppeteer使用示例云顶之弈官网

自己从0到1开发的&#xff0c;微信小程序【云顶宝藏】求求点个5星好评吧&#xff01; 需求&#xff1a;拿到所有英雄的信息 思路&#xff1a;点击每个英雄&#xff0c;进入英雄详情页&#xff0c;拿信息&#xff0c;并返回&#xff0c;继续下一个英雄** 最终效果 本地环境 win…

PostgreSQL技术大讲堂 - 第48讲:PG高可用实现keepalived

PostgreSQL从小白到专家&#xff0c;是从入门逐渐能力提升的一个系列教程&#xff0c;内容包括对PG基础的认知、包括安装使用、包括角色权限、包括维护管理、、等内容&#xff0c;希望对热爱PG、学习PG的同学们有帮助&#xff0c;欢迎持续关注CUUG PG技术大讲堂。 第48讲&#…

Spring Boot 3 极速搭建OAuth2认证框架

本篇环境 Java 17Spring Boot 3.2.3Spring Authorization Server 1.2.3开发工具 SpringToolSuite4Spring Boot 3.2.3 需要JDK 17及之上的版本。 项目初始化 项目可以使用Spring的初始化器生成, 也可以创建一个Maven类型的项目。 项目创建后的目录结构如下: 项目配置 使用 …

OpenHarmony游戏应用程序-实现的一个手柄游戏

介绍 本篇Codelab是基于TS扩展的声明式开发范式编程语言&#xff0c;以及OpenHarmony的分布式能力实现的一个手柄游戏。 说明&#xff1a; 本示例涉及使用系统接口&#xff0c;需要手动替换Full SDK才能编译通过。 完成本篇Codelab需要两台开发板&#xff0c;一台开发板作为游…

罗德与施瓦茨CMA180电信无线电测试仪

181/2461/8938产品概述&#xff1a; R&S CMA180 是适用于在 100 kHz 至 3 GHz 范围内操作的无线电系统的无线电通信测试仪。其技术完全基于数字信号处理及先进计算。 简介&#xff1a;R&S CMA180 无线电通信测试仪 R&SCMA180 是适用于在 100 kHz 至 3 GHz 范围内…

电商系统秒杀二 秒杀场景下如何进行限流

本章学习内容 1、在秒杀页面&#xff0c;客户点击秒杀后&#xff0c;在前台弹出一个验证码&#xff0c;需要用户输入验证码才能往后端发送请求&#xff0c;这样能够错开秒杀下单的时间。 2、通过验证码&#xff0c;对后台下单请求进行保护&#xff0c;防止刷单&#xff0c;即防…

通过JWT完成token登录验证

前言 什么是JWT&#xff1f; 全称是JSON Web token&#xff0c;是用于对应用程序上的用户进行身份验证的标记&#xff0c;使用 JWTS 的应用程序不再需要保存有关其用户的 cookie 或其他session数据 使用JWT的优势 提高了程序的可伸缩性&#xff0c;也极大的提高了应用程序的安全…

2024蓝桥杯每日一题(单调队列)

备战2024年蓝桥杯 -- 每日一题 Python大学A组 试题一&#xff1a;单调栈 试题二&#xff1a;滑动窗口 试题三&#xff1a;子矩阵 试题四&#xff1a;最大子序和 试题一&#xff1a;单调栈 【题目描述】 给定一个长度为 N 的整数数列&#xff0c;输出每…

第十四届蓝桥杯JavaB组省赛真题 - 幸运数字

进制转换可以参考如下的十进制&#xff0c;基本一样的&#xff0c;只是把10变成了其他数字&#xff0c; sum就是各个数位之和 public static int myUtil(int n) {int sum 0;while(n > 0) {sum n % 10;n / 10;}return sum;} 注意&#xff1a; 如果写在同一个类里面&…

基于javaSpringboot+mybatis+layui的装修验收管理系统设计和实现

基于javaSpringbootmybatislayui的装修验收管理系统设计和实现 博主介绍&#xff1a;多年java开发经验&#xff0c;专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 央顺技术团队 Java毕设项目精品实战案例《1000套》 欢迎点赞 收藏 ⭐留…

Java安全 反序列化(5) CC6链原理分析

Java安全 反序列化(5) CC6链原理分析 CC6学习的目的在于其可以无视jdk版本&#xff0c;这条链子更像CC1-LazyMap和URLDNS链子的缝合版 文章目录 Java安全 反序列化(5) CC6链原理分析前言一.CC6的原理和实现以及易错点我们如何实现调用LazyMap.get()方法一个易错点 二.完整CC6P…

亚马逊服务器ssh以及scp

ssh awspass.pem为创建服务器时创建的密钥&#xff0c;ubuntu用户 ssh -i "awspass.pem" ubuntuipscp scp -i "awspass.pem" -r dist/* ubuntuip:/home/ubuntu/

macOS下Java应用的打包和安装程序制作

文章目录 macOS应用程序结构Java应用打包JavaAppLauncherjpackage其它相关JDK命令附录JavaAppLauncher源码链接macOS应用程序结构 macOS通常以dmg或pkg作为软件发行包,安装到/Applications下后,结构比较统一。 info.plist里的CFBundleExecutable字段可以指定入口,如果不指定…