当前位置: 首页 > news >正文

Docker 完整教程(5,6) | 容器编译与编排

本教程侧重于命令实践和理解,提供可在本地环境测试的实例,每章结束都有总结要点。

目录

前边篇章介绍了

  1. Docker 基础概念和安装
  2. Docker 常用命令实践
  3. Docker 网络机制详解
  4. Docker 数据卷和挂载

本篇内容:

  1. Dockerfile 编写和镜像构建
  2. Docker Compose 多容器编排

本系列内容较多,建议在侧边栏根据需要点击目录进行跳转。

第5章:Dockerfile 编写和镜像构建

5.1 Dockerfile 基础

Dockerfile 是一个文本文件,包含了构建 Docker 镜像的所有指令。通过 Dockerfile,我们可以自动化地创建自定义镜像。

Dockerfile 基本结构

# 基础镜像
FROM ubuntu:20.04# 维护者信息
LABEL maintainer="your-email@example.com"# 设置工作目录
WORKDIR /app# 复制文件
COPY . .# 安装依赖
RUN apt-get update && apt-get install -y python3# 暴露端口
EXPOSE 8080# 启动命令
CMD ["python3", "app.py"]

第一个 Dockerfile

# 创建项目目录
mkdir -p /tmp/docker-tutorial/first-dockerfile
cd /tmp/docker-tutorial/first-dockerfile# 创建应用文件
cat > app.py << 'EOF'
#!/usr/bin/env python3
print("Hello from my first Docker image!")
print("This is a simple Python application.")
EOF# 创建 Dockerfile
cat > Dockerfile << 'EOF'
FROM python:3.11-slimWORKDIR /appCOPY app.py .CMD ["python", "app.py"]
EOF# 构建镜像
docker build -t my-first-image .# 运行容器
docker run --rm my-first-image# 查看镜像
docker images my-first-image

5.2 Dockerfile 指令详解

FROM - 基础镜像

# 使用官方镜像
FROM python:3.11-slim# 使用特定版本
FROM node:18.17.0-alpine# 使用多阶段构建
FROM golang:1.21 AS builder
FROM alpine:latest AS runtime

RUN - 执行命令

# 单个命令
RUN apt-get update# 多个命令(推荐)
RUN apt-get update && \apt-get install -y \curl \vim \git && \apt-get clean && \rm -rf /var/lib/apt/lists/*# 使用 shell 形式
RUN echo "Hello World"# 使用 exec 形式
RUN ["echo", "Hello World"]

COPY 和 ADD

# COPY - 复制文件(推荐)
COPY app.py /app/
COPY requirements.txt /app/
COPY . /app/# ADD - 复制文件(支持 URL 和自动解压)
ADD https://example.com/file.tar.gz /tmp/
ADD archive.tar.gz /app/# 复制并设置权限
COPY --chown=1000:1000 app.py /app/

WORKDIR - 工作目录

# 设置工作目录
WORKDIR /app# 相对路径(基于当前 WORKDIR)
WORKDIR subdir# 绝对路径
WORKDIR /var/log

ENV - 环境变量

# 设置环境变量
ENV NODE_ENV=production
ENV PORT=3000
ENV DATABASE_URL=postgresql://localhost/mydb# 一次设置多个
ENV NODE_ENV=production \PORT=3000 \DEBUG=false

EXPOSE - 暴露端口

# 暴露单个端口
EXPOSE 8080# 暴露多个端口
EXPOSE 8080 8443# 指定协议
EXPOSE 53/udp
EXPOSE 80/tcp

CMD 和 ENTRYPOINT

# CMD - 默认命令(可被覆盖)
CMD ["python", "app.py"]
CMD python app.py# ENTRYPOINT - 入口点(不可被覆盖)
ENTRYPOINT ["python", "app.py"]# 组合使用
ENTRYPOINT ["python"]
CMD ["app.py"]

为方便解释区别,以组合为例,比如:

FROM python:3.9
ENTRYPOINT ["python"]
CMD ["app.py"]

运行效果:

# 默认运行
docker run myapp
# 实际执行:python app.py# 运行不同的 Python 脚本 | CMD 命令会被替换
docker run myapp test.py
# 实际执行:python test.py# 传递参数给脚本
docker run myapp app.py --debug
# 实际执行:python app.py --debug

5.3 实践练习

练习1:Python Web 应用

# 创建 Python Web 应用项目
mkdir -p /tmp/docker-tutorial/python-webapp
cd /tmp/docker-tutorial/python-webapp# 创建应用代码
cat > app.py << 'EOF'
from flask import Flask, jsonify
import os
import socketapp = Flask(__name__)@app.route('/')
def hello():return jsonify({'message': 'Hello from Python Web App!','hostname': socket.gethostname(),'environment': os.environ.get('ENVIRONMENT', 'development')})@app.route('/health')
def health():return jsonify({'status': 'healthy'})if __name__ == '__main__':app.run(host='0.0.0.0', port=int(os.environ.get('PORT', 5000)))
EOF# 创建依赖文件
cat > requirements.txt << 'EOF'
Flask==2.3.3
gunicorn==21.2.0
EOF# 创建 Dockerfile
cat > Dockerfile << 'EOF'
FROM python:3.11-slim# 设置环境变量
ENV PYTHONUNBUFFERED=1
ENV PORT=5000
ENV ENVIRONMENT=production# 创建应用用户
RUN groupadd -r appuser && useradd -r -g appuser appuser# 设置工作目录
WORKDIR /app# 复制依赖文件并安装
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt# 复制应用代码
COPY app.py .# 更改文件所有者
RUN chown -R appuser:appuser /app# 切换到非 root 用户
USER appuser# 暴露端口
EXPOSE 5000# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \CMD curl -f http://localhost:5000/health || exit 1# 启动命令
CMD ["gunicorn", "--bind", "0.0.0.0:5000", "app:app"]
EOF# 构建镜像
docker build -t python-webapp .# 运行容器
docker run -d --name webapp -p 5000:5000 python-webapp# 测试应用
sleep 5
curl http://localhost:5000
curl http://localhost:5000/health# 查看健康状态
docker ps# 清理
docker stop webapp
docker rm webapp

练习2:Node.js 应用(多阶段构建)

# 创建 Node.js 项目
mkdir -p /tmp/docker-tutorial/nodejs-app
cd /tmp/docker-tutorial/nodejs-app# 创建 package.json
cat > package.json << 'EOF'
{"name": "nodejs-docker-app","version": "1.0.0","description": "Node.js app with Docker","main": "server.js","scripts": {"start": "node server.js","dev": "nodemon server.js"},"dependencies": {"express": "^4.18.2"},"devDependencies": {"nodemon": "^3.0.1"}
}
EOF# 创建服务器代码
cat > server.js << 'EOF'
const express = require('express');
const app = express();
const port = process.env.PORT || 3000;app.get('/', (req, res) => {res.json({message: 'Hello from Node.js Docker app!',timestamp: new Date().toISOString(),environment: process.env.NODE_ENV || 'development'});
});app.get('/health', (req, res) => {res.json({ status: 'healthy' });
});app.listen(port, '0.0.0.0', () => {console.log(`Server running on port ${port}`);
});
EOF# 创建 .dockerignore
cat > .dockerignore << 'EOF'
node_modules
npm-debug.log
.git
.gitignore
README.md
.env
.nyc_output
coverage
.DS_Store
EOF# 创建多阶段 Dockerfile
cat > Dockerfile << 'EOF'
# 构建阶段
FROM node:18-alpine AS builderWORKDIR /app# 复制 package 文件
COPY package*.json ./# 安装所有依赖(包括开发依赖)
RUN npm ci --only=production && npm cache clean --force# 运行阶段
FROM node:18-alpine AS runtime# 创建应用用户
RUN addgroup -g 1001 -S nodejs && \adduser -S nextjs -u 1001WORKDIR /app# 从构建阶段复制 node_modules
COPY --from=builder /app/node_modules ./node_modules# 复制应用代码
COPY --chown=nextjs:nodejs server.js .
COPY --chown=nextjs:nodejs package*.json ./# 切换到非 root 用户
USER nextjs# 暴露端口
EXPOSE 3000# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \CMD wget --no-verbose --tries=1 --spider http://localhost:3000/health || exit 1# 启动应用
CMD ["node", "server.js"]
EOF# 构建镜像
docker build -t nodejs-app .# 运行容器
docker run -d --name nodeapp -p 3000:3000 -e NODE_ENV=production nodejs-app# 测试应用
sleep 5
curl http://localhost:3000
curl http://localhost:3000/health# 查看镜像大小
docker images nodejs-app# 清理
docker stop nodeapp
docker rm nodeapp

5.4 构建优化技巧

使用 .dockerignore

# 创建 .dockerignore 文件
cat > .dockerignore << 'EOF'
# Git
.git
.gitignore# Documentation
README.md
docs/# Dependencies
node_modules/
__pycache__/
*.pyc# IDE
.vscode/
.idea/# OS
.DS_Store
Thumbs.db# Logs
*.log
logs/# Test files
test/
tests/
*.test# Build artifacts
dist/
build/
target/
EOF

docker 在构建镜像过程中,会忽略掉 .dockerignore 文件中指定的文件和目录。

层缓存优化

# 不好的做法 - 每次都重新安装依赖
FROM node:18-alpine
COPY . /app
WORKDIR /app
RUN npm install# 好的做法 - 利用层缓存
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .

后者的做法利用了 Docker 的层缓存机制,只有在依赖配置文件(package.json 或 requirements.txt)发生变化时才会重新安装依赖,而业务代码的变化不会触发依赖安装。

FROM node:18-alpine
WORKDIR /app
COPY package*.json ./    # ← 只复制依赖配置文件
RUN npm install          # ← 只有依赖变化时才重新安装
COPY . .                 # ← 最后复制业务代码

减少镜像层数

# 不好的做法 - 多个 RUN 指令
RUN apt-get update
RUN apt-get install -y curl
RUN apt-get install -y git
RUN apt-get clean# 好的做法 - 合并 RUN 指令
RUN apt-get update && \apt-get install -y curl git && \apt-get clean && \rm -rf /var/lib/apt/lists/*

5.5 构建上下文和高级技巧

构建参数 (ARG)

ARG NODE_VERSION=18
FROM node:${NODE_VERSION}-alpineARG BUILD_DATE
ARG VERSION
LABEL build_date=${BUILD_DATE}
LABEL version=${VERSION}# 构建时传递参数
# docker build --build-arg NODE_VERSION=16 --build-arg VERSION=1.0.0 .

留意 ARG 和 ENV 使用场景的区别:

  • ARG = Argument(参数)→ 构建时的"参数",构建时用完就扔
  • ENV = Environment(环境)→ 运行时的"环境变量",运行时也能用

多平台构建

# 创建构建器
docker buildx create --name multiplatform --use# 多平台构建
docker buildx build --platform linux/amd64,linux/arm64 -t my-app:latest .# 推送到仓库
docker buildx build --platform linux/amd64,linux/arm64 -t my-app:latest --push .

注:大多数容器化应用都是 Linux 容器,通过 Docker Desktop 使用 manifest list (多架构清单) 来实现跨平台支持。

构建缓存

# 使用构建缓存
docker build --cache-from my-app:latest -t my-app:new .# 禁用缓存
docker build --no-cache -t my-app .# 查看构建历史
docker history my-app

5.6 安全最佳实践

使用非 root 用户

FROM alpine:latest# 创建用户
RUN addgroup -g 1001 -S appgroup && \adduser -u 1001 -S appuser -G appgroup# 设置工作目录权限
WORKDIR /app
RUN chown appuser:appgroup /app# 切换用户
USER appuserCOPY --chown=appuser:appgroup . .

最小化攻击面

# 使用最小基础镜像
FROM alpine:latest# 只安装必要的包
RUN apk add --no-cache ca-certificates# 删除不必要的文件
RUN rm -rf /var/cache/apk/* /tmp/*# 使用特定版本而非 latest
FROM node:18.17.0-alpine

本章总结

在本章中,我们深入学习了 Dockerfile 编写和镜像构建:

  1. Dockerfile 基础:掌握了 Dockerfile 的基本语法和常用指令
  2. 指令详解:深入理解了 FROM、RUN、COPY、WORKDIR、ENV、EXPOSE、CMD、ENTRYPOINT 等指令
  3. 实践练习:通过 Python 和 Node.js 应用构建加深理解
  4. 构建优化:学会了使用 .dockerignore、层缓存、减少层数等优化技巧
  5. 高级技巧:了解了构建参数、多平台构建、构建缓存等高级特性
  6. 安全实践:掌握了非 root 用户、最小化攻击面等安全最佳实践

关键概念总结

  • 多阶段构建:减少最终镜像大小,分离构建和运行环境
  • 层缓存:合理安排指令顺序,提高构建效率
  • 构建上下文:理解 Docker 构建过程中的文件传输机制
  • 镜像优化:通过各种技巧减少镜像大小和提高安全性

下一章我们将学习 Docker Compose,实现多容器应用的编排和管理。

第6章:Docker Compose 多容器编排

6.1 Docker Compose 简介

Docker Compose 是一个用于定义和运行多容器 Docker 应用的工具。通过 YAML 文件配置应用的服务,然后使用单个命令创建并启动所有服务。

为什么需要 Docker Compose

# 传统方式启动多容器应用(繁琐且容易出错)
docker network create app-network
docker run -d --name database --network app-network -e MYSQL_ROOT_PASSWORD=root mysql
docker run -d --name redis --network app-network redis
docker run -d --name web --network app-network -p 8080:80 nginx# 使用 Docker Compose(简单且可重复)
docker-compose up -d

安装 Docker Compose

# 检查是否已安装
docker-compose --version# macOS (通过 Docker Desktop 自带)
# 已包含在 Docker Desktop 中# Linux 安装
sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose# 验证安装
docker-compose --version

6.2 Docker Compose 文件结构

基本语法

version: '3.8'services:service_name:image: image_nameports:- "host_port:container_port"environment:- ENV_VAR=valuevolumes:- host_path:container_pathnetworks:network_name:volumes:volume_name:

6.3 Compose 文件详解

服务配置选项

version: '3.8'services:app:# 使用镜像image: nginx:alpine# 或者构建镜像build:context: .dockerfile: Dockerfileargs:- BUILD_ARG=value# 容器名称container_name: my-app# 端口映射ports:- "8080:80"- "443:443"# 环境变量environment:- NODE_ENV=production- DEBUG=false# 环境变量文件env_file:- .env- .env.local# 数据卷volumes:- ./data:/app/data- app_logs:/app/logs# 网络networks:- frontend- backend# 依赖关系depends_on:- database- redis# 重启策略restart: unless-stopped# 资源限制deploy:resources:limits:memory: 512Mcpus: '0.5'# 健康检查healthcheck:test: ["CMD", "curl", "-f", "http://localhost"]interval: 30stimeout: 10sretries: 3

这里包括几个关键概念:

  • image:使用的镜像名称(必填,除非使用 build 构建)
  • build:构建镜像的上下文和 Dockerfile 路径
  • container_name:容器名称,(可选,容器的唯一标识,默认为 {项目名}_{服务名}_{序号}
  • ports:端口映射
  • environment:环境变量
  • env_file:环境变量文件(默认读取 .env 文件)
  • volumes:数据卷挂载
  • networks:网络连接
  • depends_on:依赖服务(可选,确保服务启动顺序)
  • restart:重启策略(默认 no,可选 alwayson-failureunless-stopped
  • deploy:用于配置资源约束****、副本数量健康检查等部署相关设置。

网络配置

version: '3.8'services:web:image: nginxnetworks:- frontendapi:image: node:alpinenetworks:- frontend- backenddatabase:image: mysqlnetworks:- backendnetworks: # 这里定义了两个网络frontend:driver: bridgebackend:driver: bridgeinternal: true  # 内部网络,无法访问外网

此外,可以通过 external: true 参数来指定外部已存在的网络。留意二者的区别:

  • internal: true:只能和同一网络内的其他容器通信,无法访问外网。
  • external: true:声明这是一个已经存在的外部网络,在 docker-compose down 时不会删除这个网络。

数据卷配置

version: '3.8'services:app:image: nginxvolumes:- app_data:/app/data          # 命名卷- ./config:/app/config:ro     # 绑定挂载(只读)- /tmp:/app/tmp               # 绑定挂载volumes:app_data:driver: localexternal_volume:external: true  # 使用外部已存在的卷

6.4 Compose 命令详解

基本命令

# 启动服务
docker-compose up                    # 前台启动
docker-compose up -d                 # 后台启动
docker-compose up --build            # 重新构建并启动
docker-compose up service_name       # 启动指定服务# 停止服务
docker-compose stop                  # 停止所有服务
docker-compose stop service_name     # 停止指定服务
docker-compose down                  # 停止并删除容器、网络
docker-compose down -v               # 同时删除数据卷# 查看状态
docker-compose ps                    # 查看服务状态
docker-compose logs                  # 查看所有日志
docker-compose logs -f service_name  # 实时查看指定服务日志# 执行命令
docker-compose exec service_name command    # 在运行的容器中执行命令
docker-compose run service_name command     # 运行一次性命令# 扩展服务
docker-compose up -d --scale web=3          # 扩展 web 服务到 3 个实例

配置管理

# 验证配置文件,展开默认值
docker-compose config# 使用多个配置文件
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up# 指定项目名称
docker-compose -p myproject up# 使用环境变量,优先级高于 .env 文件
export COMPOSE_PROJECT_NAME=myapp
docker-compose up

6.6 高级特性

服务扩展和负载均衡

version: '3.8'services:nginx:image: nginx:alpineports:- "80:80"volumes:- ./nginx.conf:/etc/nginx/nginx.confdepends_on:- webweb:build: .expose:- "3000"environment:- NODE_ENV=productiondatabase:image: mysql:8.0environment:- MYSQL_ROOT_PASSWORD=rootpass
# 扩展 web 服务
docker-compose up -d --scale web=3# nginx 配置负载均衡
upstream backend {server web_1:3000;server web_2:3000;server web_3:3000;
}

健康检查和依赖管理

version: '3.8'services:web:image: nginxhealthcheck:test: ["CMD", "curl", "-f", "http://localhost"]interval: 30stimeout: 10sretries: 3start_period: 40sdepends_on:api:condition: service_healthyapi:build: .healthcheck:test: ["CMD", "curl", "-f", "http://localhost:3000/health"]interval: 30stimeout: 10sretries: 3

本章总结

在本章中,我们全面学习了 Docker Compose 多容器编排:

  1. Compose 基础:理解了 Docker Compose 的作用和基本概念
  2. 文件结构:掌握了 docker-compose.yml 的语法和配置选项
  3. 服务配置:学会了配置服务、网络、数据卷等各种选项
  4. 实践应用:通过完整的 Web 应用栈和开发环境配置加深理解
  5. 命令操作:掌握了 Compose 的各种命令和使用技巧
  6. 高级特性:了解了服务扩展、负载均衡、健康检查等高级功能

Compose vs 手动管理对比

  • 简化操作:一个命令启动整个应用栈
  • 配置管理:声明式配置,易于版本控制
  • 环境一致性:确保开发、测试、生产环境一致
  • 服务发现:自动的服务名称解析
  • 扩展性:轻松扩展服务实例数量

最后一章我们将学习 Docker 镜像管理和仓库操作,包括镜像的推送、拉取、私有仓库搭建等内容。

http://www.dtcms.com/a/453221.html

相关文章:

  • 网站模板 外贸工厂济宁网站建设是什么
  • pyautocad 发送消息到消息栏 acad.doc.Utility.Prompt
  • 【传奇开心果系列】基于Flet框架实现的分析题型的掌握程度不同题型得分饼图样式示例自定义模板特色和实现原理深度解析
  • 做网站怎么防止被网警查到wordpress 设置登陆
  • 部署MySql8.4.6(Kylinv10sp3、Ubuntu2204、Rocky9.3)
  • 高并发下如何保证 Caffeine + Redis 多级缓存的一致性问题?MySQL、Redis 缓存一致性问题?
  • 吉林省建设厅网站评职称系统手机装wordpress
  • LeetCode 分类刷题:1901. 寻找峰值 II
  • ROS实战中Gazebo的基本使用
  • wordpress网站维护教程wordpress修改管理密码
  • PTA6-1 使用函数求最大公约数(C)
  • 小谈:数字化项目立项成功的方法论
  • HTTPS 真的牢不可破吗?—— 中间人攻击与安全机制解析
  • 广东省城乡建设厅网站seo短视频新地址在哪里?
  • 从 0 到 1 搭建 Python 语言 Web UI自动化测试学习系列 9--基础知识 5--常用函数 3
  • 然后在亚马逊网站上做外贸做网站需要做数据库
  • 接口测试-Postman 断言
  • 网站关键词更换了专业网站建设 公司哪家好
  • 乐观锁 与 悲观锁 笔记251007
  • Linux中select的实现
  • /UI2/CL_JSON=>DESERIALIZE :JSON反序列化
  • MySQL主主复制+Keepalived高可用集群搭建与故障切换实战
  • 幼儿网站源代码室内设计案例去什么网站
  • Spring Framework源码解析——BeanFactoryAware
  • Linux系统--进程通信初解
  • 企业网站如何建设报告jsp简述网站开发流程
  • VS2022创建项目工程笔记
  • 【学习笔记05】C++11新特性学习总结(下)
  • RNN、LSTM与GRU模型
  • 基于华为云IOT设计的粮仓环境监测系统_303