Docker-Racher-Jenkins全自动部署前后端服务

286 阅读6分钟

关闭防火墙

先在Centos7上关闭防火墙,方便验证,等服务全部部署成功后可以根据需要开启哪些端口

查看开放了哪些端口 firewall-cmd --list-all
如果显示为 FirewallD is not running 表示防火墙已关闭
永久打开8080端口
firewall-cmd --permanent --add-port=8080/tcp
执行完后一定要刷新,否则不生效
firewall-cmd --reload

docker安装

关于centos7安装docker的教程很多,这里就展开说了;只说一些注意事项:

  1. 使用阿里云镜像加速,不推荐使用官方的镜像地址,因为很慢
  2. 开启docker自启动,防止机器宕机重启后需要手动启动docker
  3. 修改镜像存储位置,防止镜像文件过多的占用var文件夹
  4. 关于docker远程部署开启2376端口,我的建议是没有安全策略的前提下不要开启,有黑客全网扫描2376端口然后入侵机器挖矿或病毒,我的机器就被入侵过

rancher1.x安装

关于为什么使用1.x的版本而不是使用2.x版本:

  1. ranche1.x相对于2.x版本来说,功能更加简单易上手,维护成本比较低
  2. 对于中小型的分布式或者微服务项目来说,docker的学习和运维成本远低于K8S
  3. rancher2.x的功能相对复杂,更多的功能是为了K8S或者云原生,没有必要将资源浪费在不需要的功能上

话不多说,开始安装rancher

  • docker搜索rancher docker search rancher
  • 选择对应的版本 1.x的版本是 rancher/server 2.x的版本是rancher/rancher
  • 拉取最新版本的镜像 docker pull rancher/server
  • 单节点部署 sudo docker run -d --restart=unless-stopped -v /etc/localtime:/etc/localtime:ro -p 8080:8080 rancher/server
  • 多节点部署参考官方文档
  • 部署完成以后添加主机,可以先创建环境再添加 这个比较简单不多说(rancher右下角可以选择中文)

安装镜像仓库

  1. 个人或者小型项目推荐register
  2. 中大型项目必须使用Harbor
  • 在rancher首页中选择环境,添加应用,添加完成后添加服务
  • register的容器中存储镜像的位置是/var/lib/registry,宿主机可以自己选择

Snipaste_2022-12-22_10-51-03.jpg

jenkins安装

  • 在rancher首页中选择环境,添加应用,添加完成后添加服务
  • 选择镜像填入:jenkins/jenkins:lts最新稳定版
  • 私有容器端口为8080,因为jenkins的服务端口是8080;宿主机端口可以自己设置
  • 滑到最下面选择,然后添加卷
  • 总共需要添加4个卷
/home/jenkins_home:/var/jenkins_home
/var/run/docker.sock:/var/run/docker.sock
/usr/bin/docker:/usr/bin/docker
/etc/localtime:/etc/localtime:ro
  1. 第一个表示将jenkins的所有文件映射到主机,后续方便jenkins升级或者重启时防止数据丢失
  2. 第二个表示将宿主机的docker的进程通信映射到jenkins容器中,这是在容器中使用docker所必须的
  3. 第三个表示将宿主机的docker命令映射到jenkins容器中,可以让jenkins使用docker命令
  4. 第四个表示容器时间与宿主机时间同步
  • 卷添加完后选择命令,然后在工作目录一行选择用户,在用户栏填入0,表示容器以root方式运行
  • 至此jenkins关键信息全部填写完成,创建服务完成后等待服务部署成功
  • 服务部署成功后可以点击端口号直接进入jenkins界面,当然也可以输入ip:port进入

Snipaste_2022-12-22_10-47-35.jpg

使用jenkins

  • 密码在容器日中可以看到
  • 选择推荐插件
  • 进入jenkins主界面 Dashboard
  • 进入系统管理,插件管理里面安装所需要的插件
[Pipeline Maven Integration Plugin](https://plugins.jenkins.io/pipeline-maven)
[Docker Pipeline](https://plugins.jenkins.io/docker-workflow)
[Rancher](https://plugins.jenkins.io/rancher)
[DingTalk](https://plugins.jenkins.io/dingding-notifications)
[NodeJS Plugin](https://plugins.jenkins.io/nodejs)
  1. maven项目 Pipeline Maven Integration Plugin
  2. docker pipeline插件
  3. rancher插件,用于远程自动部署
  4. DingTalk用于钉钉通知
  5. NodeJS用于nodejs项目,比如vue
  • 安装好后重启jenkins:重启方式

    • 1.插件安装完成等待系统空闲自动重启
    • 2.rancher中直接重启jenkins
    • 3.jenkins的IP:PORT/restart重启
  • jenkins配置完成以后,创建钉钉群,添加机器人

  • 添加nodejs,jdk,maven等配置

    • 将宿主机下载好的nodejs,jdk,maven文件复制到jenkins与宿主机映射的目录;比如题主映射的是/home/jenkins_home:/var/jenkins_home;然后进入宿主机的/home/jenkins_home/workspace下,将文件加压出来
  • 配置JDK image.png

  • 配置maven image.png

  • 配置nodejs image.png

注意事项
  1. 别名要规范,在Jenkinsfile中严格对应
  2. 安装目录都是容器内的目录,不是宿主机目录
  • 进入系统管理-Manage Credentials中 image.png 需要添加两个2个凭据 1.rancher的API秘钥(用于自动化部署) image.png 2.git账户的秘钥(用户拉取代码)

关于为什么使用pipeline(管道流)

  1. pipeline是声明式,所有的步骤都是在代码中完成,可控性好,流程清晰
  2. jenkins数据丢失后可以快速的恢复
  3. pipeline使用的是groovy语法,简单明了清晰
  4. 对初中级开发人员不怎么友好

springboot项目使用pipeline

  1. 在项目中创建两个文件夹docker jenkins
  2. 在docker文件夹中创建Dockerfile文件
  3. 在jenkins文件夹中创建Jenkinsfile文件 image.png 废话不多说,直接上jenkinsfile内容,不懂得可以评论区讨论 最终效果是: image.png

image.png

image.png

image.png

image.png

image.png

import java.text.SimpleDateFormat

def project_name = 'zjjg'
def git_account_credentialsId = '0ae8cb60-6585-4ba6-af3c-d9b3f73ec609'
def maven_settings_credentialsId = '3b0d6c7f-0a54-4683-a29c-3e504b8c74b3'
def dingtalk_credentialsId = '58b7a898-819b-4295-8a5c-96aaae63f513'
def image_repo_url = 'IP:5000'
def specificCause = currentBuild.getBuildCauses('hudson.model.Cause$UserIdCause')
def sdf = new SimpleDateFormat("yyyyMMddHHmmss")
def image_version = sdf.format(new Date())
def rancher_credentialsId='149a7d47-d817-4544-9947-be1b177af8a7'
def rancherUrl = 'http://IP:8088/v2-beta'
def rancherEnv = '1a5'
def rancherService = 'service/zjjgjp'
pipeline {
    agent any
    environment {
            applier_name="$specificCause.userName"
        }
    parameters {
        string(name: 'BRANCH', defaultValue:'yuhua-formal' ,description:'选择分支,默认雨花分支')
        choice(name: 'SkipTests', choices: ['true','false'],description: '编译调过单元测试')
        choice(name: 'StartFirst', choices: ['false','true'],description: '是否第一次部署')
        choice(name: 'confirm', choices: ['true','false'],description: '是否升级完成自动确认')
    }

    stages {
        stage('Send dingtalk'){
            steps {
                dingtalk (
                    robot: "${dingtalk_credentialsId}",
                    type: 'MARKDOWN',
                    title: 'XXX后端开始构建',
                    text: ['## XXX',
                            '- 任务:<font color=#6495ED>流水线任务开始执行</font>',
                            '- 状态:<font color=#008000>正常</font>',
                            '- 分支:<font color=#6495ED>${BRANCH}</font>',
                            '- 地址:<font color=#6495ED>[查看](http://IP:9001/job/zjjg/job/zjjg/)</font>',
                            '- 执行人:${applier_name}'],
                )
            }
        }

        stage('Pull Code') {
            steps {
                git branch: "${params.BRANCH}",
                credentialsId: "${git_account_credentialsId}",
                url: 'https://git.jsruiyin.com/niu_123/zjjg.git'
            }
            post {
                failure {
                    dingtalk (
                        robot: "${dingtalk_credentialsId}",
                        type: 'MARKDOWN',
                        title: 'XXX后端构建失败',
                        text: ['## XXX',
                               '- 任务:<font color=#6495ED>流水线任务执行结束</font>',
                               '- 状态:<font color=#FF0000>代码拉取失败</font>',
                               '- 地址:<font color=#6495ED>[查看](http://IP:9001/job/zjjg/job/zjjg/)</font>',
                               '- 执行人:${applier_name}'],
                    )
                }
                aborted {
                    dingtalk (
                            robot: "${dingtalk_credentialsId}",
                            type: 'MARKDOWN',
                            title: 'XXX后端构建失败',
                            text: ['## XXX',
                                   '- 任务:<font color=#6495ED>流水线任务执行结束</font>',
                                   '- 状态:<font color=#FFA500>代码拉取手动终止</font>',
                                   '- 执行人:${applier_name}'],
                    )
                }
            }
        }
        stage('Build Code') {
            steps {
                timeout(time: 30, unit: 'MINUTES') {
                    withMaven(
                            jdk: 'jdk1.8',
                            maven: 'maven',
                            mavenSettingsConfig: "${maven_settings_credentialsId}") {
                        sh "mvn -U clean package -Dmaven.test.skip=${SkipTests}"
                    }
                }
            }
            post {
                failure {
                    dingtalk (
                        robot: "${dingtalk_credentialsId}",
                        type: 'MARKDOWN',
                        title: 'XXX后端构建失败',
                        text: ['## XXX',
                               '- 任务:<font color=#6495ED>流水线任务执行结束</font>',
                               '- 状态:<font color=#FF0000>编译失败</font>',
                               '- 地址:<font color=#6495ED>[查看](http://IP:9001/job/zjjg/job/zjjg/)</font>',
                               '- 执行人:${applier_name}'],
                    )
                }
                aborted {
                    dingtalk (
                            robot: "${dingtalk_credentialsId}",
                            type: 'MARKDOWN',
                            title: 'XXX后端构建失败',
                            text: ['## XXX',
                                   '- 任务:<font color=#6495ED>流水线任务执行结束</font>',
                                   '- 状态:<font color=#FFA500>编译手动终止</font>',
                                   '- 执行人:${applier_name}'],
                    )
                }
            }
        }
        stage('Build Docker Image'){
            steps {
                script {
                    sh "mv target/zjjg.jar docker/zjjg.jar"
                    def customImage = docker.build("${image_repo_url}/${project_name}:${image_version}","-f docker/Dockerfile .")
                    customImage.push()
                    sh "rm -rf docker/zjjg.jar"
                }
            }
            post {
                failure {
                    dingtalk (
                        robot: "${dingtalk_credentialsId}",
                        type: 'MARKDOWN',
                        title: 'XXX后端构建失败',
                        text: ['## XXX',
                               '- 任务:<font color=#6495ED>流水线任务执行结束</font>',
                               '- 状态:<font color=#FF0000>镜像构建失败</font>',
                               '- 地址:<font color=#6495ED>[查看](http://IP:9001/job/zjjg/job/zjjg/)</font>',
                               '- 执行人:${applier_name}'],
                    )
                    script {
                        sh "rm -rf docker/zjjg.jar"
                    }
                }
                aborted {
                    dingtalk (
                            robot: "${dingtalk_credentialsId}",
                            type: 'MARKDOWN',
                            title: 'XXX后端构建失败',
                            text: ['## XXX',
                                   '- 任务:<font color=#6495ED>流水线任务执行结束</font>',
                                   '- 状态:<font color=#FFA500>镜像构建手动终止</font>',
                                   '- 执行人:${applier_name}'],
                    )
                }
            }
        }
        stage('Deploy'){
            steps {
                rancher(
                        environmentId: "${rancherEnv}",
                        endpoint: "${rancherUrl}",
                        credentialId: "${rancher_credentialsId}",
                        service: "${rancherService}",
                        image: "${image_repo_url}/${project_name}:${image_version}",
                        confirm: "${confirm}",
                        startFirst : "${StartFirst}",
                        ports: '8002:8002',
                        environments: '',
                        timeout: 300
                )
            }
            post {
                success {
                    dingtalk (
                        robot: "${dingtalk_credentialsId}",
                        type: 'MARKDOWN',
                        title: 'XXX后端构建完成',
                        text: ['## XXX',
                              '- 任务:<font color=#6495ED>流水线任务执行结束</font>',
                              '- 状态:<font color=#008000>部署成功</font>',
                              '- 执行人:${applier_name}'],
                    )
                }

                failure {
                    dingtalk (
                        robot: "${dingtalk_credentialsId}",
                        type: 'MARKDOWN',
                        title: 'XXX后端构建失败',
                        text: ['## XXX',
                               '- 任务:<font color=#6495ED>流水线任务执行结束</font>',
                               '- 状态:<font color=#FF0000>镜像启动失败</font>',
                               '- 地址:<font color=#6495ED>[查看](http://IP:9001/job/zjjg/job/zjjg/)</font>',
                               '- 执行人:${applier_name}'],
                    )
                }

                changed {
                    script {
                        echo "构建状态和之前不一致"
                    }
                }

                aborted {
                    dingtalk (
                        robot: "${dingtalk_credentialsId}",
                        type: 'MARKDOWN',
                        title: 'XXX后端构建失败',
                        text: ['## XXX',
                               '- 任务:<font color=#6495ED>流水线任务执行结束</font>',
                               '- 状态:<font color=#FFA500>手动终止</font>',
                               '- 执行人:${applier_name}'],
                    )
                }

                unstable {
                    script {
                        echo "构建结果不稳定"
                    }
                }
            }
        }
    }
}