Dockerfile與yaml
在容器使用過程中,會遇到dockerfile與yaml這兩種類型的文件,二者的用途和作用對象完全不同:Dockerfile是用于構建Docker鏡像的腳本文件,YAML則是用于容器編排的配置文件。
1、對比
Dockerfile |
YAML |
|
| 用途 | 定義“如何構建Docker鏡像” | 定義“編排容器” |
| 內容 | 構建鏡像的一系列步驟的集合 | 一系列跟配置有關的K-V結構 |
| 作用對象 | 鏡像(僅在docker build階段) | 容器(容器運行、編排階段) |
| 生效后的表現(xiàn) | 將應用代碼、依賴、環(huán)境變量打包成鏡像 | Docker Compose編排多容器、K8S管理Pod |
2、語法
Dockerfile
指令 + 參數(shù)的腳本語法,每行一條指令,描述構建鏡像的步驟
FROM python:3.9 # 基礎鏡像 WORKDIR /app # 設置工作目錄 COPY . /app # 復制本地代碼到鏡像 RUN pip install -r requirements.txt # 安裝依賴 CMD ["python", "app.py"] # 容器啟動時執(zhí)行的命令
YAML
縮進 + K:V的結構化數(shù)據(jù)格式,描述容器運行規(guī)則:
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 # 環(huán)境變量配置
3、使用
1)Dockerfile:直接運行單容器
Dockerfile的顯式使用場景為:直接通過docker run來運行單個容器,此時直接將相關配置(如端口映射、掛載目錄、環(huán)境變量等)直接通過命令行參數(shù)指定:
#運行一個NGINX容器 docker run -d -p 80:80 -v /host/data:container/data --name my-nginx nginx:latest
這里用到了:
- -d:后臺運行
- -p:端口映射
- -v:存儲掛載
本質上相當于將容器配置寫在了命令行里,由于單容器配置通常較簡單,命令行參數(shù)足以覆蓋需求,因此無需額外的YAML文件。
2)YAML:多容器協(xié)同運行
當需要管理多個容器協(xié)同運行(或者不必協(xié)同,單單啟多個容器),或者配置項非常復雜(如大量環(huán)境變量、多端口映射、自定義網絡)時,命令行會變得冗長、難以維護,此時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 # 環(huán)境變量 redis: # Redis 緩存容器 image: redis:6 # 直接使用官方 Redis 鏡像 ports: - "6379:6379"
之后用docker-compose up -d,Compose就會自動讀取這個YAML文件,按配置啟動兩個容器并維護它們的依賴關系。這比用兩條docker run手動啟動、協(xié)調要高效得多。
需要注意的是,上段鏡像一個是通過build構建的本地dockerfile,一個是直接用image來使用官方Redis鏡像。
②K8S:用YAML來定義容器部署
相較于Docker-Compose而言,K8S是目前更強大,也更主流的容器編排平臺,在生產環(huán)境大規(guī)模容器管理方面已經占據(jù)了相當一部分的市場。它完全基于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
在執(zhí)行了kubectl apply -f nginx-deployment.yaml后,K8S會讀取該YAML文件,自動創(chuàng)建3個NGINX容器副本,并保證它們按照預期運行。
③Docker Compose與K8S對YAML的不同處理
需要注意的是,Docker Compose支持在YAML中通過build來定義Dockerfile的構建過程。而K8S管理的YAML則不存在,K8S設計的理念是基于已有鏡像,而非在部署時動態(tài)構建鏡像,因此它不直接處理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扯上關系呢?剛在上一節(jié)就說了,K8S管理的是現(xiàn)有鏡像,且不會在部署時動態(tài)構建(即不存在直接給一個Dockerfile然后從零開始build為鏡像)。這是否說明在K8S管理YAML時要手動先Build Dockerfile呢?就算Build完,這里的my-docker-registry/nginx:v1又是什么東西?
答:K8S的YAML僅支持使用已經構建好的鏡像(要么是手動build、要么是通過CI/CD構建并推到倉庫),上文的my-docker-registry就是鏡像倉庫的地址。
關鍵要求:鏡像必須提前構建并推送至倉庫
K8S集群節(jié)點需要能拉取到這個鏡像,因此需要先通過docker build構建鏡像,再用docker push推送到鏡像倉庫。
K8S的核心在于容器編排與部署,而非鏡像構建。鏡像構建屬于CI(持續(xù)集成)環(huán)節(jié),應在部署到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字段是優(yōu)于build字段的,Compose也會檢查本地是否存在iamge指定的鏡像:存在時就直接使用;不存在時才執(zhí)行build重新構建。

浙公網安備 33010602011771號