docker部署机器学习/深度学习模型的容器化方案

docker部署机器学习或深度学习模型正在成为企业大规模部署的一种常规操作

什么是docker

Docker 是一个开源的应用容器引擎,基于 Go 语言 并遵从Apache2.0协议开源。
Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。
容器是完全使用沙箱机制,相互之间不会有任何接口(类似 iPhone 的 app),更重要的是容器性能开销极低。

Docker 的主要用途,目前有三大类。
(1)提供一次性的环境。比如,本地测试他人的软件、持续集成的时候提供单元测试和构建的环境。
(2)提供弹性的云服务。因为 Docker 容器可以随开随关,很适合动态扩容和缩容。
(3)组建微服务架构。通过多个容器,一台机器可以跑多个服务,因此在本机就可以模拟出微服务架构。

docker的优点

快速交付和部署
方便扩容
资源利用率高,一台主机上可以同时运行数千个docker容器. 传统用虚拟机的方式, 运行10个应用就要起10个虚拟机, docker只要启动10个隔离的应用就可以。 管理简单, 修改可以用增量的方式被分发和更新

针对常见业务场景,每个人电脑开发的开发环境都不一样,要不就是python版本不一样,要不就是TensorFlow版本不一样,避免出现我的代码只能在自己机器上跑的尴尬局面出现,因此建立一个统一的开发部署环境就成为必然。

docker image镜像

操作系统分为内核和用户空间。对于 Linux 而言,内核启动后,会挂载 root 文件系统为其提供用户空间支持。而 Docker 镜像(Image),就相当于是一个 root 文件系统。比如官方镜像 ubuntu:18.04 就包含了完整的一套 Ubuntu 18.04 最小系统的 root 文件系统。
Docker 镜像是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。镜像不包含任何动态数据,其内容在构建之后也不会被改变。
Docker 把应用程序及其依赖,打包在 image 文件里面。只有通过这个文件,才能生成 Docker 容器。image 文件可以看作是容器的模板。Docker 根据 image 文件生成容器的实例。同一个 image 文件,可以生成多个同时运行的容器实例。
image 是二进制文件。实际开发中,一个 image 文件往往通过继承另一个 image 文件,加上一些个性化设置而生成。举例来说,你可以在 Ubuntu 的 image 基础上,往里面加入 Apache 服务器,形成你的 image。

#  列出本机的所有 image 文件。
docker image ls
# 删除 image 文件
docker image rm [imageName]

image 文件是通用的,一台机器的 image 文件拷贝到另一台机器, 完全可以复用。

Dockerfile 文件

学会使用 image 文件以后,接下来的问题就是,如何可以生成 image 文件?如果你要推广自己的软件,势必要自己制作 image 文件。
这就需要用到 Dockerfile 文件。它是一个文本文件,用来配置 image。Docker 根据 该文件生成二进制的 image 文件。

** Dockerfile的常用命令**

FROM: 获取基础镜像
COPY: 复制本机文件到docker容器的指定目录
ADD: 复制解压文件到docker容器的指定目录
RUN: 运行linux命令
WORKDIR: 设置工作目录

Dockerfile配置例子

一个简单的例子
docker image的github链接:

 git clone https://github.com/ruanyf/koa-demos.git
 cd koa-demos

首先,在项目的根目录下,新建一个文本文件.dockerignore,写入下面的内容。

.git
node_modules
npm-debug.log

上面代码表示,这三个路径要排除,不要打包进入 image 文件。如果你没有路径要排除,这个文件可以不新建。
然后,在项目的根目录下,新建一个文本文件 Dockerfile,写入下面的内容。

FROM node:8.4
COPY ./app
WORKDIR /app
RUN npm install --registry=https://registry.npm.taobao.org
EXPOSE 3000

上面代码一共五行,含义如下。
FROM node:8.4:该 image 文件继承官方的 node image,冒号表示标签,这里标签是8.4,即8.4版本的 node。

COPY . /app:将当前目录下的所有文件(除了.dockerignore排除的路径),都拷贝进入 image 文件的/app目录。

WORKDIR /app:指定接下来的工作路径为/app。

RUN npm install:在/app目录下,运行npm install命令安装依赖。注意,安装后所有的依赖,都将打包进入 image 文件。

EXPOSE 3000:将容器 3000 端口暴露出来, 允许外部连接这个端口。

深度学习环境的配置

# base image
FROM ubuntu:18.04
# MAINTAINER

# 安装相应依赖
RUN apt-get update \
&& apt-get install wget curl vim gcc zlib1g-dev bzip2 -y \
&& apt-get install zlib1g.dev \
# 安装libssl1.0-dev解决pip安装时md5模块无法导入问题
&& apt-get install openssl libssl1.0-dev -y \
&& apt-get install g++ build-essential -y \
# && apt-get install python-tk -y \
# && apt-get install tk-dev -y \
&& mkdir /usr/local/source \
# 设置工作目录
WORKDIR /usr/local/source

RUN wget https://www.python.org/ftp/python/2.7.12/Python-2.7.12.tgz \
&& tar xvf Python-2.7.12.tgz && cd Python-2.7.12 \
&& ./configure --prefix=/usr/local/python27 && make && make altinstall \
# 备份旧版本
&& mv /usr/bin/python /usr/bin/python27_old \
# 配置默认python
&& ln -s /usr/local/python27/bin/python /usr/bin/python \
&& ln -s /usr/local/python27/bin/python-config /usr/bin/python-config \
# 下载安装pip
&& curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py \
&& python get-pip.py \
# 备份旧pip
# && mv /usr/bin/pip /usr/bin/pip_old
# 建立连接
&& ln -s /usr/local/python27/bin/pip /usr/bin/pip \
# 安装包
&& cd /usr/local/source \
&& pip install Cython==0.29.7 \
&& pip install pyyaml==5.1 \
&& pip install numpy==1.16.3 \
&& pip install pandas==0.23.2 \
&& pip install scipy==1.2.1 \
&& pip install scikit-learn==0.20.3 \
&& pip install matplotlib==2.1.0 \
&& pip install lightgbm==2.2.2 \
&& pip install catboost==0.13.1 \
&& pip install grpcio==1.20.1 \
&& pip install grpcio-tools==1.20.1 \

-t参数用来指定 image 文件的名字,后面还可以用冒号指定标签。如果不指定,默认的标签就是latest。最后的那个点表示 Dockerfile 文件所在的路径,上例是当前路径,所以是一个点。
如果运行成功,docker image ls就可以看到新生成的 image 文件"koa-demo"了。

创建docker镜像

sudo docker build -it mydocker:v1 . /bin/bash

请记住末尾有个 .(空格+.),后面/bin/bash的目的是镜像创建后直接开启一个并进入容器,进入命令行模式。

拷贝本地文件导docker容器:
sudo docker cp 主机文件路径 容器ID:容器路径 ## 从主机复制文件到容器
docker cp 容器ID:要拷贝的文件在容器里面的路径 要拷贝到宿主机的相应路径

docker container 容器

镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的 类 和 实例 一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。

容器的实质是进程,但与直接在宿主执行的进程不同,容器进程运行于属于自己的独立的 命名空间。因此容器可以拥有自己的 root 文件系统、自己的网络配置、自己的进程空间,甚至自己的用户 ID 空间。容器内的进程是运行在一个隔离的环境里,使用起来,就好像是在一个独立于宿主的系统下操作一样。这种特性使得容器封装的应用比直接在宿主运行更加安全。也因为这种隔离的特性,很多人初学 Docker 时常常会混淆容器和虚拟机。
按照 Docker 最佳实践的要求,容器不应该向其存储层内写入任何数据,容器存储层要保持无状态化。所有的文件写入操作,都应该使用 数据卷(Volume)、或者绑定宿主目录,在这些位置的读写会跳过容器存储层,直接对宿主(或网络存储)发生读写,其性能和稳定性更高。

数据卷的生存周期独立于容器,容器消亡,数据卷不会消亡。因此,使用数据卷后,容器删除或者重新运行之后,数据却不会丢失。

将 image 文件从仓库抓取到本地。

docker image pull library/hello-world

上面代码中,docker image pull是抓取 image 文件的命令。library/hello-world是 image 文件在仓库里面的位置,其中library是 image 文件所在的组,hello-world是 image 文件的名字。
由于 Docker 官方提供的 image 文件,都放在library组里面,所以它的是默认组,可以省略。因此,上面的命令可以写成下面这样。

docker image pull hello-world

抓取成功以后,就可以在本机看到这个 image 文件了。

docker image ls

现在,运行这个 image 文件。

docker container run hello-world

docker container run命令会从 image 文件,生成一个正在运行的容器实例。如果运行成功,你会在屏幕上读到下面的输出。

docker container run hello-world
Hello from Docker!
This message shows that your installation appears to be working correctly
......

输出这段提示以后,hello world就会停止运行,容器自动终止。
有些容器不会自动终止,因为提供的是服务。比如,安装运行 Ubuntu 的 image,就可以在命令行体验 Ubuntu 系统。

docker container run -it ubuntu bash

对于那些不会自动终止的容器,必须使用docker container kill 命令手动终止。

docker container kill [containID]

image 文件生成的容器实例,本身也是一个文件,称为容器文件。也就是说,一旦容器生成,就会同时存在两个文件: image 文件和容器文件。而且关闭容器并不会删除容器文件,只是容器停止运行而已。

模型部署

容器环境创建好以后,就需要把模型文件拷贝到容器里. 为了调用模型,除了基本的调用API接口之外, 还需要额外包装一个通信网络层,外部或者其他的容器发送请求数据给模型容器, 模型容器接收到数据之后, 计算, 返回给发送端结果.

这就是一个典型的rpc框架应用场景. 目前的rpc框架常用的是
1. Thrift,Facebook开源RPC框架,使用稍微复杂,支持跨语言传输,速度快,在测试过程中发现数据的传输不是随着数据量的递增呈线性增长,而是指数增长,适用于单次数据量较少的情况
2. grpc,Google开源RPC框架,使用方法和难度和Thrift一样,速度比Thrift慢,也支持跨多种语言传输,因为TensorFlow生态支持grpc,所以最后在性能满足要求的情况下,选择了grpc

rpc的这两个框架都需要自定义传输数据格式,并使用其特定的编译器生成接口文件,调用这些接口函数即可,并以此创建自己的API接口,完成数据预处理、特征工程、模型预测服务。

另外还有一个安装简单的zerorpc, 缺点是速度慢, 适合对性能要求不高的场景.

参考和更多阅读

https://blog.csdn.net/weixin_39848830/article/details/91400776
http://www.ruanyifeng.com/blog/2018/02/docker-tutorial.html

发布了111 篇原创文章 · 获赞 118 · 访问量 28万+

猜你喜欢

转载自blog.csdn.net/happyhorizion/article/details/101084467