html
复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Docker 教程 - FastAPI 容器化</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
:root {
--primary: #2496ed;
--secondary: #0db7ed;
--dark: #1d2733;
--light: #f5f8fa;
--success: #28a745;
--warning: #ffc107;
--danger: #dc3545;
--shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
body {
background: linear-gradient(135deg, #f0f7ff 0%, #e6f7ff 100%);
color: #333;
line-height: 1.6;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 0 20px;
}
/* Header Styles */
header {
background: linear-gradient(135deg, var(--primary) 0%, var(--secondary) 100%);
color: white;
padding: 1rem 0;
box-shadow: var(--shadow);
position: sticky;
top: 0;
z-index: 100;
}
.header-content {
display: flex;
justify-content: space-between;
align-items: center;
}
.logo {
display: flex;
align-items: center;
gap: 15px;
}
.logo i {
font-size: 2.5rem;
}
.logo-text {
font-size: 1.8rem;
font-weight: 700;
letter-spacing: 1px;
}
nav ul {
display: flex;
list-style: none;
gap: 25px;
}
nav a {
color: white;
text-decoration: none;
font-weight: 600;
padding: 8px 15px;
border-radius: 5px;
transition: all 0.3s ease;
}
nav a:hover, nav a.active {
background: rgba(255, 255, 255, 0.2);
}
/* Hero Section */
.hero {
background: linear-gradient(rgba(29, 39, 51, 0.85), rgba(29, 39, 51, 0.9)), url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100"><rect width="100" height="100" fill="%231d2733"/><path d="M0 50 L100 50 M50 0 L50 100" stroke="%232496ed" stroke-width="1" opacity="0.2"/></svg>');
background-size: cover;
color: white;
padding: 5rem 0;
text-align: center;
}
.hero h1 {
font-size: 3.5rem;
margin-bottom: 1.5rem;
text-shadow: 0 2px 4px rgba(0,0,0,0.3);
}
.hero p {
font-size: 1.3rem;
max-width: 800px;
margin: 0 auto 2rem;
opacity: 0.9;
}
.cta-button {
display: inline-block;
background: var(--success);
color: white;
padding: 12px 30px;
border-radius: 30px;
font-weight: 700;
text-decoration: none;
font-size: 1.1rem;
transition: all 0.3s ease;
box-shadow: 0 4px 15px rgba(40, 167, 69, 0.3);
}
.cta-button:hover {
background: #218838;
transform: translateY(-3px);
box-shadow: 0 6px 20px rgba(40, 167, 69, 0.4);
}
/* Main Content */
.content-section {
padding: 4rem 0;
}
.section-title {
text-align: center;
margin-bottom: 3rem;
color: var(--dark);
font-size: 2.5rem;
position: relative;
}
.section-title:after {
content: '';
display: block;
width: 80px;
height: 4px;
background: linear-gradient(90deg, var(--primary), var(--secondary));
margin: 15px auto 0;
border-radius: 2px;
}
.card-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 30px;
margin-top: 2rem;
}
.card {
background: white;
border-radius: 12px;
overflow: hidden;
box-shadow: var(--shadow);
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.card:hover {
transform: translateY(-10px);
box-shadow: 0 12px 20px rgba(0, 0, 0, 0.15);
}
.card-header {
background: linear-gradient(135deg, var(--primary), var(--secondary));
color: white;
padding: 20px;
font-weight: 700;
font-size: 1.3rem;
display: flex;
align-items: center;
gap: 10px;
}
.card-body {
padding: 25px;
}
.card-body ul {
list-style-type: none;
padding-left: 0;
}
.card-body li {
padding: 8px 0;
border-bottom: 1px dashed #eee;
display: flex;
align-items: flex-start;
gap: 10px;
}
.card-body li:last-child {
border-bottom: none;
}
.card-body li i {
color: var(--primary);
margin-top: 5px;
}
/* Code Sections */
.code-section {
background: var(--dark);
border-radius: 12px;
overflow: hidden;
margin: 3rem 0;
box-shadow: var(--shadow);
}
.code-header {
background: rgba(0, 0, 0, 0.3);
padding: 12px 20px;
color: white;
display: flex;
justify-content: space-between;
align-items: center;
}
.code-content {
padding: 20px;
overflow-x: auto;
}
pre {
color: #f8f8f2;
font-family: 'Consolas', 'Monaco', monospace;
font-size: 1rem;
line-height: 1.5;
}
.command {
color: #a6e22e;
}
.comment {
color: #75715e;
}
.option {
color: #66d9ef;
}
.yaml-key {
color: #cc7832;
}
.yaml-value {
color: #a5c261;
}
.yaml-string {
color: #a5c261;
}
.copy-btn {
background: rgba(255, 255, 255, 0.1);
color: white;
border: none;
padding: 6px 12px;
border-radius: 4px;
cursor: pointer;
transition: all 0.2s;
font-size: 0.9rem;
}
.copy-btn:hover {
background: rgba(255, 255, 255, 0.2);
}
/* Interactive Demo */
.demo-container {
background: white;
border-radius: 12px;
padding: 30px;
box-shadow: var(--shadow);
margin: 3rem 0;
}
.demo-title {
text-align: center;
margin-bottom: 25px;
color: var(--dark);
}
.terminal {
background: #1e1e1e;
border-radius: 8px;
padding: 20px;
font-family: 'Consolas', monospace;
color: #d4d4d4;
min-height: 200px;
max-height: 400px;
overflow-y: auto;
position: relative;
}
.terminal-header {
display: flex;
gap: 8px;
margin-bottom: 15px;
}
.terminal-btn {
width: 12px;
height: 12px;
border-radius: 50%;
}
.terminal-btn.red { background: #ff5f56; }
.terminal-btn.yellow { background: #ffbd2e; }
.terminal-btn.green { background: #27ca3f; }
.terminal-content {
margin-top: 10px;
}
.terminal-line {
margin-bottom: 8px;
display: flex;
}
.prompt {
color: #4ec9b0;
margin-right: 8px;
}
.user-input {
background: rgba(255, 255, 255, 0.1);
border: 1px solid #444;
color: white;
padding: 8px 12px;
border-radius: 4px;
width: 100%;
margin-top: 15px;
font-family: 'Consolas', monospace;
}
.demo-controls {
display: flex;
gap: 15px;
margin-top: 20px;
flex-wrap: wrap;
}
.demo-btn {
flex: 1;
min-width: 150px;
padding: 10px 15px;
background: var(--primary);
color: white;
border: none;
border-radius: 6px;
cursor: pointer;
font-weight: 600;
transition: all 0.2s;
}
.demo-btn:hover {
background: #1a7bc0;
transform: translateY(-2px);
}
.demo-btn.secondary {
background: #6c757d;
}
.demo-btn.secondary:hover {
background: #5a6268;
}
/* Footer */
footer {
background: var(--dark);
color: white;
padding: 3rem 0 1.5rem;
margin-top: 4rem;
}
.footer-content {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 30px;
margin-bottom: 2rem;
}
.footer-column h3 {
margin-bottom: 1.5rem;
font-size: 1.3rem;
position: relative;
padding-bottom: 10px;
}
.footer-column h3:after {
content: '';
position: absolute;
left: 0;
bottom: 0;
width: 40px;
height: 3px;
background: var(--primary);
}
.footer-column ul {
list-style: none;
}
.footer-column li {
margin-bottom: 10px;
}
.footer-column a {
color: #ccc;
text-decoration: none;
transition: color 0.2s;
}
.footer-column a:hover {
color: white;
}
.copyright {
text-align: center;
padding-top: 2rem;
border-top: 1px solid rgba(255, 255, 255, 0.1);
color: #aaa;
font-size: 0.9rem;
}
/* Responsive */
@media (max-width: 768px) {
.header-content {
flex-direction: column;
gap: 15px;
}
nav ul {
flex-wrap: wrap;
justify-content: center;
}
.hero h1 {
font-size: 2.5rem;
}
.hero p {
font-size: 1.1rem;
}
.demo-controls {
flex-direction: column;
}
.demo-btn {
width: 100%;
}
}
/* Animation */
@keyframes fadeIn {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
.card, .code-section, .demo-container {
animation: fadeIn 0.5s ease forwards;
}
.card:nth-child(1) { animation-delay: 0.1s; }
.card:nth-child(2) { animation-delay: 0.2s; }
.card:nth-child(3) { animation-delay: 0.3s; }
.card:nth-child(4) { animation-delay: 0.4s; }
.card:nth-child(5) { animation-delay: 0.5s; }
.card:nth-child(6) { animation-delay: 0.6s; }
</style>
</head>
<body>
<!-- Header -->
<header>
<div class="container header-content">
<div class="logo">
<i class="fab fa-docker"></i>
<div class="logo-text">Docker教程</div>
</div>
<nav>
<ul>
<li><a href="#" class="active">首页</a></li>
<li><a href="#concepts">基本概念</a></li>
<li><a href="#commands">常用命令</a></li>
<li><a href="#dockerfile">Dockerfile</a></li>
<li><a href="#yml">Docker Compose</a></li>
<li><a href="#demo">交互演示</a></li>
</ul>
</nav>
</div>
</header>
<!-- Hero Section -->
<section class="hero">
<div class="container">
<h1>掌握 Docker 容器化技术</h1>
<p>从入门到精通的完整指南,学习如何使用 Docker 构建、部署和运行应用程序</p>
<a href="#concepts" class="cta-button">开始学习 <i class="fas fa-arrow-right"></i></a>
</div>
</section>
<!-- Concepts Section -->
<section id="concepts" class="content-section">
<div class="container">
<h2 class="section-title">Docker 核心概念</h2>
<div class="card-grid">
<div class="card">
<div class="card-header"><i class="fas fa-box"></i> 镜像 (Image)</div>
<div class="card-body">
<ul>
<li><i class="fas fa-check-circle"></i> Docker镜像是只读模板</li>
<li><i class="fas fa-check-circle"></i> 包含运行应用所需的全部内容</li>
<li><i class="fas fa-check-circle"></i> 基于UnionFS的分层结构</li>
<li><i class="fas fa-check-circle"></i> 可从Docker Hub获取</li>
</ul>
</div>
</div>
<div class="card">
<div class="card-header"><i class="fas fa-cube"></i> 容器 (Container)</div>
<div class="card-body">
<ul>
<li><i class="fas fa-check-circle"></i> 镜像的运行实例</li>
<li><i class="fas fa-check-circle"></i> 轻量级且隔离的环境</li>
<li><i class="fas fa-check-circle"></i> 可以启动、停止和删除</li>
<li><i class="fas fa-check-circle"></i> 每个容器相互隔离</li>
</ul>
</div>
</div>
<div class="card">
<div class="card-header"><i class="fas fa-warehouse"></i> 仓库 (Registry)</div>
<div class="card-body">
<ul>
<li><i class="fas fa-check-circle"></i> 存储和分发镜像的服务</li>
<li><i class="fas fa-check-circle"></i> Docker Hub是公共仓库</li>
<li><i class="fas fa-check-circle"></i> 支持私有仓库部署</li>
<li><i class="fas fa-check-circle"></i> 类似GitHub的镜像管理</li>
</ul>
</div>
</div>
<div class="card">
<div class="card-header"><i class="fas fa-file-code"></i> Dockerfile</div>
<div class="card-body">
<ul>
<li><i class="fas fa-check-circle"></i> 构建镜像的脚本文件</li>
<li><i class="fas fa-check-circle"></i> 包含构建指令和元数据</li>
<li><i class="fas fa-check-circle"></i> 支持分层构建和缓存</li>
<li><i class="fas fa-check-circle"></i> 实现自动化构建流程</li>
</ul>
</div>
</div>
<div class="card">
<div class="card-header"><i class="fas fa-network-wired"></i> 网络 (Network)</div>
<div class="card-body">
<ul>
<li><i class="fas fa-check-circle"></i> 容器间通信机制</li>
<li><i class="fas fa-check-circle"></i> 支持多种网络驱动</li>
<li><i class="fas fa-check-circle"></i> 容器IP隔离与发现</li>
<li><i class="fas fa-check-circle"></i> 端口映射实现外部访问</li>
</ul>
</div>
</div>
<div class="card">
<div class="card-header"><i class="fas fa-boxes"></i> 数据卷 (Volume)</div>
<div class="card-body">
<ul>
<li><i class="fas fa-check-circle"></i> 持久化容器数据</li>
<li><i class="fas fa-check-circle"></i> 独立于容器生命周期</li>
<li><i class="fas fa-check-circle"></i> 高效的数据共享</li>
<li><i class="fas fa-check-circle"></i> 支持本地和云存储</li>
</ul>
</div>
</div>
</div>
</div>
</section>
<!-- Commands Section -->
<section id="commands" class="content-section" style="background: #f8f9fa;">
<div class="container">
<h2 class="section-title">常用 Docker 命令</h2>
<div class="code-section">
<div class="code-header">
<span>镜像操作</span>
<button class="copy-btn" onclick="copyCode('image-code')">复制代码</button>
</div>
<div class="code-content">
<pre id="image-code"><span class="comment"># 从仓库拉取镜像</span>
<span class="command">docker pull</span> <span class="option">[镜像名]:[标签]</span>
<span class="comment"># 列出本地镜像</span>
<span class="command">docker images</span>
<span class="comment"># 构建镜像</span>
<span class="command">docker build</span> <span class="option">-t [镜像名]:[标签] [Dockerfile路径]</span>
<span class="comment"># 删除镜像</span>
<span class="command">docker rmi</span> <span class="option">[镜像ID或名称]</span>
<span class="comment"># 查看镜像历史</span>
<span class="command">docker history</span> <span class="option">[镜像名]</span></pre>
</div>
</div>
<div class="code-section">
<div class="code-header">
<span>容器操作</span>
<button class="copy-btn" onclick="copyCode('container-code')">复制代码</button>
</div>
<div class="code-content">
<pre id="container-code"><span class="comment"># 创建并启动容器</span>
<span class="command">docker run</span> <span class="option">-d --name [容器名] [镜像名]</span>
<span class="comment"># 列出运行中的容器</span>
<span class="command">docker ps</span>
<span class="comment"># 列出所有容器</span>
<span class="command">docker ps -a</span>
<span class="comment"># 停止容器</span>
<span class="command">docker stop</span> <span class="option">[容器名或ID]</span>
<span class="comment"># 启动已停止的容器</span>
<span class="command">docker start</span> <span class="option">[容器名或ID]</span>
<span class="comment"># 删除容器</span>
<span class="command">docker rm</span> <span class="option">[容器名或ID]</span>
<span class="comment"># 查看容器日志</span>
<span class="command">docker logs</span> <span class="option">[容器名或ID]</span>
<span class="comment"># 进入容器终端</span>
<span class="command">docker exec</span> <span class="option">-it [容器名或ID] /bin/bash</span></pre>
</div>
</div>
<div class="code-section">
<div class="code-header">
<span>容器与主机交互</span>
<button class="copy-btn" onclick="copyCode('interact-code')">复制代码</button>
</div>
<div class="code-content">
<pre id="interact-code"><span class="comment"># 端口映射 (-p 主机端口:容器端口)</span>
<span class="command">docker run</span> <span class="option">-d -p 8080:80 nginx</span>
<span class="comment"># 挂载数据卷 (-v 主机目录:容器目录)</span>
<span class="command">docker run</span> <span class="option">-v /host/path:/container/path [镜像名]</span>
<span class="comment"># 设置环境变量 (-e)</span>
<span class="command">docker run</span> <span class="option">-e "ENV_VAR=value" [镜像名]</span>
<span class="comment"># 查看容器详细信息</span>
<span class="command">docker inspect</span> <span class="option">[容器名或ID]</span></pre>
</div>
</div>
</div>
</section>
<!-- Dockerfile Section -->
<section id="dockerfile" class="content-section">
<div class="container">
<h2 class="section-title">Dockerfile 示例</h2>
<p style="text-align: center; max-width: 800px; margin: 0 auto 2rem; font-size: 1.1rem;">
Dockerfile 是一个文本文件,包含构建镜像的所有指令。以下是一个FastAPI应用的Dockerfile示例(使用国内淘宝镜像源):
</p>
<div class="code-section">
<div class="code-header">
<span>FastAPI 应用 Dockerfile(国内淘宝源)</span>
<button class="copy-btn" onclick="copyCode('dockerfile-code')">复制代码</button>
</div>
<div class="code-content">
<pre id="dockerfile-code"><span class="comment"># 使用官方Python运行时作为父镜像</span>
<span class="command">FROM</span> python:3.11-slim
<span class="comment"># 设置工作目录</span>
<span class="command">WORKDIR</span> /app
<span class="comment"># 复制依赖文件</span>
<span class="command">COPY</span> requirements.txt .
<span class="comment"># 安装应用依赖(使用国内淘宝镜像源加速)</span>
<span class="command">RUN</span> pip install --no-cache-dir -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple/
<span class="comment"># 复制应用源代码</span>
<span class="command">COPY</span> . .
<span class="comment"># 暴露端口8000</span>
<span class="command">EXPOSE</span> 8000
<span class="comment"># 定义容器启动时运行的命令</span>
<span class="command">CMD</span> ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]</pre>
</div>
</div>
<div class="code-section">
<div class="code-header">
<span>requirements.txt 示例(国内淘宝源)</span>
<button class="copy-btn" onclick="copyCode('requirements-code')">复制代码</button>
</div>
<div class="code-content">
<pre id="requirements-code"><span class="comment"># FastAPI 应用依赖(使用阿里云镜像源)</span>
<span class="comment"># 安装命令: pip install -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple/</span>
fastapi==0.104.1
uvicorn[standard]==0.24.0
pydantic==2.5.0
python-multipart==0.0.6
<span class="comment"># 可选:数据库相关</span>
# sqlalchemy==2.0.23
# alembic==1.12.1
<span class="comment"># 可选:测试相关</span>
# pytest==7.4.3
# httpx==0.25.1</pre>
</div>
</div>
<div class="code-section">
<div class="code-header">
<span>应用结构示例</span>
<button class="copy-btn" onclick="copyCode('structure-code')">复制代码</button>
</div>
<div class="code-content">
<pre id="structure-code"><span class="comment"># 项目目录结构</span>
my-fastapi-app/
├── app/
│ ├── __init__.py
│ ├── main.py <span class="comment"># FastAPI 主应用文件</span>
│ ├── models.py <span class="comment"># 数据模型</span>
│ ├── routes.py <span class="comment"># API 路由</span>
│ └── database.py <span class="comment"># 数据库连接</span>
├── tests/
│ ├── __init__.py
│ └── test_main.py <span class="comment"># 测试文件</span>
├── .env <span class="comment"># 环境变量</span>
├── .gitignore
├── Dockerfile
├── docker-compose.yml <span class="comment"># 可选:多容器编排</span>
├── requirements.txt
└── README.md
<span class="comment"># main.py 示例</span>
from fastapi import FastAPI
app = FastAPI(title="My FastAPI App")
@app.get("/")
def read_root():
return {"message": "Hello, Dockerized FastAPI!"}
@app.get("/health")
def health_check():
return {"status": "healthy"}</pre>
</div>
</div>
</div>
</section>
<!-- Docker Compose Section -->
<section id="yml" class="content-section" style="background: #f8f9fa;">
<div class="container">
<h2 class="section-title">Docker Compose 示例</h2>
<p style="text-align: center; max-width: 800px; margin: 0 auto 2rem; font-size: 1.1rem;">
Docker Compose 用于定义和运行多容器应用。以下是一个包含FastAPI、PostgreSQL和Redis的docker-compose.yml示例:
</p>
<div class="code-section">
<div class="code-header">
<span>docker-compose.yml 示例(使用国内源)</span>
<button class="copy-btn" onclick="copyCode('compose-code')">复制代码</button>
</div>
<div class="code-content">
<pre id="compose-code"><span class="comment"># docker-compose.yml 版本定义</span>
<span class="command">version:</span> <span class="yaml-string">'3.8'</span>
<span class="comment">#服务定义</span>
<span class="command">services:</span>
<span class="comment"># FastAPI 应用服务</span>
<span class="command">app:</span>
<span class="comment"># 使用当前目录的Dockerfile构建镜像</span>
<span class="command">build:</span> <span class="yaml-string">.</span>
<span class="comment">#容器名称</span>
<span class="command">container_name:</span> <span class="yaml-string">fastapi-app</span>
<span class="comment"># 端口映射</span>
<span class="command">ports:</span>
<span class="yaml-string">-</span> <span class="yaml-string">"8000:8000"</span>
<span class="comment"># 环境变量</span>
<span class="command">environment:</span>
<span class="yaml-string">-</span> <span class="yaml-string">DATABASE_URL=postgresql://postgres:password@db:5432/fastapi_db</span>
<span class="yaml-string">-</span> <span class="yaml-string">REDIS_URL=redis://redis:6379/0</span>
<span class="yaml-string">-</span> <span class="yaml-string">PYTHONUNBUFFERED=1</span>
<span class="comment"># 依赖关系</span>
<span class="command">depends_on:</span>
<span class="yaml-string">-</span> <span class="yaml-string">db</span>
<span class="yaml-string">-</span> <span class="yaml-string">redis</span>
<span class="comment">#重启策略</span>
<span class="command">restart:</span> <span class="yaml-string">unless-stopped</span>
<span class="comment"># 挂载卷(用于开发环境)</span>
<span class="command">volumes:</span>
<span class="yaml-string">-</span> <span class="yaml-string">./app:/app</span>
<span class="comment"># PostgreSQL 数据库服务</span>
<span class="command">db:</span>
<span class="command">image:</span> <span class="yaml-string">postgres:15-alpine</span>
<span class="command">container_name:</span> <span class="yaml-string">fastapi-db</span>
<span class="command">environment:</span>
<span class="yaml-string">-</span> <span class="yaml-string">POSTGRES_DB=fastapi_db</span>
<span class="yaml-string">-</span> <span class="yaml-string">POSTGRES_USER=postgres</span>
<span class="yaml-string">-</span> <span class="yaml-string">POSTGRES_PASSWORD=password</span>
<span class="command">ports:</span>
<span class="yaml-string">-</span> <span class="yaml-string">"5432:5432"</span>
<span class="command">volumes:</span>
<span class="yaml-string">-</span> <span class="yaml-string">postgres_data:/var/lib/postgresql/data</span>
<span class="command">restart:</span> <span class="yaml-string">unless-stopped</span>
<span class="comment"># Redis 缓存服务</span>
<span class="command">redis:</span>
<span class="command">image:</span> <span class="yaml-string">redis:7-alpine</span>
<span class="command">container_name:</span> <span class="yaml-string">fastapi-redis</span>
<span class="command">ports:</span>
<span class="yaml-string">-</span> <span class="yaml-string">"6379:6379"</span>
<span class="command">volumes:</span>
<span class="yaml-string">-</span> <span class="yaml-string">redis_data:/data</span>
<span class="command">restart:</span> <span class="yaml-string">unless-stopped</span>
<span class="comment"># 定义命名卷</span>
<span class="command">volumes:</span>
<span class="command">postgres_data:</span>
<span class="command">redis_data:</span></pre>
</div>
</div>
<div class="code-section">
<div class="code-header">
<span>优化版 docker-compose.yml(生产环境)</span>
<button class="copy-btn" onclick="copyCode('compose-prod-code')">复制代码</button>
</div>
<div class="code-content">
<pre id="compose-prod-code"><span class="comment"># docker-compose.yml 版本定义</span>
<span class="command">version:</span> <span class="yaml-string">'3.8'</span>
<span class="comment"># 服务定义</span>
<span class="command">services:</span>
<span class="comment"># FastAPI 应用服务(生产环境)</span>
<span class="command">app:</span>
<span class="command">build:</span>
<span class="command">context:</span> <span class="yaml-string">.</span>
<span class="command">dockerfile:</span> <span class="yaml-string">Dockerfile.prod</span>
<span class="command">container_name:</span> <span class="yaml-string">fastapi-app-prod</span>
<span class="command">ports:</span>
<span class="yaml-string">-</span> <span class="yaml-string">"8000:8000"</span>
<span class="command">environment:</span>
<span class="yaml-string">-</span> <span class="yaml-string">DATABASE_URL=postgresql://postgres:${DB_PASSWORD}@db:5432/fastapi_db</span>
<span class="yaml-string">-</span> <span class="yaml-string">REDIS_URL=redis://redis:6379/0</span>
<span class="yaml-string">-</span> <span class="yaml-string">ENVIRONMENT=production</span>
<span class="yaml-string">-</span> <span class="yaml-string">PYTHONUNBUFFERED=1</span>
<span class="command">depends_on:</span>
<span class="yaml-string">-</span> <span class="yaml-string">db</span>
<span class="yaml-string">-</span> <span class="yaml-string">redis</span>
<span class="command">restart:</span> <span class="yaml-string">unless-stopped</span>
<span class="command">healthcheck:</span>
<span class="command">test:</span> <span class="yaml-string">["CMD", "curl", "-f", "http://localhost:8000/health"]</span>
<span class="command">interval:</span> <span class="yaml-string">30s</span>
<span class="command">timeout:</span> <span class="yaml-string">10s</span>
<span class="command">retries:</span> <span class="yaml-string">3</span>
<span class="comment"># PostgreSQL 数据库服务(生产环境)</span>
<span class="command">db:</span>
<span class="command">image:</span> <span class="yaml-string">postgres:15-alpine</span>
<span class="command">container_name:</span> <span class="yaml-string">fastapi-db-prod</span>
<span class="command">environment:</span>
<span class="yaml-string">-</span> <span class="yaml-string">POSTGRES_DB=fastapi_db</span>
<span class="yaml-string">-</span> <span class="yaml-string">POSTGRES_USER=postgres</span>
<span class="yaml-string">-</span> <span class="yaml-string">POSTGRES_PASSWORD=${DB_PASSWORD}</span>
<span class="command">ports:</span>
<span class="yaml-string">-</span> <span class="yaml-string">"5432:5432"</span>
<span class="command">volumes:</span>
<span class="yaml-string">-</span> <span class="yaml-string">postgres_data:/var/lib/postgresql/data</span>
<span class="command">restart:</span> <span class="yaml-string">unless-stopped</span>
<span class="command">healthcheck:</span>
<span class="command">test:</span> <span class="yaml-string">["CMD-SHELL", "pg_isready -U postgres"]</span>
<span class="command">interval:</span> <span class="yaml-string">30s</span>
<span class="command">timeout:</span> <span class="yaml-string">10s</span>
<span class="command">retries:</span> <span class="yaml-string">3</span>
<span class="comment"># Redis 缓存服务(生产环境)</span>
<span class="command">redis:</span>
<span class="command">image:</span> <span class="yaml-string">redis:7-alpine</span>
<span class="command">container_name:</span> <span class="yaml-string">fastapi-redis-prod</span>
<span class="command">command:</span> <span class="yaml-string">redis-server --appendonly yes</span>
<span class="command">ports:</span>
<span class="yaml-string">-</span> <span class="yaml-string">"6379:6379"</span>
<span class="command">volumes:</span>
<span class="yaml-string">-</span> <span class="yaml-string">redis_data:/data</span>
<span class="command">restart:</span> <span class="yaml-string">unless-stopped</span>
<span class="comment"># 定义命名卷</span>
<span class="command">volumes:</span>
<span class="command">postgres_data:</span>
<span class="command">redis_data:</span></pre>
</div>
</div>
<div class="code-section">
<div class="code-header">
<span>开发环境 docker-compose.yml</span>
<button class="copy-btn" onclick="copyCode('compose-dev-code')">复制代码</button>
</div>
<div class="code-content">
<pre id="compose-dev-code"><span class="comment"># docker-compose.yml 版本定义</span>
<span class="command">version:</span> <span class="yaml-string">'3.8'</span>
<span class="comment"># 服务定义</span>
<span class="command">services:</span>
<span class="comment"># FastAPI 应用服务(开发环境)</span>
<span class="command">app:</span>
<span class="command">build:</span> <span class="yaml-string">.</span>
<span class="command">container_name:</span> <span class="yaml-string">fastapi-app-dev</span>
<span class="command">ports:</span>
<span class="yaml-string">-</span> <span class="yaml-string">"8000:8000"</span>
<span class="command">environment:</span>
<span class="yaml-string">-</span> <span class="yaml-string">DATABASE_URL=postgresql://postgres:password@db:5432/fastapi_db</span>
<span class="yaml-string">-</span> <span class="yaml-string">REDIS_URL=redis://redis:6379/0</span>
<span class="yaml-string">-</span> <span class="yaml-string">ENVIRONMENT=development</span>
<span class="yaml-string">-</span> <span class="yaml-string">PYTHONUNBUFFERED=1</span>
<span class="command">depends_on:</span>
<span class="yaml-string">-</span> <span class="yaml-string">db</span>
<span class="yaml-string">-</span> <span class="yaml-string">redis</span>
<span class="command">restart:</span> <span class="yaml-string">unless-stopped</span>
<span class="command">volumes:</span>
<span class="yaml-string">-</span> <span class="yaml-string">./app:/app</span>
<span class="yaml-string">-</span> <span class="yaml-string">./requirements.txt:/app/requirements.txt</span>
<span class="command">command:</span> <span class="yaml-string">uvicorn main:app --host 0.0.0.0 --port 8000 --reload</span>
<span class="comment"># PostgreSQL 数据库服务(开发环境)</span>
<span class="command">db:</span>
<span class="command">image:</span> <span class="yaml-string">postgres:15-alpine</span>
<span class="command">container_name:</span> <span class="yaml-string">fastapi-db-dev</span>
<span class="command">environment:</span>
<span class="yaml-string">-</span> <span class="yaml-string">POSTGRES_DB=fastapi_db</span>
<span class="yaml-string">-</span> <span class="yaml-string">POSTGRES_USER=postgres</span>
<span class="yaml-string">-</span> <span class="yaml-string">POSTGRES_PASSWORD=password</span>
<span class="command">ports:</span>
<span class="yaml-string">-</span> <span class="yaml-string">"5432:5432"</span>
<span class="command">volumes:</span>
<span class="yaml-string">-</span> <span class="yaml-string">postgres_data_dev:/var/lib/postgresql/data</span>
<span class="command">restart:</span> <span class="yaml-string">unless-stopped</span>
<span class="comment"># Redis 缓存服务(开发环境)</span>
<span class="command">redis:</span>
<span class="command">image:</span> <span class="yaml-string">redis:7-alpine</span>
<span class="command">container_name:</span> <span class="yaml-string">fastapi-redis-dev</span>
<span class="command">ports:</span>
<span class="yaml-string">-</span> <span class="yaml-string">"6379:6379"</span>
<span class="command">volumes:</span>
<span class="yaml-string">-</span> <span class="yaml-string">redis_data_dev:/data</span>
<span class="command">restart:</span> <span class="yaml-string">unless-stopped</span>
<span class="comment"># 定义命名卷(开发环境)</span>
<span class="command">volumes:</span>
<span class="command">postgres_data_dev:</span>
<span class="command">redis_data_dev:</span></pre>
</div>
</div>
<div class="demo-container">
<h3 class="demo-title">使用 Docker Compose 管理 FastAPI 应用</h3>
<div class="terminal">
<div class="terminal-header">
<div class="terminal-btn red"></div>
<div class="terminal-btn yellow"></div>
<div class="terminal-btn green"></div>
</div>
<div class="terminal-content" id="compose-terminal-content">
<div class="terminal-line">
<span class="prompt">$</span> <span>ls -la</span>
</div>
<div class="terminal-line">
<span>total 32</span>
</div>
<div class="terminal-line">
<span>drwxr-xr-x 5 user user 160 Dec5 10:30 .</span>
</div>
<div class="terminal-line">
<span>drwxr-xr-x 15 user user 480 Dec 5 10:28 ..</span>
</div>
<div class="terminal-line">
<span>-rw-r--r-- 1 user user 123 Dec 5 10:28 .env</span>
</div>
<div class="terminal-line">
<span>-rw-r--r-- 1 user user 256 Dec 5 10:28 Dockerfile</span>
</div>
<div class="terminal-line">
<span>-rw-r--r-- 1 user user 512 Dec 5 10:28 docker-compose.yml</span>
</div>
<div class="terminal-line">
<span>drwxr-xr-x 3 user user 96 Dec 5 10:28 app/</span>
</div>
<div class="terminal-line">
<span>-rw-r--r-- 1 user user 45 Dec 5 10:28 requirements.txt</span>
</div>
<div class="terminal-line">
<span class="prompt">$</span> <span>docker-compose up -d</span>
</div>
<div class="terminal-line">
<span>Creating network "fastapi-app_default" with the default driver</span>
</div>
<div class="terminal-line">
<span>Creating volume "postgres_data" with default driver</span>
</div>
<div class="terminal-line">
<span>Creating volume "redis_data" with default driver</span>
</div>
<div class="terminal-line">
<span>Creating fastapi-db ... done</span>
</div>
<div class="terminal-line">
<span>Creating fastapi-redis ... done</span>
</div>
<div class="terminal-line">
<span>Creating fastapi-app ... done</span>
</div>
<div class="terminal-line">
<span class="prompt">$</span> <span>docker-compose ps</span>
</div>
<div class="terminal-line">
<span>NAME COMMAND SERVICE STATUS PORTS</span>
</div>
<div class="terminal-line">
<span>fastapi-app "uvicorn main:app --..." app Up 5 seconds 0.0.0.0:8000->8000/tcp</span>
</div>
<div class="terminal-line">
<span>fastapi-db "docker-entrypoint.s..." db Up 5 seconds 0.0.0.0:5432->5432/tcp</span>
</div>
<div class="terminal-line">
<span>fastapi-redis "docker-entrypoint.s..." redis Up 5 seconds 0.0.0.0:6379->6379/tcp</span>
</div>
<div class="terminal-line">
<span class="prompt">$</span> <span>curl http://localhost:8000/health</span>
</div>
<div class="terminal-line">
<span>{"status":"healthy"}</span>
</div>
<div class="terminal-line">
<span class="prompt">$</span> <span>docker-compose logs app</span>
</div>
<div class="terminal-line">
<span>app | INFO: Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)</span>
</div>
<div class="terminal-line">
<span>app | INFO: Application startup complete.</span>
</div>
</div>
</div>
</div>
</div>
</section>
<!-- Interactive Demo -->
<section id="demo" class="content-section">
<div class="container">
<h2 class="section-title">Docker 交互演示</h2>
<div class="demo-container">
<h3 class="demo-title">在终端中运行 Docker 和 Docker Compose 命令</h3>
<div class="terminal">
<div class="terminal-header">
<div class="terminal-btn red"></div>
<div class="terminal-btn yellow"></div>
<div class="terminal-btn green"></div>
</div>
<div class="terminal-content" id="demo-terminal-content">
<div class="terminal-line">
<span class="prompt">root@docker:~#</span> <span>docker --version</span>
</div>
<div class="terminal-line">
<span>Docker version 24.0.5, build ced0996</span>
</div>
<div class="terminal-line">
<span class="prompt">root@docker:~#</span> <span>docker-compose --version</span>
</div>
<div class="terminal-line">
<span>Docker Compose version v2.23.0</span>
</div>
<div class="terminal-line">
<span class="prompt">root@docker:~#</span> <span>docker ps</span>
</div>
<div class="terminal-line">
<span>CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES</span>
</div>
</div>
</div>
<input type="text" class="user-input" id="command-input" placeholder="输入Docker命令 (如: docker-compose up -d, docker ps, docker images)...">
<div class="demo-controls">
<button class="demo-btn" onclick="executeCommand()">执行命令</button>
<button class="demo-btn secondary" onclick="clearTerminal()">清空终端</button>
<button class="demo-btn secondary" onclick="resetDemo()">重置演示</button>
</div>
<div style="margin-top: 20px; background: #e9f7fe; border-radius: 8px; padding: 15px; border-left: 4px solid var(--primary);">
<h4 style="margin-bottom: 10px; color: var(--dark);">演示说明</h4>
<p style="font-size: 0.95rem;">此交互演示模拟了Docker命令执行环境。尝试输入以下命令:</p>
<ul style="padding-left: 20px; margin-top: 10px; font-size: 0.95rem;">
<li><code>docker ps</code> - 列出运行中的容器</li>
<li><code>docker images</code> - 列出本地镜像</li>
<li><code>docker-compose up -d</code> - 启动多容器应用</li>
<li><code>docker-compose ps</code> - 查看Compose服务状态</li>
<li><code>docker-compose logs</code> - 查看服务日志</li>
<li><code>docker-compose down</code> - 停止并删除容器</li>
</ul>
</div>
</div>
</div>
</section>
<!-- Footer -->
<footer>
<div class="container">
<div class="footer-content">
<div class="footer-column">
<h3>关于 Docker</h3>
<p>Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。</p>
</div>
<div class="footer-column">
<h3>学习资源</h3>
<ul>
<li><a href="#">Docker 官方文档</a></li>
<li><a href="#">Docker Hub</a></li>
<li><a href="#">FastAPI 官方文档</a></li>
<li><a href="#">阿里云镜像源</a></li>
<li><a href="#">Python 容器化指南</a></li>
</ul>
</div>
<div class="footer-column">
<h3>常用命令</h3>
<ul>
<li><a href="#">docker build</a></li>
<li><a href="#">docker run</a></li>
<li><a href="#">docker-compose up</a></li>
<li><a href="#">docker-compose down</a></li>
<li><a href="#">docker exec</a></li>
</ul>
</div>
<div class="footer-column">
<h3>社区与支持</h3>
<ul>
<li><a href="#">Docker 社区论坛</a></li>
<li><a href="#">Stack Overflow</a></li>
<li><a href="#">FastAPI GitHub</a></li>
<li><a href="#">阿里云镜像站</a></li>
<li><a href="#">Python 容器化社区</a></li>
</ul>
</div>
</div>
<div class="copyright">
<p>© 2023 Docker 教程 | 本教程仅供学习使用 | Docker 是 Docker Inc. 的注册商标</p>
<p style="margin-top: 10px; font-size: 0.85rem;">使用国内淘宝镜像源加速 pip 安装: https://mirrors.aliyun.com/pypi/simple/</p>
</div>
</div>
</footer>
<script>
// 平滑滚动
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
anchor.addEventListener('click', function (e) {
e.preventDefault();
document.querySelector(this.getAttribute('href')).scrollIntoView({
behavior: 'smooth'
});
});
});
// 导航栏高亮
window.addEventListener('scroll', function() {
const sections = document.querySelectorAll('section');
const navLinks = document.querySelectorAll('nav a');
let current = '';
sections.forEach(section => {
const sectionTop = section.offsetTop;
const sectionHeight = section.clientHeight;
if (pageYOffset >= (sectionTop - sectionHeight / 3)) {
current = section.getAttribute('id');
}
});
navLinks.forEach(link => {
link.classList.remove('active');
if (link.getAttribute('href') === `#${current}`) {
link.classList.add('active');
}
});
});
// 复制代码功能
function copyCode(id) {
const code = document.getElementById(id).textContent;
navigator.clipboard.writeText(code).then(() => {
const btn = document.querySelector(`button[onclick="copyCode('${id}')"]`);
const originalText = btn.textContent;
btn.textContent = '已复制!';
setTimeout(() => {
btn.textContent = originalText;
}, 2000);
});
}
// 模拟的Docker命令响应
const commandResponses = {
'docker ps': `CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a1b2c3d4e5f6 my-fastapi-app "uvicorn main:app --..." 2 minutes ago Up 2 minutes 0.0.0.0:8000->8000/tcp fastapi-container
f0e9d8c7b6a5 redis:alpine "docker-entrypoint.s..." 15 minutes ago Up 15 minutes 6379/tcp redis-cache`,
'docker images': `REPOSITORY TAG IMAGE ID CREATED SIZE
my-fastapi-app latest 9e8f7a6b5c4d 2 hours ago 285MB
python 3.11-slim 8c2b0a5a9c3d 3 days ago 124MB
redis alpine c30b63d3e3b3 3 weeks ago 32.4MB`,
'docker run -d my-fastapi-app': `b3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6`,
'docker ps -a': `CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b3d4e5f6a7b8 my-fastapi-app "uvicorn main:app --..." 10 seconds ago Up 9 seconds 0.0.0.0:8000->8000/tcp fastapi-container
a1b2c3d4e5f6 my-fastapi-app "uvicorn main:app --..." 2 minutes ago Up 2 minutes 0.0.0.0:8000->8000/tcp fastapi-container
f0e9d8c7b6a5 redis:alpine "docker-entrypoint.s..." 15 minutes ago Exited (0) 5 minutes ago redis-cache`,
'docker stop': `Error response from daemon: No such container: stop`,
'docker stop b3d4e5f6a7b8': `b3d4e5f6a7b8`,
'docker rm': `Error response from daemon: No such container: rm`,
'docker rm b3d4e5f6a7b8': `b3d4e5f6a7b8`,
'docker rmi': `Error response from daemon: No such image: rmi`,
'docker images -q': `9e8f7a6b5c4d
8c2b0a5a9c3d
c30b63d3e3b3`,
'docker-compose up -d': `Creating network "fastapi-app_default" with the default driver
Creating volume "postgres_data" with default driver
Creating volume "redis_data" with default driver
Creating fastapi-db ... done
Creating fastapi-redis ... done
Creating fastapi-app ... done`,
'docker-compose ps': `NAME COMMAND SERVICE STATUS PORTS
fastapi-app "uvicorn main:app --..." app Up 5 seconds 0.0.0.0:8000->8000/tcp
fastapi-db "docker-entrypoint.s..." db Up 5 seconds 0.0.0.0:5432->5432/tcp
fastapi-redis "docker-entrypoint.s..." redis Up 5 seconds 0.0.0.0:6379->6379/tcp`,
'docker-compose logs app': `app | INFO: Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
app | INFO: Application startup complete.
app | INFO: Application startup complete.
app | INFO: Application startup complete.`,
'docker-compose down': `Stopping fastapi-app ... done
Stopping fastapi-db ... done
Stopping fastapi-redis ... done
Removing fastapi-app ... done
Removing fastapi-db ... done
Removing fastapi-redis ... done
Removing network fastapi-app_default
Removing volume postgres_data
Removing volume redis_data`,
'default': `Command not found: {command}. Try 'docker --help' for available commands.
Available demo commands:
- docker ps
- docker ps -a
- docker images
- docker images -q
- docker run -d my-fastapi-app
- docker-compose up -d
- docker-compose ps
- docker-compose logs
- docker-compose down
- docker stop [container_id]
- docker rm [container_id]`
};
// 执行命令
function executeCommand() {
const input = document.getElementById('command-input');
const command = input.value.trim();
const terminal = document.getElementById('demo-terminal-content');
if (!command) return;
// 添加命令到终端
const commandLine = document.createElement('div');
commandLine.className = 'terminal-line';
commandLine.innerHTML = `<span class="prompt">root@docker:~#</span> <span>${command}</span>`;
terminal.appendChild(commandLine);
// 处理命令
let response = '';
if (command.startsWith('docker ps')) {
response = commandResponses['docker ps'];
} else if (command.startsWith('docker images')) {
if (command.includes('-q')) {
response = commandResponses['docker images -q'];
} else {
response = commandResponses['docker images'];
}
} else if (command.startsWith('docker run')) {
const containerId = Math.random().toString(16).substring(2, 18);
response = containerId;
} else if (command.startsWith('docker stop')) {
const parts = command.split(' ');
if (parts.length > 1 && parts[1] !== 'stop') {
response = commandResponses['docker stop ' + parts[1]];
} else {
response = commandResponses['docker stop'];
}
} else if (command.startsWith('docker rm')) {
const parts = command.split(' ');
if (parts.length > 1 && parts[1] !== 'rm') {
response = commandResponses['docker rm ' + parts[1]];
} else {
response = commandResponses['docker rm'];
}
} else if (command.startsWith('docker rmi')) {
response = commandResponses['docker rmi'];
} else if (command.startsWith('docker-compose up')) {
response = commandResponses['docker-compose up -d'];
} else if (command.startsWith('docker-compose ps')) {
response = commandResponses['docker-compose ps'];
} else if (command.startsWith('docker-compose logs')) {
response = commandResponses['docker-compose logs app'];
} else if (command.startsWith('docker-compose down')) {
response = commandResponses['docker-compose down'];
} else if (command.startsWith('docker') || command.startsWith('docker-compose')) {
response = commandResponses['default'].replace('{command}', command);
} else {
response = `Command not found: ${command}. This demo only supports docker commands.`;
}
// 添加响应到终端
const responseLine = document.createElement('div');
responseLine.className = 'terminal-line';
responseLine.innerHTML = `<span>${response}</span>`;
terminal.appendChild(responseLine);
// 滚动到底部
terminal.scrollTop = terminal.scrollHeight;
// 清空输入框
input.value = '';
}
// 清空终端
function clearTerminal() {
const terminal = document.getElementById('demo-terminal-content');
terminal.innerHTML = '';
}
// 重置演示
function resetDemo() {
const terminal = document.getElementById('demo-terminal-content');
terminal.innerHTML = `
<div class="terminal-line">
<span class="prompt">root@docker:~#</span> <span>docker --version</span>
</div>
<div class="terminal-line">
<span>Docker version 24.0.5, build ced0996</span>
</div>
<div class="terminal-line">
<span class="prompt">root@docker:~#</span> <span>docker-compose --version</span>
</div>
<div class="terminal-line">
<span>Docker Compose version v2.23.0</span>
</div>
<div class="terminal-line">
<span class="prompt">root@docker:~#</span> <span>docker ps</span>
</div>
<div class="terminal-line">
<span>CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES</span>
</div>
`;
document.getElementById('command-input').value = '';
}
// 输入框回车事件
document.getElementById('command-input').addEventListener('keypress', function(e) {
if (e.key === 'Enter') {
executeCommand();
}
});
</script>
</body>
</html>