原文转载自「刘悦的技术博客」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