惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

S
Schneier on Security
GbyAI
GbyAI
H
Help Net Security
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
T
The Blog of Author Tim Ferriss
Vercel News
Vercel News
Microsoft Azure Blog
Microsoft Azure Blog
Google DeepMind News
Google DeepMind News
Stack Overflow Blog
Stack Overflow Blog
AWS News Blog
AWS News Blog
Spread Privacy
Spread Privacy
Apple Machine Learning Research
Apple Machine Learning Research
L
LINUX DO - 最新话题
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
P
Privacy International News Feed
C
CERT Recently Published Vulnerability Notes
C
Cybersecurity and Infrastructure Security Agency CISA
I
Intezer
Hugging Face - Blog
Hugging Face - Blog
H
Heimdal Security Blog
N
News and Events Feed by Topic
C
Cyber Attacks, Cyber Crime and Cyber Security
T
Troy Hunt's Blog
大猫的无限游戏
大猫的无限游戏
SecWiki News
SecWiki News
Martin Fowler
Martin Fowler
人人都是产品经理
人人都是产品经理
Recent Commits to openclaw:main
Recent Commits to openclaw:main
Application and Cybersecurity Blog
Application and Cybersecurity Blog
F
Fortinet All Blogs
Hacker News: Ask HN
Hacker News: Ask HN
Know Your Adversary
Know Your Adversary
Hacker News - Newest:
Hacker News - Newest: "LLM"
博客园 - 聂微东
S
Secure Thoughts
云风的 BLOG
云风的 BLOG
O
OpenAI News
The Cloudflare Blog
Jina AI
Jina AI
U
Unit 42
L
Lohrmann on Cybersecurity
Attack and Defense Labs
Attack and Defense Labs
The Register - Security
The Register - Security
G
Google Developers Blog
量子位
Simon Willison's Weblog
Simon Willison's Weblog
V
Visual Studio Blog
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
G
GRAHAM CLULEY
TaoSecurity Blog
TaoSecurity Blog

元视角

.NET 生态下的 Agent 框架选型:从 ReAct 到原生推理 - 元视角 从「能用」到「好用」:LLM 流式响应实现方式的探索之路 - 元视角 当我用 2000 条聊天记录,让 AI 为我画一幅自画像 - 元视角 基于 Supabase 的 AI 应用开发探索 - 元视角 微博 × MCP:社交媒体新玩法解锁 - 元视角 四点钟海棠花未眠 - 元视角 Semantic Kernel × MCP:智能体的上下文增强探索 - 元视角 基于 K-Means 聚类分析实现人脸照片的快速分类 - 元视角 容器技术驱动下的代码沙箱实践与思考 - 元视角 温故而知新:后端通用查询方案的再思考 - 元视角 浅议 CancellationToken 在前后端协同取消场景中的应用 - 元视角 Semantic Kernel 视角下的 Text2SQL 实践与思考 - 元视角 关于 ChatGPT 的流式传输,你需要知道的一切 - 元视角 RAG 的是与非、Rewrite 和 Rerank - 元视角 使用 EFCore 和 PostgreSQL 实现向量存储及检索 - 元视角 基于 LLaMA 和 LangChain 实践本地 AI 知识库 - 元视角 使用 llama.cpp 在本地部署 AI 大模型的一次尝试 - 元视角 如何为 Git 配置多个 SSH Key - 元视角 C# 使用 LibUsbDotNet 实现 USB 设备检测 - 元视角 基于 C# 实现样式与数据分离的打印方案 - 元视角 基于 SVG 的图形交互方案实践 - 元视角 前端视频播放技术概览 - 元视角 温故而知新,再话 Python 动态导入 - 元视角 后 GPT 时代,NLP 不存在了? - 元视角 视频是不能 P 的系列:使用 Milvus 实现海量人脸快速检索 - 元视角 GDI+下字体大小自适应方案初探 - 元视角 小爱音箱集成 ChatGPT 的不完全教程 - 元视角 程序员视角下的三体世界随想 - 元视角 关于 Docker 容器配置信息的渐进式思考 - 元视角 在 Docker 容器内集成 Crontab 定时任务 - 元视角 为你的服务器集成 LDAP 认证 - 元视角 似花还似非花 - 元视角 视频是不能 P 的系列:使用 Dlib 实现人脸识别 - 元视角 浅议分布式链路追踪与日志的整合 - 元视角 关于 Git 大文件上传这件小事 - 元视角 .NET 进程内队列 Channel 的入门与应用 - 元视角 使用 Fody 实现 .NET 的静态编织 - 元视角 .NET Core + ELK 搭建可视化日志分析平台(下) - 元视角 聊一聊前端图片懒加载背后的故事 - 元视角 支持外部链接跳转的 Vue Router 扩展实现 - 元视角 视频是不能 P 的系列:OpenCV 和 Dlib 实现表情包 - 元视角 不得不说的 ASP.NET Core 集成测试 - 元视角 再议 DDD 视角下的 EFCore 与 领域事件 - 元视角 再见,人间四月天 - 元视角 Python 图像风格化迁移助力画家梦想 - 元视角 利用 ASP.NET Core 中的标头传播实现分布式链路追踪 - 元视角 利用 gRPC 实现文件的上传与下载 - 元视角 七种武器:延迟队列的原理和实现总结 - 元视角 gRPC 流式传输极简入门指南 - 元视角 Envoy 集成 Jaeger 实现分布式链路追踪 - 元视角 浅议非典型 Web 应用场景下的身份认证 - 元视角 gRPC 借助 Any 类型实现接口的泛化调用 - 元视角 分布式丛林探险系列之 Redis 集群模式 - 元视角 分布式丛林探险系列之 Redis 主从复制模式 - 元视角 通过 Python 预测 2021 年双十一交易额 - 元视角 gRPC 搭配 Swagger 实现微服务文档化 - 元视角 SSL/TLS 加密传输与数字证书的前世今生 - 元视角 使用 Python 自动识别防疫健康码 - 元视角 你不可不知的容器编排进阶技巧 - 元视角 ASP.NET Core 搭载 Envoy 实现 gRPC 服务代理 - 元视角 再话 AOP,从简化缓存操作说起 - 元视角 ASP.NET Core 搭载 Envoy 实现微服务身份认证(JWT) - 元视角 ASP.NET Core 搭载 Envoy 实现微服务的监控预警 - 元视角 ASP.NET Core 搭载 Envoy 实现微服务的反向代理 - 元视角 ASP.NET Core gRPC 打通前端世界的尝试 - 元视角 EFCore 实体命名约定库:EFCore.NamingConventions - 元视角 ASP.NET Core gRPC 集成 Polly 实现优雅重试 - 元视角 ASP.NET Core gRPC 健康检查的探索与实现 - 元视角 ASP.NET Core gRPC 拦截器的使用技巧分享 - 元视角 SnowNLP 使用自定义语料进行模型训练 - 元视角 使用 HttpMessageHandler 实现 HttpClient 请求管道自定义 - 元视角 ABP vNext 的实体与服务扩展技巧分享 - 元视角 ABP vNext 对接 Ant Design Vue 实现分页查询 - 元视角 源代码探案系列之 .NET Core 跨域中间件 CORS - 元视角 源代码探案系列之 .NET Core 限流中间件 AspNetCoreRateLimit - 元视角 源代码探案系列之 .NET Core 并发限制中间件 ConcurrencyLimiter - 元视角 通过 EmbededFileProvider 实现 Blazor 的静态文件访问 - 元视角 低代码,想说爱你不容易 - 元视角 记一次失败的 ThoughtWorks 面试经历 - 元视角 从 C# 1.0 到 C# 9.0,历代 C# 语言特性一览 - 元视角 通过 Python 分析 2020 年全年微博热搜数据 - 元视角 基于 Python 和 Selenium 实现 CSDN 一键三连自动化 - 元视角 使用多线程为你的 Python 爬虫提速的 N 种姿势,你会几种? - 元视角 实现网页长截图的常见思路总结 - 元视角 温故而知新,由 ADO.NET 与 Dapper 所联想到的 - 元视角 视频是不能 P 的系列:OpenCV 人脸检测 - 元视角 作为技术宅的我,是这样追鬼滅の刃的 - 元视角 使用 Python 抽取《半泽直树》原著小说人物关系 - 元视角 厉害了!打工人用 Python 分析西安市职位信息 - 元视角 使用 dotTrace 对 .NET 应用进行性能分析与优化 - 元视角 一道 HashSet 面试题引发的蝴蝶效应 - 元视角 基于选项模式实现.NET Core 的配置热更新 - 元视角 Dapper.Contrib 在 Oracle 环境下引发 ORA-00928 异常问题的解决 - 元视角 .NET Core 中对象池(Object Pool)的使用 - 元视角 利用 MySQL 的 Binlog 实现数据同步与订阅(下):EventBus 篇 - 元视角 利用 MySQL 的 Binlog 实现数据同步与订阅(中):RabbitMQ 篇 - 元视角 利用 MySQL 的 Binlog 实现数据同步与订阅(上):基础篇 - 元视角 记一次从已损坏的 Git 仓库中找回代码的经历 - 元视角 .NET Core 原生 DI 扩展之属性注入实现 - 元视角 .NET Core 原生 DI 扩展之基于名称的注入实现 - 元视角
Vue.js 前端项目容器化部署实践极简教程 - 元视角
飞鸿踏雪 · 2022-05-17 · via 元视角

大概一周前,在某个「微雨燕双飞」的下午,我正穿梭于熙熙攘攘的车流人海当中,而被雨水濯洗过的天空略显灰白,傍晚亮起的路灯恍惚中有种朝阳初升的错觉,内心更是涌现出一种「一蓑烟雨任平生」的豁达,我还没来得及给这场内心戏添油加醋,兴哥的电话突然打断了我的思绪。一番攀谈交心,我了解到,他想问的是前端容器化部署的相关问题。虽然,靠着兴哥的睿智、果敢,他第二天就想明白了整个事情的来龙去脉;但是,这完全不影响我水一篇博客出来。所以,今天这篇文章,我们来聊聊前端项目的容器化部署,并提供一个极简的实践教程,这里以 Vue.js 为例,希望对大家有所启发。

你说,这像太阳吗? 你说,这像太阳吗?

首先,我们来编写 Dockerfile,这里采用的是多阶段构建的做法,第一个阶段,即 build,主要是利用 node.js 基础镜像来实现前端项目的发布,所以,你可以看到 package.jsonnpm install 以及考虑到国情的 cnpm install 这些前端项目中喜闻乐见的东西,安装完依赖以后我们通过 npm run build 来完成打包,这取决于你项目中实际使用的脚本或者命令,如果你不喜欢 npm,你同样可以用 yarn 来编写这些指令,只要你喜欢就好。做人嘛,最重要的是开心!

# build
FROM node:lts-alpine as build
WORKDIR /app
COPY package*.json ./
RUN npm install -g cnpm --registry=https://registry.npm.taobao.org
RUN cnpm install
COPY . .
RUN npm run build

# deploy
FROM nginx:stable-alpine as deploy
COPY --from=build /app/dist/ /usr/nginx/wwwroot
COPY /nginx/nginx.conf /etc/nginx/nginx.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

OK,第二个阶段,即 deploy,前端发布出来的产物是无法直接在浏览器里打开的,这一点你平时用 Vue.js 的脚手架的话应该会注意到。所以,此时我们需要一个静态文件服务器来托管这些产物,这些产物通常会被放到 dist 目录,因此,在这一阶段主要就是把这个目录里的内容拷贝到 Nginx 下面,这里我们用的是 wwwroot。当然,如果你还怀念曾经的 LAMP 組合,同样可以替换为 Apache。我们在这个世界的一切努力,无非是为了比别人多一种选择,甚至有时候你完全没有选择。可是在计算机的世界里,你可以尽情地去创造,而这则是我的选择,从我高中在班级电脑上写出第一个 Visual Basic 程序开始,我庆幸能一直坚持这份热爱到现在。

worker_processes 1;

events {
    worker_connections  1024;
}

http {
    include  mime.types;
    default_type  application/octet-stream;
    sendfile  on;
    keepalive_timeout  65;
    server {
        listen  80;
        server_name  localhost;
        root /usr/nginx/wwwroot;
        index index.html;
    }
}

这里提到了 Nginx,那么,自然而然地,对于 Nginx 的配置问题就无可避免。可惜,事实是:每一个声称配置文件更灵活的人,从来都不会去摆弄配置文件,只有程序员天天和这些配置文件打交道。幸运的是,对于简单的静态文件服务器而言,它的配置并不算特别复杂,还记得前面的 wwwroot 吗?其实,它是在这里定义的,对应了 server 节点中的 root 属性,从这里我们可以看到,容器内部默认监听 80 端口,默认页面是 index.html。如果你现在还不太了解 Nginx 的配置文件,相信我,这几个配置已足够你快速上手啦!我不大愿意再写教程的原因是,我不喜欢每个步骤都要截图,并且还要在图上做好标记。显然,对于程序员而言,懒惰是一种美德。

version: "3.8"

services:
  font_mock:
    build:
      context: ./
      dockerfile: Dockerfile
    image: font_mock
    ports:
      - "50001:80"
    volumes:
      - '/etc/localtime:/etc/localtime:ro'
    networks:
      envoymesh:
networks:
  envoymesh: {}

好了,现在万事具备,我们再来写一个 docker-compose.yaml 来对服务进行编排,可以注意到,我们把 50001 端口绑定到了 80 端口,这就和前面呼应上了,对不对?剩下的就没什么好说的啦,不再一一赘述,如果你看不懂,可以先去了解一下 docker-compose。此时,我们运行 docker-compose up 命令,就可以看到下面的结果:

通过 Docker 部署前端项目 通过 Docker 部署前端项目

没错,我为了节省写作时间,直接使用了 在 Vue.js 中使用 Mock.js 实现接口模拟 这篇文章里的项目,果然,我再次完美发扬了 “懒惰” 这种优秀的美德,总而言之,到这里我们已经成功地通过容器技术部署了一个前端项目,在这个基础上,你还可以接入 Envoy 这个代理层 或者 是为 Nginx 添加 SSL 证书等等…当然,这些都是后话啦,各位比我聪明千倍、万倍的读者朋友们可以进一步去完善它,这篇短浅易懂的文章就当作诸位的入门教程好啦,愿「他山之石,可以攻玉」,谢谢大家,本文完!

# 创建 CA 密钥
openssl genrsa -out ca.key 1024
# 利用 CA 密钥生成自签名 CA 证书
openssl req -new -x509 -days 3650 -key ca.key -out ca.crt
# 创建服务器端证书密钥
openssl genrsa -des3 -out server.key 1024
# 生成服务器端证书
openssl req -new -key server.key -out server.csr
# 利用 CA 证书对服务器端证书进行签名
openssl ca -in server.csr -out server.crt -cert ca.crt -keyfile ca.key

此时,我们会得到服务器端证书文件 server.crt 以及密钥文件 server.key,我们将其配置到 Nginx 中即可,下面是修改后的 Nginx 配置文件:

worker_processes 1;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;
 
    sendfile        on;
    keepalive_timeout  65;
 
    server {
        listen  80;
        listen  443 ssl;
        server_name  localhost;
        
        # 证书文件
        ssl_certificate      /usr/nginx/ssl/server.crt;
        # 密钥文件
        ssl_certificate_key  /usr/nginx/ssl/server.key;
        # SSL 会话缓存大小为:1M
        ssl_session_cache    shared:SSL:1m;
        # SSL 会话超时时间为:5min
        ssl_session_timeout  5m;
        # 支持 TLS1.0/1.1/1.2 三个版本
        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
        ssl_ciphers  HIGH:!aNULL:!MD5;
        ssl_prefer_server_ciphers  on;

        root /usr/nginx/wwwroot;
        index index.html;
    }
}

需要注意的是,在创建证书时,对应的 Common Name 应该和网站的域名保持一致,这里的示例域名为:https://www.snowfly.com,在本地调试的时候,我们可以通过修改 hosts 文件来进行测试:

通过 OpenSSL 创建证书 通过 OpenSSL 创建证书

通常,你需要把自己创建的证书导入到 受信任的根证书颁发机构 这个分类下面,这样,就可以通过 HTTPS 协议访问你的站点啦!

在浏览器中查看 HTTPS 证书 在浏览器中查看 HTTPS 证书

番外预告!!!接下来会写一篇关于 ASP.NET Core 单元/集成测试的文章,敬请期待!