三分钟学会使用 Docker 部署前端项目

1、前言

1-1 引入

本篇文章带领读者利用Docker+XShell+阿里云服务器进行简单的前端网页部署。笔者用到的环境如下:

  • 本机操作系统:Windows 10(因此直接安装 Docker Desktop,图形化操作,较为方便)
  • 云服务器:阿里云 2核 2G(Ubantu)

一些本人参考的资料整理:

1-2 Docker简介

1-2-1 简介

Docker🐳 是一种容器技术,只隔离应用程序的运行时环境但容器之间可以共享同一个操作系统,可以理解成一个更轻量级的 虚拟机 并且使用的是本机的操作系统。

Docker 变得越来越流行,它可以轻便灵活地隔离环境,进行扩容,运维管理。对于业务开发者而言,随着持续集成的发展,对代码质量及快速迭代的要求也越来越高。

对于前端而言,在 CI 环境中使用也更容易集成开发,测试与部署。比如可以为流水线(Pipeline)设置 Lint/Test/Security/Audit/Deploy/Artifact 等任务,更好地把控项目质量。

1-2-3 Docker的几个概念

1. 镜像(Image):类似于虚拟机中的镜像,是一个包含有文件系统的面向Docker引擎的只读模板。任何应用程序运行都需要环境,而镜像就是用来提供这种运行环境的。例如一个Ubuntu镜像就是一个包含Ubuntu操作系统环境的模板,同理在该镜像上装上Apache软件,就可以称为Apache镜像。

2. 容器(Container):类似于一个轻量级的沙盒,可以将其看作一个极简的Linux系统环境(包括root权限、进程空间、用户空间和网络空间等),以及运行在其中的应用程序。Docker引擎利用容器来运行、隔离各个应用。容器是镜像创建的应用实例,可以创建、启动、停止、删除容器,各个容器之间是是相互隔离的,互不影响。注意:镜像本身是只读的,容器从镜像启动时,Docker在镜像的上层创建一个可写层,镜像本身不变。

3. 仓库(Repository):类似于代码仓库,这里是镜像仓库,是Docker用来集中存放镜像文件的地方。注意与注册服务器(Registry)的区别:注册服务器是存放仓库的地方,一般会有多个仓库;而仓库是存放镜像的地方,一般每个仓库存放一类镜像,每个镜像利用tag进行区分,比如Ubuntu仓库存放有多个版本(12.04、14.04等)的Ubuntu镜像。

img

1-3 Docker安装和基础配置操作

1-3-1 安装

我们可以直接点击 链接 或者去官网下载Docker Desktop for Windows安装包进行手动下载安装,下载好之后双击 Docker Desktop Installer.exe 开始安装。安装完之后打开Docker Desktop即可,自动启动Docker。

注意: 因docker第一次启动时间较久,打开Docker Desktop后,会出现一直 docker is starting 转圈的问题:

img

等待一段时间后看其是否能够成功启动,如果依然不能,见博客文章Docker启动问题docker is starting…逐一排查问题,启动成功的界面长这样:

img

1-3-2 换源

首先打开Docker的设置,选择Docker Engine,在其中输入(这里使用的是163的源,如果想要使用其他源可以自行设置,github上有个项目docker_mirror可以自动检测在你的网络环境下哪个源是最快的)。

json复制代码{
  "registry-mirrors": [
    "http://hub-mirror.c.163.com",
    "https://docker.mirrors.ustc.edu.cn"
  ],
  "insecure-registries": [],
  "debug": true,
  "experimental": false
}

img

1-3-3 基础操作

我们输入docker run hello-world是否会出现下图所示的提示,如果出现报错,这环境配置可能出现了问题。 ps:这行命令会让docker从官方仓库中拉去hello-world的镜像到本地,并且自动将其实例化成容器:

img

一些常用的命令:

  • 利用Dockerfile创建镜像:

    Dockerfile可以理解为一种配置文件,用来告诉docker build命令应该执行哪些操作。一个简易的Dockerfile文件如下所示,官方说明:Dockerfile reference

    bash复制代码# 说明该镜像以哪个镜像为基础
    FROM centos:latest
    
    # 构建者的基本信息
    MAINTAINER fe
    
    # 在build这个镜像时执行的操作
    RUN yum update
    RUN yum install -y git
    
    # 拷贝本地文件到镜像中
    COPY ./* /usr/share/gitdir/
    

    Dockerfile中常用的保留字有以下几个,更多请前往官网查阅:

    • FROM:指定基础镜像
    • RUN:容器构建时需要运行的命令
    • EXPOSE:当前容器对外暴露的端口号
    • WORKDIR:指定在创建容器后,终端默认登录进来的工作目录
    • ADD:将宿主机目录下的文件拷贝进镜像,ADD命令会自动处理URL和解压tar压缩包
    • CMD:指定一个容器启动时要运行的命令,参数为数组格式 CMD [“可执行文件”, “参数1”, “参数2” …]

    有了Dockerfile之后,就可以利用build命令构建镜像了:(其中-t用来指定新镜像的用户信息、tag等。最后的点表示在当前目录寻找Dockerfile。)

    bash
    复制代码[root@xxx ~]# docker build -t="fe/centos:gitdir" .
    
  • 对Docker操作:(Linux下,Windows下直接打开Docker Desktop即可)

    bash复制代码# 启动docker
    sudo service docker start
    # 重启docker
    sudo service docker restart
    # 停止docker
    sudo service docker stop
    
  • 对镜像的基础操作:

    bash复制代码docker image ls
    # 或者
    docker images
    

    img

    标签含义
    REPOSITORY镜像所在的仓库名称
    TAG镜像标签
    IMAGEID镜像ID
    CREATED镜像的创建日期(不是获取该镜像的日期)
    SIZE镜像大小
  • 其它常见命令可见下图:(Docker 常用命令速查手册

    img

2、本地部署

借助Docker在本地部署前端项目实际上就是利用Container容器将使用不同版本应用(node,nginx,mysql等应用)的项目隔离后进行项目的启动,避免因同一个主机安装多个不同版本应用及其切换带来的工作量及风险。

这里笔者使用本人进行Vite+React+TS前端工程化配置实践时的一个项目模板vite-react-ts-template当做实例。需要的朋友可直接拉到本地进行项目的开发而无需进行工程化的配置,也可根据自己的需要进行修改或者完善。或者大家直接使用自己的其他项目也OK,步骤是一致的。

bash复制代码git clone https://github.com/XC0703/vite-react-ts-template

cd vite-react-ts-template

# windows系统下执行cd命令可以获取当前文件夹在电脑的绝对目录,后面会用到该地址,Linux下是执行pwd命令。
cd 
# D:\StudySoft\VSCode\VSCodeFile\vite-react-ts-template

2-1 创建Dockerfile文件

参考博客:

自己动手写Dockerfile(上)

自己动手写Dockerfile(下)

前面说到,dockerfile是一个镜像构建文本文件, 里面包含了一系列的指令, 这些指令告诉Docker如何创建一个容器镜像。 在文件中可以用指令指定提供容器运行时所需要的程序,库,资源,配置等文件, 还包含了一些运行时准备的配置参数(环境变量,用户等)。

要上线一个前端项目,需要先构建打包,然后再部署。因为构建需要用到node环境,我们先使用node基础镜像来执行构建阶段,,最后将构建阶段的产物放到nginx来部署(多阶构建,可以减小最终镜像的大小)。 编写dockerfile的内容就可按照这个步骤来

在项目根目录下新建一个dockerfile文件, 内容如下:

bash复制代码# 使用 Node.js 16 作为基础镜像
FROM node:16

# 将当前工作目录设置为/app
WORKDIR /app

# 将 package.json 和 package-lock.json 复制到 /app 目录下
COPY package*.json ./

# 运行 npm install 安装依赖
RUN npm install

# 将源代码复制到 /app 目录下
COPY . .

# 打包构建
RUN npm run build

# 将构建后的代码复制到 nginx 镜像中
FROM nginx:latest
COPY --from=0 /app/dist /usr/share/nginx/html

# 暴露容器的 8080 端口,此处其实只是一个声明作用,不写的话也可以,后面运行容器的
# docker run --name container_name -p <host_port>:<container_port>命令中container_port可以覆盖此处的声明,不写就默认80端口
EXPOSE 8080

# 启动 nginx 服务
CMD ["nginx", "-g", "daemon off;"]

这里之所以先把package.json 文件复制到容器中执行npm install, 再把源码复制到容器,是因为一行指令为单独的一层,docker会把每一层单独存储,每一次构建都是从变化的那一层开始构建,如果package.json 文件没有变化, 那么就不会执行install, 如果一次性把所有文件复制进去,源代码每次都会有修改,每次都会执行npm install。

2-2 构建镜像

确认本地安装docker,启动docker(Windows下打开Docker Desktop即可启动Docker,Mac中是通过 service docker start 命令启动。)

构建镜像的命令如下:

bash复制代码docker build -t <image_name>:<tag> .
# docker build -t vite-react-ts-template-image:v1 .
  • -t 标记镜像的名字和标签(自定义,例如**docker build -t vite-react-ts-template-image:v1 . **)
  • . 表示从当前目录查找dockerfile来构建镜像

注意,如果构建镜像中.dockerignore遇到了下面这个问题:

img原因:本地项目的 node_modules 也复制了,有读写权限之类的问题。

解决办法:在根目录下添加.dockerignore文件,项目上传本地服务器时忽略 node_modules文件夹:

bash
复制代码node_modules

此时去执行docker images命令,可以看到我们的镜像已经被构建出来了:

img

2-3 运行容器

构建好镜像之后我们就需要让他成为容器,要想成功运行起来,还需要掌握几个指令:

bash复制代码# 构建运行容器
# --name 指定容器名称为 vite-react-ts-template-container
# -p 指定外部端 8080 于容器内 8080端口连接,从而可以通过主机的 8080 端口来访问容器内的服务,要记得<container_port>这个端口被nginx监听到,因为nginx默认监听80端口而已
# -v 代表绑定卷 也就是本地的 dist 文件如果变更 容器内的 dist文件也会做出相应改变
# 注意 -v 两侧均需要使用绝对路径
# -d 表示在后台运行
# 最后的 vite-react-ts-template-image:v1 表示使用指定的镜像
# docker run --name container_name -p <host_port>:<container_port> -v <path> -d <image_name>:<tag>
docker run --name vite-react-ts-template-container -p 8080:8080 -v D:\StudySoft\VSCode\VSCodeFile\vite-react-ts-template -d vite-react-ts-template-image:v1

可以看到,我们容器已经被构建出来并运行了:img

可以通过Docker Desktop的按钮或者此时执行docker start xxx 命令或者去Docker Desktop点击启动按钮即可运行容器:

img

img

bash复制代码# 查询容器
docker ps -a # 查询全部容器
docker ps -a | grep xxx # 筛选查询容器

# 运行容器
docker start xxx
# 暂停容器
docker stop xxx
# 重启容器
docker restart xxx

# 删除容器
docker rm xxx

注意:nginx默认使用的是80端口号,即上面的<container_port>默认只能为80,若想修改,则需要修改nginx的默认配置文件。有两种修改方式:

方法①:手动编辑 default.conf 文件:

Windows下直接通过Docker Desktop进入/etc/nginx/conf.d/default.conf 文件进行编辑,Linux下通过命令行进入该文件,再通过vim等编辑器进行修改。(可以使用find命令查找Nginx配置文件default.conf的位置)

bash复制代码# / 表示在系统根目录下查找 如果想在 /etc 下查找,可以输入 find /etc -name “default.conf”
find / -name "default.conf"

img

img

方法②:通过编写Dockerfile来修改端口

这里我们使用文本处理命令sed来对default.conf的文件内容进行修改。

如果你不了解这个sed命令也没关系,下面命令的意思是把第二行替换成”2c listen 8090;”,把第三行替换成” listen [::]:8090;”。

在Dockerfile中输入:

bash复制代码FROM nginx
MAINTAINER cchyi
#修改deafult.conf第二行第三行的内容
RUN sed -i '2c listen 80800;' /etc/nginx/conf.d/default.conf
RUN sed -i '3c listen [::]:8080;' /etc/nginx/conf.d/default.conf
EXPOSE 8080

此时在浏览器地址栏输入http://localhost:8080/可以看到我们的网页启动成功,说明我们本地部署成功:

img

3、云服务器部署

在云服务器上部署我们的项目与本地部署类似,无非是将本地主机环境切换成云服务器环境。分为租借云服务器(阿里云、腾讯云等均可)、连接服务器、上传文件到服务器、在服务器部署我们需要的环境(借助Dockerfile和nginx.conf)即可。

关于租借云服务器这步,本篇文章不作讨论,网上有很完整的博客资料可供参考,学生还有学生优惠,比较方便和便宜。(系统选择CentOS好一点,便于运维)

关于其它部署环节,笔者的另一篇文章 手把手带你用Django实现一个后台管理系统 最后的项目部署部分详细地带大家实现了借助腾讯云服务器+Xshell+宝塔面板实现Vue3+Django4全栈项目的部署。

这篇文章,笔者使用的是阿里云服务器+Xshell+Docker实现部署。

Xshell是远程连接云服务器的工具,支持所有平台的云服务器而且方法简单,方便下载宝塔gui面板对云服务器进行可视化傻瓜式操控。

本人租借的阿里云服务器如下:

1.jpeg

可以在安全组设置里面去配置需要开放的端口:

2.jpeg

3-1 使用XSheel连接服务器(以阿里云为例)

1、下载XSheel(安装包官网上下载,安装过程傻瓜式安装,一路点next,注意安装位置。后期有需要会上传网盘)
2、打开XSheel,点击新建(打开没弹出对话框的话点击左上角的文件就能看见)

img

3、填写名称(随便起,最好是有代表意义的)、主机(填写公网ip,不知道的上服务器首页找)、端口号(不用改,默认)。点击连接。

img

4、输入用户名(就是默认的 root),点击确定。

img

5、身份验证。这里有三种验证,默认使用第一种。

img

输入密码连接成功后的页面长这样:

img

此时,我们的本地主机已经成功连接上了云服务器。

3-2 云服务器环境配置并上传文件

这步可以采用宝塔面板这种傻瓜式的方式,也可以在Xshell的会话管理器中用Linux 命令行一步步实现。笔者这里使用Linux命令行的方式一步步带大家实现。

Xshell可以参考这篇博客学习:Xshell和Xftp安装(免费可用)和使用教程

由于笔者的阿里云服务器的Linux系统是Ubuntu,与Centos会有些许不同,它使用snap 类似yum apt这种软件包管理器。例如:

  • 查看系统的目录和文件:

    img

  • 查看已经通过snap安装的snap包:

    img

  • 可以搜索想要的snap包,例如nginx:

    img

  • 安装snap包(安装路径统一在/snap):

    img

    img

在我们的服务器安装好Docker之后,剩下的工作就和我们在本地主机的工作一样了,克隆/上传项目在服务器——>构建镜像——>运行容器,即可用IP地址访问我们的网页了。(单单前端项目的部署相对简单点,后端项目后面再细说)

3-2-1 上传项目到服务器

1、新建一个目录存放我们的项目并进入该目录:

bash
复制代码mkdir Projects && cd Projects

img

2、可以使用 rz 会弹出选择文件的框,选择需要上传的文件,等待上传完成。(若未安装rz,先使用如下命令进行安装)

bash复制代码# 安装rz
apt install lrzsz

# 文件上传
rz

此时可以看到我们的文件成功上传:

img

3、项目解压

bash复制代码# 安装unzip
apt install unzip

# 文件解压
unzip vite-react-ts-template.zip

# 删除压缩包
rm -f vite-react-ts-template.zip

# 进入项目
cd vite-react-ts-template

可以看到,我们的项目已被成功上传:

img

3-2-2 构建镜像和运行容器

1、构建镜像使用上面本地部署使用过的命令:

bash复制代码# 构建镜像
docker build -t vite-react-ts-template-image:v1 .

2、运行容器也是使用上面本地部署使用过的命令,不过要更改path路径:

bash复制代码# pwd命令获取项目的绝对地址,/root/Projects/vite-react-ts-template
pwd

# 运行容器
docker run --name vite-react-ts-template-container -p 8080:8080 -v /root/Projects/vite-react-ts-template -d vite-react-ts-template-image:v1

此时发现并没有如我们期待的那样可以直接用IP地址访问:

img

3-2-3 问题排查

上述这个问题一般出现在nginx的配置上,可以使用find命令查找nginx配置文件default.conf的位置:

arduino复制代码# / 表示在系统根目录下查找 如果想在 /etc 下查找,可以输入 find /etc -name “default.conf”
find / -name "default.conf"

img

cat命令打开该文件可以看到:

bash复制代码server {
    listen       80;
    server_name  localhost;

    #access_log  /var/log/nginx/host.access.log  main;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }

    #error_page  404              /404.html;

    # redirect server error pages to the static page /50x.html
    #
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }

    # proxy the PHP scripts to Apache listening on 127.0.0.1:80
    #
    #location ~ .php$ {
    #    proxy_pass   http://127.0.0.1;
    #}

    # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
    #
    #location ~ .php$ {
    #    root           html;
    #    fastcgi_pass   127.0.0.1:9000;
    #    fastcgi_index  index.php;
    #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
    #    include        fastcgi_params;
    #}

    # deny access to .htaccess files, if Apache's document root
    # concurs with nginx's one
    #
    #location ~ /.ht {
    #    deny  all;
    #}
}

发现这个默认的配置文件中,指定了Nginx服务器监听的端口为80,然而我们上面构建容器是映射8080端口,因此我们修改二者其一即可。

bash复制代码# 停止容器
docker stop vite-react-ts-template-container

# 删除容器
docker rm vite-react-ts-template-container

# 重新构建运行容器,容器端口映射为80
docker run --name vite-react-ts-template-container -p 80:80 -v /root/Projects/vite-react-ts-template -d vite-react-ts-template-image:v1

此时再去访问服务器公网IP,发现成功了:

img

4、域名映射与其它

4-1 域名映射

笔者的另一篇文章 不是吧,都2023年了,你的掘金个人主页还在用传统域名?详细地写了购买域名、域名备案的过程,读者可进行阅读学习。

这里如果想将已经备案好的域名映射到我们的IP地址,添加一条记录即可:

img

但我们发现域名解析到ip之后,默认访问的是80端口,而上面部署的网站设置的端口是8080,最后只能通过类似 http://www.<domain_name>:8080/ 这种方式实现网站访问,不太美观。如果我们想要不用后面的 :8080 就可以访问网站,那么可以有两种解决办法:

①重新部署我们的网站,将端口改成80。

bash复制代码# 停止容器
docker stop vite-react-ts-template-container

# 删除容器
docker rm vite-react-ts-template-container

# 重新构建运行容器,容器端口映射为80
docker run --name vite-react-ts-template-container -p 80:80 -v /root/Projects/vite-react-ts-template -d vite-react-ts-template-image:v1

②去修改nginx配置文件default.conf:

bash复制代码server {
    listen       80;
    server_name  localhost;

    #access_log  /var/log/nginx/host.access.log  main;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
        proxy_pass http://localhost:8080/;
    }
}

proxy_pass http://localhost:8080/; 这句配置的意思是将所有请求都转发到本地的 8080 端口。

此时,我们不用:8080也可以直接去访问网站了。(若后面网站内容修改,记得重新构建镜像和运行容器)

4-2 其它

这里说的其它运维操作包括以下几种:

  • 网站只能通过域名访问,ip不可访问。
  • 网站开启https,http自动跳转到https。

除了这两种外,其它如CDN内容分发、服务器性能监控、防火墙配置、日志记录分析等,需要笔者和读者下去一起学习,对nginx、docker等作进一步配置实现。

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐