ziqkimi308/docker-app-flask
GitHub: ziqkimi308/docker-app-flask
一个生产级容器化 Flask 应用示例,使用 Redis 追踪访问计数,展示了多阶段 Docker 构建、安全加固与 Docker Compose 编排的最佳实践。
Stars: 0 | Forks: 0
# Docker化 Flask App与Redis
## 概述
构建了一个生产级的容器化 Flask 应用程序,使用 Redis 跟踪访问计数。实现了多阶段 Dockerfile 以优化体积,并通过非 root 用户和 `dumb-init` 进行信号处理来加强安全性。使用带有健康检查、只读文件系统和丢弃 Linux 权限的强化版 `docker-compose.yml` 来编排 Flask 应用和 Redis。构建镜像,打上标签,并将其推送到 Docker Hub 以进行远程分发。
## 架构
- **多阶段 Dockerfile**:
- **构建阶段**:安装编译器(`gcc`)并将 Python 依赖项编译到隔离的 `/install` 文件夹中。
- **最终阶段**:以全新的 **Debian Slim** 为基础镜像(出于稳定性考虑,从 Alpine 切换而来),仅复制编译好的二进制文件(不包含编译器),添加 `dumb-init`,创建非 root 用户(`appuser:1001`),并锁定文件系统。
- **Docker Compose 编排**:
- 自定义桥接网络(`app-network`),用于容器间的通信。
- Flask 服务基于本地 Dockerfile 构建,并配置了环境变量(`REDIS_HOST=redis`)。
- Redis 服务使用 `redis:7-alpine` 并配置了健康检查(`redis-cli ping`)。
- 安全强化:`read_only: true`(根文件系统),`tmpfs:/tmp`(可写的临时空间),`cap_drop: ALL`(丢弃所有 Linux 权限)。
- **Docker Hub 分发**:标记为 `ziqkimi/docker-app-flask:latest` 和 `v1.0`,并推送到 Docker Hub,方便在任何地方进行部署。
## 技术栈
- **语言**:Python (Flask)
- **依赖项**:`flask`、`redis`、`pytest`(纯 Python——无需编译 C 扩展)
- **容器工具**:Docker、Docker Compose
- **基础镜像**:`python:3.11-slim`(两个阶段均基于 Debian)、`redis:7-alpine`
- **实用工具**:`dumb-init`(信号处理)、`redis-cli`(健康检查)
## 项目结构
```
docker-app-flask/
├── Dockerfile # Multi-stage build (builder + final)
├── docker-compose.yml # Hardened orchestration (flask + redis)
├── app.py # Flask app: / (counter) and /health
├── requirements.txt # flask, redis, pytest
└── .dockerignore # Excludes unnecessary files from build context
```
## 如何运行
```
# Clone the repository
git clone https://github.com/ziqkimi308/docker-app-flask.git
cd docker-app-flask
# 使用Docker Compose构建并运行(自动构建image,启动两个container)
docker compose up --build
# 通过 http://localhost:5000 访问 app
# 每次刷新时访问计数都会增加。
# 独立运行(不使用Compose,需要本地Redis正在运行)
docker run -d --name flask-app -p 5000:5000 -e REDIS_HOST=localhost docker-app-flask:latest
# 直接从Docker Hub拉取并运行image
docker run -d --name flask-from-hub -p 5001:5000 ziqkimi/docker-app-flask:latest
# 销毁Compose stack
docker compose down -v # -v removes volumes (clears Redis data)
```
## 遇到的问题与修复
**问题:
Docker Hub 拉取失败并提示 "Port is already allocated"**
当使用 `docker run -d --name flask-from-hub -p 5000:5000 ziqkimi/docker-app-flask:latest` 测试从 Docker Hub 拉取的镜像时,我收到了 `Bind for 0.0.0.0:5000 failed: port is already allocated` 错误。 **调查过程:**
`docker ps` 显示原始的 Compose 堆栈仍在运行并占用了端口 `5000`。然而,新容器未能启动,且在 `docker ps` 中不可见。 **根本原因:**
`docker ps` 仅显示**正在运行**的容器。失败的容器虽然已创建,但由于端口冲突立即停止了。它仍然存在并保留了名称 `flask-from-hub`,从而阻止了重试。 **修复方法:**
使用 `docker ps -a` 查看所有容器(包括已停止/失败的容器)。使用 `docker rm flask-from-hub` 删除失败的容器,然后使用不同的宿主机端口重新运行以避免冲突: ``` docker rm flask-from-hub docker run -d --name flask-from-hub -p 5001:5000 ziqkimi/docker-app-flask:latest ``` 访问了 `http://localhost:5001` —— 镜像成功运行(不过 Redis 显示“不可用”,因为它是独立运行的,没有链接 Redis 容器,这对于本次测试来说是预期的情况)。 ## 截图 ### 1. Docker & Compose 版本  ### 2. 使用 DockerFile 成功构建 Docker 镜像  ### 3. 通过终端运行 Docker 镜像及镜像验证,但 Redis 预期会失败   ### 4. 停止并删除容器  ### 5. 成功运行 docker-compose YAML 文件 & Redis 现已正常工作   ### 6. 日志 & 实时日志(Flask & Redis)   ### 7. 检查自定义网络  ### 8. 进入运行中的容器(服务发现检查)  ### 9. 打标签并推送到 Docker Hub  ### 10. 在 Docker Hub 上验证镜像  ### 11. 从 Docker Hub 拉取并运行  ### 12. 清理(Down、Prune、RMI)  ## 注意事项 - 尽管构建阶段安装了 `gcc`,尽管 `flask`/`redis` 是纯 Python 的——这是为了未来可能出现的需要编译的依赖项而采取的防御性默认设置,并非当前的要求。 - Compose 中的 `read_only: true` 和 `tmpfs:/tmp` 组合确保了 Flask 容器无法写入其根文件系统,但仍然有一个用于运行时需求的临时空间。 - 在启动堆栈之前,务必使用 `docker compose config` 验证您的 YAML 语法。 - `.dockerignore` 至关重要,它可以防止意外将大文件(例如 `venv` 或 `__pycache__`)发送到 Docker daemon,从而避免拖慢构建速度。 - 切勿将机密信息(API 密钥、数据库密码)直接存储在 Dockerfile 或 Compose 文件中——在生产环境中,请使用环境变量或 Docker secrets。
Docker Hub 拉取失败并提示 "Port is already allocated"**
当使用 `docker run -d --name flask-from-hub -p 5000:5000 ziqkimi/docker-app-flask:latest` 测试从 Docker Hub 拉取的镜像时,我收到了 `Bind for 0.0.0.0:5000 failed: port is already allocated` 错误。 **调查过程:**
`docker ps` 显示原始的 Compose 堆栈仍在运行并占用了端口 `5000`。然而,新容器未能启动,且在 `docker ps` 中不可见。 **根本原因:**
`docker ps` 仅显示**正在运行**的容器。失败的容器虽然已创建,但由于端口冲突立即停止了。它仍然存在并保留了名称 `flask-from-hub`,从而阻止了重试。 **修复方法:**
使用 `docker ps -a` 查看所有容器(包括已停止/失败的容器)。使用 `docker rm flask-from-hub` 删除失败的容器,然后使用不同的宿主机端口重新运行以避免冲突: ``` docker rm flask-from-hub docker run -d --name flask-from-hub -p 5001:5000 ziqkimi/docker-app-flask:latest ``` 访问了 `http://localhost:5001` —— 镜像成功运行(不过 Redis 显示“不可用”,因为它是独立运行的,没有链接 Redis 容器,这对于本次测试来说是预期的情况)。 ## 截图 ### 1. Docker & Compose 版本  ### 2. 使用 DockerFile 成功构建 Docker 镜像  ### 3. 通过终端运行 Docker 镜像及镜像验证,但 Redis 预期会失败   ### 4. 停止并删除容器  ### 5. 成功运行 docker-compose YAML 文件 & Redis 现已正常工作   ### 6. 日志 & 实时日志(Flask & Redis)   ### 7. 检查自定义网络  ### 8. 进入运行中的容器(服务发现检查)  ### 9. 打标签并推送到 Docker Hub  ### 10. 在 Docker Hub 上验证镜像  ### 11. 从 Docker Hub 拉取并运行  ### 12. 清理(Down、Prune、RMI)  ## 注意事项 - 尽管构建阶段安装了 `gcc`,尽管 `flask`/`redis` 是纯 Python 的——这是为了未来可能出现的需要编译的依赖项而采取的防御性默认设置,并非当前的要求。 - Compose 中的 `read_only: true` 和 `tmpfs:/tmp` 组合确保了 Flask 容器无法写入其根文件系统,但仍然有一个用于运行时需求的临时空间。 - 在启动堆栈之前,务必使用 `docker compose config` 验证您的 YAML 语法。 - `.dockerignore` 至关重要,它可以防止意外将大文件(例如 `venv` 或 `__pycache__`)发送到 Docker daemon,从而避免拖慢构建速度。 - 切勿将机密信息(API 密钥、数据库密码)直接存储在 Dockerfile 或 Compose 文件中——在生产环境中,请使用环境变量或 Docker secrets。
标签:Docker, Docker Compose, Flask, GitHub Advanced Security, NIDS, Redis, Syscall, Web开发, 安全加固, 安全防御评估, 容器化, 搜索引擎查询, 版权保护, 请求拦截, 逆向工具