Python项目使用Dockerfile编排

tone 3018 2024-06-27

视频解析:https://cloud.189.cn/t/beUvYvArYBva

项目地址:https://gitee.com/lin_yi1/aggregation-services

编排所需要的 Dockerfile内容

确保 Dockerfile 仅包含与应用相关的指令:

# 使用官方的 Python 3.11.1 镜像作为基础镜像
FROM python:3.11.1-slim
# 作者名称
LABEL authors="Tone"
# 版本
LABEL version="1.0"

# 设置工作目录为 /AggregationServices
# 注意:工作目录应该和本地编码时的目录一致,以便路径正确
WORKDIR /AggregationServices

# 将 AggregationServices/interfaceServices 目录下的 requirements.txt 文件复制到工作目录
# 注意:确保本地路径正确,否则会导致文件找不到
COPY interfaceServices/requirements.txt ./interfaceServices/requirements.txt

# 使用中科大的 Debian 镜像源
# 注意:这一步是为了加速 apt 包的下载速度,避免网络问题
RUN sed -i 's|http://deb.debian.org|https://mirrors.ustc.edu.cn|g' /etc/apt/sources.list

# 安装Vim
# 注意:apt-get update 和 apt-get install 是分开的,确保包索引先更新
RUN apt-get update && apt-get install -y vim

# 安装 Python 依赖包
# 注意:确保 requirements.txt 文件路径正确,使用国内镜像源加速下载
RUN pip install --no-cache-dir -r interfaceServices/requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple

# 将 interfaceServices 目录下的所有文件复制到容器的 /AggregationServices/interfaceServices 目录
# 注意:COPY 的源目录和目标目录路径要正确
COPY interfaceServices ./interfaceServices

# 设置环境变量,用于连接 MySQL 数据库
# 注意:确保这些环境变量在运行时需要
ENV MYSQL_DATABASE=music
ENV MYSQL_USER=root
ENV MYSQL_PASSWORD=123456

# 暴露应用运行的端口
# 注意:确保暴露的端口与应用程序监听的端口一致
EXPOSE 9529

# 重新设置工作目录为 /AggregationServices/interfaceServices因为要和pycharm编码时运行路径一致这样才能让run文件里的路径配置生效
# 注意:工作目录设置为最终运行应用程序的目录
WORKDIR /AggregationServices/interfaceServices

# 指定容器启动时运行的命令
# 注意:确保运行的命令与应用程序的启动方式一致,这里的run文件会从工作目录下查找实际执行路径为: python /AggregationServices/interfaceServices/run.py
CMD ["python", "run.py"]

# 备用启动命令,如果需要将日志输出到文件中
# 注意:此命令将应用程序的输出重定向到 output.log 文件,并保持容器前台运行
#CMD ["sh", "-c", "nohup python run.py > output.log 2>&1 & tail -f output.log"]

修改后的 docker-compose.yml

确保 docker-compose.yml 文件正确配置上下文路径和 Dockerfile 路径:

version: '2.2'  # Docker Compose 文件的版本

services:
  db:
    image: mysql:5.7
    environment:
      MYSQL_ROOT_PASSWORD: 123456  # MySQL 的 root 用户密码
      MYSQL_DATABASE: music        # 要创建的数据库名称
    ports:
      - "3306:3306"                # 将容器的 3306 端口映射到主机的 3306 端口
    volumes:
      - db_data:/var/lib/mysql     # 持久化存储 MySQL 数据

  app:
    build:
      context: .                   # 使用当前目录作为构建上下文
      dockerfile: Dockerfile       # 指定 Dockerfile 文件
    depends_on:
      - db                         # 依赖 db 服务,确保 db 服务先启动
    ports:
      - "9529:9529"                # 将容器的 9529 端口映射到主机的 9529 端口
    environment:
#      DATABASE_URL: mysql+pymysql://root:123456@db/music
      DATABASE_URL: db:3306        # 设置环境变量 DATABASE_URL,指向 db 服务

#  app:
#    # 使用本地已经存在的镜像,而不是通过 Dockerfile 构建
#    image: aggregationservices-app  # 替换为本地已有的镜像名称
#    depends_on:
#      - db                         # 依赖 db 服务,确保 db 服务先启动
#    ports:
#      - "9529:9529"                # 将容器的 9529 端口映射到主机的 9529 端口
#    environment:
#      DATABASE_URL: mysql+pymysql://root:123456@db/music # 设置环境变量 DATABASE_URL,指向 db 服务

volumes:
  db_data:                          # 定义名为 db_data 的卷,用于持久化 MySQL 数据

操作步骤

  1. 导航到 AggregationServices 目录

    打开终端并导航到 AggregationServices 目录:

cd /path/to/AggregationServices
  1. 构建 Docker 镜像

    使用 Docker Compose 构建 Docker 镜像:

docker-compose build
  1. 启动服务

    使用 Docker Compose 启动所有服务:

docker-compose up

构建镜像后可以使用 docker run --rm -it aggregationservices-app:latest bash 命令启动一个临时容器来检查文件系统:

本地无法访问Docker容器的原因及解决方案

  1. 端口映射问题:

    确保在启动容器时正确映射了端口。例如,如果容器内部的应用在端口 9529 上运行,需要使用 -p 标志将该端口映射到主机上的端口。

docker run -d -p 9529:9529 aggregationservices-app:latest 
  1. 防火墙设置:

    确保服务器上的防火墙允许通过映射的端口访问。例如,使用 iptablesufw 配置防火墙规则。

  2. 应用程序绑定的地址:

    确保应用程序在容器内绑定的是 0.0.0.0,而不是 localhost。绑定 0.0.0.0 可以使应用程序接收来自所有网络接口的连接。

  3. 网络模式:

    检查容器的网络模式。默认情况下,容器使用 bridge 网络模式,但也可以根据需求选择 host 或自定义的 Docker 网络。

导出和导入Docker镜像

导出Docker镜像:

  1. 使用 docker images 获取镜像ID。

docker images
  1. 使用 docker save 命令导出镜像到一个文件中。

docker save -o aggregationservices-app.tar   aggregationservices-app:latest 

导入Docker镜像:

  1. 使用 docker load 命令从文件中导入镜像。

docker load -i aggregationservices-app.tar

通过这些步骤,可以导出和导入Docker镜像,使得在离线环境运行容器。

使用现有镜像启动服务

docker-compose -f docker-compose.no-build.yml up

docker-compose.no-build.yml

version: '2.2'  # Docker Compose 文件的版本

services:
  db:
    image: mysql:5.7  # 使用 MySQL 5.7 镜像
    environment:
      MYSQL_ROOT_PASSWORD: 123456  # MySQL 的 root 用户密码
      MYSQL_DATABASE: music        # 要创建的数据库名称
    ports:
      - "3306:3306"  # 将容器的 3306 端口映射到主机的 3306 端口
    volumes:
      - db_data:/var/lib/mysql  # 使用名为 db_data 的卷持久化存储 MySQL 数据

  app:
    image: aggregationservices-app  # 使用现有的 aggregationservices-app 镜像
    depends_on:
      - db  # 依赖 db 服务,确保 db 服务先启动
    ports:
      - "9529:9529"  # 将容器的 9529 端口映射到主机的 9529 端口
    environment:
#      DATABASE_URL: mysql+pymysql://root:123456@db/music
      # 因为不同容器之间网络环境隔离,不能直接通过 IP 访问,但是 Docker Compose 会为每个服务分配一个内部 DNS 名称
      # 服务名称可以用作主机名来实现容器之间的通信,所以使用容器名称指定连接
      # 这里配置只取数据库地址和端口,所以这样即可服务名称加端口
      DATABASE_URL: db:3306
volumes:
  db_data:  # 定义名为 db_data 的卷,用于持久化 MySQL 数据

docker重新构建镜像时如果已经构建过相同的步骤会使用缓存内容来提高构建效率

Docker 通过以下方式判断 Dockerfile 或其上下文是否发生变化:

如何判断是否使用缓存

  1. 每条指令的哈希值:Docker 会为每条指令(例如 RUNCOPYADD 等)计算一个哈希值,这个哈希值基于该指令的内容和其依赖的上下文。例如,COPY 指令的上下文是指令涉及的文件。

  2. 层的依赖关系:每一层依赖于其前一层的内容。因此,如果前一层发生变化,后续的所有层都需要重新构建。

  3. 缓存匹配:当 Docker 构建时,它会检查每个指令的哈希值是否与之前构建时相同。如果相同,说明没有变化,可以使用缓存。如果不同,则需要重新构建。

具体来看每条指令的对比方式:

  • FROM:检查基础镜像是否已经存在,标签是否相同。

  • RUN:检查指令的具体内容(例如命令和参数)。

  • COPY** 和 ****ADD**:检查文件内容的哈希值,如果文件内容发生变化,则需要重新执行该指令。