Dockerfile 是一个文本文件,包含了一系列的指令和命令,这些指令和命令被 Docker 用来自动化构建 Docker 镜像的过程。Docker 镜像是轻量级、可执行的独立软件包,包含了运行一个应用所需的所有内容:代码、运行时环境、库、环境变量和配置文件。
Dockerfile 的主要用途如下:
- 定义环境:Dockerfile 允许你精确地定义运行你的应用所需要的操作系统环境、库以及依赖。
- 自动化构建:通过 Dockerfile,Docker 可以自动化构建镜像的过程,确保镜像的构建是可重复且一致的。
- 代码到部署的一致性:使用 Dockerfile 构建的镜像,可以确保开发、测试和生产环境中的运行环境一致性,减少了"在我机器上能运行"的问题。
- 版本控制和追踪:Dockerfile 可以像应用代码一样,被放在版本控制系统中,这样你可以追踪到环境的任何变更,以及回退到任何历史版本。
- 便捷的分发和部署:构建好的 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 包含了两个阶段:
- 构建阶段:这个阶段使用了一个带有 Node.js 的 Docker 镜像。在这个阶段中,首先设置了工作目录 /app,然后复制了 package.json 和 package-lock.json 文件,并执行了 npm install 来安装依赖。接下来,复制了所有项目文件,并执行了构建命令(例如 npm run build),这通常会生成一个 dist 文件夹,包含了所有静态文件。
- 运行阶段:这个阶段使用了一个轻量级的 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 上公开可用的前端应用容器。
- 登录到你的服务器:使用 SSH 连接到你的服务器。
bash
ssh [your-username]@[your-server-ip]
替换[your-username]
和[your-server-ip]
为你的服务器登录用户名和 IP 地址。
- 安装 Docker(如果尚未安装,安装了的):使用服务器的包管理器安装 Docker。
bash
sudo apt update
sudo apt install docker.io
- 启动 Docker 服务(如果尚未运行):
bash
sudo systemctl start docker
并确保 Docker 在每次启动时自动运行:
bash
sudo systemctl enable docker
- 拉取 Docker 镜像:从 Docker Hub 或你的私有仓库拉取你的前端应用镜像。
bash
sudo docker pull myusername/my-frontend-app:tag
- 运行 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 端口时,实际上是访问到了容器中运行的前端应用。
- 验证容器运行状态:检查容器是否正在运行。
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 分为两个步骤:
- 构建步骤(builder stage):使用 node:16-alpine 作为基础镜像,安装依赖,并构建 Nest.j s应用程序。这个阶段会生成构建好的应用程序代码。
- 运行时步骤(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 中,你可以通过几种不同的方式设置环境变量:
- 使用
Dockerfile
:
在 Dockerfile
中,可以使用 ENV
指令来设置环境变量。这些变量在构建镜像时被设置,并且在运行容器时保持不变。
dockerfile
ENV MY_VARIABLE my_value
- 在命令行中使用
docker run
命令:
当使用 docker run
命令启动容器时,可以通过 -e
或 --env
选项来传递环境变量。
shell
docker run -e "MY_VARIABLE=my_value" my_image
如果你有多个环境变量需要设置,可以多次使用 -e
选项。
- 使用环境变量文件:
如果你有许多环境变量需要设置,可以使用文件来存储这些变量,然后在使用 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
- 在
docker-compose.yml
文件中设置:
如果你使用的是 Docker Compose,可以在 docker-compose.yml
文件中的 environment
部分设置环境变量。
yaml
version: '3'
services:
my_service:
image: my_image
environment:
MY_VARIABLE: my_value
这些环境变量在容器启动时对容器内运行的应用程序可见,可以用于配置应用程序的行为,比如数据库连接信息、外部服务的 API 密钥等。