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 容器,就可以实现数据的持久化。