关键词:Docker、Nginx、Vue、Node.js、DockerFIle

Docker是流行的容器引擎,通过Docker部署项目/服务已经是流行的方式;Nginx是高性能的Web服务器,大厂都在用。显然,作为初学者来说,如果有Vue项目,通过Docker+Nginx的方式部署到服务器上,是一个简单、粗暴、合理的选择,还能学到很多东西。

但是这三样内容,其实并不在一本教材上,可能需要看三本书才能做好。并且三个东西结合,可能会有一些坑和思路上的选择, 笔者在部署时也有遇到,因此写了一篇文章专门来讨论,算是比较详细的理解和教程,欢迎讨论。
如果选用编写DockerFile的标准部署方式,可以直接跳到正式开始部署环节。

总体思路设计

我们期待的最终效果一个一般的网站的形式。所以部署Web服务,显然需要考虑三个问题。

  • (1)如何运行Vue项目? 写了项目,如何让用户的浏览器能够运行?
  • (2)Nginx服务如何配置? 一般来讲需要自己修改/配置Nginx中的.conf文件
  • (3)上述两件事,如何在Docker中完成?

针对这前两个问题的不同思考,会衍生出不同的部署方案。换言之,我们在百度或CSDN上搜索,会有很多种方案,不同的方案除了个人配置,甚至在思路上都是不一样的。笔者也给出了三种思路。
但是如果考虑Docker的特性,会发现一些思路是不合理的(前两种思路),而且绝大多数部署Docker都是通过编写DockerFile的方式。
所以想看具体步骤的同学,可以直接跳到第三种思路(本文选用的也是第三种思路,前两种只做讨论)。

1.Docker中创建Node.js容器

当我们在本地运行Vue项目的时候,我们需要安装Node.js环境,执行相关的npm命令。

npm run dev

所以,我们如果要部署Vue项目,是否也需要在服务器端安装Node.js的环境,然后这样开启一个对外服务的进程呢?这种方案,我们要在docker中实例化node.js容器
答案是否定的,Vue项目本质上是一堆静态文件(HTML、CSS、JS),就是直接运行在浏览器中的。
换言之,如果我们单纯的部署Vue项目,浏览器本身的引擎就是解析这些代码用的,我们只需要把资源放到对于的位置上即可。
这里在知乎关于vue部署的问题中,有详细的讨论。如果是第一次接触部署前端项目,可以详细读一下。也可以去了解一下Node.js到底是什么。

首先VUE 是一个javascript的前端框架,注定了它是运行在浏览器里的,对服务器本地没有任何要求,只要一个静态文件服务器能通过http访问到其资源文件就足矣。
npm run dev 是用来在本地开发的时候做调试用的,vue开发的是前端的东西,不是nodejs 服务端程序,按道理讲,生产环境里就不该存在npm,甚至nodejs也不需要(用nodejs来做web静态服务的除外)

vue.js怎么在服务器部署?–知乎问题
感觉好多人把最基本的都忘了–papersnake的回答
(因此,该方案被否)

2.Docker实例化Nginx容器,进入容器修改配置文件

先说结论:第二种方案,思路是正确的。但是实际上不可行。
思路:既然vue就是一堆静态文件,通过HTTP访问即可运行。
步骤:(1)那我实例化一个Nginx容器 (2)把Vue文件扔进去 (3)进入容器,修改.conf文件(Nginx配置文件,匹配对应目录)。
这里,把vue文件扔到Docker容器中,可能需要Docker自带的拷贝命令。

# docker cp 要拷贝的文件路径 容器名:要拷贝到容器里面对应的路径
docker cp /opt/test.js(被拷贝的文件) 容器id:/usr/local/tomcat/webapps/test/js(容器目标路径)
# 通过docker exec进入容器,这里其实用的容器中的Ubuntu提供的Bash(shell)
sudo docker exec -it xxxxxx(容器id) /bin/bash

这个思路走下来,是能够成功部署Vue项目的,但存在问题。
如果我们实例化一个Nginx服务,会发现它是跑在一个Ubuntu上面的,对外看起来是一个容器。Docker执行的逻辑是:Ubuntu容器+安装Nginx+启动Nginx,这三个东西整合为了1个容器,作为宿主机(我们的电脑上看)是一个进程。
但如果手动修改Nginx配置文件导致Nginx挂掉,会导致启动Nginx这一步报错,产生异常退出(exit),进而这个容器(进程)也就挂掉了,而挂掉以后无法在操作容器。

不能操作容器的原因:
我们之所以能够操作容器(修改容器中的文件),是因为容器中的精简Ubuntu为我们提供了Bash(Shell控制台),如果容器这个进程产生异常/错误挂掉,我们就无法使用容器中的shell了,因为容器的shell是进程中的Ubuntu提供的,如果进程直接挂了,那shell自然也就没了。
换言之,docker exec进入容器修改文件的方法此时难以实现。

1个Nginx服务 (对外提供Web服务)
1个精简的Ubuntu/CentOS系统 (提供了基础环境+给用户使用的shell)
1个Docker容器

所以采用第二种方案会遇到两个问题

  • 修改配置文件麻烦。 精简的Ubuntu仅是运行环境,没有提供Vim这样的工具。
  • 修改配置文件导致Nginx挂了,会导致整个容器挂掉,并且无法再启动。

因此,第二种方案,其实也不合理,并且很麻烦,放弃。

3.编写DockerFile,将基础镜像Nginx和配置文件写入

综上所述,选择方案3是合理的,也是Docker官方推荐的部署方式,在正式开始部署单元,可以看到具体的步骤。

这里写一些啰嗦的话(可以略过)
还在更新中。。。。。

正式开始部署(选择编写DockerFile的方式,简单直接)

1.获取dist文件,编译好的生产环境代码

(1)在Vue的项目工程文件目录下,执行命令,得到dist文件。dist文件是我们最终需要的代码。

npm run build

(2)将文件拷贝到我们的服务器中(也可以通过ftp等方式,scp简单直接)

# 从本地复制到服务器的scp命令(win10也有scp,无须额外安装。可以直接使用scp)
scp local_file remote_username@remote_ip:remote_file 
# 若拷贝文件夹 使用-r
scp -r local_file remote_username@remote_ip:remote_file 

2.编写DockerFile

我们将要编写的DockerFile,和dist文件中的代码,放在同一目录下,执行Docker相关命令,就可以获得Docker镜像。
(1)编写DockerFile。如果在服务器中,通过vim Dockerfile就可以创建文件,然后将以下内容按需要的复制到文件中。

# 设置基础镜像
FROM nginx
# 定义作者
MAINTAINER xujiang
# 将dist文件中的内容复制到 /usr/share/nginx/html/ 这个目录下面
# /nginx/html是Nginx.conf中index对应目录,不同版本Nginx可能有区别
COPY dist/  /usr/share/nginx/html/

注:
【1】COPY命令是将相关的代码拷贝到Nginx的默认的目录下,①需要注意代码存放目录,②是否需要自定义Nginx.conf文件,如果按照默认的Nginx设置,放到/nginx/html目录(默认目录)即可。
【2】为什么要用COPY命令?解析:由于 docker 的运行模式是 C/S。我们本机是 C,docker 引擎是 S。实际的构建过程是在 docker 引擎下完成的,所以这个时候无法用到我们本机的文件。这就需要把我们本机的指定目录下的文件一起打包提供给 docker 引擎使用。(来自菜鸟教程)

(2)考虑是否需要添加Nginx的配置文件。如果使用默认配置文件,不需要考虑(2)。
注:这里熟悉Nginx的同学自行完成即可。阅读nginx.conf可知,Nginx会默认#include相关目录下的.conf文件,如果需要配置Nginx,可以按需要编写后,添加到DockerFile中,COPY到容器的对应目录。

注:
【1】Dockerfile 是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需的指令和说明。
【2】所以Dockerfile定义的是要做的事,既有Docker提供的FROM、COPY、ADD等命令,可以以执行shell指令,比如合理的使用shell中的echo语句输出一些有意义的信息。
【3】如果想要做更多的事,建议学习一些Dockerfile,
【4】Nginx相关的事需要了解一下Nginx的原理,不在本文的讨论范畴。单就部署一个服务来说,最主要的是可以看一下Nginx配置文件Nginx.conf和default.conf,关注配置文件映射了哪些内容(可以单纯的实例化一个标准的Nginx容器,进入容器中,通过cat命令打印出来查看)

3.获得镜像,实例化得到Vue项目的容器

(1)通过Dockerfile构建镜像

# -t 指定1个名字
sudo docker build -t vue-test-01(自定义镜像名) .

这一步意义:将Dockerfile发给Docker,由Docker引擎自动的帮我们构建镜像。

如FROM Nginx,Docker,(可以在控制台观察执行的过程)
Docker会自动的帮我们拉取Nginx
顺序执行,以此类推。

这里可以注意一下:[1]构建命令中的 ‘.’ 是不可省略的(此处填写上下文路径),也就是说如果我们在Dockerfile所在目录下执行build命令,写 ‘.’ 即可 [2]如果build命令执行的有问题,不会生成镜像,并且会提示相应的错误。

上下文路径,是指 docker 在构建镜像,有时候想要使用到本机的文件(比如复制),docker build命令得知这个路径后,会将路径下的所有内容打包。(来自菜鸟教程)

(2)如果构建完成,可以在Docker中查看到该镜像。

# Docker查看镜像列表
sudo docker image ls
# 如果镜像有问题,可以删除对应的镜像
docker rmi vue-test-01

此时,我们通过DockerfIle构建的镜像已经在我们的本地仓库中(服务器的Docker中)已经可以查看到和使用了。如果我们想要放到Docker Hub中,则需要自己推送到对应的位置。
(3)实例化对应的容器

# --name指定容器的名字,-p是端口映射:将服务器 8080 端口映射到容器内部的 80 端口
# -d 后台运行
docker run --name vue-test-01-Con(容器名) -p 8080:80 -d nginx 

(end)到此为止,部署工作就完成了。我们访问对应的地址:端口,就可以访问刚刚部署的Vue服务了,服务是持续运行的。可以查看刚刚实例化的容器。
如果出现错误,会发现容器的状态是Exit(错误码),可以查一下原因。

# 列出正在运行的容器
sudo docker ps
# 显示所有的容器,包括未运行的(包括运行后停止的)
sudo docker ps -a

注:
部署以后可能会遇到访问比较慢的情况。主要有两个原因:【1】部署在Docker中,相当于在服务器上又跑了Ubuntu+Nginx,会有一部分性能损失 【2】Vue默认设置开发的是单页面应用,默认情况下,访问会一次加载应用中的所有页面(尽管你可能访问的是Home,但是其他组件也被加载了),这里属于Vue部分的问题,可以通过懒加载等方式解决。

其实选定合理的方案以后,正式的部署是比较简单的。

后续方案的思考(持续集成、持续交付为目标)

K8s管理docker容器方案,正在更新中。

通过Docker容器化部署一个Vue应用是比较简单的。而且如果代码进行了修改/更新,通过Dockerfile重新构建镜像(甚至Dockerfile都不需要修改),在实例化容器即可,可以非常迅速的完成部署和服务的对外发布。如果你不要这个服务了,可以通过Docker轻松地销毁他,体验容器带来的便利。
但是这仅仅是容器化部署带来的非常小的一部分好处,如果单纯为了这个目的,其实写脚本可以完成。

Logo

前往低代码交流专区

更多推荐