├── 20210206-微服务CI-CD实践.pdf ├── README.md ├── docs ├── Gitlab部署文档.pdf ├── Jenkins安装部署.pdf ├── Jira部署文档.pdf ├── Kubernetes 集群安装.pdf ├── README.md ├── SonarQube 部署文档.pdf └── 微服务CI-CD实践训练营.pdf ├── images ├── README.md └── gitlab │ └── README.md ├── jenkinsfiles ├── cd-scheduler.jenkinsfile ├── cd.jenkinsfile ├── ci-scheduler.jenkinsfile ├── ci.jenkinsfile └── jira.jenkinsfile ├── microservice-demo-service-master.zip ├── microservicecicd-env-master.zip └── microservicecicd-pipeline-dir.tar.gz /20210206-微服务CI-CD实践.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevOpsCICDCourse/microservicescicd/0bc30a138e4d8b0b730e18786483036269a9a211/20210206-微服务CI-CD实践.pdf -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 微服务CI/CD实践课程 2 | 3 | ## 直播安排 4 | 5 | - 直播时间: 6 | - - 2021-02-06 (10点-12点)(14点-16点)(18点-20点) 7 | 8 | 9 | 10 | ## 准备文档 11 | 关于训练营的准备工作,只需要一套DevOps基础环境,涉及到一些工具的安装。(Jira +GitLab + Jenkins + SonarQube + k8s) 12 | https://github.com/DevOpsCICDCourse/microservicescicd/tree/main/docs 13 | 14 | 15 | --- 16 | 17 | 18 | ## 推荐课程 19 | 20 | - [Jenkins实践](https://youdianzhishi.com/web/course/1013) 21 | 22 | - [GitLabCI实践](https://youdianzhishi.com/web/course/1016) 23 | 24 | - [Spinnaker实践](https://youdianzhishi.com/web/course/1020) 25 | 26 | - [Kubernetes实践](https://youdianzhishi.com/web/course/1007) 27 | 28 | ### Kubernetes实践训练营 29 | - [第二期](https://youdianzhishi.com/web/course/1022) 30 | - [第一期](https://youdianzhishi.com/web/course/1012) 31 | -------------------------------------------------------------------------------- /docs/Gitlab部署文档.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevOpsCICDCourse/microservicescicd/0bc30a138e4d8b0b730e18786483036269a9a211/docs/Gitlab部署文档.pdf -------------------------------------------------------------------------------- /docs/Jenkins安装部署.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevOpsCICDCourse/microservicescicd/0bc30a138e4d8b0b730e18786483036269a9a211/docs/Jenkins安装部署.pdf -------------------------------------------------------------------------------- /docs/Jira部署文档.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevOpsCICDCourse/microservicescicd/0bc30a138e4d8b0b730e18786483036269a9a211/docs/Jira部署文档.pdf -------------------------------------------------------------------------------- /docs/Kubernetes 集群安装.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevOpsCICDCourse/microservicescicd/0bc30a138e4d8b0b730e18786483036269a9a211/docs/Kubernetes 集群安装.pdf -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | ## 微服务CI/CD实践课程文档 2 | 3 | 4 | - Jira安装部署 5 | - GitLab安装部署 6 | - SonarQube安装部署 7 | - K8s安装部署 8 | -------------------------------------------------------------------------------- /docs/SonarQube 部署文档.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevOpsCICDCourse/microservicescicd/0bc30a138e4d8b0b730e18786483036269a9a211/docs/SonarQube 部署文档.pdf -------------------------------------------------------------------------------- /docs/微服务CI-CD实践训练营.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevOpsCICDCourse/microservicescicd/0bc30a138e4d8b0b730e18786483036269a9a211/docs/微服务CI-CD实践训练营.pdf -------------------------------------------------------------------------------- /images/README.md: -------------------------------------------------------------------------------- 1 | ## Docs Images 2 | -------------------------------------------------------------------------------- /images/gitlab/README.md: -------------------------------------------------------------------------------- 1 | ## Gitlab images 2 | -------------------------------------------------------------------------------- /jenkinsfiles/cd-scheduler.jenkinsfile: -------------------------------------------------------------------------------- 1 | 2 | pipeline { 3 | agent any 4 | 5 | stages { 6 | stage('GetCommitService') { 7 | steps { 8 | script{ 9 | echo 'Hello World' 10 | echo "${WebHookData}" 11 | 12 | // Git Info 13 | webhookdata = readJSON text: """${WebHookData}""" 14 | eventType = webhookdata["object_kind"] 15 | commits = webhookdata["commits"] 16 | branchName = webhookdata["ref"] - "refs/heads/" 17 | projectID = webhookdata["project_id"] 18 | commitID = webhookdata["checkout_sha"] 19 | 20 | 21 | changeServices = [] 22 | for(commit in commits) { 23 | println(commit.id) 24 | 25 | //added 26 | for (add in commit.added) { 27 | s = add.split("/") as List 28 | if (s.size() > 1){ 29 | if (changeServices.indexOf(s[0]) == -1){ 30 | changeServices.add(s[0]) 31 | } 32 | } 33 | } 34 | 35 | //modified 36 | for (m in commit.modified) { 37 | s = m.split("/") as List 38 | // println s 39 | // println s.size() 40 | // println s[0] 41 | if (s.size() > 1){ 42 | // println changeServices.indexOf(s[0]) 43 | if (changeServices.indexOf(s[0]) == -1){ 44 | changeServices.add(s[0]) 45 | } 46 | } 47 | } 48 | 49 | //removed 50 | for (r in commit.removed) { 51 | s = r.split("/") as List 52 | println s 53 | if (s.size() > 1){ 54 | if (changeServices.indexOf(s[0]) == -1){ 55 | changeServices.add(s[0]) 56 | } 57 | } 58 | } 59 | } 60 | 61 | println(changeServices) 62 | currentBuild.description = " Trigger by ${eventType} ${changeServices} " 63 | } 64 | } 65 | } 66 | 67 | stage('DefineService') { 68 | steps { 69 | script{ 70 | println(changeServices) 71 | //服务构建顺序控制 72 | services = ['service02', 'service01'] 73 | for (service in services){ 74 | if (changeServices.indexOf(service) != -1){ 75 | jobName = 'microservicecicd-'+service+'-service-CD' 76 | build job: jobName, wait: false, parameters: [string(name: 'branchName', value: "${branchName}" )] 77 | } 78 | } 79 | } 80 | } 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /jenkinsfiles/cd.jenkinsfile: -------------------------------------------------------------------------------- 1 | String serviceName ="${JOB_NAME}".split("-")[1] 2 | String nameSpace = "${JOB_NAME}".split("-")[0].split("/")[-1] 3 | 4 | 5 | //pipeline 6 | pipeline{ 7 | agent { node { label "k8s"}} 8 | 9 | stages{ 10 | 11 | stage("GetCode"){ 12 | steps{ 13 | script{ 14 | println("${branchName}") 15 | println("${env.branchName}".contains("RELEASE-")) 16 | println "获取代码" 17 | checkout([$class: 'GitSCM', branches: [[name: "${env.branchName}"]], 18 | doGenerateSubmoduleConfigurations: false, 19 | extensions: [[$class: 'SparseCheckoutPaths', 20 | sparseCheckoutPaths: [[path: "${serviceName}"]]]], 21 | submoduleCfg: [], 22 | userRemoteConfigs: [[credentialsId: 'gitlab-admin-user', url: "http://gitlab.idevops.site/microservicecicd/microservicecicd-env.git"]]]) 23 | } 24 | } 25 | } 26 | 27 | stage("HelmDeploy"){ 28 | steps{ 29 | script{ 30 | sh """ 31 | kubectl create ns "${nameSpace}-uat" || echo false 32 | 33 | helm install "${serviceName}" --namespace "${nameSpace}-uat" ./"${serviceName}" || helm upgrade "${serviceName}" --namespace "${nameSpace}-uat" ./"${serviceName}" 34 | 35 | helm list --namespace "${nameSpace}-uat" 36 | helm history "${serviceName}" --namespace "${nameSpace}-uat" 37 | 38 | """ 39 | } 40 | } 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /jenkinsfiles/ci-scheduler.jenkinsfile: -------------------------------------------------------------------------------- 1 | pipeline { 2 | 3 | agent any 4 | 5 | 6 | stages{ 7 | 8 | stage("GetData"){ 9 | steps{ 10 | script { 11 | echo "${webHookData}" 12 | 13 | data = readJSON text: "${webHookData}" 14 | 15 | println(data) 16 | 17 | env.branchName = data.ref - "refs/heads/" 18 | env.commitId = data.checkout_sha 19 | env.projectId = data.project_id 20 | commits = data["commits"] 21 | 22 | println("${env.branchName}") 23 | println("${env.commitID}") 24 | println("${env.projectId}") 25 | 26 | //env.moduleName = "service01" 27 | changeServices = [] 28 | for(commit in commits) { 29 | println(commit.id) 30 | 31 | //added 32 | for (add in commit.added) { 33 | s = add.split("/") as List 34 | if (s.size() > 1){ 35 | if (changeServices.indexOf(s[0]) == -1){ 36 | changeServices.add(s[0]) 37 | } 38 | } 39 | } 40 | 41 | //modified 42 | for (m in commit.modified) { 43 | s = m.split("/") as List 44 | // println s 45 | // println s.size() 46 | // println s[0] 47 | if (s.size() > 1){ 48 | // println changeServices.indexOf(s[0]) 49 | if (changeServices.indexOf(s[0]) == -1){ 50 | changeServices.add(s[0]) 51 | } 52 | } 53 | } 54 | 55 | //removed 56 | for (r in commit.removed) { 57 | s = r.split("/") as List 58 | println s 59 | if (s.size() > 1){ 60 | if (changeServices.indexOf(s[0]) == -1){ 61 | changeServices.add(s[0]) 62 | } 63 | } 64 | } 65 | } 66 | 67 | println(changeServices) 68 | //currentBuild.description = " Trigger by ${eventType} ${changeServices} 69 | } 70 | } 71 | } 72 | 73 | stage('DefineService') { 74 | steps { 75 | script{ 76 | println(changeServices) 77 | //服务构建顺序控制 78 | services = ['service02', 'service01'] 79 | for (service in services){ 80 | if (changeServices.indexOf(service) != -1){ 81 | jobName = 'microservicecicd-'+service+'-service-CI' 82 | build job: jobName, wait: false, parameters: [string(name: 'branchName', value: "${env.branchName}" ), 83 | string(name: 'commitId', value: "${env.commitId}" ), 84 | string(name: 'projectId', value: "${env.projectId}" )] 85 | } 86 | } 87 | } 88 | } 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /jenkinsfiles/ci.jenkinsfile: -------------------------------------------------------------------------------- 1 | 2 | String branchName = "${env.branchName}" 3 | String moduleName = "${JOB_NAME}".split("/")[1].split("-")[1] 4 | String srcUrl = "http://gitlab.idevops.site/microservicecicd/microservicecicd-demo-service.git" 5 | String commitId = "${env.commitId}" 6 | String projectId = "${env.projectId}" 7 | 8 | pipeline { 9 | agent { node { label "build" } } 10 | 11 | stages { 12 | stage('GetCode') { 13 | steps { 14 | script { 15 | checkout([$class: 'GitSCM', 16 | branches: [[name: "${branchName}"]], 17 | doGenerateSubmoduleConfigurations: false, 18 | extensions: [[$class: 'SparseCheckoutPaths', 19 | sparseCheckoutPaths: [[path: "${moduleName}"],[path: 'Dockerfile']]]], 20 | submoduleCfg: [], 21 | userRemoteConfigs: [[credentialsId: 'gitlab-admin-user', 22 | url: "${srcUrl}"]]]) 23 | } 24 | 25 | } 26 | } 27 | 28 | stage("Build&Test"){ 29 | steps{ 30 | script{ 31 | echo "Build..........." 32 | 33 | sh """ 34 | cd ${moduleName} 35 | mvn clean package 36 | 37 | """ 38 | } 39 | } 40 | post { 41 | always { 42 | junit "${moduleName}/target/surefire-reports/*.xml" 43 | } 44 | } 45 | } 46 | 47 | stage("SonarScan"){ 48 | steps{ 49 | script{ 50 | 51 | def sonarDate = sh returnStdout: true, script: 'date +%Y%m%d%H%M%S' 52 | sonarDate = sonarDate - "\n" 53 | 54 | withCredentials([string(credentialsId: 'sonar-admin-user', variable: 'sonartoken'), 55 | string(credentialsId: 'gitlab-user-token', variable: 'gitlabtoken')]) { 56 | // some block 57 | sh """ 58 | cd ${moduleName} 59 | sonar-scanner \ 60 | -Dsonar.projectKey=${JOB_NAME} \ 61 | -Dsonar.projectName=${JOB_NAME} \ 62 | -Dsonar.projectVersion=${sonarDate} \ 63 | -Dsonar.ws.timeout=30 \ 64 | -Dsonar.projectDescription="xxxxxxx" \ 65 | -Dsonar.links.homepage=http://www.baidu.com \ 66 | -Dsonar.sources=src \ 67 | -Dsonar.sourceEncoding=UTF-8 \ 68 | -Dsonar.java.binaries=target/classes \ 69 | -Dsonar.java.test.binaries=target/test-classes \ 70 | -Dsonar.java.surefire.report=target/surefire-reports \ 71 | -Dsonar.host.url="http://sonar.idevops.site" \ 72 | -Dsonar.login=${sonartoken} \ 73 | -Dsonar.gitlab.commit_sha=${commitId} \ 74 | -Dsonar.gitlab.ref_name=${branchName} \ 75 | -Dsonar.gitlab.project_id=${projectId} \ 76 | -Dsonar.dynamicAnalysis=reuseReports \ 77 | -Dsonar.gitlab.failure_notification_mode=commit-status \ 78 | -Dsonar.gitlab.url=http://gitlab.idevops.site \ 79 | -Dsonar.gitlab.user_token=${gitlabtoken} \ 80 | -Dsonar.gitlab.api_version=v4 81 | 82 | """ 83 | 84 | } 85 | 86 | } 87 | } 88 | } 89 | 90 | stage("BuildImage"){ 91 | steps{ 92 | script{ 93 | 94 | withCredentials([usernamePassword(credentialsId: 'aliyun-registry-admin', passwordVariable: 'password', usernameVariable: 'username')]) { 95 | 96 | env.nowDate = sh returnStdout: true, script: 'date +%Y%m%d%H%M%S' 97 | env.nowDate = env.nowDate - "\n" 98 | 99 | env.releaseVersion = "${env.branchName}" 100 | env.imageTag = "${releaseVersion}-${nowDate}-${commitId}" 101 | env.dockerImage = "registry.cn-beijing.aliyuncs.com/microservicecicd/microservicecicd-${moduleName}-service:${env.imageTag}" 102 | env.jarName = "${moduleName}-${branchName}-${commitId}" 103 | sh """ 104 | docker login -u ${username} -p ${password} registry.cn-beijing.aliyuncs.com 105 | cd ${moduleName} && docker build -t ${dockerImage} -f ../Dockerfile --build-arg SERVICE_NAME=${jarName} . 106 | sleep 1 107 | docker push ${dockerImage} 108 | sleep 1 109 | docker rmi ${dockerImage} 110 | """ 111 | } 112 | 113 | 114 | } 115 | } 116 | } 117 | 118 | stage("PushFile"){ 119 | // when { 120 | // expression { "${env.branchName}".contains("RELEASE-") } 121 | // } 122 | steps{ 123 | script{ 124 | if ("${env.branchName}".contains("RELEASE-")){ 125 | println("branchName = branchName") 126 | env.branchName = "master" 127 | 128 | } else { 129 | env.branchName = "feature" 130 | } 131 | 132 | for (i = 0; i < 3; i++) { 133 | //下载版本库文件 134 | response = GetRepoFile(40,"${moduleName}%2fvalues.yaml", "${env.branchName}") 135 | //println(response) 136 | 137 | //替换文件中内容 138 | yamlData = readYaml text: """${response}""" 139 | 140 | println(yamlData.image.version) 141 | println(yamlData.image.commit) 142 | yamlData.image.version = "${releaseVersion}-${env.nowDate}" 143 | yamlData.image.commit = "${commitId}" 144 | 145 | println(yamlData.toString()) 146 | 147 | sh "rm -fr test.yaml" 148 | writeYaml charset: 'UTF-8', data: yamlData, file: 'test.yaml' 149 | newYaml = sh returnStdout: true, script: 'cat test.yaml' 150 | 151 | println(newYaml) 152 | //更新gitlab文件内容 153 | base64Content = newYaml.bytes.encodeBase64().toString() 154 | 155 | // 会有并行问题,同时更新报错 156 | try { 157 | UpdateRepoFile(40,"${moduleName}%2fvalues.yaml",base64Content, "${env.branchName}") 158 | break; 159 | } catch(e){ 160 | sh "sleep 2" 161 | continue; 162 | } 163 | } 164 | } 165 | } 166 | } 167 | } 168 | } 169 | 170 | //封装HTTP请求 171 | def HttpReq(reqType,reqUrl,reqBody){ 172 | def gitServer = "http://gitlab.idevops.site/api/v4" 173 | withCredentials([string(credentialsId: 'gitlab-token', variable: 'gitlabToken')]) { 174 | result = httpRequest customHeaders: [[maskValue: true, name: 'PRIVATE-TOKEN', value: "${gitlabToken}"]], 175 | httpMode: reqType, 176 | contentType: "APPLICATION_JSON", 177 | consoleLogResponseBody: true, 178 | ignoreSslErrors: true, 179 | requestBody: reqBody, 180 | url: "${gitServer}/${reqUrl}" 181 | //quiet: true 182 | } 183 | return result 184 | } 185 | 186 | 187 | //获取文件内容 188 | def GetRepoFile(projectId,filePath,branchName){ 189 | apiUrl = "projects/${projectId}/repository/files/${filePath}/raw?ref=${branchName}" 190 | response = HttpReq('GET',apiUrl,'') 191 | return response.content 192 | } 193 | 194 | //更新文件内容 195 | def UpdateRepoFile(projectId,filePath,fileContent, branchName){ 196 | apiUrl = "projects/${projectId}/repository/files/${filePath}" 197 | reqBody = """{"branch": "${branchName}","encoding":"base64", "content": "${fileContent}", "commit_message": "update a new file"}""" 198 | response = HttpReq('PUT',apiUrl,reqBody) 199 | println(response) 200 | 201 | } 202 | -------------------------------------------------------------------------------- /jenkinsfiles/jira.jenkinsfile: -------------------------------------------------------------------------------- 1 | 2 | pipeline { 3 | agent { node { label "build"}} 4 | 5 | stages{ 6 | 7 | stage("FileterData"){ 8 | steps{ 9 | script{ 10 | response = readJSON text: """${webHookData}""" 11 | 12 | println(response) 13 | 14 | env.eventType = response["webhookEvent"] 15 | 16 | switch(eventType) { 17 | case ["jira:issue_created" , "jira:issue_updated" ]: 18 | env.issueName = response['issue']['key'] 19 | env.userName = response['user']['name'] 20 | env.moduleNames = response['issue']['fields']['components'] 21 | env.fixVersion = response['issue']['fields']['fixVersions'] 22 | currentBuild.description = " Trigger by ${userName} ${eventType} ${issueName} " 23 | break 24 | 25 | 26 | default: 27 | println("hello") 28 | } 29 | } 30 | } 31 | } 32 | 33 | stage("CreateBranchOrMR"){ 34 | 35 | when { 36 | anyOf { 37 | environment name: 'eventType', value: 'jira:issue_created' //issue 创建 /更新 38 | environment name: 'eventType', value: 'jira:issue_updated' 39 | } 40 | } 41 | 42 | steps{ 43 | script{ 44 | def projectIds = [] 45 | println(issueName) 46 | fixVersion = readJSON text: """${fixVersion}""" 47 | println(fixVersion.size()) 48 | 49 | //获取项目Id 50 | def projects = readJSON text: """${moduleNames}""" 51 | for ( project in projects){ 52 | println(project["name"]) 53 | projectName = project["name"] 54 | currentBuild.description += "\n project: ${projectName}" 55 | groupName = projectName.split("-")[0] 56 | 57 | try { 58 | projectId = GetProjectID(groupName, projectName) 59 | println(projectId) 60 | projectIds.add(projectId) 61 | } catch(e){ 62 | println(e) 63 | println("未获取到项目ID,请检查模块名称!") 64 | } 65 | } 66 | 67 | println(projectIds) 68 | 69 | 70 | if (fixVersion.size() == 0) { 71 | for (id in projectIds){ 72 | println("新建特性分支--> ${id} --> ${issueName}") 73 | currentBuild.description += "\n 新建特性分支--> ${id} --> ${issueName}" 74 | CreateBranch(id,"master","${issueName}") 75 | } 76 | 77 | 78 | 79 | } else { 80 | fixVersion = fixVersion[0]['name'] 81 | println("Issue关联release操作,Jenkins创建合并请求") 82 | currentBuild.description += "\n Issue关联release操作,Jenkins创建合并请求 \n ${issueName} --> RELEASE-${fixVersion}" 83 | 84 | for (id in projectIds){ 85 | 86 | println("创建RELEASE-->${id} -->${fixVersion}分支") 87 | CreateBranch(id,"master","RELEASE-${fixVersion}") 88 | 89 | 90 | 91 | println("创建合并请求 ${issueName} ---> RELEASE-${fixVersion}") 92 | CreateMr(id,"${issueName}","RELEASE-${fixVersion}","${issueName}--->RELEASE-${fixVersion}") 93 | 94 | } 95 | } 96 | } 97 | } 98 | } 99 | } 100 | } 101 | 102 | //封装HTTP请求 103 | def HttpReq(reqType,reqUrl,reqBody){ 104 | def gitServer = "http://gitlab.idevops.site/api/v4" 105 | withCredentials([string(credentialsId: 'gitlab-token', variable: 'gitlabToken')]) { 106 | result = httpRequest customHeaders: [[maskValue: true, name: 'PRIVATE-TOKEN', value: "${gitlabToken}"]], 107 | httpMode: reqType, 108 | contentType: "APPLICATION_JSON", 109 | consoleLogResponseBody: true, 110 | ignoreSslErrors: true, 111 | requestBody: reqBody, 112 | url: "${gitServer}/${reqUrl}" 113 | //quiet: true 114 | } 115 | return result 116 | } 117 | //获取项目ID 118 | def GetProjectID(repoName='',projectName){ 119 | projectApi = "projects?search=${projectName}" 120 | response = HttpReq('GET',projectApi,'') 121 | def result = readJSON text: """${response.content}""" 122 | 123 | for (repo in result){ 124 | // println(repo['path_with_namespace']) 125 | if (repo['path'] == "${projectName}"){ 126 | 127 | repoId = repo['id'] 128 | println(repoId) 129 | } 130 | } 131 | return repoId 132 | } 133 | 134 | 135 | //创建分支 136 | def CreateBranch(projectId,refBranch,newBranch){ 137 | try { 138 | branchApi = "projects/${projectId}/repository/branches?branch=${newBranch}&ref=${refBranch}" 139 | response = HttpReq("POST",branchApi,'').content 140 | branchInfo = readJSON text: """${response}""" 141 | } catch(e){ 142 | println(e) 143 | } //println(branchInfo) 144 | } 145 | 146 | //创建合并请求 147 | def CreateMr(projectId,sourceBranch,targetBranch,title,assigneeUser=""){ 148 | try { 149 | def mrUrl = "projects/${projectId}/merge_requests" 150 | def reqBody = """{"source_branch":"${sourceBranch}", "target_branch": "${targetBranch}","title":"${title}","assignee_id":"${assigneeUser}"}""" 151 | response = HttpReq("POST",mrUrl,reqBody).content 152 | return response 153 | } catch(e){ 154 | println(e) 155 | } 156 | } 157 | 158 | -------------------------------------------------------------------------------- /microservice-demo-service-master.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevOpsCICDCourse/microservicescicd/0bc30a138e4d8b0b730e18786483036269a9a211/microservice-demo-service-master.zip -------------------------------------------------------------------------------- /microservicecicd-env-master.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevOpsCICDCourse/microservicescicd/0bc30a138e4d8b0b730e18786483036269a9a211/microservicecicd-env-master.zip -------------------------------------------------------------------------------- /microservicecicd-pipeline-dir.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevOpsCICDCourse/microservicescicd/0bc30a138e4d8b0b730e18786483036269a9a211/microservicecicd-pipeline-dir.tar.gz --------------------------------------------------------------------------------