全栈 dockerfile 的编写指南(前端 + 后端 nest)

Dockerfile 是一个文本文件,包含了一系列的指令和命令,这些指令和命令被 Docker 用来自动化构建 Docker 镜像的过程。Docker 镜像是轻量级、可执行的独立软件包,包含了运行一个应用所需的所有内容:代码、运行时环境、库、环境变量和配置文件。

Dockerfile 的主要用途如下:

  1. 定义环境:Dockerfile 允许你精确地定义运行你的应用所需要的操作系统环境、库以及依赖。
  2. 自动化构建:通过 Dockerfile,Docker 可以自动化构建镜像的过程,确保镜像的构建是可重复且一致的。
  3. 代码到部署的一致性:使用 Dockerfile 构建的镜像,可以确保开发、测试和生产环境中的运行环境一致性,减少了"在我机器上能运行"的问题。
  4. 版本控制和追踪:Dockerfile 可以像应用代码一样,被放在版本控制系统中,这样你可以追踪到环境的任何变更,以及回退到任何历史版本。
  5. 便捷的分发和部署:构建好的 Docker 镜像可以被推送到 Docker Hub 或其他容器镜像仓库,从而方便地被分发和部署到任何支持 Docker 的平台上。

一个基本的 Dockerfile 可能包含以下指令:

  • FROM:指定基础镜像。所有的 Dockerfile 都必须以一个 FROM 指令开始,它定义了将要构建的镜像的基础(父)镜像。
  • RUN:执行命令并创建新的镜像层,用于安装软件包和做其他配置。
  • COPY 和 ADD:从构建上下文中复制文件到镜像中。
  • CMD:提供容器默认执行的命令。Dockerfile 中只能有一个 CMD 指令。
  • ENTRYPOINT:配置容器启动时运行的命令,允许容器像应用程序一样运行。
  • EXPOSE:声明容器运行时监听的端口。
  • ENV:设置环境变量。
  • WORKDIR:设置工作目录,即容器内部的当前目录。
  • VOLUME:创建一个可以从本地主机或其他容器挂载的挂载点(或称为卷)。

使用 Dockerfile 构建镜像的命令是 docker build。这个过程包括读取 Dockerfile 的每一条指令,执行它们,最终创建一个可用的 Docker 镜像。

前端

在前端项目中使用 Docker 通常是为了确保一致的开发环境和简化部署流程。

Dockerfile 通常包含了构建前端项目所需的所有步骤,包括安装依赖、构建静态文件以及运行服务。以下是一个典型的前端项目的 Dockerfile 示例:

dockerfile 复制代码
# 使用多阶段构建,首先定义构建阶段
# 选择一个带有Node.js的轻量级基础镜像
FROM node:16-alpine as build-stage

# 设置工作目录
WORKDIR /app

# 复制package.json和package-lock.json(如果存在)
COPY package*.json ./

# 安装项目生产依赖
# 利用Docker缓存层,如果 package.json 没有变化,则不会重新安装node modules
RUN npm install --only=production

# 复制项目文件到工作目录
COPY . .

# 构建应用
RUN npm run build

# 阶段2:运行
# 使用 Nginx 镜像作为基础来提供前端静态文件服务
FROM nginx:stable-alpine as production-stage

# 定义环境变量,例如NODE_ENV
ARG NODE_ENV=production
ENV NODE_ENV=${NODE_ENV}

WORKDIR /app

# 从构建阶段拷贝构建出的文件到Nginx目录
COPY --from=build-stage /app/dist /usr/share/nginx/html

# 配置nginx,如果有自定义的nginx配置可以取消注释并修改下面的行
# COPY nginx.conf /etc/nginx/conf.d/default.conf

# 暴露80端口
EXPOSE 80

# 启动Nginx服务器
CMD ["nginx", "-g", "daemon off;"]

这个 Dockerfile 包含了两个阶段:

  1. 构建阶段:这个阶段使用了一个带有 Node.js 的 Docker 镜像。在这个阶段中,首先设置了工作目录 /app,然后复制了 package.json 和 package-lock.json 文件,并执行了 npm install 来安装依赖。接下来,复制了所有项目文件,并执行了构建命令(例如 npm run build),这通常会生成一个 dist 文件夹,包含了所有静态文件。
  2. 运行阶段:这个阶段使用了一个轻量级的 Nginx 镜像来作为静态文件服务器。它从构建阶段复制了 dist 文件夹的内容到 Nginx 的服务目录。最后,暴露了端口 80,并设置了默认的启动命令来运行 Nginx。

当你运行这个 Docker 容器时,它会启动 Nginx 服务器并提供你的前端应用。

选择官方、经过验证的基础镜像,以确保安全性和可维护性。使用尽可能精简的基础镜像,比如 alpine,减少最终镜像的大小。

在这个 Dockerfile 中,我们使用了多阶段构建和利用 Docker 缓存层。这样做的好处是可以减小最终镜像的大小,因为构建阶段所需的依赖和工具在最终镜像中通常是不需要的。所以利用 Docker 的层次结构,将经常变动的指令放在 Dockerfile 的底部,这样可以充分利用缓存。

使用 ARG 和 ENV 来设置构建时和运行时的环境变量。这样可以在不修改 Dockerfile 的情况下重新构建镜像,更灵活。使用 ARG 声明的 NODE_ENV 构建参数,使用 ${NODE_ENV} 来取。花括号可加可不加。

利用多阶段构建可以将编译和运行环境分开,最终只将运行时必须的文件打包进镜像。

根据你的项目实际情况,可能还需要调整构建命令、复制的文件路径等。例如,如果你的构建命令不是 npm run build,就需要修改对应的 RUN 指令。如果你的静态文件输出目录不是 dist,也需要修改最后一个 COPY 指令中的路径。

此外,你可能还需要配置 Nginx,比如添加自定义的 nginx.conf 文件。这可以通过在第二个阶段添加一个 COPY 指令来实现,将你的配置文件复制到容器中的 Nginx 配置目录下。

确保在 Dockerfile 所在的目录结构中有你的前端代码和所有必要的文件,然后你可以通过以下命令来构建和运行你的Docker容器

dockerfile 复制代码
docker build -t my-frontend-app .
docker run -it -p 80:80 my-frontend-app

以上命令中 -t my-frontend-app 为构建出的镜像设置了一个标签,-p 80:80 将容器的 80 端口映射到宿主机的 80 端口。这样你就可以通过浏览器访问宿主机的 80 端口来访问你的前端应用了。

如果想要在服务器上运行,步骤如下:

例如运行 Ubuntu 的云服务器,以及一个在 Docker Hub 上公开可用的前端应用容器。

  1. 登录到你的服务器:使用 SSH 连接到你的服务器。
bash 复制代码
ssh [your-username]@[your-server-ip]

替换[your-username][your-server-ip]为你的服务器登录用户名和 IP 地址。

  1. 安装 Docker(如果尚未安装,安装了的):使用服务器的包管理器安装 Docker。
bash 复制代码
sudo apt update
sudo apt install docker.io
  1. 启动 Docker 服务(如果尚未运行):
bash 复制代码
sudo systemctl start docker

并确保 Docker 在每次启动时自动运行:

bash 复制代码
sudo systemctl enable docker
  1. 拉取 Docker 镜像:从 Docker Hub 或你的私有仓库拉取你的前端应用镜像。
bash 复制代码
sudo docker pull myusername/my-frontend-app:tag
  1. 运行 Docker 容器 :一旦镜像被拉取到服务器上,使用docker run命令来启动你的容器。
bash 复制代码
sudo docker run -d --name my-frontend-app-container -p 80:80 myusername/my-frontend-app:tag

这里的-d选项意味着"detached"模式,即在后台运行容器。--name给容器分配一个名称,以便于后续管理。

尽量为构建的镜像使用有意义的标签,并遵循版本控制最佳实践。
-p 80:80是端口映射,将容器内的 80 端口映射到主机的 80 端口上,这样外界访问服务器的 80 端口时,实际上是访问到了容器中运行的前端应用。

  1. 验证容器运行状态:检查容器是否正在运行。
bash 复制代码
sudo docker ps

现在,如果一切设置正确,你应该能够通过服务器的IP地址或绑定的域名在浏览器中访问你的前端应用了。

如果你需要查看应用的日志,可以使用:

bash 复制代码
sudo docker logs my-frontend-app-container

如果你需要停止容器,可以使用:

bash 复制代码
docker stop my-frontend-app-container

如果你需要重新启动容器,可以使用:

bash 复制代码
docker restart my-frontend-app-container

确保服务器的防火墙设置允许来自外部的 HTTP(端口80)和 HTTPS(端口 443,如果你使用 SSL)流量。

如果你需要配置 SSL 或设置一个更复杂的部署(如使用 Docker Compose,Kubernetes 等),这些步骤会更加复杂。

请注意,具体的命令可能会根据你的服务器配置、Docker 镜像设置以及你的需求有所不同。

后端 nest

在创建 Nest.js 项目的 Dockerfile 时,你需要考虑几个关键步骤:安装依赖项、构建应用程序和运行应用程序。以下是一个简单的 Dockerfile 示例,它将帮助你将 Nest.js 应用程序容器化:

dockerfile 复制代码
# Step 1: 使用带有Node.js的基础镜像
FROM node:16-alpine as builder

# 设置工作目录
WORKDIR /usr/src/app

# 复制package.json和package-lock.json(如果可用)
COPY package*.json ./

# 安装项目依赖
RUN npm install --only=production

# 复制所有文件到容器中
COPY . .

# 构建应用程序
RUN npm run build

# Step 2: 运行时使用更精简的基础镜像
FROM node:16-alpine

WORKDIR /usr/src/app

# 从builder阶段复制构建好的文件
COPY --from=builder /usr/src/app/dist ./dist
COPY --from=builder /usr/src/app/node_modules ./node_modules

# 暴露3000端口
EXPOSE 3000

# 运行Nest.js应用程序
CMD ["node", "dist/main"]

这个 Dockerfile 分为两个步骤:

  1. 构建步骤(builder stage):使用 node:16-alpine 作为基础镜像,安装依赖,并构建 Nest.j s应用程序。这个阶段会生成构建好的应用程序代码。
  2. 运行时步骤(runtime stage):再次使用 node:16-alpine 作为基础镜像,但这次只是复制构建步骤中生成的 dist 目录和 node_modules 目录到新的工作目录中。这样做的目的是保持镜像尽可能的精简。因为构建步骤中的依赖、源代码和其他不必要的文件在运行时阶段是不需要的。

最后,通过 EXPOSE 指令声明容器运行时需要暴露的端口,然后通过 CMD 指令指定容器启动时运行的命令。

在你的实际项目中,你可能还需要设置环境变量、处理私有依赖库或者添加额外的配置文件。记得根据你项目的实际需求调整 Dockerfile。

gitlab 自动部署

下面是一个示例 .gitlab-ci.yml 文件,用于自动化构建和部署前端应用程序到 Docker 容器中:

yaml 复制代码
stages:
  - build
  - deploy

build:
  stage: build
  image: docker:latest
  services:
    - docker:dind
  script:
    - docker build -t your-image-name .
    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
    - docker push your-image-name

deploy:
  stage: deploy
  image: docker:latest
  services:
    - docker:dind
  script:
    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
    - docker pull your-image-name
    - docker run -d --name your-container-name -p 80:80 your-image-name
  only:
    - master

上述示例中的.gitlab-ci.yml文件定义了两个阶段(stage):build 和 deploy。

在 build 阶段,使用 Docker 构建你的镜像,并将其推送到你的 Docker 注册表(registry)。

在 deploy 阶段,从 Docker 注册表中拉取镜像,并在容器中运行应用程序。

only 关键字指定了只有在推送到 master 分支时才会执行部署作业。

请注意,上述示例中使用了 GitLab CI/CD 提供的 CI/CD 变量(CI_REGISTRY_USER、CI_REGISTRY_PASSWORD 和 CI_REGISTRY),这些变量需要在 GitLab 项目的设置中进行配置。

你需要根据你的具体情况修改上述示例中的镜像名称、容器名称和端口映射等参数,以适应你的项目需求。此外,你还可以根据需要在 script 部分添加其他命令或步骤,例如运行测试、执行静态代码分析等。

完成后,将上述内容保存为 .gitlab-ci.yml 文件,并将其提交到你的 GitLab 代码仓库中。GitLab 将根据配置的 .gitlab-ci.yml 文件自动执行构建和部署操作。

docker 的环境变量

Docker 容器中的环境变量是一个关键特性,用于管理容器内的配置。环境变量可以在容器运行时传递给容器内部的应用程序,从而允许用户调整容器行为而无需修改应用程序代码。

在 Docker 中,你可以通过几种不同的方式设置环境变量:

  1. 使用 Dockerfile

Dockerfile 中,可以使用 ENV 指令来设置环境变量。这些变量在构建镜像时被设置,并且在运行容器时保持不变。

dockerfile 复制代码
ENV MY_VARIABLE my_value
  1. 在命令行中使用 docker run 命令:

当使用 docker run 命令启动容器时,可以通过 -e--env 选项来传递环境变量。

shell 复制代码
docker run -e "MY_VARIABLE=my_value" my_image

如果你有多个环境变量需要设置,可以多次使用 -e 选项。

  1. 使用环境变量文件:

如果你有许多环境变量需要设置,可以使用文件来存储这些变量,然后在使用 docker run 命令时通过 --env-file 选项指定该文件。

shell 复制代码
docker run --env-file my_env_file.txt my_image

其中 my_env_file.txt 文件包含了环境变量的键值对,每行一个,如下所示:

ini 复制代码
MY_VARIABLE=my_value
ANOTHER_VARIABLE=another_value
  1. docker-compose.yml 文件中设置:

如果你使用的是 Docker Compose,可以在 docker-compose.yml 文件中的 environment 部分设置环境变量。

yaml 复制代码
version: '3'
services:
  my_service:
    image: my_image
    environment:
      MY_VARIABLE: my_value

这些环境变量在容器启动时对容器内运行的应用程序可见,可以用于配置应用程序的行为,比如数据库连接信息、外部服务的 API 密钥等。

相关推荐
Ian10251 分钟前
《Learn Three.js》学习(3)光源
前端·javascript·学习·webgl·图形学·三维·三维光源
帅比九日2 分钟前
基于@ohos/axios学习HarmonyOS Next的网络数据请求
前端·华为·harmonyos
涔溪19 分钟前
css Grid网格布局
前端·css
秦老师Q37 分钟前
HTML CSS JS基础考试题与答案
开发语言·前端·javascript·css·面试·html
liuxin334455661 小时前
林业产品推荐系统:Spring Boot架构设计
数据库·spring boot·后端
AndyGoWei1 小时前
BFC (Block Formatting Context) 原理规则,看这篇就够了
前端·css·html
BillKu1 小时前
修改插槽样式,el-input 插槽 append 的样式
前端·css·vue.js
金色浪花1 小时前
VUE项目部署服务器之后刷新页面异常
前端·javascript·vue.js
小白本无忧2 小时前
【Laravel】模型封装属性基础
前端·javascript·laravel
2 小时前
Fabric.js使用
前端