devin0910

全干工程师

Docker Compose入门到开发环境

Docker Compose定义服务之间的关系,很方便地管理多个容器的生命周期。你可以使用 docker-compose.yml 配置文件定义服务之间的关系,然后通过命令行来管理配置文件中定义的服务的生命周期,一般用在开发、测试环境。

docker-compose.yml

docker-compose.yml描述容器的运行状态,包含了运行服务的容器的配置信息,容器之间的网络交互,挂载文件夹等。 使用yaml格式,具体的语法可以查看wiki上的介绍。

下面是一个docker-compose.yml文件的示例:

version: '2'
services:
  web:
    build: .
    depends_on:
      - db
      - redis
  redis:
    image: redis
  db:
    image: postgres

第一行一般标识这个配置文件的语法是哪个版本的,不同的版本对应的支持不同的Docker Engine版本,现在最新版本是3.x。 1.x版本中,每个顶级节点为服务名称,次级节点则为服务容器的配置信息。在2.x之后所有的服务都必须定义在 services 节点下面,2.x支持Compose 1.6.0以上的版本,并且Docker Engine需要1.10.0以上的版本。3.x主要是与Docker Engine的swarm模式兼容。不同版本之间的区别、升级指南可以在官方文档中查看。

服务的配置项里主要有:build、environment、image、networks、ports、volumes等,想了解更多可查看官方文档

docker compose 相关命令

通过docker-compose命令行能方便地构建服务、管理服务的生命周期、查看日志等操作。

docker-compose build    // 构建服务镜像

如果服务的Dockerfile有更改或者build目录里有文件修改,那么会重新构建服务镜像。

下面来做个简单的示例:通过docker-compose管理一个php cli server。项目的根目录是phpcli:

phpcli/
├── docker-compose.yml
└── web
    ├── Dockerfile
    └── src
        └── index.php

web目录里有个Dockerfile描述如何构建这个服务,web服务的代码都放在web/src目录下。

<?php

echo 'hello world';

index.php里面的文件内容。

docker-compose.yml文件里面指定使用配置版本是 3services 里定义了一个php-cli-server服务,build 项包含了构建容器时的配置信息, 这里./web是构建容器的上下文,volumes 指定挂载的目录, ports 指定服务暴露的端口。

version: '3'

services:
    php-cli-server:
        build: ./web
        volumes:
            - ./web/src:/var/www/social
        ports:
            - 8080:8000

当我们运行完docker-compose build命令完之后再运行docker images会发现生成了一个新的镜像phpcli_php-cli-server。 镜像的命名规则为project_service,project默认是目录名,你也可以通过-p--project-name选项指定项目名。你也可以使用 image 来指定要构建的服务容器名。

现在我们可以通过下面的命令启动服务

docker-compose up   // 创建并启动容器

控制台输出:

Creating network "phpcli_default" with the default driver
Creating phpcli_php-cli-server_1 ... 
Creating phpcli_php-cli-server_1 ... done
Attaching to phpcli_php-cli-server_1
php-cli-server_1  | PHP 7.1.8 Development Server started at Fri Aug 18 06:12:05 2017

从上面我们可以看到,docker compse会先创建一个默认的网络 phpcli_default , 可以通过docker network ls看到这个新创建的网络。

NETWORK ID          NAME                    DRIVER              SCOPE
52b806c648eb        phpcli_default          bridge              local

接着会创建并启动一个以phpcli_php-cli-server为镜像的容器,并加入到上面创建的网络中,最后attach到容器的控制台,所有容器中的输出会打印在控制台上。现在你可以通过浏览器访问这个web server了。一般你可以使用-d选项让docker compose以后台服务的方式运行项目。

docker-compose logs

Attaching to phpcli_php-cli-server_1
php-cli-server_1  | PHP 7.1.8 Development Server started at Fri Aug 18 06:30:28 2017
php-cli-server_1  | [Fri Aug 18 06:30:40 2017] 192.168.10.1:57739 [200]: /
php-cli-server_1  | PHP 7.1.8 Development Server started at Fri Aug 18 06:31:35 2017
php-cli-server_1  | [Fri Aug 18 06:33:36 2017] 192.168.10.1:57754 [200]: /

可以查看所有容器中产生的日志,每条日志前面会有日志产生的容器的名称。-f跟linux tail命令的-f选项相似,可以持续的输出最新的日志。--tail可以指定输出最近的日志条数,默认为 all ,例如--tail=10会打印出所有容器中最近的10条日志。

docker-compose stop

停止正在运行的容器,但不会删除容器。可以通过docker compose start再次启动服务。

docker-compose start

启动已经存在的服务容器

docker-compose ps

         Name                        Command               State           Ports          
-----------------------------------------------------------------------------------------
phpcli_php-cli-server_1   docker-php-entrypoint php  ...   Up      0.0.0.0:8080->8000/tcp

列出所有容器的状态,正在运行的命令,端口映射信息。

docker-compose rm

删除已停止的服务容器。

docker-compose port [options] SERVICE PRIVATE_PORT

打印某个服务容器中的端口对外映射的端口号。例如:docker-compose port php-cli-server 8000会打印出0.0.0.0:8080

docker-compose pause

暂停某个服务的正在运行的容器,你可以在之后使用docker-compose unpause命令恢复暂停的服务。

docker-compose exec [options] SERVICE COMMAND [ARGS...]

在某个服务容器中运行命令,与docker exec -it相似,默认情况下会自动分配一个TTY终端。

docker-compose down

停止所有的容器并删除网络、挂载点、构建时生成的镜像。--rmi local也会删除项目中定义的服务镜像,-v删除所有命名的、匿名的挂载点。

下面介绍如何cli server如何从mysql数据库中读取数据:首先在services节点下定义一个db服务,db使用mysql镜像,并且设置了环境变量MYSQL_ALLOW_EMPTY_PASSWORD,允许用空密码登录,在开发环境中简单方便:

db:
    image: mysql:5.7
    ports:
        - 3306:3306
    volumes:
        - ./db/data:/var/lib/mysql
        - ./db/sql:/data/sql
    environment:
        MYSQL_ALLOW_EMPTY_PASSWORD: 'yes'

并对原先的php-cli-server服务进行了修改:

php-cli-server:
    build: ./web
    image: "cli-server"
    volumes:
        - ./web/src:/var/www/social
    ports:
        - 8080:8000
    depends_on:
        - db

depends_on 会在docker-compose up的时候会按依赖次序来启动服务,db服务会在php-cli-server服务之前启动,而且在docker-compose up php-cli-server也会创建(如果容器不存在)并启动db服务。

由于php:7.1-alpine镜像中默认没有安装mysql扩展,所以需要在web/Dockerfile中增加RUN docker-php-ext-install pdo_mysql

导入数据库:首先执行docker-compose exec db /bin/bash,进入mysql服务容器终端,然后执行mysql -u root -p < /data/sql/social.sql导入数据(root用户密码为空)。

修改web/src/index.php文件:

$db = new PDO('mysql:host=db;dbname=social;charset=utf8mb4', 'root', '', [
    PDO::ATTR_EMULATE_PREPARES => false, 
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
]);

$stmt = $db->query("SELECT * FROM posts");
foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $post) {
    var_dump($post);
}

现在我们可以打开浏览器查看数据库里面的数据了。

到现在为止我们完成了php与mysql的交互,一般情况下我们都会使用nginx,那如何让php与nginx交互呢?我们先通过docker-compose down --rmi local -v停止并删除项目中的服务,并移除构建的本地镜像,删除挂载数据信息。

首先得添加nginx服务:

nginx:
    image: nginx:latest
    ports:
        - 8080:80
    volumes:
        - ./web/src:/var/www/social
        - ./nginx/conf/social.conf:/etc/nginx/conf.d/social.conf
    depends_on:
        - web

删除前面的php-cli-server服务的定义,这次使用php-fpm来做web服务,把web目录下Dockerfile中的基础镜像改成php:fpm,在docker-compose.yml中添加下面的web服务。

web:
    build: ./web
    volumes:
        - ./web/src:/var/www/social
    ports:
        - 9000
    depends_on:
        - db

下面是social.conf文件里的配置信息,其中fastcgi_pass web:9000;中的web是docker-compose.yml中定义的web服务的容器地址。

server {
    index index.php index.html;
    server_name social.local;
    error_log  /var/log/nginx/error.log;
    access_log /var/log/nginx/access.log;
    root /var/www/social;

    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass web:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }
}

然后根据上面的命令,数据库中重新导入数据,然后在宿主机的hosts中加入127.0.1.1 social.local。通过浏览器访问http://social.local:8080就可以查看数据了。

我们了解了Docker compose的基本用法,也实现了如何搭建一个lnmp的docker开发环境。

留言