• Docker篇章12:用docker-compose部署构建django+uwsgi+redis+mysql项目


    • 上图是上一篇章,我们手动构建四个容器,分别对应Nginx,Django Uwsgi,Redis,MySQL器,部署一个web项目。然而在实际生产环境中,我们定义数量较多的docker容器,并且伴随容器之间关系比较复杂。一个个去构建容器,不仅效率低下,而且容器出错。而docker-compose可以定义容器集群的编排

    1.docker-compose什么鬼

    • 它用来定义和运行复杂应用Docker工具。使用docker-compose后不再需要使用shell脚本来逐一创建和启动容器,还可以通过docker-compose.yml 文件构建和管理复杂容器组合

    • 下载docker-compose

      # 下载并安装docker-compose
      curl -L https://github.com/docker/compose/releases/download/1.14.0/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose            
      # 设置权限
      chmod +x /usr/local/bin/docker-compose
      # 检查
      docker-compose -version   
      

    2.docker-compose组合容器

    • 通过docker-compose编排并启动4个容器,这更接近于实际生成环境下的部署。

      1.Django + Uwsgi容器:应用程序,后端

      2.MySQL容器:数据库服务

      3.Redis容器:缓存服务

      4.Nginx容器:反向代理,处理静态资源

    这四个容器的依赖关系是:Django+Uwsgi 容器依赖 Redis 容器和 MySQL 容器,Nginx 容器依赖Django+Uwsgi容器。这四个容器别名及通信端口如下图所示:

    3.Docker-compose部署Django项目布局树形图

    • 在根目录新建一个文件夹build_project,用于项目构建,根目录下创建项目目录,这样不同django项目可以共享compose文件。结构目录如下

      /build_project/
      ├── compose# 存放各容器服务Dockerfile配置文件
      │   ├── mysql
      │   │   ├── conf
      │   │   │   └── my.cnf# mysql配置文件
      │   │   ├── init
      │   │   │   └── init.sql# mysql初始化启动脚本
      │   │   └── sqldata# sql数据
      │   │       └── west_coast.sql
      │   ├── nginx
      │   │   ├── Dockerfile# 构建nginx镜像的dockerfile
      │   │   ├── log# 挂载保存nginx容器内日志
      │   │   ├── nginx.conf# nginx配置文件
      │   │   ├── phone.tar.gz# vue静态打包文件手机端
      │   │   └── web.tar.gz# vue静态打包文件pc端
      │   ├── redis
      │   │   └── redis.conf# redis配置文件
      │   └── uwsgi# 挂载保存django+uwsgi容器内uwsgi日志
      ├── docker-compose.yml# 部署编排文件
      └── west_coast__company_project# 项目目录
          ├── app# 存在项目app
          ├── Dockerfile# # 构建Django+Uwsgi镜像的dockerfile
          ├── logs# 项目日志
          ├── manage.py
          ├── pip.conf# pypi源设置。加速pip install
          ├── requirements.txt# django项目依赖
          ├── run.sh# 启动Django+Uwsgi 脚本
          ├── static# 静态文件
          ├── uwsgi.ini# uwsgi配置
          ├── uwsgi.log
          └── west_coast__company_project# Django项目配置文件
              ├── __init__.py
              ├── settings.py
              ├── urls.py
              └── wsgi.py
      
      

    4.基础镜像下载

    nginx: docker pull nginx
    redis: docker pull redis:3.2
    mysql: docker pull mysql:5.6
    python3: docker pull python:3.6
    

    5.编写Dockerfile

    • 通过docker-compose.yml,编排了4项容器服务,别名分别为redis, db, nginx和web:

      version: "3"
      
      volumes: # 自定义数据卷,位于宿主机/var/lib/docker/volumes内
        myproject_db_vol: # 定义数据卷同步容器内mysql数据
        myproject_redis_vol: # 定义数据卷同步redis容器内数据
      
      services:
        redis:
          image: redis:3.2
          volumes:
             - myproject_redis_vol:/data #给redis数据备份
             - ./compose/redis/redis.conf:/etc/redis/redis.conf # 挂载redis配置文件
          expose:
             - "6379"
          restart: always # always表容器运行发生错误时一直重启
        db:
          image: mysql:5.7
          environment:
             - MYSQL_ROOT_PASSWORD=123456 # 数据库密码
             - MYSQL_DATABASE=west_coast # 数据库名称
             - MYSQL_USER=xujunkai # 数据库用户名
             - MYSQL_PASSWORD=123456 # 用户密码
      
          volumes:
             - myproject_db_vol:/var/lib/mysql:rw # 挂载数据库数据, 可读可写
             - ./compose/mysql/sqldata:/opt:rw
             - ./compose/mysql/conf/my.cnf:/etc/mysql/my.cnf # 挂载配置文件
             - ./compose/mysql/init:/docker-entrypoint-initdb.d/ # 挂载数据初始化sql脚本
          ports:
             - "3306:3306" # 与配置文件保持一致,映射端口
          restart: always
      
        web:
          build: ./west_coast__company_project # 使用west_coast__company_project目录下的Dockerfile
          ports:
             - "9000:9000"
          expose:
             - "9000"
          volumes:
             - ./west_coast__company_project:/var/api/west_coast__company_project # 挂载项目代码
             - ./compose/uwsgi:/tmp # 挂载uwsgi日志
          links:
             - db
             - redis
          depends_on: # 依赖关系
             - db
             - redis
          environment:
             - DEBUG=False
          restart: always
          tty: true
          stdin_open: true
      
        nginx:
          build: ./compose/nginx
          ports:
             - "80:80"
             - "8000:8000"
          expose:
             - "80"
             - "8000"
          volumes:
             - ./compose/nginx/log:/var/log/nginx # 挂载日志
          links:
             - web
          depends_on:
             - web
          restart: always
      

    6.编写web镜像

    • 构建west_coast__company_project/Dockerfile

      # 建立 python3.6 环境
      FROM python:3.6
      MAINTAINER xujunkai<xujunkaipy@163.com>
       # 设置 python 环境变量
      ENV PYTHONUNBUFFERED 1
      COPY pip.conf /root/.pip/pip.conf
      # 容器内创建项目目录
      RUN mkdir -p /opt/west_coast__company_project
      WORKDIR /opt/west_coast__company_project
      # 将当前目录下文件 放入容器指定目录
      ADD . /opt/west_coast__company_project
      # 更新pip
      RUN /usr/local/bin/python -m pip install --upgrade pip
      
      # 安装依赖
      RUN pip3 install -r requirements.txt
      
      # 启动项目脚本 增加执行权限
      RUN chmod +x ./run.sh
      
      
      
    • run.sh

      #!/bin/bash
      # 生成数据库可执行文件,
      # 根据数据库可执行文件来修改数据库
      # 用 uwsgi启动 django 服务
      python3 manage.py makemigrations && python3 manage.py migrate && uwsgi --ini /opt/west_coast__company_project/uwsgi.ini
      
      
    • uwsgi.ini配置

      [uwsgi]
      project=west_coast__company_project
      
      base=/opt
      # the base directory (full path)
      # 指定项目的绝对路径的第一层路径(很重要)
      chdir = %(base)/%(project)
      
      # Django's wsgi file
      # 指定项目的 wsgi.py文件
      # 写入相对路径即可,这个参数是以chdir参数为相对路径
      module = %(project).wsgi:application
      master = true
      processes = 2
      socket = 0.0.0.0:9000
      vacuum = true
      max-requests = 5000
      pidfile=/tmp/%(project)-master.pid
      daemonize=/tmp/%(project)-uwsgi.log
      #设置一个请求的超时时间(秒),如果一个请求超过了这个时间,则请求被丢弃
      harakiri = 60
      post buffering = 8192
      buffer-size= 65535
      #当一个请求被harakiri杀掉会,会输出一条日志
      harakiri-verbose = true
      #开启内存使用情况报告
      memory-report = true
      #设置平滑的重启(直到处理完接收到的请求)的长等待时间(秒)
      reload-mercy = 10
      #设置工作进程使用虚拟内存超过N MB就回收重启
      reload-on-as= 1024
      python-autoreload=1
      
      

    7.编写Nginx镜像

    • Nginx镜像使用Dockerfile如下所述:

      FROM nginx:latest
      # 删除原有配置文件
      RUN rm /etc/nginx/conf.d/default.conf
      # 静态文件拷贝容器,并解压
      ADD phone.tar.gz /opt/
      ADD web.tar.gz /opt/
      # 添加新配置文件
      ADD ./nginx.conf /etc/nginx/conf.d/
      # 关闭守护模式
      CMD ["nginx","-g","daemon off;"]
      
      
    • nginx.conf

      server {
              listen       80 default_server;
              listen       [::]:80 default_server;
              server_name  localhost;
              location / {
                      root /opt/web/dist;
      {
      root /opt/phone/dist;
      }
                      index index.html;
                      try_files $uri $uri/ /index.html;
              }
              location ~.*(jpg|jpeg|png|gif|ico|css|js)$ {
                      root /opt/web/dist;
      {
      root /opt/phone/dist;
      }
                      expires 365d;
              }
              error_page 404 /404.html;
                  location = /40x.html {
              }
      
              error_page 500 502 503 504 /50x.html;
                  location = /50x.html {
              }
          }
          server {
              listen 8000;
              server_name web;
              location / {
                  # 指定Docker-compose web服务的端口。反向代理
                  uwsgi_pass web:9000;
                  uwsgi_read_timeout 600;
                  uwsgi_connect_timeout 600;
                  uwsgi_send_timeout 600;
                  include    uwsgi_params;
                  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                  proxy_set_header Host $http_host;
                  proxy_redirect off;
                  proxy_set_header X-Real-IP  $remote_addr;
                      }
          }
      
          access_log /var/log/nginx/access.log main;
          error_log /var/log/nginx/error.log warn;
      
          server_tokens off;
      

    8.编写MySQL容器

    • 之前我们已经从官网拉取镜像,用官网镜像即可,只需更改MySQL相关配置,

      # compose/mysql/conf/my.cnf
      [mysqld]
      user=mysql
      default-storage-engine=INNODB
      character-set-server=utf8
      
      port            = 3306 # 这里端口于docker-compose里映射端口保持一致
      #bind-address= localhost
      
      basedir         = /usr
      datadir         = /var/lib/mysql
      tmpdir          = /tmp
      pid-file        = /var/run/mysqld/mysqld.pid
      socket          = /var/run/mysqld/mysqld.sock
      skip-name-resolve# 这个参数是禁止域名解析的,远程访问推荐开启skip_name_resolve。
      
      [client]
      port = 3306
      default-character-set=utf8
      
      [mysql]
      no-auto-rehash
      default-character-set=utf8
      
      
    • 当然我们需要设置启动脚本命令。这里给docker-compose.yml里设置的MySQL的环境变量要一致。

      GRANT ALL PRIVILEGES ON west_coast.* TO xujunkai@"%" IDENTIFIED BY "123456";
      FLUSH PRIVILEGES;
      

    9.编写redis容器配置

    • 这里使用默认配置

      # compose/redis/redis.conf
      注释掉 bind 127.0.0.1 即可
      

    10.修改django项目settings.py

    • 在这里修改mysql,redis服务连接配置

      # 生产环境设置 Debug = False
      Debug = False
      ALLOWED_HOSTS = ["*"] #或是你的服务的IP
      
      # 设置数据库。这里用户名和密码必需和docker-compose.yml里mysql环境变量保持一致
       DATABASES = {
           'default': {
               'ENGINE': 'django.db.backends.mysql',
               'NAME': 'myproject', # 数据库名
               'USER':'xujunkai', # 你设置的用户名 - 非root用户
               'PASSWORD':'123456', # # 换成你自己密码
               'HOST': 'db', # 注意:这里使用的是db别名,docker会自动解析成ip
               'PORT':'3306', # 端口
          }
       }
       
       # 设置redis缓存。这里密码为redis.conf里设置的密码
       CACHES = {
           "default": {
               "BACKEND": "django_redis.cache.RedisCache",
               "LOCATION": "redis://redis:6379/1", #这里直接使用redis别名作为host ip地址
               "OPTIONS": {
                   "CLIENT_CLASS": "django_redis.client.DefaultClient",
                   # "PASSWORD": "yourpassword", # 换成你自己密码
               },
           }
       }
      

    11.使用docker-compose构建镜像并启动容器组

    # 在docker-compose.yml所在文件夹下。输入指令
    sudo docker-compose build
    # 查看已生成的镜像
    sudo docker images
    # 启动容器组服务
    sudo docker-compose up
    # 查看运行中的容器
    sudo docker ps
    
    # 重新构建
    docker-compose up --build -d
    
    • 可以看到运行容器

    12.进入web容器执行启动脚本

    sudo docker exec -it {web容器id} /bin/bash start.sh
    

    13.数据导入

    • 这里我进入容器进行数据导入,当然也可以通过构建mysql的dockerfile去执行shell命令导入
    #进入mysql 容器
    docker exec -it {mysql容器id} /bin/bash
    #登陆mysql
    mysql -uroot -p你的密码
    # use到指定项目的库
    use west_coast
    # 数据导入
    source /opt/west_coast.sql
    
    • 最终访问ip就可以啦!

    ---问题存在:

    • 连接数据库粗在‘performance_schema.session_variables’ doesn’t exist问题。可进入构建mysql容器

      docker exec -it {mysql容器id} /bin/bash
      # 执行命令
      mysql_upgrade -u root -p --force
      # 输入密码,然后重启mysql服务即可
      
    • 参考文献:https://zhuanlan.zhihu.com/p/145364353

  • 相关阅读:
    重构技巧 引入Null对象
    python yield
    todo
    Python 函数式编程学习
    Python 修饰器
    socket
    Exception、RuntimeException
    设计模式
    线程池
    VMware异常关闭后再次启动提示“以独占方式锁定此配置文件失败”!!!
  • 原文地址:https://www.cnblogs.com/xujunkai/p/13040868.html
Copyright © 2020-2023  润新知