GVKun编程网logo

使用 Docker 让部署 Django 项目更加轻松(docker部署django应用)

6

本文将带您了解关于使用Docker让部署Django项目更加轻松的新内容,同时我们还将为您解释docker部署django应用的相关知识,另外,我们还将为您提供关于centos8使用Docker部署D

本文将带您了解关于使用 Docker 让部署 Django 项目更加轻松的新内容,同时我们还将为您解释docker部署django应用的相关知识,另外,我们还将为您提供关于centos8使用Docker部署Django项目的详细教程、Django ImportError:使用Docker时无法导入Django、Django-Docker容器化部署:Django-Docker-MySQL-Nginx-Gunicorn云端部署、Django-Docker容器化部署:Django-Docker-MySQL部署的实用信息。

本文目录一览:

使用 Docker 让部署 Django 项目更加轻松(docker部署django应用)

使用 Docker 让部署 Django 项目更加轻松(docker部署django应用)

作者:HelloGitHub-追梦人物

文中涉及的示例代码,已同步更新到 HelloGitHub-Team 仓库

之前一系列繁琐的部署步骤让我们感到痛苦。这些痛苦包括:

  • 要去服务器上执行 n 条命令
  • 本地环境和服务器环境不一致,明明本地运行没问题,一部署服务器上就挂挂,死活启动不起来
  • 如果上面的情况发生了,又要去服务器上执行 n 条命令以解决问题
  • 本地更新了代码,部署上线后,上述历史又重演一遍,想死的心都有了

那么我们有没有办法,让本地开发环境和线上环境保持一致?这样我们在部署上线前,就可以在本地进行验证,只要验证没问题,我们就有 99% 的把握保证部署上线后也没有问题(1%保留给程序玄学)。

这个办法就是使用 Docker。

Docker 是一种容器技术,可以为我们提供一个隔离的运行环境。要使用 Docker,首先我们需要编排一个镜像,镜像就是用来描述这个隔离环境应该是什么样子的,它需要安装哪些依赖,需要运行什么应用等,可以把它类比成一搜货轮的制造图。

有了镜像,就可以在系统中构建出一个实际隔离的环境,这个环境被称为容器,就好比根据设计图,工厂制造了一条船。工厂也可以制造无数条这样的船。

容器造好了,只要启动它,隔离环境便运行了起来。由于事先编排好了镜像,因此无论是在本地还是线上,运行的容器内部环境都一样,所以保证了本地和线上环境的一致性,大大减少了因为环境差异导致的各种问题。

所以,我们首先来编排 Docker 镜像。

类似于分离 settings.py 文件为 local.py 和 production.py,我们首先建立如下的目录结构,分别用于存放开发环境的镜像和线上环境的镜像:

HelloDjango-blog-tutorial\
	  blog\
	  ...
	  compose\
		    local\
		    production\
			      django\
			      nginx\
	...

local 目录下存放开发环境的 Docker 镜像文件,production\ 下的 django 文件夹存放基于本项目编排的镜像,由于线上环境还要用到 Nginx,所以 nginx 目录下存放 Nginx 的镜像。

线上环境

镜像文件

我们先来在 production\django 目录下编排博客项目线上环境的镜像文件,镜像文件以 Dockerfile 命名:

FROM python:3.6-alpine

ENV PYTHONUNBUFFERED 1

RUN apk update \
  # Pillow dependencies
  && apk add jpeg-dev zlib-dev freetype-dev lcms2-dev openjpeg-dev tiff-dev tk-dev tcl-dev

WORKDIR /app

RUN pip install pipenv -i https://pypi.douban.com/simple

COPY Pipfile /app/Pipfile
COPY Pipfile.lock /app/Pipfile.lock
RUN pipenv install --system --deploy --ignore-pipfile

COPY . /app

COPY ./compose/production/django/start.sh /start.sh
RUN sed -i ''s/\r//'' /start.sh
RUN chmod +x /start.sh

首先我们在镜像文件开头使用 FROM python:3.6-alpine 声明此镜像基于 python:3.6-alpine 基础镜像构建。alpine 是一个 Linux 系统发行版,主打小巧、轻量、安全。我们程序运行需要 Python 环境,因此使用这个小巧但包含完整 Python 环境的基础镜像来构建我们的应用镜像。

ENV PYTHONUNBUFFERED 1 设置环境变量 PYTHONUNBUFFERED=1

接下来的一条 RUN 命令安装图像处理包 Pilliow 的依赖,因为如果使用 django 处理图片时,会使用到 Pillow 这个Python 库。

接着使用 WORKDIR /app 设置工作目录,以后在基于此镜像启动的 Docker 容器中执行的命令,都会以这个目录为当前工作目录。

然后我们使用命令 RUN pip install pipenv 安装 pipenv,-i 参数指定 pypi 源,国内一般指定为豆瓣源,这样下载 pipenv 安装包时更快,国外网络可以省略 -i 参数,使用官方的 pypi 源即可。

然后我们将项目依赖文件 Pipfile 和 Pipfile.lock copy 到容器里,运行 pipenv install 安装依赖。指定 --system 参数后 pipenv 不会创建虚拟环境,而是将依赖安装到容器的 Python 环境里。因为容器本身就是个虚拟环境了,所以没必要再创建虚拟环境。

接着将这个项目的文件 copy 到容器的 /app 目录下(当然有些文件对于程序运行是不必要的,所以一会儿我们会设置一个 dockerignore 文件,里面指定的文件不会被 copy 到容器里)。

然后我们还将 start.sh 文件复制到容器的 / 目录下,去掉回车符(windows 专用,容器中是 linux 系统),并赋予了可执行权限。

start.sh 中就是启动 Gunicorn 服务的命令:

#!/bin/sh

python manage.py migrate
python manage.py collectstatic --noinput
gunicorn blogproject.wsgi:application -w 4 -k gthread -b 0.0.0.0:8000 --chdir=/app

我们会让容器启动时去执行此命令,这样就启动了我们的 django 应用。--chdir=/app 表明以 /app 为根目录,这样才能找到 blogproject.wsgi:application。

在项目根目录下建立 .dockerignore 文件,指定 copy 到容器的文件:

.*
_credentials.py
fabfile.py
*.sqlite3

线上环境使用 Nginx,同样来编排 Nginx 的镜像,这个镜像文件放到 compose\production\nginx 目录下:

FROM nginx:1.17.1

# 替换为国内源
RUN mv /etc/apt/sources.list /etc/apt/sources.list.bak
COPY ./compose/production/nginx/sources.list /etc/apt/
RUN apt-get update && apt-get install -y --allow-unauthenticated certbot python-certbot-nginx

RUN rm /etc/nginx/conf.d/default.conf
COPY ./compose/production/nginx/HelloDjango-blog-tutorial.conf /etc/nginx/conf.d/HelloDjango-blog-tutorial.conf

这个镜像基于 nginx:1.17.1 基础镜像构建,然后我们更新系统并安装 certbot 用于配置 https 证书。由于要安装大量依赖, nginx:1.17.1 镜像基于 ubuntu,所以安装会比较慢,我们将软件源替换为国内源,这样稍微提高一下安装速度。

最后就是把应用的 nginx 配置复制到容器中 nginx 的 conf.d 目录下。里面的内容和直接在系统中配置 nginx 是一样的。

upstream hellodjango_blog_tutorial  {
    server hellodjango_blog_tutorial:8000;
}

server {
    server_name  hellodjango-blog-tutorial-demo.zmrenwu.com;

    location /static {
        alias /apps/hellodjango_blog_tutorial/static;
    }

    location / {
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        proxy_pass http://hellodjango_blog_tutorial;
    }

    listen 80;
}

相比之前直接在宿主机配置 Nginx,这里使用了 Nginx 的 upstream 模块,实际上就是做一个请求转发。Nginx 将所有请求转发给上游 hellodjango_blog_tutorial 模块处理,而 hellodjango_blog_tutorial 这个模块的服务实际就是运行 django 应用的容器 hellodjango_blog_tutorial(接下来会运行这个容器)。

镜像编排完毕,接下来就可以通过镜像构建容器并运行容器了。但是先等一等,我们有两个镜像,一个是 django 应用的,一个是 Nginx 的,这意味着我们需要构建 2 次容器,并且启动容器 2 次,这会比较麻烦。有没有办法一次构建,一条命令运行呢?答案就是使用 docker-compose。

docker-compose 将各个容器的镜像,以及构建和运行容器镜像时的参数等编写在一个 ymal 文件里。这样我们只需要一条 build 命令就可以构建多个容器,使用一条命令 up 就可以启动多个容器。

我们在项目根目录建一个 production.yml 文件来编排 django 容器和 nginx 容器。

version: ''3''

volumes:
  static:
  database:

services:
  hellodjango_blog_tutorial:
    build:
      context: .
      dockerfile: compose/production/django/Dockerfile
    image: hellodjango_blog_tutorial
    container_name: hellodjango_blog_tutorial
    working_dir: /app
    volumes:
      - database:/app/database
      - static:/app/static
    env_file:
      - .envs/.production
    ports:
      - "8000:8000"
    command: /start.sh

  nginx:
    build:
      context: .
      dockerfile: compose/production/nginx/Dockerfile
    image: hellodjango_blog_tutorial_nginx
    container_name: hellodjango_blog_tutorial_nginx
    volumes:
      - static:/apps/hellodjango_blog_tutorial/static
    ports:
      - "80:80"
      - "443:443"

version: ''3'' 声明 docker-compose 为第三代版本的语法

volumes:
  static:
  database:

声明了 2 个命名数据卷,分别为 static 和 database。数据卷是用来干嘛的呢?由于 docker 容器是一个隔离环境,一旦容器被删除,容器内的文件就会一并删除。试想,如果我们启动了博客应用的容器并运行,一段时间后,容器中的数据库就会产生数据。后来我们更新了代码或者修改了容器的镜像,这个时候就要删除旧容器,然后重新构建新的容器并运行,那么旧容器中的数据库就会连同容器一并删除,我们辛苦写的博客文章付之一炬。

所以我们使用 docker 的数据卷来管理需要持久存储的数据,只要数据被 docker 的数据卷管理起来了,那么新的容器启动时,就可以从数据卷取数据,从而恢复被删除容器里的数据。

我们有 2 个数据需要被数据卷管理,一个是数据库文件,一个是应用的静态文件。数据库文件容易理解,那么为什么静态文件也要数据卷管理呢?启动新的容器后使用 python manage.py collectstatic 命令重新收集不就好了?

答案是不行,数据卷不仅有持久保存数据的功能,还有跨容器共享文件的功能。要知道,容器不仅和宿主机隔离,而且容器之间也是互相隔离的。Nginx 运行于独立容器,那么它处理的静态文件从哪里来呢?应用的静态文件存放于应用容器,Nginx 容器是访问不到的,所以这些文件也通过数据卷管理,nginx 容器从数据卷中取静态文件映射到自己的容器内部。

接下来定义了 2 个 services,一个是应用服务 hellodjango_blog_tutorial,一个是 nginx 服务。

build:
      context: .
      dockerfile: compose/production/django/Dockerfile

告诉 docker-compose,构建容器是基于当前目录(yml 文件所在的目录),且使用的镜像是 dockerfile 指定路径下的镜像文件。

image 和 container_name 分别给构建的镜像和容器取个名字。

working_dir 指定工作目录。

  • volumes:
      - database:/app/database
      - static:/app/static
    

    同时这里要注意,数据卷只能映射文件夹而不能映射单一的文件,所以对我们应用的数据库来说,db.sqlite3 文件我们把它挪到了 database 目录下。因此我们要改一下 django 的配置文件中数据库的配置,让它正确地将数据库文件生成在项目根目录下的 database 文件夹下:

    DATABASES = {
        ''default'': {
            ''ENGINE'': ''django.db.backends.sqlite3'',
          ''NAME'': os.path.join(BASE_DIR, ''database'', ''db.sqlite3''),
        }
    }
    
  • env_file:
        - .envs/.production
    

    容器启动时读取 .envs/.production文件中的内容,将其注入环境变量。

    我们创建一下这个文件,把 secret_key 写进去。

    DJANGO_SECRET_KEY=2pe8eih8oah2_2z1=7f84bzme7^bwuto7y&f(#@rgd9ux9mp-3
    

    注意将这些包含敏感信息的文件加入版本控制工具的忽略列表里,防止一不小心推送到公开仓库供大众观光。

  • ports:
      - "8000:8000"
    

    暴露容器内的 8000 端口并且和宿主机的 8000 端口绑定,于是我们就可以通过宿主机的 8000 端口访问容器。

command: /start.sh 容器启动时将执行 start.sh,从而启动 django应用。

nginx 服务容器也类似,只是注意它从数据卷 static 中取静态文件并映射到 nginx 容器内的 /apps/hellodjango_blog_tutorial/static,所以我们在 nginx 的配置中:

location /static {
    alias /apps/hellodjango_blog_tutorial/static;
}

这样可以正确代理静态文件。

万事具备,在本地执行一下下面的两条命令来构建容器和启动容器。

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

此时我们可以通过域名来访问容器内的应用,当然,由于 Nginx 在本地环境的容器内运行,需要修改一下 本地 hosts 文件,让域名解析为本地 ip 即可。

如果本地访问没有问题了,那么就可以直接在服务器上执行上面两条命令以同样的方式启动容器,django 应用就顺利地在服务上部署了。

开发环境

既然线上环境都使用 Docker 了,不妨开发环境也一并使用 Docker 进行开发。开发环境的镜像和 docker-compose 文件比线上环境简单一点,因为不用使用 nginx。

开发环境的镜像文件,放到 compose\local 下:

FROM python:3.6-alpine

ENV PYTHONUNBUFFERED 1

RUN apk update \
  # Pillow dependencies
  && apk add jpeg-dev zlib-dev freetype-dev lcms2-dev openjpeg-dev tiff-dev tk-dev tcl-dev

WORKDIR /app

RUN pip install pipenv -i https://pypi.douban.com/simple

COPY Pipfile /app/Pipfile
COPY Pipfile.lock /app/Pipfile.lock
RUN pipenv install --system --deploy --ignore-pipfile

COPY ./compose/local/start.sh /start.sh
RUN sed -i ''s/\r//'' /start.sh
RUN chmod +x /start.sh

要注意和线上环境不同的是,我们没有把整个代码 copy 到容器里。线上环境代码一般比较稳定,而对于开发环境,由于需要频繁修改和调试代码,如果我们把代码 copy 到容器,那么容器外做的代码修改,容器内部是无法感知的,这样容器内运行的应用就没法同步我们的修改了。所以我们会把代码通过 Docker 的数据卷来管理。

start.sh 不再启动 gunicorn,而是使用 runserver 启动开发服务器。

#!/bin/sh

python manage.py migrate
python manage.py runserver 0.0.0.0:8000

然后创建一个 docker-compose 文件 local.yml(和 production.yml 同级),用于管理开发容器。

version: ''3''

services:
  djang_blog_tutorial_v2_local:
    build:
      context: .
      dockerfile: ./compose/local/Dockerfile
    image: django_blog_tutorial_v2_local
    container_name: django_blog_tutorial_v2_local
    working_dir: /app
    volumes:
      - .:/app
    ports:
      - "8000:8000"
    command: /start.sh

注意我们将整个项目根目录下的文件挂载到了 /app 目录下,这样就能容器内就能实时反映代码的修改了。

线上部署

如果容器在本地运行没有问题了,线上环境的容器运行也没有问题,因为理论上,我们在线上服务器也会构建和本地测试用的容器一模一样的环境,所以几乎可以肯定,只要我们服务器有 Docker,那么我们的应用就可以成功运行。

首先在服务安装 Docker,安装方式因系统而异,方式非常简单,我们以 CentOS 7 为例,其它系统请参考 Docker 的官方文档。

首先安装必要依赖:

$ sudo yum install -y yum-utils \
  device-mapper-persistent-data \
  lvm2

然后添加仓库源:

$ sudo yum-config-manager \
    --add-repo \
    https://download.docker.com/linux/centos/docker-ce.repo

最后安装 Docker:

$ sudo yum install docker-ce docker-ce-cli containerd.io

启动 Docker:

$ sudo systemctl start docker

(境外服务器忽略)设置 Docker 源加速(使用 daocloud 提供的镜像源),否则拉取镜像时会非常慢

curl -sSL https://get.daocloud.io/daotools/set_mirror.sh | sh -s http://f1361db2.m.daocloud.io

在 docker 中运行一个 hello world,确认 docker 安装成功:

$ sudo docker run hello-world

docker 安装成功了,还要安装一下 docker-compose。其实是一个 python 包,我们直接通过 pip 安装就可以了:

$ pip install docker-compose

为了避免运行一些 docker 命令时可能产生的权限问题,我们把系统当前用户加入到 docker 组里:

$ sudo usermod -aG docker ${USER}

添加组后要重启一下 shell(ssh 连接的话就断开重连)。

万事俱备,只欠东风了!

开始准备让我们的应用在 docker 容器里运行。由于之前我们把应用部署在宿主机上,首先来把相关的服务停掉:

# 停掉 nginx,因为我们将在容器中运行 nginx
$ sudo systemctl stop nginx

# 停掉博客应用
$ supervisorctl stop hellodjango-blog-tutorial -c ~/etc/supervisord.conf

接下来拉取最新的代码到服务器,进入项目根目录下,创建线上环境需要的环境变量文件:

$ mkdir .envs
$ cd .envs
$ vi .production

将线上环境的 secret key 写入 .production 环境变量文件,

DJANGO_SECRET_KEY=2pe8eih8oah2_2z1=7f84bzme7^bwuto7y&f(#@rgd9ux9mp-3

保存并退出。

回到项目根目录,运行 build 命令构建镜像:

$ docker-compose -f prodcution.yml build

然后我们可以开始启动根据构建好的镜像启动 docker 容器,不过为了方便,我们的 docker 进程仍然由 supervisor 来管理,我们修改一下博客应用的配置,让它启动时启动 docker 容器。

打开 ~/etc/supervisor/conf.d/hellodjango-blog-tutorial.ini,修改为如下内容:

[program:hellodjango-blog-tutorial]
command=docker-compose -f production.yml up --build
directory=/home/yangxg/apps/HelloDjango-blog-tutorial
autostart=true
autorestart=unexpected
user=yangxg
stdout_logfile=/home/yangxg/etc/supervisor/var/log/hellodjango-blog-tutorial-stdout.log
stderr_logfile=/home/yangxg/etc/supervisor/var/log/hellodjango-blog-tutorial-stderr.log

主要就是把之前的使用 Gunicorn 来启动服务换成了启动 docker。

修改 ini 配置 要记得 reread 使配置生效:

$ supervisorctl -c ~/etc/supervisord.conf
> reread
> start 

docker 容器顺利启动,访问我们的博客网站。抛掉镜像编排的准备工作,相当于我们只执行了一条构建容器并启动容器的命令就部署了我们的博客应用。如果换台服务器,也只要再执行一下镜像构建和启动容器的命令,服务就又可以起来!这就是 docker 的好处。

由于开发 django 用的最多的 IDE Pycharm 也能很好地集成 Docker,我现在开发工作已经全面拥抱 Docker 了,前所未有的体验,前所未有的方便和稳定,一定要学着用起来!

HTTPS

最后,由于 Nginx 在新的容器里运行,所以需要重新申请和配置 https 证书,这和之前是一样,只是此前 Nginx 在宿主机上,这次我们在容器里运行 certbot 命令。编排 nginx 镜像时已经安装了 certbot,直接执行命令即可,在 docker 容器内执行命令如下:

我们首先通过 docker ps 命令查看正在运行的容器,记住 nginx 容器的名字,然后使用 docker exec -it 容器名 命令的格式在指定容器内执行命令,所以我们执行:

$ docker exec -it nginx certbot --nginx

根据提示输入信息即可,过程和上一节在宿主机上部署一模一样,这里不再重复。

自动化部署

fabric 无需修改,来尝试本地执行一下:

pipenv run fab -H server_ip --prompt-for-login-password -p deploy

完美!至此,我们的博客已经稳定运行于线上,陆陆续续会有更多的人来访问我们的博客,让我们来继续完善它的功能吧!


『讲解开源项目系列』——让对开源项目感兴趣的人不再畏惧、让开源项目的发起者不再孤单。跟着我们的文章,你会发现编程的乐趣、使用和发现参与开源项目如此简单。欢迎留言联系我们、加入我们,让更多人爱上开源、贡献开源~

本文分享 CNBlog - 削微寒的程序员之路。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

centos8使用Docker部署Django项目的详细教程

centos8使用Docker部署Django项目的详细教程

引言

在本文中将介绍在Docker中通过django + uwsgi + nginx部署方式部署Django项目,

由于记录的是学习过程,使用的都是目前较高的版本。

python  版本为3.8.3
django  版本为3.0.6
nginx   版本为1.17.10

好了简单的介绍之后,就进入正题了。

创建一个工作目录

创建一个工作目录用来存放项目,和Dockerfile等文件。

mkdir uwsgidocker

简单说明一下各个文件

docker-compose.yml: Docker Compose是 docker 提供的一个命令行工具,用来定义和运行由多个容器组成的应用。
            使用 compose,我们可以通过 YAML 文件声明式的定义应用程序的各个服务,并由单个命令完成应用的创建和启动。
            在一开始我没有使用docker-compose.yml
Dockerfile:      是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需的指令和说明。
my_django:     是一个刚创建的django项目,主要是将 ALLOWED_HOSTS = [] 改为 ALLOWED_HOSTS = ["*"] 
nginxconf:       是个包含nginx配置和创建nginx镜像的Dockerfile文件的文件夹。
pip.conf:       是关于pip的配置,主要是用于pip加速下载的。
uwsgi_conf.ini: uwsgi的配置文件

注意:在django项目中的settings.py文件里,需要将   ALLOWED_HOSTS = [] 改为 ALLOWED_HOSTS = [ " * " ] 。

制作uwsgi镜像

根据Dockerfile文件制作uwsgi的镜像并运行。

FROM python:3.8.3
# 创建目录
RUN mkdir -p /usr/src/app
# 设置工作目录
WORKDIR /usr/src/app

# 将pip.conf文件复制到/root/.pip/pip.conf
COPY pip.conf /root/.pip/pip.conf
# 更新pip
RUN pip install --upgrade pip
# 下载django和uwsgi 在一般项目中只需下载requirement.txt
RUN pip install django && pip install uwsgi
# 将当前目录下的文件全部复制过去,只有是复制项目,uwsgi配置文件
COPY . /usr/src/app/
# 在run的时候启动uwsgi
CMD uwsgi --ini uwsgi_conf.ini
# 暴露端口
EXPOSE 80 8080 8000 8888

uwsgi 配置文件, 官网

[uwsgi]
# 项目目录,由于在当前目录,直接写就好了
chdir = my_django
# uwsgi的启动文件,在项目下的wsgi.py
module = my_django.wsgi
# 允许主线程存在(true)
master = true
# 进程数
processes = 1
# 用于指定项目的运行的端口,可以使用socket和http,我使用的是http便于查看
http = 0.0.0.0:8000
# socket = 0.0.0.0:8000

# http = 10.0.0.10:8000
# socket = 10.0.0.10:8008
# socket = /usr/src/app/my_django/uwsgi.sock
# 当服务器退出的时候自动清理环境,删除unix socket文件和pid文件
vacuum = true

好了,有了着两个文件就可以制作uwsgi镜像了。执行下面命令,就能生成镜像了。

docker build -t myuwsgi ./

使用 docker images 查看镜像

运行uwsgi镜像

既然镜像已经制作完成了,接下来就是运行镜像,在浏览器查看。

直接使用如下命令,暴露端口便于查看。

docker run --rm -it --name webuwsgi -p 8000:8000 myuwsgi

运行结果

接下来就可以在浏览器访问了,输入ip和端口进行访问  192.168.56.102:8000

这就证明uwsgi镜像制作完成,并能成功运行。

接下来就是制作nginx镜像,用于反向代理

制作Nginx镜像

首先进入nginxconf目录, cd nginxconf/  便于操作,然后编辑Dockerfile文件

FROM nginx

# 删除默认的nginx配置文件
RUN rm -rf /etc/nginx/conf.d/default.conf
# 将当前目录下的配置文件拷贝到/etc/nginx/conf.d/目录下
COPY nginx.conf /etc/nginx/conf.d/nginx.conf

EXPOSE 80

编辑nginx.conf文件

server {
 # 监听端口
 listen 80;
 # 主机名
 server_name localhost;
 location / {
 include uwsgi_params;
 # uwsgi服务的ip与端口,
 proxy_pass http://192.167.0.2:8000;
 # uwsgi使用socket时可直接使用
 # uwsgi_pass 192.167.0.2:8000;
 proxy_set_header X-Real-IP $remote_addr;
 proxy_set_header Host $host;
 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
 }
 
 location /static {
 # 静态文件
 alias /usr/share/nginx/html/static;
 }
}

uwsgi容器的IP可以用docker inspect 容器名

docker inspect webuwsgi

查看

好了,接下来就是制作nginx镜像了,使用如下命令,制作镜像

docker build -t mynginx ./

使用 docker images 查看镜像

运行Nginx镜像

既然镜像已经制作完成了,接下来就是运行镜像,然后在浏览器查看。

直接使用如下命令,暴露端口便于查看。

docker run --rm -it -p 80:80 --name nginxweb mynginx

运行结果

接下来就可以在浏览器访问了,输入ip直接进行访问 192.168.56.102

好了,这就是在docker上使用uwsgi+nginx部署django项目。

接下来我们使用uwsgi+nginx+docker-compose部署django项目。

使用Docker-compose

编辑docker-compose.yml文件,分配ip,并在nginx,uwsgi配置文件稍做修改就好了

docker-compose.yml文件

version: ''3''
services:
version: ''3''
services:
 uwsgi:
 build:
 context: ./
 image: uwsgi
 restart: always
 networks:
 django:
 ipv4_address: 10.0.0.10
 ports:
 - "8000:8000"
 volumes:
 - /root/uwsgidocker/:/usr/src/app/:rw
 command: uwsgi --ini /usr/src/app/uwsgi_conf.ini

 nginx:
 image: myweb
 build:
 context: ./nginxconf
 ports:
 - "80:80"
 - "8080:8080"
 volumes:
 - /root/uwsgidocker/nginxconf/nginx.conf:/etc/nginx/conf.d/nginx.conf:rw
 restart: always
 privileged: true
 networks:
 django:
 ipv4_address: 10.0.0.20
networks:
 django:
 ipam:
 config:
 - subnet: 10.0.0.0/24

uwsgi_conf.ini 文件,就是改一下ip

[uwsgi]
chdir = my_django

module = my_django.wsgi

uid = root
gid = root

master = true

processes = 1

# http = 0.0.0.0:8000
# socket = 0.0.0.0:8000

# http = 10.0.0.10:8000
socket = 10.0.0.10:8008
# socket = /usr/src/app/my_django/uwsgi.sock

vacuum = true

nginx.conf文件,同理,更改ip

server {
 listen 80;
 server_name localhost;
 location / {
 include uwsgi_params;
 # proxy_pass http://192.167.0.2:8000;
 # uwsgi_pass 192.167.0.2:8000;
 # proxy_set_header Host $host;
 # proxy_redirect off;
 # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
 # uwsgi_pass unix:/usr/src/app/my_django/uwsgi.sock;
 uwsgi_pass 10.0.0.10:8008;
 proxy_set_header X-Real-IP $remote_addr;
 proxy_set_header Host $host;
 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
 }
 location /static {
 alias /usr/share/nginx/html/static;
 }
}

好了,将配置稍作修改之后,就可以直接运行了

docker-compose运行

1.启动-构建镜像&&启动容器

docker-compose up 或者 docker-compose up -d 后台运行

2.停止

docker-compose stop #停止容器的运行

3.停止并删除容器

docker-compose down

4.输入IP,进行访问,结果

是不是发现使用docker-compose特别方便啊,在此我也推荐大家使用这个哦!

总结

到此这篇关于centos8使用Docker部署Django项目的详细教程的文章就介绍到这了,更多相关docker部署django项目内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!

您可能感兴趣的文章:
  • 详解将Django部署到Centos7全攻略
  • 将Django项目部署到CentOs服务器中
  • 详解centos7+django+python3+mysql+阿里云部署项目全流程
  • Centos8下django项目部署 nginx+uwsgi的教程
  • Centos部署django服务nginx+uwsgi的方法
  • CentOS下宝塔部署Django项目的详细教程
  • 将django项目部署到centos的踩坑实战

Django ImportError:使用Docker时无法导入Django

Django ImportError:使用Docker时无法导入Django

如何解决Django ImportError:使用Docker时无法导入Django?

在尝试使用docker时,控制台出现错误。如何修复 但是当我使用localhost测试时,它就可以工作。

enter image description here

错误

PS C:\Users\Test\Desktop\Projects\Testadmin\master> docker-compose up
Creating network "master_default" with the default driver
Creating master_web_1 ... done
Attaching to master_web_1
web_1  | Traceback (most recent call last):
web_1  |   File "manage.py",line 8,in <module>
web_1  |     from django.core.management import execute_from_command_line
web_1  | ModuleNotFoundError: No module named ''django''
web_1  |
web_1  | The above exception was the direct cause of the following exception:
web_1  |
web_1  | Traceback (most recent call last):
web_1  |   File "manage.py",line 10,in <module>
web_1  |     raise ImportError(
web_1  | ImportError: Couldn''t import Django. Are you sure it''s installed and available on your PYTHONPATH environment variable? Did you forget to activate a virtual environment?
master_web_1 exited with code 1

docker-compose.yml

version: ''3''

services:
    web:
        build: .
        command: python manage.py runserver 0.0.0.0:8000
        volumes:
            - .:/app
        ports: 
            - "8000:8000"
            

Dockerfile

FROM python:3
ENV PYTHONUNBUFFERED l
RUN mkdir /app
@R_301_4715@ /app
copY requirements.txt /app/
RUN pip install -r requirements.txt
copY . /app/

manage.py

#!/ usr / bin / env python 导入操作系统 导入系统

if __name__ == ''__main__'':
    os.environ.setdefault(''DJANGO_SETTINGS_MODULE'',''master.settings'')
    try:
        from django.core.management import execute_from_command_line
    except ImportError as exc:
        raise ImportError(
            "Couldn''t import Django. Are you sure it''s installed and "
            "available on your PYTHONPATH environment variable? Did you "
            "forget to activate a virtual environment?"
        ) from exc
    execute_from_command_line(sys.argv)

requirements.txt

Django==3.8.5

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)

Django-Docker容器化部署:Django-Docker-MySQL-Nginx-Gunicorn云端部署

Django-Docker容器化部署:Django-Docker-MySQL-Nginx-Gunicorn云端部署

上一章我们实现了在 Docker 中添加了 MySQL 数据库,但采用的开发服务器虽然使用便捷,但性能差、可靠性低,无法应用在生产环境中。

因此本章将实现 Docker + Django + MySQL + Nginx + Gunicorn 容器项目,完成最终的服务器部署。

直接进入本章的 Docker 入门读者,建议回到教程第一章开始阅读,否则某些内容不好理解。对 Django 项目部署都没有概念的读者,还可以先阅读我的博文:将 Django 项目部署到服务器。

Docker-compose

在部署到服务器之前,先来尝试本地部署。

在上一章的基础上,继续修改 docker-compose.yml 配置:

version: "3"

services:
  app:
    restart: always
    build: .
    command: bash -c "python3 manage.py collectstatic --no-input && python3 manage.py migrate && gunicorn --timeout=30 --workers=4 --bind :8000 django_app.wsgi:application"
    volumes:
      - .:/code
      - static-volume:/code/collected_static
    expose:
      - "8000"
    depends_on:
      - db
    networks:
      - web_network
      - db_network
  db:
    image: mysql:5.7
    volumes:
      - "./mysql:/var/lib/mysql"
    ports:
      - "3306:3306"
    restart: always
    environment:
      - MYSQL_ROOT_PASSWORD=mypassword
      - MYSQL_DATABASE=django_app
    networks:
      - db_network
  nginx:
    restart: always
    image: nginx:latest
    ports:
      - "8000:8000"
    volumes:
      - static-volume:/code/collected_static
      - ./config/nginx:/etc/nginx/conf.d
    depends_on:
      - app
    networks:
      - web_network
      
networks:
  web_network:
    driver: bridge
  db_network:
    driver: bridge
    
volumes:
  static-volume:

有点复杂。来看看大体思路:

  • 定义了 3 个容器,分别是 appdbnginx 。容器之间通过定义的端口进行通讯。
  • 定义了 2 个网络,分别是 web_networkdb_network 。只有处在相同网络的容器才能互相通讯。不同网络之间是隔离的,即便采用同样的端口,也无法通讯。
  • 定义了 1 个数据卷static-volume 。数据卷非常适合多个容器共享使用同一数据,你可以看到 appnginx 都用到了它。
  • exposeports 都可以暴露容器的端口,区别是 expose 仅暴露给其他容器,而 ports 会暴露给其他容器和宿主机。

这么讲可能还是很难理解,让我们继续分解。

网络 network

Docker 允许用户给每个容器定义其工作的网络,只有在相同的网络之中才能进行通讯。你可以看到 nginx 容器处于 web_network 网络,而 db 容器处于 db_network 网络,因此它两是无法通讯的,实际上确实也不需要通讯。而 app 容器同时处于 web_networkdb_network 网络,相当于是桥梁,连通了3个容器。

定义网络可以隔离容器的网络环境,也方便运维人员一眼看出网络的逻辑关系。

数据卷

之前我们见识过的用于映射宿主机和容器目录的卷了,实际上称为挂载;现在新出现的 static-volume 才叫。它的使用方式像这样:static-volume:/code/collected_static ,冒号后面还是容器内的目录,但冒号前的却不是宿主机目录、仅仅是卷的名称而已。从本质上讲,数据卷也是实现了宿主机和容器的目录映射,但是数据卷是由 Docker 进行管理的,你甚至都不需要知道数据卷保存在宿主机的具体位置。

相比挂载,数据卷的优点是由于是 Docker 统一管理的,不存在由于权限不够引发的挂载问题,也不需要在不同服务器指定不同的路径;缺点是它不太适合单配置文件的映射。

和挂载一样,数据卷的生命周期脱离了容器,删除容器之后卷还是存在的。下次构建镜像时,指定卷的名称就可以继续使用了。

既然 Docker 能够管理卷,所以要想删除卷也是非常容易的。指令嘛,我不告诉你,生产环境千万不要手贱。定期备份数据是个好习惯。

数据卷有个很重要的特性:启动时如果卷是空的,则会将容器映射目录的所有内容复制到卷里去。换句话说就是,只要卷初始化完成后,容器原始的 collected_static 目录就不会再使用了,新增的文件也只存在于卷中,容器中是没有的。

实际上 static 静态文件(以及 media 媒体文件)的持久存储,通过挂载或者数据卷都可以实现;具体用哪种,这个就见仁见智了,你自己选择。

篇幅有限,教程没有讲到 media 媒体文件,但它的设置和 static 是完全相同的。

其他配置

首先修改 Nginx 的配置文件,即映射到 nginx 容器的 config/nginx/django_app.conf

upstream app {
  ip_hash;
  server app:8000;
}

server {
  listen 8000;
  server_name localhost;
  
  location /static/ {
    autoindex on;
    alias /code/collected_static/;
  }
  
  location / {
    proxy_pass http://app/;
  }
}

此配置下 Nginx 会监听容器的 8000 端口,并将受到的请求发送到 app 容器(静态文件请求除外)。

requirements.txt 文件中增加 gunicorn 库:

django==2.2
mysqlclient==1.3.14
gunicorn==19.9.0

最后修改 django_app/settings.py和静态文件存放目录的配置:

...

ALLOWED_HOSTS = [''*'']

...

STATIC_ROOT = os.path.join(BASE_DIR, ''collected_static'')
STATIC_URL = ''/static/''

所有配置就完成了。

教程使用空的 Django 项目,为演示效果,就没有修改 DEBUG=False 了。若你用的自己的项目测试,记得把它为 False。

测试

测试指令就一条:

$ docker-compose up

浏览器访问 127.0.0.1:8000 又看到熟悉的 Django 小火箭了。

和上一章类似,第一次启动容器时可能会出现无法连接 MySQL 的错误,这是由于虽然 db 容器已经启动,但初始化并未完成;重新启动容器之后就可以正常工作了。若多次启动都无法正常工作,那就是别的原因了,好好检查吧。

本地部署成功,下一步服务器部署。

服务器部署

有了本地部署的经验,服务器部署就非常非常简单了。

还是类似的,部署前将 Docker 、 Docker-compose 、 Python3 等工具在服务器上安装好;将项目用 Git 克隆到服务器本地。

接下来把 settings.pyconfig/nginx/django_app.confrequirements.txt 相关位置都按教程流程改好;将 docker-compose.ymlDockerfile 复制到服务器。

由于 http 请求默认为 80 端口,所以为了接收公网请求,还需要做一点点修改 docker-compose.yml 的工作:

version: "3"

services:
  app:
    ...
    command: bash -c "... your_project_name.wsgi:application"  # 改为你的项目名称
    ...
  db:
    ...
  nginx:
    ...
    ports:
      - "80:8000"  # 监听 80 端口
    ...
      
networks:
  ...
    
volumes:
  ...

修改 Gunicorn 绑定的项目名称,以及让宿主机监听公网 http 默认的 80 端口。

此外还要修改 config/nginx/django_app.conf

upstream your_domain_name {
  ip_hash;
  server app:8000;
}

server {
  ...
  
  location / {
    proxy_pass http://your_domain_name/;
  }
}

这个改动主要是为了照顾各种第三方登录的回调地址(不改这里, GitHub、Weibo 三方登录都会失败)。如果你没有类似的需求,不改也是可以的。比如博主的个人网站是 www.dusaiphoto.com,所以这里的 your_domain_name 就修改为 www.dusaiphoto.com

最后,记得将 settings.py 中的 DEBUG 配置修改好:

# DEBUG=True 注释掉
DEBUG=False

这样就可以了!构建镜像并启动容器:

 docker-compose up

在浏览器中就可以正常访问你的网站了。

总结

现在你已经可以部署一个线上的容器化 Django 项目了,恭喜!

若本教程对你有帮助,请到GitHub给个 Star 哟,也欢迎阅读我的Django 搭建博客教程。

老朋友们,下个教程见!


  • 有疑问请在杜赛的个人网站留言,我会尽快回复。
  • 教程示例代码:django-docker-tutorial
  • 或Email私信我:dusaiphoto@foxmail.com

Django-Docker容器化部署:Django-Docker-MySQL部署

Django-Docker容器化部署:Django-Docker-MySQL部署

上一章我们成功搭建了容器化的 Django 项目,用到的数据库为默认的 Sqlite。Sqlite 虽然简单易用,但是线上部署时通常会选择更高效、更可靠的数据库,比如 MySQL。

本章将在上一章的基础上,修改并构建 Docker + Django + MySQL 的容器项目。

Docker-compose

我们在学习面向对象的编程语言时,会想方设法把功能独立的模块给独立出来,方便复用和维护。

容器也是一样的。虽然理论上可以把所有组件塞到同一个容器中去,但更好的做法是各模块在单独容器中,只要保持必要的通信就可以了。

也就是说,本教程中现在需要两个容器了:

  • 名称叫 app 的 Django 容器
  • 名称叫 db 的 MySQL 容器

所以如何构建 MySQL 镜像?别担心,这么常用的镜像官方已经帮你构建好了,只需要把它从仓库拉取到本地就可以了。

修改上一章写的 docker-compose.yml ,增加 MySQL 容器:

version: "3"
services:
  app:
    restart: always
    build: .
    command: bash -c "python3 manage.py migrate && python3 manage.py runserver 0.0.0.0:8000"
    volumes:
      - .:/code
    ports:
      - "8000:8000"
    depends_on:
      - db
  db:
    image: mysql:5.7
    volumes:
      - "./mysql:/var/lib/mysql"
    ports:
      - "3306:3306"
    restart: always
    environment:
      - MYSQL_ROOT_PASSWORD=mypassword
      - MYSQL_DATABASE=django_app

app 容器的 command 指令做了修改,让其在运行前先执行数据迁移;新增了配置 depends_on ,意思是此容器需要等待 db 容器启动完毕才能够启动。

分析一下新添加的 db 容器:

  • image :从仓库拉取 MySQL 5.7 。最新版本为 MySQL 8,不过很坑的是新版本修改了用户登录的验证方法,导致很容易出现无法通过身份验证的问题。教程为了简单起见选用 5.7 版本。后期会在教程示例代码中添加[mysql-8]()分支并给出操作方法,有兴趣的读者可以查看。
  • volumes :定义卷(这里实际是挂载),上一章已经讲过了,它实现了宿主机和容器目录的映射。功能是将容器中的 MySQL 数据映射到宿主机。
  • ports :MySQL 默认通信端口为 3306 。
  • environment :定义容器的环境变量,设置了 MySQL 的 root 用户的密码、数据库的名称。

这里为什么要用?就让数据在容器中、保持隔离不好吗?把数据保存在容器中,理论上确实是可以的,但有一个致命的问题,即数据和容器的生命周期挂钩了:万一哪天手贱把容器给删了,连同里面的数据随风而逝,你就是全公司那个删库跑路的传奇人物了。要知道容器的生命周期可能会非常短暂,删除指令也相当顺滑(docker-compose down)。将数据映射到宿主机,容器即使被删除掉,但数据还是安全的躺在你的服务器中的。换句话说,容器内部非常适合运行无状态的应用;涉及到如数据之类有状态的东西,一定要谨慎思考。

Dockerfile

接下来修改 Dockerfile

FROM python:3.7
ENV PYTHONUNBUFFERED 1

# 添加这两行
RUN apt-get update
RUN apt-get install python3-dev default-libmysqlclient-dev -y

RUN mkdir /code
WORKDIR /code
RUN pip install pip -U
ADD requirements.txt /code/
RUN pip install -r requirements.txt
ADD . /code/

增加的两行代码在系统中安装了 MySQL 的连接器,具体解释见官方文档。

其他配置

修改 requirements.txt ,增加 MySQL 驱动:

django==2.2
mysqlclient==1.3.14

然后还需要修改 django_app/settings.py ,将数据库设置为 MySQL:

DATABASES = {
    ''default'': {
        ''ENGINE'': ''django.db.backends.mysql'',
        ''NAME'': ''django_app'',
        ''USER'': ''root'',
        ''PASSWORD'': ''mypassword'',
        ''HOST'': ''db'',
        ''PORT'': ''3306'',
        ''OPTIONS'': {''charset'': ''utf8mb4''},
    }
}

注意 HOST 填写的是容器的名称,即 db 。

这就可以啦。接下来测试。

测试

测试之前,请先确认没有其他程序占用了 3306 端口,比如宿主机安装的 MySQL。

重新生成镜像:

$ docker-compose build

生成并启动容器:

$ docker-compose up

Creating network "django_app_default" with the default driver
Creating django_app_db_1 ... done
Creating django_app_app_1 ... done
Attaching to django_app_db_1, django_app_app_1
db_1   | 2019-10-06T12:24:57.183860Z 0 [Note] mysqld (mysqld 5.7.27) starting as process 1 ...

...

db_1   | 2019-10-06T12:24:58.120480Z 0 [Note] mysqld: ready for connections.
db_1   | Version: ''5.7.27''  socket: ''/var/run/mysqld/mysqld.sock''  port: 3306  MySQL Community Server (GPL)

app_1  | Operations to perform:
app_1  |   Apply all migrations: admin, auth, contenttypes, sessions
app_1  | Running migrations:
app_1  |   Applying contenttypes.0001_initial... OK
...
app_1  |   Applying sessions.0001_initial... OK

app_1  | Watching for file changes with StatReloader
app_1  | Performing system checks...
app_1  | 
app_1  | System check identified no issues (0 silenced).
app_1  | October 06, 2019 - 12:24:58
app_1  | Django version 2.2, using settings ''django_app.settings''
app_1  | Starting development server at http://0.0.0.0:8000/
app_1  | Quit the server with CONTROL-C.

打开浏览器访问 127.0.0.1:8000 ,又能看到 Django 小火箭啦。

注意:第一次启动容器时可能会出现无法连接 MySQL 的错误,这是由于虽然 db 容器已经启动,但初始化并未完成;重新启动容器之后就可以正常工作了。若多次启动都无法正常工作,那就是别的原因了,好好检查吧。

总结

本章加入了 MySQL 容器,并实现了多容器协同工作。

下一章将实现正式部署的 Docker + Django + MySQL + Nginx + Gunicorn 项目。


  • 有疑问请在杜赛的个人网站留言,我会尽快回复。
  • 教程示例代码:django-docker-tutorial
  • 或Email私信我:dusaiphoto@foxmail.com

我们今天的关于使用 Docker 让部署 Django 项目更加轻松docker部署django应用的分享就到这里,谢谢您的阅读,如果想了解更多关于centos8使用Docker部署Django项目的详细教程、Django ImportError:使用Docker时无法导入Django、Django-Docker容器化部署:Django-Docker-MySQL-Nginx-Gunicorn云端部署、Django-Docker容器化部署:Django-Docker-MySQL部署的相关信息,可以在本站进行搜索。

本文标签: