Docker Compose详解

2021-02-25 16:00:39 浏览数 (1)

前言

前面我们使用 Docker 的时候,定义 Dockerfile 文件,然后使用 docker builddocker run 等命令操作容器。

然而微服务架构的应用系统一般包含若干个微服务,每个微服务一般都会部署多个实例,如果每个微服务都要手动启停,那么效率之低,维护量之大可想而知

使用 Docker Compose 可以轻松、高效的管理容器,它是一个用于定义和运行多容器 Docker 的应用程序工具

安装 Docker Compose

安装

代码语言:javascript复制
apt install docker.io
apt install docker-compose

查看版本

代码语言:javascript复制
docker --version
docker-compose --version

设置Docker镜像

针对Docker客户端版本大于 1.10.0 的用户

创建或修改 /etc/docker/daemon.json 文件

代码语言:javascript复制
vi /etc/docker/daemon.json

添加或修改

代码语言:javascript复制
{
    "registry-mirrors": ["https://tiaudqrq.mirror.aliyuncs.com"]
}

重启Docker

代码语言:javascript复制
systemctl daemon-reload
systemctl restart docker.service

查找可用的Java8镜像

代码语言:javascript复制
docker search java8

拉取镜像

代码语言:javascript复制
docker pull williamyeh/java8

部署Jar服务

假如我们的项目是helloworld-0.0.1-SNAPSHOT.jar,对应端口是8080

把服务的jar放到 /root/helloworld/目录下

在 jar 包所在路径创建 Dockerfile 文件,添加以下内容

代码语言:javascript复制
FROM williamyeh/java8
# 将本地文件tmp挂载到容器
VOLUME /tmp
# 拷贝jar
ADD helloworld-0.0.1-SNAPSHOT.jar /app.jar
# 设置暴露的端口号
EXPOSE 8080
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]

测试下 Dockerfile 文件是否可用

代码语言:javascript复制
docker build -t psvmc/helloworld /root/helloworld/

在 jar 包所在路径创建文件 docker-compose.yml,添加以下内容

代码语言:javascript复制
version: '2'
services:
  hello-world:
    build: /root/helloworld
    ports:
      - "9000:8080"

注意

hello-world 是指定服务名称 build 指定 Dockerfile 所在文件夹路径

docker-compose.yml 所在路径下执行该命令 Compose 就会自动构建镜像并使用镜像启动容器

代码语言:javascript复制
docker-compose -f docker-compose.yml up -d hello-world

这样服务就可以访问了

http://www.psvmc.cn:9000/

网络

官方文档:https://docs.docker.com/compose/networking/

查看网络

查看网络列表

代码语言:javascript复制
docker network ls

上面的示例中没有设置网络,就会产生

NETWORK ID NAME DRIVER SCOPE a327e58d7a47 helloworld_default bridge local

也就是说它会根据文件所在文件夹的名称_default作为网络名

查看指定的网络设置

代码语言:javascript复制
docker network inspect helloworld_default

注意这里的helloworld_default 可以传网络的ID或者是网络的名称

从返回的信息中我们可以看到容器内的网络

网络互通

上面的例子中我们的服务是单独的,但是实际上我们的服务之间需要互相能访问,比如我们的接口和数据库,这样该如何设置呢?

/root/nettest 下创建 docker-compose.yml

代码语言:javascript复制
version: '2'
services:
  web1:
    image: nginx
    ports:
      - "6061:80"
    container_name: "web1"
    networks:
      - dev
  web2:
    image: nginx
    ports:
      - "6062:80"
    container_name: "web2"
    networks:
      - dev
      - pro
  web3:
    image: nginx
    ports:
      - "6063:80"
    container_name: "web3"
    networks:
      - pro
 
networks:
  dev:
    driver: bridge
  pro:
    driver: bridge

启动

代码语言:javascript复制
docker-compose -f docker-compose.yml up -d

这样就可以访问

http://www.psvmc.cn:6061 http://www.psvmc.cn:6062 http://www.psvmc.cn:6063

执行

代码语言:javascript复制
docker network ls

我们可以看到

NETWORK ID NAME DRIVER SCOPE 423fc9d510c3 nettest_dev bridge local a2c26563c23e nettest_pro bridge local

其实上面的本质上相当于创建了对应的网络

代码语言:javascript复制
docker network create nettest_dev

或者

代码语言:javascript复制
docker network create --driver=bridge --subnet=172.25.0.1/16 --gateway=172.25.0.1 mynet

查看指定的网络设置

代码语言:javascript复制
docker network inspect nettest_dev
docker network inspect nettest_pro

可以看到

可以看出

web1和web2在一个内网中 web2和web3在一个内网中

复用之前的网络

/root/nettest2 下创建 docker-compose.yml

代码语言:javascript复制
version: '2'
services:
  web4:
    image: nginx
    ports:
      - "6064:80"
    container_name: "web4"
    networks:
      - nettest_dev
networks:
  nettest_dev:
    external:
      name: nettest_dev

启动

代码语言:javascript复制
cd /root/nettest2
docker-compose up -d

这时再查看网络

代码语言:javascript复制
docker network inspect nettest_dev

如下图

会发现web1web2web4已经在同一个网段下了。

links

示例

代码语言:javascript复制
version: "3"
services:
  web:
    build: .
    links:
      - "db:database"
  db:
    image: postgres

这样我们就可以在web的服务中用dbdatabase就可以访问到数据库了

也就是说在web容器中可以用类似于postgres://db:5432或者 postgres://database:5432 来代替之前的postgres://{DOCKER_IP}:5432来访问数据库

depends_on

当使用 depends_on 来定义服务之间的依赖关系时会造成下面的影响2

  • docker-compose up 会依据依赖顺序启动服务
  • docker-compose up 启动时 SERVICE 会自动包括 SERVICE 的依赖

看这个例子:

代码语言:javascript复制
version: '2'
services:
  web:
    build: .
    depends_on:
      - db
      - redis
  redis:
    image: redis
  db:
    image: postgres

这个例子中 db ,redis 容器启动顺序要优先于 web 容器;当启动 web 容器时会自动创建 redis 和 db 容器。

不过需要注意的是, depends_on 不会等到 db 和 redis 容器 ready 再启动,web 容器仅仅等到 redis 和 db 容器启动就开始启动。

使用aliases代替link

还是上面的例子

代码语言:javascript复制
version: '2'

services:
  web:
    depends_on:
      - db
    networks:
      - dev
  db:
    image: postgres
    networks:
      dev:
        aliases:
          - database
      pro:
        aliases:
          - mydb
networks:
  dev:
    driver: bridge
  pro:
    driver: bridge

web依赖于db这样我们就可以在web的服务中用database就可以访问到数据库了

也就是说在web容器中可以用类似于 postgres://database:5432 来代替之前的postgres://{DOCKER_IP}:5432来访问数据库.

必要条件

  1. 两者有依赖关系
  2. 在同一个网段下
  3. 被依赖的例如db设置网络的别名

常见命令

ps:列出所有运行容器

代码语言:javascript复制
docker-compose ps

logs:查看服务日志输出

代码语言:javascript复制
docker-compose logs

port:打印绑定的公共端口,下面命令可以输出 web1 服务 8761 端口所绑定的公共端口

代码语言:javascript复制
docker-compose port web1 8761

build:构建或者重新构建服务

代码语言:javascript复制
docker-compose build

start:启动指定服务已存在的容器

代码语言:javascript复制
docker-compose start web1

stop:停止已运行的服务的容器

代码语言:javascript复制
docker-compose stop web1

rm:删除指定服务的容器

代码语言:javascript复制
docker-compose rm web1

up:构建、启动容器

代码语言:javascript复制
docker-compose up

更新容器

当服务的配置发生更改时,可使用 docker-compose up 命令更新配置

此时,Compose 会删除旧容器并创建新容器,新容器会以不同的 IP 地址加入网络,名称保持不变,任何指向旧容起的连接都会被关闭,重新找到新容器并连接上去

kill:通过发送 SIGKILL 信号来停止指定服务的容器

代码语言:javascript复制
docker-compose kill web1

pull:下载服务镜像

scale:设置指定服务运气容器的个数,以 service=num 形式指定

代码语言:javascript复制
docker-compose scale user=3 movie=3

run:在一个服务上执行一个命令

代码语言:javascript复制
docker-compose run web1 bash

0 人点赞