利用docker、docker-compose部署Eureka集群的完全详细步骤
前言写这篇文章只是为了详细的记录下我的部署过程和要注意的地方。因为本人公司需要,此文章对于每个server、provider、consumer都采用了单独的项目来做的,没有作为父子项目的形式创建。其中server采用了docker-compse和Dockerfile方式来部署,provider和consumer暂且使用Dockerfile一、创建并发布Server还是采用快速创建选择s...
前言
写这篇文章只是为了详细的记录下我的部署过程和要注意的地方。
因为本人公司需要,此文章对于每个server、provider、consumer都采用了单独的项目来做的,没有作为父子项目的形式创建。其中server采用了docker-compse和Dockerfile方式来部署,provider和consumer暂且使用Dockerfile
一、创建并发布Server
还是采用快速创建
选择springboot方式。
组件选择springcloud discovery 中的 eureka server,如图:
完成后,
1、在application上加上注解 :@EnableEurekaServer
如果采用maven直接install的方式 安装到docker中,需要在pom中加入插件,但是本文采用半手动的方式
所以可以不需要。加入的插件如下:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>com.spotify</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>1.2.0</version>
<executions>
<!--设置在执行maven 的install时构建镜像-->
<execution>
<id>build-image</id>
<phase>install</phase>
<goals>
<goal>build</goal>
</goals>
</execution>
</executions>
<!--<configuration>-->
<!--<imageName>reg-service</imageName>-->
<!--<dockerDirectory>src/main/docker</dockerDirectory>-->
<!--<dockerHost>http://XXXXX</dockerHost>-->
<!--<resources>-->
<!--<resource>-->
<!--<targetPath>/</targetPath>-->
<!--<directory>${project.build.directory}</directory>-->
<!--<include>${project.build.finalName}.jar</include>-->
<!--</resource>-->
<!--</resources>-->
<!--</configuration>-->
</plugin>
</plugins>
</build>
其中docker-maven-plugin 就是上面提到的 插件。
2、编写application.yml
application.yml的有效位置,要么在classes目录的根目录下,或者 classes目录下的config目录下,要么在resources的根目录下,或者resources目录下的config目录下。
spring:
application:
name: eureka-server
---
spring:
profiles: eureka-server1
server:
port: 8001
eureka:
instance:
hostname: 172.30.100.193
prefer-ip-address: true
instance-id: 172.30.100.193:8001
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://172.30.100.193:8002/eureka/
---
spring:
profiles: eureka-server2
server:
port: 8002
eureka:
instance:
hostname: 172.30.100.193
prefer-ip-address: true
instance-id: 172.30.100.193:8002
client:
fetch-registry: true
register-with-eureka: true
service-url:
defaultZone: http://172.30.100.193:8001/eureka/
这里为了做高可用,做了集群。需要注意的是,两个server是作为两个docker container运行的,所以这里需要用ip来作为hostname,所以
eureka:
instance:
hostname: 172.30.100.193
prefer-ip-address: true
3、编写Dockerfile 和dockercompose.yml
在项目的 src/main 目录下创建docker目录,在docker目录下创建Dockerfile以及docker-compose.yml文件。
Dockerfile 如下:
# 基于哪个镜像
FROM java:8
# 将本地文件夹挂载到当前容器
VOLUME /tmp
# 拷贝文件到容器,handcuffs-reg-0.0.1-SNAPSHOT.jar这里是maven打包后的名字
ADD eurekaserver-0.0.1.jar app.jar
RUN bash -c 'touch /app.jar'
# 配置容器启动后执行的命令
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
没有任何特殊地方。
docker-compose.yml如下:
version: '2'
services:
eureka-server1:
image: eurekaserver
container_name: eureka-server1
hostname: eureka-server1
networks:
- eureka-net
ports:
- 8001:8001
environment:
- spring.profiles.active=eureka-server1
eureka-server2:
image: eurekaserver
container_name: eureka-server2
hostname: eureka-server2
networks:
- eureka-net
ports:
- 8002:8002
environment:
- spring.profiles.active=eureka-server2
networks:
eureka-net:
driver: bridge
这里是用来编排docker container 服务的
完成后,直接 在 idea中找到 maven package 就完成编译。
编译后,按照Dockerfile中定义的eurekaserver-0.0.1.jar 修改下生成的 jar的名字。
因为我用的是xshell,所以直接在 xshell 中登录 centos 环境后,使用 rz命令,将 jar包,Dockerfile以及 docker-compose.yml统统拷贝到centos环境中
4、部署到docker
完成后,直接运行
docker build -t eurekaserver . 生成 docker image。注意后面有个 .号
生成后,运行docker images查看
image生成后,运行 docker-compose up -d 来运行 docker-compse.yml生成container。
其中-d是 后台运行
完成后,运行docker ps 查看正在运行的docker container
结束后回到 windows环境,在浏览器中 访问:http://172.30.100.193:8001/ ,http://172.30.100.193:8002/ 可以看到 服务互相注册成功。
二、Eureka-provider 的创建和部署,
eureka-provider 顾名思义,服务提供者,那么一般都是 restapi,我们使用前面文章中创建的 springboot 集成mybatis 的那个项目
文章链接如下:
springboot集成mybatis-plus连接sqlserver
直接 修改下application.yml, pom.xml 添加Dockerfile 部署到docker中。步骤如下:
1、修改pom.xml
在pom中添加对于 springcloud、eureka-client的依赖。完整的 pom如下:
<?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>2.1.7.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.xyzh.mybatisPlus</groupId>
<artifactId>demo</artifactId>
<packaging>jar</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>sqljdbc4</artifactId>
<version>4.2</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.1.2</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.1.2</version>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>springloaded</artifactId>
<version>1.2.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<version>2.1.2.RELEASE</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
在application上面 添加注解:@EnableDiscoveryClient
2、修改application.yml
在原有的spring中添加配置 spring.application.name: microservice-provider
新加完整的 eureka的配置,完整如下:
mybatis-plus:
mapper-locations: classpath:/mapper/*.xml
global-config:
db-config:
id-type: auto
table-underline: true
logic-not-delete-value: 0
logic-delete-value: 1
spring:
datasource:
driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver
type: com.alibaba.druid.pool.DruidDataSource
url: jdbc:sqlserver://xxxx:1433;databaseName=xxxx
username: sa
password:xxxx
application:
name: microservice-provider
server:
port: 8101
eureka:
client:
service-url:
defaultZone: http://172.30.100.193:8001/eureka/,http://172.30.100.193:8002/eureka/
instance:
instance-id: microservice-provider8101
prefer-ip-address: true
info:
app.name: microservice-provider
company.name: www.xyzh.com
build.artifactId: ${project.artifactId}
build.version: ${project.version}
需要注意的是 这里一样要添加
instance:
instance-id: microservice-provider8101
prefer-ip-address: true
来保证可以以ip的形式 注册到eurekaserver上,如果步添加 prefer-ip-address : true,那么因为默认采用的是域名注册,所以后面 consumer 会找不到provider 报出 unknownhostexception的错误。
3、添加Dockerfile
同样在src/main下创建docker,在docker目录中新建文件Dockerfile
#基于哪个镜像
FROM java:8
# 将本地文件夹挂载到当前容器
VOLUME /tmp
# 拷贝文件到容器,demo-0.0.1.jar这里是maven打包后的名字
ADD demo-0.0.1.jar app.jar
# 配置容器启动后执行的命令
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
完成后,编译,打包项目,修改jar包名称等于 demo-0.0.1.jar
4、上传centos、部署docker
将 jar包 和 Dockerfile上传到centos中,
上传完成后,运行docker build -t eurekaprovider . 来创建docker image
创建完成后运行docker images查看如下图:
接着直接运行docker run来使用 image创建container
命令: docker run -d -p 8101:8101 --name eurekaprovider eurekaprovider
其中 -d是后台运行,
-p是端口映射 格式是 主机(宿主)端口:容器端口
–name 后面跟的是 container的名称,最后是image的名称
完成后运行docker ps来查看。
生成了docker container
再windows中访问 http://172.30.100.193:8001/,http://172.30.100.193:8002/
可以看到:
直接访问 provider的 路径也是可以访问的:
访问:http://172.30.100.193:8101/internal-meeting-user-info/userinfo/1
5、遵循上例继续创建 eureka-provid
因为是集群,所以这个服务可以使用多个docker一起来提供,供consumer 按照某个规则来选择调用。
所以我们还需要创建多个eureka-provider,当然可以通过 在application.yml中添加 profiles的形式来创建,然后再添加docker-compose.yml来编排服务,这个后面 再通过文章介绍吧,这里就直接复制 我们的demo工程,修改下application.yml来创建多个eureka-provider,修改的时候请注意,
需要修改的内容 是 server.port 、eureka.instance.instance-id 其他的都不改。尤其是 spring.application.name 这个是不变的.然后再遵循上面的步骤 创建 部署。在这里插入图片描述
三、Eureka-consumer的创建和部署
1、创建springboot的项目
可以看到,这里除了选择了 eureka-client-discovery 之外,还选择了 spring cloud routing 中的ribbon和 openFeign。其实这里就是通过 openFeign来访问 eureka-provider的。
2、编写 Feign。
再application类上添加注解:
@EnableDiscoveryClient,这里表示既是发现服务,也要注册到eurekaserver上。
@EnableFeignClients(“com.xyzh.eurekaconsumer.service”),这里表示启用Feign,其实Feign 就是一个AOP封装Ribbon。
在 项目中添加 service 接口 ConsumerService,完整代码如下:
package com.xyzh.eurekaconsumer.service;
import com.xyzh.eurekaconsumer.models.InternalMeetingUserInfo;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import java.util.List;
@FeignClient(name = "microservice-provider")
public interface ConsumerService {
@RequestMapping(value="/internal-meeting-user-info/userinfo/{userStatus}",method= RequestMethod.GET)
public List<InternalMeetingUserInfo> get(@PathVariable("userStatus") Integer userStatus);
}
这里需要注意的地方,就是FeignClient中用name 表示了 需要包装访问的 服务提供者,这里客户端可以通过默认规则来选择服务提供者访问
接下来在项目中添加控制器 contoller userInfoController
控制器就是通过刚才定义的 FeignClient 类 来访问 服务提供者了。完整代码如下:
import com.xyzh.eurekaconsumer.models.InternalMeetingUserInfo;
import com.xyzh.eurekaconsumer.service.ConsumerService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.List;
@Controller
public class userInfoController {
@Autowired
ConsumerService consumerService;
@RequestMapping(value = "/userinfo/{userStatus}",method = RequestMethod.GET )
@ResponseBody
public List<InternalMeetingUserInfo> get(@PathVariable(value = "userStatus") Integer userStatus){
try {
InternalMeetingUserInfo userinfo=new InternalMeetingUserInfo();
return consumerService.get(userStatus);
}
catch (Exception ex){
ex.printStackTrace();
throw ex;
}
}
}
需要注意的是,上面的 InternalMeetingUserInfo 是一个实体,所以需要实体 类是可序列化的,
需要实现 Serializable 接口,且有getter setter方法以及一个 无参的构造函数。否则会报错
实体类完整代码如下:
package com.xyzh.eurekaconsumer.models;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import java.io.Serializable;
import java.util.Date;
@Slf4j
@Getter
@Setter
@NoArgsConstructor
public class InternalMeetingUserInfo implements Serializable {
private static final long serialVersionUID = 1L;
private Integer id;
private Integer meetingId;
private Integer userId;
private String userName;
private String eName;
private Integer areaName;
private String telephone;
private String email;
private Integer service;
private String secretName;
private String secretEmail;
private String secretPhone;
private String weixinNo;
private String whatsApp;
private Integer tshirt;
private String language;
private String otherLanguage;
private Integer meal;
private String otherMeal;
private Integer allergy;
private String otherAllergy;
private String firstName;
private String lastName;
private String passPortNum;
private Integer gender;
private Date passportDate;
private Date passportBirthday;
private Integer invitation;
private Integer withFamily;
private String otherService;
private String enfirstName;
private String enLastName;
private String chineseName;
private String countryCode;
private String passPortIssuing;
private Integer internalStatus;
private Integer isDeleted;
private Date createDateTime;
private String createUser;
private Integer userStatus;
private Date lastUpdateTime;
}
另外,还有
本例中,因为涉及到时间转换,所以需要用到一个 时间转换类,在config目录下新增 时间转换类: DateFormatConfig
完整代码如下:
package com.xyzh.eurekaconsumer.config;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import org.springframework.boot.jackson.JsonComponent;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
@JsonComponent
public class DateFormatConfig {
private static SimpleDateFormat dateFormat=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
public static class DateJsonSerializer extends JsonSerializer<Date>{
@Override
public void serialize(Date date, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
jsonGenerator.writeString(dateFormat.format(date));
}
}
public static class DateJsonDeserializer extends JsonDeserializer<Date>{
@Override
public Date deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
try{
return dateFormat.parse(jsonParser.getText());
}catch (ParseException e){
throw new RuntimeException(e);
}
}
}
}
还有:使用 Feign 固然有默认的访问规则 和RestTemplate,但是我们也可以自定以替换如果自定义替换,定义一个配置对象即可
在config中创建 ConfigBean,如下:
package com.xyzh.eurekaconsumer.config;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RoundRobinRule;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class ConfigBean {
@Bean
@LoadBalanced
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
@Bean
public IRule myRule(){
return new RoundRobinRule();
}
}
其中定义了 loadbalance template 和 轮询访问规则
完整的项目结果如下:
3、编写 application.yml 和pom.xml
pom.xml就不用再改写了,按照生成来的就好,
applicaiton.yml如下
server:
port: 8201
spring:
application:
name: microservice-consumer
eureka:
instance:
instance-id: microserver-consumer8201
prefer-ip-address: true
client:
service-url:
defaultZone: http://172.30.100.193:8001/eureka/,http://172.30.100.193:8002/eureka/
依然注意 prefer-ip-address: true
4、创建Dockerfile
再src/main中创建Dockerfile,内容如下:
#基于哪个镜像
FROM java:8
# 将本地文件夹挂载到当前容器
VOLUME /tmp
# 拷贝文件到容器,eurekaconsumer-0.0.1.jar这里是maven打包后的名字
ADD eurekaconsumer-0.0.1.jar app.jar
# 配置容器启动后执行的命令
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
5、部署到docker
编译后 按照 eurekaconsumer-0.0.1.jar 修改生成的jar包名称,然后拷贝jar包 以及 Dockerfile 到 centos中,
然后 运行 docker build -t eurekaconsumer .来生成 镜像,生成后运行docker images来查看:
完成后,运行 docker run -d -p 8201:8201 --name eurekaconsumer eurekaconsumer 来创建container
然后运行 docker ps来查看运行的container:
这样就部署完成了。可以通过 http://172.30.100.193:8201/userinfo/1 来访问 consumer看看结果
这样,整个集群就已经部署完毕,
下一次通过 父子项目 docker-compose的方式来再写一篇。
更多推荐
所有评论(0)