发布于 
loading

Dokcer + CentOS 7 + Anaconda + FastAPI + PostgreSQL 超详细配置 & 出错解决

封面图片
封面图片

首先讲讲我的配置清单🧾

宿主机 OS: CentOS 7

Nginx 版本:1.16.1

Docker 版本: 19.03.13

Docker 容器系统: CentOS 7

Python 虚拟环境管理: Anaconda

Python 版本: Python 3.7

选用的后端框架: Fastapi

Python 操作 PostgreSQL: Psycopg2 (毋容置疑)

数据库: PostgreSQL 12(毋容置疑 + 1)


宿主机中需要做的配置

1. 安装 & 配置 Nginx

大部分内容出自此链接 🔗:https://juejin.im/post/6844904134345228301

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 安装 Nginx
yum -y install nginx

# 卸载 Nginx
yum remove nginx

# 设置开机启动,建议打开
systemctl enable nginx

# 启动 nginx 服务,安装后需运行
systemcrl start nginx

# 停止 nginx 服务
systemcrl stop nginx

# 重启 nginx 服务
systemcrl restart nginx

我的 Nginx 配置,以下仅为部分配置,可下载一键脚本进行配置。
如果不知道自己的 Nginx 配置的文件位置在哪,可使用 systemctl status nginx 查看。

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
# 编辑的文件
# 我的文件地址是
# vi /etc/nginx/conf.d/default.conf

server {
listen 80;
server_name www.xxx.xxx;
rewrite ^(.*)$ https://$host$1 permanent;
}
server {
listen 443 ssl http2;
server_name www.xxx.xxx;
root /etc/nginx/html;
index index.php index.html;
location / {
try_files $uri $uri/ /index.php?$args;
}
# fastapi main
location /helloworld {
proxy_pass http://127.0.0.1:8011;
}
# fastapi docs
location /docs {
proxy_pass http://127.0.0.1:8011/api/docs;
}
}

2. 安装 & 配置 Docker

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
# 安装 Docker
yum -y install docker

# 启动 Docker 后台服务,安装完后需运行
systemctl start docker

# 开机自启动 Dokcer,建议开启
systemctl enable docker

# 查看 Dokcer 运行信息
systemctl status docker

# 重启 Docker 服务
systemctl restart docker

# 检测 Docker 是否正常安装,尝试跑一个叫 hello-word 的镜像
docker run hello-world

# 查看是存在 hello-world 镜像,如果存在,则成功
docker images

# 拉取 CentOS 镜像,注意':'后面带的是系统版本,
# 同样的 docker images 可以查看是否存在 centos 这个镜像
docker pull centos:7.2.1511

# 运行 docker centos 的时候,
# 一定要注意开放端口,以方便容器内的 Fastapi 使用
docker run -ti -d -p 80:80 -p 8011:8011 --privileged=true centos:7.8.2003 /usr/sbin/init

# 查看所有镜像的信息,方便使用 container id 进入
docker ps -a

# 先执行 attach 命令,以获得 systemctl 权限
docker attach docker_container_id

# 下次进入 docker 就不是上面那句 attach 命令了,而是
docker exec -it docker_container_id /bin/bash
# 所以需要 docker ps -a 查看 container id

!重要!:之后进入这个容器就不能用 docker attach docker_container_id 了,但为了保险,先 attach 一次,以获得容器内 CentOS 7 执行 systemctl 命令的权限

1
2
# 然后关掉终端或命令行,开启新的终端或命令行,这次换另外一条命令进入 虚拟机
docker exec -it docker_container_id /bin/bash

关于 CentOS 7 安装 Docker 更详细的信息:https://www.jianshu.com/p/3a4cd73e3272

关于 Docker 安装 CentOS 7 及基本配置:https://victorzhong.github.io/2018/01/15/Docker%E5%AE%89%E8%A3%85CentOS7%E5%8F%8A%E5%9F%BA%E6%9C%AC%E9%85%8D%E7%BD%AE/


容器内虚拟机需要做的配置

1. 安装 & 配置PostgreSQL 12

记得在 sql shell 里面的命令,结尾都要加上 ; 分号。

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
# 先安装 yum 的下载源,即安装 epel-release,
# 下载之后,就可以直接跳到 安装 PostgreSQl 12 那一步

#(还有其它的国内源请看:https://www.jianshu.com/p/541c737bc947)

yum -y install epel-release

# 如果选择不安装 yum 下载源 则使用下面的命令
yum install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-7-x86_64/pgdg-redhat-repo-latest.noarch.rpm

# 安装 PostgreSQL 12
yum install -y postgresql12 postgresql12-server

# 初始化数据库
/usr/pgsql-12/bin/postgresql-12-setup initdb

# 启动PostgreSQL服务
systemctl start postgresql-12

# 设置 PostgreSQL 服务为开机启动
systemctl enable postgresql-12

# 查看 PostgreSQL 服务状态
systemctl status postgresql-12

# 进入 PostgreSQL 命令行
su postgres

# 启动SQL Shell
psql

!重要!,此时先不要退出 sql shell!接下来,可输入 \l 查看 DataBaseEncoding,假若 Encoding 不为 UTF8,插入中文值到数据库的时候,会出错!

请先不要急着卸载或执行破坏性命令(血与泪的教训),请按照顺序执行下面的命令,以更改 DataBaseEncoding

这些命令全都要在 SQL Shell 里面执行!记得 ; 分号结尾,如果还是忘了,按 ctrl / command + c 可以退回到初始状态。

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
# 先切换 DataBase
\c template0;

# 将 template1 的 datistemplate 改为 false
update pg_database set datistemplate = FALSE where datname = 'template1';

# 删除 template1 DataBase
drop database template1;

# 重新创建 template1 DataBase 以 UTF8 编码
create database template1 with encoding = 'UTF8' LC_CTYPE = 'en_US.UTF-8' LC_COLLATE = 'en_US.UTF-8' template = template0;

# 重新将 template1 的 datistemplate 改为 true
update pg_database set datallowconn = TRUE where datname = 'template1';

# 接下来切换到 template1 Database
\c template1;

# 重复步骤,修改 template0 的 datistemplate
update pg_database set datistemplate = FALSE where datname = 'template0';

# 删除 template0 DataBase
drop database template0;

# 重新创建 template0 DataBase 以 UTF8 编码
create database template0 with encoding = 'UTF8' LC_CTYPE = 'en_US.UTF-8' LC_COLLATE = 'en_US.UTF-8' template = template1;

# 重新将 template0 的 datistemplate 改为 true
update pg_database set datallowconn = TRUE where datname = 'template0';

!重要!,切勿真的删除 template0 & template1 这两个数据库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# postgres 数据库,重复以上步骤,即可把 Encoding 改为 UTF8,不再赘述注释

\c template1;

update pg_database set datistemplate = FALSE where datname = 'postgres';

drop database template0;

create database postgres with encoding = 'UTF8' LC_CTYPE = 'en_US.UTF-8' LC_COLLATE = 'en_US.UTF-8' template = template0;

update pg_database set datallowconn = TRUE where datname = 'postgres';

\c postgres;

# 再次输入 \l 查看 Encoding,确保修改成功。

当执行了破坏性命令,例如:yum remove postgresql12 postgresql12-server

并重新执行了yum install postgresql12 postgresql12-server后,执行初始化数据库命令时会出错,

即当在[root@xxx /]#状态下执行 /usr/pgsql-12/bin/postgresql-12-setup initdb 命令时会出现,该文件夹 📁 不为空的报错

此时需执行:rm -rf /var/lib/pgsql/12/data/ 删除该文件夹。

然后重新执行 /usr/pgsql-12/bin/postgresql-12-setup initdb 命令即可。

1
2
# 修改 postgres 数据库密码
ALTER USER postgres WITH PASSWORD 'NewPassword';

!重要!,允许所有 IP 访问,我的配置

1
2
3
4
5
6
7
8
9
10
11
12
# 修改配置文件
vi /var/lib/pgsql/12/data/pg_hba.conf

# 将 ipv4 下面的内容改为
# IPv4 local connections:
host all all 127.0.0.1/32 trust

# 重启 postgresql-12 服务,注意⚠️一定要带上 -12
systemctl restart postgresql-12

# 如果需要退出 postgres=# 或 bash-4.2$ 的状态
直接输入 exit 按回车即可。

PostgreSQL 12 安装 & 配置完毕

PostgreSQL 修改数据库编码方式代码源自🔗:https://www.jianshu.com/p/62893363b0d2

更详细的信息可点击此链接🔗(大部分内容也源自此链接):https://ken.io/note/centos7-postgresql12-install-and-configuration


2. 安装 & 配置 Anaconda

以下内容大部分来自此链接🔗:https://juejin.im/post/6854573222273220621

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
# 下载 wget
yum -y install wget

# 配置 下载源
yum -y install perl

# 下载 Anaconda
wget https://repo.anaconda.com/archive/Anaconda3-2020.02-Linux-x86_64.sh

# 安装 Anaconda
bash Anaconda3-5.3.1-Linux-x86_64.sh

# 进入安装程序,提示输入“ENTER”继续:
Please, press ENTER to continue
>>> ENTER

# 输入yes确认接受许可协议
Do you accept the license terms? [yes|no]
[no] >>> yes

# 确认Anaconda的安装位置, 可改可不改
Anaconda3 will now be installed into this location:/root/anaconda3  - 
Press ENTER to confirm the location  - Press CTRL-C to abort the installation  - 
Or specify a different location below[/root/anaconda3] >>> /opt/anaconda3

# 安装完成后,出现询问是否在用户的.bashrc文件中初始化Anaconda3的相关内容,此处选 yes
Do you wish the installer to initialize Anaconda3by running conda init? [yes|no][no] >>> yes

安装完成 ✅ ,Anaconda 的一些基础命令:

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
# 执行下:source ~/.bashrc,
# 使用 conda 命令时就不会报 conda command not found 了

# 创建一个 Python3.7 版本的虚拟环境
conda create --name fastapienv python=3.7

# 删除虚拟环境命令
conda remove -n fastapienv --all

# 激活虚拟环境,可直接激活虚拟环境,无需先停用当前虚拟环境
conda activate fastapienv

# 停用虚拟环境
conda deactivate fastapienv

# 查看当前虚拟环境已安装的包
conda list

# conda 安装包命令,假如是安装 fastapi
conda install fastapi

# 当 conda install 无法安装某个包时,通过查询 pip 的路径,
# 如果有显示当前虚拟环境名,则可以使用 pip 安装 Python 包,看是否能装上

whereis pip
pip install fastapi

# 如果 pip install / coonda install 都无法安装,则需要下载源码包,使用命令解压安装。

解决每次进入虚拟机时,Anaconda 虚拟环境皆为 base 的问题
(源自此链接🔗:https://www.cnblogs.com/alphacode/p/13760470.html)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 修改 ~/.bash_profile 文件,有时 ~/.bashrc 文件里也会有此配置

export PATH="~/anaconda/envs/your_env_name/bin:$PATH"
# your_env_name 是你自定义的环境名

# 修改 ~/.bashrc 文件

conda activate your_env_name
# "your_env_name"就是你的环境名

# 更新配置
source ~/.bashrc
source ~/.bash_profile

# 设置好后,返回到刚进入虚拟机的状态 [root@xxx /]#,
# 执行以下命令以停止 base 虚拟环境自启动
conda config --set auto_activate_base false

我的配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# vi ~/.bashrc

# >>> conda initialize >>>
# !! Contents within this block are managed by 'conda init' !!
__conda_setup="$('/root/anaconda3/bin/conda' 'shell.bash' 'hook' 2> /dev/null)"
if [ $? -eq 0 ]; then
eval "$__conda_setup"
else
if [ -f "/root/anaconda3/etc/profile.d/conda.sh" ]; then
. "/root/anaconda3/etc/profile.d/conda.sh"
else
export PATH="/root/anaconda3/bin:$PATH"
fi
fi
unset __conda_setup
conda activate fastapienv
# <<< conda initialize <<<

# vi ~/.bash_profile

# PATH=$PATH:$HOME/bin
PATH="~/anaconda3/envs/fastapienv/bin:$PATH"
export PATH
export LANG="en_US.UTF-8"

Anaconda 配置完毕

我的 Anaconda 虚拟环境 fastapienv 还需要安装的包

1
2
3
4
5
6
7
8
9
# 除了基本的包以外

还安装了:
fastapi
uvicorn
psycopg2

# 小程序解密用
pycryptodome

3. 安装 & 配置 & 启动一个 Fastapi 基础后端

fastapi官方中文链接🔗:https://fastapi.tiangolo.com/zh/

执行下面的步骤前,必须先安装好 fastapi & uvicorn & psycopg2

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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# 找个你喜欢的路径,(我喜欢 /tmp/) 创建 main.py 文件,键入以下代码:

from typing import Optional
from fastapi import FastAPI

# 跨域
from fastapi.middleware.cors import CORSMiddleware

import psycopg2
import psycopg2.extras

app = FastAPI()

# 跨域配置
origins = [
"http://localhost.tiangolo.com",
"https://localhost.tiangolo.com",
"http://localhost",
"http://localhost:8080",
"http://127.0.0.1",
"http://127.0.0.1:8080",
"*"
]

# 跨域配置
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"]
)

# 一般都是 5432 端口,下文会提及如何查询
conn = psycopg2.connect(database="postgres", user="postgres", password="Your_Pass_Word", host="127.0.0.1", port="5432")

# 这段代码很关键,下文会解释
cursor = conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor)


@app.get("/")
def read_root():
return {"Hello": "World"}


# 创建员工数据表
@app.get("/create/stafftable")
def create_staff_table():
sql = """
CREATE TABLE staff(
id varchar(11) PRIMARY KEY,
username varchar(20),
password varchar(50)
);
"""
try:
cursor.execute(sql)
print("staff table created successfully")
conn.commit()
except Exception as e:
conn.rollback()
else:
conn.commit()


# 创建员工
@app.get("/create/staff")
def create_staff(id: str, username: str, password: str):
idsql = """SELECT * FROM staff where id = %s"""
idparams = (id,)
cursor.execute(idsql, idparams)
conn.commit()
rows = cursor.fetchall()
if rows:
return -1
else:
sql = """INSERT INTO staff (id, username, password) VALUES (%(id)s,%(username)s, %(password)s)"""
params = {'id': id, 'username': username, 'password': password}
try:
cursor.execute(sql, params)
conn.commit()
except Exception as e:
conn.rollback()
else:
conn.commit()


# 删除员工
@app.get("/delete/staff")
def delete_staff(id: str):
sql = """delete from staff where id = %s """
params = (id,)
try:
cursor.execute(sql, params)
conn.commit()
except Exception as e:
conn.rollback()
else:
conn.commit()


# 查找所有员工
@app.get("/searchall/staff")
def search_all_staff():
sql = """SELECT * FROM staff;"""
try:
cursor.execute(sql)
rows = cursor.fetchall()
conn.commit()
return rows
except Exception as e:
conn.rollback()
else:
conn.commit()


# 关闭数据库连接
def close_database():
cursor = conn.cursor()
cursor.close()
conn.close()

!重要!,此时,我们进来 Dokcer 容器的那条命令就发挥作用了,我们进入的时候,映射了两个端口给虚拟机,分别是 80 & 8011

如果你没有跑 docker run -ti -d -p 80:80 -p 8011:8011 --privileged=true centos:7.8.2003 /usr/sbin/init 这条命令就进入虚拟机,很抱歉,你需要回到创建 docker container 的位置重新创建…

写好 main.py 后,执行以下命令:

1
2
3
uvicorn main:app --host 0.0.0.0 --port 8011 --reload

# 按 ctrl / command + c 可停止运行

此时,你在浏览器的地址栏中输入,你的物理机IP,后面加上:8011,就能看到 hello world 的提示。

IP后输入 :8011/docs 你还能看到 fastapi 为我们准备的 交互式 API 文档,你可以在里面测试连接数据库是否存在问题。

:8011/docs 还能进行一定的接口测试,看看返回的 Data 是否符合自己的需要。

如键入中文值存在问题,请返回到上文,看看是否是,DataBase Encoding 的编码问题。

另外,如果你的 Uvicorn 在后台运作,而你希望重新启动,可使用以下命令让它停止运行

1
2
3
4
5
6
7
8
9
10
11
12
13
# 检查端口被哪个进程占用
netstat -lnp|grep 8011

# 如果无法使用 netstat 执行:
yum install net-tools

# 查看进程的详细信息
ps 11100

# 杀掉进程
kill -9 11100

# 通常,还需再使用 netstat -lnp|grep 8011 复查

更多详细信息:https://blog.csdn.net/u011389452/article/details/53982204


4. 可能存在的 Psycopg2 操作 PostgreSQL 数据库问题

如果没有 import psycopg2.extras & cursor = conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor) 这段代码。

你的 /searchall/staff 请求的返回值,就不会以键值对的形式返回给前端。

以下内容你可以忽略

当初我为了这个问题,“学习了”下 PostgreSQL json & jsonb 数据类型的操作,jsonb 的读取性能更快(比 json 快很多很多倍,但是顺序会乱)

下面放一下 jsonb 的 数据库命令 操作,即,直接在 sql shell 中执行的命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# postgresql jsonb 增删改查 知识点记录 📝 (注意!是jsonb):

# 在 sql shell 创建表:
CREATE table test_jsonb(id int, info jsonb);

# 增:
insert into test_jsonb values(2, '{"company":"sanzro design", "name":"sanzro", "career":"Full Stack Engineer"}');

# 删(暂时不知道如何通过jsonb去删除整个元素):
delete from test_jsonb where id = 2;

# 改:
update test_jsonb set info = info||'{"company":"sanzro design"}' WHERE id = 2;

# 查:
select * from test_jsonb where info @> '{"company":"sanzro design"}';
# 查询 id
select * from test_jsonb where id=2;

还有如果你需要 id 自增,则创建表的时候将 id 配置为 serial

1
2
3
4
CREATE TABLE test_jsonb (
id SERIAL PRIMARY KEY,
info jsonb
);

id 为自增时,其它不变,插入数据变为:

1
insert into test_jsonb (info) values('{"company":"sanzro design", "name":"sanzro", "career":"Full Stack Engineer"}');

其它遇到的问题

后端解密小程序函数

!重要!,需要 pip install pycryptodome ,上文有提及


如果依旧无法使用,请参考此链接🔗:从 “警告:请勿使用 pycrypto” 看起:https://qastack.cn/programming/19623267/importerror-no-module-named-crypto-cipher

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 示例代码
from fastapi.encoders import jsonable_encoder

@app.post('/code')
def user_wxlogin(appid, secret, code):
params = {
'appid': appid,
'secret': secret,
'js_code': code,
'grant_type': 'authorization_code'
}
url = 'https://api.weixin.qq.com/sns/jscode2session'
r = requests.get(url, params=params)
openid = r.json().get('openid', '')
session_key = r.json().get('session_key', '')
return {'openid': openid, 'session_key': session_key}


Sanzro Info 公众号二维码
Sanzro Info 公众号二维码

内容较长,感谢 🙏 你看到这里。

如有误,请提出,必纠正,谢谢。

请我喝杯咖啡吧🙏
请我喝杯咖啡吧🙏

本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。

本站由 @Kolin Lee 创建,使用 Stellar 作为主题。