January 24, 2018

docker-compose上手

docker compose 用于快速在集群中部署分布式应用。按我的理解也可以用于简化部署单个应用。譬如我要使用dock er启动一个nginx服务,需要做端口映射,挂载数据文件,指定镜像…等等,这种情况下,可以将启动容器的命令整合到docker-compose.yml文件中,可以在多个服务器上运行,瞬间就完成了nginx的安装及配置,再也不用去编译,解决环境依赖了,这种感觉实在是太爽了!!!

安装

  1. 使用pip pip install docker-compose
  2. 从官方Github Release下载二进制包文件
  3. 其他方法略去

使用场景

在日常工作中,经常会碰到需要多个容器相互配合来完成某项任务的情况。例如要实现一个 Web 项目,除了 Web 服务容器本身,往往还需要再加上后端的数据库服务容器,甚至还包括负载均衡容器等。

实战场景

需要部署的项目,只有两个docker容器,一个server,一个db。一般的部署方式是,分别启动两个容器,容器间通过互联的方式通信:

sudo docker run --rm -p 5433:5432 --name postgres -e POSTGRES_PASSWORD=minepwd -e POSTGRES_USER=mineusr -d postgres

sudo docker run --rm -p 9091:9091 --link postgres:postgres --name mineserver -d me/mineserver

这两条命令还是有挺麻烦的,如果记不住,当然可以用shell脚本来运行,可以如果其中某一个服务无法如期运行。。。就很监介了。这时候就可以引入docker-compose了。

编写docker-compose.yml来部署项目

version: "2" # 指定docker-compose版本
services:    # 项目依赖的服务
  postgres:  # 服务名字
    image: postgres # 服务需要的docker镜像与docker run命令中的镜像指定方式一致
    volumes:        # 挂载卷,这里的主要目的是,方便同步数据库和数据脚本
      - ./postgres:/var/lib/postgresql/data
      - ./sh:/usr/src/sh
    ports:          # 端口绑定
      - 5433:5432
    container_name: postgres
    environment:    # 设置环境变量
      POSTGRES_PASSWORD: "minepwd"
      POSTGRES_USER: "mineusr"
      POSTGRES_DB: "minedb"
  mineserver:
    image: me/mineserver
    volumes:        # 挂载卷,方便查看输出日志
      - ./logs:/usr/src/mineserver/logs
    ports:
      - 9091:9091
    container_name: mineserver
    links:          # 容器互联
      - postgres:postgres

在编写docker-compose.yml的时候,需要注意的是各个选项的数据类型,不过docker-compose会有提示,也很方便

这样编写之后,可以直接运行docker-compose up就可以启动两个容器了。输出如下:

➜  mineserver git:(yeqown) docker-compose up
Starting postgres ... done
Starting mineserver ... done
Attaching to postgres, mineserver
mineserver  | 2018/01/25 06:28:02 Loading config: ./configs/config.json
mineserver  | 2018/01/25 06:28:02 init all logger done
mineserver  | 2018/01/25 06:28:02 host=postgres user=mineusr dbname=minedb sslmode=disable password=minepwd
mineserver  | panic: dial tcp 172.18.0.2:5432: getsockopt: connection refused
mineserver  |
mineserver  | goroutine 1 [running]:
mineserver  | mineserver/vendor/app/models.ConnPgsql(0xc4200127d0, 0x4a)
mineserver  |   /go/src/mineserver/vendor/app/models/pgsql.go:17 +0x28b
mineserver  | main.main()
mineserver  |   /go/src/mineserver/main.go:32 +0x16d
mineserver exited with code 2
postgres  | 2018-01-25 06:28:05.360 UTC [1] LOG:  listening on IPv4 address "0.0.0.0", port 5432
postgres  | 2018-01-25 06:28:05.360 UTC [1] LOG:  listening on IPv6 address "::", port 5432
postgres  | 2018-01-25 06:28:05.363 UTC [1] LOG:  listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432"
postgres  | 2018-01-25 06:28:05.449 UTC [20] LOG:  database system was shut down at 2018-01-25 05:48:24 UTC
postgres  | 2018-01-25 06:28:05.475 UTC [1] LOG:  database system is ready to accept connections

如输出,使用过程中遇到一个问题,mineserver依赖于postgre,导致mineserver无法正常启动。解决方案有: 1 重启minerserver,docker-compose start mineserver 2 改写mineserver链接数据库的部分,增加重试机制 3 分成多个docker-composr.yml,按依赖关系来分先后启动 4 添加依赖关系来控制启动顺序,新增depends_on选项如下:

# docker-compose.yml
...
mineserver:
    ... 
    depends_on:     # 依赖关系
      - postgres
    links:          # 容器互联
      - postgres:postgres

但是,也没有办法知道被依赖的服务是不是启动成功了,所以在必须依赖的时候后还是会有问题 5 参见官网解决方案,增加一个wait-for-it.sh。 docker-compose.yml 文件如下:

# docker-compose.yml
...
mineserver:
    ... 
    depends_on:     # 依赖关系
      - postgres
    links:          # 容器互联
      - postgres:postgres
    command: ["./wait-postgres.sh", "./mineserver"] # 结合wait-postgres.sh理解

wait-postgres.sh 文件如下:

#!/bin/sh
# wait-postgre.sh

host="postgres"

for i in $(seq 1 10)
do
  nc -z $host 5432
  if [[ $? -eq "" ]]; then
    echo -n .
    sleep 1
  else
    echo "Postgres is ready"
    break
  fi
done

# execute mineserver, $1 is command that start mineserver
$1

# how to use?
# command: ["./wait-postgres.sh", "./imetro-server"]

关于5th,需要注意的要注意wait-for-it.sh, 需要放到服务镜像中去;要根据server镜像中的shell来指定sh,譬如说,我最开始使用的是bash,然而bash在alpine中并不存在……;另外wait-for-it.sh 需要可执行权限哦。

关于docker-compose.yml的其他命令

官方文档或者Docker入门到实践已经讲的很清楚了

comments powered by Disqus