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

原文地址:https://www.cnblogs.com/xujunkai/p/13040868.html