Docker 简介
简而言之,Docker 容器轻量级、启动快、可移植,适合微服务架构。主要组件包括 Docker Engine、Docker 镜像、Docker 容器和 Docker Hub,它通过容器打包应用程序及其依赖项,使得应用在任何环境中都能一致运行。
这里不详细介绍 docker,想了解更多相关知识可以去官网查看docker 官网
安装 docker (mac 系统)
1.通过官网下载小鲸鱼(Docker Desktop),查看 About Dokcer Desktop,可以看到 docker 的信息
2.打开终端,输入docker -v
查看当前的版本,或者查看 docker 服务状态docker info
docker -v 或者 docker info
➜ ~ docker -v
Docker version 27.0.3, build 7d4bcd8
3.如果zsh: command not found: docker
,按照以下步骤处理:
- 在.bash_profile 写入:
export PATH=$PATH:/Applications/Docker.app/Contents/Resources/bin/
- 在.zshrc 中写入:
source ~/.bash_profile
- 运行
source .zshrc
- 运行
docker -v
测试 docker
终端运行docker run hello-world
, 会得到以下结果:
➜ ~ docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
c1ec31eb5944: Pull complete
Digest: sha256:1408fec50309afee38f3535383f5b09419e6dc0925bc69891e79d84cc4cdcec6
Status: Downloaded newer image for hello-world:latest
Hello from Docker!
This message shows that your installation appears to be working correctly.
....(忽略其他的)
hello-world 是 docker 上面发布的镜像,在 Docker Desktop 中也能看到这个 Image 和 Container,说明 docker 已经可以正常使用了。
docker 镜像和容器
这里来说下 docker 镜像和容器的关系:
- 想象一下,你要做一个蛋糕。蛋糕的配方就像是 Docker 镜像。
- 这个配方详细列出了制作蛋糕所需的所有材料和步骤。同样,Docker 镜像包含了一个应用程序运行所需的所有文件、依赖项和设置(可以理解为一个完整的项目)。
- 当你有了配方(Docker 镜像)之后,你可以根据这个配方反复制作蛋糕(启动容器)。
- 每次制作出来的蛋糕(容器)都是一样的,因为它们都是根据同一个配方(镜像)做出来的。
镜像的拉取和创建
docker pull
从 Docker Hub 或者其他注册表中拉取镜像
# 拉取 node 镜像最新版本或者指定版本
docker pull node:latest 或 docker pull node:20.10.0
docker image build
从 Dockerfile 构建一个镜像(下面会讲)
docker build -t <镜像名>:<标签> <Dockerfile所在目录>
容器的启动
- 使用该镜像运行一个容器
docker run [选项] <镜像名>:[标签]
docker run -d -p 8000:3000 --name my-node-app node:20.10.0
常用选项:
-d
: 后台运行-p
: 端口映射(如 -p 8000:3000, 访问 localhost:8000 代替 localhost:3000)--name
: 为容器指定一个名称
- 查看所有容器(包括停止的容器)
docker ps -a
- 停止和开启容器
docker stop <容器 ID 或名称> / docker start <容器 ID 或名称>
- 删除容器
docker rm <容器 ID 或名称>
以上介绍和示例跑通说明我们已经可以开始使用 docker 来部署我们的项目了(其他更多的 docker 语法可以在网上自行查阅,这里不进行详细讲解)
Dockerfile
# 选择基础镜像
FROM node:latest
# 设置维护者信息
LABEL maintainer="edon"
# 防止中文打印信息显示乱码
ENV LANG="C.UTF-8"
# WORKDIR:设置工作目录,所有后续指令(如RUN、COPY、ADD)都会在这个目录下执行。如果目录不存在,会自动创建。
WORKDIR /app
# COPY <源路径> <目标路径> 将文件或目录从构建上下文复制到镜像中。(如有忽略文件配置在.dockerignore中)
COPY ./package.json /app
COPY . /app
# RUN: 在镜像内执行命令。常用于安装软件包或配置环境。
RUN npm install
RUN npm run build
或
RUN npm install && npm run build
# EXPOSE: 声明镜像要监听的端口,这只是一个文档化的指令,实际上并不会开放端口。
EXPOSE 3000
# CMD:指定容器启动时要执行的命令,Dockerfile中只能有一个CMD指令,后面的会覆盖前面的
CMD ["node", "app.js"]
还有其他的配置如,ADD
、ENTRYPOINT
、VOLUME
、USER
、ARG
等等,在这里不详细列出。
以上是 Dockerfile 最基础的结构,将 Dockerfile 放置在根目录下,执行docker image build -t [image:name]:[tag] .
即可创建镜像,创建完就可以docker run
来运行了。
执行:docker image build -t my-node-app:0.1 .
在Docker Desktop的Images可以看到:
Docker Compose
Dockerfile 构建的是一个独立的镜像,但是像我们的后端项目,一般还会连接数据库,比如 mongodb,按照 Dockerfile 模块的介绍,我们还要创建 mongo 的镜像和开启 mongo 容器
# 拉取mongo镜像
docker pull mongo:latest
# 运行mongo容器
docker run -d --name mongo -p 27017:27017 -v mongo-data:/data/db mongo:latest
当我们有一个后端项目,连接着数据库,如 node+mongo,我们可以使用Docker Compose
,在一个 docker-compose.yml 文件中定义 Node.js 应用和 MongoDB 的服务,并一次性启动它们。
version: "3.8"
services:
app:
image: node:20.16.0
container_name: node-koa-temp
working_dir: /app/server
volumes:
- ./:/app/server
- /app/server/node_modules
environment:
- HOST_MONGO_URL=mongodb://mongo:27017
- PORT=8000
depends_on:
- mongo
ports:
- "8001:8000"
command: sh -c "npm install -g pnpm@latest --registry=https://registry.npmmirror.com && pnpm install && npm run build && npm run start:build"
mongo:
image: mongo:latest
container_name: node-koa-mongodb
ports:
- "27018:27017"
volumes:
- mongo-data:/data/db
volumes:
mongo-data:
以上的配置看着是不是很熟悉,跟 Dockerfile 的配置很相似,配置介绍可参考:Docker Compose
实战 node+koa+ts+mongo
1.先准备好一个 node 后端项目,这里我们会写一个 node+koa+ts+mongo 的项目(这里本地具备 node 和 mongo 环境)
仓库地址
demo仓库地址:github node+koa+ts+mongo
Demo项目介绍
node-koa-temp
│
├── src
│ ├── index.ts
│ ├── controllers
│ │ └── users.ts
│ ├── models
│ │ └── users.ts
│ ├── mongodb
│ │ └── index.ts
│ ├── routes
│ │ └── index.ts
│ ├── types
│ │ ├── common.ts
│ │ └── user.ts
├── .dockerignore
├── .npmrc
├── docker-compose.yml
├── Dcokerfile
├── nodemon.json
├── package.json
├── tsconfig.json
└── README.md
src/mongodb/index.ts
import mongoose from "mongoose"
const uri = "mongodb://localhost:27017"
export const connectToDatabase = async () => {
try {
await mongoose.connect(uri, { dbName: "local-mongodb" })
console.log("Connected to MongoDB with Mongoose")
} catch (error) {
console.error("Failed to connect to the database", error)
throw error
}
}
src/index.ts
import cors from "@koa/cors"
import http from "http"
import Koa from "koa"
import bodyParser from "koa-bodyparser"
import router from "src/routes"
import { connectToDatabase } from "./mongodb"
const app = new Koa()
app.use(
cors({
origin: "*",
allowMethods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
allowHeaders: ["Content-Type", "Authorization", "Accept"],
})
)
app.use(bodyParser())
app.use(router.routes()).use(router.allowedMethods())
const server = http.createServer(app.callback())
connectToDatabase()
.then(() => {
const PORT = 8000
server.listen(PORT, () => {
console.log(`Server is running http://localhost:${PORT}`)
})
})
.catch((error) => {
console.error("Failed to connect to the database", error)
})
tyconfig.json
{
"compilerOptions": {
"target": "es6",
"module": "commonjs",
"outDir": "./dist",
"strict": true,
"esModuleInterop": true,
"baseUrl": "./",
"paths": {
"src/*": ["./src/*"],
"~/*": ["./*"]
},
"typeRoots": ["node_modules/@types", "typings"]
},
"include": ["src/**/*", "typings"],
"exclude": ["node_modules"]
}
nodemon.json
{
"ignore": ["./node_modules/**"],
"watch": ["src"],
"exec": "cross-env ts-node -r tsconfig-paths/register src/index.ts",
"ext": "ts,json"
}
package.json
"scripts": {
"dev": "cross-env MODE=stage nodemon --config nodemon.json",
"build": "rimraf dist && tsc && tsc-alias",
"start:build": "cross-env MODE=prod node dist/index.js"
},
本地运行项目
npm run dev
运行成功,可以访问 localhost:8000
本地编译打包项目和启动
npm run build
npm run start:build
运行成功,可以访问 localhost:8000
docker-compose.yml
version: "3.8"
services:
app:
image: node:20.16.0
container_name: node-koa-temp
working_dir: /app/server
volumes:
- ./:/app/server
- /app/server/node_modules
environment:
- HOST_MONGO_URL=mongodb://mongo:27017
- PORT=8000
depends_on:
- mongo
ports:
- "8001:8000"
command: sh -c "npm install -g pnpm@latest --registry=https://registry.npmmirror.com && pnpm install && npm run build && npm run start:build"
mongo:
image: mongo:latest
container_name: node-koa-mongodb
ports:
- "27018:27017"
volumes:
- mongo-data:/data/db
volumes:
mongo-data:
在根目录下执行docker-compse up --build
,一次性启动两个容器
Docker Desktop 的 Container 可以看到:
这个时候访问 http://localhost:8001, 就可以访问到我们的服务了。
按照以上流程,使用 Dockerfile 可以直接部署 vue 或 React 前端项目,实现 docker 部署前后端项目项目。