十一、Docker搭建部署SpringCloud微服務專案Demo

炒燜煎糖板栗發表於2022-01-04

環境介紹

技術選型SpringCloud&SpringCloud Alibaba&Docker

微服務模組劃分

  1. 員工模組:ems-employees
  2. 部門模組:ems-departments
  3. 閘道器模組:ems-gateway
  4. 公共模組:ems-commons

其他環境

Mysql8.0+、nacos1.3+、JDK1.8

前置準備知識

SpringCloudSpringCloud alibabaDockerDocker-ComposeDockerfile

資料庫結構:

一個部門表和一個員工表,員工表裡面有個部門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;

部署流程

  1. 先在伺服器安裝Docker,然後在Docker中安裝mysql、nacos映象,並啟動容器
  2. 在員工、部門等微服務模組中指定nacos註冊中心地址,使服務註冊進去
  3. 把springcloud微服務模組打包成jar包上傳至伺服器,然後通過Dockerfile構建成映象
  4. 最後通過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、啟動成功

image-20220102180005212

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、使用客戶端連線

image-20220102183304777

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

image-20220102184603996

表示啟動成功

3、訪問成功

image-20220102184738169

預設使用者名稱登入密碼都是nacos

3.搭建SpringCloud微服務模組

3.1 搭建父工程模組

image-20220103104841235

image-20220103104929409

image-20220103105150507

父工程的必須遵循以下兩點要求:

1.父工程的 packaging 標籤的文字內容必須設定為 pom,如果不指定會預設打包成jar包

2.刪除src目錄

image-20220103105323383

搭建父工程的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 搭建員工子模組

image-20220103105744331

image-20220103105854905

點選下一步最後完成

image-20220103110016595

刪除一些沒用的檔案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 中 新增子模組標識

image-20220103110152948

開啟服務註冊中心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

image-20220103160733218

然後利用idea中安裝的外掛Easycode,根據表去生成service、controller、dao、mapper相關程式碼

點選這個

image-20220103162655774

module代表生成的模組

package:包名

path:生成的路徑

image-20220103163437305

最後生成成功

image-20220103163630949

其中有分頁部分爆紅的方法,刪掉就行了,只簡單演示

然後記得新增相關注解@Mapper、@Service、@Repository等等

訪問成功

image-20220103181039770

3.3 搭建部門子模組

按照上一個模組流程搭建,pom檔案也是相同的,埠改為8086

訪問成功

image-20220103183405568

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();
    }

4、測試localhost:8085/employee

image-20220103195635159

3.6 搭建閘道器子模組

image-20220103201046959

1、開啟服務註冊發現

@SpringBootApplication
@EnableDiscoveryClient
public class GatewayApplication {
    public static void main(String[] args) {
        SpringApplication.run(GatewayApplication.class, args);
    }
}

2、閘道器配置

image-20220103220634321

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、通過閘道器訪問成功

image-20220103220426218

至此整個專案流程就打通了

部署

1.本地測試

1、打包之前每個專案都需要有springboot的打包外掛,沒有的話要在專案中引入

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

安裝之後出現這個就可以了

image-20220103221640922

2、先對父專案進行清理(clean)再打包(Package),common公共模組是沒主啟動類的,這時候把父專案的pom檔案的該外掛註釋調就行了。

   <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

全部打包完成

image-20220103221818398

3、先在本地測試jar是否成功

執行員工模組

image-20220103222146017

執行部門模組

image-20220103222411533

執行閘道器模組

image-20220103222437716

都成功之後本地訪問http://localhost:8888/ems/employee

到這裡都沒有問題說明本地測試通過了

2.編寫Dockerfile

docker中需要有JDK1.8的映象,安裝JDK

docker pull openjdk:8
image-20220103223207189

在idea中編寫員工模組Dockerfile

image-20220103225314017

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所在伺服器

image-20220103225516099

3.Dockerfile檔案上傳

然後把專案的檔案上傳到服務自己建的ems資料夾中

image-20220103230243686

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

image-20220103231213593

報錯

有個服務報錯:Error: Invalid or corrupt jarfile employess.jar

image-20220104001204222

檢查了好幾遍,重新打包上傳還是這樣,最後進目錄檢視發現jar包每次都沒有上傳完整

image-20220104001321050

檔案大小明顯不對,因為打包錯了裡面沒有主啟動類,我在打包之前就刪除這些,新增進來然後重新執行 mvn install即可

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

這下正常了

image-20220104002539137

再次執行因為之前構建的映象還在,即便重新上傳還是執行的之前構建的,沒有效果,所以的刪除之前構建過的錯誤映象,三個都執行成功

image-20220104003902487

部署成功!

image-20220104004009904

總結

還有很多可以優化的地方,因為本節是著重演示部署流程,細節方面就沒有優化了

這就是一整個部署的大概流程,但每次專案程式碼如果有更改,又需要手動重新生成映象然後在伺服器重新執行,還是不太方便,後續會出Jenkins+Docker自動化部署SpringCloud,實現程式碼提交自動進行編譯打包上傳並部署,簡化在部署方面的操作。

專案細節難免有紕漏之處,附專案地址:https://gitee.com/yanglingcong/spring-cloud-docker

相關文章