目前,在企业中部署应用一般就是普通虚拟机部署和k8s容器化部署两种方式。这篇文章主要用来介绍这两种场景下分别怎么部署。
普通虚拟机部署
普通虚拟机部署通常有两种方式,分别是:
- 自由风格方式部署
- pipeline流水线方式部署
- maven方式部署
安装 Jenkins 插件
Publish Over SSHPublish Over SSH
Jenkins->Manage Jenkins->Manage Plugins,点击 Available
Publish Over SSH
Publish Over SSH
创建流水线
pipeline{
agent any
stages{
stage("拉取代码"){
steps {
checkout([$class: 'GitSCM', branches: [[name: '*/main']], extensions: [], userRemoteConfigs: [[credentialsId: '68a87abf-6af7-4e60-94dd-cf45c280c247', url: 'git@gitlab.abck8s.com:xiaoyangaijishu/html.git']]])
}
}
stage("SonarQube代码审查"){
steps {
script {
scannerHome = tool 'sonarqube-scanner'
}
withSonarQubeEnv('sonarqube8.9.8') {
sh "${scannerHome}/bin/sonar-scanner"
}
}
}
stage("判断代码扫描状态"){
steps {
script {
timeout(5) {
qg = waitForQualityGate()
if (qg.status != 'OK') {
error "扫描失败,状态错误: ${qg.status}"
} else {
echo "扫描成功"
}
}
}
}
}
}
}
pipeline{
agent any
stages{
stage("拉取代码"){
steps {
checkout([$class: 'GitSCM', branches: [[name: '*/main']], extensions: [], userRemoteConfigs: [[credentialsId: '68a87abf-6af7-4e60-94dd-cf45c280c247', url: 'git@gitlab.abck8s.com:xiaoyangaijishu/html.git']]])
}
}
stage("SonarQube代码审查"){
steps {
script {
scannerHome = tool 'sonarqube-scanner'
}
withSonarQubeEnv('sonarqube8.9.8') {
sh "${scannerHome}/bin/sonar-scanner"
}
}
}
stage("判断代码扫描状态"){
steps {
script {
timeout(5) {
qg = waitForQualityGate()
if (qg.status != 'OK') {
error "扫描失败,状态错误: ${qg.status}"
} else {
echo "扫描成功"
}
}
}
}
}
stage("部署代码"){
steps {
sshPublisher(
publishers: [
sshPublisherDesc(
configName: 'web01',
transfers: [
sshTransfer(
cleanRemote: false,
excludes: '',
execCommand: '''#!/bin/bash''',
execTimeout: 120000,
flatten: false,
makeEmptyDirs: false,
noDefaultExcludes: false,
patternSeparator: '[, ]+',
remoteDirectory: '',
remoteDirectorySDF: false,
removePrefix: '',
sourceFiles: '**/**'
)
],
usePromotionTimestamp: false,
useWorkspaceInPromotion: false,
verbose: false
),
sshPublisherDesc(
configName: 'web02',
transfers: [
sshTransfer(
cleanRemote: false,
excludes: '',
execCommand: '#!/bin/bash',
execTimeout: 120000,
flatten: false,
makeEmptyDirs: false,
noDefaultExcludes: false,
patternSeparator: '[, ]+',
remoteDirectory: '',
remoteDirectorySDF: false,
removePrefix: '',
sourceFiles: '**/**'
)
],
usePromotionTimestamp: false,
useWorkspaceInPromotion: false,
verbose: false
)
]
)
}
}
}
}
部署成功。
部署结束发送邮件
post {
always {
emailext (
body: """
<!DOCTYPE html><html><head><meta charset="UTF-8"><title>${PROJECT_NAME}-第${BUILD_NUMBER}次构建日志</title></head><body leftmargin="8" marginwidth="0" topmargin="8" marginheight="4"
offset="0"><table width="95%" cellpadding="0" cellspacing="0" style="font-size: 11pt; font-family: Tahoma, Arial, Helvetica, sans-serif"><tr>(本邮件由系统自动发出,无需回复!)<br/>各位好,以下是${PROJECT_NAME}项目构建信息<br/><td><font color="#CC0000">构建结果 - ${BUILD_STATUS}</font></td></tr><tr><td><br/><b><font color="#0B610B">构建信息 - ${BUILD_STATUS}</font></b><hr size="2" width="100%" align="center" /></td></tr><tr><td><ul><li>项目名称:${PROJECT_NAME}</li><li>构建编号:第${BUILD_NUMBER}次构建</li><li>构建版本:2021.1.0.0</li><li>触发原因:${CAUSE}</li><li>构建状态:${BUILD_STATUS}</li><li>构建日志:<a href="${BUILD_URL}console">${BUILD_URL}console</a></li><li>构建地址:<a href="${BUILD_URL}">${BUILD_URL}</a></li><li>工作目录:<a href="${PROJECT_URL}ws">${PROJECT_URL}ws</a></li><li>项目地址:<a href="${PROJECT_URL}">${PROJECT_URL}</a></li><li><a href="http://1xx.1xx.3.xx:81xx/plateform-backend/report/interfaceReport/xxx/${BUILD_TIMESTAMP}/index.html" >查看测试报告</a></li></ul><h4><font color="#0B610B">测试结果</font></h4><hr size="2" width="100%" /><div><hr size="2" width="100%" />
$FAILED_TESTS<br/><h4><font color="#0B610B">变更记录</font></h4><hr size="2" width="100%" />变更明细:<a href="${PROJECT_URL}changes">${PROJECT_URL}changes</a><br/></td></tr></table></body></html>
""",
mimeType: 'text/html',
subject: '自动化构建报告:$PROJECT_NAME - Build # $BUILD_NUMBER - $BUILD_STATUS!',
to: 'chenyangqit@163.com'
)
}
}
K8S容器化部署
K8S容器化部署就是说将应用部署到容器中。
安装 k8s 插件
Jenkins 连接 K8S
最近我们构建和部署服务的方式与原来相比简直就是突飞猛进,像那种笨拙的、单一的、用于构建单体式应用程序的方式已经是过去式了。现在的应用为了提供更好的拓展性和可维护性,都会去拆解成各种相互依赖小、解耦性强的微服务,这些服务有各自的依赖和进度。这跟我们的Kubernetes不谋而合。
使用Jenkins链接K8S需要创建一些秘钥。
第一步:创建admin-csr.json
cat > admin-csr.json << EOF
{
"CN":"admin",
"key":{
"algo":"rsa",
"size":2048
},
"names":[
{
"C":"CN",
"L":"BeiJing",
"ST":"BeiJing",
"O":"system:masters",
"OU":"System"
}
]
}
EOF
第二步:创建证书和私钥
cfssljson:https://github.com/cloudflare/cfssl/releases/download/v1.6.1/cfssljson_1.6.1_linux_amd64
cfssl:https://github.com/cloudflare/cfssl/releases/download/v1.6.1/cfssl_1.6.1_linux_amd64
cfssl gencert -ca=/etc/kubernetes/pki/ca.crt -ca-key=/etc/kubernetes/pki/ca.key --profile=kubernetes admin-csr.json | cfssljson -bare admin
第三步:配置证书
openssl pkcs12 -export -out ./jenkins-admin.pfx -inkey ./admin-key.pem -in ./admin.pem -passout pass:123456
第四步:将证书私钥填写至Jenkins
cat /etc/kubernetes/pki/ca.crt
第五步:上传证书并输入密码
Jenkins 连接 k8s
测试部署
使用 Jenkins 打包镜像部署到 k8s。
注意:配置清单中的变量居多,小心配置。
pipeline {
agent {
kubernetes {
cloud "${KUBERNETES_NAME}"
slaveConnectTimeout 1200
yaml '''
apiVersion: v1
kind: Pod
spec:
containers:
- name: jnlp
image: jenkins/inbound-agent:4.7-1-jdk11
args: [\'$(JENKINS_SECRET)\', \'$(JENKINS_NAME)\']
imagePullPolicy: IfNotPresent
volumeMounts:
- mountPath: "/etc/localtime"
name: "volume-2"
readOnly: false
- name: docker
image: docker:19.03.15-git
imagePullPolicy: IfNotPresent
tty: true
volumeMounts:
- mountPath: "/etc/localtime"
name: "volume-2"
readOnly: false
- mountPath: "/var/run/docker.sock"
name: "volume-docker"
readOnly: false
- mountPath: "/etc/hosts"
name: "volume-hosts"
readOnly: false
- name: kubectl
image: registry.cn-beijing.aliyuncs.com/citools/kubectl:1.17.4
imagePullPolicy: IfNotPresent
tty: true
command:
- "cat"
volumeMounts:
- mountPath: "/etc/localtime"
name: "volume-2"
readOnly: false
- mountPath: "/var/run/docker.sock"
name: "volume-docker"
readOnly: false
- mountPath: "/root/.kube"
name: "kubeconfig"
readOnly: false
- mountPath: "/.kube"
name: "kubeconfig"
readOnly: false
- name: maven
image: maven:3.6.3-openjdk-8
tty: true
command:
- "cat"
volumeMounts:
- mountPath: "/etc/localtime"
name: "volume-2"
readOnly: false
- mountPath: "/root/.m2/repository"
name: "volume-maven-repo"
readOnly: false
env:
- name: "LANGUAGE"
value: "en_US:en"
- name: "LC_ALL"
value: "en_US.UTF-8"
- name: "LANG"
value: "en_US.UTF-8"
- name: sonarscanner
image: emeraldsquad/sonar-scanner:2.2.0
tty: true
command:
- "cat"
volumeMounts:
- mountPath: "/etc/localtime"
name: "volume-2"
readOnly: false
- mountPath: "/root/.m2/repository"
name: "volume-maven-repo"
readOnly: false
- mountPath: "/etc/hosts"
name: "volume-hosts"
readOnly: false
env:
- name: "LANGUAGE"
value: "en_US:en"
- name: "LC_ALL"
value: "en_US.UTF-8"
- name: "LANG"
value: "en_US.UTF-8"
volumes:
- name: volume-maven-repo
emptyDir: {}
- name: volume-2
hostPath:
path: "/usr/share/zoneinfo/Asia/Shanghai"
- name: kubeconfig
secret:
secretName: kubeconfig
items:
- key: config
path: config
- name: volume-docker
hostPath:
path: "/var/run/docker.sock"
- name: volume-hosts
hostPath:
path: /etc/hosts
'''
}
}
stages {
stage('源代码管理') {
parallel {
stage('拉取代码') {
steps {
git(url: "${GIT_REPOSITORY_URL}", branch: "master", changelog: true, credentialsId: "${CREDENTIALS_ID}")
}
}
stage('系统检查及初始化') {
steps {
sh """
echo "Check Sysyem Env"
"""
}
}
}
}
stage('代码处理') {
steps {
sh """
git checkout $GIT_TAG
"""
}
}
stage("SonarQube代码审查"){
steps {
container(name: 'sonarscanner') {
script {
scannerHome = tool 'sonarqube-scanner'
}
withSonarQubeEnv('sonarqube8.9.8') {
sh "${scannerHome}/bin/sonar-scanner"
}
}
}
}
stage("判断代码扫描状态"){
steps {
script {
timeout(5) {
qg = waitForQualityGate()
if (qg.status != 'OK') {
error "扫描失败,状态错误: ${qg.status}"
} else {
echo "扫描成功"
}
}
}
}
}
stage('编译及构建') {
parallel {
stage('初始化操作系统及kubernetes环境') {
steps {
script {
CommitID = sh(returnStdout: true, script: "git log -n 1 --pretty=format:'%h'").trim()
CommitMessage = sh(returnStdout: true, script: "git log -1 --pretty=format:'%h : %an %s'").trim()
def curDate = sh(script: "date '+%Y%m%d-%H%M%S'", returnStdout: true).trim()
TAG = curDate[0..14] + "-" + CommitID + "-master"
}
}
}
}
}
stage('构建镜像及检查kubernetes环境') {
parallel {
stage('构建镜像') {
steps {
withCredentials([usernamePassword(credentialsId: "${DOCKER_REPOSITORY_CREDENTIAL_ID}", passwordVariable: "Password", usernameVariable: "Username")]) {
container(name: 'docker') {
sh """
docker build -t ${HARBOR_HOST}/${NAMESPACE_NAME}/${REPOSITORY_NAME}:${TAG} .
docker login ${HARBOR_HOST} --username=${Username} --password=${Password}
docker push ${HARBOR_HOST}/${NAMESPACE_NAME}/${REPOSITORY_NAME}:${TAG}
"""
}
}
}
}
stage('检查kubernetes环境') {
steps {
withCredentials([usernamePassword(credentialsId: "${DOCKER_REPOSITORY_CREDENTIAL_ID}", passwordVariable: "Password", usernameVariable: "Username")]) {
container(name: 'kubectl') {
sh """
kubectl get nodes --kubeconfig=/root/.kube/config
kubectl delete secret aliyun-registry-key -n ${K8S_NAMESPACE_NAME}
kubectl create secret docker-registry aliyun-registry-key -n ${K8S_NAMESPACE_NAME} --docker-server=${HARBOR_HOST} --docker-username=${Username} --docker-password=${Password} --kubeconfig=/root/.kube/config
"""
}
}
}
}
}
}
stage('部署容器到kubernetes') {
steps {
container(name: 'kubectl') {
sh """
kubectl set image ${CONTROLLER_TYPE} -l ${CONTROLLER_LABEL} -n ${K8S_NAMESPACE_NAME} ${CONTAINER_NAME}=${HARBOR_HOST}/${NAMESPACE_NAME}/${REPOSITORY_NAME}:${TAG} --kubeconfig=/root/.kube/config
"""
}
}
}
}
post {
always {
emailext (
body: '测试邮件',
mimeType: 'text/html',
subject: '自动化构建报告',
to: 'cxxxxit@163.com'
)
}
}
}
k8s 部署清单
apiVersion: apps/v1
kind: Deployment
metadata:
name: python
labels:
app: python
spec:
selector:
matchLabels:
app: python
template:
metadata:
labels:
app: python
spec:
containers:
- name: python
image: nginx
---
apiVersion: v1
kind: Service
metadata:
name: python
labels:
app: python
spec:
ports:
- port: 80
targetPort: 80
nodePort: 30080
selector:
app: python
type: NodePort
Jenkins部署Npm项目
linux虚拟机版
// 前端项目
// 1、拉取代码
// 2、切换分支
// 3、扫描代码
// 4、获取代码状态
// 5、编译代码
// 6、部署
// 7、发送部署邮件
pipeline {
agent any
parameters {
listGitBranches branchFilter: '.*',
credentialsId: 'bd34af1d-f1fb-4c19-a185-b746531a6930',
defaultValue: '',
listSize: '5',
name: 'GIT_TAG',
quickFilterEnabled: false,
remoteURL: 'git@gitlab.abck8s.com:douyin-xiaoyangaijishu/vue-tetris-master.git',
selectedValue: 'NONE',
sortMode: 'NONE',
tagFilter: '*',
type: 'PT_TAG'
}
stages {
stage("拉取代码") {
steps {
checkout(
[
$class: 'GitSCM',
branches: [[name: '*/master']],
extensions: [],
userRemoteConfigs: [[
credentialsId: 'bd34af1d-f1fb-4c19-a185-b746531a6930',
url: 'git@gitlab.abck8s.com:douyin-xiaoyangaijishu/vue-tetris-master.git'
]]
]
)
}
}
stage("切换分支") {
steps {
script {
sh """
git checkout $GIT_TAG
"""
}
}
}
stage("代码漏洞扫描") {
steps {
// 指定需要使用的Tools
script {
scannerTool = tool(
name: 'sonarqube-scanner',
type: 'hudson.plugins.sonar.SonarRunnerInstallation'
)
}
// 使用Tool来进行代码扫描
withSonarQubeEnv('sonarqube8.9.8') {
sh "${scannerTool}/bin/sonar-scanner"
}
}
}
stage("代码漏洞扫描状态判断") {
steps {
script {
timeout(1) {
qg = waitForQualityGate()
if (qg.status != 'OK') {
error "代码漏洞扫描失败,状态为: ${qg.status}"
} else {
echo "代码漏洞扫描通过"
}
}
}
}
}
stage("编译代码") {
steps {
script {
sh """
npm config set registry https://registry.npm.taobao.org
npm install
npm run build
"""
}
}
}
stage("部署") {
steps {
sshPublisher(
publishers: [
sshPublisherDesc(
configName: 'web02',
transfers: [
sshTransfer(
cleanRemote: false,
excludes: '',
execCommand: '''#!/bin/bash
mkdir vue-tetris
mv dist vue-tetris''',
execTimeout: 120000,
flatten: false,
makeEmptyDirs: false,
noDefaultExcludes: false,
patternSeparator: '[, ]+',
remoteDirectory: '',
remoteDirectorySDF: false,
removePrefix: '', sourceFiles: 'dist/**,index.html'
)
],
usePromotionTimestamp: false,
useWorkspaceInPromotion: false,
verbose: false
)
]
)
}
}
}
}
k8s容器版
pipeline {
agent {
kubernetes {
cloud 'kubernetes'
namespace 'default'
yaml '''
apiVersion: v1
kind: Pod
spec:
containers:
- name: jnlp
image: jenkins/inbound-agent:4.7-1-jdk11
args: [\'$(JENKINS_SECRET)\', \'$(JENKINS_NAME)\']
imagePullPolicy: IfNotPresent
volumeMounts:
- mountPath: /etc/localtime
name: valume-time
- mountPath: /etc/hosts
name: hosts
- name: docker
image: docker:19.03.15-git
imagePullPolicy: IfNotPresent
tty: true
volumeMounts:
- mountPath: /etc/localtime
name: valume-time
- mountPath: /var/run/docker.sock
name: docker-socket
- mountPath: /etc/hosts
name: hosts
- name: kubectl
image: alvinos/kubectl:1.17.4
imagePullPolicy: IfNotPresent
tty: true
command:
- cat
volumeMounts:
- mountPath: /.kube
name: kubeconfig
readOnly: false
- mountPath: /etc/localtime
name: valume-time
- name: sonarqube
image: emeraldsquad/sonar-scanner:2.2.0
tty: true
command:
- cat
volumeMounts:
- mountPath: /etc/localtime
name: valume-time
- mountPath: /etc/hosts
name: hosts
- name: node
image: node:16.15.1
tty: true
command:
- cat
volumeMounts:
- mountPath: /etc/localtime
name: valume-time
volumes:
- name: valume-time
hostPath:
path: /usr/share/zoneinfo/Asia/Shanghai
- name: docker-socket
hostPath:
path: /var/run/docker.sock
- name: hosts
hostPath:
path: /etc/hosts
- name: kubeconfig
secret:
secretName: kubeconfig
items:
- key: config
path: config
- name: maven-repository
nfs:
path: /nfs/v2
server: 172.16.0.11
- name: maven-k8s-devops
configMap:
name: maven-k8s-devops
items:
- key: settings.xml
path: settings.xml
'''
}
}
parameters {
listGitBranches branchFilter: '.*',
credentialsId: 'bd34af1d-f1fb-4c19-a185-b746531a6930',
defaultValue: '',
listSize: '5',
name: 'GIT_TAG',
quickFilterEnabled: false,
remoteURL: 'git@gitlab.abck8s.com:douyin-xiaoyangaijishu/vue-tetris-master.git',
selectedValue: 'NONE',
sortMode: 'NONE',
tagFilter: '*',
type: 'PT_TAG'
}
stages {
stage("拉取代码") {
steps {
checkout(
[
$class: 'GitSCM',
branches: [[name: '*/master']],
extensions: [],
userRemoteConfigs: [[
credentialsId: 'bd34af1d-f1fb-4c19-a185-b746531a6930',
url: 'git@gitlab.abck8s.com:douyin-xiaoyangaijishu/vue-tetris-master.git'
]]
]
)
}
}
stage("切换分支") {
steps {
script {
sh """
git checkout $GIT_TAG
"""
}
}
}
stage("代码漏洞扫描") {
steps {
container('sonarqube') {
script {
scannerTool = tool(
name: 'sonarqube-scanner',
type: 'hudson.plugins.sonar.SonarRunnerInstallation'
)
}
withSonarQubeEnv('sonarqube8.9.8') {
sh """
export JAVA_HOME=/usr/local/openjdk-11
${scannerTool}/bin/sonar-scanner
"""
}
}
}
}
stage("代码漏洞扫描状态判断") {
steps {
script {
timeout(1) {
qg = waitForQualityGate()
if (qg.status != 'OK') {
error "代码漏洞扫描失败,状态为: ${qg.status}"
} else {
echo "代码漏洞扫描通过"
}
}
}
}
}
stage("编译代码") {
steps {
container('node') {
sh """
npm config set registry https://registry.npm.taobao.org
npm install
npm run build
"""
}
}
}
stage("初始化docker环境和k8s环境") {
steps {
script {
CommitID = sh(returnStdout: true, script: "git log -n 1 --pretty=format:'%h'").trim()
BuildTime = sh(returnStdout: true, script: "date '+%s'").trim()
TAG = CommitID + "-" + BuildTime + "-" + GIT_TAG
}
}
}
stage("构建docker镜像") {
steps {
withCredentials([
usernamePassword(
credentialsId: 'c67fa380-07fa-49c9-9df4-69b3dc562350',
passwordVariable: 'Password',
usernameVariable: 'Username'
)]) {
container('docker'){
sh """
docker build -t registry.cn-hangzhou.aliyuncs.com/alvinos/java:${TAG} .
docker login registry.cn-hangzhou.aliyuncs.com --username=${Username} --password=${Password}
docker push registry.cn-hangzhou.aliyuncs.com/alvinos/java:${TAG}
"""
}
}
}
}
stage("部署到k8s集群中") {
steps {
withCredentials([
usernamePassword(
credentialsId: 'c67fa380-07fa-49c9-9df4-69b3dc562350',
passwordVariable: 'Password',
usernameVariable: 'Username'
)]) {
container('kubectl'){
sh """
kubectl delete secrets aliyun-registry --kubeconfig=/.kube/config
kubectl create secret docker-registry aliyun-registry --docker-server=registry.cn-hangzhou.aliyuncs.com --docker-username=${Username} --docker-password=${Password} --kubeconfig=/.kube/config
kubectl set image deployment vue vue=registry.cn-hangzhou.aliyuncs.com/alvinos/java:${TAG} --kubeconfig=/.kube/config
"""
}
}
}
}
}
}
部署Java项目
部署Tomcat
wget https://dlcdn.apache.org/tomcat/tomcat-9/v9.0.64/bin/apache-tomcat-9.0.64.tar.gz
[root@nexus apache-tomcat-9.0.64]# vim conf/tomcat-users.xml
<role rolename="tomcat"/>
<role rolename="role1"/>
<role rolename="manager-script"/>
<role rolename="manager-gui"/>
<role rolename="manager-status"/>
<role rolename="admin-gui"/>
<role rolename="admin-script"/>
<user username="tomcat" password="tomcat" roles="manager-gui,manager-script,tomcat,admin-gui,admin-script"/>
[root@nexus apache-tomcat-9.0.64]# vim webapps/manager/META-INF/context.xml
<!--<Valve className="org.apache.catalina.valves.RemoteAddrValve"
allow="127\.\d+\.\d+\.\d+|::1|0:0:0:0:0:0:0:1" />-->
// Java项目
// 1、拉取代码
// 2、切换分支
// 3、扫描代码
// 4、获取代码状态
// 5、编译代码
// 6、上传到制品库
// 6、部署
// 7、发送部署邮件
pipeline {
agent any
environment {
NEXUS_VERSION = "nexus3"
NEXUS_MOTHEN = "http"
NEXUS_URL = "nexus.abck8s.com"
NEXUS_REPOSITORY = "xiaoyangaijishu-devops"
NEXUS_CREDENTIAL_ID = "16352058-0ab1-4270-858b-3639919803ca"
}
parameters {
listGitBranches branchFilter: '.*',
credentialsId: 'bd34af1d-f1fb-4c19-a185-b746531a6930',
defaultValue: '',
listSize: '5',
name: 'GIT_TAG',
quickFilterEnabled: false,
remoteURL: 'git@gitlab.abck8s.com:douyin-xiaoyangaijishu/springboot.git',
selectedValue: 'NONE',
sortMode: 'NONE',
tagFilter: '*',
type: 'PT_TAG'
}
stages {
stage("拉取代码") {
steps {
checkout(
[
$class: 'GitSCM',
branches: [[name: '*/master']],
extensions: [],
userRemoteConfigs: [[
credentialsId: 'bd34af1d-f1fb-4c19-a185-b746531a6930',
url: 'git@gitlab.abck8s.com:douyin-xiaoyangaijishu/springboot.git'
]]
]
)
}
}
stage("切换分支") {
steps {
script {
sh """
git checkout $GIT_TAG
"""
}
}
}
stage("代码测试") {
steps {
script {
sh """
mvn test
"""
}
}
}
stage("代码漏洞扫描") {
steps {
// 指定需要使用的Tools
script {
scannerTool = tool(
name: 'sonarqube-scanner',
type: 'hudson.plugins.sonar.SonarRunnerInstallation'
)
}
// 使用Tool来进行代码扫描
withSonarQubeEnv('sonarqube8.9.8') {
sh "${scannerTool}/bin/sonar-scanner"
}
}
}
stage("代码漏洞扫描状态判断") {
steps {
script {
timeout(1) {
qg = waitForQualityGate()
if (qg.status != 'OK') {
error "代码漏洞扫描失败,状态为: ${qg.status}"
} else {
echo "代码漏洞扫描通过"
}
}
}
}
}
stage("编译代码") {
steps {
script {
sh """
mvn package -DskipTests=true
"""
}
}
}
stage("上传至制品库") {
steps {
script {
// 获取pom.xml中的详细信息
pom = readMavenPom file: 'pom.xml'
// 通过 pom.xml 获取可能生成的文件相对路径
filesbyGlob = findFiles(glob: "target/*.${pom.packaging}")
// 判断该文件是否生成
artifactPath = filesbyGlob[0].path
artifactExists = fileExists artifactPath
// 如果存在则开始上传至 Nexus 制品库
if (artifactExists) {
nexusArtifactUploader(
artifacts: [
[
artifactId: pom.artifactId,
classifier: '',
file: artifactPath,
type: pom.packaging
], [
artifactId: pom.artifactId,
classifier: '',
file: 'pom.xml',
type: 'pom'
]
],
credentialsId: NEXUS_CREDENTIAL_ID,
groupId: pom.groupId,
nexusUrl: NEXUS_URL,
nexusVersion: NEXUS_VERSION,
protocol: NEXUS_MOTHEN,
repository: NEXUS_REPOSITORY,
version: pom.version
)
} else {
// 不存在则返回提示信息
error "文件 ${artifactPath} 不存在"
}
}
}
}
stage("部署到Tomcat") {
steps {
deploy(
adapters: [
tomcat9(
credentialsId: '822eba73-92cf-424b-b381-80a2ca3e70ad',
path: '',
url: 'http://192.168.15.31:8080')],
contextPath: null,
war: 'target/*.war'
)
}
}
}
}
Jenkins部署Python项目
Nginx + uwsgi
因为nginx不支持uwsgi协议,无法直接调用py开发的webApp。 在nginx+uWsgi+Django的框架里,nginx代理+webServer,uWsgi是wsgiServer,Django是webApp。 nginx接收用户请求,并判定哪些转发到uWsgi,uWsgi再去调用pyWebApp。
创建项目用户
groupadd django -g 888
useradd django -u 888 -g 888 -r -M -s /bin/sh
安装依赖软件
yum install python3 libxml* python-devel gcc* pcre-devel openssl-devel python3-devel -y
安装uWsgi
pip3 install uwsgi django -i https://pypi.doubanio.com/simple
配置uwsgi
[root@localhost ~]# cat /opt/linux/myweb_uwsgi.ini
[uwsgi]
# 端口号
socket = :8000
# 指定项目的目录
chdir = /opt/python
# wsgi文件路径
wsgi-file = python/wsgi.py
# 模块wsgi路径
module = python.wsgi
# 是否开启master进程
master = true
# 工作进程的最大数目
processes = 4
# 结束后是否清理文件
vacuum = true
配置Nginx
[root@localhost ~]# cat /etc/nginx/conf.d/python.conf
server {
listen 80;
server_name py.test.com;
location / {
include uwsgi_params;
uwsgi_pass 127.0.0.1:8000;
uwsgi_read_timeout 2;
uwsgi_param UWSGI_SCRIPT python.wsgi;
uwsgi_param UWSGI_CHDIR /opt/python;
index index.html index.htm;
client_max_body_size 35m;
}
}
Linux版Python部署
// python项目
// 1、拉取代码
// 2、切换分支
// 3、扫描代码
// 4、获取代码状态
// 6、部署
// 6.1、下载包
// 7、发送部署邮件
pipeline {
agent any
parameters {
listGitBranches branchFilter: '.*',
credentialsId: 'bd34af1d-f1fb-4c19-a185-b746531a6930',
defaultValue: '',
listSize: '5',
name: 'GIT_TAG',
quickFilterEnabled: false,
remoteURL: 'git@gitlab.abck8s.com:douyin-xiaoyangaijishu/python.git',
selectedValue: 'NONE',
sortMode: 'NONE',
tagFilter: '*',
type: 'PT_TAG'
}
stages {
stage("拉取代码") {
steps {
checkout(
[
$class: 'GitSCM',
branches: [[name: '*/master']],
extensions: [],
userRemoteConfigs: [[
credentialsId: 'bd34af1d-f1fb-4c19-a185-b746531a6930',
url: 'git@gitlab.abck8s.com:douyin-xiaoyangaijishu/python.git'
]]
]
)
}
}
stage("切换分支") {
steps {
script {
sh """
git checkout $GIT_TAG
"""
}
}
}
stage("代码漏洞扫描") {
steps {
// 指定需要使用的Tools
script {
scannerTool = tool(
name: 'sonarqube-scanner',
type: 'hudson.plugins.sonar.SonarRunnerInstallation'
)
}
// 使用Tool来进行代码扫描
withSonarQubeEnv('sonarqube8.9.8') {
sh "${scannerTool}/bin/sonar-scanner"
}
}
}
stage("代码漏洞扫描状态判断") {
steps {
script {
timeout(1) {
qg = waitForQualityGate()
if (qg.status != 'OK') {
error "代码漏洞扫描失败,状态为: ${qg.status}"
} else {
echo "代码漏洞扫描通过"
}
}
}
}
}
stage("部署") {
steps {
sshPublisher(
publishers: [
sshPublisherDesc(
configName: 'jenkins',
transfers: [
sshTransfer(
cleanRemote: false,
excludes: '',
execCommand: '''#!/bin/bash
pip3 install django===2.2.2 -i https://pypi.doubanio.com/simple
pip3 install uwsgi -i https://pypi.doubanio.com/simple
cd /opt/python
uwsgi --stop uwsgi.pid || echo 1
uwsgi -d --ini uwsgi.ini
''',
execTimeout: 120000,
flatten: false,
makeEmptyDirs: false,
noDefaultExcludes: false,
patternSeparator: '[, ]+',
remoteDirectory: '',
remoteDirectorySDF: false,
removePrefix: '', sourceFiles: '**/**'
)
],
usePromotionTimestamp: false,
useWorkspaceInPromotion: false,
verbose: false
)
]
)
}
}
}
}
k8s容器版Python部署
// python项目
// 1、拉取代码
// 2、切换分支
// 3、扫描代码
// 4、获取代码状态
// 6、部署
// 6.1、下载包
// 7、发送部署邮件
pipeline {
agent {
kubernetes {
cloud 'kubernetes'
namespace 'default'
yaml '''
apiVersion: v1
kind: Pod
spec:
containers:
- name: jnlp
image: jenkins/inbound-agent:4.7-1-jdk11
args: [\'$(JENKINS_SECRET)\', \'$(JENKINS_NAME)\']
imagePullPolicy: IfNotPresent
volumeMounts:
- mountPath: /etc/localtime
name: valume-time
- mountPath: /etc/hosts
name: hosts
- name: docker
image: docker:19.03.15-git
imagePullPolicy: IfNotPresent
tty: true
volumeMounts:
- mountPath: /etc/localtime
name: valume-time
- mountPath: /var/run/docker.sock
name: docker-socket
- mountPath: /etc/hosts
name: hosts
- name: kubectl
image: alvinos/kubectl:1.17.4
imagePullPolicy: IfNotPresent
tty: true
command:
- cat
volumeMounts:
- mountPath: /.kube
name: kubeconfig
readOnly: false
- mountPath: /etc/localtime
name: valume-time
- name: sonarqube
image: emeraldsquad/sonar-scanner:2.2.0
tty: true
command:
- cat
volumeMounts:
- mountPath: /etc/localtime
name: valume-time
- mountPath: /etc/hosts
name: hosts
- name: maven
image: maven:3.6.3-openjdk-8
imagePullPolicy: IfNotPresent
tty: true
command:
- cat
volumeMounts:
- mountPath: /etc/localtime
name: valume-time
- mountPath: /root/.m2/repository
name: maven-repository
readOnly: false
- mountPath: /usr/share/maven/conf/settings.xml
name: maven-k8s-devops
subPath: settings.xml
readOnly: false
env:
- name: "LANGUAGE"
value: "en_US:en"
- name: "LC_ALL"
value: "en_US.UTF-8"
- name: "LANG"
value: "en_US.UTF-8"
volumes:
- name: valume-time
hostPath:
path: /usr/share/zoneinfo/Asia/Shanghai
- name: docker-socket
hostPath:
path: /var/run/docker.sock
- name: hosts
hostPath:
path: /etc/hosts
- name: kubeconfig
secret:
secretName: kubeconfig
items:
- key: config
path: config
- name: maven-repository
nfs:
path: /nfs/v2
server: 172.16.0.11
- name: maven-k8s-devops
configMap:
name: maven-k8s-devops
items:
- key: settings.xml
path: settings.xml
'''
}
}
parameters {
listGitBranches branchFilter: '.*',
credentialsId: 'bd34af1d-f1fb-4c19-a185-b746531a6930',
defaultValue: '',
listSize: '5',
name: 'GIT_TAG',
quickFilterEnabled: false,
remoteURL: 'git@gitlab.abck8s.com:douyin-xiaoyangaijishu/python.git',
selectedValue: 'NONE',
sortMode: 'NONE',
tagFilter: '*',
type: 'PT_TAG'
}
stages {
stage("拉取代码") {
steps {
checkout(
[
$class: 'GitSCM',
branches: [[name: '*/master']],
extensions: [],
userRemoteConfigs: [[
credentialsId: 'bd34af1d-f1fb-4c19-a185-b746531a6930',
url: 'git@gitlab.abck8s.com:douyin-xiaoyangaijishu/python.git'
]]
]
)
}
}
stage("切换分支") {
steps {
script {
sh """
git checkout $GIT_TAG
"""
}
}
}
stage("代码漏洞扫描") {
steps {
container('sonarqube') {
script {
scannerTool = tool(
name: 'sonarqube-scanner',
type: 'hudson.plugins.sonar.SonarRunnerInstallation'
)
}
withSonarQubeEnv('sonarqube8.9.8') {
sh """
export JAVA_HOME=/usr/local/openjdk-11
${scannerTool}/bin/sonar-scanner
"""
}
}
}
}
stage("代码漏洞扫描状态判断") {
steps {
script {
timeout(1) {
qg = waitForQualityGate()
if (qg.status != 'OK') {
error "代码漏洞扫描失败,状态为: ${qg.status}"
} else {
echo "代码漏洞扫描通过"
}
}
}
}
}
stage("初始化docker环境和k8s环境") {
steps {
script {
CommitID = sh(returnStdout: true, script: "git log -n 1 --pretty=format:'%h'").trim()
BuildTime = sh(returnStdout: true, script: "date '+%s'").trim()
TAG = CommitID + "-" + BuildTime + "-" + GIT_TAG
}
}
}
stage("构建docker镜像") {
steps {
withCredentials([
usernamePassword(
credentialsId: 'c67fa380-07fa-49c9-9df4-69b3dc562350',
passwordVariable: 'Password',
usernameVariable: 'Username'
)]) {
container('docker'){
sh """
docker build -t registry.cn-hangzhou.aliyuncs.com/alvinos/java:${TAG} .
docker login registry.cn-hangzhou.aliyuncs.com --username=${Username} --password=${Password}
docker push registry.cn-hangzhou.aliyuncs.com/alvinos/java:${TAG}
"""
}
}
}
}
stage("部署到k8s集群中") {
steps {
withCredentials([
usernamePassword(
credentialsId: 'c67fa380-07fa-49c9-9df4-69b3dc562350',
passwordVariable: 'Password',
usernameVariable: 'Username'
)]) {
container('kubectl'){
sh """
kubectl delete secrets aliyun-registry --kubeconfig=/.kube/config
kubectl create secret docker-registry aliyun-registry --docker-server=registry.cn-hangzhou.aliyuncs.com --docker-username=${Username} --docker-password=${Password} --kubeconfig=/.kube/config
kubectl set image deployment python python=registry.cn-hangzhou.aliyuncs.com/alvinos/java:${TAG} --kubeconfig=/.kube/config
"""
}
}
}
}
}
}
Jenkins部署Golang项目
linux版
// golang项目
// 1、拉取代码
// 2、切换分支
// 3、代码扫描
// 4、判断代码扫描的状态
// 5、编译
// 6、上传至远程服务器
pipeline {
agent any
parameters {
listGitBranches branchFilter: '.*',
credentialsId: 'bd34af1d-f1fb-4c19-a185-b746531a6930',
defaultValue: '',
listSize: '5',
name: 'GIT_TAG',
quickFilterEnabled: false,
remoteURL: 'git@gitlab.abck8s.com:douyin-xiaoyangaijishu/gin.git',
selectedValue: 'NONE',
sortMode: 'NONE',
tagFilter: '*',
type: 'PT_TAG'
}
stages {
stage("拉取代码") {
steps {
checkout(
[
$class: 'GitSCM',
branches: [[name: '*/master']],
extensions: [],
userRemoteConfigs: [[
credentialsId: 'bd34af1d-f1fb-4c19-a185-b746531a6930',
url: 'git@gitlab.abck8s.com:douyin-xiaoyangaijishu/gin.git'
]]
]
)
}
}
stage("切换分支") {
steps {
script {
sh """
git checkout $GIT_TAG
"""
}
}
}
stage("代码漏洞扫描") {
steps {
// 指定需要使用的Tools
script {
scannerTool = tool(
name: 'sonarqube-scanner',
type: 'hudson.plugins.sonar.SonarRunnerInstallation'
)
}
// 使用Tool来进行代码扫描
withSonarQubeEnv('sonarqube8.9.8') {
sh "${scannerTool}/bin/sonar-scanner"
}
}
}
stage("代码漏洞扫描状态判断") {
steps {
script {
timeout(1) {
qg = waitForQualityGate()
if (qg.status != 'OK') {
error "代码漏洞扫描失败,状态为: ${qg.status}"
} else {
echo "代码漏洞扫描通过"
}
}
}
}
}
stage("编译代码") {
steps {
script {
sh """
sh ./build.sh
"""
}
}
}
stage("上传至远程服务器") {
steps {
sshPublisher(
publishers: [
sshPublisherDesc(
configName: 'golang',
transfers: [
sshTransfer(
cleanRemote: false,
excludes: '',
execCommand: '''#!/bin/bash
cd /opt/golang
chmod +x main
systemctl restart golang-server
''',
execTimeout: 120000,
flatten: false,
makeEmptyDirs: false,
noDefaultExcludes: false,
patternSeparator: '[, ]+',
remoteDirectory: '',
remoteDirectorySDF: false,
removePrefix: '',
sourceFiles: '**/main'
)
],
usePromotionTimestamp: false,
useWorkspaceInPromotion: false,
verbose: false
)
]
)
}
}
}
}
k8s版
// golang项目
// 1、拉取代码
// 2、切换分支
// 3、代码扫描
// 4、判断代码扫描的状态
// 5、编译
// 6、上传至远程服务器
pipeline {
agent {
kubernetes {
cloud 'kubernetes'
namespace 'default'
yaml '''
apiVersion: v1
kind: Pod
spec:
containers:
- name: jnlp
image: jenkins/inbound-agent:4.7-1-jdk11
args: [\'$(JENKINS_SECRET)\', \'$(JENKINS_NAME)\']
imagePullPolicy: IfNotPresent
volumeMounts:
- mountPath: /etc/localtime
name: valume-time
- mountPath: /etc/hosts
name: hosts
- name: docker
image: docker:19.03.15-git
imagePullPolicy: IfNotPresent
tty: true
volumeMounts:
- mountPath: /etc/localtime
name: valume-time
- mountPath: /var/run/docker.sock
name: docker-socket
- mountPath: /etc/hosts
name: hosts
- name: kubectl
image: alvinos/kubectl:1.17.4
imagePullPolicy: IfNotPresent
tty: true
command:
- cat
volumeMounts:
- mountPath: /.kube
name: kubeconfig
readOnly: false
- mountPath: /etc/localtime
name: valume-time
- name: sonarqube
image: emeraldsquad/sonar-scanner:2.2.0
tty: true
command:
- cat
volumeMounts:
- mountPath: /etc/localtime
name: valume-time
- mountPath: /etc/hosts
name: hosts
- name: maven
image: maven:3.6.3-openjdk-8
imagePullPolicy: IfNotPresent
tty: true
command:
- cat
volumeMounts:
- mountPath: /etc/localtime
name: valume-time
- mountPath: /root/.m2/repository
name: maven-repository
readOnly: false
- mountPath: /usr/share/maven/conf/settings.xml
name: maven-k8s-devops
subPath: settings.xml
readOnly: false
env:
- name: "LANGUAGE"
value: "en_US:en"
- name: "LC_ALL"
value: "en_US.UTF-8"
- name: "LANG"
value: "en_US.UTF-8"
- name: golang
image: golang:1.16.3
imagePullPolicy: IfNotPresent
tty: true
command:
- cat
volumeMounts:
- mountPath: /etc/localtime
name: valume-time
env:
- name: "LANGUAGE"
value: "en_US:en"
- name: "LC_ALL"
value: "en_US.UTF-8"
- name: "LANG"
value: "en_US.UTF-8"
volumes:
- name: valume-time
hostPath:
path: /usr/share/zoneinfo/Asia/Shanghai
- name: docker-socket
hostPath:
path: /var/run/docker.sock
- name: hosts
hostPath:
path: /etc/hosts
- name: kubeconfig
secret:
secretName: kubeconfig
items:
- key: config
path: config
- name: maven-repository
nfs:
path: /nfs/v2
server: 172.16.0.11
- name: maven-k8s-devops
configMap:
name: maven-k8s-devops
items:
- key: settings.xml
path: settings.xml
'''
}
}
parameters {
listGitBranches branchFilter: '.*',
credentialsId: 'bd34af1d-f1fb-4c19-a185-b746531a6930',
defaultValue: '',
listSize: '5',
name: 'GIT_TAG',
quickFilterEnabled: false,
remoteURL: 'git@gitlab.abck8s.com:douyin-xiaoyangaijishu/gin.git',
selectedValue: 'NONE',
sortMode: 'NONE',
tagFilter: '*',
type: 'PT_TAG'
}
stages {
stage("拉取代码") {
steps {
checkout(
[
$class: 'GitSCM',
branches: [[name: '*/master']],
extensions: [],
userRemoteConfigs: [[
credentialsId: 'bd34af1d-f1fb-4c19-a185-b746531a6930',
url: 'git@gitlab.abck8s.com:douyin-xiaoyangaijishu/gin.git'
]]
]
)
}
}
stage("切换分支") {
steps {
script {
sh """
git checkout $GIT_TAG
"""
}
}
}
stage("代码漏洞扫描") {
steps {
container('sonarqube') {
script {
scannerTool = tool(
name: 'sonarqube-scanner',
type: 'hudson.plugins.sonar.SonarRunnerInstallation'
)
}
withSonarQubeEnv('sonarqube8.9.8') {
sh """
export JAVA_HOME=/usr/local/openjdk-11
${scannerTool}/bin/sonar-scanner
"""
}
}
}
}
stage("代码漏洞扫描状态判断") {
steps {
script {
timeout(1) {
qg = waitForQualityGate()
if (qg.status != 'OK') {
error "代码漏洞扫描失败,状态为: ${qg.status}"
} else {
echo "代码漏洞扫描通过"
}
}
}
}
}
stage("编译代码下载代码依赖包") {
steps {
container('golang'){
sh """
export GOPATH=/go
sh ./build.sh
"""
}
}
}
stage("初始化docker环境和k8s环境") {
steps {
script {
CommitID = sh(returnStdout: true, script: "git log -n 1 --pretty=format:'%h'").trim()
BuildTime = sh(returnStdout: true, script: "date '+%s'").trim()
TAG = CommitID + "-" + BuildTime + "-" + GIT_TAG
}
}
}
stage("构建docker镜像") {
steps {
withCredentials([
usernamePassword(
credentialsId: 'c67fa380-07fa-49c9-9df4-69b3dc562350',
passwordVariable: 'Password',
usernameVariable: 'Username'
)]) {
container('docker'){
sh """
docker build -t registry.cn-hangzhou.aliyuncs.com/alvinos/java:${TAG} .
docker login registry.cn-hangzhou.aliyuncs.com --username=${Username} --password=${Password}
docker push registry.cn-hangzhou.aliyuncs.com/alvinos/java:${TAG}
"""
}
}
}
}
stage("部署到k8s集群中") {
steps {
withCredentials([
usernamePassword(
credentialsId: 'c67fa380-07fa-49c9-9df4-69b3dc562350',
passwordVariable: 'Password',
usernameVariable: 'Username'
)]) {
container('kubectl'){
sh """
kubectl delete secrets aliyun-registry --kubeconfig=/.kube/config
kubectl create secret docker-registry aliyun-registry --docker-server=registry.cn-hangzhou.aliyuncs.com --docker-username=${Username} --docker-password=${Password} --kubeconfig=/.kube/config
kubectl set image deployment python python=registry.cn-hangzhou.aliyuncs.com/alvinos/java:${TAG} --kubeconfig=/.kube/config
"""
}
}
}
}
}
post {
always {
emailext(
body: '构建结果通知!',
subject: "自动化构建报告:$JOB_NAME - Build",
to: 'chenyangqit@163.com'
)
}
}
}