一、案例描述
现在使用Linux
系统作为服务器已经非常普遍,无论是生态上还是稳定性上Linux
系统都有它独特的优势。那么,如何去配置一套可用并且好用的环境来实现Python Web
项目的部署呢?以Ubuntu
系统为例,下面内容是个人的一些经验总结。
二、案例分析及解决过程
修改
apt
源地址为公司源,进行软件的安装与更新。修改/etc/apt/sources.list
为以下内容:1
2
3
4
5
6
7
8
9
10deb http://mirrors.xxxxxxxx.com.cn/ubuntu/ xenial main restricted universe multiverse
deb http://mirrors.xxxxxxxx.com.cn/ubuntu/ xenial-security main restricted universe multiverse
deb http://mirrors.xxxxxxxx.com.cn/ubuntu/ xenial-updates main restricted universe multiverse
deb http://mirrors.xxxxxxxx.com.cn/ubuntu/ xenial-proposed main restricted universe multiverse
deb http://mirrors.xxxxxxxx.com.cn/ubuntu/ xenial-backports main restricted universe multiverse
deb-src http://mirrors.xxxxxxxx.com.cn/ubuntu/ xenial main restricted universe multiverse
deb-src http://mirrors.xxxxxxxx.com.cn/ubuntu/ xenial-security main restricted universe multiverse
deb-src http://mirrors.xxxxxxxx.com.cn/ubuntu/ xenial-updates main restricted universe multiverse
deb-src http://mirrors.xxxxxxxx.com.cn/ubuntu/ xenial-proposed main restricted universe multiverse
deb-src http://mirrors.xxxxxxxx.com.cn/ubuntu/ xenial-backports main restricted universe multiverse其中
xential
是Ubuntu 16.04
的代号,可替换成其他版本相应的代号。
使用sudo apt update && sudo apt upgrade -y
命令将软件包都更新到最新。
shell
的强化这里使用了
zsh
来替换默认的bash
。zsh
对比bash
有以下优势:兼容
bash
。原来在bash
上面的习惯可以无缝转移过来。更完善的历史记录功能。比如输入
su
按上下箭头,就能翻阅所有执行过的su开头的命令,如sudo -s
,supervisorctl reload
。智能拼写纠错,输入
history | gtep reload
,它会贴心提醒你1
zsh: correct 'gtep' to 'grep' [nyae]?
这时输入
y
就会自动展示history | grep reload
的结果。路径补全、命令补全等功能。只需要按一下或两下
Tab
,就能看到推荐的补全选项,再按Tab
或者ctrl+n/p/f/b
还能在补全选项中上下左右切换。比如要进入/etc/nginx/conf.d
目录,只需输入cd /e/n/c
再按Tab
,系统会自动补全出/etc/nginx/conf.d
。目录跳转强化。输入
d
,就会列出你在这个会话中访问的目录列表,再输入前面的序号,即可直接跳转到该目录。还有在任何目录输入~
都会跳转到主目录,输入.
或者...
都会跳转到上级或上上级目录等等。各种插件的支持。比如
git
插件可以自动识别git
目录,并且识别目录的状态,是否有修改等等。首先查看是否已安装
zsh
。使用命令1
cat /etc/shells
显示如下:
1
2
3
4
5
6
7
8/bin/sh
/bin/dash
/bin/bash
/bin/rbash
/usr/bin/tmux
/usr/bin/screen
/bin/zsh
/usr/bin/zsh如果结果中没有
zsh
,则需要使用命令sudo apt install zsh
先进行安装。其实zsh
只是个基础,我们用oh-my-zsh
来获得最佳的体验。可以使用Github
上面的自动安装脚本,由于网络管控原因我们采用手动安装的方式。先从https://github.com/robbyrussell/oh-my-zsh
下载zip
包并解压,cp
出tools/install.sh
到主目录,修改install.sh
里面的部分内容:1
2
3
4git clone --depth=1 --branch "$BRANCH" "$REMOTE" "$ZSH" || {
error "git clone of oh-my-zsh repo failed"
exit 1
}为
1
mv oh-my-zsh-master ~/.oh-my-zsh
运行
sh install.sh
,会提示你要不要把默认shell
替换成zsh
,选择y
即可,退出shell
重新登录就能使用zsh
了。
使用
pyenv
给不同的项目创建虚拟环境有时候我们需要在一台服务器上面部署多个项目,这时不同项目所依赖的
Python
环境的隔离就尤为必要。下面介绍pyenv
的安装与使用。去
https://github.com/pyenv/pyenv
下载zip
包,解压到~/.pyenv
。
去https://github.com/pyenv/pyenv-virtualenv
下载zip
包,解压至$~/.pyenv/plugins/pyenv-virtualenv
。添加以下三行代码到shell
的环境文件中(如使用zsh
则环境文件是~/.zshrc
)1
2
3export PATH="$HOME/.pyenv/bin:$PATH"
eval "$(pyenv init -)"
eval "$(pyenv virtualenv-init -)"使用命令
1
source ~/.zshrc
来使环境立即生效。
安装
Python
基础版本。比如安装3.6.5
版本作为基础版本,再从这个版本上面创建出虚拟环境。我们可手动下载安装包进行安装,先去Python
官网下载Python-3.6.5.tar.xz
,放至~/.pyenv/cache/
目录下。修改.pyenv/plugins/python-build/share/python-build/3.6.5
文件的以下内容1
install_package "Python-3.6.5" "https://www.python.org/ftp/python/3.6.5/Python-3.6.5.tar.xz#f434053ba1b5c8a5cc597e966ead3c5143012af827fd3f0697d21450bb8d87a6" ldflags_dirs standard verify_py36 copy_python_gdb ensurepip
为
1
install_package "Python-3.6.5" "~/.pyenv/cache/Python-3.6.5.tar.xz" ldflags_dirs standard verify_py36 copy_python_gdb ensurepip
然后运行
pyenv install 3.6.5
就能进行基础版本的安装了。附
pyenv
基本命令介绍:pyenv versions
列出当前所有安装的虚拟环境,前面带*
的是正在使用的环境pyenv virtualenv 3.6.5 my_env
基于3.6.5
基础版本建立一个名为my_env
的虚拟环境pyenv activate my_env
激活my_env
环境,当shell
前面有(my_env)
这样的显示表示当前正在使用虚拟环境pyenv deactivate
退出当前虚拟环境注意需要修改
pip
源地址为公司源,才能使用pip
命令安装包。在主目录~
下面创建.pip/pip.conf
,写入如下内容1
2
3
4
5[global]
timeout = 6000
index-url = http://mirrors.xxxxxxxx.com.cn/python-pypi/simple
[install]
trusted-host = mirrors.xxxxxxxx.com.cn
使用
supervisor
做统一的项目启动管理使用
sudo apt intstall supervisor
安装supervisor
,使用echo_supervisord_conf > /etc/supervisor/supervisord.conf
生成默认配置文件,修改下面几项:1
2
3
4
5
6
7[inet_http_server] ; inet (TCP) server disabled by default
port=0.0.0.0:9001 ; (ip_address:port specifier, *:port for all iface)
username=*** ; (default is no username (open server))
password=******* ; (default is no password (open server))
[include]
files = /etc/supervisor/conf.d/*.conf这样就开启了界面管理,各配置项都可以放到
/etc/supervisor/conf.d/
中,以*.conf
命名。其中username
和password
项是登录界面管理的用户名和密码。去
/etc/supervisor/conf.d/
添加配置文件myproject.conf
1
2
3
4
5
6
7
8[program:myproject]
directory=/home/guo/project/myproject ; 项目目录
command=/home/guo/.pyenv/versions/myproject/bin/gunicorn -w 10 --timeout 60 -b 0.0.0.0:4000 app:app ; 项目使用gunicorn启动在4000端口
autostart=true ; 启动supervisor自动启动
autorestart=true ; 异常退出后自动重启
startretries=10
redirect_stderr=true ; stderr的日志也重定向到stdout地址
stdout_logfile=/var/log/supervisor/myproject.log ; stdout地址使用
service supervisor status
查看supervisor
是否启动。附
supervisor
基本命令介绍:supervisorctl status
查看所有管理的进程的状态supervisorctl stop program_name
关闭program_name
进程supervisorctl start program_name
启动program_name
进程supervisorctl restart program_name
重启program_name
进程supervisorctl stop all
关闭所有进程supervisorctl start all
启动所有进程supervisorctl update
更新新的配置到supervisord
supervisorctl reload
重新启动配置中的所有程序
Nginx
的配置一台服务器上要让多个项目能同时提供服务,各项目需要启动在不同的端口,但这样访问时就需要
ip
或域名
加端口号,使用上来说有不便之处。这里可以通过Nginx
做请求转发,它启动在80
端口,通过项目标识来区分不同项目,转发请求到项目相应的启动端口上。使用
sudo apt install nginx
来进行Nginx
的安装,这样它会以服务的形式启动。默认的配置文件在/etc/nginx/nginx.conf
,配置events
项中使用epoll
模型,1
2
3
4
5events {
use epoll; # 异步非阻塞IO模型
worker_connections 65535;
# multi_accept on;
}配置
http
项中自定义配置文件的位置1
2
3
4http {
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}然后在
/etc/nginx/sites-enabled/
目录下就可以写自己的配置文件了,如下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# configuration of the server
server {
# the port your site will be served on
listen 80;
# the domain name it will serve for
server_name _; # substitute your machine's IP address or FQDN
charset utf-8;
# max upload size
client_max_body_size 75M; # adjust to taste
location /my_project1/ {
add_header Cache-Control no-cache;
proxy_set_header Host 这里替换成服务器IP ;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_pass http://localhost:8000/my_project1/;
}
location /my_project2/ {
add_header Cache-Control no-cache;
proxy_set_header Host 这里替换成服务器IP ;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_pass http://localhost:8001/my_project2/;
}
}假设两个项目的标识分别为
my_project1
和my_project2
,分别启动在端口8000
和8001
上,那么访问服务器IP/my_project1/
路径就能访问到相应的项目服务了。附
Nginx
常用命令介绍:service nginx start
启动Nginx
service nginx status
查看Nginx
状态service nginx reload
重新加载Nginx
配置service nginx restart
重启Nginx
进程
三、经验总结及注意事项
校时。
在拿到服务器后,需要对服务器时间做校正,公司有
10.1.7.88
提供校时服务。使用sudo apt install ntp
安装ntp
服务,修改配置文件/etc/ntp.conf
1
2
3
4
5
6
7
8
9
10
11
12
13driftfile /var/lib/ntp/ntp.drift
# Enable this if you want statistics to be logged.
#statsdir /var/log/ntpstats/
statistics loopstats peerstats clockstats
filegen loopstats file loopstats type day enable
filegen peerstats file peerstats type day enable
filegen clockstats file clockstats type day enable
restrict -4 default kod notrap nomodify nopeer noquery limited
restrict -6 default kod notrap nomodify nopeer noquery limited
# Local users may interrogate the ntp server more closely.
restrict 127.0.0.1
restrict ::1
server 10.1.7.88 iburstservice ntp restart
重启ntp
服务,ntpq -p
查看同步状态,1
2
3remote refid st t when poll reach delay offset jitter
==========================================================================
*hik-dc2.hikvisi 10.1.7.17 5 u 298 1024 377 1.503 -33.461 78.224校时还有可能需要调整时区。先用
date -R
命令查看当前系统时间信息,如果最后面显示的不是+0800
则系统时区需要调整。运行tzselect
,在出现的选项中依次选择Asia
、China
、Beijing
,然后把东八区的时区文件复制到系统时区目录下,1
stt@ubuntu:/$ sudo cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
再次查看时间信息,可以看到已经修改为北京时间。
软件包的安装与更新
定期使用
sudo apt update
从软件源更新最新软件包信息,使用sudo apt upgrade -y
安装最新软件包,使用sudo apt autoremove
自动卸载不需要的软件包。如遇到/boot
分区空间满了无法更新软件包的情况,先使用uname -r
命令查看当前系统内核版本,dpkg --get-selections | grep linux
查看所有安装的系统内核,1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22console-setup-linux install
libselinux1:amd64 install
linux-base install
linux-firmware install
linux-generic install
linux-headers-4.4.0-157 install
linux-headers-4.4.0-157-generic install
linux-headers-4.4.0-159 install
linux-headers-4.4.0-159-generic install
linux-headers-generic install
linux-image-4.4.0-154-generic deinstall
linux-image-4.4.0-157-generic install
linux-image-4.4.0-159-generic install
linux-image-generic install
linux-libc-dev:amd64 install
linux-modules-4.4.0-154-generic deinstall
linux-modules-4.4.0-157-generic install
linux-modules-4.4.0-159-generic install
linux-modules-extra-4.4.0-154-generic deinstall
linux-modules-extra-4.4.0-157-generic install
linux-modules-extra-4.4.0-159-generic install
util-linux install把当前使用的内核及前一个版本的之前的内核全都卸载掉,
sudo dpkg --purge linux-headers-4.4.0-128-generic linux-headers-4.4.0-128 linux-image-extra-4.4.0-128-generic linux-image-4.4.0-128-generic
,以上排名是有先后顺序的。其实卸载了一个版本的,看/boot
有空间了以后就能使用sudo apt autoremove
自动卸载其他版本的内核了。crontab任务加锁
比如需要每分钟定时运行任务A,如果A的运行持续时间超过了一分钟,同一时刻可能会有两个A在运行,这并不是设计的初衷。这里可以使用
Linux
的文件锁flock
,下面是一个加了锁的定时任务例子:1
*/1 * * * * flock -xn /tmp/rsync_A.lock -c 'rsync -vzrtopg --progress --exclude=.svn --delete stt@****:/home/stt/A /home/stt/ >> /var/log/rsync_cron/A_$(date +\%Y\%m\%d).log 2>&1'
每分钟运行
rsync
命令去远程同步内容到本地,如果已经有锁了说明上一次同步命令还在进行,将不会启动这次的任务。不建议直接使用
root
账号有以下几个原因,不建议直接使用
root
账号做日常管理与维护,应该使用专门的管理账号和部署账号。root
账号权限太大,容易误操作到系统的一些文件造成系统问题- 以
root
运行的应用程序如果被攻击,其权限也是root
,会有潜在的安全性问题 - 多个用户都对服务器进行操作维护的情况下,都用
root
账号不便于管理
小键盘映射
Windows
使用XShell
进行远程连接时,如果出现了小键盘不能的情况,尝试把XShell
属性里面的终端
->终端类型
改为linux
。如果还是存在问题,把一下小键盘的映射方案加入到shell
环境文件中(如.zshrc
)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
35
36
37
38
39
40
41# key bindings
bindkey "\e[1~" beginning-of-line
bindkey "\e[4~" end-of-line
bindkey "\e[5~" beginning-of-history
bindkey "\e[6~" end-of-history
# #
# # # for rxvt
bindkey "\e[8~" end-of-line
bindkey "\e[7~" beginning-of-line
# # # for non RH/Debian xterm, can't hurt for RH/DEbian xterm
bindkey "\eOH" beginning-of-line
bindkey "\eOF" end-of-line
# # # for freebsd console
bindkey "\e[H" beginning-of-line
bindkey "\e[F" end-of-line
# # # completion in the middle of a line
bindkey '^i' expand-or-complete-prefix
#
# # Fix numeric keypad
# # # # 0 . Enter
bindkey -s "^[Op" "0"
bindkey -s "^[On" "."
bindkey -s "^[OM" "^M"
# # # 1 2 3
bindkey -s "^[Oq" "1"
bindkey -s "^[Or" "2"
bindkey -s "^[Os" "3"
# # # # 4 5 6
bindkey -s "^[Ot" "4"
bindkey -s "^[Ou" "5"
bindkey -s "^[Ov" "6"
# # # # 7 8 9
bindkey -s "^[Ow" "7"
bindkey -s "^[Ox" "8"
bindkey -s "^[Oy" "9"
# # # # + - * /
bindkey -s "^[Ol" "+"
bindkey -s "^[Om" "-"
bindkey -s "^[Oj" "*"
bindkey -s "^[Oo" "/"
# #使用自带的
service
来管理系统服务service
是RedHat Linux
发行版下面控制系统服务的实用工具,用于对系统服务进行管理,比如启动(start
)、停止(stop
)、重启(restart
)、查看状态(status
)等。相关的命令还包括
chkconfig
、ntsysv
等,chkconfig
用于查看、设置服务的运行级别,ntsysv
用于直观方便的设置各个服务是否自动启动。
service
命令本身是一个shell
脚本,它在/etc/init.d/
目录查找指定的服务脚本,然后调用该服务脚本来完成任务。因此使用者可以编写自己的service
服务,要设置开机启动的话还需要结合chkconfig
命令。本文提供的部署资料不仅限于
Python Web
项目,其他方式启动的Web
项目都可以使用supervisor
和Nginx
这一套方式去部署。