使用docker 部署基于jenkins 的CI/CD 实践

目录

  • show case
  • docker 和jenkins 介绍
  • 使用docker部署jenkins
  • jenkins 的一些常用配置
  • 搭建一个自动集成环境
  • 总结

docker 和jenkins 介绍


  • Docker是目前最流行的虚拟化技术
  • Jenkins是一个开放易用的持续集成工具

Centos 7 安装docker

# 卸载旧版本(如果安装过旧版本的话)
sudo yum remove docker  docker-common docker-selinux docker-engine

# 安装需要的软件包, yum-util 提供yum-config-manager功能,另外两个是devicemapper驱动依赖的
sudo yum install -y yum-utils device-mapper-persistent-data lvm2

# 设置yum源
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

# 可以查看所有仓库中所有docker版本,并选择特定版本安装
yum list docker-ce --showduplicates | sort -r

# 安装docker
sudo yum install docker-ce

# 启动并加入开机启动
sudo systemctl start docker
sudo systemctl enable docker

#验证安装是否成功(有client和service两部分表示docker安装启动都成功了)
docker version

安装nginx

docker pull nginx:latest # 最新版本
docker pull nginx:1.11.1 # 指定版本

通过docker images查看当前的镜像

可以通过镜像id,删除镜像:

docker rmi 8cf1bfb43ff5

注:这里也只能删除没有创建容器的镜像,如果镜像被使用了,就不能删除


运行容器

docker run --name nginx-test -p 8080:80 -d nginx

通过docker ps查看运行中的容器

可以看出容器id为e889f0283dea, 然后停止容器

docker stop e889f0283dea # 停止容器

此时再通过docker ps已经看不到运行中的容器了,但是可以通过docker ps -a查看stop的容器。


可以访问nginx服务了:http://127.0.0.1:8080/


删除容器

docker rm e889f0283dea # 删除指定id的容器
  • 再回顾一下前面启动容器的命令:docker run --name nginx-test -p 8080:80 -d nginx,我们再启动的时候指定了name参数,所以在执行命令的时候,可以用name替代id,比如删除容器可以写为docker rm nginx-test

  • 启动容器的命令中还有-d参数代表在“后台运行”。

  • -p是容器端口映射到本机的端口的参数。


现在,如果我们想修改nginx文件,应该怎么做呢?

  • 首先能想到的是进入容器
docker exec -it e889f0283dea  bash

# 进入容器之后,找到nginx配置文件目录
cd /etc/nginx/conf.d/

接下来按照nginx配置修改即可。


这个方式有点不靠谱

我们用数据卷,加上-v参数

docker run --name nginx-test -p 8080:80 \ 
-v /home/docker-nginx/nginx.conf:/etc/nginx/nginx.conf  \
-v /home/docker-nginx/log:/var/log/nginx \ 
-d \
nginx

这样的话, 直接可以在本地修改配置,不用进入到容器里面了,而且能做到配置持久化


Dockerfile

想想,如果哪天,需要对nginx 配置ssl证书,感觉需求会一直变动,为了对操作步骤自动化,引入Dockerfile. 创建如下目录结构(可以从本项目中看到):

  • config目录中包含了nginx的配置文件
  • ssl目录用来保存ssl证书。

实现简单的Dockerfile文件如下:

FROM nginx:1.11.1

RUN mkdir -p /etc/nginx/ssl \
    mkdir -p /var/www 

COPY ./ssl/ /etc/nginx/ssl/

此镜像继承自nginx:1.11.1, 后面可以配置一些自己的特殊需求。

build镜像

docker build -t my/nginx:v1 . 

后面启动nginx,就可以直接用my/nginx:v1镜像了。


docker-compose

如果想进一步自动化,可以通过配置docker-compose 新建一个docker-compose.yml文件,内容如下:

version: '3'
services: 
  web:
    build: 
      context: ./services/nginx
      dockerfile: Dockerfile
    ports: 
      - "8081:8081"
      - "80:80"

    volumes: 
      - ./services/nginx/config:/etc/nginx/conf.d
      - ./www:/var/www

docker-compose 常用的操作

# build Dockerfile
docker-compose build

# 启动, -d代表后台启动
docker-compose up -d

# stop
docker-compose down

# 进入容器内部
docker-compose exec nginx bash

目前这些都还是单机的,如果想用集群,那么有

Kubernetes(k8s)和Docker swarm

目前k8s完全胜出。


小技巧:快速批量删除 docker 镜像或容器

Docker 本身并没有提供批量删除的功能,当有大量的镜像或者容器需要删除的时候,手动的一个一个删就比较麻烦了。


1. 直接删除所有镜像或容器

# 直接删除所有镜像
docker rmi `docker images -q`

# 直接删除所有容器
docker rm `docker ps -aq`

2. 按条件筛选之后删除

# 按条件筛选之后删除镜像
docker rmi `docker images | grep xxxxx | awk '{print $3}'`

# 按条件筛选之后删除容器
docker rm `docker ps -a | grep xxxxx | awk '{print $1}'`

使用docker部署jenkins


创建如下docker-compose.yml文件

version: '3'
services: 
  web:
    build: 
      context: ./services/nginx
      dockerfile: Dockerfile
    ports: 
      - "8081:8081"
      - "80:80"

    volumes: 
      - ./services/nginx/config:/etc/nginx/conf.d
      - ./www:/var/www
  jenkins:
    image: jenkins:latest
    environment:
        JAVA_OPTS: -Dorg.apache.commons.jelly.tags.fmt.timeZone=Asia/Shanghai
    ports:
        - "50000:50000"
        - "9001:8080"
    volumes:
        - ./app/jenkins:/var/jenkins_home
        - ~/.ssh:/var/jenkins_home/.ssh

ps: 值得注意的是environment部分的JAVA_OPTS配置,能解决时区问题。


配置jenkins的nginx

server {
  listen          80;       # Listen on port 80 for IPv4 requests

  server_name     localhost;
  gzip on;
  gzip_min_length 1000;
  gzip_types application/json text/css application/x-javascript;
  keepalive_timeout 65;
  client_max_body_size 2m;

  #this is the jenkins web root directory (mentioned in the /etc/default/jenkins file)
#  root            /var/run/jenkins/war/;

 # access_log      /var/log/nginx/jenkins/access.log;
 # error_log       /var/log/nginx/jenkins/error.log;

  location ~ "^/static/[0-9a-fA-F]{8}\/(.*)$" {

    #rewrite all static files into requests to the root
    #E.g /static/12345678/css/something.css will become /css/something.css
    rewrite "^/static/[0-9a-fA-F]{8}\/(.*)" /$1 last;
  }

  location /userContent {
        #have nginx handle all the static requests to the userContent folder files
        #note : This is the $JENKINS_HOME dir
    root /var/lib/jenkins/;
        if (!-f $request_filename){
           #this file does not exist, might be a directory or a /**view** url
           rewrite (.*) /$1 last;
       break;
        }
    sendfile on;
  }

  location @jenkins {
      sendfile off;
      proxy_pass         http://jenkins:8080;
      proxy_redirect     default;

      proxy_set_header   Host             $host;
      proxy_set_header   X-Real-IP        $remote_addr;
      proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
      proxy_max_temp_file_size 0;

      #this is the maximum upload size
      client_max_body_size       10m;
      client_body_buffer_size    128k;

      proxy_connect_timeout      90;
      proxy_send_timeout         90;
      proxy_read_timeout         90;

      proxy_buffer_size          4k;
      proxy_buffers              4 32k;
      proxy_busy_buffers_size    64k;
      proxy_temp_file_write_size 64k;
}

  location / {

     # Optional configuration to detect and redirect iPhones
      if ($http_user_agent ~* '(iPhone|iPod)') {
          rewrite ^/$ /view/iphone/ redirect;
      }

      try_files $uri @jenkins;
   }
}


通过docker-compose up启动。 然后访问http://localhost,即可进入jenkins。

依次安装即可。 ps:安装过程可能会遇到一些问题,比如: 安装jenkins时出现 No such plugin: cloudbees-folder的解决办法


jenkins 的一些常用配置



系统设置

  • 可以配置主目录
  • JenkinsURL
  • 邮件SMTP
  • ...

权限配置


权限配置误操作了怎么办?

ps: 配置的时候需要慎重,不然误点了会导致进不了系统了。 万一真的误点了,可以参考这里 https://www.cnblogs.com/sker/p/9255368.html

当然也可以备份里面找到jenkins的config.xml 配置文件,找到如下几行,恢复重启即可。


推荐插件

  • Backup plugin | 备份
  • description setter plugin
  • Global Variable String Parameter
  • Hidden Parameter plugin
  • Readonly Parameter plugin
  • Mask Passwords
  • Rebuilder
  • ......

节点配置

目前安装完jnekins之后,此时执行任务的话都是在jenkins的docker环境下面的,想象一下我们此时需要用npm要怎么办呢?


这样新建的job可以使用这个节点来打包了


备份

方式很多,我采用了一个定时任务的job

https://github.com/sue445/jenkins-backup-script

可以做到每日备份。


搭建一个自动集成环境


  • 创建job
  • 参数
  • 构建环境
  • 构建
  • 构建后操作

创建job



参数


构建环境


构建


构建脚本

#!/bin/bash

function func_log_print(){
    local level="$1"
    local msg="$2"
        case $level in
        error)  echo -e "\033[41;30;1m${msg}\033[0m";;
        warn)   echo -e "\033[43;30;1m${msg}\033[0m";;
    info)   echo -e "\033[47;30;1m${msg}\033[0m";;
    concern)    echo -e "\033[42;30;1m${msg}\033[0m";;
    *)      echo "${msg}";;
    esac
}

function check_or_exit(){
    if [ $? -ne 0 ] ; then
        echo "error code : $?"
        echo $1
        exit 127
    fi
}

echo;
func_log_print warn "------------------------Build Script Start ------------------------------\n\n"
func_log_print warn "------------------------Argument parse ------------------------------\n\n"
while [[ $# > 1 ]]; do
    key="$1"
    case $key in
        -gitrepo)
            GIT_REPO="$2"
            shift
            ;;
        -tag)
            GIT_TAG="$2"
            shift
            ;;
      -build_type)
          BUILD_TYPE="$2"
          shift
          ;;
        *)
        # unknown option
                func_log_print warn "warning--->unknown option"
        ;;
    esac
    shift # past argument or value
done

if [ -z $GIT_REPO ]; then
  echo "git地址不能为空"
  exit 127
fi

# tag为空的时候默认master
if [ -z $GIT_TAG ]; then
  GIT_TAG='master'
fi

projectName=${GIT_REPO##*/}
projectName=${projectName%%.*}

func_log_print warn "gitrepo --->  $GIT_REPO"
func_log_print warn "tag    --->  $GIT_TAG"

func_log_print warn "------------------------ pull source ------------------------------\n\n"
cd ${WORKSPACE}
rm -rf $projectName # 删除项目
git clone $GIT_REPO -b ${GIT_TAG}
cd $projectName
npm install 

func_log_print warn "------------------------  生成test 报告 ------------------------------\n\n"
npm test

func_log_print warn "------------------------ 上传test 报告 ------------------------------\n\n"
mkdir ${BUILD_ID}
mv testResultsProcessorResult.html ${BUILD_ID}/testResultsProcessorResult.html
sed -i "" "s/\/Users\/gtts\/Documents\/workspace\/workspace\/jstest\/jest-html-reporter\/style/http:\/\/192.168.1.26:8000\/style/g" `grep -rl \/Users\/gtts\/Documents\/workspace\/workspace\/jstest\/jest-html-reporter ./`
sed -i "" "s/\/Users\/gtts\/Documents\/workspace\/workspace\/jstest\/jest-html-reporter\/test/https:\/\/github.com\/Hargne\/jest-html-reporter\/tree\/master\/test/g" `grep -rl \/Users\/gtts\/Documents\/workspace\/workspace\/jstest\/jest-html-reporter ./`
cp -r ${BUILD_ID} ~/Desktop/jstest

echo "report: http://192.168.1.26:8000/${BUILD_ID}/testResultsProcessorResult.html username: ${BUILD_USER} buildtype: ${BUILD_TYPE}"

func_log_print warn "------------------------ done. ------------------------------\n\n"

构建后操作

想要这样的输出效果:

可以方便看测试报告,构建的用户名和构建环境


构建后操作

  • 安装插件:description setter plugin
  • 构建脚本输出:echo "report: http://192.168.1.26:8000/${BUILD_ID}/testResultsProcessorResult.html username: ${BUILD_USER} buildtype: ${BUILD_TYPE}"
  • 通过正则,可以用html输出

构建后可以触发通知等其它事件


其它强调点

  • job执行过程中,如果需要做一些其它审批,可以通过异步请求暂停,日中中输出一个url供用户去审批,审批完了之后再继续执行
  • 定时、hooks触发
  • 发短信、邮件通知结果
  • 因为是本地搭建,没法使用Gitlab hooks功能,所以可以采用定时任务的策略,来定时构建

总结

  • docker 和jenkins 介绍
  • 使用docker部署jenkins
  • jenkins 的一些常用配置
  • 搭建一个自动集成环境

Thanks!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,302评论 5 470
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,232评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,337评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,977评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,920评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,194评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,638评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,319评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,455评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,379评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,426评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,106评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,696评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,786评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,996评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,467评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,043评论 2 341