Jenkins一键式构建部署

什么是Jenkins?Jenkins是一个开源软件项目,是基于Java开发的一种持续集成工具,用于监控持续重复的工作,旨在提供一个开放易用的软件平台,使软件的持续集成变成可能。

由于某好友的鼓励及提供, 所以写下了此篇文章, 主要是Jenkins部署项目实在很是方便, 这里用到的方法主要是一键从码云下载项目构建docker镜像, 接着删除老镜像以及已经在docker容器里run起来的项目, 顺便把备份镜像push到自己docker仓库.

流程及准备:

  • docker的安装
  • docker安装Jenkins
  • docker安装Registry镜像仓库
  • 一个可在docker容器里run的项目(DockerFile)
  • 注意: 这里的端口号映射一切可以随自己喜好更改

安装docker

这里使用阿里云的脚本进行安装: curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun

安装完毕后替换一下docker加速源, 加速源自己挑选, 可以选择自己阿里云的

  1. sudo mkdir -p /etc/docker
  2. sudo tee /etc/docker/daemon.json <<-'EOF' { "registry-mirrors": ["加速源地址"] } EOF
  3. sudo systemctl daemon-reload
  4. sudo systemctl restart docker

安装Registry

由于装了这个要修改daemon.json, 安装步骤放在Jenkins前面

  • 修改daemon.json, 加入本机ip+准备映射给registry的端口作为入口: "insecure-registries": ["192.168.65.129:5001"], 重启docker(这里可以和上面写在一起, 就省得2次重启了)

  • docker pull registry
  • docker run --name IMAGE_REGISTRY -d -p 5001:5000 --restart=always -v /opt/registry:/opt/lib/registry registry
  • 查看镜像仓库是否运行

安装Jenkins

  • docker run -p 8080:8080 -p 50000:50000 -v jenkins_data:/var/jenkins_home -v /var/run/docker.sock:/usr/bin/docker jenkinsci/blueocean
  • 初次启动Jenkins会让你做一些简单配置, 以及输入启动密码, 密码在输入完docker命令后出现在控制台

  • sudo chmod -R 777 /var/run/docker.sock, 这部很重要, 因为Jenkins是容器化运行的, 否则后面构建会出现无法访问docker.sock的情况

  • 安装一些插件依赖(系统管理-插件管理-可以选插件搜索:docker), 等待重启

构建准备

前面也说过了, 需要有一个可以在docker容器里正常运行的项目, 我这里使用的是一个python-FastAPI为基础的项目, 可以参考一下我的DockerFile

FROM python:3.8.5

EXPOSE 5000

COPY . /app
WORKDIR /app

RUN pip install -r requirements.txt -i https://pypi.douban.com/simple/

CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "5000"]

项目结构大致是这样的

Jenkins项目配置

  • 选择项目类型

  • 勾选github类型项目以及填写git地址

  • 根据下图勾选和填入地址后添加一个Credentials

  • 添加凭证, 用户名密码是有权限访问此git链接的账户

注意, ID很重要, 涉及到后面Jenkinsfile里的Credentials_ID

  • 最终样式

  • 开始构建项目

完成以上步骤之后就可以愉快的一键git构建docker镜像及发布了, 每当有新版本点一些就完成所有操作

这里附上一些成功构建的样式

  • 构建失败以及成功

上图所示如果出现红框框, 这时候就说明哪个框框对应的步骤出了问题, 这时候就要排查日志, 看看是Jenkinsfile还是你的git项目有问题, 全绿色就代表成功咯, 里面显示的时间是步骤耗时, 对应步骤是Git下载项目 - 构建镜像 - 删除旧容器以及发布新版本 - 删除旧镜像, 这时候最新的容器都会以最新构建的镜像来发布

  • 查看镜像及容器

实际上每构建一次TAG都会+1, 此方法是在Jenkinsfile里实现的

带ip的就是你仓库里保存的镜像, 实际上每次被删除的旧镜像都会备份再/opt/registry路径中

重点: Jenkinsfile

基本上这套代码可以通用任意一个打包docker镜像发布的项目, 供大家参考, 每一个stage就是一个步骤

node {
    try {
        currentBuild.result = "SUCCESS"
        env.IMAGE_TAG = "${env.BUILD_NUMBER}"
        env.NAMESPACE = "default"
        stage('Git') {
            checkout([$class: 'GitSCM', branches: [[name: 'master']],
                 userRemoteConfigs: [[credentialsId: 'book', url: 'https://gitee.com/my_lot/book_api.git']]])
        }
        stage('Build docker image') {
            echo "run Build start"
            dockerImage = "bookimage:${env.BUILD_NUMBER}"
            docker.withRegistry("http://192.168.93.128:5001") {
                docker.withServer(env.BUILD_SERVER) {
                    def customImage = docker.build("${dockerImage}")
                    echo "run push start"
                    echo env.IMAGE_REGISTRY
                    customImage.push()
                    echo "run push end"
                }
            }
            echo "run Build end"
        }
        stage('Deploy') {
            dockerImage = "bookimage:${env.BUILD_NUMBER}"
            docker.withServer(env.BUILD_SERVER) {
                try {
                    sh "docker rm -f web_container"
                } catch(e) {
                    echo e
                }
                echo "run image start"
                docker.image(dockerImage).run("-p 5000:5000 --name web_container")
                echo "run image end"
            }
        }

        stage('clean image') {
            build_number = Integer.parseInt(env.BUILD_NUMBER) - 1
            docker.withServer(env.BUILD_SERVER) {
                try {
                    sh "docker image rm 192.168.93.128:5001/bookimage:${build_number}"
                    sh "docker image rm bookimage:${build_number}"
                } catch (e) {
                    echo "clean image error"
                }
            }
        }
        stage('notifaction') {
            echo "success"
        }
    }
    catch (err) {
        currentBuild.result = "FAILURE"
        echo "failed"
        throw err
    }
}

参数解析:

  • 第4行: env.IMAGE_TAG代表构建的次数
  • 第8行: userRemoteConfigs: [[credentialsId: 'book', url: 'https://gitee.com/my_lot/book_api.git']]]) 里的credentialsId则是配置流水线里提到的
  • 第12行: dockerImage = "bookimage:${env.BUILD_NUMBER}" 代表新构建的镜像名: 次数
  • 第13行: docker.withRegistry("http://192.168.93.128:5001") 代表推送的镜像地址, 如果说你不要备份镜像, 其实这部是可以不要的, 只需要后面的docker.withServer(env.BUILD_SERVER) 以及去掉 customImage.push() 即可, 注意: echo env.IMAGE_REGISTRY , 这里实际上是可以填入docker.withRegistry 里而不需要填ip地址和域名的, 好像是当时调试的时候是在虚拟机, 是nat网络, 没有eth0物理网卡地址, 以至于打印env.IMAGE_REGISTRY 是个null, 至于什么原因得问一些大佬们
  • 第28行: sh "docker rm -f web_container" 删除旧容器
  • 第33行: docker.image(dockerImage).run("-p 5000:5000 --name web_container") 以新镜像运行新容器发布
  • 第39行: build_number = Integer.parseInt(env.BUILD_NUMBER) - 1 构建次数+1
  • 第42-43行: 删除旧镜像

如果本文对你有启发,或者对本文有疑问或者功能 / 方法建议,可以在下方做出评论,或者直接联系我,谢谢您的观看和支持!

添加新评论

本站现已启用评论投票,被点踩过多的评论将自动折叠。与本文无关评论请发留言板。请不要水评论,谢谢。

已有 0条评论