本文将介绍如何通过
CICD
将SpringBoot
框架的Web项目发布到k8s集群
中,文章中有使用到eureka
的注册,如果对如何在k8s集群
中部署eureka
,那么可以参考本人的 k8s部署eureka集群 文章。如果只是为了测试部署Web
服务到k8s集群
中,那么你们可以自己搭建项目时,忽略eureka
的相关依赖和配置
Deployment
是最常用的用于部署无状态服务的方式。Deployment
控制器使得您能够以声明的方式更新 Pod
(容器组)和 ReplicaSet
Kubernetes 中 Service
是一个 API 对象,通过 kubectl + YAML定义一个 Service,可以将符合 Service 指定条件的 Pod 作为可通过网络访问的服务提供给服务调用者。Service 是 Kubernetes 中的一种服务发现机制
这里不做具体的创建项目演示,通过Idea
创建非常的方便快捷,最终的pom
文件如下,如果只是普通的Web
服务,那么无需增加SpringCloud
的相关依赖。至于其他的依赖那就根据你们项目的情况来增加了,这里只是为了演示,所以不做过多的依赖引入
<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.0modelVersion>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.5.1version>
<relativePath/>
parent>
<groupId>com.gjing.projectsgroupId>
<artifactId>k8s-web-demoartifactId>
<version>0.0.1-SNAPSHOTversion>
<name>k8s-web-demoname>
<description>Demo project for Spring Bootdescription>
<properties>
<java.version>1.8java.version>
<spring-cloud.version>2020.0.3spring-cloud.version>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-actuatorartifactId>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-dependenciesartifactId>
<version>${spring-cloud.version}version>
<type>pomtype>
<scope>importscope>
dependency>
dependencies>
dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
exclude>
excludes>
configuration>
plugin>
plugins>
build>
project>
开启Eureka
的支持,普通Web
项目跳过
/**
* @author Gjing
*/
@EnableEurekaClient
@SpringBootApplication
public class K8sWebDemoApplication {
public static void main(String[] args) {
SpringApplication.run(K8sWebDemoApplication.class, args);
}
}
这里使用了变量的形式设置配置的值,这样就可以根据不同的环境来分别配置了。如果对变量的使用不熟悉的话建议恶补一下 SpringBoot 项目在 Yaml 文件使用变量。这里只是演示的配置,在实际使用时根据业务需求来合理配置
server:
port: ${SERVER_PORT:8081}
spring:
application:
name: ${SERVER_NAME:web-demo}
eureka:
client:
service-url:
defaultZone: ${EUREKA_URL:http://localhost:8761/eureka/}
instance:
hostname: ${HOST_NAME:localhost}
lease-renewal-interval-in-seconds: 5 # 续约间隔时间
lease-expiration-duration-in-seconds: 10 # 服务失效时间
prefer-ip-address: true # 开启服务IP注册,如果网关使用了Cloud-Gateway那么一定要增加该配置
FROM openjdk:8-jdk
COPY target/*.jar app.jar
ENTRYPOINT java $JAVA_OPTS -jar $CONFIG app.jar
不是很熟悉CI写法的建议先看阅读:SpringBoot使用CICD
before_script:
- export IMAGE_FULL_NAME=$CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHA
stages:
- compile
- build
- run
variables:
MAVEN_REPO: "/.m2"
PROJECT_NAME: "k8s-web"
K8S_FILE: "web-k8s.yml"
compile:
stage: compile
image: 172.20.9.4:5001/gjing/maven:1.0
only:
- master
tags:
- pub
script:
- mvn -Dmaven.repo.local=$MAVEN_REPO clean package -Dmaven.test.skip=true
artifacts:
name: $PROJECT_NAME
expire_in: 1 week
paths:
- target/*.jar
build:
stage: build
image: docker:stable
only:
- master
tags:
- pub
script:
- docker login --username $CI_REGISTRY_USER --password $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker build -t $IMAGE_FULL_NAME .
- docker push $IMAGE_FULL_NAME
- docker rmi -f $IMAGE_FULL_NAME
run:
stage: run
image: roffe/kubectl
only:
- master
tags:
- pub
variables:
PROJECT_PORT: 8081
PROJECT_NAMESPACE: gj # 命名空间需要提前在k8s中创建好
script:
- mkdir -p /root/.kube # 配置 kubectl, ${KUBE_CONFIG}这个变量会在下面发布的章节介绍如何配置
- echo $KUBE_CONFIG | base64 -d > /root/.kube/config
- export KUBECONFIG=/root/.kube/config
- kubectl version
- sed -i "s#{PROJECT_NAME}#$PROJECT_NAME#g;
s#{PROJECT_PORT}#$PROJECT_PORT#g;
s#{PROJECT_NAMESPACE}#$PROJECT_NAMESPACE#g;
s#{PROJECT_IMAGE}#$IMAGE_FULL_NAME#g" $K8S_FILE
- kubectl apply -f $K8S_FILE
创建一个名为web-k8s.yml
文件,文件名要和CI文件中的K8S_FILE变量的值一致
,如果是普通Web
项目,那么下方配置中,忽略掉env
中的EUREKA_URL
环境变量配置即可
apiVersion: v1
kind: Service
metadata:
name: {PROJECT_NAME}
namespace: {PROJECT_NAMESPACE}
labels:
app: {PROJECT_NAME}
spec:
selector:
app: {PROJECT_NAME}
ports:
- port: {PROJECT_PORT}
targetPort: {PROJECT_PORT}
name: {PROJECT_NAME}
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: {PROJECT_NAME}
namespace: {PROJECT_NAMESPACE}
labels:
app: {PROJECT_NAME}
spec:
replicas: 3
selector:
matchLabels:
app: {PROJECT_NAME}
template:
metadata:
labels:
app: {PROJECT_NAME}
spec:
containers:
- name: {PROJECT_NAME}
image: {PROJECT_IMAGE}
ports:
- containerPort: {PROJECT_PORT}
readinessProbe:
httpGet:
path: /actuator/health
port: {PROJECT_PORT}
failureThreshold: 3 # 探测失败的阈值,超过则认定该pod失败状态
initialDelaySeconds: 60 # pod启动延迟多久进行检查
periodSeconds: 10 # 检查的周期
successThreshold: 1 # 探测成功的阈值,只要成功一次就认定pod为正常
timeoutSeconds: 10 # 超时时间,如果超时则认为pod是失败状态
env:
- name: SERVER_PORT
value: "{PROJECT_PORT}"
- name: SERVER_NAME
value: {PROJECT_NAME}
- name: EUREKA_URL
valueFrom:
configMapKeyRef: # 这里是取eureka项目里定义的configMap里的值
name: eureka-host
key: registry_url
- name: HOST_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
这时候我们的项目准备工作都做好了,不过好像少了点接口用来测试,我们先增加几个测试接口,项目中创建个控制器,代码如下
/**
* @author Gjing
**/
@RestController
public class TestController {
@PostMapping("/test1")
public ResponseEntity<String> test1() {
return ResponseEntity.ok("web-demo test1 is ok");
}
@GetMapping("/test2")
public ResponseEntity<String> test2(String user) {
return ResponseEntity.ok("web-demo test2 is ok: " + user);
}
}
到此,我们的项目才算准备完成了,接下来就是发布了
由于我们配了CI文件,那么当我们代码提交到Gitlab的时候,就会自动进行构建并启动啦
首先,我们先登陆到 k8s master节点服务器上,进入到/etc/kubernetes/
目录,然后通过cat admin.conf
将这个文件的内容输出到控制台,最后将复制出来的内容先保存到
自己电脑的文本编辑器中,然后修改红色框中的地址,将dns
修改为你的ApiServer
的IP,如果是多master的话就是填写ApiServer的LoadBalance IP了
然后我们复制修改后的所有内容,到浏览器随便搜索一个在线的base64加密工具将内容进行加密。随后,我们来到GitLab,进到具体项目或者项目组里,点击下方图中的选项
点击后进到下方页面并添加变量,注意:键
要和你ci里面写的保持一致,值
的话就是刚刚加密后的内容了
最好将此变量配置在项目组中,这样该项目组的所有项目都会继承该变量
上面已经配置了KUBE_CONFIG
变量了,这时候我们就可以直接提交代码到GitLab啦,提交成功后就可以在GitLab项目左侧的CICD选项中看到流水线在执行
当三个阶段都打勾了就说明执行成功啦,如果出现了错误,那就可以点击指定阶段进去查看下错误日志进行针对性修改了
这时我们可以去master服务器上执行kubectl get pod -n gj
查看下pod启动成功没
可以看到三个Pod
都是running状态了,这时我们也可以通过kubectl logs -f
命令进行查看下其中一个Pod
的日志,这里我们可以看到web服务
已经成功起来了
由于我们定义了Service
,且配置了Port
,那么我们可以在集群内部通过IP
去访问,首先我们通过kubectl get svc -n gj
去查看下运行的 Service
可以看到名叫 k8s-web 的 Service,这就是我们 web 服务的 Service,这时候我们通过它的 IP 进行测试
可以看到正常返回,那就说明成功了