docker从入门到实践: (3)docker-compose

在第二篇文章中,我们学会了使用 dockerfile 构建 docker 镜像,看起来已经能够满足我们的日常需求了。无论需要什么环境,在 dockerfile 里逐步构建,然后 build、run,就 ok 了,也满足了我们docker 隔离性、快速部署的要求,那为什么还会有这一节?

来看一个网站开发最常见的场景:我们要有数据库,网站应用,nginx,互相配合才是完整的环境。是的,我们完全可以以 ubuntu 为基础镜像,把这些一股脑全装进去,然后运行。但是这样有很多缺点,比如我们每次都要重新装 mysql 而不是直接利用 mysql 官方的基础镜像,升级维护不方便;如果我们的应用要扩展也很难,因为每个应用都连接的自己内部的数据库,无法共享数据;事实上,这种方式是典型的虚拟机的使用方式,不是 docker 的正确打开方式。

docker 是轻量化的应用程序,docker 官方推荐每个 docker 容器中只运行一个进程(下篇文章你将明白这是为什么),那么就是说,我们需要分别为我们的应用、数据库、nginx 创建单独的 docker 容器,然后分别启动它。想象一下,构建好 docker 之后,每次启动我们的网站,都要至少 docker run 三次,是不是很繁琐?而且此时这几个 docker 是分散独立的,很不方便管理。既然这几个 docker 都是为了同一个网站服务,是不是应该把它们放到一起?这就引出了 docker-compose 项目。


docker-compose是 docker 官方的开源项目,使用 python 编写,实现上调用了 Docker 服务的 API 进行容器管理。其官方定义为为 「定义和运行多个 Docker 容器的应用(Defining and running multi-container Docker applications)),其实就是上面所讲的功能。

一:安装

默认情况下,windows 和 mac 下的 docker 已经自带了 docker-compose 工具,可以使用 `docker-compose -v` 命令查看。

对于 linux 系统,需要自己手动安装,可以直接下载二进制文件安装,参考官方文档,更酷的是,可以直接使用 pip 安装,甚至可以使用 docker-compose 容器(比较复杂,不推荐~)。

二:简介

类似 docker 的Dockerfile文件,docker-compose使用 YAML 文件对容器进行管理。

对于 docker-compose 有两个基本的概念:

  • 服务(service):一个应用容器,即 docker 容器,比如之前所说的mysql 容器、nginx 容器
  • 项目(project):由一组关联的应用容器组成的一个完整业务单元,比如上面所讲的由 mysql、web app、nginx 容器组成的网站。docker-compose 面向项目进行管理。

再简单说下 YAML 文件格式。

1.大小写敏感,缩进表示表示层级关系

2.缩进空格数不重要,相同层级左侧对齐即可。(不允许使用 tab 缩进!)

3.由冒号分隔的键值对表示对象;一组连词线开头的行,构成一个数组;字符串默认不使用引号

这些基本够我们使用了,详细的格式说明可参考这篇YAML 语言教程-阮一峰

三:使用

接下来我们使用 docker-compose 构建一个php 网站项目,并逐步讲解其使用。

  1. 我们需要一个网站项目,这里以 summerblue 的larabbs论坛系统为例,这个项目使用了 mysql、redis,我们可以验证搭建是否成功。从远程仓库把其克隆到本地,然后开始我们今天的工作。

2. 在项目文件夹下创建 docker-compose.yml文件。

3. 先在 docker-compose.yml 文件里添加如下代码,构建我们的 php 应用。

version: '2'
services:

    # our web application
    app:
        build:
            context: ./
            dockerfile: app.dockerfile
        volumes:
            - ./:/var/www
        working_dir: /var/www
        environment:
            - DB_HOST=database
            - REDIS_HOST=redis

下面解释下我们的代码。

  • version: 表示我们的compose文件的版本,目前有1,2,3,每个版本语法不尽相同,这里以版本2为例,具体可参考 docker-compose 文档
  • services: 即我们要开始定义服务,每个docker容器为一个服务。
  • app: 这里我们定义了第一个服务,app 为其名字
  • build: 指定该容器构建参数
  • volumes: 与 dockerfile 中 -v 参数相似,这里是将当前文件夹挂载到容器的/var/www 目录下
  • working_dir: 指定容器工作目录
  • environment: 设置环境变量。由于 laravel 框架在环境变量已有值的情况下不会加载.env 配置,这里 DB_HOST和 REDIS_HOST 就是.env 文件中配置数据库连接的参数,我们设置它以便连接docker 的数据库,database 和 redis 是接下来定义的服务名称。

这是 app.dockerfile 文件的内容,之前都讲过,不再细说。

FROM php:7.1.22-fpm

# 安装必要的 php 依赖包
RUN apt-get update \
    && apt-get install -qq git curl libmcrypt-dev libjpeg-dev libpng-dev libfreetype6-dev libbz2-dev \
    && apt-get clean

# 安装 php 扩展
RUN docker-php-ext-install pdo pdo_mysql mcrypt zip gd

4. 创建一个 composer 服务以安装 composer 依赖,docker-compose.yml 文件添加以下内容

# install dependencies
    composer:
        image: prooph/composer:7.1
        volumes:
            - ./:/var/www
        working_dir: /var/www
        command: install

注意这里同样将当前文件夹挂载到了容器中,因此对文件所做的更改都直接作用于本地文件,而我们的 app 容器也挂载了当前文件夹,这里安装的包文件都能生效。

5. 创建一个 nginx 服务,docker-compose.yml 文件添加以下内容

# web server
    nginx:
        build:
            context: ./
            dockerfile: nginx.dockerfile
        volumes:
            - ./public:/var/www/public
        ports:
            - 80:80
  • 这里将 public 文件夹挂载到了容器中, nginx 直接返回了静态文件,否则你将看到网站格式乱了,因为获取不到 css 等文件,如果是单纯后端可以不挂载此文件夹
  • ports 将nginx容器的80端口映射到本机80端口

nginx.dockerfile 文件内容,为了添加默认配置文件

FROM nginx:1.10

ADD vhost.conf /etc/nginx/conf.d/default.conf

vhost.conf 文件,nginx 配置文件

server {
    listen 80;
    server_name www.larabbs.test
    index index.php index.html;
    root /var/www/public;

    error_log /var/log/nginx/error.log notice;
    access_log /var/log/nginx/access.log main;

    location / {
        try_files $uri /index.php?$args;
    }

    location ~ \.php$ {
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass app:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }
}
  • 这里配置了 server_name,因为 larabbs 使用了sudo-su包,不配置域名访问会有权限问题。
  • fastcgi_pass app:9000 这里将动态请求转发给了 app 容器的9000端口,即 php-fpm 服务的端口,默认 docker-compose 同一项目下的容器是在同一个网络中,无需映射可以直接互相访问。

6. 创建数据库服务,docker-compose.yml 文件添加以下内容

# mysql database
    database:
        image: mysql:5.7
        environment:
          - "MYSQL_ROOT_PASSWORD=root"
          - "MYSQL_DATABASE=larabbs"
          - "MYSQL_USER=homestead"
          - "MYSQL_PASSWORD=secret"

    # redis database
    redis:
        image: redis:5
  • 这里 database 和 redis 是服务名,也即在 app 服务的 environment 变量设置的参数,因此 app 才能访问到我们容器中的数据库,当然你也可以使用其它名字。
  • environment 这里我们设置了 mysql 的数据库及用户名密码,即是 env 文件中配置的用户名密码,mysql 容器会自动初始化,然后应用才有权限连接。

到目前为止配置文件已经写完了,完整的文件可以在我的 github 看到。

7. 启动项目

docker-compose 最常用的命令就是 docker-compose up 了,该命令十分强大,它将尝试自动完成包括构建镜像,(重新)创建服务,启动服务,并关联服务相关容器的一系列操作。

因此,在项目文件夹下执行此命令。注意要在项目文件夹下,否则 docker-compose 找不到 docker-compose.yml 文件,也不知道你是如何配置的。

时间可能较长,请耐心等待。如果遇到网络故障,可以重试。

简单介绍下输出:

可以看到 此时app 服务已启动,等待连接。

redis 服务已启动。

database 服务已启动,在3306端口等待连接。

composer 服务准备开始安装依赖。

composer 服务完成任务退出。

当然顺序可能不同,但正常情况下nginx、mysql、redis、app 服务都已经启动,运行正常。

另外,你可以给命令加上-d 参数,以忽略输出,当然第一次运行还是仔细观察输出为好,将来使用时可以这么做。

8. 项目使用

首先执行下 docker ps,可以看到目前有4个容器,容器名都加上了项目前缀。

此时你可以使用 docker exec 命令进入相应容器执行初始化操作,因为 docker-compose 本身也是调用的 docker api,但是既然使用了 docker-compose 来管理项目,我们必然有更方便的方式。

执行 docker-compose ps,可以至查看当前项目的容器状态。

可以看到,四个服务正在运行,而 composer 服务已经执行完任务退出。

如果要容器执行命令,直接 docker-compose exec service_name command 更方便。

比如,进入我们的 nginx 容器,nginx 即是 YAML 文件里定义的服务名。

接下来,我们进行网站的初始化工作。即生成秘钥、初始化数据库等。

app 也是 YAML 文件里定义的服务名。

一切都顺利进行。

对了,因为上面提到 sudo-su的原因,你必须使用域名访问网站,在 host 文件添加 larabbs.test到127.0.0.1的映射即可。

然后,你应该就可以正常访问 http://larabbs.test 网站了。

8. 容器的停止

直接 control-c 或者 docker-compose stop 即可。

注意下次docker-compose up 默认仍会继续使用之前的容器和数据。

必要时你可以添加--build 参数重新构建镜像,或者--force-recreate参数重新创建容器。

更多资料:docker 三剑客-compose

docker-compose 官方文档


闲言

这个系列写了三篇了,算是把 docker 的基本使用介绍完了,更准确的说,应该是把我会用的介绍完了。因为本身是开发工程师,更着重于日常开发过程中使用,经验不多,对于运维视角的 docker不甚了解,而 docker 更大的意义应该是在运维层,所以有介绍的不合适甚至错误的地方,欢迎指出,或者分享你对 docker 的理解与使用。

另外,接下来会介绍 docker 与虚拟机的区别,docker 的原理等,写起来会比较难,但我会尽快完成。相信看了之后,会对 docker 的实质有更深的理解,就算是吹牛逼也会更有自信,欢迎关注~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值