此文章优势
- 适用于基础者
- 适用于前端
- 一套掌握最最基础的Docker构建前后端项目方法
- 经过实践,完美部署
0.事前准备
安装
确保本地有如下的东西,如果直接在Docker构建那就只需要Docker以及docker-compose
- Docker以及docker-compose(必须)
- Docker图形化界面(非必须)
- Node.js(必须)
- MongoDB图形化界面(非必须)
- yarn (非必须,可以自行替换为npm,pnpm)
前置知识
确保有如下基础知识,这篇文章主要着眼于使用Docker的部署和构建
一些开发细节上的问题不会详细给出
- Docker基础知识
- Mongodb基础知识
- Nginx基础知识
- 前端(vue,react..),后端(node,koa..)的基础知识
环境
- OS:Windows 10
- 编辑器:VS Code
- Node.js:v16.3.0
- Docker:v20.10.13
demo
这个文章的demo也已经上传GitHub,欢迎各位大佬参考
另外本人的开源项目Rrea也使用相同方法构建,欢迎参考和star(一个全栈的项目,管理+客户双端+服务端+数据)
1.前端准备工作
如果你已经有了项目那么就跳过这一步,直接看 4.前端Dockerfile
这里使用vite构建vue3项目,你可以自由选择你的前端框架
如果你想看现成的前端文件夹,请看这里
在根文件夹新建文件夹frontend并初始化vite
yarn create vite
选择你要构建的前端框架,安装
删除不需要的东西,并安装axios
yarn add -D axios
在App.vue整理并加入代码如下(使用了ts,用js也无所谓)
不考代码优雅等等,目前的效果就是启动前端项目就会调用axios请求api,并把结果打印到控制台和页面
/test就是后端的提供api地址(后面会讲到)
<template>
<main>
<div><strong>データ:</strong></div>
<br />
<div>{{ data }}</div>
</main>
</template>
<script setup lang="ts">
import { ref } from "vue";
import axios from "axios";
const host: number = 7021;
interface IDocker {
id: number;
}
// 请求数据
const data = ref<IDocker[]>();
const api = async (): Promise<void> => {
await axios.get<IDocker[]>("/test").then((res): void => {
console.log(res.data);
data.value = res.data;
});
};
api();
</script>
下面是package.json脚本参考
"scripts": {
"dev": "vite",
"build": "vue-tsc --noEmit && vite build",
"preview": "vite preview"
},
前端准备完毕
2.后端准备工作
如果你已经有了项目那么就跳过这一步,直接看 5.后端Dockerfile
这里使用Node.js的Koa.js + TS构建项目,你可以自由选择你的后端项目框架
如果你想看现成的后端文件夹,请看这里
在根文件夹新建文件夹backend并新建项目
由于之前写过Koa.js + TS项目的构建方法,请直接参考这里
安装路由
yarn add koa-router
在index.ts整理并加入代码如下(使用了ts,用js也无所谓)
从数据库内读取数据,并建立test路由
当test路由被请求时,返回数据
import Koa from "koa";
import Router from "koa-router";
import { connect, Schema, model } from "mongoose";
const app = new Koa();
const router = new Router();
const host: number = 7022;
const url: string = "mongodb://foo:foo@database:27017/docker";
// #################### 数据库相关 ####################
const connectMongoDB = async (): Promise<void> => {
await connect(url)
.then((): void => {
console.log("mongodb connect success");
})
.catch((): void => {
console.log("mongodb connect failed");
});
};
interface IDocker {
id: number;
}
const schema = new Schema<IDocker>(
{ id: { type: Number, required: true } },
{ versionKey: false }
);
const dockerModel = model<IDocker>("tests", schema);
// #################### 路由相关 ####################
router.get("/test", async (ctx: Koa.Context): Promise<void> => {
console.log("requested");
await dockerModel.find({}, { _id: 0 }).then((res: IDocker[]): void => {
console.log(res);
ctx.body = {
message: "取得成功",
result: res,
};
});
});
// 启动服务
connectMongoDB();
app.use(router.routes()).use(router.allowedMethods());
app.listen(host, async (): Promise<void> => {
console.log(`backend on port ${host} 🚀`);
});
注意!
url是数据库的容器内地址,将会在后面讲到
后端准备完毕
3.数据准备工作
如果你已经有了项目那么就跳过这一步,直接看 6.数据端Dockerfile
这里使用Mongodb及其自带的MongoDBCompass图形管理应用
如果你想看现成的数据,请看这里
在根文件夹新建文件夹database并新建js文件mongo-init.js
这个js是干什么的呢,因为node.js和mongo身处不同容器,访问必须通过密码访问
超级管理员密码已经在构建容器的时候指定了,但是还需要创建具体库的管理员来读写数据
而且有一些固定的数据希望在容器启动的时候添加到数据库中,所以就利用这个js来自动注册并加入数据
这个js脚本没有也可以,因为你可以在构建好容器后利用mongo shell创建,那样就会很麻烦失去自动化的意义
下面插入了数据[{ id: 1 }, { id: 2 }]
// 自动注册库管理员和数据库docker
db.createUser({
user: "foo",
pwd: "foo",
roles: [
{
role: "readWrite",
db: "docker",
},
],
});
// 切换到刚才自动注册的docker数据库
db = db.getSiblingDB("docker");
// 自动生成表并插入数据
db.createCollection("tests");
db.tests.insertMany([{ id: 1 }, { id: 2 }]);
数据准备完毕
小总结
到此,你应该有这么三个文件夹了
下面开始docker化这三个东西
backend
├──node_modules
├── index.ts
├── tsconfig.json
├── yarn.lock
└── package.json
frontend
├── node_modules
├── public
├── src
├── vite.config.ts
├── tsconfig.json
├── yarn.lock
└── package.json
// 省略了一部分
database
└── mongo-init.js
4.前端Dockerfile
思路
把需要的前端文件复制到容器内,容器准备好运行环境并打包,打包后通过nginx反向代理到容器内的后端
第一步 拉取镜像
拉取node和nginx镜像
这一步不是必须的如果你的电脑里已经有了相关镜像就不需要
docker pull node
docker pull nginx
第二步 nginx配置
在前端文件夹frontend内新建nginx配置文件default.conf
前端将会跑在7021端口
server {
listen 7021;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
location /test {
proxy_pass http://backend:7022;
}
}
注意!
proxy_pass是后端服务器的容器内地址,将会在后面讲到
第三步 Dockerfile
在frontend文件夹新建Dockerfile,用来创建前端容器
写入下面的东西
# 指定node镜像
FROM node:16.3.0
# 指定作者
LABEL maintainer="kensoz"
# 指定容器内的工作路径
WORKDIR /usr/src/frontend
# 复制package.json和yarn.lock
COPY ["package.json", "yarn.lock", "./"]
# 安装
RUN yarn
# 复制全部文件,源代码
COPY . .
# 构建
RUN yarn build
# 指定node镜像
FROM nginx:latest
# 复制容器内的dist文件夹到nginx目录
COPY --from=0 /usr/src/frontend/dist/ /usr/share/nginx/html/
# 复制nginx配置文件
COPY default.conf /etc/nginx/conf.d/default.conf
用大白话解释一下:
我tm现在就要创建一个容器,来装老子的前端项目!
FROM node:16.3.0为了我的项目可以在容器里使用,我要在容器里能用node环境
WORKDIR /usr/src/frontend给我项目指定容器内的位置
COPY ["package.json", "yarn.lock", "./"]把我本地的前端项目package.json复制到容器
RUN yarn在容器内安装我的前端项目
COPY . .把我的项目文件统统复制到容器
RUN yarn build在容器内构建项目
FROM nginx:latest为了我的前端项目配置反向代理,我要用nginx
COPY --from=0 /usr/src/frontend/dist/ /usr/share/nginx/html/把我容器内构建好的dist文件放入容器内nginx文件夹
COPY default.conf /etc/nginx/conf.d/default.conf把我的本地的nginx配置复制到容器nginx
前端配置完毕
5.后端Dockerfile
思路
把需要的后端文件复制到容器内,容器准备好运行环境并打包,打包后启动打包好的js文件启动服务器
第一步 Dockerfile
后端将会跑在7022端口
因为前边已经拉取了node,所以不需要再拉取
在backend文件夹新建Dockerfile,用来创后端容器
写入下面的东西
# 指定node镜像
FROM node:16.3.0
# 指定作者
LABEL maintainer="kensoz"
# 指定容器内的工作路径
WORKDIR /usr/src/backend
# 复制package.json和yarn.lock
COPY ["package.json", "yarn.lock", "./"]
# 安装
RUN yarn
# 复制全部文件,源代码
COPY . .
# 构建
RUN yarn build
# 这个容器暴露的端口
EXPOSE 7022
# 容器启动时执行的命令
ENTRYPOINT [ "yarn", "start" ]
用大白话解释一下:
我tm现在就要创建一个容器,来装老子的后端项目!
FROM node:16.3.0为了我的项目可以在容器里使用,我要在容器里能用node环境
WORKDIR /usr/src/backend给我项目指定容器内的位置
COPY ["package.json", "yarn.lock", "./"]把我本地的后端项目package.json复制到容器
RUN yarn在容器内安装我的后端项
COPY . .把我的项目文件统统复制到容器
RUN yarn build在容器内构建项
EXPOSE 7022把7022作为项目的端口暴露出去
ENTRYPOINT [ "yarn", "start" ]最后启动我的后端api服务器
后端配置完毕
6.数据端Dockerfile
第一步 拉取镜像
数据将会跑在27017端口并使用docker数据库
拉取mongo镜像
这一步不是必须的如果你的电脑里已经有了相关镜像就不需要
docker pull mongo
第二步 Dockerfile
在database文件夹新建Dockerfile,用来创数据库容器
写入下面的东西
# 指定mongodb镜像
FROM mongo:latest
# 指定作者
LABEL maintainer="kensoz"
# 默认开启授权,并创建超管用户
ENV MONGO_INITDB_ROOT_USERNAME root
# 超管密码
ENV MONGO_INITDB_ROOT_PASSWORD root
# 你要用的数据库
ENV MONGO_INITDB_DATABASE docker
# 启动容器时执行脚本,自动注册库管理员
ADD mongo-init.js /docker-entrypoint-initdb.d/
用大白话解释一下:
我tm现在就要创建一个容器,来装老子的数据
FROM mongo:latest为了我的数据可以在容器里使用,我要在容器里安装mongo
ENV MONGO_INITDB_ROOT_USERNAM和ENV MONGO_INITDB_ROOT_PASSWORD安装mongo的同时指定超级管理员的密码和用户名,掌控数据库
ADD mongo-init.js /docker-entrypoint-initdb.d/执行前面准备的自动注册,数据写入脚本
数据配置完毕
小提示
为了防止浪费不必要的时间,建议在各个文件夹内新建.dockerignore文件,来忽略不需要用到的文件
node_modules;
dist.vscode;
logs;
coverage;
npm - debug.log;
yarn - debug.log;
7.docker-compose.yml
第一步 在根文件夹新建docker-compose.yml
version: "3.8"
# network
# 这个是容器内局域网网络名,这里取名dockertest-network
networks:
dockertest-network:
driver: bridge
services:
### frontend #################
# 前端文件,注意这里可以当作变量在局域网内使用,前端端口名frontend
frontend:
container_name: depoly-frontend
build:
context: ./frontend
ports:
- 127.0.0.1:7021:7021
restart: always
depends_on:
- backend
networks:
- dockertest-network
### backend #################
# 后端文件,注意这里可以当作变量在局域网内使用,后端端口名backend
backend:
container_name: depoly-backend
build:
context: ./backend
ports:
- 127.0.0.1:7022:7022
restart: always
depends_on:
- database
networks:
- dockertest-network
### database #################
# 数据库,注意这里可以当作变量在局域网内使用,数据端口名:database
database:
container_name: depoly-database
build:
context: ./database
ports:
- "127.0.0.1:27017:27017"
restart: always
networks:
- dockertest-network
用大白话解释一下:
- 用
docker-compose.yml来组织管理整体项目,分别执行里面的Dockerfile - 利用
docker network来实现容器内部互相通信 docker network的好处都有啥?数据库地址平时我们这么写localhost:27017/但是在docker内,每个容器的地址是不同与本地开发的,是动态的,并没有localhost。每一个容器都有一个自己的动态地址。通过上面的networks:我们建立容器内局域网,并且将指定容器的名称作为地址名database将容器的地址固定化,方便容器见的内部互联。就像本文章的数据库地址就变成了database:27017
至此docker-compose.yml准备工作完成
8.执行docker构建
话不多说,在根文件夹直接干
docker-compose up -d
不出意外,你的启动就成功了,如下
9.验证
前端验证
启动http://localhost:7021/发现控制台和页面都打印了数据
后端验证
打开Docker可视化工具,看到后端项目正常打印了log
数据验证
打开MongoDB图形化界面,docker也已经出现,数据也已经插入
结论
验证成功,可谓一句docker-compose up -d就可以自动启动整个全栈项目,非常滴爽
10.最后
- 本文章并没有做
volumes持久化数据,各位根据自己的喜好添加吧 - 本文章并没有做
CD/CI自动持续部署,各位根据自己的喜好添加,钩子自动执行docker-compose up -d即可 - 虽然本文章使用vue和koa,你也可以换成react和nest等等,修改一下命令即可
- 看到最后你是不是应该star一下?项目地址