阅读量:4
提供python服务的docker一键部署,示例已配置负载均衡,不需要的在nginx.conf和docker-compose注释相关代码即可
文件结构
1、dockerfile
# 服务的dockerfile # 服务依赖的镜像 FROM python:3.7 # 设置容器内服务的工作目录 WORKDIR /app # 复制当前文件夹所有文件到容器的工作目录,可以选择性按照选择依次COPY COPY . /app # 安装服务所需依赖 RUN pip install -i https://pypi.tuna.tsinghua.edu.cn/simple -r req.txt # 服务启动的接口,要与服务启动文件里面的保持一致 EXPOSE 1000 # 服务启动命令 CMD ["sh", "start.sh"]
2、docker-compose.yml
version: '3.3' networks: python_app_net: # 定义容器间网络的名称 driver: bridge services: mysql_app: image: mysql:5.7 container_name: mysql_app environment: MYSQL_DATABASE: 'polls' # 数据库名称 MYSQL_USER: 'user' # 新建数据库用户 MYSQL_PASSWORD: '123' # 新建用户的密码 MYSQL_ROOT_PASSWORD: '123' # 数据库root账号的密码 volumes: - ../mysql:/var/lib/mysql ports: - "1002:3306" networks: - python_app_net redis_app: image: redis:latest container_name: redis_app ports: - "1003:6379" volumes: - ../redis:/data networks: - python_app_net python_app: # 服务的名称 build: context: . # Dockerfile所在的目录路径 dockerfile: dockerfile # dockerfile的文件名称,有自定义名称的话按照这个寻找 container_name: python_app # 指定容器名称,nginx使用docker部署的时候用得上 image: python_image:1.0 # 镜像的名称与tag volumes: - ../python-app:/app # 服务挂载的卷,挂载以后可以在宿主机直接更改文件,容器内会同步修改,反之亦然,前面为宿主机路径,后面为容器内路径(宿主机路径选择为目前项目路径,新指定路径的话需要将文件都提前放进去,因为是先创建容器再将宿主机挂载的目录整个copy进容器,如果指定了其他路径里面为空的话容器内的工作目录会被覆盖为空,服务无法启动) # ports: # 如果走nginx代理,则不需要将服务的端口暴露出去 # - "1000:1000" # 容器对外映射的端口,前面为宿主机,后面为容器内,容器内端口需要与服务的端口,dockerfile的expose端口保持一致 depends_on: # 在其他指定容器只后启动 - redis_app - mysql_app networks: - python_app_net python_app1: # 服务的名称 build: context: . # Dockerfile所在的目录路径 dockerfile: dockerfile # dockerfile的文件名称,有自定义名称的话按照这个寻找 container_name: python_app1 # 指定容器名称,nginx使用docker部署的时候用得上 image: python_image:1.0 # 镜像的名称与tag volumes: - ../python-app:/app # 服务挂载的卷,挂载以后可以在宿主机直接更改文件,容器内会同步修改,反之亦然,前面为宿主机路径,后面为容器内路径(宿主机路径选择为目前项目路径,新指定路径的话需要将文件都提前放进去,因为是先创建容器再将宿主机挂载的目录整个copy进容器,如果指定了其他路径里面为空的话容器内的工作目录会被覆盖为空,服务无法启动) # ports: # 如果走nginx代理,则不需要将服务的端口暴露出去 # - "1000:1000" # 容器对外映射的端口,前面为宿主机,后面为容器内,容器内端口需要与服务的端口,dockerfile的expose端口保持一致 depends_on: # 在其他指定容器只后启动 - redis_app - mysql_app networks: - python_app_net nginx_app: image: nginx:latest container_name: nginx_app ports: - "1001:80" volumes: - ./nginx.conf:/etc/nginx/nginx.conf depends_on: - python_app networks: - python_app_net
3、main.py
import os import redis import pymysql import socket import logging from flask import Flask, jsonify from flask_cors import CORS app = Flask(__name__) app.json.ensure_ascii = False CORS(app, supports_credentials=True) @app.route('/', methods=['GET']) def index(): # 连接redis redis_client = redis.Redis(host='redis_app', port=6379, db=0, decode_responses=True) # host为容器名称,port为容器内端口,不是容器暴露的端口 num = redis_client.get('key') or 1 redis_client.set('key', int(num) + 1) # 连接mysql mysql_connection = pymysql.connect(host='mysql_app', user='root', password='Admin123.', database='polls', port=3306) # host为容器名称,port为容器内端口,不是容器暴露的端口 try: with mysql_connection.cursor() as cursor: cursor.execute('SELECT VERSION()') res = cursor.fetchone() msg = f'mysql的版本为:{res}' except Exception as e: msg = f'连接mysql失败,{e}' finally: mysql_connection.close() hostname = socket.gethostname() ip_address = socket.gethostbyname(hostname) pid = os.getpid() return jsonify({'code': 200, 'msg': 'success', 'mysql': msg, 'redis': f'这是你第{num}次访问', 'data': f'ip: {ip_address}, pid: {pid}'}) if __name__ == '__main__': app.run(debug=False, host='0.0.0.0', port=1000) # 用容器启动的话host必须为0.0.0.0,不然无法被其他容器访问
4、req.txt
flask==3.0.3 gunicorn==22.0.0 flask_cors redis pymysql
5、start.sh
# --daemon 后台运行的指令不需要,会让容器启动的时候发现进程结束了,直接关闭容器 # --reload会在配置了挂载目录的时候在宿主机的文件更改直接生效,不需要重启容器 # --bind必须绑定0.0.0.0,因为在容器里面,从其他容器访问的话使用127.0.0.1是无法访问到的 gunicorn --reload -w 4 --bind 0.0.0.0:1000 main:app
6、启动命令
# -d会让容器后台运行,不会直接挂在打印台 docker-compose up -d
注意:如果运行拉取镜像报错,可以先单独docker pull 指定镜像,拉取到本地,然后运行docker-compose