带有 dockerized ReactJS App 的 GitLab CI/CD 示例 🚀

2025-05-25

带有 dockerized ReactJS App 的 GitLab CI/CD 示例 🚀

下午好!
今天我们将使用 GitLab 创建 CI/CD 流水线,实现 ReactJS docker 部署的自动化。

介绍

所以今天我们将使用 Create-react-app 来生成一个简单的 ReactJS 项目,然后我们将在本地环境中对该项目进行 docker 化以进行测试,然后我们将把代码上传到 GitLab 存储库以便使用它的 CI/CD 管道功能,然后将我们的 docker 化应用程序部署到 Digital Ocean droplet 中。

因此,要遵循本教程,您应该具备:

1.- 已安装 create-react-app ⚛️
2.- 已安装 docker 🐳
3.- 对 docker 有很好的理解 🐳
4.- 对 nginx 有很好的理解 🆖
5.- GitLab 帐户 🦊
6.- Digital Ocean 帐户 🌊

让我们开始吧💪

1.- 让我们使用 create-react-app 生成一个 React 项目

我将创建一个名为 Budgefy 🐖 的项目(一个我从未完成的旧项目),我们只需要输入:



npx create-react-app budgefy


Enter fullscreen mode Exit fullscreen mode

我们将看到类似这样的内容:
控制台输出

项目成功创建后,让我们验证一下我们是否可以通过输入以下内容来启动该项目:



cd budgefy
npm start


Enter fullscreen mode Exit fullscreen mode

它将在我们的浏览器中打开一个新标签页并运行该项目,您将看到以下内容:

控制台输出

让我们检查测试是否也通过了,输入以下内容:(
首先按 ctrl + c 停止项目)



npm test


Enter fullscreen mode Exit fullscreen mode

控制台中会提示:

测试菜单

然后只需输入“a”即可运行所有测试,我们期望得到以下输出:

测试输出

2.- 让我们将应用程序docker化

这不是一篇关于docker的文章,所以我假设你对docker有很好的理解。我计划在几天甚至几周后写一篇关于docker的文章,我会尽快完成。总之,这是我们的docker文件(该文件将位于我们项目的根文件夹中):



# Set the base image to node:12-alpine
FROM node:12-alpine as build

# Specify where our app will live in the container
WORKDIR /app

# Copy the React App to the container
COPY . /app/

# Prepare the container for building React
RUN npm install
RUN npm install react-scripts@3.0.1 -g
# We want the production version
RUN npm run build

# Prepare nginx
FROM nginx:1.16.0-alpine
COPY --from=build /app/build /usr/share/nginx/html
RUN rm /etc/nginx/conf.d/default.conf
COPY nginx/nginx.conf /etc/nginx/conf.d

# Fire up nginx
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]


Enter fullscreen mode Exit fullscreen mode

我们需要创建一个 .dockerignore 文件(该文件将位于我们项目的根文件夹中)来忽略我们的 dockerized 应用程序中的 node_modules 文件夹,因此,我们的 .dockerignore 的内容如下:



node_modules


Enter fullscreen mode Exit fullscreen mode

此外,由于我们将使用 nginx(我将在另一篇文章中介绍 nginx),我们需要在应用程序的根文件夹中创建 nginx 文件夹,并在其中创建包含以下内容的 nginx.conf 文件:



server {

  listen 80;

  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;
  }

}



Enter fullscreen mode Exit fullscreen mode

现在我们已经准备好文件了,请确保您的终端位于 Dockerfile 所在的同一文件夹中,然后运行此命令来创建我们的映像:



docker build --tag budgefy:1.0 .


Enter fullscreen mode Exit fullscreen mode

docker 将在构建过程中记录大量消息,最后我们可以通过输入 docker images 来验证我们的镜像是否已创建,我们应该看到我们的budgefy镜像,如下所示:

Docker 镜像

现在我们可以使用以下命令运行我们的图像:



docker run -p 4250:80 -d --name bugefycontainer budgefy:1.0


Enter fullscreen mode Exit fullscreen mode

运行我们的镜像后,我们将看到类似这样的输出,我们将看到我们的应用程序正在运行一个容器

Docker 镜像

所以现在,如果您使用的是 ubuntu,您可以转到 localhost:4250,您将看到我们的 dockerized 应用程序正在运行,在我的情况下,因为我在 Windows 中使用 Docker,所以我必须通过 docker 提供给我的 IP 访问该应用程序,这是我们的结果:

Docker化应用程序正在运行

太好了,一切正常!!!😎💪

下一步是什么?让我们将代码上传到 GitLab!

3.- 在 GitLab 上创建项目

要在 GitLab 上创建项目非常简单,只需登录您的帐户并单击“新建项目”按钮:

创建新项目

然后只需填写名称字段,让我们将其保留为私人存储库并单击“创建项目”:

在 GitLab 上创建新项目

太棒了!我们有了项目,让我们上传代码,在我们的 GitLab 中我们将看到说明,就我而言,我需要遵循以下说明:

将我们的代码上传到 GitLab

按照这些说明操作后,我们将在 GitLab 存储库中看到我们的代码,如下图所示:

更新了存储库

4.- 让我们创建我们的管道

为了创建我们的管道,我们需要在项目的根文件夹中添加一个名为 .gitlab-ci.yml 的新文件

一旦我们添加了 .gitlab-ci.yml 文件并将其推送到我们的 GitLab 仓库,GitLab 就会检测到该文件,然后 GitLab 运行器会遍历该文件并运行我们在此处指定的所有作业。默认情况下,GitLab 提供了“共享运行器”,除非我们在文件中指定其他内容,否则它们将自动运行流水线。我们也可以使用“特定运行器”,这意味着在一台允许您根据需要自定义运行器的机器上安装 GitLab 运行器服务,但在本例中,我们将使用共享运行器。

在这个文件中,我们可以定义我们想要运行的脚本,我们可以按顺序或并行运行命令,我们可以定义我们想要部署应用程序的位置,并指定我们是否要自动运行脚本或手动触发其中任何一个。

我们需要按照适合我们应用程序的顺序并根据我们想要执行的测试来组织脚本

让我们看下一个例子:



stages:
  - build
  - test

build:
  stage: build
  image: node
  script: 
    - echo "Start building App"
    - npm install
    - npm build
    - echo "Build successfully!"

test:
  stage: test
  image: node
  script:
    - echo "Testing App"
    - npm install
    - CI=true npm test
    - echo "Test successfully!"



Enter fullscreen mode Exit fullscreen mode

让我们将此代码包含在我们的 .gitlab-ci.yml 文件中,并将这些更改提交到我们的 repo。

如果我们转到我们的 repo,我们将看到我们的管道正在运行,让我们看一下我们的管道,我们需要转到 CI/CD,然后转到侧边栏中的管道:

侧边栏菜单

然后点击我们的状态按钮:

管道

然后我们将看到我们的工作进度/状态,正如您在此处看到的:

工作状态

由于我们在本地测试我们的应用程序,所以一切都应该按预期工作,最终我们将看到成功的消息。

这是一个非常简单的示例,用于演示管道的工作原理。我们有两个阶段,第一个阶段我们只构建应用程序,第二个阶段我们运行测试。你可能会问,为什么要运行两次“npm install”,肯定有更好的方法。

这是因为每个作业都在一个新的空实例中运行,并且我们没有来自以前作业的任何数据,为了共享数据,我们需要使用工件或缓存,有什么区别?

文物:

1.- 我通常会使用构建工具的输出。2.-
在 GitLab CI 中,设计用于保存构建过程中的一些编译/生成路径。3.-
工件可用于在阶段/作业之间传递数据。

缓存:

1.- 缓存不应用于存储构建结果
2.- 缓存仅应用于作为项目依赖项的临时存储。

因此,让我们改进我们的管道:



stages:
  - build
  - test

build:
  stage: build
  image: node
  script: 
    - echo "Start building App"
    - npm install
    - npm build
    - echo "Build successfully!"
    artifacts:
      expire_in: 1 hour
      paths:
        - build
        - node_modules/

test:
  stage: test
  image: node
  script:
    - echo "Testing App"
    - CI=true npm test
    - echo "Test successfully!"


Enter fullscreen mode Exit fullscreen mode

让我们提交代码,然后我们会看到一切仍然有效,这很好!🌟

5.- 让我们在管道中构建我们的图像

现在让我们创建另一个阶段来将我们的应用程序docker化。看一下我们的“docker-build”阶段,我们的文件将如下所示:



stages:
  - build
  - test
  - docker-build

build:
  stage: build
  image: node
  script: 
    - echo "Start building App"
    - npm install
    - npm build
    - echo "Build successfully!"
  artifacts:
    expire_in: 1 hour
    paths:
      - build
      - node_modules/

test:
  stage: test
  image: node
  script:
    - echo "Testing App"
    - CI=true npm test
    - echo "Test successfully!"

docker-build:
  stage: docker-build
  image: docker:latest
  services: 
    - name: docker:19.03.8-dind
  before_script:
    - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
  script:
    - docker build --pull -t "$CI_REGISTRY_IMAGE" .
    - docker push "$CI_REGISTRY_IMAGE"




Enter fullscreen mode Exit fullscreen mode

提交并推送我们的代码后,管道将需要几分钟才能完成作业,如果一切顺利,您将看到所有作业都已通过,如下所示:

所有作业均已通过

另外,如果您进入 GitLab 仪表板的侧边栏,进入“软件包和注册表”,然后进入“容器注册表”

软件包和注册表

您将看到我们刚刚构建的图像😎

Docker 镜像

太棒了!👌

那么,我们的“docker-build”阶段发生了什么?🐳
基本上与我们在本地环境中构建 docker 镜像的操作相同,我们使用 docker 镜像是因为我们需要运行一些 docker 命令,还需要使用 docker-dind 服务,在本例中我使用这个特定版本 (docker:19.03.8-dind) 因为我在使用其他版本时遇到了一些问题,之后我们只需登录到我们的 GitLab 帐户并构建镜像并将其推送到 GitLab 注册表即可。

我们还使用了一些预定义的 GitLab 变量,那是什么?

预定义环境变量:

GitLab 提供了一组预定义变量,我们可以看到并使用它们,如果其中一些对我们的特定需求有用,您可以在此处查看完整列表(https://docs.gitlab.com/ee/ci/variables/predefined_variables.html)在我们的特定情况下,我们使用以下变量:

1.- CI_REGISTRY_USER:用于将容器推送到当前项目的 GitLab 容器注册表的用户名。🤵

2.- CI_REGISTRY_PASSWORD:用于将容器推送到当前项目的 GitLab 容器注册表的密码。🙈

3.- CI_REGISTRY:如果启用了容器注册表,则返回 GitLab 容器注册表的地址。如果在注册表配置中指定了 :port 值,则此变量包含该值。🔗

4.- CI_REGISTRY_IMAGE:如果项目启用了容器注册表,它将返回与特定项目绑定的注册表的地址🔗

那么,下一步是什么?我们需要将应用部署到服务器上!首先,让我们

6.- 添加部署阶段

再次,我们需要执行在本地环境中所做的事情,我们需要从 GitLab 注册表中提取镜像,然后运行它,就是这样!我们的应用程序将在服务器上可用。因此,首先让我们在 .gitlab-ci.yml 文件中添加一些命令,该文件的最终版本将是:



stages:
  - build
  - test
  - docker-build
  - deploy

build:
  stage: build
  image: node
  script: 
    - echo "Start building App"
    - npm install
    - npm build
    - echo "Build successfully!"
  artifacts:
    expire_in: 1 hour
    paths:
      - build
      - node_modules/

test:
  stage: test
  image: node
  script:
    - echo "Testing App"
    - CI=true npm test
    - echo "Test successfully!"

docker-build:
  stage: docker-build
  image: docker:latest
  services: 
    - name: docker:19.03.8-dind
  before_script:
    - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
  script:
    - docker build --pull -t "$CI_REGISTRY_IMAGE" .
    - docker push "$CI_REGISTRY_IMAGE"
    - echo "Registry image:" $CI_REGISTRY_IMAGE

deploy:
  stage: deploy
  image: kroniak/ssh-client
  before_script:
    - echo "deploying app"
  script:
    - chmod 400 $SSH_PRIVATE_KEY
    - ssh -o StrictHostKeyChecking=no -i $SSH_PRIVATE_KEY root@$PROD_SERVER_IP "docker pull registry.gitlab.com/alfredomartinezzz/budgefy"
    - ssh -o StrictHostKeyChecking=no -i $SSH_PRIVATE_KEY root@$PROD_SERVER_IP "docker stop budgefycontainer || true && docker rm budgefycontainer || true"
    - ssh -o StrictHostKeyChecking=no -i $SSH_PRIVATE_KEY root@$PROD_SERVER_IP "docker run -p 3001:80 -d --name budgefycontainer registry.gitlab.com/alfredomartinezzz/budgefy"



Enter fullscreen mode Exit fullscreen mode

我们在做什么?

为了实现这一点,我们需要在管道和服务器之间建立 ssh 连接,为此我们需要将服务器的 IP 存储为环境变量以及私钥。

因此,在此阶段,我们将使用带有 ssh 客户端(kroniak/ssh-client)的图像,并将逐个运行命令,如下所示:



ssh -o StrictHostKeyChecking=no -i <private_key> <user_in_server>@<server_ip> "<command>"


Enter fullscreen mode Exit fullscreen mode

但是如果我们想要测试我们的最后阶段,我们需要让我们的服务器做好准备!

不要提交/推送此更改(它将引发错误)我们稍后会执行此操作

6.- 在 Digital Ocean 中创建我们的服务器

您不需要使用 Digital Ocean,但我认为它是让我们的服务器运行起来的一种非常快速和简单的选择!您只需要创建一个帐户,大多数情况下他们会提供 100 个 dll,您可以在接下来的 60 天内使用,我们将使用的服务器每月花费 5 个 dll,所以我发现 Digital Ocean 对于练习和学习非常有用。

因此,只需继续创建您的帐户,它会询问您的付款方式,您需要提供您的信用卡,但它不会向您收取一分钱。

拥有帐户后,转到仪表板并创建 Droplet

创建Droplet

然后您需要选择您的 droplet 要求,我们需要一个非常基本的要求,选择每月 5 个 dll 中的一个,如下图所示:

选择我们的要求

您可以保留其余选项,只需输入密码并为您的服务器起一个很酷的名字😎

创建我们的Droplet

就这样,大约需要 55 秒即可启动并运行你的服务器,很简单不是吗?👌

现在您可以看到您的服务器及其 IP!

我们的服务器

现在,让我们从本地环境通过 SSH 进入我们的服务器,让我们转到我们的终端(我使用的是 Windows 的 cmder 终端,如果您使用的是常规终端,也许您需要下载 putty 或者您可以从 powershell 建立 ssh 连接,如果您使用的是 Mac 或 Linux,您可以从常规终端执行此操作),所以我们只需要输入:



ssh root@<server_ip>


Enter fullscreen mode Exit fullscreen mode

如果您想建立连接,它会提示您一条消息:

访问我们的服务器

然后它会要求您输入创建 droplet 时设置的密码,只需输入即可进入!

你已加入!

现在我们有一个干净的 ubuntu 服务器,我们需要安装 docker,然后登录到我们的 GitLab 帐户,拉取我们的项目映像并运行它。

这是在我们的 ubuntu 服务器中安装 docker 的非常简单的指南:https://www.digitalocean.com/community/tutorials/how-to-install-and-use-docker-on-ubuntu-20-04

我们可以通过输入 docker -v 或/和 docker ps 列出我们的容器来验证 docker 是否已成功安装:

验证docker安装

因此,让我们转到 GitLab 中的容器注册表,我们会发现一个蓝色按钮,上面写着“CLI 命令”:

CLI 命令

我们需要登录我们的 GitLab 帐户,然后我们需要在我们的服务器中手动拉取并运行图像,所以让我们这样做吧。

让我们登录:

登录

然后让我们拉取我们的图像:

拉取我们的镜像

然后让我们用这个命令运行它,如果图像名称不同,请确保更改图像名称,如果您想使用另一个端口,只需更改它,在我的情况下,我将用这个命令运行它:



docker run -p 3005:80 -d --name budgefycontainer registry.gitlab.com/alfredomartinezzz/budgefy


Enter fullscreen mode Exit fullscreen mode

从服务器运行我们的图像

我们可以运行 docker ps 命令来查看我们的容器:

列出我们的容器

然后让我们进入浏览器并转到我们的 SERVER_IP:PORT

就我而言,我将通过端口 3005 访问该应用程序,我的服务器的 IP 是:138.68.254.184

现在我们就可以在服务器中看到我们的应用程序启动并运行了!就这么简单!👍

应用程序在服务器上运行

因此,现在我们验证我们的服务器运行正常,并且我们可以在那里运行我们的应用程序,我们需要将服务器的私钥作为环境变量存储在我们的 GitLab 项目中,并且我们还需要存储 IP 地址,所以让我们这样做。

让我们转到 GitLab 仪表板中的侧边栏,然后单击设置,然后单击 CI/CD,我们将看到很多选项,让我们展开变量部分:

设置

然后点击“添加变量”按钮,会弹出一个模式,我们的变量键将是“PROD_SERVER_IP”,值将是我们的服务器IP,其余选项保持不变,然后点击“添加变量”。

现在我们需要添加私钥,但首先让我们在服务器中创建一个。转到你的服务器,打开终端并输入以下内容:



ssh-keygen -m PEM -t rsa -b 4096 -C "your_email@example.com"


Enter fullscreen mode Exit fullscreen mode

它会要求您提供一个文件来保存密钥,只需键入 Enter 即可使用默认文件,然后它会要求您输入密码,在这个例子中,让我们将其留空并按几次 Enter,然后您将看到一条成功消息,然后我们需要复制我们的私钥并将其添加到 GitLab 上的项目中,我们可以运行此命令来查看我们的私钥:

ssh 密钥生成

然后我们复制我们的私钥

让我们输入 cat ~/.ssh/id_rsa 并复制输出,创建一个新变量,密钥将是 SSH_PRIVATE_KEY,值将是我们的私钥:



cat ~/.ssh/id_rsa


Enter fullscreen mode Exit fullscreen mode

因此,让我们复制内容并粘贴它。

添加我们的私钥

然后我们需要进入我们的服务器并运行此命令:



cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys


Enter fullscreen mode Exit fullscreen mode

现在一切准备就绪,让我们提交并推送我们的代码来查看结果。

最终结果

就这样,现在每次我们将代码推送到我们的仓库时,我们的管道都会构建我们的应用程序,然后它将运行我们的测试,它将对我们的应用程序进行 dockerize 并将其推送到 GitLab 注册表,最后它将我们的应用程序部署到我们的服务器中!

我希望你喜欢这篇文章并且觉得它有用,如果你喜欢它,请随意分享,如果你对这篇文章有任何想法,请随时在这里发表评论或联系我,任何反馈都将不胜感激。

祝你有美好的一天!✌️

文章来源:https://dev.to/christianmontero/gitlab-ci-cd-example-with-a-dockerized-reactjs-app-1cda
PREV
通过制作 2D 平台游戏学习 Godot 4 — 第 1 部分:项目编辑器和概述
NEXT
JavaScript 中的类 什么是类?JavaScript 中的类 公共与私有访问器方法 Final 语句