今天我们来聊一个让很多开发者都比较头疼的问题,这个问题就是项目部署。传统的项目部署,开发团队和运维团队的职责划分并不是特别清楚,开发团队通常要产出可以部署到生产环境的项目,还要负责向运维团队提供相应的文档,文档中必须要对项目所依赖的底层库、三方模块、数据持久化方案、缓存、消息队列、环境参数等一系列的内容加以说明。首选这些工作本身就不是很轻松,而且最为关键的问题是无法保证开发环境和运行环境是一致的。面试的时候也经常有面试官问“有没有遇到项目在开发环境能运行,到了生产环境就出问题的情况,你是如何解决的”之类的问题。
开发环境和生产环境的不一致,还会随着应用的复杂性而加剧,尤其是在将原来的单体应用改造成微服务架构的时候。微服务架构对部署提出了更高的要求,因为每个微服务使用的编程语言、技术栈、依赖的其他服务都可能完全不同,这些都会给部署带来更大的难度。所以,我们需要虚拟化容器技术来解决这些问题,而在所有的容器化技术中,Docker可能是目前最为流行的方案。
简单的说,基于Docker的虚拟化容器技术最为关键的地方在于,我们可以将需要部署的项目做成一个镜像,而这个镜像中包含了项目所依赖的全部内容。将来我们只需要把一个镜像交给运维团队,而运维团队通过这个镜像可以创建一个或多个容器来运行我们的项目,再对这些容器进行管理就可以了。
在介绍Docker之前,我们要先来解释一个叫“LXC”的名词。维基百科上对LXC的解释是:“LXC是Linux软件容器的缩写,是一种操作系统层虚拟化技术,它是Linux内核容器功能的一个用户空间接口。在Linux内核中,提供了cgroups
功能来达成资源的区隔化,与此同时也提供了名称空间区隔化的功能,使应用程序看到的操作系统环境被区隔成独立区间,包括进程树、网络、用户ID以及挂载的文件系统”。Docker是基于Go语言开发的开源应用容器引擎,对LXC做了进一步的封装,可以管理LXC的环境并提供了简单易用的使用接口,是目前最为流行的Linux容器解决方案。
目前,Docker主要被用在以下几个领域:
可以按照下面描述的步骤来安装Docker,我们以CentOS为例。
第1步:确定操作系统内核版本(CentOS 7要求64位,内核版本3.10+;CentOS 6要求64位,内核版本2.6+)。
uname -r
第2步:更新系统底层的库文件(建议一定要执行,否则在使用Docker时可能会出现莫名其妙的问题)。
yum update
第3步:移除可能存在的旧的Docker版本。
yum erase -y docker docker-common docker-engine
第4步:安装yum工具包和Docker底层依赖项。
yum install -y yum-utils device-mapper-persistent-data lvm2
第5步:通过yum工具包添加yum安装docker-ce的源。
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
第6步:在CentOS下使用yum安装docker-ce并启动。
yum -y install docker-ce
第7步:启动Docker服务。
systemctl start docker
第8步:查看Docker版本和信息。
docker version
docker info
下面我们带着大家一起来创建几个容器,先感受一下虚拟化容器技术的魅力。
Nginx是高性能的Web服务器,同时也是做反向代理服务器的上佳选择,使用Docker可以帮助我们用极为简单的方式创建出运行Nginx的容器。
首先,我们来下载Nginx的官方镜像。如果你有安装操作系统或大型软件的系经验,对镜像这个词一定不会陌生,镜像就类似于我们安装软件时使用的光盘或者ISO文件。我们可以通过下面的命令从Docker仓库中下载Nginx的官方镜像。
docker pull nginx:latest
如果没有特殊说明,默认是从官方提供的镜像仓库来下载该镜像,在我是用的阿里云服务器上,该命令连接的是阿里云提供的官方仓库的替代,因为国内的仓库下载速度更快。当然,如果愿意也可以通过修改/etc/docker
目录下的daemon.json
文件来指定下载镜像时所使用的镜像仓库,如下所示。
{
"registry-mirrors": [
"http://hub-mirror.c.163.com"
]
}
提示:修改了配置文件之后,需要重新启动Docker服务。
可以使用docker images
来查看所有下载过的镜像,也可以使用docker rmi
命令通过镜像的ID来删除指定的镜像。通过镜像创建容器可以使用docker run
命令,如果没有提前使用docker pull
下载指定的镜像文件,那么在docker run
的时候也会先下载该镜像文件,然后再基于该镜像创建容器。
docker container run -d -p 80:80 --rm --name webserver nginx:latest
说明:上面的参数
-d
是--detach
的缩写,表示容器在后台运行并显示容器的ID;-p
是--publish
的缩写,用来映射容器的端口到宿主机的端口,冒号前面是宿主机的端口,冒号后面是容器内部使用的端口;--rm
表示容器停止后自动删除容器,执行命令docker stop webserver
后,容器就不复存在了;--name
后面是自定义容器的名字;在创建容器的过程中,需要用到nginx的镜像文件,镜像文件的下载是自动完成的,如果没有指定版本号,默认是latest
。
如果需要将自己的Web项目部署到Nginx上,可以使用容器拷贝命令将指定路径下所有的文件和文件夹拷贝到容器的指定目录中。
docker cp /root/web/index.html mynginx:/usr/share/nginx/html
如果不愿意拷贝文件,可以在创建容器时用数据卷操作实现目录映射,通过--volume
或-v
将指定的文件夹映射到容器的/usr/share/nginx/html
目录,如下所示。
docker run -d -p 80:80 --rm --name webserver -v /root/html:/usr/share/nginx/html nginx:latest
提示:如果要重新创建名为
webserver
的容器,需要先删除之前创建的容器。可以通过docker stop webserver
来停掉它使其自动删除,也可以通过docker rm -f webserver
来强行删除运行中的容器。
至此,我们可以打开浏览器来查看部署到容器中的Web项目了。如果需要查看运行中的容器,可以使用docker ps
命令;如果希望看到所有的容器,可以使用docker container ls -a
命令。
通过上面的例子,相信大家已经感受到了容器的便捷性,我们再来尝试用Docker创建运行MySQL服务的容器。
这次我们首先来确认一下有没有名为MySQL的镜像。
docker search mysql
INDEX NAME DESCRIPTION STARS OFFICIAL AUTOMATED
docker.io docker.io/mysql MySQL is a ... 8486 [OK]
...
说明:上面查询结果的列依次代表索引、镜像名、镜像描述、用户评价、是否官方镜像、自动构建。
下载MySQL镜像并指定镜像的版本号。
docker pull mysql:5.7
创建并运行MySQL容器。
docker run -d -p 3306:3306 --name mysql57 -v /root/mysql/conf:/etc/mysql/mysql.conf.d -v /root/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7
注意:在创建容器时我们使用了数据卷操作,那是因为容器通常是即用即删的,而数据库中的数据却是需要保留下来的。上面的命令中,我们执行了两个数据卷操作,一个是映射了MySQL配置文件所在的文件夹,一个是映射了MySQL数据文件所在的文件夹。在创建该容器的时候,我们还用了
-e
参数来指定环境参数,通过MYSQL_ROOT_PASSWORD=123456
来为MySQL指定超级管理员账号root
对应的口令。当然,在实际应用中,不建议大家使用像123456
这样的弱口令,因为它会给你的系统带来潜在的风险。
到此为止,我们已经掌握了如何通过官方提供的镜像来创建并运行容器。如果愿意,我们也可以创建自己的镜像甚至将这些镜像发布到官方镜像仓库或者是自己的私有仓库中。推荐大家使用Dockerfile的方式来构建自己的镜像,下面我们通过例子来说明Dockerfile的使用。
我们首先来编写如下所示的Dockerfile文件,Dockerfile文件是用DSL(领域特定语言)描述的构建一个Docker镜像的指令清单,只要编辑好了这个文件,就可以通过docker build
来构建我们自己的镜像了。
# 指定基础镜像
FROM python:3.7
# 指定镜像的维护者
MAINTAINER jackfrued "jackfrued@126.com"
# 设置工作目录
WORKDIR /root
# 从版本控制克隆代码
RUN git clone https://gitee.com/jackfrued/apidemo.git
# 设置工作目录
WORKDIR /root/apidemo
# 安装项目依赖项
RUN pip install -r requirements.txt -i https://pypi.doubanio.com/simple/
# 为启动脚本添加执行权限
RUN chmod 755 start.sh
# 容器启动时要执行的命令
ENTRYPOINT ["./start.sh"]
# 暴露端口
EXPOSE 8000
Dockerfile中使用的指令对于懂英语的人来说并不难理解,我们在后续的文章中会为大家专门讲解Dockerfile中的指令。上面的代码通过执行git clone
命令从Git仓库克隆了代码,这里我们先简单介绍一个apidemo
这个项目。这个项目非常简单,由三个文件构成,分别是项目的代码、依赖项清单和启动脚本。
app.py
文件是我们用Flask编写的提供API接口的Web后端服务,简单起见并没有使用数据库而是将数据放在了一个列表容器中,代码如下所示。
from flask import Flask
from flask_restful import Resource, Api
from flask_cors import CORS
app = Flask(__name__)
CORS(app, resources={r'/api/*': {'origins': '*'}})
api = Api(app)
class Product(Resource):
def get(self):
products = ['Ice Cream', 'Chocolate', 'Coca Cola', 'Hamburger']
return {'products': products}
api.add_resource(Product, '/api/products')
requirements.txt
文件是项目的依赖项清单,有Python开发经验的对这个文件一定不会陌生。其中,flask-restful
是用来简化API接口开发的三方库,而flask-cors
是用来解决跨域数据请求的三方库,gunicorn
是我们运行Python项目的WSGI服务器,由于添加了gevent
库,在启动该服务器时,通过--worker-class=gevent
参数和--woker-connections=xxx
参数可以改善服务器的性能,因为gevent
解决了Python中通过线程的方式来无感知使用协程的问题。
flask
flask-restful
flask-cors
gunicorn
gevent
在说一下start.sh
文件,它是项目的启动脚本,用来启动Gunicorn服务器,代码如下所示。
#!/bin/bash
exec gunicorn -w 4 -b 0.0.0.0:8000 --worker-class=gevent --worker-connections=512 app:app
接下来我们可以使用docker build
命令来创建镜像,如下所示。
docker build -t "jackfrued/myapp" .
提示:上面的命令中,
-t
参数用来指定镜像的名字;最后面的.
表示从当前路径下寻找Dockerfile。当然,如果你的Dockerfile文件并不在当前路径下,也可以通过绝对路径或相对路径的方式指出Dockerfile文件的位置。
到这里,我们可以使用docker images
指令看看我们自己的镜像是否已经创建好了。
接下来我们就可以在容器中部署Python项目了,因为有了我们自己定制的镜像,部署项目的工作就变成了一条非常简单的命令。
docker run -d -p 8000:8000 --name myapp jackfrued/myapp:latest
执行完上面的命令后,就可以打开浏览器访问服务器的8000端口了,因为上面的项目没有前端页面,我们直接访问API接口,对应的URL路径是/api/products
。
至此,我们已经完成了通过容器部署Python项目的工作,大家一定感受到了容器的简单和强大。但是目前我们使用的apidemo
这个项目过于简单,甚至没有数据库和缓存,也没有部署前端页面。在后续的文章中,我们会实现项目的前后端分离,把项目需要用到的数据库服务器、缓存服务器、消息队列服务器等全部加入进来,并为大家介绍如何实现多个容器的管理。多个容器能够协同工作才能支撑起一个真正意义上的项目,这些内容会在后续更新的文章中为大家阐述,也希望大家能够点赞支持我继续创作。
如果你对Python感兴趣,想要学习python,这里给大家分享一份Python全套学习资料,都是我自己学习时整理的,希望可以帮到你,一起加油!
😝有需要的小伙伴,可以V扫描下方二维码免费领取🆓
?
对于从来没有接触过Python的同学,我们帮你准备了详细的学习成长路线图。可以说是最科学最系统的学习路线,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。
还有很多适合0基础入门的学习视频,有了这些视频,轻轻松松上手Python~
每节视频课后,都有对应的练习题哦,可以检验学习成果哈哈!
学习Python常用的开发软件都在这里了!每个都有详细的安装教程,保证你可以安装成功哦!
光学理论是没用的,要学会跟着一起敲代码,动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。100+实战案例源码等你来拿!
如果觉得上面的实战案例有点枯燥,可以试试自己用Python编写小游戏,让你的学习过程中增添一点趣味!
我们学会了Python之后,有了技能就可以出去找工作啦!下面这些面试题是都来自阿里、腾讯、字节等一线互联网大厂,并且有阿里大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。
上述所有资料 ?? ,朋友们如果有需要的,可以扫描下方👇👇👇二维码免费领取🆓
?