前言
作者目前打算分享一期关于devOps系列的文章,希望对热爱学习和探索的你有所帮助。
文章主要记录一些简洁、高效的运维部署指令,旨在 记录和能够快速地构建系统。就像运维文档或者手册一样,方便进行系统的重建、改造和优化。每篇文章独立出来,可以单独作为其中一项组件的部署和使用。
本章为 devOps系列(四)jenkins搭建
大纲
devOps系列介绍
devOps系列(一)docker搭建
devOps系列(二)gitlab搭建
devOps系列(三)nexus-harbor搭建
devOps系列(四)jenkins搭建
devOps系列(五)efk系统搭建
devOps系列(六)grafana+prometheus搭建
devOps系列(七)grafana+prometheus监控告警
devOps系列(八)efk+prometheus+grafana日志监控和告警
正文
创建数据目录
1 2
| mkdir -p /data/jenkins/ chmod o+w /data/jenkins/
|
部署jenkins
1 2 3 4 5 6 7 8 9 10 11 12
| docker run --detach \ --publish 8080:8080 \ --privileged=true \ --user=0 \ --name jenkins \ --restart always \ --volume /data/jenkins:/var/jenkins_home \ --volume /usr/bin/docker:/usr/bin/docker \ --volume /var/run/docker.sock:/var/run/docker.sock \ --env TZ=Asia/Shanghai \ --env JAVA_OPTS="-Xms1024m -Xmx4000m -Duser.timezone=GMT+08 -Dfile.encoding=utf-8 -DsessionTimeout=0 -Dhudson.security.csrf.GlobalCrumbIssuerConfiguration.DISABLE_CSRF_PROTECTION=true" \ jenkins/jenkins:2.414
|
访问
浏览器访问 http://ip:8080 ,初始化密码可以从日志查看:
也可以直接查看初始化密码文件
1
| docker exec jenkins cat /var/jenkins_home/secrets/initialAdminPassword
|
默认安装推荐的插件
创建管理员用户
建议:jenkins可以做一下域名解析,如 jenkins.jafir.top 到 nginx 转发到ip: 8080,来访问
jenkins装好后,最重要的就是构建任务的创建和测试了。
pipeline示例
这里给一个java程序的示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
| pipeline { agent any environment { GIT_URL = "git@gitlab.jafir.top:example-server.git" JAR_FILE = "target/application.jar" IMAGE = "${JOB_NAME}" RegistryUrl = "harbor.jafir.top" GIT_BRANCH = "master" IMAGETAG = "prod-${BUILD_ID}" APP_PROFILE = "prod" JVM_OPTS = "-Dspring.profiles.active=${APP_PROFILE} -DappName=${JOB_NAME} -Duser.timezone=GMT+08 -Dfile.encoding=utf-8 -Xmn1g -Xms2G -Xmx2G -XX:MetaspaceSize=100m -XX:+PrintCommandLineFlags -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -Xloggc:gc.log -XX:+PrintHeapAtGC -XX:-UseAdaptiveSizePolicy -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/java.hprof:" APP_CONTAINER_NAME = '${JOB_NAME}' APP_HOST_PORT = 8080 APP_CONTAINER_PORT = 8080 } stages { stage('拉取代码') { steps { sh "echo '拉取代码'" git credentialsId: 'gitlab_credential_ssh', url: "$GIT_URL", branch: "$GIT_BRANCH" } } stage('maven构建') { agent { docker { image 'maven:3.6.3-jdk-8' args '-v /data/jenkins_maven_cache:/root/.m2' reuseNode true } } steps { sh "echo 'maven构建'" sh """ mvn -v mvn clean package \ -Dmaven.test.skip=true \ -Dmaven.compile.fork=true \ """ } } stage('docker构建') { steps { configFileProvider([configFile(fileId: 'java_dockerfile', targetLocation: 'Dockerfile')]) { withCredentials([usernamePassword( credentialsId: 'harbor_credential', usernameVariable: 'DOCKER_HUB_USER', passwordVariable: 'DOCKER_HUB_PASSWORD')]) { echo "构建 Docker 镜像" sh """ docker login ${RegistryUrl} -u ${DOCKER_HUB_USER} -p ${DOCKER_HUB_PASSWORD} && \ docker build -t ${RegistryUrl}/java/${IMAGE}:${IMAGETAG} \ --build-arg JAR_FILE=${JAR_FILE} \ --build-arg JVM_OPTS='${JVM_OPTS}' . && \ docker push ${RegistryUrl}/java/${IMAGE}:${IMAGETAG} && \ docker logout ${RegistryUrl} """ } } } } stage('发布') { steps { echo "发布" script { configFileProvider([configFile(fileId: 'deploy.sh', targetLocation: 'deploy.sh')]) { sshPublisher(failOnError: true, publishers: [ sshPublisherDesc( configName: 'ssh-server', transfers: [ sshTransfer( cleanRemote: false, excludes: '', execCommand: "sh /root/data/project/${IMAGE}/deploy.sh '${RegistryUrl}/java/${IMAGE}:${IMAGETAG}' ${APP_CONTAINER_NAME} ${APP_HOST_PORT} ${APP_CONTAINER_PORT}", execTimeout: 120000, flatten: false, makeEmptyDirs: true, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: "/data/project/${IMAGE}", remoteDirectorySDF: false, removePrefix: '', sourceFiles: 'deploy.sh' ) ], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: true ) ]) } } } } } post { failure { // 构建失败时发送企业微信通知 script { def message = "构建失败:${currentBuild.fullDisplayName}" // 使用HTTP POST请求发送消息到企业微信机器人 sh """ curl -X POST -H 'Content-Type: application/json' -d '{ "msgtype": "text", "text": { "content": "${message}" } }' ${webhookUrl} """ } } } }
|
主要任务内容为:
从gitlab拉不同分支的代码,然后进行构建,构建好打包jar为docker img镜像,然后上传到harbor。再通过ssh 目标部署服务器执行 部署脚本,部署失败发送企业微信通知。部署脚本内容大致为: 从harbor拉取镜像,然后重启实例。
脚本文件及变量:
gitlab_credential_ssh: gitlab的ssh(证书 或者 账密)
java_dockerfile:java程序构建的通用dockerfile
1 2 3 4 5 6 7
| FROM harbor.jafi.top/java/java-base:latest ARG PROJECT_PATH=/app ARG JAR_FILE ARG JVM_OPTS WORKDIR ${PROJECT_PATH} COPY <jar> ${PROJECT_PATH}/app.jar ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar"]
|
这里引用的baseJava镜像,自己打包的,主要是把一些常用命令和arthas打包进去,免得每次都要下载。
1 2 3 4 5 6 7 8 9
| FROM openjdk:8u292-jdk-slim RUN sed -i "s:deb.debian.org:mirrors.tuna.tsinghua.edu.cn:g" /etc/apt/sources.list \ && sed -i "s:security.debian.org:mirrors.tuna.tsinghua.edu.cn:g" /etc/apt/sources.list \ && apt-get update \ && apt-get install -y libfreetype6 fontconfig wget curl vim telnet inetutils-ping \ && apt-get clean \ && apt-get autoclean \ && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* COPY arthas /arthas-bin
|
1
| docker build -t harbor.jafir.top/java/java-base:latest .
|
1 2
| docker login harbor.jafir.top -u admin -p Harbor12345 docker push harbor.jafir.top/java/java-base:latest
|
ssh-server: 部署的目标机器配置,在jenkins的系统配置里面ssh添加server
DOCKER_HUB_USER: harbor的账号
DOCKER_HUB_PASSWORD:harbor的密码
deploy.sh:
示例如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| #!/bin/bash
# 提取参数 IMAGE="$1" APP_CONTAINER_NAME="$2" APP_HOST_PORT="$3" APP_CONTAINER_PORT="$4"
# 登录 Harbor docker login -u harborAccount -p harborPwd "https://barbor.jafir.top"
# 停止并删除已运行的容器 docker stop "${APP_CONTAINER_NAME}" >/dev/null 2>&1 docker rm "${APP_CONTAINER_NAME}" >/dev/null 2>&1
# 运行 Docker 容器 docker run -d --restart=always --name "${APP_CONTAINER_NAME}" -p "${APP_HOST_PORT}:${APP_CONTAINER_PORT}" "${IMAGE}"
|
正常情况下,jenkins的自动化构建就已经建立起来了,jenkins也可以通过配置定时或者触发来进行任务的自动化构建。最终发布到部署的目标服务器,进行部署更新。