V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
爱意满满的作品展示区。
codelover2016
V2EX  ›  分享创造

手把手教你用 Jenkins CI 自动部署 Docker(阿里云镜像服务自动构建+ webhook 触发)

  •  
  •   codelover2016 ·
    liguobao · 2018-05-07 16:46:30 +08:00 · 6769 次点击
    这是一个创建于 2392 天前的主题,其中的信息可能已经有所发展或是发生改变。

    Jenkins 部分

    首先,我们要有个 Jenkins 咯,下载链接:https://jenkins.io/download/

    我们安装官网教程安装好 jenkins,安装教程略....

    嗯?不是说好手把手么?你妹的.

    好好好,我们还是来手把手教程好了.

    首先安装 JDK8

    添加安装源之后直接 apt-get install 就好,下面是 ubuntu 的安装命令,其他系统自己玩一下就好.

    
    sudo add-apt-repository ppa:webupd8team/java
    
    sudo apt-get update
    
    sudo apt-get install oracle-java8-installer
    
    

    下载 jenkins.war + 启动 Jenkins

    下载链接:http://mirrors.jenkins.io/war-stable/

    在这里面找最新的下载,我当前最新的应该是2.107.2

    下载好了 jenkins.war 之后,在当前目录创建一个 jenkins-home 文件夹,设置 JENKINS_HOME 环境变量为 jenkins-home(不设置也可以,默认在~/.jenkins)

    
    wget http://mirrors.jenkins.io/war-stable/2.107.2/jenkins.war;
    mkdir ~/jenkins-home;
    export JENKINS_HOME=~/jenkins-home;
    tmux;
    java -jar jenkins.war
    
    

    一般建议开个后台进程来跑 jenkins,免得终端退出之后 jenkins 就死掉了.

    所以上面我先打开了 tmux 之后再跑 java -jar jenkins.war.

    如下图: jenkins 启动

    接着 留意一下 initialAdminPassword 的输出

    
    Jenkins initial setup is required. An admin user has been created and a password generated.
    Please use the following password to proceed to installation:
    
    XXXXXXXXXXXXXX
    
    This may also be found at: /root/jenkins-home/secrets/initialAdminPassword
    

    这个时候访问当前主机的 8080 端口已经可以看到 jenkins 正在启动了,稍等片刻就可以看到 jenkins 登录页.

    这个时候把上面的 XXXXXXXXXXXXXX 复制出来,输进去点击 继续配置 jenkins 账号密码信息之类的.

    配置 jenkins

    接着安装默认插件.

    安装插件

    这里估计也要等几分钟不等,看你的机器性能和网络速度.

    安装好了之后会进入配置登录账号密码,安装提示配置就完事.

    最后 进入 jenkins 页面是这样的. jenkins

    到现在我们已经把 jenkins 跑起来了,也有了一些常用的插件.

    我们先去把 dotnet core docker 编译发布相关的东西弄好之后再回来继续做 jenkins 任务.

    dotnet core docker 打包

    在项目目录下新建 Dockerfile 文件,内容如下:

    
    FROM microsoft/aspnetcore-build:2.0 AS build-env
    WORKDIR /app
    
    # copy csproj and restore as distinct layers
    COPY *.csproj ./
    RUN dotnet restore
    
    # copy everything else and build
    COPY . ./
    RUN dotnet publish -c Release -o out
    
    # build runtime image
    FROM microsoft/aspnetcore:2.0
    WORKDIR /app
    COPY --from=build-env /app/out .
    ENTRYPOINT ["dotnet", "你的 dotnet core 程序.dll"]
    
    

    这个 Dockerfile 基本就是把当前目录的 文件 拷贝到 aspnetcore-build 镜像中,再里面编译好之后再发布到 aspnetcore:2.0 镜像 中,

    最后指定运行你的 dotnet core 程序

    来源:https://github.com/DaoCloud/dotnet-docker-samples

    docker build + run 脚本(非必须,可以使用 jenkins 中脚本编译替代)

    HouseCrawler.Web为例,

    
    #!/bin/sh
    image_version=`date +%Y%m%d%H%M`;
    echo $image_version;
    cd ~/code/58HouseSearch/HouseCrawler.Core/HouseCrawler.Web;
    git pull --rebase origin master;
    docker stop house-web;
    docker rm house-web;
    docker build -t house-web:$image_version .;
    docker images;
    docker run -p 8080:80 -v ~/docker-data/house-web/appsettings.json:/app/appsettings.json -v ~/docker-data/house-web/NLogFile/:/app/NLogFile  --restart=always --name house-web -d house-web:$image_version;
    docker logs house-web;
    
    

    通过上面这个 build+run 脚本,我们已经把 dotnet core 程序编译好了,并且打包成了 docker images,还直接跑起来了.

    但是我们想要的应该是自动化编译部署,而且上面我们都把 jenkins 跑起来了,所以....

    jenkins job 配置

    新建 Job

    打开 jenkins 首页,左侧选择"新建任务"(newJob),如下图:

    newJob

    给新的 job 取个名字,然后选择"构建自由风格的软件项目",如图:

    构建自由风格的软件项目

    添加源码仓库

    确认之后进入 Job 配置页面,源码管理里面选择 git,如图: 源码管理

    如果 git 仓库是需要权限的话需要配置一下权限,我一般简单粗暴直接把 jenkins 主机的公钥添加到 git 仓库里面,所以这里直接配置成'From the Jenkins master ~/.ssh',也可以用账号密码访问等等的.

    git 仓库权限配置

    "Branch Specifier (blank for 'any') "默认 master 分支,根据自己的需求填入不同的分支.

    构建触发器和构建环境先跳过,我们不管,待会弄.

    构建

    点击"添加构建步骤",选择"Execute shell",然后能看到如下图: Execute shell

    还记得我们上一步的脚本么?修改一下源码路径再放进去.

    # 切换到源码目录,对应在 jenkins-home 的 workspace 下面
    cd ~jenkins-home/workspace/项目名称 /Dockerfile 所在目录;
    image_version=`date +%Y%m%d%H%M`;
    echo $image_version;
    # 停止之前的 docker container
    docker stop house-web;
    # 删除这个 container
    docker rm house-web;
    # build 镜像并且打上 tag
    docker build -t house-web:$image_version .;
    docker images;
    # 把刚刚 build 出来的镜像跑起来
    docker run -p 8080:80 -v ~/docker-data/house-web/appsettings.json:/app/appsettings.json -v ~/docker-data/house-web/NLogFile/:/app/NLogFile  --restart=always --name house-web -d house-web:$image_version;
    docker logs house-web;
    

    如果 jenkins 主机和程序运行主机不在一台机器上,建议直接在把上面的脚本放在运行主机上,命名成 start_XXX.sh.

    上面的命令直接就是成了

    ssh username@发布主机的 IP '~/start_XXX.sh'
    

    ps:记得在 jenkins 主机配置ssh 免登陆

    构建触发器

    构建触发器就是我们选择什么时候来触发构建任务,有几种方案可以做.

    1. 使用 Build periodically,定时 or 隔 N 久去拉一次代码构建
    2. Poll SCM:定时检查源码变更(根据 SCM 软件的版本号),如果有变化就去执行构建
    3. GitHub hook trigger for GITScm polling 或者其他 Git 平台提供的 webhook
    4. 安装 Generic Webhook Trigger 插件之后,使用其他平台的 webhook 来触发构建任务.

    我这里选择第 4 种方案,安装 Generic Webhook Trigger 插件,下面马上回告诉你为什么这样做的.

    Generic Webhook Trigger 插件在"系统管理-管理插件-可选插件"里面直接搜"Generic Webhook Trigger"安装就可以.

    从上一步的构建步骤里面的脚本中我们就知道,其实我们现在要不就在 jenkins 主机上 docker build,要不就在发布目标主机上 build,

    build 过程比较慢而且还会产生镜像在本机 or 目标主机上,docker images 也没有被管理起来.

    有什么好的办法么?嗯,还真有.直接用阿里云"容器镜像服务"来构建镜像

    使用阿里云-容器镜像服务

    首先登录阿里云,然后进入容器镜像服务,地址是https://cr.console.aliyun.com/

    首次进入估计需要创建一个命名空间,一般用公司名或者你的名字就完事.

    接着选择"创建镜像仓库".

    创建镜像仓库

    选地区-选命名空间-填仓库名称(就是镜像名称)-填摘要-设置代码源(支持 GitHub/阿里云 code/Bitbucket/私有 Gitlab/本地 Git 等等,给个授权就完事)

    选地区

    构建设置选择"代码变更时自动构建镜像",然后选一下构建分支为你想要的分支,填入 Dockerfile 在源码中的路径,然后保存 构建分支

    接着我们进入管理平台看一下.

    aliyun-构建

    点击一下"立即构建",然后查看一下日志. build 日志

    构建成功

    这个时候,我们用 docker pull registry-internal.cn-hangzhou.aliyuncs.com/你的命名空间 /你的镜像名称 就可以拉到这个阿里云 build 成功的镜像了.

    镜像 build 的问题解决了,那么我们怎么自动把镜像发布到我们的运行主机呢?

    这时候 webhook 又出来了.

    jenkins webhook 触发配置

    我们看阿里云镜像构建服务里面,有一项是 webhook 的,官方介绍在这里:阿里云-webhook 管理

    阿里云-webhook 管理

    这里就需要填入我们的 webhook 地址,还记得前面我无端端选择的第四种方案,然后让大家跟着安装的 Generic Webhook Trigger 插件么?

    我们就是用这货来为我们提供 webhook API.

    理一下流程:

    git 仓库代码变化 ->阿里云容器构建服务启动 -> 构建好镜像之后触发 webhook -> jenkins 收到阿里云的 webhook 之后触发 job 执行部署脚本 ->部署脚本使用阿里云镜像 run 起来 ->完事.

    我们继续配置 Generic Webhook Trigger.

    Generic Webhook Trigger 支持的命名触发 URL 格式是这样的:

    http://jenkins 登录用户名:token 授权码 @jenkins IP:8080/generic-webhook-trigger/invoke?token=触发器名称
    

    jenkins 登录名和 token 在"账号-设置-API Token-Show API Token..."里面能看到,找出来之后填到上面去就可以.

    最后一个 token 参数其实就是"构建触发器"中"触发远程构建"的参数,建议使用 job 名字.这里的配置大概是这样的:

    触发远程构建

    最后我们还需要在 jenkins 全局安全设置中取消勾选“防止跨站点请求伪造( Prevent Cross Site Request Forgery exploits)"选项,这样阿里云 webhook 才能过得来.

    手动在浏览器中访问一下 http://jenkins 登录用户名:token 授权码 @jenkins IP:8080/generic-webhook-trigger/invoke?token=触发器名称 如果对应的 jenkins Job 能正常开始执行,说明整个流程已经 ok 了.

    最后我们回到上面"阿里云-容器镜像服务-对应镜像仓库-webhook-添加记录" webhook-添加记录

    PS:webhook 名称不要带特殊字符 or "-"之类的,不然一直保存失败而且还不会提示你是因为名字不合法,下午被这个坑了半个小时.

    到这里,我们基本大功告成了.

    最后我们再改一下 jenkins 的脚本,不在本地 build docker 了,直接拿 阿里云镜像服务构建出来的镜像跑就可以.

    # 停止之前的 docker container
    docker stop house-web;
    # 删除这个 container
    docker rm house-web;
    docker pull 你的阿里云镜像地址;
    # 把刚刚 build 出来的镜像跑起来
    docker run --restart=always --name 你的 contianer 名称 你的阿里云镜像地址;
    
    

    总结一下我们做了什么

    1. 搭建 jenkins
    2. 编写 Dockerfile 文件,直接编译发布+打包成 docker 镜像+部署脚本
    3. 使用阿里云-容器构建服务构建 docker 镜像, 构建成功后使用 webhook 通知 jenkins
    4. 配置 jenkins webhook 触发器,触发部署脚本
    5. 完事...
    11 条回复    2018-05-08 14:57:09 +08:00
    padeoe
        1
    padeoe  
       2018-05-07 20:05:54 +08:00 via iPhone
    在 docker 里安装 jenkins 岂不更加方便?
    E1n
        2
    E1n  
       2018-05-07 22:30:41 +08:00 via Android
    CI/CD 如何入门啊。
    naiba
        3
    naiba  
       2018-05-07 22:31:23 +08:00 via Android
    gmywq0392
        4
    gmywq0392  
       2018-05-07 23:53:46 +08:00 via Android
    @naiba GoCD 这名字,已经有个先用了,还挺棒的 233333
    coolloves
        5
    coolloves  
       2018-05-08 06:12:43 +08:00 via iPhone
    马克一下,谢谢分享
    codelover2016
        6
    codelover2016  
    OP
       2018-05-08 07:45:01 +08:00
    @padeoe 是的,直接用 docker 跑 jenkins 也是很方便的,不过我之前的需求是 jenkins 还要调用 docker build + kubectl,这也就麻烦点了(外挂进去也是 OK 的)
    codelover2016
        7
    codelover2016  
    OP
       2018-05-08 07:46:52 +08:00
    @E1n 这个文章就是最简单的入门了...
    如果再把 jenkins 和 k8s 打通,基本就是完善的一套 CI/CD 了.
    当然其实也还比较基础...
    携程那边有一套开源的 CD 方案,在 Github 上你可以看看.
    codelover2016
        8
    codelover2016  
    OP
       2018-05-08 07:48:42 +08:00
    @naiba 不错不错.
    naiba
        9
    naiba  
       2018-05-08 08:00:58 +08:00 via Android
    @gmywq0392 GoCD is golang CD😏
    keepcleargas
        10
    keepcleargas  
       2018-05-08 11:15:41 +08:00
    现在 jenkins 不是都用 pipeline build 了吗?
    codelover2016
        11
    codelover2016  
    OP
       2018-05-08 14:57:09 +08:00
    @keepcleargas 是的,我这里手把手教程嘛,等我下次写 jenkins 打通 k8s 的时候估计会涉及到这方面.
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2653 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 03:01 · PVG 11:01 · LAX 19:01 · JFK 22:01
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.