简介

本项目针对刚刚接触 Docker 的新手,讲解 Docker 基本操作,并结合一个实际案例来讲解具体应用。

环境说明

操作系统:MacOS Ventura 13.0

安装 Docker

通过官方网站地址选择对应的操作系统进行安装即可 官方连接

查看 Docker 版本

1
docker version

安装成功会显示如下信息(MacOS 版)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
Client:
Cloud integration: v1.0.35
Version: 24.0.2
API version: 1.43
Go version:go1.20.4
Git commit:cb74dfc
Built: Thu May 25 21:51:16 2023
OS/Arch: darwin/amd64
Context: desktop-linux
Server: Docker Desktop 4.21.1 (114176)
Engine:
Version: 24.0.2
API version: 1.43 (minimum version 1.12)
Go version: go1.20.4
Git commit: 659604f
Built:Thu May 25 21:52:17 2023
OS/Arch: linux/amd64
Experimental: false
containerd:
Version: 1.6.21
GitCommit:3dce8eb055cbb6872793272b4f20ed16117344f8
runc:
Version: 1.1.7
GitCommit:v1.1.7-0-g860f061
docker-init:
Version: 0.19.0
GitCommit:de40ad0

创建本地项目

初始化项目

1
2
3
mkdir learn-docker
npm init -y
npm install express

启动简单的服务

创建 app.js 文件

1
2
3
4
5
6
7
8
9
10
11
12
const express = require("express");
const app = express();
const PORT = 3000;
app.get("/", (req, res) => {
res.send("<p>大家好啊!</p>");
});
app.listen(PORT, () => {
console.log("running at 3000 prot");
});

执行 `node app.js` 启动服务 此时我们可以在 `http://localhost:3000/` 访问到我们的内容。 接下来我们使用
Docker 来实现。

创建 Dockerfile 文件

在项目的根目录创建 Dockerfile 文件

1
2
3
4
5
6
7
FROM node:20-alpine3.17 # 表示我们使用node 20的版本 注意1
WORKDIR /myDocker # 指定我们的工作目录
COPY package.json . # 将 package.json 复制到工作目录 .表示更目录 也就是我们指定的工作目录
RUN npm install # 执行 package.json
COPY . . # 将本地全部文件拷贝到Docker的工作目录 注意2
EXPOSE 3000 # 暴露3000端口 注意3
CMD ["node","app.js"] # 执行启动服务命令
  • 注意 1: Alpine 操作系统是一个面向安全的轻型 Linux 发行版。它不同于通常 Linux 发行版,Alpine 采用了 musl libc 和 busybox 以减小系统的体积和运行时资源消耗,但功能上比 busybox 又完善的多,因此得到开源社区越来越多的青睐
  • 注意 2:我们这里需要忽略 node_modules 等一些文件的复制
  • 注意 3:EXPOSE 3000 只有文档说明作用 不起任何实际作用。实际开启 3000 端口的是 app.js 的内容;而 Dockerfile 里的 EXPOSE 只是让人们知道这个容器使用的是 3000 端口

创建 .dockerignore 文件

前面提到的注意 2 中的事项,我们已经通过 npm install 安装了 node_modules ,所以不需要再复制一遍。

1
2
3
4
5
node_modules
Dockerfile
.dockerignore
.git
.gitignore

构建镜像

通过上面的操作我们就可以来构建镜像了。

1
docker build .

查看镜像

1
docker images

会看到如下的展示

1
2
REPOSITORYTAG   IMAGE ID   CREATED SIZE
nodejs-image latest227b17a0a994 About an hour ago 189MB

给镜像取名字 tag

1
docker tag 227 baituzai/nodejs:v1.0
  • 227 是镜像 id 的前 3 位数字
  • baituzai/nodejs:v1.0 用户名/镜像名:版本

注意:如果不加版本就是 lasted 建议务必加上

登录并推送 Docker Hub

1
2
3
4
docker login
# 根据提示输入用户名和密码
# 成功登录后执行
docker push baituzai/nodejs:v1.0

在构建镜像的时候就定义名字 具名镜像 -t

1
docker build -t my_docker_image_name .

注意:. 表示相对地址

删除本地的镜像

已经存在于 Docker Hub 所以把本地删除

1
docker rmi -f baituzai/nodejs:v1.0
  • rm remove 移除
  • i 表示 image 镜像
  • f force 强制删除(在使用中的镜像会被删除)

把镜像拉取到本地

1
docker pull baituzai/nodejs:v1.0 # docker pull 镜像名称

运行镜像

1
docker run nodejs-image # docker run 镜像名称

这种方式会占用我们的当前命令行窗口,使用 -d 选项使容器在后台运行

1
docker run -d nodejs-image # docker run -d 镜像名称

查看在运行的容器

1
2
3
docker ps
# or
docker ps -a
  • ps 表示 process status
  • -a 产看全部 包括未运行的容器

端口映射

当我们运行起容器后,想要在本地访问发现是不能成功的,我们需要把 Docker 服务器的端口转发到本地端口才能进行访问。

1
docker run -d -p 3000:3000 nodejs-image
  • 3000:3000 主机端口:容器端口,访问主机端口 3000 的时候就会访问容器端口 3000。使用其他端口也可以,只要不冲突就好。

给这个容器自定义一个名字

如果不定义那么系统就会给容器随机定义一个名字

1
docker run -d -p 3000:3000 --name nodejs-container nodejs-image

停止运行容器(关机)

把不使用的容器停止运行,也就关机,节省资源。

1
docker stop nodejs-container # 容器的id 或者是容器的名字都可以

删除容器

1
docker rm container_id/contanier_name

强制删除

1
docker rm -f container_id/contanier_name

修改本地文件 同步到 docker 文件

修改本地文件后,docker 不会自动同步, 镜像如同一张照片,只修改文件并没有修改镜像,所以需要生成新的镜像

查看我们正在运行的容器

如何访问容器呢?

1
docker exec -it nodejs-container /bin/sh
  • exec ececute 执行
  • i interactive 交互
  • t pseudo-TTY 伪终端
  • nodejs-container 容器名
  • /bin/sh 表示我们执行一个新的 bash shell

执行后会直接进入我的工作目录 myDocker 使用 exit 退出 shell

销毁容器

1
docker rm -f nodejs-container

重新开启一个容器 -v

1
docker run -d -v /Users/your_name/Desktop/learnDocker/:/myDocker -p 3000:3000 --name nodejs-container nodejs-image
  • 绝对路径 本地文件夹路径:容器文件夹路径 (/Users/your_name/Desktop/learnDocker/:/myDocker)
  • 本地文件夹路径使用 pwd 查看或者使用环境变量

改动后能否成功?

虽然文件内容同步更改了,但是还是不行 因为根据镜像启动容器的时候 使用 node app.js 是根据执行是的服务器文件来启动服务的。
如果文件有修改我们需要重新执行 node app.js 才能显示最新的内容。

使用 nodemon 来自动重启

  • 再次删除容器
  • 安装 nodemon
1
npm i nodemon -D

修改 package.json 的脚本

1
2
3
"scripts": {
"dev": "nodemon app.js"
}

修改 Dockerfile

CMD ["node","app.js"] 改成 CMD [ "npm","run","dev"]

删除之前的镜像 并重构镜像

使用-v 选项再次启动容器

1
docker run -d -v /Users/jiajunhua/Desktop/learnDocker/:/myDocker -p 3000:3000 --name nodejs-container nodejs-image

特殊处理

不要同步的文件 node_modules

1
docker run -d -v /Users/jiajunhua/Desktop/learnDocker/:/myDocker -v /myDocker/node_modules -p 3000:3000 --name nodejs-container nodejs-image
  • 说明 ndoe_modules 文件夹不进行同步

容器内容修改也会导致本地内容修改 这不是我们想要的

我们要让本地变成只读模式 readonly 也就是 容器修改不会影响到本地的内容 单项流通 在-v 后面加上冒号 ro :ro

1
docker run -d -v /Users/jiajunhua/Desktop/learnDocker/:/myDocker:ro -v /myDocker/node_modules -p 3000:3000 --name nodejs-container nodejs-image

使用 volume 时 当删除容器的时候 把对应的 volume 也删除

1
docker rm -fv nodejs-container

解决每次写命令都很长的问题 docker-compose

1
touch docker-compose.yml # 创建 docker-compose.yml 文件
1
2
3
4
5
6
7
8
9
version: '3.8'
services:
nodejs-contaier:
build: .
ports:
- "3000:3000"
volumes:
- ./:/myDocker:ro
- /myDocker/node_modules

注意这里的缩进是必要的

启动 docker-compose

1
2
3
docker-compose up
docker-compose up -d # -d 后台运行模式
docker-compose up -d --build # --build 镜像修改后 docker-compose 自动重建

清除 docker-compose

1
docker-compose down -y

项目仓库地址

github项目地址