每日分享
It's up to you how far you go. If you don't try, you'll never know!
能走多远取决于你自己,如果不愿尝试,你将永远不会知道!
小闫语录:
长路漫漫,唯夜作伴。如果因前路的未知,丧失了尝试的勇气,前路将永远变成未知。
插播一条消息
3月11日邓先生询问一个问题,今天才看到,回复的时候发现已经过了48小时,无法主动联系你。所以在此回答您的问题,向您表示歉意。因为后台是机器人回复,好多人在逗它,导致消息超多,所以您的消息被淹没了,不好意思哈。
问题
请问,在执行docket的时候提示内存空间不足,怎么办?(我想了一会,查了一下百度,不清楚docket是什么🤔,你应该是想问docker吧....如果不是请告知)
思路
因为不了解您的具体情况,无法做出准确的判断,所以向您提供一些解决的思路:
1.查看Docker的磁盘使用情况:
docker system df
2.清理磁盘,删除关闭的容器、一些没用的数据卷和网络,还有那些没有tag的镜像:
docker system prune
3.更加彻底的清理:
1
docker system prune -a
2、3命令慎用,它会将你暂时关闭的容器以及暂时没有使用的docker镜像都删除。同时docker system命令是1.13版本之后才有的命令,建议使用新版的docker。
4.另外一种思路是查看/var/lib/docker/目录下的文件,docker的镜像和容器等等所有文件都在这个目录下,看看真正占用空间的是什么文件。
5.如果是上线的项目,日志文件会超大,可以将日志文件备份后删除,当然这方法有点傻,日志还是会生成。那么可以限制容器的日志大小。如果是自己线下测试的项目,日志可能并不是很大,视情况而定。
6.最后是一招百试百灵的方法:重启docker。俗话说没有什么是『重启』解决不了的问题,如果有,那就多重启几次。
如果还是无法解决,可以看本文docker相关的命令尝试动手解决,也可以选择CSDN、Google上查询相关经验贴。
笔试题
1.什么是SQL注入,如何防止,ORM中如何防止?
答:SQL注入就是利用正常的SQL语句,获取到了非法的数据。防御措施大体有以下几点:对用户的输入进行校验,可以通过正则表达式或限制长度;对单引号和 --
等特殊字符进行转义;不要动态的拼接SQL语句,使用参数化的SQL(下面的例子就是使用参数化解决SQL注入)查询数据库;永远不要使用管理员权限的数据库连接,为每个应用使用单独的权限有限的连接数据库;不要把机密的信息直接存放,而是经过hash加盐加密等措施保护敏感数据;应用的异常信息应该尽可能的少提示,最好使用自定义的错误信息对原始错误信息进行包装。(永远不要信任用户的任何输入,很有可能对面是一个想要攻击你的黑客!!!!)ORM底层其实是使用了参数化的形式执行SQL语句,而且ORM接口是属于内部封装机制,对外无接口,理论上很安全了,但是凡事没有绝对,万一要攻击你数据库的是一位高手呢?那么怎么办呢?如果是这样,说明你公司已经十分的厉害了,能让一个人耗费老鼻子劲攻击,到这种程度,你公司的财富应该也请得起比对面黑客更牛x的人了吧,还是不用你操心,开不开心。当然这是一句玩笑话,毕竟小编知识有限,如果你找到了ORM攻击的方式与解决措施,别忘了联系我。
举例说明SQL注入
我们在书写查询语句的时候,有可能涉及到占位符进行数据替换,后面接入用户输入的用户名和密码之类的数据:
select * from user where username = '%s' and password = '%s';
如果用户输入了一些特殊的字符,那么会产生一些严重的后果(拖库,直接获取到所有的数据)。比如用户的用户名输入了 root' or 1 --
,然后将其拼接到上述的SQL语句中,会出现下面的现象:
select * from user where username = 'root' or 1 -- ' and password = '%s';
-- 代表注释的意思
上述查询条件where为 username='root'
或者是 1
,后面的密码因为 --
的出现变成了注释,不会执行,因此只对用户名进行校验。username无论对与错,因为是逻辑运算符 或
,后面 1
代表真,判断条件永远成立,那么直接返回查询结果。
就问你可怕不可怕,当然上面只是利用简单的一个例子进行说明。你肯定会问,那么就不能防止SQL注入吗?答案是可以的。那就是参数化,问题又来了,什么是参数化呢?就是我们在python数据库编程的时候,将 SQL 语句的所有数据参数存在一个元组(或者列表、字典)中传递给 execute 函数的第二个参数。下面演示效果:
from pymysql import * # 创建数据库连接 db_connect = Connect(host='localhost',port=3306,database='test_db',user='root',password='123123',charset='utf8') # 获取游标 cur = db_connect.cursor() # 请输入一个查询的ID query_id = input('please input ID:') # 使用参数化来解决SQL注入 # 以字符串形式书写SQL语句,因为SQL语句中也会出现字符串,避免单引号或者双引号的错误,我们直接使用三引号进行书写 sql_str = ''' select * from students where id = %s ''' # 在准备SQL字符串时,不能再直接拼接参数 # 而是将参数做成一个元组,列表,字典,传入到 execute 方法中 # 下面执行SQL语句,并传入元组形式的参数 cur.execute(sql_str, (query_id,)) # 获取所有的数据 result = cur.fetchall() # 遍历出所有的结果 for t in result: print(t) # 关闭游标 cur.close() # 关闭数据库 db_connect.close()
部署相关知识
部署方面最重要的知识分为两块,一块是Nginx,一块是Docker,下面就这两块内容,进行阐述。
1. Nginx
Nginx是一款基于异步框架的轻量级服务器,它支持高并发量,能高效的处理相关业务。平时我们用来做web服务器、缓存服务器以及反向代理服务器,当然它还能做邮件服务器。那么它除了支持高并发,还有什么优点吗?内存消耗少,配置简单还稳定,扔到远程服务器上基本就不用管了。如果公司想用有限的资源解决更多的问题,那么它是首选,因为它便宜啊,还支持多系统。最最重要的一点,就是它善于处理静态文件,因此我们常常将静态文件放到Nginx上,减少后端服务器的压力。
1.1相关命令
查看Nginx状态(active或者dead):
systemctl status nginx
启动|停止|重启|重新加载Nginx服务器:
systemctl start|stop|restart|reload nginx
其实上面的命令用来开启关闭还是太麻烦,那么可以使用下面的命令替换:
nginx 启动 nginx -s stop|reload 停止|重载
检查配置文件是否符合语法要求(超级重要,在工作中只要配置文件发生改变,马上要执行的命令就是这个,检查完之后再重新启动。否则最后出错,难以排查问题):
nginx -t
查看当前系统下开启服务所占用端口的信息:
netstat -tnulp
配置文件目录:
/etc/nginx/conf.d
文件的结构要明白:
全局配置段 http配置段 server配置段 # 项目或者应用的网站 location配置段 # 网站里面的文件url
1.2 Nginx访问原理
浏览器拆分URL地址获取相关的请求。分为地址、端口和路径关键字。其中每个请求的目的是根据地址找服务器,根据端口找服务器上的应用,路径关键字用于location匹配。
url:
协议:// 网站地址:端口 (/)路径地址 ? 参数
server配置段:
server { listen 端口; server_name 主机名; ... }
location配置:
location optional_modifier location_match {...}
optional_modifier:匹配条件;location_match是匹配的样式;{...}:要执行的操作。
另外补充一点:location常见的动作中,alias 相当于$uri 直接去alias指定的目录下请求就可以了,是绝对路径。而root 则是到root指定的目录下的$uri/ 去找,是相对路径。
1.3正向代理&反向代理
从安全性来讲,正向代理可以保护客户端的身份,而反向代理则是保护服务器的身份。
我们翻阅天朝的墙时,使用的VPN就是正向代理。当我们爬取数据,采用高匿IP时,也是正向代理,毕竟要保护爬虫工程师的人生安全嘛。那么什么是反向代理呢?我们采用的Nginx就是反向代理啊?忘记了吗?
1.4Nginx代理模块
关键参数就是 proxy_pass
,设定的是请求跳转后的地址,也就是被代理服务器的地址和被映射的URI。
server{ listen 99; location / { proxy_pass http://192.168.33.24:888/ethanyan/; } }
一定要注意
proxy_pass
中的地址结尾处的/
。有没有结果大不相同。
1.5负载均衡(超级重要)
上面我们使用 proxy_pass
的方式实现了Nginx反向代理,请求后端。当网站的访问量越来越多的时候,一台服务器就有点力不从心了,那么怎么办,就是采用负载均衡。简单的理解就是多准备几台服务器,就是这么简单粗暴。
负载均衡就用到了我们Nginx中的 upstream
模块。它定义了一个后端服务地址的集合列表,每个后端服务使用一个server命令指定。它还可以通过一系列的属性设置负载均衡中的主机情况。
down 当前主机故障时,直接进行隔离 backup 后备主机,当线上主机故障或者访问量剧增服务器繁忙时,才开启 max_fails 允许请求的最大失败数,默认是1,配合下一个参数使用 fail_timeout 经历max_fails次失败后,暂停服务的时间,默认为10s。
最后说一个是常识,但是超级重要的命令:
curl [option] [url] 如: curl http://www.ethanyan.com # 执行之后请求的页面内容就显示在屏幕上了,作为一个运维人员,或者一个后端服务器工程师,这个命令如果不晓得就说不过去了
1.6Nginx调度算法
内置策略:
轮询
:默认算法,按服务器顺序依次转发相关请求。(要雨露均沾嘛)
加权轮询
:指定轮询权重,值越大,分配到的几率就越大,适合后端服务器性能不均衡的情况。
ip_hash
:按访问IP的哈希结果分配请求,让同一个IP访问固定一台服务器,有效的解决动态网页会话共享问题。
第三方算法:
fair
:这个是按服务器的响应时间来分配请求的,当某一台服务器请求无延迟,直接就将请求交给他了。
url_hash
:按url的哈希结果来分配请求,使得同一个URL定向到同一台后端服务器,可提高后端缓存服务器的效率。
1.7日志
日志地址: /var/log/nginx
还可以定制日志,在下面的文件中进行配置:
/etc/nginx/nginx.conf
2. Docker
一提到Docker,你脑中蹦出来的词是什么呢?虚拟化、容器等等。如果是这些,那么说明你了解到了它的精髓。它没有固定的概念,曾有人这么描述:Docker是一种快速解决生产问题的技术手段。文绉绉,难以理解。
Docker其实就是将开发环境完整封装的一个容器,它解决了开发工程师和运维人员之间的甩锅操作,开发是什么样子,测试就是什么样子。还有部署项目的时候,怎么实现负载均衡,手动一台台配啊?那不得累死,直接将Docker搬过去啊,下载打开运行成功,立马搞定。
2.1相关操作
启动docker:
systemctl start docker
查看Docker的状态:
systemctl status docker
Docker服务命令:
docker start | stop | restart docker
删除命令:
你还真看啊,涉及到删除命令,哥劝你用的时候手动查一下,利用查询的时间思考一下
搜索镜像:
docker search [image_name]
先在本地仓库找,找不到去网络仓库找
获取镜像:
docker pull [image_name]
查看镜像:
docker images # 查看一个镜像 docker images [image_name]
查看镜像历史信息:
docker history nginx
查看历史操作过的命令以及产生文件的大小
重命名,打标签:
docker tag [old_image]:[old_version] [new_image]:[new_version]
删除镜像:
docker rmi [IMAGE ID] 或: docker rmi [image]:[image_version]
Docker的家目录:
/var/lib/docker
将Docker的镜像导出,进行备份:
docker save -o [包文件] [镜像] 如: docker save -o nginx.tar ethanyan-nginx
导入镜像:
1. docker load < [image.tar_name] 2. docker load --input [image.tar_name] 查看正在运行的容器:
docker ps
查看所有运行过的容器:
docker ps -a
启动容器;
1. docker run <参数,可选> [docker_image] [执行的命令] 2. # 让Docker容器在后台以守护形式运行 3. docker run -d [docker_image] 4. # 启动已经终止的容器 5. docker start [container_id]
创建并进入到容器里面:
docker run --name [container_name] -it [docker_image] /bin/bash --name 给容器定义一个名字 -i 让容器的标准输入保持打开 -t 让docker分配一个伪终端,并绑定在容器的标准输入上
进入到容器里面:
docker exec -it <容器id> /bin/bash
关闭容器:
docker stop [container_id]
基于容器创建镜像:
docker commit -m <注释> -a <作者> [container_id] [new_image]:[new_version]
查看容器所有的详细信息:
docker inspect [container_name]
查看容器运行日志:
docker logs [container_id]
2.2私有仓库部署
1.下载registry镜像:
docker pull registry
2.启动容器:
docker run -d -p 5000:5000 --restart=always registry
--restart 代表的是什么时间重启
3.检查容器效果:
curl 127.0.0.1:5000/v2/_catelog
4.配置容器权限:
vim /etc/docker/daemon.json {"registry-mirrors":["http://74f21445.m.daocloud.io"], "insecureregistries":["192.168.8.14: 5000"]}
私有仓库ip地址是宿主机的ip,而且ip两侧要有双引号
5.重启docker服务:
systemctl restart docker systemctl status docker
效果查看:
docker start <container_id> docker tag ubuntu-mini 192.168.33.24:5000/buntu-16.04-mini docker push 192.168.33.24:5000/ubuntu-16.04-mini docker pull 192.168.33.24:5000/ubuntu-16.04-mini
打标签时版本号如果不指定,默认是latest。