柚子快報激活碼778899分享:運維 devops(后端)
柚子快報激活碼778899分享:運維 devops(后端)
1.前言
該devpos架構(gòu)為gitlab+jenkins+harbor+k8s,項目是java項目,流程為從gitlab拉取項目代碼到j(luò)enkins,jenkins通過maven將項目代碼打成jar包,通過dockerfile構(gòu)建jdk環(huán)境的鏡像并把jar包放到鏡像中啟動,構(gòu)建好的鏡像通過docker上傳到harbor鏡像倉庫中,最后k8s通過更新鏡像的方式去發(fā)布新的服務(wù),此套流程通過jenkins的pipeline實現(xiàn),其中還涉及多分支、回滾操作
2.部署環(huán)境
gitlab部署參考:gitlab部署_Apex Predator的博客-CSDN博客
jenkins部署參考:jenkins部署_Apex Predator的博客-CSDN博客
harbor部署參考:k8s harbor鏡像倉庫搭建_k8s鏡像倉庫_Apex Predator的博客-CSDN博客
k8s部署參考:kubeadm部署k8s 1.26.0版本高可用集群_Apex Predator的博客-CSDN博客
3.配置環(huán)境
jenkins主機配置
在部署jnekins環(huán)境的時候已經(jīng)安裝了jdk、maven、git環(huán)境,現(xiàn)在還需要在安裝docker、kubectl,docker用于構(gòu)建鏡像和推送鏡像到harbor倉庫,kubectl用于操作k8s發(fā)布新版本
docker部署參考:部署docker-ce_Apex Predator的博客-CSDN博客
部署完成后需要配置一下docker的daemon.json文件(因為是私有倉庫,docker是不允許拉取不安全倉庫的鏡像)?
vi /etc/docker/daemon.json
{
"registry-mirrors": ["https://sudzwtcw.mirror.aliyuncs.com"],
"insecure-registries": ["harbor.apex.com"] #配置該項,使得docker允許訪問不安全的鏡像倉庫
}
重啟docker服務(wù)
systemctl restart docker?
部署kubectl
配置阿里云的k8s yum源
cat > /etc/yum.repos.d/kubernetes.repo << EOF
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=0
repo_gpgcheck=0
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF
安裝kubectl
yum -y install kubectl-1.26.0
在jenkins上引用安裝的環(huán)境
?
在jenkins中安裝以下插件
Git
Git plugin
Git Parameter
GitLab
Credentials
Credentials Binding
CloudBees Docker Build and Publish plugin
Build With Parameters
Dynamic Extended Choice Parameter Plug-In
Dynamic Parameter Plug-in
Extended Choice Parameter
List Git Branches Parameter
Pipeline
Pipeline: Declarative
kubernetes
Kubernetes plugin
Kubernetes CLI Plugin
Kubernetes Credentials Plugin
在jenkins上配置ssh密鑰(一路回車即可)
ssh-keygen
查看公鑰并拷貝到gitlba上
cat ~/.ssh/id_rsa.pub
?將以上公鑰填入以下gitlab配置中即可?
配置jenkins?Credentials
創(chuàng)建gitlab憑據(jù)
查看jenkins的私鑰
cat ~/.ssh/id_rsa? ? ? #復(fù)制輸出的所有內(nèi)容
?
?
?
創(chuàng)建harbor憑據(jù)
創(chuàng)建k8s憑據(jù)
先在k8s下載密鑰文件(就是集群的配置文件,里面包含有密鑰和請求集群的接口等配置)
ls .kube/config
sz .kube/config?
harbor配置
配置harbor倉庫項目信息
分別創(chuàng)建兩個項目,一個存放基礎(chǔ)鏡像叫base_image,一個存放后端服務(wù)鏡像叫jdk
gitlab配置
創(chuàng)建項目
?創(chuàng)建完成后上傳項目代碼
k8s集群配置?
?在k8s的node節(jié)點上配置docker的daemon.json文件
vi /etc/docker/daemon.json
{
"registry-mirrors": ["https://sudzwtcw.mirror.aliyuncs.com"],
"insecure-registries": ["harbor.apex.com"], #配置該項,使得docker允許訪問不安全的鏡像倉庫
"exec-opts": ["native.cgroupdriver=systemd"]
}
重啟docker服務(wù)
systemctl restart docker
4.構(gòu)建發(fā)布
使用jenkins的pipeline和webhook實現(xiàn)ci/cd自動化發(fā)布
jenkins配置
新建流水線項目
?配置Choice Parameter,直接在Jenkins file中寫parameter不手動配置parameter的話,第一次執(zhí)行會失敗,執(zhí)行完后會自動生成parameter,所以還是手動也配置一下
?
?配置webhook tigger用于觸發(fā)自動構(gòu)建
?
?
?配置流水線腳本
選擇pipeline script模式
填入以下腳本
pipeline { #配置pipeline
agent any #客戶端配置,jenkins可以使用k8s作為agent環(huán)境去發(fā)布,這里使用any為任意環(huán)境
environment { #配置環(huán)境變量參數(shù),用來給下面調(diào)用
registry = "harbor.apex.com" #配置harbor倉庫地址
harbor_auth = "a1e2c627-dc62-4599-a035-8e98d74665ab" #配置harbor credentials憑據(jù)id
project = "jdk" #配置harbor倉庫鏡像項目
app_name = "k8s-cs" #配置k8s的pod名稱
namespace = "k8s-cs" #配置k8s的命名空間
k8s_auth = "k8s-kubeconfig" #配置k8s credentials憑據(jù)id
}
parameters { #配置parameters功能
gitParameter(branch: '', branchFilter: '.*', defaultValue: '', description: 'Branch for build and deploy', name: 'branch', quickFilterEnabled: false, selectedValue: 'NONE', sortMode: 'NONE', tagFilter: '*', type: 'PT_BRANCH') #配置分支選擇的gitParameter,用于回滾和手動發(fā)布的分支選擇,此處默認(rèn)為空值,避免下面階段使用branch變量判斷出現(xiàn)問題
choice(choices: ['deploy', 'rollback'], description: '''deploy ---部署 rollback ---回滾''', name: 'status') #配置發(fā)布回滾選擇的choice,用于選擇發(fā)布還是回滾,此處默認(rèn)時deploy發(fā)布
}
stages { #配置構(gòu)建的每個階段
stage('Checkout code') { #配置從gitlab拉取代碼
parallel { #配置以下兩個階段的操作并行執(zhí)行
stage('webhook tigger') { #配置自動觸發(fā)執(zhí)行的操作
when { #使用when判斷env.gitlabBranch的值是否為空,使用webhook自動構(gòu)建,是通過env.gitlabBranch變量來賦予分支值,判斷該值是否為空,就能判斷是通過webhook構(gòu)建還是手動構(gòu)建的
expression { params.status == 'deploy' && env.gitlabBranch != null }
} #params的值用來判斷,是否執(zhí)行的是發(fā)布操作,如果是發(fā)布操作才執(zhí)行該操作,使用&&是需要兩個條件都為true才執(zhí)行
steps { #以上判斷通過后執(zhí)行從gitlab對應(yīng)的分支拉取代碼的操作
checkout([$class: 'GitSCM', branches: [[name: '${env.gitlabBranch}']], extensions: [], userRemoteConfigs: [[credentialsId: 'gitlab_auth', url: 'git@10.1.60.114:gitlab-instance-c484dcfc/java-project.git']]]) #可以看到branch使用的是env.gitlabBranch這個變量,因為webhook自動構(gòu)建是將分支的值賦予到這個變量中,credentialsId就配置gitlab的credentials憑據(jù)id
sh "git branch" #這里是測試是否能獲取到分支的值
echo "Current branch: ${env.gitlabBranch}" #這里是輸出分支的值
script { #提取gitlab的項目id,用來制作鏡像tag
commit_id = sh(returnStdout: true, script: "git log -n 1 --pretty=format:'%h'").trim()
tag = BUILD_TAG + '-' + commit_id #使用jenkins的構(gòu)建標(biāo)簽和gitlab的項目id作為鏡像標(biāo)簽的tag
}
}
}
stage('jenkins scm') { #此處就是判斷是否用的手動構(gòu)建
when { #使用when判斷env.gitlabBranch是否等于空值,是空值就證明是通過手動構(gòu)建的
expression { params.status == 'deploy' && env.gitlabBranch == null }
} #params的值用來判斷,是否執(zhí)行的是發(fā)布操作
steps { #執(zhí)行拉取gitlab代碼操作
checkout([$class: 'GitSCM', branches: [[name: '${branch}']], extensions: [], userRemoteConfigs: [[credentialsId: 'gitlab_auth', url: 'git@10.1.60.114:gitlab-instance-c484dcfc/java-project.git']]]) #這里和上面自動構(gòu)建的命令沒有什么區(qū)別就除了branches使用branch作為變量,因為我們上面配置parameters,手動構(gòu)建需要選擇名為branch的choice去選擇分支,所以我們就通過該變量獲取到選擇的分支名稱
sh "git branch"
echo "Current branch: ${branch}"
script {
commit_id = sh(returnStdout: true, script: "git log -n 1 --pretty=format:'%h'").trim()
tag = BUILD_TAG + '-' + commit_id
}
}
}
} #到這里parallel并行操作就結(jié)束了
} #到這里上面的拉取代碼操作就結(jié)束了
stage('Build jar') { #接下來就是編譯代碼打包的操作步驟
when { #使用when判斷是否是發(fā)布操作,回滾是不用執(zhí)行這個階段的,上面的拉代碼操作也是
expression { params.status == 'deploy' }
}
steps { #when判斷通過后執(zhí)行以下命令打包,打包命令可能會不一樣,可以咨詢一下開發(fā)
sh "mvn clean install -DskipTests" #編譯打包命令
sh "ls target/" #查看是否有打出來jar包
}
}
stage('docker image build and push') { #構(gòu)建鏡像和推送鏡像到harbor倉庫步驟
when {
expression { params.status == 'deploy' }
}
steps {
withCredentials([usernamePassword(credentialsId: "${harbor_auth}", passwordVariable: 'password', usernameVariable: 'username')]) { #使用harbor的credentials憑據(jù),因為推鏡像和拉基礎(chǔ)鏡像都是需要訪問harbor倉庫的
sh "docker build -t ${registry}/${project}/${app_name}:${tag} ."
sh "docker push ${registry}/${project}/${app_name}:${tag}"
} #可能生產(chǎn)、測試環(huán)境打包的鏡像名稱要求不一樣,這時就需要跟上面一樣使用when去判斷是哪個環(huán)境構(gòu)建鏡像
}
}
stage('k8s update iamge version') { #發(fā)布版本操作
parallel { #以上有講解此參數(shù)
stage ('to apex') {
when { #判斷分支,決定發(fā)布到哪個環(huán)境中
expression { params.status == 'deploy' && ( env.gitlabBranch == 'apex' || params.branch == 'apex' ) }
} #后面用了一個|| 或的判斷,即兩個獲取分支的變量只要有一個成立即可,主要是自動構(gòu)建和手動構(gòu)建的分支變量不一樣,所以必須得使用兩個分支變量判斷
steps { #配置k8s集群得credentials憑據(jù),通過憑據(jù)調(diào)用k8s集群的apiserver
withCredentials([file(credentialsId: "${k8s_auth}", variable: 'KUBECONFIG')]) {
sh "kubectl --kubeconfig ${KUBECONFIG} set image deployment -l app=${app_name} ${app_name}=${registry}/${project}/${app_name}:${tag} -n ${namespace} --record"
} #使用kubectl命令指定k8s集群的配置文件執(zhí)行更新鏡像命令的操作,更新鏡像操作即發(fā)布版本,并記錄該操作用于回滾
}
}
stage('to master') {
when { #判斷分支,決定發(fā)布到哪個環(huán)境中
expression { params.status == 'deploy' && ( env.gitlabBranch == 'master' || params.branch == 'master' ) }
}
steps {
withCredentials([file(credentialsId: "${k8s_auth}", variable: 'KUBECONFIG')]) {
sh "kubectl --kubeconfig ${KUBECONFIG} get pod -n ${namespace}"
sh "echo ${params.branch}"
sh "echo ${env.gitlabBranch}"
} #以上命令是測試用的,要是發(fā)版命令改為以上的set命令即可
}
}
}
}
stage('rollback version') { #回滾操作,當(dāng)發(fā)布的版本有問題時,會需要使用到回滾操作
parallel {
stage('to apex') {
when { #判斷params.status變量是否為rollback,且判斷分支,因為回滾操作都是手動操作的所以使用branch變量判斷分支即可
expression { params.status == 'rollback' && params.branch == 'apex' }
}
steps { #此處也是配置k8s集群的credentials憑據(jù)
withCredentials([file(credentialsId: "${k8s_auth}", variable: 'KUBECONFIG')]) {
sh "kubectl --kubeconfig ${KUBECONFIG} rollout undo deployment ${app_name} -n ${namespace}"
} #使用rollout命令并指定deployment回滾版本
}
}
stage('to master') {
when {
expression { params.status == 'rollback' && params.branch == 'master' }
}
steps {
withCredentials([file(credentialsId: "${k8s_auth}", variable: 'KUBECONFIG')]) {
sh "kubectl --kubeconfig ${KUBECONFIG} get deployment ${app_name} -n ${namespace}"
} #此處也是測試命令,回滾命令參照上面寫即可
}
}
}
}
}
}
制作基礎(chǔ)鏡像(打包的時候直接使用基礎(chǔ)鏡像會更快)
vim dockerfile
FROM alpine:latest #拉取系統(tǒng)鏡像
ENV TZ="Asia/Shanghai" #這個環(huán)境變量用于下面配置時區(qū)
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories \ #配置源
&& apk add --upgrade --no-cache openjdk8 tzdata ttf-dejavu fontconfig \ #安裝jdk環(huán)境、字體等工具
&& cp /usr/share/zoneinfo/${TZ} /etc/localtime \ #配置時區(qū)
&& echo ${TZ} > /etc/timezone
構(gòu)建鏡像
docker build -t harbor.apex.com/base_image/jdk8_image:latest .
上傳鏡像
docker push??harbor.apex.com/base_image/jdk8_image:latest
gitlab配置
在項目代碼倉庫中創(chuàng)建dockerfile用于構(gòu)建發(fā)布鏡像
?
dockerfile內(nèi)容如下
FROM harbor.apex.com/base_image/jdk8_image:latest #使用harbor倉庫中的基礎(chǔ)鏡像
ENV JVM_OPTS="-Xms512m -Xms512m" #配置關(guān)于java的環(huán)境變量
ENV HEAP_DUMP_OPTS="-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/opt/java_jar/log"
RUN mkdir -p /opt/java_jar/log #創(chuàng)建存放jar包目錄還有日志目錄
WORKDIR /opt/java_jar/ #設(shè)置存放jar包目錄為工作目錄,即相當(dāng)于cd到這個目錄上
COPY ./target/*.jar ./ #拷貝jar包到鏡像中,target目錄是在jenkins上打包后,jar包的生成目錄
EXPOSE 8761 #配置需要暴露的端口
ENTRYPOINT java ${JVM_POST} ${HEAP_DUMP_OPTS} -jar *.jar #配置啟動jar包服務(wù)
配置webhook用于觸發(fā)jenkins自動化構(gòu)建
?參考:gitlab配置webhook_Apex Predator的博客-CSDN博客
k8s集群?配置(在master節(jié)點執(zhí)行)
創(chuàng)建namespace
kubectl create namespace k8s-cs
創(chuàng)建secret用于拉取harbor倉庫的鏡像使用
kubectl create secret docker-registry harbor-secret --namespace=k8s-cs --docker-server=https://harbor.apex.com --docker-username=admin --docker-password=Harbor12345
查看secret
kubectl get secret -n k8s-cs
?
創(chuàng)建yaml
?vim k8s-cs.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: k8s-cs
name: k8s-cs
namespace: k8s-cs
spec:
replicas: 5
progressDeadlineSeconds: 600
minReadySeconds: 10
strategy: #配置滾動更新策略
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
type: RollingUpdate
selector:
matchLabels:
app: k8s-cs
template:
metadata:
labels:
app: k8s-cs
spec:
containers:
- name: k8s-cs
image: harbor.apex.com/jdk/k8s-cs #填寫harbor倉庫的鏡像地址
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8761
readinessProbe: #配置就緒探針
httpGet:
path: /
port: 8761
scheme: HTTP
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 2
successThreshold: 1
failureThreshold: 2
livenessProbe: #配置存活探針
tcpSocket:
port: 8761
initialDelaySeconds: 30
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 2
failureThreshold: 2
imagePullSecrets: #配置拉取鏡像使用的secret
- name: harbor-secret
restartPolicy: Always
---
apiVersion: v1
kind: Service #配置service映射端口
metadata:
name: k8s-cs
namespace: k8s-cs
spec:
selector:
app: k8s-cs
type: NodePort
clusterIP:
ports:
- port: 8761
targetPort: 8761
nodePort: 30002
protocol: TCP
執(zhí)行yaml創(chuàng)建pod
kubectl apply -f k8s-cs.yaml
5.測試發(fā)布、回滾
手動構(gòu)建
?
?
回滾?
?
自動化構(gòu)建
更改一下分支合并到master看看會不會觸發(fā)自動化構(gòu)建
更改的過程我就省略了,更改好之后創(chuàng)建合并請求
?批準(zhǔn)且合并后觸發(fā)Jenkins構(gòu)建
?
?這個也是多分支的發(fā)布,合并其它分支也是可以觸發(fā),我就不演示了
6.補充
pipeline有兩種模式,還有一種是pipeline script from scm,就是在流水線配置界面就編輯好從gitlab倉庫拉代碼的信息,并且把jenkinsfile放到gitlab的倉庫中,跟著代碼一起拉下來,接下來也說一下這種方式的使用
創(chuàng)建pipeline項目,這里就不貼圖了
配置git parameter,用來選擇發(fā)布時的分支
?
?
?
在gitlab的項目上創(chuàng)建jenkinsfile文件
?
?
jenkinsfile腳本如下
pipeline {
agent any
environment {
registry = "harbor.apex.com"
harbor_auth = "a1e2c627-dc62-4599-a035-8e98d74665ab"
project = "jdk"
app_name = "k8s-cs"
namespace = "k8s-cs"
image_url = "${registry}/${project}/${app_name}:${tag}"
k8s_auth = "k8s-kubeconfig"
k8s_name = "kubernetes"
} #這里和之前的pipeline不同,因為配置了scm后在jenkinsfile中就不需要再配置拉取代碼的步驟了,其它的配置都是一樣的,不過我這是一個簡化版的適合單分支
stages {
stage('Build jar') {
steps {
sh "mvn clean install -DskipTests"
sh "ls target/"
}
}
stage('docker image build and push') {
steps {
withCredentials([usernamePassword(credentialsId: "${harbor_auth}", passwordVariable: 'password', usernameVariable: 'username')]) {
sh "docker build -t ${image_url} ."
sh "docker push ${image_url}"
}
}
}
stage('push yaml to k8s') {
steps {
withCredentials([file(credentialsId: "${k8s_auth}", variable: 'KUBECONFIG')]) {
sh "kubectl --kubeconfig ${KUBECONFIG} set image deployment -l app=${app_name} ${app_name}=${image_url} -n ${namespace} --record"
}
}
}
}
}
去執(zhí)行構(gòu)建就可以了,這里是jenkins項目通過scm的gitlab拉取項目代碼,拉取了項目后再去執(zhí)行流水線的jenkinsfile腳本,所以jenkinsfile里是不需要配置拉代碼這個動作的
以下再 講解一下通過jenkins agent來執(zhí)行流水線,這里講訴使用k8s集群的pod作為jenkins agent去發(fā)布,大概流程就是使用k8s插件連接k8s集群,調(diào)用k8s的api server去創(chuàng)建jenkins agent,流水線的所有步驟都在jenkins agent上執(zhí)行,期間還需要配置所有需要用的環(huán)境的pod,這里就不詳細(xì)介紹,就說一下踩到的坑
jenkins agent使用的jnlp鏡像的jdk環(huán)境需要和jenkins的jdk環(huán)境一致,不然是沒辦法連接的
使用jenkins agent除了要打開jenkins 50000端口與Jenkins agent通信外,還需要配置Git Host Key Verification Configuration項,不然的話在從gitlab拉代碼的適合會一直報錯
?
里面填寫的密鑰在 known_hosts文件中,配置的是gitlab主機的密鑰 ,一定要配置此項不然pod拉不到gitlab的項目代碼
cat /root/.ssh/known_hosts?
?還有就是使用docker鏡像,鏡像里的docker是沒辦法配置daemon.json的,所以訪問不到harbor的私有倉庫,除非harbor使用的是公有證書和公有域名
柚子快報激活碼778899分享:運維 devops(后端)
相關(guān)文章
本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點和立場。
轉(zhuǎn)載請注明,如有侵權(quán),聯(lián)系刪除。