884 lines
27 KiB
Markdown
884 lines
27 KiB
Markdown
## 项目部署上线指南
|
||
|
||
### 准备上线
|
||
|
||
1. 上线前的检查工作。
|
||
|
||
```Shell
|
||
python manage.py check --deploy
|
||
```
|
||
|
||
2. 将DEBUG设置为False并配置ALLOWED_HOSTS。
|
||
|
||
```Python
|
||
DEBUG = False
|
||
ALLOWED_HOSTS = ['*']
|
||
```
|
||
|
||
3. 安全相关的配置。
|
||
|
||
```Python
|
||
# 保持HTTPS连接的时间
|
||
SECURE_HSTS_SECONDS = 3600
|
||
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
|
||
SECURE_HSTS_PRELOAD = True
|
||
|
||
# 自动重定向到安全连接
|
||
SECURE_SSL_REDIRECT = True
|
||
|
||
# 避免浏览器自作聪明推断内容类型
|
||
SECURE_CONTENT_TYPE_NOSNIFF = True
|
||
|
||
# 避免跨站脚本攻击
|
||
SECURE_BROWSER_XSS_FILTER = True
|
||
|
||
# COOKIE只能通过HTTPS进行传输
|
||
SESSION_COOKIE_SECURE = True
|
||
CSRF_COOKIE_SECURE = True
|
||
|
||
# 防止点击劫持攻击手段 - 修改HTTP协议响应头
|
||
# 当前网站是不允许使用<iframe>标签进行加载的
|
||
X_FRAME_OPTIONS = 'DENY'
|
||
```
|
||
|
||
4. 敏感信息放到环境变量或文件中。
|
||
|
||
```Python
|
||
SECRET_KEY = os.environ['SECRET_KEY']
|
||
|
||
DB_USER = os.environ['DB_USER']
|
||
DB_PASS = os.environ['DB_PASS']
|
||
|
||
REDIS_AUTH = os.environ['REDIS_AUTH']
|
||
```
|
||
|
||
### 更新服务器Python环境到3.x
|
||
|
||
> 说明:如果需要清除之前的安装,就删除对应的文件和文件夹即可
|
||
|
||
1. 安装底层依赖库。
|
||
|
||
```Shell
|
||
yum -y install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel gdbm-devel libdb4-devel libpcap-devel xz-devel libffi-devel libxml2
|
||
```
|
||
|
||
2. 下载Python源代码。
|
||
|
||
```Shell
|
||
wget https://www.python.org/ftp/python/3.7.6/Python-3.7.6.tar.xz
|
||
```
|
||
|
||
3. 验证下载文件。
|
||
|
||
```Bash
|
||
md5sum Python-3.7.6.tar.xz
|
||
```
|
||
|
||
4. 解压缩和解归档。
|
||
|
||
```Shell
|
||
xz -d Python-3.7.6.tar.xz
|
||
tar -xvf Python-3.7.6.tar
|
||
```
|
||
|
||
5. 执行安装前的配置(生成Makefile文件)。
|
||
|
||
```Shell
|
||
cd Python-3.7.6
|
||
./configure --prefix=/usr/local/python37 --enable-optimizations
|
||
```
|
||
|
||
6. 构建和安装。
|
||
|
||
```Shell
|
||
make && make install
|
||
```
|
||
|
||
7. 配置PATH环境变量(用户或系统环境变量)并激活。
|
||
|
||
```Shell
|
||
vim ~/.bash_profile
|
||
vim /etc/profile
|
||
```
|
||
|
||
```INI
|
||
... 此处省略上面的代码...
|
||
|
||
export PATH=$PATH:/usr/local/python37/bin
|
||
|
||
... 此处省略下面的代码...
|
||
```
|
||
|
||
```Shell
|
||
source ~/.bash_profile
|
||
source /etc/profile
|
||
```
|
||
|
||
8. 注册软链接(符号链接)- 这一步不是必须的,但通常会比较有用。
|
||
|
||
```Shell
|
||
ln -s /usr/local/python37/bin/python3 /usr/bin/python3
|
||
```
|
||
|
||
9. 测试Python环境是否更新成功(安装Python 3一定不能破坏原来的Python 2)。
|
||
|
||
```Shell
|
||
python3 --version
|
||
python --version
|
||
```
|
||
|
||
### 项目目录结构
|
||
|
||
假设项目文件夹为`project`,下面的五个子目录分别是:`code`、`conf`、`logs`、`stat`和`venv`分别用来保存项目的代码、配置文件、日志文件、静态资源和虚拟环境。其中,`conf`目录下的子目录`cert`中保存了配置HTTPS需要使用的证书和密钥;`code`目录下的项目代码可以通过版本控制工具从代码仓库中检出;虚拟环境可以通过工具(如:venv、virtualenv、pyenv等)进行创建。
|
||
|
||
```
|
||
project
|
||
├── code
|
||
│ └── fangtx
|
||
│ ├── api
|
||
│ ├── common
|
||
│ ├── fangtx
|
||
│ ├── forum
|
||
│ ├── rent
|
||
│ ├── user
|
||
│ ├── manage.py
|
||
│ ├── README.md
|
||
│ ├── static
|
||
│ └── templates
|
||
├── conf
|
||
│ ├── cert
|
||
│ │ ├── 214915882850706.key
|
||
│ │ └── 214915882850706.pem
|
||
│ ├── nginx.conf
|
||
│ └── uwsgi.ini
|
||
├── logs
|
||
│ ├── access.log
|
||
│ ├── error.log
|
||
│ └── uwsgi.log
|
||
├── stat
|
||
│ └── css
|
||
│ └── images
|
||
│ └── js
|
||
└── venv
|
||
├── bin
|
||
│ ├── activate
|
||
│ ├── activate.csh
|
||
│ ├── activate.fish
|
||
│ ├── celery
|
||
│ ├── celerybeat
|
||
│ ├── celeryd
|
||
│ ├── celeryd-multi
|
||
│ ├── coverage
|
||
│ ├── coverage3
|
||
│ ├── coverage-3.7
|
||
│ ├── django-admin
|
||
│ ├── django-admin.py
|
||
│ ├── easy_install
|
||
│ ├── easy_install-3.7
|
||
│ ├── pip
|
||
│ ├── pip3
|
||
│ ├── pip3.7
|
||
│ ├── __pycache__
|
||
│ ├── pyrsa-decrypt
|
||
│ ├── pyrsa-decrypt-bigfile
|
||
│ ├── pyrsa-encrypt
|
||
│ ├── pyrsa-encrypt-bigfile
|
||
│ ├── pyrsa-keygen
|
||
│ ├── pyrsa-priv2pub
|
||
│ ├── pyrsa-sign
|
||
│ ├── pyrsa-verify
|
||
│ ├── python -> python3
|
||
│ ├── python3 -> /usr/bin/python3
|
||
│ └── uwsgi
|
||
├── include
|
||
├── lib
|
||
│ └── python3.7
|
||
├── lib64 -> lib
|
||
├── pip-selfcheck.json
|
||
└── pyvenv.cfg
|
||
```
|
||
|
||
下面以阿里云为例,简单说明如何为项目注册域名、解析域名以及购买权威机构颁发的证书。
|
||
|
||
1. [注册域名](https://wanwang.aliyun.com/domain/)。
|
||
|
||
![](./res/aliyun-domain.png)
|
||
|
||
2. [域名备案](https://beian.aliyun.com/)。
|
||
|
||
![](./res/aliyun-keeprecord.png)
|
||
|
||
3. [域名解析](https://dns.console.aliyun.com/#/dns/domainList)。
|
||
|
||
![](./res/aliyun-dnslist.png)
|
||
|
||
![](./res/aliyun-resolve-settings.png)
|
||
|
||
4. [购买证书](https://www.aliyun.com/product/cas)。
|
||
|
||
![](./res/aliyun-certificate.png)
|
||
|
||
可以使用类似于sftp的工具将证书上传到`conf/cert`目录,然后使用git克隆项目代码到`code`目录。
|
||
|
||
```Shell
|
||
cd code
|
||
git clone <url>
|
||
```
|
||
|
||
回到项目目录,创建并激活虚拟环境。
|
||
|
||
```Shell
|
||
python3 -m venv venv
|
||
source venv/bin/activate
|
||
```
|
||
|
||
重建项目依赖项。
|
||
|
||
```Shell
|
||
pip install -r code/teamproject/requirements.txt
|
||
```
|
||
|
||
### uWSGI的配置
|
||
|
||
1. 安装uWSGI。
|
||
|
||
```Shell
|
||
pip install uwsgi
|
||
```
|
||
|
||
2. 修改uWSGI的配置文件(`/root/project/conf/uwsgi.ini`)。
|
||
|
||
```INI
|
||
[uwsgi]
|
||
# 配置前导路径
|
||
base=/root/project
|
||
# 配置项目名称
|
||
name=teamproject
|
||
# 守护进程
|
||
master=true
|
||
# 进程个数
|
||
processes=4
|
||
# 虚拟环境
|
||
pythonhome=%(base)/venv
|
||
# 项目地址
|
||
chdir=%(base)/code/%(name)
|
||
# 指定python解释器
|
||
pythonpath=%(pythonhome)/bin/python
|
||
# 指定uwsgi文件
|
||
module=%(name).wsgi
|
||
# 通信的地址和端口(自己服务器的IP地址和端口)
|
||
socket=172.18.61.250:8000
|
||
# 日志文件地址
|
||
logto=%(base)/logs/uwsgi.log
|
||
```
|
||
|
||
> 说明:可以先将“通信的地址和端口”项等号前面改为http来进行测试,如果没有问题再改回 成socket,然后通过Nginx来实现项目的“动静分离”(静态资源交给Nginx处理,动态内容交给 uWSGI处理)。按照下面的方式可以启动uWSGI服务器。
|
||
|
||
5. 启动服务器。
|
||
|
||
```Shell
|
||
nohup uwsgi --ini conf/uwsgi.ini &
|
||
```
|
||
|
||
### Nginx的配置
|
||
|
||
1. 安装Nginx。
|
||
|
||
```Shell
|
||
yum -y install nginx
|
||
```
|
||
|
||
2. 修改全局配置文件(`/etc/nginx/nginx.conf`)。
|
||
|
||
```Nginx
|
||
# 配置用户
|
||
user nginx;
|
||
# 工作进程数(建议跟CPU的核数量一致)
|
||
worker_processes auto;
|
||
# 错误日志
|
||
error_log /var/log/nginx/error.log;
|
||
# 进程文件
|
||
pid /run/nginx.pid;
|
||
# 包含其他的配置
|
||
include /usr/share/nginx/modules/*.conf;
|
||
# 工作模式(多路IO复用方式)和连接上限
|
||
events {
|
||
use epoll;
|
||
worker_connections 1024;
|
||
}
|
||
# HTTP服务器相关配置
|
||
http {
|
||
# 日志格式
|
||
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||
'$status $body_bytes_sent "$http_referer" '
|
||
'"$http_user_agent" "$http_x_forwarded_for"';
|
||
# 访问日志
|
||
access_log /var/log/nginx/access.log main;
|
||
# 开启高效文件传输模式
|
||
sendfile on;
|
||
# 用sendfile传输文件时有利于改善性能
|
||
tcp_nopush on;
|
||
# 禁用Nagle来解决交互性问题
|
||
tcp_nodelay on;
|
||
# 客户端保持连接时间
|
||
keepalive_timeout 30;
|
||
types_hash_max_size 2048;
|
||
# 包含MIME类型的配置
|
||
include /etc/nginx/mime.types;
|
||
# 默认使用二进制流格式
|
||
default_type application/octet-stream;
|
||
# 包含其他配置文件
|
||
include /etc/nginx/conf.d/*.conf;
|
||
# 包含项目的Nginx配置文件
|
||
include /root/project/conf/*.conf;
|
||
}
|
||
```
|
||
|
||
3. 编辑局部配置文件(`/root/project/conf/nginx.conf`)。
|
||
|
||
```Nginx
|
||
server {
|
||
listen 80;
|
||
server_name _;
|
||
access_log /root/project/logs/access.log;
|
||
error_log /root/project/logs/error.log;
|
||
location / {
|
||
include uwsgi_params;
|
||
uwsgi_pass 172.18.61.250:8000;
|
||
}
|
||
location /static/ {
|
||
alias /root/project/stat/;
|
||
expires 30d;
|
||
}
|
||
}
|
||
server {
|
||
listen 443;
|
||
server_name _;
|
||
ssl on;
|
||
access_log /root/project/logs/access.log;
|
||
error_log /root/project/logs/error.log;
|
||
ssl_certificate /root/project/conf/cert/214915882850706.pem;
|
||
ssl_certificate_key /root/project/conf/cert/214915882850706.key;
|
||
ssl_session_timeout 5m;
|
||
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
|
||
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
|
||
ssl_prefer_server_ciphers on;
|
||
location / {
|
||
include uwsgi_params;
|
||
uwsgi_pass 172.18.61.250:8000;
|
||
}
|
||
location /static/ {
|
||
alias /root/project/static/;
|
||
expires 30d;
|
||
}
|
||
}
|
||
```
|
||
|
||
到此为止,我们可以启动Nginx来访问我们的应用程序,HTTP和HTTPS都是没有问题的,如果Nginx已经运行,在修改配置文件后,我们可以用下面的命令重新启动Nginx。
|
||
|
||
4. 重启Nginx服务器。
|
||
|
||
```Shell
|
||
nginx -s reload
|
||
```
|
||
|
||
或
|
||
|
||
```Shell
|
||
systemctl restart nginx
|
||
```
|
||
|
||
> 说明:可以对Django项目使用`python manage.py collectstatic`命令将静态资源收集到指定目录下,要做到这点只需要在项目的配置文件`settings.py`中添加`STATIC_ROOT`配置即可。
|
||
|
||
#### 负载均衡配置
|
||
|
||
下面的配置中我们使用Nginx实现负载均衡,为另外的三个Nginx服务器(通过Docker创建)提供反向代理服务。
|
||
|
||
```Shell
|
||
docker run -d -p 801:80 --name nginx1 nginx:latest
|
||
docker run -d -p 802:80 --name nginx2 nginx:latest
|
||
docker run -d -p 803:80 --name nginx3 nginx:latest
|
||
```
|
||
|
||
```Nginx
|
||
user root;
|
||
worker_processes auto;
|
||
error_log /var/log/nginx/error.log;
|
||
pid /run/nginx.pid;
|
||
|
||
include /usr/share/nginx/modules/*.conf;
|
||
|
||
events {
|
||
worker_connections 1024;
|
||
}
|
||
|
||
# 为HTTP服务配置负载均衡
|
||
http {
|
||
upstream xx {
|
||
server 192.168.1.100 weight=2;
|
||
server 192.168.1.101 weight=1;
|
||
server 192.168.1.102 weight=1;
|
||
}
|
||
|
||
server {
|
||
listen 80 default_server;
|
||
listen [::]:80 default_server;
|
||
listen 443 ssl;
|
||
listen [::]:443 ssl;
|
||
|
||
ssl on;
|
||
access_log /root/project/logs/access.log;
|
||
error_log /root/project/logs/error.log;
|
||
ssl_certificate /root/project/conf/cert/214915882850706.pem;
|
||
ssl_certificate_key /root/project/conf/cert/214915882850706.key;
|
||
ssl_session_timeout 5m;
|
||
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
|
||
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
|
||
ssl_prefer_server_ciphers on;
|
||
|
||
location / {
|
||
proxy_set_header Host $host;
|
||
proxy_set_header X-Forwarded-For $remote_addr;
|
||
# proxy_set_header X-Real-IP $remote_addr;
|
||
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||
proxy_buffering off;
|
||
proxy_pass http://fangtx;
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
> 说明:Nginx在配置负载均衡时,默认使用WRR(加权轮询算法),除此之外还支持ip_hash、fair(需要安装upstream_fair模块)和url_hash算法。此外,在配置upstream模块时可以指定服务器的状态值,包括:backup(备份机器,其他服务器不可用时才将请求分配到该机器)、down、fail_timeout(请求失败达到max_fails后的暂停服务时间)、max_fails(允许请求失败的次数)和weight(轮询的权重)。
|
||
|
||
### Keepalived
|
||
|
||
当使用Nginx进行负载均衡配置时,要考虑负载均衡服务器宕机的情况。为此可以使用Keepalived来实现负载均衡主机和备机的热切换,从而保证系统的高可用性。Keepalived的配置还是比较复杂,通常由专门做运维的人进行配置,一个基本的配置可以参照[《Keepalived的配置和使用》](https://www.jianshu.com/p/dd93bc6d45f5)。
|
||
|
||
### MySQL主从复制
|
||
|
||
下面还是基于Docker来演示如何配置MySQL主从复制。我们事先准备好MySQL的配置文件以及保存MySQL数据和运行日志的目录,然后通过Docker的数据卷映射来指定容器的配置、数据和日志文件的位置。
|
||
|
||
```Shell
|
||
root
|
||
└── mysql
|
||
├── master
|
||
│ ├── conf
|
||
| └── data
|
||
└── slave-1
|
||
| ├── conf
|
||
| └── data
|
||
└── slave-2
|
||
| ├── conf
|
||
| └── data
|
||
└── slave-3
|
||
├── conf
|
||
└── data
|
||
```
|
||
|
||
1. MySQL的配置文件(master和slave的配置文件需要不同的server-id)。
|
||
```
|
||
[mysqld]
|
||
pid-file=/var/run/mysqld/mysqld.pid
|
||
socket=/var/run/mysqld/mysqld.sock
|
||
datadir=/var/lib/mysql
|
||
log-error=/var/log/mysql/error.log
|
||
server-id=1
|
||
log-bin=/var/log/mysql/mysql-bin.log
|
||
expire_logs_days=30
|
||
max_binlog_size=256M
|
||
symbolic-links=0
|
||
# slow_query_log=ON
|
||
# slow_query_log_file=/var/log/mysql/slow.log
|
||
# long_query_time=1
|
||
```
|
||
|
||
2. 创建和配置master。
|
||
|
||
```Shell
|
||
docker run -d -p 3306:3306 --name mysql-master \
|
||
-v /root/mysql/master/conf:/etc/mysql/mysql.conf.d \
|
||
-v /root/mysql/master/data:/var/lib/mysql \
|
||
-e MYSQL_ROOT_PASSWORD=123456 mysql:5.7
|
||
|
||
docker exec -it mysql-master /bin/bash
|
||
```
|
||
|
||
```Shell
|
||
mysql -u root -p
|
||
Enter password:
|
||
Welcome to the MySQL monitor. Commands end with ; or \g.
|
||
Your MySQL connection id is 1
|
||
Server version: 5.7.23-log MySQL Community Server (GPL)
|
||
Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
|
||
Oracle is a registered trademark of Oracle Corporation and/or its
|
||
affiliates. Other names may be trademarks of their respective
|
||
owners.
|
||
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
|
||
|
||
mysql> grant replication slave on *.* to 'slave'@'%' identified by 'iamslave';
|
||
Query OK, 0 rows affected, 1 warning (0.00 sec)
|
||
|
||
mysql> flush privileges;
|
||
Query OK, 0 rows affected (0.00 sec)
|
||
|
||
mysql> show master status;
|
||
+------------------+----------+--------------+------------------+-------------------+
|
||
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
|
||
+------------------+----------+--------------+------------------+-------------------+
|
||
| mysql-bin.000003 | 590 | | | |
|
||
+------------------+----------+--------------+------------------+-------------------+
|
||
1 row in set (0.00 sec)
|
||
|
||
mysql> quit
|
||
Bye
|
||
exit
|
||
```
|
||
|
||
上面创建Docker容器时使用的`-v`参数(`--volume`)表示映射数据卷,冒号前是宿主机的目录,冒号后是容器中的目录,这样相当于将宿主机中的目录挂载到了容器中。
|
||
|
||
3. 备份主表中的数据(如果需要的话)。
|
||
|
||
```SQL
|
||
mysql> flush table with read lock;
|
||
```
|
||
|
||
```Bash
|
||
mysqldump -u root -p 123456 -A -B > /root/backup/mysql/mybak$(date +"%Y%m%d%H%M%S").sql
|
||
```
|
||
|
||
```SQL
|
||
mysql> unlock table;
|
||
```
|
||
|
||
4. 创建和配置slave。
|
||
|
||
```Shell
|
||
docker run -d -p 3308:3306 --name mysql-slave-1 \
|
||
-v /root/mysql/slave-1/conf:/etc/mysql/mysql.conf.d \
|
||
-v /root/mysql/slave-1/data:/var/lib/mysql \
|
||
-e MYSQL_ROOT_PASSWORD=123456 \
|
||
--link mysql-master:mysql-master mysql:5.7
|
||
|
||
docker run -d -p 3309:3306 --name mysql-slave-2 \
|
||
-v /root/mysql/slave-2/conf:/etc/mysql/mysql.conf.d \
|
||
-v /root/mysql/slave-2/data:/var/lib/mysql \
|
||
-e MYSQL_ROOT_PASSWORD=123456 \
|
||
--link mysql-master:mysql-master mysql:5.7
|
||
|
||
docker run -d -p 3310:3306 --name mysql-slave-3 \
|
||
-v /root/mysql/slave-3/conf:/etc/mysql/mysql.conf.d \
|
||
-v /root/mysql/slave-3/data:/var/lib/mysql \
|
||
-e MYSQL_ROOT_PASSWORD=123456 \
|
||
--link mysql-master:mysql-master mysql:5.7
|
||
|
||
docker exec -it mysql-slave-1 /bin/bash
|
||
```
|
||
|
||
```Shell
|
||
mysql -u root -p
|
||
Enter password:
|
||
Welcome to the MySQL monitor. Commands end with ; or \g.
|
||
Your MySQL connection id is 2
|
||
Server version: 5.7.23-log MySQL Community Server (GPL)
|
||
Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
|
||
Oracle is a registered trademark of Oracle Corporation and/or its
|
||
affiliates. Other names may be trademarks of their respective
|
||
owners.
|
||
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
|
||
|
||
mysql> reset slave;
|
||
Query OK, 0 rows affected (0.02 sec)
|
||
|
||
mysql> change master to master_host='mysql-master', master_user='slave', master_password='iamslave', master_log_file='mysql-bin.000003', master_log_pos=590;
|
||
Query OK, 0 rows affected, 2 warnings (0.03 sec)
|
||
|
||
mysql> start slave;
|
||
Query OK, 0 rows affected (0.01 sec)
|
||
|
||
mysql> show slave status\G
|
||
*************************** 1. row ***************************
|
||
Slave_IO_State: Waiting for master to send event
|
||
Master_Host: mysql57
|
||
Master_User: slave
|
||
Master_Port: 3306
|
||
Connect_Retry: 60
|
||
Master_Log_File: mysql-bin.000001
|
||
Read_Master_Log_Pos: 590
|
||
Relay_Log_File: f352f05eb9d0-relay-bin.000002
|
||
Relay_Log_Pos: 320
|
||
Relay_Master_Log_File: mysql-bin.000001
|
||
Slave_IO_Running: Yes
|
||
Slave_SQL_Running: Yes
|
||
Replicate_Do_DB:
|
||
Replicate_Ignore_DB:
|
||
Replicate_Do_Table:
|
||
Replicate_Ignore_Table:
|
||
Replicate_Wild_Do_Table:
|
||
Replicate_Wild_Ignore_Table:
|
||
Last_Errno: 0
|
||
Last_Error:
|
||
Skip_Counter: 0
|
||
Exec_Master_Log_Pos: 590
|
||
Relay_Log_Space: 534
|
||
Until_Condition: None
|
||
Until_Log_File:
|
||
Until_Log_Pos: 0
|
||
Master_SSL_Allowed: No
|
||
Master_SSL_CA_File:
|
||
Master_SSL_CA_Path:
|
||
Master_SSL_Cert:
|
||
Master_SSL_Cipher:
|
||
Master_SSL_Key:
|
||
Seconds_Behind_Master: 0
|
||
Master_SSL_Verify_Server_Cert: No
|
||
Last_IO_Errno: 0
|
||
Last_IO_Error:
|
||
Last_SQL_Errno: 0
|
||
Last_SQL_Error:
|
||
Replicate_Ignore_Server_Ids:
|
||
Master_Server_Id: 1
|
||
Master_UUID: 30c38043-ada1-11e8-8fa1-0242ac110002
|
||
Master_Info_File: /var/lib/mysql/master.info
|
||
SQL_Delay: 0
|
||
SQL_Remaining_Delay: NULL
|
||
Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates
|
||
Master_Retry_Count: 86400
|
||
Master_Bind:
|
||
Last_IO_Error_Timestamp:
|
||
Last_SQL_Error_Timestamp:
|
||
Master_SSL_Crl:
|
||
Master_SSL_Crlpath:
|
||
Retrieved_Gtid_Set:
|
||
Executed_Gtid_Set:
|
||
Auto_Position: 0
|
||
Replicate_Rewrite_DB:
|
||
Channel_Name:
|
||
Master_TLS_Version:
|
||
1 row in set (0.00 sec)
|
||
|
||
mysql> quit
|
||
Bye
|
||
exit
|
||
```
|
||
|
||
接下来可以如法炮制配置出slave2和slave3,这样就可以搭建起一个“一主带三从”的主从复制环境。上面创建创建容器时使用的`--link`参数用来配置容器在网络上的主机名(网络地址别名)。
|
||
|
||
配置好主从复制后,写数据的操作应该master上执行,而读数据的操作应该在slave上完成。为此,在Django项目中需要配置DATABASE_ROUTERS并通过自定义的主从复制路由类来实现读写分离操作,如下所示:
|
||
|
||
```Python
|
||
DATABASE_ROUTERS = [
|
||
# 此处省略其他配置
|
||
'common.routers.MasterSlaveRouter',
|
||
]
|
||
```
|
||
|
||
```Python
|
||
class MasterSlaveRouter(object):
|
||
"""主从复制路由"""
|
||
|
||
@staticmethod
|
||
def db_for_read(model, **hints):
|
||
"""
|
||
Attempts to read auth models go to auth_db.
|
||
"""
|
||
return random.choice(('slave1', 'slave2', 'slave3'))
|
||
|
||
@staticmethod
|
||
def db_for_write(model, **hints):
|
||
"""
|
||
Attempts to write auth models go to auth_db.
|
||
"""
|
||
return 'default'
|
||
|
||
@staticmethod
|
||
def allow_relation(obj1, obj2, **hints):
|
||
"""
|
||
Allow relations if a model in the auth app is involved.
|
||
"""
|
||
return None
|
||
|
||
@staticmethod
|
||
def allow_migrate(db, app_label, model_name=None, **hints):
|
||
"""
|
||
Make sure the auth app only appears in the 'auth_db'
|
||
database.
|
||
"""
|
||
return True
|
||
```
|
||
|
||
上面的内容参考了Django官方文档的[DATABASE_ROUTERS配置](https://docs.djangoproject.com/en/2.1/topics/db/multi-db/#topics-db-multi-db-routing),对代码进行了适当的调整。
|
||
|
||
### Docker
|
||
|
||
事实上,项目上线中最为麻烦的事情就是配置软件运行环境,环境的差异会给软件的安装和部署带来诸多的麻烦,而Docker正好可以解决这个问题。关于Docker在之前的文档中我们已经介绍过了,接下来我们对Docker的知识做一些必要的补充。
|
||
|
||
1. 创建镜像文件。
|
||
|
||
将容器保存成镜像:
|
||
|
||
```Shell
|
||
docker commit -m "..." -a "jackfrued" <container-name> jackfrued/<image-name>
|
||
```
|
||
|
||
使用Dockerfile构建镜像:
|
||
|
||
```Dockerfile
|
||
# 指定基础镜像文件
|
||
FROM centos:latest
|
||
|
||
# 指定维护者信息
|
||
MAINTAINER jackfrued
|
||
|
||
# 执行命令
|
||
RUN yum -y install gcc
|
||
RUN cd ~
|
||
RUN mkdir -p project/code
|
||
RUN mkdir -p project/logs
|
||
|
||
# 拷贝文件
|
||
COPY ...
|
||
|
||
# 暴露端口
|
||
EXPOSE ...
|
||
|
||
# 在容器启动时执行命令
|
||
CMD ~/init.sh
|
||
```
|
||
|
||
```Shell
|
||
docker build -t jackfrued/<image-name> .
|
||
```
|
||
|
||
2. 镜像的导入和导出。
|
||
|
||
```Shell
|
||
docker save -o <file-name>.tar <image-name>:<version>
|
||
docker load -i <file-name>.tar
|
||
```
|
||
|
||
3. 推送到DockerHub服务器。
|
||
|
||
```Shell
|
||
docker tag <image-name>:<version> jackfrued/<name>
|
||
docker login
|
||
docker push jackfrued/<name>
|
||
```
|
||
|
||
4. 容器之间的通信。
|
||
|
||
```Shell
|
||
docker run --link <container-name>:<alias-name>
|
||
```
|
||
|
||
|
||
如果我们能够在Docker中完成项目的部署,并且将整个部署好的容器打包成镜像文件进行分发和安装,这样就可以解决项目在多个节点上进行部署时可能遇到的麻烦,而且整个部署可以在很短的时间内完成。
|
||
|
||
### Supervisor
|
||
|
||
[Supervisor](https://github.com/Supervisor/supervisor)是一个用Python写的进程管理工具,可以很方便的用来在类Unix系统下启动、重启(自动重启程序)和关闭进程,目前Supervisor暂时还没有提供对Python 3的支持,可以通过Python 2来安装和运行Supervisor,再通过Supervisor来管理Python 3的程序。
|
||
|
||
> **提示**:还有一个和Supervisor功能类似的工具名为Circus,支持Python 3。
|
||
|
||
1. 安装Supervisor。
|
||
|
||
```Shell
|
||
virtualenv -p /usr/bin/python venv
|
||
source venv/bin/activate
|
||
pip install supervisor
|
||
```
|
||
|
||
2. 查看Supervisor的配置文件。
|
||
|
||
```Shell
|
||
vim /etc/supervisord.conf
|
||
```
|
||
|
||
```INI
|
||
; 此处省略上面的代码
|
||
; The [include] section can just contain the "files" setting. This
|
||
; setting can list multiple files (separated by whitespace or
|
||
; newlines). It can also contain wildcards. The filenames are
|
||
; interpreted as relative to this file. Included files *cannot*
|
||
; include files themselves.
|
||
[include]
|
||
files = supervisord.d/*.ini
|
||
```
|
||
|
||
可以看出自定义的管理配置代码可以放在`/etc/supervisord.d`目录中,并且文件名以`ini`作为后缀即可。
|
||
|
||
3. 编写自己的配置文件`fangtx.ini`并放在`/etc/supervisord.d`目录中。
|
||
|
||
```INI
|
||
[program:project]
|
||
command=uwsgi --ini /root/project/conf/uwsgi.ini
|
||
stopsignal=QUIT
|
||
autostart=true
|
||
autorestart=true
|
||
redirect_stderr=true
|
||
|
||
[program:celery]
|
||
; Set full path to celery program if using virtualenv
|
||
command=/root/project/venv/bin/celery -A fangtx worker
|
||
user=root
|
||
numprocs=1
|
||
stdout_logfile=/var/log/supervisor/celery.log
|
||
stderr_logfile=/var/log/supervisor/celery_error.log
|
||
autostart=true
|
||
autorestart=true
|
||
startsecs=10
|
||
|
||
; Need to wait for currently executing tasks to finish at shutdown.
|
||
; Increase this if you have very long running tasks.
|
||
;stopwaitsecs = 600
|
||
|
||
; When resorting to send SIGKILL to the program to terminate it
|
||
; send SIGKILL to its whole process group instead,
|
||
; taking care of its children as well.
|
||
killasgroup=true
|
||
; Set Celery priority higher than default (999)
|
||
; so, if rabbitmq is supervised, it will start first.
|
||
priority=1000
|
||
```
|
||
|
||
4. 启动Supervisor。
|
||
|
||
```Shell
|
||
supervisorctl -c /etc/supervisord.conf
|
||
```
|
||
|
||
|
||
### 其他服务
|
||
|
||
1. 常用开源软件。
|
||
|
||
| 功能 | 开源方案 |
|
||
| ------------------- | ------------------------------- |
|
||
| 版本控制工具 | Git、Mercurial、SVN |
|
||
| 缺陷管理 | Redmine、Mantis |
|
||
| 负载均衡 | Nginx、LVS、HAProxy |
|
||
| 邮件服务 | Postfix、Sendmail |
|
||
| HTTP服务 | Nginx、Apache |
|
||
| 消息队列 | RabbitMQ、ZeroMQ、Redis、Kafka |
|
||
| 文件系统 | FastDFS |
|
||
| 基于位置服务(LBS) | MongoDB、Redis |
|
||
| 监控服务 | Nagios、Zabbix |
|
||
| 关系型数据库 | MySQL、PostgreSQL |
|
||
| 非关系型数据库 | MongoDB、Redis、Cassandra、TiDB |
|
||
| 搜索引擎 | ElasticSearch、Solr |
|
||
| 缓存服务 | Mamcached、Redis |
|
||
|
||
2. 常用云服务。
|
||
|
||
| 功能 | 可用的云服务 |
|
||
| -------------- | -------------------------------------- |
|
||
| 团队协作工具 | Teambition、钉钉 |
|
||
| 代码托管平台 | Github、Gitee、CODING |
|
||
| 邮件服务 | SendCloud |
|
||
| 云存储(CDN) | 七牛、OSS、LeanCloud、Bmob、又拍云、S3 |
|
||
| 移动端推送 | 极光、友盟、百度 |
|
||
| 即时通信 | 环信、融云 |
|
||
| 短信服务 | 云片、极光、Luosimao、又拍云 |
|
||
| 第三方登录 | 友盟、ShareSDK |
|
||
| 网站监控和统计 | 阿里云监控、监控宝、百度云观测、小鸟云 |
|
||
|