k8s最佳实践.md

k8s最佳实践.md

Kubernetes一个自动化部署java项目的最佳实践

前言 :

一个容器中最好只存在一个进程,方便健康检查

容器的基础镜像越小越好

本文将部署一个java后端接口项目在k8s,并实现自动化部署及无缝更新。

痛点:

入口不统一

不方便配置SSL及负载和统一配置其他策略。

  • 使用固定一台Nginx用作处理请求,将接口请求转发给k8s的clusterIP 👌

  • 使用k8s的service

配置文件

配置文件需要根据环境进行更改,现在配置文件都在本机文件不利于灵活部署。

  • 使用配置中心

  • 使用启动参数 👌

日志

多节点会导致查看日志不便。

此项痛点不是刚需,大部分只有调试阶段才会出现频繁看日志的情况,上线后需求少。

  • ELK(不推荐,功能完整但是组件复杂 整体比较庞大,而且有延迟。)

  • 保持现状,进入容器查看日志👌

业务可用性

保持业务可用性,减少更新带来的中断时间。

  • 使用滚动更新,配置容器的启动探针 👌

可伸缩性

根据业务量随时扩容与缩减。保障业务量大的时候支撑服务,业务量少的时候节省资源使用。

  • kubernetes👌

部署更新简便

迭代交付方便 简单 迅速

  • jenkins shell-script docker👌
  • jenkins 流水线 (有学习门槛,使用shell脚本更加方便通用)

整体部署流程:

k8s最佳实践流程drawio.drawio

构建镜像

部署harbor私有镜像仓库

harbor[1]

Harbor是使用docker的方式部署的,用docker compose编排。

  1. Harbor服务分在线安装和离线安装,这里推荐使用离线安装:
#下载harbor离线包
wget https://github.com/goharbor/harbor/releases/download/v2.4.1-rc1/harbor-offline-installer-v2.4.1-rc1.tgz

tar -zxvf harbor-offline-installer-v2.4.1-rc1.tgz
  1. 进入解压后的目录,编辑harbor.yml配置文件。如下几项进行更改:
"harbor.yml" 201L, 7893C

#主机名,推荐设置证书的域名
hostname: test.abc.cn

# http的端口
http:
#  # port for http, default is 80. If https enabled, this port will redirect to https port
  port: 8086

# https的端口
#这里推荐使用https,因为docker拉取镜像默认是https的。如果不设置https这里可以跳过
https:
  # https port for harbor, default is 443
  port: 8084
  # ssl证书位置
  certificate: /opt/nginx/conf/ssl/5507833_test.abc.cn.pem
  private_key: /opt/nginx/conf/ssl/5507833_test.abc.cn.key

#管理员密码  
harbor_admin_password: harbor32354

# Harbor DB configuration
database:
  # The password for the root user of Harbor DB. Change this before any production use.
  password: root123
  # The maximum number of connections in the idle connection pool. If it <=0, no idle connections are retained.
  max_idle_conns: 100
  # The maximum number of open connections to the database. If it <= 0, then there is no limit on the number of open connections.
  # Note: the default number of connections is 1024 for postgres of harbor.
  max_open_conns: 900

# 存放镜像的目录,这里会做映射的 写宿主机的目录就行了。
data_volume: /data

详细配置见官网[2]

  1. 开始安装,运行install.sh即可

如果你没有使用https的harbor,必须将 --insecure-registry 添加到docker引擎内,一般配置文件在/etc/docker/daemon.json

{
"insecure-registries" : ["myregistrydomain.com:5000", "0.0.0.0"]
}

保存并重启docker引擎和harbor

systemctl restart docker

docker-compose down -v

docker-compose up -d
  1. 登录harbor的地址,使用配置文件中的密码。

新建一个test的项目,开始准备实验:

image-20211216103019858

  1. 使用docker登录仓库

docker login <harbor_address>

  1. 推送一个测试镜像

    #标记图像
    docker tag hello-world:latest <harbor_address>/test/hello-world:latest
    #推送
    docker push <harbor_address>/test/hello-world:latest
    
  2. 登录web控制台即可查看推送的镜像。


构建业务镜像

  1. 本次实验是部署一个maven构建的java后端接口项目,所以基础镜像使用jdk来做。

Dockerfile文件如下:

FROM openjdk:8u312-jdk-oraclelinux8
  
ADD sbserver.jar app.jar

EXPOSE 9093

ENTRYPOINT ["java","-jar","/app.jar","--spring.profiles.active=dev"]
  • 其中sbserver.jar是项目jar包,把他放到和dockerfile同路径下。

如果是war包,基础镜像就使用tomcat的。

  • EXPOSE是声明端口,注意自己sprint boot项目的配置文件端口,根据实际情况填写或者更改相应的配置文件。
  1. 构建并推送镜像
docker build -t sbserver:v0.1 .
#-t 指定镜像名称及标签 注意后面有个.是代表工作路径为当前路径

#设置标签,其中harbor更换为你们对应的地址
docker tag sbserver:v0.1 <harbor_address>/test/sbserver:v0.1

#推送镜像
docker push <harbor_address>/test/sbserver:v0.1
  1. 登录harbor镜像仓库控制台,看看刚推送的业务镜像是否存在。

配置kubernetes

本次实验并不是完全自动化,在创建新的部署项目时还需要手动创建 k8s的部署任务和jenkins任务。

新建项目

  1. 登录k8s 控制台

从右上角新建一个任务,选择从表单创建对新人比较友好。

image-20211216112548454

  1. 填写配置

    deployments详细配置可以见文档[3]

配置项备注
应用名称sbserver
容器镜像<harbor_address>/test/sbserver:v0.1注意更改仓库地址
pod数量1需要运行的节点数量
serviceExternal对外服务
端口9093根据实际情况填写
描述任意
命名空间test默认default,这里需要创建一个
拉取镜像的secretts-re默认是default token,这里是拉取镜像的凭据,我们harbor中的镜像是私有的,所以这里要新建一个。

命名空间这里选择新建一个,名为test

image-20211216112808365

secret 拉取镜像的凭据,这里使用命令行创建一个。

#进入master主机 
kubectl create secret docker-registry ts-re --docker-server=test.abc.cn:8084 --docker-username=admin --docker-password=hardorps -n test
  • docker-registry ts-re 凭据名称
  • --docker-server test.abc.cn:8084 仓库地址
  • --docker-username admin 登录仓库的用户名,这里可以在harbor控制台新建一个用户
  • --docker-password 用户的密码
  • -n 指定命名空间,这里test是前面刚创建的
  1. 完成配置后部署,在上方命名空间选择test

image-20211216115437826

部署页(Deployments)中可以看到前面配置的应用.

在pod页可以看到容器具体的启动情况,可以点击如下查看日志和进入容器终端。

image-20211216115604197

查看容器启动情况,如果失败注意pod的事件和日志内容。

service这里使用默认的(LoadBalancer),pods数量大于1的时候会有负载均衡。

service的详细用法可以参照官方文档[4]

配置容器探针

  1. 编辑app.yml配置探针功能,目的是为了实现无缝更新,让k8s更清楚的了解容器的就绪情况。

在部署页(Deployments)中选择编辑

image-20211216140400444

目录层级如下,注意缩进是俩个空格不要使用制表符

spec:

template:

spec:

containers:

livenessProbe:

kind: Deployment
apiVersion: apps/v1
metadata:
  name: sbserver
  namespace: test
  ...略
spec:
  ...略
  template:
    metadata:
      name: sbserver
      labels:
        k8s-app: sbserver
    spec:
      containers:
        - name: sbserver
          image: test.abc.cn:8084/test/sbserver:v0.1
          resources: {}
          #配置容器存活探针,此处使用的http请求。(还有TCP和shell命令等探测方法)
          livenessProbe:
            httpGet:
            #请求的路径,这个是一个测试的接口,请求这个路径会返回200状态,根据实际应用情况更改。
              path: /sbserver/state
              port: 9093
              scheme: HTTP
            #容器启动后 等待5秒再开始检测  
            initialDelaySeconds: 5
            #超时时间
            timeoutSeconds: 1
            #检测间隔
            periodSeconds: 5
            #成功阈值
            successThreshold: 1
            #失败阈值
            failureThreshold: 3
          #启动前探针,此处可以让一些启动比较慢的应用一些宽容时间。  
          #选项与上面基本一样
          startupProbe:
            httpGet:
              path: /sbserver/state
              port: 9093
              scheme: HTTP
            timeoutSeconds: 1
            #探测间隔
            periodSeconds: 6
            successThreshold: 1
            #失败阈值,此处和探测间隔就是在任务分发下来后,有6*20 120秒的时间启动
            #每过6秒探测一次,如果探测了20次还没有启动就认为启动失败,k8s就不会把流量转入这个新的pod上。
            failureThreshold: 20
          ...略

容器的探针用法详细参照官方文档[5]

完成以上配置,点击更新。

  1. 测试无缝更新

向私有镜像仓库重新推送一个app版本,模拟生产的版本迭代

#设置标签,这里直接还是使用v0.1的镜像,但是更改一下标签
docker tag sbserver:v0.1 <harbor_address>/test/sbserver:v0.2

#推送镜像
docker push <harbor_address>/test/sbserver:v0.2

#临时编写一个测试脚本,模拟用户一直在请求流量。
cat test-service.sh

#!/bin/bash
while true
do
	#此处curl的地址是service对外暴露映射的随机高端口,创建完毕后此端口是固定的。
	curl -o /dev/null -s http://192.168.31.182:30489/sbserver/state -w "%{http_code}\n"
sleep 1
done


#保存,开个终端在边上运行着。
chmod +x test-service.sh
./test-service.sh
200
200
200

#如上一直返回200即代表现在请求都是正常的。

编辑app.yml,修改其中的image标签即可完成更新操作


spec:
  ...略
  template:
    metadata:
      name: sbserver
      labels:
        k8s-app: sbserver
    spec:
      containers:
        - name: sbserver
          image: test.sbc.cn:8084/test/sbserver:v0.2
          #设置标签为v0.2

点击更新即可完成更新操作,同步查看后台测试脚本是否一直返回200而且无中断。

至此k8s最佳实践基本完成,后续配合jenkins和shell脚本进行自动化部署。

配置jenkins

实现自动部署

Jenkins的部署及详细配置方式这里不多解释。

新建一个Maven的项目

主题配置项备注
源码管理gitgit地址
分支test
构建触发器 这里不使用触发器 手动构建
构建调用maven-T 32 clean package -Dmaven.test.skip=true-T多线程编译
执行shell脚本sudo /opt/jenkins/workspace/update-test_k8s.sh sbserver 9093此处脚本是自定义脚本,根据需要可以自己编写。

编写脚本

具体实现自动化的主要是shell脚本,因为我不太会流水线 所以这里使用脚本代替。

cat update-test_k8s.sh 
#!/bin/bash
#自动化更新k8s接口服务

if [ -z ${1} ];then
        echo -e "\033[31m 请传参(服务名 端口),程序退出。 \033[0m"
        exit 1
fi

#设置target目录
target="/opt/jenkins/workspace/${1}-test-k8s/ruoyi-admin/target"

#设置k8s 命名空间
namespace="test"

#设置kubectl配置文件
kubeConfig="/etc/kubernetes/admin.conf"

#当前最后一个版本号
n=`docker images ${1} --format "{{.Tag}}" | head -1 | awk -F. '{print $2}'`
last="v0.${n}"
#版本号+1
let "n++"
last1="v0.${n}"

#镜像仓库地址
docHub="test.abc.cn:8084/test"

echo -e "\033[36m \n \
	target目录:${target}\n \
	k8s命名空间:${namespace}\n \
	kubectl配置文件:${kubeConfig}\n \
	当前镜像:${1}:${last}\n \
	预计打包镜像:${1}:${last1}\n \
	镜像仓库地址:${docHub}\n \
	\033[0m"
#-----------

fhz(){
if [ $1 == 0 ];then
	echo -e "\033[36m ${2}完成 \033[0m"
else
	echo -e "\033[31m ${2}失败,原因见上,程序退出。 \033[0m"
	exit 1
fi
}

#构建业务镜像

FROM="openjdk:8u312-jdk-oraclelinux8"
ADD="${1}.jar app.jar"
EXPOSE="${2}"
ENTRYPOINT='["java","-jar","/app.jar","--spring.profiles.active=dev"]'

cd ${target}
fhz $? 进入目录${target}

mv ./ruoyi-admin.jar ./${1}.jar
fhz $? 重命名${1}.jar

if [ -f "Dockerfile" ];then
        echo -e "\033[36m  Dockerfile文件存在 \033[0m"
else
        echo  -e "\033[31m Dockerfile文件不存在,正在创建 \033[0m"
	echo "FROM ${FROM}" >> Dockerfile
	echo "ADD ${ADD}" >> Dockerfile
	echo "EXPOSE ${EXPOSE}" >> Dockerfile
	echo "ENTRYPOINT ${ENTRYPOINT}" >> Dockerfile
fi
echo -e "\033[36m  Dockerfile内容如下: \033[0m"
cat Dockerfile

docker build -t ${1}:${last1} .
fhz $? 构建镜像${1}:${last1}

docker tag ${1}:${last1} ${docHub}/${1}:${last1}
fhz $? 镜像标签${docHub}/${1}:${last1}设置

docker push ${docHub}/${1}:${last1}
fhz $? 推送镜像${docHub}/${1}:${last1}

#k8s部署任务
kubectl --kubeconfig ${kubeConfig} -n ${namespace} set image deploy ${1} *=${docHub}/${1}:${last1}
fhz $? k8s分发部署任务

echo -e "\033[36m 如果此容器有问题将会导致新版本无法上架,业务不受影响,具体请登录k8s控制台查看容器启动情况。  \033[0m"

保存此脚本在Jenkins节点主机上面,构建的时候会调用此脚本。注意此机器上面也要安装Kubctl用来更改镜像标签。

声明

原文:k8s最佳实践 - good good study,day day up~

作者:AHA

联系:liu.liuy@qq.com

资料参考:


  1. Harbor docs | Download the Harbor Installer ↩︎

  2. Harbor docs | Configure the Harbor YML File ↩︎

  3. Deployments | Kubernetes ↩︎

  4. 服务 | Kubernetes ↩︎

  5. 配置存活、就绪和启动探测器 | Kubernetes ↩︎

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×