Docker帮助我们解决服务的打包安装的问题,随着而来的问题就是服务过多的带来如下问题:
当我们服务数量增多的时候,上面三个问题就会更加的被放大,如果这三个问题不解决,其实从虚拟机到容器化除了机器减少一些浪费以外,好像没有更多的变化。Docker有没有什么好的方法,可以让我们通过一个配置就搞定容器编排和运行呢?这个时候Docker Compose就站出来了。
Docker Compose可以做到以下几点:
Docker Compose有以下特征:
Docker Compose是一个工具,用于定义和运行多容器应用程序的工具;
Docker Compose通过yml文件定义多容器的docker应用;
Docker Compose通过一条命令根据yml文件的定义去创建或管理多容器;

Docker Compose 是用来做Docker 的多容器控制,是一个用来把 Docker 自动化的东西。有了 Docker Compose 你可以把所有繁复的 Docker 操作全都一条命令,自动化的完成。
Docker Compose安装的最新的版本1.29.2,对于Mac和Windows安装好Docker以后,就已经安装好Docker Compose,不需要手动安装,这里的安装方式是基于Linux的Cnetos的,大家也可以参考官方网站去安装,
具体步骤如下:
sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose

Docker Compose版本与引擎的对应关系如下,可以看到中间主要有两个版本2和版本3两种格式,目前大家使用比较多也就是这两种,对于这两个版本的差别给大家介绍一下:
注意:官方目前在 1.20.0 引入了一个新–compatibility标志,帮助开发人员轻松的过渡到v3,目前还有些问题官方还不建议直接使用到生产,建议大家直接上手v3版本。

Docker Compose命令基本上和Docker相差不多,主要就是对Docker Compose生命周期控制、日志格式等相关命令,可以通过docker-compose --help进行帮助。
#构建建启动nignx容器
docker-compose up -d nginx
#进入nginx容器中
docker-compose exec nginx bash
#将会停止UP命令启动的容器,并删除容器
docker-compose down
#显示所有容器
docker-compose ps
#重新启动nginx容器
docker-compose restart nginx
#构建镜像
docker-compose build nginx
#不带缓存的构建
docker-compose build --no-cache nginx
#查看nginx的日志
docker-compose logs nginx
#查看nginx的实时日志
docker-compose logs -f nginx
#验证(docker-compose.yml)文件配置,
#当配置正确时,不输出任何内容,当文件配置错误,输出错误信息
docker-compose config -q
#以json的形式输出nginx的docker日志
docker-compose events --json nginx
#暂停nignx容器
docker-compose pause nginx
#恢复ningx容器
docker-compose unpause nginx
#删除容器
docker-compose rm nginx
#停止nignx容器
docker-compose stop nginx
#启动nignx容器
docker-compose start nginx
我们构建一个如下的应用,通过Nginx转发给后端的两个Java应用;

/**
* hello
*
* @author wangtongzhou
* @since 2021-07-25 09:43
*/
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello(HttpServletRequest req) throws UnknownHostException {
return "hello";
}
}
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<!-- 指定该Main Class为全局的唯一入口 -->
<mainClass>cn.wheel.getway.WheelGetWay</mainClass>
</configuration>
<executions>
<execution>
<goals>
<!--可以把依赖的包都打包到生成的Jar包中-->
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
mvn package
#指定基础镜像
FROM java:8
LABEL name="docker-compose-demo" version="1.0" author="wtz"
COPY ./getway-1.0-SNAPSHOT.jar ./docker-compose-demo.jar
#启动参数
CMD ["java","-jar","docker-compose-demo.jar"]
version: '3.0'
networks:
docker-compose-demo-net:
driver: bridge
ipam:
config:
- subnet: 192.168.1.0/24
gateway: 192.168.1.1
services:
docker-compose-demo01:
build:
#构建的地址
context: /usr/local/docker-compose-demo
dockerfile: Dockerfile
image: docker-compose-demo
container_name: docker-compose-demo01
#选择网络
networks:
- docker-compose-demo-net
#选择端口
ports:
- 8081:8080/tcp
restart: always
docker-compose-demo02:
build:
#构建的地址
context: /usr/local/docker-compose-demo
dockerfile: Dockerfile
image: docker-compose-demo
container_name: docker-compose-demo02
#选择网络
networks:
- docker-compose-demo-net
#选择端口
ports:
- 8082:8080/tcp
restart: always
nginx:
image: nginx:latest
container_name: nginx-demo
networks:
- docker-compose-demo-net
ports:
- 80:80/tcp
restart: always
volumes:
- /usr/local/docker-compose-demo/nginx.conf:/etc/nginx/nginx.conf:rw
volumes:
docker-compose-demo-volume: {}
user nginx;
worker_processes 1;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
location / {
proxy_pass http://docker-compose-demo;
proxy_set_header Host $host;
proxy_set_header X-real-ip $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
upstream docker-compose-demo{
server docker-compose-demo01:8080;
server docker-compose-demo02:8080;
}
include /etc/nginx/conf.d/*.conf;
server {
listen 80;
location / {
proxy_pass http://docker-compose-demo;
proxy_set_header Host $host;
proxy_set_header X-real-ip $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
upstream docker-compose-demo{
server docker-compose-demo01:8080;
server docker-compose-demo02:8080;
}
include /etc/nginx/conf.d/*.conf;
}
查看/usr/local/docker-compose-demo目录,有以下确保有以下四个文件;

检查docker-compose.yml的语法是否正确,如果不发生报错,说明语法没有发生错误;
docker-compose config
启动docker-compose.yml定义的服务;
docker-compose up

#查看宿主机ip
ip add
#访问对应的服务
curl http://172.21.122.231/hello


version
指定使用的版本;
Services
每个Service代表一个Container,与Docker一样,Container可以是从DockerHub中拉取到的镜像,也可以是本地Dockerfile Build的镜像。
image
标明image的ID,这个image ID可以是本地也可以是远程的,如果本地不存在,Docker Compose会尝试pull下来;
image: ubuntu
build
该参数指定Dockerfile文件的路径,Docker Compose会通过Dockerfile构建并生成镜像,然后使用该镜像;
build:
#构建的地址
context: /usr/local/docker-compose-demo
dockerfile: Dockerfile
ports
暴露端口,指定宿主机到容器的端口映射,或者只指定容器的端口,则表示映射到主机上的随机端口,一般采用主机:容器的形式来映射端口;
#暴露端口
ports:
- 8081:8080/tcp
expose
暴露端口,但不需要建立与宿主机的映射,只是会向链接的服务提供;
environment
加入环境变量,可以使用数组或者字典,只有一个key的环境变量可以在运行compose的机器上找到对应的值;
env_file
从一个文件中引入环境变量,该文件可以是一个单独的值或者一个列表,如果同时定义了environment,则environment中的环境变量会重写这些值;
depends_on
定义当前服务启动时,依赖的服务,当前服务会在依赖的服务启动后启动;
depends_on:
- docker-compose-demo02
- docker-compose-demo01
deploy
该配置项在version 3里才引入,用于指定服务部署和运行时相关的参数;
replicas
指定副本数;
version: '3.4'
services:
worker:
image: nginx:latest
deploy:
replicas: 6
restart_policy
指定重启策略;
version: "3.4"
services:
redis:
image: redis:latest
deploy:
restart_policy:
condition: on-failure #重启条件:on-failure, none, any
delay: 5s # 等待多长时间尝试重启
max_attempts: 3 #尝试的次数
window: 120s # 在决定重启是否成功之前等待多长时间
update_config
定义更新服务的方式,常用于滚动更新;
version: '3.4'
services:
vote:
image: docker-compose-demo
depends_on:
- redis
deploy:
replicas: 2
update_config:
parallelism: 2 # 一次更新2个容器
delay: 10s # 开始下一组更新之前,等待的时间
failure_action:pause # 如果更新失败,执行的动作:continue, rollback, pause,默认为pause
max_failure_ratio: 20 # 在更新过程中容忍的失败率
order: stop-first # 更新时的操作顺序,停止优先(stop-first,先停止旧容器,再启动新容器)还是开始优先(start-first,先启动新容器,再停止旧容器),默认为停止优先,从version 3.4才引入该配置项
resources
限制服务资源;
version: '3.4'
services:
redis:
image: redis:alpine
deploy:
resources:
#限制CPU的使用率为50%内存50M
limits:
cpus: '0.50'
memory: 50M
#始终保持25%的使用率内存20M
reservations:
cpus: '0.25'
memory: 20M
healthcheck
执行健康检查;
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost"] # 用于健康检查的指令
interval: 1m30s # 间隔时间
timeout: 10s # 超时时间
retries: 3 # 重试次数
start_period: 40s # 启动多久后开始检查
restart
重启策略;
#默认的重启策略,在任何情况下都不会重启容器
restart: "no"
#容器总是重新启动
restart: always
#退出代码指示失败错误,则该策略会重新启动容器
restart: on-failure
#重新启动容器,除非容器停止
restart: unless-stopped
networks
网络类型,可指定容器运行的网络类型;
#指定对应的网络
networks:
- docker-compose-demo-net
networks:
docker-compose-demo-net:
driver: bridge
ipam:
config:
- subnet: 192.168.1.0/24
gateway: 192.168.1.1
ipv4_address, ipv6_address
加入网络时,为此服务指定容器的静态 IP 地址;
version: "3.9"
services:
app:
image: nginx:alpine
networks:
app_net:
ipv4_address: 172.16.238.10
ipv6_address: 2001:3984:3989::10
networks:
app_net:
ipam:
driver: default
config:
- subnet: "172.16.238.0/24"
- subnet: "2001:3984:3989::/64"
Networks
网络决定了服务之间以及服务和外界之间如何去通信,在执行docker-compose up的时候,docker会默认创建一个默认网络,创建的服务也会默认的使用这个默认网络。服务和服务之间,可以使用服务的名字进行通信,也可以自己创建网络,并将服务加入到这个网络之中,这样服务之间可以相互通信,而外界不能够与这个网络中的服务通信,可以保持隔离性。
Volumes
挂载主机路径或命名卷,指定为服务的子选项。可以将主机路径挂载为单个服务定义的一部分,无需在顶级volume中定义。如果想在多个服务中重用一个卷,则在顶级volumes key 中定义一个命名卷,将命名卷与服务一起使用。
Docker Compose 的整体使用步骤还是比较简单的,三个步骤为:
虽然 docker-compose.yml 文件详解和Compose 常用命令这两大块的内容比较多,但是如果要快速入门使用 Compose,其实只需要了解其中部分内容即可。后期大家可在项目生产环境中根据自身情况再进一步深入学习即可。
?博客主页:https://xiaoy.blog.csdn.net?本文由呆呆敲代码的小Y原创,首发于CSDN??学习专栏推荐:Unity系统学习专栏?游戏制作专栏推荐:游戏制作?Unity实战100例专栏推荐:Unity实战100例教程?欢迎点赞?收藏⭐留言?如有错误敬请指正!?未来很长,值得我们全力奔赴更美好的生活✨------------------❤️分割线❤️-------------------------
MIMO技术的优缺点优点通过下面三个增益来总体概括:阵列增益。阵列增益是指由于接收机通过对接收信号的相干合并而活得的平均SNR的提高。在发射机不知道信道信息的情况下,MIMO系统可以获得的阵列增益与接收天线数成正比复用增益。在采用空间复用方案的MIMO系统中,可以获得复用增益,即信道容量成倍增加。信道容量的增加与min(Nt,Nr)成正比分集增益。在采用空间分集方案的MIMO系统中,可以获得分集增益,即可靠性性能的改善。分集增益用独立衰落支路数来描述,即分集指数。在使用了空时编码的MIMO系统中,由于接收天线或发射天线之间的间距较远,可认为它们各自的大尺度衰落是相互独立的,因此分布式MIMO
我刚刚看到whitehouse.gov正在使用drupal作为CMS和门户技术。drupal的优点之一似乎是很容易添加插件,而且编程最少,即重新发明轮子最少。这实际上正是Ruby-on-Rails的DRY理念。所以:drupal的缺点是什么?Rails或其他基于Ruby的技术有哪些不符合whitehouse.org(或其他CMS门户)门户技术的资格? 最佳答案 Whatarethedrawbacksofdrupal?对于Ruby和Rails,这确实是一个相当主观的问题。Drupal是一个可靠的内容管理选项,非常适合面向社区的站点。它
当音乐碰上区块链技术,会擦出怎样的火花?或许周杰伦已经给了我们答案。8月29日下午,B站独家首发周杰伦限定珍藏Demo独家访谈VCR,周杰伦在VCR里分享了《晴天》《青花瓷》《搁浅》《爱在西元前》四首经典歌曲Demo背后的创作故事,并首次公布18年前未发布的神秘作品《纽约地铁》的Demo。在VCR中,方文山和杰威尔音乐提及到“多亏了区块链技术,现在我们可以将这些Demos,变成独一无二具有收藏价值的艺术品,这些Demos可以在薄盒(国内数藏平台)上听到。”如何将音乐与区块链技术相结合,薄盒方面称:“薄盒作为区块链技术服务方,打破传统对于区块链技术只能作为数字收藏的理解。聚焦于区块链技术赋能,在
目录SpringBootStarter是什么?以前传统的做法使用SpringBootStarter之后starter的理念:starter的实现: 创建SpringBootStarter步骤在idea新建一个starter项目、直接执行下一步即可生成项目。 在xml中加入如下配置文件:创建proterties类来保存配置信息创建业务类:创建AutoConfiguration测试如下:SpringBootStarter是什么? SpringBootStarter是在SpringBoot组件中被提出来的一种概念、简化了很多烦琐的配置、通过引入各种SpringBootStarter包可以快速搭建出一
我感到有点困惑——大约24小时以来,我一直在考虑在我的项目中使用哪种组播技术。基本上,我需要的是:创建组(通过一些后端进程)任意客户端广播消息(1:N,N:N)(可能)直接消息(1:1)(重要)使用我自己的后端(例如,通过某种HTTPAPI)对客户端进行身份验证/授权能够通过后端进程(或服务器插件)踢出特定的客户端这是我要的:Ruby或Haxe中的后端相关流程JS+Haxe(Flash9)中的前端—在浏览器中,因此理想情况下通过80/443进行通信,但不一定。因此,这项技术必须能够在HaxeforFlash中轻松访问,最好是Ruby。我一直在考虑:RabbitMQ(或OpenAMQ)、
文章目录概述背景为何要存算分离优势**应用场景**存算分离产品技术流派华为JuiceFSHashDataXSKY概述背景Hadoop一出生就是奔存算一体设计,当时设计思想就是存储不动而计算(code也即是代码程序)动,负责调度Yarn会把计算任务尽量发到要处理数据所在的实例上,这也是与传统集中式存储最大的不同。为何当时Hadoop设计存算一体的耦合?要知道2006年服务器带宽只有100Mb/s~1Gb/s,但是HDD也即是磁盘吞吐量有50MB/s,这样带宽远远不够传输数据,网络瓶颈尤为明显,无奈之举只好把计算任务发到数据所在的位置。众观历史常言道天下分久必合合久必分,随着云计算技术的发展,数据
文章目录华为OD面试流程1.mysql数据库建了两个字段,且设置了联合索引,如果其中有一个字段为空会出现什么问题?2.谈谈springIOC的理解,有什么好处,解决了什么问题3.谈谈springAOP的理解,切面编程有没有实际应用,有哪些注解,作用是什么,有那些应用场景?4.Erika和zookeeper有了解过吗,作用是什么,主要解决了什么问题5.谈谈JDK、JRE、JVM的理解,区别是什么6.谈谈对泛型的理解7.JVM的组成华为OD面试流程机试:三道算法题,关于机试,橡皮擦已经准备好了各语言专栏,可以直接订阅。性格测试:机试技术一面(本专栏核心)技术二面(本专栏核心)主管面试定级定薪发of
解开谜团:深入探索ChatGPT的技术奇迹。ChatGpt无处不在,无论是在播客、博客、YouTube还是社交媒体上。当我注意到这项新技术如此受欢迎时,我决定试一试,我被震惊了!有很多关于ChatGpt及其魔力的博客,但在这篇博客中,我将深入探讨其内部技术及其工作原理!ChatGpt简介根据OpenAI,ChatGpt被描述为:“我们训练了一个名为ChatGpt的模型,它以对话方式进行交互。对话格式使ChatGpt可以回答后续问题、承认错误、挑战不正确的前提并拒绝不适当的请求。ChatGPT是InstructGPT的兄弟模型,它经过训练可以按照提示中的说明进行操作并提供详细的响应。”OpenA
我在/usr/local/lib中安装了一些本地库。我现在正在尝试安装一个需要这些的gem,以便正确构建,但是gem构建失败,因为它找不到图书馆。gem的extconf.rb文件试图确认它可以找到库have_library()但由于某种原因失败了。我尝试设置一堆环境变量,但似乎没有任何效果:irb(main):003:0>require'mkmf'=>trueirb(main):004:0>have_library('gecodesearch')checkingformain()in-lgecodesearch...no=>falseirb(main):005:0>ENV['LD_LI