从前端到全栈:Docker 部署 Node.js + MySQL 后端和 Vue.js 前端

572 阅读8分钟

引言

  • 项目概况:本篇文章着重介绍我使用Docker在服务器上运行起我的练习网站项目——一个简易CMS。需要部署的项目有三个:一个Node.js编写的后端,一个前端管理项目,一个前端新闻展示项目。

image.png

  • Docker 优势
  1. 环境一致性
    • Docker 提供了一个一致的运行环境,无论是在开发、测试还是生产环境中,应用程序都运行在相同的容器中。这消除了“在我机器上可以正常运行”的问题。
  2. 依赖管理
    • Docker 容器包含了应用所需的所有依赖项,因此不需要担心在不同服务器上安装和配置不同版本的依赖。
  3. 易于扩展和缩放
    • 使用 Docker,可以轻松地在多个容器实例之间扩展应用程序。这对于处理高流量和负载平衡非常有用。
  4. 快速部署
    • Docker 容器启动速度快,可以在几秒钟内启动新实例,这对于部署更新和快速恢复服务非常有优势。
  5. 资源隔离
    • Docker 容器提供了资源隔离,使得每个应用程序都在自己的容器中运行,不会干扰其他应用程序。这也增加了安全性。
  6. 版本控制和回滚
    • Docker 镜像可以进行版本控制,允许轻松回滚到先前的版本。这对于处理更新问题和快速恢复旧版本非常有用。
  7. 跨平台兼容性
    • Docker 可以在任何支持 Docker 的平台上运行,包括本地开发环境、测试服务器和云环境,提供了跨平台的兼容性。
  8. 简化的 CI/CD 工作流
    • Docker 容器可以与持续集成/持续部署(CI/CD)工具无缝集成,简化了构建、测试和部署的自动化流程。
  9. 开发和生产环境的隔离
    • Docker 允许在同一台机器上运行多个不同的环境,帮助开发者在本地测试不同的应用配置,而不会影响生产环境。

准备工作

  • 云服务器:我选择了京东云-轻服务器。选择了2核、2G内存配置,这是最便宜的服务器,毕竟学习使用,能用就行。
  • 服务器系统:选择CentOS 7.9

Docker安装

添加 Docker 仓库国内源

    // 这样下载docker时能快很多
    sudo yum-config-manager --add-repo https://download.docker.com+https://mirrors.tuna.tsinghua.edu.cn/docker-ce

安装 Docker 引擎

    sudo yum install docker-ce docker-ce-cli containerd.io
  1. Docker CE (Community Edition)
  • 简介:Docker 的社区版,提供完整的容器化功能。
  • 功能:包含 Docker 引擎,用于创建和管理容器。
  • 用途:适合开发和测试环境。
  1. Docker CE CLI
  • 简介:Docker 的命令行工具。
  • 功能:用于执行 Docker 命令(如启动、停止容器)。
  • 用途:通过命令行管理 Docker 容器。
  1. containerd.io
  • 简介:容器运行时,管理容器生命周期。
  • 功能:负责容器的创建、执行和管理。
  • 用途:Docker 和 Kubernetes 的核心组件。

设置Docker镜像源

Docker基本认识

image.png

  1. 构建镜像
    • 使用Dockerfile定义应用程序的环境、依赖和配置。通过docker build命令,可以从Dockerfile构建出一个 Docker 镜像。
  2. 管理镜像
    • 构建好的镜像可以通过docker push命令上传到 Docker 仓库(例如 Docker Hub),方便共享和分发。
    • 也可以使用docker pull命令从仓库中拉取镜像,获取其他开发者或团队发布的应用环境。
    • 镜像可以通过docker save命令保存为.tar文件,便于备份或传输。
    • 使用docker load命令可以从.tar文件加载镜像,恢复镜像到 Docker 环境中。
  3. 运行容器
    • 使用docker run命令可以将镜像实例化为一个运行中的容器。容器是镜像的可执行实例,包含应用程序及其运行时环境。
  4. 管理容器
    • 如果对运行中的容器进行了修改,可以使用docker commit命令将这些更改保存为一个新的镜像,便于后续使用或分发。

Docker常用命令

    // 启动docker
    sudo systemctl start docker

    # 镜像相关命令
    // 列出本地镜像
    docker images
    docker pull <image_name> 
    docker rmi <image_name_or_id>

    # 容器相关命令
    // 列出正在运行的容器
    docker ps
    // 列出所有容器(包括已停止的)
    docker ps -a
    // 启动容器
    docker start <container_id_or_name>
    // 停止容器
    docker stop <container_id_or_name>
    // 删除容器
    docker rm <container_id_or_name>
    // 运行一个新容器
    docker run -d -p 80:80 <image_name>

    # 容器管理
    // 进入正在运行的容器
    docker exec -it <container_id_or_name> /bin/bash

    // 查看容器日志:
    docker logs <container_id_or_name>

    #网络和卷

    // 使用 docker-compose 来管理多个服务
    docker compose -f /var/www/cms/cms-server-node/docker-compose.yml up -d
    docker compose -f /var/www/cms/cms-server-node/docker-compose.yml down -d
    // 重新构建服务
    docker compose -f /var/www/cms/cms-server-node/docker-compose.yml up -d --build

方案设计

如下,启动5个容器,Nginx容器负责接收用户请求,将/api开头的请求代理到Nodejs服务容器上,将/admin开头的请求代理到CMS后台管理项目容器上,将/开头的请求代理到CMS新闻展示项目容器上。

image.png

项目结构

三个独立的项目放在/cms文件夹下。每个项目下放一个Dockerfile文件。在后端nodejs服务项目下放总体构建的docker-compose.yml文件和用于反向代理的nginx.conf

    /cms
    │
    ├── /cms-front-vue
    │   ├── 前端后台管理项目源码
    │   ├── Dockerfile
    │
    ├── /cms-web-vue
    │   ├── 前台新闻网站项目源码
    │   ├── Dockerfile
    │
    ├── /cms-server-node
        ├── 后端nodejs服务项目源码
        ├── Dockerfile
        ├── docker-compose.yml
        ├── nginx.conf

部署实施

  1. 上传项目:将本地/cms文件夹上传到服务器/var/www目录下。

    rsync -av -e "ssh -i ~/.ssh/jdc_ssh_key.pem" --exclude='node_modules' /本地路径/cms root@116.198.34.50:/var/www

scp和rsync命令都可以上传文件到服务器,但是rsync命令更强大,比如增加 --exclude='node_modules'参数可以不上传node_modules文件夹,rsync每次上传只上传更改的文件,上传效率更高。

  1. 编写 Dockerfile
    • 前端后台管理项目/前端新闻项目

两个vue.js的Dockerfile趋同,只展示一个。

    # 使用 Node.js 18 作为构建阶段的基础镜像
    FROM node:18 AS build
    # 设置工作目录
    WORKDIR /app
    # 复制 package.json 和 package-lock.json(如果有)
    COPY package*.json ./
    # 设置 npm 镜像源
    RUN npm config set registry https://registry.npmmirror.com
    # 安装项目依赖
    RUN npm install
    # 复制项目文件到容器中
    COPY . .
    # 构建项目
    RUN npm run build-only
    # 使用 Nginx 作为生产阶段的基础镜像
    FROM nginx:alpine
    # 复制构建的文件到 Nginx 默认的静态文件目录
    COPY --from=build /app/dist /usr/share/nginx/html
    # 暴露端口
    EXPOSE 80
    # 启动 Nginx
    CMD ["nginx", "-g", "daemon off;"]
  • Nodejs服务端项目

    # 使用 Node.js 18 作为基础镜像
    FROM node:18
    # 设置工作目录
    WORKDIR /app
    # 复制 package.json 和 package-lock.json(如果存在)
    COPY package*.json ./
    # 设置 npm 镜像源
    RUN npm config set registry https://registry.npmmirror.com
    # 安装应用程序依赖
    RUN npm install
    # 如果你在生产环境中使用,可以使用以下命令代替
    # RUN npm ci --only=production
    # 复制应用程序的源代码到工作目录
    COPY . .
    # 暴露应用程序运行的端口(假设应用程序在 3000 端口上运行)
    EXPOSE 8080
    # 定义容器启动时要运行的命令
    CMD ["npm", "start"]
  1. 配置 Docker Compose
    • 编写docker-compose.yml文件,定义后端、两个前端、反向代理和数据库服务。

    services:
      frontend-manage:
        build:
          context: ./../cms-front-vue
          dockerfile: Dockerfile
        depends_on:
          - backend
        environment:
          - NODE_ENV=production
      frontend-web:
        build:
          context: ./../cms-web-vue
          dockerfile: Dockerfile
        depends_on:
          - backend
        environment:
          - NODE_ENV=production
      backend:
        build:
          context: ./
          dockerfile: Dockerfile
        depends_on:
          - db
      db:
        image: mysql:8.0
        ports:
          - "3306:3306"
        environment:
          MYSQL_ROOT_PASSWORD: 12345678
          MYSQL_DATABASE: cms
          MYSQL_USER: admin
          MYSQL_PASSWORD: 12345678
        volumes:
          - mysql-data:/var/lib/mysql
          - ./db/backup.sql:/docker-entrypoint-initdb.d/backup.sql
      nginx:
        image: nginx:latest
        ports:
          - "80:80"
        volumes:
          - ./nginx.conf:/etc/nginx/nginx.conf:ro
        depends_on:
          - frontend-manage
          - frontend-web
          - backend
    volumes:
      mysql-data:
  1. 配置 Nginx

在docker-compose.yml配置中,三个容器可以通过服务名来进行通信,所以在Nginx配置中,我们指定这三个服务名,Nginx容器就可以代理到它们。

    worker_processes  1; #全局块
    events {
        worker_connections  1024;
    }
    http {
        upstream backend {
            server backend:8080;
        }
        upstream frontend_manage {
            server frontend-manage:80;
        }

        upstream frontend_web {
            server frontend-web:80;
        }

        server {
            listen 80;
            include /etc/nginx/mime.types;
            default_type application/octet-stream;

            sendfile on;
            keepalive_timeout 65;

            location /api/ {
                proxy_pass http://backend;
                proxy_set_header Host $host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header X-Forwarded-Proto $scheme;
                 # 去掉 /api 前缀
                rewrite ^/api/(.*)$ /$1 break;
            }

            location /admin {
                proxy_pass http://frontend_manage/;
                proxy_set_header Host $host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header X-Forwarded-Proto $scheme;
            }

            location / {
                proxy_pass http://frontend_web;
                proxy_set_header Host $host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header X-Forwarded-Proto $scheme;
            }
        }
    }
  1. 启动服务

在服务器上执行以下命令,我们就将后端、两个前端、反向代理和数据库服务都启动起来啦。

    // 使用 docker-compose 来管理多个服务
    docker compose -f /var/www/cms/cms-server-node/docker-compose.yml up -d
    // 每次更改代码后,重新构建服务
    docker compose -f /var/www/cms/cms-server-node/docker-compose.yml up -d --build

总结

回顾部署过程。我们学习到了Docker的基本用法,已经如何用docker在服务器上运行我们的全栈项目。还有一点不足是上传项目使用的比较原始的上传文件方式,现在都流行CI/CD,也就是代码推送到git服务器自动集成和部署,下一步打算研究这部分内容。

附录

源码地址

CMS前端前台: github.com/double-chen…

CMS前端后台: github.com/double-chen…

CMS后端服务: github.com/double-chen…

项目展示:文章的重点不在于这个练习项目,随便展示两个页面。

后台文章列表页

image.png

新闻网站首页 image2.png