📚前言
👀回顾,系统学习docker系列已发布内容:
【docker基础】第三课:镜像管理与Dockerfile基础
【docker基础】第五课:Docker网络详解-CSDN博客
🔗相关文档:
【docker基础】Ubuntu 安装 Docker 超详细小白教程
📒本课学习目标:
-
Nginx 容器部署:运行 Nginx、端口映射、静态网站托管
-
配置文件挂载:自定义 Nginx 配置实现灵活部署
-
MySQL 容器:运行 MySQL、环境变量配置、数据库操作
-
数据持久化:使用卷挂载确保数据不丢失
-
PostgreSQL 容器:另一种主流数据库的部署方式
-
实战练习:部署完整的 Web 应用(前端 + 后端 + 数据库)
-
Docker Compose:使用 YAML 文件管理多容器应用
🌍Docker 第六周学习教程:Web应用与数据库容器部署
欢迎来到 Docker 第六周的学习!本周我们将深入学习如何使用 Docker 部署 Web 应用和数据库服务,这是 Docker 在实际生产环境中最常用的场景。
第一章:Web应用部署 - Nginx容器部署
1.1 什么是 Nginx
Nginx 是一个高性能的 HTTP 和反向代理服务器,常用于:
-
静态网站托管
-
负载均衡
-
反向代理
-
缓存服务
📌反向代理 是一种服务器配置,它接收来自客户端的请求,然后将这些请求转发给后端的多个服务器,并将响应返回给客户端。
1.2 运行第一个 Nginx 容器
打开终端,执行以下命令:
docker run -d -p 8080:80 --name mynginx nginx
命令解释:
-
docker run: 创建并运行容器 -
-d: 后台运行(detached 模式) -
-p 8080:80: 将宿主机的 8080 端口映射到容器的 80 端口 -
--name mynginx: 给容器命名为 mynginx -
nginx: 使用的镜像名称
命令执行后会输出类似这样的内容:
abc123def4567890abc123def4567890abc123def4567890abc123def
这串字符是容器的 ID。
1.3 验证 Nginx 是否运行成功
docker ps
预期输出:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
abc123def456 nginx "/docker-entrypoint...." 2 minutes ago Up 2 minutes 0.0.0.0:8080->80/tcp mynginx
现在打开浏览器,访问 http://localhost:8080,您会看到 Nginx 的欢迎页面!
1.4 停止和删除容器
# 停止容器
docker stop mynginx
# 删除容器
docker rm mynginx
第二章:静态网站托管
2.1 准备静态网站文件
首先,创建一个本地目录来存放网站文件:
mkdir -p ~/mywebsite
cd ~/mywebsite
创建一个简单的 HTML 文件 index.html:
<!DOCTYPE html>
<html>
<head>
<title>我的第一个 Docker 网站</title>
<style>
body {
font-family: Arial, sans-serif;
text-align: center;
margin-top: 100px;
background-color: #f0f0f0;
}
h1 {
color: #333;
}
.container {
background: white;
padding: 40px;
border-radius: 10px;
box-shadow: 0 0 10px rgba(0,0,0,0.1);
width: 500px;
margin: 0 auto;
}
</style>
</head>
<body>
<div class="container">
<h1>🎉 欢迎来到我的 Docker 网站!</h1>
<p>这是一个使用 Nginx 容器托管的静态网站。</p>
<p>通过 Docker 挂载宿主机目录实现文件共享。</p>
</div>
</body>
</html>
2.2 使用目录挂载部署静态网站
docker run -d -p 8080:80 --name mywebsite -v ~/mywebsite:/usr/share/nginx/html nginx
命令解释:
-
-v ~/mywebsite:/usr/share/nginx/html: 将宿主机的~/mywebsite目录挂载到容器内的/usr/share/nginx/html目录 -
/usr/share/nginx/html: 是 Nginx 默认的网页根目录
2.3 测试网站
打开浏览器访问 http://localhost:8080,您会看到自己创建的网页!
2.4 热更新测试
无需重启容器,直接修改 index.html 文件:
echo "<h1>🔄 网站已更新!</h1>" >> ~/mywebsite/index.html
刷新浏览器,您会看到网页内容已经更新了!
第三章:配置文件挂载
3.1 为什么需要挂载配置文件
容器默认的配置可能不符合我们的需求:
-
修改端口
-
添加 SSL 证书
-
配置反向代理
-
设置缓存策略
3.2 创建自定义 Nginx 配置
创建配置文件目录:
mkdir -p ~/nginx/conf
mkdir -p ~/nginx/html
创建自定义配置文件 ~/nginx/conf/default.conf:
server {
listen 80;
listen [::]:80;
server_name localhost;
# 根目录和默认页面
root /usr/share/nginx/html;
index index.html index.htm;
# 主页面
location / {
try_files $uri $uri/ =404;
}
# 自定义错误页面
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
# 添加访问日志
access_log /var/log/nginx/host.access.log;
error_log /var/log/nginx/host.error.log;
}
创建一个简单的错误页面 ~/nginx/html/50x.html:
<!DOCTYPE html>
<html>
<head>
<title>服务器错误</title>
</head>
<body>
<h1>Oops! 服务器出错了 (50x)</h1>
<p>请稍后再试...</p>
</body>
</html>
3.3 启动带自定义配置的容器
docker run -d -p 8080:80 --name customnginx \
-v ~/nginx/html:/usr/share/nginx/html \
-v ~/nginx/conf:/etc/nginx/conf.d \
nginx
命令解释:
-
-v ~/nginx/html:/usr/share/nginx/html: 挂载网页目录 -
-v ~/nginx/conf:/etc/nginx/conf.d: 挂载配置目录
3.4 验证配置是否生效
查看容器日志:
docker logs customnginx
预期输出:
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
...
nginx: [notice] 1#1: start worker process 32
访问 http://localhost:8080 查看效果。
第四章:数据库容器 - MySQL 部署
4.1 运行 MySQL 容器
docker run -d -p 3306:3306 --name mymysql \
-e MYSQL_ROOT_PASSWORD=123456 \
mysql:5.7
命令解释:
-
-e MYSQL_ROOT_PASSWORD=123456: 设置环境变量,配置 MySQL root 用户密码为 123456 -
mysql:5.7: 使用 MySQL 5.7 版本镜像(指定版本更稳定)
4.2 连接 MySQL 容器
方法一:使用容器内的 mysql 命令
docker exec -it mymysql mysql -uroot -p123456
命令解释:
-
docker exec: 在运行的容器中执行命令 -
-it: 交互式终端 -
mysql -uroot -p123456: 使用 root 用户登录,密码为 123456
方法二:使用本地 MySQL 客户端
mysql -h localhost -P 3306 -u root -p123456
4.3 创建数据库和表
进入 MySQL 命令行后,执行以下 SQL 命令:
-- 创建数据库
CREATE DATABASE myappdb;
-- 使用数据库
USE myappdb;
-- 创建用户表
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 插入测试数据
INSERT INTO users (name, email) VALUES
('张三', 'zhangsan@example.com'),
('李四', 'lisi@example.com');
-- 查询数据
SELECT * FROM users;
预期输出:
+----+--------+---------------------+---------------------+
| id | name | email | created_at |
+----+--------+---------------------+---------------------+
| 1 | 张三 | zhangsan@example.com| 2024-01-15 10:30:00 |
| 2 | 李四 | lisi@example.com | 2024-01-15 10:30:00 |
+----+--------+---------------------+---------------------+
4.4 数据持久化问题
问题: 如果删除容器,数据会丢失!
# 停止并删除容器
docker stop mymysql
docker rm mymysql
# 重新创建容器
docker run -d -p 3306:3306 --name mymysql -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7
# 连接查看数据(数据已丢失!)
docker exec -it mymysql mysql -uroot -p123456 -e "USE myappdb; SELECT * FROM users;"
错误输出:
ERROR 1049 (42000): Unknown database 'myappdb'
第五章:数据库数据持久化
5.1 使用数据卷挂载实现持久化
# 创建数据目录
mkdir -p ~/mysql/data
# 启动带数据卷挂载的 MySQL 容器
docker run -d -p 3306:3306 --name mymysql \
-e MYSQL_ROOT_PASSWORD=123456 \
-v ~/mysql/data:/var/lib/mysql \
mysql:5.7
命令解释:
-
-v ~/mysql/data:/var/lib/mysql: 将宿主机目录挂载到 MySQL 容器的数据目录 -
/var/lib/mysql: MySQL 默认的数据存储目录
5.2 验证数据持久化
-
创建数据库和表(重复第四章的步骤)
-
停止并删除容器
-
重新创建容器(使用相同的数据卷挂载)
-
验证数据是否存在
停止并删除容器
docker stop mymysql
docker rm mymysql重新创建容器(使用相同的挂载目录)
docker run -d -p 3306:3306 --name mymysql
-e MYSQL_ROOT_PASSWORD=123456
-v ~/mysql/data:/var/lib/mysql
mysql:5.7验证数据
docker exec -it mymysql mysql -uroot -p123456 -e "USE myappdb; SELECT * FROM users;"
预期输出: 数据依然存在!
第六章:PostgreSQL 容器部署
6.1 运行 PostgreSQL 容器
docker run -d -p 5432:5432 --name mypostgres \
-e POSTGRES_PASSWORD=123456 \
-e POSTGRES_DB=myappdb \
-v ~/postgres/data:/var/lib/postgresql/data \
postgres:13
命令解释:
-
POSTGRES_PASSWORD: 设置 PostgreSQL 密码 -
POSTGRES_DB: 设置默认数据库名称 -
-v ~/postgres/data:/var/lib/postgresql/data: 数据持久化
6.2 连接 PostgreSQL
docker exec -it mypostgres psql -U postgres
6.3 创建表和插入数据
-- 创建用户表
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 插入数据
INSERT INTO users (name, email) VALUES
('王五', 'wangwu@example.com'),
('赵六', 'zhaoliu@example.com');
-- 查询数据
SELECT * FROM users;
第七章:实战练习 - 部署完整的 Web 应用
7.1 项目架构
我们将部署一个完整的 Web 应用:
-
前端: Nginx 托管静态页面
-
后端: Python Flask API
-
数据库: MySQL
7.2 创建项目结构
mkdir -p ~/fullstack-app/{frontend,backend}
cd ~/fullstack-app
📌解释:
mkdir -p ~/fullstack-app/{frontend,backend}
等价于:
mkdir -p ~/fullstack-app/frontend
mkdir -p ~/fullstack-app/backend
7.3 创建后端 API (Flask)
创建 backend/app.py:
from flask import Flask, jsonify, request
from flask_cors import CORS
import pymysql
app = Flask(__name__)
CORS(app) # 允许跨域访问
# 数据库连接配置
db = pymysql.connect(
host='mymysql', # 容器名称作为主机名
user='root',
password='123456',
database='myappdb'
)
@app.route('/api/users', methods=['GET'])
def get_users():
cursor = db.cursor()
cursor.execute("SELECT * FROM users")
users = cursor.fetchall()
cursor.close()
# 转换为字典列表
result = []
for user in users:
result.append({
'id': user[0],
'name': user[1],
'email': user[2],
'created_at': str(user[3])
})
return jsonify(result)
@app.route('/api/users', methods=['POST'])
def add_user():
data = request.json
name = data.get('name')
email = data.get('email')
cursor = db.cursor()
sql = "INSERT INTO users (name, email) VALUES (%s, %s)"
cursor.execute(sql, (name, email))
db.commit()
cursor.close()
return jsonify({'message': '用户添加成功', 'id': cursor.lastrowid}), 201
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)
创建 backend/requirements.txt:
Flask==2.0.1
Flask-CORS==3.0.10
PyMySQL==1.0.2
7.4 创建 Dockerfile 用于构建后端镜像
创建 backend/Dockerfile:
# 使用 Python 基础镜像
FROM python:3.9-slim
# 设置工作目录
WORKDIR /app
# 复制依赖文件
COPY requirements.txt .
# 安装依赖
RUN pip install --no-cache-dir -r requirements.txt
# 复制应用代码
COPY app.py .
# 暴露端口
EXPOSE 5000
# 启动应用
CMD ["python", "app.py"]
7.5 构建后端镜像
cd ~/fullstack-app/backend
docker build -t myflaskapp .
命令解释:
-
docker build: 构建镜像 -
-t myflaskapp: 给镜像打标签为 myflaskapp -
.: 使用当前目录的 Dockerfile
7.6 创建前端页面
创建 frontend/index.html:
<!DOCTYPE html>
<html>
<head>
<title>用户管理系统</title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 800px;
margin: 0 auto;
padding: 20px;
}
h1 {
color: #2c3e50;
text-align: center;
}
.user-list {
margin-top: 30px;
}
.user-card {
background: #f8f9fa;
padding: 15px;
margin: 10px 0;
border-radius: 5px;
border-left: 4px solid #3498db;
}
.form-container {
background: #fff;
padding: 20px;
border-radius: 5px;
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
margin-bottom: 20px;
}
input {
display: block;
width: 100%;
padding: 10px;
margin: 10px 0;
border: 1px solid #ddd;
border-radius: 4px;
box-sizing: border-box;
}
button {
background: #3498db;
color: white;
padding: 10px 20px;
border: none;
border-radius: 4px;
cursor: pointer;
}
button:hover {
background: #2980b9;
}
</style>
</head>
<body>
<h1>👥 用户管理系统</h1>
<div class="form-container">
<h3>添加新用户</h3>
<input type="text" id="name" placeholder="姓名">
<input type="email" id="email" placeholder="邮箱">
<button onclick="addUser()">添加用户</button>
</div>
<div class="user-list" id="userList">
<!-- 用户列表将在这里显示 -->
</div>
<script>
// 获取用户列表
async function loadUsers() {
const response = await fetch('http://localhost:5000/api/users');
const users = await response.json();
displayUsers(users);
}
// 显示用户列表
function displayUsers(users) {
const userList = document.getElementById('userList');
userList.innerHTML = '';
users.forEach(user => {
const card = document.createElement('div');
card.className = 'user-card';
card.innerHTML = `
<h4>${user.name}</h4>
<p>邮箱: ${user.email}</p>
<p>创建时间: ${user.created_at}</p>
`;
userList.appendChild(card);
});
}
// 添加用户
async function addUser() {
const name = document.getElementById('name').value;
const email = document.getElementById('email').value;
await fetch('http://localhost:5000/api/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ name, email })
});
// 清空表单
document.getElementById('name').value = '';
document.getElementById('email').value = '';
// 重新加载用户列表
loadUsers();
}
// 页面加载时获取用户列表
window.onload = loadUsers;
</script>
</body>
</html>
7.7 启动完整的应用栈
步骤 1:启动 MySQL 容器
docker run -d -p 3306:3306 --name mymysql \
-e MYSQL_ROOT_PASSWORD=123456 \
-v ~/mysql/data:/var/lib/mysql \
mysql:5.7
步骤 2:创建数据库表
docker exec -it mymysql mysql -uroot -p123456 -e "
CREATE DATABASE IF NOT EXISTS myappdb;
USE myappdb;
CREATE TABLE IF NOT EXISTS users (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
"
步骤 3:启动 Flask 后端
docker run -d -p 5000:5000 --name myflaskapp \
--link mymysql:mymysql \
myflaskapp
命令解释:
--link mymysql:mymysql: 链接到 mymysql 容器,使其可以通过容器名访问
步骤 4:启动 Nginx 前端
docker run -d -p 80:80 --name myfrontend \
-v ~/fullstack-app/frontend:/usr/share/nginx/html \
nginx
7.8 测试完整应用
-
打开浏览器访问
http://localhost -
您会看到用户管理系统页面
-
可以添加新用户,用户数据会存储在 MySQL 数据库中
第八章:使用 Docker Compose 简化部署(选学)
8.1 什么是 Docker Compose
Docker Compose 是一个工具,可以通过一个 YAML 文件定义和运行多个 Docker 容器。
8.2 安装 Docker Compose
# 检查是否已安装
docker-compose --version
8.3 创建 docker-compose.yml
version: '3.8'
services:
db:
image: mysql:5.7
container_name: mymysql
environment:
MYSQL_ROOT_PASSWORD: 123456
MYSQL_DATABASE: myappdb
volumes:
- ./mysql/data:/var/lib/mysql
ports:
- "3306:3306"
backend:
build: ./backend
container_name: myflaskapp
ports:
- "5000:5000"
depends_on:
- db
environment:
- DB_HOST=db
- DB_USER=root
- DB_PASSWORD=123456
- DB_NAME=myappdb
frontend:
image: nginx
container_name: myfrontend
ports:
- "80:80"
volumes:
- ./frontend:/usr/share/nginx/html
8.4 使用 Compose 启动应用
cd ~/fullstack-app
docker-compose up -d
8.5 停止应用
docker-compose down
内容回顾
本周我们学习了:
-
Nginx 容器部署:运行 Nginx、端口映射、静态网站托管
-
配置文件挂载:自定义 Nginx 配置实现灵活部署
-
MySQL 容器:运行 MySQL、环境变量配置、数据库操作
-
数据持久化:使用卷挂载确保数据不丢失
-
PostgreSQL 容器:另一种主流数据库的部署方式
-
实战练习:部署完整的 Web 应用(前端 + 后端 + 数据库)
-
Docker Compose:使用 YAML 文件管理多容器应用
练习作业:
-
尝试部署一个 WordPress 博客(提示:需要 WordPress 镜像和 MySQL)
-
尝试使用 Docker Compose 部署一个包含 Redis 缓存的应用
命令速查表
| 操作 | 命令 |
|---|---|
| 运行 Nginx | docker run -d -p 8080:80 nginx |
| 挂载目录 | docker run -d -p 8080:80 -v /host/path:/container/path nginx |
| 运行 MySQL | docker run -d -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7 |
| 进入容器 | docker exec -it <容器名> /bin/bash |
| 查看日志 | docker logs <容器名> |
| 停止容器 | docker stop <容器名> |
| 删除容器 | docker rm <容器名> |
| 构建镜像 | docker build -t <镜像名> . |