- Check the project before going live.
python manage.py check --deploy- Set
DEBUGtoFalseand configureALLOWED_HOSTS.
DEBUG = False
ALLOWED_HOSTS = ['*']- Security-related configuration.
# How long to keep HTTPS connections
SECURE_HSTS_SECONDS = 3600
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_HSTS_PRELOAD = True
# Automatically redirect to secure connections
SECURE_SSL_REDIRECT = True
# Avoid letting the browser guess the content type by itself
SECURE_CONTENT_TYPE_NOSNIFF = True
# Avoid cross-site scripting attacks
SECURE_BROWSER_XSS_FILTER = True
# Cookies can only be sent through HTTPS
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
# Prevent clickjacking by changing the HTTP response header
# The current website does not allow loading with an <iframe> tag
X_FRAME_OPTIONS = 'DENY'- Put sensitive information into environment variables or files.
SECRET_KEY = os.environ['SECRET_KEY']
DB_USER = os.environ['DB_USER']
DB_PASS = os.environ['DB_PASS']
REDIS_AUTH = os.environ['REDIS_AUTH']Note: If you need to remove a previous installation, just delete the related files and folders.
- Install low-level dependency libraries.
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- Download Python source code.
wget https://www.python.org/ftp/python/3.7.6/Python-3.7.6.tar.xz- Verify the downloaded file.
md5sum Python-3.7.6.tar.xz- Unzip and extract.
xz -d Python-3.7.6.tar.xz
tar -xvf Python-3.7.6.tar- Run configuration before installation and generate the
Makefile.
cd Python-3.7.6
./configure --prefix=/usr/local/python37 --enable-optimizations- Build and install.
make && make install- Configure the
PATHenvironment variable and activate it.
vim ~/.bash_profile
vim /etc/profileexport PATH=$PATH:/usr/local/python37/binsource ~/.bash_profile
source /etc/profile- Register a soft link. This step is not required, but it is often useful.
ln -s /usr/local/python37/bin/python3 /usr/bin/python3- Test whether the Python environment was updated successfully. Installing Python 3 must not damage the original Python 2.
python3 --version
python --versionSuppose the project folder is project. The five subdirectories code, conf, logs, stat, and venv are used to save project code, configuration files, log files, static resources, and the virtual environment. The subdirectory cert under conf stores the certificate and key used for HTTPS. The project code under code can be checked out from a code repository by a version control tool. The virtual environment can be created with tools such as venv, virtualenv, and pyenv.
project
├── code
│ └── fangtx
│ ├── api
│ ├── common
│ ├── fangtx
│ ├── forum
│ ├── rent
│ ├── user
│ ├── manage.py
│ ├── README.md
│ ├── static
│ └── templates
├── conf
│ ├── cert
│ ├── nginx.conf
│ └── uwsgi.ini
├── logs
├── stat
└── venv
Below, Aliyun is used as an example to briefly explain how to register a domain name, resolve the domain name, and buy a certificate issued by an authority.
You can use a tool similar to sftp to upload the certificate to the conf/cert directory, and then use git clone to put the project code into the code directory.
cd code
git clone <url>Go back to the project directory, create the virtual environment, and activate it.
python3 -m venv venv
source venv/bin/activateRebuild project dependencies.
pip install -r code/teamproject/requirements.txt- Install
uWSGI.
pip install uwsgi- Modify the
uWSGIconfiguration file/root/project/conf/uwsgi.ini.
[uwsgi]
# Base path
base=/root/project
# Project name
name=teamproject
# Daemon process
master=true
# Number of processes
processes=4
# Virtual environment
pythonhome=%(base)/venv
# Project path
chdir=%(base)/code/%(name)
# Python interpreter
pythonpath=%(pythonhome)/bin/python
# uwsgi file
module=%(name).wsgi
# Address and port for communication
socket=172.18.61.250:8000
# Log file path
logto=%(base)/logs/uwsgi.logNote: You can first change the item before the equals sign for communication address and port from
sockettohttpfor testing. If there is no problem, change it back tosocket, and then use Nginx to separate dynamic and static content. Static resources are handled by Nginx, and dynamic content is handled by uWSGI.
- Start the server.
nohup uwsgi --ini conf/uwsgi.ini &- Install Nginx.
yum -y install nginx- Modify the global configuration file
/etc/nginx/nginx.conf.
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
include /usr/share/nginx/modules/*.conf;
events {
use epoll;
worker_connections 1024;
}
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;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 30;
types_hash_max_size 2048;
include /etc/nginx/mime.types;
default_type application/octet-stream;
include /etc/nginx/conf.d/*.conf;
include /root/project/conf/*.conf;
}- Edit the local configuration file
/root/project/conf/nginx.conf.
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;
}
}At this point, you can start Nginx to access the application. Both HTTP and HTTPS can work normally. If Nginx is already running, after changing the configuration file, you can restart it with the following command.
- Restart the Nginx server.
nginx -s reloador
systemctl restart nginxNote: You can use the command
python manage.py collectstaticin a Django project to collect static resources into a specified directory. To do this, you only need to addSTATIC_ROOTin the project'ssettings.py.
In the configuration below, Nginx is used for load balancing and provides reverse proxy service for three other Nginx servers created through Docker.
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:latestuser 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 {
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_buffering off;
proxy_pass http://fangtx;
}
}
}Note: When Nginx is configured for load balancing, it uses WRR, weighted round robin, by default. In addition, it also supports
ip_hash,fair, andurl_hash. When configuring theupstreammodule, you can also specify server status values such asbackup,down,fail_timeout,max_fails, andweight.
When Nginx is used for load balancing, the possibility that the load-balancing server itself may go down must also be considered. For this, Keepalived can be used to switch between the primary and standby load-balancing hosts, so the system can keep high availability. Keepalived configuration is relatively complex and is usually handled by specialized operations staff.
Below, Docker is still used to show how to configure MySQL master-slave replication. First prepare the MySQL configuration files and the directories that save MySQL data and runtime logs. Then use Docker volume mapping to specify where the container configuration, data, and log files are stored.
root
└── mysql
├── master
│ ├── conf
│ └── data
├── slave-1
│ ├── conf
│ └── data
├── slave-2
│ ├── conf
│ └── data
└── slave-3
├── conf
└── data
- MySQL configuration file. The master and slave configuration files need different
server-idvalues.
[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- Create and configure the master.
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/bashgrant replication slave on *.* to 'slave'@'%' identified by 'iamslave';
flush privileges;
show master status;The -v parameter used above means mapping a data volume. The directory before the colon is a directory on the host machine, and the directory after the colon is a directory inside the container. This is equal to mounting the directory on the host machine into the container.
- Back up the data in the master tables if necessary.
flush table with read lock;mysqldump -u root -p 123456 -A -B > /root/backup/mysql/mybak$(date +"%Y%m%d%H%M%S").sqlunlock table;- Create and configure the slaves.
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.7reset slave;
change master to master_host='mysql-master', master_user='slave', master_password='iamslave', master_log_file='mysql-bin.000003', master_log_pos=590;
start slave;
show slave status\GYou can configure slave2 and slave3 in the same way, and then build a one-master-three-slaves replication environment. The --link parameter used when creating the container is used to configure the host name of the container on the network.
After replication is configured, write operations should be done on the master, and read operations should be done on the slaves. For this reason, in a Django project, DATABASE_ROUTERS needs to be configured, and a custom master-slave router class is used to implement read-write separation.
DATABASE_ROUTERS = [
'common.routers.MasterSlaveRouter',
]class MasterSlaveRouter(object):
"""Master-slave replication router."""
@staticmethod
def db_for_read(model, **hints):
return random.choice(('slave1', 'slave2', 'slave3'))
@staticmethod
def db_for_write(model, **hints):
return 'default'
@staticmethod
def allow_relation(obj1, obj2, **hints):
return None
@staticmethod
def allow_migrate(db, app_label, model_name=None, **hints):
return TrueIn fact, the most troublesome thing when a project goes live is configuring the software runtime environment. Differences between environments bring many troubles to software installation and deployment, and Docker can solve this problem. Docker was introduced in previous documents. Here we add some necessary knowledge.
- Create an image file.
Save a container as an image:
docker commit -m "..." -a "jackfrued" <container-name> jackfrued/<image-name>Build an image with a 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.shdocker build -t jackfrued/<image-name> .- Import and export images.
docker save -o <file-name>.tar <image-name>:<version>
docker load -i <file-name>.tar- Push to DockerHub.
docker tag <image-name>:<version> jackfrued/<name>
docker login
docker push jackfrued/<name>- Communication between containers.
docker run --link <container-name>:<alias-name>If deployment can be completed inside Docker, and the fully deployed container can be packed into an image file for distribution and installation, then the troubles that may appear when deploying the project on multiple nodes can be solved, and the whole deployment can be finished in a short time.
Supervisor is a process management tool written in Python. It can conveniently start, restart, and close processes on Unix-like systems. Supervisor does not currently support Python 3 directly, so Python 2 can be used to install and run Supervisor, and then Supervisor can be used to manage Python 3 programs.
- Install Supervisor.
virtualenv -p /usr/bin/python venv
source venv/bin/activate
pip install supervisor- Check the Supervisor configuration file.
vim /etc/supervisord.conf[include]
files = supervisord.d/*.iniThis shows that custom management configuration can be put in the /etc/supervisord.d directory, and the file name only needs to use the ini suffix.
- Write your own configuration file
fangtx.iniand place it in/etc/supervisord.d.
[program:project]
command=uwsgi --ini /root/project/conf/uwsgi.ini
stopsignal=QUIT
autostart=true
autorestart=true
redirect_stderr=true
[program:celery]
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
killasgroup=true
priority=1000- Start Supervisor.
supervisorctl -c /etc/supervisord.conf- Common open-source software.
| Function | Open-source solution |
|---|---|
| Version control tool | Git, Mercurial, SVN |
| Defect management | Redmine, Mantis |
| Load balancing | Nginx, LVS, HAProxy |
| Mail service | Postfix, Sendmail |
| HTTP service | Nginx, Apache |
| Message queue | RabbitMQ, ZeroMQ, Redis, Kafka |
| File system | FastDFS |
| Location-based service | MongoDB, Redis |
| Monitoring service | Nagios, Zabbix |
| Relational database | MySQL, PostgreSQL |
| Non-relational database | MongoDB, Redis, Cassandra, TiDB |
| Search engine | ElasticSearch, Solr |
| Cache service | Memcached, Redis |
- Common cloud services.
| Function | Available cloud service |
|---|---|
| Team collaboration tool | Teambition, DingTalk |
| Code hosting platform | GitHub, Gitee, CODING |
| Mail service | SendCloud |
| Cloud storage (CDN) | Qiniu, OSS, LeanCloud, Bmob, 又拍云, S3 |
| Mobile push | Jiguang, Umeng, Baidu |
| Instant messaging | Huanxin, Rongyun |
| SMS service | Yunpian, Jiguang, Luosimao, 又拍云 |
| Third-party login | Umeng, ShareSDK |
| Website monitoring and statistics | Aliyun Monitoring, 监控宝, Baidu Cloud Observation, Xiaoniaoyun |




