Skip to content
On this page

docker

docker 是什么

它把系统的所有文件封装成一个镜像,镜像跑起来作为容器,它可以在一台机器上跑多个容器,每个容器都有独立的操作系统环境,比如文件系统、网络端口等,在容器内跑各种服务。

这样整个环境都保存在这个镜像里,部署多个实例只要通过这个镜像跑多个容器就行

Dockerfile

dockerfile
FROM node:latest # 基于一个基础镜像来修改

WORKDIR /app # 指定当前工作目录

COPY . . # 把容器外的内容复制到容器内

RUN npm config set registry https://registry.npmmirror.com/

RUN npm install -g http-server

EXPOSE 8080 # 向外暴露的端口

VOLUME /app # run时指定将真实的文件夹挂载到/app(相当于同一引用)

CMD ["http-server", "-p", "8080"] # 容器启动的时候执行的命令

nest 中的 dockerfile

.dockerignore

dockerfile
.md
!README.md
node_modules/
[a-c].txt
.git/
.DS_Store
.vscode/
.dockerignore
.eslintignore
.eslintrc
.prettierrc
.prettierignore

docker build 时,会先解析 .dockerignore,把该忽略的文件忽略掉,然后把剩余文件打包发送给 docker daemon 作为上下文来构建产生镜像。

多阶段构建

使跑起来的容器不存在无关的文件(比如源码,测试代码)

dockerfile
FROM node:18 as build-stage

WORKDIR /app

COPY package.json .

RUN npm config set registry https://registry.npmmirror.com/

RUN npm install

COPY . .

RUN npm run build


FROM node:18 as production-stage

COPY --from=build-stage /app/dist /app
COPY --from=build-stage /app/package.json /app/package.json

WORKDIR /app

RUN npm install --production

EXPOSE 3000

CMD ["node", "/app/main.js"]

mini 基础镜像

镜像依然很大,那是因为我们用的基础的 linux 镜像比较大,可以换成 alpine 的,这是一个 linux 发行版,主打的就是一个体积小。

dockerfile
FROM node:18.0-alpine3.14 as build-stage

技巧

  • 使用 alpine 的镜像,而不是默认的 linux 镜像,可以极大减小镜像体积,比如 node:18-alpine3.14 这种
  • 使用多阶段构建,比如一个阶段来执行 build,一个阶段把文件复制过去,跑起服务来,最后只保留最后一个阶段的镜像。这样使镜像内只保留运行需要的文件以及 dependencies。
  • 使用 ARG 增加构建灵活性,ARG 可以在 docker build 时通过 --build-arg xxx=yyy 传入,在 dockerfile 中生效,可以使构建过程更灵活。如果是想定义运行时可以访问的变量,可以通过 ENV 定义环境变量,值使用 ARG 传入。
  • CMD 和 ENTRYPOINT 都可以指定容器跑起来之后运行的命令,CMD 可以被覆盖,而 ENTRYPOINT 不可以,两者结合使用可以实现参数默认值的功能。
  • ADD 和 COPY 都可以复制文件到容器内,但是 ADD 处理 tar.gz 的时候,还会做一下解压。

灵活使用这些技巧,可以让你的 Dockerfile 更加灵活、性能更好。

docker 实现原理

Docker 的实现原理依赖 linux 的 Namespace、Control Group、UnionFS 这三种机制。

Namespace 做资源隔离,Control Group 做容器的资源限制,UnionFS 做文件系统的分层镜像存储、镜像合并。

我们通过 dockerfile 描述镜像构建的过程,每一条指令都是一个镜像层。

镜像通过 docker run 就可以跑起来,对外提供服务,这时会添加一个可写层(容器层)。

挂载一个 volume 数据卷到 Docker 容器,就可以实现数据的持久化。