docker+kubernetes+springcloud微服务集群部署,spring-cloud-kubernetes,使用k8s部署spring cloud并实现服务注册、负载均衡、网关等功能
-
官方地址: https://github.com/spring-cloud/spring-cloud-kubernetes
-
参考:https://blog.csdn.net/boling_cavalry/article/details/91346780
https://blog.csdn.net/u013360850/article/details/100635405
-
本机环境
地址 | 服务 |
---|---|
192.168.0.11 | k8s-master |
192.168.0.22 | k8s-node1 , docker registry |
192.168.0.33 | k8s-node2 |
代码见https://github.com/heliu0/springcloud-k8s.git
<?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>springcloud-k8s-parent</artifactId>
<groupId>com.yayiyo.k8s</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>springcloud-k8s-producer</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>${spring-cloud-openfegin.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<version>${spring-boot.version}</version>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>${spring-boot.version}</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-kubernetes</artifactId>
<version>${spring-cloud.k8s}</version>
</dependency>
</dependencies>
</project>
package com.yayiyo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class ProducerApplication {
public static void main(String[] args) {
SpringApplication.run(ProducerApplication.class, args);
}
}
package com.yayiyo.controllers;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.net.InetAddress;
import java.net.UnknownHostException;
@Controller
public class RpcController {
@GetMapping("/ping")
@ResponseBody
public String ping() {
try {
return InetAddress.getLocalHost().getHostName();
} catch (UnknownHostException e) {
return "Pong";
}
}
}
spring:
application:
name: producer-service
cloud:
kubernetes:
config:
sources:
- name: ${spring.application.name}
namespace: default
reload:
enabled: true
mode: event
discovery:
all-namespaces: true
server:
port: 8082
management:
endpoint:
restart:
enabled: true
endpoints:
web:
exposure:
include: restart
FROM openjdk:8-jdk-alpine
LABEL version="1.0" maintainer="yayiyo@chinaunicom.com"
VOLUME /tmp
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
ARG JAR_FILE
ADD target/springcloud-k8s-producer-0.0.1-SNAPSHOT.jar app.jar
ENTRYPOINT ["java", "-jar","/app.jar"]
EXPOSE 8082
#查看本地仓库里面是否有该镜像
docker images
# 推到远程镜像仓库
docker push 镜像名
kubectl apply -f producer-service.yaml
apiVersion: v1
kind: Service
metadata:
name: producer-service
labels:
app.kubernetes.io/name: producer-service
spec:
type: ClusterIP
ports:
- port: 8082
targetPort: 8082
nodePort: 8082
protocol: TCP
name: http
selector:
app.kubernetes.io/name: producer-service
---
apiVersion: apps/v1producer-service
kind: Deployment
metadata:
name: producer-service
labels:
app.kubernetes.io/name: producer-service
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: producer-service
template:
metadata:
labels:
app.kubernetes.io/name: producer-service
app.kubernetes.io/instance: sad-markhor
spec:
containers:
- name: producer-service
# 镜像名需要与仓库中的镜像名一致
image: "192.168.0.22:5000/spring-cloud-k8s-producer:1.0"
imagePullPolicy: Always
ports:
- name: http
containerPort: 8082
protocol: TCP
可以看到有 producer-service 的pod正常运行。
<?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>springcloud-k8s-parent</artifactId>
<groupId>com.yayiyo.k8s</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>springcloud-k8s-customer</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>${spring-cloud-openfegin.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
<version>${spring-cloud-openfegin.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<version>${spring-boot.version}</version>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>${spring-boot.version}</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-kubernetes</artifactId>
<version>${spring-cloud.k8s}</version>
</dependency>
</dependencies>
</project>
package com.yayiyo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class CustomerApplication {
public static void main(String[] args) {
SpringApplication.run(CustomerApplication.class, args);
}
}
package com.yayiyo.controllers;
import com.yayiyo.client.ProducerClient;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@Slf4j
public class CoustomerController {
@Autowired
private DiscoveryClient discoveryClient;
@Autowired
private ProducerClient producerClient;
@GetMapping("/service")
public Object getClient() {
return discoveryClient.getServices();
}
@GetMapping("/instance")
public List<ServiceInstance> getInstance(String instanceId) {
return discoveryClient.getInstances(instanceId);
}
@GetMapping("/ping")
public String ping() {
return producerClient.ping();
}
}
package com.yayiyo.client;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@FeignClient(name = "http://producer-service:8082", url = "http://producer-service:8082", fallback = ProducerClientFallback.class)
public interface ProducerClient {
@RequestMapping(value = "/ping", method = RequestMethod.GET)
String ping();
}
@Component
class ProducerClientFallback implements ProducerClient{
@Override
public String ping() {
return "Error";
}
}
spring:
application:
name: customer-service
cloud:
kubernetes:
config:
sources:
- name: ${spring.application.name}
namespace: default
reload:
enabled: true
mode: event
discovery:
all-namespaces: true
server:
port: 8081
management:
endpoint:
restart:
enabled: true
endpoints:
web:
exposure:
include: restart
FROM openjdk:8-jdk-alpine
LABEL version="1.0" maintainer="yayiyo@chinaunicom.com"
VOLUME /tmp
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
ARG JAR_FILE
ADD target/springcloud-k8s-customer-0.0.1-SNAPSHOT.jar app.jar
ENTRYPOINT ["java", "-jar","/app.jar"]
EXPOSE 808
#查看本地仓库里面是否有该镜像
docker images
# 推到远程镜像仓库
docker push 镜像名
kubectl apply -f customer-service.yaml
apiVersion: v1
kind: Service
metadata:
name: customer-service
labels:
app.kubernetes.io/name: customer-service
spec:
# 可以直接使用NodePort方式放开端口,这里使用ClusterIP+nginx的方式,其好处是使用负载均衡以及nginx代理。
# 注意:如果使用NodePort方式,则不用编写ingress-nginx-controller以及tcp-services-configmap
type: ClusterIP
ports:
- port: 8081
targetPort: 8081
nodePort: 8081
protocol: TCP
name: http
selector:
app.kubernetes.io/name: customer-service
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: customer-service
labels:
app.kubernetes.io/name: customer-service
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: customer-service
template:
metadata:
labels:
app.kubernetes.io/name: customer-service
app.kubernetes.io/instance: sad-markhor
spec:
containers:
- name: customer-service
image: "192.168.0.22:5000/spring-cloud-k8s-customer:1.0"
imagePullPolicy: Always
ports:
- name: http
containerPort: 8081
protocol: TCP
---
# Source: ingress-nginx/templates/controller-service.yaml
apiVersion: v1
kind: Service
metadata:
labels:
helm.sh/chart: ingress-nginx-2.13.0
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/version: 0.35.0
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/component: controller
name: ingress-nginx-controller
namespace: ingress-nginx
spec:
type: LoadBalancer
externalTrafficPolicy: Cluster
ports:
# 该名称需要与消费者service中的name保持一致
- name: customer-service
port: 8081
protocol: TCP
targetPort: 8081
nodePort: 8081
selector:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/component: controller
---
apiVersion: v1
kind: ConfigMap
metadata:
# 该文件需要在ingress-nginx-controller中引用。
name: tcp-services-configmap
namespace: ingress-nginx
data:
"8081": "default/customer-service:8081"
正常可以在浏览器中看到:
- 在ide编辑时一定要用LF格式
- 执行dockerfile后记得在服务器上push镜像。
- customer中的producerCLient.java中FeignClient 的url要写ip:port,只写服务名是找不到该服务的。
@FeignClient(name = "http://producer-service:8082", url = "http://producer-service:8082", fallback = ProducerClientFallback.class)
- 如果想在本机测试,可以在host里面设置producer-service
127.0.0.1 producer-service