原文转载自「刘悦的技术博客」https://v3u.cn/a_id_203

容器,又见容器。Docker容器的最主要优点就在于它们是可移植的。一套服务,其所有的依赖关系可以捆绑到一个独立于Linux内核、平台分布或部署模型的主机版本的单个容器中。此容器可以传输到另一台运行Docker的主机上,并且在没有兼容性问题的情况下执行。而传统的微服务架构会将各个服务单独封装为容器,虽然微服务容器化环境能够在给定数量的基础架构内实现更高的工作负载密度,但是,在整个生产环境中创建、监视和销毁的容器需求总量呈指数级增长,从而显著增加了基于容器管理环境的复杂性。

藉此,本次我们将服务化零为整,将Tornado服务和Nginx服务器以及配套的监控管理程序Supervisor集成到一个单独的容器中,将其高度可移植性最大化地发挥。

Docker具体安装流程请移玉步到:一寸宕机一寸血,十万容器十万兵|Win10/Mac系统下基于Kubernetes(k8s)搭建Gunicorn+Flask高可用Web集群

整体容器内的系统架构如图所示:

首先,创建项目目录 mytornado:

mkdir mytornado

这里web服务框架我们使用业内著名的非阻塞异步框架Tornado6.2,创建一个服务的入口文件main.py

import json
import tornado.ioloop
import tornado.web
import tornado.httpserver
from tornado.options import define, options define('port', default=8000, help='default port', type=int) class IndexHandler(tornado.web.RequestHandler):
def get(self):
self.write("Hello, Tornado") def make_app():
return tornado.web.Application([
(r"/", IndexHandler),
]) if __name__ == "__main__":
tornado.options.parse_command_line()
app = make_app()
http_server = tornado.httpserver.HTTPServer(app)
http_server.listen(options.port)
tornado.ioloop.IOLoop.instance().start()

这里运行端口我们通过命令行传参的方式进行监听,方便多进程服务的启动。

之后,创建 requirements.txt 项目依赖文件:

tornado==6.2

接下来,创建Nginx的配置文件 tornado.conf

upstream mytornado {
server 127.0.0.1:8000;
server 127.0.0.1:8001;
}
server {
listen 80; location / {
proxy_pass http://mytornado;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}

这里Nginx监听80端口,反向代理到本地系统的8000和8001端口,这里我们使用默认的负载均衡方案:轮询,如果有其他需求,可以按照其他的方案进行修改:

1、轮询(默认)
每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器down掉,能自动剔除。 upstream backserver {
server 192.168.0.14;
server 192.168.0.15;
} 2、权重 weight
指定轮询几率,weight和访问比率成正比,用于后端服务器性能不均的情况。 upstream backserver {
server 192.168.0.14 weight=3;
server 192.168.0.15 weight=7;
} 3、ip_hash( IP绑定)
上述方式存在一个问题就是说,在负载均衡系统中,假如用户在某台服务器上登录了,那么该用户第二次请求的时候,因为我们是负载均衡系统,每次请求都会重新定位到服务器集群中的某一个,那么已经登录某一个服务器的用户再重新定位到另一个服务器,其登录信息将会丢失,这样显然是不妥的。 我们可以采用ip_hash指令解决这个问题,如果客户已经访问了某个服务器,当用户再次访问时,会将该请求通过哈希算法,自动定位到该服务器。 每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,可以解决session的问题。 upstream backserver {
ip_hash;
server 192.168.0.14:88;
server 192.168.0.15:80;
} 4、fair(第三方插件)
按后端服务器的响应时间来分配请求,响应时间短的优先分配。 upstream backserver {
server server1;
server server2;
fair;
} 5、url_hash(第三方插件)
按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器,后端服务器为缓存时比较有效。 upstream backserver {
server squid1:3128;
server squid2:3128;
hash $request_uri;
hash_method crc32;
}

下面我们编写Supervisor的配置文件supervisord.conf:

[supervisord]
nodaemon=true [program:nginx]
command=/usr/sbin/nginx [group:tornadoes]
programs=tornado-8000,tornado-8001 [program:tornado-8000]
command=python3.8 /root/mytornado/main.py --port=8000
# 执行目录
directory=/root/mytornado
# 自动重启
autorestart=true
# 启动supervisor时,程序自启动
autostart=true
# 日志
stdout=/var/log/tornado-8000.log
redirect_stderr=true
loglevel=info [program:tornado-8001]
command=python3.8 /root/mytornado/main.py --port=8001
# 执行目录
directory=/root/mytornado
# 自动重启
autorestart=true
# 启动supervisor时,程序自启动
autostart=true
# 日志
stdout=/var/log/tornado-8001.log
redirect_stderr=true
loglevel=info

Supervisor 是专门用来在类 Unix 系统上监控管理进程的工具,发布于 2004 年,它对应的角色分别为 Supervisorctl 和 Supervisord。后者的主要作用是启动配置好的程序、响应 Supervisorctl 发过来的指令以及重启退出的子进程,而前者是 Supervisor 的客户端,它以命令行的形式提供了一系列参数,来方便用户向 Supervisord 发送指令,常用的有启动、暂停、移除、更新等命令。

这里我们主要使用Supervisor针对Tornado服务进行监控和管理,这里默认的项目目录为/root/mytornado/

进程配置两个,分别对应nginx的监听端口:8000和8001

最后,编写容器配置文件Dockerfile:

FROM yankovg/python3.8.2-ubuntu18.04  

RUN sed -i "s@/archive.ubuntu.com/@/mirrors.163.com/@g" /etc/apt/sources.list \
&& rm -rf /var/lib/apt/lists/* \
&& apt-get update --fix-missing -o Acquire::http::No-Cache=True
RUN apt install -y nginx supervisor pngquant # application
RUN mkdir /root/mytornado
WORKDIR /root/mytornado
COPY main.py /root/mytornado/
COPY requirements.txt /root/mytornado/
RUN pip install -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple/ # nginx
RUN rm /etc/nginx/sites-enabled/default
COPY tornado.conf /etc/nginx/sites-available/
RUN ln -s /etc/nginx/sites-available/tornado.conf /etc/nginx/sites-enabled/tornado.conf
RUN echo "daemon off;" >> /etc/nginx/nginx.conf # supervisord
RUN mkdir -p /var/log/supervisor
COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf # run
CMD ["/usr/bin/supervisord"]

这里基础镜像选择预装了Python3.8的Ubuntu18,兼具了小体积和可扩展的特性,添加apt-get的安装源之后,分别安装Nginx以及Supervisor。

随后,依照Supervisor配置文件内所书,在容器内部创建项目目录/root/mytornado/

并且将上面编写好的main.py以及requirements.txt复制到容器内部,运行pip install -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple/ 安装项目的所有依赖。

最后,将tornado.conf和supervisord.conf也拷贝到对应的配置路径中,分别启动Nginx和Supervisor服务。

编写好之后,在项目根目录的终端内运行命令打包镜像:

docker build -t 'mytornado' .

首次编译会等待一小会儿,因为需要下载基础镜像服务:

liuyue:docker_tornado liuyue$ docker build -t mytornado .
[+] Building 16.2s (19/19) FINISHED
=> [internal] load build definition from Dockerfile 0.1s
=> => transferring dockerfile: 37B 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [internal] load metadata for docker.io/yankovg/python3.8.2-ubuntu18.04:latest 15.9s
=> [internal] load build context 0.0s
=> => transferring context: 132B 0.0s
=> [ 1/14] FROM docker.io/yankovg/python3.8.2-ubuntu18.04@sha256:811ad1ba536c1bd2854a42b5d6655fa9609dce1370a6b6d48087b3073c8f5fce 0.0s
=> CACHED [ 2/14] RUN sed -i "s@/archive.ubuntu.com/@/mirrors.163.com/@g" /etc/apt/sources.list && rm -rf /var/lib/apt/lists/* 0.0s
=> CACHED [ 3/14] RUN apt install -y nginx supervisor pngquant 0.0s
=> CACHED [ 4/14] RUN mkdir /root/mytornado 0.0s
=> CACHED [ 5/14] WORKDIR /root/mytornado 0.0s
=> CACHED [ 6/14] COPY main.py /root/mytornado/ 0.0s
=> CACHED [ 7/14] COPY requirements.txt /root/mytornado/ 0.0s
=> CACHED [ 8/14] RUN pip install -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple/ 0.0s
=> CACHED [ 9/14] RUN rm /etc/nginx/sites-enabled/default 0.0s
=> CACHED [10/14] COPY tornado.conf /etc/nginx/sites-available/ 0.0s
=> CACHED [11/14] RUN ln -s /etc/nginx/sites-available/tornado.conf /etc/nginx/sites-enabled/tornado.conf 0.0s
=> CACHED [12/14] RUN echo "daemon off;" >> /etc/nginx/nginx.conf 0.0s
=> CACHED [13/14] RUN mkdir -p /var/log/supervisor 0.0s
=> CACHED [14/14] COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf 0.0s
=> exporting to image 0.0s
=> => exporting layers 0.0s
=> => writing image sha256:2dd8f260882873b587225d81f7af98e1995032448ff3d51cd5746244c249f751 0.0s
=> => naming to docker.io/library/mytornado 0.0s

打包成功后,运行命令查看镜像信息:

docker images

可以看到镜像总大小不到1g:

liuyue:docker_tornado liuyue$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mytornado latest 2dd8f2608828 4 hours ago 828MB

接着让我们来启动容器:

docker run -d -p 80:80 mytornado

通过端口映射技术,将容器内的80端口服务映射到宿主机的80端口。

输入命令查看服务进程:

docker ps

显示正在运行:

docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
60e071ba2a36 mytornado "/usr/bin/supervisord" 6 seconds ago Up 2 seconds 0.0.0.0:80->80/tcp, :::80->80/tcp frosty_lamport
liuyue:docker_tornado liuyue$

此时我们打开浏览器访问 http://127.0.0.1

没有任何问题。

同时可以根据运行中的容器id来选择进入对应的容器:

liuyue:docker_tornado liuyue$ docker exec -it 60e071ba2a36 /bin/sh
#

在容器内部我们可以看到项目的所有文件:

# pwd
/root/mytornado
# ls
main.py requirements.txt
#

重要的是,可以使用Supervisor对既有的Tornado进程进行管理操作,

查看所有进程:

supervisorctl status

根据配置文件,我们容器内运行着三个服务:

# supervisorctl status
nginx RUNNING pid 10, uptime 0:54:28
tornadoes:tornado-8000 RUNNING pid 11, uptime 0:54:28
tornadoes:tornado-8001 RUNNING pid 12, uptime 0:54:28

依据服务名称,对服务进行停止操作:

# supervisorctl stop tornadoes:tornado-8001
tornadoes:tornado-8001: stopped
# supervisorctl status
nginx RUNNING pid 10, uptime 0:55:52
tornadoes:tornado-8000 RUNNING pid 11, uptime 0:55:52
tornadoes:tornado-8001 STOPPED Dec 28 08:47 AM
#

再次启动:

# supervisorctl start tornadoes:tornado-8001
tornadoes:tornado-8001: started
# supervisorctl status
nginx RUNNING pid 10, uptime 0:57:09
tornadoes:tornado-8000 RUNNING pid 11, uptime 0:57:09
tornadoes:tornado-8001 RUNNING pid 34, uptime 0:00:08
#

如果服务进程意外终止,Supervisor可以对其进行拉起操作,满血复活:

# ps -aux | grep python
root 1 0.0 0.1 55744 20956 ? Ss 07:58 0:01 /usr/bin/python /usr/bin/supervisord
root 11 0.0 0.1 102148 22832 ? S 07:58 0:00 python3.8 /root/mytornado/main.py --port=8000
root 34 0.0 0.1 102148 22556 ? S 08:48 0:00 python3.8 /root/mytornado/main.py --port=8001
root 43 0.0 0.0 11468 1060 pts/0 S+ 08:51 0:00 grep python
# kill -9 34
# supervisorctl status
nginx RUNNING pid 10, uptime 1:00:27
tornadoes:tornado-8000 RUNNING pid 11, uptime 1:00:27
tornadoes:tornado-8001 RUNNING pid 44, uptime 0:00:16

如果愿意,也可以将编译好的镜像提交到Dockerhub上,这样可以做到随时使用随时拉取,不需要每次都进行编译操作,这里我已经将镜像推送到云端,需要的话可以直接拉取使用:

docker pull zcxey2911/mytornado:latest

Dockerhub的具体操作流程请参见:利用DockerHub在Centos7.7环境下部署Nginx反向代理Gunicorn+Flask独立架构

结语:诚然,Docker容器技术消除了线上线下的环境差异,保证了服务生命周期的环境一致性标准化。开发者使用镜像实现标准开发环境的构建,开发完成后通过封装着完整环境和应用的镜像进行迁移,藉此,测试和运维人员可以直接部署软件镜像来进行测试和发布,大大简化了持续集成、测试和发布的过程,但是我们也不得不正视容器技术现有阶段的劣势,那就是性能的损耗,Docker容器对CPU和内存的使用几乎没有任何开销,但它们会影响I/O和OS交互。这种开销是以每个I/O操作的额外周期的形式出现的,所以小I/O比大I/O遭受的损失要大得多。这种开销增加了I/O延迟,减少了用于有用工作的CPU周期,从而限制了吞吐量。也许不久的将来,随着内核技术的提升,该缺陷会被逐步解决,最后奉上项目地址,与君共觞:https://github.com/zcxey2911/Docker_Tornado6_Supervisor_Python3.8

原文转载自「刘悦的技术博客」 https://v3u.cn/a_id_203

四位一体水溶交融,Docker一拖三Tornado6.2 + Nginx + Supervisord非阻塞负载均衡容器式部署实践的更多相关文章

  1. nginx反向代理和负载均衡的简单部署

    1.   安装 1)         从Nginx官网下载页面(http://nginx.org/en/download.html)下载Nginx最新版本(目前是1.5.13版本)安装包: 2)    ...

  2. Nginx反向代理,负载均衡,redis session共享,keepalived高可用

    相关知识自行搜索,直接上干货... 使用的资源: nginx主服务器一台,nginx备服务器一台,使用keepalived进行宕机切换. tomcat服务器两台,由nginx进行反向代理和负载均衡,此 ...

  3. Nginx 服务器 之Nginx与tomcat实现负载均衡

      本文讲解我们如何使用Nginx做反向带服务器,实现nginx与tomcat服务器集群做负载均衡. 一.nginx与tomcat实现负载均衡 1.在/usr/local/ngnix/conf  创建 ...

  4. Nginx代理功能与负载均衡详解

    序言 Nginx的代理功能与负载均衡功能是最常被用到的,关于nginx的基本语法常识与配置已在上篇文章中有说明,这篇就开门见山,先描述一些关于代理功能的配置,再说明负载均衡详细. Nginx代理服务的 ...

  5. Nginx+Tomcat+Redis实现负载均衡、资源分离、session共享

    Nginx+Tomcat+Redis实现负载均衡.资源分离.session共享 CentOS安装Nginx http://centoscn.com/CentosServer/www/2013/0910 ...

  6. Nginx做NodeJS应用负载均衡配置实例

    这篇文章主要介绍了Nginx做NodeJS应用负载均衡配置实例,本文直接给出配置实例,需要的朋友可以参考下. 负载均衡可以把用户的请求分摊到多个服务器上进行处理,从而实现了对海量用户的访问支持.负载均 ...

  7. Nginx+Keepalived主主负载均衡服务器

    Nginx+keepalived主主负载均衡服务器测试实验环境: 主Nginx之一:192.168.11.27主Nginx之二:192.168.11.28Web服务器一:192.168.11.37We ...

  8. nginx : TCP代理和负载均衡的stream模块

    一直以来,Nginx 并不支持tcp协议,所以后台的一些基于TCP的业务就只能通过其他高可用负载软件来完成了,比如Haproxy. 这算是一个nginx比较明显的缺憾.不过,在1.90发布后这个认知将 ...

  9. 【转】Nginx+Tomcat搭建高性能负载均衡集群

    最近对负载均衡比较感兴趣,研究了公司的负载均衡的配置,用的是阿里的SLB,相当于不用运维,只需要在后台进行简单的配置就能完成Tomcat的负载均衡,索性在网上找了几篇文章去尝试搭建一个集群,然而很多都 ...

随机推荐

  1. IE 浏览器将停止服务,这是真的吗?

    浏览器通常是指用来检索.展示以及传递 Web 资源信息的一种应用程序,它能将网页.图片.视频等等 Web 上的信息呈现给我们. 如果现在发起一个投票:"你觉得好用的浏览器是什么?" ...

  2. 【多线程】线程优先级 Priority

    线程优先级 Priority Java提供一个线程调度器来监控程序中启动后进入就绪状态的所有线程,线程调度 器按照优先级决定应该调度哪个线程来执行. 线程的优先级用数字表示,范围从1~10. Thre ...

  3. 在MySQL中保存Java对象

    需要在MySQL中保存Java对象. 说明: 对象必须实现序列化 MySQL中对应字段设置为blob 将Java对象序列化为byte[] public static byte[] obj2byte(O ...

  4. MyBatis 结果映射总结

    前言 结果映射指的是将数据表中的字段与实体类中的属性关联起来,这样 MyBatis 就可以根据查询到的数据来填充实体对象的属性,帮助我们完成赋值操作.其实 MyBatis 的官方文档对映射规则的讲解还 ...

  5. python之数据类型的内置方法(set、tuple、dict)与简单认识垃圾回收机制

    目录 字典的内置方法 类型转换 字典取值 修改值 计算字典长度 成员运算 删除元素 获取元素 更新字典 快速生成字典 setdefault()方法 元组的内置方法 类型转换 索引与切片操作 统计长度 ...

  6. K8S 使用Minikube搭建Kubernetes(K8S)~单机运行Kubernetes~适用于快速学习

    在一台主机上运行起来的Kubernetes,仅适用于学习!~~~ 系统版本:CentOS Linux release 7.6.1810 (Core) 软件版本:Docker-ce-18.06.0.Ku ...

  7. thusc2022游记

    DAY -1: 刷往年相关的题 DAY 0: 刷会儿题了,搞电脑,下obs.不过,发现电脑出了很多问题. obs没有录频效果,因为卡,杀毒软件把vc++全都删了.因此无dll文件错误,搞了一晚上都没搞 ...

  8. Eclipse for C/C++ 开发环境部署保姆级教程

    Eclipse for C/C++ 开发环境部署保姆级教程 工欲善其事,必先利其器. 对开发人员来说,顺手的开发工具必定事半功倍.自学编程的小白不知道该选择那个开发工具,Eclipse作为一个功能强大 ...

  9. BUUCTF-神秘龙卷风

    神秘龙卷风 通过提示知道压缩包密码是四位纯数字,通过爆破得到 得到一串编码 看样子应该是brainfuck编码 flag{e4bbef8bdf9743f8bf5b727a9f6332a8}

  10. 自己实现一个自定义React项目脚手架「ReactCli」

    前言 首先为什么想到自己实现一个React脚手架呢?是因为之前刚接触create-react-app时,觉得不太灵活.虽然文件目录很清晰,但是还是觉得不如VueCLI的可以自定义配置更加灵活.当然Re ...