部署前端应用程序 — — 有趣的方式 别废话,直接说 TL;DR 问题 解开魔盒 结论 无耻的自我推销

2025-05-24

部署前端应用程序——有趣的方式

别废话了,直接说 TL;DR

问题

解开魔盒

结论

无耻的自我推销

在这篇文章中,我将向你展示如何使用 GitHub、Jenkins、Docker 和Digital Ocean部署我的前端应用程序。在我的学习过程中,我遇到了一些疑问,所以我决定把我学到的东西写在这篇文章里,作为我的笔记。

注意:我的朋友,作为拥有 15 年以上 DevOps 架构经验的专家和顾问大师,这篇文章并非为您而写;它面向的是那些刚刚开始探索 CI/CD 技术之美的读者。本文可能包含一些不好的做法,请谨慎对待。


别废话了,直接说 TL;DR

你跟我一样,四处看看,捡到子弹,然后就走人了。以下是 TL;DR 的总结:

  1. 启动 2 台安装了 Docker 的服务器:构建服务器和生产服务器
  2. 在构建服务器中安装 Jenkins(或任何其他 CI)
  3. 在你的 CI 中创建一个作业,在 Docker 镜像中克隆、安装和构建你的项目
  4. 在 GitHub 中设置 webhook,以便在每次推送时触发该作业
  5. 将 Docker 镜像推送到您的个人 Docker Hub
  6. 通过 SSH 连接到您的生产服务器
  7. 从 Docker Hub 拉取镜像并运行容器
  8. 利润

基于Docker的持续部署工作流程基于Docker的持续部署工作流程

谢谢阅读。


希望我的文章能引起你的注意,让你现在想了解更多细节。在接下来的段落中,我将概述我的思路,并解释我的部署流程是如何运作的。我不会深入探讨技术细节,而是会提供一些有用的链接,供你进一步研究。

问题

简单:我在 Angular 中开发了一个TypeScript AST 交互式查看器,并且我想部署它。

TypeScript AST 交互式查看器TypeScript AST 交互式查看器

可是……为什么不使用 Firebase、Google Engine、原生 FTP、GitHub 页面呢?你可能会问,就像“一键部署”一样。所有这些工具都很好用,但大多数要么太贵,要么感觉太神奇(没有什么比“gcloud app deploy”更好了),而且学习起来也不那么有趣!我想要理解、自动化并完全控制整个部署过程。我想要挑战,我想要学习,我想要从中获得乐趣(我的灵感真的来了)。

归根结底

我设立了自己的挑战,如下所示:

  1. 我想要推送代码并让它自动部署——也就是持续交付。

  2. 我想支付便宜的托管服务

让我们在黑盒图中绘制这些非功能性需求:

问题说明。从 GitHub 到 Live App。图标:由 Noun Project 的 ✦ Shmidt Sergey ✦ 设计的魔法问题说明。从 GitHub 到 Live App。图标:由 Noun Project 的 ✦ Shmidt Sergey ✦ 设计的魔法

解开魔盒

我将本章分为三个部分。每个部分将揭示我的“魔法盒”的一小部分:

  1. 从 GitHub 到 Magic

  2. 开发魔法

  3. 从魔术到 Live App


1. 从 GitHub 到 Magic

推送代码,坐下来放松,刷新上线的应用,然后赚钱。这就是我想要的。

选择我的 VPS(虚拟专用服务器)

第一步是搭建一个服务器,它可以从 GitHub 获取我的代码,并执行一系列命令(npm i && npm run build)。我不太确定下一步该做什么,但我知道我必须从这里开始。

在了解了市面上最好的 VPS 提供商之后,我最终选择了Digital Ocean很棒的教程,新手上手简单,DNS 管理也不错,价格也很合理——完全不费脑子。

无处不在的 CI 工具

注册后,我知道我需要某种工具来获取代码并自动化构建过程——CI (持续集成)工具。市面上有很多这样的工具,有些是专门为开源项目设计的,有些主要设计为自托管,有些是付费的,有些是免费的。我选择 Jenkins 主要是因为它的流水线概念,而且我对这个工具比较熟悉。

看了一些教程,我觉得启动并运行我的 Jenkins 实例相对容易。现在我需要告诉 Jenkins 每次我 git push 的时候都抓取我的代码。我发现网上有很多帖子教你如何设置一个从你的仓库指向 Jenkins Droplet IP 的 GitHub webhook。设置过程比我预想的要快(不过对于私有 GitHub 仓库来说就没那么简单了)。

让我们回顾一下

目前,我有一个运行 Linux 的 DO droplet,里面有一个 Jenkins 实例,每次 git push 都会从 GitHub 拉取代码。是不是很酷?让我们看看我们的“魔盒”是如何展现它的:

使用 Digital Ocean Droplet 和 Jenkins 的黑盒图使用 Digital Ocean Droplet 和 Jenkins 的黑盒图

有用的链接:

  1. 如何在 Digital Ocean 中创建 Droplet

  2. 如何在 DO Droplet 中安装 Jenkins

  3. 如何设置 Jenkins 管道

  4. 如何将 GitHub 与 Jenkins 集成


2. 发挥魔法

在接下来的几段中,我将阐述我的策略核心,该策略利用了 Docker 和 DO Droplet。让我们开始吧。

Docker 化一切

此时,我有一个dist文件夹,里面有一个index.html 文件及其依赖项,一切准备就绪。我知道我需要启动一个 Web 服务器来通过 Web 提供这些文件。接下来,让我们在同一台服务器上安装nginx(或Apache)来提供这些文件。我还需要安装 Node 和一些全局 Node 包。很简单,我们开始吧……

“但是等等,卡洛斯,那个嗯……感觉不太对劲——你最终会在服务器上安装一大堆东西,管理依赖项以后会变得非常麻烦……只是说说而已”——内心的自我

确实,我需要一种方法来封装依赖项、dist组件,甚至 Web 服务器,以免弄乱我的服务器。那就用Docker吧。它可以让我构建一个镜像,将 Web 服务器运行在服务器的一个端口上,而服务器文件系统几乎不会察觉到我刚才的操作。是不是很酷?

我为我的应用程序设置了一个Dockerfile,并在 Jenkins 中编辑了作业,构建了一个 Docker 镜像,并运行了暴露 80 端口的容器。一切运行正常。我可以通过http://my.server.ip实时访问我的应用程序。

关于扩展和其他

我计划在同一台服务器上部署多个采用相同模式的应用程序。这样一来,将 Jenkins 和所有容器都运行在同一台服务器上就显得不合理了。我感觉我可以做得更好——我想把关注点分开。当然,我可以同时使用不同的用户,让 Jenkins 驻留在自己的用户中等等,但我内心深处真的想保留一台专门用于构建应用程序的机器。

基于此前提,我创建了另一个 Droplet(又名服务器),它内存较小(不做繁重工作,仅用于服务 Web 应用),并安装了 Docker,因为它应该能够运行 Docker 容器。然后,我会在这台服务器上运行我的所有应用。这样可以实现良好的扩展性,因为我可以轻松更改构建服务器上的内存分配,同时不影响我的应用。

让我们回顾一下

我们取得了相当不错的进展。我们已经确定使用 Docker 作为核心构建机制,并且为了便于维护,我们还决定在另一台服务器上部署一个独立的生产服务器。

使用 Docker 和 2 个 DO droplet 的部署工作流程使用 Docker 和 2 个 DO droplet 的部署工作流程

有用的链接

  1. 如何将AngularReactVue应用程序 Docker 化。

  2. 如何在 Ubuntu 中安装 Docker


3. 从魔术到直播应用

我不确定如何集成我的服务器(构建 + 生产)。在寻求帮助和研究之后,我得出结论,对于我的特定用例,我可以实现以下工作流程:

  1. 在Build Server中构建 docker 镜像

  2. 将 Docker 镜像推送到我的Docker Hub

  3. 通过 SSH 登录我的生产服务器

  4. 从Docker Hub拉取镜像并运行容器

这很合理,因为我不需要使用 docker-machine 或 Kubernetes 之类的工具来编排我的服务器。它很好用,简单易用,而且对我来说看起来足够简洁。

安全注意事项:建议在生产服务器上禁用基于密码的身份验证,并在构建服务器上仅启用基于密钥的身份验证。也就是说,如果不从构建服务器登录,几乎不可能登录到生产服务器。

给我看一些代码

一篇技术文章如果不展示一些代码就不算是真正的技术文章。让我们看看在集成整个流程时,Jenkins 流水线在 CI 中是什么样子的:

#!/usr/bin/env groovy

node {
  def app

  stage("Clone") {
    git 'https://github.com/caroso1222/ast-viewer.git'
  }

  stage("Build") {
    app = docker.build("caroso1222/ts-ast-viewer")
  }

  stage("Push") {
    docker.withRegistry("https://registry.hub.docker.com", "docker-hub-credentials") {
      app.push("${env.BUILD_ID}")
      app.push("latest")
    }
  }

  stage("Deploy") {
    sh "ssh root@my.server.ip \"docker stop ast_0 && \
        docker rm ast_0 && \
        docker pull caroso1222/ts-ast-viewer:latest && \
        docker run -d --name=ast_0 -p 8080:80 caroso1222/ts-ast-viewer:latest\""
  }
}

我在代码片段中标记了一些行,让我们快速浏览一下:

  1. 根据Dockerfile构建 docker 镜像

  2. 将 Docker 镜像推送到我的Docker Hub帐户。

  3. 通过 SSH 进入生产服务器

  4. 从我的 Docker Hub 拉取镜像

  5. 从我们刚刚拉取的镜像中运行容器。我将容器运行在 8080 端口上,这是因为我设置了 Nginx,通过子域名proxy_pass将流量路由到同一服务器中的多个容器(例如,domainA.com 服务于容器 A,domainB.com 服务于容器 B)。我不会详细阐述这项技术,因为它超出了本文的讨论范围。

正如本文开头所述,此流水线在每个git pushmaster 分支上运行。下图展示了 Jenkins 每次部署的流程。顺便说一句,我很喜欢这张图片,因为它描绘了我在深入研究之前脑海中对这个挑战的设想。

Jenkins 流水线的阶段视图。每一行代表由 git push 触发的一次部署。Jenkins 流水线的阶段视图。每一行代表由 git push 触发的一次部署。

让我们总结一下

我们终于成功了。我们解开了黑匣子。所有秘密都已揭晓,我们也能够覆盖其每一个组件。现在,让我们来看看最终的部署工作流程是什么样的!

本文涵盖的完整部署策略图。Docker 镜像在构建服务器中构建,经过 Docker Hub 传输,最终到达生产服务器。本文涵盖的完整部署策略图。Docker 镜像在构建服务器中构建,经过 Docker Hub 传输,最终到达生产服务器。

有用的链接

  1. 在 Ubuntu 中启用基于密钥的身份验证

  2. 运行 Docker 容器并公开端口


结论

市面上部署策略种类繁多,各有优缺点,并且每一种都依赖于不同的技术栈,各有各的特色。这正是它的魅力所在。在本文中,我仅介绍了其中一种策略,它让我能够完全控制使用两台服务器、一个持续集成 (CI) 和 Docker 的自定义部署流水线。

如果你对我们讨论的概念不太熟悉,这一切听起来可能有点吓人。别担心,我说。这篇文章很长,主要是因为它总结了我近三个月的学习历程,我每晚都要花一两个小时在这些服务器上磨练,阅读一些我不太熟悉的东西。

即使你是一位专注于浏览器领域的前端开发者,我仍然认为熟悉全栈开发非常有价值。这将使你在公司讨论 DevOps 问题时,能够进行扎实的沟通并形成自己的观点。与其说“嗯,那不是我的事,你们这些运维人员自己解决吧”,不如说“你们是专家,但这是我对此事的看法……”。

我希望你能得到一些启发,继续实施你的个人部署管道,并了解所有这些 DevOps 技术——未来会充满乐趣!


无耻的自我推销

我不是业余的 SoundCloud 说唱歌手,也不是在 Patreon 上寻找资金。我只是帮助开发者在Toptal等顶级远程平台找到工作。我撰写有关职业发展、面试技巧CSS 的趣味文章,并时不时在 DEV 上发布一些讨论

现在我正在写一本免费指南,里面有很多技巧和窍门,教你如何在远程技术面试中脱颖而出。如果你感兴趣,可以在这里注册候补名单,成为第一个获得它的人。

替代文本

在 Twitter 上找到我@caroso1222,别忘了跟我打招呼!

文章来源:https://dev.to/caroso1222/deploying-frontend-applications-the-fun-way-1fpf
PREV
你从未见过的 Hashmap 伪装成对象或集合的 Hashmap 读写 Hash 的高效方法。至于“哈希”函数,字符计数,免费性能提升,输入越大,性能越好。保持好奇心,我写了一本电子书来帮助你
NEXT
获得顶级远程工作的最佳网站[+10万美元/年] Toptal CrossOver TripleByte Turing Arc Gun.io 准备并顺利通过面试