環境介紹
技術選型: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