前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Docker 部署 SpringCloud 微服务的服务提供者和消费者(初级版)

Docker 部署 SpringCloud 微服务的服务提供者和消费者(初级版)

作者头像
子乾建建-Jeff
发布2020-06-29 15:25:57
1.3K0
发布2020-06-29 15:25:57
举报
文章被收录于专栏:iBroProiBroPro

Spring Cloud 微服务和 Docker 容器化技术,随便拿出来一个,都够你玩半天喝二两的。那么当它俩交叉在一起时,确实让新手烧脑。

开始本篇操作前,你要先在本地先成功安装 Docker,并能进行拉取镜像,启动、删除容器操作。我用的是 Mac 端的 Docker,用起来很方便。

好了,接下来才是重点。

书写一个微服务服务提供者

microservice-simple-provider-user,

一个微服务服务消费者

microservice-simple-consumer-shopping。

采用 Dockerfile 方式将其部署在 Docker 容器,后面做了高并发集群案例再考虑用 docker-compose,别着急一步步来。

SpringBoot 和 SpringCloud 版本要求挺严格,项目之间务必保持一致。

要点:

SpringCloud 微服务代码书写

采用 Dockerfile 方式部署微服务

微服务服务提供者

microservice-simple-provider-user

1 创建项目

1.1 IDEA new project,选择 Spring Initializr ,里面内容就默认了,

点击右下角 Next;

1.2 来到这个页面,完善你的项目元数据:

Group、Artifact、Name、Pacgage 我都做了简单修改;

Name 里面的值就是你的启动类的名字,自动驼峰命名去掉了横线;

其他的名字就不需要多解释了吧,再点击 Next。

1.3 选择基础的依赖

可以先忽略不管中间上面 SpringBoot 的版本,因为后面有手动修改;

一共选择了右侧的四个依赖。然后 Next;

这里选择了 DataJPA 和 H2 Database,是为了方便,直接就可用,没有其他配置,你也可以选择使用 Mybatis ...

1.4 选择项目位置,点击 Finish,项目创建完成。

2 写代码

2.1 pom.xml

首先,pom.xml 里已填满依赖信息。我做了两处修改:

一是第 8 行,修改 SpringBoot 版本:

代码语言:javascript
复制
<version>1.5.9.RELEASE</version>

二是第 19 行,修改 SpringCloud 的版本:

代码语言:javascript
复制
<spring-cloud.version>Edgware.RELEASE</spring-cloud.version>

版本虽然老,但是比较可靠,就这么来吧伙计。

完整的 pom.xml 文件如下:

代码语言:javascript
复制
<?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>

        <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, 以及 resources 资源:

2.2.1 新建 User 类

代码语言:javascript
复制
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;
    }
}

2.2.2 新建 UserReposity 类,在 repository 包下

代码语言:javascript
复制
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> {

}

函数里面啥也不需要写,因为简单嘛,就是这样简单的。

2.2.3 新建 UserController 类,在 controller 包下

代码语言:javascript
复制
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); }
}

关于 RestController 与 Controller 注解的区别,可以看下这篇文章:

谈谈 @RestController 和 @Controller

此时它提供的访问路径就是 IP:端口号/user/具体的一个id。

2.2.4 新增 data.sql 和 schema.sql

别问为啥,就是 H2 Database 用着方便。

data.sql 的内容:

代码语言:javascript
复制
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);

schemal.sql 内容:

代码语言:javascript
复制
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));

2.2.5 修改 application.properties

将 application.properties 改名为 application.yml,加入内容:

代码语言:javascript
复制
server:
  port: 8000
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数据库的数据脚本
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@

2.2.6 关于启动类 ProviderUserApplication

无需改变。

此时通过启动类启动,可以成功启动。若提示 Test 类有错误,是测试类问题,可以先将其删除。

通过 localhost:8000/user/1 是可以查看到返回的数据结果的。

user/1,user/2 都是可以的。

此时说明项目是没问题的,将其停掉,可以准备部署。

3 准备部署

3.1 新建 Dockerfile

在项目的根目录,新建 Dockerfile,内容为:

代码语言:javascript
复制
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"]

FROM:指定基础镜像。java:8 ,表示基于 jdk1.8 版本

VOLUME:授权访问从容器内到主机上的目录。如果不太清楚怎么写,就先写上 /tmp

ADD 《src》《destination》复制文件指令。src 是本地文件,destination 是容器内文件名字。上面的意思就是将本地 targer 目录下的 xxx.jar 包复制到容器内,命名为 /app.jar

本地文件目录尽量不要出现 ../ (上一级)这种形式,可能会出现找不到文件。好的方法是 jar 包和 Dockerfile 放在同一级目录

EXPOSE:暴漏的端口。和微服务的保持一致,防止混淆弄乱

ENTRYPOINT:你仔细品,有 java、-jar、app.jar ,是不是很像从终端命令行运行一个 jar 包的命令。没错就是了。中间那一串是一个随机数,加速启动。

3.2 制作 docker 镜像

有两种方法,一种是在 pom.xml 里面引入插件,打包和制作镜像一步完成,生成的镜像名字是通过 pom.xml 里面的插件格式规定的。另一种就是手动操作镜像名字版本。这儿我选择的手动操作设置,咱自己一步步来。

3.2.1 打 jar 包

在 IDEA 里面,通过 MAVEN-Lifecycle-pacgage,快速打包;或者使用命令行 mvn clean package(注意要在该项目的根目录下执行)。

此时在项目的 target 目录下就出现了该 jar 包。

成功后,在控制台会提示 "BUILD SUCCESS" 字样。

3.2.2 生成 docker 镜像

该项目基于 Java jdk1.8,所以要保证你的 Docker 有 java:8 这个镜像。没有的话先拉取一下:

代码语言:javascript
复制
docker pull java:8

然后生成该项目的镜像,因为 Dockerfile 在项目的根目录,因此在终端命令行 cd 到该根目录,执行:

代码语言:javascript
复制
docker built -t isclab/microservice-simple-provider-user:0.0.1 .

docker built -t 是基础的命令,isclab/microservice-simple-provider-user 是镜像名字,0.0.1 是版本号,最后的 . 不要忘记,表示容器的当前目录。

如果忘记了点,会在执行的时候提示参数问题,因为你漏掉了参数嘛。或者提示 unknown shorthand flag: 't' in -t ,也可能是这个问题。

执行命令正确的话,通过查看镜像 docker images ,可以看到该镜像已经存在了。如上图。

3.2.3 启动容器,访问

在终端输入

代码语言:javascript
复制
docker run -d -p 8000:8000 --name provider isclab/microservice-simple-provider-user:0.0.1

-d 后台运行

-p 指定映射端口

-- name 此时并用不着,是为了服务消费者而准备的

启动成功返回一个 ID 号。

此时输入 docker ps 查看已经启动的容器。

会发现该容器 NAMES 一栏的名字正好是我们的命名 provider。

此时再通过浏览器访问 localhost:8000/user/1 ,可以查找到数据。

微服务服务提供者到此就部署完成。

服务消费者

microservice-simple-consumer-shopping

1 创建项目

和服务提供者基本一样,项目元数据设置如下:

它并不需要直接调用数据库,因此在选择依赖时,可以只选择 Spring Web 和 Cloud Bootstrap。

直至点击 Finish 完成。

2 写代码

2.1 修改 pom.xml

和服务提供者一样,保持 SpringBoot 和 SpringCloud 版本的一致。

完整的 pom.xml 如下:

代码语言:javascript
复制
<?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>

        <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 包

2.2.1 新建 User 类,在 entity 包下

内容和服务提供者的 User 类一模一样。

2.2.2 新建 ShoppingController 类,在 controller 包下

提供访问的入口

代码语言:javascript
复制
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://provider:8000/user/"+id, User.class);
    }
}

此时,消费者调用提供者的路径已经不再是 localhost:8000/xxx,因为在不同的容器里面,localhost 是不通的。这时就用到了我们上面启动提供者容器时,命名的 --name provider。用 provider 代替 localhost:8000 即可。

2.2.3 修改启动类 ConsumerShopping

因为在 ShoppingController 中,通过 restTemplate 进行调用,因此需要在启动类用注解加以启用。

代码语言:javascript
复制
package ouc.isclab.microservice;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
public class ConsumerShoppingApplication {

    @Bean
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
    public static void main(String[] args) {
        SpringApplication.run(ConsumerShoppingApplication.class, args);
    }

}

2.2.4 修改 application.properties

将其重命名为 application.yml

代码语言:javascript
复制
server:
  port: 8010

提供一个访问接口。

3 制作 docker 镜像

3.1 新建 Dockerfile

在项目根目录下新建 Dockerfile 文件,内容为:

代码语言:javascript
复制
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"]

和服务提供者很相似,不再赘述。

3.2 打 jar 包

和服务提供者一样。

当 Test 类有错误(或有其他错误)而没修改时,可能出现下面的错误:(惨败)最后的 BUILD FAILURE!就代表你已经输了。

3.3 生成 docker 镜像,启动容器

3.3.1 生成镜像

在终端,cd 该项目根目录,执行

代码语言:javascript
复制
docker build -t isclab/microservice-simple-consumer-shopping:0.0.1 .

生成镜像,可查看验证一下

3.3.2 启动容器,并查看

输入命令

代码语言:javascript
复制
docker run -d -p 8010:8010 --name consumer --link provider:provider isclab/microservice-simple-consumer-shopping:0.0.1

--link containerNAMES:name ,和其他容器进行通信。

containerNAMES : 被链接的容器的名字

name:在该项目中使用的名字

此时,在浏览器输入 localhost:8010/user/1 也可以查询到数据

这样,简单的微服务服务提供者、服务消费者的 Docker 部署就结束了。

整体的项目结构:

  • provider-user 服务提供者
  • consumer-shopping 服务消费者

重点:两个容器的通信通过 --link 连接,关键还是要名字的相互对应,服务提供者容器的名字 和 服务消费者访问服务提供者的路径名字保持一致。

可以想象一下,如果再加一个微服务注册与发现,--name、--link 或许可以满足要求,但是微服务的注册与发现如果需要高集群该怎么做呢?

这个问题下篇文章通过 docker-compose 编排微服务来解决,这篇就这样了,拜拜各位。

感谢阅读,感谢陪伴!

项目的源代码地址:https://gitee.com/JeffBro/microservice-simple-provider-user

2020-06-05 该版代码是此次项目对应的代码

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-06-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 iBroPro 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档