[关闭]
@longj 2018-06-07T12:42:36.000000Z 字数 5255 阅读 2545

在 Ubuntu 16.04 LTS 上使用 docker-compose 实现 Nginx+Flask+MySQL+Redis 的 web 后台应用部署

Author Johnny Law

注:本博客不涉及对 nginx, flask, mysql 或者 redis 过多的介绍,并假定读者已经有了一定的 Docker 入门基础。本博客重点介绍如何使用 docker-compose 把它们连接起来。

对 nginx, flask, mysql, redis 不熟悉并不影响阅读。 另可参考docker 的简单介绍

本博客所介绍的 docker-compose.yml 文件的标签只是基础的,更加丰富的使用的方法请参考官方文档


前言

Docker Compose 是 Docker 官方编排(Orchestration)项目之一,负责快速的部署分布式应用。
index.png-7.5kB

Compose 定位是 「定义和运行多个 Docker 容器的应用(Defining and running multi-container Docker applications)」,其前身是开源项目 Fig。Compose 项目由 Python 编写,实现上调用了 Docker 服务提供的 API 来对容器进行管理。因此,只要所操作的平台支持 Docker API,就可以在其上利用 Compose 来进行编排管理。

通过之前对于 docker 的简单介绍,我们知道使用一个 Dockerfile 模板文件,可以让用户很方便的定义一个单独的应用容器。然而,在日常工作中,经常会碰到需要多个容器相互配合来完成某项任务的情况。例如要实现一个 Web 项目,除了 Web 服务容器本身,往往还需要再加上后端的数据库服务容器,甚至还包括负载均衡容器等。

deployment_img.png-29.6kB

本篇博客将对上图所描述 web 后台结构实现 docker-compose 一键部署


安装 Docker Compose

按照官网给出的指导进行安装即可。

下面是在 Linux 下安装流程

下载最新版本的 docker-compose(于2018.06.03, 最新版本以官网为准)

  1. sudo curl -L https://github.com/docker/compose/releases/download/1.21.2/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose

给可执行文件赋予运行权限

  1. sudo chmod +x /usr/local/bin/docker-compose

测试安装结果,查看 docker-compose 的版本

  1. $ docker-compose --version
  2. docker-compose version 1.21.2, build 1719ceb

如果可以看到对应的 docker-compose 的版本号,则显示安装成功。


docker-compose.yml 的样例

Docker Compose 允许你在项目根目录下的一个陈述性语言 yaml 文件 docker-compose.yml定义你这个项目所要用到的所有容器,网络,或者挂载的信息。然后运行一个简单的命令 docker-compose up 即可以进行一键部署。

项目的文件目录组织情况因人而异,我个人比较喜欢的是把每个容器的需要东西都放在一个独立的文件夹中,然后由 docker-compose 进行统一的调用。下面是我们小组课程项目的文件结构目录:

  1. .
  2. ├── app
  3. ├── app.py
  4. ├── data
  5. ├── menu_database.json
  6. └── resturant_database.json
  7. ├── data_importer.py
  8. ├── db_insert.py
  9. ├── dbOperators.py
  10. ├── Dockerfile
  11. ├── requirements.txt
  12. ├── tools.py
  13. └── wait-for-it.sh
  14. ├── db
  15. ├── 01-my-script.sh
  16. ├── Dockerfile
  17. ├── README.md
  18. └── TinyHippo.sql
  19. ├── docker-compose.yml
  20. ├── LICENSE
  21. ├── nginx
  22. └── conf.d
  23. └── web.conf
  24. └── README.md

下面是我的项目中 docker-compose.yml 的例子:

  1. version: '3'
  2. services:
  3. db:
  4. restart: always
  5. build: db/.
  6. environment:
  7. MYSQL_ROOT_PASSWORD: tiny-hippo
  8. MYSQL_DATABASE: TINYHIPPO
  9. MYSQL_USER: tiny
  10. MYSQL_PASSWORD: tiny-hippo
  11. ports:
  12. - "3306:3306"
  13. networks:
  14. - db_nw
  15. web:
  16. restart: always
  17. build: app/.
  18. volumes:
  19. - ./app:/code/app
  20. working_dir: /code/app
  21. command: bash -c "/code/app/run-after-db-init.sh"
  22. depends_on:
  23. - db
  24. - redis
  25. networks:
  26. - db_nw
  27. - web_nw
  28. - redis_nw
  29. stdin_open: true
  30. tty: true
  31. redis:
  32. image: "redis:alpine"
  33. networks:
  34. - redis_nw
  35. nginx:
  36. image: nginx:latest
  37. restart: always
  38. ports:
  39. - "8080:80"
  40. volumes:
  41. - ./nginx/conf.d:/etc/nginx/conf.d
  42. depends_on:
  43. - web
  44. networks:
  45. - web_nw
  46. networks:
  47. db_nw:
  48. driver: bridge
  49. web_nw:
  50. driver: bridge
  51. redis_nw:
  52. driver: bridge

各个容器的构建

我们需要在 services 标签下指定各个容器的名字和基本属性。

基础语法

build
指定 Dockerfile 所在文件夹的路径(可以是绝对路径,或者相对 docker-compose.yml 文件的路径)。 Compose 将会利用它自动构建这个镜像,然后使用这个镜像。
image
对于可以直接使用原始镜像,不用进行二次 build 的 service 来说,可以使用 image 标签来指定使用的镜像。(需要 build 的镜像在它们各自的 Dockerfile 中指定了初始的镜像)
ports
暴露端口信息。使用宿主端口:容器端口 (HOST:CONTAINER) 格式,或者仅仅指定容器的端口(宿主将会随机选择端口)都可以。
此处,在 nginx 中将 host 的 8080 端口和 nginx 容器中的 80 端口关联起来。作为访问 web 服务的唯一入口,在 db 中的端口映射 3306:3306 只是为了暴露 mysql 的接口方便本地进行调试,实际部署到生产环境的时候可以去掉
restart
设置 restart: always ,当容器意外退出的时候可以一直重启,保证容器跑的进程不会 exit,方便调试。
networks
指定该容器和哪些 networks 相连,其中 networks 在上一级的 networks 标签中指定。

MySQL db 细节

  1. environment:
  2. MYSQL_ROOT_PASSWORD: tiny-hippo
  3. MYSQL_DATABASE: TINYHIPPO
  4. MYSQL_USER: tiny
  5. MYSQL_PASSWORD: tiny-hippo

上述命令是用来指定 MySQL db 容器的环境变量,使得 mysql 的容器一启动起来就可以按照设置的环境变量进行初始化

web 细节

volumes
数据卷所挂载路径设置。可以设置宿主机路径 (HOST:CONTAINER) 或加上访问模式 (HOST:CONTAINER:ro)。该指令中路径支持相对路径。这样的话,在 docker-compose up 运行了整个服务后,修改本地代码文件即可以直接反映在对应的容器中,而不需要重启 docker-compose, 方便调试。
depends_on
解决容器的依赖、启动先后的问题。在这里 web 容器会等待 db 和 redis 容器都启动后才启动。
command
覆盖容器启动后默认执行的命令。此处运行了自己写的 sh 脚本 run-after-db-init.sh, web 会先一直向 db 的 3306 发送请求,直至成功连接后才启动服务 python app.py ,防止web 在 db 启动后, 初始化未完成时就尝试连接数据库导致连接失败的情况。
stdin_open, tty
上述两个设置为 true, 可以将容器内容的输出重定向到目前的终端上,方便调试。

其他容器

对于 redis 和 nginx, 并没有特别需要设置的,所用到的设置也已经在前面介绍过,不再赘述。


各个容器的连接

services & networks

networks 标签下指定各个网络的名字和连接方式。常用的连接方式是桥接 bridge.

docker-compose 会在宿主机 (host) 的内部构建一个虚拟的网络环境,并且为各个容器分配了一个 ip 地址,services 中的各个容器的名字,eg. web, db, nginx 将会被加载进 docker-compose 提供的 DNS 系统里面。这意味着我们可以在程序中直接使用 services 的名字作为 host 来实现连接

Snipaste_2018-06-06_23-05-08.png-22.3kB

eg. 在我们的项目中, 用 python3 写的持久化层可以直接与 db 建立连接:

  1. db = pymysql.connect(host='db',
  2. user='root',
  3. password='tiny-hippo',
  4. database='TINYHIPPO',
  5. charset='utf8')

这样我们就可以非常方便地在 docker-compose 中添加我们想要的服务容器,并实现相互沟通。

在 Nginx 的容器中,我们挂载一个简单的配置文件

  1. server {
  2. listen 80;
  3. server_name localhost;
  4. location / {
  5. proxy_set_header Host $host;
  6. proxy_set_header X-Real-IP $remote_addr;
  7. proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  8. proxy_set_header X-Forwarded-Proto $scheme;
  9. proxy_set_header Host $http_host;
  10. proxy_pass http://web:5000;
  11. }
  12. }

注意这里的 proxy_pass 的设置中 hostnane 直接就设置成 docker-compose.yml 中设置的容器的名字 web, 这是因为 Docker 内部的 DNS 可以处理拿到正确的 ip 地址。


后台服务跑起来!

定义好了各个容器的构建方式,还有总体的 docker-compose 模板文件 docker-compose.yml 后,就可以很轻松地使用 docker-compose 进行一键部署了!

一键部署

在项目根目录下运行下面命令:

  1. docker-compose up

实验结果截图
Screenshot from 2018-06-06 16-54-23.png-69.2kB

后台已经成功部署并开始监听。

访问 http:localhost:8080/ 获取 json 数据:
Screenshot from 2018-06-06 17-00-51.png-70kB

访问 http:localhost:8080/testRedis 并进行几次刷新,对后台进行测试。
Screenshot from 2018-06-06 16-59-17.png-10.5kB
其中的数字会更新,说明 redis 缓冲可以正常工作

访问 http:localhost:8080/insert_fake_data1 插入假数据
Screenshot from 2018-06-06 17-03-27.png-8.2kB

查看后台记录:
Screenshot from 2018-06-06 17-04-51.png-30.4kB
nginx 运行正常

其他命令

  1. docker-compose up -d 让 docker-compose 在后台运行
  2. 若想停止服务,执行 docker-compose down
  3. 若想重新构建一个镜像(以 web 为例), 执行 docker-compose build web
  4. docker-compose up -d --scale web=3 可以方便地多开几 (3) 个 web 容器,提高业务处理的性能。

其他优化

  1. 在生产环境中,应该把数据库文件挂载在本地的 mysql 上,这样子就不需要每次重启 db 容器都需要进行数据库初始化,也不会丢失数据。
  2. 理论上 docker-compose 熟悉了之后,不同的服务可以使用不同的实现方式进行任意组合,如:后台实现可以换成是 node.js 或者 php 的实现,数据库可以使用非关系型数据库 mongoDB 的镜像,proxy 端可以考虑换成 Apache 。更换只需要改变 docker 的镜像,选择开发人员自己熟悉的语言和环境,免去了繁杂的系统环境配置,开发的灵活性大大提升。

文中所用的代码参考仓库rookies-sysu/Order-System-Backend

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注