前面的一篇文章,通过对每个项目建立单独的 Dockerfile,可以实现对单个项目生成 Docker 镜像,然后单独启动容器,可以实现简单连接,达到部署的目的。
但是微服务比较多的情况下,每次手动启动都比较麻烦;另外,还要考虑微服务的高可用(双节点或多节点)情况,通过上一篇文章(Docker 部署 SpringCloud 微服务的服务提供者和消费者(初级版))的方法解决起来有点麻烦。
针对上述情况,可采用 docker-compose 编排微服务。
说白了,就是通过 docker-compose 可以实现对多个微服务以及微服务高可用的编排,统一管理。
该篇文章涉及的项目及场景:
基于 Docker 实现 SpringCloud 微服务实例的容器化部署和运行,包含 5 个微服务实例。
一
服务注册与发现
microservice-simple-eureka-discovery
项目的整体完整架构:
1 新建项目 microservice-simple-eureka-discovery
详细的创建过程可参考上一篇文章,(Docker 部署 SpringCloud 微服务的服务提供者和消费者(初级版))这里只贴出重点的地方。
项目的元数据部分:
选择依赖:
这里仍然只添加了基本的依赖,再需要的后续手动添加,肯定要添加 eureka-server 的啦。
最后 Next 直至 Finish,完成创建。
2 写代码,并验证正确性
2.1 修改 pom.xml
为了保证版本前后一致,这里的 SpringBoot 版本也修改为:
<version>1.5.9.RELEASE</version>
SpringCloud 版本修改为:
<spring-cloud.version>Edgware.RELEASE</spring-cloud.version>
同时,在里面添加 eureka-server 的依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
完整的 pom.xml 文件:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.9.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>ouc.isclab</groupId>
<artifactId>microservice-simple-eureka-discovery</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>eureka-discovery</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Edgware.RELEASE</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2.2 修改启动类 EurekaDiscoveryApplication
在启动类上面添加注解: @EnableEurekaServer
启动类代码:
package ouc.isclab.microservice;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer
public class EurekaDiscoveryApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaDiscoveryApplication.class, args);
}
}
2.3 修改 application.properties
将 application.properties 重命名为 application.yml,添加以下内容:
spring:
application:
name: microservice-discovery-eureka # 微服务实例的名称
# 第一个 eureka 环境
---
spring:
profiles: peer1
server:
port: 8761 # 开放的端口
eureka:
instance:
hostname: peer1
prefer-ip-address: true
client:
service-url:
defaultZone: http://peer2:8762/eureka/ # 注册到另一个服务实例
register-with-eureka: true
fetch-registry: false
# 第二个 eureka 环境
---
spring:
profiles: peer2
eureka:
instance:
hostname: peer2
prefer-ip-address: true
client:
service-url:
defaultZone: http://peer1:8761/eureka/ # 注册到另一个服务实例
register-with-eureka: true
fetch-registry: false
server:
port: 8762 # 开放的端口
这里在单机环境下模仿多台机器环境,因此配置了 peer1、peer2, 此配置需要在自己的电脑中修改操作系统的配置文件。
Mac 和 Linux 电脑,路径在 /etc/hosts
通过 vim 编辑器直接添加即可,上图是我的添加完成的。
Windows系统的文件路径为 C:\Windows\System32\drivers\etc\hosts
第 5 行和第 20 行的 --- 表示一个单独的 eureka 环境配置,上面就是配置了两个 eureka 环境。
最上面不在任何一个 --- 里面的,表示多个 eureka 环境共用的环境配置。
spring:
profiles: peer1
profiles 的值为你在 hosts 中设置的其中一个。
server:
port: 8761 # 开放的端口
port 为该 spirng.profiles:XXX 主机下提供的端口
eureka:
instance:
hostname: peer1
prefer-ip-address: true
client:
service-url:
defaultZone: http://peer2:8762/eureka/ # 注册到另一个服务实例
register-with-eureka: true
fetch-registry: false
hostname: 表示该主机的地址
prefer-ip-address: 表示微服务通过地址可达
defaultZone:表示注册的目标地址,peer1 和 peer2 之间互相注册
register-with-eureka:是否允许向 eureka server 注册信息
fetch-registry: 是否允许客户端向 eureka 注册表获取信息
测试了几次,这种配置能成功,先这么用着吧。
2.4 通过终端启动
项目打一个 jar 包,在终端命令行,输入命令:
java -jar xxx.jar --spring.profiles.active=peer1
启动报错不用慌,就像这种错误,
因为它和 peer2 相互注册,此时peer2 还没启动。只需另起一个终端,将 peer2 也启动一下:
java -jar xxx.jar --spring.profiles.active=peer2
此时,两个终端都可以正常启动,终端提示有一个 replicate = true,基本没啥毛病。
通过浏览器,输入 localhost:8761 或者 localhost:8762
有红线标注的说明服务注册发现组件没问题。可以准备打包。
停掉服务,开始打包。
3 生成镜像,准备启动
在 src/main/ 路径下新建 docker 文件夹,并新建 Dockerfile 文件、docker-compose.yml 文件。
需要你的docker 已拉取 java:8 镜像,如果还没有,打开终端执行:
docker pull java:8
3.1 项目打 jar 包
在项目根目录下执行 mvn clean package,或者在 IDEA 中,依次点击MACEN-Lifecycle-package ,在 target 目录下得到 xxx.jar。
3.2 使用 Dockerfile 制作 Docker镜像
注意这里的 jar 包位置。将 target 目录下生成的 jar 包拷贝在src/main/docker 目录下。在 Dockerfile 中写入以下内容:
# 基于哪个镜像
FROM java:8
# 将本地文件夹挂载到当前容器
VOLUME /tmp
# 拷贝文件到容器
ADD microservice-simple-eureka-discovery-0.0.1-SNAPSHOT.jar /app.jar
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
在终端 cd 到src/main/docker 目录,执行命令:
docker build -t isclab/eureka-discovery:0.0.1 .
再通过 docker images 可以发现,镜像已经存在。
现在可以去书写 docker-compose.yml。
3.3 使用 docker-compose.yml 编排微服务,启动
首先要在本地安装 docker-compose,根据官方来就行。Mac 安装了 docker 后自带了 docker-compose,我就可以直接使用。
可以通过查看版本看本地是否安装了:1.25.5 是 compose 的版本
在 docker-compose.yml 里面写入:
version: '3'
services:
peer1:
hostname: peer1
image: isclab/eureka-discovery:0.0.1
ports:
- 8761:8761
environment:
- spring.profiles.active=peer1
peer2:
hostname: peer2
image: isclab/eureka-discovery:0.0.1
ports:
- 8762:8762
environment:
- spring.profiles.active=peer2
version:是根据 docker 版本而写的,规定compose file 的格式。
下图是一个对应关系,去官网链接可以根据自己的 docker 版本,查看自己的用哪一个。
官网:https://docs.docker.com/compose/compose-file/
我的是19.03.8,因此使用 3 是完全可以的
services:服务。这个地方的名字其实可以随便命名,当这两者相互注册的,如果随便起一个名字,会造成死循环注册。报错:
ERROR:Circular dependency between 名字1 and 名字2
在这里就用 peer1、peer2 方案来解决。
hostname: 主机地址
iamge:连接的对应的镜像名字,必须和你生成的镜像一模一样,版本号也一定要加上(默认latest,因为之前我们加了0.0.1,没有latest)
ports: 就是暴漏端口映射。保持一致,不易混淆。
environment:必须加,就是我们通过命令行启动的命令。
做完上面的工作,就可以在终端命令行 cd 到src/main/docker 目录下,执行:
docker-compose up -d
-d:仍然表示后台执行
此时,通过 docker ps,可看到:
因为我们并没有给容器起名字,所以,默认了 docker_xxx_x 的名字。
此时,去浏览器,输入 localhost:8761 或者 8762 也都是可以访问成功的。
二
服务提供者
microservice-simple-provider-user
项目完整结构:
1 新建项目 microservice-simple-provider-user
填写项目元数据:
选择依赖:
先选择这么多,后面手动补。
2 写代码,并验证正确性
同样注意版本问题。
2.1 修改 pom.xml
为了保证版本前后一致,这里的 SpringBoot 版本也修改为:
<version>1.5.9.RELEASE</version>
SpringCloud 版本修改为:
<spring-cloud.version>Edgware.RELEASE</spring-cloud.version>
同时,在里面添加 eureka-client 的依赖:
<!-- Eureka -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
完整的 pom.xml 文件内容:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.9.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>ouc.isclab</groupId>
<artifactId>microservice-simple-provider-user</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>provider-user</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Edgware.RELEASE</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter</artifactId>
</dependency>
<!-- Eureka -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2.2 新增 controller、entity、repository 包
在包下面新建对应的类,entity/User 类:
package ouc.isclab.microservice.entity;
import javax.persistence.*;
import java.math.BigDecimal;
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column
private String username;
@Column
private String name;
@Column
private Integer age;
@Column
private BigDecimal balance;
public User(){}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public BigDecimal getBalance() {
return balance;
}
public void setBalance(BigDecimal balance) {
this.balance = balance;
}
}
repository/UserRepository 类:
package ouc.isclab.microservice.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import ouc.isclab.microservice.entity.User;
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
}
controller/UserController 类:
package ouc.isclab.microservice.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import ouc.isclab.microservice.entity.User;
import ouc.isclab.microservice.repository.UserRepository;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@RestController
public class UserController {
@Autowired
public UserRepository userRepository;
// 地址栏直接接参数
@GetMapping("/user/{id}")
public User findUserById(@PathVariable Long id){ return userRepository.findOne(id); }
}
2.3 启动类 ProviderUserApplication
无需修改
2.4 修改 application.properties
重命名为 application.yml,内容如下:
spring:
jpa:
generate-ddl: false
show-sql: true
hibernate:
ddl-auto: none
datasource: # 指定数据源
platform: h2 # 指定数据源类型
schema: classpath:schema.sql # 指定h2数据库的建表脚本
data: classpath:data.sql # 指定h2数据库的数据脚本
application:
name: microservice-simple-provier-user
logging: # 配置日志级别,让hibernate打印出执行的SQL
level:
root: INFO
org.hibernate: INFO
org.hibernate.type.descriptor.sql.BasicBinder: TRACE
org.hibernate.type.descriptor.sql.BasicExtractor: TRACE
## INFO
info:
app:
name: @project.artifactId@
decoding: @project.build.sourceEncoding@
java:
source: @java.version@
target: @java.version@
# eureka
eureka:
client:
service-url:
defaultZone: http://peer1:8761/eureka/,http://peer2:8761/eureka/
instance:
prefer-ip-address: true
management:
security:
enabled: false
---
spring:
profiles: peer1
server:
port: 8000
---
spring:
profiles: peer2
server:
port: 8001
defaultZone: 表示服务注册发现组件地址,也就是前面写的项目
management:SpringBoot 1.5.X 以上默认开通了安全认证,如果不关闭会要求权限,在此把它关闭
---:表示单独配置一个实例
此配置文件中,表示 peer1 的 8000 端口;peer2 的 8001 端口。
借此实现服务提供者的高可用。
2.5 新增 sql 文件
因为使用的 H2 Database,很方便测试用。此处与MySQL等略微不同。
在 resources 下面添加 data.sql 和 schema.sql。
data.sql:
insert into user (id, username, name, age, balance) values (1, 'account1', '张三', 20, 100.00);
insert into user (id, username, name, age, balance) values (2, 'account2', '李四', 28, 180.00);
insert into user (id, username, name, age, balance) values (3, 'account3', '王五', 32, 280.00);
insert into user (id, username, name, age, balance) values (4, 'account3', '赵六', 33, 300.00);
schema.sql:
drop table user if exists;
create table user (id bigint generated by default as identity, username varchar(40), name varchar(20), age int(3), balance decimal(10,2), primary key (id));
到此项目写完,因为它需要注册到服务提供与发现端,在这里不再单独测试。
3 生成镜像,准备测试启动
3.1 项目打 jar 包
在 target 目录下找到项目的 jar 包。
3.2 使用 Dockerfile 制作 Docker镜像
在项目的根目录下新建 Dockerfile 文件,内容:
FROM java:8
VOLUME /tmp
ADD target/microservice-simple-provider-user-0.0.1-SNAPSHOT.jar /app.jar
EXPOSE 8000
ENTRYPOINT ["java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "/app.jar"]
执行命令构建镜像:(不要忘记最后的 . )
docker build -t isclab/microservice-simple-provider-user:0.0.1 .
可看到已经成功制作了镜像,通过 docker run 可以启动试一下。
此时通过 --link 去链接服务注册发现组件容器,发现并不成功。
docker run -d -p 8000:8000 --name provider --link docker_peer1_1:peer1 --link docker_peer2_1:peer2 isclab/microservice-simple-provider-user:0.0.1
提示错误信息:
docker: Error response from daemon: Cannot link to /docker_peer1_1, as it does not belong to the default network.
因为不在同一网络,那这时就可以设想通过 docker-compose 来解决。
3.3 使用 docker-compose.yml 编排微服务,启动
此时,已经涉及两个项目(服务注册与发现、服务提供者),因此,我在其他文件夹新建一个 docker-compose 文件夹,在该文件夹下新建 docker-compse.yml,这是一个综合管理的 yml 文件,来管理这两个项目。
docker-compose.yml 的内容为:
version: '3'
services:
peer1:
hostname: peer1
image: isclab/eureka-discovery:0.0.1
container_name: docker_peer1_1
ports:
- 8761:8761
environment:
- spring.profiles.active=peer1
peer2:
hostname: peer2
image: isclab/eureka-discovery:0.0.1
container_name: docker_peer2_1
ports:
- 8762:8762
environment:
- spring.profiles.active=peer2
provider-1:
hostname: peer1
image: isclab/microservice-simple-provider-user:0.0.1
container_name: provider-1
ports:
- 8000:8000
environment:
- server.port=8000
provider-2:
hostname: peer2
image: isclab/microservice-simple-provider-user:0.0.1
container_name: provider-2
ports:
- 8001:8001
environment:
- server.port=8001
provider-1、provider-2: 服务提供者1、服务提供者2(高可用)
environment: 命令行启动时的格式
image:镜像名字
此时,可以先去停掉、删除之前启动的服务注册与发现的容器和镜像。
然后在该 docker-compose.yml 的根目录下执行:
docker-compose up -d
此时,会出现Creating .... done 。
通过 docker ps 可看到 4 个容器均已启动,通过浏览器访问 localhost:8761,
这儿仅显示了 8001 ,没有 8000。但是 8000 和 8001 端口都可以访问到。回看 Docker 容器,8000/tcp,8001 都对应了 8001,我猜测和这儿有关系。没有去特意解决该问题。
访问 localhost:8000/user/1 或者 localhost:8001/user/2 都可以访问到数据。
到此,服务注册与发现、服务提供者两个项目均部署完成,接下来就是服务消费者。现在累了吧,累了就歇歇,再干!
三
服务消费者
microservice-simple-consumer-shopping
整体项目结构:
1 新建项目 microservice-simple-consumer-shopping
设置项目元数据:
选择项目依赖:
点击Next,直至 Finish 完成。
2 写代码
2.1 修改 pom.xml
为了保证版本前后一致,这里的 SpringBoot 版本也修改为:
<version>1.5.9.RELEASE</version>
SpringCloud 版本修改为:
<spring-cloud.version>Edgware.RELEASE</spring-cloud.version>
同时,在里面添加 eureka-client 的依赖:
<!-- Eureka -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
完整的 pom.xml 内容:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.9.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>ouc.isclab</groupId>
<artifactId>microservice-simple-consumer-shopping</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>consumer-shopping</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Edgware.RELEASE</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter</artifactId>
</dependency>
<!-- Eureka -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2.2 新增 controller 和entity
entity/User 类:
package ouc.isclab.microservice.entity;
import java.math.BigDecimal;
public class User {
private Long id;
private String username;
private String name;
private Integer age;
private BigDecimal balance;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public BigDecimal getBalance() {
return balance;
}
public void setBalance(BigDecimal balance) {
this.balance = balance;
}
}
controller/ShoppingController 类:
package ouc.isclab.microservice.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import ouc.isclab.microservice.entity.User;
@RestController
public class ShoppingController {
@Autowired
private RestTemplate restTemplate;
@GetMapping("/user/{id}")
public User findById(@PathVariable Long id){
return this.restTemplate.getForObject("http://microservice-simple-provier-user/user/"+id, User.class);
}
}
注意:就是这儿的地址,指向的是服务提供者,写服务提供者的服务名字即可。
该名字是在每个项目的 application.yml 里面 spring.application.name 指定的。
2.3 修改启动类 EurekaDiscoveryApplication
因为 controller 里面使用了 restTemplate,需要在这里添加,并加上注解 @Bean。
另外为了负载均衡,需要在这里加 @LoadBalanced 注解。
(因为加入了 eureka-client 依赖,里面包含负载均衡的依赖,不需要单独再添加依赖)
最后,由于服务提供者做了高可用,因此服务消费者必须要通过负载均衡访问,否则,在通过消费者访问时,会报 unknowhostnameException 异常。
完整的启动类内容:
package ouc.isclab.microservice;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
public class ConsumerShoppingApplication {
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(ConsumerShoppingApplication.class, args);
}
}
2.4 修改 application.properties
重命名为 application.yml,内容为:
server:
port: 8010
spring:
application:
name: microservice-consumer-shopping
# eureka
eureka:
client:
service-url:
defaultZone: http://peer1:8761/eureka/,http://peer2:8761/eureka/
instance:
prefer-ip-address: true
management:
security:
enabled: false
提供 8010 端口
名字为 microservice-consumer-shopping
注册进服务发现端 peer1/8761、peer2/8762
3 生成镜像,准备启动
3.1 项目打 jar 包
在命令行 cd 到项目根目录,执行mvn clean package,或在 IDEA 里面 通过 MAVEN-Lifecycle-package,在 target 目录下得到 jar 包。
3.2 使用 Dockerfile 制作 Docker镜像
在项目根目录新建 Dockerfile 文件:
FROM java:8
VOLUME /tmp
ADD target/microservice-simple-consumer-shopping-0.0.1-SNAPSHOT.jar /app.jar
EXPOSE 8010
ENTRYPOINT ["java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "/app.jar"]
并执行命令:
docker build -t isclab/microservice-simple-consumer-shopping:0.0.1 .
得到镜像,通过 docker ps 可以查看
此时三个镜像全都存在,没有问题。通过 docker-compose 进行启动。
3.3 使用 docker-compose.yml 编排微服务,启动
仍然是找到上次写的综合管理服务注册发现、服务提供的 docker-compose 文件,在里面加入服务消费者的启动信息。
version: '3'
services:
peer1:
hostname: peer1
image: isclab/eureka-discovery:0.0.1
container_name: docker_peer1_1
ports:
- 8761:8761
environment:
- spring.profiles.active=peer1
peer2:
hostname: peer2
image: isclab/eureka-discovery:0.0.1
container_name: docker_peer2_1
ports:
- 8762:8762
environment:
- spring.profiles.active=peer2
provider-1:
hostname: peer1
image: isclab/microservice-simple-provider-user:0.0.1
container_name: provider-1
ports:
- 8000:8000
environment:
- server.port=8000
provider-2:
hostname: peer2
image: isclab/microservice-simple-provider-user:0.0.1
container_name: provider-2
ports:
- 8001:8001
environment:
- server.port=8001
consumer:
image: isclab/microservice-simple-consumer-shopping:0.0.1
ports:
- 8010:8010
尾部的 consumer 则表示服务消费者, iamge 对应刚刚制作的镜像,暴漏端口 8010。
现在该文件就变成了一个综合管理服务的 docker-compose 配置文件。
此时在命令行 cd 到 这个综合管理服务的 docker-compose 文件夹,执行
docker-compose up -d
此时,可以看到前四个容器都是 up-to-date,因为之前已经启动了。
消费者容器显示 done,通过 docker images 可以看到容器已全部启动。
访问 localhost:8761 或 8762,
通过消费者查询信息,localhost:8010/user/1 , user/2 可查询到信息
至此,服务注册发现、服务提供者、服务消费者均通过 Docker 部署完成。完事,拜拜!
其实不难,关键在于弄清楚对应关系,记下来。
项目源码:
服务注册与发现eureka:
https://gitee.com/JeffBro/microservice-simple-eureka-discovery
服务提供者provider-user:
https://gitee.com/JeffBro/microservice-simple-provider-user
服务消费者:
https://gitee.com/JeffBro/microservice-simple-consumer-shopping
错误与技巧
Service 'consumer has a link to service 'xx:xx' which is undefined
这是测试中的一个例子,我的前后名字当时没写错。(别杠我
)
感谢阅读,感谢陪伴,这篇文章快写吐了.....