Python - 装机系列2 Ubuntu(云)

说明


要让客户比较方便的使用应用,最方便的应该就是网站服务了,这里介绍一些基础的搭建过程。完全是围绕Python安装的。
实现的功能包括:

  • 0 SSH
  • 1 代码服务(Git)
  • 2 Python环境-VirtualEnv
  • 3 消息队列RabbitMQ
  • 4 数据库Mysql
  • 5 网站服务(Flask)
  • 6 负载均衡(Nginx)

以阿里云为例,进行介绍。乌班图可以选18的版本,保险一点,我还是用了16的。

0 SSH


  • 1 在阿里云的管理平台找到实例,给root重置密码,参考

  • 2 通过终端ssh登录(密码登录)

  • 3 打开.ssh 文件夹

    • cd .ssh
    • 此时来到了当前用户的文件夹root@xxxxxxxxxxx:~/.ssh#
  • 4 查看当前授权文件(第一次是空的)

    • cat authorized_keys
  • 5 此时需要上传公钥,如果还没有公钥/私钥,则百度一下如何生成。

    • 在我的Mac上已经有了公钥,私钥对
    • ls的文件分别有authorized_keys, id_rsa , id_rsa.pub ,known_hosts
      • 其中authorized_keys中也存了自己的公钥(id_rsa.pub)
		+ 1 cd ~/.ssh
		+ 2 ls
		+ 3 cat id_rsa.pub
  • 6 使用命令向主机传送公钥(会自动识别.pub的文件上传)
    • ssh-copy-id [email protected]
    • 按提示输出当前root的密码(应该在此时将密码和rsa做了绑定)
  • 7 免密登录设置完成

为了更方便使用,可以在自己的bash设置软连接

  • 1 cd ~
    • 切换到用户目录
  • 2 vi .bash_profile
    • 对bash文件进行编辑
  • 3 增加软连接
  • 4 保存退出并source生效
    • 1 esc键
    • 2 :号
    • 3 wq命令(write quit)
    • 4 source .bash_profile

现在可以在终端使用toweb直接登录了。为了避免在网上被人轻易的把密码撞开,可以设置一个32位的密码(办法自己想),然后登录上去修改:

  • sudo passwd root
  • 把密码拷贝进入(可以使用软连接把这个保存在bash中)

ssh连接时间太短

参考这个
三板斧如下

# 1 改配置
vim /etc/ssh/sshd_config
# 2 加语句
ClientAliveInterval 30
ClientAliveCountMax 86400
# 3 重启ssh服务
service sshd restart

ClientAliveInterval 30
ClientAliveCountMax 86400
这两行的意思分别是
1、客户端每隔多少秒向服务发送一个心跳数据
2、客户端多少秒没有相应,服务器自动断掉连接

ssh失效重建

碰到中间人共计后重新恢复,ssh时错误类型如下:
Python - 装机系列2 Ubuntu(云)_第1张图片
此时需要重新刷新一下ssh的已知主机列表重连:

ssh-keygen -R xxx.xxx.xxx.xxx

这时会把旧的主机信息删掉。保险起见,应该把用户密码改掉:
sudo passwd 【用户名】

1 git环境

为了可以把代码改动比较快的部署到云上,需要安装一个git服务,这样就可以方便的拷贝代码了。这部分可以参考这个帖子
这部分可以自己定义一些个性化的东西(例如用户名),但是没什么必要,所以随大流就好了。

  • 1 创建用户
$ adduser git # 除了输入密码和确认密码,一律回车吧
# 如果新建错了可以使用下面的指令进行删除用户
# $ userdel git
  • 2 创建可读写文件

如果需要切换到root用户就用su命令,切换到其他就su some user name

# 创建文件夹
mkdir /opt/git
# 切换过去
cd /opt/git
# pwd
/opt/git
  • 3 安装git服务
    安装服务可以参考这个
# 首先更新apt
apt-get update -y
# 然后再升级(我也不知道为什么)
apt-get upgrade -y
# 安装git
apt install git
# 查看版本,以确认成功(git version 2.7.4)
git --version
# 修改文件夹可写权限(毕竟git就是频繁读写)
chmod -Rf 777 /opt/git

安装好服务之后,我们开始设置对应的ssh和项目文件夹。

  • 4 在git用户之下操作
1.切换到git用户
 su git   
2.切换到用户目录(/home/git)
 cd ~
3. 建立ssh登录文件夹(/home/git/.ssh)
 mkdir .ssh 
 cd .ssh
4. 编辑秘钥文件,如果没有要创建/home/git/.ssh/authorized_keys
>一种方式是vim文件,然后粘贴再保存
vim authorized_keys (创建后粘贴再:wq)
找到自己的公钥(xxx.pub),打开后拷贝粘贴

>另一种是先创建文件再由命令直接写入
touch authorized_keys(创建)
切换到本地机器的公钥目录(本地操作)
cd ~/.ssh
ssh-copy-id [email protected]
然后在vi中类似地建立软连接,例如起个名叫gitweb

5.我们给git用户更大的权限,方便后面其他操作

# 使用root用户授权
su root
# 编辑权限
vim /etc/sudoers
在文件中添加
git ALL=(ALL) NOPASSWD:ALL 添加git用户到sudoer列表
# 改密码
sudo passwd git
需要使用wq!强制保存

6.创建项目文件并初始化

# 切换到用户目录,建立仓库
su git
cd ~
pwd
# -》 /home/git
在当前用户下创建仓库,结尾使用.git(其中codes是自定义名称)
mkdir codes.git
# 将仓库初始化
sudo git init --bare codes.git
# -> Initialized empty Git repository in /home/git/codes.git/
#  将该文件划给git用户
sudo chown -R git codes.git
# 建立一个专门存放各个项目代码文件夹
mkdir ~/mycodes
ls
# ->/home/git/   codes.git  mycodes
# 切换至该文件夹(mycodes)
cd ~/mycodes
# 在仓库边实例一个文件夹,用于启动
git clone /home/git/codes.git 
#->Cloning into 'codes'...
# warning: You appear to have cloned an empty repository.
# done.

# 此时mycodes下已经多出了一个文件夹(仓库文件夹)
ls
# ->codes

# 去这个空的仓库文件夹下建立一个初始文件
cd codes 
touch 说明.md
# 配置自己的身份(git 2强制)
git config --global user.email "[email protected]"
git config --global user.name "Your Name"
# 将新文件提交到仓库(codes.git)
git add .
git commit -m 'x'
git push

by the way, 之后很可能用会用这个命令来清除本地git的更改

git reset --hard 清除本地的git更改

到此为止,服务器端的git已经创建好了,我们在线下可以尝试同步。

#先建立一个文件夹,切换过去
cd ~/yoursfolder
#初次下载(千万记得地址要对,一个斜线都不要少。可以在云主机上pwd获取准确路径)
git clone [email protected]:/home/git/codes.git 

终端的结果

└─ $ git clone git@xxx.xxx.xxx.xxx:/home/git/codes.git
Cloning into 'codes'...
remote: Counting objects: 3, done.
remote: Total 3 (delta 0), reused 0 (delta 0)
Receiving objects: 100% (3/3), done.

如果碰到git服务器更换ip地址

1. 进入本地git文件夹 ls -a ,找到. git文件夹
2. 进入.git 文件夹找到config文件
3. 修改ip地址

7.代码上传测试
在本地随便打开编辑器,对「说明.md」这个文件进行修改,然后三板斧:

git add .
git commit -m 'x'
git push
# ->
└─ $ git push
Counting objects: 3, done.
Writing objects: 100% (3/3), 252 bytes | 252.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To 47.95.195.6:/home/git/codes.git
   6d83e00..d76bc96  master -> master

在云端的项目文件夹

git@fdadfafafa:~/mycodes$ pwd
/home/git/mycodes
# 切换到git文件夹
cd codes
# 拉取代码
git pull
# ----------------->
remote: Counting objects: 3, done.
remote: Total 3 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
From /home/git/codes
   6d83e00..d76bc96  master     -> origin/master
Updating 6d83e00..d76bc96
Fast-forward
 "\350\257\264\346\230\216.md" | 1 +
 1 file changed, 1 insertion(+)

查看更新的文件内容

cat 说明.md
# ->
yoyo check it now

方便起见,也可以在~./bachrc下面设置软连接,直接跳转到对应目录操作

2 Python环境

首先发现服务器已经有python3了,但这不是重点,也不是终点,是一个起点

$ python3
Python 3.5.2 (default, Apr 16 2020, 17:47:17) 
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> 

看一下pip(用于安装python函数包的一个小组件?)

$ pip list
certifi (2020.4.5.1)
chardet (3.0.4)
Cheetah (2.4.4)
cloud-init (0.7.6)
configobj (5.0.6)
idna (2.9)
Jinja2 (2.11.2)
jsonpatch (1.25)
jsonpointer (2.0)
Markdown (3.2.1)
MarkupSafe (1.1.1)
oauth (1.0.1)
pip (8.1.1)
prettytable (0.7.2)
PyYAML (5.3.1)
requests (2.23.0)
setuptools (46.1.3)
six (1.14.0)
urllib3 (1.25.9)
wheel (0.29.0)

如果没有的话可以

apt install python3-pip

虚拟环境

对于应用来说,最好用的还是一个镜像环境,这个需要通过虚拟环境来实现

1.安装virtualenv

pip3 install virtualenv

我的机器目前是3.6.5

python3
Python 3.6.5 (default, Apr 25 2018, 14:23:58) 
[GCC 4.2.1 Compatible Apple LLVM 9.1.0 (clang-902.0.39.1)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>>

[插播一下]安装对应版本的Python

# 1安装包
sudo apt-get install python-software-properties
# 2增加包的系统执行命令(否则3的命令无法执行)
sudo apt install software-properties-common
#3 增加源
sudo add-apt-repository ppa:fkrull/deadsnakes
# 4更新源
sudo apt-get update
# 安装版本(似乎没有3.6.5,只能3.6了)
sudo apt-get install python3.6

版本还是略有差异,但是问题应该不大

python3.6
Python 3.6.2 (default, Jul 17 2017, 23:14:31) 
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> 

2.创建第一个虚拟环境

1 创建文件夹存放环境包
mkdir /home/env
2 创建第一个环境
mkdir /home/env/flkenv
3 按照指版本创建虚拟环境
virtualenv /home/env/flkenv --python=python3.6
4 激活虚拟环境 
source /home/env/flkenv/bin/activate
5 将启动虚拟环境的命令写入bash中
vim ~/.bashrc
alias flkenv="source /home/env/flkenv/bin/activate"
保存退出,刷新bash
source ~/.bashrc

在创建(3 按照指版本创建虚拟环境)过程中,有报一些错,但都是python3.5版本下的错,当前的python包资源下面有:

# cd /usr/local/lib/
# ls
python2.7  python3.5  python3.6

不过最后虚拟环境似乎按要求建立起来了

# python
Python 3.6.2 (default, Jul 17 2017, 23:14:31) 
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> 
KeyboardInterrupt
>>> 

pip list
Package    Version
---------- -------
pip        20.1.1
setuptools 49.2.0
wheel      0.34.2

现在使用flkenv就可激活虚拟环境了,deactivate就可以退出

上传本地安装包

现在本地开发环境,执行导出包清单的命令

 pip3 freeze>requirements.txt

在本地生成了一个txt文本文件,现在要使用scp命令传上去

# 先在/home下再建一个文件夹
mkdir uploads
# 使用scp上传
scp ~/code_togo/codes/requirements.txt  [email protected]:/home/uploads

scp简单来说就是声明左边到右边的动作,左边和右边的表达形式略有不同
服务器资源:[email protected]:/xxx/xxx/xxx
本地资源: ~/xxx/xxx/xxx

scp -r 左边 右边

在虚拟环境下批量安装包

$ flkenv
$ pip3 install -r /home/upload/requirements.txt

3 安装RabbitMQ

使用18.04安装很简单,但是没能选我希望的搭配,暂时不管了,单独安装包的方式太容易出错。参考这个

3.1 erlang

sudo apt-get install erlang-nox
sudo apt-get update

3.2 RabbitMQ

sudo apt-get install rabbitmq-server

3.3 设置用户

启动、停止、重启、状态rabbitMq命令

sudo rabbitmq-server start
sudo rabbitmq-server stop
sudo rabbitmq-server restart
sudo rabbitmqctl status

添加admin用户,密码设置为admin。

sudo rabbitmqctl add_user  admin  admin  

赋予权限

sudo rabbitmqctl set_user_tags admin administrator

赋予virtual host中所有资源的配置、写、读权限以便管理其中的资源

sudo rabbitmqctl  set_permissions -p / admin '.*' '.*' '.*'
 增加插件,可以打开网页
rabbitmq-plugins enable rabbitmq_management
重启rabbitmq
service rabbitmq-server restart
命令有点长,还是用软连接替代

vim ~/.bashrc
alias rabbit_start="sudo rabbitmq-server start"
alias rabbit_stop="sudo rabbitmq-server stop"
alias rabbit_restart="sudo rabbitmq-server restart"
source ~/.bashrc

4 安装Mysql

参考文章

4.1 安装

安装三板斧

sudo apt-get install mysql-server
sudo apt-get install mysql-client
sudo apt-get install libmysqlclient-dev
# 检查一下
mysql -u root -p
# 修改密码
set password for root@localhost = password('123');

Mysql的导入导出参考

4.2 建库建表

创建用户,参考

create user 'username'@'%' identified by 'password';

show grants for 'username'@'%';

grant all privileges on *.* to 'username'@'%';

删除用户

Delete FROM user Where User='username' and Host='localhost';
flush privileges;

创建数据库

CREATE DATABASE your_database_name DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;

show databases;
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| your_database_name|
| performance_schema |
| sys                |
+--------------------+

5 Flask服务

FLask默认是阻塞式的,不能直接用于生产,使用gevent来使得其以协程方式运行。
【nohup 启动,以及日志屏蔽(不要全部输出)】

用manage封装了Flask App 之后,使用

# IO异步并发响应
from gevent import monkey
from gevent.pywsgi import WSGIServer
# 并发版
monkey.patch_all()
if __name__ == '__main__':
    # 阻塞版
    # manager.run()
    # 并发版/ 基于协程,并不是真的多核
    server = WSGIServer(("0.0.0.0", 5000), app)
    print("Server started")
    server.serve_forever()
    # nohup python3 manage_prod.py runserver &
    # nohup 命令后不可以直接关掉终端,要使用exit文明退出(不然可能6~7个小时后nohup会重启

不要忘记打开5000端口
Python - 装机系列2 Ubuntu(云)_第2张图片

5.1 nohup 启动

后台启动但不要任何信息

nohup python3 manager_prod.py runserver >/dev/null 2>&1 &

可以在 ~/.bashrc中设置软连接, 这个可以叫start_web

5.2 端口检查

netstat -nutlp|grep 5000
看看服务是否启动
必要的话kill 进程
设置软连接,这个叫check_web

更多的进程检查可以参考

jobs
jobs -l

6 Nginx

6.1 安装

参考这里,有安装包和源代码安装两种方式,当然我还是喜欢安装包安装。

apt-get install nginx

# ------>
Reading package lists... Done
Building dependency tree       
Reading state information... Done
nginx is already the newest version (1.14.0-0ubuntu1.7).
0 upgraded, 0 newly installed, 0 to remove and 3 not upgraded.


nginx -v
nginx version: nginx/1.14.0 (Ubuntu)

# 启动
service nginx start

# 彻底卸载nginx
apt-get --purge autoremove nginx

直接输入IP地址 xxx.xxx.xxx.xxx 会返回如下页面
Python - 装机系列2 Ubuntu(云)_第3张图片
nginx文件安装完成之后的文件位置:

/usr/sbin/nginx:主程序
/etc/nginx:存放配置文件
/usr/share/nginx:存放静态文件
/var/log/nginx:存放日志

6.2 跨域问题

没想到用nginx填的第一个坑是跨域…
跨域资料一
跨域资料二
nginx 跨域资料三
nginx 跨域资料四
关于preflight request-预检请求

URL 说明 是否允许通信
http://www.a.com/a.js – http://www.a.com/b.js 同一域名下 允许
http://www.a.com/lab/a.js – http://www.a.com/script/b.js 同一域名下不同文件夹 允许
http://www.a.com:8000/a.js – http://www.a.com/b.js 同一域名,不同端口 不允许
http://www.a.com/a.js – https://www.a.com/b.js 同一域名,不同协议 不允许
http://www.a.com/a.js – http://70.32.92.74/b.js 域名和域名对应ip 不允许
http://www.a.com/a.js - http://script.a.com/b.js 主域相同,子域不同 不允许
http://www.a.com/a.js – http://a.com/b.js 同一域名,不同二级域名(同上) 不允许(cookie这种情况下也不允许访问)
http://www.cnblogs.com/a.js – http://www.a.com/b.js 不同域名 不允许

问题

在本地起一个服务,端口5000, 然后再起一个服务,端口5555。现在在5555要引用5000的路径,会发生错误

<script>
function test_cross(which) {
url = 'http://127.0.0.1:5000/app002/api/upload_localtest';
// url = 'http://127.0.0.1:5000/app002/api/current_filelist';
// url = 'http://127.0.0.1:5000'; -- 访问根目录受限
para_dict = JSON.stringify({'a':1, 'b':2});
$.post(url, para_dict,function (res_data) {
data_status = res_data.status;
if (data_status == true) {
alert('success')

} else {
alert('fail')
}
});
}
script>

1.全局的设置一定要通过函数作用在app上。
如果使用蓝图模式,要在manager.py中作用,而不是在__init__.py中作用。

CORS(app)

2.也可以直接json返回头增加。

json_res = jsonify(res_dict)
json_res.headers['Access-Control-Allow-Origin'] = '*'

显示调用成功。
如果增加开放某个api的设置,那么就无法正常访问。(允许只能访问app002, 那么访问根目录就是跨域)

CORS(app,  resources={r"/app002/*": {"origins": "*"}}, supports_credentials=True)

Python - 装机系列2 Ubuntu(云)_第4张图片
CORS 参数
resources (dict, iterable or string) –
The series of regular expression and (optionally) associated CORS options to be applied to the given resource path.

If the argument is a dictionary, it’s keys must be regular expressions, and the values must be a dictionary of kwargs, identical to the kwargs of this function.

If the argument is a list, it is expected to be a list of regular expressions, for which the app-wide configured options are applied.

If the argument is a string, it is expected to be a regular expression for which the app-wide configured options are applied.

Default : Match all and apply app-level configuration

origins (list, string or regex) –
The origin, or list of origins to allow requests from. The origin(s) may be regular expressions, case-sensitive strings, or else an asterisk

Default : ‘*’

methods (list or string) –
The method or list of methods which the allowed origins are allowed to access for non-simple requests.

Default : [GET, HEAD, POST, OPTIONS, PUT, PATCH, DELETE]

expose_headers (list or string) –
The header or list which are safe to expose to the API of a CORS API specification.

Default : None

allow_headers (list, string or regex) –
The header or list of header field names which can be used when this resource is accessed by allowed origins. The header(s) may be regular expressions, case-sensitive strings, or else an asterisk.

Default : ‘*’, allow all headers

supports_credentials (bool) –
Allows users to make authenticated requests. If true, injects the Access-Control-Allow-Credentials header in responses. This allows cookies and credentials to be submitted across domains.

note: This option cannot be used in conjuction with a ‘*’ origin
Default : False

max_age (timedelta, integer, string or None) –
The maximum time for which this CORS request maybe cached. This value is set as the Access-Control-Max-Age header.

Default : None

send_wildcard (bool) –
If True, and the origins parameter is *, a wildcard Access-Control-Allow-Origin header is sent, rather than the request’s Origin header.

Default : False

vary_header (bool) –
If True, the header Vary: Origin will be returned as per the W3 implementation guidelines.

Setting this header when the Access-Control-Allow-Origin is dynamically generated (e.g. when there is more than one allowed origin, and an Origin than ‘*’ is returned) informs CDNs and other caches that the CORS headers are dynamic, and cannot be cached.

If False, the Vary header will never be injected or altered.

Default : True

进一步使用Nginx来使得服务负载均衡,提供更高的稳定性。
待续…

你可能感兴趣的:(全栈)