引子
Nginx足够优秀【Web服务上】
Django也足够优秀【web框架上】
环境
- centos7
- docker 17
- docker-compose 1.17
- Django 1.11
- nginx 1.11
目的
想搭建一个环境,让自己的web程序可以很方便的移植到服务器上
所以要用到Docker
艰难的配置
先给出架设最后的文件列表结构
~/django-web 根目录
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| ├── docker-compose.yml ├── nginx │ ├── conf.d │ │ └── hProj.conf │ ├── Dockerfile │ ├── html │ │ └── index.htm │ └── log │ ├── access.log │ ├── error.log │ ├── hProj.access.log │ └── hProj.error.log ├── production.yml ├── README.md └── web ├── db.sqlite3 ├── Dockerfile ├── helloworld │ ├── admin.py │ ├── apps.py │ ├── __init__.py │ ├── migrations │ ├── models.py │ ├── __pycache__ │ ├── tests.py │ └── views.py ├── hProj │ ├── __init__.py │ ├── __pycache__ │ ├── settings.py │ ├── urls.py │ └── wsgi.py ├── manage.py └── requirements.txt
|
用的是Django
所以先创建一个 Django 的 Dockerfile
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| # 基于Python 版本 FROM python:3 # 设置Python环境 ENV PYTHONUNBUFFERED 1
# 创建一个Code文件夹作为工作目录,将python库的需求文件拷贝进来 RUN mkdir /code ADD requirements.txt /code/
#以/code文件夹作为工作目录 WORKDIR /code
#执行安装库的脚本,这里考虑到默认库下载很慢,使用阿里云的镜像安装 RUN pip install --trusted-host mirrors.aliyun.com -i http://mirrors.aliyun.com/pypi/simple -r requirements.txt
|
requirements.txt【库信息】
1 2 3 4
| Django>=1.8,<2.0 gunicorn>=19,<21 uwsgi psycopg2
|
接下来需要使用Docker-compose
这是一个管理多Docker容器的工具,可以很方便管理多容器
docker-compose.yml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| version: '3'
services: nginx: image: nginx:latest ports: - "8000:80" - "3000:443" volumes: - ./nginx/conf.d:/etc/nginx/conf.d - ./nginx/html:/usr/share/nginx/html - ./nginx/log:/var/log/nginx depends_on: - web links: - web container_name: ng01
db: image: postgres container_name: ps01
web: build: ./web container_name: dg01 command: uwsgi -s :3031 -w hProj.wsgi -p 3 volumes: - ./web:/code expose: - "3031" depends_on: - db
|
这个里面有太多东西了
慢慢说:
version: ‘3’
表示Docker-compose 文件的解析版本
services Docker服务节点
这里面创建了三个节点
nginx : web服务用
db: 数据库用
web:web app处理逻辑
- 对nginx
image 表示选用什么镜像版本,这里是最新的Nginx
ports 表示端口映射 暴露容器端口到主机的任意端口或指定端口,用法:
1 2 3 4
| ports: - "8000:80" # 绑定容器的80端口到主机的8000端口 - "3000:1001" # 绑定容器的1001端口到主机的3000端口 - "443" # 绑定容器的443端口到主机的任意端口,容器启动时随机分配绑定的主机端口号
|
这里需要 注意 ports 和 expose 区别
expose暴露容器给link到当前容器的容器,用法:
1 2 3
| expose: - "3000" - "8000"
|
以上指令将当前容器的端口3000和8000暴露给link到本容器的容器。
和ports的区别是,expose不会将端口暴露给主机。
expose 一般可与 link 一起使用
link :
在消费和服务容器之间创建链接
这会创建一系列环境变量,并且在/etc/hosts 文件中添加入口项
volumes 是什么?
相当于U盘,可以挂载数据,让主机数据挂载到容器上
depends_on 标签表示依赖,决定容器创建启动的先后顺序,决的是启动顺序问题
例如下面容器会先启动 redis 和 db 两个服务,最后才启动 web 服务:
1 2 3 4 5 6 7 8 9 10 11
| version: '2' services: web: build: . depends_on: - db - redis redis: image: redis db: image: postgres
|
注意的是,默认情况下使用 docker-compose up web 这样的方式启动 web 服务时,也会启动 redis 和 db 两个服务,因为在配置文件中定义了依赖关系。
links: 这个标签解决的是容器连接问题,会连接到其它服务中的容器。
格式如下:
1 2 3 4
| links: - db - db:database - redis
|
使用的别名将会自动在服务容器中的/etc/hosts里创建。例如:
1 2 3
| 172.12.2.186 db 172.12.2.186 database 172.12.2.187 redis
|
最后一项比较容易,是指命名容器
这个时候最好先测试下
docker-compose.yml
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| version: '3'
services: nginx: image: nginx:latest ports: - "8000:80" - "3000:443" volumes: - ./nginx/conf.d:/etc/nginx/conf.d - ./nginx/html:/usr/share/nginx/html - ./nginx/log:/var/log/nginx container_name: ng01
|
使用
然后访问
1 2
| [root@localhost django_web]# curl 127.0.0.1:8000 curl: (56) Recv failure: Connection reset by peer
|
Why?
百度了一下没找到原因
没办法直接进容器去看
1 2
| docker exec -it ng01 bash cat /etc/nginx/nginx.conf
|
应该是没有配置默认网站信息
退出容器,添加网站配置
1 2 3 4
| echo "hello">nginx/html/index.htm
vi nginx/conf.d/hProj.conf
|
nginx/conf.d/hProj.conf
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| server { listen 80; server_name 172.20.1.7; #server_name localhost;
access_log /var/log/nginx/hProj.access.log; error_log /var/log/nginx/hProj.error.log;
location / { root /usr/share/nginx/html; index index.html index.htm; } access_log off; }
|
然后访问
1 2 3
| [root@localhost django_web]# curl 127.0.0.1:8000 hello
|
测试通过
接下来说Django
build: 标签标识使用 Dockerfile 建立容器
接下来
测试django 项目创建是否有问题
1 2 3 4 5 6 7 8 9 10 11
| version: '3'
services: web: build: ./web container_name: dg01 command: python3 manage.py runserver 0.0.0.0:8000 volumes: - ./web:/code ports: - "8000:8000"
|
创建项目
1
| docker-compose run web django-admin.py startproject django_example .
|
如果不Ok,请检查Dockerfile
接下来启动web服务
1 2 3
| docker-compose stop docker-compose rm docker-compose up -d
|
然后访问
1
| [root@localhost django_web]# curl 127.0.0.1:8000
|
如果被拒绝请对应找原因,这里我没有被卡住
最重要的怎么将Django项目和 Nginx结合起来
这里使用 gunicorn 或者 uwsgi
简单说,这两个东西相当于在 web 和 nginx中间加了一层,所以一定会有数据传输,为什么要用这里不讨论
数据传输最简单就是 Socket,就会有 IP:PORT
修改 docker-compose.yml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| version: '3' services: nginx: image: nginx:latest ports: - "8000:80" - "3000:443" volumes: - ./nginx/conf.d:/etc/nginx/conf.d - ./nginx/html:/usr/share/nginx/html - ./nginx/log:/var/log/nginx depends_on: - web links: - web container_name: ng01
web: build: ./web container_name: dg01 command: uwsgi -s :3031 -w hProj.wsgi -p 3 volumes: - ./web:/code expose: - "3031"
|
这里主要做 两件事
将命令换成 uwsgi ,换成这个命令以后,无法使用Web访问,所以这里无法测试
将端口从暴露给主机到不暴露给主机
将ports 写法改成 expose
需要注意在nginx 容器里面需要加上 links 属性,这里要特别注意
接下来需要修改 nginx的配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| upstream uwsgicluster { server web:3031; } server { listen 80; server_name localhost;
access_log /var/log/nginx/hProj.access.log; error_log /var/log/nginx/hProj.error.log;
location / { uwsgi_pass uwsgicluster; include /etc/nginx/uwsgi_params; } access_log off; }
|
重新启动
1 2 3
| docker-compose stop docker-compose rm docker-compose up -d
|
测试访问
1
| [root@localhost django_web]# curl 127.0.0.1:8000
|
这里Ok 就结束了,如果有问题,检查下是否那一步不对
关于使用Nginx处理Django静态文件的问题
上述一通操作以后,发现无法使用静态文件了,原因是没有配置~~~
方法太多,这里 我只会一种
由于Django 里面有很多App,可能都用到静态文件了,这样如果每个app下都有一个static,冗余就多了
这里Django 可以收集静态文件,统一放到一个文件下
先设置 settings.py
1 2 3 4
| STATIC_URL = '/static/'
# 新加 STATIC_ROOT = os.path.join(BASE_DIR, 'static')
|
然后收集 静态文件
1
| python manage.py collectstatic
|
收集前结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| [web@localhost web]$ tree -L 2 . ├── db.sqlite3 ├── Dockerfile ├── helloworld │ ├── admin.py │ ├── apps.py │ ├── __init__.py │ ├── migrations │ ├── models.py │ ├── __pycache__ │ ├── serializers.py │ ├── templates │ ├── tests.py │ └── views.py ├── hProj │ ├── __init__.py │ ├── __pycache__ │ ├── settings.py │ ├── urls.py │ └── wsgi.py ├── manage.py └── requirements.txt
|
收集后结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| [web@localhost web]$ tree -L 2 . ├── db.sqlite3 ├── Dockerfile ├── helloworld │ ├── admin.py │ ├── apps.py │ ├── __init__.py │ ├── migrations │ ├── models.py │ ├── __pycache__ │ ├── serializers.py │ ├── templates │ ├── tests.py │ └── views.py ├── hProj │ ├── __init__.py │ ├── __pycache__ │ ├── settings.py │ ├── urls.py │ └── wsgi.py ├── manage.py ├── requirements.txt └── static ├── admin └── rest_framework
|
设置修改 Docker-compose Nginx选项
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| nginx: image: nginx:latest ports: - "80:80" - "8001:8001" - "443:443" volumes: - ./web:/usr/share/nginx/web - ./nginx/conf.d:/etc/nginx/conf.d - ./nginx/html:/usr/share/nginx/html - ./nginx/log:/var/log/nginx depends_on: - web links: - web container_name: ng01
|
修改 nginx 配置 hProj.conf
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| upstream uwsgicluster { #server unix:///tmp/uwsgi.sock; server web:3031; } server { listen 80; server_name localhost;
access_log /var/log/nginx/hProj.access.log; error_log /var/log/nginx/hProj.error.log; location /static { alias /usr/share/nginx/web/static; } location / { #root /usr/share/nginx/html; #index index.html index.htm; uwsgi_pass uwsgicluster; include /etc/nginx/uwsgi_params; #uwsgi_pass 127.0.0.1:8077; #uwsgi_param UWSGI_SCRIPT index; #uwsgi_param UWSGI_PYHOME $document_root; #uwsgi_param UWSGI_CHDIR $document_root; } access_log off; }
|
测试下就OK