diff --git a/ci/lab03-jenkins/README.md b/ci/lab03-jenkins/README.md index ec9282a..467d1bb 100644 --- a/ci/lab03-jenkins/README.md +++ b/ci/lab03-jenkins/README.md @@ -39,7 +39,6 @@ * https://www.jenkins.io/download/ * https://www.jenkins.io/blog/2011/06/16/jenkins-long-term-support-release/ * https://www.jenkins.io/blog/2012/03/13/why-does-jenkins-have-blue-balls/ -* https://www.jenkins.io/blog/2014/07/08/workflow-plugin-tutorial-writing-a-step-impl/ * https://www.jenkins.io/blog/2017/01/17/Jenkins-is-upgrading-to-Java-8/ ### 1.3 相关工具对比 @@ -290,7 +289,6 @@ pipeline { 1. 2014 年 5 月,groovy-cps 库诞生了 0.1 版本。 2. 2016 年 4 月,Jenkins 发布了 2.0 版本,对应的 groovy-cps-1.7。 -3. 2016 年 4 月,Jenkins 发布了 2.0 版本。 4. 2016 年 8 月,Jenkins 的 pipeline-model-definition 插件发布 0.1 版本。 5. 2017 年 2 月,Jenkins 的 pipeline-model-definition 插件发布 1.0 GA 版本。 6. 2017 年 4 月,Blue Ocean 1.0 @@ -350,6 +348,7 @@ node { * https://www.jenkins.io/blog/2017/02/15/declarative-notifications/ * https://www.jenkins.io/blog/2017/04/05/say-hello-blueocean-1-0/ * https://www.jenkins.io/blog/2017/04/10/jenkins-has-upgraded-to-java-8/ +* https://www.jenkins.io/blog/2014/07/08/workflow-plugin-tutorial-writing-a-step-impl/ #### 3. Declarative Pipeline 特点和原理 @@ -493,5 +492,7 @@ def purgeBranchString(branch) { * https://github.com/opsbox-dev/oes-pipeline-plugin ## 4. 实战练习 - -* https://github.com/seanly/cloudogu-jenkinsfiles \ No newline at end of file + + >两三句话的简介? + +* https://github.com/seanly/cloudogu-jenkinsfiles diff --git a/ci/lab03-jenkins/templates/baseimage/Jenkinsfile b/ci/lab03-jenkins/templates/baseimage/Jenkinsfile new file mode 100644 index 0000000..3b735a3 --- /dev/null +++ b/ci/lab03-jenkins/templates/baseimage/Jenkinsfile @@ -0,0 +1,170 @@ +/* + +# 功能描述 + +构建基础镜像 + +# 参数配置 + +```yaml + +coderepo: + auth: xxx + url: xxx + +dockerpush: + auth: xxx + registry: xxx + namespace: xxx + image: xxx + +build_method: docker-compose +``` + +# 插件依赖 + +* https://www.jenkins.io/doc/pipeline/steps/workflow-basic-steps/ +* https://plugins.jenkins.io/docker-workflow/ +* https://github.com/opsbox-dev/oes-template-plugin + + +# 使用方法 + +*/ + +def branch = purgeBranchString(coderepo.branch) + +pipeline { + + agent any + + options { + disableConcurrentBuilds() + skipDefaultCheckout true + } + + stages { + + stage("Checkout Code") { + steps { + script { + deleteDir() + def gitParams = [ + $class : 'GitSCM', + branches : [[name: "${branch}"]], + doGenerateSubmoduleConfigurations: false, + extensions : [[$class: 'CleanBeforeCheckout']], + submoduleCfg : [], + userRemoteConfigs : [[url: "${coderepo.url}"]] + ] + if (coderepo.auth != null) { + gitParams.userRemoteConfigs = [[credentialsId: "${coderepo.auth}", + url : "${coderepo.url}"]] + } + checkout(gitParams) + } + } + } // end: Checkout Code + + stage("Build Image by Docker Compose") { + when { + expression { build_method == "docker-compose" } + } + steps { + script { + // 检查关键文件是否存在 + if (!fileExists('docker-compose.yml')) { + error( "--//ERR: 缺少docker-compose.yml文件") + } + + def _docker_compose_j2 = """ + |{% set version = "${branch}" %} + |version: '3' + |services: + |{%- for name, _ in services.items() %} + | {{ name }}: + | {% if version == "main" %} + | image: "${dockerpush.registry}/${dockerpush.namespace}/${dockerpush.image}:{{name}}" + | {% else %} + | image: "${dockerpush.registry}/${dockerpush.namespace}/${dockerpush.image}:{{name}}-{{ version }}" + | {% endif %} + |{%- endfor %} + """.stripMargin().stripIndent() + writeFile(file: 'docker-compose.j2', text: _docker_compose_j2) + + def _dockerfile = ''' + FROM rockylinux:8 + RUN yum install -y python3 && pip3 install jinja2-cli[yaml] + '''.stripIndent() + writeFile(file: 'Dockerfile', text: _dockerfile) + + def jinja2Image = docker.build("rockylinux8:jinja2") + jinja2Image.inside { + sh """ + set -eux + jinja2 ./docker-compose.j2 ./docker-compose.yml > docker-compose.override.yml + """ + } + + docker.withRegistry("https://${dockerpush.registry}", "${dockerpush.auth}") { + sh """ + set -eux + docker-compose -f docker-compose.yml -f docker-compose.override.yml build + docker-compose -f docker-compose.yml -f docker-compose.override.yml push + """ + } + } + } + } // end: Build Image by Docker Compose + + stage("Build Image by Docker") { + when { + expression { build_method == "docker" } + } + steps { + script { + if (!fileExists('Dockerfile')) { + error( "--//ERR: 缺少 Dockerfile 文件") + } + docker.withRegistry("https://${dockerpush.registry}", "${dockerpush.auth}") { + def _tag = branch + if (branch == "master") { + _tag = "latest" + } + def _image = docker.build("${dockerpush.registry}/${dockerpush.namespace}/${dockerpush.image}:${_tag}") + _image.push() + } + } + } + } // end: Build Image by Docker + + } +} + +// looks for string [ci skip] in commit message +boolean getCiSkip() { + sh(returnStdout: true, script: 'git show --pretty=%s%b -s', + label : 'check skip CI?' + ).toLowerCase().contains('[ci skip]') +} + +String getGitCommit() { + sh( + returnStdout: true, script: 'git rev-parse HEAD', + label : 'getting GIT commit' + ).trim() +} + +def purgeBranchString(branch) { + def gitBranch = branch + if (gitBranch?.startsWith("refs/heads/")) { + gitBranch = gitBranch.replace("refs/heads/", "") + if (gitBranch != "main") { + error("--//INFO: 不支持除 main 之外的分支") + } + } + if (gitBranch?.startsWith("refs/tags/")) { + gitBranch = gitBranch.replace("refs/tags/", "") + } + return gitBranch +} diff --git a/ci/lab03-jenkins/templates/general/Jenkinsfile b/ci/lab03-jenkins/templates/general/Jenkinsfile new file mode 100644 index 0000000..0cdfe84 --- /dev/null +++ b/ci/lab03-jenkins/templates/general/Jenkinsfile @@ -0,0 +1,146 @@ +/* + +# 功能描述 + +构建基础镜像 + +# 参数配置 + +```yaml + +coderepo: + auth: xxx + url: xxx + branch: mkt4d + +registry: + url: xxx + auth: xxx + +pipeline: + build: + script: | + # 配置环境变量 + # 使用 dapper 编译代码 + dapper -m bind + + archive: + script: | + # 打包镜像 + docker build -t $DOCKER_REG/xxx/xxx:version . -f Dockerfile + docker push $DOCKER_REG/xxx/xxx:version + + deploy: + image: xxx/xxx + kubeconfig: xxx # credential id. + script: | + kubectl set image =$DOCKER_REG/xxx/xxx:version -n + kubectl rollout status --timeout=300 -n + +``` + +# 插件依赖 + +* https://www.jenkins.io/doc/pipeline/steps/workflow-basic-steps/ +* https://plugins.jenkins.io/docker-workflow/ +* https://www.jenkins.io/doc/book/pipeline/docker/ +* https://docs.cloudbees.com/docs/admin-resources/latest/plugins/docker-workflow +* https://github.com/opsbox-dev/oes-template-plugin + + +# 使用方法 + +演示样例代码:https://jihulab.com/oes-workspace/spring-demo +*/ + +def branch = purgeBranchString(coderepo.branch) + +pipeline { + + agent any + + options { + disableConcurrentBuilds() + skipDefaultCheckout true + } + + stages { + + stage("Checkout Code") { + steps { + script { + deleteDir() + def gitParams = [ + $class : 'GitSCM', + branches : [[name: "${branch}"]], + doGenerateSubmoduleConfigurations: false, + extensions : [[$class: 'CleanBeforeCheckout']], + submoduleCfg : [], + userRemoteConfigs : [[url: "${coderepo.url}"]] + ] + if (coderepo.auth != null) { + gitParams.userRemoteConfigs = [[credentialsId: "${coderepo.auth}", + url : "${coderepo.url}"]] + } + checkout(gitParams) + } + } + } // end: Checkout Code + + stage("build") { + steps { + script { + docker.withRegistry("https://${registry.url}", "${registry.auth}") { + sh """ + ${pipeline.build.script} + """.stripIndent() + } + } + } + } + + stage("archive") { + steps { + script { + docker.withRegistry("https://${registry.url}", "${registry.auth}") { + sh """ + export DOCKER_REG=${registry.url} + ${pipeline.build.script} + """.stripIndent() + } + } + } + } + + stage("deploy") { + environment { + KUBECONFIG = credentials("${pipeline.deploy.kubeconfig}") + } + steps { + script { + docker.withRegistry("https://${registry.url}", "${registry.auth}") { + docker.image("${pipeline.deploy.image}").inside("-e KUBECONFIG=/root/.kube/config -v ${KUBECONFIG}:/root/.kube/config") { + sh """ + ${pipeline.deploy.script} + """.stripIndent() + } + } + } + } + } // end deploy stage. + } +} + +def purgeBranchString(branch) { + def gitBranch = branch + if (gitBranch?.startsWith("refs/heads/")) { + gitBranch = gitBranch.replace("refs/heads/", "") + if (gitBranch != "main") { + error("--//INFO: 不支持除 main 之外的分支") + } + } + if (gitBranch?.startsWith("refs/tags/")) { + gitBranch = gitBranch.replace("refs/tags/", "") + } + return gitBranch +}