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服务即可
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库