Dockerfile与yaml
在容器使用过程中,会遇到dockerfile与yaml这两种类型的文件,二者的用途和作用对象完全不同:Dockerfile是用于构建Docker镜像的脚本文件,YAML则是用于容器编排的配置文件。
1、对比
Dockerfile |
YAML |
|
| 用途 | 定义“如何构建Docker镜像” | 定义“编排容器” |
| 内容 | 构建镜像的一系列步骤的集合 | 一系列跟配置有关的K-V结构 |
| 作用对象 | 镜像(仅在docker build阶段) | 容器(容器运行、编排阶段) |
| 生效后的表现 | 将应用代码、依赖、环境变量打包成镜像 | Docker Compose编排多容器、K8S管理Pod |
2、语法
Dockerfile
指令 + 参数的脚本语法,每行一条指令,描述构建镜像的步骤
FROM python:3.9 # 基础镜像 WORKDIR /app # 设置工作目录 COPY . /app # 复制本地代码到镜像 RUN pip install -r requirements.txt # 安装依赖 CMD ["python", "app.py"] # 容器启动时执行的命令
YAML
缩进 + K:V的结构化数据格式,描述容器运行规则:
version: '3' services: # 定义要运行的容器(服务) app: # 应用容器名 image: my-python-app # 使用的镜像(可由 Dockerfile 构建) ports: - "8000:8000" # 端口映射 depends_on: - db # 依赖 MySQL 容器 db: # MySQL 容器名 image: mysql:8.0 environment: - MYSQL_ROOT_PASSWORD=123456 # 环境变量配置
3、使用
1)Dockerfile:直接运行单容器
Dockerfile的显式使用场景为:直接通过docker run来运行单个容器,此时直接将相关配置(如端口映射、挂载目录、环境变量等)直接通过命令行参数指定:
#运行一个NGINX容器 docker run -d -p 80:80 -v /host/data:container/data --name my-nginx nginx:latest
这里用到了:
- -d:后台运行
- -p:端口映射
- -v:存储挂载
本质上相当于将容器配置写在了命令行里,由于单容器配置通常较简单,命令行参数足以覆盖需求,因此无需额外的YAML文件。
2)YAML:多容器协同运行
当需要管理多个容器协同运行(或者不必协同,单单启多个容器),或者配置项非常复杂(如大量环境变量、多端口映射、自定义网络)时,命令行会变得冗长、难以维护,此时YAML就成了标准化的配置方案。
YAML的核心应用场景有两个:
①Docker Compose:Docker用YAML管理多容器应用
②Kubernetes(K8S):用YAML定义容器部署
①Docker Compose
Docker Compose是Docker官方提供的多容器编排工具,其核心就是通过一个docker-compose.yml文件,定义所有容器的配置(镜像、端口、挂载、依赖关系等),然后用一条指令启动所有容器。
例子:一个“Flask后端 + Redis缓存”的多容器应用,docker-compose.yml会写为:
# docker-compose.yml version: '3' # Compose 版本 services: # 定义所有容器(服务) flask-app: # 后端容器 build: . # 从当前目录的 Dockerfile 构建镜像 ports: - "5000:5000" # 端口映射:主机5000 → 容器5000 depends_on: - redis # 依赖 Redis 容器(确保 Redis 先启动) environment: - REDIS_URL=redis://redis:6379/0 # 环境变量 redis: # Redis 缓存容器 image: redis:6 # 直接使用官方 Redis 镜像 ports: - "6379:6379"
之后用docker-compose up -d,Compose就会自动读取这个YAML文件,按配置启动两个容器并维护它们的依赖关系。这比用两条docker run手动启动、协调要高效得多。
需要注意的是,上段镜像一个是通过build构建的本地dockerfile,一个是直接用image来使用官方Redis镜像。
②K8S:用YAML来定义容器部署
相较于Docker-Compose而言,K8S是目前更强大,也更主流的容器编排平台,在生产环境大规模容器管理方面已经占据了相当一部分的市场。它完全基于YAML配置文件来定义如何部署容器(如Deployment、Pod、Service等资源)。
例如,一个简单的NGINX部署的YAML文件:(nginx-deployment.yaml):
# nginx-deployment.yaml apiVersion: apps/v1 kind: Deployment # 资源类型:部署(管理 Pod 副本) metadata: name: nginx-deployment spec: replicas: 3 # 启动 3 个 Nginx 副本(高可用) selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: # 定义容器配置 - name: nginx image: nginx:1.21 ports: - containerPort: 80
在执行了kubectl apply -f nginx-deployment.yaml后,K8S会读取该YAML文件,自动创建3个NGINX容器副本,并保证它们按照预期运行。
③Docker Compose与K8S对YAML的不同处理
需要注意的是,Docker Compose支持在YAML中通过build来定义Dockerfile的构建过程。而K8S管理的YAML则不存在,K8S设计的理念是基于已有镜像,而非在部署时动态构建镜像,因此它不直接处理Dockerfile的构建逻辑。
4、K8S的YAML与Dockerfile的关系
一个标准的K8S YAML如下所示:
# nginx-deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment spec: replicas: 2 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx # 直接指定已构建好的镜像(可以是 Dockerfile 构建的自定义镜像) image: my-docker-registry/nginx:v1 # 需提前推送到仓库(如 Docker Hub、私有仓库) ports: - containerPort: 80
其中上图iamge之处即为镜像的位置。
但是这如何跟我们自写的Dockerfile扯上关系呢?刚在上一节就说了,K8S管理的是现有镜像,且不会在部署时动态构建(即不存在直接给一个Dockerfile然后从零开始build为镜像)。这是否说明在K8S管理YAML时要手动先Build Dockerfile呢?就算Build完,这里的my-docker-registry/nginx:v1又是什么东西?
答:K8S的YAML仅支持使用已经构建好的镜像(要么是手动build、要么是通过CI/CD构建并推到仓库),上文的my-docker-registry就是镜像仓库的地址。
关键要求:镜像必须提前构建并推送至仓库
K8S集群节点需要能拉取到这个镜像,因此需要先通过docker build构建镜像,再用docker push推送到镜像仓库。
K8S的核心在于容器编排与部署,而非镜像构建。镜像构建属于CI(持续集成)环节,应在部署到K8S之前完成(例如通过Jenkins、GitLab CI等工具构建并推送镜像)。
5、疑问
1)YAML中一定要有个镜像,这是否意味着Dockerfile一定是YAML的先决文件?
这种说法不完全准确。
因为YAML是否能用,只看有没有可用的镜像,这个镜像可以是官方的、用Dockerfile自制的、从仓库拉取的。
Dockerfile只是其中一种情况,因此不能说没了Dockerfile,YAML就完全没用了。
以下给出几个YAML使用不同来源镜像的例子:
①官方镜像
docker-compose.yml
version: '3' services: nginx: image: nginx:latest # 直接用官方 Nginx 镜像,无需 Dockerfile ports: - "80:80" mysql: image: mysql:8.0 # 直接用官方 MySQL 镜像,无需 Dockerfile environment: MYSQL_ROOT_PASSWORD: 123456
像上文这种直接写nginx:latest,也是能拉取到官方镜像的,这是因为当没写官方仓库地址时,Docker会使用默认的Docker Hub(地址为:docker.io),所以上述的image: nginx:latest,实际上Docker拉取镜像时的完整地址是:docker.io/library/nginx:latest。
只有使用非Docker Hub的仓库时,才需要手写完整的镜像地址。
②自定义镜像
先写一个Dockerfile
FROM node:18 WORKDIR /app COPY package*.json ./ RUN npm install COPY . . CMD ["node", "server.js"]
再写docker-compose.yml,并基于这个自定义镜像启动容器(起了两个,其中一个还是用的官方的)
version: '3' services: app: image: my-node-app # 用 Dockerfile 构建的自定义镜像 build: . # 可选:YAML 还能帮你自动构建镜像(不用手动 docker build) ports: - "3000:3000" redis: image: redis:latest # 依然用官方镜像,无需 Dockerfile
以上是纯dockerfile还没build构建的情况下的写法,如果dockerfile已经经过了build构建,就不用写build: .了:
version: '3' services: app: image: my-node-app:latest # 直接使用已手动构建好的镜像 ports: - "3000:3000" # 不需要写 build: .,避免重复构建 redis: image: redis:latest
此外,iamge字段是优于build字段的,Compose也会检查本地是否存在iamge指定的镜像:存在时就直接使用;不存在时才执行build重新构建。

浙公网安备 33010602011771号