??項(xiàng)目部署有多種方式,從最原始的可運(yùn)行 jar 包直接部署到 JDK 環(huán)境下運(yùn)行,到將可運(yùn)行的 jar 包放到 docker 容器中運(yùn)行,再到現(xiàn)在比較流行的把可運(yùn)行的 jar 包和 docker 放到 k8s 的 pod 環(huán)境中運(yùn)行。每一種新的部署方式都是對原有部署方式的改進(jìn)和優(yōu)化,這里不著重介紹每種方式的優(yōu)缺點(diǎn),只簡單說明一下使用 Kubernetes 的原因:Kubernetes 主要提供彈性伸縮、服務(wù)發(fā)現(xiàn)、自我修復(fù),版本回退、負(fù)載均衡、存儲編排等功能。
??日常開發(fā)部署過程中的基本步驟如下:
- 提交代碼到 gitlab 代碼倉庫
- gitlab 通過 webhook 觸發(fā) Jenkins 構(gòu)建代碼質(zhì)量檢查
- Jenkins 需通過手動觸發(fā),來拉取代碼、編譯、打包、構(gòu)建 Docker 鏡像、發(fā)布到私有鏡像倉庫 Harbor、執(zhí)行 kubectl 命令從 Harbor 拉取 Docker 鏡像部署至 k8s
一、安裝配置
1. 安裝插件
??安裝Kubernetes plugin插件、Git Parameter插件(用于流水線參數(shù)化構(gòu)建)、Extended Choice Parameter插件(用于多個(gè)微服務(wù)時(shí),選擇需要構(gòu)建的微服務(wù))、 Pipeline Utility Steps插件(用于讀取 maven 工程的.yaml、pom.xml 等)和 Kubernetes Continuous Deploy(一定要使用 1.0 版本,從官網(wǎng)下載然后上傳) ,Jenkins --> 系統(tǒng)管理 --> 插件管理 --> 可選插件 --> Kubernetes plugin /Git Parameter/Extended Choice Parameter ,選中后點(diǎn)擊 Install without restart 按鈕進(jìn)行安裝
Blueocean目前還不支持Git Parameter插件和Extended Choice Parameter插件,Git Parameter是通過Git Plugin讀取分支信息,我們這里使用Pipeline script而不是使用Pipeline script from SCM,是因?yàn)槲覀儾幌M褬?gòu)建信息放到代碼里,這樣做可以開發(fā)和部署分離。
2. 配置Kubernetes plugin插件,Jenkins --> 系統(tǒng)管理 --> 節(jié)點(diǎn)管理 --> Configure Clouds --> ?Add a new cloud -> Kubernetes
3. 增加 kubernetes 證書
cat ~/.kube/config
# 以下步驟暫不使用,將certificate-authority-data、client-certificate-data、client-key-data替換為~/.kube/config里面具體的值
#echo certificate-authority-data | base64 -d > ca.crt
#echo client-certificate-data | base64 -d > client.crt
#echo client-key-data | base64 -d > client.key
# 執(zhí)行以下命令,自己設(shè)置密碼
#openssl pkcs12 -export -out cert.pfx -inkey client.key -in client.crt -certfile ca.crt
系統(tǒng)管理–>憑據(jù)–>系統(tǒng)–>全局憑據(jù)
4. 添加訪問 Kubernetes 的憑據(jù)信息,這里填入上面登錄 Kubernetes Dashboard 所創(chuàng)建的 token 即可,添加完成之后選擇剛剛添加的憑據(jù),然后點(diǎn)擊連接測試,如果提示連接成功,那么說明我們的 Jenkins 可以連接 Kubernetes 了
5. jenkins 全局配置 jdk、git 和 maven
jenkinsci/blueocean 鏡像默認(rèn)安裝了 jdk 和 git,這里需要登錄容器找到路徑,然后配置進(jìn)去,通過命令進(jìn)入 jenkins 容器,并查看 JAVA_HOEM 和 git 路徑。
[root@localhost ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0520ebb9cc5d jenkinsci/blueocean "/sbin/tini -- /usr/…" 2 days ago Up 30 hours 50000/tcp, 0.0.0.0:18080->8080/tcp, :::18080->8080/tcp root-jenkins-1
[root@localhost ~]# docker exec -it 0520ebb9cc5d /bin/bash
bash-5.1# echo $JAVA_HOME
/opt/java/openjdk
bash-5.1# which git
/usr/bin/git
通過命令查詢可知,JAVA_HOME=/opt/java/openjdk ? ?GIT= /usr/bin/git , 在 Jenkins 全局工具配置中配置
Maven 可以在宿主機(jī)映射的/data/docker/ci/jenkins/home 中安裝,然后配置時(shí),配置容器路徑為/var/jenkins_home 下的 Maven 安裝路徑
在系統(tǒng)配置中設(shè)置 MAVEN_HOME 供 Pipeline script 調(diào)用,如果執(zhí)行腳本時(shí)提示沒有權(quán)限,那么在宿主 Maven 目錄的 bin 目錄下執(zhí)行 chmod 777 *
6. 為 k8s 新建 harbor-key,用于 k8s 拉取私服鏡像,配置在代碼的 k8s-deployment.yml 中使用。
kubectl create secret docker-registry harbor-key --docker-server=172.16.20.175 --docker-username='robot$gitegg' --docker-password='Jqazyv7vvZiL6TXuNcv7TrZeRdL8U9n3'
7. 新建 pipeline 流水線任務(wù)
8. 配置流水線任務(wù)參數(shù)
9. 配置 pipeline 發(fā)布腳本
在流水線下面選擇 Pipeline script
pipeline {
agent any
parameters {
gitParameter branchFilter: 'origin/(.*)', defaultValue: 'master', name: 'Branch', type: 'PT_BRANCH', description:'請選擇需要構(gòu)建的代碼分支'
choice(name: 'BaseImage', choices: ['openjdk:8-jdk-alpine'], description: '請選擇基礎(chǔ)運(yùn)行環(huán)境')
choice(name: 'Environment', choices: ['dev','test','prod'],description: '請選擇要發(fā)布的環(huán)境:dev開發(fā)環(huán)境、test測試環(huán)境、prod 生產(chǎn)環(huán)境')
extendedChoice(
defaultValue: 'gitegg-gateway,gitegg-oauth,gitegg-plugin/gitegg-code-generator,gitegg-service/gitegg-service-base,gitegg-service/gitegg-service-extension,gitegg-service/gitegg-service-system',
description: '請選擇需要構(gòu)建的微服務(wù)',
multiSelectDelimiter: ',',
name: 'ServicesBuild',
quoteValue: false,
saveJSONParameterToFile: false,
type: 'PT_CHECKBOX',
value:'gitegg-gateway,gitegg-oauth,gitegg-plugin/gitegg-code-generator,gitegg-service/gitegg-service-base,gitegg-service/gitegg-service-extension,gitegg-service/gitegg-service-system',
visibleItemCount: 6)
string(name: 'BuildParameter', defaultValue: 'none', description: '請輸入構(gòu)建參數(shù)')
}
environment {
PRO_NAME = "gitegg"
BuildParameter="${params.BuildParameter}"
ENV = "${params.Environment}"
BRANCH = "${params.Branch}"
ServicesBuild = "${params.ServicesBuild}"
BaseImage="${params.BaseImage}"
k8s_token = "7696144b-3b77-4588-beb0-db4d585f5c04"
}
stages {
stage('Clean workspace') {
steps {
deleteDir()
}
}
stage('Process parameters') {
steps {
script {
if("${params.ServicesBuild}".trim() != "") {
def ServicesBuildString = "${params.ServicesBuild}"
ServicesBuild = ServicesBuildString.split(",")
for (service in ServicesBuild) {
println "now got ${service}"
}
}
if("${params.BuildParameter}".trim() != "" && "${params.BuildParameter}".trim() != "none") {
BuildParameter = "${params.BuildParameter}"
}
else
{
BuildParameter = ""
}
}
}
}
stage('Pull SourceCode Platform') {
steps {
echo "${BRANCH}"
git branch: "${Branch}", credentialsId: 'gitlabTest', url: 'http://172.16.20.188:2080/root/gitegg-platform.git'
}
}
stage('Install Platform') {
steps{
echo "==============Start Platform Build=========="
sh "${MAVEN_HOME}/bin/mvn -DskipTests=true clean install ${BuildParameter}"
echo "==============End Platform Build=========="
}
}
stage('Pull SourceCode') {
steps {
echo "${BRANCH}"
git branch: "${Branch}", credentialsId: 'gitlabTest', url: 'http://172.16.20.188:2080/root/gitegg-cloud.git'
}
}
stage('Build') {
steps{
script {
echo "==============Start Cloud Parent Install=========="
sh "${MAVEN_HOME}/bin/mvn -DskipTests=true clean install -P${params.Environment} ${BuildParameter}"
echo "==============End Cloud Parent Install=========="
def workspace = pwd()
for (service in ServicesBuild) {
stage ('buildCloud${service}') {
echo "==============Start Cloud Build ${service}=========="
sh "cd ${workspace}/${service} && ${MAVEN_HOME}/bin/mvn -DskipTests=true clean package -P${params.Environment} ${BuildParameter} jib:build -Djib.httpTimeout=200000 -DsendCredentialsOverHttp=true -f pom.xml"
echo "==============End Cloud Build ${service}============"
}
}
}
}
}
stage('Sync to k8s') {
steps {
script {
echo "==============Start Sync to k8s=========="
def workspace = pwd()
mainpom = readMavenPom file: 'pom.xml'
profiles = mainpom.getProfiles()
def version = mainpom.getVersion()
def nacosAddr = ""
def nacosConfigPrefix = ""
def nacosConfigGroup = ""
def dockerHarborAddr = ""
def dockerHarborProject = ""
def dockerHarborUsername = ""
def dockerHarborPassword = ""
def serverPort = ""
def commonDeployment = "${workspace}/k8s-deployment.yaml"
for(profile in profiles)
{
// 獲取對應(yīng)配置
if (profile.getId() == "${params.Environment}")
{
nacosAddr = profile.getProperties().getProperty("nacos.addr")
nacosConfigPrefix = profile.getProperties().getProperty("nacos.config.prefix")
nacosConfigGroup = profile.getProperties().getProperty("nacos.config.group")
dockerHarborAddr = profile.getProperties().getProperty("docker.harbor.addr")
dockerHarborProject = profile.getProperties().getProperty("docker.harbor.project")
dockerHarborUsername = profile.getProperties().getProperty("docker.harbor.username")
dockerHarborPassword = profile.getProperties().getProperty("docker.harbor.password")
}
}
for (service in ServicesBuild) {
stage ('Sync${service}ToK8s') {
echo "==============Start Sync ${service} to k8s=========="
dir("${workspace}/${service}") {
pom = readMavenPom file: 'pom.xml'
echo "group: artifactId: ${pom.artifactId}"
def deployYaml = "k8s-deployment-${pom.artifactId}.yaml"
yaml = readYaml file : './src/main/resources/bootstrap.yml'
serverPort = "${yaml.server.port}"
if(fileExists("${workspace}/${service}/k8s-deployment.yaml")){
commonDeployment = "${workspace}/${service}/k8s-deployment.yaml"
}
else
{
commonDeployment = "${workspace}/k8s-deployment.yaml"
}
script {
sh "sed 's#{APP_NAME}#${pom.artifactId}#g;s#{IMAGE_URL}#${dockerHarborAddr}#g;s#{IMAGE_PROGECT}#${PRO_NAME}#g;s#{IMAGE_TAG}#${version}#g;s#{APP_PORT}#${serverPort}#g;s#{SPRING_PROFILE}#${params.Environment}#g' ${commonDeployment} > ${deployYaml}"
kubernetesDeploy configs: "${deployYaml}", kubeconfigId: "${k8s_token}"
}
}
echo "==============End Sync ${service} to k8s=========="
}
}
echo "==============End Sync to k8s=========="
}
}
}
}
}
常見問題:
1. Pipeline Utility Steps 第一次執(zhí)行會報(bào)錯(cuò) Scripts not permitted to use method 或者 Scripts not permitted to use staticMethod org.codehaus.groovy.runtime.DefaultGroovyMethods getProperties java.lang.Object
解決:系統(tǒng)管理–>In-process Script Approval->點(diǎn)擊 Approval
2. 通過 NFS 服務(wù)將所有容器的日志統(tǒng)一存放在 NFS 的服務(wù)端
3. Kubernetes Continuous Deploy,使用 1.0.0 版本,否則報(bào)錯(cuò),不兼容
4. 解決 docker 注冊到內(nèi)網(wǎng)問題
spring:
cloud:
inetutils:
ignored-interfaces: docker0
5. 配置 ipvs 模式,kube-proxy 監(jiān)控 Pod 的變化并創(chuàng)建相應(yīng)的 ipvs 規(guī)則。ipvs 相對 iptables 轉(zhuǎn)發(fā)效率更高。除此以外,ipvs 支持更多的 LB 算法。
kubectl edit cm kube-proxy -n kube-system
修改 mode: “ipvs”
重新加載 kube-proxy 配置文件
kubectl delete pod -l k8s-app=kube-proxy -n kube-system
查看 ipvs 規(guī)則
ipvsadm -Ln
6. k8s 集群內(nèi)部訪問外部服務(wù),nacos,redis 等
- a、內(nèi)外互通模式,在部署的服務(wù)設(shè)置 hostNetwork: true
spec:
hostNetwork: true
- b、Endpoints 模式
kind: Endpoints
apiVersion: v1
metadata:
name: nacos
namespace: default
subsets:
- addresses:
- ip: 172.16.20.188
ports:
- port: 8848
apiVersion: v1
kind: Service
metadata:
name: nacos
namespace: default
spec:
type: ClusterIP
ports:
- port: 8848
targetPort: 8848
protocol: TCP
- c、service 的 type: ExternalName 模式,“ExternalName” 使用 CNAME 重定向,因此無法執(zhí)行端口重映射,域名使用
EndPoints和type: ExternalName
以上外部新建 yaml,不要用內(nèi)部的,這些需要在環(huán)境設(shè)置時(shí)配置好。文章來源:http://www.zghlxwxcb.cn/news/detail-618419.html
7. k8s 常用命令
查看 pod: ? kubectl get pods
查看 service: kubectl get svc
查看 endpoints: kubectl get endpoints
安裝: kubectl apply -f XXX.yaml
刪除:kubectl delete -f xxx.yaml
刪除 pod: kubectl delete pod podName
刪除 service: kubectl delete service serviceName
進(jìn)入容器: kubectl exec -it podsNamexxxxxx -n ?default – /bin/sh文章來源地址http://www.zghlxwxcb.cn/news/detail-618419.html
到了這里,關(guān)于【K8S專題】八、Jenkins 自動打包部署配置的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!