使用Docker部署

Dockerfile仅包含源码及其依赖的Python模块,不包含redis和nginx环境。

注解

您仍需要准备好redis环境,可以参考 NO.1 启动Redis

Docker部署有两种方法,一是使用开发者打包的镜像(就称之为官方镜像),二是自己打包。


1. 官方镜像

位于Docker官方仓库,可以点击查看公开信息。

  • master分支即latest,dev分支标签是dev,其他已发布版本其版本号即标签

这是利用了travis-ci在提交代码后自动构建镜像并上传,所以latest总是构建 master分支,dev标签构建dev分支,而其他tag则是已发布版本的代码(1.4.0+)

拉取master分支(尝鲜版)镜像: docker pull staugur/picbed

拉取dev分支(开发版)镜像: docker pull staugur/picbed:dev

拉取1.4.0镜像: docker pull staugur/picbed:1.4.0

拉取1.5.0镜像: docker pull staugur/picbed:1.5.0

其他诸如1.5.1、1.6.0、1.7.0等等,请参考镜像地址中的tag。

2. 自行打包

v1.4.0增加了Dockerfile文件,它使用alpine3.11 + python3.6,构建完成大概290M。

在 1.6.0 版更改: 重写了Dockerfile,采用分阶段构建,最终打包150M左右。

在 1.8.0 版更改: 更新清减部分依赖,目前构建完成105M左右。

打包步骤如下:

  • 国内环境

    使用国内的软件源安装依赖(默认)

    $ git clone https://github.com/staugur/picbed && cd picbed
    $ docker build -t staugur/picbed .
    
  • 国外环境

    切换到国外官方软件源

    $ git clone https://github.com/staugur/picbed && cd picbed
    $ docker build -t staugur/picbed . --build-arg PIPMIRROR=https://pypi.org/simple
    

小技巧

由于Dockerfile安装了所有依赖(包括本地禁用的扩展依赖),但实际上可能用 不着所有,故可以修改Dockerfile的 pip install 部分,仅安装/requirements/prod.txt

3. 启动运行

3.1 单独启动

$ docker run -tdi --name picbed --net=host --restart=always \
    -e picbed_redis_url=redis://xxx staugur/picbed

这大概是最小的配置了,使用了宿主机网络,监听 127.0.0.1:9514 ,picbed要求的 配置必需有picbed_redis_url,设置redis连接信息。 其他的可选配置请参考 2.3 修改配置 自行设置环境变量。

查看我录制的使用docker单独启动的gif图: picbed-alone-docker.gif

小技巧

可以将容器中的/picbed/static/upload、/picbed/logs挂载到宿主机或数据卷, 前者是本地方式上传图片的保存目录,后者是日志。

示例:把容器内的静态资源(/picbed/static)挂载到数据卷picbed_static中, 把上传目录挂载到宿主机 /data/picbed 目录上, 如此宿主机的nginx可以直接访问了。

$ docker volume create picbed_static
$ docker run -tdi --name picbed --net=host --restart=always \
    -e picbed_redis_url=redis://xxxx \
    -v picbed_static:/picbed/static \
    -v /data/picbed:/picbed/static/upload \
    staugur/picbed

不过需要注意的是,数据卷持久化存储,后面如果更新了容器(静态资源)并 不会更新宿主机的,所以如果重新启动容器(升级版本或更新代码后),建议 先删除数据卷:

$ docker volume rm picbed_static

因为使用bind方式挂载了upload上传目录,所以删除数据卷并不会删除已经上传 的图片(位于宿主机/data/picbed)!

查看我录制的使用docker单独启动的gif图(包括数据卷和nginx): picbed-docker-volume.gif

如果没有问题,docker ps查看其状态是Up,系统中能看到进程:

$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
fa3b592f6ae5        picbed              "gunicorn app:app -c…"   2 hours ago         Up 2 hours                              picbed

$ ps aux|grep picbed
root   23546  -- gunicorn: master [picbed]
root   23548  -- gunicorn: worker [picbed]
// 以上是使用setproctitle模块设置了优雅的进程名的效果,下面是未使用效果
root  - {gunicorn} /python /bin/gunicorn app:app -c picbed.py
root  - {gunicorn} /python /bin/gunicorn app:app -c picbed.py

3.2 使用docker-compose启动

1.6.0 新版功能.

编写了一个简单docker-compose.yml,构建并启动picbed和redis,无nginx, redis开启AOF,宿主机映射9514端口以供外部访问。

$ cd picbed
$ docker-compose up -d
$ docker-compose ps
    Name                 Command               State           Ports
---------------------------------------------------------------------------------
picbed_redis_1    docker-entrypoint.sh redis ...   Up      6379/tcp
picbed_webapp_1   gunicorn app:app -c picbed ...   Up      0.0.0.0:9514->9514/tcp

$ docker-compose images
    Container     Repository      Tag      Image Id       Size
------------------------------------------------------------------
picbed_redis_1    redis           alpine   b546e82a6d0e   31.51 MB
picbed_webapp_1   picbed_webapp   latest   1f3c98af1c3a   105.9 MB
    在 1.8.0 版更改:
  • 1. 增加了数据卷,把容器内部静态目录(/picbed/static)挂载到数据卷中, 故此宿主机上nginx可以方便访问容器内静态文件了。

    注意! 也将upload上传目录(位于static内)挂载到 /data/picbed

    1. 更新代码后的操作

    升级版本或更新代码后,建议先down了所有docker-compose生成的资源(主要是 数据卷、已构建的镜像),再构建启动新容器。

    $ cd picbed
    $ docker-compose down -v
    $ docker-compose up -d
    

    因为使用bind方式挂载了upload上传目录,所以删除数据卷并不会删除已经上传 的图片(位于宿主机/data/picbed)!

    查看我录制的使用docker-compose启动的gif图: picbed-docker-compose.gif

4. nginx

上述不论是单独启动,还是使用docker-compose启动,对外接收请求的是gunicorn, 遗憾的是,它处理静态资源性能不好,所以一般会加一层nginx。

4.1 如果使用宿主机的nginx服务

单独启动请按照上面小技巧中的示例,先创建数据卷再挂载数据。

使用docker-compose启动,已经在配置中完成了,直接启动就好了。

4.1.1 设置数据卷存放目录所有人有执行权(否则可能nginx 403权限拒绝)

$ chmod +x $(docker info -f '{{ .DockerRootDir }}')/volumes

4.1.2 nginx配置

先获取数据卷在宿主机的目录:

$ docker volume inspect -f '{{ .Mountpoint }}' picbed_static
/var/lib/docker/volumes/picbed_static/_data

配置示例:

server {
    listen 80;
    server_name 域名;
    charset utf-8;
    #上传大小限制12M(实际程序上限是10M)
    client_max_body_size 12M;
    #可以设置不允许搜索引擎抓取信息
    #处理静态资源,root路径根据实际情况修改
    location ^~ /static/ {
        # 上一步获取的数据卷在宿主机的目录,注意末尾/不要丢
        alias /var/lib/docker/volumes/picbed_static/_data/;
    }
    location ^~ /static/upload/ {
        # 容器内上传目录挂载到宿主机的目录,注意末尾/不要丢
        alias /data/picbed/;
    }
    location / {
        #9514是默认端口,根据实际情况修改
        proxy_pass http://127.0.0.1:9514;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

4.2 在Docker中使用nginx服务

这就简单了,启动docker版nginx同样挂载数据卷和上传目录,配置参考 NO.3 Nginx配置

5. 后续

接下来建议您看下一节使用说明,刚开始需要创建一个管理员账号的,而使用docker 第一次启动也需要,命令如下:

$ docker exec -i picbed flask sa create -u 管理员账号 -p 密码 --isAdmin

如果使用docker-compose启动,命令如下:

$ docker-compose exec webapp flask sa create -u 管理员账号 -p 密码 --isAdmin

其他额外选项,如昵称、头像就不说了。