1.避免每次更新代码后都重新安装依赖

最简单的Dockerfile指令打包一个项目(以某python项目为例):


1
2
3
4
5
6
7
8
9
10
# 选择一个基础镜像
FROM python:3.6
# 设置虚拟机中的工作路径
WORKDIR /qqzone
# 将当前目录下所有文件拷贝到工作路径中  
COPY . /qqzone  
# 执行命令,安装依赖
RUN pip install -r requirements.txt
# 执行命令,启动服务
CMD python src/web/server.py

但是这样存在一个巨大的问题,每次更新代码后重新build镜像都会重新安装依赖,会浪费大量时间

有两种途径可以解决这个问题,一是将安装依赖后的环境打包为一个镜像,但是这样做显然有点麻烦,并且每次更新依赖后都得重新打包,因此推荐下面这种方式:使用缓存

先安装依赖再拷贝代码时就会显示Using cache

只需要更改上面的Dockerfile命令如下:


1
2
3
4
5
6
7
8
9
FROM python:3.6
WORKDIR /qqzone
# 先将依赖文件拷贝到项目中
COPY requirements.txt /qqzone
# 执行指令,安装依赖
RUN pip install -i -r requirements.txt
# 拷贝项目文件和代码
COPY . /qqzone
CMD python src/web/server.py

与之前代码不同的是,先单独拷贝依赖文件(requirements.txt)到docker中,再立即安装依赖。由于通常在更新代码之后,依赖文件并没有改变(改变的代码部分在下一步才会被拷贝到镜像中),因此docker在build中会显示“using cache”(调用缓存),从而避免了重新安装依赖。

2. 配置国内Docker镜像(阿里云)

默认的docker镜像在国外,特别慢。这里改为阿里云的镜像,如果是部署到阿里云的服务器的话,速度飞快。

vim /etc/docker/daemon.json

添加如下内容:


1
2
3
4
5
6
7
8
9
10
{
    "registry-mirrors": [
    "https://kfwkfulq.mirror.aliyuncs.com",
    "https://2lqq34jg.mirror.aliyuncs.com",
    "https://pee6w651.mirror.aliyuncs.com",
    "https://registry.docker-cn.com",
    "http://hub-mirror.c.163.com"
    ],
    "dns": ["8.8.8.8","8.8.4.4"]
}

3.修改Docker0默认网段

这简直是个神坑,遇见的情况很罕见!

docker 默认的网络模式是桥接模式,它会在启动时创建一个虚拟的以太网桥,docker0。这个docker0的默认网段是:172.17.0.1/16

一般是没什么问题的,然而,很不幸,这和我们学院提供的免费云服务器的网段冲突了……这就会导致一旦在这个服务器上开启docker,服务器和docker都无法访问(最直接的表现就是ssh直接中断,但还是能通过VNC访问)。所以,这个时候最简单的解决方式就是修改docker的默认网段。

修改后的docker0

vim /etc/docker/daemon.json

添加如下内容:


1
2
3
{
    "bip":"192.168.100.1/24"
}

其中ip和网关都可以自己选,只要不和宿主机的网段冲突就行

参考博客:Docker——–修改Docker0网桥默认网段

4.docker-compose

docker-compose是用来同时启动多个docker容器的工具。比如我写了一个爬虫项目,需要访问redis,最好的方法就是把爬虫项目和redis分布打包为docker镜像,然后用docker-compose来管理(构建、启动、停止等)。

docker-compose 使用yaml做为配置文件,使用时需要和在Dockerfile同一路径下新建文件docker-compose.yml,下面给出一个简单的示例:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
version: '2'

services:
    web:
        build: .
        ports:
            - "80:5000"
        volumes:
            - .:/qqzone
        depends_on:
            - redis
    redis:
        image: redis
        command: redis-server

这里定义了两个镜像,web和redis,其中web是需要构建,redis直接从远程仓库下载镜像,注意其中的depends_on,它表示web模块依赖于redis。

5.访问docker中的redis(Docker 中出现Redis Connection refused)

一般情况下,python连接redis的核心代码如下(使用连接池):


1
2
pool = redis.ConnectionPool(host="127.0.0.1", port=6379, decode_responses=True)
conn = redis.Redis(connection_pool=pool)

127.0.0.1表示的是本地访问,但是在docker-compose 启动程序之后,由于redis和web容器其实属于两个不同的镜像,就是两个不同的虚拟机,所以web容器中再使用127.0.0.1访问redis时就会出现Connection refused。所以,此时应该把host替换为镜像的名称,默认是“redis”。即:


1
2
pool = redis.ConnectionPool(host="redis", port=6379, decode_responses=True)
conn = redis.Redis(connection_pool=pool)

参考博客:Docker Redis Connection refused解决方法

但这样也有不方便的地方,比如我在本地开发时,是用pyCharm直接运行,线上部署才是用的docker,这意味着我需要频繁手动更换host,所以我写了一个用于判断当前应该连接哪个host的函数:

  

(其中get_pool()和get_docker_pool()是返回两个不同的redis连接池)

本质上就是用try except的方法试一下哪个host能正常连接,然后将正确的结果保存下来。因为我开发的是web程序,所以将结果保存在session中,避免频繁的进行判断。

6.清理无用的docker镜像

使用docker在build镜像时,由于各种各样的原因,经常产生一些失败的镜像,并且这些镜像往往体积很大,非常浪费硬盘空间,所以最好经常清理。

查看全部镜像:

docker images

其中REPOSITORY和TAG都为none的镜像就是垃圾镜像,可以使用docker rmi <IMAGE ID> 删除

点击量:225

分类: 开发笔记

发表评论

电子邮件地址不会被公开。 必填项已用*标注