手把手教你实现前端容器化部署

312 阅读5分钟

要做的事情

  1. 前端应用实现容器化构建
  2. 容器化部署,使用 Docker-Compose 管理容器
  3. Nginx 伺服静态资源
  4. 对接两个 server 节点,用 Nginx 实现负载均衡
  5. 支持 https 访问

编写 nginx.conf 文件

在前端代码库根目录编写 nginx.conf 文件

nginx.conf 内的层次结构如下:

events {

}

http {
  upstream {

  }
  server {
    location {

    }
  }
}

server

server 表示要监听的端口和对应的域名/IP,每个域名/IP 对应一个 server 配置项。

server_name 是对外提供服务的 ip/域名

e.g.

server {
        listen       80;
        server_name  localhost;
}
server {
       listen       443 ssl;
       server_name  www.safevue3.com;
}
https 配置
server {
    listen       443 ssl;
    server_name  www.safevue3.com;

    ssl_certificate      cert/server.crt;
    ssl_certificate_key  cert/server.key;
}

这里的 ssl_certificatessl_certificate_key 是相对于 Nginx 根目录的。

正式环境需要申请 https 证书,开发/测试环境可以用自签名的证书。 生成自签名证书可以使用 openssl,命令如下:

openssl genpkey -algorithm RSA -out server.key
openssl req -new -key server.key -out server.csr
openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt

location

location 表示路由,常用于反向代理。一般返回 html 都是 / 路由。如果需要反向代理,可以增加 location 配置项,配置对应的路由和 proxy_pass

e.g.

location / {
    root   html;
    index  index.html index.htm;
}

几个反向代理的场景
场景 1:前端需要调两个后端服务的接口
思路

用不同的前缀区分不同服务的接口,通过 Nginx 反向代理。

处理方式

前端通过 url 前缀区分两个后端服务。e.g. /a/b

请求先到达 Nginx,再由 Nginx 转发到对应服务的后台。需要配置 location 路由。

location /a {
  proxy_pass http://<a服务的后端IP/域名 或者 a服务的upstream名字>;
}
location /b {
  proxy_pass http://<b服务的后端IP/域名 或者 b服务的upstream名字>;
}
场景 2:两个前端应用,使用不用的域名,部署到同一个环境上,对接同一个后端服务。
思路

HTTP 请求的域名首先被 DNS 解析成 IP,再根据 IP 和端口(URL 没有端口号时,采用默认的端口)请求服务端。

由于两个应用部署在同一个环境上,所以域名解析出来的 IP 是相同的,单靠 IP 无法区分出请求来自哪个域名。

不过,请求头中还有 Host 字段,值为发起请求的域名。所以,Nginx 可以根据 Host 得知请求来自哪个域,从而转发请求到对应的服务。

处理方式

再搞个 Nginx 服务,做反向代理。根据请求头的 Host,将请求转发到对应的 Nginx

20240713_134724_image.png

upstream

upstream 可以理解成一组服务端节点的集合,常用于负载均衡。

可以在 location 下的 proxy_pass 中配置 upstream 的名字,把 locationupstream 关联起来。

upstream 中默认的负载均衡策略是轮询,其他的负载均衡策略还有 ip_hashweight.

如果配置 ip_hash,只需要在 upstream 中单独一行写 ip_pash;

如果 upstream 中只配置了 server,没有其他属性,那就是轮询方式.

e.g.

upstream backend {
    ip_hash;
    server 192.168.1.102:3001;
    server 192.168.1.102:3002;
}
server {
  location /upstream {
    proxy_pass http://backend;
  }
}

画成图,就是如下形式:

20240713_135023_image.png

容器化构建

在前端代码库根目录编写 Dockerfile 文件

基于 Nginx 基础镜像,构建前端应用的镜像.

要做的就是:

  1. 将构建产物目录 dist 下的所有文件,复制到 Nginx 镜像中的 /etc/nginx/html 目录中
  2. nginx.conf 复制到 /etc/nginx/
  3. 为了支持 https,需要将证书目录 cert 复制到 /etc/nginx/cert/ 中(本来 nginx 镜像中没有 cert 目录,需要用 RUN mkdir 创建目录)

容器化的 Nginx,不同版本的 Nginx 路径可能会有差异。可以用 whereis nginx 来查询 Nginx 的路径。

FROM nginx:1.26.1

COPY dist/ /etc/nginx/html/
COPY nginx.conf /etc/nginx/

RUN mkdir /etc/nginx/cert/
COPY cert/ /etc/nginx/cert/

构建 Docker 镜像时,在前端代码库根目录执行以下命令:

npm run build

docker build -t <镜像名> .

就把镜像构建出来了。可以使用以下命令查看已有的镜像:

docker images

如果要删除镜像,运行以下命令:

docker rmi <镜像ID 或者 镜像名:镜像版本号>

配置 Docker-Compose

为了方便拉起和销毁 Docker 容器,我们使用 Docker-Compose 来管理容器。

需要在 Linux 环境上维护一份 Docker-Compose.yml 配置文件。内容如下:

version: "3.8"
services:
  vue2-demo:
    image: vue2-demo:latest
    ports:
      - "443:443"
    networks:
      - mynetwork
  server01:
    image: koa2-demo:latest
    ports:
      - "3001:3000"
    networks:
      - mynetwork
    volumes:
      - ./logs:/app/logs # 将主机上的./logs目录挂载到容器的/app/logs目录
      - data-volume:/app/data # 将名为data-volume的数据卷挂载到容器的/app/data目录
  server02:
    image: koa2-demo:latest
    ports:
      - "3002:3000"
    networks:
      - mynetwork
    volumes:
      - ./logs:/app/logs # 将主机上的./logs目录挂载到容器的/app/logs目录
      - data-volume:/app/data # 将名为data-volume的数据卷挂载到容器的/app/data目录
networks:
  mynetwork:
    driver: bridge
volumes:
  data-volume: # 定义一个名为data-volume的数据卷

services 下面是所有要拉起的容器 每个 service 需要配置对于的镜像 images,和端口号 ports ports 为 <宿主机端口>:<容器内端口> 的形式

docker-componse.yml 配置好后,运行命令批量拉起容器:

docker-componse up -d

如果要停止并删除容器,运行以下命令:

docker-componse down

顺便讲几个 Docker 相关命令

查看运行中的容器

docker ps

查看所有容器(包括停止但没有删除的容器)

docker ps -a

手动删除容器

docker rm -f <容器ID>

查看容器的日志

docker logs <容器ID>

实时打印容器日志

docker logs -f <容器ID>

进入容器

docker exec -it <容器ID> sh