在前面的文章Docker部署Spring Boot中,使用maven构建镜像,然后使用docker命令操作容器。微服务架构的应用系统中一般包含若干个微服务,每个微服务一般都会部署多个实例,如果每个微服务都要手动启停,维护的工作量会很大。Docker Compose可以轻松的管理容器,降低维护工作量。
一、Docker Compose简介
Docker Compose是一个编排多容器分布式部署的工具,提供命令集管理容器化应用的完整开发周期,包括服务构建,启动和停止。官网地址
Compose 中有两个重要的概念:
- 服务 ( service ):一个应用的容器,实际上可以包括若干运行相同镜像的容器实例
- 项目 ( project ):由一组关联的应用容器组成的一个完整业务单元,在 dockercompose.yml 文件中定义。
Compose 的默认管理对象是项目,通过子命令对项目中的一组容器进行便捷地生命周期管理。可见,一个项目可以由多个服务(容器)关联而成, Compose 面向项目进行管理
Compose 项目由 Python 编写,实现上调用了 Docker 服务提供的 API 来对容器进行管理。因此,只要所操作的平台支持 Docker API,就可以在其上利用 Compose 来进行编排管理。
二、CentOS 7 安装docker compose
Compose有很多种安装方式,例如通过Shell、pip以及将Compose作为容器安装等。本文通过pip来安装Compose,其它安装方式可以参照官方文档
1. 检查linux有没有安装python-pip包
pip -V
2. 没有安装python-pip执行下面命令
yum -y install epel-release
3. 执行成功之后,再次执行下面的命令
yum -y install python-pip
4. 对安装好的pip进行升级
pip install --upgrade pip
5. 安装docker compose
pip install docker-compose
6. 检查安装的docker compose版本
docker-compose -version
7. 安装compose命令补全工具
curl -L https://raw.githubusercontent.com/docker/compose/$(docker-compose version --short)/contrib/completion/bash/docker-compose -o /etc/bash_completion.d/docker-compose
这样重新登陆之后,输入docker-compose
并按下tab键,Compose就可以自动补全命令。
三、docker compose入门
3.1 基本步骤
- 在 Dockfile 中定义你的应用环境,使其可以在任何地方重现该环境。
- 在
docker-compose.yml
中定义组成应用程序的服务,以便它们可以在隔离的环境中一起运行。 - 运行
dcoker-compose up
,Compose 将启动并运行整个应用程序。
3.2 工程、服务、容器
Docker Compose将所管理的容器分为三层,分别是工程(project)、服务(service)、容器(container)。Docker Compose运行目录下的所有文件(docker-compose.yml、extends文件或环境变量文件)组成一个工程(默认为docker-compose.yml所在目录的目录名称)。一个工程可包含多个服务,每个服务中定义了容器运行的镜像、参数、依赖,一个服务科包括多个容器实例
3.3 docker-compose.yml常用命令
build
配置构建时的选项,Compose会利用它自动构建镜像。build的值可以是一个路径,例如:
build: ./dir
也可以是一个对象,用于指定Dockerfile和参数,例如:
build: context: ./dir dockerfile: Dockerfile-alternate args: buildno: 1
command
覆盖容器启动后默认执行命令:
command: bundle exec thin -p 3000
也可以是一个list,类似于Dockerfile中的CMD指令,格式如下:
command: ["bundle", "exec", "thin", "-p", "3000"]
dns
配置DNS服务器。可以是一个值,也可以是一个列表。例如:
dns: 8.8.8.8 dns: - 8.8.8.8 - 9.9.9.9
dns_search
配置DNS搜索域,可以是一个值,也可以是一个列表。例如:
dns_search: example.com dns_search: - dc1.example.com - dc2.example.com
environment
环境变量设置,可使用数组或字典两种方式,例如:
environment: RACK_ENV: development SHOW: 'true' SESSION_SECRET: environment: - RACK_ENV=development - SHOW=true - SESSION_SECRET
env_file
从文件中获取环境变量,可指定一个文件路径或路径列表。如果通过docker-compose -f FiLE指定了Compose文件,那么env_file中的路径是Compose文件所在目录的相对路径。使用environment指定的环境变量会覆盖env_file指定的环境变量。例如:
env_file: .env env_file: - ./common.env - ./apps/web.env - /opt/secrets.env
expose
暴露端口,只将端口暴露给连接的服务,而不暴露给宿主机。例如:
expose: - "3000" - "8000"
external_links
连接到docker-compose.yml外部的容器,甚至并非Compose管理的容器,特别是提供共享或公共服务的容器。格式跟links类似,例如:
external_links: - redis_1 - project_db_1:mysql - project_db_1:postgresql
image
指定镜像名称或镜像ID,如果本地不存在该镜像,Compose会尝试下载该镜像。例如:
image: java
links
连接到其他服务容器。可以指定服务名称和服务列表(SERVICE:ALIAS),也可只指定服务名称。例如:
web: links: - "db" - "db:database" - "redis"
network_mode
设置网络模式,例如:
network_mode: "bridge" network_mode: "host" network_mode: "none" network_mode: "service:[service name]" network_mode: "container:[container name/id]"
ports
暴露端口信息,可使用HOST:CONTAINER的格式,也可只指定容器端口(此时缩主机将会随机选择端口),类似于docker run -p
需要注意的是,当使用HOST:CONTAINER格式映射端口时,容器端口小于60将会得到错误的接口。因此,建议使用字符串的形式,例如:ports: - "3000" - "3000-3005" - "8000:8000" - "9090-9091:8080-8081" - "49100:22" - "127.0.0.1:8001:8001" - "127.0.0.1:5000-5010:5000-5010" - "6060:6060/udp" - "12400-12500:1240"
volumes
卷挂载路径设置。可以设置宿主机路径(HOST:CONTAINER),也可指定访问模式(HOST:CONTAINER:ro),例如:
volumes: # Just specify a path and let the Engine create a volume - /var/lib/mysql # Specify an absolute path mapping - /opt/data:/var/lib/mysql # Path on the host, relative to the Compose file - ./cache:/tmp/cache # User-relative path - ~/configs:/etc/configs/:ro # Named volume - datavolume:/var/lib/mysql
volumes_from
从另外一个服务或容器挂载卷。可指定只读(ro)或读写(rw),默认是读写(rw),例如:
volumes_from: - service_name - service_name:ro - container:container_name - container:container_name:r
四、docker-compose常用命令
下面讨论docker-compose的常用命令。
1. build
构建或重新构建服务。服务被构建后将会以project_service的形式存在,例如:compo-setest_db
2. help
查看指定命令的文档
```cmd
docker-compose help COMMAND
```
3. kill
通过发送SIGKILL信号停止指定服务的容器。示例:
```cmd
docker-compose kill eureka
```
4. logs
查看服务的日志输入
5. port
打印绑定的公共端口。示例:
```cmd
docker-compose port eureka 8761
```
可输出eureka服务8761端口所绑定的公共端口
6. ps
列出所有容器。示例:
```cmd
docker-compose ps
```
7. pull
下载服务镜像
8. rm
删除指定服务的容器。示例:
```cmd
docker-compose rm eureka
```
9. run
在一个服务上执行一个命令。示例:
```cmd
docker-composse run web bash
```
这样可以启动一个web服务,同时执行bash命令
10. scale
设置指定服务运实例的个数,以service=num的形式 指定。示例:
```cmd
docker-compose sscale user=3 movice=3
```
11. start
启动指定服务已存在的容器。示例 :
```cmd
docker-compose start eureka
```
12. stop
停止已运行的容器。示例:
```cmd
docker-compose sstop eureka
```
13. up
构建、创建、重新构建启动连接服务相关的容器。所有连接的服务都会启动,除非它们已运行。docker-compose up命令会聚合所有容器的输出,当命令退出时,所有容器都会退出。使用docker-compose up -d可在后台启动并运行所有容器。
五、部署示例
本节使用docker compose部署spring cloud项目。
1. 服务概述
我们一共部署四个服务,如下所示:
服务 | 端口 | 备注 |
---|---|---|
eureka-server | 1111,1112 | 服务注册与发现中心(高可用部署) |
demo | 8102 | 服务1 |
feign-upload_first | 8100 | 服务2 |
feign_upload_second | 8101 | 服务 |
2. 各服务添加Docker构建插件
<!-- Docker maven plugin -->
<plugin>
<groupId>com.spotify</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>1.0.0</version>
<configuration>
<imageName>simon/${project.artifactId}:${project.version}</imageName>
<!--<dockerDirectory>src/main/docker</dockerDirectory>-->
<forceTags>true</forceTags>
<baseImage>java</baseImage>
<entryPoint>["java","-jar","/${project.build.finalName}.jar"]</entryPoint>
<resources>
<resource>
<targetPath>/</targetPath>
<directory>${project.build.directory}</directory>
<include>${project.build.finalName}.jar</include>
</resource>
</resources>
</configuration>
</plugin>
3. 修改服务注册中心地址
一组 compose 的服务通讯需要使用 services 的名称进行访问
之前各个项目配置的服务注册中心地址如下:
```properties
eureka.client.service-url.defaultZone=http://localhost:1111/eureka/,http://localhost:1112/eureka/
```
由于Docker默认网络模式是bridge,各个容器的IP不相同,因此上面的配置不满足需求。可为Eureka Server所在的容器配置主机名,并让各个服务使用主机名访问Eureka Server。所有服务修改配置如下:
```properties
eureka.client.service-url.defaultZone=http://peer1:1111/eureka/,http://peer2:1112/eureka/
```
由于Eureka server是高可用部署,所以配置文件如下:
* application-peer1.properties
```properties
server.port=1111
spring.application.name=eureka-server
eureka.instance.hostname=peer1
eureka.client.service-url.defaultZone=http://peer2:1112/eureka/
```
* application-peer2.properties
```properties
server.port=1112
spring.application.name=eureka-server
eureka.instance.hostname=peer2
eureka.client.service-url.defaultZone=http://peer1:1111/eureka/
```
4. 编写docker-compose-manage.yml
```yml
version: "2"
services:
# 指定服务名称
peer1:
image: ibase/eureka-server:0.0.1-SNAPSHOT
ports:
- "1111:1111"
environment:
- spring.profiles.active=peer1
peer2:
image: ibase/eureka-server:0.0.1-SNAPSHOT
hostname: peer2
ports:
- "1112:1112"
environment:
- spring.profiles.active=peer2
```
5. 编写docker-compose-services.yml
```yml
version: "2"
services:
# 指定服务名称
feign_upload_first:
#指定服务所使用的镜像名称
image: ibase/feign_upload_first:0.0.1-SNAPSHOT
ports:
- "8100:8100"
feign_upload_second:
image: ibase/feign_upload_second:0.0.1-SNAPSHOT
ports:
- "8101:8101"
demo:
image: ibase/demo:0.0.1-SNAPSHOT
ports:
- "8102:8102"
```
这里说明一下,为什么有两份配置,不清楚什么原因,配置写在一起,启动容器会报错,服务治理与服务service分开就不会出错,这个需要研究一下。
6. 编译部署
将所有项目和配置文件上传到linux上,在各个服务根目录使用如下命令构建镜像:
```cmd
mvn clean package docker:build
```
先后执行如下命令启动项目:
```cmd
docker-compose docker-compose-manage.yml up
```
```cmd
docker-compose docker-compose-services.yml up
```
7. 启动后测试
正常访问服务接口。