十一、Docker搭建部署SpringCloud微服务项目Demo
环境介绍
技术选型:SpringCloud
&SpringCloud Alibaba
&Docker
微服务模块划分:
- 员工模块:ems-employees
- 部门模块:ems-departments
- 网关模块:ems-gateway
- 公共模块:ems-commons
其他环境:
Mysql8.0+、nacos1.3+、JDK1.8
前置准备知识:
SpringCloud
、SpringCloud alibaba
、Docker
、Docker-Compose
、Dockerfile
数据库结构:
一个部门表和一个员工表,员工表里面有个部门ID和部门表主键相关联
数据库sql脚本
use ems
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for department
-- ----------------------------
DROP TABLE IF EXISTS `department`;
CREATE TABLE `department` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(80) DEFAULT NULL COMMENT '部门名称',
`created_at` datetime DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------
-- Table structure for employee
-- ----------------------------
DROP TABLE IF EXISTS `employee`;
CREATE TABLE `employee` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(40) DEFAULT NULL,
`birthday` datetime DEFAULT NULL COMMENT '生日',
`salary` double(10,2) DEFAULT NULL COMMENT '工资',
`department_id` int(11) DEFAULT NULL COMMENT '部门信息',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
SET FOREIGN_KEY_CHECKS = 1;
部署流程
- 先在服务器安装Docker,然后在Docker中安装mysql、nacos镜像,并启动容器
- 在员工、部门等微服务模块中指定nacos注册中心地址,使服务注册进去
- 把springcloud微服务模块打包成jar包上传至服务器,然后通过Dockerfile构建成镜像
- 最后通过docker-compose构建编排项目,将这些微服务镜像打包成一整个项目并启动
环境搭建
1.Centos7.X安装Docker
网上操作教程很多,略
2.Docker安装mysql、nacos镜像
2.1 安装mysql
1、没有指定版本一般安装的都是最新的8.0+
docker pull mysql
2、docker启动mysql,简单演示就没有创建数据卷了
docker run --name=mysql01 -it -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 -d mysql
3、启动成功
4、进入mysql容器
docker exec -it mysql01 /bin/bash
5、登陆mysql
mysql -u root -p
6、授权所有用户可以登录
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%'WITH GRANT OPTION;
7、刷新权限
FLUSH PRIVILEGES;
8、使用客户端连接
2.2 安装nacos
docker pull nacos/nacos-server:1.3.0
1、运行nacos
docker run --name nacos-quick -e MODE=standalone -p 8848:8848 -d nacos/nacos-server:1.3.0
2、查看nacos运行日志
docker logs -f b1aacab47d2a
表示启动成功
3、访问成功
默认用户名登录密码都是nacos
3.搭建SpringCloud微服务模块
3.1 搭建父工程模块
父工程的必须遵循以下两点要求:
1.父工程的 packaging 标签的文本内容必须设置为 pom,如果不指定会默认打包成jar包
2.删除src目录
搭建父工程的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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.ylc</groupId>
<artifactId>springcloud-dockerDemo</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<mysql.version>8.0.23</mysql.version>
<spring.cloud.version>Hoxton.SR1</spring.cloud.version>
<spring.cloud.alibaba.version>2.2.0.RELEASE</spring.cloud.alibaba.version>
</properties>
<dependencyManagement>
<dependencies>
<!--spring cloud Hoxton.SR1-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring.cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--spring cloud alibaba 2.1.0.RELEASE-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring.cloud.alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
3.2 搭建员工子模块
点击下一步最后完成
删除一些没用的文件HELP.md、MVNW等等,修改子项目的 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>
<!--父工程 gropuId-->
<groupId>com.ylc</groupId>
<!--父工程 artifactId-->
<artifactId>springcloud-dockerDemo</artifactId>
<!--父工程 版本-->
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>ems-employess</artifactId>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!--web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--nacos-service-discovery-client-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--druid mysql mybatis-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.6</version>
</dependency>
<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.23</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.0</version>
</dependency>
<!--远程调用openfegin-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.10.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.3.4.RELEASE</version>
<configuration>
<fork>true</fork>
<addResources>true</addResources>
</configuration>
</plugin>
</plugins>
</build>
</project>
在父工程 pom.xml 中 添加子模块标识
开启服务注册中心nacos,并开启远程调用
@EnableFeignClients
@EnableDiscoveryClient
@SpringBootApplication
public class EmsEmploysApplication {
public static void main(String[] args) {
SpringApplication.run(EmsEmploysApplication.class, args);
}
}
然后在配置文件application.properties
配置nacos的参数、以及数据源配置
server.port=8085
spring.application.name=DEPARTMENTS
spring.cloud.nacos.server-addr=xxx:8848
# datasource
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://xxxx:3306/ems?useSSL=false&characterEncoding=UTF-8
spring.datasource.username=root
spring.datasource.password=123456
# mybatis
mybatis.type-aliases-package=com.ylc.entity
mybatis.mapper-locations=classpath:com/ylc/mapper/*.xml
# log
logging.level.com.ylc=debug
在bootstrap.properties
中配置nacos
spring.cloud.nacos.config.server-addr=121.43.33.150:8848
spring.cloud.nacos.discovery.server-addr=121.43.33.150:8848
在idea中远程连接mysql
然后利用idea中安装的插件Easycode,根据表去生成service、controller、dao、mapper相关代码
点击这个
module代表生成的模块
package:包名
path:生成的路径
最后生成成功
其中有分页部分爆红的方法,删掉就行了,只简单演示
然后记得添加相关注解@Mapper、@Service、@Repository等等
访问成功
3.3 搭建部门子模块
按照上一个模块流程搭建,pom文件也是相同的,端口改为8086
访问成功
3.4 抽取公共模块
上面两个微服务会有重复代码,抽取公共部分包含项目一些公共的类以及jar包
Department
package com.ylc;
import java.io.Serializable;
import java.util.Date;
/**
* @author yanglingcong
* 部门类
*/
public class Department implements Serializable {
private static final long serialVersionUID = 279210942586979318L;
private Integer id;
/**
* 部门名称
*/
private String name;
/**
* 创建时间
*/
private Date createdAt;
private Employee employee;
public Employee getEmployee() {
return employee;
}
public void setEmployee(Employee employee) {
this.employee = employee;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getCreatedAt() {
return createdAt;
}
public void setCreatedAt(Date createdAt) {
this.createdAt = createdAt;
}
}
Employee
package com.ylc;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serializable;
import java.util.Date;
/**
* (Employee)实体类
* @author yanglingcong
*/
public class Employee implements Serializable {
private static final long serialVersionUID = -87055454147065054L;
private String id;
private String name;
/**
* 生日
*/
private Date birthday;
/**
* 工资
*/
private String salary;
/**
* 部门信息
*/
@JsonProperty("department_id")
private Integer departmentId;
private Department department;
public Department getDepartment() {
return department;
}
public void setDepartment(Department department) {
this.department = department;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String getSalary() {
return salary;
}
public void setSalary(String salary) {
this.salary = salary;
}
public Integer getDepartmentId() {
return departmentId;
}
public void setDepartmentId(Integer departmentId) {
this.departmentId = departmentId;
}
}
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>
<!--父工程 gropuId-->
<groupId>com.ylc</groupId>
<!--父工程 artifactId-->
<artifactId>springcloud-dockerDemo</artifactId>
<!--父工程 版本-->
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>ems-employess</artifactId>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!--web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--nacos-service-discovery-client-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--druid mysql mybatis-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.6</version>
</dependency>
<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.23</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.0</version>
</dependency>
<!--远程调用openfegin-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.10.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.3.4.RELEASE</version>
<configuration>
<fork>true</fork>
<addResources>true</addResources>
</configuration>
</plugin>
</plugins>
</build>
</project>
公共模块搭建很简单就两个类,然后在其他模块引用公共模块
<dependencies>
<!--公共模块-->
<dependency>
<groupId>com.ylc</groupId>
<artifactId>ems-commons</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
到此就完成了
3.5.测试
通过查询员工信息,然后远程调用部门信息
远程接口
@FeignClient("DEPARTMENTS")
public interface DepartmentClient {
//部门详细
@GetMapping("/department/{id}")
Department detail(@PathVariable("id") Integer id);
}
1、接口定义
/**
* 查询员工以及部门的详细信息
* @return List<Employee>
*/
List<Employee> queryAll();
2、实现类
@Override
public List<Employee> queryAll() {
List<Employee> employees=employeeDao.queryAll();
employees.forEach(emp->{
Integer departmentid=emp.getDepartmentId();
Department detail = departmentClient.detail(departmentid);
emp.setDepartment(detail);
});
return employees;
}
3、调用方法
//员工列表
@GetMapping
public List<Employee> employees() {
return employeeService.queryAll();
}
3.6 搭建网关子模块
1、开启服务注册发现
@SpringBootApplication
@EnableDiscoveryClient
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}
2、网关配置
spring:
cloud:
gateway:
routes: # 用来配置网关路由规则
- id: employee_route
uri: lb://EMPLOYESS
predicates:
- Path=/ems/employee
filters:
- StripPrefix=1
- id: department_route
uri: lb://DEPARTMENTS
predicates:
- Path=/ems/department
filters:
- StripPrefix=1
3、bootstrap.yml
server.port=8888
spring.application.name=GATEWAY
spring.cloud.nacos.server-addr=121.43.33.150:8848
spring.cloud.nacos.config.server-addr=121.43.33.150:8848
spring.cloud.nacos.discovery.server-addr=121.43.33.150:8848
spring.cloud.nacos.config.enabled=false
4、通过网关访问成功
至此整个项目流程就打通了
部署
1.本地测试
1、打包之前每个项目都需要有springboot的打包插件,没有的话要在项目中引入
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
安装之后出现这个就可以了
2、先对父项目进行清理(clean)再打包(Package),common公共模块是没主启动类的,这时候把父项目的pom文件的该插件注释调就行了。
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
全部打包完成
3、先在本地测试jar是否成功
运行员工模块
运行部门模块
运行网关模块
都成功之后本地访问http://localhost:8888/ems/employee
到这里都没有问题说明本地测试通过了
2.编写Dockerfile
docker中需要有JDK1.8的镜像,安装JDK
docker pull openjdk:8
在idea中编写员工模块Dockerfile
FROM openjdk:8
ENV APP_HOME=/apps
WORKDIR $APP_HOME
COPY ./ems-employess-1.0-SNAPSHOT.jar ./employess.jar
EXPOSE 8086
ENTRYPOINT ["java","-jar"]
CMD ["employess.jar"]
部门模块Dockerfile
FROM openjdk:8
ENV APP_HOME=/apps
WORKDIR $APP_HOME
COPY ./ems-departments-0.0.1-SNAPSHOT.jar ./departments.jar
EXPOSE 8085
ENTRYPOINT ["java","-jar"]
CMD ["departments.jar"]
网关模块Dockerfile
FROM openjdk:8
ENV APP_HOME=/apps
WORKDIR $APP_HOME
COPY ./ems-gateway-1.0-SNAPSHOT.jar ./gateway.jar
EXPOSE 8888
ENTRYPOINT ["java","-jar"]
CMD ["gateway.jar"]
然后在idea 中登录docker所在服务器
3.Dockerfile文件上传
然后把项目的文件上传到服务自己建的ems文件夹中
4.编写docker-compose.yml
直接利用dockerfile文件的路径打包成镜像,最后编排运行
version: "3.8"
networks:
ems:
volumes:
data:
services:
employee:
build:
context: ./employee
dockerfile: Dockerfile
ports:
- "8085:8085"
networks:
- ems
department:
build:
context: ./department
dockerfile: Dockerfile
ports:
- "8086:8086"
networks:
- ems
gateway:
build:
context: ./gateway
dockerfile: Dockerfile
ports:
- "8888:8888"
networks:
- ems
nacos:
image: nacos/nacos-server:1.3.1
ports:
- "8848:8848"
environment:
- "MODE=standalone"
networks:
- ems
mysql:
image: mysql
ports:
- "3306:3306" #只写一个端口随机使用宿主机一个端口进行容器端口映射
environment:
- "MYSQL_ROOT_PASSWORD=root"
- "MYSQL_DATABASE=ems"
volumes:
- data:/var/lib/mysql
#- ./ems.sql:/docker-entrypoint-initdb.d/ems.sql
networks:
- ems
5.项目启动
在服务器ems文件夹中输入
docker-compose up -d department
docker-compose up -d employee
docker-compose up -d gateway
报错
有个服务报错:Error: Invalid or corrupt jarfile employess.jar
检查了好几遍,重新打包上传还是这样,最后进目录查看发现jar包每次都没有上传完整
文件大小明显不对,因为打包错了里面没有主启动类,我在打包之前就删除这些,添加进来然后重新运行 mvn install即可
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
这下正常了
再次运行因为之前构建的镜像还在,即便重新上传还是运行的之前构建的,没有效果,所以的删除之前构建过的错误镜像,三个都运行成功
部署成功!
总结
还有很多可以优化的地方,因为本节是着重演示部署流程,细节方面就没有优化了
这就是一整个部署的大概流程,但每次项目代码如果有更改,又需要手动重新生成镜像然后在服务器重新运行,还是不太方便,后续会出Jenkins+Docker自动化部署SpringCloud,实现代码提交自动进行编译打包上传并部署,简化在部署方面的操作。
项目细节难免有纰漏之处,附项目地址:https://gitee.com/yanglingcong/spring-cloud-docker