前言:

  最近有个项目需要上线,是python中sanic网络异步框架写的,并且要求使用docker+nginx来部署项目实现负载均衡,于是乎百度了sanic项目部署,基本上都是基于docker+gunicorn部署sanic项目这篇文章,里面讲的也稍稍微有些简略,不过对于小白特别不友好,按步骤操作肯定是不行的,因为文章中只举了很小很小的一个例子,感觉更像demo。而小白可能只是临时接受部署任务,按部就班的操作是会出现很多错误的。现在就来排排坑。(建议先看一遍再动手部署)

一、Dockerfile文件放在哪?

  这是sanic项目的总目录,首先明确一点我的主运行文件是run.py,所以Dockerfile需要放在和我主文件相同地方,这样执行build指令就可以直接在当前目录下创建。可以直接使用vim指令在该项目目录下创建Dockerfile,记住文件名一定要相同

二、Dockerfile里面写什么?为什么要写

FROM taoliu/gunicorn3

WORKDIR /temp1

ADD . /temp1

RUN pip install --upgrade pip

RUN pip install -r requirements.txt -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com

EXPOSE 9010

CMD gunicorn run:app --bind 0.0.0.0:9010 --worker-class sanic.worker.GunicornWorker

  下面一个个来解释

  FROM:表示这个镜像是基于什么创建的,也就是基础镜像,这里使用taoliu/gunicorn3表示我使用的是gunicorn3来运行我的镜像,可以理解为项目需要一个环境来运行。而这个镜像是国内的,所以下载会较快

  WORKDIR:表示工作目录是在docker中的哪里,可以稍微理解一下docker是个独立的系统,就像安装在Windows中虚拟机虚拟的linux,和外面的Windows命令和目录是不相互关联的。而这个目录也是我们后面执行命令所在的目录。

  ADD:这里使用ADD . /temp1,前面的“.”表示将当前所在目录的所有文件全部放到docker中的/temp1这里要和上面的WORKDIR设置的一样,命名按照自己喜欢的来,这里是测试就用temp1代替

  RUN:就相当于开始运行指令(可以理解为在linux中输入命令行,但其实这是在docker环境中输入的)了,docker中的系统一些python依赖的库是不存在的,所以我们开始先更新一下docker中的pip,再由pip获取项目所需镜像,这里我整理到了固定的文件内即requirements.txt,推荐使用国内镜像。这样下载较快,我使用的是阿里云镜像。

  阿里云:http://mirrors.aliyun.com/pypi/simple/

  豆瓣:http://pypi.douban.com/simple/

  清华大学:https://pypi.tuna.tsinghua.edu.cn/simple/

  中国科学技术大学:http://pypi.mirrors.ustc.edu.cn/simple/

  华中科技大学:http://pypi.hustunique.com/

  EXPOSE:设置镜像暴露端口,记录容器启动时监听哪些端口,容器启动时,Docker Daemon会扫描镜像中暴露的端口,如果加入-P参数,Docker Daemon会把镜像中所有暴露端口导出,并为每个暴露端口分配一个随机的主机端口(暴露端口是容器监听端口,主机端口为外部访问容器的端口)

  注意:EXPOSE只设置暴露端口并不导出端口,只有启动容器时使用-P/-p才导出端口,这个时候才能通过外部访问容器提供的服务

  CMD:设置容器的启动命令,也就是当我们启动容器的时候执行的命令,我的项目端口是0.0.0.0:9010,文件是run,所以使用gunicorn3启动时,命令为上述文件中。需要注意的是Dockerfile中只能有一条CMD命令,如果写多了则最后一条生效

三、build镜像

  上面的步骤处理完之后就可以build出新镜像了,使用下面命令:

sudo docker build -t sanic_item .

  这里千万要加后面的点,代表当前路径下创建镜像

四、使用run还是使用create+start

  在对于新技术肯定要经过较多的测试才能很好的掌握,如果使用下面这条命令:

sudo docker run --name sanic1 -p 8080:8080 sanic_item

  --name:为容器起个别名,这样可以使用这个别名操作容器,而不需要用随机的容器ID来进行操作

  -p:来指定端口,前面的端口是linux的,后面的端口是docker中项目运行的端口,两个可以一样可以不一样。但是为了方便开发及测试,建议尽量一样.

  后面就是镜像名了。而这条run语句就等于create+start即创建并开启容器。这里说一下容器是基于镜像来运行的。关于容器和镜像的关系要深入docker中了解。这里不详细介绍。这条语句的弊端就是第一次使用的部署可以使用,但是如果第二次还使用,那么就会不停的创建新容器。在不了解的情况下,以为run指令只会运行镜像。没想到docker中是根据镜像来创建容器再运行。滥用run指令的结果图:

  可以看出很多是基于一个镜像来创建的容器。其实第一次使用完run之后便可使用一些经常使用的命令:

sudo docker stop sanic1 #停止当前运行的容器,前提是run指令时有--name来指代名字
sudo docker start sanic1 #只需要启动就行,不需要再用run或create
sudo docker ps #查看当前运行镜像
sudo docker ps -a #查看当前容器状态,正在运行的容器PORTS列会有参数,上图就是没有容器正在运行
sudo docker rmi 镜像ID/别名 #需要先使用ps指令找到要删除的镜像ID再删除
sudo docker rm 容器ID/别名 #比如删除sanic1这个容器sudo docker rm sanic1

五、使用nginx实现负载均衡

  首先明确一点一个端口不能同时被两个程序所占用。就打个比方来说,现在的项目前端发来的请求访问的是8080端口,如果是单机版项目,直接运行监听8080即可。但是目前遇到的情况是项目部署在docker上,还要启动nginx来监听。也就会造成这个端口有两个进程在监听,这时候只能启动一个。并且我们要部署多个后台服务。所以首先考虑nginx。我的nginx配置文件如下(注意看中文注释部分)

http { #代表HTTP协议其他的协议需要其他定义
include mime.types;
default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' #这里规定的是日志的输出格式,建议打开
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
  
#access_log logs/access.log main;
  
sendfile on;
#tcp_nopush on; #keepalive_timeout 0;
keepalive_timeout 65; #gzip on;
  server{
listen 8080;#监听8080端口
server_name localhost;
   access_log /usr/logs/host1.access.log main;#开启日志功能,只要访问这个端口的都会有输出,具体的名字和目录自己指定,main为上面定义的日志格式
location /{
  proxy_pass http://localhost; #对于发送到8080端口的请求可以进行转发
  }
}
  server { #nginx默认服务,这里只需要放入前端界面即可
listen 80;
server_name localhost; #charset koi8-r; access_log /usr/logs/host.access.log main; #不同端口我建立了不同日志,必须要保证日志所在目录有效才会创建,同时日志我这里没设置无缓存刷出,若要看见实时消息的才设置
root /usr/local/dist2/;
# location / {
# root html;
# index index.html index.htm;
location /{
index index.html index.htm;
  }
} upstream localhost{#这里是实现负载均衡的策略,我的上一篇博客中介绍过为什么使用这种方法
ip_hash;
server 0.0.0.0:9010 weight=1;
server 0.0.0.0:9011 weight=1;
server 0.0.0.0:9012 weight=1;
}
}#这里代表HTTP协议的请求即定义的服务完成

  可以看到我们对于8080端口的请求,转发到了9010,9011,9012三个端口,那么docker需要准备三个不同镜像,来创建三个不同容器,这样才能实现nginx的代理。对于sanic项目只需要改一下运行端口即可,其余部分相同,Dockerfile中的端口也要与其对应。比如我当前的sanic项目改了三个不同端口为9010,9011,9012。(对应上面讲的Dockerfile也要变),然后build三个不同镜像为sanic_item1,sanic_item2,sanic_item3。然后启动三个命令窗口输入下面的指令

sudo docker run --name sanic1 -p 9010:9010 sanic_item1
sudo docker run --name sanic2 -p 9011:9011 sanic_item2
sudo docker run --name sanic3 -p 9012:9012 sanic_item3

  便能运行三个容器了。

  注意:这里介绍的是纵向扩展的负载均衡架构,也是一个介绍。如果多台其实只要改ip地址即可,端口可以不改变。这里所说的docker+nginx实现负载均衡,不需要Nginx部署在docker内部,Nginx只是一个请求转发的工具,如果是遇到上千万级请求或上亿级,超过了nginx的负荷才需要部署多台。主要的压力还是在后端和前端处理和解析数据上。

总结:

  这篇博客主要是目前使用sanic项目部署的资料特别少,而这么少的资料中整理起来,以及遇到的一些bug很难查找。所以稍微讲了一下部署项目遇到的坑和解决方案。建议先通读一遍,脑子里大概有个印象再上手部署。

  补充一点:为什么要部署在docker上,因为Docker有点像Git,也就是你创建完的镜像,可以上传到DockerHub中让别人或者开发组的其他人下载,实现一次部署就能到处运行,emmm,我觉得这才是最主要的。不然上述部署过程完全能够在linux中实现。

 

记基于docker+gunicorn部署sanic项目遇到的很多很多坑的更多相关文章

  1. docker自动化部署前端项目实战一

    docker自动化部署前端项目实战一 本文适用于个人项目,如博客.静态文档,不涉及后台数据交互,以部署文档为例. 思路 利用服务器node脚本,监听github仓库webhook push事件触发po ...

  2. docker中部署django项目~~Dockfile方式和compose方式

    1.  背景:   本机win10上,后端django框架代码与前端vue框架代码联调通过. 2.  目的:   在centos7系统服务器上使用docker容器部署该项目. 3.  方案一:仅使用基 ...

  3. Nginx 和 Gunicorn 部署 Django项目

    目录 Nginx 和 Gunicorn 部署 Django项目 配置Nginx 安装配置Gunicorn 通过命令行直接启动 Gunicorn 与 uwsgi 的区别,用哪个好呢 Gunicorn u ...

  4. 庐山真面目之十微服务架构 Net Core 基于 Docker 容器部署 Nginx 集群

    庐山真面目之十微服务架构 Net Core 基于 Docker 容器部署 Nginx 集群 一.简介      前面的两篇文章,我们已经介绍了Net Core项目基于Docker容器部署在Linux服 ...

  5. 基于docker 如何部署surging分布式微服务引擎

    1.前言 转眼间surging 开源已经有1年了,经过1年的打磨,surging已从最初在window 部署的分布式微服务框架,到现在的可以在docker部署利用rancher 进行服务编排的分布式微 ...

  6. Docker实战部署JavaWeb项目-基于SpringBoot

    最近在滴滴云上看到服务器很便宜,1核2G,1年只需要68块钱.下面是我基于Docker部署Javaweb服务的过程.目前我见过的最便宜的服务器,阿里云打折的时候都没有这么便宜啊,果断入手.有需要的话可 ...

  7. 基于Docker一键部署大规模Hadoop集群及设计思路

    一.背景: 随着互联网的发展.互联网用户的增加,互联网中的数据也急剧膨胀.每天产生的数据量数以万计,本地文件系统和单机CPU已无法满足存储和计算要求.Hadoop分布式文件系统(HDFS)是海量数据存 ...

  8. Docker如何部署Python项目

    Docker 部署Python项目 作者:白宁超 2019年5月24日09:09:00 导读: 软件开发最大的麻烦事之一就是环境配置,操作系统设置,各种库和组件的安装.只有它们都正确,软件才能运行.如 ...

  9. mac和linux下使用Docker,部署SpringBoot项目到docker

    主要是看一下如何在linux及mac上安装docker,创建docker镜像,部署SpringBoot项目到docker,并借助于DaoCloud进行docker镜像下载加速等. 我用的电脑是mac, ...

随机推荐

  1. 【基本数据结构之堆】-C++

    注意:这篇博客讲的是手写堆,喜欢用C++自带数据结构模拟的慎入 今天我们来聊一聊一种奇怪 的数据结构: 堆 为什么说这个数据结构有点奇怪呢? 先看看其他的在我眼里是正常的数据结构: 队列(近似于排队) ...

  2. python爬虫笔记之re.match匹配,与search、findall区别

    为什么re.match匹配不到?re.match匹配规则怎样?(捕一下seo) re.match(pattern, string[, flags]) pattern为匹配规则,即输入正则表达式. st ...

  3. MediatR-进程内的消息通信框架

    MediatR是一款进程内的消息订阅.发布框架,提供了Send方法用于发布到单个处理程序.Publish方法发布到多个处理程序,使用起来非常方便.目前支持 .NET Framework4.5..NET ...

  4. C#3.0新增功能09 LINQ 基础04 基本 LINQ 查询操作

    连载目录    [已更新最新开发文章,点击查看详细] 本篇介绍 LINQ 查询表达式和一些在查询中执行的典型操作. 获取数据源 在 LINQ 查询中,第一步是指定数据源. 和大多数编程语言相同,在使用 ...

  5. Elasticsearch 7.x Nested 嵌套类型查询 | ES 干货

    一.什么是 ES Nested 嵌套 Elasticsearch 有很多数据类型,大致如下: 基本数据类型: string 类型.ES 7.x 中,string 类型会升级为:text 和 keywo ...

  6. 关于Object.defineProperty 的基础知识

    Object.defineProperty 这个方法大家耳熟能详,可以对 对象的属性进行添加或修改的操作.即可以进行  数据劫持 .vue就是通过这个方法来劫持数据的. 平时我们创建对象的时候,一般通 ...

  7. php 自己封装一个调用第三方接口的函数

    ①在php.ini中开启php_curl扩展(必须开启) ②建议在php.ini中开启php_openssl扩展(本身不是curl必须的,是调用一些第三方接口需要的 ③如果以上操作重启apache后, ...

  8. Anaconda大法好,为什么要用Anaconda(附linux安装与用例)

    距离写上一个博客已经过去很久了,注册的时候我还是个大三学生抱着windows系统的visual studio在OPENCV等等复杂组件下面瑟瑟发抖,一不小心就担心hpp找不到了,依赖库没了,或者安装了 ...

  9. 彻底搞懂Python切片操作

        在利用Python解决各种实际问题的过程中,经常会遇到从某个对象中抽取部分值的情况,切片操作正是专门用于完成这一操作的有力武器.理论上而言,只要条件表达式得当,可以通过单次或多次切片操作实现任 ...

  10. 【python-django后端开发】Redis缓存配置使用详细教程!!!

    官方查阅资料:https://django-redis-chs.readthedocs.io/zh_CN/latest/ 1. 安装django-redis扩展包 1.安装django-redis扩展 ...