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重新构建。

posted @ 2025-09-04 16:10  ShineLe  阅读(70)  评论(0)    收藏  举报