经过前文讲解,可使用Dockerfile(或Maven)构建镜像,然后使用docker命令操作容器,例如docker run、docker kiil等。然而,使用微服务架构的应用系统一般包含若干个微服务,每个微服务一般都会部署国歌示例。如果每个微服务都有手动启停,那么效率之低、维护量之大可想而知。
Compose是一个用于定义和运行多容器Docker应用程序的工具,前身是Fig。它非常适合用在开发、测试、构建CI工作流等场景。这里使用的Compose版本是1.10.0。
1)通过以下命令自动下载并安装适应系统版本的Compose
curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
2)为安装脚本添加执行权限
chmod +x /usr/local/bin/docker-compose
这样,Compose就按照完成了。
可使用以下命令测试安装结果:
docker-compose --version
Compose大致有3个步骤:
1)使用mvn clean package命令打包项目,获得jar包。
2)在jar所在路径创建DOckerfile文件,并在其中添加如下内容。
#基于哪个镜像
FROM java:8
#将本地文件夹挂载到当前容器
VOLUME /tmp
#复制文件到容器
ADD microservice-discovery-eureka-1.0-SNAPSHOT.jar app.jar
RUN bash -c 'touch /app.jar'
#声明需要暴露的端口
EXPOSE 8761
#配置容器启动后执行的命令
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
3)在jar所在路径创建文件docker-compose.yml,在其中添加
version: '3.8'
services:
eureka: #指定服务名称
build: . #指定Dockerfile所在路径
ports:
- "8761:8761" #指定端口映射,类似docker run -p选项,注意使用字符串形式
4)在docker-compose.yml所在路径执行以下命令:
docker-compose up
Docker Compose将管理的容器分为三层,分别是工程(project),服务(service)以及容器(container)。Docker Compose运行目录下的所有文件(docker-compose.yml、extends文件或环境变量文件等)组成一个工程(默认为docker-compose.yml所在目录的目录名称)。一个工程可包含多个服务,每个服务中定义了容器运行的镜像、参数和依赖,一个服务可包括多个容器示例。
对应上文,工程名称是docker-compose.yml所在的目录名。该工程包含了1个服务,服务名称是eureka。执行docker-compose up时,启动类eureka 服务的一个容器实例。
docker-compose.yml是Compose的默认模板文件。该文件有多种格式,例如Version 1 file format、Version 2 file format、Version 2.1 file format、Version 3 file format等。其中,Version 1 file format、将逐步被弃用,Version 2.x及Version3.x基本兼容。
这里只讨论Version 3 file format下的常用命令
build: ./dir
也可以是一个对象,用于指定Dockerfile和参数,例如:
build:
context: ./dir
dockerfile: Dockerfile-alternate
args:
buildno:1
command: bundle exec thin -p 3000
也可以是一个list,类似Dockerfile中的CMD指令,格式如下:
command: [bundle, exec, thin, -p, 3000]
dns: 8.8.8.8
dns:
- 8.8.8.8
- 9.9.9.9
dns_search: example.com
dns_search:
- dc1.example.com
- dc2.example.com
environment:
RACK_ENV: development
SHOW: 'true'
SESSION_SECRET:
environment:
- RACK_ENV=development
- SHOW=true
- SESSION_SECRET
env_file: .env
env_file:
- ./common.env
- ./apps/web.env
- /opt/secrets.env
expose:
- "3000"
- "8000"
external_links:
- redis_1
- project_db_1:mysql
- project_db_1:postgersql
image: java
web:
links:
- db
- db:database
- redis
network_mode: "bridge"
network_mode: "host"
network_mode: "none"
network_mode: "service:[service name]"
network_mode: "container:[container name/id]"
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"
volumes:
- /var/lib/mysql
- /opt/data:/var/lib/mysql
- ./cache:/tmp/cache
- ~/configs:/etc/configs/:ro
- datavolume:/var/lib/mysql
注:docker-compose.yml还有很多其他命令,比如depends_on、pid、devices等略。
和docker命令一样,docker-compose命令也有很多选项
docker-compose help COMMAND
docker-compose kill eureka
该命令也支持通过参数来指定发送的信号。
docker-compose kill -s SIGINT
docker-compose port eureka 8761
这样就可输出eureka服务8761端口所绑定的公共端口。
docker-compose ps
也可列出指定服务的容器
docker-compose ps eureka
docker-compose rm eureka
docker-compose run web bash
docker-compose scale user=3 movie=3
docker-compose start eureka
docker-compose stop eureka
停止后,可使用docker-compose start再次启动这些容器。
默认情况下,Compose会为应用创建一个网络,服务的每个容器都会加入该网络中。这样,容器就可被网络中的其他容器访问,不仅如此,该容器还能以服务名称作为hostname被其他容器访问。
默认情况下,应用程序的网络名称基于Compose的工程名称,而项目名称基于docker-compose.yml所在目录的名称。如需修改工程名称,可使用-project-name标识或COMPOSE_PORJECT_NAME环境变量。
例子:
一个应用程序在名为myapp的目录中,并且docker-compose.yml
version: '3'
service:
web:
build: .
ports:
- "8000:8000"
db:
image: postgres
当运行docker-compose up时,将执行以下几步:
1)创建一个名为myapp_default的网络。
2)使用web服务的配置创建容器,它以"web"这个名称加入网络myapp_default。
3)使用db服务的配置创建容器,它以"db"这个名称加入网络myapp_default。
容器间可使用服务名称(web或db)作为hostname相互访问。例如,web这个服务可使用postgres://db:5432访问db容器。
当服务的配置发生更改时,可使用docker-compose up命令更新配置。
此时,Compose会删除就容器并创建新容器。新容器会以不同的IP地址加入网络,名称保持不变。任何指向旧容器的连接都会被关闭,容器会重新找到新容器并链接上去。
前文讲过,默认情况下,服务之间可使用服务名称相互访问。links允许定义一个别名从而使用该别名访问其他服务。
version: '3'
services:
web:
build: .
links:
- "db:database"
db:
image: postgres
这样Web服务就可使用db或database作为hostname访问db服务了。
一些场景下,默认的网络配置满足不了我们的需求,此时可使用networks命令自定义网络。networks命令允许创建更加复杂的网络拓扑并指定自定义网络驱动和选项。不仅如此,还可使用networks将服务连接到不是由Compose管理的、外部创建的网络。
如下,在其中定义了两个自定义网络。
version: '3'
services:
proxy:
build: ./proxy
networks:
- front
app:
build: ./app
netoworks:
- front
- back
db:
image: postgres
networks:
- back
networks:
front:
driver: custom-driver-1
back:
driver: custom-driver-2
driver_opts:
foo: "1"
bar: "2"
其中,proxy服务与db服务隔离,两者分别使用自己的网络,app服务可与两者通信。使用networks命令即可方便实现服务间的网络隔离与连接。
version: '3'
services:
web:
build: .
ports:
- "8000:8000"
db:
image: postgres
networks:
default:
driver: custom-driver-1
一些场景下,并不需要创建新的网络,只需加入已存在的网络,此时可使用external选项。
networks:
default:
external:
name: my-pre-existing-network
微服务项目名称 | 项目微服务中的角色 |
---|---|
microservice-discovery-eureka | 服务发现组件 |
microservice-provider-user | 服务提供者 |
microservice-consumer-movie-ribbon-hystrix | 服务消费者 |
1)使用Maven插件构建Docker镜像,在各个项目的pom.xml中添加以下内容
<plugin>
<groupId>com.spotifygroupId>
<artifactId>docker-maven-pluginartifactId>
<version>1.0.0version>
<executions>
<execution>
<id>build-imageid>
<phase>packagephase>
<goals>
<goal>buildgoal>
goals>
execution>
executions>
<configuration>
<imageName>example/${project.artifactId}:${project.version}imageName>
<forceTags>trueforceTags>
<dockerHost>http://192.168.2.120:2375dockerHost>
<baseImage>192.168.2.120:5000/javabaseImage>
<entryPoint>["java", "-jar","/${project.build.finalName}.jar"]entryPoint>
<resources>
<resource>
<targetPath>/targetPath>
<directory>${project.build.directory}directory>
<include>${project.build.finalName}.jarinclude>
resource>
resources>
configuration>
plugin>
2)前文中为各个项目配置的eureka.client.serviceUrl.defaultZone的值是http://localhost:8761/eureka/。由于Docker默认的网络模式是bridge,各个容器的IP都不相同,因此使用http://localhost:8761/eureka/满足不了需求。可为Eureka Server所在容器配置一个主机名,并让各个微服务使用主机名访问Eureka Server。
将所有微服务eureka.client.serviceUrl.defaultZone修改为
eureka:
client:
service-url:
defaultZone: http://discovery:8761/eureka/
3)在每个项目的根目录执行以下命令,构建Docker镜像
mvn clean package docker:build
4)编写docker-compose.yml
version: '3'
services:
microservice-discovery-eureka:
image: example/microservice-discovery-eureka:1.0-SNAPSHOT
ports:
- "8761:8761"
microservice-provider-user:
image: example/microservice-provider-user:1.0-SNAPSHOT
links:
- microservice-provider-user:discovery
microservice-comsumer-movie-ribbon-hystrix:
image: example/microservice-comsumer-movie-ribbon-hystrix:1.0-SNAPSHOT
links:
- microservice-comsumer-movie-ribbon-hystrix:discovery
测试
1)执行以下命令启动项目
docker-compose up
1)执行以下命令构建Docker镜像
mvn clean package docker:build
2)编写docker-compose.yml
version: '3'
services:
microservice-discovery-eureka-ha1:
hostname: peer1
image: example/microservice-discovery-eureka-ha:1.0-SNAPSHOT
links:
- microservice-discovery-eureka-ha2
ports:
- "8761:8761"
environment:
- spring.profiles.active=peer1
microservice-discovery-eureka-ha2:
hostname: peer2
image: example/microservice-discovery-eureka-ha:1.0-SNAPSHOT
links:
- microservice-discovery-eureka-ha1
ports:
- "8762:8762"
environment:
- spring.profiles.active=peer2
从异常可知,该写法存在循环依赖,也就是说,links无法实现双向连接。
version: '3'
services:
peer1:
image: example/microservice-discovery-eureka-ha:1.0-SNAPSHOT
ports:
- "8761:8761"
environment:
- spring.profiles.active=peer1
peer2:
image: example/microservice-discovery-eureka-ha:1.0-SNAPSHOT
hostname: peer2
ports:
- "8762:8762"
environment:
- spring.profiles.active=peer2
1)由于使用了microservice-discovery-eureka-ha,需要将所有微服务的eureka.client.serviceUrl.defaultZone属性修改为
eureka:
client:
service-url:
defaultZone: http://pee1:8761/eureka/,http://pee2:8762/eureka/
2)在每个项目的根目录,执行以下命令构建Docker镜像。
mvn clean package docker:build
3)编写docker-compose.yml
version: '2'
services:
peer1:
image: example/microservice-discovery-eureka-ha:1.0-SNAPSHOT
ports:
- "8761:8761"
environment:
- spring.profiles.active=peer1
peer2:
image: example/microservice-discovery-eureka-ha:1.0-SNAPSHOT
hostname: peer2
ports:
- "8762:8762"
environment:
- spring.profiles.active=peer2
microservice-provider-user:
image: example/microservice-provider-user:1.0-SNAPSHOT
microservice-comsumer-movie-ribbon-hystrix:
image: example/microservice-comsumer-movie-ribbon-hystrix:1.0-SNAPSHOT
测试
1)执行以下命令启动项目
docker-compose up
2)测试
3)执行以下命令,为各个微服务动态扩容。让除Eureka Server以外的所有服务启动3个示例
docker-compose scale microservice-provider-user=3 microservice-comsumer-movie-ribbon-hystrix=3