Let’s Encrypt SSL证书

生成

yum install epel-release -y
yum install certbot -y


certbot certonly --webroot -w /home/wwwroot/bt.wktadmin.com -d bt.wktadmin.com -m [email protected] --agree-tos
****

nginx 配置


upstream tornadoes { server 127.0.0.1:8000; server 127.0.0.1:8002; } server { listen 80; server_name bt.wktadmin.com; return 301 https://bt.wktadmin.com$request_uri; } server { listen 443; server_name bt.wktadmin.com; ssl_certificate /etc/letsencrypt/live/bt.wktadmin.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/bt.wktadmin.com/privkey.pem; location /static { root /root/tools/tornado; autoindex on; } location /.well-known { root /home/wwwroot/bt.wktadmin.com; autoindex on; } location / { proxy_pass_header Server; proxy_set_header Host $http_host; proxy_redirect off; proxy_set_header X-Real-IP $remote_addr; # 把请求方向代理传给tornado服务器,负载均衡 proxy_pass http://tornadoes; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; } }

自动更新

30 2 * */2 * /usr/bin/certbot renew --quiet && /bin/systemctl restart nginx

详细:
https://juejin.im/entry/5b59c3f26fb9a04fda4e2238

scrapy爬虫部署(scrapy管理)


常用:

  • 开启:
curl https:///schedule.json -d project=default -d spider=btspider
  • 本次开启使用
curl https://blog.wktadmin.com/scrapyd/schedule.json  -d project=default -d spider=btspider
  • 关闭
 curl https://blog.wktadmin.com/scrapyd/cancel.json -d   project=default -d job=284a5496078d11e98a7df6afa62feb35

  • 列表
curl https://blog.wktadmin.com/scrapyd/listspiders.json?project=default

import cv2错误: ImportError: libXrender.so.1: cannot open shared object file: No such file or directory

环境: centos,python3.6
错误: import cv2 出错
已安装: pip install opencv-python==3.4.3.18

解决参考: https://www.centos.org/forums/viewtopic.php?t=49456

yum install libXrender.x86_64

mysql如何支持emoji/原文: mysql数据库中utf8与utf8mb4的区别:记一次sqlalchemy的InternalError

遇到的问题
使用sqlalchemy执行下面语句的时候包错了。

insert into datasource value('YnWZ8Q4928ruM4z63I+9IQ==','','盖乐世社区','S8','刚刚看到一个贴,特搞笑。这头说完下面就有人评论打脸了😂    bixby不说最好,但怎么说也是在现有的语音技术基础上面提升一大步。(注意:现有的技术基础提升)真的搜不出来的话可能也许大概是输入的命令不对而已,可以换一句话试一试嘛。都说了bixby更人性化一点,肯定跟其他的不一样的嘛。当然,所有的语音都不说最好的,还有待提升。    好了,屁话不多说,回到我们图上这位小哥,估计是果粉,然后尝新鲜买了个s8。但还是偏向iPhone吧应该,然后一肚子火跑来撒气。但是!!我们看到评论这边,哈哈哈,秒打脸','2017-12-14','负向','http://www.galaxyclub.cn/thread-445992-4-61.html')

错误类型是InternalError,错误信息

sqlalchemy.exc.InternalError: (pymysql.err.InternalError) (1366, "Incorrect string value: '\\xF0\\x9F\\x98\\x82\\x09b...' for column 'content' at row 1") [SQL: "insert into datasource value('YnWZ8Q4928ruM4z63I+9IQ==','','盖乐世社区','S8','刚刚看到一个贴,特搞笑。这头说完下面就有人评论打脸了😂\tbixby不说最好,但怎么说也是在现有的语音技术基础上面提升一大步。(注意:现有的技术基础提升)真的搜不出来的话可能也许大概是输入的命令不对而已,可以换一句话试一试嘛。都说了bixby更人性化一点,肯定跟其他的不一样的嘛。当然,所有的语音都不说最好的,还有待提升。\t好了,屁话不多说,回到我们图上这位小哥,估计是果粉,然后尝新鲜买了个s8。但还是偏向iPhone吧应该,然后一肚子火跑来撒气。但是!!我们看到评论这边,哈哈哈,秒打脸','2017-12-14','负向','http://www.galaxyclub.cn/thread-445992-4-61.html')"]

按照之前的经验,百分之八十问题是出在这个贱贱的表情上。复查下整个连接、建表中的数据。

  • 链路上的字符集设置

1 链接引擎

engine = create_engine("mysql+pymysql://root:[email protected]:3306/bi_bigeye?charset=utf8")

2 建表

create table if not exists datasource_type( siteName varchar(20) primary key, field varchar(10) ,scope varchar(10)) Default charset='utf8'

从整个链路上看,已经使用了utf8字符集了,理论上不应该出现emoji表情无法存储的情况了。

峰回路转

网上查了篇文档也是说吧字符集设置称为utf8mb4就可以了,为什么我这还报错。。。等等,为什么mb4是什么?

这一查才知道,原来mysql中utf8字符也藏了这么复杂的坑。

utf8这种是一种变长编码方法,也就是说到使用1到4个字节来表示一个字符。但是在mysql中的utf8却最多只能存储3个字节所表示的字符,也只能支持0x0000到0xFFFF的字符串,也就是Basic Muiltilingual Plane所规划的范围,而这个范围是不包含emoji的,所以在碰到这个贱贱表情是hold不住报错了。

解决问题

既然是使用字符串的问题,那么修改下相关的字符串编码即可。对于连接引擎来说,解决起来还是很简单的,将utf8替换成utf8mb4即可,对于数据库而言已经存储了不少内容,自然无法删掉重建。这时候就需要使用平时很少用到的ALTER语法。

ALTER TABLE `datasource` DEFAULT CHARACTER SET utf8mb4 ; # 更改表的编码,不影响各个字段的编码

alter table datasource convert to character set utf8mb4;  # 更改表的编码,删除各个字段的编码

通过show create table targetTable查看各个字段的编码,更改了之后问题也就消除了。

小结

在这个过程中,了解了在mysql环境下使用utf8编码还是不够的,而要使用utf8mb4;并且学习了使用alter 更改数据库的字符集的方法。

原文

http://zhouchen.tech/2018/03/15/mysql%E6%95%B0%E6%8D%AE%E5%BA%93%E4%B8%ADutf8%E4%B8%8Eutf8mb4%E7%9A%84%E5%8C%BA%E5%88%AB%EF%BC%9A%E8%AE%B0%E4%B8%80%E6%AC%A1sqlalchemy%E7%9A%84InternalError/

supervisor进程管理

以supervisor管理celery进程为例

一 安装supervisor

二 配置

三 启动和关闭

四 打开web监听


安装supervisor

python3 无法直接使用pypi源安装, 使用

pip3 install git+https://github.com/Supervisor/supervisor

配置

  • 生成默认的配置文件
echo_supervisord_conf > /etc/supervisord.conf
  • 添加自定义配置

在生成的conf文件最后添加

[program:tiis_is_name]
command=/home/wukt/.virtualenvs/p3.6/bin/celery worker -l INFO -c 1 -A flaskrun.celery --beat --loglevel debug --logfile celery_beat.log
stdout_logfile=celeryd.log
stderr_logfile=celeryd.log
autostart=true
autorestart=true
startsecs=1
stopwaitsecs=600

启动和关闭

启动

supervisord -c supervisord.conf

关闭supervisord需要通过supervisor的控制器:

supervisorctl -c supervisord.conf shutdown

重启supervisord也是通过supervisor的控制器:

supervisorctl -c supervisord.conf reload

打开web监听

在生成的conf文件删除指定的注释即可:

[supervisorctl]
serverurl=unix:///tmp/supervisor.sock ; use a unix:// URL  for a unix socket
;serverurl=http://127.0.0.1:9001 ; use an http:// url to specify an inet socket
# ...


一些配置文件的含义, 来源 https://www.jianshu.com/p/805977544d7f:

[program:usercenter]
directory = /home/leon/projects/usercenter       ; 程序的启动目录
command = gunicorn -c gunicorn.py wsgi:app         ; 启动命令,可以看出与手动在命令行启动的命令是一样的
process_name=%(program_name)s       ; process_name expr (default %(program_name)s)
numprocs=1           ; number of processes copies to start (def 1)
autostart = true     ; 在 supervisord 启动的时候也自动启动
startsecs = 1        ; 启动 1 秒后没有异常退出,就当作已经正常启动了
autorestart = true   ; 程序异常退出后自动重启
startretries = 3     ; 启动失败自动重试次数,默认是 3
user = leon          ; 用哪个用户启动
redirect_stderr = true          ; 把 stderr 重定向到 stdout,默认 false
stdout_logfile_maxbytes = 20MB  ; stdout 日志文件大小,默认 50MB
stdout_logfile_backups = 10     ; stdout 日志文件备份数
; stdout 日志文件,需要注意当指定目录不存在时无法正常启动,所以需要手动创建目录(supervisord 会自动创建日志文件)
stdout_logfile = /data/logs/usercenter_stdout.log
;这一配置项的作用是:如果supervisord管理的进程px又产生了若干子进程,使用supervisorctl停止px进程,停止信号会传播给px产生的所有子进程,确保子进程也一起停止。这一配置项对希望停止所有进程的需求是非常有用的。
stopasgroup=true

; 可以通过 environment 来添加需要的环境变量,一种常见的用法是修改PYTHONPATH ;process environment additions      
; environment=PYTHONPATH=$PYTHONPATH:/path/to/somewhere

主要参考:

常用

  1. 已有密钥生成公钥
openssl rsa -in app_private_key.pem  -put app_public.pem 
  1. 支付宝回调参数
ipdb> request.form                                                                                                                                                                            
ImmutableMultiDict([('gmt_create', '2018-11-06 17:24:31'), ('charset', 'utf-8'), ('gmt_payment', '2018-11-06 17:24:46'), ('notify_time', '2018-11-06 17:24:47'), ('subject', 'elllfjdl'), ('sign', 'rB/dXq+3IkqGwMSSOG1DpiGzGGfe2L7nTBNP+XGVhDiHzL1rRGCXQfIrApd+05d9hP/sfAq+sSB+PvvMbKxGDBPNWFEBKiFj5pzo+bnDiUMF6MDGaV2M7OCq8xkr/sl4yPYv/GhqT7I3TUYRgqdrW8mvPC7EBupW0TWgBX4ghb7F8FX47EJCkUYCprbHZX/hW0GxJtGxYxq6s+3qeDktICaOk9c4jsKoZDHMpCZfoco6/Rec8g7nnRRORiWxYX/YQF5tsLowzmz1I7owRL6m2pB1ccfH3NVEQdfScToEgl5D9D5Xl7VEa2eWoDQm5NocUuuFfkUXsY7fOryLtoh/UA=='), ('buyer_id', '2088102176406494'), ('invoice_amount', '0.01'), ('version', '1.0'), ('notify_id', '1997cfd51e7c1de6050d2d11205ca77js9'), ('fund_bill_list', '[{"amount":"0.01","fundChannel":"ALIPAYACCOUNT"}]'), ('notify_type', 'trade_status_sync'), ('out_trade_no', 'kfcDNMZ8nZ8jfqpmg5baa4qlFufoRps1'), ('total_amount', '0.01'), ('trade_status', 'TRADE_SUCCESS'), ('trade_no', '2018110622001406490500653962'), ('auth_app_id', '2016091900546396'), ('receipt_amount', '0.01'), ('point_amount', '0.00'), ('app_id', '2016091900546396'), ('buyer_pay_amount', '0.01'), ('sign_type', 'RSA2'), ('seller_id', '2088102176308352')])
ipdb> request.form.to_dict()                                                                                                                                                                  
{'gmt_create': '2018-11-06 17:24:31', 'charset': 'utf-8', 'gmt_payment': '2018-11-06 17:24:46', 'notify_time': '2018-11-06 17:24:47', 'subject': 'elllfjdl', 'sign': 'rB/dXq+3IkqGwMSSOG1DpiGzGGfe2L7nTBNP+XGVhDiHzL1rRGCXQfIrApd+05d9hP/sfAq+sSB+PvvMbKxGDBPNWFEBKiFj5pzo+bnDiUMF6MDGaV2M7OCq8xkr/sl4yPYv/GhqT7I3TUYRgqdrW8mvPC7EBupW0TWgBX4ghb7F8FX47EJCkUYCprbHZX/hW0GxJtGxYxq6s+3qeDktICaOk9c4jsKoZDHMpCZfoco6/Rec8g7nnRRORiWxYX/YQF5tsLowzmz1I7owRL6m2pB1ccfH3NVEQdfScToEgl5D9D5Xl7VEa2eWoDQm5NocUuuFfkUXsY7fOryLtoh/UA==', 'buyer_id': '2088102176406494', 'invoice_amount': '0.01', 'version': '1.0', 'notify_id': '1997cfd51e7c1de6050d2d11205ca77js9', 'fund_bill_list': '[{"amount":"0.01","fundChannel":"ALIPAYACCOUNT"}]', 'notify_type': 'trade_status_sync', 'out_trade_no': 'kfcDNMZ8nZ8jfqpmg5baa4qlFufoRps1', 'total_amount': '0.01', 'trade_status': 'TRADE_SUCCESS', 'trade_no': '2018110622001406490500653962', 'auth_app_id': '2016091900546396', 'receipt_amount': '0.01', 'point_amount': '0.00', 'app_id': '2016091900546396', 'buyer_pay_amount': '0.01', 'sign_type': 'RSA2', 'seller_id': '2088102176308352'}

Alembic隐藏数据库配置信息

Alembic数据库迁移使用参考: https://blog.csdn.net/deerlux/article/details/50181997


此迁移工具的详细配置信息在alembic.ini文件中, 其中包括

sqlalchemy.url = driver://user:[email protected]/dbname

为了防止不小心将密码信息提交, 可将此行删除,并修改alembic/env.py

import sys

sys.path.append(os.path.realpath('.'))
from planet.common.base_model import DB_PARAMS

from planet import models
# this is the Alembic Config object, which provides
# access to the values within the .ini file in use.


config = context.config
config.set_main_option('sqlalchemy.url', DB_PARAMS)  # 关键行

target_metadata = None

target_metadata = models.Base.metadata

ctrlp.vim, ack.vim, syntastic快捷键速查

一. ctrlp.vim

ctrlp.vim可以模糊查询定位:工程下的所有文件,打开的buffer,buffer内的tag,最近访问的文件.
进入搜索模式后的快捷键:

* <f5> 更新目录缓存。
* <c-f> / <c-b> 在模式之间切换
* <c-d> 在”完整路径匹配“ 和 ”文件名匹配“ 之间切换
* <c-r> 在“字符串模式” 和 “正则表达式模式” 之间切换
* <c-j> / <c-k> 上下移动光标
* <c-t> 在新的 tab 打开文件
* <c-v> 垂直分割打开
* <c-x> 水平分割打开
* <c-p>, <c-n> 选择历史记录
* <c-y> 文件不存在时创建文件及目录
* <c-z> 标记/取消标记, 标记多个文件后可以使用 <c-o> 同时打开多个文件

更多:

git: https://github.com/ctrlpvim/ctrlp.vim

以及比较丑的官网: http://kien.github.io/ctrlp.vim/

二. ack.vim

ack是一个全局搜索工具, 比Vim自带的grep快很多。

?           帮助,显示所有快捷键
Enter/o     打开文件
O           打开文件并关闭Quickfix
go          预览文件,焦点仍然在Quickfix
t           新标签页打开文件
q           关闭Quickfix

更多:

git: https://github.com/mileszs/ack.vim

三. syntastic

e
打开错误列表

\n
移动到下一个错误位置

\p
移动到上一个错误位置

更多:

git: https://github.com/vim-syntastic/syntastic

其他

本配置中, ctrlp和ack的前缀分别为: ,e,r

sentry with flask

sentry 安装过程参考:

centos7下部署sentry日志管理服务

flask 配置

from raven.contrib.flask import Sentry
sentry = Sentry(app, dsn='YOUR_DSN_HERE')

或者,如果使用了工厂,那么可以在稍后初始化:

from raven.contrib.flask import Sentry
sentry = Sentry(dsn='YOUR_DSN_HERE')

def create_app():
    app = Flask(__name__)
    sentry.init_app(app)
    ...
    return app

YOUR_DSN_HERE会在创建sentry项目的时候给出,

邮件配置

邮件配置在 docker-compose.yml 里面可以新增 额外的环境变量:

配置完成后重启docker项目:

docker-compose down && docker-compose up -d

SMTP 已经生效,点击测试发送即可收到一封测试email