docker-dockerfile练习
-
- [1. 开发环境标准化](#1. 开发环境标准化)
- [2. 静态网站托管](#2. 静态网站托管)
- [3. 多服务应用(WordPress)](#3. 多服务应用(WordPress))
- [4. 微服务+负载均衡](#4. 微服务+负载均衡)
- [5. 数据持久化与备份](#5. 数据持久化与备份)
- [6. 多阶段构建优化镜像](#6. 多阶段构建优化镜像)
- [7. 日志集中管理(EFK/ELK)](#7. 日志集中管理(EFK/ELK))
- [8. 私有镜像仓库与CI模拟](#8. 私有镜像仓库与CI模拟)
- [9. 网络隔离与通信](#9. 网络隔离与通信)
- [10. 安全加固:以非root用户运行](#10. 安全加固:以非root用户运行)
- [11. 资源限制与健康检查](#11. 资源限制与健康检查)
- [12. Docker Swarm 集群部署](#12. Docker Swarm 集群部署)
1. 开发环境标准化
背景 :公司新入职了几名Python开发,每个人的本地环境(Python版本、依赖包)不一致,导致"在我电脑上能跑"的问题频发。
需求:
- 为现有的一个Python Flask项目(假设项目代码在Git仓库中)编写Dockerfile。
- 要求使用Python 3.9 slim镜像,安装
requirements.txt中的依赖,暴露5000端口。 - 开发人员能够通过一条命令启动容器,并在本地修改代码后容器自动重载(使用volume挂载代码)。
- 最终开发团队所有人都使用同一个Docker镜像运行项目。
a.在/app路径中创建dockerfile文件
bash
# 要求使用Python 3.9 slim镜像
FROM python:3.9-slim
# 设置工作目录
WORKDIR /app
# 安装`requirements.txt`中的依赖
COPY requirements.txt .
# 安装python依赖
RUN pip install --no-cache-dir -r requirements.txt
# 将项目代码复制到容器(开发时会用 volume 覆盖,此步骤用于构建完整镜像)
# 将宿主机上项目根目录的所有文件,复制到镜像的 /app 目录下。
COPY . .
# 设置环境变量,使 Flask 以开发模式运行并开启自动重载
ENV FLASK_APP=app.py
ENV FLASK_ENV=development
ENV FLASK_DEBUG=1
# 暴露5000端口
EXPOSE 5000
# 启动命令:flask run 监听所有地址,开启重载
CMD ["flask", "run", "--host=0.0.0.0", "--port=5000", "--reload"]
b.构建镜像
bash
# 在myapp文件夹执行
docker build -t my-flask-app .
# 推送镜像
docker tag my-flask-app your-registry/my-flask-app:latest
docker push your-registry/my-flask-app:latest
# 拉取镜像
docker pull your-registry/my-flask-app:latest
c.开发时运行容器
bash
docker run -p 5000:5000 -v $(pwd):/app your-registry/my-flask-app
- -p 5000:5000:将容器 5000 端口映射到宿主机,访问 http://localhost:5000 即可。
- -v $(pwd):/app:将当前目录挂载到容器的 /app,覆盖镜像中的代码,本地修改即时生效。
- your-registry/my-flask-app:公司内部docker hub的名称
- 容器启动后,Flask 会监视文件变化并自动重启服务。
2. 静态网站托管
背景 :市场部需要上线一个简单的品牌展示静态网站(HTML+CSS+JS),希望快速部署并能随时更新内容。
需求:
- 使用Nginx官方镜像,将本地
./public目录下的静态文件打包到镜像中。 - 编写Dockerfile,复制文件到
/usr/share/nginx/html。 - 构建镜像,运行容器并映射宿主机8080端口,访问
http://localhost:8080看到网站。 - 优化:未来更新内容只需要替换本地文件并重新构建镜像,或通过挂载卷实现热更新。
a.创建dockerfile文件
bash
# 使用Nginx官方镜像
FROM nginx:alpine
# 将本地`./public`目录下的静态文件打包到镜像中
COPY ./public /usr/share/nginx/html
# 映射宿主机8080端口
EXPOSE 80
b.构建镜像
bash
docker build -t my-nginx-app .
# 推送镜像
docker tag my-nginx-app your-registry/my-nginx-app:latest
docker push your-registry/my-nginx-app:latest
# 拉取镜像
docker pull your-registry/my-nginx-app:lates
c.运行容器
bash
docker run -d -p 8080:80 -v $(pwd):/public:/usr/share/nginx/html:ro your-registry/my-nginx-app
3. 多服务应用(WordPress)
背景 :公司要搭建一个企业博客,运维团队希望用WordPress快速实现,同时保证数据不丢失。
需求:
- 使用
docker-compose.yml定义两个服务:db(MySQL 5.7)和wordpress(最新版PHP+Apache)。 - MySQL需设置root密码、创建数据库,数据持久化到宿主机
./mysql_data目录。 - WordPress服务链接到MySQL,并暴露80端口,访问即可安装博客。
- 要求容器重启后数据依然存在。
a.创建yaml文件
bash
version: '3' # 是Compose文件版本
services: # 定义两个服务
db:
image: mysql:5.7
container_name: wordpress_db
restart: always # 确保容器退出时自动重启
environment:
MYSQL_ROOT_PASSWORD: QAZ@!123qqaa # 设置 root 密码
MYSQL_DATABASE: wordpress # 自动创建名为 wordpress 的数据库
volumes:
- ./mysql_data:/var/lib/mysql # 将数据库数据持久化到宿主机当前目录的 mysql_data 文件夹
ports:
- "3306:3306" # (可选)暴露 MySQL 端口,通常不需要对外暴露,可注释掉
wordpress:
image: wordpress:latest
container_name: wordpress_app
restart: always # 确保容器退出时自动重启
depends_on:
- db # 确保数据库先启动
ports:
- "8080:80" # 将容器的 80 端口映射到宿主机的 8080 端口
environment:
WORDPRESS_DB_HOST: db:3306 # 数据库服务名(db)加端口
WORDPRESS_DB_USER: root # 连接数据库的用户名(此处使用 root)
WORDPRESS_DB_PASSWORD: QAZ@!123qqaa # 对应上面设置的 root 密码
WORDPRESS_DB_NAME: wordpress # 数据库名
# 可选:持久化 WordPress 上传的文件和插件(如需完整备份可取消注释)
# volumes:
# - ./wp-content:/var/www/html/wp-content
运行:
bash
# 首次启动会拉取 MySQL 和 WordPress 镜像。
docker-compose up -d
停止:
bash
docker-compose down
4. 微服务+负载均衡
背景 :公司有一个Node.js的API服务,访问量逐渐增大,需要水平扩展并统一入口。
需求:
- 编写Node.js应用Dockerfile,应用监听3000端口,返回当前容器的主机名(或IP)便于验证负载。
- 使用docker-compose定义:
app服务:构建本地镜像,并启动3个副本(--scale app=3)。nginx服务:使用官方nginx镜像,配置反向代理将请求分发到3个app实例(轮询)。
- 测试访问nginx(80端口),每次刷新应看到不同容器返回的信息。
5. 数据持久化与备份
背景 :公司内部使用PostgreSQL作为核心业务数据库,需要定期备份数据,同时避免容器删除导致数据丢失。
需求:
- 运行PostgreSQL容器,使用命名卷(
db-data)持久化数据库文件。 - 设置环境变量初始化数据库和用户。
- 创建一个临时容器(如
postgres:latest)挂载同一个卷,并执行pg_dump备份数据到宿主机。 - 模拟删除原容器,重新创建一个新容器使用相同卷,验证数据是否恢复。
6. 多阶段构建优化镜像
背景 :开发了一个Go语言编写的REST API,但直接构建的镜像包含了编译工具,体积超过500MB,部署慢。
需求:
- 编写多阶段Dockerfile:
- 阶段一:使用
golang:1.18作为构建环境,编译出二进制文件。 - 阶段二:使用
alpine:latest,仅复制编译好的二进制文件,并设置CMD运行它。
- 阶段一:使用
- 要求最终镜像大小控制在20MB以内。
- 构建并运行,验证API功能正常。
7. 日志集中管理(EFK/ELK)
背景 :公司有多个微服务容器,日志分散在各个主机上,排查问题困难。需要统一收集、检索和可视化。
需求:
- 使用docker-compose部署Elasticsearch、Fluentd(或Logstash)、Kibana。
- 配置Fluentd收集所有容器的标准输出日志,发送到Elasticsearch。
- 在Kibana中创建索引模式,能够查看和搜索日志。
- 额外:让其中一个应用产生不同级别的日志,验证日志收集。
8. 私有镜像仓库与CI模拟
背景 :公司不允许将镜像推送到Docker Hub,需要搭建内部镜像仓库,并模拟CI流程:代码提交后自动构建并推送到私有仓库。
需求:
- 运行一个
registry:2容器作为私有仓库,挂载本地目录存储镜像,端口映射到5000。 - 编写一个简单的应用Dockerfile,构建后打上标签
localhost:5000/myapp:latest,推送到私有仓库。 - 从另一台机器(或本机删除原镜像后)拉取并运行该镜像,验证私有仓库可用。
- 模拟CI:写一个shell脚本,自动执行构建、打标签、推送。
9. 网络隔离与通信
背景 :公司有一个三层的应用:前端Nginx、后端API、数据库。要求前端可以访问API,API可以访问数据库,但数据库不能直接暴露给前端,且外界只能访问Nginx。
需求:
- 创建两个自定义网络:
frontend和backend。 - Nginx容器连接
frontend网络,同时通过某种方式能访问API(例如将API也连入frontend,但API还需要访问数据库)。 - API容器同时连接
frontend和backend网络。 - 数据库容器只连接
backend网络。 - 测试:从Nginx容器能ping通API,但不能ping通数据库;从API容器能ping通数据库;外部无法直接访问API和数据库端口。
10. 安全加固:以非root用户运行
背景 :安全团队扫描发现,公司很多容器默认以root运行,存在安全隐患。要求所有应用容器必须使用非root用户。
需求:
- 选择一个基础镜像(如node:14),在Dockerfile中创建用户
appuser,并赋予其对应用目录的权限。 - 确保容器启动命令使用该用户(
USER appuser)。 - 构建镜像,运行后进入容器验证用户身份,并验证应用是否能正常监听端口(可能需要使用大于1024的端口或设置权限)。
- 注意:如果应用需要绑定80端口,需要额外处理(如使用authbind或转发)。
11. 资源限制与健康检查
背景 :某Java应用消耗内存较高,偶尔会因为内存不足被OOM Killer杀死。运维希望限制容器资源,并增加健康检查以便自动恢复。
需求:
- 编写Dockerfile运行一个Java应用(可以是简单的Spring Boot示例)。
- 使用
docker run时限制内存为512M、CPU为0.5核。 - 在Dockerfile中添加
HEALTHCHECK指令,定期检查应用的健康端点(如/actuator/health)。 - 运行容器,观察资源限制效果,并模拟应用故障,查看Docker的健康状态变化。
12. Docker Swarm 集群部署
背景 :公司要将一个Web服务部署到三台服务器上,需要实现高可用和滚动更新。
需求:
- 搭建一个单节点Swarm集群(或使用虚拟机模拟多节点)。
- 创建一个
docker-compose.yml(version 3.8)定义服务,包含:web服务:使用前面构建的镜像,部署2个副本,更新策略为滚动更新。redis服务:用于会话缓存。
- 将服务部署为Stack(
docker stack deploy)。 - 模拟滚动更新:修改镜像标签,重新部署,观察更新过程服务不中断。
- 将服务暴露到集群外部(使用路由网或发布端口)。