Docker 化现代 Web 应用程序
如今,大多数网站都是单页应用(简称 SPA),单个入口文件负责处理用户可能访问的所有路由。在云托管的潮流下,你可能需要将 SPA 进行“docker 化”。也就是说,将其封装到 Docker 镜像中,并以容器的形式运行。
在本文中,我们将探讨如何实现这一点。我们将构建一个简单的 SPA,它只会告诉用户他们当前正在访问我们网站的哪个路由。这意味着您不仅可以访问 SPA /
,还可以访问您能想到的任何路由,例如/unicorn
或/rainbow
。这个 SPA 非常简单且手工制作,但您可以将其视为任何您想要部署的复杂 React、Angular 或 Vue 应用的代表。最后,我们将把这个 SPA 构建到 Docker 镜像中,并将其作为容器部署。
我们将详细介绍我们正在做的所有基础知识。因此,无论您是 Docker 的资深用户,只是无法在集群上运行 SPA,还是一位优秀的 Web 开发人员,负责处理 Docker 相关事务,这篇文章都适合您。
该网站
我们的网站将非常简单。只有一个标题和一段文字,告诉用户他们当前所在的位置window.location
。下方我们将提供一些导航链接,方便用户前往几条路线。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Simple SPA</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body style="font-family: sans-serif;">
<h1>Welcome to a simple SPA</h1>
<p>You are on: <span id="locationSpan"></span></p>
<p>You could go to:</p>
<ul>
<li><a href="/">Home</a></li>
<li><a href="/unicorn">Unicorn</a></li>
<li><a href="/rainbow">Rainbow</a></li>
</ul>
<script>
const span = document.querySelector('#locationSpan')
span.innerHTML = window.location.pathname
</script>
</body>
</html>
要在本地测试,您可以初始化 package.json,安装live-server并向 package.json 添加启动脚本"start": "live-server --entry-file=index.html"
。
npm init
npm i -D live-server
# Now add the script o your package.json before running:
npm start
继续并单击几个链接来移动或在导航栏中输入另一条路径。
我们的超级简单的 SPA 会告诉用户他们在哪里并允许他们
导航。
你可能已经注意到,我们正在做一些事情来让 SPA 按预期工作。我们需要告诉 live-server 在所有它找不到文件的路由上提供 index.html 文件。我们使用 来实现这一点--entry-file=index.html
。你可以尝试运行不带 --entry-file 参数的 ive-server,看看会发生什么。
记住这个标志,因为我们需要对我们的 dockerization 做一些等效的事情。
请访问dockerized-spa.now.sh查看实际运行的网站。(已实现 docker 化并托管在 Now.sh 上。)
幼稚的 Docker 尝试
Docker是一个创建镜像的系统,这些镜像可以作为容器运行。你可以将 Docker 镜像视为可以在多个平台上运行的超轻量级虚拟机(在 Docker 镜像中,容器就是运行的虚拟机)。Docker 的奇妙之处在于,一旦你构建了一个 Docker 镜像并在某个地方运行它,它就能在任何地方运行。一旦我们成功地在本地构建了一个可以作为容器运行的 Docker 镜像,我们就知道它也可以在 AWS、GCP、Portainer 或贵公司可能使用的其他平台上运行。
Docker 解决了臭名昭著的“它在我的机器上能用”的问题。容器
无论在哪儿启动,都能以相同的方式运行!
首先,你需要一个 Dockerfile。我们先从Naive-Dockerfile开始。我们将在其中定义创建镜像所需的步骤。在本例中,我们只需要一个可以服务网站并保存单页应用程序副本的镜像。
FROM nginx
COPY index.html /usr/share/nginx/html
这里我们以镜像为基础nginx
。NGINX是一个简单轻量级的 Web 服务器,可以为我们的 index.html 提供服务。为了实现这一点,我们将网站复制到 NGINX 将要服务的文件夹中。现在我们有了这些,让我们构建并运行镜像。
上面我们首先使用Docker build 命令创建 Docker 镜像。使用-f
Flag 告诉 Docker 使用哪个“Dockerfile”,哪些文件包含构建镜像所需的配置。该-t
Flag 为我们的 Docker 镜像添加了标签,赋予了镜像一个可以用来运行它的名称。
然后,我们使用Docker run 命令将镜像作为容器启动。通过使用-p
它可以指定暴露端口的映射,在本例中,我们希望在本地机器上通过8888端口访问暴露的80端口。接下来,打开http://localhost:8888/来查看结果。
这并不是我们想象的那样……
采用我们的“简单 Docker”方法,除了入口路线之外的所有路线都/
显示 NGINX 的 404 页面。
docker rmi -f docker-spa
让我们使用Dockerrmi命令进行清理,并-f
强制它删除我们创建的镜像。是时候撸起袖子,让它完全正常工作了。
增强 SPA 功能
还记得上面我们需要将--entry-file=index.html
live-server 参数传递给它,以便它在每次路由找不到文件时都能提供index.html文件吗?我们现在需要的是 NGINX 中与此参数等效的参数。
为此,我们将使用 NGINX 配置并将其添加到我们的 Docker 镜像中。
server {
listen 80;
listen [::]:80 default ipv6only=on;
root /usr/share/nginx/html;
index index.html;
server_name _; # all hostnames
location / {
try_files $uri /index.html;
}
}
在上面的配置中,我们告诉 NGINX 无论域名是什么,都接受80端口的流量。然后,我们告诉它解析以斜杠结尾的路径,index.html
并最后指定所有路由都应检查是否存在文件,否则提供索引文件。
将上述内容添加到我们的项目后,我们现在还可以将其复制到我们的 Docker 镜像中以告诉 NGINX 使用它。
FROM nginx
COPY nginx.config /etc/nginx/conf.d/default.conf
COPY index.html /usr/share/nginx/html
再次,您可以使用与上面相同的命令,在新的Dockerfile中在本地进行测试。记得在浏览器中访问http://localhost:8888/unicorn来查看实际效果。
docker rmi -f docker-spa
点击链接,你会看到它现在已经正常工作了。你访问的每条路线现在都由我们一开始构建的单页应用程序提供服务。
奖励级别——在 Docker 中编译你的 SPA
您的应用程序很可能不仅仅是一个静态的 HTML 文件。事实上,您可能拥有一个相当先进且复杂的工具链来构建您的应用程序,其中包括 TypeScript、Webpack、Parcel 或类似的工具。您可以在 Docker 文件中轻松完成此构建步骤。
# ---- Base Node ----
FROM node:alpine AS base
# Copy project file
COPY . .
# Build project
RUN npm run build
# ---- Prod ----
FROM nginx
# Copy needed files
COPY nginx.config /etc/nginx/conf.d/default.conf
COPY --from=base build /usr/share/nginx/html
上面使用了多阶段 Docker 构建。它首先基于 Node 构建一个镜像,我们在其中运行构建脚本,然后像之前一样构建一个镜像,但是从构建镜像复制已编译的应用程序,
而不是从我们运行的本地文件系统复制docker run
。
我们可以通过向package.json添加构建脚本来使用简单的 SPA 来说明它的用法。
"build": "rm -rf build && mkdir build && cp index.html build/index.html"
继续尝试吧。
docker rmi -f docker-spa
在本 repo 中一起查看所有这些内容,了解如何使用 Docker 托管 SPA。
多么美好的一天
我们构建了一个单页应用程序,在本地对其进行了测试,将其打包在 Docker 镜像中,最后使 Docker 镜像能够充当 SPA,响应所有路由。
希望你今天学到了一两点。现在,鼓起勇气,大胆尝试,运用你新学到的知识,用 Docker 托管你的应用程序吧。
鏂囩珷鏉ユ簮锛�https://dev.to/hoverbaum/dockerizing-spas-2lc9