原文转载自「刘悦的技术博客」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/py... 装置我的项目的所有依赖。

最初,将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/...\_Tornado6\_Supervisor\_Python3.8

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