Docker 下的 Nacos 环境开发
echo "Starting nacos"n && \
cd ~/nacos/bin && \
./startup.sh -m standalone && \
cd ../logs && \
tail -f start.out
有两个重要信息需要注意:
nacos 的官方参考启动命令是./startup.sh -m standalone,这个命令会将 jvm 的输出重定向到 start.out 文件,也就是说 nacos 的 JVM 进程是在后台运行的,不会占用控制台(相比之下,spring boot 应用使用 java -jar 启动时会占用控制台),对于 docker 来说,容器内的进程如果不占用控制台,docker 就认为该容器已经结束工作,就会停止该容器,所以,为了避免 nacos 在 docker 刚刚启动就退出,需要用 tail -f start.out 来占领控制台;
用 tail -f start.out 来占领控制台可以避免容器刚刚启动就退出,但也有个弊端,就是容器中有了多个进程,并且 nacos 进程的 PID 不是 1,所以在执行 docker stop 命令时,结束进程的信号量不会到 nacos 进程,而是去了 PID 等于 1 的进程,所以 nacos 进程不会立即退出,只能等到 30 秒后被强制 kill,这个问题最好的解法是修改 nacos 的 startup.sh,让 nacos 进程始终保持在控制台,不要重定向到后台,但这样就导致 Dockerfile 不好处理了,每次下载和解压了 nacos 安装包后,都要用本地的 startup.sh 去替换原有的,这样做的话,如果 nacos 升级版本,这边本地的 startup.sh 也要随之更新,很是麻烦…
构建镜像
Dockerfile 和 docker-entrypoint.sh 文件准备好之后放在同一个目录,执行以下命令构建镜像:
docker build -t bolingcavalry/nacossimpleprovider:1.0-SNAPSHOT
如果您在 hub.docker.com 已经注册,可以执行以下命令将本地镜像上传到 hub.docker.com ,这样任何人都可以下载使用该镜像了:
docker push bolingcavalry/nacossimpleprovider:1.0-SNAPSHOT
Nacos 镜像的制作已经完成,接下来制作一个 java 应用的镜像:服务提供者;
java 应用的父工程
接下来要开发的 simple-provider 和 simple-consumer 两个应用都是 java 应用,为了管理方便,做一个基于 maven 的父工程,再将 simple-provider 和 simple-consumer 以 module 的形式加入到这个父工程中;
基于 maven 创建父工程,名为 nacosdemo,其 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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<modules>
<module>simpleconsumer</module>
<module>simpleprovider</module>
</modules>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.5.RELEASE</version>
</parent>
<groupId>com.bolingcavalry</groupId>
<artifactId>nacosdemo</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring.boot.version>2.0.5.RELEASE</spring.boot.version>
<spring.cloud.version>Finchley.SR1</spring.cloud.version>
<spring.cloud.alibaba.version>0.2.2.RELEASE</spring.cloud.alibaba.version>
</properties>
<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>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring.cloud.alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>
</plugins>
</build>
</project>
可见这是个普通的父工程,里面对 spring cloud 和 spring cloud alibaba 的版本做了控制,避免子工程还要各种指定版本的繁琐操作;
制作服务提供者镜像
simple-provider 是个 java web 应用,使用了 spring cloud alibaba 的依赖库之后可以使用 Nacos 的注册发现服务,整个工程的开发步骤如下:
基于 maven 创建工程,其 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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>nacosdemo</artifactId>
<groupId>com.bolingcavalry</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>simpleprovider</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencies>
<build>
<plu
gins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>com.google.cloud.tools</groupId>
<artifactId>jib-maven-plugin</artifactId>
<version>1.3.0</version>
<configuration>
<from>
<image>openjdk:8u201-jdk-alpine3.9</image>
</from>
<to>
<!--镜像名称和 tag,使用了 mvn 内置变量{project.version}-->
<image>bolingcavalry/nacos{project.version}</image>
</to>
<container>
<jvmFlags>
<jvmFlag>-Xms1g</jvmFlag>
<jvmFlag>-Xmx1g</jvmFlag>
</jvmFlags>
</container>
</configuration>
</plugin>
</plugins>
</build>
</project>
上述内容有两点需要注意:
a. 依赖 spring-cloud-starter-alibaba-nacos-discovery,这样可以用上 spring cloud nacos 的服务;
b. 使用了 maven 插件 jib-maven-plugin,用于将应用构建成 docker 镜像,此插件相关的详情请参考《Docker与Jib(maven插件版)实战》;
2. 配置文件 application.properties,配置应用名称和 nacos 地址,注意这里 nacos 地址配置的是 nacoshost,对应的是后面 docker-compose.yml 中的 link 参数:
spring.application.name=simple-provider
spring.cloud.nacos.discovery.server-addr=nacoshost:8848
应用启动类 SimpleProviderApplication ,配置了注解 EnableDiscoveryClient,用于启动注册发现服务:
package simpleprovider;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@EnableDiscoveryClient
@SpringBootApplication
public class SimpleProviderApplication {
public static void main(String[] args) {
SpringApplication.run(SimpleProviderApplication.class, args);
}
}
增加一个提供 http 服务的 controller 类 ProviderController:
package simpleprovider.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.RestController;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
@Description: 提供 web 服务的 controller
@author: willzhao E-mail: zq2599@gmail.com
@date: 2019/7/28 11:08
*/
@RestController
public class ProviderController {
@RequestMapping(value = "/hello/{name}", method = RequestMethod.GET)
public String hello(@PathVariable("name") String name){
return "hello " + name + ", " + new SimpleDateFormat("yyyy-mm-dd HH:mm:ss").format(new Date());
}
}
以上就是 simple-provider 的所有源码了,在 pom.xml 所在目录执行以下命令,即可构建 docker 镜像,存入本地仓库:
mvn compile jib:dockerBuild
制作服务消费者镜像
simple-consumer 是个 java web 应用,启动后对外提供 http 服务,响应的时候,通过 nacos 取得 simple-provider 的地址,然后向 simple-provider 发请求,将响应返回给浏览器:
基于 maven 创建工程,其 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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>nacosdemo</artifactId>
<groupId>com.bolingcavalry</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>simpleconsumer</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>com.google.cloud.tools</groupId>
<artifactId>jib-maven-plugin</artifactId>
<version>1.3.0</version>
<configuration>
<from>
<image>openjdk:8u201-jdk-alpine3.9</image>
</from>
<to>
<!--镜像名称和 tag,使用了 mvn 内置变量{project.version}-->
<image>bolingcavalry/nacos{project.version}</image>
</to>
<container>
<jvmFlags>
<jvmFlag>-Xms1g</jvmFlag>
<jvmFlag>-Xmx1g</jvmFlag>
</jvmFlags>
<ports>
<port>8080</port>
</ports>
</container>
</configuration>
</plugin>
</plugins>
</build>
</project>
配置文件 application.properties,配置应用名称和 nacos 地址,注意这里 nacos 地址配置的是 nacoshost,对应的是后面 docker-compose.yml 中的 link 参数:
spring.application.name=simple-consumer
spring.cloud.nacos.discovery.server-addr=nacoshost:8848
应用启动类 SimpleConsumerApplication,配置了注解 EnableDiscoveryClient,用于启动注册发现服务:
package com.bolingcavalry.simpleconsumer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@EnableDiscoveryClient
@SpringBootApplication
public class SimpleConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(SimpleConsumerApplication.class, args);
}
}
增加一个提供 http 服务的 controller 类 ConsumerController,通过 LoadBalancerClient 取得 simple-provider 的服务地址,然后发请求过去 :
package com.bolingcavalry.simpleconsumer.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
@Description: 提供 web 服务的 controller
@author: willzhao E-mail: zq2599@gmail.com
@date: 2019/7/28 11:08
*/
@RestController
public class ConsumerController {
@Autowired
LoadBalancerClient loadBalancerClient;
@RequestMapping("/test")
public String test(){
//根据应用名称取得实例对象
ServiceInstance serviceInstance = loadBalancerClient.choose("simple-provider");
评论