为了搭建Scrapy-Redis服务而反复地被Docker折麽了数天,终于对于Docker的使用有了一些理解,本文记录初用Docker的一些注意事项。
一些理解可能不够准确,望指正。
1.为什么要使用Docker
下面是两个我遇到需要使用Docker的典型情景:
-
情景1:安装配置数据库等服务
- 非Docker:拿数据库举例,如果我们需要一个Mysql、Redis或Mongodb数据库,配过环境的同学都知道,该过程往往需要下载安装包、解压、编译、配置设置文件等过程。这些过程往往会被一些错误或时间过早的博文误导而导致环境配置失败。且如果一步做错,想要重新卸载干净再重新安装时,往往会因为遗留问题而导致重装失败。
- Docker:两行代码安装运行一切数据库,基本不需要考虑环境配置问题,因为Docker中的容器基本都是配置好的,直接可以用于生产的。且可以很方便地开多个容器(多个数据库),删除重装的操作也很简单。
-
情景2:安装配置自己的应用
- 非Docker:以部署Scrapy-Redis分布式爬虫框架为例。在单机下需要安装Scrapy、安装Scrapy-Redis,需要配置很多Python包,需要运行Scrapyd服务。在单机搭建完成后,如果想把这一切都重新在第二个服务器上部署,麻烦且难免会出现一些问题。
- Docker:把配置好的单机环境打包成Docker容器,在其他服务器上下载容器即可。不仅方便、快捷,最重要的是可以保证各个结点的一致性。
2. Docker容器是如何存在的?
我曾不明白为何Docker既可以拉一个ubuntu系统,又可以拉一个mysql数据库,或者说可以拉任何应用。
这个问题我是这样理解的(这里没有特别认真地查询资料,待指正):Docker可以制作任何可以运行在linux系统中的应用。事实上,如果我们制作一个mysql数据库镜像,也是需要指定一个linux系统版本:通常是ubuntu。我们使用docker pull mysql
拉取下来的mysql,如果我们用docker exec -it mysql bash
以bash进入该容器的话,也可以发现这就是一个ubuntu系统,我们可以用apt-get update
升级,之后可以用apt-get install vim
安装文本编辑器vim。
3. Docker和虚拟机的区别?
很多文章如: Docker与虚拟机的简介以及比较 已指出Docker与虚拟机在架构、量级与安全性等方面的差异。我的理解是:
- Docker更加适合于应用的部署
- 虚拟机更适合作为服务器
因此,如果需要搭建一个分布式的服务,之前的做法是用多台服务器来做分布式。如果服务器不够,就用虚拟机当服务器。Docker并不能改变这个状况,它还不适合作为一个服务器。
4. 如何写好docker run指令
以Docker安装Redis服务为例。
我们首先需要pull一个Redis镜像(在不指定特定版本时,默认安装最新的版本):
docker pull redis
之后可以通过docker image ls
查看pull后的镜像列表。
要想使用镜像,需要用docker run
指令。
很多博客只是说要docker run -p 6379:6379 --name redis redis
就可以运行Redis服务,其中-p是配置端口号。但这样简单的一行代码仍给了我很大困惑:
- 不使用Docker镜像时,我们需要编写配置文件
redis.conf
、再用redis-server redis.conf
运行Redis-server。这里如果想修改配置,该如何指定配置文件? - 用上述方法开启了Redis后,这个redis指的是redis-server吗?最后的两个redis分别是什么意思?
反复试验后我得到了一个自己最心仪的docker run指令:
docker run -p 6379:6379 --name redis_server -v /root/doc/redis.conf:/etc/redis/redis.conf -v /root/doc/data:/data -d redis redis-server /etc/redis/redis.conf --appendonly yes
-p
是指定端口,形式为:主机端口/容器端口。如果这里写成6378:6379
,说简单点就是我们在自己的服务器的6378端口可以看到docker容器中6379端口发出的内容。如果我们需要创三个redis服务,分别使用6377:6379
、6378:6379
、6379:6379
执行三次docker run
就可以分别在自己服务器的三个6377~6379三个端口部署三个Redis服务了。--name redis_server
是对要创建的容器进行命名。这里的意思是用redis
镜像创建一个名为redis_server
的容器。选择的镜像redis
在命令中写在了-d
后面。-v
是指定配置文件位置。Redis有两个常用的配置:一个是配置文件redis.conf
,另一个data
文件夹。这里和-p
一样,也是指定本机文件位置/容器文件位置。如:-v /root/doc/redis.conf:/etc/redis/redis.conf
就是在把自己主机/root/doc/redis.conf
文件映射到docker容器中的/etc/redis/redis.conf
中。我们由此可以先在主机中写好配置文件,然后就可以使用这个配置文件来启动Redis服务了。-d
是指定该容器一直在后台运行的意思。redis
在前面提到了。是指定的镜像redis-server /etc/redis/redis.conf --appendonly yes
是使用镜像的指令,这些都是Redis自己的事了。因为我要使用配置文件去运行redis-server,所以我运行的是这行代码。如果不需要使用配置文件运行redis-server,直接使用redis
,或redis-server
即可。然后我指定了一个Redis运行指令:appendonly,是让Redis中的数据持久化存储,即将数据保存到磁盘上。
5. 何为docker exec
在创建好镜像后,可以使用docker exec -it [镜像名] bash
进入镜像的bash命令行中。
这也是之前在第2步分钟提到过的,每个镜像其实都存在于一个linux系统中。
还是以Redis服务为例,Redis在开启redis-server
后,往往需要使用redis-cli
客户端。这时,我们就可以先运行docker exec -it redis_server bash
进入bash命令行,然后运行redis-cli
进入客户端。
很多时候run一个容器的目的就是进入该容器的bash,常常可以通过sh -c '[command]'
合并成一步进行操作:
例如我们希望快速进入一个redis-cli的bash(基于上述已建立好的一个redis_server容器):
$ docker run -it --rm --link some-redis:redis_server redis sh -c 'exec redis-cli -h "$REDIS_PORT_6379_TCP_ADDR" -p "$REDIS_PORT_6379_TCP_PORT"'
注1:docker run --link
可以用来链接2个容器,使得源容器(被链接的容器)和接收容器(主动去链接的容器)之间可以互相通信,并且接收容器可以获取源容器的一些数据,如源容器的环境变量。
注2:docker run --rm
是容器运行完成后即删除。
6. 如何删除容器
这里要注意的是:删除容器之前必须先停止容器。
使用docker ps
可以查看到运行中的容器。这里的容器都是不可以删除的。
使用docker ps -a
查看所有容器。只有停止运行的容器可以删除。
让容器停止的指令是docker stop [container_name / container_id]
停止后可以删除:docker rm [container_name / container_id]
容器的id往往很长,一般输入前两个字符即可。
7. 如何编写Dockerfile
待补