Docker-Compose介绍
Compose 是 Docker 公司推出的一个工具软件,可以管理多个 Docker 容器组成一个应用。你需要定义一个 YAML 格式的配置文件docker-compose.yml,写好多个容器之间的调用关系。然后,只要一个命令,就能同时启动/关闭这些容器
Docker-Compose是Docker官方的开源项目,负责实现对Docker容器集群的快速编排。
作用
docker建议我们每一个容器中只运行一个服务,因为docker容器本身占用资源极少,所以最好是将每个服务单独的分割开来但是这样我们又面临了一个问题?
如果我需要同时部署好多个服务,难道要每个服务单独写Dockerfile然后再构建镜像,构建容器,这样累都累死了,所以docker官方给我们提供了docker-compose多服务部署的工具
例如要实现一个Web微服务项目,除了Web服务容器本身,往往还需要再加上后端的数据库mysql服务容器,redis服务器,注册中心eureka,甚至还包括负载均衡容器等等。
Compose允许用户通过一个单独的docker-compose.yml模板文件(YAML 格式)来定义一组相关联的应用容器为一个项目(project)。
可以很容易地用一个配置文件定义一个多容器的应用,然后使用一条指令安装这个应用的所有依赖,完成构建。Docker-Compose 解决了容器与容器之间如何管理编排的问题。
下载
compose-file是Docker Compose使用的文件格式,用于定义所有服务的配置和资源。Compose-file允许您指定应用程序的服务、网络、卷和环境变量等,以及它们之间的依赖关系和交互。Compose-file中定义的服务可以通过Docker Compose工具进行管理和启动。
compose-file是Docker Compose的一部分,是用于定义多容器应用程序的配置文件格式。Docker Compose则是使用该配置文件进行启动和管理多容器应用程序的工具。
compose-file版本
官网:https://docs.docker.com/compose/compose-file/compose-file-v3/
官网提供了V2、V3版本
这两个版本之间有以下区别:
- 网络: v2版本使用link指令连接容器,而v3版本使用网络服务连接容器。
- 部署: v2版本允许部署容器在特定的节点上,而v3版本添加了支持Stacks,允许用户在Docker Swarm模式下创建分布式应用程序,这样可以更好地管理多个容器并部署到多个节点上。
- 配置: v3版本增加了更多的配置选项,例如配置CPU亲和性、日志记录等,在更高级的方案中提供更多灵活性。
- 缩放: v3版本可以按名称缩放服务,而不是按容器ID。
总的来说,v3版本相对于v2版本更加强大和灵活,特别是在容器部署和管理方面有更多的选择,同时也提供了更多的功能来管理多个容器。
Compose file version 3 对应 Docker Compose 版本为 1.13.0 或更高版本。
下载地址:https://docs.docker.com/compose/install/
安装
Docker Compose版本为1.29.2
curl -L “https://github.com/docker/compose/releases/download/1.29.2/docker-compose- ( u n a m e − s ) − (uname -s)- (uname−s)−(uname -m)” -o /usr/local/bin/docker-compose
如果提示Failed connect to github.com:443; 拒绝连接
这个错误通常说明你的系统无法连接到 Github.com 上。可能是因为你的网络连接有问题,或者该域名被防火墙阻止。你可以尝试使用
ping github.com 命令来测试是否能够访问。如果无法访问,你可以尝试使用 VPN 或更换网络环境来解决问题。
查看github.com对应的ip 随便找个网站
确保网络可用的情况下,修改host
vi /etc/hosts
然后又提示Failed connect to objects.githubusercontent.com:443; 拒绝连接
如法炮制
尝试了几次算是成功了,安装完后hosts里的映射可以考虑删除
赋予用户文件的读写权限
chmod +x /usr/local/bin/docker-compose
查看版本
docker-compose --version
卸载
rm /usr/local/bin/docker-compose
Compose常用命令
docker-compose -h # 查看帮助
docker-compose up # 启动所有docker-compose服务
docker-compose up -d # 启动所有docker-compose服务并后台运行
docker-compose down # 停止并删除容器、网络、卷、镜像。
docker-compose exec yml里面的服务id # 进入容器实例内部 docker-compose exec docker-compose.yml文件中写的服务id /bin/bash
docker-compose ps # 展示当前docker-compose编排过的运行的所有容器
docker-compose top # 展示当前docker-compose编排过的容器进程
docker-compose logs yml里面的服务id # 查看容器输出日志
docker-compose config # 检查配置
docker-compose config -q # 检查配置,有问题才有输出
docker-compose restart # 重启服务
docker-compose start # 启动服务
docker-compose stop # 停止服务
Compose使用的三个步骤
1.编写Dockerfile定义各个微服务应用并构建出对应的镜像文件
2.使用 docker-compose.yml 定义一个完整业务单元,安排好整体应用中的各个容器服务。
3.最后,执行docker-compose up命令 来启动并运行整个应用程序,完成一键部署上线
Compose编排微服务案例
对之前通过<dockerfile发布微服务部署到docker容器>章节创建的docker-boot项目进行改造,来熟悉Compose编排与命令
改造升级微服务工程docker-boot
sql建表
CREATE TABLE `t_user` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`username` varchar(50) NOT NULL DEFAULT '' COMMENT '用户名',
`password` varchar(50) NOT NULL DEFAULT '' COMMENT '密码',
`sex` tinyint(4) NOT NULL DEFAULT '0' COMMENT '性别 0=女 1=男 ',
`deleted` tinyint(4) unsigned NOT NULL DEFAULT '0' COMMENT '删除标志,默认0不删除,1删除',
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='用户表'
一键生成工具
https://github.com/dongguo4812/mybatis-generator.git
替换对应数据库,将生成的entity、mapper复制到docker-boot项目中
改POM
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<junit.version>4.12</junit.version>
<log4j.version>1.2.17</log4j.version>
<lombok.version>1.16.18</lombok.version>
<mysql.version>5.1.47</mysql.version>
<druid.version>1.1.16</druid.version>
<mapper.version>4.1.5</mapper.version>
<mybatis.spring.boot.version>1.3.0</mybatis.spring.boot.version>
</properties>
<dependencies>
<!--guava Google 开源的 Guava 中自带的布隆过滤器-->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>23.0</version>
</dependency>
<!-- redisson -->
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.13.4</version>
</dependency>
<!--SpringBoot通用依赖模块-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--swagger2-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
<!--SpringBoot与Redis整合依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--springCache-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<!--springCache连接池依赖包-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<!-- jedis -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.1.0</version>
</dependency>
<!--Mysql数据库驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<!--SpringBoot集成druid连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>${druid.version}</version>
</dependency>
<!--mybatis和springboot整合-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${mybatis.spring.boot.version}</version>
</dependency>
<!-- 添加springboot对amqp的支持 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.10</version>
</dependency>
<!--通用基础配置junit/devtools/test/log4j/lombok/hutool-->
<!--hutool-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.2.3</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<optional>true</optional>
</dependency>
<!--persistence-->
<dependency>
<groupId>javax.persistence</groupId>
<artifactId>persistence-api</artifactId>
<version>1.0.2</version>
</dependency>
<!--通用Mapper-->
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper</artifactId>
<version>${mapper.version}</version>
</dependency>
</dependencies>
写YML
server:
port: 8081
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://192.168.122.139:3306/idtest?useUnicode=true&characterEncoding=utf-8&useSSL=false
username: root
password: root
druid:
test-while-idle: false
mvc:
pathmatch:
matching-strategy: ant_path_matcher
redis:
database: 0
# host: 192.168.122.139
host: redis
port: 6379
password: root
jedis:
pool:
max-active: 8
max-wait: 1ms
max-idle: 8
min-idle: 0
swagger2:
enabled: true
mybatis:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.dongguo.entity
主启动
@SpringBootApplication
@MapperScan("com.dongguo.mapper")
public class DockerBootApplication {
public static void main(String[] args) {
SpringApplication.run(DockerBootApplication.class, args);
}
}
完整项目传送门:https://github.com/dongguo4812/docker-study/tree/master/docker-boot
mvn package命令将微服务形成新的jar包
并上传到Linux服务器/mydocker目录下
编写Dockerfile
# 基础镜像使用java
FROM java:8
# 作者
MAINTAINER dongguo
# VOLUME 指定临时文件目录为/tmp,在主机/var/lib/docker目录下创建了一个临时文件并链接到容器的/tmp
VOLUME /tmp
# 将jar包添加到容器中并更名为dg-docker.jar
ADD docker-boot-0.0.1-SNAPSHOT.jar dg-docker.jar
# 运行jar包
RUN bash -c 'touch /dg-docker.jar'
ENTRYPOINT ["java","-jar","/dg-docker.jar"]
#暴露8081端口作为微服务
EXPOSE 8081
构建镜像
docker build -t dg-docker:1.0 .
before
不使用Compose的话启动tomcat mysql redis。分别启动这三个容器实例
单独的mysql容器实例
新建mysql容器实例
docker run -p 3306:3306 --name mysql57 --privileged=true -v /dongguo/mysql/conf:/etc/mysql/conf.d -v /dongguo/mysql/logs:/logs -v /dongguo/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=root -d mysql:5.7
进入mysql容器实例并新建库idtest新建表t_user
docker exec -it mysql57 /bin/bash
mysql -uroot -p
create database idtest;
use idtest;
CREATE TABLE `t_user` (
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`username` VARCHAR(50) NOT NULL DEFAULT '' COMMENT '用户名',
`password` VARCHAR(50) NOT NULL DEFAULT '' COMMENT '密码',
`sex` TINYINT(4) NOT NULL DEFAULT '0' COMMENT '性别 0=女 1=男 ',
`deleted` TINYINT(4) UNSIGNED NOT NULL DEFAULT '0' COMMENT '删除标志,默认0不删除,1删除',
`update_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`create_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='用户表';
单独的redis容器实例
docker run -p 6379:6379 --name redis608 --privileged=true -v /app/redis/redis.conf:/etc/redis/redis.conf -v /app/redis/data:/data -d redis:6.0.8 redis-server /etc/redis/redis.conf
启动微服务工程
docker run -d -p 8081:8081 dg-docker:1.0
上面三个容器实例依次顺序启动成功
swagger测试
http://你的ip:你的端口/swagger-ui.html#/
显然这样启动有很多的问题
先后顺序要求固定,先mysql+redis才能微服务访问成功;
容器间的启停或宕机,有可能导致IP地址对应的容器实例变化,映射出错,要么生产IP写死(可以但是不推荐,很少这样),要么通过服务名调用
如果需要启动多个容器,可能需要手动运行多个docker run指令,每个容器都需要单独设置不同的配置和参数,这会增加管理难度。
如果需要更新容器的配置或参数,需要手动修改每个容器的启动指令,这会增加更新难度和错误的风险。
after
使用Docker-compose
编写docker-compose.yml文件
version: "3"
services:
bootService:
image: dg-docker:1.0
container_name: boot
ports:
- "8081:8081"
volumes:
- /app/microService:/data
networks:
- dg_net
depends_on:
- redis
- mysql
redis:
image: redis:6.0.8
ports:
- "6379:6379"
volumes:
- /app/redis/redis.conf:/etc/redis/redis.conf
- /app/redis/data:/data
networks:
- dg_net
command: redis-server /etc/redis/redis.conf
mysql:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: 'root'
MYSQL_ALLOW_EMPTY_PASSWORD: 'no'
MYSQL_DATABASE: 'idtest'
MYSQL_USER: 'dongguo'
MYSQL_PASSWORD: 'dongguo'
ports:
- "3306:3306"
volumes:
- /app/mysql/db:/var/lib/mysql
- /app/mysql/conf/my.cnf:/etc/my.cnf
- /app/mysql/init:/docker-entrypoint-initdb.d
networks:
- dg_net
command: --default-authentication-plugin=mysql_native_password #解决外部无法访问
networks:
dg_net:
这三个容器在同一网段,通过服务名就可以访问
再次修改微服务工程docker-boot
yml
将ip访问修改为服务名访问
server:
port: 8081
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
#url: jdbc:mysql://192.168.122.139:3306/idtest?useUnicode=true&characterEncoding=utf-8&useSSL=false
url: jdbc:mysql://mysql:3306/idtest?useUnicode=true&characterEncoding=utf-8&useSSL=false
username: root
password: root
druid:
test-while-idle: false
mvc:
pathmatch:
matching-strategy: ant_path_matcher
redis:
database: 0
# host: 192.168.122.139
host: redis
port: 6379
password: root
jedis:
pool:
max-active: 8
max-wait: 1ms
max-idle: 8
min-idle: 0
swagger2:
enabled: true
mybatis:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.dongguo.entity
mvn package命令将微服务形成新的jar包,并上传到Linux服务器/mydocker目录下
编写Dockerfile
这里和之前的内容是一样的。
# 基础镜像使用java
FROM java:8
# 作者
MAINTAINER dongguo
# VOLUME 指定临时文件目录为/tmp,在主机/var/lib/docker目录下创建了一个临时文件并链接到容器的/tmp
VOLUME /tmp
# 将jar包添加到容器中并更名为dg-docker.jar
ADD docker-boot-0.0.1-SNAPSHOT.jar dg-docker.jar
# 运行jar包
RUN bash -c 'touch /dg-docker.jar'
ENTRYPOINT ["java","-jar","/dg-docker.jar"]
#暴露8081端口作为微服务
EXPOSE 8081
删除构建的容器
删除之前构建的镜像
重新构建镜像
docker build -t dg-docker:1.0 .
先确认文件的配置是否正确
docker-compose config -q
没有消息是最好的消息
执行 docker-compose up或者执行 docker-compose up -d
从控制台能够看出如果不定义容器名container_name,会生成mydocker_XXX_I 的名称
创建网络mydocker_dg_net
容器都已经启动
进入mysql容器实例并新建库idtest+新建表t_user
docker exec -it baf541a8a2a2 /bin/bash
之前创建过idtest数据库,现在已经同步。可以直接访问mysql
mysql -uroot -p
use idtest;
CREATE TABLE `t_user` (
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`username` VARCHAR(50) NOT NULL DEFAULT '' COMMENT '用户名',
`password` VARCHAR(50) NOT NULL DEFAULT '' COMMENT '密码',
`sex` TINYINT(4) NOT NULL DEFAULT '0' COMMENT '性别 0=女 1=男 ',
`deleted` TINYINT(4) UNSIGNED NOT NULL DEFAULT '0' COMMENT '删除标志,默认0不删除,1删除',
`update_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`create_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='用户表';
测试
停止容器
docker-compose stop
通过Docker-compose,可以通过一个YAML文件一次性启动和管理多个容器实例,而不需要手动逐个启动和管理。这样可以简化管理操作,并确保容器实例的一致性。
启动、关闭多个容器实例变得如此简单